run_in_sandbox tool, verified end to end by a real MCP client.
Level: intermediate · Time: ~20 minutes · Pattern: the box is a tool the model calls.
When to use this
The Model Context Protocol is becoming the common way to hand external capabilities to LLM clients. When several different agents, IDEs, or desktop clients all need “execute this in an isolated sandbox”, you do not want to reimplement the call path for each one. You want one standard tool that every client discovers and calls the same way. This guide builds that:SimpleBox.exec behind an MCP tool named run_in_sandbox, so any client gets “run a command in a hardware-isolated microVM and receive stdout, stderr, and the exit code”.
The division of labor is worth stating once: the MCP transport is yours, the sandbox is BoxLite’s. You bring an MCP framework — this guide uses FastMCP from the official mcp package — and BoxLite provides the isolated execution behind each tool call.
Architecture
Protocol handling — handshake, tool discovery, JSON-RPC — runs in your process. Everycall_tool starts a clean SimpleBox, runs the command in its own kernel, and destroys the box afterwards.
Prerequisites
- BoxLite installed and a working virtualization host — see Installation.
- The official MCP Python SDK, which BoxLite does not bundle.
Build it
Step 1: the MCP server
Save assandbox_mcp_server.py. It runs directly as a stdio MCP server.
Step 2: a client that proves the handshake works
Save asmcp_client_test.py. It launches the server, initializes, discovers tools, and calls one.
SimpleBox.exec parameter table is on MCP tool handler.
Run it
stdout came from echo running inside the microVM, serialized back over JSON-RPC.
Now confirm the behaviour that surprises people most — a failing command returns data rather than raising. Change the tool call to:
Trust and limits
Two layers, with different guarantees.- Execution layer — isolated. Every
call_toolstarts its own microVM with its own kernel, filesystem, memory, and resource budget. However untrusted the command an MCP client sends,rm -rf /damages only that box, which is destroyed on exit. - Protocol layer — yours to secure.
FastMCPruns in your host process, outside any sandbox. Anything that can connect to this server can callrun_in_sandbox. Authentication, rate limiting, and any command allowlist are your responsibility — add them in the tool function before the box is created. - Failures arrive as data or as exceptions, never as crashes. A non-zero exit is returned in the result. Missing virtualization or a failed image pull raises
RuntimeError(notBoxliteError), which the handler above catches and serializes back to the client. - Fresh box per call is a deliberate trade. It gives maximum isolation and costs a start each time. Reusing one long-lived box is faster but lets state leak between calls — see Next steps.
Troubleshooting
Next steps
- Connect a real client. Register
sandbox_mcp_server.pyin your client’s MCP configuration (commandplusargs); it performs the same stdio handshake verified above and discoversrun_in_sandboxautomatically. - Add more tools. Write additional
@mcp.tool()functions —read_file/write_fileovercopy_in/copy_out, orrun_pythonoverCodeBox.run(see Build a code interpreter). - Add access control. A command allowlist and authentication in the tool function are the first things to add once the server is reachable — see Run untrusted tools safely.
- Reuse one box per session. Hold a long-lived box on the server instead of creating one per call, and weigh the speed against the state that then persists across calls.

