Context
AshAi.Mcp.Server.process_request/3 (deps/ash_ai/lib/ash_ai/mcp/server.ex:363-388 in 0.6.x) hard-codes AshAi.Tools.execute/3 as the dispatcher for tools/call. Downstream projects that want to route MCP tools/call through a project-specific authorization layer (capability gate, audit logging, etc.) must hand-roll the JSON-RPC envelope handling because wrapping AshAi.Mcp.Router bypasses their authorization.
Request
Accept a :tool_dispatcher opt on AshAi.Mcp.Router / AshAi.Mcp.Server.handle_post/4 that defaults to &AshAi.Tools.execute/3 and that callers can override with their own (tool, args, context) -> {:ok, json, raw} | {:error, term} function. Concretely: route the tools/call clause through the configured dispatcher instead of calling AshAi.Tools.execute/3 directly.
Why
Our project (qorpay) ships an embedded MCP server and routes tools/call through Qorpay.Agents.ToolResolver.execute/3 for capability-gate enforcement. We had to hand-roll the JSON-RPC dispatch because wrapping AshAi.Mcp.Router would skip our capability check. A :tool_dispatcher opt would let us drop ~210 LOC of hand-rolled router/server code and adopt the upstream library.
Scope
Backwards-compatible: default behavior unchanged. Tests: one new test asserting the dispatcher opt is called with (tool, args, context).
Context
AshAi.Mcp.Server.process_request/3(deps/ash_ai/lib/ash_ai/mcp/server.ex:363-388 in 0.6.x) hard-codesAshAi.Tools.execute/3as the dispatcher fortools/call. Downstream projects that want to route MCPtools/callthrough a project-specific authorization layer (capability gate, audit logging, etc.) must hand-roll the JSON-RPC envelope handling because wrappingAshAi.Mcp.Routerbypasses their authorization.Request
Accept a
:tool_dispatcheropt onAshAi.Mcp.Router/AshAi.Mcp.Server.handle_post/4that defaults to&AshAi.Tools.execute/3and that callers can override with their own(tool, args, context) -> {:ok, json, raw} | {:error, term}function. Concretely: route thetools/callclause through the configured dispatcher instead of callingAshAi.Tools.execute/3directly.Why
Our project (qorpay) ships an embedded MCP server and routes
tools/callthroughQorpay.Agents.ToolResolver.execute/3for capability-gate enforcement. We had to hand-roll the JSON-RPC dispatch because wrappingAshAi.Mcp.Routerwould skip our capability check. A:tool_dispatcheropt would let us drop ~210 LOC of hand-rolled router/server code and adopt the upstream library.Scope
Backwards-compatible: default behavior unchanged. Tests: one new test asserting the dispatcher opt is called with
(tool, args, context).