# Docker MCP Server (oci · ghcr.io/l337-org/docker-mcp-server:2.2.2)

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

- Trust score: 33/100 (low)
- Registry status: active
- Liveness: live
- Owner verified: no
- Last scored: 2026-08-03

## Components

- mcpb · `docker-mcp-server-2.2.2.mcpb`: 13/100, [markdown](https://verifymcp.io/servers/l337-org-docker-mcp-server/https-github-com-l337-org-docker-mcp-releases-download-v2-2-2-docker-mcp-server.md), [page](https://verifymcp.io/servers/l337-org-docker-mcp-server/https-github-com-l337-org-docker-mcp-releases-download-v2-2-2-docker-mcp-server)
- oci · `ghcr.io/l337-org/docker-mcp-server:2.2.2`: 33/100 (this document), [markdown](https://verifymcp.io/servers/l337-org-docker-mcp-server/ghcr-io-l337-org-docker-mcp-server-2-2-2.md), [page](https://verifymcp.io/servers/l337-org-docker-mcp-server/ghcr-io-l337-org-docker-mcp-server-2-2-2)
- pypi · `docker-mcp-server`: 25/100, [markdown](https://verifymcp.io/servers/l337-org-docker-mcp-server/docker-mcp-server.md), [page](https://verifymcp.io/servers/l337-org-docker-mcp-server/docker-mcp-server)

## Channel facts

- Registry: `oci`
- Package: `ghcr.io/l337-org/docker-mcp-server:2.2.2`
- 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**: 32/100
  - Source repository is publicly reachable at the declared URL.
  - Provenance check failed: no build-provenance attestation is published.
  - License check failed: no license is declared.
  - Actively maintained (last published 2 days ago).
  - Disclosure check failed: no security disclosure policy was found in the source repository.
- **Schema Quality & AI Usability**: 72/100
  - 100% of prompts and resources have a non-trivial description (not blank, and not just the item's name).
  - AI-judged instruction clarity (good).
  - Context-footprint check failed: tool/resource definitions use about 35053 tokens (~216/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**: 0/100
  - Stability not yet verified: not enough scan history yet (needs a 30-day window).
- **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 current MCP spec version (2026-07-28).

**Unverified: 2 categories.** Categories scored 0 because we could not verify them: 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 l337-org-docker-mcp-server -- docker run --rm -i ghcr.io/l337-org/docker-mcp-server:2.2.2
```

### Codex

```bash
codex mcp add l337-org-docker-mcp-server -- docker run --rm -i ghcr.io/l337-org/docker-mcp-server:2.2.2
```

### opencode

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

### Hermes

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

### Other

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

## 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-01 (score 33, +27)

- [security] Stability: Stability not yet verified: not enough scan history yet (needs a 30-day window).
- [functional improvement] MCP protocol: unverified → pass
- [functional improvement] Schema quality: unverified → 100
- [functional improvement] Tool coverage: unverified → 100
- [functional] First check of Schema quality: good
- [functional] First check of Schema quality: fail
- [functional] First check of Tool coverage: 0
- [functional] First check of Tool coverage: 23
- [functional] First check of Schema quality: fail

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

First indexed and scored.

## MCP tools (156)

### `buildx_build` (~1026 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.
With no local buildx plugin and an `ssh://` target, the build runs on that host: a local `context`
directory is copied there honouring `.dockerignore`, as are `file`, `build_contexts` and `secret`
paths. Raises RuntimeError in that case for `output`/`cache_to` with a filesystem `dest=`,
\`cache_from` with a local `src=`, or any `ssh=` — each would resolve on the remote machine, losing
the output or silently changing the build.

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. Copied
                   to the target host when it names a local directory and there is no local plugin.
    tags - Image references to apply (`-t`, repeatable)
    platforms - Target platforms, e.g. ["linux/amd64", "linux/arm64"]
    file - Dockerfile path. A relative path resolves against this server's working directory
                  (buildx's own rule), NOT against `context` — pass e.g. "ctx/Dockerfile" for a
                  Dockerfile inside the context directory "ctx".
    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 (mutual…

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` (~327 tokens)

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

Use it for multi-target builds declared in `docker-bake.hcl`/compose files; for a single
Dockerfile target use `buildx_build`.
Does not raise on a non-zero CLI exit — inspect `returncode`/`stderr` in the result.

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; copied to
                  the target host if no local plugin)
    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` (~316 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. Verify
the result with `buildx_imagetools_inspect`.
Does not raise on a non-zero CLI exit — inspect `returncode`/`stderr` in the result.

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 (copied to the
                        target host if no local plugin)
    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` (~105 tokens)

List builder instances.

Machine-parsed view of every builder; use `buildx_inspect` for one builder's human-readable
detail and `buildx_use` to switch the default.
Raises RuntimeError if the CLI call fails.

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` (~249 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.
Raises RuntimeError if the CLI call fails.

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` (~152 tokens)

Inspect a builder instance.

Human-readable detail (driver, status, supported platforms) for one builder; `buildx_list`
returns machine-parsed JSON for all builders.
Does not raise on a non-zero CLI exit — inspect `returncode`/`stderr` in the result.

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` (~160 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. Reclaim the cache with `buildx_prune` (`system_df` covers daemon-side
disk, not builder cache).
Raises RuntimeError if the CLI call fails.

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` (~348 tokens)

Create a new BuildKit builder instance.

Needed when the default `docker` driver falls short: multi-platform builds and cache export
require a `docker-container` (or `kubernetes`/`remote`) builder. Pass `use=True` to make it
the default for later `buildx_build` calls (else switch with `buildx_use`); `bootstrap=True`
starts the builder now rather than on first build.
Does not raise on a non-zero CLI exit — inspect `returncode`/`stderr` in the result.

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 (copied to the target host if no local plugin)
    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` (~204 tokens)

Remove a builder instance.

Deletes a builder made by `buildx_create`, including its build cache unless keep_state=True;
use `buildx_prune` to reclaim cache while keeping the builder.
Does not raise on a non-zero CLI exit — inspect `returncode`/`stderr` in the result.

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` (~83 tokens)

Check that the Docker server is responsive.

The cheapest daemon health check. A failure here usually means connection config rather than
daemon load — `system_reconnect` rebuilds a wedged client, `host_list` shows the configured
endpoints. For daemon details use `system_version` / `system_info`.

returns: bool - True if the daemon responded successfully

Output parameters:

- `result` (boolean)

### `system_version` (~81 tokens)

Return Docker server version information.

Engine version, API level, and per-component versions — the first thing to check for feature
availability. `system_info` reports runtime state (counts, drivers, swarm role) instead.

returns: dict - {"Version", "ApiVersion", "MinAPIVersion", "Os", "Arch", "Components", ...}

### `system_info` (~85 tokens)

Return system-wide Docker information, like `docker info`.

Daemon runtime state: container/image counts, storage and logging drivers, swarm role, and
daemon warnings. Use `system_version` for version/API level and `system_df` for disk usage.

returns: dict - {"Containers", "Images", "Driver", "ServerVersion", "Swarm", "Warnings", ...}

### `system_df` (~135 tokens)

Summarize Docker disk usage: layer storage plus per-object sizes for images, containers, volumes, build cache.

Equivalent to `docker system df`. Use it to find what to reclaim before `image_prune` /
\`container_prune` / `volume_prune` / `buildx_prune`; use `system_info` for daemon config and
counts rather than sizes. The reply enumerates every object on the daemon, so expect a large
payload on busy hosts.

returns: dict - {"LayersSize", "Images", "Containers", "Volumes", "BuildCache"} with per-object
    size fields

### `host_list` (~164 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 that the `host` argument selects from. The `default` entry is the one used when
\`host` is omitted; pass a `name` as the `host` argument of daemon-backed tools
(`system_ping(host=...)` checks one entry). The `docker-mcp://hosts` resource mirrors this
tool.

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` (~233 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. Credentials let
\`image_pull` / `image_push` reach private repositories; `system_logout` clears them.

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 login response: {"Status"} always; "IdentityToken" only when the registry issues one

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` (~145 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. `system_close` closes pooled clients without rebuilding;
\`host_list` shows the configured endpoints.

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

### `compose_up` (~310 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, copied to the target host if no local
                  plugin; 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` (~261 tokens)

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

Inverse of `compose_up`. Images are kept; named volumes go only with volumes=True
(destructive). Use `compose_stop` to stop without removing anything.
Does not raise on a non-zero CLI exit — inspect `returncode`/`stderr` in the result.

args:
    project_dir - Dir with the compose file (default: server cwd; copied to the target host if no local plugin)
    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` (~226 tokens)

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

Container-level view of one project (state, health, publishers); `compose_list` enumerates
projects, and `container_list` covers non-compose containers.
Does not raise on a non-zero CLI exit: `services` comes back empty — inspect `raw.stderr`.

args:
    project_dir - Dir with the compose file (default: server cwd; copied to the target host if no local plugin)
    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` (~312 tokens)

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

Bounded and non-following by design, so it always returns promptly. For one container's logs
use `container_logs`; for a swarm service use `service_logs`. Log text arrives on `stdout`.
Does not raise on a non-zero CLI exit — inspect `returncode`/`stderr` in the result.

args:
    project_dir - Dir with the compose file (default: server cwd; copied to the target host if no local plugin)
    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` (~246 tokens)

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

Use it to validate compose files and see exactly what the CLI will run before `compose_up`.
Does not raise on a non-zero CLI exit: on a failed render `config` may be None — inspect
\`raw.stderr`.

args:
    project_dir - Dir with the compose file (default: server cwd; copied to the target host if no local plugin)
    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` (~247 tokens)

Build images for a compose project.

Builds the images declared by the project's `build:` sections without starting anything —
\`compose_up(build=True)` builds and starts in one step.
Does not raise on a non-zero CLI exit — inspect `returncode`/`stderr` in the result.

args:
    project_dir - Dir with the compose file (default: server cwd; copied to the target host if no local plugin)
    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` (~273 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; copied to the target host if no local plugin)
    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` (~265 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; copied to the target host if no local plugin)
    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` (~210 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; copied to the target host if no local plugin)
    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` (~193 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; copied to the target host if no local plugin)
    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` (~361 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. Unlike `compose_exec`, this starts a NEW container for the service rather than
running inside the existing one.

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; copied to the target host if no local plugin)
    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` (~319 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; copied to the target host if no local plugin)
    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` (~200 tokens)

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

Answers "what image and tag does each service container actually run?" — the containers must
exist (`compose_up`/`compose_create` first). Use `compose_ps` for container state and
\`image_list` for daemon-wide images.
Raises RuntimeError if the CLI call fails.

args:
    project_dir - Dir with the compose file (default: server cwd; copied to the target host if no local plugin)
    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` (~329 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. For non-compose containers
read `container_inspect`'s NetworkSettings.Ports instead.
Raises RuntimeError if the CLI call fails.

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; copied to the target host if no local plugin)
    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` (~228 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. For a single container use `container_wait`; for swarm services
use `service_wait`.

args:
    services - One or more services to wait on. At least one is required.
    project_dir - Dir with the compose file (default: server cwd; copied to the target host if no local plugin)
    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` (~194 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`. The
per-container equivalent is `container_top`.
Does not raise on a non-zero CLI exit — inspect `returncode`/`stderr` in the result.

args:
    services - Restrict to these services (default: all)
    project_dir - Dir with the compose file (default: server cwd; copied to the target host if no local plugin)
    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` (~529 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
\`container_archive_get`.
Does not raise on a non-zero CLI exit — inspect `returncode`/`stderr` in the result. With no local
compose plugin and an `ssh://` target, runs the real `docker compose cp` on that host instead and
relays whichever side of the copy is local over the same SSH connection — every parameter above
behaves the same either way, since the actual copy always runs through the real CLI. The one
difference: a container->host copy is refused with `FileExistsError` if the local destination already
exists, since only this host (not the remote one) knows that. `unix://`/`tcp://`+TLS hosts with no
local plugin are not covered by this fallback (no shell to run the CLI on) and still raise
\`RuntimeError` — use `container_archive_put` (host to container) or `container_archive_get_to_file`
(container to host) there instead; both talk to the daemon directly and need no local CLI
(`compose_ps` gives you the container name).

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; copied to the target host if no local plugin)
    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` (~250 tokens)

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

Immediate, with no grace period — prefer `compose_stop` for a clean shutdown (stop signal,
then kill after a timeout).
Does not raise on a non-zero CLI exit — inspect `returncode`/`stderr` in the result.

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; copied to the target host if no local plugin)
    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` (~220 tokens)

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

Paused containers stop consuming CPU but keep memory, network endpoints, and state; resume
with `compose_unpause`. To actually stop containers (each one's configured stop signal,
freeing resources) use `compose_stop`; to stop and delete them use `compose_down`.
Does not raise on a non-zero CLI exit — inspect `returncode`/`stderr` in the result.

args:
    services - Restrict to these services (default: all)
    project_dir - Dir with the compose file (default: server cwd; copied to the target host if no local plugin)
    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` (~195 tokens)

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

Reverse of `compose_pause`: processes continue from where they were frozen (no restart).
\`compose_start` is the counterpart for stopped containers.
Does not raise on a non-zero CLI exit — inspect `returncode`/`stderr` in the result.

args:
    services - Restrict to these services (default: all)
    project_dir - Dir with the compose file (default: server cwd; copied to the target host if no local plugin)
    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` (~85 tokens)

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

Project-level view (one entry per project); `compose_ps` lists the containers of a single
project.
Raises RuntimeError if the CLI call fails.

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

Input parameters:

- `all` (boolean)

### `config_create` (~243 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 ({"ID", "Version", "CreatedAt", "Spec", ...})

Input parameters:

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

### `config_inspect` (~124 tokens)

Get a swarm config's full inspect payload by id or name.

Requires a swarm manager. Unlike a secret, a config's payload IS readable after creation:
\`Spec.Data` in the result holds the base64-encoded contents. Use `config_list` to enumerate
configs; use this to read one config's contents and metadata.

args: id_or_name - The config id or name
returns: dict - The config's attrs (ID, CreatedAt, UpdatedAt, Spec{Name, Labels, Data base64})

Input parameters:

- `id_or_name` (string, required)

### `config_list` (~121 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). Fetch a single config by id/name with `config_inspect`.

args: filters - Narrow the list; omit to return every config
returns: list - One full config document ({"ID", "Spec", ...}) per config

Input parameters:

- `filters` (object)

### `config_remove` (~79 tokens)

Remove a swarm config.

Requires a swarm manager, and fails while any service still references the config — update or
remove those services first. The last step of the rotation flow described in `config_create`.

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` (~529 tokens)

Run a container from an image (create and start in one call, like `docker run`).

Use `container_create` to prepare a container without starting it, or `container_exec` to run
a command in a container that already exists. With detach=False the call blocks until the
container exits and returns its output, so long-running images need detach=True. Created
containers are stamped with provenance labels.

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` (~131 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. To enumerate many
containers use `container_list` instead (same payload per container by default; abridged
with sparse=True). 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` (~290 tokens)

List containers on the daemon (running only by default).

Pass all=True to include stopped containers. For a compose project `compose_ps` groups
containers by service; for swarm services use `service_ps` (tasks may live on other nodes).

args:
    all - Show all containers, including stopped ones (default False: running only)
    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 - One dict per container: full inspect payloads by default (each match is
    inspected, like `container_inspect`); sparse=True skips the per-container inspect calls
    and returns the daemon's abridged list entries instead

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` (~121 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 inspect payload after starting

Input parameters:

- `id_or_name` (string, required)

### `container_stop` (~186 tokens)

Gracefully stop a running container (its configured stop signal, then SIGKILL after a timeout).

Prefer this over `container_kill` for a clean shutdown: the main process receives the
container's stop signal (`STOPSIGNAL`, default SIGTERM) and has stop_timeout_seconds to exit
before the daemon force-kills it. Use `container_restart` to stop and start again in one call,
or `container_pause` to freeze processes without stopping. When the server runs containerized
it refuses to stop its own container.

args:
    id_or_name - The container id or name
    stop_timeout_seconds - Seconds between the stop signal and SIGKILL (default 10)
returns: dict - The container's attrs after the stop (exit code under State.ExitCode)

Input parameters:

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

### `container_restart` (~147 tokens)

Restart a container: stop then start again in one call.

The container receives its configured stop signal (`STOPSIGNAL`, default SIGTERM), SIGKILL
after stop_timeout_seconds, and is then started. Use `container_stop`/`container_start` to do
the halves separately. When the server runs containerized it refuses to restart its own
container.

args:
    id_or_name - The container id or name
    stop_timeout_seconds - Seconds between the stop signal and SIGKILL (default 10)
returns: dict - The container's full inspect payload after the restart

Input parameters:

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

### `container_kill` (~188 tokens)

Send a signal to a running container (default SIGKILL — immediate, no graceful shutdown).

Use it to force-kill a container that ignores `container_stop`, or with `signal` to poke a
process without stopping it (e.g. SIGHUP for a config reload). For a normal shutdown prefer
\`container_stop`, which sends the container's configured stop signal first. Fails with a
conflict error if the container is not running. When the server runs containerized it refuses
to signal its own container.

args:
    id_or_name - The container id or name
    signal - Signal name or number as a string (e.g. "SIGHUP", "9"); default SIGKILL
returns: dict - The container's full inspect payload after the signal

Input parameters:

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

### `container_pause` (~127 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 full inspect payload after pause (State.Paused true)

Input parameters:

- `id_or_name` (string, required)

### `container_unpause` (~100 tokens)

Resume all processes in a paused container (the reverse of `container_pause`).

Only valid on a paused container — it fails if the container is merely stopped; use
\`container_start` for stopped containers. Processes continue from where they were frozen.

args: id_or_name - The container id or name
returns: dict - The container's attrs after unpause (State.Paused becomes false)

Input parameters:

- `id_or_name` (string, required)

### `container_remove` (~172 tokens)

Remove a container, deleting its writable layer.

The image is untouched (`image_remove` deletes images); named volumes are never removed —
volumes=True only covers anonymous ones. A running container is refused unless force=True,
which kills it first. When the server runs containerized it refuses to remove its own
container.

args:
    id_or_name - The container id or name
    volumes - Also remove anonymous volumes (the CLI's `--volumes`); named volumes persist
    link - Remove the specified link
    force - Kill a running container before removing it (default False: running is an error)
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` (~135 tokens)

Get one point-in-time resource-usage snapshot for a container (non-streaming).

Returns the raw engine stats payload; CPU percent must be computed from the delta between
\`cpu_stats` and `precpu_stats`. For a pre-computed human-readable summary prefer the
\`docker-stats://{id_or_name}` resource; for a process listing use `container_top`.

args: id_or_name - The container id or name
returns: dict - Engine stats payload (read, cpu_stats, precpu_stats, memory_stats, networks,
    pids_stats, ...)

Input parameters:

- `id_or_name` (string, required)

### `container_top` (~161 tokens)

List the processes running inside a container (the daemon runs `ps` on the host).

Works on any running container without executing anything in it, so it needs no shell or `ps`
binary in the image — unlike `container_exec` with `ps`. Use `container_stats` for resource
usage rather than process lists. Fails if the container is not running.

args:
    id_or_name - The container id or name
    ps_args - Extra ps arguments (e.g. "aux"); default is the daemon's standard ps invocation
returns: dict - {"Titles": [ps column names], "Processes": [[one row of values per process]]}

Input parameters:

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

### `container_exec` (~342 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 - {"exit_code", "output"}; output is combined stdout+stderr, or a
    [stdout, stderr] pair with demux=True

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` (~323 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 `image_build` with a Dockerfile instead; publish the result with
\`image_tag` + `image_push`. 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 full inspect payload (Id is the new image id)

Input parameters:

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

### `container_diff` (~117 tokens)

List filesystem changes a container has made relative to its image.

Use it to audit what a container wrote before `container_commit` or `container_archive_get`,
or to debug unexpected writes. Only the writable container layer is compared — files in
volumes and bind mounts never show up.

args: id_or_name - The container id or name
returns: list - Dicts of {"Path", "Kind"}; Kind 0=modified, 1=added, 2=deleted

Input parameters:

- `id_or_name` (string, required)

### `container_rename` (~143 tokens)

Rename a container in place; its id, state, and configuration are unchanged.

Use it to free up or claim a container name (names are unique per daemon) — e.g. before
starting a replacement under the old name. Fails with a conflict error if the new name is
already taken. Not related to `image_tag`, which names images.

args:
    id_or_name - The container id or name
    name - The new name; must not be in use by any other container
returns: dict - The container's full inspect payload after the rename

Input parameters:

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

### `container_update` (~246 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 (`container_remove` +
\`container_run`).

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 inspect payload after the update

Input parameters:

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

### `container_wait` (~698 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`. For a compose
project use `compose_wait`; for swarm services use `service_wait`.

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 t…

Input parameters:

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

### `container_export` (~316 tokens)

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

The tar is a flat filesystem snapshot with no image metadata or layers — use `image_save` for
an archive that `image_load` can restore, and `container_archive_get` for a single file or
directory. 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` (~213 tokens)

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

File-writing variant of `container_archive_get` — prefer it for anything large, since in-band
bytes are base64-encoded by MCP. For the whole filesystem use `container_export`. 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` (~226 tokens)

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

Inverse of `container_archive_get`: the archive is extracted at `path` inside the container.
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` (~128 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.
Use `context_inspect` for one context's full config and `context_use` to switch.
Raises RuntimeError if the CLI call fails.

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

### `context_inspect` (~104 tokens)

Return the full configuration for a single Docker context.

Full endpoint/TLS detail for one context; `context_list` gives the one-line summary of all.
Raises RuntimeError if the CLI call fails.

args: name - Context name (use the `Name` field from `context_list`)
returns: dict - The parsed `docker context inspect` entry (keys include "Name" and
    "Endpoints" with the daemon URL)

Input parameters:

- `name` (string, required)

### `context_create` (~289 tokens)

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

Registers a named endpoint for the CLI; switch with `context_use`, enumerate with
\`context_list`. It does not retarget this server's docker-py client (pinned at startup).
Does not raise on a non-zero CLI exit — inspect `returncode`/`stderr` in the result.

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` (~134 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. Create contexts with `context_create`; list them with
\`context_list`.

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` (~134 tokens)

Remove a Docker CLI context.

Deletes only the CLI's connection metadata — the daemon it pointed at is untouched. The
current context needs force=True (or `context_use` another first).
Does not raise on a non-zero CLI exit — inspect `returncode`/`stderr` in the result.

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` (~620 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` (~168 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 - {"Descriptor", "Platforms"} — the OCI descriptor and the platforms available
    for the reference

Input parameters:

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

### `image_list` (~172 tokens)

List images in the daemon's local store.

Local only — for a registry's contents use `registry_tags` / `hub_tags`, and `image_search`
to find images on Docker Hub. Dangling (untagged) build leftovers show with
filters={"dangling": True}.

args:
    repository - Only show images of this repository
    all - Show intermediate image layers
    filters - Filter by attributes (label, dangling, before, since, etc.)
returns: list - One summary dict per image ({"Id", "RepoTags", "RepoDigests", "Created",
    "Size", "Labels", ...}); use `image_inspect` for a full inspect payload

Input parameters:

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

### `image_pull` (~166 tokens)

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

Private repositories need credentials — `system_login` (or `docker login` on the host) first.
Use `image_load` for tarballs, and `registry_manifest` / `image_registry_data` to inspect a
remote image without pulling it.

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` (~185 tokens)

Push an image or repository to a registry.

The local image must already bear the target name — `image_tag` it with the
registry-qualified `repository[:tag]` first; a bare name pushes to Docker Hub. Private
registries need credentials (`system_login`, or `docker login` on the host).

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` (~136 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.

args:
    term - Search keyword, e.g. "nginx" or "python"
    limit - Maximum number of results to return (Docker Hub default is 25)
returns: list - Result dicts: {"name", "description", "star_count", "is_official",
    "is_automated"}

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` (~201 tokens)

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

Counterpart of `image_save`; when the image lives in a registry, `image_pull` is the normal
route. 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 - One full inspect payload per loaded image

Input parameters:

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

### `image_save` (~321 tokens)

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

The archive keeps layers, tags, and metadata so `image_load` can restore it — different from
\`container_export`, which flattens one container's filesystem. 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` (~173 tokens)

Tag an image into a repository (add a name to an existing local image).

The image id stays the same and no data is copied — a tag is an alias. Typical flow: tag with
the registry-qualified name, then `image_push`. `image_remove` on a tag merely untags while
other names remain.

args:
    id_or_name - The source image name or id
    repository - Target repository name (registry-qualified for pushing, e.g. "ghcr.io/o/r")
    tag - Optional tag for the new image (default "latest")
    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` (~344 tokens)

Create a network.

The daemon default driver is `bridge` (single-host); use `overlay` for swarm-wide networks.
Creating a network attaches nothing — connect containers afterwards with `network_connect` or
at start via `container_run(network=...)`. Created networks are stamped with provenance labels
(find them later via `network_list(managed_only=True)`).

args:
    name - The name of the network
    driver - Driver name (daemon default `bridge`; `overlay` for swarm scope)
    options - Driver-specific options dict
    ipam - IPAM configuration as a dict (engine shape: {"Driver", "Config": [{"Subnet", "Gateway", ...}]})
    check_duplicate - Reject creation if a duplicate name exists (deprecated: recent daemons always check)
    internal - Restrict external access
    labels - Labels to set on the network
    enable_ipv6 - Enable IPv6 networking
    attachable - Allow standalone containers to attach (swarm overlay networks)
    scope - Network scope: "local", "global", or "swarm"
    ingress - Make this an ingress network for swarm routing-mesh
returns: dict - The created network's attrs (Id, Name, Driver, Scope, IPAM)

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` (~280 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 - One dict ({"Id", "Name", "Driver", "Scope", ...}) per network: summary attrs
    by default, full inspect attrs (adding "Containers") when greedy=True

Input parameters:

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

### `network_prune` (~123 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). Use
\`network_remove` to delete one specific network instead.

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` (~137 tokens)

Disconnect a container from a network.

The container keeps running with its other network attachments; only this endpoint is removed
(the reverse of `network_connect`). A network with connected containers cannot be deleted, so
disconnect them before `network_remove`.

args:
    id_or_name - The network id or name
    container - The container id or name to disconnect
    force - Force the disconnect; use to clear a stale endpoint (e.g. from a deleted container)
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` (~135 tokens)

Get a swarm node's full inspect payload by id or name.

Must run against a swarm manager. Shows role, availability, status, and manager reachability —
use `node_list` to enumerate nodes first, or the `docker://nodes` resource for a fleet
summary; `service_ps(filters={"node": ...})` shows what a service runs on one node.

args: id_or_name - The node id or hostname (as shown by `node_list`)
returns: dict - The node's attrs (Spec{Role, Availability}, Status, ManagerStatus for managers)

Input parameters:

- `id_or_name` (string, required)

### `node_list` (~99 tokens)

List swarm nodes.

Must run against a swarm manager. The fleet view of membership, role, and state; drill into
one node with `node_inspect`, or read the `docker://nodes` resource for a computed summary.

args: filters - Filter by attributes (id, name, membership, role)
returns: list - One full node document per node (Spec, Status, ManagerStatus for managers)

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` (~323 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. `service_wait` covers
service convergence; `node_list` shows every node's state at once.

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` (~196 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 ({"Id", "Name", "Enabled", "Settings", "Config"})

Input parameters:

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

### `plugin_list` (~112 tokens)

List installed engine plugins with their full attrs.

Covers managed engine plugins (volume/network/logging drivers installed via `plugin_install`)
— not docker CLI plugins such as compose, buildx, or scout. Use it to find exact plugin names
for `plugin_inspect`/`plugin_enable`/`plugin_disable`/`plugin_remove`; the `Enabled` key shows
each plugin's state.

returns: list - One attrs dict per installed plugin (Id, Name, Enabled, Settings, Config)

### `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` (~114 tokens)

Uninstall an engine plugin from the daemon.

Permanent removal — to deactivate but keep a plugin installed use `plugin_disable` instead. An
enabled plugin must be disabled first unless `force=True`. Plugin names come from
\`plugin_list`.

args:
    name - The plugin name (e.g. "vieux/sshfs:latest")
    force - Remove even if the plugin is enabled (default False)
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` (~292 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). Fetch one tag's manifest with `registry_manifest`; `hub_tags` adds Hub-specific
tag metadata (sizes, push dates).

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` (~139 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. Hub-only metadata (stars, pulls, description) — use
\`registry_tags` for tag lists on any OCI registry and `hub_tags` for Hub tag details.

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` (~307 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 full document ({"ID", "Version", "Spec", ...})

Input parameters:

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

### `service_inspect` (~140 tokens)

Get a swarm service by id or name.

Must run against a swarm manager. Returns the desired-state spec and rollout status — for the
actually-running tasks use `service_ps`, or the `service-tasks://{id_or_name}` resource for a
computed rollout summary.

args:
    id_or_name - The service id or name
    insert_defaults - Merge default values into the output
returns: dict - The full service document ({"ID", "Version", "Spec", "Endpoint", ...};
    "UpdateStatus" during a rolling update)

Input parameters:

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

### `service_list` (~135 tokens)

List swarm services.

Must run against a swarm manager. One entry per service (the desired state); `service_ps`
lists a service's tasks, and `stack_services` groups services by stack.

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 - One full service document ({"ID", "Spec", ...}) per service

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` (~87 tokens)

Stop and remove a swarm service.

Requires a swarm manager. Deletes the service definition and shuts down its tasks — no
confirmation, no undo. To stop work but keep the definition, `service_scale` to 0 replicas.

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` (~192 tokens)

List a swarm service's tasks (per-replica scheduling units), like `docker service ps`.

Shows where replicas run and why they fail: each task carries `Status`
(State/Message/ContainerStatus), `DesiredState`, `NodeID`, and `Slot`. Prefer this over
\`container_list` for services (tasks may run on other nodes), `stack_ps` for a whole stack,
and the `service-tasks://{id_or_name}` resource for a computed rollout summary. Requires a
swarm manager.

args:
    id_or_name - The service id or name
    filters - Filter dict; keys: id, name, node, label, desired-state (running|shutdown|accepted)
returns: list - Task dicts (ID, Slot, NodeID, Status, DesiredState, Spec)

Input parameters:

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

### `service_logs` (~329 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. Logs aggregate
across all the service's tasks — `container_logs` reads a single container, and the
\`service-logs://{id_or_name}` resource is the resource-flavored equivalent of this tool.

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` (~328 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 that runs the CLI — this server's host, or the target `ssh://` host
itself when no local scout plugin is installed. Start with `scout_quickview` for a
per-severity summary; `scout_sbom` inventories packages without vulnerability matching.
Does not raise on a non-zero CLI exit (a missing scout plugin still raises) — inspect
\`raw.stderr`.

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` (~180 tokens)

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

The fastest triage step — counts per severity plus base-image status. Drill into individual
findings with `scout_cves`; get upgrade suggestions with `scout_recommendations`.
Does not raise on a non-zero CLI exit (a missing scout plugin still raises) — inspect
\`raw.stderr`.

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` (~270 tokens)

Suggest base-image upgrades for an image.

Computed against Docker Scout's catalog; generally needs `docker login` on the host that runs the
CLI (the target `ssh://` host itself when no local scout plugin is installed) to return useful
results for private or rarely-scanned base images. The natural follow-up to `scout_cves` when the
fix is a newer base image.
Does not raise on a non-zero CLI exit (a missing scout plugin still raises) — inspect
\`raw.stderr`.

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` (~379 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. Use it after a rebuild to check the new image against the old (`scout_cves` scans a
single image).
Does not raise on a non-zero CLI exit (a missing scout plugin still raises) — inspect
\`raw.stderr`. Raises ValueError if `to` names a local directory/archive while the call has to run
on a remote `ssh://` host (no local scout plugin): the file is not staged, so it would resolve
against that host's filesystem instead.

args:
    image - The new / candidate image reference
    to - Compare against this image reference, directory, or archive (a local directory/archive
                  only when the CLI runs on this host — see above)
    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` (~272 tokens)

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

Package inventory only — `scout_cves` adds vulnerability matching on top. 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.
Does not raise on a non-zero CLI exit (a missing scout plugin still raises) — inspect
\`raw.stderr`.

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` (~205 tokens)

Create a swarm secret; requires a swarm manager.

Write-once: the payload can never be read back through the API (`secret_inspect` returns
metadata only) and cannot be changed later — to rotate, create a new secret and update the
consuming services, keeping your own copy of the value. For non-sensitive data that should
stay readable, use `config_create` instead. Created secrets are stamped with provenance
labels.

args:
    name - Name for the secret (unique within the swarm)
    data - The secret payload (max 500 KB; must be empty when driver is set)
    labels - Labels to set on the secret
    driver - Optional secret-driver config for values held in an external store
returns: dict - The created secret's attrs (ID and Spec metadata; never the payload)

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` (~377 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`). The swarm analogue of `compose_up`; watch the rollout with
\`stack_services` / `stack_ps`.
Does not raise on a non-zero CLI exit — inspect `returncode`/`stderr` in the result.

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;
                  copied to the target host if no local docker CLI)
    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` (~85 tokens)

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

Requires the target daemon to be a swarm manager. `compose_list` is the non-swarm equivalent;
drill into one stack with `stack_services`.
Raises RuntimeError if the CLI call fails.

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

### `stack_ps` (~167 tokens)

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

Task-level view across every service in the stack (`service_ps` covers one service): where
each task runs and why it failed. Requires a swarm manager.
Raises RuntimeError if the CLI call fails.

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` (~145 tokens)

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

Service-level rollup (replicas ready per service); use `stack_ps` for individual tasks and
\`service_inspect` for one service's full spec. Requires a swarm manager.
Raises RuntimeError if the CLI call fails.

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` (~209 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) — the reverse of
\`stack_deploy` and the swarm analogue of `compose_down`. Defaults to `detach=True` so the call
returns once removal is requested rather than waiting for teardown.
Does not raise on a non-zero CLI exit — inspect `returncode`/`stderr` in the result.

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` (~97 tokens)

Leave the current swarm.

The daemon's service tasks are rescheduled to the remaining nodes. A manager refuses to leave
without force=True, since leaving can break raft quorum. The departed node lingers as "down"
in `node_list` until a manager runs `node_remove`.

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` (~82 tokens)

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

Works on a manager node only. Cluster-level configuration — for per-node state use
\`node_list`; for the tokens new nodes need, `swarm_join_tokens`.

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` (~318 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. List existing volumes with
\`volume_list`; reclaim unused ones with `volume_prune`. Created volumes are stamped with provenance
labels.

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 ({"Name", "Driver", "Mountpoint", "Labels", ...})

Input parameters:

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

### `volume_inspect` (~115 tokens)

Get a volume's full inspect payload by name.

Use it after `volume_list` to see a volume's on-disk location, driver, and labels — e.g.
before a backup or `volume_remove`. Volumes are addressed purely by name; they have no
separate id.

args: name - The volume name (volumes have no ids)
returns: dict - The volume's attrs (Name, Driver, Mountpoint, CreatedAt, Labels, Options, Scope)

Input parameters:

- `name` (string, required)

### `volume_list` (~151 tokens)

List volumes.

Volumes are addressed by name only — feed a Name to `volume_inspect` for detail or
\`volume_remove` / `volume_prune` to clean up. filters={"dangling": True} finds volumes that no
container references.

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 - One volume document ({"Name", "Driver", "Mountpoint", ...}) per volume

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/l337-org-docker-mcp-server/ghcr-io-l337-org-docker-mcp-server-2-2-2#diagnostics

## Score history

- 2026-08-03: 33
- 2026-08-02: 33
- 2026-08-01: 33
- 2026-07-31: 6

## Links

- Repository: https://github.com/L337-org/docker-mcp
- Changelog RSS feed: https://verifymcp.io/servers/l337-org-docker-mcp-server/ghcr-io-l337-org-docker-mcp-server-2-2-2/changelog.xml
- Changelog JSON feed: https://verifymcp.io/servers/l337-org-docker-mcp-server/ghcr-io-l337-org-docker-mcp-server-2-2-2/changelog.json
- HTML version of this page: https://verifymcp.io/servers/l337-org-docker-mcp-server/ghcr-io-l337-org-docker-mcp-server-2-2-2
