Sandboxing & Isolation
7 min read
The MCP Client executes every MCP server inside a lightweight process-level sandbox. This is not VM-level isolation – it uses operating system primitives to constrain what a running process can access and consume. The depth of isolation depends on the host platform.
Sandbox Architecture
When mcp run launches an MCP server, the following isolation layers are applied in order:
1. Process Creation
└─ Fork a new process for the MCP server
2. Resource Limits
├─ Memory limit (cgroups v2 / rlimits / Job Objects)
├─ CPU limit (cgroups v2 / rlimits / Job Objects)
├─ PID limit (cgroups v2 / rlimits)
└─ File descriptor limit (rlimits)
3. Network Isolation (Linux only)
└─ Network namespace with default-deny
4. Filesystem Isolation
├─ Linux: bind mounts + Landlock LSM
├─ macOS: UNIX file permissions (best-effort)
└─ Windows: NTFS ACLs (best-effort)
5. Subprocess Control
├─ Linux: seccomp BPF filters
├─ macOS: process monitoring (limited)
└─ Windows: not available
6. Environment Filtering
└─ Only allowed env vars passed to process
7. STDIO Transport
└─ Communication via stdin/stdout only
Resource limits are mandatory – they cannot be disabled, only adjusted. The default limits are designed to be generous enough for typical MCP servers while preventing runaway resource consumption.
Resource Limits
Every MCP server process runs with enforced resource limits. These limits apply regardless of platform.
Default Limits
| Resource | Default | Flag Override | Config Key |
|---|---|---|---|
| Memory | 256 MB | --max-memory | executor.resource_limits.max_memory |
| CPU | 1.0 cores | --max-cpu | executor.resource_limits.max_cpu |
| PIDs | 64 | --max-pids | executor.resource_limits.max_pids |
| File Descriptors | 256 | --max-fds | executor.resource_limits.max_fds |
| Execution Timeout | 5 minutes | --timeout | executor.default_timeout |
How Limits Are Enforced
| Resource | Linux | macOS | Windows |
|---|---|---|---|
| Memory | cgroups v2 memory.max | RLIMIT_AS | Job Object JobObjectExtendedLimitInformation |
| CPU | cgroups v2 cpu.max | RLIMIT_CPU (time-based) | Job Object JobObjectCpuRateControlInformation |
| PIDs | cgroups v2 pids.max | RLIMIT_NPROC | Not available (Job Object has no PID limit) |
| File Descriptors | RLIMIT_NOFILE | RLIMIT_NOFILE | Not applicable (handles are different) |
Behavior When Limits Are Exceeded
- Memory exceeded: On Linux, the kernel OOM killer terminates the process (exit code 137). On macOS, the process receives a
SIGKILL. On Windows, the Job Object terminates the process. - CPU exceeded: On Linux, the process is throttled (not killed). On macOS, a
SIGXCPUsignal is sent. On Windows, the process is throttled. - PID limit exceeded: On Linux,
fork()calls fail withEAGAIN. On macOS,fork()calls fail. On Windows, not enforced. - FD limit exceeded:
open()calls fail withEMFILEon all UNIX platforms. - Timeout exceeded: The client sends
SIGTERM, waits 5 seconds, then sendsSIGKILL. Exit code is 124.
Adjusting Limits
# Generous limits for a heavy workload
mcp run acme/[email protected] \
--max-memory 2g \
--max-cpu 4.0 \
--max-pids 256 \
--max-fds 1024 \
--timeout 30m
Or configure globally:
# ~/.mcp/config.yaml
executor:
default_timeout: "30m"
resource_limits:
max_memory: "2g"
max_cpu: 4.0
max_pids: 256
max_fds: 1024
Network Isolation
Network isolation prevents MCP servers from making unauthorized outbound connections. This defends against data exfiltration, SSRF, and covert channels.
Linux (Production-Ready)
On Linux, the client creates a dedicated network namespace for the MCP server process. By default, the namespace has:
- No network interfaces (not even loopback in the strictest mode)
- No routing table entries
- No DNS resolution
This means the MCP server cannot make any network connections unless explicitly allowed.
To allow network access:
mcp run acme/[email protected] --network allow
A future release will support manifest-declared network allowlists, where the MCP server manifest specifies which domains it needs to reach. The sandbox will allow connections only to those domains.
macOS and Windows
Network isolation is not available on macOS or Windows. The MCP server process inherits the host’s full network stack. The --network deny flag is accepted but has no effect on these platforms.
$ mcp doctor
...
Network Isolation: NOT AVAILABLE (macOS does not support network namespaces)
...
Without network isolation, a compromised MCP server on macOS or Windows can exfiltrate data or contact external services. For production workloads with untrusted MCPs, use Linux or run the MCP Client inside a Docker container.
Filesystem Isolation
Filesystem isolation confines the MCP server process to a specific working directory, preventing it from reading or writing files outside its sandbox.
Linux (Production-Ready)
On Linux, the client uses two mechanisms:
Bind mounts: The MCP server’s root filesystem is a minimal set of bind-mounted directories. Only the working directory is mounted read-write.
Landlock LSM: If the kernel supports Landlock (Linux 5.13+), additional filesystem access restrictions are applied at the kernel level. This provides mandatory access control that the MCP server cannot bypass even with elevated privileges within its namespace.
The effective filesystem view:
/ (read-only, minimal)
├── usr/lib/ (read-only, shared libraries)
├── lib/ (read-only, shared libraries)
├── tmp/ (read-write, temporary files)
└── workspace/ (read-write, MCP working directory)
macOS (Best-Effort)
On macOS, the client sets UNIX file permissions on the working directory and relies on the operating system’s permission model. This is a best-effort approach – a determined process with knowledge of the filesystem layout can potentially access files outside the sandbox.
Windows (Best-Effort)
On Windows, the client uses NTFS ACLs to restrict directory access. Similar to macOS, this is best-effort and does not provide the same guarantees as Linux bind mounts and Landlock.
Subprocess Control
Subprocess control restricts whether the MCP server can fork or execute child processes.
Linux (seccomp)
On Linux, the client installs a seccomp BPF filter on the MCP server process. This filter intercepts system calls at the kernel level:
fork(),vfork(),clone(): Blocked (returnsEPERM)execve(),execveat(): Blocked (returnsEPERM)
This is a kernel-level enforcement that cannot be bypassed from user space.
When allow_subprocess is true in the policy configuration, these syscalls are permitted but the child processes still inherit all resource limits from the parent cgroup.
macOS (Limited)
On macOS, subprocess control is implemented via process monitoring. The client watches for child process creation and sends termination signals. This is a reactive mechanism (kill after detection) rather than a preventive one (block the syscall), and there is a brief window where a child process can execute before being terminated.
Windows (Not Available)
Subprocess control is not implemented on Windows. MCP servers can spawn child processes without restriction.
Platform Comparison
| Feature | Linux | macOS | Windows |
|---|---|---|---|
| Resource Limits | cgroups v2 + rlimits | rlimits only | Job Objects |
| Memory Enforcement | Hard kill (OOM) | Soft signal | Hard kill |
| CPU Enforcement | Throttling | Time-based signal | Throttling |
| PID Limits | Enforced (cgroups) | Enforced (rlimits) | Not available |
| FD Limits | Enforced (rlimits) | Enforced (rlimits) | Not applicable |
| Network Isolation | Network namespaces (full) | Not available | Not available |
| Filesystem Isolation | Bind mounts + Landlock | UNIX perms (best-effort) | NTFS ACLs (best-effort) |
| Subprocess Control | seccomp BPF (preventive) | Process monitoring (reactive) | Not available |
| Audit Logging | Full | Full | Full |
| Production Ready | Yes | No | No |
Understanding mcp doctor Output
The mcp doctor command reports the status of each sandbox capability on your system.
Status Indicators
| Indicator | Meaning |
|---|---|
| OK | Capability is fully available and production-ready |
| PARTIAL | Capability is available with limitations |
| LIMITED | Capability exists but has known bypass vulnerabilities |
| NOT AVAILABLE | Capability is not supported on this platform |
Reading the Overall Assessment
| Assessment | Meaning |
|---|---|
| PRODUCTION READY | All critical sandbox capabilities are available. Safe for untrusted MCPs. |
| DEVELOPMENT ONLY | Some capabilities are missing. Safe for trusted MCPs from verified publishers. Not suitable for untrusted code. |
Common mcp doctor Results
Linux with cgroups v2:
Overall: PRODUCTION READY
All features available. This is the recommended setup.
Linux without cgroups v2:
Resource Limits: PARTIAL (rlimits only, cgroups v2 not available)
Overall: DEVELOPMENT ONLY
Upgrade to a kernel with cgroups v2 support, or ensure the cgroups v2 hierarchy is mounted.
macOS (any version):
Resource Limits: PARTIAL (rlimits only, no cgroups)
Network Isolation: NOT AVAILABLE
Filesystem: PARTIAL (best-effort UNIX permissions)
Subprocess Ctrl: LIMITED
Overall: DEVELOPMENT ONLY
This is expected on macOS. Use for development and testing only.
Production vs Development Recommendations
Production Environments
For production workloads, especially those running untrusted or community MCP servers:
- Use Linux with cgroups v2 enabled
- Set
min_cert_levelto at least 2 (Security Certified) - Restrict
allowed_originsto Official and Verified - Keep
network_defaultat deny - Keep
allow_subprocessat false - Enable audit logging
- Consider running the MCP Client inside a Docker container for additional isolation
Development Environments
For local development and testing with trusted packages:
- Any platform is acceptable (Linux, macOS, Windows)
min_cert_level: 0for flexibilitynetwork_default: allowif the MCP server needs network accessallow_subprocess: trueif needed for your development workflow- Audit logging optional but recommended
Docker as an Additional Layer
For maximum isolation on any platform, run the MCP Client inside a Docker container:
docker run --rm -it \
-v ~/.mcp:/home/mcp/.mcp \
-e MCP_REGISTRY_TOKEN=$MCP_REGISTRY_TOKEN \
mcphub/mcp-client:latest \
run acme/[email protected]
This provides Docker’s container isolation (namespaces, cgroups, seccomp) as a foundation, with the MCP Client’s own sandbox as an additional layer inside the container.