Skip to main content
Glama

mcpdockery

An MCP server that gives an LLM (Claude, etc.) direct, natural-language control over your local Docker daemon — containers, images, volumes, networks, and Compose stacks.

Built with FastMCP and the Docker SDK for Python.

Table of contents

Related MCP server: portainer-mcp-server

Requirements

Requirement

Notes

Python >= 3.14

Interpreter version pinned in .python-version

Docker

Docker Desktop or Docker Engine, running locally

Docker Compose v2 CLI

docker compose must be available on PATH — required for the stack/compose tools

Trivy

trivy must be available on PATH — required for the scan_image and scan_dockerfile tools

Hadolint

hadolint must be available on PATH — required for the lint_dockerfile tool

uv

Used for dependency management and running the server

For pulling from or pushing to a private registry (Docker Hub, AWS ECR, GCR, etc.), authenticate with that registry beforehand using your normal docker login flow — this server never accepts or stores credentials itself.

Installation

  1. Clone the repository:

    git clone <this-repo>
    cd mcpdockery
  2. Install dependencies:

    uv sync

    This creates a .venv and installs the exact dependency versions pinned in uv.lock.

  3. Confirm Docker is running:

    docker info

    If this command fails, start Docker Desktop (or your Docker Engine) before continuing.

Running the server

uv run src/main.py

The server communicates over stdio, so it's meant to be launched by an MCP client rather than run standalone in a terminal.

Connecting to an MCP client

Add an entry to your MCP client's configuration (e.g. claude_desktop_config.json for Claude Desktop, or your project's .mcp.json for Claude Code):

{
  "mcpServers": {
    "mcpdockery": {
      "command": "uv",
      "args": ["--directory", "/absolute/path/to/mcpdockery", "run", "src/main.py"]
    }
  }
}

Replace /absolute/path/to/mcpdockery with the actual path where you cloned the repository, then restart the client. The tools listed below will become available to the model.

Available tools

Containers (containers.py)

Tool

Description

run_container

Runs a container from an image, mapping a container port to a host port

stop_container

Stops a running container

container_start

Starts a stopped container

container_restart

Restarts a container

delete_container

Force-removes a container (stops it first if needed). Destructive — requires confirm=True; the first call only previews what would be deleted

list_containers

Lists all containers and their status

container_logs

Fetches the last N log lines from a container. Secret-shaped values (passwords, tokens, API keys) are redacted

container_stats

Reports live CPU % and memory usage

container_inspect

Shows env vars, mounts, network IPs, and health status. Secret-shaped env values are redacted

container_exec

Executes a shell command inside a running container. Secret-shaped values in the output are redacted

Images (images.py)

Tool

Description

list_images

Lists all local images, including untagged/intermediate ones, with size

pull_image

Pulls an image from a registry without running it; defaults to the alpine tag unless a different tag is requested

build_image

Builds an image from a Dockerfile already on disk

push_image

Tags and pushes a local image to a registry (requires prior docker login)

delete_image

Force-removes a local image. Destructive — requires confirm=True; the first call only previews what would be deleted

Volumes (volumes.py)

Tool

Description

list_volumes

Lists volumes with driver and mountpoint

create_volume

Creates a new volume

remove_volume

Deletes a volume (fails if still in use). Destructive — requires confirm=True; the first call only previews what would be deleted

Networks (networks.py)

Tool

Description

list_networks

Lists networks with driver and scope

create_network

Creates a new network

Optimization (optimization.py)

Tool

Description

analyze_multistage

Detects whether a Dockerfile would benefit from a multi-stage build (build-tool commands in a single-stage image); returns reasoning + raw content for the model to draft the rewrite

Diagnostics (diagnostics.py)

Tool

Description

docker_doctor

Scans all containers and reports only the ones needing attention: OOM kills, restart loops, unhealthy checks, crashes, high CPU/memory

check_exposed_ports

Flags running containers with sensitive ports (databases, admin panels, Docker daemon API) or any port bound to all network interfaces

Security (security.py)

Tool

Description

scan_image

Scans an image for known vulnerabilities using Trivy; defaults to CRITICAL/HIGH severity only

generate_sbom

Generates a Software Bill of Materials (SBOM) for an image using Trivy, in CycloneDX or SPDX-JSON format

scan_dockerfile

Scans a Dockerfile for misconfigurations (root user, latest tag, hardcoded secrets, missing HEALTHCHECK, etc.) before it's even built

lint_dockerfile

Lints a Dockerfile with Hadolint for best-practice/style issues (unpinned versions, ADD vs COPY, missing --no-install-recommends, etc.)

audit_dockerfile

Combined report: scan_dockerfile + lint_dockerfile + raw file content, so the model can also draft a corrected Dockerfile — use for a general "check my Dockerfile" request

Compose stacks (stacks.py)

Tool

Description

deploy_stack

Deploys a stack from an inline docker-compose.yml (compose up -d)

stop_stack

Stops a stack's containers without removing them

remove_stack

Stops and removes a stack, including its volumes (compose down -v). Destructive — requires confirm=True; the first call only previews what would be removed

list_stacks

Lists all compose projects, including stopped ones

stack_status

Shows the status of a stack's containers (compose ps)

stack_logs

Collects logs from every container in a stack

Usage examples

Once connected, you can drive the server with natural-language requests. A few examples of what to expect:

You ask

Tool(s) the model will likely use

"Pull the alpine version of redis"

pull_image

"Run an nginx container on port 8080"

run_container

"Show me the logs for my-app from the last hour"

container_logs

"What's using all the CPU right now?"

list_containers, container_stats

"Is anything broken right now?"

docker_doctor

"Is anything exposed to the network that shouldn't be?"

check_exposed_ports

"Deploy this docker-compose file as 'staging'"

deploy_stack

"Push my-app:latest to my ECR repo"

push_image

"Clean up the my-app container and its image"

delete_container, delete_image

"Scan my-app:latest for vulnerabilities"

scan_image

"Generate an SBOM for my-app:latest"

generate_sbom

"Check my Dockerfile for security issues before I build it"

scan_dockerfile

"Lint my Dockerfile for best practices"

lint_dockerfile

"Check/review my Dockerfile"

audit_dockerfile

"Should this Dockerfile use multi-stage builds?"

analyze_multistage

The model chooses which tool(s) to call based on your request — you don't need to name the tool yourself.

Project structure

src/
  main.py             # Entrypoint: registers tool modules and starts the MCP server
  server.py           # Shared FastMCP server instance
  docker_client.py    # Lazy singleton Docker SDK client
  compose_client.py   # Thin wrapper around the `docker compose` CLI
  helper.py           # Shared helpers (path normalization, image tag parsing, Trivy wrapper)
  containers.py       # Container lifecycle & inspection tools
  images.py           # Image pull/build/push/list/delete tools
  volumes.py          # Volume tools
  networks.py         # Network tools
  stacks.py           # Compose stack tools
  security.py         # Image/Dockerfile vulnerability & misconfiguration scanning tools
  diagnostics.py      # Cross-container health triage tools
  optimization.py     # Dockerfile efficiency analysis tools

Safety notes

This server gives the model real, unsandboxed control over your Docker daemon:

  • delete_container, delete_image, remove_volume, and remove_stack are destructive and require an explicit confirm=True argument. The first call (confirm defaults to False) performs no action and only returns a preview of what would be deleted — the model is instructed to only pass confirm=True after you've explicitly agreed in the conversation. This is a safety net against a misread request, not a hard permission system: any client with tool access can still pass confirm=True directly.

  • remove_stack deletes volumes (-v), which is destructive and irreversible for stateful data.

  • container_exec runs arbitrary shell commands inside a container.

  • container_logs, container_exec, and container_inspect redact values that look like secrets (keys matching PASSWORD/TOKEN/API_KEY/etc., in KEY=value, KEY: value, or "key": "value" form) before returning them. This is a best-effort heuristic, not a guarantee — anything that doesn't match the pattern (or that a container prints in an unusual format) is returned as-is, and remember that tool output is sent to the model provider as part of the conversation regardless of how "local" the Docker daemon is.

  • push_image and pull_image use your existing local Docker credentials — the model can push to or pull from any registry you're currently authenticated with. Note that AWS ECR tokens expire after 12 hours; if a push/pull suddenly fails with an auth error, re-run your docker login / aws ecr get-login-password flow rather than assuming the tool is broken.

  • The Docker socket grants root-equivalent access to the host. Giving a model tool access to this server is equivalent to giving it that level of access to your machine, whether or not the daemon is reachable over the network.

Only connect this server to clients/agents you trust, and be deliberate about which containers and stacks you let it touch.

License

No license specified.

Available Tools

34 tools
analyze_multistageA

Analyzes a Dockerfile and reports whether it would benefit from a multi-stage build. Detects build-tool commands (npm install/build, mvn, gradle, go build, cargo build, pip install with compilers, dotnet build/publish, make/cmake/gcc) combined with a single-stage FROM, which usually means build tools and dev dependencies end up shipped in the final image unnecessarily — increasing image size and attack surface.

This tool only analyzes and returns reasoning plus the raw Dockerfile content — it does NOT generate the rewritten Dockerfile itself. If it reports multi-stage as recommended, use the returned content and detected build system to draft a multi-stage version yourself: a "builder" stage that runs the build commands, and a slim runtime stage that only COPYs the compiled artifact from the builder stage.

Args: dockerfile_path: full path to an existing Dockerfile on this machine. Accepts either a Windows path ("C:\path\Dockerfile") or a Git Bash style path ("/c/path/Dockerfile").

Inputs: dockerfile_path (required). Returns: result

audit_dockerfileA

Runs a full pre-build Dockerfile audit: Trivy's security misconfiguration scan plus Hadolint's best-practice/style lint, combined into one report, plus the raw Dockerfile content. Use this for a general "check/review/audit my Dockerfile" request when the user hasn't specified security vs. style specifically. For a narrower, single-tool check, use scan_dockerfile (security only) or lint_dockerfile (style only) instead — those return findings only, not the raw content, so they're cheaper when a rewrite isn't needed. Requires both trivy (https://trivy.dev) and hadolint (https://github.com/hadolint/hadolint) installed and on PATH.

Args: dockerfile_path: full path to an existing Dockerfile on this machine. Accepts either a Windows path ("C:\path\Dockerfile") or a Git Bash style path ("/c/path/Dockerfile"). severity: comma-separated Trivy severities to include (default "CRITICAL,HIGH")

Inputs: dockerfile_path (required), severity. Returns: result

build_imageA

Builds a Docker image from a Dockerfile already saved on disk. The build context is the folder containing the Dockerfile, so COPY/ADD of other files in that same folder works normally. Accepts either a Windows path ("C:\path\Dockerfile") or a Git Bash style path ("/c/path/Dockerfile"). Args: image_tag: tag to give the built image, e.g. "my-app:latest" dockerfile_path: full path to an existing Dockerfile on this machine

Inputs: image_tag (required), dockerfile_path (required). Returns: result

check_exposed_portsA

Scans all running containers' published port bindings and flags anything worth a second look: known database/admin-panel ports (Postgres, MySQL, Redis, MongoDB, Elasticsearch, the Docker daemon API, etc.) and any port bound to 0.0.0.0/all interfaces rather than localhost. Meant to catch services that ended up reachable from the network when they were only meant for local access. Does not distinguish trusted vs. untrusted networks — a flagged binding may be fine on an isolated host, so review findings in context.

Inputs: no named parameters. Returns: result

container_execA

Executes a shell command inside a running container and returns its output. Values that look like secrets (PASSWORD=, "token": "...", etc.) are redacted before being returned. Args: container_name: Docker Container name command: shell command to run inside the container, e.g. "ls -la /app"

Inputs: command (required), container_name (required). Returns: result

container_inspectB

Returns detailed information about a container: environment variables, mounts, network IP, and health status. Env var values that look like secrets (PASSWORD, TOKEN, API_KEY, etc.) are redacted. Args: container_name: Docker Container name

Inputs: container_name (required). Returns: result

container_logsA

Collect and display the logs for a container. Values that look like secrets (PASSWORD=, "token": "...", etc.) are redacted before being returned. Args: container_name: Container name to collect logs tail: Number of log lines to return (default 200)

Inputs: container_name (required), tail. Returns: result

container_restartD

Restarting a container Args: container_name: name to restart the container

Inputs: container_name (required). Returns: result

container_startC

Starting a container Args: container_name: name to start the container

Inputs: container_name (required). Returns: result

container_statsA

Shows live CPU and memory usage for a running container. Args: container_name: Docker Container name

Inputs: container_name (required). Returns: result

create_networkA

Creates a new Docker network. Args: network_name: name to give the new network driver: network driver to use, e.g. "bridge" (default), "overlay" (swarm), "macvlan"

Inputs: network_name (required), driver. Returns: result

create_volumeC

Creates a new Docker volume. Args: volume_name: name to give the new volume driver: volume driver to use (default "local")

Inputs: volume_name (required), driver. Returns: result

delete_containerA

Delete a container by its name. Stops it first if it's still running. Destructive and irreversible. The first call (confirm=False, the default) does NOT delete anything — it only previews what would happen. Only pass confirm=True after the user has explicitly agreed to the deletion. Args: container_name: Container name that should be deleted confirm: must be True to actually perform the deletion (default False)

Inputs: container_name (required), confirm. Returns: result

delete_imageA

Delete a Docker image by tag or ID. Removed even if still referenced by a stopped container (force). Destructive and irreversible. The first call (confirm=False, the default) does NOT delete anything — it only previews what would happen. Only pass confirm=True after the user has explicitly agreed to the deletion. Args: image_name: image name to be deleted confirm: must be True to actually perform the deletion (default False)

Inputs: image_name (required), confirm. Returns: result

deploy_stackA

Deploys a multi-container application from a docker-compose YAML definition. Args: project_name: unique name for this stack, used to group/manage its containers compose_yaml: full contents of a docker-compose.yml describing the services

Inputs: compose_yaml (required), project_name (required). Returns: result

docker_doctorA

Scans every container and reports only the ones that need attention: OOM kills, restart loops, unhealthy health checks, crashed containers, or high CPU/memory usage. Returns a clean-bill-of-health message if nothing is flagged — use this instead of checking containers one by one.

Args: cpu_threshold: CPU %% above which a running container is flagged (default 80.0) mem_threshold: memory %% of its limit above which a container is flagged (default 80.0)

Inputs: cpu_threshold, mem_threshold. Returns: result

generate_sbomA

Generates a Software Bill of Materials (SBOM) for a Docker image using Trivy — a full inventory of every OS package and language dependency the image contains. Useful for supply-chain compliance, license audits, and tracking exposure when a new CVE is disclosed (search the SBOM instead of re-scanning). Requires the trivy CLI installed and on PATH (https://trivy.dev).

Args: image: image to generate an SBOM for, e.g. "nginx:latest" or "my-app:v1" format: SBOM format, "cyclonedx" (default) or "spdx-json"

Inputs: image (required), format. Returns: result

lint_dockerfileA

Lints a Dockerfile with Hadolint for best-practice and style issues — unpinned package/base image versions, missing --no-install-recommends, use of ADD instead of COPY, sudo usage, missing WORKDIR before relative paths, and similar. Complements scan_dockerfile (Trivy), which focuses on security misconfigurations rather than style/best-practice rules. Requires the hadolint CLI installed and on PATH (https://github.com/hadolint/hadolint).

Args: dockerfile_path: full path to an existing Dockerfile on this machine. Accepts either a Windows path ("C:\path\Dockerfile") or a Git Bash style path ("/c/path/Dockerfile").

Inputs: dockerfile_path (required). Returns: result

list_containersB

Returns all containers with their status

Inputs: no named parameters. Returns: result

list_imagesA

Lists all local Docker images, including untagged/intermediate ones. Each line shows: short ID, tags, and size in MB.

Inputs: no named parameters. Returns: result

list_networksA

Lists all Docker networks with their driver and scope

Inputs: no named parameters. Returns: result

list_stacksA

Lists all compose projects, including stopped ones

Inputs: no named parameters. Returns: result

list_volumesA

Lists all Docker volumes with their driver and mountpoint

Inputs: no named parameters. Returns: result

pull_imageA

Pulls a Docker image from a registry (Docker Hub, ECR, GCR, etc.) without running it. Requires prior docker login if the registry needs auth — this tool does not accept credentials.

Defaults to the "alpine" tag (smaller, faster to pull) when no tag is specified. Only pass a different tag (e.g. "latest" or a specific version) if the user explicitly asks for the full/standard image — not every image publishes an "alpine" variant, in which case the pull will fail and you should retry with "latest".

Args: image: repository name, e.g. "nginx" or "myregistry.com:5000/my-app". Can include a tag directly (e.g. "nginx:1.27"), in which case the tag argument is ignored. tag: tag to pull if not already included in image (default "alpine") platform: optional, e.g. "linux/amd64" or "linux/arm64" — force a specific architecture on multi-arch images

Inputs: image (required), tag, platform. Returns: result

push_imageA

Tags a local Docker image with a registry repository name and pushes it (e.g. Docker Hub, AWS ECR). Requires that you have already run docker login locally — this tool does not accept credentials. Args: local_image: the image currently on your machine, e.g. "my-app:latest" repository: full destination repository name, e.g. "myusername/my-app" or "123456789012.dkr.ecr.eu-west-1.amazonaws.com/my-app" image_tag: tag to push, e.g. "latest" or "v1.0"

Inputs: repository (required), local_image (required), image_tag. Returns: result

remove_stackA

Stops and permanently removes a compose stack: containers, networks, and volumes (data is deleted). The first call (confirm=False, the default) does NOT remove anything — it only previews what would happen. Only pass confirm=True after the user has explicitly agreed to the removal. Args: project_name: unique name for this stack, used to group/manage its containers confirm: must be True to actually perform the removal (default False)

Inputs: project_name (required), confirm. Returns: result

remove_volumeA

Deletes a Docker volume by name. Data stored in it is permanently lost. Fails if the volume is currently in use by a container. The first call (confirm=False, the default) does NOT delete anything — it only previews what would happen. Only pass confirm=True after the user has explicitly agreed to the deletion. Args: volume_name: name of the volume to remove confirm: must be True to actually perform the deletion (default False)

Inputs: volume_name (required), confirm. Returns: result

run_containerA

Runs a Docker container locally for testing Args: image: Docker image to run, e.g. "nginx:latest" If no tag is specified, then usel alpine for default.It is smaller and faster to pull container_name: container name container_port: port the app listens on INSIDE the container, e.g. "80" for nginx host_port: port on your machine to access it, e.g. "8080" → http://localhost:8080

Inputs: image (required), host_port (required), container_name (required), container_port (required). Returns: result

scan_dockerfileA

Scans a Dockerfile for security misconfigurations using Trivy's config scanner — BEFORE the image is even built. Flags things like: missing USER directive (container would run as root), use of the "latest" tag, hardcoded secrets in ENV/ARG, missing HEALTHCHECK, and use of ADD instead of COPY. Requires the trivy CLI installed and on PATH (https://trivy.dev).

Args: dockerfile_path: full path to an existing Dockerfile on this machine. Accepts either a Windows path ("C:\path\Dockerfile") or a Git Bash style path ("/c/path/Dockerfile"). severity: comma-separated severities to include (default "CRITICAL,HIGH")

Inputs: dockerfile_path (required), severity. Returns: result

scan_imageA

Scans a Docker image for known vulnerabilities using Trivy. Requires the trivy CLI installed and on PATH (https://trivy.dev). The first scan on a fresh machine downloads Trivy's vulnerability database, which can take a moment.

Defaults to showing only CRITICAL and HIGH severity findings to keep the output compact. Widen it by passing e.g. severity="CRITICAL,HIGH,MEDIUM,LOW".

Args: image: image to scan, e.g. "nginx:latest" or "my-app:v1" severity: comma-separated severities to include (default "CRITICAL,HIGH")

Inputs: image (required), severity. Returns: result

stack_logsA

Collects logs from all containers in a compose stack. Args: project_name: unique name for this stack, used to group/manage its containers tail: number of log lines to return per container (default 200)

Inputs: project_name (required), tail. Returns: result

stack_statusA

Shows the status of all containers in a compose stack (like docker compose ps). Args: project_name: unique name for this stack, used to group/manage its containers

Inputs: project_name (required). Returns: result

stop_containerC

User will pass the container name that we need to stop Args: container_name: Docker Container name

Inputs: container_name (required). Returns: result

stop_stackA

Stops all containers in a compose stack without removing them, so it can be started again later. Args: project_name: unique name for this stack, used to group/manage its containers

Inputs: project_name (required). Returns: result

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    B3.1/5.0

    Scored across 34 tools

    Disambiguation4/5

    Most tools have clear, distinct purposes (e.g., container_logs vs. container_stats vs. docker_doctor), but a few overlap in intent (scan_dockerfile vs. lint_dockerfile vs. audit_dockerfile) and could confuse an agent if descriptions are not read carefully.

    Naming Consistency2/5

    Naming is inconsistent: some tools use object_verb (container_logs, container_restart), others use verb_object (stop_container, delete_container), and some have no clear pattern (docker_doctor, generate_sbom). This makes it harder to predict tool names.

    Tool Count3/5

    With 34 tools, the server is heavy for a typical MCP, but it covers a broad Docker domain comprehensively. Each tool has a distinct function, so the count is justified, though it exceeds the typical 3-15 range.

    Completeness5/5

    The toolset covers all major Docker operations: container lifecycle, image management, Dockerfile analysis, volumes, networks, and health/security checks. No obvious gaps for common Docker workflows.

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      D
      maintenance
      An MCP server that allows managing Docker containers through natural language, enabling users to compose, introspect, and debug containers without running commands themselves.
      3,908 PyPI
      753
      GPL 3.0
    • A
      license
      B
      quality
      D
      maintenance
      MCP server for Portainer REST API that enables AI assistants to manage Docker containers, stacks, images, networks, and volumes through natural language.
      18
      40 npm
      MIT
    • F
      license
      B
      quality
      D
      maintenance
      An MCP server that gives LLMs direct control over a local Docker daemon, enabling container, image, volume, network, and Compose stack management through natural language.
      23
      4
      -
    • A
      license
      B
      quality
      D
      maintenance
      MCP server for managing Docker containers, images, and Compose services via natural language, with configurable tool permissions and safety annotations.
      16
      MIT