ash-project / ash-project/ash_ai
Pluggable tool dispatcher for AshAi.Mcp.Server.process_request
- Dominant language
- Elixir
- Stars
- 189
- Forks
- 89
- Avg merge
- 8h 32m
- Merged PRs (30d)
- 3
Description
## 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)`.
Contributor guide
Research direction
Read deps/ash_ai/lib/ash_ai/mcp/server.ex:363-388 and the AshAi.Mcp.Router / AshAi.Mcp.Server.handle_post/4 entry points to trace how tools/call is dispatched. Add coverage for a :tool_dispatcher override receiving (tool, args, context), while confirming the default remains AshAi.Tools.execute/3 and existing behavior is unchanged.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- elixir
- Domain
- api, backend
- Issue type
- Feature
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 68/100