Single MCP method table for handler modules invoked with their own state.
ExMCP.Server.HandlerServer (test/BEAM transports) and
ExMCP.Server.StdioServer both drive an ExMCP.Server.Handler module by
calling its callbacks with the handler state and turning the return value
into a JSON-RPC response. They used to carry two independently maintained
copies of that table, which drifted: stdio never implemented
completion/complete, resources/subscribe, roots/list,
logging/setLevel or the task methods, and the two copies normalized tool
results differently.
This module owns the table. Transports keep their own framing (stdout lines
vs. transport send_message/2), batching, and cancellation bookkeeping, and
delegate callback invocation plus result shaping here. Shaping itself lives
in ExMCP.Server.ResultNormalizer, which the HTTP message processor also
shares, so every transport agrees
on tool-result shape and on which error detail is safe to return.
Return value
{:response, response_map, new_handler_state}for requests{:notification, new_handler_state}for notifications (no response)
Callbacks that ExMCP.Server.Handler marks optional are probed with
function_exported?/3; a handler that does not implement one answers
-32601 Method not found.
Summary
Functions
Dispatches a decoded JSON-RPC request or notification to handler_module.
Whether method is part of the shared MCP method table.
Returns the list of MCP methods handled by this dispatcher.
Builds the argument map handed to ExMCP.Server.Handler.handle_call_tool/3.
Types
@type handler_state() :: term()
@type result() :: {:response, map(), handler_state()} | {:notification, handler_state()}
Functions
@spec dispatch(map(), module(), handler_state()) :: result()
Dispatches a decoded JSON-RPC request or notification to handler_module.
Whether method is part of the shared MCP method table.
@spec methods() :: [String.t()]
Returns the list of MCP methods handled by this dispatcher.
Builds the argument map handed to ExMCP.Server.Handler.handle_call_tool/3.
Request-level _meta (which carries progressToken) lives beside
arguments in the JSON-RPC params, but ExMCP.Server.Handler documents it
as reachable from the arguments map, so it is merged in here. Arguments that
already carry their own _meta win.