MCP Gateway — Expose Agents as MCP Tools
The initrunner mcp serve command exposes one or more InitRunner agents as an MCP (Model Context Protocol) server. This lets Claude Desktop, Claude Code, Cursor, and any other MCP client call your agents directly as tools.
InitRunner already supports MCP as a client (consuming external MCP servers as agent tools). The gateway adds the reverse direction — your agents become the server.
Quick Start
# Expose a single agent over stdio (for Claude Desktop / Claude Code)
initrunner mcp serve examples/roles/hello-world.yaml
# Expose multiple agents
initrunner mcp serve roles/researcher.yaml roles/writer.yaml roles/reviewer.yaml
# Use SSE transport for network clients
initrunner mcp serve roles/agent.yaml --transport sse --host 0.0.0.0 --port 8080Each role becomes an MCP tool. The tool name is derived from metadata.name in the role YAML. When names collide, suffixes (_2, _3, ...) are appended automatically.
CLI Options
Synopsis: initrunner mcp serve ROLE_FILES... [OPTIONS]
| Option | Type | Default | Description |
|---|---|---|---|
ROLE_FILES | Path... | (required) | One or more role YAML files to expose as MCP tools. |
--transport, -t | str | stdio | Transport protocol: stdio, sse, or streamable-http. |
--host | str | 127.0.0.1 | Host to bind to (sse/streamable-http only). |
--port | int | 8080 | Port to listen on (sse/streamable-http only). |
--server-name | str | initrunner | MCP server name reported to clients. |
--pass-through | bool | false | Also expose the agents' own MCP tools directly (see Pass-Through Mode). |
--audit-db | Path | ~/.initrunner/audit.db | Path to audit database. |
--no-audit | bool | false | Disable audit logging. |
--skill-dir | Path | None | Extra skill search directory. |
Transports
stdio (default)
The standard transport for local MCP integrations. The MCP client launches initrunner mcp serve as a subprocess and communicates over stdin/stdout.
All status output (agent listing, errors) is printed to stderr to keep stdout clean for the MCP protocol.
initrunner mcp serve roles/agent.yamlSSE (Server-Sent Events)
For network-accessible servers. The MCP client connects via HTTP.
initrunner mcp serve roles/agent.yaml --transport sse --host 0.0.0.0 --port 8080Streamable HTTP
Modern HTTP-based transport with bidirectional streaming.
initrunner mcp serve roles/agent.yaml --transport streamable-http --port 9090How It Works
- At startup, the gateway loads and builds all specified roles (using
load_and_build). - Each agent is registered as an MCP tool with the name from
metadata.name. - When an MCP client calls a tool, the gateway runs the agent with the provided
promptstring and returns the output. - Agent execution errors are returned as error strings — they never crash the MCP server.
- Audit logging works the same as in other execution modes.
Tool Naming
Tool names are derived from the role's metadata.name field. Characters that are not alphanumeric, hyphens, or underscores are replaced with _. When multiple roles share the same name, suffixes are appended:
| Role Name | Tool Name |
|---|---|
researcher | researcher |
writer | writer |
writer (duplicate) | writer_2 |
my agent! | my_agent_ |
Tool Schema
Each registered tool accepts a single parameter:
| Parameter | Type | Description |
|---|---|---|
prompt | string | The prompt to send to the agent. |
The tool description is taken from metadata.description in the role YAML.
Client Configuration
Claude Desktop
Add to your claude_desktop_config.json:
{
"mcpServers": {
"initrunner": {
"command": "initrunner",
"args": ["mcp", "serve", "/path/to/roles/agent.yaml"]
}
}
}For multiple agents:
{
"mcpServers": {
"initrunner": {
"command": "initrunner",
"args": [
"mcp", "serve",
"/path/to/roles/researcher.yaml",
"/path/to/roles/writer.yaml"
]
}
}
}Claude Code
Add to your .mcp.json:
{
"mcpServers": {
"initrunner": {
"command": "initrunner",
"args": ["mcp", "serve", "roles/agent.yaml"]
}
}
}Cursor
Add to your Cursor MCP settings:
{
"mcpServers": {
"initrunner": {
"command": "initrunner",
"args": ["mcp", "serve", "roles/agent.yaml"]
}
}
}Network Clients (SSE / Streamable HTTP)
Start the server:
initrunner mcp serve roles/agent.yaml --transport sse --host 0.0.0.0 --port 8080Then configure your MCP client to connect to http://<host>:8080.
Pass-Through Mode
With --pass-through, the gateway also exposes MCP tools that the agents themselves consume. This is useful when you want a single MCP server to expose both the agents and their underlying tools.
initrunner mcp serve roles/agent.yaml --pass-throughHow It Works
- Only
type: mcptools from the role are passed through. Other tool types (shell, filesystem, etc.) are skipped because they require PydanticAIRunContext, which doesn't exist outside an agent run. - If no roles have MCP tools configured,
--pass-throughis a no-op. - Pass-through tools are prefixed with
{agent_name}_to avoid collisions across agents. If the MCP tool config also has atool_prefix, both prefixes are combined. - The role's
tool_filter,tool_exclude, andtool_prefixsettings are honored.
Security
Pass-through mode applies the same sandbox checks as agent execution:
- MCP commands are validated against
security.tools.mcp_command_allowlist. - Environment variables are scrubbed using
sensitive_env_prefixes,sensitive_env_suffixes, andenv_allowlistfrom the role's security policy. - Working directories are resolved relative to the role file's directory.
Multiple Agents Example
Create a multi-tool MCP server from several specialized agents:
# roles/researcher.yaml — searches the web and summarizes findings
# roles/writer.yaml — writes polished prose from notes
# roles/reviewer.yaml — reviews text for clarity and correctness
initrunner mcp serve roles/researcher.yaml roles/writer.yaml roles/reviewer.yamlAn MCP client (e.g., Claude Desktop) can then orchestrate all three agents as tools within a single conversation.
Error Handling
- Startup errors: If any role file fails to load, the gateway exits immediately with a clear error message identifying the problematic file.
- Runtime errors: Agent execution failures are returned as error strings (
"Error: ...") to the MCP client. Unexpected exceptions are caught and returned as"Internal error: ...". The MCP server never crashes due to an agent error. - Invalid transport: Rejected at startup with a descriptive error listing the valid options.
Audit Logging
Agent runs through the gateway are audit-logged the same way as any other execution mode. Use --audit-db to set a custom database path, or --no-audit to disable logging.
# Query audit logs for gateway runs
initrunner audit query --agent-name researcherProgrammatic API
The gateway can also be used programmatically:
from pathlib import Path
from initrunner.mcp.gateway import build_mcp_gateway, run_mcp_gateway
mcp = build_mcp_gateway(
[Path("roles/agent.yaml")],
server_name="my-server",
)
run_mcp_gateway(mcp, transport="stdio")Or via the services layer:
from pathlib import Path
from initrunner.services.operations import build_mcp_gateway_sync
mcp = build_mcp_gateway_sync([Path("roles/agent.yaml")])See the CLI Reference for the full list of mcp serve flags.
Deferred Tool Loading
Since v2026.4.6, MCP tool configs support defer: true to delay server connections until the first tool call. This speeds up agent startup when MCP servers are slow to connect or rarely used.
tools:
- type: mcp
server_name: heavy-server
command: npx
args: ["-y", "@some/mcp-server"]
defer: trueWhen defer: true is set:
- Cache hit — If a cached schema exists at
~/.initrunner/cache/mcp/, the agent starts immediately using the cached tool definitions. The real server connection is deferred until a tool from that server is actually called. - Cache miss — The server is connected eagerly (same as
defer: false), and the schema is cached for next time. - Connected — Once connected, all tool calls go directly to the live server. If the live schema differs from the cache, a warning is logged about schema drift.
Cache files use atomic writes to prevent corruption. The dashboard shows a "deferred" badge on MCP servers using this mode and displays the cache age.
FastMCP 3.x
Since v2026.4.5, InitRunner requires fastmcp>=3.2.0. The gateway internals were migrated to the new FastMCP 3.x API:
| Old (2.x) | New (3.x) |
|---|---|
FastMCP.as_proxy(transport) | create_proxy(transport) |
proxy.filtered(lambda ...) | proxy.add_transform(Visibility(...)) |
proxy.prefixed(name) | mcp.mount(proxy, namespace=namespace) |
This migration fixes CVE-2025-64340, CVE-2026-27124, and CVE-2026-32871.
No changes are required to YAML configuration or CLI commands. If you use the programmatic API directly with FastMCP objects, update your code to use create_proxy and Visibility transforms:
from fastmcp.server import create_proxy
from fastmcp.server.transforms import Visibility
proxy = create_proxy(transport)
proxy.add_transform(Visibility(False, names={"internal_tool"}))
mcp.mount(proxy, namespace="my-agent")The build_mcp_gateway and run_mcp_gateway wrapper functions are unchanged.
MCP Hub Dashboard
The built-in dashboard includes an MCP Hub page at /mcp for managing MCP servers across all your agents. The sidebar shows a red status dot when any server is unhealthy (polled every 30 seconds).
Servers Tab
Aggregated view of every MCP server declared in any agent's tools: config. Servers are deduplicated by connection identity (transport, command, args, url, cwd, headers, env keys).
Each server card shows the display name, transport badge (stdio/sse/streamable-http), health indicator (green/amber/red/gray), and chips linking to consuming agents. Click a card to lazy-load the full tool list via introspection. Each tool shows its name, description, and a "Test" button that jumps to the Playground with that server and tool pre-selected.
Health status values: healthy (response < 3s), degraded (3-5s), unhealthy (timeout or error).
Discover Tab
Curated registry of popular MCP servers with categories (filesystem, database, web, developer, productivity, communication). Each card includes a description, transport indicator, and an "Add to Agent" button that copies a ready-to-paste tools: YAML snippet to the clipboard.
Playground Tab
Execute MCP tools in isolation without running an LLM agent. Select a server and tool from cascading pickers, fill in the auto-generated form (built from the tool's inputSchema JSON Schema), and view the syntax-highlighted JSON response with timing and success indicators.
Recent calls are stored in localStorage (max 50, FIFO) and can be replayed with the same arguments. Sandbox rules from the originating role are enforced.
Canvas Tab
@xyflow/svelte topology visualization showing MCP server-to-agent relationships. Servers appear on the left, agents on the right, connected by animated edges. Click agent nodes to navigate to the agent detail page. "Export YAML" copies all server configs as a tools: section to the clipboard.
Browser MCP Auto-Retry
When browser-based MCP servers (initrunner-browser-mcp, Playwright, Puppeteer) fail to launch Chrome due to sandbox restrictions, InitRunner automatically retries with --no-sandbox. A warning is logged on fallback. No configuration is needed.
This is relevant for Docker containers, VMs, and Ubuntu 23.10+ where AppArmor or unprivileged user namespace restrictions can block the Chrome sandbox.