Module: ActionMCP::Server::Elicitation
- Included in:
- TransportHandler
- Defined in:
- lib/action_mcp/server/elicitation.rb
Overview
Handles elicitation requests from the server to the client.
Two modes per MCP 2025-11-25:
- Form mode: structured data collection with JSON Schema validation
- URL mode: out-of-band interaction via external URL (sensitive data, OAuth flows)
Constant Summary collapse
- URL_ELICITATION_REQUIRED_CODE =
-32_042
Instance Method Summary collapse
-
#send_elicitation_complete_notification(elicitation_id) ⇒ Object
Send a completion notification for a URL mode elicitation.
-
#send_elicitation_create(message:, requested_schema:, _meta: {}, task: nil) ⇒ Object
Send a form mode elicitation request to the client.
-
#send_elicitation_create_url(message:, url:, elicitation_id: nil, _meta: {}, task: nil) ⇒ Object
Send a URL mode elicitation request to the client.
-
#send_url_elicitation_required_error(request_id, message:, elicitations:) ⇒ Object
Build a URLElicitationRequiredError response (-32042).
Instance Method Details
#send_elicitation_complete_notification(elicitation_id) ⇒ Object
Send a completion notification for a URL mode elicitation. Informs the client that the out-of-band interaction has completed.
61 62 63 64 65 66 67 68 69 70 71 |
# File 'lib/action_mcp/server/elicitation.rb', line 61 def send_elicitation_complete_notification(elicitation_id) require_client_elicitation_support!(:url) unless elicitation_id.is_a?(String) && elicitation_id.present? raise ArgumentError, "elicitation_id must be a non-empty string" end send_jsonrpc_notification( "notifications/elicitation/complete", { elicitationId: elicitation_id } ) end |
#send_elicitation_create(message:, requested_schema:, _meta: {}, task: nil) ⇒ Object
Send a form mode elicitation request to the client.
20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
# File 'lib/action_mcp/server/elicitation.rb', line 20 def send_elicitation_create(message:, requested_schema:, _meta: {}, task: nil) require_client_elicitation_support!(:form) require_client_elicitation_task_support! if task request = ElicitationRequest.new( message: , requested_schema: requested_schema, _meta: , task: task ) request.assert_valid! send_jsonrpc_request("elicitation/create", params: request.to_params) end |
#send_elicitation_create_url(message:, url:, elicitation_id: nil, _meta: {}, task: nil) ⇒ Object
Send a URL mode elicitation request to the client. Used for sensitive data collection (API keys, OAuth, payments) that must not pass through the MCP client.
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
# File 'lib/action_mcp/server/elicitation.rb', line 42 def send_elicitation_create_url(message:, url:, elicitation_id: nil, _meta: {}, task: nil) require_client_elicitation_support!(:url) require_client_elicitation_task_support! if task request = UrlElicitationRequest.new( message: , url: url, elicitation_id: elicitation_id, _meta: , task: task ) request.assert_valid! send_jsonrpc_request("elicitation/create", params: request.to_params) end |
#send_url_elicitation_required_error(request_id, message:, elicitations:) ⇒ Object
Build a URLElicitationRequiredError response (-32042). Used when a request cannot proceed until an elicitation is completed.
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 |
# File 'lib/action_mcp/server/elicitation.rb', line 78 def send_url_elicitation_required_error(request_id, message:, elicitations:) require_client_elicitation_support!(:url) raise ArgumentError, "message must be a string" unless .is_a?(String) raise ArgumentError, "elicitations must be an array" unless elicitations.is_a?(Array) normalized_elicitations = elicitations.map do |elicitation| unless elicitation.respond_to?(:to_h) && elicitation.to_h.is_a?(Hash) raise ArgumentError, "Each elicitation must be an object" end attributes = elicitation.to_h.with_indifferent_access raise ArgumentError, "Each elicitation must have mode: 'url'" unless attributes[:mode] == "url" raise ArgumentError, "Each elicitation must have an elicitationId" unless attributes[:elicitationId].present? request = UrlElicitationRequest.new( message: attributes[:message], url: attributes[:url], elicitation_id: attributes[:elicitationId], _meta: attributes[:_meta], task: attributes[:task] ) request.assert_valid! extensions = attributes.except(:mode, :message, :url, :elicitationId, :_meta, :task) request.to_params.merge(extensions) end error = { code: URL_ELICITATION_REQUIRED_CODE, message: , data: { elicitations: normalized_elicitations } } send_jsonrpc_response(request_id, error: error) end |