--- status: draft last_updated: 2026-04-16 --- # MCP Server: Discovery + Call Interface ## Overview The hub exposes an MCP endpoint using `@hono/mcp`'s `StreamableHTTPTransport`. Instead of exposing many operations as individual MCP tools (which bloats the LLM's context with tool definitions it mostly doesn't need), the MCP server exposes four tools for **discovery and execution**. Agents list or search for what they need, get the schema, then call it. Everything else goes through the operation registry via the call protocol. This pattern is proven: the toolEnv POC ran it as HTTP endpoints (`/list`, `/search`, `/schema/:tool`, `/call`). We wrap the same four operations as MCP tools instead. `@hono/mcp` is the Hono MCP middleware (npm: `@hono/mcp`). Source for reference: @hono/mcp (npm package). ## Why Discovery + Call, Not Direct Exposure | Direct Exposure (many MCP tools) | Discovery + Call (4 MCP tools) | | ---------------------------------------------- | --------------------------------------------------- | | Every operation becomes an MCP tool definition | Agent lists or searches for what it needs, gets schema on demand | | N operations = N tool defs in context | 4 tool defs in context always | | LLM sees worktree/git tools irrelevant to task | LLM only loads schemas for operations it will use | | Adding operations = restart MCP, re-discover | Adding operations = automatic, search finds them | | No namespace awareness | `list` and `search` support namespace filtering | The core problem with direct exposure: MCP tool definitions sit in the LLM's context for the entire conversation. An implementation specialist working on a React component doesn't need `git.worktreeCreate` and `coord.spawn` cluttering its thinking. With discovery + call, it searches `coord`, gets the schemas for `coord.message`, and calls it. Four tool definitions, not thirty. ## How It Works ### Hub MCP Endpoint The hub MCP endpoint creates an `McpServer` from `@modelcontextprotocol/sdk`, connects it to a `StreamableHTTPTransport` from `@hono/mcp`, and mounts it at `/mcp`. Four tools are registered: | Tool | Input | Output | Description | |------|-------|--------|-------------| | list | { namespace?: string } | OperationSpec[] | List available operations, optionally filtered by namespace | | search | { q?: string, namespace?: string } | { tool, description }[] | Search operations by name, description, or namespace | | schema | { tool: string } | { inputSchema, outputSchema } | Get schemas for a specific operation | | call | { calls: [{ tool, input? }] } | { success, result/error }[] | Execute operations via call protocol | `list` returns all available operations (or those in a given namespace) — useful when the agent needs to browse what's available. `search` filters the operation registry by query string and/or namespace — useful when the agent knows roughly what it needs. `schema` returns the TypeBox input/output schemas for a given operation. `call` accepts an array of operation calls and returns results. `call` routes through `callMap.call()` (the call protocol), not `registry.execute()` directly. This gives full call graph tracking, abort cascading, and structured error handling. ### Agent Workflow Example ``` Agent: "I need to spawn a worktree for the auth feature" → search({ q: "spawn" }) → [{ tool: "coord.spawn", description: "..." }] → schema({ tool: "coord.spawn" }) → { inputSchema: { sessionId, task, branch, ... }, ... } → call({ calls: [{ tool: "coord.spawn", input: { sessionId: "...", task: "implement auth", branch: "feat/auth" } }] }) Agent: "Let me check on the spawned sessions" → search({ namespace: "coord" }) → [{ tool: "coord.status", ... }, { tool: "coord.message", ... }, ...] → schema({ tool: "coord.status" }) → { inputSchema: { parentSessionId }, ... } → call({ calls: [{ tool: "coord.status", input: { parentSessionId: "..." } }] }) ``` Only the tool definitions the agent actually needs enter context, and only when it needs them. ## Auth The MCP endpoint uses bearer token auth. Each runner gets a token at registration. The hub validates the token and attaches the runner's identity to the operation context for access control. ## What This Replaces | Previous | Now | | ------------------------------------------ | ---------------------------------------- | | `mcp-visible` tag, many MCP tool defs | 4 MCP tools, operations discovered dynamically | | Per-container MCP servers (websearch, etc.) | Shared hub registry, `call` dispatches to any operation | | Manual tool exposure per operation | Automatic — all registered operations are searchable |