docker-mcp-server 2.1.3__tar.gz → 2.1.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/.github/copilot-instructions.md +7 -4
  2. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/.github/workflows/codeql.yaml +3 -3
  3. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/CLAUDE.md +7 -3
  4. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/PKG-INFO +2 -2
  5. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/README.md +1 -1
  6. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/docker_mcp/tools/buildx.py +31 -9
  7. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/docker_mcp/tools/compose.py +53 -11
  8. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/docker_mcp/tools/configs.py +6 -3
  9. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/docker_mcp/tools/containers.py +54 -25
  10. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/docker_mcp/tools/context.py +17 -2
  11. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/docker_mcp/tools/images.py +36 -15
  12. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/docker_mcp/tools/networks.py +4 -2
  13. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/docker_mcp/tools/nodes.py +6 -2
  14. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/docker_mcp/tools/plugins.py +1 -1
  15. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/docker_mcp/tools/registry.py +5 -2
  16. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/docker_mcp/tools/scout.py +25 -8
  17. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/docker_mcp/tools/services.py +17 -4
  18. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/docker_mcp/tools/stack.py +21 -6
  19. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/docker_mcp/tools/swarm.py +7 -0
  20. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/docker_mcp/tools/system.py +23 -8
  21. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/docker_mcp/tools/volumes.py +9 -3
  22. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/manifest.json +1 -1
  23. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/pyproject.toml +1 -1
  24. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/scripts/build-mcpb.sh +71 -9
  25. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/uv.lock +1 -1
  26. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/.claude/commands/docker-sdk.md +0 -0
  27. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/.claude/settings.json +0 -0
  28. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/.dockerignore +0 -0
  29. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/.github/CODEOWNERS +0 -0
  30. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  31. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  32. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  33. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/.github/actions/file-failure-issue/action.yaml +0 -0
  34. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/.github/dependabot.yaml +0 -0
  35. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/.github/release.yml +0 -0
  36. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/.github/workflows/canary.yaml +0 -0
  37. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/.github/workflows/images.yaml +0 -0
  38. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/.github/workflows/premerge.yaml +0 -0
  39. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/.github/workflows/publish-homebrew.yaml +0 -0
  40. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/.github/workflows/publish.yaml +0 -0
  41. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/.gitignore +0 -0
  42. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/.mcpbignore +0 -0
  43. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/.python-version +0 -0
  44. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/CODE_OF_CONDUCT.md +0 -0
  45. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/CONTRIBUTING.md +0 -0
  46. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/DOCKERHUB.md +0 -0
  47. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/Dockerfile +0 -0
  48. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/LICENSE +0 -0
  49. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/MIGRATION-2.0.md +0 -0
  50. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/PRIVACY.md +0 -0
  51. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/SECURITY.md +0 -0
  52. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/assets/README.md +0 -0
  53. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/assets/icon.png +0 -0
  54. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/docker_mcp/__init__.py +0 -0
  55. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/docker_mcp/__main__.py +0 -0
  56. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/docker_mcp/_env.py +0 -0
  57. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/docker_mcp/_hosts.py +0 -0
  58. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/docker_mcp/server.py +0 -0
  59. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/docker_mcp/tools/__init__.py +0 -0
  60. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/docker_mcp/tools/_cli.py +0 -0
  61. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/docker_mcp/tools/_labels.py +0 -0
  62. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/docker_mcp/tools/_ssh_proxy.py +0 -0
  63. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/docker_mcp/tools/_utils.py +0 -0
  64. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/docker_mcp/tools/prompts.py +0 -0
  65. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/docker_mcp/tools/resources.py +0 -0
  66. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/docker_mcp/tools/secrets.py +0 -0
  67. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/glama.json +0 -0
  68. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/mcpb_run.py +0 -0
  69. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/scripts/docker-mcp-server.rb.tpl +0 -0
  70. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/server.json +0 -0
  71. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/tests/__init__.py +0 -0
  72. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/tests/conftest.py +0 -0
  73. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/tests/integration/__init__.py +0 -0
  74. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/tests/integration/conftest.py +0 -0
  75. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/tests/integration/test_buildx.py +0 -0
  76. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/tests/integration/test_cli.py +0 -0
  77. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/tests/integration/test_compose.py +0 -0
  78. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/tests/integration/test_containers.py +0 -0
  79. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/tests/integration/test_context.py +0 -0
  80. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/tests/integration/test_file_payloads.py +0 -0
  81. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/tests/integration/test_networks.py +0 -0
  82. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/tests/integration/test_nodes.py +0 -0
  83. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/tests/integration/test_registry.py +0 -0
  84. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/tests/integration/test_scout.py +0 -0
  85. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/tests/integration/test_services.py +0 -0
  86. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/tests/integration/test_smoke.py +0 -0
  87. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/tests/integration/test_stack.py +0 -0
  88. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/tests/test_buildx.py +0 -0
  89. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/tests/test_cli.py +0 -0
  90. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/tests/test_compose.py +0 -0
  91. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/tests/test_configs.py +0 -0
  92. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/tests/test_containers.py +0 -0
  93. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/tests/test_context.py +0 -0
  94. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/tests/test_env.py +0 -0
  95. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/tests/test_hosts.py +0 -0
  96. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/tests/test_images.py +0 -0
  97. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/tests/test_labels.py +0 -0
  98. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/tests/test_main.py +0 -0
  99. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/tests/test_naming.py +0 -0
  100. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/tests/test_networks.py +0 -0
  101. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/tests/test_nodes.py +0 -0
  102. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/tests/test_plugins.py +0 -0
  103. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/tests/test_prompts.py +0 -0
  104. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/tests/test_pyproject_pins.py +0 -0
  105. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/tests/test_registry.py +0 -0
  106. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/tests/test_resources.py +0 -0
  107. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/tests/test_scout.py +0 -0
  108. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/tests/test_secrets.py +0 -0
  109. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/tests/test_server.py +0 -0
  110. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/tests/test_services.py +0 -0
  111. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/tests/test_ssh_proxy.py +0 -0
  112. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/tests/test_stack.py +0 -0
  113. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/tests/test_swarm.py +0 -0
  114. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/tests/test_system.py +0 -0
  115. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/tests/test_utils.py +0 -0
  116. {docker_mcp_server-2.1.3 → docker_mcp_server-2.1.4}/tests/test_volumes.py +0 -0
@@ -89,7 +89,7 @@ An additional distribution channel alongside the uvx-from-git install (unchanged
89
89
 
90
90
  ### Desktop Extension (MCPB)
91
91
 
92
- A third distribution channel for one-click install in Claude Desktop. Repo-root sources: `manifest.json` (MCPB manifest, `manifest_version` 0.4, `server.type: "uv"`), `mcpb_run.py` (bundle entry point — `from docker_mcp import main; main()`, at the root so `import docker_mcp` resolves under the host's managed `uv`), `.mcpbignore` (trims the packed bundle to source + `pyproject.toml` + `uv.lock` + `README.md`/`LICENSE` + manifest/entry-point + `assets/`), and `assets/icon.png` (512×512). It's a `uv`-type bundle: the host resolves deps from `pyproject.toml` at install time (no vendored venv). `manifest.json`'s `user_config` maps install-dialog fields to env — `DOCKER_MCP_SERVER_HOSTS` (the single host field; `DOCKER_HOST` is **not** exposed — the bare-value shorthand keeps the one-daemon case a one-liner) and the `DOCKER_MCP_SERVER_READONLY` / `_NO_DESTRUCTIVE` / `_DISABLE` switches (the container-only `_ALLOW_SELF_TERMINATE` is intentionally omitted — the bundle never runs containerized). The `mcpb` job in `.github/workflows/publish.yaml` rewrites the manifest `version` from the release tag, packs the `.mcpb` via `npx @anthropic-ai/mcpb`, and attaches it (plus a `.sha256` recording the bare filename, so `sha256sum -c` works on downloads) to each GitHub Release. `scripts/build-mcpb.sh` is the **developer-only** local equivalent of that pack step (version from `pyproject.toml`, auto-incrementing output in `dist/`, never mutates `manifest.json`) for smoke-testing in Claude Desktop — it is deliberately **not** used by CI. `PRIVACY.md` (no-telemetry statement) is referenced by the manifest's `privacy_policies`. Keep the manifest `version` aligned with `pyproject.toml`; update this section when the manifest's tool/env surface or the bundled file set changes.
92
+ A third distribution channel for one-click install in Claude Desktop. Repo-root sources: `manifest.json` (MCPB manifest, `manifest_version` 0.4, `server.type: "uv"`), `mcpb_run.py` (bundle entry point — `from docker_mcp import main; main()`, at the root so `import docker_mcp` resolves under the host's managed `uv`), `.mcpbignore` (trims the packed bundle to source + `pyproject.toml` + `uv.lock` + `README.md`/`LICENSE` + manifest/entry-point + `assets/`), and `assets/icon.png` (512×512). It's a `uv`-type bundle: the host resolves deps from `pyproject.toml` at install time (no vendored venv). `manifest.json`'s `user_config` maps install-dialog fields to env — `DOCKER_MCP_SERVER_HOSTS` (the single host field; `DOCKER_HOST` is **not** exposed — the bare-value shorthand keeps the one-daemon case a one-liner) and the `DOCKER_MCP_SERVER_READONLY` / `_NO_DESTRUCTIVE` / `_DISABLE` switches (the container-only `_ALLOW_SELF_TERMINATE` is intentionally omitted — the bundle never runs containerized). The `mcpb` job in `.github/workflows/publish.yaml` rewrites the manifest `version` from the release tag, packs the `.mcpb` via `npx @anthropic-ai/mcpb`, and attaches it (plus a `.sha256` recording the bare filename, so `sha256sum -c` works on downloads) to each GitHub Release. `scripts/build-mcpb.sh` is the **developer-only** local equivalent of that pack step (auto-incrementing output in `dist/`) for smoke-testing in Claude Desktop — it is deliberately **not** used by CI. It stamps a **dev version** from `pyproject.toml` + git HEAD — `<version>-dev.<short-commit>[.dirty]` — so a local bundle can't be mistaken for a release and is traceable to its commit; the stamp goes into `manifest.json` only for the pack and is restored by an `EXIT` trap. `PRIVACY.md` (no-telemetry statement) is referenced by the manifest's `privacy_policies`. Keep the manifest `version` aligned with `pyproject.toml`; update this section when the manifest's tool/env surface or the bundled file set changes.
93
93
 
94
94
  ### Homebrew tap (`L337-org/homebrew-tap`) — PAUSED
95
95
 
@@ -205,9 +205,12 @@ touches — do not demand rewrites of untouched legacy docstrings.
205
205
  ("name - The volume name") — it scores 2/5 on the rubric. Canonical shared-param prefixes in
206
206
  `tests/test_naming.py` still apply — tool-specific detail is appended after the canonical
207
207
  prefix, not reworded.
208
- 4. **`returns:` names the shape, not just the type** for dict/list returns the load-bearing keys
209
- must be listed (`{"Titles", "Processes"}`); flag a bare "dict - The X's attrs" on a
210
- new/modified tool.
208
+ 4. **`returns:` names the shape, not just the type.** For computed or partial returns the
209
+ load-bearing keys must be listed (`{"Titles", "Processes"}`). For a full engine inspect
210
+ document, key enumeration is NOT wanted — an arbitrary subset of hundreds of keys is noise; the
211
+ line should identify the document ("full inspect payload, as `docker inspect`"), optionally
212
+ plus one or two keys a caller typically wants. Flag the shapeless "dict - The X's attrs" on a
213
+ new/modified tool, which identifies neither form.
211
214
  5. **Front-loaded and terse** — the description is paid for in every session's context.
212
215
  6. **Every factual claim must be verifiable** against the docker-py docs / Engine API spec (Docker
213
216
  SDK Policy below). Flag claims that contradict them — especially identifier semantics ("name or
@@ -31,12 +31,12 @@ jobs:
31
31
  uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
32
32
 
33
33
  - name: Initialize CodeQL
34
- uses: github/codeql-action/init@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # v4
34
+ uses: github/codeql-action/init@7188fc363630916deb702c7fdcf4e481b751f97a # v4
35
35
  with:
36
36
  languages: ${{ matrix.language }}
37
37
 
38
38
  - name: Autobuild
39
- uses: github/codeql-action/autobuild@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # v4
39
+ uses: github/codeql-action/autobuild@7188fc363630916deb702c7fdcf4e481b751f97a # v4
40
40
 
41
41
  - name: Perform CodeQL Analysis
42
- uses: github/codeql-action/analyze@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # v4
42
+ uses: github/codeql-action/analyze@7188fc363630916deb702c7fdcf4e481b751f97a # v4
@@ -155,7 +155,7 @@ An additional distribution channel alongside uvx-from-git (which is unchanged).
155
155
 
156
156
  ### Desktop Extension (MCPB bundle)
157
157
 
158
- A third distribution channel (alongside uvx/PyPI and the container images) for one-click install in Claude Desktop. The repo root carries the bundle sources: `manifest.json` (the MCPB manifest, `manifest_version` 0.4, `server.type: "uv"`), `mcpb_run.py` (the bundle entry point — `from docker_mcp import main; main()`, kept at the root so `import docker_mcp` resolves however the host's managed `uv` lays out `sys.path`), `.mcpbignore` (trims the packed bundle to source + `pyproject.toml` + `uv.lock` + `README.md`/`LICENSE` + `manifest.json`/`mcpb_run.py` + `assets/`), and `assets/icon.png` (512×512). Because it's a `uv`-type bundle, the host resolves dependencies from `pyproject.toml` at install time — there's no vendored venv, so the bundle stays ~250 KB and cross-platform. `manifest.json`'s `user_config` block renders the install-dialog fields and maps them to env: `DOCKER_MCP_SERVER_HOSTS` (the single host field — `DOCKER_HOST` is deliberately **not** exposed; the bare-value shorthand keeps the simple one-daemon case a one-liner) plus the `DOCKER_MCP_SERVER_READONLY` / `_NO_DESTRUCTIVE` / `_DISABLE` switches (the container-only `_ALLOW_SELF_TERMINATE` is deliberately **not** exposed — the bundle never runs containerized). The `manifest.json` `version` is kept in step with `pyproject.toml` (`tests/test_pyproject_pins.py` asserts it), but the `mcpb` job in `.github/workflows/publish.yaml` rewrites it from the release tag at pack time so it can't drift; that job packs the `.mcpb` with `npx @anthropic-ai/mcpb` and attaches it (plus a `.sha256` recording the bare filename, so `sha256sum -c` works on downloads) to each GitHub Release. `scripts/build-mcpb.sh` is the **developer-only** local equivalent of that pack step (reads the version from `pyproject.toml`, packs to `dist/` with an auto-incrementing name, never mutates `manifest.json`) — for smoke-testing a bundle in Claude Desktop; it is deliberately **not** wired into CI, which uses the workflow above. `PRIVACY.md` (a no-telemetry/no-backend statement) is referenced by the manifest's `privacy_policies` and summarized in the README. **When the manifest's tool/env surface or the bundled file set changes, update this section.**
158
+ A third distribution channel (alongside uvx/PyPI and the container images) for one-click install in Claude Desktop. The repo root carries the bundle sources: `manifest.json` (the MCPB manifest, `manifest_version` 0.4, `server.type: "uv"`), `mcpb_run.py` (the bundle entry point — `from docker_mcp import main; main()`, kept at the root so `import docker_mcp` resolves however the host's managed `uv` lays out `sys.path`), `.mcpbignore` (trims the packed bundle to source + `pyproject.toml` + `uv.lock` + `README.md`/`LICENSE` + `manifest.json`/`mcpb_run.py` + `assets/`), and `assets/icon.png` (512×512). Because it's a `uv`-type bundle, the host resolves dependencies from `pyproject.toml` at install time — there's no vendored venv, so the bundle stays ~250 KB and cross-platform. `manifest.json`'s `user_config` block renders the install-dialog fields and maps them to env: `DOCKER_MCP_SERVER_HOSTS` (the single host field — `DOCKER_HOST` is deliberately **not** exposed; the bare-value shorthand keeps the simple one-daemon case a one-liner) plus the `DOCKER_MCP_SERVER_READONLY` / `_NO_DESTRUCTIVE` / `_DISABLE` switches (the container-only `_ALLOW_SELF_TERMINATE` is deliberately **not** exposed — the bundle never runs containerized). The `manifest.json` `version` is kept in step with `pyproject.toml` (`tests/test_pyproject_pins.py` asserts it), but the `mcpb` job in `.github/workflows/publish.yaml` rewrites it from the release tag at pack time so it can't drift; that job packs the `.mcpb` with `npx @anthropic-ai/mcpb` and attaches it (plus a `.sha256` recording the bare filename, so `sha256sum -c` works on downloads) to each GitHub Release. `scripts/build-mcpb.sh` is the **developer-only** local equivalent of that pack step (packs to `dist/` with an auto-incrementing name) for smoke-testing a bundle in Claude Desktop. It stamps a **dev version** derived from `pyproject.toml` plus the git HEAD — `<version>-dev.<short-commit>[.dirty]` (`.dirty` = uncommitted changes at pack time) — so a local bundle is never mistaken for a release in Claude Desktop's extension list and is traceable to the commit it was built from despite having no tag; the stamp is written into `manifest.json` only for the duration of the pack and restored by an `EXIT` trap, so the working tree is left unmodified. It is deliberately **not** wired into CI, which uses the workflow above. `PRIVACY.md` (a no-telemetry/no-backend statement) is referenced by the manifest's `privacy_policies` and summarized in the README. **When the manifest's tool/env surface or the bundled file set changes, update this section.**
159
159
 
160
160
  ### Homebrew tap (`L337-org/homebrew-tap`) — PAUSED
161
161
 
@@ -305,8 +305,12 @@ legacy docstrings are cleaned opportunistically, not churned):
305
305
  prefixes in `tests/test_naming.py` still apply — append tool-specific detail after the
306
306
  canonical prefix rather than rewording it.
307
307
  4. **`returns:` names the shape, not just the type.** There is no output schema, so this line is
308
- all an agent gets: for dict/list returns name the load-bearing keys (`{"Titles", "Processes"}`;
309
- `{"LayersSize", "Images", "Containers", "Volumes", "BuildCache"}`), never just "the attrs".
308
+ all an agent gets. For computed or partial returns, name the load-bearing keys (`{"Titles",
309
+ "Processes"}`; `{"LayersSize", "Images", "Containers", "Volumes", "BuildCache"}`). For a full
310
+ engine inspect document, do NOT enumerate an arbitrary subset of its hundreds of keys — say
311
+ what document it is ("full inspect payload, as `docker inspect`"), optionally plus the one or
312
+ two keys a caller typically wants from it. What stays banned is the shapeless "dict - The X's
313
+ attrs", which identifies neither form.
310
314
  5. **Front-load and stay terse** — the description is paid for in every session's context; every
311
315
  sentence must earn its place.
312
316
  6. **Verify every factual claim** against the live docker-py docs / Engine API spec per the Docker
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: docker-mcp-server
3
- Version: 2.1.3
3
+ Version: 2.1.4
4
4
  Summary: MCP server for managing Docker resources via the Docker SDK for Python
5
5
  Project-URL: Homepage, https://github.com/L337-org/docker-mcp
6
6
  Project-URL: Repository, https://github.com/L337-org/docker-mcp
@@ -412,7 +412,7 @@ Connecting this server to an AI agent grants it the same level of access as a lo
412
412
  | Desktop Extension (.mcpb) | [GitHub Releases](https://github.com/L337-org/docker-mcp/releases) |
413
413
  | Official MCP Registry | [io.github.L337-org/docker-mcp-server](https://registry.modelcontextprotocol.io/v0.1/servers/io.github.L337-org%2Fdocker-mcp-server/versions) |
414
414
  | Glama | [docker-mcp-server](https://glama.ai/mcp/servers/L337-org/docker-mcp) |
415
- | mcp.so | [docker-mcp-server](https://mcp.so/server/docker-mcp-server/GavinLucas) |
415
+ | mcp.so | [docker-mcp-server](https://mcp.so/servers/docker-1ae67d) |
416
416
  | awesome-mcp-servers | [punkpeye/awesome-mcp-servers](https://github.com/punkpeye/awesome-mcp-servers#cloud-platforms) |
417
417
 
418
418
  ## Privacy Policy
@@ -384,7 +384,7 @@ Connecting this server to an AI agent grants it the same level of access as a lo
384
384
  | Desktop Extension (.mcpb) | [GitHub Releases](https://github.com/L337-org/docker-mcp/releases) |
385
385
  | Official MCP Registry | [io.github.L337-org/docker-mcp-server](https://registry.modelcontextprotocol.io/v0.1/servers/io.github.L337-org%2Fdocker-mcp-server/versions) |
386
386
  | Glama | [docker-mcp-server](https://glama.ai/mcp/servers/L337-org/docker-mcp) |
387
- | mcp.so | [docker-mcp-server](https://mcp.so/server/docker-mcp-server/GavinLucas) |
387
+ | mcp.so | [docker-mcp-server](https://mcp.so/servers/docker-1ae67d) |
388
388
  | awesome-mcp-servers | [punkpeye/awesome-mcp-servers](https://github.com/punkpeye/awesome-mcp-servers#cloud-platforms) |
389
389
 
390
390
  ## Privacy Policy
@@ -178,6 +178,10 @@ def buildx_bake(
178
178
  """
179
179
  Build multiple targets defined in a bake file (HCL, JSON, or compose).
180
180
 
181
+ Use it for multi-target builds declared in `docker-bake.hcl`/compose files; for a single
182
+ Dockerfile target use `buildx_build`.
183
+ Does not raise on a non-zero CLI exit — inspect `returncode`/`stderr` in the result.
184
+
181
185
  args:
182
186
  targets - Bake targets to build (default: the `default` group)
183
187
  files - Bake file paths (`-f`, repeatable)
@@ -273,7 +277,9 @@ def buildx_imagetools_create(
273
277
  Create a manifest list / OCI image index from existing per-platform tags.
274
278
 
275
279
  Replaces `docker manifest create` + `docker manifest push` — builds the index and pushes it in
276
- one operation. Source tags must already be pushed; this only stitches them together.
280
+ one operation. Source tags must already be pushed; this only stitches them together. Verify
281
+ the result with `buildx_imagetools_inspect`.
282
+ Does not raise on a non-zero CLI exit — inspect `returncode`/`stderr` in the result.
277
283
 
278
284
  args:
279
285
  target - Tag for the new manifest list (`-t`)
@@ -311,6 +317,10 @@ def buildx_list(host: str | None = None) -> list:
311
317
  """
312
318
  List builder instances.
313
319
 
320
+ Machine-parsed view of every builder; use `buildx_inspect` for one builder's human-readable
321
+ detail and `buildx_use` to switch the default.
322
+ Raises RuntimeError if the CLI call fails.
323
+
314
324
  returns: list - One dict per builder (parsed from `--format '{{json .}}'`).
315
325
  If the captured stdout was truncated by MAX_CLI_OUTPUT_BYTES the
316
326
  last (likely partial) record is dropped before parsing.
@@ -346,8 +356,10 @@ def buildx_history_inspect(ref: str = "", builder: str | None = None, host: str
346
356
  """
347
357
  Inspect a single build record by ref, parsed from `--format json`.
348
358
 
349
- Returns the full record for one build — duration, materials, attestations, error (if any) — for
350
- debugging a failed or slow build found via `buildx_history_list`. Requires buildx >= v0.13.
359
+ Returns the full record for one build — duration, materials, attestations, error (if any) —
360
+ for debugging a failed or slow build found via `buildx_history_list`. Requires buildx >=
361
+ v0.13.
362
+ Raises RuntimeError if the CLI call fails.
351
363
 
352
364
  args:
353
365
  ref - Build record ref. Pass the `ref` field from `buildx_history_list` directly — it
@@ -386,6 +398,10 @@ def buildx_inspect(name: str | None = None, bootstrap: bool = False, host: str |
386
398
  """
387
399
  Inspect a builder instance.
388
400
 
401
+ Human-readable detail (driver, status, supported platforms) for one builder; `buildx_list`
402
+ returns machine-parsed JSON for all builders.
403
+ Does not raise on a non-zero CLI exit — inspect `returncode`/`stderr` in the result.
404
+
389
405
  args:
390
406
  name - Builder name (defaults to the active builder)
391
407
  bootstrap - Boot the builder if it isn't already running
@@ -405,10 +421,12 @@ def buildx_du(builder: str | None = None, host: str | None = None) -> list:
405
421
  """
406
422
  Report BuildKit cache disk usage as a list of records.
407
423
 
408
- A large cache can easily generate more output than MAX_CLI_OUTPUT_BYTES; if that
409
- happens the captured stdout is truncated and this tool drops the final (partial)
410
- record before parsing. For an exhaustive accounting on a busy builder, run
411
- `docker buildx du --format '{{json .}}'` on the host directly.
424
+ A large cache can easily generate more output than MAX_CLI_OUTPUT_BYTES; if that happens the
425
+ captured stdout is truncated and this tool drops the final (partial) record before parsing.
426
+ For an exhaustive accounting on a busy builder, run `docker buildx du --format '{{json .}}'`
427
+ on the host directly. Reclaim the cache with `buildx_prune` (`system_df` covers daemon-side
428
+ disk, not builder cache).
429
+ Raises RuntimeError if the CLI call fails.
412
430
 
413
431
  args: builder - Override the active builder
414
432
  returns: list - One dict per cache record (parsed from `--format '{{json .}}'`)
@@ -482,8 +500,8 @@ def buildx_create(
482
500
  Needed when the default `docker` driver falls short: multi-platform builds and cache export
483
501
  require a `docker-container` (or `kubernetes`/`remote`) builder. Pass `use=True` to make it
484
502
  the default for later `buildx_build` calls (else switch with `buildx_use`); `bootstrap=True`
485
- starts the builder now rather than on first build. Does not raise on a non-zero CLI exit —
486
- inspect `returncode`/`stderr` in the result.
503
+ starts the builder now rather than on first build.
504
+ Does not raise on a non-zero CLI exit — inspect `returncode`/`stderr` in the result.
487
505
 
488
506
  args:
489
507
  name - Name for the new builder (defaults to a generated name)
@@ -557,6 +575,10 @@ def buildx_remove(
557
575
  """
558
576
  Remove a builder instance.
559
577
 
578
+ Deletes a builder made by `buildx_create`, including its build cache unless keep_state=True;
579
+ use `buildx_prune` to reclaim cache while keeping the builder.
580
+ Does not raise on a non-zero CLI exit — inspect `returncode`/`stderr` in the result.
581
+
560
582
  args:
561
583
  name - Builder name to remove (mutually exclusive with `all_inactive`)
562
584
  all_inactive - Remove every inactive builder
@@ -115,6 +115,10 @@ def compose_down(
115
115
  """
116
116
  Stop and remove containers, networks (and optionally volumes) for a compose project.
117
117
 
118
+ Inverse of `compose_up`. Images are kept; named volumes go only with volumes=True
119
+ (destructive). Use `compose_stop` to stop without removing anything.
120
+ Does not raise on a non-zero CLI exit — inspect `returncode`/`stderr` in the result.
121
+
118
122
  args:
119
123
  project_dir - Dir with the compose file (default: server cwd)
120
124
  files - Explicit compose file paths (repeatable, `-f`)
@@ -145,6 +149,10 @@ def compose_ps(
145
149
  """
146
150
  List containers in a compose project, parsed from `--format json`.
147
151
 
152
+ Container-level view of one project (state, health, publishers); `compose_list` enumerates
153
+ projects, and `container_list` covers non-compose containers.
154
+ Does not raise on a non-zero CLI exit: `services` comes back empty — inspect `raw.stderr`.
155
+
148
156
  args:
149
157
  project_dir - Dir with the compose file (default: server cwd)
150
158
  files - Explicit compose file paths (repeatable, `-f`)
@@ -190,6 +198,10 @@ def compose_logs(
190
198
  """
191
199
  Fetch a bounded slice of logs from a compose project (never follows).
192
200
 
201
+ Bounded and non-following by design, so it always returns promptly. For one container's logs
202
+ use `container_logs`; for a swarm service use `service_logs`. Log text arrives on `stdout`.
203
+ Does not raise on a non-zero CLI exit — inspect `returncode`/`stderr` in the result.
204
+
193
205
  args:
194
206
  project_dir - Dir with the compose file (default: server cwd)
195
207
  files - Explicit compose file paths (repeatable, `-f`)
@@ -227,6 +239,10 @@ def compose_config(
227
239
  """
228
240
  Render the canonical compose configuration after merges, profiles, and variable substitution.
229
241
 
242
+ Use it to validate compose files and see exactly what the CLI will run before `compose_up`.
243
+ Does not raise on a non-zero CLI exit: on a failed render `config` may be None — inspect
244
+ `raw.stderr`.
245
+
230
246
  args:
231
247
  project_dir - Dir with the compose file (default: server cwd)
232
248
  files - Explicit compose file paths (repeatable, `-f`)
@@ -269,6 +285,10 @@ def compose_build(
269
285
  """
270
286
  Build images for a compose project.
271
287
 
288
+ Builds the images declared by the project's `build:` sections without starting anything —
289
+ `compose_up(build=True)` builds and starts in one step.
290
+ Does not raise on a non-zero CLI exit — inspect `returncode`/`stderr` in the result.
291
+
272
292
  args:
273
293
  project_dir - Dir with the compose file (default: server cwd)
274
294
  files - Explicit compose file paths (repeatable, `-f`)
@@ -441,7 +461,9 @@ def compose_run(
441
461
  """
442
462
  Run a one-off command against a compose service.
443
463
 
444
- Always passes `-T` (no TTY under MCP). Defaults to detached with `--rm` so the call returns promptly.
464
+ Always passes `-T` (no TTY under MCP). Defaults to detached with `--rm` so the call returns
465
+ promptly. Unlike `compose_exec`, this starts a NEW container for the service rather than
466
+ running inside the existing one.
445
467
 
446
468
  args:
447
469
  service - Service name from the compose file
@@ -540,7 +562,8 @@ def compose_images(
540
562
 
541
563
  Answers "what image and tag does each service container actually run?" — the containers must
542
564
  exist (`compose_up`/`compose_create` first). Use `compose_ps` for container state and
543
- `image_list` for daemon-wide images. Raises RuntimeError if the CLI call fails.
565
+ `image_list` for daemon-wide images.
566
+ Raises RuntimeError if the CLI call fails.
544
567
 
545
568
  args:
546
569
  project_dir - Dir with the compose file (default: server cwd)
@@ -577,7 +600,9 @@ def compose_port(
577
600
  Resolve the host binding for a service's container port.
578
601
 
579
602
  The compose equivalent of `docker port`: which host address/port a service's private port is
580
- published on. `published` is None when the port isn't published.
603
+ published on. `published` is None when the port isn't published. For non-compose containers
604
+ read `container_inspect`'s NetworkSettings.Ports instead.
605
+ Raises RuntimeError if the CLI call fails.
581
606
 
582
607
  args:
583
608
  service - Service name from the compose file
@@ -630,7 +655,8 @@ def compose_wait(
630
655
 
631
656
  For one-shot / batch services. A long-running service that never exits blocks until
632
657
  `timeout_seconds`, then the subprocess is killed (TimeoutExpired) — bound it sensibly.
633
- Exit codes are on stdout.
658
+ Exit codes are on stdout. For a single container use `container_wait`; for swarm services
659
+ use `service_wait`.
634
660
 
635
661
  args:
636
662
  services - One or more services to wait on. At least one is required.
@@ -658,7 +684,9 @@ def compose_top(
658
684
  """
659
685
  Show the running processes of a compose project's containers.
660
686
 
661
- Output is the `ps`-style process table per service (not JSON); read it from `stdout`.
687
+ Output is the `ps`-style process table per service (not JSON); read it from `stdout`. The
688
+ per-container equivalent is `container_top`.
689
+ Does not raise on a non-zero CLI exit — inspect `returncode`/`stderr` in the result.
662
690
 
663
691
  args:
664
692
  services - Restrict to these services (default: all)
@@ -688,9 +716,11 @@ def compose_cp(
688
716
  """
689
717
  Copy files/folders between a service container and the server host's filesystem.
690
718
 
691
- Exactly one of `source`/`dest` is `SERVICE:PATH`; the other is a path on the host running this MCP
692
- server, read/written as the server's user (same host exposure as the file-path archive tools — see
693
- SECURITY.md). Copying to stdout (`dest="-"`) is unsupported; use the container-archive tools.
719
+ Exactly one of `source`/`dest` is `SERVICE:PATH`; the other is a path on the host running this
720
+ MCP server, read/written as the server's user (same host exposure as the file-path archive
721
+ tools — see SECURITY.md). Copying to stdout (`dest="-"`) is unsupported; use
722
+ `container_archive_get`.
723
+ Does not raise on a non-zero CLI exit — inspect `returncode`/`stderr` in the result.
694
724
 
695
725
  args:
696
726
  source - `SERVICE:SRC_PATH` or a host path
@@ -726,6 +756,10 @@ def compose_kill(
726
756
  """
727
757
  Send a signal to a compose project's containers (default SIGKILL).
728
758
 
759
+ Immediate, with no grace period — prefer `compose_stop` for a clean shutdown (stop signal,
760
+ then kill after a timeout).
761
+ Does not raise on a non-zero CLI exit — inspect `returncode`/`stderr` in the result.
762
+
729
763
  args:
730
764
  services - Restrict to these services (default: all)
731
765
  signal - Signal to send (default "SIGKILL"; e.g. "SIGTERM", "SIGHUP")
@@ -757,9 +791,9 @@ def compose_pause(
757
791
  Pause the containers of a compose project (freezes their processes in place).
758
792
 
759
793
  Paused containers stop consuming CPU but keep memory, network endpoints, and state; resume
760
- with `compose_unpause`. To actually stop containers (each one's configured stop signal, freeing
761
- resources) use `compose_stop`; to stop and delete them use `compose_down`. Does not raise on a
762
- non-zero CLI exit — inspect `returncode`/`stderr` in the result.
794
+ with `compose_unpause`. To actually stop containers (each one's configured stop signal,
795
+ freeing resources) use `compose_stop`; to stop and delete them use `compose_down`.
796
+ Does not raise on a non-zero CLI exit — inspect `returncode`/`stderr` in the result.
763
797
 
764
798
  args:
765
799
  services - Restrict to these services (default: all)
@@ -785,6 +819,10 @@ def compose_unpause(
785
819
  """
786
820
  Unpause the containers of a compose project (resumes paused processes).
787
821
 
822
+ Reverse of `compose_pause`: processes continue from where they were frozen (no restart).
823
+ `compose_start` is the counterpart for stopped containers.
824
+ Does not raise on a non-zero CLI exit — inspect `returncode`/`stderr` in the result.
825
+
788
826
  args:
789
827
  services - Restrict to these services (default: all)
790
828
  project_dir - Dir with the compose file (default: server cwd)
@@ -803,6 +841,10 @@ def compose_list(all: bool = False, host: str | None = None) -> list:
803
841
  """
804
842
  List compose projects known to the daemon (across all directories).
805
843
 
844
+ Project-level view (one entry per project); `compose_ps` lists the containers of a single
845
+ project.
846
+ Raises RuntimeError if the CLI call fails.
847
+
806
848
  args: all - Include stopped projects
807
849
  returns: list - One dict per project (parsed from `--format json`)
808
850
  """
@@ -25,7 +25,7 @@ def config_create(
25
25
  data - Raw bytes content of the config file
26
26
  labels - Labels to set on the config
27
27
  templating - Templating driver config (e.g. {"Name": "golang"} for Go template syntax)
28
- returns: dict - The created config's attrs including its id
28
+ returns: dict - The created config's attrs ({"ID", "Version", "CreatedAt", "Spec", ...})
29
29
  """
30
30
  kwargs: dict = {
31
31
  "name": name,
@@ -57,10 +57,10 @@ def config_list(filters: dict | None = None, host: str | None = None) -> list:
57
57
 
58
58
  Unlike secrets, config attrs include the actual config data (`Spec.Data`, base64-encoded)
59
59
  since configs are not treated as sensitive. Valid filter keys: `id`, `name`, `names`,
60
- `label` (key or key=value).
60
+ `label` (key or key=value). Fetch a single config by id/name with `config_inspect`.
61
61
 
62
62
  args: filters - Narrow the list; omit to return every config
63
- returns: list - A list of config attrs dicts
63
+ returns: list - One full config document ({"ID", "Spec", ...}) per config
64
64
  """
65
65
  return [c.attrs for c in _get_client(host).configs.list(**drop_none(filters=filters))]
66
66
 
@@ -70,6 +70,9 @@ def config_remove(id_or_name: str, host: str | None = None) -> bool:
70
70
  """
71
71
  Remove a swarm config.
72
72
 
73
+ Requires a swarm manager, and fails while any service still references the config — update or
74
+ remove those services first. The last step of the rotation flow described in `config_create`.
75
+
73
76
  args: id_or_name - The config id or name
74
77
  returns: bool - True after removal
75
78
  """
@@ -56,7 +56,12 @@ def container_run(
56
56
  host: str | None = None,
57
57
  ) -> dict | str:
58
58
  """
59
- Run a container from an image.
59
+ Run a container from an image (create and start in one call, like `docker run`).
60
+
61
+ Use `container_create` to prepare a container without starting it, or `container_exec` to run
62
+ a command in a container that already exists. With detach=False the call blocks until the
63
+ container exits and returns its output, so long-running images need detach=True. Created
64
+ containers are stamped with provenance labels.
60
65
 
61
66
  args:
62
67
  image - The image to run
@@ -158,9 +163,9 @@ def container_inspect(id_or_name: str, host: str | None = None) -> dict:
158
163
  Return the full inspect detail for a single container.
159
164
 
160
165
  Use this when you need complete information about one container — config, state,
161
- network settings, mounts, environment variables, and resource limits. For a quick
162
- overview of many containers use `container_list` instead (returns a summary per
163
- container). For just logs or stats use `container_logs` / `container_stats`.
166
+ network settings, mounts, environment variables, and resource limits. To enumerate many
167
+ containers use `container_list` instead (same payload per container by default; abridged
168
+ with sparse=True). For just logs or stats use `container_logs` / `container_stats`.
164
169
 
165
170
  args: id_or_name - Container id (full or short) or name
166
171
  returns: dict - Full container inspect attrs (equivalent to `docker inspect`)
@@ -181,10 +186,13 @@ def container_list(
181
186
  host: str | None = None,
182
187
  ) -> list:
183
188
  """
184
- List containers.
189
+ List containers on the daemon (running only by default).
190
+
191
+ Pass all=True to include stopped containers. For a compose project `compose_ps` groups
192
+ containers by service; for swarm services use `service_ps` (tasks may live on other nodes).
185
193
 
186
194
  args:
187
- all - Show all containers, including stopped ones
195
+ all - Show all containers, including stopped ones (default False: running only)
188
196
  since - Only show containers created after this id or name
189
197
  before - Only show containers created before this id or name
190
198
  limit - Maximum number of results
@@ -193,7 +201,9 @@ def container_list(
193
201
  ignore_removed - Ignore containers removed during listing
194
202
  managed_only - Only return containers created by this MCP server (filters on the
195
203
  docker-mcp-server.managed label); combines with any `filters` given
196
- returns: list - A list of container attrs dicts
204
+ returns: list - One dict per container: full inspect payloads by default (each match is
205
+ inspected, like `container_inspect`); sparse=True skips the per-container inspect calls
206
+ and returns the daemon's abridged list entries instead
197
207
  """
198
208
  if managed_only:
199
209
  filters = managed_filter(filters)
@@ -234,7 +244,7 @@ def container_start(id_or_name: str, host: str | None = None) -> dict:
234
244
  raised). To stop then start a running container use `container_restart`.
235
245
 
236
246
  args: id_or_name - Container id (full or short) or name
237
- returns: dict - The container's full attrs after starting
247
+ returns: dict - The container's full inspect payload after starting
238
248
  """
239
249
  container = _get_client(host).containers.get(id_or_name)
240
250
  container.start()
@@ -268,12 +278,17 @@ def container_stop(id_or_name: str, stop_timeout_seconds: int = 10, host: str |
268
278
  @tool()
269
279
  def container_restart(id_or_name: str, stop_timeout_seconds: int = 10, host: str | None = None) -> dict:
270
280
  """
271
- Restart a container.
281
+ Restart a container: stop then start again in one call.
282
+
283
+ The container receives its configured stop signal (`STOPSIGNAL`, default SIGTERM), SIGKILL
284
+ after stop_timeout_seconds, and is then started. Use `container_stop`/`container_start` to do
285
+ the halves separately. When the server runs containerized it refuses to restart its own
286
+ container.
272
287
 
273
288
  args:
274
289
  id_or_name - The container id or name
275
- stop_timeout_seconds - Seconds to wait for graceful stop before SIGKILL and restart
276
- returns: dict - The container's attrs after restart
290
+ stop_timeout_seconds - Seconds between the stop signal and SIGKILL (default 10)
291
+ returns: dict - The container's full inspect payload after the restart
277
292
  """
278
293
  container = _get_client(host).containers.get(id_or_name)
279
294
  guard_not_self(container, host=host)
@@ -296,7 +311,7 @@ def container_kill(id_or_name: str, signal: str | None = None, host: str | None
296
311
  args:
297
312
  id_or_name - The container id or name
298
313
  signal - Signal name or number as a string (e.g. "SIGHUP", "9"); default SIGKILL
299
- returns: dict - The container's attrs after the signal
314
+ returns: dict - The container's full inspect payload after the signal
300
315
  """
301
316
  container = _get_client(host).containers.get(id_or_name)
302
317
  guard_not_self(container, host=host)
@@ -316,7 +331,7 @@ def container_pause(id_or_name: str, host: str | None = None) -> dict:
316
331
  `container_exec` fails against a paused container until it is unpaused.
317
332
 
318
333
  args: id_or_name - The container id or name
319
- returns: dict - The container's attrs after pause
334
+ returns: dict - The container's full inspect payload after pause (State.Paused true)
320
335
  """
321
336
  container = _get_client(host).containers.get(id_or_name)
322
337
  guard_not_self(container, host=host)
@@ -347,13 +362,18 @@ def container_remove(
347
362
  id_or_name: str, volumes: bool = False, link: bool = False, force: bool = False, host: str | None = None
348
363
  ) -> bool:
349
364
  """
350
- Remove a container.
365
+ Remove a container, deleting its writable layer.
366
+
367
+ The image is untouched (`image_remove` deletes images); named volumes are never removed —
368
+ volumes=True only covers anonymous ones. A running container is refused unless force=True,
369
+ which kills it first. When the server runs containerized it refuses to remove its own
370
+ container.
351
371
 
352
372
  args:
353
373
  id_or_name - The container id or name
354
- volumes - Also remove anonymous volumes (the CLI's `--volumes`)
374
+ volumes - Also remove anonymous volumes (the CLI's `--volumes`); named volumes persist
355
375
  link - Remove the specified link
356
- force - Force remove a running container
376
+ force - Kill a running container before removing it (default False: running is an error)
357
377
  returns: bool - True after removal completes
358
378
  """
359
379
  container = _get_client(host).containers.get(id_or_name)
@@ -601,7 +621,8 @@ def container_exec(
601
621
  environment - Environment variables
602
622
  workdir - Working directory inside the container
603
623
  demux - Return stdout and stderr separately
604
- returns: dict - Mapping with exit_code and output keys
624
+ returns: dict - {"exit_code", "output"}; output is combined stdout+stderr, or a
625
+ [stdout, stderr] pair with demux=True
605
626
  """
606
627
  container = _get_client(host).containers.get(id_or_name)
607
628
  result = container.exec_run(
@@ -641,7 +662,8 @@ def container_commit(
641
662
  Snapshot a container's current filesystem state as a new image.
642
663
 
643
664
  Useful for capturing a debugging state or saving manual changes made inside a container.
644
- For repeatable builds use a Dockerfile instead. The container is paused by default during
665
+ For repeatable builds use `image_build` with a Dockerfile instead; publish the result with
666
+ `image_tag` + `image_push`. The container is paused by default during
645
667
  the snapshot to ensure filesystem consistency — set `pause=False` only if the container
646
668
  cannot be paused. `changes` accepts Dockerfile instructions to apply on top of the
647
669
  snapshot, e.g. `["CMD [\"python\", \"app.py\"]", "ENV FOO=bar"]`.
@@ -655,7 +677,7 @@ def container_commit(
655
677
  pause - Pause the container during commit for consistency (default True)
656
678
  changes - Dockerfile instructions (CMD, ENV, EXPOSE, etc.) to apply to the image
657
679
  conf - Additional image configuration overrides as a dict
658
- returns: dict - The new image's attrs
680
+ returns: dict - The new image's full inspect payload (Id is the new image id)
659
681
  """
660
682
  container = _get_client(host).containers.get(id_or_name)
661
683
  image = container.commit(
@@ -698,7 +720,7 @@ def container_rename(id_or_name: str, name: str, host: str | None = None) -> dic
698
720
  args:
699
721
  id_or_name - The container id or name
700
722
  name - The new name; must not be in use by any other container
701
- returns: dict - The container's attrs after the rename
723
+ returns: dict - The container's full inspect payload after the rename
702
724
  """
703
725
  container = _get_client(host).containers.get(id_or_name)
704
726
  container.rename(name)
@@ -717,12 +739,13 @@ def container_update(id_or_name: str, updates: dict, host: str | None = None) ->
717
739
  default 1024), `cpu_period` / `cpu_quota` (microseconds for CFS throttling),
718
740
  `cpuset_cpus` (e.g. "0-1"), `restart_policy` (dict with `Name` such as
719
741
  "on-failure"/"always"/"unless-stopped" and optional `MaximumRetryCount`). To change
720
- image, env, or volumes the container must be recreated.
742
+ image, env, or volumes the container must be recreated (`container_remove` +
743
+ `container_run`).
721
744
 
722
745
  args:
723
746
  id_or_name - Container id or name to update
724
747
  updates - Resource fields to update; see description for valid keys
725
- returns: dict - The container's full attrs after the update
748
+ returns: dict - The container's full inspect payload after the update
726
749
  """
727
750
  container = _get_client(host).containers.get(id_or_name)
728
751
  container.update(**updates)
@@ -779,7 +802,8 @@ def container_wait(
779
802
  reached) and `timed_out`. The stop conditions ("not-running"/"next-exit"/"removed") use the
780
803
  daemon's blocking wait and fill `status_code`/`error` (the container's exit info); "healthy" polls
781
804
  the container's HEALTHCHECK every `poll_interval`s and fills `health`/`status`; "log-match" polls
782
- recent logs every `poll_interval`s for `pattern` and fills `matched_line`.
805
+ recent logs every `poll_interval`s for `pattern` and fills `matched_line`. For a compose
806
+ project use `compose_wait`; for swarm services use `service_wait`.
783
807
 
784
808
  Health semantics: with no HEALTHCHECK defined, once the container is `running` the tool returns
785
809
  promptly with `health: null` and `met: false` (false = "not confirmed healthy", not "unhealthy" —
@@ -891,7 +915,9 @@ def container_export(
891
915
  """
892
916
  Export a container's filesystem as a tar archive: to a file on the server host, or in band.
893
917
 
894
- With `dest_path` the archive streams straight to disk (no byte cap), so it handles large
918
+ The tar is a flat filesystem snapshot with no image metadata or layers use `image_save` for
919
+ an archive that `image_load` can restore, and `container_archive_get` for a single file or
920
+ directory. With `dest_path` the archive streams straight to disk (no byte cap), so it handles large
895
921
  containers — the file is written by the server's user, `~` is expanded, and an existing file is
896
922
  refused unless `overwrite=True`. Without `dest_path` the tar bytes are returned in band, capped
897
923
  at `max_bytes` (default 32 MiB) because MCP base64-encodes them — a fallback for when no
@@ -939,7 +965,9 @@ def container_archive_get_to_file(
939
965
  """
940
966
  Retrieve a file or directory from a container as a tar archive written to a file on the server host.
941
967
 
942
- Streams straight to disk (no in-band byte cap). The file is written by the server's user; `~` is
968
+ File-writing variant of `container_archive_get` prefer it for anything large, since in-band
969
+ bytes are base64-encoded by MCP. For the whole filesystem use `container_export`. Streams
970
+ straight to disk (no in-band byte cap). The file is written by the server's user; `~` is
943
971
  expanded and an existing file is refused unless `overwrite=True`.
944
972
 
945
973
  args:
@@ -966,6 +994,7 @@ def container_archive_put(
966
994
  """
967
995
  Upload a tar archive to a path inside a container, from in-band bytes or a file on the server host.
968
996
 
997
+ Inverse of `container_archive_get`: the archive is extracted at `path` inside the container.
969
998
  Pass exactly one of `data` (tar bytes in band) or `from_file` (a path on the server host, streamed
970
999
  straight to the daemon — preferred for large archives, since in-band bytes are base64-encoded by
971
1000
  MCP). `from_file` is read by the server's user; `~` is expanded.