·

What Is Docker MCP

Learn what Docker MCP is and how it lets your AI agent manage containers, images, and logs.

Docker MCP is the umbrella term for Model Context Protocol servers that expose the Docker Engine API — images, containers, networks, volumes, and Compose stacks — as structured tools an AI coding agent can call directly. Instead of you typing docker ps, copying the output into a chat window, and describing what went wrong, the agent calls a tool, gets back structured JSON, and reasons over it in the same turn it decides what to do next.

The landscape isn't a single vendor like Sentry or GitHub. Several implementations exist: mcp-server-docker (Python, installed via uv/uvx, maintained by ckreiling) wraps the Docker SDK for Python directly against the socket; docker-mcp (Node/Python variants from different maintainers) offers a narrower tool set focused on container lifecycle and Compose; and Docker itself ships an MCP Toolkit inside Docker Desktop (4.40+) that runs curated MCP servers — including a first-party Docker server — behind a local gateway process (docker mcp gateway run) with secret injection and tool-call logging built in. This topic treats "Docker MCP" as the category and calls out where a specific implementation's behavior diverges.

What they share is the underlying transport: every one of these servers eventually talks to the Docker daemon over the same Unix socket (or named pipe on Windows) that the docker CLI itself uses. That single fact — a socket, not a scoped API — is the thread running through this entire topic, and it's why the setup and security sections below matter more here than in most other MCP integrations you'll connect.


Core Docker MCP Tools: Images, Containers, Logs, Exec, and Compose

Regardless of which server you run, the tool catalog clusters into five families that map onto the Docker CLI verbs you already know.

Imageslist_images, pull_image, build_image, inspect_image, remove_image. build_image takes a build context path and Dockerfile path and streams back the build log line by line (or a final success/failure summary, depending on implementation), which is what lets an agent diagnose a failed layer without you pasting terminal output.

Containerslist_containers, create_container, start_container, stop_container, restart_container, remove_container, inspect_container. inspect_container is the workhorse: it returns the same payload as docker inspect, including State (status, exit code, OOMKilled, started/finished timestamps), Config (env vars, entrypoint, cmd, exposed ports), NetworkSettings (IP, gateway, connected networks), and Mounts.

Logsfetch_container_logs, usually parameterized by tail (last N lines) and sometimes since/until timestamps. Few implementations support live streaming inside a single tool call; most return a snapshot, so an agent debugging a slow-starting service will call this tool repeatedly rather than "tail -f" style.

Execexec_in_container, the equivalent of docker exec. It runs a command inside a running container's namespace and returns stdout, stderr, and exit code. This is the single most powerful — and most dangerous — tool in the catalog, because the command runs with whatever privileges the container's process has, and if that container has host mounts, the agent's "debug command" can read or write host files.

Composecompose_up, compose_down, compose_ps, compose_logs, and sometimes compose_build. These shell out to (or reimplement) docker compose against a given docker-compose.yml/compose.yaml file, letting the agent bring a multi-service stack up or down without you leaving the chat.

// Typical MCP client config entry — shape is consistent across Claude Code, Cursor, etc.
{
  "mcpServers": {
    "docker": {
      "command": "uvx",
      "args": ["mcp-server-docker"]
    }
  }
}
uvx mcp-server-docker --help

Tips
- Tool names vary by implementation — always run the server's --help or ask the agent to "list your available tools" before writing prompts that assume a specific tool exists.
- inspect_container output is large. If you only need one field, ask the agent to extract it ("just tell me the exit code and OOMKilled flag") rather than dumping the full JSON into the conversation.
- Treat exec_in_container as equivalent to giving the agent a shell inside that container — because that's exactly what it is.


Docker MCP Setup: Socket Access, Contexts, and Permission Model

Every Docker MCP server needs a path to the Docker daemon's API. On Linux that's almost always the Unix socket at /var/run/docker.sock; on Docker Desktop for macOS it's ~/.docker/run/docker.sock (a symlink is often placed at the standard path too); on Windows it's the named pipe \\.\pipe\docker_engine. Whichever process runs the MCP server needs read/write access to that socket — there is no finer-grained permission inside the Docker Engine API itself. You either have full daemon access or none.

ls -l /var/run/docker.sock

sudo usermod -aG docker $USER

Being in the docker group is functionally equivalent to root on that host — the daemon runs as root and will happily execute anything a group member asks, including mounting the host filesystem into a new container. Keep that in mind before you casually add a service account to docker just to unblock an MCP connection.

Docker contexts. If you manage more than one Docker daemon — local dev, a staging VM, a CI runner — Docker contexts decide which one any given command (and any given MCP server) talks to.

docker context ls

docker context use staging

The MCP server inherits whatever context (or explicit DOCKER_HOST environment variable) is active in the process that launches it. This is a genuinely useful safety lever: point a "production incident" session at a read-mostly staging context by default, and only switch to a production-capable context deliberately, in its own session, so you never have an agent one ambiguous prompt away from restarting a production container.

// Pin the MCP server to a specific Docker host explicitly, instead of relying on ambient context
{
  "mcpServers": {
    "docker-staging": {
      "command": "uvx",
      "args": ["mcp-server-docker"],
      "env": { "DOCKER_HOST": "ssh://deploy@staging.internal" }
    }
  }
}

Remote daemons over SSH or TLS. DOCKER_HOST=ssh://user@host uses your existing SSH key and agent forwarding — no extra daemon config needed, but it does mean the MCP server can execute anything your SSH key is authorized to do on that box. DOCKER_HOST=tcp://host:2376 with DOCKER_TLS_VERIFY=1 and DOCKER_CERT_PATH set is the alternative for daemons exposed over TCP; never point an MCP server (or anything else) at an unencrypted tcp:// endpoint on 2375 — that port has no authentication at all.

Tips
- Run docker context show at the start of any AI-assisted Docker session and have the agent confirm it before executing anything destructive — it's a cheap guard against acting on the wrong host.
- Never expose the Docker daemon on TCP port 2375 (unencrypted) to run an MCP server against it, even "just for local testing" — anything on the network segment gets root.
- If you're on Docker Desktop, docker context ls usually shows a desktop-linux context in addition to default — verify which one your MCP client actually inherited if commands seem to hit the wrong engine.


What AI Can Automate with Docker MCP: Builds, Debugging, and Cleanup

With the tool catalog connected, the practical value splits into three buckets that come up constantly in day-to-day development.

Build diagnosis and iteration. Ask the agent to build an image, and when a layer fails, it reads the exact error line from the build log, cross-references it against the Dockerfile it can also read from your working tree, and proposes a fix — then rebuilds and confirms the fix worked, all without you re-running docker build by hand each time.

Build the image from ./Dockerfile with tag myapp:dev. If the build fails,
show me the failing layer's exact command and error, then propose a fix
and rebuild.

Runtime debugging. A container that crash-loops, an environment variable that isn't reaching the process, a network two containers can't reach each other over — the agent can chain inspect_container, fetch_container_logs, and exec_in_container to build a timeline of what happened without you manually running three separate commands and mentally correlating timestamps.

Container "api" keeps restarting. Inspect its state and restart count,
fetch the last 100 log lines, and tell me the most likely root cause.

Cleanup and hygiene. Dangling images, stopped containers, unused volumes, and orphaned build cache accumulate fast in an active dev environment. An agent with list_images/remove_image access can audit disk usage and propose (or, if you allow it, execute) a cleanup pass — something that's tedious enough manually that most developers just let docker system df grow until it's a problem.

List all images not used by any running container, tell me the total
reclaimable disk space, and remove the ones older than 30 days.

The common thread: Docker MCP turns "describe the symptom, wait for a human to run commands, paste output back" into a single conversational loop. The agent does the mechanical data-gathering; you supply judgment on anything with real consequences — which is exactly where the security section below draws the line.

Tips
- For build loops, ask the agent to summarize each failed attempt in one line before it retries — long build-fix-rebuild chains otherwise bury the actual root cause under repeated log output.
- Cleanup prompts should always ask for a dry-run list first ("show me what you would remove") before granting permission to actually delete anything — image and volume deletion is not undoable.
- Combine Docker MCP with filesystem access in the same agent session so it can read the Dockerfile/compose file it's debugging, not just the running container state.


Security Risks of Giving an Agent Docker Socket Access

This is the section to actually read carefully, not skim. Mounting or exposing the Docker socket to any process — human tool, MCP server, or otherwise — is widely understood in the container security community as equivalent to giving that process root on the host. The reasoning is short: a process with socket access can ask the daemon to start a new container with --privileged, or with -v /:/host mounting the entire host filesystem, or with --pid=host joining the host's process namespace. The daemon does not ask whether the caller "should" be allowed to do that — daemon access is all-or-nothing.

docker run -it --rm -v /:/host --privileged alpine chroot /host sh

An AI agent with Docker MCP connected is that process. It has no innate concept of "this action is more dangerous than that one" beyond what your prompts and any client-side permission gates tell it. A model that's confidently wrong about a fix — or one nudged by a prompt-injection payload sitting in a log line or a file it read — can call exec_in_container or create_container with the same blast radius as a human with a root shell.

Concrete mitigations, roughly in order of effectiveness:

  • Run the MCP server rootless where possible. Rootless Docker (dockerd-rootless.sh) confines the daemon itself to the invoking user's namespace, so even full socket access doesn't translate directly to host root — though it's not a complete guarantee, and some container escapes still apply.
  • Use a socket proxy that filters the API surface. Tools like docker-socket-proxy sit between the client and the real socket and allow you to expose only specific endpoints (e.g., GET /containers/json and GET /containers/{id}/logs, but not POST /containers/create), turning "all or nothing" into something closer to real least-privilege.
  • Prefer Docker's own MCP Toolkit gateway over a raw stdio server for anything beyond local solo dev. The gateway process can log every tool call and gate specific tools behind explicit approval, giving you an audit trail and a chokepoint you don't get from a bare uvx mcp-server-docker process talking straight to the socket.
  • Scope by context, not by hope. Point agent sessions at a disposable or staging Docker context by default (see the setup section above), and require a separate, deliberate action to switch to a context that can touch production.
  • Keep your AI client's tool-approval prompts on for exec_in_container, remove_image, remove_container, and anything under Compose's down. Auto-approving read tools (list_containers, fetch_container_logs) while requiring a manual click for mutating or destructive ones is a reasonable default posture for most teams.
docker run -d --name docker-proxy \
  -e CONTAINERS=1 -e IMAGES=1 -e POST=0 \
  -v /var/run/docker.sock:/var/run/docker.sock:ro \
  -p 127.0.0.1:2375:2375 \
  tecnativa/docker-socket-proxy

None of this makes Docker MCP unsafe to use — plenty of teams run it productively every day — but it does mean the decision to connect it deserves the same scrutiny you'd give to handing someone SSH access to a production box, not the scrutiny you'd give a read-only API key.

Tips
- Never run a Docker MCP server against your primary workstation's default context if that machine also has other people's credentials, SSH keys, or unrelated production access cached on it.
- Ask new team members to read this section before they connect Docker MCP for the first time — "it's just a container tool" is the exact framing that leads to skipping the socket-access conversation entirely.
- If your organization has a security review process for new tool integrations, route Docker MCP through it explicitly rather than treating it as a routine dev-tooling install.


Tips

Tips
- Before connecting any Docker MCP server, run docker context show and confirm exactly which daemon it will control — this single check prevents the majority of "the agent touched the wrong environment" incidents.
- Start with a socket proxy or Docker's gateway rather than raw socket access if more than one person on your team will use the integration — retrofitting an audit trail after an incident is much harder than having one from day one.
- Keep destructive tools (remove_image, remove_container, exec_in_container, compose down) behind manual approval in your AI client even after you trust the read-only tools completely.