MCP server (coding agents)

Connect Claude Code, Cursor, Codex, Grok Build, and other MCP hosts to grain sandboxes.

grain exposes sandbox tools over the Model Context Protocol so coding agents can create, inspect, run commands in, and delete microVMs.

MCP is built into the main grain binary. It talks to a running grain daemon via the same HTTP/unix API as the CLI (plus host-local image/log helpers).

Quick start

The install script can enable MCP by default (mcp.enabled: true in ~/.grain/config.yaml). Otherwise:

bash
grain up --mcp                 # daemon + Streamable HTTP MCP
# or permanently in ~/.grain/config.yaml:
# mcp:
#   enabled: true
#   listen: 127.0.0.1:7476

grain image pull grain-ubuntu  # or grain_image_pull via MCP

Default MCP HTTP endpoint: http://127.0.0.1:7476/mcp.

For IDE hosts that spawn a stdio server:

bash
grain mcp                      # stdio (daemon must already be up)

Configuration

yaml
mcp:
  enabled: false             # true = grain up always starts MCP HTTP
  listen: 127.0.0.1:7476     # Streamable HTTP bind (path /mcp)
FieldMeaning
mcp.enabledCo-start MCP Streamable HTTP with the daemon
mcp.listenhost:port (default 127.0.0.1:7476)

CLI:

CommandTransport
grain up --mcpDaemon + MCP HTTP in one process
grain mcpMCP stdio (spawn from host config)
grain mcp --httpMCP HTTP only (daemon must already be up)
grain mcp --http --listen 127.0.0.1:7476Override listen address

Host configuration

Each agent has its own config file and schema. Pick a host, choose stdio or HTTP, then copy the snippet (and path when it differs by OS).

Transport

JSON

Before connecting: grain up for stdio tools, or grain up --mcp for Streamable HTTP (http://127.0.0.1:7476/mcp). Prefer stdio when the host can spawn a local process.

Connection to the daemon

Variable / configMeaning
(default)Unix socket ~/.grain/grain.sock
GRAIN_SOCKETOverride socket path
GRAIN_APIHTTP base URL (http://127.0.0.1:7474)
GRAIN_TOKENBearer token when required

Tools

Lifecycle

ToolPurpose
grain_healthDaemon liveness + version
grain_list_vmsList sandboxes
grain_get_vmInspect one sandbox
grain_create_vmCreate VM (defaults: image=grain-ubuntu, wait=agent)
grain_start_vm / grain_stop_vmStart / stop
grain_delete_vmDelete (idempotent if missing)
grain_workspace_sandboxOne-shot: create + mount host dir at /work + wait agent + optional first command

Guest exec & files

ToolPurpose
grain_execRun command; streams stdout/stderr into result by default; timeout (default 15m); prefer go build over go test ./...
grain_write_file / grain_read_fileWrite/read guest files (text or base64)
grain_put_tar / grain_get_tarUpload/download tar (base64)
grain_fs_readdir / grain_fs_stat / grain_fs_mkdir / grain_fs_removeStructured guest FS

Observability

ToolPurpose
grain_agent_healthGuest agent /health
grain_logsHost serial console log (or qemu=true for hypervisor log)
grain_statsGuest mem/load/disk stats

Ports & images

ToolPurpose
grain_forward_add / grain_forward_removeLive host→guest TCP forwards; add returns localhost:PORT
grain_image_list / grain_image_pullCatalog + local readiness; pull base images on the host

Recipes

ToolPurpose
grain_actGitHub Actions via nektos/act in an ephemeral act-preset sandbox (mounts project at /work)
grain_k3sk3s lab (k3s preset, port 6443, waits for kubectl get nodes unless skip_wait). Kind is not a separate preset—use k3s.

Create parameters (high level)

FieldNotes
nameOptional; daemon generates if empty
imageDefault grain-ubuntu
waitDefault agent
cpus / memory_mb / disk_gbResources
persistentKeep disk after stop
presetdocker | k3s | act (merges userdata)
publish["8080:80"] or ["80"]
mounts["/host/path:/guest/path"]
timeoutGo duration for create readiness

Exec parameters

FieldNotes
streamDefault true — accumulate streamed stdout/stderr + progress chunks
timeoutCap runtime (default 15m)
cwdOptional guest working directory

Typical agent flows

Coding sandbox

  1. grain_image_list / grain_image_pull if needed
  2. grain_workspace_sandbox with host_dir = project root
  3. grain_write_file / grain_exec (focused builds)
  4. grain_delete_vm when done

GitHub Actions

text
grain_act  host_dir=<repo>  act_args=["-j","test"]

k3s lab

text
grain_k3s  name=lab  (optional host_dir)

Limits

  • No interactive PTY shell, proxy UI, secrets MCP, or golden bake via MCP (use CLI).
  • Create/exec can take minutes (cold image, apt, act). Set host tool timeouts accordingly (e.g. 600s).
  • Prefer focused builds in-guest; avoid full go test ./... unless intentional.

See also