# 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) ```bash # 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 ```bash # 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:** 1. Detects the runtime from the command (uvx→Python, npx→Node.js) 2. Selects appropriate Docker image 3. Wraps command in `docker run` with resource limits 4. Tracks container lifecycle 5. Cleans up container on exit ## Configuration ### Global Docker Isolation Settings Located in `~/.mcpproxy/mcp_config.json`: ```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: ```json { "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? ```bash # 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 ```bash # 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 ```bash # 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 ```bash # 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. ```json // 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: ```json { "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): ```json { "isolation": { "enabled": false } } ``` **Solution 2: Mount volumes** (more secure): ```json { "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:** ```bash grep "network_mode" ~/.mcpproxy/mcp_config.json ``` **Solution:** Change network mode: ```json { "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:** ```bash # 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: ```bash # 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:** ```bash # 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: ```json { "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: ```bash # 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:** ```bash 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`: ```json { "docker_isolation": { "enabled": false // Disables for all servers } } ``` ### Per-Server (Recommended) Only disable for servers that need it: ```json { "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 ```bash # Is isolation enabled for this server? grep -i "docker isolation" ~/Library/Logs/mcpproxy/server-SERVER_NAME.log | tail -5 ``` ### Step 2: Check Container Status ```bash # Is container running? docker ps | grep mcpproxy-SERVER_NAME # Did container exit? docker ps -a | grep mcpproxy-SERVER_NAME ``` ### Step 3: View Container Logs ```bash # 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 ```bash # See exact command being used grep "docker_run_args" ~/Library/Logs/mcpproxy/main.log | tail -3 ``` ### Step 5: Test Manually ```bash # 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 ```bash # 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 ```bash grep -i "docker isolation" ~/Library/Logs/mcpproxy/server-NAME.log | tail -5 ``` ### List containers ```bash docker ps | grep mcpproxy ``` ### View container logs ```bash docker logs CONTAINER_NAME ``` ### Disable isolation for server ```json {"isolation": {"enabled": false}} ``` ### Increase resources ```json {"isolation": {"memory_limit": "2g", "cpu_limit": "2.0"}} ``` ### Change network mode ```json {"isolation": {"network_mode": "host"}} ``` ### Use custom image ```json {"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.