Back to Mcpproxy Go

Native Sandbox Isolation (Linux, no Docker)

docs/features/sandbox-isolation.md

0.47.03.1 KB
Original Source

Native Sandbox Isolation (Linux, no Docker)

MCPProxy can isolate a stdio MCP server without Docker using the Linux Landlock LSM plus resource limits (setrlimit). This is the sandbox isolation mode (MCP-34), built for hosts where Docker is unavailable or broken — notably Ubuntu 24.04 with snap-installed Docker under AppArmor. Unlike bubblewrap / user-namespace sandboxes, Landlock does not require unprivileged user namespaces, so it is not blocked by kernel.apparmor_restrict_unprivileged_userns=1 (default on Ubuntu 23.10+).

Enabling

Set the isolation mode to sandbox, globally or per server:

json
{
  "docker_isolation": { "mode": "sandbox" },
  "mcpServers": [
    { "name": "obsidian", "command": "uvx", "args": ["obsidian-mcp"],
      "isolation": { "mode": "sandbox" } }
  ]
}

A per-server isolation.mode wins over the global mode. The legacy docker_isolation.enabled boolean still maps to docker/none for back-compat; mode supersedes it (see MCP-34.2).

What it enforces

  • Filesystem write allowlist. Reads stay broad (the runtime can load interpreters, node_modules, and site-packages from anywhere), but writes are denied outside a small allowlist: the server's working_dir, the OS temp dir, and the common package caches (~/.npm, ~/.cache, ~/.local/share). Tightening reads is deferred — a read allowlist breaks tool discovery.
  • Resource limits. Core dumps are disabled (RLIMIT_CORE=0, so in-memory secrets can't spill to disk) and the descriptor table is capped (RLIMIT_NOFILE).
  • Process-group cleanup. Reuses the existing Setpgid group teardown, so a sandboxed server and its children are killed together on disconnect.

Confinement is applied by a tiny re-exec wrapper (mcpproxy __sandbox_exec) that calls Landlock/setrlimit and then execs the real command — so the server's stdin/stdout pass straight through with no intervening multiplexer.

Honest limits

  • No uid/gid separation by default. The wrapper performs a best-effort privilege drop only when it is running as root with a non-root real user. In the personal edition mcpproxy runs as your user (not root), so this is a documented no-op — real uid/gid separation needs root or CAP_SETUID.
  • Reads are not confined (write-allowlist only; see above).
  • Graceful degrade. If the kernel lacks Landlock (pre-5.13, or LSM disabled), the server still starts but runs unconfined, and the host log records a DEGRADED/unconfined diagnostic. This favors availability; use docker mode when you need a hard guarantee.

Platform support

Platformmode: sandbox behavior
Linux (kernel 5.13+ with Landlock)Enforced: write-allowlist + rlimits
Linux (no Landlock)Degraded → runs unconfined, logged
macOS / WindowsDocumented no-op → effective none (Landlock is Linux-only)

See also: Docker Isolation for the Docker mode, and the non-Docker sandbox spike for the mechanism evaluation.