Class: McpToolkit::Dispatcher

Inherits:
Object
  • Object
show all
Defined in:
lib/mcp_toolkit/dispatcher.rb

Overview

Hand-rolled JSON-RPC dispatcher for the AUTHORITY + gateway path: it handles a single JSON-RPC request (one element of a batch), serving the host's own tools and, as a gateway, aggregating + proxying upstream MCP servers — WITHOUT the official mcp SDK in the request path.

The gem carries two dispatch front-ends by design (see McpToolkit::Protocol): this Dispatcher for the authority/gateway endpoint, and McpToolkit::Server.build (the SDK wrapper) for satellites. They are independent; nothing here touches the satellite path.

Everything host-specific is injected:

* `context`  — an McpToolkit::Authority::Context (the resolved account, the
             authenticated principal, and the bearer token to forward
             upstream). Re-created PER JSON-RPC request by the transport, so
             each batch element carries its own account.
* `config`   — server identity (`server_name`/`server_version`), the
             negotiable protocol versions, the registered `upstreams`, and
             the `tool_provider` (the host's api-agnostic tool catalog).

The wire behavior — top-level JSON-RPC tool-error codes, initialize capabilities { tools: { listChanged: true } }, 3-version negotiation, verbatim upstream error relay, and the custom notifications/<app>/tools/list_changed cache-bust — is the byte contract of a first-party endpoint and is preserved exactly.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(context:, config: McpToolkit.config) ⇒ Dispatcher

Returns a new instance of Dispatcher.



30
31
32
33
# File 'lib/mcp_toolkit/dispatcher.rb', line 30

def initialize(context:, config: McpToolkit.config)
  @context = context
  @config = config
end

Instance Attribute Details

#configObject (readonly)

Returns the value of attribute config.



28
29
30
# File 'lib/mcp_toolkit/dispatcher.rb', line 28

def config
  @config
end

#contextObject (readonly)

Returns the value of attribute context.



28
29
30
# File 'lib/mcp_toolkit/dispatcher.rb', line 28

def context
  @context
end

Instance Method Details

#handle_request(request) ⇒ Object



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/mcp_toolkit/dispatcher.rb', line 35

def handle_request(request)
  dispatch_request(request)
rescue McpToolkit::Protocol::Error => e
  return nil unless request.key?("id")

  McpToolkit::Protocol.error_response(id: request["id"], error: e)
rescue StandardError => e
  config.logger&.error("MCP dispatcher error: #{e.message}\n#{e.backtrace&.join("\n")}")
  return nil unless request.key?("id")

  McpToolkit::Protocol.error_response(
    id: request["id"],
    error: McpToolkit::Protocol::InternalError.new(e.message)
  )
end