MCP Tool Execution#
The runner service (services/runner/) delivers Agenta gateway tools (Composio/callback) to agent harnesses via the Model Context Protocol (MCP). Two transports are available depending on sandbox type :
- HTTP loopback (
tool-mcp-http.ts) β used on local sandboxes; the runner serves a stateless JSON-RPC endpoint on127.0.0.1. - In-sandbox stdio shim (
tool-mcp-stdio.ts) β used on remote Daytona sandboxes, where127.0.0.1resolves to the sandbox's own loopback and cannot reach the runner host .
Transport selection happens in buildSessionMcpServers() . Both transports advertise tools under the reserved MCP server name agenta-tools (INTERNAL_TOOL_MCP_SERVER_NAME). User-declared MCP servers are blocked from claiming this name via assertNoReservedUserMcpName() β the name is load-bearing because Claude Code permission rules are keyed against it .
Transport Details#
HTTP Loopback (tool-mcp-http.ts)#
startInternalToolMcpServer() mints a randomBytes(32).toString("base64url") bearer token per instance and exposes the InternalToolMcpServer interface (URL + authorizationToken + close()) . The token is advertised to the harness as an Authorization: Bearer <token> header in the MCP server entry .
Authentication is enforced via hasValidAuthorization() using crypto.timingSafeEqual β requests are rejected with 401 before the body is read, preventing untrusted input from reaching the parser . JSON-RPC batch requests that include a client-kind tools/call are rejected upfront with code -32600, because client tools cross a turn boundary and cannot safely participate in concurrent batch execution .
Handled JSON-RPC methods: initialize, tools/list, tools/call .
In-Sandbox Stdio Shim (tool-mcp-stdio.ts)#
A dependency-free NDJSON JSON-RPC shim bundled into the Daytona sandbox via tool-mcp-assets.ts. It implements the same three handlers and calls the runner's relay on execution . The shim reads its environment contract from tool-mcp-env.ts: AGENTA_AGENT_TOOLS_RELAY_DIR and AGENTA_AGENT_TOOLS_PUBLIC_SPECS_FILE .
Argument and Result Storage Caps#
In cold-replay transcripts, tool call arguments are never capped β approval resume instructions tell the model to re-issue calls "with the same arguments," so args must remain complete .
Tool result bodies are capped at 4,000 characters (TOOL_RESULT_RENDER_MAX_CHARS = 4000) with an [... N chars omitted] marker . This prevents large outputs (e.g., discover_tools dumps at 30β60 KB) from evicting earlier conversation history via tail-slicing. The default transcript window (DEFAULT_HISTORY_MAX_CHARS) is 100,000 characters, overridable via AGENTA_AGENT_HISTORY_MAX_CHARS .
The runner-side tool_call_update handler in tracing/otel.ts records args whenever the serialized form genuinely changes (not just once), fixing a bug where early partial deltas could suppress final argument recording .
Claude Code MCP Settings & Permission Gates#
For Claude Code harnesses, the runner generates .claude/settings.json with per-tool MCP permission rules using the naming convention mcp__agenta-tools__<tool_name> . An allow permission writes a rule that bypasses Claude's own interactive gate; ask preserves human-in-the-loop (HITL) by keeping Claude's native approval prompt .
The central enforcement module is services/runner/src/permission-plan.ts, which both the Pi relay gate and the Claude Code gate read from β ensuring they cannot produce conflicting decisions .
Permission values and semantics:
| Value | Behavior |
|---|---|
allow | Executes without human intervention |
ask | Runner pauses; emits pending_interaction; frontend shows Approve/Deny |
deny | Tool rejected immediately |
allow_reads (agent default) | Read ops auto-approve; write ops escalate to ask |
Approval decisions are keyed on stable anchors: tool spec name (relay gate) or recorded tool_call name plus a canonical args hash (Claude gate). Each decision is consumed once β a config change to deny overrides a stale approval .
Key Source Files#
| File | Purpose |
|---|---|
services/runner/src/tools/tool-mcp-http.ts | HTTP loopback MCP server with bearer auth |
services/runner/src/tools/tool-mcp-stdio.ts | In-sandbox stdio shim for Daytona |
services/runner/src/tools/tool-mcp-env.ts | Env contract for the stdio shim |
services/runner/src/tools/mcp-bridge.ts | Builds MCP server entries; advertises bearer token |
services/runner/src/engines/sandbox_agent/mcp.ts | Transport selection, agenta-tools name enforcement, Claude settings |
services/runner/src/engines/sandbox_agent/tool-mcp-assets.ts | Uploads stdio shim to Daytona sandbox |
services/runner/src/engines/sandbox_agent/relay-guard.ts | Relay execution guard for all harnesses |
services/runner/src/permission-plan.ts | Single permission decision module |
services/runner/src/engines/sandbox_agent/transcript.ts | Result caps, transcript tail-slicing |
services/runner/src/tracing/otel.ts | Tool arg recording with change-detection |