AgentWorks documentation
π MCP Bridge Layer & Exposed APIs
The MCP Bridge Layer is a critical architectural component of Runloop. It acts as a universal proxy and translation layer, allowing external local CLI agents such as Claude Code, Codex, and Pi to access the orchestrator's loaded tools, virtual tools, and workspace capabilities.
Architecture Overview
Instead of requiring every agent to manage its own MCP server connections, the orchestrator centralizes tool discovery, session management, and routing. External agents use a lightweight proxy binary called mcpbridge to communicate with the orchestrator's REST API.
- Local CLI Agent (e.g.,
claude-code,gemini) spawnsmcpbridge. - mcpbridge translates the stdio-based MCP protocol into HTTP REST calls.
- Orchestrator processes the HTTP request, executes the tool (routing to Docker, external APIs, or the local Workspace), and returns the result.
π Exposed APIs
The orchestrator exposes several API layers to facilitate this bridge and manage the workspace.
1. Tool Execution & Discovery (Bridge API)
These endpoints are consumed by mcpbridge and the web UI to interact with tools.
POST /api/mcp/execute- The central routing endpoint. Accepts a JSON payload containing the
server_name,tool_name, andarguments. - Automatically routes the request to the correct underlying MCP server, virtual tool, or workspace capability.
- The central routing endpoint. Accepts a JSON payload containing the
GET /api/tools- Returns a flattened, formatted schema of all available tools across all connected MCP servers and virtual tools.
GET /api/mcp-config&POST /api/mcp-config- Retrieves and updates the active MCP server configuration (
mcp_servers.json).
- Retrieves and updates the active MCP server configuration (
POST /api/mcp-config/discover- Forces a manual discovery and reconnection to all configured MCP servers.
2. Workspace API (Port 8080)
The workspace container runs a dedicated Planner API that the orchestrator interfaces with for local file and system management.
- Document Management:
GET /api/documents/POST /api/documentsGET/PUT/DELETE /api/documents/*filepathGET /api/glob(File discovery via glob patterns)
- Search & Semantic Intelligence:
GET /api/search(Lexical grep search)POST /api/search/process-file
- System & Execution:
POST /api/execute(Secure shell command execution within the workspace)POST /api/upload(File uploads)
π Universal Stdio Gateway
The mcpbridge binary isn't just for Claude or Geminiβit serves as a Universal Stdio Gateway.
Any external LLM agent, framework (LangChain, AutoGPT, CrewAI), or custom script that supports the Model Context Protocol (MCP) via stdio can use mcpbridge to access your entire tool ecosystem through a single connection.
Why use the Centralized Bridge?
- Single Connection, 100+ Tools: Connect to one "server" (
mcpbridge) and immediately gain access to every tool configured in your orchestrator (Slack, Workspace, Browser, etc.). - Centralized Auth: Manage API keys and OAuth tokens in one place (the orchestrator) rather than in every individual agent script.
- Session Isolation: Use the
MCP_SESSION_IDenvironment variable to isolate tool execution and folder guards between different external agents. - Monitoring: Every tool call made via the bridge is logged and visible in the orchestrator's central dashboard.
Configuration for External Frameworks
To connect an external agent, simply point it to the mcpbridge binary:
# Example: Launching a custom MCP-compatible agent
my-agent-cli --mcp-command "mcpbridge" --mcp-env "MCP_API_URL=http://localhost:8080/api"
πͺΆ Lean variant: the agentsession pattern (small, fixed tool sets)
Everything above describes the full orchestrator case: a Gin-backed API server with
potentially 100+ tools across arbitrary user-built workflows, where the model
discovers a tool's schema via get_api_spec and then calls it through
execute_shell_command + curl using $MCP_CUSTOM/$MCP_AUTH. That discovery
route exists because the full tool catalog is too large/dynamic to hand the
model natively every session.
Small, standalone apps with a fixed, known-in-advance tool set (e.g.
agent_go/internal/agentsession β used by family-server) use a leaner
variant of the same bridge, not the curl-discovery route:
- No Gin server, no HTTP handlers in the app itself. Tools are plain Go
functions:
agentsession.Tool{Name, Description, Params, Handler}, passed directly intoagentsession.New(ctx, agentsession.Config{Tools: [...]}). agentsession.Newcallsagent.RegisterCustomTool(...), which publishes each handler into a session-scoped in-process registry, and starts (once per process, viaensureSharedBridge) a small in-process HTTP "executor" server (agentsession.startExecutorServer) exposing/tools/custom/{name}.mcpagent's ownbridgeToolsvar (mcpagent/agent/coding_agents_bridge.go) is a small, fixed, package-level list β exactly 4 entries (execute_shell_command,diff_patch_workspace_file,agent_browser,get_api_spec) β pinned byTestBridgeToolsList. It is shared across every consumer of the mcpagent module (including AgentWorks itself) β never add your own app's tool names to it. An earlier version of family-server did exactly that (addedset_child_profile,celebrate,suggest_handoff, etc. directly tobridgeTools), which broke the guardrail test and leaked family-server-specific tool names into every other consumer's sessions. Reverted. The correct, scoped mechanism ismcpagent.WithAdditionalBridgeTools(names ...string)β anAgentOptionthat exposes the named tools natively for that one agent instance only (stored inAgent.additionalBridgeTools, unioned withbridgeToolsinsideBuildBridgeMCPConfig, never touching the shared var).agentsession.Newcalls this automatically for every tool inConfig.Toolsβ callers never need to touch mcpagent's own files at all.mcpagent.BuildBridgeMCPConfig()combinesbridgeTools+Agent.additionalBridgeTools, resolves each name to its real schema, serializes the result into theMCP_TOOLSenv var, and launchesmcpbridgewith that set for the session.mcpbridgeitself has zero hardcoded tool names β it reads its entire tool list fromMCP_TOOLSat startup (seecmd/mcpbridge/main.go). For a"custom"type entry, a tool call becomesPOST {MCP_API_URL}/tools/custom/{name}with anX-Session-IDheader β landing back on the same app process that registered the handler in step 2, not a separate orchestrator.
Net effect: two hops (Claude Code β mcpbridge stdio β app's own executor
HTTP β Go handler), both fast/local, and the model calls the tool directly by
name β no schema discovery, no curl construction. This is more reliable for a
small tool set and is the intended pattern for apps like family-server, not a
workaround.
The one thing to remember: a new custom tool registered via
agentsession.Config.Tools is exposed automatically β no manual step needed,
and nothing to edit in the shared mcpagent module. If you're calling
mcpagent.NewAgent directly (not through agentsession), you must pass
mcpagent.WithAdditionalBridgeTools(yourToolNames...) yourself, or the tool
is registered (handler exists) but genuinely invisible to the model β a real,
easy-to-hit gap, not a permissions issue. Either way, never add app-specific
names to the shared bridgeTools var itself.