Class: MCP::Client::HTTP
- Inherits:
-
Object
- Object
- MCP::Client::HTTP
- Defined in:
- lib/mcp/client/http.rb
Overview
TODO: HTTP GET for SSE streaming is not yet implemented.
https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#listening-for-messages-from-the-server
TODO: Resumability and redelivery with Last-Event-ID is not yet implemented.
https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#resumability-and-redelivery
Constant Summary collapse
- ACCEPT_HEADER =
"application/json, text/event-stream"- SESSION_ID_HEADER =
"Mcp-Session-Id"- PROTOCOL_VERSION_HEADER =
"MCP-Protocol-Version"
Instance Attribute Summary collapse
-
#protocol_version ⇒ Object
readonly
Returns the value of attribute protocol_version.
-
#session_id ⇒ Object
readonly
Returns the value of attribute session_id.
-
#url ⇒ Object
readonly
Returns the value of attribute url.
Instance Method Summary collapse
-
#close ⇒ Object
Terminates the session by sending an HTTP DELETE to the MCP endpoint with the current ‘Mcp-Session-Id` header, and clears locally tracked session state afterward.
-
#initialize(url:, headers: {}, &block) ⇒ HTTP
constructor
A new instance of HTTP.
-
#send_request(request:) ⇒ Object
Sends a JSON-RPC request and returns the parsed response body.
Constructor Details
#initialize(url:, headers: {}, &block) ⇒ HTTP
Returns a new instance of HTTP.
18 19 20 21 22 23 24 |
# File 'lib/mcp/client/http.rb', line 18 def initialize(url:, headers: {}, &block) @url = url @headers = headers @faraday_customizer = block @session_id = nil @protocol_version = nil end |
Instance Attribute Details
#protocol_version ⇒ Object (readonly)
Returns the value of attribute protocol_version.
16 17 18 |
# File 'lib/mcp/client/http.rb', line 16 def protocol_version @protocol_version end |
#session_id ⇒ Object (readonly)
Returns the value of attribute session_id.
16 17 18 |
# File 'lib/mcp/client/http.rb', line 16 def session_id @session_id end |
#url ⇒ Object (readonly)
Returns the value of attribute url.
16 17 18 |
# File 'lib/mcp/client/http.rb', line 16 def url @url end |
Instance Method Details
#close ⇒ Object
Terminates the session by sending an HTTP DELETE to the MCP endpoint with the current ‘Mcp-Session-Id` header, and clears locally tracked session state afterward. No-op when no session has been established.
Per spec, the server MAY respond with HTTP 405 Method Not Allowed when it does not support client-initiated termination, and returns 404 for a session it has already terminated. Both mean the session is gone —the desired end state. Other errors surface to the caller; local session state is cleared either way. modelcontextprotocol.io/specification/2025-11-25/basic/transports#session-management
107 108 109 110 111 112 113 114 115 116 117 |
# File 'lib/mcp/client/http.rb', line 107 def close return unless @session_id begin client.delete("", nil, session_headers) rescue Faraday::ClientError => e raise unless [404, 405].include?(e.response&.dig(:status)) ensure clear_session end end |
#send_request(request:) ⇒ Object
Sends a JSON-RPC request and returns the parsed response body. After a successful ‘initialize` handshake, the session ID and protocol version returned by the server are captured and automatically included on subsequent requests.
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
# File 'lib/mcp/client/http.rb', line 30 def send_request(request:) method = request[:method] || request["method"] params = request[:params] || request["params"] response = client.post("", request, session_headers) body = parse_response_body(response, method, params) capture_session_info(method, response, body) body rescue Faraday::BadRequestError => e raise RequestHandlerError.new( "The #{method} request is invalid", { method: method, params: params }, error_type: :bad_request, original_error: e, ) rescue Faraday::UnauthorizedError => e raise RequestHandlerError.new( "You are unauthorized to make #{method} requests", { method: method, params: params }, error_type: :unauthorized, original_error: e, ) rescue Faraday::ForbiddenError => e raise RequestHandlerError.new( "You are forbidden to make #{method} requests", { method: method, params: params }, error_type: :forbidden, original_error: e, ) rescue Faraday::ResourceNotFound => e # Per spec, 404 is the session-expired signal only when the request # actually carried an `Mcp-Session-Id`. A 404 without a session attached # (e.g. wrong URL or a stateless server) surfaces as a generic not-found. # https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#session-management if @session_id clear_session raise SessionExpiredError.new( "The #{method} request is not found", { method: method, params: params }, original_error: e, ) else raise RequestHandlerError.new( "The #{method} request is not found", { method: method, params: params }, error_type: :not_found, original_error: e, ) end rescue Faraday::UnprocessableEntityError => e raise RequestHandlerError.new( "The #{method} request is unprocessable", { method: method, params: params }, error_type: :unprocessable_entity, original_error: e, ) rescue Faraday::Error => e # Catch-all raise RequestHandlerError.new( "Internal error handling #{method} request", { method: method, params: params }, error_type: :internal_error, original_error: e, ) end |