Class: MCP::Client
- Inherits:
-
Object
- Object
- MCP::Client
- Defined in:
- lib/mcp/client.rb,
lib/mcp/client/http.rb,
lib/mcp/client/tool.rb,
lib/mcp/client/oauth.rb,
lib/mcp/client/stdio.rb,
lib/mcp/client/oauth/flow.rb,
lib/mcp/client/oauth/pkce.rb,
lib/mcp/client/elicitation.rb,
lib/mcp/client/oauth/provider.rb,
lib/mcp/client/oauth/discovery.rb,
lib/mcp/client/paginated_result.rb,
lib/mcp/client/oauth/in_memory_storage.rb,
lib/mcp/client/oauth/jwt_client_assertion.rb,
lib/mcp/client/oauth/storage_backed_provider.rb,
lib/mcp/client/oauth/client_credentials_provider.rb
Defined Under Namespace
Modules: Elicitation, OAuth Classes: HTTP, InputRequiredError, ListPromptsResult, ListResourceTemplatesResult, ListResourcesResult, ListToolsResult, RequestHandlerError, ServerError, ServerRequestError, SessionExpiredError, Stdio, Tool, ValidationError
Instance Attribute Summary collapse
-
#transport ⇒ Object
readonly
The user may want to access additional transport-specific methods/attributes So keeping it public.
Instance Method Summary collapse
-
#call_tool(name: nil, tool: nil, arguments: nil, progress_token: nil, meta: nil, cancellation: nil) ⇒ Hash
Calls a tool via the transport layer and returns the full response from the server.
-
#complete(ref:, argument:, context: nil, meta: nil, cancellation: nil) ⇒ Hash
Requests completion suggestions from the server for a prompt argument or resource template URI.
-
#connect(client_info: nil, protocol_version: nil, capabilities: {}) ⇒ Hash?
Performs the MCP
initializehandshake by delegating to the transport (e.g.MCP::Client::HTTP,MCP::Client::Stdio). -
#connected? ⇒ Boolean
Returns true once
connecthas completed the handshake on the underlying transport. -
#get_prompt(name:, meta: nil, cancellation: nil) ⇒ Hash
Gets a prompt from the server by name and returns its details.
-
#initialize(transport:) ⇒ Client
constructor
Initializes a new MCP::Client instance.
-
#list_prompts(cursor: nil, meta: nil, cancellation: nil) ⇒ MCP::Client::ListPromptsResult
Returns a single page of prompts from the server.
-
#list_resource_templates(cursor: nil, meta: nil, cancellation: nil) ⇒ MCP::Client::ListResourceTemplatesResult
Returns a single page of resource templates from the server.
-
#list_resources(cursor: nil, meta: nil, cancellation: nil) ⇒ MCP::Client::ListResourcesResult
Returns a single page of resources from the server.
-
#list_tools(cursor: nil, meta: nil, cancellation: nil) ⇒ MCP::Client::ListToolsResult
Returns a single page of tools from the server.
-
#on_elicitation(&handler) ⇒ Object
Registers a handler for
elicitation/createrequests the server sends while one of this client's requests is in flight. -
#ping(meta: nil, cancellation: nil) ⇒ Hash
Sends a
pingrequest to the server to verify the connection is alive. -
#prompts(cancellation: nil) ⇒ Array<Hash>
Returns every prompt available on the server.
-
#read_resource(uri:, meta: nil, cancellation: nil) ⇒ Array<Hash>
Reads a resource from the server by URI and returns the contents.
-
#resource_templates(cancellation: nil) ⇒ Array<Hash>
Returns every resource template available on the server.
-
#resources(cancellation: nil) ⇒ Array<Hash>
Returns every resource available on the server.
-
#server_info ⇒ Object
The server's
InitializeResult(protocol version, capabilities, server info, instructions), as reported by the transport after a successfulconnect. -
#tools(cancellation: nil) ⇒ Array<MCP::Client::Tool>
Returns every tool available on the server.
Constructor Details
#initialize(transport:) ⇒ Client
Initializes a new MCP::Client instance.
90 91 92 |
# File 'lib/mcp/client.rb', line 90 def initialize(transport:) @transport = transport end |
Instance Attribute Details
#transport ⇒ Object (readonly)
The user may want to access additional transport-specific methods/attributes So keeping it public
96 97 98 |
# File 'lib/mcp/client.rb', line 96 def transport @transport end |
Instance Method Details
#call_tool(name: nil, tool: nil, arguments: nil, progress_token: nil, meta: nil, cancellation: nil) ⇒ Hash
The exact requirements for arguments are determined by the transport layer in use.
Consult the documentation for your transport (e.g., MCP::Client::HTTP) for details.
Calls a tool via the transport layer and returns the full response from the server.
342 343 344 345 346 347 348 349 350 351 352 353 354 355 |
# File 'lib/mcp/client.rb', line 342 def call_tool(name: nil, tool: nil, arguments: nil, progress_token: nil, meta: nil, cancellation: nil) tool_name = name || tool&.name raise ArgumentError, "Either `name:` or `tool:` must be provided." unless tool_name params = { name: tool_name, arguments: arguments } = ? .dup : {} if progress_token .delete("progressToken") [:progressToken] = progress_token end params[:_meta] = unless .empty? request(method: "tools/call", params: params, cancellation: cancellation) end |
#complete(ref:, argument:, context: nil, meta: nil, cancellation: nil) ⇒ Hash
Requests completion suggestions from the server for a prompt argument or resource template URI.
393 394 395 396 397 398 399 400 |
# File 'lib/mcp/client.rb', line 393 def complete(ref:, argument:, context: nil, meta: nil, cancellation: nil) params = { ref: ref, argument: argument } params[:context] = context if context response = request(method: "completion/complete", params: params, meta: , cancellation: cancellation) response.dig("result", "completion") || { "values" => [], "hasMore" => false } end |
#connect(client_info: nil, protocol_version: nil, capabilities: {}) ⇒ Hash?
Performs the MCP initialize handshake by delegating to the transport
(e.g. MCP::Client::HTTP, MCP::Client::Stdio). Returns the server's
InitializeResult.
When the transport does not respond to :connect, this is a no-op and
returns nil.
https://modelcontextprotocol.io/specification/2025-11-25/basic/lifecycle#initialization
121 122 123 124 125 126 127 128 129 |
# File 'lib/mcp/client.rb', line 121 def connect(client_info: nil, protocol_version: nil, capabilities: {}) return unless transport.respond_to?(:connect) transport.connect( client_info: client_info, protocol_version: protocol_version, capabilities: capabilities, ) end |
#connected? ⇒ Boolean
Returns true once connect has completed the handshake on the underlying
transport. Transports that do not expose connection state are assumed
connected and return true.
134 135 136 137 138 |
# File 'lib/mcp/client.rb', line 134 def connected? return transport.connected? if transport.respond_to?(:connected?) true end |
#get_prompt(name:, meta: nil, cancellation: nil) ⇒ Hash
Gets a prompt from the server by name and returns its details.
377 378 379 380 381 |
# File 'lib/mcp/client.rb', line 377 def get_prompt(name:, meta: nil, cancellation: nil) response = request(method: "prompts/get", params: { name: name }, meta: , cancellation: cancellation) response.fetch("result", {}) end |
#list_prompts(cursor: nil, meta: nil, cancellation: nil) ⇒ MCP::Client::ListPromptsResult
Returns a single page of prompts from the server.
280 281 282 283 284 285 286 287 288 289 290 291 292 |
# File 'lib/mcp/client.rb', line 280 def list_prompts(cursor: nil, meta: nil, cancellation: nil) params = cursor ? { cursor: cursor } : nil response = request(method: "prompts/list", params: params, meta: , cancellation: cancellation) result = response["result"] || {} ListPromptsResult.new( prompts: result["prompts"] || [], next_cursor: result["nextCursor"], meta: result["_meta"], ttl_ms: result["ttlMs"], cache_scope: result["cacheScope"], ) end |
#list_resource_templates(cursor: nil, meta: nil, cancellation: nil) ⇒ MCP::Client::ListResourceTemplatesResult
Returns a single page of resource templates from the server.
245 246 247 248 249 250 251 252 253 254 255 256 257 |
# File 'lib/mcp/client.rb', line 245 def list_resource_templates(cursor: nil, meta: nil, cancellation: nil) params = cursor ? { cursor: cursor } : nil response = request(method: "resources/templates/list", params: params, meta: , cancellation: cancellation) result = response["result"] || {} ListResourceTemplatesResult.new( resource_templates: result["resourceTemplates"] || [], next_cursor: result["nextCursor"], meta: result["_meta"], ttl_ms: result["ttlMs"], cache_scope: result["cacheScope"], ) end |
#list_resources(cursor: nil, meta: nil, cancellation: nil) ⇒ MCP::Client::ListResourcesResult
Returns a single page of resources from the server.
210 211 212 213 214 215 216 217 218 219 220 221 222 |
# File 'lib/mcp/client.rb', line 210 def list_resources(cursor: nil, meta: nil, cancellation: nil) params = cursor ? { cursor: cursor } : nil response = request(method: "resources/list", params: params, meta: , cancellation: cancellation) result = response["result"] || {} ListResourcesResult.new( resources: result["resources"] || [], next_cursor: result["nextCursor"], meta: result["_meta"], ttl_ms: result["ttlMs"], cache_scope: result["cacheScope"], ) end |
#list_tools(cursor: nil, meta: nil, cancellation: nil) ⇒ MCP::Client::ListToolsResult
Returns a single page of tools from the server.
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 |
# File 'lib/mcp/client.rb', line 158 def list_tools(cursor: nil, meta: nil, cancellation: nil) params = cursor ? { cursor: cursor } : nil response = request(method: "tools/list", params: params, meta: , cancellation: cancellation) result = response["result"] || {} tools = (result["tools"] || []).map do |tool| Tool.new( name: tool["name"], description: tool["description"], input_schema: tool["inputSchema"], output_schema: tool["outputSchema"], ) end ListToolsResult.new( tools: tools, next_cursor: result["nextCursor"], meta: result["_meta"], ttl_ms: result["ttlMs"], cache_scope: result["cacheScope"], ) end |
#on_elicitation(&handler) ⇒ Object
Registers a handler for elicitation/create requests the server sends while one of
this client's requests is in flight. The handler receives the request params
(message and requestedSchema, string keys) and must return an ElicitResult-shaped Hash:
{ action: "accept" | "decline" | "cancel", content: { ... } }.
Requires a transport that supports server-to-client requests (e.g. MCP::Client::HTTP);
pass capabilities: { elicitation: {} } to connect so the server knows it may send them.
https://modelcontextprotocol.io/specification/2025-11-25/client/elicitation
418 419 420 421 422 423 424 |
# File 'lib/mcp/client.rb', line 418 def on_elicitation(&handler) unless transport.respond_to?(:on_server_request) raise ArgumentError, "The transport does not support server-to-client requests" end transport.on_server_request(Methods::ELICITATION_CREATE, &handler) end |
#ping(meta: nil, cancellation: nil) ⇒ Hash
Sends a ping request to the server to verify the connection is alive.
Per the MCP spec, the server responds with an empty result.
440 441 442 443 444 445 |
# File 'lib/mcp/client.rb', line 440 def ping(meta: nil, cancellation: nil) result = request(method: Methods::PING, meta: , cancellation: cancellation)["result"] raise ValidationError, "Response validation failed: missing or invalid `result`" unless result.is_a?(Hash) result end |
#prompts(cancellation: nil) ⇒ Array<Hash>
Returns every prompt available on the server. Iterates through all pages automatically
when the server paginates, so the full collection is returned regardless of the server's page_size setting.
Use #list_prompts when you need fine-grained cursor control.
Each call will make a new request - the result is not cached.
302 303 304 305 |
# File 'lib/mcp/client.rb', line 302 def prompts(cancellation: nil) # TODO: consider renaming to `list_all_prompts`. fetch_all_pages { |cursor| list_prompts(cursor: cursor, cancellation: cancellation) }.flat_map(&:prompts) end |
#read_resource(uri:, meta: nil, cancellation: nil) ⇒ Array<Hash>
Reads a resource from the server by URI and returns the contents.
364 365 366 367 368 |
# File 'lib/mcp/client.rb', line 364 def read_resource(uri:, meta: nil, cancellation: nil) response = request(method: "resources/read", params: { uri: uri }, meta: , cancellation: cancellation) response.dig("result", "contents") || [] end |
#resource_templates(cancellation: nil) ⇒ Array<Hash>
Returns every resource template available on the server. Iterates through all pages automatically
when the server paginates, so the full collection is returned regardless of the server's page_size setting.
Use #list_resource_templates when you need fine-grained cursor control.
Each call will make a new request - the result is not cached.
267 268 269 270 |
# File 'lib/mcp/client.rb', line 267 def resource_templates(cancellation: nil) # TODO: consider renaming to `list_all_resource_templates`. fetch_all_pages { |cursor| list_resource_templates(cursor: cursor, cancellation: cancellation) }.flat_map(&:resource_templates) end |
#resources(cancellation: nil) ⇒ Array<Hash>
Returns every resource available on the server. Iterates through all pages automatically
when the server paginates, so the full collection is returned regardless of the server's page_size setting.
Use #list_resources when you need fine-grained cursor control.
Each call will make a new request - the result is not cached.
232 233 234 235 |
# File 'lib/mcp/client.rb', line 232 def resources(cancellation: nil) # TODO: consider renaming to `list_all_resources`. fetch_all_pages { |cursor| list_resources(cursor: cursor, cancellation: cancellation) }.flat_map(&:resources) end |
#server_info ⇒ Object
The server's InitializeResult (protocol version, capabilities, server info,
instructions), as reported by the transport after a successful connect.
Returns nil before connect, after close, or when the transport does
not expose a cached handshake result.
102 103 104 |
# File 'lib/mcp/client.rb', line 102 def server_info transport.server_info if transport.respond_to?(:server_info) end |
#tools(cancellation: nil) ⇒ Array<MCP::Client::Tool>
Returns every tool available on the server. Iterates through all pages automatically
when the server paginates, so the full collection is returned regardless of the server's page_size setting.
Use #list_tools when you need fine-grained cursor control.
Each call will make a new request - the result is not cached.
197 198 199 200 |
# File 'lib/mcp/client.rb', line 197 def tools(cancellation: nil) # TODO: consider renaming to `list_all_tools`. fetch_all_pages { |cursor| list_tools(cursor: cursor, cancellation: cancellation) }.flat_map(&:tools) end |