Module: MCPClient

Defined in:
lib/mcp_client.rb,
lib/mcp_client/auth.rb,
lib/mcp_client/root.rb,
lib/mcp_client/task.rb,
lib/mcp_client/tool.rb,
lib/mcp_client/client.rb,
lib/mcp_client/errors.rb,
lib/mcp_client/prompt.rb,
lib/mcp_client/version.rb,
lib/mcp_client/resource.rb,
lib/mcp_client/deep_copy.rb,
lib/mcp_client/server_sse.rb,
lib/mcp_client/server_base.rb,
lib/mcp_client/server_http.rb,
lib/mcp_client/session_pin.rb,
lib/mcp_client/deprecations.rb,
lib/mcp_client/oauth_client.rb,
lib/mcp_client/server_stdio.rb,
lib/mcp_client/subscription.rb,
lib/mcp_client/audio_content.rb,
lib/mcp_client/cached_result.rb,
lib/mcp_client/config_parser.rb,
lib/mcp_client/header_params.rb,
lib/mcp_client/resource_link.rb,
lib/mcp_client/auth/peer_text.rb,
lib/mcp_client/result_caching.rb,
lib/mcp_client/server_factory.rb,
lib/mcp_client/client/task_api.rb,
lib/mcp_client/json_rpc_common.rb,
lib/mcp_client/request_metadata.rb,
lib/mcp_client/resource_content.rb,
lib/mcp_client/schema_validator.rb,
lib/mcp_client/client/task_shape.rb,
lib/mcp_client/input_round_trips.rb,
lib/mcp_client/resource_template.rb,
lib/mcp_client/round_trip_marker.rb,
lib/mcp_client/auth/browser_oauth.rb,
lib/mcp_client/request_meta_scope.rb,
lib/mcp_client/auth/oauth_provider.rb,
lib/mcp_client/client/cache_slices.rb,
lib/mcp_client/client/task_support.rb,
lib/mcp_client/client/task_updates.rb,
lib/mcp_client/client/task_workers.rb,
lib/mcp_client/deprecation_notices.rb,
lib/mcp_client/http_transport_base.rb,
lib/mcp_client/result_completeness.rb,
lib/mcp_client/client/task_registry.rb,
lib/mcp_client/subscription_support.rb,
lib/mcp_client/client/task_lifetimes.rb,
lib/mcp_client/elicitation_validator.rb,
lib/mcp_client/request_authorization.rb,
lib/mcp_client/server_sse/sse_parser.rb,
lib/mcp_client/called_tool_definition.rb,
lib/mcp_client/server_streamable_http.rb,
lib/mcp_client/client/list_aggregation.rb,
lib/mcp_client/schema_validator/shapes.rb,
lib/mcp_client/schema_validator/scalars.rb,
lib/mcp_client/server_sse/origin_policy.rb,
lib/mcp_client/json_rpc_common/envelopes.rb,
lib/mcp_client/schema_validator/dialects.rb,
lib/mcp_client/client/sampling_validation.rb,
lib/mcp_client/schema_validator/instances.rb,
lib/mcp_client/server_stdio/child_session.rb,
lib/mcp_client/client/notification_routing.rb,
lib/mcp_client/client/task_wait_boundaries.rb,
lib/mcp_client/json_rpc_common/input_waits.rb,
lib/mcp_client/schema_validator/evaluation.rb,
lib/mcp_client/schema_validator/references.rb,
lib/mcp_client/json_rpc_common/error_bodies.rb,
lib/mcp_client/schema_validator/annotations.rb,
lib/mcp_client/schema_validator/composition.rb,
lib/mcp_client/server_sse/reconnect_monitor.rb,
lib/mcp_client/schema_validator/keyword_scan.rb,
lib/mcp_client/server_sse/json_rpc_transport.rb,
lib/mcp_client/schema_validator/ecma_patterns.rb,
lib/mcp_client/schema_validator/normalization.rb,
lib/mcp_client/server_http/json_rpc_transport.rb,
lib/mcp_client/auth/oauth_provider/token_store.rb,
lib/mcp_client/schema_validator/uri_references.rb,
lib/mcp_client/server_stdio/json_rpc_transport.rb,
lib/mcp_client/http_transport_base/tool_listing.rb,
lib/mcp_client/http_transport_base/cache_support.rb,
lib/mcp_client/http_transport_base/era_detection.rb,
lib/mcp_client/http_transport_base/listen_stream.rb,
lib/mcp_client/http_transport_base/param_headers.rb,
lib/mcp_client/http_transport_base/stream_capture.rb,
lib/mcp_client/auth/oauth_provider/scope_selection.rb,
lib/mcp_client/http_transport_base/bounded_inflate.rb,
lib/mcp_client/http_transport_base/stream_recovery.rb,
lib/mcp_client/schema_validator/input_requirements.rb,
lib/mcp_client/auth/oauth_provider/pending_requests.rb,
lib/mcp_client/http_transport_base/request_recovery.rb,
lib/mcp_client/http_transport_base/session_recovery.rb,
lib/mcp_client/subscription/notification_dispatcher.rb,
lib/mcp_client/http_transport_base/sse_event_scanner.rb,
lib/mcp_client/auth/oauth_provider/challenge_handling.rb,
lib/mcp_client/auth/oauth_provider/registration_store.rb,
lib/mcp_client/auth/oauth_provider/response_validation.rb,
lib/mcp_client/auth/oauth_provider/client_authentication.rb,
lib/mcp_client/server_streamable_http/json_rpc_transport.rb

Overview

Model Context Protocol (MCP) Client module Provides a standardized way for agents to communicate with external tools and services through a protocol-based approach

Defined Under Namespace

Modules: Auth, CalledToolDefinition, DeepCopy, DeprecationNotices, Deprecations, ElicitationValidator, Errors, HeaderParams, HttpTransportBase, InputRoundTrips, JsonRpcCommon, RequestAuthorization, RequestMetaScope, RequestMetadata, ResultCaching, ResultCompleteness, RoundTripMarker, SchemaValidator, SessionPin, SubscriptionSupport Classes: AudioContent, CachedResult, Client, ConfigParser, OAuthClient, Prompt, Resource, ResourceContent, ResourceLink, ResourceTemplate, Root, ServerBase, ServerFactory, ServerHTTP, ServerSSE, ServerStdio, ServerStreamableHTTP, Subscription, Task, Tool

Constant Summary collapse

VERSION =

Current version of the MCP client gem

'3.0.0'
LATEST_PROTOCOL_VERSION =

Latest MCP protocol revision this client implements (basic/versioning). Modern revisions (2026-07-28 and later) carry the protocol version, client identity and capabilities as per-request _meta fields instead of negotiating them once in an initialize handshake.

'2026-07-28'
MODERN_PROTOCOL_VERSIONS =

Protocol revisions that use per-request metadata (no handshake), newest first. Every request to a modern server declares one of these in _meta["io.modelcontextprotocol/protocolVersion"].

%w[2026-07-28].freeze
LEGACY_PROTOCOL_VERSIONS =

Protocol revisions that establish a session with an initialize handshake (2025-11-25 and earlier), newest first.

%w[2025-11-25 2025-06-18 2025-03-26 2024-11-05].freeze
PROTOCOL_VERSION =

Protocol version sent in the legacy initialize request: the newest handshake-based revision. A legacy server may negotiate down to any other LEGACY_PROTOCOL_VERSIONS entry.

'2025-11-25'
SUPPORTED_PROTOCOL_VERSIONS =

Every protocol version this client can speak, in preference order.

(MODERN_PROTOCOL_VERSIONS + LEGACY_PROTOCOL_VERSIONS).freeze

Class Method Summary collapse

Class Method Details

.connect(target) {|Faraday::Connection| ... } ⇒ MCPClient::Client

Simplified connection API - auto-detects transport and returns connected client

Accepts keyword arguments for connection options:

  • headers [Hash] HTTP headers for remote transports
  • read_timeout [Integer] Request timeout in seconds (default: 30)
  • retries [Integer] Retry attempts
  • retry_backoff [Numeric] Backoff delay (default: 1)
  • name [String] Optional server name
  • logger [Logger] Optional logger
  • env [Hash] Environment variables for stdio
  • ping [Integer] Ping interval for SSE (default: 10)
  • endpoint [String] JSON-RPC endpoint path (default: '/rpc')
  • transport [Symbol] Force transport type (:stdio, :sse, :http, :streamable_http). :sse forces the deprecated HTTP+SSE transport (SEP-2596); earliest removal is three months after SEP-2596 reaches Final. Prefer :streamable_http.
  • sampling_handler [Proc] Handler for sampling requests. Deprecated since MCP 2026-07-28 (SEP-2577); earliest removal is the first revision released on or after 2027-07-28. Integrate directly with the LLM provider API instead.
  • protocol [Symbol] :auto (default), :modern or :legacy — which protocol era to speak (stdio, HTTP and Streamable HTTP; :modern with transport: :sse raises ArgumentError, the HTTP+SSE transport being legacy-only)
  • discover_timeout [Numeric] bound on the server/discover probe in seconds
  • extensions [Array] MCP extensions the client declares, e.g. 'io.modelcontextprotocol/tasks'

Examples:

Connect to Streamable HTTP server

client = MCPClient.connect('http://localhost:8000/mcp')

Connect to SSE server (deprecated transport; prefer Streamable HTTP)

client = MCPClient.connect('http://localhost:8000/sse')

Connect with options

client = MCPClient.connect('http://api.example.com/mcp',
  headers: { 'Authorization' => 'Bearer token' },
  read_timeout: 60
)

Connect to stdio server

client = MCPClient.connect('npx -y @modelcontextprotocol/server-filesystem /home')
# or with Array
client = MCPClient.connect(['npx', '-y', '@modelcontextprotocol/server-filesystem', '/home'])

Connect to multiple servers

client = MCPClient.connect(['http://server1/mcp', 'http://server2/mcp'])

Force transport type

client = MCPClient.connect('http://custom-server.com', transport: :streamable_http)

With Faraday customization

client = MCPClient.connect('https://internal.server.com/mcp') do |faraday|
  faraday.ssl.cert_store = custom_cert_store
end

Parameters:

  • target (String, Array<String>) —

    URL(s) or command for connection

    • URLs ending in /sse -> SSE transport. The HTTP+SSE transport has been deprecated since MCP 2025-03-26 and is listed in the 2026-07-28 deprecated features registry (SEP-2596); earliest removal is three months after SEP-2596 reaches Final. New integrations should use Streamable HTTP.
    • URLs ending in /mcp -> Streamable HTTP transport
    • stdio://command or Array commands -> stdio transport
    • Commands starting with npx, node, python, ruby, etc. -> stdio transport
    • Other HTTP URLs -> Try Streamable HTTP, then the deprecated HTTP+SSE transport (SEP-2596), then HTTP. The SSE step is a fallback for an existing server, not a choice a new integration should rely on.

Yields:

  • (Faraday::Connection) —

    Optional block for Faraday customization

Returns:

Raises:



115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/mcp_client.rb', line 115

def self.connect(target, **, &)
  # Handle array targets: either a single stdio command or multiple server URLs
  if target.is_a?(Array)
    # Check if it's a stdio command array (elements are command parts, not URLs)
    if stdio_command_array?(target)
      connect_single(target, **, &)
    else
      # It's an array of server URLs/commands
      connect_multiple(target, **, &)
    end
  else
    connect_single(target, **, &)
  end
end

.create_client(mcp_server_configs: [], server_definition_file: nil, logger: nil) ⇒ MCPClient::Client

Create a new MCPClient client

Parameters:

  • mcp_server_configs (Array<Hash>) (defaults to: []) —

    configurations for MCP servers

  • server_definition_file (String, nil) (defaults to: nil) —

    optional path to a JSON file defining server configurations The JSON may be a single server object or an array of server objects.

  • logger (Logger, nil) (defaults to: nil) —

    optional logger for client operations

Returns:



413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
# File 'lib/mcp_client.rb', line 413

def self.create_client(mcp_server_configs: [], server_definition_file: nil, logger: nil)
  require 'json'
  # Start with any explicit configs provided
  configs = Array(mcp_server_configs)
  # Load additional configs from a JSON file if specified
  if server_definition_file
    # Parse JSON definitions into clean config hashes
    parser = MCPClient::ConfigParser.new(server_definition_file, logger: logger)
    parsed = parser.parse
    parsed.each_value do |cfg|
      case cfg[:type].to_s
      when 'stdio'
        cmd_list = [cfg[:command]] + Array(cfg[:args])
        configs << MCPClient.stdio_config(
          command: cmd_list,
          name: cfg[:name],
          logger: logger,
          env: cfg[:env]
        )
      when 'sse'
        configs << MCPClient.sse_config(base_url: cfg[:url], headers: cfg[:headers] || {}, name: cfg[:name],
                                        logger: logger)
      when 'http'
        configs << MCPClient.http_config(base_url: cfg[:url], endpoint: cfg[:endpoint],
                                         headers: cfg[:headers] || {}, name: cfg[:name], logger: logger)
      when 'streamable_http'
        configs << MCPClient.streamable_http_config(base_url: cfg[:url], endpoint: cfg[:endpoint],
                                                    headers: cfg[:headers] || {}, name: cfg[:name], logger: logger)
      end
    end
  end
  MCPClient::Client.new(mcp_server_configs: configs, logger: logger)
end

.http_config(base_url:, endpoint: '/rpc', headers: {}, read_timeout: 30, retries: 3, retry_backoff: 1, name: nil, logger: nil, protocol: :auto, discover_timeout: nil) {|faraday| ... } ⇒ Hash

Create a standard server configuration for HTTP

Parameters:

  • base_url (String) —

    base URL for the server

  • endpoint (String) (defaults to: '/rpc') —

    JSON-RPC endpoint path (default: '/rpc')

  • headers (Hash) (defaults to: {}) —

    HTTP headers to include in requests

  • read_timeout (Integer) (defaults to: 30) —

    read timeout in seconds (default: 30)

  • retries (Integer) (defaults to: 3) —

    number of retry attempts (default: 3)

  • retry_backoff (Integer) (defaults to: 1) —

    backoff delay in seconds (default: 1)

  • name (String, nil) (defaults to: nil) —

    optional name for this server

  • logger (Logger, nil) (defaults to: nil) —

    optional logger for server operations

  • protocol (Symbol) (defaults to: :auto) —

    :auto (default), :modern or :legacy — which protocol era to speak

  • discover_timeout (Numeric, nil) (defaults to: nil) —

    bound on the server/discover probe in seconds

Yield Parameters:

  • faraday (Faraday::Connection) —

    the configured connection instance for additional customization (e.g., SSL settings, custom middleware). The block is called after default configuration is applied.

Returns:

  • (Hash) —

    server configuration



513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
# File 'lib/mcp_client.rb', line 513

def self.http_config(base_url:, endpoint: '/rpc', headers: {}, read_timeout: 30, retries: 3, retry_backoff: 1,
                     name: nil, logger: nil, protocol: :auto, discover_timeout: nil, &faraday_config)
  {
    type: 'http',
    base_url: base_url,
    endpoint: endpoint,
    headers: headers,
    read_timeout: read_timeout,
    retries: retries,
    retry_backoff: retry_backoff,
    name: name,
    logger: logger,
    protocol: protocol,
    discover_timeout: discover_timeout,
    faraday_config: faraday_config
  }
end

.parse_content_item(item) ⇒ MCPClient::ResourceLink, Hash

Parse a single content item from a tool result into a typed object Recognizes 'resource_link' type and returns an MCPClient::ResourceLink. Unrecognized types are returned as-is (the original Hash).

Parameters:

  • item (Hash) —

    a content item with a 'type' field

Returns:



576
577
578
579
580
581
582
583
# File 'lib/mcp_client.rb', line 576

def self.parse_content_item(item)
  case item['type']
  when 'resource_link'
    ResourceLink.from_json(item)
  else
    item
  end
end

.parse_tool_content(content) ⇒ Array<MCPClient::ResourceLink, Hash>

Parse the content array from a tool result into typed objects Each item with type 'resource_link' is converted to an MCPClient::ResourceLink. Other items are returned as-is.

Parameters:

  • content (Array<Hash>) —

    content array from a tool result

Returns:



590
591
592
# File 'lib/mcp_client.rb', line 590

def self.parse_tool_content(content)
  Array(content).map { |item| parse_content_item(item) }
end

.sse_config(base_url:, headers: {}, read_timeout: 30, ping: 10, retries: 0, retry_backoff: 1, name: nil, logger: nil) ⇒ Hash

Deprecated.

The HTTP+SSE transport has been deprecated since MCP 2025-03-26 and is listed in the 2026-07-28 deprecated features registry (SEP-2596); earliest removal is three months after SEP-2596 reaches Final. Use streamable_http_config and ServerStreamableHTTP.

Create a standard server configuration for SSE

Parameters:

  • base_url (String) —

    base URL for the server

  • headers (Hash) (defaults to: {}) —

    HTTP headers to include in requests

  • read_timeout (Integer) (defaults to: 30) —

    read timeout in seconds (default: 30)

  • ping (Integer) (defaults to: 10) —

    time in seconds after which to send ping if no activity (default: 10)

  • retries (Integer) (defaults to: 0) —

    number of retry attempts (default: 0)

  • retry_backoff (Integer) (defaults to: 1) —

    backoff delay in seconds (default: 1)

  • name (String, nil) (defaults to: nil) —

    optional name for this server

  • logger (Logger, nil) (defaults to: nil) —

    optional logger for server operations

Returns:

  • (Hash) —

    server configuration



484
485
486
487
488
489
490
491
492
493
494
495
496
497
# File 'lib/mcp_client.rb', line 484

def self.sse_config(base_url:, headers: {}, read_timeout: 30, ping: 10, retries: 0, retry_backoff: 1,
                    name: nil, logger: nil)
  {
    type: 'sse',
    base_url: base_url,
    headers: headers,
    read_timeout: read_timeout,
    ping: ping,
    retries: retries,
    retry_backoff: retry_backoff,
    name: name,
    logger: logger
  }
end

.stdio_config(command:, name: nil, logger: nil, env: {}, protocol: :auto, discover_timeout: nil) ⇒ Hash

Create a standard server configuration for stdio

Parameters:

  • command (String, Array<String>) —

    command to execute

  • name (String, nil) (defaults to: nil) —

    optional name for this server

  • logger (Logger, nil) (defaults to: nil) —

    optional logger for server operations

  • env (Hash) (defaults to: {}) —

    environment variables for the subprocess

  • protocol (Symbol) (defaults to: :auto) —

    how to establish the server's MCP era: :auto (probe with server/discover, fall back to the initialize handshake), :modern (2026-07-28+ only) or :legacy (initialize handshake only)

  • discover_timeout (Numeric, nil) (defaults to: nil) —

    seconds to wait for the server/discover probe

Returns:

  • (Hash) —

    server configuration



457
458
459
460
461
462
463
464
465
466
467
# File 'lib/mcp_client.rb', line 457

def self.stdio_config(command:, name: nil, logger: nil, env: {}, protocol: :auto, discover_timeout: nil)
  {
    type: 'stdio',
    command: command,
    name: name,
    logger: logger,
    env: env || {},
    protocol: protocol,
    discover_timeout: discover_timeout
  }
end

.streamable_http_config(base_url:, endpoint: '/rpc', headers: {}, read_timeout: 30, retries: 3, retry_backoff: 1, name: nil, logger: nil, max_decompressed_body_bytes: MCPClient::ServerStreamableHTTP::JsonRpcTransport::MAX_DECOMPRESSED_BODY_BYTES, protocol: :auto, discover_timeout: nil) {|faraday| ... } ⇒ Hash

Create configuration for Streamable HTTP transport This transport uses HTTP POST requests but expects Server-Sent Event formatted responses

Parameters:

  • base_url (String) —

    Base URL of the MCP server

  • endpoint (String) (defaults to: '/rpc') —

    JSON-RPC endpoint path (default: '/rpc')

  • headers (Hash) (defaults to: {}) —

    Additional headers to include in requests

  • read_timeout (Integer) (defaults to: 30) —

    Read timeout in seconds (default: 30)

  • retries (Integer) (defaults to: 3) —

    Number of retry attempts on transient errors (default: 3)

  • retry_backoff (Integer) (defaults to: 1) —

    Backoff delay in seconds (default: 1)

  • name (String, nil) (defaults to: nil) —

    Optional name for this server

  • logger (Logger, nil) (defaults to: nil) —

    Optional logger for server operations

  • max_decompressed_body_bytes (Integer) (defaults to: MCPClient::ServerStreamableHTTP::JsonRpcTransport::MAX_DECOMPRESSED_BODY_BYTES) —

    ceiling on how far a gzip-encoded response may expand before it is rejected, guarding against a small highly compressed body exhausting memory (default: 64 MiB)

  • protocol (Symbol) (defaults to: :auto) —

    :auto (default), :modern or :legacy — which protocol era to speak

  • discover_timeout (Numeric, nil) (defaults to: nil) —

    bound on the server/discover probe in seconds

Yield Parameters:

  • faraday (Faraday::Connection) —

    the configured connection instance for additional customization (e.g., SSL settings, custom middleware). The block is called after default configuration is applied.

Returns:

  • (Hash) —

    server configuration



549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
# File 'lib/mcp_client.rb', line 549

def self.streamable_http_config(base_url:, endpoint: '/rpc', headers: {}, read_timeout: 30, retries: 3,
                                retry_backoff: 1, name: nil, logger: nil,
                                max_decompressed_body_bytes:
                                  MCPClient::ServerStreamableHTTP::JsonRpcTransport::MAX_DECOMPRESSED_BODY_BYTES,
                                protocol: :auto, discover_timeout: nil, &faraday_config)
  {
    type: 'streamable_http',
    base_url: base_url,
    endpoint: endpoint,
    headers: headers,
    read_timeout: read_timeout,
    retries: retries,
    retry_backoff: retry_backoff,
    name: name,
    logger: logger,
    max_decompressed_body_bytes: max_decompressed_body_bytes,
    protocol: protocol,
    discover_timeout: discover_timeout,
    faraday_config: faraday_config
  }
end