End-to-end verification that forkd-mcp works. A
host-side Python "agent" drives the forkd-mcp server over stdio
JSON-RPC — exactly the way Claude Desktop / Cursor / Cline drive it —
and exercises the full BRANCH + fan-out flow.
This recipe is not a guest-side rootfs; it's a host-side reproducible demo of the MCP integration. Run it once after installing forkd-mcp to confirm the protocol works on your box.
list_tools → expect 11 (forkd-mcp 0.2.0)
list_snapshots → pick first tag
spawn_sandboxes → 1 source sandbox
exec_command → `echo hello-from-forkd; uname -r`
branch_sandbox(diff=true) → snapshot with v0.3 diff mode
spawn_sandboxes(branch) → fan out 3 grandchildren
kill_sandbox x4 → cleanup
Prints pause_ms and diff_physical_bytes from the BRANCH so you
can see the v0.3 diff-snapshot numbers in your own environment.
-
forkd-controller running and reachable. Either:
sudo systemctl start forkd-controller # OR sudo nohup forkd-controller serve \ --bind 127.0.0.1:8889 \ --token-file /etc/forkd/token \ --snapshot-root /var/lib/forkd/snapshots \ > /var/log/forkd.log 2>&1 &
-
At least one snapshot registered. Build a quick one with
forkd snapshot(see main README) or pull an existing one from the Hub:forkd pull deeplethe/langgraph-react
-
Install both pieces of the MCP plumbing:
pip install forkd-mcp mcp
-
Provision host network for fanout. The demo fans out 3 children, which requires per-child netns:
sudo bash scripts/host-tap.sh # forkd-tap0 for the source sandbox sudo bash scripts/netns-setup.sh 3 # forkd-child-{1..3} netns
-
Run the demo:
FORKD_TOKEN=$(sudo cat /etc/forkd/token) \ python3 recipes/mcp-agent/demo.py
Optional first argument: pin a specific snapshot tag instead of letting the demo auto-pick the first one.
FORKD_TOKEN=$(sudo cat /etc/forkd/token) \
python3 recipes/mcp-agent/demo.py langgraph-react[mcp-agent] forkd-mcp registers 11 tools:
- list_snapshots
- spawn_sandboxes
- branch_sandbox
- create_snapshot
- wait_for_text
- list_sandboxes
- get_sandbox
- kill_sandbox
- exec_command
- eval_code
- ping_sandbox
[mcp-agent] using snapshot 'langgraph-react'
[mcp-agent] spawned sandbox sb-6a0...
[mcp-agent] exec result:
stdout: 'hello-from-forkd\n6.1.141\n'
exit_code: 0
[mcp-agent] BRANCH (diff=true): pause_ms=205 diff_physical_bytes=983040
[mcp-agent] fanned out 3 children from branch:
- sb-6a0...0001
- sb-6a0...0002
- sb-6a0...0003
[mcp-agent] cleaned up grandchildren
[mcp-agent] cleaned up source sandbox sb-6a0...
pause_ms in the BRANCH line is forkd's v0.3 diff-snapshot pause —
typically 200-300 ms regardless of source memory size on commodity
SSD. See
bench/pause-window/RESULTS-v0.3.md
for the full curve.
The Python script reproduces the same calls Claude Desktop / Cursor / Cline would make. To drive forkd-mcp from a real client instead:
- Claude Desktop: see
sdk/mcp/README.md#register-with-claude-desktop - Cursor: see
sdk/mcp/README.md#register-with-cursor - Cline: see
sdk/mcp/README.md#register-with-cline - Claude Code:
claude mcp add forkd --env FORKD_URL=... --env FORKD_TOKEN=... -- forkd-mcp
Once registered, ask the agent in plain English:
Spawn a Python sandbox, run
pip install requestsinside it, then BRANCH it with diff snapshots enabled and fan out 3 children from the branch. Show me the BRANCH timing.
The agent picks the right tools (spawn_sandboxes → exec_command → branch_sandbox with diff=true → spawn_sandboxes again) and reports the metrics. Same flow as this script, less typing.
mcpimport fails →pip install mcp>=1.0forkd-mcpnot found →pip install forkd-mcp>=0.2.0. The script spawnsforkd-mcpas a subprocess; it must be onPATH.no snapshots on the controller→ register one viaforkd snapshot --tag foo --kernel ... --rootfs ...orforkd pull deeplethe/langgraph-react.- HTTP 401 from forkd-controller → token mismatch. Make sure
FORKD_TOKENenv on this script matches whatforkd-controller --token-filewas given. - HTTP 400 from
branch_sandboxwithdiff=true→ daemon is pre-v0.3.0; either upgrade (pip install forkd>=0.3.0) or remove"diff": Truefrom the script.
If this script runs to completion and prints non-zero pause_ms
under 1 second, your end-to-end pipeline is:
- forkd-controller speaking REST correctly
- forkd-mcp wrapping it correctly into MCP tools
- An MCP client (this script) driving it with the correct framing
- v0.3 diff snapshots working under the MCP path
This is the minimum reproducible footprint you'd want before pointing a real LLM-driven agent at forkd via MCP. If the script fails, debug here before debugging in Claude Desktop.