- Status: Accepted
- Date: 2026-06-19
- Refs:
KAIBAN-v2.0-MASTER-PLAN.md§B5.1 Phase M + §B1.2 (federation invariants); §B8 BETA.2
v2.0 adds a first-party MCP server so MCP-speaking hosts (IDEs, agents, the Model Context Protocol
ecosystem) can discover and use a curated slice of the distributed runtime. The repo already ships an
MCP client (MCPFederationClient) so agent workers can consume external tools; what was missing
is the inbound direction — exposing our capabilities as MCP primitives.
The federation posture is fixed by §B1.2: A2A is the public, agent-to-agent front door; MCP is the internal tool/context surface. The MCP server must therefore be least-privilege, env-gated off by default, and must not become an unauthenticated side-door around the gateway's security chain.
src/infrastructure/federation/mcp-server.ts—buildMcpServer(deps)builds an@modelcontextprotocol/sdkMcpServerexposing an allow-listed set of the four primitives:- Tools —
dispatch_task(the one side-effecting action: hand an instruction to an agent). - Resources —
kaiban://agents(agent list) and thekaiban://agents/{agentId}/statusURI template (read-only grounding context). - Prompts —
delegate_task(a reusable templated delegation flow). - Elicitation — a protocol-level HITL consent gate in front of
dispatch_task. Capabilities come in as injected dependencies (dispatchTask,listAgents,getAgentStatus), so the server never reaches into the messaging layer directly and unit-tests against an in-memory transport with zero brokers.
- Tools —
- Least-privilege: an optional
allowlist (per kind) restricts what is registered; nothing registered ⇒ that capability is not advertised at all (the SDK answers list calls with-32601). - Fail-closed consent:
dispatch_taskasks the client to authorize via elicitation before any token-spending work starts. A client that does not support elicitation is refused (no silent dispatch).requireDispatchConsent: falseis available for trusted non-interactive deployments. src/infrastructure/federation/mcp-http.ts—createMcpHttpHandler(deps)bridges the gateway's Express surface to the SDKStreamableHTTPServerTransportin stateful mode (one transport + server permcp-session-id) so server→client requests (elicitation) round-trip within a session.enableJsonResponsekeeps it a plain-JSON RPC surface (no lingering SSE). Session lifecycle uses the transport'sonsessioninitialized/onsessionclosedcallbacks (each handed a guaranteed id).- Wired into the gateway (
GatewayAppPOST/GET/DELETE atMCP_SERVER_PATH) behind the same security chain as A2A — helmet → per-IP rate-limit → env-gated JWT (A2A_JWT_SECRET) → request timeout. Env-gated OFF by default (MCP_SERVER_ENABLED). Dispatch reuses the A2AvalidateTaskInputcaps +taskIddedup, so the MCP path and the A2A path enforce the same input contract and idempotency invariant. - New direct dependency:
zod ^4.4.3— required by the MCP SDK's tool/prompt input schemas (it was already present transitively via the SDK). Additive; no consumer-facing change.
- A2A in front, MCP internally (§B1.2): A2A remains the agent-to-agent wire; the MCP server is an internal surface and the MCP client is the worker-side consumer. The MCP server never bypasses the gateway auth/rate-limit chain.
taskIdidempotency / input caps: MCPdispatch_taskpublishes through the samevalidateTaskInput(A2A_INPUT_CAPS) and per-taskIddedup as A2A.- Security opt-in / default-off / fail-closed: the whole surface is off unless
MCP_SERVER_ENABLED, and the consent gate fails closed.
- MCP Roots and OAuth 2.1 / PKCE — the gateway JWT (
A2A_JWT_SECRET) is v2.0 auth; OAuth is a later beta. resource_linkoverflow for large tool outputs — current tool outputs are small structured JSON (taskId/status); when tools later return large payloads they should emitresource_links.- Sampling / server→client
createMessage— not exposed yet.
- Hosts can drive the runtime over MCP, but only the curated, allow-listed, consent-gated slice.
- The server is fully unit-tested (real SDK
Clientover an in-memory transport + a realStreamableHTTPClientTransportround-trip over loopback) at 100% coverage with no brokers. - One more env knob (
MCP_SERVER_ENABLED+ path/consent/allow-list) and one new direct dep (zod).