Dev Tools·
advanced
·15 min read·Apr 4, 2026·Updated Oct 10, 2026
By Rad Tome·Lead AI Systems Architect·How we verify this

Docker MCP Server Configuration Guide

Manage Docker containers, images, and volumes through your AI agent using the Docker MCP server. Build, run, and monitor containers with natural language.

dockercontainersdevopsinfrastructuredeploymentmcpdocker-socketcloud-tools
Config Target: claude_desktop_config.json
{
  "mcpServers": {
    "docker": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-server-docker"
      ]
    }
  }
}
Interactive Tool
1-Click Export

Generate & Test Docker MCP Server Config

One-click export with environment variables & path locators for Claude Desktop, Cursor, Windsurf, and OpenAI Codex CLI.

Open in Generator

Docker MCP Server Configuration Guide

Container virtualization has become the universal runtime standard for backend microservices, ephemeral integration test suites, and reproducible developer environments. When engineering teams debug service failures or test microservice architectures, developers repeatedly switch between their code editors and terminal consoles to run docker ps, tail log files from crash-looping containers, and prune orphaned volumes.

By integrating the Docker engine directly into the Model Context Protocol (MCP), developers can provide AI assistants in Claude Desktop, Cursor, or OpenAI Codex CLI with structured, programmatic control over local container lifecycles. An agent can inspect container health metrics, diagnose exit codes, summarize recent standard output logs, and spin up isolated test dependencies.

However, connecting an autonomous reasoning model to the Docker engine introduces severe security risks. Access to the Docker daemon socket is equivalent to root privileges on the host system. Operating a Docker MCP server safely requires socket proxies, unprivileged API scoping, and log tail budgeting.

This guide provides an end-to-end architectural manual, multi-host configurations, a complete production TypeScript MCP server, and security hardening procedures for managing Docker through the Model Context Protocol.


1. System Architecture: Daemon Communication and Socket Isolation

The Docker MCP server runs as a local child process that bridges JSON-RPC tool calls from the AI host into Docker REST API calls across local communication channels:

diagram

Host Privilege Boundary

Direct Socket

Guarded Proxy

AI Agent: tools/call list_containers

Docker MCP Server Process

Socket Security Proxy Active?

Direct /var/run/docker.sock: Full Root Equivalent

docker-socket-proxy: Read-Only Scoped

Docker Engine Daemon

Container Stats and Logs Stream

Communication Channels Across Operating Systems

  1. ▸Linux and macOS UNIX Domain Socket: Communication flows over /var/run/docker.sock. Because the socket owner is root, unprivileged users must be assigned to the docker user group.
  2. ▸Windows Named Pipe: Communication flows over the Windows named pipe //./pipe/docker_engine. When configuring client environments on Windows, path formatting must account for pipe naming conventions.
  3. ▸The Root Access Hazard: Because a client with unrestricted Docker socket access can spawn a privileged container mounting the host filesystem (-v /:/host), production implementations should insert an intermediary socket filter proxy (such as tecnativa/docker-socket-proxy) to block arbitrary container creation.

2. Environment Prerequisites and Software Matrix

Verify that your workstation satisfies the following software requirements:

ComponentMinimum VersionInstallation VerificationPurpose
Docker Engine>= 24.0.0docker --versionContainer runtime engine
Docker Desktop>= 4.25.0Check GUI or versionDesktop daemon provider for macOS/Windows
Node.js>= 20.0.0node -vServer runtime environment
dockerode>= 3.3.5Package manifestOfficial Docker REST API client for Node.js
@modelcontextprotocol/sdk>= 1.2.0Package manifestCore Model Context Protocol framework

Ensure the Docker daemon is running before launching the server:

bash
docker info

3. Multi-Host Configuration Snippets

Configure your MCP clients to launch the Docker server over standard input and output (stdio).

Claude Desktop Configuration (claude_desktop_config.json)

On macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
On Windows: %APPDATA%\Claude\claude_desktop_config.json

json
{
  "mcpServers": {
    "docker": {
      "command": "node",
      "args": ["/opt/mcp-servers/docker/dist/index.js"],
      "env": {
        "DOCKER_SOCKET_PATH": "/var/run/docker.sock",
        "MAX_LOG_TAIL_LINES": "100"
      }
    }
  }
}

Cursor IDE Configuration (.cursor/mcp.json)

json
{
  "mcpServers": {
    "docker": {
      "command": "node",
      "args": ["./dist/index.js"]
    }
  }
}

OpenAI Codex CLI Configuration (~/.codex/config.toml)

toml
[mcp_servers.docker]
command = "node"
args = ["/opt/mcp-servers/docker/dist/index.js"]

[mcp_servers.docker.env]
DOCKER_SOCKET_PATH = "/var/run/docker.sock"
MAX_LOG_TAIL_LINES = "100"

4. Production TypeScript Docker MCP Server Implementation

The following implementation provides three foundational diagnostic tools: list_containers, get_container_logs, and get_container_stats. Save this as src/index.ts:

typescript
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
import Docker from 'dockerode';

const isWindows = process.platform === 'win32';
const socketPath = process.env.DOCKER_SOCKET_PATH || (isWindows ? '//./pipe/docker_engine' : '/var/run/docker.sock');

const docker = new Docker({ socketPath });

const server = new Server(
  { name: 'docker-mcp-server', version: '1.0.0' },
  { capabilities: { tools: {} } }
);

server.setRequestHandler(ListToolsRequestSchema, async () => {
  return {
    tools: [
      {
        name: 'list_containers',
        description: 'List active and stopped Docker containers with their status, image, and exposed ports.',
        inputSchema: {
          type: 'object',
          properties: {
            all: { type: 'boolean', default: false, description: 'Include stopped containers' }
          }
        }
      },
      {
        name: 'get_container_logs',
        description: 'Retrieve the most recent stdout and stderr logs from a container.',
        inputSchema: {
          type: 'object',
          properties: {
            container_id: { type: 'string', description: 'Container ID or name' },
            tail_lines: { type: 'number', default: 50, maximum: 100, description: 'Number of lines to tail' }
          },
          required: ['container_id']
        }
      },
      {
        name: 'get_container_stats',
        description: 'Retrieve a snapshot of container CPU and memory usage statistics.',
        inputSchema: {
          type: 'object',
          properties: {
            container_id: { type: 'string', description: 'Container ID or name' }
          },
          required: ['container_id']
        }
      }
    ]
  };
});

server.setRequestHandler(CallToolRequestSchema, async (request) => {
  const { name, arguments: args } = request.params;

  try {
    if (name === 'list_containers') {
      const showAll = Boolean(args?.all);
      const containers = await docker.listContainers({ all: showAll });

      const simplified = containers.map(c => ({
        id: c.Id.slice(0, 12),
        names: c.Names,
        image: c.Image,
        state: c.State,
        status: c.Status,
        ports: c.Ports.map(p => `${p.PublicPort || ''}:${p.PrivatePort}`).filter(Boolean)
      }));

      return {
        content: [{ type: 'text', text: JSON.stringify(simplified, null, 2) }]
      };
    }

    if (name === 'get_container_logs') {
      const containerId = args?.container_id as string;
      const tail = Math.min(Number(args?.tail_lines) || 50, 100);

      const container = docker.getContainer(containerId);
      const logsBuffer = await container.logs({
        stdout: true,
        stderr: true,
        tail: tail,
        timestamps: true
      });

      // Strip Docker multiplexed stream headers
      const cleanLogs = logsBuffer.toString('utf8').replace(/[\x00-\x09\x0B-\x1F]/g, '');

      return {
        content: [{ type: 'text', text: cleanLogs }]
      };
    }

    if (name === 'get_container_stats') {
      const containerId = args?.container_id as string;
      const container = docker.getContainer(containerId);
      const stats = await container.stats({ stream: false });

      const memoryUsageMB = (stats.memory_stats.usage / (1024 * 1024)).toFixed(2);
      const memoryLimitMB = (stats.memory_stats.limit / (1024 * 1024)).toFixed(2);

      const result = {
        container_id: containerId,
        memory_usage_mb: memoryUsageMB,
        memory_limit_mb: memoryLimitMB,
        pids: stats.pids_stats.current || 0
      };

      return {
        content: [{ type: 'text', text: JSON.stringify(result, null, 2) }]
      };
    }

    throw new Error(`Tool '${name}' is not recognized.`);
  } catch (err: any) {
    return {
      isError: true,
      content: [{ type: 'text', text: `Docker API Error: ${err.message}` }]
    };
  }
});

async function main() {
  const transport = new StdioServerTransport();
  await server.connect(transport);
}

main().catch((err) => {
  process.stderr.write(`Fatal server error: ${err.message}\n`);
  process.exit(1);
});

5. JSON-RPC 2.0 Wire Payloads

Inspecting the underlying protocol frames helps confirm clean JSON-RPC messaging across host and client.

Tool Invocation Request (tools/call)

json
{
  "jsonrpc": "2.0",
  "id": "docker-list-01",
  "method": "tools/call",
  "params": {
    "name": "list_containers",
    "arguments": {
      "all": false
    }
  }
}

Result Payload

json
{
  "jsonrpc": "2.0",
  "id": "docker-list-01",
  "result": {
    "content": [
      {
        "type": "text",
        "text": "[\n  {\"id\": \"e4a19b88c2f1\", \"names\": [\"/redis-cache\"], \"image\": \"redis:7-alpine\", \"state\": \"running\", \"status\": \"Up 3 hours\"}\n]"
      }
    ]
  }
}

6. Common Errors and Production Troubleshooting

When operating the Docker MCP server on developer workstations, monitor for the following standard issues:

Error: connect EACCES /var/run/docker.sock

  • ▸Root Cause: The user executing the AI host application lacks read/write permissions to the Docker socket.
  • ▸Resolution: On Linux, add your local user to the docker group: sudo usermod -aG docker $USER. Log out and log back in to apply group membership.

Error: connect ENOENT /var/run/docker.sock

  • ▸Root Cause: The Docker daemon is stopped, or Docker Desktop has not enabled the default system socket symlink.
  • ▸Resolution: In Docker Desktop Settings, navigate to Advanced and enable Allow the default Docker socket to be used.

Error: Windows Named Pipe Connection Failure

  • ▸Root Cause: The MCP server defaulted to the Linux socket path /var/run/docker.sock on a Windows operating system.
  • ▸Resolution: Set DOCKER_SOCKET_PATH="//./pipe/docker_engine" in your client environment configuration.

7. External Citations and Security Guardrails

Running Docker tools through generative models requires defense-in-depth security safeguards:

Technical Changelog

Weekly Protocol Diffs & Verified Drops

New server guides, benchmarks, and security audits. No spam. Unsubscribe anytime.

Zero marketing spam. 1-click unsubscribe anytime.

Ready to Deploy?

Build your full agent toolstack in the Visual Generator

Combine Docker with databases, search APIs, and memory graphs in a single configuration file.

Customize in Generator
Developer Verification & Feedback
0 reports

Did this setup guide work with your AI host?

Help test this configuration across Claude, Cursor, and Codex CLI. Be the first to report:

Docker MCP Server Configuration Guide FAQ

What is the Docker MCP Server Configuration Guide?

Manage Docker containers, images, and volumes through your AI agent using the Docker MCP server. Build, run, and monitor containers with natural language.

How do I configure Docker MCP Server Configuration Guide in Claude Desktop or Cursor?

You can copy the configuration JSON from our guide or launch the interactive MCP Codex Config Generator at https://mcp-codex.com/generator to export valid configs in 1 click.

Can I use Docker MCP Server Configuration Guide with the OpenAI Codex CLI?

Yes, OpenAI Codex CLI supports Model Context Protocol. You can add it directly to ~/.codex/config.toml or pass arguments to codex mcp add.

RT

Written by Rad Tome

Lead AI Systems Architect & Maintainer, MCP Codex

@RadTome

Specializing in Model Context Protocol (MCP) integrations, autonomous AI agent orchestration, and distributed developer toolchains. Researches and benchmarks production MCP client-server architectures across OpenAI Codex, Claude, and Cursor.

Editorial Integrity: Package names are checked against the npm registry and repositories against the GitHub API. Where a package could not be verified, the guide says so instead of giving you a command to run.

Related Guides