Build a Claude Managed Agent: Sandbox and MCP Tunnel Setup
A hands-on walkthrough to stand up a self-hosted sandbox, run an MCP server, open an MCP tunnel, and drive a Claude managed agent.
Reading about managed-agent architecture is one thing; getting a Claude agent to actually run a command inside a container you control is another. This walkthrough is the hands-on version. We will build a small but real setup: an ephemeral sandbox container, an MCP server inside it that exposes two scoped tools, an outbound tunnel to the control plane, and a system prompt that tells the agent how to behave. By the end you will have a working loop you can extend, plus the exact failure modes to watch for the first time you run it.
Key takeaways
- You can stand up a working managed-agent sandbox with a container, one MCP server, and an outbound tunnel — no public ports.
- Tools should be defined with tight JSON schemas so the agent knows exactly what arguments are valid before it calls.
- The MCP server runs inside the sandbox next to your credentials; the agent reaches it only through the tunnel.
- Start with read-only tools, confirm the trace looks right, then add write tools behind explicit confirmation.
- Most first-run failures are schema mismatches, oversized results, or a tunnel that dropped mid-run.
Step 1: Provision the sandbox
Begin with a disposable container that holds only what the task needs. The goal is a clean, per-run environment: when the run ends, you destroy it, and nothing leaks into the next task. Mount just the working directory, inject just the credentials the tools require, and nothing else.
docker run --rm -it \
--name agent-sandbox \
-e DB_URL="$DB_URL" \
-e ALLOWED_ORG=acme \
-v "$PWD/workspace:/work" \
--network egress-only \
agent-sandbox:latest
The --network egress-only piece matters: the sandbox can dial out (to reach the control plane and any allowed APIs) but accepts no inbound connections. That single constraint is what lets you skip firewall holes entirely. The --rm flag makes the container ephemeral so state cannot survive the run.
Step 2: Define scoped tools in an MCP server
Inside the sandbox, run an MCP server that exposes the agent's tools. Define each tool with a strict schema so the model knows the exact argument shape. Start narrow: a lookup and a list, both read-only.
{
"name": "get_invoice",
"description": "Fetch one invoice by id for the current org.",
"input_schema": {
"type": "object",
"properties": {
"invoice_id": { "type": "string", "pattern": "^inv_[a-z0-9]+$" }
},
"required": ["invoice_id"],
"additionalProperties": false
}
}
The pattern and additionalProperties: false are doing quiet but important work — they reject malformed calls before any code runs, which catches a surprising share of agent mistakes at the boundary instead of deep in your handler. The server's job is to validate, execute against your scoped credentials, and return a compact result.
Step 3: Open the MCP tunnel
Now connect the sandbox to the control plane. The sandbox initiates an outbound, authenticated session and holds it open; the agent's tool calls flow down it. The exact command depends on your runtime, but the shape is always the same: authenticate once, then serve.
Hear it before you finish reading
Talk to a live CallSphere AI voice agent in your browser — 60 seconds, no signup.
mcp-tunnel connect \
--server http://localhost:8931 \
--control-plane wss://agent.anthropic-control.example \
--token "$AGENT_SESSION_TOKEN" \
--keepalive 20s
flowchart TD
A["Start sandbox container"] --> B["Launch MCP server on localhost"]
B --> C["Tunnel dials control plane (outbound)"]
C --> D["Authenticate session with token"]
D --> E["Register tool schemas"]
E --> F{"Agent run starts"}
F -->|Tool call| G["Server validates & executes"]
G --> H["Compact result back over tunnel"]
H --> F
Once the session is up, the control plane can see your tools but the wider internet cannot. The --keepalive matters because the tunnel is stateful; if it drops mid-run, in-flight calls fail and the agent may stall. Plan for reconnect from the start.
Step 4: Write the system prompt and register the agent
With tools live, give the agent its operating instructions. Keep the system prompt about behavior and boundaries, not about restating the tool schemas — the schemas already describe the tools. Tell the agent its goal, its constraints, and when to stop.
You are an accounts assistant operating in a sandbox for org "acme".
Use get_invoice and list_overdue to answer billing questions.
Never guess an invoice id; if you do not have one, call list_overdue first.
Return a short summary plus the specific invoice ids you used.
Stop as soon as the question is answered; do not call tools speculatively.
That last line is doing real work. Without an explicit stop instruction, agents tend to keep exploring, and every extra tool call adds latency and tokens. Be concrete about what "done" looks like.
It also helps to state the output contract precisely, because a managed agent's result is consumed by something downstream — a ticket system, a Slack message, another agent. "Return a short summary plus the specific invoice ids you used" tells the model the shape you expect, and that shape becomes something you can parse and validate. Vague instructions like "explain what you found" produce prose that varies run to run and is annoying to consume programmatically. Treat the agent's output like an API response: define it, then hold the agent to it in the prompt.
Step 5: Run it and read the trace
Send a goal and watch the tool-call trace rather than just the final answer. The trace tells you whether the agent picked the right tools, passed valid arguments, and got compact results back. A healthy first run for "which acme invoices are overdue?" looks like one list_overdue call, maybe a couple of get_invoice calls for detail, then a final summary — not a dozen speculative lookups.
If the agent calls a tool with arguments your schema rejects, that is good news: the boundary caught it, and you will see a clear validation error in the trace instead of corrupt behavior. Feed those errors back as observations; capable models usually self-correct on the next turn.
Reading the trace is also how you catch the subtler failure where the agent technically succeeds but reasons poorly — calling get_invoice on every invoice one by one when a single list_overdue would do. The final answer might still be correct, so you would never notice from output alone, but the cost and latency are quietly several times higher than they should be. Make trace review a habit for the first dozen runs of any new agent; it is the cheapest, highest-signal feedback you will get, and most prompt and tool refinements come straight out of watching what the agent actually did.
Still reading? Stop comparing — try CallSphere live.
CallSphere ships complete AI voice agents per industry — 14 tools for healthcare, 10 agents for real estate, 4 specialists for salons. See how it actually handles a call before you book a demo.
Step 6: Add write tools carefully, then tear down
Only after read tools behave should you add anything that mutates state. Gate write tools behind explicit confirmation — either a human approval step or a tool that requires a token the agent had to fetch first — so a hallucinated call cannot silently change data. When the run finishes, destroy the container. Ephemeral sandboxes mean no secret or scratch file survives into the next task, which is the cheapest security control you will ever add.
Common pitfalls
- Loose schemas. Without
requiredandadditionalProperties: false, the agent can send malformed calls that fail deep in your code instead of at the boundary. - Restating tools in the prompt. Duplicating schema details in the system prompt wastes context and drifts out of sync. Let the schema be the source of truth.
- Skipping reconnect logic. A dropped tunnel mid-run strands the agent. Add keepalive and idempotent tools so retries are safe.
- Going straight to write tools. Test read-only first; you cannot tell if the agent reasons correctly until you have watched it not break anything.
- Long-lived shared sandboxes. Reusing one container across runs leaks state between tasks. Make them per-run and ephemeral.
Where things break on first run
| Symptom | Likely cause | Fix |
|---|---|---|
| Tool never called | Schema description too vague | Sharpen the tool description and name |
| Validation errors | Agent guessed an argument | Add a discovery tool it must call first |
| Run stalls mid-task | Tunnel dropped | Enable keepalive + reconnect |
| Costs spike | Oversized tool results | Trim and paginate at the server |
Frequently asked questions
Do I need a public URL for my MCP server?
No. The sandbox dials out to the control plane and holds the session open, so the MCP server only ever listens on localhost inside the container. Nothing is exposed to inbound traffic.
Where do credentials live in this setup?
Inside the sandbox container's environment, used only by the MCP server when it executes a tool. The model never receives them — it only sees the tool's structured result.
How do I stop the agent from calling tools speculatively?
Give it an explicit stop condition in the system prompt and define tools narrowly. Watching the trace on early runs lets you catch over-exploration and tighten the instructions.
How do I make tool calls safe to retry after a dropped tunnel?
Design tools to be idempotent — the same arguments produce the same effect — so a reconnect-and-retry cannot double-apply a change. Pair that with keepalive to reduce drops in the first place.
Bringing agentic AI to your phone lines
The same sandbox, tunnel, and tool-trace discipline powers CallSphere's voice and chat agents — they answer every call, call internal tools mid-conversation, and book work 24/7. Try it at callsphere.ai.
Source & attribution: This is an independent, original explainer inspired by Anthropic's coverage on the Claude blog. Claude, Claude Code, Claude Cowork, Claude Opus, and the Model Context Protocol are products and trademarks of Anthropic. CallSphere is not affiliated with or endorsed by Anthropic.
Try CallSphere AI Voice Agents
See how AI voice agents work for your industry. Live demo available -- no signup required.