boxer

MCP server

boxer's MCP server: the boxer_run and boxer_status tools, the brief resource, and lifecycle behaviour.

boxer mcp gives any MCP client two tools, boxer_run and boxer_status, and one resource.

boxer mcp [--harness NAME]

It serves MCP over stdio as newline-delimited JSON-RPC 2.0, protocol 2025-06-18 (or 2025-03-26 and 2024-11-05 when the client asks for one). boxer_run calls run side by side and each answers when it finishes, so ping and other calls are answered during a long run. It answers initialize, ping, tools/list, tools/call, resources/list and resources/read. It ignores notifications. Any harness that supports MCP can use it, including harnesses boxer has no specific integration for.

--harness selects the [harness.<name>] override layer, so per-harness settings such as mode apply here too.

Registering it

{
  "mcpServers": {
    "boxer": { "command": "boxer", "args": ["mcp"] }
  }
}

boxer install <harness> writes this entry into the file that harness reads.

Tools

boxer_run

FieldType
commandstringA POSIX shell line, run with sh -c in the guest. Give this or task
taskstringA [tasks] entry to run, with its environment and timeout, as boxer run --task does
cwdstringOptional. The directory to run in. Defaults to the server's working directory. A directory in another repository is refused; another worktree of the same one is not

Returns stdout and stderr interleaved, followed by [exit N]. Output over 128 KB keeps its first and last 64 KB, with a line saying how many bytes were left out between them. Stdin is empty. isError is set when the exit is non-zero or when boxer refused. A refusal is the same boxer: <reason> text, with cause and fix lines, that the CLI prints. The sandbox is created first when create_on includes run.

boxer_status

FieldType
cwdstringOptional

One line with the scope, isolation, state, image, worktree and mount path, then one line per forwarded guest port with its URL, else http://127.0.0.1:<host port>. When no sandbox exists yet it says so and names the image it would boot.

How cwd is interpreted

A client may pass a host path or a guest path. boxer accepts both:

  • A host path inside the worktree becomes the matching guest directory.
  • A path under the guest mount maps back to the host worktree.
  • Anything else falls back to the server's own working directory, and the result starts with a note: line saying so.

Resource

The server has one resource, boxer://brief, of type text/markdown. It holds the same brief that boxer brief prints and the hooks inject, resolved for the server's working directory. The brief lists:

  • the mount
  • the mode
  • the intercept and passthrough lists
  • the declared tasks, with what each is for

boxer generates the brief on each read. Any other URI is an error.

Lifecycle signals

For harnesses with no hook API, boxer treats MCP lifecycle messages as session start and end. Both signals apply only when create_on includes mcp, which it does by default.

  • initialize provisions the server's scope in the background, so the sandbox is warm before the first command. It is skipped under session and subagent isolation, because MCP carries no session id.
  • stdin EOF records the scope's last use, so gc's idle clock starts at the session's end.

Register the MCP server even on a harness where hooks already enforce sandboxing. You still get these signals.

Running someone else's MCP server in the sandbox

Some MCP servers must run next to the code. For example, next-devtools-mcp talks to a running Next.js dev server, so it must run in the same sandbox. boxer run passes stdio through unchanged, so you can wrap the server command with it:

{
  "mcpServers": {
    "next-devtools": {
      "command": "boxer",
      "args": ["run", "--", "npx", "-y", "next-devtools-mcp@latest"]
    }
  }
}

The harness stays on the host and talks to the server inside the guest. The server needs no changes.

On this page