โ† Back to articles

Docker MCP Gateway vs Claude Desktop Native MCP

Path: Computer Tech/AI/ML/OpenCode/Docker MCP Gateway vs Claude Desktop Native MCP.mdUpdated: 2/3/2026

Docker MCP Gateway vs Claude Desktop Native MCP

Overview

When building custom MCP (Model Context Protocol) servers, you have two deployment approaches: Docker MCP Gateway (containerized) or Claude Desktop native (direct process). This article explains the tradeoffs between speed, security, isolation, and management complexity.

What Are These Approaches?

Docker MCP Gateway

  • Architecture: MCP servers run in Docker containers, managed by Docker's MCP gateway
  • Configuration: Servers defined in ~/.docker/mcp/catalogs/*.yaml and enabled in ~/.docker/mcp/config.yaml
  • Process model: Gateway runs as single process, spawns containers on-demand
  • Tool namespace: Tools prefixed with MCP_DOCKER_servername_toolname

Claude Desktop Native

  • Architecture: MCP servers run as direct child processes of Claude Desktop/OpenCode
  • Configuration: Servers defined in ~/Library/Application Support/Claude/claude_desktop_config.json (Claude Desktop) or ~/.config/opencode/opencode.json (OpenCode)
  • Process model: Each server is a separate stdio process
  • Tool namespace: Tools prefixed with servername_toolname

Comparison Matrix

DimensionDocker GatewayNative ApproachWinner
Speed~50-100ms overhead for container startup/communication~5-10ms process spawn + stdioNative
SecurityFull process isolation, network policies, secrets blockingOS-level process isolation onlyDocker
Resource limitsConfigurable CPU/memory limits per serverNo built-in limitsDocker
Auto-restartGateway manages lifecycle, auto-restarts on crashClient restarts on next tool callDocker
Tool reloadRequires gateway restart or MCP management toolsRequires client restartTie
Network isolationCan block external network access (--block-network)Full network accessDocker
Development iterationMust rebuild/restart gateway for code changesImmediate - just edit TypeScript/Python filesNative
Multi-client accessCan run gateway on TCP port, serve multiple clientsSingle client only (stdio)Docker
DebuggingContainer logs + gateway logs (more complex)Direct stderr logs (simpler)Native
DeploymentCatalog-based, versioned, shareable configsManual JSON config per machineDocker

Speed Analysis

Docker Gateway Overhead

Sources of latency:

  1. Container spawn: 30-50ms (if not long-lived)
  2. Gateway routing: 10-20ms (JSON-RPC over TCP/stdio bridge)
  3. Network stack: 5-10ms (even localhost)
  4. Total: ~50-100ms per tool call

Mitigation:

  • Use --long-lived flag to keep containers running
  • Reduces overhead to ~10-20ms after initial spawn

Native Approach

Sources of latency:

  1. Process spawn: 5-10ms (first call only, then keeps stdio open)
  2. JSON-RPC over stdio: 1-2ms
  3. Total: ~5-10ms first call, <2ms subsequent calls

Real-world impact:

  • For interactive workflows (article creation, search), 50-100ms is imperceptible
  • For batch operations (100+ tool calls), Docker adds ~5-10 seconds overhead
  • For latency-sensitive workflows (real-time code generation), native wins

Security & Isolation

Docker Gateway Advantages

  1. Process isolation: Each server in separate container namespace
  2. Network policies: Can block internet access, allow only localhost
  3. Secrets blocking: Gateway can filter secrets from being sent to tools (--block-secrets)
  4. Resource limits: Prevent runaway servers from consuming all CPU/memory
  5. Read-only filesystem: Can mount code as read-only

Use case: Third-party MCP servers from untrusted sources

Native Approach Risks

  1. Full filesystem access: Server can read/write any file the client can
  2. Full network access: Can make arbitrary HTTP requests
  3. No resource limits: Buggy server can freeze your machine
  4. Process escape: Malicious server could spawn additional processes

Use case: First-party servers you fully control and trust

Development Workflow

Docker Gateway Iteration

bash
# Edit server code
vim ~/.config/mcp-servers/myserver/index.ts

# Rebuild catalog (if structure changed)
docker mcp gateway run --dry-run  # Validate config

# Restart gateway to reload
pkill -f "docker.*mcp.*gateway"
# OpenCode will auto-restart gateway on next tool call

# Or use restart tool (if implemented)
myserver_restart_mcp_server()

Pain points:

  • Gateway restart required for code changes
  • Container builds add complexity for non-Docker users
  • Harder to debug with container layers

Native Approach Iteration

bash
# Edit server code
vim ~/.config/mcp-servers/myserver/index.ts

# Changes live immediately (TypeScript interpreted by Bun)
# Server restarts automatically on next tool call

Pain points:

  • Must manually manage dependencies (npm/bun install)
  • No isolation if server crashes or has memory leaks

When to Use Each Approach

Use Docker Gateway When:

  • Security matters: Third-party servers or untrusted code
  • Resource limits needed: Servers that might consume excessive CPU/memory
  • Multi-client access: Want to share MCP server across machines (TCP mode)
  • Production deployment: Need versioning, rollback, health checks
  • Team environments: Shareable catalog configs across developers

Use Native Approach When:

  • Rapid development: Building/testing your own MCP servers
  • Performance critical: Batch operations or low-latency requirements
  • Simple setup: Single developer, local-only usage
  • Full system access needed: Server needs to interact with local dev environment
  • Debugging: Need direct stderr logs without container complexity

Hybrid Approach (Recommended)

Development: Native approach for your own servers

json
{
  "mcp": {
    "myserver": {
      "type": "local",
      "command": ["bun", "run", "/path/to/server/index.ts"]
    }
  }
}

Production: Docker gateway for all servers

yaml
# ~/.docker/mcp/catalogs/personal.yaml
registry:
  myserver:
    description: My custom MCP server
    command: ["bun", "run", "/path/to/server/index.ts"]
    tools:
      - name: my_tool
yaml
# ~/.docker/mcp/config.yaml
myserver: {}

Migration path:

  1. Develop with native approach (fast iteration)
  2. Add to Docker catalog once stable
  3. Test with --long-lived flag to measure overhead
  4. Switch OpenCode config to use gateway only
  5. Remove native config entry

Real-World Example: The Sly Professor Migration

We recently migrated the theslyprofessor MCP server from native to Docker gateway:

Before (Native):

json
{
  "mcp": {
    "theslyprofessor": {
      "type": "local",
      "command": ["bun", "run", "/Users/ntiruviluamala/.config/mcp-servers/theslyprofessor/index.ts"],
      "enabled": true
    }
  }
}

After (Docker Gateway):

yaml
# ~/.docker/mcp/catalogs/personal.yaml
name: personal
displayName: Personal MCP Servers
registry:
  theslyprofessor:
    title: The Sly Professor
    description: Personal productivity MCP server with ARF routing, vault management, chezmoi integration, and email workflow
    version: "2.0.0"
    command:
      - "bun"
      - "run"
      - "/Users/ntiruviluamala/.config/mcp-servers/theslyprofessor/index.ts"
    tools:
      - name: find_context
      - name: refresh_arf_catalog
      # ... 17 total tools
yaml
# ~/.docker/mcp/config.yaml
theslyprofessor: {}
json
// ~/.config/opencode/opencode.json
{
  "mcp": {
    "MCP_DOCKER": {
      "type": "local",
      "command": ["docker", "mcp", "gateway", "run"],
      "enabled": true
    }
  }
}

Why we migrated:

  • Better lifecycle management: Gateway auto-restarts on crashes
  • Centralized catalog: Easier to share configs across machines (chezmoi managed)
  • Tool reload mechanism: Added restart_mcp_server tool for seamless updates
  • Future-proofing: Easier to migrate to TCP mode for remote access

Tradeoffs accepted:

  • ~50ms overhead per tool call (imperceptible for our use cases)
  • Slightly more complex debugging (container logs)
  • Gateway restart required for code changes (mitigated by restart_mcp_server tool)

Recommendations

For individual developers building personal tools: โ†’ Start native, migrate to Docker gateway once stable

For teams sharing MCP infrastructure: โ†’ Docker gateway from day one (use catalog versioning)

For AI coding assistants (OpenCode, Claude Desktop): โ†’ Native for first-party tools, Docker gateway for third-party

For latency-sensitive applications (real-time code generation): โ†’ Native approach, use --long-lived Docker if security needed

For untrusted third-party servers: โ†’ Docker gateway always, enable --block-network and --block-secrets

Future Considerations

Docker Desktop evolution:

  • Docker may improve container startup performance (็›ฎๅ‰ ~50ms)
  • Gateway may add hot-reload for code changes
  • TCP mode may become default for better multi-client support

MCP protocol evolution:

  • Protocol may add built-in tool reload notifications
  • May support WebSocket transport for lower latency
  • May add resource limit hints in protocol itself

Tooling improvements:

  • Better debugging tools for containerized MCP servers
  • Catalog validation and testing frameworks
  • Performance profiling for tool call latency

Conclusion

Neither approach is universally better - the choice depends on your priorities:

  • Speed: Native wins (~5-10ms vs ~50-100ms)
  • Security: Docker wins (full isolation vs process-only)
  • Development: Native wins (live reload vs gateway restart)
  • Production: Docker wins (lifecycle management, versioning)

Most developers should start with native for rapid development, then migrate to Docker gateway once their server is stable and they want better lifecycle management and security isolation.

The key insight: Docker's 50ms overhead is negligible for interactive AI workflows, while the security and management benefits are substantial for production deployments.