Class: McpToolkit::Gateway::Client
- Inherits:
-
Object
- Object
- McpToolkit::Gateway::Client
- Defined in:
- lib/mcp_toolkit/gateway/client.rb
Overview
Minimal MCP client over Streamable HTTP, used by a GATEWAY to talk to an upstream MCP server when aggregating its tool list and proxying tool calls.
It speaks the same Streamable-HTTP MCP that McpToolkit::Transport serves:
1. POST `initialize` -> capture the `Mcp-Session-Id` response header
2. POST `notifications/initialized` (a notification; no response expected)
3. POST `tools/list` / `tools/call`, echoing the session header
Auth & account selection are pass-through: the caller's bearer token and the
account selector (_meta) are forwarded so the upstream can introspect the
same token against its authority and resolve the same account.
Transport notes
- Content negotiation: we POST application/json and Accept both
application/json and text/event-stream. If the upstream answers with SSE
(one message + EOF, as the toolkit's own transport does) we extract the
single JSON payload from the
data:line. - Every public method may raise McpToolkit::Gateway::Client::Error (timeouts, non-2xx, unparseable bodies, JSON-RPC errors). Callers decide whether to degrade (omit from list) or surface the error (proxied call).
Everything app-specific (server identity, protocol version, timeout, logger) is injected via McpToolkit::Configuration; nothing here names a deployment.
Defined Under Namespace
Classes: Error
Constant Summary collapse
- SESSION_HEADER =
"Mcp-Session-Id"- JSONRPC_VERSION =
"2.0"- DEFAULT_PROTOCOL_VERSION =
The protocol version offered on the handshake when the config does not pin one. Sourced from the wrapped
mcpSDK's latest-supported constant when available, with a literal fallback so the gem still loads if the SDK moves the constant.config.protocol_versionoverrides it. if defined?(MCP::Configuration) && MCP::Configuration.const_defined?(:LATEST_STABLE_PROTOCOL_VERSION) MCP::Configuration::LATEST_STABLE_PROTOCOL_VERSION else "2025-06-18" end
- SESSION_LOSS_HTTP_STATUS =
An upstream whose session store is not shared across its pods can answer a NON-initialize request with HTTP 404 (the pod fielding it never saw our initialize), or with a JSON-RPC -32001 "Session not found or expired". Both mean the same thing: our session is gone and a fresh handshake recovers it.
404- SESSION_NOT_FOUND_CODE =
-32_001
Instance Attribute Summary collapse
-
#bearer_token ⇒ Object
readonly
Returns the value of attribute bearer_token.
-
#config ⇒ Object
readonly
Returns the value of attribute config.
-
#timeout ⇒ Object
readonly
Returns the value of attribute timeout.
-
#upstream ⇒ Object
readonly
Returns the value of attribute upstream.
Instance Method Summary collapse
-
#initialize(upstream:, bearer_token: nil, config: McpToolkit.config) ⇒ Client
constructor
A new instance of Client.
-
#tools_call(name:, arguments: {}, meta: nil) ⇒ Object
Proxies a tools/call to the upstream.
-
#tools_list ⇒ Object
Returns the upstream's raw tools array (each a tool definition hash with string keys: "name", "description", "inputSchema").
Constructor Details
#initialize(upstream:, bearer_token: nil, config: McpToolkit.config) ⇒ Client
Returns a new instance of Client.
68 69 70 71 72 73 74 75 |
# File 'lib/mcp_toolkit/gateway/client.rb', line 68 def initialize(upstream:, bearer_token: nil, config: McpToolkit.config) @upstream = upstream @bearer_token = bearer_token @config = config @timeout = config.upstream_timeout @session_id = nil @initialized = false end |
Instance Attribute Details
#bearer_token ⇒ Object (readonly)
Returns the value of attribute bearer_token.
66 67 68 |
# File 'lib/mcp_toolkit/gateway/client.rb', line 66 def bearer_token @bearer_token end |
#config ⇒ Object (readonly)
Returns the value of attribute config.
66 67 68 |
# File 'lib/mcp_toolkit/gateway/client.rb', line 66 def config @config end |
#timeout ⇒ Object (readonly)
Returns the value of attribute timeout.
66 67 68 |
# File 'lib/mcp_toolkit/gateway/client.rb', line 66 def timeout @timeout end |
#upstream ⇒ Object (readonly)
Returns the value of attribute upstream.
66 67 68 |
# File 'lib/mcp_toolkit/gateway/client.rb', line 66 def upstream @upstream end |
Instance Method Details
#tools_call(name:, arguments: {}, meta: nil) ⇒ Object
Proxies a tools/call to the upstream. arguments and meta are forwarded
as-is. Returns the upstream's result hash verbatim (typically
{ "content" => [...] }). A JSON-RPC error from the upstream is raised as an
Error carrying jsonrpc_error so a proxy can relay it.
91 92 93 94 95 96 97 |
# File 'lib/mcp_toolkit/gateway/client.rb', line 91 def tools_call(name:, arguments: {}, meta: nil) params = { "name" => name, "arguments" => arguments } params["_meta"] = if .present? with_session_recovery("tools/call #{name}") do rpc!("tools/call", params) end end |
#tools_list ⇒ Object
Returns the upstream's raw tools array (each a tool definition hash with string keys: "name", "description", "inputSchema"). Bare names — the caller namespaces them.
80 81 82 83 84 85 |
# File 'lib/mcp_toolkit/gateway/client.rb', line 80 def tools_list with_session_recovery("tools/list") do result = rpc!("tools/list") Array(result["tools"]) end end |