ExMCP.Server.HandlerServer (ex_mcp v1.0.0-rc.8)

Copy Markdown View Source

Transport-aware process for ExMCP.Server.Handler modules.

This module runs a handler module behind the MCP transports that need a server process, including the in-memory test transport.

Usage

# Handler module implementing ExMCP.Server.Handler
defmodule MyHandler do
  use ExMCP.Server.Handler

  @impl true
  def handle_initialize(params, state) do
    {:ok, %{
      protocolVersion: "2025-03-26",
      serverInfo: %{name: "test-server", version: "1.0.0"},
      capabilities: %{tools: %{}}
    }, state}
  end

  @impl true
  def handle_list_tools(_cursor, state) do
    tools = [
      %{
        name: "ping",
        description: "Simple ping tool",
        inputSchema: %{type: "object", properties: %{}}
      }
    ]
    {:ok, tools, nil, state}
  end
end

# Start the server
{:ok, server} = ExMCP.Server.HandlerServer.start_link(transport: :test, handler: MyHandler)

Summary

Functions

Returns a specification to start this module under a supervisor.

Starts a handler-based server.

Types

handler_module()

@type handler_module() :: module()

state()

@type state() :: %{
  handler_module: handler_module(),
  handler_state: any(),
  transport: any(),
  transport_state: any(),
  protocol_version: String.t() | nil,
  validation_state: %{
    seen_request_ids: MapSet.t(String.t() | integer()),
    max_request_ids: pos_integer(),
    protocol_version: String.t() | nil
  },
  protocol_mode: ExMCP.Types.protocol_mode() | nil,
  connection_era: :legacy | :modern | nil,
  instructions: String.t() | nil,
  request_state: keyword() | nil,
  endpoint: String.t() | nil,
  principal_id: String.t() | nil,
  tenant_id: String.t() | nil,
  replay_cache: module() | {module(), keyword()} | nil,
  require_replay_protection: boolean(),
  pending_requests: map(),
  cancelled_requests: MapSet.t(),
  cancellation_tracker: module(),
  subscriptions: map(),
  subscription_options: keyword()
}

Functions

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

start_link(opts)

@spec start_link(keyword()) :: GenServer.on_start()

Starts a handler-based server.

Options

  • :handler - Module implementing ExMCP.Server.Handler behaviour (required)
  • :transport - Transport type (:test, :stdio, :http, etc.)
  • :handler_args - Optional term passed to handler.init/1 (default: [])
  • :cancellation_tracker - Module implementing ExMCP.Server.CancellationTracker used to propagate notifications/cancelled into handler state (default: ExMCP.Server.CancellationTracker.Default)
  • :max_request_ids - Maximum number of distinct client request IDs retained for this server process (default: 10_000). Once reached, new request IDs fail closed while already-seen IDs continue to be rejected as duplicates.
  • Other options are passed to the transport