Skip to content
DevOps & ContainerizationJune 2026 · 9 min read

Docker MCP Server Deployment: Containerizing AI Tools with Security

Learn how to package, sandbox, and execute Model Context Protocol servers inside hardened Docker containers across Claude Desktop, Cursor IDE, and cloud clusters.

1. Why Containerize Model Context Protocol Servers?

As developers configure increasing numbers of MCP servers across their workstations—spanning different Node.js engines, Python virtualenvs, and native system libraries—dependency conflicts and security concerns inevitably arise.

Deploying MCP servers with Docker delivers three major operational advantages:

  • Zero Host Pollution: Run complex Python 3.12 or Node.js 20 servers without installing runtimes, compilers, or global package managers on your local machine.
  • Workstation Sandbox Isolation: Prevent untrusted open-source tool scripts from inspecting private SSH keys, browsing local directories, or tampering with host settings.
  • Team Reproducibility: Package tool dependencies into immutable OCI container images that run identically across macOS, Linux, and Windows WSL2 environments.

2. Critical Stdio Mechanics: Why `-i` and `--rm` Are Mandatory

The most common pitfall when running Dockerized MCP servers is omitting the interactive flag. In standard Model Context Protocol communication over stdio, the host client communicates with the server through stdin and stdout streams.

When executing docker run:

  • -i (--interactive): Keeps stdin open even if unattached. Without this, Docker closes the input stream immediately, causing the MCP handshake to abort with “Stdio pipe closed”.
  • --rm: Automatically removes the container when it exits, preventing hundreds of dangling stopped containers from accumulating on your workstation.
  • DO NOT use -t (--tty): Allocating a pseudo-TTY corrupts JSON-RPC 2.0 framing by injecting ANSI escape codes and newline translation into the binary stream.

3. Production Dockerfile Examples

Here are production-ready, security-hardened Dockerfiles for both Node.js and Python MCP server stacks:

Node.js TypeScript Server

Node 20 Alpine
FROM node:20-alpine AS runner
WORKDIR /app

# Drop root privileges
USER node

# Run official package directly
ENTRYPOINT ["npx", "-y", "@modelcontextprotocol/server-github"]

Python Fast Server

Python 3.12 uv
FROM ghcr.io/astral-sh/uv:python3.12-alpine
WORKDIR /app

RUN adduser -D mcpuser
USER mcpuser

ENTRYPOINT ["uvx", "mcp-server-sqlite"]

4. Claude Desktop & Cursor Client Configurations

To configure Claude Desktop or Cursor to execute your Dockerized MCP servers, structure your JSON configuration as follows:

{
  "mcpServers": {
    "docker-github": {
      "command": "docker",
      "args": [
        "run",
        "-i",
        "--rm",
        "-e",
        "GITHUB_PERSONAL_ACCESS_TOKEN",
        "mcp/github-server:latest"
      ],
      "env": {
        "GITHUB_PERSONAL_ACCESS_TOKEN": "ghp_yourTokenHere"
      }
    },
    "docker-postgres": {
      "command": "docker",
      "args": [
        "run",
        "-i",
        "--rm",
        "-e",
        "DATABASE_URL",
        "mcp/postgres-server:latest"
      ],
      "env": {
        "DATABASE_URL": "postgresql://postgres:<password>@host.docker.internal:5432/analytics"
      }
    }
  }
}

5. Multi-Container Orchestration with Docker Compose (SSE Mode)

When hosting multiple MCP servers for an entire engineering team or deploying to a cloud VM, configure a multi-service Docker Compose file using Server-Sent Events (SSE) transports:

version: "3.8"

services:
  mcp-github:
    image: mcp/github-server:latest
    environment:
      - GITHUB_PERSONAL_ACCESS_TOKEN=${GITHUB_TOKEN}
    ports:
      - "3001:3000"
    restart: unless-stopped

  mcp-stripe:
    image: mcp/stripe-server:latest
    environment:
      - STRIPE_SECRET_KEY=${STRIPE_SECRET_KEY}
    ports:
      - "3002:3000"
    restart: unless-stopped

6. Host Networking & DNS Resolution Across Operating Systems

When a containerized MCP server needs to query a database or API running on the host workstation:

  • macOS and Windows (Docker Desktop): Use the special DNS name host.docker.internal in connection strings (e.g. postgresql://user:<password>@host.docker.internal:5432/db).
  • Linux Native Docker: Pass --add-host=host.docker.internal:host-gateway in the Docker args array to enable identical DNS mapping.
  • WSL2 Windows Subsystem for Linux: Ensure Docker Desktop integration is enabled in Settings → Resources → WSL Integration.

7. Volume Mount Security & Read-Only Sandboxes

When mounting project source code into filesystem or git MCP servers, always append the :ro read-only modifier to the volume parameter. This guarantees that code analysis agents cannot inadvertently delete, overwrite, or corrupt repository source files during automated reasoning passes.

8. Container Health Checks & Automatic Recovery

In production team environments or daemonized background services, declare a Docker healthcheck to monitor MCP server responsiveness and restart unresponsive containers:

Add HEALTHCHECK --interval=30s --timeout=5s CMD ps aux | grep node || exit 1 to your Dockerfile to ensure continuous liveness.

Discover Pre-Built MCP Server Images

Browse our directory of verified MCP server configurations with pre-tested Docker run commands: