11 KiB
Docker Isolation - Complete Guide
When to use this reference: Docker isolation is enabled and servers are failing, or you see "not a TTY" errors.
This reference explains how MCPProxy's Docker isolation feature works and how to debug issues with it.
What is Docker Isolation?
MCPProxy can run stdio MCP servers inside Docker containers for security isolation. This prevents untrusted servers from accessing your filesystem or network.
Key concept: MCPProxy wraps the server command in docker run, manages the container lifecycle, and handles stdio communication between Claude Code and the containerized server.
How It Works
Normal Flow (No Isolation)
# User configures:
command: "uvx"
args: ["mcp-server-sqlite", "--db-path", "/path/to/db"]
# MCPProxy runs directly:
uvx mcp-server-sqlite --db-path /path/to/db
With Docker Isolation Enabled
# User configures same as above
# MCPProxy detects runtime (uvx → Python) and wraps in Docker:
docker run -i --rm \
--memory="512m" \
--cpus="1.0" \
--network=bridge \
python:3.11 \
uvx mcp-server-sqlite --db-path /path/to/db
MCPProxy automatically:
- Detects the runtime from the command (uvx→Python, npx→Node.js)
- Selects appropriate Docker image
- Wraps command in
docker runwith resource limits - Tracks container lifecycle
- Cleans up container on exit
Configuration
Global Docker Isolation Settings
Located in ~/.mcpproxy/mcp_config.json:
{
"docker_isolation": {
"enabled": true, // Master switch
"memory_limit": "512m", // Per-container memory limit
"cpu_limit": "1.0", // CPU cores (1.0 = 1 core)
"timeout": "30s", // Container startup timeout
"network_mode": "bridge", // Docker network mode
"default_images": {
"uvx": "python:3.11", // Image for uvx commands
"npx": "node:20", // Image for npx commands
"python": "python:3.11", // Image for python commands
"node": "node:20" // Image for node commands
}
}
}
Per-Server Isolation Override
You can override isolation settings for specific servers:
{
"name": "my-server",
"command": "uvx",
"args": ["mcp-server-name"],
"isolation": {
"enabled": false, // Disable isolation for this server
// OR customize settings:
"enabled": true,
"image": "python:3.12-slim", // Custom image
"memory_limit": "1g", // More memory
"cpu_limit": "2.0", // More CPU
"network_mode": "none", // No network access
"working_dir": "/workspace" // Working directory in container
}
}
Checking Docker Isolation Status
Is Isolation Enabled for a Server?
# Check server log for isolation setup
grep -i "docker isolation enabled\|docker isolation setup" \
~/Library/Logs/mcpproxy/server-SERVER_NAME.log | tail -5
# Look for:
# "Docker isolation enabled for server: SERVER_NAME"
# "Docker isolation setup successful"
View the Docker Command Being Used
# See actual docker run command
grep "docker_run_args" ~/Library/Logs/mcpproxy/main.log | tail -3
# Example output:
# docker_run_args: ["run", "-i", "--rm", "--memory=512m", "--cpus=1.0",
# "--network=bridge", "python:3.11", "uvx", "mcp-server-name"]
List Running Containers
# List all MCPProxy containers
docker ps | grep mcpproxy
# Check specific server container
docker ps | grep mcpproxy-SERVER_NAME
# Check container health
docker inspect --format='{{.State.Status}}' CONTAINER_ID
View Container Logs
# If container is running
docker logs CONTAINER_NAME
# If container exited, find it in history
docker ps -a | grep mcpproxy-SERVER_NAME
docker logs CONTAINER_ID
Common Docker Isolation Issues
Issue 1: Docker-in-Docker (Most Common)
Symptom: "the input device is not a TTY" error for Docker-based servers
Root cause: MCPProxy's Docker isolation wraps a Docker command in Docker, creating nested containers.
// Server config uses Docker directly
{
"command": "docker",
"args": ["run", "-i", "--rm", "mcp-image:latest"]
}
// MCPProxy wraps it in another Docker (if isolation enabled):
docker run ... python:3.11 docker run -i --rm mcp-image:latest
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This fails: Docker-in-Docker
Solution: Explicitly disable isolation for Docker-based servers:
{
"name": "docker-server",
"command": "docker",
"args": ["run", "-i", "--rm", "mcp-image:latest"],
"isolation": {
"enabled": false // CRITICAL: Always disable for Docker commands
}
}
Why explicit is better: MCPProxy should auto-detect Docker commands and skip isolation, but explicit configuration is more reliable and prevents edge cases.
Issue 2: File Access Problems
Symptom: Server can't access local files, permission errors
Root cause: Container can't access host filesystem by default.
Solution 1: Disable isolation (if file access is required):
{
"isolation": {
"enabled": false
}
}
Solution 2: Mount volumes (more secure):
{
"isolation": {
"enabled": true,
"volumes": [
"/host/path:/container/path:ro" // Read-only mount
]
}
}
Note: Volume mounting requires MCPProxy support. Check documentation for current status.
Issue 3: Network Access Blocked
Symptom: Server can't make API calls, network timeouts
Root cause: Container network mode blocks external access.
Check current network mode:
grep "network_mode" ~/.mcpproxy/mcp_config.json
Solution: Change network mode:
{
"isolation": {
"enabled": true,
"network_mode": "bridge" // Default, allows external access
// OR
"network_mode": "host" // Full host network access
// OR
"network_mode": "none" // No network (most secure)
}
}
Issue 4: Container Image Not Found
Symptom: "context deadline exceeded", stderr shows "pull" or "not found"
Investigation:
# Check stderr for pull errors
grep -i "pull\|not found" ~/Library/Logs/mcpproxy/server-SERVER_NAME.log
# Try pulling image manually
docker pull python:3.11
Solution: Ensure Docker image exists locally or can be pulled:
# Pull image before starting mcpproxy
docker pull python:3.11
# Or specify a custom image that exists
{
"isolation": {
"image": "python:3.12-slim" // Different image
}
}
Issue 5: Resource Limits Too Low
Symptom: Container exits unexpectedly, out of memory errors
Investigation:
# Check container exit status
docker ps -a | grep mcpproxy-SERVER_NAME
# Look for OOMKilled status
docker inspect CONTAINER_ID | grep -i "oom"
Solution: Increase resource limits:
{
"isolation": {
"enabled": true,
"memory_limit": "2g", // Increase from default 512m
"cpu_limit": "2.0" // Increase from default 1.0
}
}
Docker Context Support (Colima)
MCPProxy uses your system's default Docker context. For Colima users:
# Check current Docker context
docker context show
# List all contexts
docker context ls
# Example output:
# NAME DESCRIPTION DOCKER ENDPOINT
# default Current DOCKER_HOST based configuration unix:///var/run/docker.sock
# colima * colima unix:///Users/.../.colima/docker.sock
# MCPProxy uses whichever has the asterisk (*)
To change context:
docker context use colima
docker context use default
After changing context: Restart mcpproxy for changes to take effect.
Disabling Docker Isolation
Globally (All Servers)
Edit ~/.mcpproxy/mcp_config.json:
{
"docker_isolation": {
"enabled": false // Disables for all servers
}
}
Per-Server (Recommended)
Only disable for servers that need it:
{
"name": "special-server",
"command": "docker", // Or any command that needs no isolation
"args": ["..."],
"isolation": {
"enabled": false // Only this server runs without isolation
}
}
Best practice: Keep isolation enabled globally, disable per-server only when necessary.
Debugging Workflow for Docker Isolation Issues
Use this systematic workflow:
Step 1: Verify Isolation Status
# Is isolation enabled for this server?
grep -i "docker isolation" ~/Library/Logs/mcpproxy/server-SERVER_NAME.log | tail -5
Step 2: Check Container Status
# Is container running?
docker ps | grep mcpproxy-SERVER_NAME
# Did container exit?
docker ps -a | grep mcpproxy-SERVER_NAME
Step 3: View Container Logs
# Get container ID
CONTAINER_ID=$(docker ps -a | grep mcpproxy-SERVER_NAME | awk '{print $1}')
# View logs
docker logs $CONTAINER_ID
Step 4: Check Docker Command
# See exact command being used
grep "docker_run_args" ~/Library/Logs/mcpproxy/main.log | tail -3
Step 5: Test Manually
# Extract docker run command from logs and test it manually
# Example:
docker run -i --rm --memory=512m --cpus=1.0 python:3.11 uvx mcp-server-name
Step 6: Apply Fix
Based on the issue:
- Docker-in-Docker → Disable isolation
- File access → Disable isolation or mount volumes
- Network issues → Change network_mode
- Resource limits → Increase memory/CPU
- Image not found → Pull image or change image
Step 7: Reload and Verify
# Trigger config reload
touch ~/.mcpproxy/mcp_config.json
# Or restart
pkill mcpproxy && open /Applications/mcpproxy.app
# Verify fix
curl -s "http://127.0.0.1:8080/api/v1/servers?apikey=YOUR_KEY" | \
python3 -m json.tool | grep -A 10 '"name": "SERVER_NAME"'
When to Use Docker Isolation
✅ Use Docker Isolation When:
- Running untrusted third-party MCP servers
- Need security boundaries between servers
- Want resource limits per server
- Servers don't need host filesystem access
- Servers don't need special network configurations
❌ Disable Docker Isolation When:
- Server needs to access local files
- Server command is already Docker (prevents Docker-in-Docker)
- Server needs host network access
- Troubleshooting connection issues
- Performance is critical (isolation adds overhead)
Quick Reference
Check if isolation is active
grep -i "docker isolation" ~/Library/Logs/mcpproxy/server-NAME.log | tail -5
List containers
docker ps | grep mcpproxy
View container logs
docker logs CONTAINER_NAME
Disable isolation for server
{"isolation": {"enabled": false}}
Increase resources
{"isolation": {"memory_limit": "2g", "cpu_limit": "2.0"}}
Change network mode
{"isolation": {"network_mode": "host"}}
Use custom image
{"isolation": {"image": "python:3.12-slim"}}
Summary
Docker isolation provides security but adds complexity. Start with isolation disabled while getting servers working, then enable it once everything is stable. Always disable isolation explicitly for Docker-based servers to prevent Docker-in-Docker issues.