# Docker MCP Server (oci · ghcr.io/gavinlucas/docker-mcp-server:2.1.1)

Manage Docker (containers, images, Compose, Swarm, registries) via the Docker SDK and CLI.

- Trust score: 33/100 (low)
- Change this week: +2
- Registry status: deprecated
- Liveness: live
- Owner verified: no
- Last scored: 2026-08-03

> **Deprecated**: this server is marked deprecated in the MCP registry.

## Components

- mcpb · `docker-mcp-server-2.1.1.mcpb`: 8/100, [markdown](https://verifymcp.io/servers/gavinlucas-docker-mcp-server/https-github-com-gavinlucas-docker-mcp-releases-download-v2-1-1-docker-mcp-serve.md), [page](https://verifymcp.io/servers/gavinlucas-docker-mcp-server/https-github-com-gavinlucas-docker-mcp-releases-download-v2-1-1-docker-mcp-serve)
- oci · `ghcr.io/gavinlucas/docker-mcp-server:2.1.1`: 33/100 (this document), [markdown](https://verifymcp.io/servers/gavinlucas-docker-mcp-server/ghcr-io-gavinlucas-docker-mcp-server-2-1-1.md), [page](https://verifymcp.io/servers/gavinlucas-docker-mcp-server/ghcr-io-gavinlucas-docker-mcp-server-2-1-1)
- pypi · `docker-mcp-server`: 5/100, [markdown](https://verifymcp.io/servers/gavinlucas-docker-mcp-server/docker-mcp-server.md), [page](https://verifymcp.io/servers/gavinlucas-docker-mcp-server/docker-mcp-server)

## Channel facts

- Registry: `oci`
- Package: `ghcr.io/gavinlucas/docker-mcp-server:2.1.1`
- Transport: `stdio`

## Trust breakdown

How this component scores in each security and reliability category. Every signal is checked automatically from public evidence about the published package, including repeated runs of it in an isolated sandbox, and we only credit what we can confirm. Scores are 0–100 per category. Scoring method: https://verifymcp.io/docs/scoring (what has changed: https://verifymcp.io/docs/scoring/changelog)

Scored 2026-08-03.

- **Supply Chain Security**: 0/100
  - Malware scan not yet available for this package.
  - CVE data not yet available for this package.
  - Install-script risk not yet assessed.
  - Dependency-health data not yet available.
- **Provenance & Transparency**: 6/100
  - Repository check failed: the declared repository URL redirects; it must resolve directly.
  - Provenance check failed: no build-provenance attestation is published.
  - License check failed: no license is declared.
  - Actively maintained (last published 25 days ago).
  - Disclosure check failed: no security disclosure policy was found in the source repository.
- **Schema Quality & AI Usability**: 77/100
  - 100% of prompts and resources have a non-trivial description (not blank, and not just the item's name).
  - AI-judged instruction clarity (excellent).
  - Context-footprint check failed: tool/resource definitions use about 29203 tokens (~180/item across 162 items; 156 tools + 6 resources), over budget; trim descriptions and params.
  - Usage-examples check failed: none of the tools include examples.
- **Stability & Change Management**: 27/100
  - Stability observed for 8 of 30 days with no destabilising changes; credit accrues until the full window elapses.
- **Tool Coverage**: 71/100
  - 100% of tools have a non-trivial description (not blank, and not just the tool's name).
  - 0% of tool parameters carry a description.
  - Structured output schemas are declared (23% of tools); any adoption earns full credit.
- **Capabilities**: 100/100
  - Implements a supported MCP spec version (2025-11-25); the latest is 2026-07-28.

**Unverified: 1 category.** A category scored 0 because we could not verify it: a data source with nothing on this package, evidence we could not reach, or a check we could not run. We only credit what we can confirm.

## Install

### Claude

```bash
claude mcp add gavinlucas-docker-mcp-server -- docker run --rm -i ghcr.io/gavinlucas/docker-mcp-server:2.1.1
```

### Codex

```bash
codex mcp add gavinlucas-docker-mcp-server -- docker run --rm -i ghcr.io/gavinlucas/docker-mcp-server:2.1.1
```

### opencode

```json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "gavinlucas-docker-mcp-server": {
      "type": "local",
      "command": [
        "docker",
        "run",
        "--rm",
        "-i",
        "ghcr.io/gavinlucas/docker-mcp-server:2.1.1"
      ],
      "enabled": true
    }
  }
}
```

### Hermes

```yaml
mcp_servers:
  gavinlucas-docker-mcp-server:
    command: "docker"
    args: ["run", "--rm", "-i", "ghcr.io/gavinlucas/docker-mcp-server:2.1.1"]
```

### Other

```json
{
  "mcpServers": {
    "gavinlucas-docker-mcp-server": {
      "command": "docker",
      "args": [
        "run",
        "--rm",
        "-i",
        "ghcr.io/gavinlucas/docker-mcp-server:2.1.1"
      ]
    }
  }
}
```

## Changelog

Every change recorded for this component, newest first. Days that predate change tracking, or that we cannot explain, say so: "we were watching and nothing happened" and "we were not watching" are different claims.

### 2026-08-03 (score 33, +4)

- [functional improvement] Stability: unverified → 0.27

### 2026-07-31 (score 29, −2)

- [functional] We updated how we score, so this day's move reflects our rubric, not a change to the server

### 2026-07-27 (score 31, 0)

- [functional] We updated how we score, so this day's move reflects our rubric, not a change to the server

### 2026-07-26 (score 31)

First indexed and scored.

## MCP tools (156)

### `buildx_build` (~800 tokens)

Build an image with BuildKit via `docker buildx build`.

Replaces the legacy `image_build` tool when you need any of: multi-platform output
(`platforms`), modern cache export (`cache_from`/`cache_to`), SBOM or provenance
attestations, build secrets, or multi-stage builds with `target`. Always runs with
\`--progress=plain` so output is captured rather than redrawn on a TTY.

args:
    context - Build context: a filesystem path or Git/HTTP URL (verbatim; no `~`/glob expansion).
                   The `-` stdin-tarball form is NOT supported (stdin isn't forwarded — it'd block
                   on the server's own stdin); serve a pre-packed tarball over HTTP instead.
    tags - Image references to apply (`-t`, repeatable)
    platforms - Target platforms, e.g. ["linux/amd64", "linux/arm64"]
    file - Dockerfile path (relative to context unless absolute)
    build_args - Build-time variables (each becomes `--build-arg KEY=VALUE`)
    build_contexts - Additional named build contexts (e.g. {"deps": "./vendor"})
    labels - Labels to set on the resulting image (each becomes `--label KEY=VALUE`)
    annotations - OCI manifest annotations (passed verbatim, repeatable)
    target - Target build stage to stop at
    push - Push the result to the registry (mutually exclusive with `load`)
    load - Load the result into the local image store (single-platform builds only)
    output - Custom `--output` specs (e.g. ["type=tar,dest=out.tar"])
    no_cache - Do not use cache when building
    no_cache_filter - Stage names to exclude from caching
    pull - Always attempt to pull a newer version of each base image
    cache_from - Cache import specs, e.g. ["type=registry,ref=user/img:cache"]
    cache_to - Cache export specs
    builder - Override the active builder
    sbom - Shorthand for `--attest=type=sbom`; pass "true" or a config string
    provenance - Shorthand for `--attest=type=provenance`; pass "true", "false", or a config string
    attest - Custom attestation specs (r…

Input parameters:

- `annotations` (array)
- `attest` (array)
- `build_args` (object)
- `build_contexts` (object)
- `builder` (string)
- `cache_from` (array)
- `cache_to` (array)
- `context` (string, required)
- `file` (string)
- `labels` (object)
- `load` (boolean)
- `no_cache` (boolean)
- `no_cache_filter` (array)
- `output` (array)
- `platforms` (array)
- `provenance` (string)
- `pull` (boolean)
- `push` (boolean)
- `sbom` (string)
- `secret` (array)
- `ssh` (array)
- `tags` (array)
- `target` (string)
- `timeout_seconds` (number)

### `buildx_bake` (~260 tokens)

Build multiple targets defined in a bake file (HCL, JSON, or compose).

args:
    targets - Bake targets to build (default: the `default` group)
    files - Bake file paths (`-f`, repeatable)
    set_overrides - Per-target overrides, e.g. ["app.platform=linux/amd64"]
    push - Push results to the registry
    load - Load results into the local image store
    no_cache - Do not use cache when building
    pull - Always pull a newer base image
    builder - Override the active builder
    cwd - Working directory containing the bake file (defaults to the server's cwd)
    timeout_seconds - Subprocess timeout (default 1800s)
returns: dict - {"returncode": int, "stdout": str, "stderr": str, "truncated": bool}

Input parameters:

- `builder` (string)
- `cwd` (string)
- `files` (array)
- `load` (boolean)
- `no_cache` (boolean)
- `pull` (boolean)
- `push` (boolean)
- `set_overrides` (array)
- `targets` (array)
- `timeout_seconds` (number)

### `buildx_imagetools_inspect` (~272 tokens)

Inspect a manifest in a registry without pulling.

Replaces `docker manifest inspect`. The standalone `docker manifest` command is in
maintenance mode and lacks support for OCI image indexes, attestations, and
annotations — `buildx imagetools inspect` is the path forward and handles both
single-platform manifests and multi-platform manifest lists / OCI indexes. Uses the docker
CLI's credential store; `registry_manifest` answers the same question over direct HTTPS
with no daemon or plugin.

args:
    image - Image reference, e.g. "alpine:3.19" or "ghcr.io/org/repo@sha256:..."
    raw - Return the raw manifest bytes (a JSON document) instead of the
                human-rendered tree
    format - Go template format string (mutually exclusive with `raw`)
    builder - Override the active builder
returns: dict - {"returncode": int, "stdout": str, "stderr": str, "truncated": bool}.
                When `raw=True` or `format="{{json .}}"`, `stdout` is a JSON document
                the caller can parse.

Input parameters:

- `builder` (string)
- `format` (string)
- `image` (string, required)
- `raw` (boolean)

### `buildx_imagetools_create` (~266 tokens)

Create a manifest list / OCI image index from existing per-platform tags.

Replaces `docker manifest create` + `docker manifest push` — builds the index and pushes it in
one operation. Source tags must already be pushed; this only stitches them together.

args:
    target - Tag for the new manifest list (`-t`)
    sources - Source image references to combine
    append - Append to the existing manifest at `target` rather than replacing
    dry_run - Print the resulting manifest without pushing
    annotations - OCI annotations (repeatable; passed verbatim)
    platforms - Filter source platforms when combining
    descriptor_files - Files to read source descriptors from, instead of refs
    builder - Override the active builder
    timeout_seconds - Subprocess timeout (default 600s)
returns: dict - {"returncode": int, "stdout": str, "stderr": str, "truncated": bool}

Input parameters:

- `annotations` (array)
- `append` (boolean)
- `builder` (string)
- `descriptor_files` (array)
- `dry_run` (boolean)
- `platforms` (array)
- `sources` (array, required)
- `target` (string, required)
- `timeout_seconds` (number)

### `buildx_list` (~62 tokens)

List builder instances.

returns: list - One dict per builder (parsed from `--format '{{json .}}'`).
                If the captured stdout was truncated by MAX_CLI_OUTPUT_BYTES the
                last (likely partial) record is dropped before parsing.

### `buildx_history_list` (~151 tokens)

List recent build records (BuildKit build history), parsed from `--format '{{json .}}'`.

Each record is a past build with its ref, name, status, step counts, and timestamps — useful for
finding a build to drill into with `buildx_history_inspect`. Requires buildx >= v0.13 (older
versions have no `history` subcommand and this raises with the CLI's "unknown command" error).

args:
    builder - Builder instance to read history from (defaults to the active builder)
returns: list - One dict per build record (ref, name, status, total/completed/cached steps, times)

Input parameters:

- `builder` (string)

### `buildx_history_inspect` (~241 tokens)

Inspect a single build record by ref, parsed from `--format json`.

Returns the full record for one build — duration, materials, attestations, error (if any) — for
debugging a failed or slow build found via `buildx_history_list`. Requires buildx >= v0.13.

args:
    ref - Build record ref. Pass the `ref` field from `buildx_history_list` directly — it
               reports a qualified "<builder>/<node>/<id>", but `history inspect` only accepts the
               bare id, so this reduces it to the id and (unless `builder` is given) targets the
               builder named in the ref. Empty/omitted inspects the most recent build; the `^N`
               syntax (e.g. "^0" = latest) is also valid.
    builder - Builder instance the build ran on (defaults to the one in `ref`, else active)
returns: dict - The parsed build record (or {"raw": <stdout>} if the output isn't a JSON object)

Input parameters:

- `builder` (string)
- `ref` (string)

### `buildx_inspect` (~100 tokens)

Inspect a builder instance.

args:
    name - Builder name (defaults to the active builder)
    bootstrap - Boot the builder if it isn't already running
returns: dict - {"returncode": int, "stdout": str, "stderr": str, "truncated": bool}.
                stdout is human-readable; parse with the agent or call buildx_list for JSON.

Input parameters:

- `bootstrap` (boolean)
- `name` (string)

### `buildx_du` (~128 tokens)

Report BuildKit cache disk usage as a list of records.

A large cache can easily generate more output than MAX_CLI_OUTPUT_BYTES; if that
happens the captured stdout is truncated and this tool drops the final (partial)
record before parsing. For an exhaustive accounting on a busy builder, run
\`docker buildx du --format '{{json .}}'` on the host directly.

args: builder - Override the active builder
returns: list - One dict per cache record (parsed from `--format '{{json .}}'`)

Input parameters:

- `builder` (string)

### `buildx_prune` (~248 tokens)

Remove BuildKit cache entries.

Destructive: this tool always passes `--force` because no interactive prompt is
available under MCP. Pair with `buildx_du` first to inventory what would be removed.

args:
    all - Include internal/frontend images
    filters - Filter by attributes (e.g. {"until": "24h", "type": "exec.cachemount"})
    reserved_space - Amount of disk to always keep (e.g. "10GB")
    max_used_space - Maximum disk space the cache may use (e.g. "20GB")
    min_free_space - Target amount of free disk after pruning (e.g. "5GB")
    builder - Override the active builder
    timeout_seconds - Subprocess timeout (default 600s)
returns: dict - {"returncode": int, "stdout": str, "stderr": str, "truncated": bool}

Input parameters:

- `all` (boolean)
- `builder` (string)
- `filters` (object)
- `max_used_space` (string)
- `min_free_space` (string)
- `reserved_space` (string)
- `timeout_seconds` (number)

### `buildx_create` (~233 tokens)

Create a new builder instance.

args:
    name - Name for the new builder (defaults to a generated name)
    driver - BuildKit driver (e.g. "docker-container", "kubernetes", "remote")
    driver_opts - Driver-specific options (each becomes `--driver-opt KEY=VALUE`)
    use - Set the new builder as the current one
    bootstrap - Boot the builder immediately
    platforms - Platforms the builder advertises
    config - Path to a buildkitd config file
    node_name - Node name within the builder (for multi-node builders)
    append - Append a node to an existing builder named `name`
returns: dict - {"returncode": int, "stdout": str, "stderr": str, "truncated": bool}

Input parameters:

- `append` (boolean)
- `bootstrap` (boolean)
- `config` (string)
- `driver` (string)
- `driver_opts` (object)
- `name` (string)
- `node_name` (string)
- `platforms` (array)
- `use` (boolean)

### `buildx_use` (~198 tokens)

Select the active builder for subsequent buildx operations.

Without `default` or `global_default` the switch applies only to the current CLI
session. `default` persists the choice for the current Docker context; `global_default`
persists across all Docker contexts. Use `buildx_list` to see available builders and their
current status. To avoid switching the global default, pass a specific builder name
directly via `buildx_build`'s `builder` parameter instead.

args:
    name - Builder name to activate (from `buildx_list`)
    default - Persist as default builder for the current Docker context
    global_default - Persist as default builder across all Docker contexts
returns: dict - {"returncode": int, "stdout": str, "stderr": str, "truncated": bool}

Input parameters:

- `default` (boolean)
- `global_default` (boolean)
- `name` (string, required)

### `buildx_remove` (~147 tokens)

Remove a builder instance.

args:
    name - Builder name to remove (mutually exclusive with `all_inactive`)
    all_inactive - Remove every inactive builder
    keep_state - Keep the BuildKit state volume
    keep_daemon - Keep the BuildKit daemon process running
    force - Force removal even if the builder is in use
returns: dict - {"returncode": int, "stdout": str, "stderr": str, "truncated": bool}

Input parameters:

- `all_inactive` (boolean)
- `force` (boolean)
- `keep_daemon` (boolean)
- `keep_state` (boolean)
- `name` (string)

### `system_ping` (~28 tokens)

Check that the Docker server is responsive.

returns: bool - True if the daemon responded successfully

Output parameters:

- `result` (boolean)

### `system_version` (~26 tokens)

Return Docker server version information.

returns: dict - Version information from the Docker daemon

### `system_info` (~26 tokens)

Return system-wide Docker information.

returns: dict - System information from the Docker daemon

### `system_df` (~29 tokens)

Return Docker disk usage information.

returns: dict - Data usage information for images, containers and volumes

### `host_list` (~121 tokens)

List the Docker hosts configured via DOCKER_MCP_SERVER_HOSTS.

With a single host (or the var unset) this is the one resolved daemon; with several it is the set the
\`host` argument selects from. The `default` entry is the one used when `host` is omitted.

returns: list[dict] - one per host: name; url (resolved daemon URL, null = docker-py platform
    default); read_only; tls (whether a per-host cert dir is configured); default (the omitted-host fallback)

Output parameters:

- `result` (array)

### `system_login` (~198 tokens)

Authenticate with a Docker registry.

Security: the password is sent as a tool argument, which many MCP clients log verbatim. Prefer
running `docker login` once on the host so the `docker` module reuses the credentials cached in
\`~/.docker/config.json`, and avoid calling this tool from an agent loop.

args:
    username - Registry username
    password - Registry password or token
    email - Registry account email
    registry - URL to the registry (defaults to Docker Hub)
    reauth - Force re-authentication even if valid credentials exist
    dockercfg_path - Path to a custom dockercfg file
returns: dict - The server response from the login request

Input parameters:

- `dockercfg_path` (string)
- `email` (string)
- `password` (string, required)
- `reauth` (boolean)
- `registry` (string)
- `username` (string, required)

### `system_logout` (~209 tokens)

Clear cached registry credentials from this server's in-memory Docker client.

docker-py / the Engine have no true logout: `system_login` validates against the registry (the daemon's
\`/auth` is stateless) and caches credentials in-process. This drops that in-memory cache; it does
NOT contact the daemon or touch the host's `~/.docker/config.json`. With no `registry`, clears
every cached credential; pass one to clear just that entry (key must match `system_login`; Docker Hub
is cached under "docker.io"). `system_close`/`system_reconnect` also clear it by discarding the client.

Reaches into a private docker-py attribute (`api._auth_configs`); degrades to clearing nothing if
that internal shape changes.

args:
    registry - Registry key to clear, or None to clear every cached credential
returns: dict - {"cleared": [<registry keys removed>]}

Input parameters:

- `registry` (string)

### `system_events` (~359 tokens)

Stream real-time events from the Docker server, bounded by `limit` events or `timeout_seconds`.

Returns when `limit` events are collected or `timeout_seconds` elapses, whichever comes first
(`limit` caps memory; `timeout_seconds` caps how long the call blocks — without it a quiet daemon
would block indefinitely, since the stream only yields on an actual event).

Caveat for `ssh://` daemons: docker-py can't cancel an SSH stream, so the `timeout_seconds`
watchdog can't interrupt a fully idle stream — bound with `until`/`limit` (or a non-SSH endpoint).

"Wait for the next matching event" idiom: pass `limit=1` with `filters` narrowed to what you
care about (e.g. `{"type": "container", "event": "health_status"}`) and a generous
\`timeout_seconds`. This blocks until that one event arrives (or the timeout elapses, returning an
empty list) instead of re-polling a snapshot on a timer — there's no separate wait tool for this
since the filtering this call already does covers it.

args:
    since - Show events created since this timestamp
    until - Show events created until this timestamp
    filters - Filters to apply to the event stream
    limit - Max events to return (default 100)
    timeout_seconds - Max wall-clock seconds before returning what was collected (default 30)
returns: list - A list of decoded event dicts (length <= limit)

Input parameters:

- `filters` (object)
- `limit` (integer)
- `since` (string)
- `timeout_seconds` (number)
- `until` (string)

### `system_close` (~114 tokens)

Close and drop pooled Docker client connection(s); each is rebuilt lazily on next use.

Use this to force a stale or errored connection to be discarded. Prefer `system_reconnect` when you
want to immediately re-establish the connection rather than wait for the next tool call to
trigger a lazy rebuild. With `host` omitted every pooled client is closed (unlike other tools,
where omitting it means the default host). Closing clients does not affect running containers.

returns: bool - True once closed

Output parameters:

- `result` (boolean)

### `system_reconnect` (~126 tokens)

Rebuild a pooled Docker client from its configured endpoint, to recover a wedged connection.

Validates the rebuilt client before swapping in (and only then closes the old one), so a failed
rebuild leaves the working client in place. Rebuilds the default host's client when `host` is
omitted. It CANNOT retarget to a different daemon — to add or change a daemon, edit
DOCKER_MCP_SERVER_HOSTS and restart.

returns: dict - the rebuilt host's version info (same shape as `system_version`), confirming connectivity

### `compose_up` (~298 tokens)

Bring up a Docker Compose project, detached.

Always runs detached (`-d`) so it can't block the server. Use `compose_ps` to confirm
services are running, or `wait=True` to block until they're healthy.

args:
    project_dir - Dir with the compose file (default: server cwd; paths verbatim, no shell expansion)
    files - Explicit compose file paths (repeatable, `-f`)
    project_name - Compose project name override
    profiles - Profiles to activate
    services - Specific services to bring up (default: all)
    build - Build images before starting
    pull - Pull strategy: "always", "missing", "never", or "policy" (compose default)
    remove_orphans - Remove containers for services not in the compose file
    wait - Block until services are healthy (adds `--wait`)
    timeout_seconds - Subprocess timeout (default 600s)
returns: dict - {"returncode": int, "stdout": str, "stderr": str, "truncated": bool}

Input parameters:

- `build` (boolean)
- `files` (array)
- `profiles` (array)
- `project_dir` (string)
- `project_name` (string)
- `pull` (string)
- `remove_orphans` (boolean)
- `services` (array)
- `timeout_seconds` (number)
- `wait` (boolean)

### `compose_down` (~195 tokens)

Stop and remove containers, networks (and optionally volumes) for a compose project.

args:
    project_dir - Dir with the compose file (default: server cwd)
    files - Explicit compose file paths (repeatable, `-f`)
    project_name - Compose project name override
    profiles - Profiles to consider
    volumes - Also remove named volumes declared by the project (destructive)
    remove_orphans - Remove containers not declared in the compose file
    timeout_seconds - Subprocess timeout (default 300s)
returns: dict - {"returncode": int, "stdout": str, "stderr": str, "truncated": bool}

Input parameters:

- `files` (array)
- `profiles` (array)
- `project_dir` (string)
- `project_name` (string)
- `remove_orphans` (boolean)
- `timeout_seconds` (number)
- `volumes` (boolean)

### `compose_ps` (~162 tokens)

List containers in a compose project, parsed from `--format json`.

args:
    project_dir - Dir with the compose file (default: server cwd)
    files - Explicit compose file paths (repeatable, `-f`)
    project_name - Compose project name override
    services - Restrict output to these services
    all - Include stopped containers as well
returns: dict - {"services": list[dict], "raw": <CliResult dict>}; on non-zero exit
                `services` is an empty list and the caller should inspect `raw.stderr`.

Input parameters:

- `all` (boolean)
- `files` (array)
- `project_dir` (string)
- `project_name` (string)
- `services` (array)

### `compose_logs` (~237 tokens)

Fetch a bounded slice of logs from a compose project (never follows).

args:
    project_dir - Dir with the compose file (default: server cwd)
    files - Explicit compose file paths (repeatable, `-f`)
    project_name - Compose project name override
    services - Restrict to these services (default: all)
    tail - Lines per container (default 200), or the literal "all" (still capped at MAX_CLI_OUTPUT_BYTES)
    since - Show logs since this timestamp/duration (e.g. "10m", "2024-01-01T00:00:00")
    until - Show logs before this timestamp/duration
    timestamps - Include per-line timestamps
returns: dict - {"returncode": int, "stdout": str, "stderr": str, "truncated": bool}

Input parameters:

- `files` (array)
- `project_dir` (string)
- `project_name` (string)
- `services` (array)
- `since` (string)
- `tail`
- `timestamps` (boolean)
- `until` (string)

### `compose_config` (~190 tokens)

Render the canonical compose configuration after merges, profiles, and variable substitution.

args:
    project_dir - Dir with the compose file (default: server cwd)
    files - Explicit compose file paths (repeatable, `-f`)
    project_name - Compose project name override
    profiles - Profiles to activate before rendering
    services_only - List service names only (`--services`)
    format - "yaml" (default) or "json"
returns: dict - {"config": str|dict|None, "raw": <CliResult dict>};
                `config` is a parsed dict when format="json" and parsing succeeds,
                otherwise the rendered text from stdout.

Input parameters:

- `files` (array)
- `format` (string)
- `profiles` (array)
- `project_dir` (string)
- `project_name` (string)
- `services_only` (boolean)

### `compose_build` (~185 tokens)

Build images for a compose project.

args:
    project_dir - Dir with the compose file (default: server cwd)
    files - Explicit compose file paths (repeatable, `-f`)
    project_name - Compose project name override
    services - Specific services to build (default: all)
    pull - Always attempt to pull a newer base image
    no_cache - Do not use cache when building
    timeout_seconds - Subprocess timeout (default 1800s)
returns: dict - {"returncode": int, "stdout": str, "stderr": str, "truncated": bool}

Input parameters:

- `files` (array)
- `no_cache` (boolean)
- `project_dir` (string)
- `project_name` (string)
- `pull` (boolean)
- `services` (array)
- `timeout_seconds` (number)

### `compose_pull` (~263 tokens)

Pre-fetch images for a compose project's services without starting them.

Use this to stage images before an outage window, to refresh cached images before
\`compose_up`, or to verify images are accessible without starting containers. For
registry-authenticated pulls ensure the daemon is logged in first with `system_login`.
\`compose_up --pull always` does the same as part of startup; use this tool when you
want to separate the pull step.

args:
    project_dir - Dir with the compose file (default: server cwd)
    files - Explicit compose file paths (repeatable, `-f`; overrides auto-discovery)
    project_name - Override the compose project name
    services - Pull only these services; omit to pull all
    ignore_pull_failures - Continue if an individual image pull fails
    timeout_seconds - Subprocess timeout (default 1800s for large image pulls)
returns: dict - {"returncode": int, "stdout": str, "stderr": str, "truncated": bool}

Input parameters:

- `files` (array)
- `ignore_pull_failures` (boolean)
- `project_dir` (string)
- `project_name` (string)
- `services` (array)
- `timeout_seconds` (number)

### `compose_restart` (~255 tokens)

Stop then start services without recreating containers or applying config changes.

Use this to bounce a service (e.g. to pick up a runtime file change or clear an
in-memory state). If the compose file has changed (new image, environment, volumes,
ports) use `compose_up` instead — it recreates affected containers to apply the diff.
\`stop_timeout_seconds` controls the SIGTERM grace period before Docker sends SIGKILL.

args:
    project_dir - Dir with the compose file (default: server cwd)
    files - Explicit compose file paths (repeatable, `-f`)
    project_name - Override the compose project name
    services - Restart only these services; omit to restart all
    stop_timeout_seconds - Seconds to wait for graceful stop before SIGKILL
    timeout_seconds - Subprocess timeout (default 300s)
returns: dict - {"returncode": int, "stdout": str, "stderr": str, "truncated": bool}

Input parameters:

- `files` (array)
- `project_dir` (string)
- `project_name` (string)
- `services` (array)
- `stop_timeout_seconds` (integer)
- `timeout_seconds` (number)

### `compose_stop` (~200 tokens)

Stop services in a compose project without removing their containers.

Unlike `compose_down`, containers/networks/volumes survive — use `compose_start` to bring them back.

args:
    project_dir - Dir with the compose file (default: server cwd)
    files - Explicit compose file paths (repeatable, `-f`)
    project_name - Compose project name override
    services - Specific services to stop (default: all)
    stop_timeout_seconds - Grace period before SIGKILL (passed as `--timeout`)
    timeout_seconds - Subprocess timeout (default 300s)
returns: dict - {"returncode": int, "stdout": str, "stderr": str, "truncated": bool}

Input parameters:

- `files` (array)
- `project_dir` (string)
- `project_name` (string)
- `services` (array)
- `stop_timeout_seconds` (integer)
- `timeout_seconds` (number)

### `compose_start` (~183 tokens)

Start existing (stopped) containers of a compose project.

Counterpart to `compose_stop`: starts existing containers without recreating them. Use
\`compose_up` to (re)create containers from the compose file.

args:
    project_dir - Dir with the compose file (default: server cwd)
    files - Explicit compose file paths (repeatable, `-f`)
    project_name - Compose project name override
    services - Specific services to start (default: all)
    timeout_seconds - Subprocess timeout (default 600s)
returns: dict - {"returncode": int, "stdout": str, "stderr": str, "truncated": bool}

Input parameters:

- `files` (array)
- `project_dir` (string)
- `project_name` (string)
- `services` (array)
- `timeout_seconds` (number)

### `compose_run` (~327 tokens)

Run a one-off command against a compose service.

Always passes `-T` (no TTY under MCP). Defaults to detached with `--rm` so the call returns promptly.

args:
    service - Service name from the compose file
    command - Command + args to run (exec-form; no shell unless you invoke one)
    project_dir - Dir with the compose file (default: server cwd)
    files - Explicit compose file paths (repeatable, `-f`)
    project_name - Compose project name override
    detach - Run detached (default True)
    rm - Remove the container after the run (default True)
    no_deps - Don't start linked services
    workdir - Working directory inside the container
    user - User to run as inside the container (uid or name)
    env - Environment variables to set inside the container
    name - Optional container name
    timeout_seconds - Subprocess timeout (default 600s)
returns: dict - {"returncode": int, "stdout": str, "stderr": str, "truncated": bool}

Input parameters:

- `command` (array)
- `detach` (boolean)
- `env` (object)
- `files` (array)
- `name` (string)
- `no_deps` (boolean)
- `project_dir` (string)
- `project_name` (string)
- `rm` (boolean)
- `service` (string, required)
- `timeout_seconds` (number)
- `user` (string)
- `workdir` (string)

### `compose_exec` (~309 tokens)

Run a command inside an already-running compose service container (see also `container_exec`).

Always passes `-T` (no TTY). Pass an exec-form argv (e.g. `["python", "-V"]`); a
\`["sh", "-c", "..."]` form interprets shell metacharacters in untrusted substrings.

args:
    service - Service name from the compose file
    command - Argv to execute inside the container
    project_dir - Dir with the compose file (default: server cwd)
    files - Explicit compose file paths (repeatable, `-f`)
    project_name - Compose project name override
    index - Container index when the service has multiple replicas (default 1)
    workdir - Working directory inside the container
    user - User to run as inside the container (uid or name)
    env - Environment variables to set for the exec session
    timeout_seconds - Subprocess timeout (default 60s)
returns: dict - {"returncode": int, "stdout": str, "stderr": str, "truncated": bool}

Input parameters:

- `command` (array, required)
- `env` (object)
- `files` (array)
- `index` (integer)
- `project_dir` (string)
- `project_name` (string)
- `service` (string, required)
- `timeout_seconds` (number)
- `user` (string)
- `workdir` (string)

### `compose_images` (~132 tokens)

List the images used by a compose project's services, parsed from `--format json`.

args:
    project_dir - Dir with the compose file (default: server cwd)
    files - Explicit compose file paths (repeatable, `-f`)
    project_name - Compose project name override
    services - Restrict to these services (default: all)
returns: list - One dict per container image (service, container, repository, tag, id, size)

Input parameters:

- `files` (array)
- `project_dir` (string)
- `project_name` (string)
- `services` (array)

### `compose_port` (~291 tokens)

Resolve the host binding for a service's container port.

The compose equivalent of `docker port`: which host address/port a service's private port is
published on. `published` is None when the port isn't published.

args:
    service - Service name from the compose file
    private_port - The container-internal port to look up
    protocol - "tcp" (default) or "udp"
    index - Container index when the service has multiple replicas (default 1)
    project_dir - Dir with the compose file (default: server cwd)
    files - Explicit compose file paths (repeatable, `-f`)
    project_name - Compose project name override
returns: dict - {"service", "private_port", "protocol", "published": "host:port"|None,
                 "host": str|None, "port": int|None, "bindings": list[str]}.
                 `published`/`host`/`port` describe the first binding; `bindings` lists every
                 line (a port can be published on more than one address, e.g. IPv4 and IPv6).

Input parameters:

- `files` (array)
- `index` (integer)
- `private_port` (integer, required)
- `project_dir` (string)
- `project_name` (string)
- `protocol` (string)
- `service` (string, required)

### `compose_wait` (~200 tokens)

Block until the named service containers stop, then return their exit codes.

For one-shot / batch services. A long-running service that never exits blocks until
\`timeout_seconds`, then the subprocess is killed (TimeoutExpired) — bound it sensibly.
Exit codes are on stdout.

args:
    services - One or more services to wait on. At least one is required.
    project_dir - Dir with the compose file (default: server cwd)
    files - Explicit compose file paths (repeatable, `-f`)
    project_name - Compose project name override
    timeout_seconds - Subprocess timeout (default 300s)
returns: dict - {"returncode": int, "stdout": str, "stderr": str, "truncated": bool}

Input parameters:

- `files` (array)
- `project_dir` (string)
- `project_name` (string)
- `services` (array, required)
- `timeout_seconds` (number)

### `compose_top` (~151 tokens)

Show the running processes of a compose project's containers.

Output is the `ps`-style process table per service (not JSON); read it from `stdout`.

args:
    services - Restrict to these services (default: all)
    project_dir - Dir with the compose file (default: server cwd)
    files - Explicit compose file paths (repeatable, `-f`)
    project_name - Compose project name override
returns: dict - {"returncode": int, "stdout": str, "stderr": str, "truncated": bool}

Input parameters:

- `files` (array)
- `project_dir` (string)
- `project_name` (string)
- `services` (array)

### `compose_cp` (~303 tokens)

Copy files/folders between a service container and the server host's filesystem.

Exactly one of `source`/`dest` is `SERVICE:PATH`; the other is a path on the host running this MCP
server, read/written as the server's user (same host exposure as the file-path archive tools — see
SECURITY.md). Copying to stdout (`dest="-"`) is unsupported; use the container-archive tools.

args:
    source - `SERVICE:SRC_PATH` or a host path
    dest - `SERVICE:DEST_PATH` or a host path (not "-")
    index - Container index when the service has multiple replicas (default 1)
    all_containers - Copy to/from all containers of the service (`--all`)
    project_dir - Dir with the compose file (default: server cwd)
    files - Explicit compose file paths (repeatable, `-f`)
    project_name - Compose project name override
    timeout_seconds - Subprocess timeout (default 300s)
returns: dict - {"returncode": int, "stdout": str, "stderr": str, "truncated": bool}

Input parameters:

- `all_containers` (boolean)
- `dest` (string, required)
- `files` (array)
- `index` (integer)
- `project_dir` (string)
- `project_name` (string)
- `source` (string, required)
- `timeout_seconds` (number)

### `compose_kill` (~191 tokens)

Send a signal to a compose project's containers (default SIGKILL).

args:
    services - Restrict to these services (default: all)
    signal - Signal to send (default "SIGKILL"; e.g. "SIGTERM", "SIGHUP")
    remove_orphans - Also remove containers for services not in the compose file
    project_dir - Dir with the compose file (default: server cwd)
    files - Explicit compose file paths (repeatable, `-f`)
    project_name - Compose project name override
returns: dict - {"returncode": int, "stdout": str, "stderr": str, "truncated": bool}

Input parameters:

- `files` (array)
- `project_dir` (string)
- `project_name` (string)
- `remove_orphans` (boolean)
- `services` (array)
- `signal` (string)

### `compose_pause` (~132 tokens)

Pause the containers of a compose project (freezes their processes).

args:
    services - Restrict to these services (default: all)
    project_dir - Dir with the compose file (default: server cwd)
    files - Explicit compose file paths (repeatable, `-f`)
    project_name - Compose project name override
returns: dict - {"returncode": int, "stdout": str, "stderr": str, "truncated": bool}

Input parameters:

- `files` (array)
- `project_dir` (string)
- `project_name` (string)
- `services` (array)

### `compose_unpause` (~134 tokens)

Unpause the containers of a compose project (resumes paused processes).

args:
    services - Restrict to these services (default: all)
    project_dir - Dir with the compose file (default: server cwd)
    files - Explicit compose file paths (repeatable, `-f`)
    project_name - Compose project name override
returns: dict - {"returncode": int, "stdout": str, "stderr": str, "truncated": bool}

Input parameters:

- `files` (array)
- `project_dir` (string)
- `project_name` (string)
- `services` (array)

### `compose_list` (~54 tokens)

List compose projects known to the daemon (across all directories).

args: all - Include stopped projects
returns: list - One dict per project (parsed from `--format json`)

Input parameters:

- `all` (boolean)

### `config_create` (~231 tokens)

Create an immutable Swarm config object; requires a swarm manager.

Configs store non-sensitive configuration files (nginx.conf, app.yaml, etc.) and mount
them into service containers at a specified path. Unlike secrets, config data is not
encrypted at rest — use `secret_create` for credentials or keys. `data` is raw bytes;
encode strings first (e.g. `"my config".encode()`). Once created, a config is immutable:
to update it, create a new config with a new name and update the service to reference it,
then remove the old config with `config_remove`.

args:
    name - Unique config name within the swarm
    data - Raw bytes content of the config file
    labels - Labels to set on the config
    templating - Templating driver config (e.g. {"Name": "golang"} for Go template syntax)
returns: dict - The created config's attrs including its id

Input parameters:

- `data` (string, required)
- `labels` (object)
- `name` (string, required)
- `templating` (object)

### `config_inspect` (~49 tokens)

Get a swarm config by id or name.

args: id_or_name - The config id or name
returns: dict - The config's attrs

Input parameters:

- `id_or_name` (string, required)

### `config_list` (~100 tokens)

List swarm configs; requires a swarm manager.

Unlike secrets, config attrs include the actual config data (`Spec.Data`, base64-encoded)
since configs are not treated as sensitive. Valid filter keys: `id`, `name`, `names`,
\`label` (key or key=value).

args: filters - Narrow the list; omit to return every config
returns: list - A list of config attrs dicts

Input parameters:

- `filters` (object)

### `config_remove` (~43 tokens)

Remove a swarm config.

args: id_or_name - The config id or name
returns: bool - True after removal

Input parameters:

- `id_or_name` (string, required)

Output parameters:

- `result` (boolean)

### `container_run` (~453 tokens)

Run a container from an image.

args:
    image - The image to run
    command - The command to run in the container
    name - Name to assign to the container
    detach - Run in the background and return container info
    environment - Environment variables to set
    ports - Port mappings, e.g. {'2222/tcp': 3333}
    volumes - Volumes to mount
    network - Name of the network to attach
    hostname - Optional hostname for the container
    user - Username or UID to run as
    working_dir - Working directory inside the container
    entrypoint - Entrypoint to override the image default
    restart_policy - Restart policy, e.g. {'Name': 'on-failure', 'MaximumRetryCount': 3}
    labels - Labels to set on the container
    remove - Remove the container when it exits (only with detach=False)
    auto_remove - Enable auto-removal of the container on daemon side
    privileged - Give extended privileges to the container
    tty - Allocate a pseudo-TTY
    stdin_open - Keep STDIN open
    mem_limit - Memory limit
    cpu_count - Number of CPUs
    extra_kwargs - Additional keyword arguments forwarded to ContainerCollection.run (call
                   `docs_lookup(section="containers")` for the full accepted set)
returns: dict | str - Container attrs when detach=True, otherwise stdout/stderr as a string

Input parameters:

- `auto_remove` (boolean)
- `command`
- `cpu_count` (integer)
- `detach` (boolean)
- `entrypoint`
- `environment`
- `extra_kwargs` (object)
- `hostname` (string)
- `image` (string, required)
- `labels`
- `mem_limit`
- `name` (string)
- `network` (string)
- `ports` (object)
- `privileged` (boolean)
- `remove` (boolean)
- `restart_policy`
- `stdin_open` (boolean)
- `tty` (boolean)
- `user` (string)
- `volumes`
- `working_dir` (string)

Output parameters:

- `result`

### `container_create` (~283 tokens)

Create a container from an image without starting it.

Use this when you need to configure a container (with `extra_kwargs`) before its first
start, or want creation and start as separate observable steps. For the common case of
create-then-start-immediately use `container_run` instead — it does both in one call.
Start the created container with `container_start`. Common `extra_kwargs` keys: `name`
(str), `environment` (list of "KEY=VAL" or dict), `ports` (dict, e.g.
\`{"80/tcp": 8080}`), `volumes` (dict, e.g. `{"/host/path": {"bind": "/container/path",
"mode": "rw"}}`), `labels` (dict). For anything else docker-py's `ContainerCollection.create`
accepts, call `docs_lookup(section="containers")` rather than guessing a key name.

args:
    image - Image to create the container from, e.g. "nginx:alpine"
    command - Override the image's default command; string or list of strings
    extra_kwargs - Additional docker-py ContainerCollection.create keyword arguments
returns: dict - The created container's attrs (not yet running)

Input parameters:

- `command`
- `extra_kwargs` (object)
- `image` (string, required)

### `container_inspect` (~126 tokens)

Return the full inspect detail for a single container.

Use this when you need complete information about one container — config, state,
network settings, mounts, environment variables, and resource limits. For a quick
overview of many containers use `container_list` instead (returns a summary per
container). For just logs or stats use `container_logs` / `container_stats`.

args: id_or_name - Container id (full or short) or name
returns: dict - Full container inspect attrs (equivalent to `docker inspect`)

Input parameters:

- `id_or_name` (string, required)

### `container_list` (~198 tokens)

List containers.

args:
    all - Show all containers, including stopped ones
    since - Only show containers created after this id or name
    before - Only show containers created before this id or name
    limit - Maximum number of results
    filters - Filter by attributes (e.g. status, label)
    sparse - Skip inspect calls and return less detail
    ignore_removed - Ignore containers removed during listing
    managed_only - Only return containers created by this MCP server (filters on the
                         docker-mcp-server.managed label); combines with any `filters` given
returns: list - A list of container attrs dicts

Input parameters:

- `all` (boolean)
- `before` (string)
- `filters` (object)
- `ignore_removed` (boolean)
- `limit` (integer)
- `managed_only` (boolean)
- `since` (string)
- `sparse` (boolean)

### `container_prune` (~156 tokens)

Remove all stopped containers to reclaim disk space.

Only removes containers that are not running — running containers are never affected.
Use `container_list(all=True)` to preview what would be removed before calling this.
Valid filter keys: `until` (RFC3339 timestamp or duration like "24h" — removes containers
stopped before that point), `label` (key or key=value). For a broader cleanup of
containers plus unused images, networks, and volumes see the `prune_managed` prompt.

args: filters - Narrow which stopped containers to remove; omit to remove all stopped
returns: dict - {"ContainersDeleted": [...], "SpaceReclaimed": <bytes>}

Input parameters:

- `filters` (object)

### `container_start` (~120 tokens)

Start an existing stopped container.

Use this to restart a container that was previously created or stopped without removing it.
To create and start a new container in one step use `container_run` instead. Calling on
an already-running container has no effect (the daemon returns 304 and no error is
raised). To stop then start a running container use `container_restart`.

args: id_or_name - Container id (full or short) or name
returns: dict - The container's full attrs after starting

Input parameters:

- `id_or_name` (string, required)

### `container_stop` (~71 tokens)

Stop a container.

args:
    id_or_name - The container id or name
    stop_timeout_seconds - Seconds to wait for graceful stop before SIGKILL
returns: dict - The container's attrs after stop

Input parameters:

- `id_or_name` (string, required)
- `stop_timeout_seconds` (integer)

### `container_restart` (~73 tokens)

Restart a container.

args:
    id_or_name - The container id or name
    stop_timeout_seconds - Seconds to wait for graceful stop before SIGKILL and restart
returns: dict - The container's attrs after restart

Input parameters:

- `id_or_name` (string, required)
- `stop_timeout_seconds` (integer)

### `container_kill` (~70 tokens)

Send a signal to a container.

args:
    id_or_name - The container id or name
    signal - Signal to send (defaults to SIGKILL)
returns: dict - The container's attrs after kill

Input parameters:

- `id_or_name` (string, required)
- `signal` (string)

### `container_pause` (~119 tokens)

Suspend all processes in a container using the kernel freezer cgroup.

Unlike sending SIGSTOP, the freezer cgroup suspends processes without their being able
to observe or intercept the suspension. A paused container keeps its resources (memory,
open file descriptors) but consumes no CPU. Resume with `container_unpause` —
\`container_exec` fails against a paused container until it is unpaused.

args: id_or_name - The container id or name
returns: dict - The container's attrs after pause

Input parameters:

- `id_or_name` (string, required)

### `container_unpause` (~51 tokens)

Resume all processes in a paused container.

args: id_or_name - The container id or name
returns: dict - The container's attrs after unpause

Input parameters:

- `id_or_name` (string, required)

### `container_remove` (~98 tokens)

Remove a container.

args:
    id_or_name - The container id or name
    volumes - Also remove anonymous volumes (the CLI's `--volumes`)
    link - Remove the specified link
    force - Force remove a running container
returns: bool - True after removal completes

Input parameters:

- `force` (boolean)
- `id_or_name` (string, required)
- `link` (boolean)
- `volumes` (boolean)

Output parameters:

- `result` (boolean)

### `container_logs` (~377 tokens)

Get the logs of a container: a one-shot snapshot by default, or a bounded live tail with `follow=True`.

Follow mode returns when `limit_lines` lines are collected, `timeout_seconds` elapses, or the
container exits, whichever comes first — so the agent can watch live output without blocking
forever. `limit_lines`/`timeout_seconds` apply only in follow mode; `until` only in snapshot mode.

Caveat for `ssh://` daemons: docker-py can't cancel an SSH stream, so in follow mode the
\`timeout_seconds` watchdog can't interrupt a fully silent container — use the snapshot mode
there if you need a hard time bound.

args:
    id_or_name - The container id or name
    stdout - Include stdout
    stderr - Include stderr
    timestamps - Include timestamps
    tail - Number of lines from the end (default 200), or the literal "all" for everything
    since - Only return logs created after this unix timestamp
    until - Only return logs created before this unix timestamp (snapshot mode only)
    follow - Follow the live log stream instead of returning a snapshot
    limit_lines - Follow mode: max lines to collect before returning (default 200)
    timeout_seconds - Follow mode: max wall-clock seconds before returning what was collected (default 30)
returns: str - Decoded log output (up to `limit_lines` lines in follow mode)

Input parameters:

- `follow` (boolean)
- `id_or_name` (string, required)
- `limit_lines` (integer)
- `since` (number)
- `stderr` (boolean)
- `stdout` (boolean)
- `tail`
- `timeout_seconds` (number)
- `timestamps` (boolean)
- `until` (number)

Output parameters:

- `result` (string)

### `container_stats` (~50 tokens)

Get a single resource usage stats snapshot for a container.

args: id_or_name - The container id or name
returns: dict - Decoded stats snapshot

Input parameters:

- `id_or_name` (string, required)

### `container_top` (~70 tokens)

Show the running processes inside a container.

args:
    id_or_name - The container id or name
    ps_args - Arguments to pass to ps inside the container
returns: dict - Output of the top command

Input parameters:

- `id_or_name` (string, required)
- `ps_args` (string)

### `container_exec` (~320 tokens)

Run a command inside a running container (for a compose service, prefer `compose_exec`).

Security: when any element of `cmd` is agent-controlled, use an exec-form argv list that does not
invoke a shell (e.g. `["python", "-V"]`, `["ls", path]`). A string `cmd`, or a shell form like
\`["sh", "-c", template]`, interprets shell metacharacters in the untrusted parts.

args:
    id_or_name - The container id or name
    cmd - Command to execute (prefer exec-form argv, no shell, when any element is agent-controlled)
    stdout - Attach to stdout
    stderr - Attach to stderr
    stdin - Attach to stdin
    tty - Allocate a pseudo-TTY
    privileged - Run with extended privileges
    user - User to run the command as
    detach - Detach from the exec
    environment - Environment variables
    workdir - Working directory inside the container
    demux - Return stdout and stderr separately
returns: dict - Mapping with exit_code and output keys

Input parameters:

- `cmd` (required)
- `demux` (boolean)
- `detach` (boolean)
- `environment`
- `id_or_name` (string, required)
- `privileged` (boolean)
- `stderr` (boolean)
- `stdin` (boolean)
- `stdout` (boolean)
- `tty` (boolean)
- `user` (string)
- `workdir` (string)

### `container_commit` (~295 tokens)

Snapshot a container's current filesystem state as a new image.

Useful for capturing a debugging state or saving manual changes made inside a container.
For repeatable builds use a Dockerfile instead. The container is paused by default during
the snapshot to ensure filesystem consistency — set `pause=False` only if the container
cannot be paused. `changes` accepts Dockerfile instructions to apply on top of the
snapshot, e.g. `["CMD ["python", "app.py"]", "ENV FOO=bar"]`.

args:
    id_or_name - Container id or name to snapshot
    repository - Repository name for the new image, e.g. "myorg/myimage"
    tag - Tag for the new image (default: "latest")
    message - Commit message stored in the image metadata
    author - Author string stored in the image metadata
    pause - Pause the container during commit for consistency (default True)
    changes - Dockerfile instructions (CMD, ENV, EXPOSE, etc.) to apply to the image
    conf - Additional image configuration overrides as a dict
returns: dict - The new image's attrs

Input parameters:

- `author` (string)
- `changes`
- `conf` (object)
- `id_or_name` (string, required)
- `message` (string)
- `pause` (boolean)
- `repository` (string)
- `tag` (string)

### `container_diff` (~51 tokens)

Inspect changes on a container's filesystem.

args: id_or_name - The container id or name
returns: list - Filesystem changes since the image was created

Input parameters:

- `id_or_name` (string, required)

### `container_rename` (~61 tokens)

Rename a container.

args:
    id_or_name - The container id or name
    name - The new name
returns: dict - The container's attrs after rename

Input parameters:

- `id_or_name` (string, required)
- `name` (string, required)

### `container_update` (~236 tokens)

Update resource limits on a container without recreating it.

Changes take effect immediately on Linux (cgroups); not all fields are updatable on
every platform. Common `updates` keys: `mem_limit` (bytes, e.g. 134217728 for 128 MB),
\`memswap_limit` (memory+swap in bytes; -1 = unlimited), `cpu_shares` (relative weight,
default 1024), `cpu_period` / `cpu_quota` (microseconds for CFS throttling),
\`cpuset_cpus` (e.g. "0-1"), `restart_policy` (dict with `Name` such as
"on-failure"/"always"/"unless-stopped" and optional `MaximumRetryCount`). To change
image, env, or volumes the container must be recreated.

args:
    id_or_name - Container id or name to update
    updates - Resource fields to update; see description for valid keys
returns: dict - The container's full attrs after the update

Input parameters:

- `id_or_name` (string, required)
- `updates` (object, required)

### `container_wait` (~680 tokens)

Block until a container reaches a condition: stopped, "healthy", or its logs contain a pattern.

One contract for every mode: never raises on timeout — the result always carries `met` (condition
reached) and `timed_out`. The stop conditions ("not-running"/"next-exit"/"removed") use the
daemon's blocking wait and fill `status_code`/`error` (the container's exit info); "healthy" polls
the container's HEALTHCHECK every `poll_interval`s and fills `health`/`status`; "log-match" polls
recent logs every `poll_interval`s for `pattern` and fills `matched_line`.

Health semantics: with no HEALTHCHECK defined, once the container is `running` the tool returns
promptly with `health: null` and `met: false` (false = "not confirmed healthy", not "unhealthy" —
check `health` to tell them apart). A container that exits before becoming healthy returns its
terminal `status` and `met: false`.

Log-match semantics: `pattern` is matched as a **plain substring** by default — safe against any
input, including adversarial ones. Pass `regex=True` to match `pattern` as a regular expression
(via `re.search`) instead; only do this with patterns you trust, since a regex with catastrophic
backtracking run against attacker-influenced log content can exhaust CPU (ReDoS). Checks stdout
and stderr, most recent lines first within each poll. If the container exits/dies before the
pattern ever appears, returns promptly with `met=false` (not `timed_out`) — no further logs can
arrive, so there's nothing to keep polling for.

args:
    id_or_name - The container id or name
    until - Condition to wait for: "not-running" (default), "next-exit", "removed", "healthy",
            or "log-match" (requires `pattern`)
    timeout_seconds - Max seconds to wait before returning with timed_out=true (default 600)
    poll_interval - "healthy"/"log-match" only: seconds between re-checks (default 2, > 0);
                    capped by the time left so a large value can't push the total wait past the…

Input parameters:

- `id_or_name` (string, required)
- `pattern` (string)
- `poll_interval` (number)
- `regex` (boolean)
- `timeout_seconds` (number)
- `until` (string)

### `container_export` (~271 tokens)

Export a container's filesystem as a tar archive: to a file on the server host, or in band.

With `dest_path` the archive streams straight to disk (no byte cap), so it handles large
containers — the file is written by the server's user, `~` is expanded, and an existing file is
refused unless `overwrite=True`. Without `dest_path` the tar bytes are returned in band, capped
at `max_bytes` (default 32 MiB) because MCP base64-encodes them — a fallback for when no
writable host path exists (e.g. a containerized server without a bind mount).

args:
    id_or_name - The container id or name
    dest_path - Destination path on the server host; omit to return the bytes in band
    overwrite - Replace dest_path if it already exists (default False)
    max_bytes - In-band mode: abort with ValueError beyond this many bytes (default 32 MiB)
returns: bytes | dict - the tar bytes (in band), or {"path": <resolved path>, "bytes_written": int}

Input parameters:

- `dest_path` (string)
- `id_or_name` (string, required)
- `max_bytes` (integer)
- `overwrite` (boolean)

Output parameters:

- `result`

### `container_archive_get` (~154 tokens)

Retrieve a file or directory from a container as a tar archive, returned in band.

For large paths prefer `container_archive_get_to_file`, which streams to a host path; the in-band
bytes here are capped (default 32 MiB) because MCP base64-encodes them.

args:
    id_or_name - The container id or name
    path - Path inside the container
    max_bytes - Abort with ValueError if the archive exceeds this many bytes (defaults to 32 MiB)
returns: dict - Mapping with archive (bytes) and stat (dict) keys

Input parameters:

- `id_or_name` (string, required)
- `max_bytes` (integer)
- `path` (string, required)

### `container_archive_get_to_file` (~174 tokens)

Retrieve a file or directory from a container as a tar archive written to a file on the server host.

Streams straight to disk (no in-band byte cap). The file is written by the server's user; `~` is
expanded and an existing file is refused unless `overwrite=True`.

args:
    id_or_name - The container id or name
    path - Path inside the container
    dest_path - Destination path on the server host for the tarball
    overwrite - Replace dest_path if it already exists (default False)
returns: dict - {"path": <resolved path>, "bytes_written": int, "stat": dict}

Input parameters:

- `dest_path` (string, required)
- `id_or_name` (string, required)
- `overwrite` (boolean)
- `path` (string, required)

### `container_archive_put` (~207 tokens)

Upload a tar archive to a path inside a container, from in-band bytes or a file on the server host.

Pass exactly one of `data` (tar bytes in band) or `from_file` (a path on the server host, streamed
straight to the daemon — preferred for large archives, since in-band bytes are base64-encoded by
MCP). `from_file` is read by the server's user; `~` is expanded.

args:
    id_or_name - The container id or name
    path - Destination path inside the container (must already exist)
    data - Tar archive bytes; exactly one of data/from_file
    from_file - Path on the server host to the tar archive to upload; exactly one of data/from_file
returns: bool - True if the upload succeeded

Input parameters:

- `data` (string)
- `from_file` (string)
- `id_or_name` (string, required)
- `path` (string, required)

Output parameters:

- `result` (boolean)

### `context_list` (~99 tokens)

List Docker CLI contexts known to the host running this MCP server.

Contexts are a CLI concept (stored in the docker config dir) letting one CLI target multiple
daemons. This server uses whatever DOCKER_HOST / current-context resolved to at startup, so
changing contexts only affects future subprocess-based tools, not the docker-py SDK client.

returns: list - One dict per context with at least name, description, dockerEndpoint, and current

### `context_inspect` (~61 tokens)

Return the full configuration for a single Docker context.

args: name - Context name (use the `Name` field from `context_list`)
returns: dict - The parsed `docker context inspect` entry for that context

Input parameters:

- `name` (string, required)

### `context_create` (~227 tokens)

Create a new Docker CLI context pointing at a daemon endpoint.

args:
    name - Name for the new context (must not already exist)
    docker_host - Daemon URL, e.g. "tcp://10.0.0.5:2376" or "unix:///var/run/docker.sock"
    description - Optional human description shown in `context ls`
    tls_ca - Path on the local host to the CA cert (for TLS daemons)
    tls_cert - Path on the local host to the client cert
    tls_key - Path on the local host to the client key
    skip_tls_verify - Disable TLS verification (insecure; for testing only)
returns: dict - {"returncode": int, "stdout": str, "stderr": str, "truncated": bool}

Input parameters:

- `description` (string)
- `docker_host` (string, required)
- `name` (string, required)
- `skip_tls_verify` (boolean)
- `tls_ca` (string)
- `tls_cert` (string)
- `tls_key` (string)

### `context_use` (~119 tokens)

Set the active Docker context for the CLI on the host running this MCP server.

Note: this does not retarget the long-lived docker-py client — SDK-backed tools keep using the
endpoint they connected to at startup. To retarget those, restart the server with a different
DOCKER_HOST / DOCKER_CONTEXT.

args: name - Existing context name to set as default
returns: dict - {"returncode": int, "stdout": str, "stderr": str, "truncated": bool}

Input parameters:

- `name` (string, required)

### `context_remove` (~79 tokens)

Remove a Docker CLI context.

args:
    name - Context name to remove
    force - Force removal even if the context is the current one
returns: dict - {"returncode": int, "stdout": str, "stderr": str, "truncated": bool}

Input parameters:

- `force` (boolean)
- `name` (string, required)

### `image_build` (~612 tokens)

Build an image from a Dockerfile using the daemon's classic builder.

Use this for simple single-platform builds from a local context. For multi-platform
builds, BuildKit cache export/import, or advanced build features prefer `buildx_build`.
\`path` must be a directory accessible on the host running this server (it is the build
context sent to the daemon). `dockerfile` is relative to `path`; omit to use the
default `Dockerfile`.

args:
    path - Build context directory path on the server host
    tag - Name and optional tag in "name:tag" format to apply to the built image
    quiet - Suppress verbose build output (final image id still returned)
    nocache - Ignore the layer cache and rebuild all layers
    rm - Remove intermediate containers on success (default True)
    pull - Always pull a newer version of each FROM base image before building
    forcerm - Remove intermediate containers even on build failure
    dockerfile - Dockerfile filename relative to path (default: "Dockerfile")
    buildargs - Build-time variables passed as `--build-arg`; dict of str→str
    container_limits - Resource limits for the build container, e.g. {"memory": 134217728}
    shmsize - Size of /dev/shm in bytes for build steps that need shared memory
    labels - Labels to set on the resulting image (dict of str→str)
    cache_from - List of image references to use as layer cache sources
    target - Stop at this named build stage (multi-stage Dockerfiles)
    network_mode - Network mode for RUN instructions during build (e.g. "host", "none")
    squash - Squash all new layers into one (experimental; requires daemon flag)
    extra_hosts - Additional /etc/hosts entries during build; dict of hostname→ip
    platform - Target platform, e.g. "linux/amd64" (single platform only; use buildx for multi)
    isolation - Windows isolation technology ("default", "process", "hyperv")
    use_config_proxy - Forward proxy env vars from Docker client config to build
returns: dict - The built imag…

Input parameters:

- `buildargs` (object)
- `cache_from` (array)
- `container_limits` (object)
- `dockerfile` (string)
- `extra_hosts` (object)
- `forcerm` (boolean)
- `isolation` (string)
- `labels` (object)
- `network_mode` (string)
- `nocache` (boolean)
- `path` (string)
- `platform` (string)
- `pull` (boolean)
- `quiet` (boolean)
- `rm` (boolean)
- `shmsize` (integer)
- `squash` (boolean)
- `tag` (string)
- `target` (string)
- `use_config_proxy` (boolean)

### `image_inspect` (~173 tokens)

Return the full inspect detail for a single local image.

Includes config (env, entrypoint, exposed ports), size, layer digests (`RootFS.Layers`),
and all tags/digests referencing it (`RepoTags`/`RepoDigests`). For a quick overview of
many images use `image_list` instead. For the per-layer build history (which command
produced each layer) use `image_history`. Only inspects images already present locally —
for a remote image's manifest without pulling it use `image_registry_data` or
\`registry_manifest`.

args: id_or_name - Image name (with optional tag/digest) or id
returns: dict - Full image inspect attrs (equivalent to `docker inspect` on an image)

Input parameters:

- `id_or_name` (string, required)

### `image_registry_data` (~152 tokens)

Get registry data for an image without pulling it, via the daemon's distribution endpoint.

Uses the daemon (and its cached credentials) to resolve the remote descriptor and platform
list. For direct registry access without a daemon use `registry_manifest`.

Security: `auth_config` carries registry credentials, which many MCP clients log verbatim. Prefer
\`docker login` on the host so the `docker` module reuses credentials cached in
\`~/.docker/config.json`, and leave `auth_config` unset.

args:
    repository - Image reference
    auth_config - Optional registry authentication config
returns: dict - Registry data attrs

Input parameters:

- `auth_config` (object)
- `repository` (string, required)

### `image_list` (~85 tokens)

List images on the server.

args:
    repository - Only show images of this repository
    all - Show intermediate image layers
    filters - Filter by attributes (label, dangling, before, since, etc.)
returns: list - A list of image attrs dicts

Input parameters:

- `all` (boolean)
- `filters` (object)
- `repository` (string)

### `image_pull` (~115 tokens)

Pull an image from a registry to the daemon's local store.

args:
    repository - The image repository
    tag - The image tag (ignored when all_tags=True)
    all_tags - Pull all tags from the repository
    platform - Platform in os/arch format
returns: dict | list - Pulled image attrs (or a list of attrs if all_tags=True)

Input parameters:

- `all_tags` (boolean)
- `platform` (string)
- `repository` (string, required)
- `tag` (string)

Output parameters:

- `result`

### `image_push` (~130 tokens)

Push an image or repository to a registry.

Security: `auth_config` carries registry credentials, which many MCP clients log verbatim. Prefer
\`docker login` on the host so the `docker` module reuses credentials cached in
\`~/.docker/config.json`, and leave `auth_config` unset.

args:
    repository - The image repository
    tag - The tag to push
    auth_config - Optional registry authentication config
returns: str - Push output as a string

Input parameters:

- `auth_config` (object)
- `repository` (string, required)
- `tag` (string)

Output parameters:

- `result` (string)

### `image_remove` (~181 tokens)

Remove a local image by name or id.

Fails without `force` if the image is tagged by multiple names (untag first with
\`image_tag`) or if stopped containers reference it. Running containers always block
removal regardless of `force`. `noprune` keeps untagged parent layers that would
otherwise be removed as a side-effect; leave False unless you need to preserve
the parent layers for another purpose.

args:
    id_or_name - Image name (with optional tag/digest) or id to remove
    force - Remove even if referenced by stopped containers or multiple tags
    noprune - Do not delete untagged intermediate parent layers
returns: bool - True after removal completes

Input parameters:

- `force` (boolean)
- `id_or_name` (string, required)
- `noprune` (boolean)

Output parameters:

- `result` (boolean)

### `image_search` (~147 tokens)

Search Docker Hub for public images matching a term.

Searches Docker Hub only — not GHCR, ECR, or other registries. For listing tags on a
specific image from any OCI registry use `registry_tags` instead. Each result dict
includes `name`, `description`, `star_count`, `is_official`, and `is_automated`.

args:
    term - Search keyword, e.g. "nginx" or "python"
    limit - Maximum number of results to return (Docker Hub default is 25)
returns: list - List of matching image dicts from Docker Hub

Input parameters:

- `limit` (integer)
- `term` (string, required)

### `image_prune` (~166 tokens)

Remove unused local images to reclaim disk space.

Without filters removes only "dangling" images — untagged layers not referenced by any
tag or container. To remove all images not used by any container (including tagged ones)
pass `filters={"dangling": False}`. Valid filter keys: `dangling` (bool as string
"true"/"false"), `until` (RFC3339 timestamp or duration like "24h"), `label`
(key or key=value). Use `system_df` first to see how much space is reclaimable.

args: filters - Narrow which images to remove; omit to remove dangling images only
returns: dict - {"ImagesDeleted": [...], "SpaceReclaimed": <bytes>}

Input parameters:

- `filters` (object)

### `image_load` (~176 tokens)

Load an image from a tarball produced by image_save, from in-band bytes or a file on the server host.

Pass exactly one of `data` (tarball bytes in band) or `from_file` (a path on the server host,
streamed straight to the daemon — preferred for anything but small images, since in-band bytes are
base64-encoded by MCP). `from_file` is read by the server's user; `~` is expanded.

args:
    data - Tarball contents; exactly one of data/from_file
    from_file - Path to a tarball produced by `docker save` / `image_save`; exactly one of data/from_file
returns: list - A list of loaded image attrs dicts

Input parameters:

- `data` (string)
- `from_file` (string)

### `image_save` (~285 tokens)

Save an image as a tar archive: to a file on the server host, or in band.

With `dest_path` the archive streams straight to disk (no byte cap), so it handles large images —
the file is written by the server's user, `~` is expanded, and an existing file is refused unless
\`overwrite=True`. Without `dest_path` the tar bytes are returned in band, capped at `max_bytes`
(default 32 MiB) because MCP base64-encodes them — a fallback for when no writable host path
exists (e.g. a containerized server without a bind mount).

args:
    id_or_name - Image name or id
    dest_path - Destination path on the server host; omit to return the bytes in band
    named - Whether to retain repository/tag names in the saved archive
    overwrite - Replace dest_path if it already exists (default False)
    max_bytes - In-band mode: abort with ValueError beyond this many bytes (default 32 MiB)
returns: bytes | dict - the tarball bytes (in band), or {"path": <resolved path>, "bytes_written": int}

Input parameters:

- `dest_path` (string)
- `id_or_name` (string, required)
- `max_bytes` (integer)
- `named` (boolean)
- `overwrite` (boolean)

Output parameters:

- `result`

### `image_tag` (~95 tokens)

Tag an image into a repository.

args:
    id_or_name - The source image name or id
    repository - Target repository name
    tag - Optional tag for the new image
    force - Force the tag
returns: bool - True if the image was tagged

Input parameters:

- `force` (boolean)
- `id_or_name` (string, required)
- `repository` (string, required)
- `tag` (string)

Output parameters:

- `result` (boolean)

### `image_history` (~144 tokens)

Return the layer history of an image.

Useful for auditing what commands built each layer and diagnosing image size. Each entry
includes `Id` (layer digest or "<missing>" for imported layers), `Created` (unix
timestamp), `CreatedBy` (the Dockerfile command that produced the layer, e.g. a RUN or
COPY), `Size` (bytes added by that layer), and `Comment`. For full image metadata use
\`image_inspect` instead.

args: id_or_name - Image name (with optional tag/digest) or id
returns: list - Layer history entries, newest first

Input parameters:

- `id_or_name` (string, required)

### `network_create` (~226 tokens)

Create a network.

args:
    name - The name of the network
    driver - Driver name (e.g. bridge, overlay)
    options - Driver-specific options
    ipam - IPAM configuration as a dict
    check_duplicate - Reject creation if a duplicate name exists
    internal - Restrict external access
    labels - Labels to set on the network
    enable_ipv6 - Enable IPv6 networking
    attachable - Allow standalone containers to attach (swarm)
    scope - Network scope (local, global, swarm)
    ingress - Make this an ingress network for swarm routing-mesh
returns: dict - The created network's attrs

Input parameters:

- `attachable` (boolean)
- `check_duplicate` (boolean)
- `driver` (string)
- `enable_ipv6` (boolean)
- `ingress` (boolean)
- `internal` (boolean)
- `ipam` (object)
- `labels` (object)
- `name` (string, required)
- `options` (object)
- `scope` (string)

### `network_inspect` (~126 tokens)

Return the full inspect detail for a single network.

Includes the connected containers (`Containers`, keyed by container id, with each
entry's assigned IP), IPAM config, and driver options. For a quick overview of many
networks use `network_list` instead — its default (non-`greedy`) response omits the
per-network `Containers` detail for speed.

args: id_or_name - The network id or name
returns: dict - Full network inspect attrs (equivalent to `docker network inspect`)

Input parameters:

- `id_or_name` (string, required)

### `network_list` (~249 tokens)

List networks.

Valid filter keys: `driver` (driver name), `label` (key or key=value), `type`
("custom" or "builtin"). `names`/`ids` are a separate shorthand for filtering by exact
name/id, applied in addition to `filters`. Set `greedy` to fetch each network's attrs
individually (adds the connected-containers detail that `network_inspect` returns, at
the cost of one extra daemon call per network) — leave it False for a fast summary list.

args:
    names - Filter by exact network names
    ids - Filter by exact network ids
    filters - Additional server-side filters; see description for valid keys
    greedy - Fetch extended per-network details (including connected containers)
    managed_only - Only return networks created by this MCP server (filters on the
                         docker-mcp-server.managed label); combines with any `filters` given
returns: list - A list of network attrs dicts

Input parameters:

- `filters` (object)
- `greedy` (boolean)
- `ids` (array)
- `managed_only` (boolean)
- `names` (array)

### `network_prune` (~110 tokens)

Remove networks that have no active container endpoints.

Built-in networks (bridge, host, none) are never removed. Only networks with zero
connected containers are eligible. Valid filter keys: `until` (RFC3339 timestamp or
duration — removes networks created before that point), `label` (key or key=value).

args: filters - Narrow which networks to remove; omit to remove all unused custom networks
returns: dict - {"NetworksDeleted": [...]}

Input parameters:

- `filters` (object)

### `network_remove` (~114 tokens)

Remove a single custom network by id or name.

Fails if any container is still attached (disconnect with `network_disconnect` or stop
the containers first). Built-in networks (`bridge`, `host`, `none`) can never be removed
and return an error regardless of attachment state. For bulk cleanup of every unused
custom network at once use `network_prune` instead.

args: id_or_name - The network id or name
returns: bool - True after removal

Input parameters:

- `id_or_name` (string, required)

Output parameters:

- `result` (boolean)

### `network_connect` (~294 tokens)

Attach a running container to an additional network without restarting it.

Use this to give a container access to services on a network it was not started with.
\`aliases` sets extra DNS names for this container within the network (other containers
can reach it by those names in addition to its container name). `ipv4_address` /
\`ipv6_address` assign a specific IP on the network; omit to let the driver assign one.
\`links` is a legacy feature (deprecated; prefer DNS aliases). Use `network_disconnect`
to undo.

args:
    id_or_name - Network id or name to connect the container to
    container - Container id or name to attach
    aliases - Additional DNS names for this container within the network
    links - Legacy container links (deprecated)
    ipv4_address - Static IPv4 address to assign on this network
    ipv6_address - Static IPv6 address to assign on this network
    link_local_ips - Link-local IP addresses to assign
    driver_opt - Driver-specific endpoint options
returns: bool - True after the container is connected

Input parameters:

- `aliases` (array)
- `container` (string, required)
- `driver_opt` (object)
- `id_or_name` (string, required)
- `ipv4_address` (string)
- `ipv6_address` (string)
- `link_local_ips` (array)
- `links` (array)

Output parameters:

- `result` (boolean)

### `network_disconnect` (~78 tokens)

Disconnect a container from a network.

args:
    id_or_name - The network id or name
    container - The container id or name
    force - Force disconnect
returns: bool - True after the container is disconnected

Input parameters:

- `container` (string, required)
- `force` (boolean)
- `id_or_name` (string, required)

Output parameters:

- `result` (boolean)

### `node_inspect` (~49 tokens)

Get a swarm node by id or name.

args: id_or_name - The node id or name
returns: dict - The node's attrs

Input parameters:

- `id_or_name` (string, required)

### `node_list` (~48 tokens)

List swarm nodes.

args: filters - Filter by attributes (id, name, membership, role)
returns: list - A list of node attrs dicts

Input parameters:

- `filters` (object)

### `node_update` (~150 tokens)

Replace a node's spec (availability, name, role, labels).

Replacement, not a merge: `spec` becomes the node's entire spec, and omitted keys are cleared.
Fetch the current spec via `node_inspect` (its `Spec` key), modify it, and resubmit the whole
dict — e.g. sending just {"Availability": "drain"} would also wipe the node's role and labels.

args:
    id_or_name - The node id or name
    spec - The complete new node spec (see description — omitted keys are cleared)
returns: bool - True after the update

Input parameters:

- `id_or_name` (string, required)
- `spec` (object, required)

Output parameters:

- `result` (boolean)

### `node_remove` (~114 tokens)

Remove a node from the swarm.

A node should normally be drained (`node_update` with Availability "drain") and have left the
swarm first, so its tasks reschedule cleanly. Removing an active/reachable node requires `force=True`.

args:
    id_or_name - The node id or name to remove
    force - Force removal of an active/reachable node
returns: bool - True after the node is removed

Input parameters:

- `force` (boolean)
- `id_or_name` (string, required)

Output parameters:

- `result` (boolean)

### `node_wait` (~302 tokens)

Block until a swarm node's Status.State reaches a target value.

Never raises on timeout — the result always carries `met` and `timed_out`. Polls
\`Status.State` (one of "unknown"/"down"/"ready"/"disconnected") every `poll_interval`s.
Common uses: `until="ready"` after a newly joined node, or `until="down"` while draining a
node before removal. Does not track task placement — for "has this drained node's workload
fully moved off", inspect the relevant services' tasks directly; no single cheap call spans
every service in the swarm, so that check isn't built into this tool.

args:
    id_or_name - The node id or name
    until - Target Status.State to wait for: "ready" (default), "down", "disconnected", "unknown"
    timeout_seconds - Max seconds to wait before returning with timed_out=true (default 300)
    poll_interval - Seconds between re-inspections (default 2, > 0); capped by the time left so
                    a large value can't push the total wait past the timeout
returns: dict - {"node", "until", "met", "timed_out", "state", "availability", "waited_seconds"}

Input parameters:

- `id_or_name` (string, required)
- `poll_interval` (number)
- `timeout_seconds` (number)
- `until` (string)

### `plugin_inspect` (~118 tokens)

Return the full attrs for a single installed plugin.

Use this to check a plugin's `Enabled` state before calling `plugin_enable` /
\`plugin_disable`, or to read the config keys it exposes under `Settings.Env` before
calling `plugin_configure`. For the set of all installed plugins use `plugin_list`.

args: name - Plugin name, e.g. "vieux/sshfs:latest"
returns: dict - The plugin's attrs, including `Enabled` and `Settings`

Input parameters:

- `name` (string, required)

### `plugin_install` (~180 tokens)

Install a plugin from Docker Hub.

\`remote` is a Docker Hub reference in `author/name:tag` form, e.g.
\`vieux/sshfs:latest`. The daemon handles permission grants non-interactively.
After installation use `plugin_inspect` to confirm the plugin's enabled state, then call
\`plugin_enable` to activate it if needed, and optionally `plugin_configure` first if
it requires settings. Use `plugin_list` to list all plugins, or `plugin_remove` to
uninstall.

args:
    remote - Docker Hub plugin reference, e.g. "vieux/sshfs:latest"
    local_name - Alias to refer to the plugin locally; defaults to remote
returns: dict - The installed plugin's attrs

Input parameters:

- `local_name` (string)
- `remote` (string, required)

### `plugin_list` (~25 tokens)

List installed plugins.

returns: list - A list of plugin attrs dicts

### `plugin_configure` (~164 tokens)

Set runtime configuration options on an installed plugin.

Use `plugin_inspect` first to see which keys the plugin exposes under `Settings.Env`; pass
those same keys as a plain dict, e.g. `{"DEBUG": "1", "SOCKET": "/run/x.sock"}`. The
plugin must be disabled before reconfiguring — call `plugin_disable` first if it is
currently active, then `plugin_enable` afterwards to apply the new settings.

args:
    name - Plugin name, e.g. "vieux/sshfs:latest"
    options - Key/value settings to apply, matching the plugin's declared env keys
returns: bool - True after configuration

Input parameters:

- `name` (string, required)
- `options` (object, required)

Output parameters:

- `result` (boolean)

### `plugin_disable` (~144 tokens)

Disable a plugin so it stops intercepting Docker API calls; the plugin remains installed.

A disabled plugin cannot be used by new containers but existing containers that already
have it attached are unaffected. Use `force=True` to disable even if active containers
are still using it — this may cause those containers to lose access to plugin-provided
resources (e.g. a volume driver). Re-enable with `plugin_enable`.

args:
    name - The plugin name
    force - Disable even if active containers are using the plugin (may disrupt them)
returns: bool - True after the plugin is disabled

Input parameters:

- `force` (boolean)
- `name` (string, required)

Output parameters:

- `result` (boolean)

### `plugin_enable` (~151 tokens)

Activate an installed plugin so Docker routes relevant API calls through it.

Activates a plugin that is currently disabled — either freshly installed or previously
disabled via `plugin_disable`. If the plugin exposes configuration (check via
\`plugin_inspect`), call `plugin_configure` while it is still disabled before enabling it.
\`timeout_seconds` controls how long Docker waits for the plugin process to become healthy;
0 means wait indefinitely.

args:
    name - The plugin name to enable
    timeout_seconds - Seconds to wait for the plugin to become healthy (0 = no timeout)
returns: bool - True after the plugin is enabled

Input parameters:

- `name` (string, required)
- `timeout_seconds` (integer)

Output parameters:

- `result` (boolean)

### `plugin_remove` (~56 tokens)

Remove a plugin.

args:
    name - The plugin name
    force - Force removal even if the plugin is enabled
returns: bool - True after removal

Input parameters:

- `force` (boolean)
- `name` (string, required)

Output parameters:

- `result` (boolean)

### `plugin_upgrade` (~159 tokens)

Upgrade an installed plugin to a newer version.

The plugin must be disabled first — call `plugin_disable` before this, then
\`plugin_enable` afterwards to bring it back up. `remote` lets you upgrade to a
different reference (e.g. a newer tag) than the plugin's current name; omit it to
re-pull the same reference. Existing settings and volumes created by the plugin
persist across the upgrade.

args:
    name - The plugin name to upgrade
    remote - Reference to upgrade to, e.g. "vieux/sshfs:next" (default: same as name)
returns: bool - True after the upgrade completes

Input parameters:

- `name` (string, required)
- `remote` (string)

Output parameters:

- `result` (boolean)

### `registry_tags` (~265 tokens)

List tags for a repository in an OCI v2 registry without pulling.

Works against Docker Hub, GHCR, ECR, GAR, and any OCI-compliant registry; anonymous if no
credentials are passed. Talks directly to the registry over HTTPS and does NOT read
\`~/.docker/config.json` — for private registries prefer the DOCKER_MCP_SERVER_REGISTRY_USERNAME /
DOCKER_MCP_SERVER_REGISTRY_PASSWORD env vars (keeps secrets out of tool args, which clients often log).

args:
    repository - Image/repository ref, e.g. "alpine", "ghcr.io/org/repo"; any `:tag`/`@digest` is stripped
    username - Optional registry username (overrides DOCKER_MCP_SERVER_REGISTRY_USERNAME)
    password - Optional registry password/token (overrides DOCKER_MCP_SERVER_REGISTRY_PASSWORD)
    limit - Max tags to return (default 1000, >= 1); pagination capped at 50 pages
returns: dict - {"name": <repo>, "registry": <host>, "tags": [..], "truncated": bool}

Input parameters:

- `limit` (integer)
- `password` (string)
- `repository` (string, required)
- `username` (string)

### `registry_tag_wait` (~428 tokens)

Block until a specific tag appears in a repository (e.g. waiting for a CI push to land).

Never raises on timeout — the result always carries `met` and `timed_out`. Polls `registry_tags`
every `poll_interval`s and checks whether `tag` is in its result. Works against Docker Hub too
(`registry_tags`' own scope covers it), so there is no separate Hub variant. Unlike every other
wait tool, this has no `host` argument — registry tools talk HTTPS directly to the registry, not
a Docker daemon.

Caveat: `registry_tags` paginates up to 50 pages (or `limit` tags, whichever comes first); if
\`tag` would only appear beyond that window it is never found, even once it exists. Raise `limit`
if you expect a very large tag list.

args:
    repository - Image/repository ref, e.g. "alpine", "ghcr.io/org/repo"; any `:tag`/`@digest` is stripped
    tag - The exact tag name to wait for
    username - Optional registry username (overrides DOCKER_MCP_SERVER_REGISTRY_USERNAME)
    password - Optional registry password/token (overrides DOCKER_MCP_SERVER_REGISTRY_PASSWORD)
    limit - Max tags to scan per poll (default 1000, >= 1); forwarded to `registry_tags`
    timeout_seconds - Max seconds to wait before returning with timed_out=true (default 600)
    poll_interval - Seconds between re-checks (default 5, > 0); capped by the time left so a
                    large value can't push the total wait past the timeout
returns: dict - {"repository", "tag", "met", "timed_out", "waited_seconds"}

Input parameters:

- `limit` (integer)
- `password` (string)
- `poll_interval` (number)
- `repository` (string, required)
- `tag` (string, required)
- `timeout_seconds` (number)
- `username` (string)

### `registry_manifest` (~240 tokens)

Fetch a repository's manifest without pulling.

May return a single-platform image manifest or a multi-platform manifest list / OCI image
index, depending on what the registry serves for that tag. Talks HTTPS directly — no daemon
or CLI needed. Alternatives for the same question: `buildx_imagetools_inspect` (uses the
docker CLI and its credential store) and `image_registry_data` (asks the daemon).

args:
    repository - Image/repository ref, e.g. "ghcr.io/org/repo"; `:tag`/`@digest` is stripped — pass via `reference`
    reference - Tag or digest (default "latest")
    username - Optional registry username (overrides DOCKER_MCP_SERVER_REGISTRY_USERNAME; no config.json)
    password - Optional registry password/token (overrides DOCKER_MCP_SERVER_REGISTRY_PASSWORD)
returns: dict - {"name", "registry", "reference", "media_type", "digest", "manifest": <JSON body>}

Input parameters:

- `password` (string)
- `reference` (string)
- `repository` (string, required)
- `username` (string)

### `registry_image_config` (~292 tokens)

Fetch and parse an image's config blob from a registry without pulling.

Answers "what's inside this image?" — env vars, entrypoint/cmd, workdir, exposed ports, user,
labels, layer history (what `registry_manifest` only points at via `config.digest`).
Resolves in up to three hops: manifest -> (if multi-platform) the `platform` entry's manifest
\-> the config blob.

args:
    repository - Image/repository ref, e.g. "ghcr.io/org/repo"; `:tag`/`@digest` is stripped — pass via `reference`
    reference - Tag or digest (default "latest")
    platform - Platform to select from a multi-platform image, "os/arch[/variant]"
                    (default "linux/amd64"); ignored for single-platform images
    username - Optional registry username (overrides DOCKER_MCP_SERVER_REGISTRY_USERNAME)
    password - Optional registry password/token (overrides DOCKER_MCP_SERVER_REGISTRY_PASSWORD)
returns: dict - {"name", "registry", "reference", "platform", "config_digest", "config": <parsed>};
                `platform` is the selected platform (None if single-platform)

Input parameters:

- `password` (string)
- `platform` (string)
- `reference` (string)
- `repository` (string, required)
- `username` (string)

### `hub_tags` (~191 tokens)

List tags on a Docker Hub repository with Hub-specific metadata.

Hits the Hub UI API (hub.docker.com) for richer per-tag data than `registry_tags` —
last pushed date, per-platform sizes, digest. Public repos only: sends no auth and does NOT
read `~/.docker/config.json`; private repos return 404/401 (use `registry_tags` against
registry-1.docker.io with credentials).

args:
    repository - Hub repository, e.g. "library/alpine" or "myorg/myimage"
    limit - Max tags to return (default 100, >= 1); pagination capped at 50 pages
returns: dict - {"name": <repo>, "tags": [{name, full_size, last_updated, digest, images}, ...],
                 "truncated": bool}

Input parameters:

- `limit` (integer)
- `repository` (string, required)

### `hub_repo_info` (~105 tokens)

Fetch Docker Hub metadata for a repository.

Public repos only: sends no auth and does NOT read the local Docker credential store;
private repos return 404/401.

args: repository - Hub repository, e.g. "library/alpine" or "myorg/myimage"
returns: dict - The Hub /v2/repositories/<repo>/ response (description, star_count,
                pull_count, last_updated, is_private, etc.)

Input parameters:

- `repository` (string, required)

### `hub_rate_limit` (~230 tokens)

Report the caller's remaining Docker Hub pull-rate-limit budget.

Sends a HEAD to the `ratelimitpreview/test` manifest (a HEAD isn't metered as a pull, so the
check costs no budget) and reads the RateLimit-Limit / RateLimit-Remaining headers. Call it
before a large `compose_pull` / `image_pull` to avoid hitting the cap mid-deploy. Credentials
raise the limit and switch metering from per-IP to per-account; falls back to
DOCKER_MCP_SERVER_REGISTRY_USERNAME / DOCKER_MCP_SERVER_REGISTRY_PASSWORD, does NOT read `~/.docker/config.json`.
Plans with no limit return no headers — reported as `"unlimited": true`.

args:
    username - Optional Hub username (overrides DOCKER_MCP_SERVER_REGISTRY_USERNAME)
    password - Optional Hub password/token (overrides DOCKER_MCP_SERVER_REGISTRY_PASSWORD)
returns: dict - {"authenticated", "limit", "remaining", "window_seconds", "unlimited"}

Input parameters:

- `password` (string)
- `username` (string)

### `service_create` (~295 tokens)

Create a Swarm service; requires a swarm manager node.

Use this instead of `container_run` when you need replicated or global scheduling,
rolling updates, or automatic restart across the swarm. Common `extra_kwargs` keys:
\`name` (str), `env` (list of "KEY=VAL"), `mode` ({"Replicated": {"Replicas": N}} or
{"Global": {}}), `networks` (list of network names/ids), `endpoint_spec`
({"Ports": [{"PublishedPort": 80, "TargetPort": 8080}]}), `labels` (dict),
\`restart_policy` ({"Condition": "on-failure", "MaxAttempts": 3}),
\`resources` ({"Limits": {"NanoCPUs": 500000000, "MemoryBytes": 134217728}}). For anything else
docker-py's `ServiceCollection.create` accepts, call `docs_lookup(section="services")` rather
than guessing a key name.

args:
    image - Image to run service tasks from (e.g. "nginx:alpine")
    command - Override the image's default command; string or list of strings
    extra_kwargs - Additional docker-py ServiceCollection.create keyword arguments
returns: dict - The created service's attrs

Input parameters:

- `command`
- `extra_kwargs` (object)
- `image` (string, required)

### `service_inspect` (~69 tokens)

Get a swarm service by id or name.

args:
    id_or_name - The service id or name
    insert_defaults - Merge default values into the output
returns: dict - The service's attrs

Input parameters:

- `id_or_name` (string, required)
- `insert_defaults` (boolean)

### `service_list` (~91 tokens)

List swarm services.

args:
    filters - Filter by attributes (id, name, label, mode)
    managed_only - Only return services created by this MCP server (filters on the
                         docker-mcp-server.managed label); combines with any `filters` given
returns: list - A list of service attrs dicts

Input parameters:

- `filters` (object)
- `managed_only` (boolean)

### `service_update` (~180 tokens)

Update a swarm service's configuration, or force a redeploy with no spec change.

Pass exactly one of `updates` (fields to change, same parameters as `service_create`) or
\`force=True` (the `docker service update --force` equivalent: bumps the ForceUpdate counter so
the service's tasks redeploy with an unchanged spec — e.g. to reschedule after a node change or
re-pull a mutable tag).

args:
    id_or_name - The service id or name
    updates - Fields to update on the service; exactly one of updates/force
    force - Redeploy the service without changing its spec; exactly one of updates/force
returns: bool - True after the update

Input parameters:

- `force` (boolean)
- `id_or_name` (string, required)
- `updates` (object)

Output parameters:

- `result` (boolean)

### `service_remove` (~48 tokens)

Stop and remove a swarm service.

args: id_or_name - The service id or name
returns: bool - True after the service is removed

Input parameters:

- `id_or_name` (string, required)

Output parameters:

- `result` (boolean)

### `service_ps` (~73 tokens)

List the tasks of a swarm service.

args:
    id_or_name - The service id or name
    filters - Filter by id, name, node, label, desired-state
returns: list - A list of task dicts

Input parameters:

- `filters` (object)
- `id_or_name` (string, required)

### `service_logs` (~285 tokens)

Get a bounded snapshot of a swarm service's logs (never follows).

\`follow` is intentionally not exposed: the stream is joined into one string before returning, so
following would block forever and grow unbounded. Collection is capped at `max_bytes` (ValueError
if exceeded) so a noisy service can't OOM the server. The default is a bounded `tail=200`;
\`tail="all"` returns the whole buffer, which can be huge on long-running services and exceed
the agent's context — prefer an integer, or `since`, to constrain output.

args:
    id_or_name - The service id or name
    details - Show extra details
    stdout - Include stdout
    stderr - Include stderr
    since - Show logs since this Unix timestamp
    timestamps - Include timestamps
    tail - Number of lines from the end (default 200), or the literal "all" for everything
    max_bytes - Abort with ValueError if the buffered logs exceed this many bytes (default 32 MiB)
returns: str - Decoded log output

Input parameters:

- `details` (boolean)
- `id_or_name` (string, required)
- `max_bytes` (integer)
- `since` (integer)
- `stderr` (boolean)
- `stdout` (boolean)
- `tail`
- `timestamps` (boolean)

Output parameters:

- `result` (string)

### `service_scale` (~172 tokens)

Set the desired replica count for a Replicated-mode swarm service.

Only applies to services in `Replicated` mode; a `Global` service runs one task per
eligible node and has no replica count to set. The swarm scheduler places or removes
tasks asynchronously to converge on the new count — this call returns once the update
is accepted, not once every task is running. Check progress with `service_ps` or
\`service_inspect`. For any other spec change (image, env, resources) use
\`service_update` instead.

args:
    id_or_name - The service id or name
    replicas - The desired number of running task replicas
returns: bool - True once the scale request is accepted

Input parameters:

- `id_or_name` (string, required)
- `replicas` (integer, required)

Output parameters:

- `result` (boolean)

### `service_rollback` (~154 tokens)

Roll a swarm service back to its previous spec (the docker `service rollback` equivalent).

Re-applies the service's `PreviousSpec` — the spec from before the most recent `service_update` /
\`service_scale`. Raises ValueError if the service has no PreviousSpec
(it has never been updated, or was already rolled back). The high-level SDK exposes no rollback,
so this reads the current version and previous spec via the low-level APIClient and submits them
with the low-level `update_service` API call.

args: id_or_name - The service id or name
returns: dict - The daemon response (a dict with a "Warnings" key)

Input parameters:

- `id_or_name` (string, required)

### `service_wait` (~396 tokens)

Block until a swarm service's tasks converge, or a rolling update finishes.

One contract for both modes: never raises on timeout — the result always carries `met` and
\`timed_out`. "running" polls task state via the same task-counting logic as
\`service-tasks://{id_or_name}` (not the unconfirmed daemon `ServiceStatus` field) until running
tasks reach the desired count (Replicated mode) or every returned task is running (Global mode,
which has no fixed target). "update-converged" polls `UpdateStatus.State` until it reaches a
terminal value (`completed` or `rollback_completed`); if the service has never been updated (no
\`UpdateStatus` at all), returns promptly with `met=false` — there's nothing to converge to, same
as `container_wait`'s no-healthcheck case.

args:
    id_or_name - The service id or name
    until - Condition to wait for: "running" (default) or "update-converged"
    replicas - "running" mode only: override the desired replica count (e.g. right after a
               same-turn `service_scale` call, before polling reflects the new target)
    timeout_seconds - Max seconds to wait before returning with timed_out=true (default 600)
    poll_interval - Seconds between re-checks (default 2, > 0); capped by the time left so a
                    large value can't push the total wait past the timeout
returns: dict - {"service", "until", "met", "timed_out", "running_tasks", "desired_tasks",
                 "failed_tasks", "update_state", "waited_seconds"}

Input parameters:

- `id_or_name` (string, required)
- `poll_interval` (number)
- `replicas` (integer)
- `timeout_seconds` (number)
- `until` (string)

### `docs_lookup` (~283 tokens)

Look up Docker SDK/CLI/registry reference documentation by section.

A tool-callable mirror of the docker-docs:// resources, for clients that can't read MCP
resources (e.g. Claude Desktop, Cursor). Always registered regardless of
DOCKER_MCP_SERVER_DISABLE — looking something up costs nothing and isn't tied to any single
Docker feature area — but an individual section still refuses if the domain it documents is
disabled, matching the equivalent `docker-docs://{section}` resource exactly.

Omit `section` to list every available section with its source URL (same as
\`docker-docs://contents`); pass a `section` name to fetch that page's content (same as
\`docker-docs://{section}`). Most useful before constructing an `extra_kwargs`-style passthrough
dict for a tool like `container_run`/`container_create`/`service_create` (their docstrings only
list common keys, not every key docker-py accepts), or before writing Compose/Dockerfile/buildx
bake-file syntax, which no tool generates.

args: section - Section name (from a no-argument call's index); omit to list all sections instead
returns: str - JSON section index (no `section`) or that section's raw HTML/Markdown content

Input parameters:

- `section` (string)

Output parameters:

- `result` (string)

### `scout_cves` (~251 tokens)

List vulnerabilities (CVEs) in an image via Docker Scout.

Anonymous scans work for public images; Hub policy enforcement and richer recommendations need
\`docker login` on the host running this MCP server.

args:
    image - Image reference (a tag or a digest)
    only_fixed - Only report CVEs with a fixed version available
    only_severity - Filter to severities: "critical", "high", "medium", "low", "unspecified"
    ignore_base - Exclude CVEs introduced by the base image
    format - Output format: "json" (default; parsed into the return dict),
                  "sarif", "spdx", "list", "markdown", or "text"
    platform - Platform of the image to analyze, e.g. "linux/amd64"
returns: dict - {"format": <format>, "result": <parsed-json-or-raw-text>,
                 "raw": <CliResult dict>}

Input parameters:

- `format` (string)
- `ignore_base` (boolean)
- `image` (string, required)
- `only_fixed` (boolean)
- `only_severity` (array)
- `platform` (string)

### `scout_quickview` (~118 tokens)

Render a compact summary of an image's CVE posture.

args:
    image - Image reference
    format - Output format: "json" (default) or "text"
    platform - Platform of the image to analyze, e.g. "linux/amd64"
returns: dict - {"format": <format>, "result": <parsed-json-or-raw-text>,
                 "raw": <CliResult dict>}

Input parameters:

- `format` (string)
- `image` (string, required)
- `platform` (string)

### `scout_recommendations` (~208 tokens)

Suggest base-image upgrades for an image.

Computed against Docker Scout's catalog; generally needs `docker login` on the host running this
MCP server to return useful results for private or rarely-scanned base images.

args:
    image - Image reference
    only_refresh - Only show "refresh" recommendations (same major/minor)
    only_update - Only show "update" recommendations (newer minor/major)
    tag - Restrict to suggestions matching this tag pattern
    format - Output format: "json" (default) or "text"
    platform - Platform of the image to analyze
returns: dict - {"format": <format>, "result": <parsed-json-or-raw-text>,
                 "raw": <CliResult dict>}

Input parameters:

- `format` (string)
- `image` (string, required)
- `only_refresh` (boolean)
- `only_update` (boolean)
- `platform` (string)
- `tag` (string)

### `scout_compare` (~261 tokens)

Compare two image references and report the CVE delta.

Exactly one of `to`, `to_env`, or `to_latest=True` must be supplied to identify
the comparison target.

args:
    image - The new / candidate image reference
    to - Compare against this image reference, directory, or archive
    to_env - Compare against an image associated with this Scout environment
    to_latest - Compare against the latest scan of `image`
    only_severity - Filter to severities ("critical", "high", "medium", "low", "unspecified")
    ignore_unchanged - Exclude unchanged packages from the diff
    format - Output format: "json" (default), "markdown", or "text"
    platform - Platform of the image to analyze
returns: dict - {"format": <format>, "result": <parsed-json-or-raw-text>,
                 "raw": <CliResult dict>}

Input parameters:

- `format` (string)
- `ignore_unchanged` (boolean)
- `image` (string, required)
- `only_severity` (array)
- `platform` (string)
- `to` (string)
- `to_env` (string)
- `to_latest` (boolean)

### `scout_sbom` (~229 tokens)

Generate a Software Bill of Materials (SBOM) for an image.

SBOMs can be large; captured stdout is subject to MAX_CLI_OUTPUT_BYTES and may be truncated for
big images. If that's a concern, run `docker scout sbom -o file.json …` on the host and load the
file separately.

args:
    image - Image reference
    format - SBOM format: "spdx" (default, SPDX JSON), "cyclonedx" (CycloneDX JSON),
                  "json" (Scout's native JSON), "list" (plain-text package list)
    platform - Platform of the image to analyze
returns: dict - {"format", "result", "raw": <CliResult dict>}. `result` is a parsed dict when
                `format` is "spdx"/"cyclonedx"/"json" and stdout parses cleanly; for "list" or a
                parse failure it's the raw text.

Input parameters:

- `format` (string)
- `image` (string, required)
- `platform` (string)

### `secret_create` (~88 tokens)

Create a swarm secret.

args:
    name - The name of the secret
    data - The secret payload
    labels - Labels to set on the secret
    driver - Optional secret driver configuration
returns: dict - The created secret's attrs

Input parameters:

- `data` (string, required)
- `driver` (object)
- `labels` (object)
- `name` (string, required)

### `secret_inspect` (~159 tokens)

Get a swarm secret's metadata by id or name; requires a swarm manager.

The returned attrs never include the secret's actual data (`Spec.Data` is write-only —
the daemon accepts it on `secret_create` but never returns it back, by design). Use this
to check a secret's `CreatedAt`, `Labels`, or which driver created it, not to read its
contents. To see which services reference it, inspect each service's spec via
\`service_inspect` (there is no server-side filter for "services using this secret").

args: id_or_name - The secret id or name
returns: dict - The secret's attrs, excluding the actual secret data

Input parameters:

- `id_or_name` (string, required)

### `secret_list` (~102 tokens)

List swarm secrets' metadata; requires a swarm manager.

Like `secret_inspect`, results never include secret data, only metadata (name, id,
labels, timestamps). Valid filter keys: `id`, `name`, `names`, `label` (key or
key=value).

args: filters - Narrow the list; omit to return every secret
returns: list - A list of secret attrs dicts (data-free)

Input parameters:

- `filters` (object)

### `secret_remove` (~123 tokens)

Remove a Swarm secret; requires a swarm manager.

Removing a secret does not immediately affect running service tasks — tasks that already
have the secret mounted retain access until they are restarted or the service is updated.
Use `service_list` and inspect each service's spec via `service_inspect` to identify
services that mount the secret before removing it (service filters do not support
filtering by secret reference).

args: id_or_name - The secret id or name to remove
returns: bool - True after removal

Input parameters:

- `id_or_name` (string, required)

Output parameters:

- `result` (boolean)

### `stack_deploy` (~320 tokens)

Deploy (or update) a stack to the swarm from one or more Compose files.

Requires the target daemon to be a swarm manager. Re-running with the same `name` updates
the stack in place. Defaults to `detach=True` (returns once specs are submitted, not on
convergence); set `detach=False` to wait for the rollout (give it a generous `timeout_seconds`).

args:
    name - Name of the stack to create or update
    compose_files - One or more Compose file paths (repeated `-c`; later override earlier). At least one required.
    with_registry_auth - Send registry credentials to swarm agents (needed for private images)
    prune - Remove services no longer defined in the Compose file
    resolve_image - Image-digest resolution: "always" (default), "changed", or "never"
    detach - Return immediately after submitting specs (True) vs wait for convergence (False)
    cwd - Working directory for resolving relative Compose paths (defaults to the server's cwd)
    timeout_seconds - Subprocess timeout (default 1800s)
returns: dict - {"returncode": int, "stdout": str, "stderr": str, "truncated": bool}

Input parameters:

- `compose_files` (array, required)
- `cwd` (string)
- `detach` (boolean)
- `name` (string, required)
- `prune` (boolean)
- `resolve_image` (string)
- `timeout_seconds` (number)
- `with_registry_auth` (boolean)

### `stack_list` (~58 tokens)

List the stacks deployed to the swarm, parsed from `--format '{{json .}}'`.

Requires the target daemon to be a swarm manager (raises otherwise).

returns: list - One dict per stack (name, services count, orchestrator)

### `stack_ps` (~126 tokens)

List the tasks of a stack, parsed from `--format '{{json .}}'`.

args:
    name - The stack to list tasks for
    no_trunc - Do not truncate task IDs / errors in the output
    filters - Filter by attributes, e.g. {"desired-state": "running"}; a list value repeats the filter
returns: list - One dict per task (id, name, node, image, desired/current state, error)

Input parameters:

- `filters` (object)
- `name` (string, required)
- `no_trunc` (boolean)

### `stack_services` (~98 tokens)

List the services of a stack, parsed from `--format '{{json .}}'`.

args:
    name - The stack to list services for
    filters - Filter by attributes, e.g. {"name": "web"}; a list value repeats the filter
returns: list - One dict per service (id, name, mode, replicas, image, ports)

Input parameters:

- `filters` (object)
- `name` (string, required)

### `stack_remove` (~167 tokens)

Remove one or more stacks from the swarm (tears down their services, networks, and secrets).

Destructive: this stops and deletes every service in the named stack(s). Defaults to
\`detach=True` so the call returns once removal is requested rather than waiting for teardown.

args:
    names - One or more stack names to remove. At least one is required.
    detach - Return immediately (True) vs wait for the stack(s) to be fully removed (False)
    timeout_seconds - Subprocess timeout (default 300s)
returns: dict - {"returncode": int, "stdout": str, "stderr": str, "truncated": bool}

Input parameters:

- `detach` (boolean)
- `names` (array, required)
- `timeout_seconds` (number)

### `swarm_init` (~418 tokens)

Initialize a new swarm, making this Engine its first manager node.

Fails if the Engine is already part of a swarm — call `swarm_leave` first to reset it.
\`advertise_addr` only needs setting when the host has multiple network interfaces or is
behind NAT (otherwise it is auto-detected); it must be reachable by every other node
that will join. To add more nodes afterwards, retrieve join tokens with
\`swarm_join_tokens` and call `swarm_join` on each one. Set `autolock_managers=True` to
require the unlock key (`swarm_unlock_key`) on every manager restart — store that key
securely immediately, since it is only shown once autolock is enabled.

args:
    advertise_addr - Externally reachable address advertised to other nodes
    listen_addr - Listen address used for inter-manager communication
    force_new_cluster - Force a new single-node cluster from this node's current state
                         (disaster recovery when a majority of managers is lost)
    default_addr_pool - IP address pools for swarm overlay networks
    subnet_size - Subnet size for the IP pool
    data_path_addr - Address to use for data path traffic
    data_path_port - Port number for data path traffic
    name - Name of the swarm
    labels - Labels to set on the swarm
    autolock_managers - Require the unlock key after every manager restart
    log_driver - Default log driver configuration
returns: str - The node id of the newly created swarm manager

Input parameters:

- `advertise_addr` (string)
- `autolock_managers` (boolean)
- `data_path_addr` (string)
- `data_path_port` (integer)
- `default_addr_pool` (array)
- `force_new_cluster` (boolean)
- `labels` (object)
- `listen_addr` (string)
- `log_driver` (object)
- `name` (string)
- `subnet_size` (integer)

Output parameters:

- `result` (string)

### `swarm_join` (~269 tokens)

Join this Engine to an existing swarm as a worker or manager.

Fails if the Engine is already part of a swarm. Whether this node joins as a worker or
a manager is determined entirely by which token is passed — `join_token` must be one of
the two tokens from `swarm_join_tokens`, called against any existing manager. `advertise_addr`
only needs setting when this host has multiple network interfaces or is behind NAT
(otherwise it is auto-detected from the interface used to reach `remote_addrs`); it must
be reachable by every other node in the swarm.

args:
    remote_addrs - Address(es) of existing swarm managers to connect to
    join_token - The worker or manager join token (from `swarm_join_tokens`) — determines
                 the role this node joins as
    listen_addr - Listen address for inter-manager communication
    advertise_addr - Externally reachable address advertised to other nodes
    data_path_addr - Address to use for data path traffic
returns: bool - True after the engine joins the swarm

Input parameters:

- `advertise_addr` (string)
- `data_path_addr` (string)
- `join_token` (string, required)
- `listen_addr` (string)
- `remote_addrs` (array, required)

Output parameters:

- `result` (boolean)

### `swarm_leave` (~45 tokens)

Leave the current swarm.

args: force - Force leave even if the node is a manager
returns: bool - True after leaving the swarm

Input parameters:

- `force` (boolean)

Output parameters:

- `result` (boolean)

### `swarm_update` (~209 tokens)

Update swarm-wide settings: the single home for join-token and unlock-key rotation.

Must be called on a swarm manager node. Token rotation invalidates the old join token
immediately — nodes that have not yet joined using the old token must use the new one.
Existing joined nodes are unaffected. Use `swarm_join_tokens` to retrieve the new
tokens after rotation. Rotating the unlock key requires all managers to be re-unlocked
on restart with the new key; retrieve it immediately via `swarm_unlock_key`.

args:
    rotate_worker_token - Issue a new worker join token, invalidating the current one
    rotate_manager_token - Issue a new manager join token, invalidating the current one
    rotate_manager_unlock_key - Issue a new autolock unlock key for manager restart
returns: bool - True after the update completes

Input parameters:

- `rotate_manager_token` (boolean)
- `rotate_manager_unlock_key` (boolean)
- `rotate_worker_token` (boolean)

Output parameters:

- `result` (boolean)

### `swarm_inspect` (~48 tokens)

Inspect the swarm this daemon belongs to (id, spec, join-token config, CA info).

returns: dict - The swarm's attrs, as returned by the daemon's swarm inspect endpoint

### `swarm_unlock` (~177 tokens)

Unlock a manager node that is locked after restart due to autolock being enabled.

When autolock is enabled (via `swarm_init` or `swarm_update`), manager nodes require
the unlock key after every restart before they can rejoin the swarm and resume
scheduling. Must be called on the locked manager node directly. Retrieve the current
unlock key with `swarm_unlock_key` from any unlocked manager — store it securely
when enabling autolock. A locked node cannot serve API requests and cannot return its
own key while locked; other unlocked managers in the swarm can still serve the key.
Once unlocked the manager resumes automatically.

args: key - The swarm unlock key (from `swarm_unlock_key`)
returns: bool - True after the swarm is unlocked

Input parameters:

- `key` (string, required)

Output parameters:

- `result` (boolean)

### `swarm_unlock_key` (~124 tokens)

Return the swarm's current unlock key.

The key only serves a purpose when autolock is enabled (see `swarm_init`'s /
\`swarm_update`'s `autolock_managers` / `rotate_manager_unlock_key`). Must be called
against an unlocked manager — a locked manager cannot serve API requests, including
this one. Feed the result's key to `swarm_unlock` to unlock a manager after restart.
Treat the key as a sensitive credential.

returns: dict - {"UnlockKey": <the current unlock key>}

### `swarm_join_tokens` (~131 tokens)

Return the swarm's worker and manager join tokens.

These are the tokens a new node passes to `swarm_join` — without one, `swarm_join` cannot be
called, so this closes the init -> join loop. The tokens are secret bearer credentials (anyone
holding the manager token can join as a manager); treat the result as sensitive and avoid logging
it. Reads `swarm.attrs["JoinTokens"]` after a reload, so it always reflects the current tokens.

returns: dict - {"Worker": <worker join token>, "Manager": <manager join token>}

### `volume_create` (~276 tokens)

Create a volume managed by Docker.

Named volumes persist after their containers stop or are removed; use them for
databases, uploads, or any data that must outlive a container. Anonymous volumes
(no `name`) are only removed automatically when the container was started with `--rm`
or removed with `docker rm -v`; otherwise they accumulate and must be pruned manually.
Common `driver_opts` for the default `local` driver: bind-mount an existing host path
with `{"type": "none", "device": "/host/path", "o": "bind"}`, or mount an NFS share
with `{"type": "nfs", "device": "server:/export", "o": "addr=server,rw"}`. Third-party
drivers (e.g. `rexray`, `convoy`) accept their own option keys.

args:
    name - Volume name; auto-generated if omitted (creates an anonymous volume)
    driver - Volume driver to use (default: "local")
    driver_opts - Driver-specific options dict
    labels - Labels to set on the volume
returns: dict - The created volume's attrs

Input parameters:

- `driver` (string)
- `driver_opts` (object)
- `labels` (object)
- `name` (string)

### `volume_inspect` (~40 tokens)

Get a volume by name.

args: name - The volume name
returns: dict - The volume's attrs

Input parameters:

- `name` (string, required)

### `volume_list` (~91 tokens)

List volumes.

args:
    filters - Filter by attributes (e.g. dangling, name, label)
    managed_only - Only return volumes created by this MCP server (filters on the
                         docker-mcp-server.managed label); combines with any `filters` given
returns: list - A list of volume attrs dicts

Input parameters:

- `filters` (object)
- `managed_only` (boolean)

### `volume_prune` (~160 tokens)

Remove volumes not referenced by any container, running or stopped.

A volume used by even one stopped container is not "unused" and survives the prune —
remove the container first (or use `container_prune`, then this) to reclaim its
volumes. Valid filter keys: `label` (key or key=value), `all` ("true" as a string —
without it only anonymous volumes are eligible, matching `docker volume prune`'s
default). Use `volume_list` first to see what currently exists.

args: filters - Narrow which unused volumes to remove; omit to remove all anonymous ones
returns: dict - {"VolumesDeleted": [...], "SpaceReclaimed": <bytes>}

Input parameters:

- `filters` (object)

### `volume_remove` (~129 tokens)

Remove a single volume by name.

Fails if any container, running or stopped, still references the volume — remove or
recreate those containers first, or pass `force=True` to remove it anyway (the
containers keep their reference but lose the underlying data). For bulk cleanup of
volumes with no container references at all, use `volume_prune` instead.

args:
    name - Volume name to remove
    force - Remove even if a container still references the volume
returns: bool - True after removal

Input parameters:

- `force` (boolean)
- `name` (string, required)

Output parameters:

- `result` (boolean)

## Diagnostics

Captured diagnostic sections: Provenance. The full working is on the page: https://verifymcp.io/servers/gavinlucas-docker-mcp-server/ghcr-io-gavinlucas-docker-mcp-server-2-1-1#diagnostics

## Score history

- 2026-08-03: 33
- 2026-08-02: 29
- 2026-08-01: 29
- 2026-07-31: 29
- 2026-07-30: 31
- 2026-07-29: 31
- 2026-07-28: 31
- 2026-07-27: 31
- 2026-07-26: 31

## Links

- Changelog RSS feed: https://verifymcp.io/servers/gavinlucas-docker-mcp-server/ghcr-io-gavinlucas-docker-mcp-server-2-1-1/changelog.xml
- Changelog JSON feed: https://verifymcp.io/servers/gavinlucas-docker-mcp-server/ghcr-io-gavinlucas-docker-mcp-server-2-1-1/changelog.json
- HTML version of this page: https://verifymcp.io/servers/gavinlucas-docker-mcp-server/ghcr-io-gavinlucas-docker-mcp-server-2-1-1
