Skip to content

Claude and MCP

limabean includes an MCP server, so Claude can manage your VMs itself. From Claude Code or Claude Desktop on your Mac, Claude can create a VM for a task, clone a repository into it, run the build and tests, snapshot it before something risky, and stop it when it's done. Nothing it runs touches your Mac.

claude mcp add --scope user limabean -- limabean mcp

That's the whole setup for Claude Code. Then ask for something like:

Make a VM called scratch, clone rossedman/limabean into it, and run the tests.

To see a whole task through, from drafting a project file to a fix you can push, follow the walkthrough.

MCP or an SSH connection?

They work together. MCP lets Claude, running on your Mac, manage VMs and run commands in them. An SSH connection, which limabean up adds to Claude Desktop for every VM, puts a whole Claude session inside one VM. See Claude Desktop for that.

Set it up

Claude Code

claude mcp add --scope user limabean -- limabean mcp

--scope user makes it available in all your projects. Without it, Claude Code uses local scope: just you, and only in the project where you ran the command. Check it with claude mcp list, or /mcp inside a session, which also lists the tools. To remove it: claude mcp remove limabean.

Arguments after -- go to limabean, so this also offers the destructive tools:

claude mcp add --scope user limabean -- limabean mcp --allow-destructive

Claude Desktop

  1. Open Claude → Settings… → Developer → Edit Config. That opens ~/Library/Application Support/Claude/claude_desktop_config.json, creating it if needed.
  2. Add limabean under mcpServers:

    {
      "mcpServers": {
        "limabean": {
          "command": "limabean",
          "args": ["mcp"]
        }
      }
    }
    
  3. Quit Claude Desktop completely and open it again.

If the server doesn't show up, use the full path from which limabean as the command, for example /opt/homebrew/bin/limabean: apps started from the Dock don't always see your shell's PATH. Claude Desktop's logs are in ~/Library/Logs/Claude; mcp-server-limabean.log has limabean's own output.

Claude Code can copy servers from Claude Desktop's config with claude mcp add-from-claude-desktop.

What to ask for

Claude picks the tools; you describe the task.

  • "Create a VM called api with 8 GB of memory, clone acme/api into it and get the test suite passing."
  • "What's listening in dev? Which of those can I open on my Mac?"
  • "Snapshot dev, then try upgrading the project to Go 1.27. If the tests fail, tell me what broke."
  • "Make a locked sandbox that can only reach GitHub and PyPI, clone acme/scraper into it and run it."
  • "Clone dev three times and try a different fix for the flaky test in each. Tell me which one worked."
  • "Make a scratch VM that deletes itself in two hours and benchmark the three JSON libraries in it."
  • "Stop every VM I'm not using."

Repositories go to ~/code/<host>/<owner>/<repo> in the VM, so after clone_repo Claude runs commands with cd ~/code/github.com/acme/api && …. For a checkout with a .limabean.yaml, project_run does that for it.

Ready-made workflows

limabean also offers a few workflows as MCP prompts: a whole task, written out for Claude, that you start with its arguments. In Claude Code they're slash commands; type /mcp__limabean__ to see them:

/mcp__limabean__test_in_sandbox /Users/me/src/shop
/mcp__limabean__triage_repo acme/scraper
/mcp__limabean__try_a_change /Users/me/src/shop "upgrade to Go 1.27"

In Claude Desktop, they're under the + button, in limabean's menu.

Prompt Arguments What Claude does
test_in_sandbox a checkout's path Drafts a .limabean.yaml if there's none and writes it once you agree, shows you the plan, brings the VM up, runs the tests in its clone and reports
triage_repo a repository, and optionally what it may reach Creates a locked VM for an unfamiliar repository, snapshots it, clones, installs and tests, and reports what works
try_a_change a checkout's path and the change Snapshots the project's VM, makes the change in its clone, runs the tests and shows you the diff; if it didn't work, gives you the restore command
run_untrusted what to run Runs a script, tool or repository in a throwaway locked VM that deletes itself in two hours, reads it first, and reports what it did and which hosts it tried to reach
tidy_vms none Lists your VMs, suggests which to stop or delete, stops the ones you agree to, and gives you the rm commands for the rest

A prompt is only instructions: it runs nothing itself, so every tool's guards still apply. Each one also tells Claude to show you plans first, never to try to widen a network, and to leave deleting VMs and restoring snapshots to you.

Sandboxes for a task

create_vm takes allow and locked, so Claude can make itself a VM that can only reach what the task needs:

Create a VM called triage that can only reach github and python, locked. Clone acme/scraper, install its dependencies and run the test suite.

The VM gets an allowlist: every other domain is blocked, for the VM and its containers. Locked takes sudo and Docker away from the VM's user, so nothing in it, Claude included, can lift the allowlist. An agent can narrow a new VM's network this way; no tool can widen one. Only you can, with limabean network.

Pair it with snapshots: "snapshot triage before you change anything", then restore from the command line (limabean snapshot restore triage) if something goes wrong.

When something in the sandbox can't reach a host, Claude can see which name was blocked with network_log, and tell you; adding it is up to you (limabean network allow triage <domain>).

Claude Code inside a VM

MCP lets Claude on your Mac drive VMs. To run an agent inside one instead, give the VM the claude pack and a login secret, and lock it down: the agent works with the VM's tools and network, never your Mac's. Combine it with a project file (packs: [claude]) or with limabean run --rm for a VM that's gone when the task is done. Agents in a VM walks through it: interactive sessions in tmux, headless runs, throwaway VMs and attempts side by side. An agent in a VM can run limabean-info to see what it has to work with: its tools, the clone, which hosts it can reach and which secrets it has, by name.

Projects

When a checkout has a .limabean.yaml, Claude can use it the way you use limabean up: "bring up the VM for ~/src/shop and get its tests passing". The project tools take the checkout's absolute path:

  1. Without a file yet, project_init drafts one from the checkout's files, as limabean init --project does. It only reads and writes nothing: Claude shows you the draft, and writes it as .limabean.yaml once you agree.
  2. project_plan shows what up would do: a new VM's packs, size, network, environment, setup and start commands, or what differs from an existing one. Claude should show you this first.
  3. project_up does it. Claude Code asks you before every call, so you approve with the plan in front of you. Changed start commands count as approved when you say yes.
  4. project_run runs a command in the VM's clone of the repository, such as the tests, without Claude working out where the clone is.
  5. project_status, project_logs and project_down check on it, read its provisioning, setup or start output, and stop it.

The same rules hold as in your terminal, plus a few for MCP:

  • A file never widens a VM's network; those changes come back as limabean network commands for you to run.
  • A change that rebuilds the VM (new packs or environment template) is refused unless the server runs with --allow-destructive.
  • Only the directory's own .limabean.yaml is read: not a parent directory's, not a symlink, not any other path, so a tool call can't make limabean read something else on your Mac.
  • project_init takes only a git checkout's directory, and what it reads there only shapes the draft (pack names, commands from a fixed list, names that pass the file's checks); no file's contents come back.
  • The checkout's origin is read from .git/config as a file; git doesn't run on the Mac.
  • Setup runs without a terminal, and its output comes back to Claude.

Tools

Tool Does
project_init Drafts a .limabean.yaml for a git checkout from its files, writing nothing
project_plan What up would create or change for a checkout's .limabean.yaml, changing nothing
project_up Creates or updates the checkout's VM and runs its start commands; Claude Code asks you first (projects)
project_status The checkout's VM as JSON: status, start, ports, pending changes
project_logs The end of its provisioning, setup or start log
project_down Stops the checkout's VM
list_vms Lists VMs: status, environment, size, secrets, network
create_vm Creates a VM: name, and optionally environment, CPUs, memory, with (the packs the task needs; without it, only core and the PACKS setting's), allow, locked, and ttl to have it deleted later. It gets your shared secrets
clone_vm Copies a VM in seconds, ~/code and all (clones)
start_vm, stop_vm Starts or stops a VM
project_run Runs a shell command in the checkout's VM, in its clone of the repository, and returns the exit code and output
run_in_vm Runs a shell command in a running VM and returns the exit code and output
clone_repo Clones a repository into ~/code with ghq
vm_info What a running VM knows about itself, as JSON: packs, tools, network, secrets' names, and the project's clone, ports and logs (limabean-info)
list_ports Lists the ports programs in a VM listen on, and which reach http://localhost:<port> on the Mac
network_log Lists the names a sandboxed VM looked up, and which its allowlist blocked
snapshot_save, snapshot_list Saves and lists snapshots
snapshot_restore, delete_vm, rebuild_vm Only with --allow-destructive

run_in_vm runs as you, in your home directory, through your login shell. It isn't interactive: a command that waits for input times out. The default timeout is 10 minutes, and Claude can ask for up to an hour. Long output is trimmed to its last 100 KiB, where errors usually are.

Tools that destroy work

snapshot_restore, delete_vm and rebuild_vm only exist if you start the server with limabean mcp --allow-destructive. Even then:

  • Claude Code asks you before every call to them, whatever its permission mode, with no "don't ask again".
  • delete_vm refuses while a repository in ~/code has uncommitted, stashed or unpushed work, just like limabean rm.
  • They're marked destructive (destructiveHint) for any other MCP client that uses that.

What Claude can't do

  • Run anything on your Mac. Every command runs inside a VM, over SSH.
  • See or add secrets. No tool returns secret values. New VMs get only your shared secrets: adding a secret could run a cmd: reference on the Mac.
  • Widen a VM's network. It can create a restricted VM, but not change an existing VM's allowlist or lock, from a project file or otherwise.
  • Read arbitrary files. The project tools read only a checkout's own .limabean.yaml (and its .git/config for the origin).
  • Delete a VM it didn't ask to be temporary. ttl only applies to a VM as create_vm makes it; no tool sets one on an existing VM.
  • Pass names as flags. VM names, environments, snapshot names and domains are checked before they reach limabean's command line, so a "name" like --force is refused.

A command in a VM runs as you there, with that VM's secrets and GitHub token, and can reach whatever the VM can. Give a VM only the secrets an agent should use, and lock it when it should only reach certain hosts. The reasoning is in design note D14.

Troubleshooting

Symptom Fix
Claude Code doesn't list the tools claude mcp list should show limabean. Added without --scope user, it only loads in the project where you added it.
Claude Desktop doesn't show it Quit and reopen the app. Use the full path from which limabean as command. Check ~/Library/Logs/Claude/mcp-server-limabean.log.
limabean mcp in a terminal prints nothing That's right: it waits for a client on stdin. Press Ctrl-C.
"dev is stopped; start it with start_vm" Commands only run in running VMs; ask Claude to start it.
"timed out after 10m0s" Ask for a longer timeout (up to an hour), or run the command in the background in the VM.
A clone or install fails in a sandbox The domain isn't on its allowlist. Add it from your Mac: limabean network allow <vm> <domain>.