docker-mcp-server 2.1.1__tar.gz → 2.1.2__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.
- docker_mcp_server-2.1.2/.claude/settings.json +15 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/.github/PULL_REQUEST_TEMPLATE.md +1 -1
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/.github/copilot-instructions.md +3 -3
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/.github/workflows/canary.yaml +2 -2
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/.github/workflows/codeql.yaml +3 -3
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/.github/workflows/premerge.yaml +4 -4
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/.github/workflows/publish-homebrew.yaml +1 -1
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/.github/workflows/publish.yaml +21 -11
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/CLAUDE.md +3 -3
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/CONTRIBUTING.md +1 -1
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/DOCKERHUB.md +7 -7
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/PKG-INFO +21 -21
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/PRIVACY.md +1 -1
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/README.md +17 -17
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/SECURITY.md +1 -1
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/manifest.json +6 -6
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/pyproject.toml +4 -4
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/scripts/docker-mcp-server.rb.tpl +4 -4
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/server.json +4 -4
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/tests/integration/test_stack.py +14 -2
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/uv.lock +1 -1
- docker_mcp_server-2.1.1/.claude/settings.json +0 -15
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/.claude/commands/docker-sdk.md +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/.dockerignore +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/.github/CODEOWNERS +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/.github/actions/file-failure-issue/action.yaml +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/.github/dependabot.yaml +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/.github/release.yml +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/.github/workflows/images.yaml +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/.gitignore +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/.mcpbignore +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/.python-version +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/CODE_OF_CONDUCT.md +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/Dockerfile +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/LICENSE +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/MIGRATION-2.0.md +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/assets/README.md +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/assets/icon.png +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/docker_mcp/__init__.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/docker_mcp/__main__.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/docker_mcp/_env.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/docker_mcp/_hosts.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/docker_mcp/server.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/docker_mcp/tools/__init__.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/docker_mcp/tools/_cli.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/docker_mcp/tools/_labels.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/docker_mcp/tools/_ssh_proxy.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/docker_mcp/tools/_utils.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/docker_mcp/tools/buildx.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/docker_mcp/tools/compose.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/docker_mcp/tools/configs.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/docker_mcp/tools/containers.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/docker_mcp/tools/context.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/docker_mcp/tools/images.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/docker_mcp/tools/networks.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/docker_mcp/tools/nodes.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/docker_mcp/tools/plugins.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/docker_mcp/tools/prompts.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/docker_mcp/tools/registry.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/docker_mcp/tools/resources.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/docker_mcp/tools/scout.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/docker_mcp/tools/secrets.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/docker_mcp/tools/services.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/docker_mcp/tools/stack.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/docker_mcp/tools/swarm.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/docker_mcp/tools/system.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/docker_mcp/tools/volumes.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/glama.json +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/mcpb_run.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/scripts/build-mcpb.sh +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/tests/__init__.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/tests/conftest.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/tests/integration/__init__.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/tests/integration/conftest.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/tests/integration/test_buildx.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/tests/integration/test_cli.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/tests/integration/test_compose.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/tests/integration/test_containers.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/tests/integration/test_context.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/tests/integration/test_file_payloads.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/tests/integration/test_networks.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/tests/integration/test_nodes.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/tests/integration/test_registry.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/tests/integration/test_scout.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/tests/integration/test_services.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/tests/integration/test_smoke.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/tests/test_buildx.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/tests/test_cli.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/tests/test_compose.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/tests/test_configs.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/tests/test_containers.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/tests/test_context.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/tests/test_env.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/tests/test_hosts.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/tests/test_images.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/tests/test_labels.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/tests/test_main.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/tests/test_naming.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/tests/test_networks.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/tests/test_nodes.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/tests/test_plugins.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/tests/test_prompts.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/tests/test_pyproject_pins.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/tests/test_registry.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/tests/test_resources.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/tests/test_scout.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/tests/test_secrets.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/tests/test_server.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/tests/test_services.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/tests/test_ssh_proxy.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/tests/test_stack.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/tests/test_swarm.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/tests/test_system.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/tests/test_utils.py +0 -0
- {docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/tests/test_volumes.py +0 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"hooks": {
|
|
3
|
+
"PostToolUse": [
|
|
4
|
+
{
|
|
5
|
+
"matcher": "Edit|Write|MultiEdit",
|
|
6
|
+
"hooks": [
|
|
7
|
+
{
|
|
8
|
+
"type": "command",
|
|
9
|
+
"command": "python3 -c \"import json,sys,os; d=json.load(sys.stdin); fp=(d.get('tool_input') or {}).get('file_path',''); root=os.environ.get('CLAUDE_PROJECT_DIR') or os.getcwd(); print(json.dumps({'hookSpecificOutput':{'hookEventName':'PostToolUse','additionalContext':'You edited CLAUDE.md \\u2014 MIRROR RULE: make the equivalent change in .github/copilot-instructions.md (it drives GitHub Copilot review of every PR). Treat the change as incomplete until both files reflect it.'}})) if fp and os.path.normpath(os.path.join(root, fp)) == os.path.normpath(os.path.join(root, 'CLAUDE.md')) else None\""
|
|
10
|
+
}
|
|
11
|
+
]
|
|
12
|
+
}
|
|
13
|
+
]
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -9,6 +9,6 @@
|
|
|
9
9
|
## Checklist
|
|
10
10
|
|
|
11
11
|
- [ ] `uv run pytest -v`, `uv run ruff check .`, `uv run ruff format --check .`, and `uv run pyright` all pass locally
|
|
12
|
-
- [ ] If this adds or changes a tool: the ["Checklist when adding a new tool module"](https://github.com/
|
|
12
|
+
- [ ] If this adds or changes a tool: the ["Checklist when adding a new tool module"](https://github.com/L337-org/docker-mcp/blob/main/CONTRIBUTING.md#checklist-when-adding-a-new-tool-module) in `CONTRIBUTING.md` has been followed (tests, prompts, resources, README, naming convention)
|
|
13
13
|
- [ ] If this changes project structure, conventions, env vars, or the tool/prompt/resource surface: both `CLAUDE.md` and `.github/copilot-instructions.md` are updated (see the mirror rule at the top of `CLAUDE.md`)
|
|
14
14
|
- [ ] If this changes a dependency: `uv.lock` is updated (`uv lock`) and committed alongside `pyproject.toml`
|
|
@@ -4,7 +4,7 @@ This file provides guidance to GitHub Copilot when working with code in this rep
|
|
|
4
4
|
|
|
5
5
|
## Project
|
|
6
6
|
|
|
7
|
-
`docker-mcp` is a Python MCP (Model Context Protocol) server that exposes the Docker SDK for Python — plus selected docker CLI features (Compose, Context, Buildx, Scout) and direct OCI-registry HTTPS access — as MCP tools. It requires Python >=3.14 and is managed with `uv`. It is published to PyPI as **`docker-mcp-server`** and as a container image to GHCR (`ghcr.io/
|
|
7
|
+
`docker-mcp` is a Python MCP (Model Context Protocol) server that exposes the Docker SDK for Python — plus selected docker CLI features (Compose, Context, Buildx, Scout) and direct OCI-registry HTTPS access — as MCP tools. It requires Python >=3.14 and is managed with `uv`. It is published to PyPI as **`docker-mcp-server`** and as a container image to GHCR (`ghcr.io/l337-org/docker-mcp-server`), mirrored to Docker Hub (`gavinlucas/docker-mcp-server`) when the opt-in `DOCKERHUB_*` release secrets are configured (the import package stays `docker_mcp`, the repo stays `…/docker-mcp`); two console scripts — `docker-mcp` and `docker-mcp-server` — both target `docker_mcp:main`. A third distribution channel packages the server as a **Claude Desktop Extension (`.mcpb`)** attached to each GitHub Release (see "Desktop Extension (MCPB)" below). A fourth channel (**Homebrew tap**) exists in `gavinlucas/homebrew-tap` but is currently **paused** — see "Homebrew tap" below.
|
|
8
8
|
|
|
9
9
|
The `docker` dep uses the `[ssh]` extra (paramiko), so `DOCKER_HOST=ssh://…` works via a pure-Python transport (no system `ssh` binary; works in the container images). docker-py auto-selects paramiko for `ssh://`, so there's no transport code — only the `ssh://` branch in `system._connection_help`. CLI-backed tools (Compose, Buildx, Context, Scout) shell out to `docker`, which would otherwise need the system `ssh` client — instead, `_cli.py:run_docker` detects `DOCKER_HOST=ssh://…` and routes the subprocess through a per-call local TCP proxy (`docker_mcp/tools/_ssh_proxy.py`) that opens its own paramiko connection and runs `docker system dial-stdio` over it, so the CLI authenticates the same way the docker-py-backed tools do, with no system `ssh` binary involved (except a `ProxyCommand` in `~/.ssh/config` for bastion/jump-host setups, which paramiko runs as an external command — commonly `ssh -W %h:%p ...` — for both tool families alike).
|
|
10
10
|
|
|
@@ -97,11 +97,11 @@ The infrastructure exists (`scripts/docker-mcp-server.rb.tpl`, `.github/workflow
|
|
|
97
97
|
|
|
98
98
|
### MCP Registry (`server.json`)
|
|
99
99
|
|
|
100
|
-
A discovery listing in the official MCP Registry (`registry.modelcontextprotocol.io`), which stores only metadata pointing at the existing artifacts. `server.json` (repo root, name `io.github.
|
|
100
|
+
A discovery listing in the official MCP Registry (`registry.modelcontextprotocol.io`), which stores only metadata pointing at the existing artifacts. `server.json` (repo root, name `io.github.L337-org/docker-mcp-server`) declares three package types — `pypi`, `oci` (GHCR image), `mcpb` (release `.mcpb`). The `registry` job in `.github/workflows/publish.yaml` stamps the tag version + the published `.mcpb`'s `fileSha256` into `server.json`, authenticates via GitHub OIDC (`id-token: write`, no secret), and runs `mcp-publisher publish`. Ownership is verified per package against `server.json`'s `name`, so three markers must equal it: the `<!-- mcp-name: … -->` comment in `README.md` (PyPI), the `io.modelcontextprotocol.server.name` image label in the `images` job (OCI), and the `.mcpb` URL + hash (MCPB). Keep them in sync with `server.json`'s `name`.
|
|
101
101
|
|
|
102
102
|
### Release pipeline (`.github/workflows/publish.yaml`)
|
|
103
103
|
|
|
104
|
-
All publishing runs through one workflow on each **published GitHub Release**: `preflight` → `pypi` ∥ `images`(→`dockerhub-description`) ∥ `mcpb` → `registry` → `verify`, plus a `notify` job on failure. `preflight` resolves the tag once (every job checks out **the tag ref**) and fails fast if the tag disagrees with the committed `pyproject.toml` / `manifest.json` / `uv.lock` self-entry versions — preventing a split-brain release where PyPI ships the pyproject version and everything else ships the tag version. `verify` confirms all channels serve the version (PyPI JSON API, both GHCR tags, `.mcpb` asset + checksum, registry listing). `notify` files a deduplicated `ci-failure` + `wf:release` issue via `.github/actions/file-failure-issue` (one open issue per failure stream; a scheduled Claude responder routine polls `ci-failure` issues). Re-runs go through `workflow_dispatch` with the tag and are idempotent end-to-end (`skip-existing` on PyPI, re-pushed image tags, `--clobber` on the `.mcpb`, duplicate-tolerant registry publish). **PyPI Trusted Publishing pins the workflow *filename* (`publish.yaml`)** — when reviewing a PR that renames or splits this workflow, flag that the PyPI trusted publisher must be updated first. `.github/release.yml` (GitHub's release-*notes* config — a different file) groups generated notes; `publish-homebrew.yaml` (paused, dispatch-only) stays separate. When reviewing changes to the pipeline's job graph, ownership markers, or re-run semantics, check this section stays accurate.
|
|
104
|
+
All publishing runs through one workflow on each **published GitHub Release**: `preflight` → `pypi` ∥ `images`(→`dockerhub-description`) ∥ `mcpb` → `registry` → `verify`, plus a `notify` job on failure. `preflight` resolves the tag once (every job checks out **the tag ref**) and fails fast if the tag disagrees with the committed `pyproject.toml` / `manifest.json` / `uv.lock` self-entry versions — preventing a split-brain release where PyPI ships the pyproject version and everything else ships the tag version. It also refuses to run when `github.repository_owner` isn't `L337-org`, so a release published from a fork (or mis-timed around a repo transfer) fails before anything ships rather than half-publishing. `verify` confirms all channels serve the version (PyPI JSON API, both GHCR tags, `.mcpb` asset + checksum, registry listing). `notify` files a deduplicated `ci-failure` + `wf:release` issue via `.github/actions/file-failure-issue` (one open issue per failure stream; a scheduled Claude responder routine polls `ci-failure` issues). Re-runs go through `workflow_dispatch` with the tag and are idempotent end-to-end (`skip-existing` on PyPI, re-pushed image tags, `--clobber` on the `.mcpb`, duplicate-tolerant registry publish). **PyPI Trusted Publishing pins the workflow *filename* (`publish.yaml`)** — when reviewing a PR that renames or splits this workflow, flag that the PyPI trusted publisher must be updated first. `.github/release.yml` (GitHub's release-*notes* config — a different file) groups generated notes; `publish-homebrew.yaml` (paused, dispatch-only) stays separate. When reviewing changes to the pipeline's job graph, ownership markers, or re-run semantics, check this section stays accurate.
|
|
105
105
|
|
|
106
106
|
## Conventions
|
|
107
107
|
|
|
@@ -41,7 +41,7 @@ jobs:
|
|
|
41
41
|
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
|
42
42
|
|
|
43
43
|
- name: Set up uv
|
|
44
|
-
uses: astral-sh/setup-uv@
|
|
44
|
+
uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
|
|
45
45
|
with:
|
|
46
46
|
# Pinned (matching the Dockerfile's uv image tag) so this step never needs the
|
|
47
47
|
# live "resolve latest" fetch to raw.githubusercontent.com — that network call
|
|
@@ -102,7 +102,7 @@ jobs:
|
|
|
102
102
|
os: [macos-latest, macos-15-intel, windows-latest]
|
|
103
103
|
steps:
|
|
104
104
|
- name: Set up uv
|
|
105
|
-
uses: astral-sh/setup-uv@
|
|
105
|
+
uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
|
|
106
106
|
with:
|
|
107
107
|
# This job deliberately has no checkout — it tests the *published* package, not the
|
|
108
108
|
# repo — so disable the repo-keyed cache and the empty-workdir warning it triggers.
|
|
@@ -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@
|
|
34
|
+
uses: github/codeql-action/init@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # v4
|
|
35
35
|
with:
|
|
36
36
|
languages: ${{ matrix.language }}
|
|
37
37
|
|
|
38
38
|
- name: Autobuild
|
|
39
|
-
uses: github/codeql-action/autobuild@
|
|
39
|
+
uses: github/codeql-action/autobuild@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # v4
|
|
40
40
|
|
|
41
41
|
- name: Perform CodeQL Analysis
|
|
42
|
-
uses: github/codeql-action/analyze@
|
|
42
|
+
uses: github/codeql-action/analyze@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # v4
|
|
@@ -33,7 +33,7 @@ jobs:
|
|
|
33
33
|
python-version: "3.14"
|
|
34
34
|
|
|
35
35
|
- name: Set up uv
|
|
36
|
-
uses: astral-sh/setup-uv@
|
|
36
|
+
uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
|
|
37
37
|
|
|
38
38
|
- name: Install dependencies
|
|
39
39
|
# --locked fails if uv.lock disagrees with pyproject.toml instead of silently
|
|
@@ -62,7 +62,7 @@ jobs:
|
|
|
62
62
|
python-version: "3.14"
|
|
63
63
|
|
|
64
64
|
- name: Set up uv
|
|
65
|
-
uses: astral-sh/setup-uv@
|
|
65
|
+
uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
|
|
66
66
|
|
|
67
67
|
- name: Install dependencies
|
|
68
68
|
# --locked fails if uv.lock disagrees with pyproject.toml instead of silently
|
|
@@ -91,7 +91,7 @@ jobs:
|
|
|
91
91
|
python-version: "3.14"
|
|
92
92
|
|
|
93
93
|
- name: Set up uv
|
|
94
|
-
uses: astral-sh/setup-uv@
|
|
94
|
+
uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
|
|
95
95
|
|
|
96
96
|
- name: Install dependencies
|
|
97
97
|
# --locked fails if uv.lock disagrees with pyproject.toml instead of silently
|
|
@@ -158,7 +158,7 @@ jobs:
|
|
|
158
158
|
python-version: "3.14"
|
|
159
159
|
|
|
160
160
|
- name: Set up uv
|
|
161
|
-
uses: astral-sh/setup-uv@
|
|
161
|
+
uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
|
|
162
162
|
|
|
163
163
|
- name: Install dependencies
|
|
164
164
|
# --locked fails if uv.lock disagrees with pyproject.toml instead of silently
|
|
@@ -64,7 +64,7 @@ jobs:
|
|
|
64
64
|
run: git fetch --depth=1 origin main && git checkout origin/main -- scripts/docker-mcp-server.rb.tpl
|
|
65
65
|
|
|
66
66
|
- name: Install uv
|
|
67
|
-
uses: astral-sh/setup-uv@
|
|
67
|
+
uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
|
|
68
68
|
|
|
69
69
|
- name: Resolve version, Python target, and macOS floor
|
|
70
70
|
run: |
|
|
@@ -15,7 +15,7 @@ name: Release
|
|
|
15
15
|
# channel actually converged so a partial release is loud instead of silent.
|
|
16
16
|
#
|
|
17
17
|
# PyPI Trusted Publishing pins the WORKFLOW FILENAME: the trusted publisher on PyPI must list
|
|
18
|
-
# `publish.yaml` (owner
|
|
18
|
+
# `publish.yaml` (owner L337-org, repo docker-mcp). If the pypi job fails with an OIDC
|
|
19
19
|
# `invalid-publisher` error, that registration is missing — add it on PyPI, then re-run.
|
|
20
20
|
#
|
|
21
21
|
# Partial-failure semantics: no rollback is attempted (PyPI files are immutable anyway). The
|
|
@@ -55,6 +55,16 @@ jobs:
|
|
|
55
55
|
tag: ${{ steps.resolve.outputs.tag }}
|
|
56
56
|
version: ${{ steps.resolve.outputs.version }}
|
|
57
57
|
steps:
|
|
58
|
+
- name: Assert canonical repository owner
|
|
59
|
+
# The GHCR path, MCP Registry name, and PyPI trusted publisher are all pinned to the
|
|
60
|
+
# L337-org identity. Publishing from anywhere else (a fork, or the window between the
|
|
61
|
+
# identity sweep landing and the repo transfer) would half-publish — PyPI first, then
|
|
62
|
+
# fail on GHCR/registry. Fail fast before anything ships; every other job needs preflight.
|
|
63
|
+
if: github.repository_owner != 'L337-org'
|
|
64
|
+
run: |
|
|
65
|
+
echo "::error::This pipeline publishes the L337-org identity but is running in ${GITHUB_REPOSITORY}. Refusing to publish."
|
|
66
|
+
exit 1
|
|
67
|
+
|
|
58
68
|
- name: Resolve tag and version
|
|
59
69
|
id: resolve
|
|
60
70
|
env:
|
|
@@ -142,7 +152,7 @@ jobs:
|
|
|
142
152
|
python-version: "3.14"
|
|
143
153
|
|
|
144
154
|
- name: Install uv
|
|
145
|
-
uses: astral-sh/setup-uv@
|
|
155
|
+
uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
|
|
146
156
|
|
|
147
157
|
- name: Build sdist and wheel
|
|
148
158
|
run: uv build
|
|
@@ -160,7 +170,7 @@ jobs:
|
|
|
160
170
|
# Publishes the container images:
|
|
161
171
|
# full -> docker-mcp-server:latest + :<version>
|
|
162
172
|
# no-scout -> docker-mcp-server:no-scout + :<version>-no-scout
|
|
163
|
-
# Images go to GHCR (ghcr.io/
|
|
173
|
+
# Images go to GHCR (ghcr.io/l337-org/docker-mcp-server) always, and are mirrored to Docker
|
|
164
174
|
# Hub (docker.io/gavinlucas/docker-mcp-server) when the DOCKERHUB_USER / DOCKERHUB_TOKEN repo
|
|
165
175
|
# secrets are set. The Hub mirror is opt-in: with the secrets unset the Hub login/tags steps
|
|
166
176
|
# are skipped and only GHCR is pushed, so a release never fails for lack of Hub credentials.
|
|
@@ -202,7 +212,7 @@ jobs:
|
|
|
202
212
|
VERSION: ${{ needs.preflight.outputs.version }}
|
|
203
213
|
run: |
|
|
204
214
|
# GHCR always; mirror to Docker Hub only when the credentials are present (see header).
|
|
205
|
-
registries="ghcr.io/
|
|
215
|
+
registries="ghcr.io/l337-org/docker-mcp-server"
|
|
206
216
|
if [ -n "$DOCKERHUB_USER" ] && [ -n "$DOCKERHUB_TOKEN" ]; then
|
|
207
217
|
registries="$registries docker.io/gavinlucas/docker-mcp-server"
|
|
208
218
|
fi
|
|
@@ -254,9 +264,9 @@ jobs:
|
|
|
254
264
|
# match `name` in server.json so the registry can verify we own this image (see the
|
|
255
265
|
# registry job below). image.version is the v-stripped version, matching the image tags.
|
|
256
266
|
labels: |
|
|
257
|
-
org.opencontainers.image.source=https://github.com/
|
|
267
|
+
org.opencontainers.image.source=https://github.com/L337-org/docker-mcp
|
|
258
268
|
org.opencontainers.image.version=${{ needs.preflight.outputs.version }}
|
|
259
|
-
io.modelcontextprotocol.server.name=io.github.
|
|
269
|
+
io.modelcontextprotocol.server.name=io.github.L337-org/docker-mcp-server
|
|
260
270
|
build-args: |
|
|
261
271
|
INSTALL_CLI=${{ matrix.install_cli }}
|
|
262
272
|
INSTALL_SCOUT=${{ matrix.install_scout }}
|
|
@@ -341,7 +351,7 @@ jobs:
|
|
|
341
351
|
# Publishes server.json to the official MCP Registry (registry.modelcontextprotocol.io). The
|
|
342
352
|
# registry stores only metadata — it points at the artifacts the sibling jobs above publish —
|
|
343
353
|
# and verifies we own each listed package via a marker that must equal server.json's `name`
|
|
344
|
-
# (io.github.
|
|
354
|
+
# (io.github.L337-org/docker-mcp-server):
|
|
345
355
|
# - pypi -> the `<!-- mcp-name: ... -->` comment in README.md (PyPI long-description)
|
|
346
356
|
# - oci -> the io.modelcontextprotocol.server.name image label (set in the images job)
|
|
347
357
|
# - mcpb -> the .mcpb release-asset URL (must contain "mcp") + a matching fileSha256
|
|
@@ -393,9 +403,9 @@ jobs:
|
|
|
393
403
|
.version = $v
|
|
394
404
|
| (.packages[] | select(.registryType == "pypi") | .version) = $v
|
|
395
405
|
| (.packages[] | select(.registryType == "oci") | .identifier)
|
|
396
|
-
= "ghcr.io/
|
|
406
|
+
= "ghcr.io/l337-org/docker-mcp-server:\($v)"
|
|
397
407
|
| (.packages[] | select(.registryType == "mcpb") | .identifier)
|
|
398
|
-
= "https://github.com/
|
|
408
|
+
= "https://github.com/L337-org/docker-mcp/releases/download/\($tag)/docker-mcp-server-\($v).mcpb"
|
|
399
409
|
| (.packages[] | select(.registryType == "mcpb") | .fileSha256) = $sha
|
|
400
410
|
' server.json > server.tmp && mv server.tmp server.json
|
|
401
411
|
echo "--- server.json ---"; cat server.json
|
|
@@ -481,7 +491,7 @@ jobs:
|
|
|
481
491
|
for tag in "${VERSION}" "${VERSION}-no-scout"; do
|
|
482
492
|
ok=""
|
|
483
493
|
for i in $(seq 1 5); do
|
|
484
|
-
if docker buildx imagetools inspect "ghcr.io/
|
|
494
|
+
if docker buildx imagetools inspect "ghcr.io/l337-org/docker-mcp-server:${tag}" >/dev/null 2>&1; then
|
|
485
495
|
echo "GHCR OK: :${tag}"; ok=1; break
|
|
486
496
|
fi
|
|
487
497
|
echo "::notice::GHCR tag :${tag} not readable yet (attempt $i/5); waiting 15s"
|
|
@@ -512,7 +522,7 @@ jobs:
|
|
|
512
522
|
- name: Verify the MCP Registry lists the version
|
|
513
523
|
run: |
|
|
514
524
|
set -euo pipefail
|
|
515
|
-
url="https://registry.modelcontextprotocol.io/v0/servers?search=io.github.
|
|
525
|
+
url="https://registry.modelcontextprotocol.io/v0/servers?search=io.github.L337-org/docker-mcp-server"
|
|
516
526
|
for i in $(seq 1 5); do
|
|
517
527
|
if curl -fsS "$url" | jq -e --arg v "$VERSION" \
|
|
518
528
|
'.servers[] | select(.server.version == $v)' >/dev/null; then
|
|
@@ -11,7 +11,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
|
|
11
11
|
|
|
12
12
|
## Project
|
|
13
13
|
|
|
14
|
-
`docker-mcp` is a Python MCP server (requires Python >=3.14) managed with `uv` that exposes the Docker SDK for Python as MCP tools. The entry point is the `docker_mcp` package, run with `python -m docker_mcp` or via the installed console script. It is **published to PyPI as `docker-mcp-server`** (the `docker-mcp` name was already taken) and as a container image to GHCR (`ghcr.io/
|
|
14
|
+
`docker-mcp` is a Python MCP server (requires Python >=3.14) managed with `uv` that exposes the Docker SDK for Python as MCP tools. The entry point is the `docker_mcp` package, run with `python -m docker_mcp` or via the installed console script. It is **published to PyPI as `docker-mcp-server`** (the `docker-mcp` name was already taken) and as a container image to GHCR (`ghcr.io/l337-org/docker-mcp-server`), mirrored to Docker Hub (`gavinlucas/docker-mcp-server`) when the opt-in `DOCKERHUB_*` release secrets are configured; the import package stays `docker_mcp` and the repo stays `…/docker-mcp`. Two console scripts are installed — `docker-mcp` and `docker-mcp-server` — both targeting `docker_mcp:main`. A third channel packages the server as a **Claude Desktop Extension (`.mcpb`)** attached to each GitHub Release — see "Desktop Extension (MCPB bundle)" below. A fourth channel (**Homebrew tap**) exists in `gavinlucas/homebrew-tap` but is currently **paused** — see "Homebrew tap" below.
|
|
15
15
|
|
|
16
16
|
The `docker` dependency is pulled with its `[ssh]` extra (paramiko), so `DOCKER_HOST=ssh://…` works through a pure-Python transport — no system `ssh` binary, identical on the host and in the container images. docker-py auto-selects paramiko for `ssh://` when present, so there is no transport code to maintain (just the `ssh://` branch in `system._connection_help`). CLI-backed tools (Compose, Buildx, Context, Scout) shell out to `docker`, which would otherwise use the *system* `ssh` — instead, `_cli.py:run_docker` detects `DOCKER_HOST=ssh://…` and routes the subprocess through a per-call local TCP proxy (`docker_mcp/tools/_ssh_proxy.py`) that opens its own paramiko connection (mirroring docker-py's `SSHHTTPAdapter` defaults) and runs `docker system dial-stdio` over it, so the CLI authenticates identically to the docker-py-backed tools with no system `ssh` binary involved (the one exception being a `ProxyCommand` in `~/.ssh/config` for bastion/jump-host setups, which paramiko runs as an external command — commonly `ssh -W %h:%p ...` — same as it would for the docker-py-backed tools).
|
|
17
17
|
|
|
@@ -163,11 +163,11 @@ The infrastructure exists (`scripts/docker-mcp-server.rb.tpl`, `.github/workflow
|
|
|
163
163
|
|
|
164
164
|
### MCP Registry (`server.json`)
|
|
165
165
|
|
|
166
|
-
A discovery listing in the official MCP Registry (`registry.modelcontextprotocol.io`), which stores only **metadata** pointing at the artifacts the other channels already publish — so it's not a fourth artifact, just an index entry covering all of them. `server.json` (repo root, server name `io.github.
|
|
166
|
+
A discovery listing in the official MCP Registry (`registry.modelcontextprotocol.io`), which stores only **metadata** pointing at the artifacts the other channels already publish — so it's not a fourth artifact, just an index entry covering all of them. `server.json` (repo root, server name `io.github.L337-org/docker-mcp-server`) declares three package types in one entry: `pypi` (`docker-mcp-server`), `oci` (the GHCR image), and `mcpb` (the release `.mcpb`). The `registry` job in `.github/workflows/publish.yaml` stamps the tag version and the published `.mcpb`'s `fileSha256` into `server.json`, authenticates via **GitHub OIDC** (`id-token: write`, no stored secret), and runs `mcp-publisher publish`. The registry verifies we own each listed package by matching a marker against `server.json`'s `name`, so three markers must stay equal to it: the `<!-- mcp-name: … -->` comment in `README.md` (PyPI long-description), the `io.modelcontextprotocol.server.name` image label in the `images` job (OCI), and the `.mcpb` URL (must contain "mcp") + its hash (MCPB). The job runs `needs: [pypi, images, mcpb]`, so all three markers are live before it starts — its short retries only absorb registry-side read lag. **If `server.json`'s name/markers or the package set change, update this section.**
|
|
167
167
|
|
|
168
168
|
### Release pipeline (`.github/workflows/publish.yaml`)
|
|
169
169
|
|
|
170
|
-
All publishing runs through one workflow on each **published GitHub Release** (nothing publishes without that human step): `preflight` → `pypi` ∥ `images`(→`dockerhub-description`) ∥ `mcpb` → `registry` → `verify`, with a `notify` job on failure. `preflight` resolves the tag once for every job (each checks out **the tag ref**, not the event SHA) and fails fast if the tag disagrees with the committed `pyproject.toml` / `manifest.json` / `uv.lock` self-entry versions — preventing a split-brain release (PyPI ships the pyproject version; every other channel ships the tag version). `verify` confirms all four channels actually serve the version (PyPI JSON API, both GHCR tags, the `.mcpb` asset + checksum, the registry listing) so a partial release is loud. `notify` files (or comments on) a deduplicated issue labeled `ci-failure` + `wf:release` via the composite action `.github/actions/file-failure-issue` — one open issue per failure stream; a scheduled Claude responder routine polls `ci-failure` issues. Re-run a failed release via `workflow_dispatch` with the tag: every job is idempotent (`skip-existing` on PyPI, re-pushed image tags, `--clobber` on the `.mcpb`, duplicate-tolerant registry publish). **PyPI Trusted Publishing pins the workflow *filename*** — the trusted publisher on PyPI must name `publish.yaml`; if the `pypi` job fails OIDC, that registration is missing. Version-bump checklist for a release: edit `pyproject.toml` + `manifest.json`, run `uv lock`, merge, then publish a GitHub Release whose tag matches (`.github/release.yml` — GitHub's release-*notes* config, a different file — groups the generated notes, Dependabot PRs under "Dependencies"). `publish-homebrew.yaml` (paused, dispatch-only) stays separate. **When the pipeline's job graph, markers, or re-run semantics change, update this section.**
|
|
170
|
+
All publishing runs through one workflow on each **published GitHub Release** (nothing publishes without that human step): `preflight` → `pypi` ∥ `images`(→`dockerhub-description`) ∥ `mcpb` → `registry` → `verify`, with a `notify` job on failure. `preflight` resolves the tag once for every job (each checks out **the tag ref**, not the event SHA) and fails fast if the tag disagrees with the committed `pyproject.toml` / `manifest.json` / `uv.lock` self-entry versions — preventing a split-brain release (PyPI ships the pyproject version; every other channel ships the tag version). It also refuses to run when `github.repository_owner` isn't `L337-org`, so a release published from a fork (or mis-timed around a repo transfer) fails before anything ships rather than half-publishing. `verify` confirms all four channels actually serve the version (PyPI JSON API, both GHCR tags, the `.mcpb` asset + checksum, the registry listing) so a partial release is loud. `notify` files (or comments on) a deduplicated issue labeled `ci-failure` + `wf:release` via the composite action `.github/actions/file-failure-issue` — one open issue per failure stream; a scheduled Claude responder routine polls `ci-failure` issues. Re-run a failed release via `workflow_dispatch` with the tag: every job is idempotent (`skip-existing` on PyPI, re-pushed image tags, `--clobber` on the `.mcpb`, duplicate-tolerant registry publish). **PyPI Trusted Publishing pins the workflow *filename*** — the trusted publisher on PyPI must name `publish.yaml`; if the `pypi` job fails OIDC, that registration is missing. Version-bump checklist for a release: edit `pyproject.toml` + `manifest.json`, run `uv lock`, merge, then publish a GitHub Release whose tag matches (`.github/release.yml` — GitHub's release-*notes* config, a different file — groups the generated notes, Dependabot PRs under "Dependencies"). `publish-homebrew.yaml` (paused, dispatch-only) stays separate. **When the pipeline's job graph, markers, or re-run semantics change, update this section.**
|
|
171
171
|
|
|
172
172
|
## Conventions
|
|
173
173
|
|
|
@@ -185,4 +185,4 @@ It reads the version from `pyproject.toml`, creates `dist/` if needed, writes a
|
|
|
185
185
|
|
|
186
186
|
## Reporting issues
|
|
187
187
|
|
|
188
|
-
Bug reports and feature requests have templates that you can choose when you [`create an issue`](https://github.com/
|
|
188
|
+
Bug reports and feature requests have templates that you can choose when you [`create an issue`](https://github.com/L337-org/docker-mcp/issues/new/choose). Please select the correct issue type and follow the template.
|
|
@@ -4,11 +4,11 @@ More than just a fully featured [MCP](https://modelcontextprotocol.io) server th
|
|
|
4
4
|
|
|
5
5
|
It can manage multiple Docker daemons, e.g. both your local dev environment and also a remote production environment over TCP, TLS or SSH in a single session. It can also be configured to mark some daemons as read-only, so that you can monitor them without the risk of making accidental changes. It also exposes things like logs and stats as resources so that you can easily monitor and triage your environments with a few prompts.
|
|
6
6
|
|
|
7
|
-
The server runs entirely on your machine and sends no telemetry. You are entirely in control — see the [Privacy Policy](https://github.com/
|
|
7
|
+
The server runs entirely on your machine and sends no telemetry. You are entirely in control — see the [Privacy Policy](https://github.com/L337-org/docker-mcp#privacy-policy).
|
|
8
8
|
|
|
9
|
-
This image is the container distribution of the project. **Full documentation, configuration, and source are on GitHub: <https://github.com/
|
|
9
|
+
This image is the container distribution of the project. **Full documentation, configuration, and source are on GitHub: <https://github.com/L337-org/docker-mcp>.**
|
|
10
10
|
|
|
11
|
-
> The same images are published to GHCR as [`ghcr.io/
|
|
11
|
+
> The same images are published to GHCR as [`ghcr.io/l337-org/docker-mcp-server`](https://github.com/L337-org/docker-mcp/pkgs/container/docker-mcp-server) — identical content, so use whichever registry you prefer.
|
|
12
12
|
|
|
13
13
|
## Quick start
|
|
14
14
|
|
|
@@ -72,14 +72,14 @@ Set these in the client's `env` block. Three switches restrict which tools are r
|
|
|
72
72
|
|
|
73
73
|
`DOCKER_HOST` / `DOCKER_TLS_VERIFY` / `DOCKER_CERT_PATH` retarget the daemon (e.g. `-e DOCKER_HOST=tcp://remote-host:2375`).
|
|
74
74
|
|
|
75
|
-
See the [full configuration reference](https://github.com/
|
|
75
|
+
See the [full configuration reference](https://github.com/L337-org/docker-mcp#configuration) for the complete list and examples.
|
|
76
76
|
|
|
77
77
|
## Security
|
|
78
78
|
|
|
79
|
-
Connecting this server to an AI agent grants it the same access as a local Docker CLI session against the configured daemon — the daemon's socket is effectively root-equivalent on its host. Prefer pointing it at a daemon dedicated to workloads the agent may touch (a dev VM, a remote sandbox, Docker Desktop, a rootless install) rather than your production socket. See the [Security considerations](https://github.com/
|
|
79
|
+
Connecting this server to an AI agent grants it the same access as a local Docker CLI session against the configured daemon — the daemon's socket is effectively root-equivalent on its host. Prefer pointing it at a daemon dedicated to workloads the agent may touch (a dev VM, a remote sandbox, Docker Desktop, a rootless install) rather than your production socket. See the [Security considerations](https://github.com/L337-org/docker-mcp#security-considerations) on GitHub before enabling the server.
|
|
80
80
|
|
|
81
81
|
## Links
|
|
82
82
|
|
|
83
|
-
- **Source, full docs & issues:** <https://github.com/
|
|
84
|
-
- **Also on PyPI** (run without a container): `uvx docker-mcp-server` — see the [README](https://github.com/
|
|
83
|
+
- **Source, full docs & issues:** <https://github.com/L337-org/docker-mcp>
|
|
84
|
+
- **Also on PyPI** (run without a container): `uvx docker-mcp-server` — see the [README](https://github.com/L337-org/docker-mcp#using-the-server).
|
|
85
85
|
- **License & contributing:** see the GitHub repository.
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: docker-mcp-server
|
|
3
|
-
Version: 2.1.
|
|
3
|
+
Version: 2.1.2
|
|
4
4
|
Summary: MCP server for managing Docker resources via the Docker SDK for Python
|
|
5
|
-
Project-URL: Homepage, https://github.com/
|
|
6
|
-
Project-URL: Repository, https://github.com/
|
|
7
|
-
Project-URL: Issues, https://github.com/
|
|
5
|
+
Project-URL: Homepage, https://github.com/L337-org/docker-mcp
|
|
6
|
+
Project-URL: Repository, https://github.com/L337-org/docker-mcp
|
|
7
|
+
Project-URL: Issues, https://github.com/L337-org/docker-mcp/issues
|
|
8
8
|
Author: Gavin Lucas
|
|
9
9
|
License-Expression: MIT
|
|
10
10
|
License-File: LICENSE
|
|
@@ -26,13 +26,13 @@ Requires-Dist: mcp>=1.27.1
|
|
|
26
26
|
Requires-Dist: requests>=2.26.0
|
|
27
27
|
Description-Content-Type: text/markdown
|
|
28
28
|
|
|
29
|
-
<img src="https://raw.githubusercontent.com/
|
|
29
|
+
<img src="https://raw.githubusercontent.com/L337-org/docker-mcp/main/assets/icon.png" align="left" width="72" height="72" alt="">
|
|
30
30
|
|
|
31
31
|
# docker-mcp-server
|
|
32
32
|
|
|
33
33
|
[](https://glama.ai/mcp/servers/GavinLucas/docker-mcp)
|
|
34
34
|
|
|
35
|
-
<!-- mcp-name: io.github.
|
|
35
|
+
<!-- mcp-name: io.github.L337-org/docker-mcp-server -->
|
|
36
36
|
|
|
37
37
|
More than just a fully featured [MCP](https://modelcontextprotocol.io) server that lets AI agents manage Docker — containers, images, networks, volumes, swarm services, secrets, configs, nodes, plugins, etc., it helps you create workflows to easily manage your Docker environments.
|
|
38
38
|
|
|
@@ -79,7 +79,7 @@ To pin a specific version, append `==<version>` to the package name (e.g. `docke
|
|
|
79
79
|
"command": "uvx",
|
|
80
80
|
"args": [
|
|
81
81
|
"--from",
|
|
82
|
-
"git+https://github.com/
|
|
82
|
+
"git+https://github.com/L337-org/docker-mcp.git",
|
|
83
83
|
"docker-mcp-server"
|
|
84
84
|
],
|
|
85
85
|
"env": {}
|
|
@@ -93,7 +93,7 @@ To pin a specific revision, append `@<tag-or-commit>` to the git URL.
|
|
|
93
93
|
### Install as a Desktop Extension (.mcpb)
|
|
94
94
|
|
|
95
95
|
For [Claude Desktop](https://claude.com/download), a one-click bundle is attached to each
|
|
96
|
-
[GitHub Release](https://github.com/
|
|
96
|
+
[GitHub Release](https://github.com/L337-org/docker-mcp/releases) as
|
|
97
97
|
`docker-mcp-server-<version>.mcpb` (with a matching `.sha256`). Download it and drag it into
|
|
98
98
|
**Settings → Extensions**, or use **Settings → Extensions → Advanced settings → Install extension…**
|
|
99
99
|
and pick the file. The install dialog surfaces a **Docker host(s)** field and the read-only /
|
|
@@ -110,7 +110,7 @@ Docker context; set one endpoint (`ssh://user@host`) for a remote daemon, or lis
|
|
|
110
110
|
Running the server as a container removes the Python / uv / git prerequisites entirely — the only
|
|
111
111
|
thing the host needs is Docker, which you already have. Prebuilt multi-arch images (linux/amd64 +
|
|
112
112
|
linux/arm64) are published on each release to **Docker Hub** (`gavinlucas/docker-mcp-server`) and
|
|
113
|
-
**GHCR** (`ghcr.io/
|
|
113
|
+
**GHCR** (`ghcr.io/l337-org/docker-mcp-server`) — the two are identical. Point your MCP client at
|
|
114
114
|
`docker run`:
|
|
115
115
|
|
|
116
116
|
```json
|
|
@@ -131,14 +131,14 @@ linux/arm64) are published on each release to **Docker Hub** (`gavinlucas/docker
|
|
|
131
131
|
|
|
132
132
|
`-i` is required (the server speaks MCP over stdio); `--rm` cleans up when the client disconnects. To
|
|
133
133
|
pin a version, replace `:latest` with a release tag (e.g. `:1.5.1`). To pull from GHCR instead, use
|
|
134
|
-
`ghcr.io/
|
|
134
|
+
`ghcr.io/l337-org/docker-mcp-server:latest`.
|
|
135
135
|
|
|
136
|
-
> **Image renamed.** As of 1.5.0 the image is published
|
|
137
|
-
>
|
|
138
|
-
>
|
|
136
|
+
> **Image renamed.** As of 1.5.0 the image is published as `docker-mcp-server` (matching the PyPI
|
|
137
|
+
> name). The old `ghcr.io/gavinlucas/docker-mcp` image is frozen at 1.4.0 and no longer updated —
|
|
138
|
+
> point new pulls at `ghcr.io/l337-org/docker-mcp-server`.
|
|
139
139
|
|
|
140
140
|
**Image variants.** Two variants are published to both registries (`gavinlucas/docker-mcp-server` on
|
|
141
|
-
Docker Hub and `ghcr.io/
|
|
141
|
+
Docker Hub and `ghcr.io/l337-org/docker-mcp-server` on GHCR), both built from one `Dockerfile`. The
|
|
142
142
|
CLI-backed domains (Compose, Stack, Buildx, Scout, Context) shell out to the `docker` CLI and its
|
|
143
143
|
plugins.
|
|
144
144
|
|
|
@@ -361,7 +361,7 @@ All of these go in the `env` block of the server entry in your MCP client config
|
|
|
361
361
|
"command": "uvx",
|
|
362
362
|
"args": [
|
|
363
363
|
"--from",
|
|
364
|
-
"git+https://github.com/
|
|
364
|
+
"git+https://github.com/L337-org/docker-mcp.git",
|
|
365
365
|
"docker-mcp-server"
|
|
366
366
|
],
|
|
367
367
|
"env": {
|
|
@@ -379,7 +379,7 @@ Swap `DOCKER_MCP_SERVER_READONLY` for `DOCKER_MCP_SERVER_NO_DESTRUCTIVE` to allo
|
|
|
379
379
|
```bash
|
|
380
380
|
claude mcp add docker-mcp-server-readonly \
|
|
381
381
|
--env DOCKER_MCP_SERVER_READONLY=1 \
|
|
382
|
-
-- uvx --from git+https://github.com/
|
|
382
|
+
-- uvx --from git+https://github.com/L337-org/docker-mcp.git docker-mcp-server
|
|
383
383
|
```
|
|
384
384
|
|
|
385
385
|
## Security considerations
|
|
@@ -407,10 +407,10 @@ Connecting this server to an AI agent grants it the same level of access as a lo
|
|
|
407
407
|
| Channel | Link |
|
|
408
408
|
|---------|------|
|
|
409
409
|
| PyPI | [docker-mcp-server](https://pypi.org/project/docker-mcp-server/) |
|
|
410
|
-
| GHCR (container) | [ghcr.io/
|
|
410
|
+
| GHCR (container) | [ghcr.io/l337-org/docker-mcp-server](https://github.com/L337-org/docker-mcp/pkgs/container/docker-mcp-server) |
|
|
411
411
|
| Docker Hub (container) | [gavinlucas/docker-mcp-server](https://hub.docker.com/r/gavinlucas/docker-mcp-server) |
|
|
412
|
-
| Desktop Extension (.mcpb) | [GitHub Releases](https://github.com/
|
|
413
|
-
| Official MCP Registry | [io.github.
|
|
412
|
+
| Desktop Extension (.mcpb) | [GitHub Releases](https://github.com/L337-org/docker-mcp/releases) |
|
|
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/GavinLucas/docker-mcp) |
|
|
415
415
|
| mcp.so | [docker-mcp-server](https://mcp.so/server/docker-mcp-server/GavinLucas) |
|
|
416
416
|
| awesome-mcp-servers | [punkpeye/awesome-mcp-servers](https://github.com/punkpeye/awesome-mcp-servers#cloud-platforms) |
|
|
@@ -419,8 +419,8 @@ Connecting this server to an AI agent grants it the same level of access as a lo
|
|
|
419
419
|
|
|
420
420
|
docker-mcp-server collects no data, sends no telemetry, and has no author-operated backend. It runs
|
|
421
421
|
locally and talks only to the Docker daemon and container registries **you** point it at, as part of
|
|
422
|
-
the operations you request. The full statement is in [PRIVACY.md](https://github.com/
|
|
422
|
+
the operations you request. The full statement is in [PRIVACY.md](https://github.com/L337-org/docker-mcp/blob/main/PRIVACY.md).
|
|
423
423
|
|
|
424
424
|
## Contributing
|
|
425
425
|
|
|
426
|
-
Contributions are welcome. The project values a tight mapping between the Docker SDK's public surface and the MCP tools we expose. See [CONTRIBUTING.md](https://github.com/
|
|
426
|
+
Contributions are welcome. The project values a tight mapping between the Docker SDK's public surface and the MCP tools we expose. See [CONTRIBUTING.md](https://github.com/L337-org/docker-mcp/blob/main/CONTRIBUTING.md) for the project layout, tool conventions, the checklist for adding a new tool module, and local development setup.
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
<img src="https://raw.githubusercontent.com/
|
|
1
|
+
<img src="https://raw.githubusercontent.com/L337-org/docker-mcp/main/assets/icon.png" align="left" width="72" height="72" alt="">
|
|
2
2
|
|
|
3
3
|
# docker-mcp-server
|
|
4
4
|
|
|
5
5
|
[](https://glama.ai/mcp/servers/GavinLucas/docker-mcp)
|
|
6
6
|
|
|
7
|
-
<!-- mcp-name: io.github.
|
|
7
|
+
<!-- mcp-name: io.github.L337-org/docker-mcp-server -->
|
|
8
8
|
|
|
9
9
|
More than just a fully featured [MCP](https://modelcontextprotocol.io) server that lets AI agents manage Docker — containers, images, networks, volumes, swarm services, secrets, configs, nodes, plugins, etc., it helps you create workflows to easily manage your Docker environments.
|
|
10
10
|
|
|
@@ -51,7 +51,7 @@ To pin a specific version, append `==<version>` to the package name (e.g. `docke
|
|
|
51
51
|
"command": "uvx",
|
|
52
52
|
"args": [
|
|
53
53
|
"--from",
|
|
54
|
-
"git+https://github.com/
|
|
54
|
+
"git+https://github.com/L337-org/docker-mcp.git",
|
|
55
55
|
"docker-mcp-server"
|
|
56
56
|
],
|
|
57
57
|
"env": {}
|
|
@@ -65,7 +65,7 @@ To pin a specific revision, append `@<tag-or-commit>` to the git URL.
|
|
|
65
65
|
### Install as a Desktop Extension (.mcpb)
|
|
66
66
|
|
|
67
67
|
For [Claude Desktop](https://claude.com/download), a one-click bundle is attached to each
|
|
68
|
-
[GitHub Release](https://github.com/
|
|
68
|
+
[GitHub Release](https://github.com/L337-org/docker-mcp/releases) as
|
|
69
69
|
`docker-mcp-server-<version>.mcpb` (with a matching `.sha256`). Download it and drag it into
|
|
70
70
|
**Settings → Extensions**, or use **Settings → Extensions → Advanced settings → Install extension…**
|
|
71
71
|
and pick the file. The install dialog surfaces a **Docker host(s)** field and the read-only /
|
|
@@ -82,7 +82,7 @@ Docker context; set one endpoint (`ssh://user@host`) for a remote daemon, or lis
|
|
|
82
82
|
Running the server as a container removes the Python / uv / git prerequisites entirely — the only
|
|
83
83
|
thing the host needs is Docker, which you already have. Prebuilt multi-arch images (linux/amd64 +
|
|
84
84
|
linux/arm64) are published on each release to **Docker Hub** (`gavinlucas/docker-mcp-server`) and
|
|
85
|
-
**GHCR** (`ghcr.io/
|
|
85
|
+
**GHCR** (`ghcr.io/l337-org/docker-mcp-server`) — the two are identical. Point your MCP client at
|
|
86
86
|
`docker run`:
|
|
87
87
|
|
|
88
88
|
```json
|
|
@@ -103,14 +103,14 @@ linux/arm64) are published on each release to **Docker Hub** (`gavinlucas/docker
|
|
|
103
103
|
|
|
104
104
|
`-i` is required (the server speaks MCP over stdio); `--rm` cleans up when the client disconnects. To
|
|
105
105
|
pin a version, replace `:latest` with a release tag (e.g. `:1.5.1`). To pull from GHCR instead, use
|
|
106
|
-
`ghcr.io/
|
|
106
|
+
`ghcr.io/l337-org/docker-mcp-server:latest`.
|
|
107
107
|
|
|
108
|
-
> **Image renamed.** As of 1.5.0 the image is published
|
|
109
|
-
>
|
|
110
|
-
>
|
|
108
|
+
> **Image renamed.** As of 1.5.0 the image is published as `docker-mcp-server` (matching the PyPI
|
|
109
|
+
> name). The old `ghcr.io/gavinlucas/docker-mcp` image is frozen at 1.4.0 and no longer updated —
|
|
110
|
+
> point new pulls at `ghcr.io/l337-org/docker-mcp-server`.
|
|
111
111
|
|
|
112
112
|
**Image variants.** Two variants are published to both registries (`gavinlucas/docker-mcp-server` on
|
|
113
|
-
Docker Hub and `ghcr.io/
|
|
113
|
+
Docker Hub and `ghcr.io/l337-org/docker-mcp-server` on GHCR), both built from one `Dockerfile`. The
|
|
114
114
|
CLI-backed domains (Compose, Stack, Buildx, Scout, Context) shell out to the `docker` CLI and its
|
|
115
115
|
plugins.
|
|
116
116
|
|
|
@@ -333,7 +333,7 @@ All of these go in the `env` block of the server entry in your MCP client config
|
|
|
333
333
|
"command": "uvx",
|
|
334
334
|
"args": [
|
|
335
335
|
"--from",
|
|
336
|
-
"git+https://github.com/
|
|
336
|
+
"git+https://github.com/L337-org/docker-mcp.git",
|
|
337
337
|
"docker-mcp-server"
|
|
338
338
|
],
|
|
339
339
|
"env": {
|
|
@@ -351,7 +351,7 @@ Swap `DOCKER_MCP_SERVER_READONLY` for `DOCKER_MCP_SERVER_NO_DESTRUCTIVE` to allo
|
|
|
351
351
|
```bash
|
|
352
352
|
claude mcp add docker-mcp-server-readonly \
|
|
353
353
|
--env DOCKER_MCP_SERVER_READONLY=1 \
|
|
354
|
-
-- uvx --from git+https://github.com/
|
|
354
|
+
-- uvx --from git+https://github.com/L337-org/docker-mcp.git docker-mcp-server
|
|
355
355
|
```
|
|
356
356
|
|
|
357
357
|
## Security considerations
|
|
@@ -379,10 +379,10 @@ Connecting this server to an AI agent grants it the same level of access as a lo
|
|
|
379
379
|
| Channel | Link |
|
|
380
380
|
|---------|------|
|
|
381
381
|
| PyPI | [docker-mcp-server](https://pypi.org/project/docker-mcp-server/) |
|
|
382
|
-
| GHCR (container) | [ghcr.io/
|
|
382
|
+
| GHCR (container) | [ghcr.io/l337-org/docker-mcp-server](https://github.com/L337-org/docker-mcp/pkgs/container/docker-mcp-server) |
|
|
383
383
|
| Docker Hub (container) | [gavinlucas/docker-mcp-server](https://hub.docker.com/r/gavinlucas/docker-mcp-server) |
|
|
384
|
-
| Desktop Extension (.mcpb) | [GitHub Releases](https://github.com/
|
|
385
|
-
| Official MCP Registry | [io.github.
|
|
384
|
+
| Desktop Extension (.mcpb) | [GitHub Releases](https://github.com/L337-org/docker-mcp/releases) |
|
|
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/GavinLucas/docker-mcp) |
|
|
387
387
|
| mcp.so | [docker-mcp-server](https://mcp.so/server/docker-mcp-server/GavinLucas) |
|
|
388
388
|
| awesome-mcp-servers | [punkpeye/awesome-mcp-servers](https://github.com/punkpeye/awesome-mcp-servers#cloud-platforms) |
|
|
@@ -391,8 +391,8 @@ Connecting this server to an AI agent grants it the same level of access as a lo
|
|
|
391
391
|
|
|
392
392
|
docker-mcp-server collects no data, sends no telemetry, and has no author-operated backend. It runs
|
|
393
393
|
locally and talks only to the Docker daemon and container registries **you** point it at, as part of
|
|
394
|
-
the operations you request. The full statement is in [PRIVACY.md](https://github.com/
|
|
394
|
+
the operations you request. The full statement is in [PRIVACY.md](https://github.com/L337-org/docker-mcp/blob/main/PRIVACY.md).
|
|
395
395
|
|
|
396
396
|
## Contributing
|
|
397
397
|
|
|
398
|
-
Contributions are welcome. The project values a tight mapping between the Docker SDK's public surface and the MCP tools we expose. See [CONTRIBUTING.md](https://github.com/
|
|
398
|
+
Contributions are welcome. The project values a tight mapping between the Docker SDK's public surface and the MCP tools we expose. See [CONTRIBUTING.md](https://github.com/L337-org/docker-mcp/blob/main/CONTRIBUTING.md) for the project layout, tool conventions, the checklist for adding a new tool module, and local development setup.
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
If you believe you have found a security issue in `docker-mcp`, please open a
|
|
6
6
|
private vulnerability report via GitHub's
|
|
7
|
-
[security advisory flow](https://github.com/
|
|
7
|
+
[security advisory flow](https://github.com/L337-org/docker-mcp/security/advisories/new)
|
|
8
8
|
rather than filing a public issue. That keeps the discussion private until a
|
|
9
9
|
fix is available.
|
|
10
10
|
|
|
@@ -2,24 +2,24 @@
|
|
|
2
2
|
"manifest_version": "0.4",
|
|
3
3
|
"name": "docker-mcp-server",
|
|
4
4
|
"display_name": "Docker MCP Server",
|
|
5
|
-
"version": "2.1.
|
|
5
|
+
"version": "2.1.2",
|
|
6
6
|
"description": "Manage Docker through the Docker SDK for Python and the docker CLI: containers, images, networks, volumes, Compose, Swarm, Buildx, Scout, and OCI registries, exposed as MCP tools.",
|
|
7
7
|
"long_description": "Manage one or more Docker daemons through your AI agent — containers, images, networks, volumes, Compose, Swarm, Buildx, Scout, and OCI registries, exposed as MCP tools.\n\nDiscovery is automatic for your local socket with no configuration required. Or point it at additional remote daemons over TCP, TLS, or SSH (and mark any of them read-only to monitor without the risk of accidental changes). It also surfaces logs and stats as resources for triage. Read-only / no-destructive / disabled-domain switches let you register a restricted tool surface.\n\nAnswer questions like: ‘why did my local container crash?’, ‘is my production system under memory pressure?’, ‘what differences are there between my staging and production systems?’\n\nRuns entirely on your machine and sends no telemetry — see the Privacy Policy.",
|
|
8
8
|
"author": {
|
|
9
9
|
"name": "Gavin Lucas",
|
|
10
10
|
"url": "https://github.com/GavinLucas"
|
|
11
11
|
},
|
|
12
|
-
"homepage": "https://github.com/
|
|
13
|
-
"documentation": "https://github.com/
|
|
14
|
-
"support": "https://github.com/
|
|
12
|
+
"homepage": "https://github.com/L337-org/docker-mcp",
|
|
13
|
+
"documentation": "https://github.com/L337-org/docker-mcp#readme",
|
|
14
|
+
"support": "https://github.com/L337-org/docker-mcp/issues",
|
|
15
15
|
"license": "MIT",
|
|
16
16
|
"icon": "assets/icon.png",
|
|
17
17
|
"repository": {
|
|
18
18
|
"type": "git",
|
|
19
|
-
"url": "https://github.com/
|
|
19
|
+
"url": "https://github.com/L337-org/docker-mcp"
|
|
20
20
|
},
|
|
21
21
|
"keywords": ["docker", "containers", "compose", "swarm", "buildx", "scout", "devops", "mcp"],
|
|
22
|
-
"privacy_policies": ["https://github.com/
|
|
22
|
+
"privacy_policies": ["https://github.com/L337-org/docker-mcp/blob/main/PRIVACY.md"],
|
|
23
23
|
"server": {
|
|
24
24
|
"type": "uv",
|
|
25
25
|
"entry_point": "mcpb_run.py",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "docker-mcp-server"
|
|
3
|
-
version = "2.1.
|
|
3
|
+
version = "2.1.2"
|
|
4
4
|
description = "MCP server for managing Docker resources via the Docker SDK for Python"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = "MIT"
|
|
@@ -45,9 +45,9 @@ docker-mcp = "docker_mcp:main"
|
|
|
45
45
|
docker-mcp-server = "docker_mcp:main"
|
|
46
46
|
|
|
47
47
|
[project.urls]
|
|
48
|
-
Homepage = "https://github.com/
|
|
49
|
-
Repository = "https://github.com/
|
|
50
|
-
Issues = "https://github.com/
|
|
48
|
+
Homepage = "https://github.com/L337-org/docker-mcp"
|
|
49
|
+
Repository = "https://github.com/L337-org/docker-mcp"
|
|
50
|
+
Issues = "https://github.com/L337-org/docker-mcp/issues"
|
|
51
51
|
|
|
52
52
|
[build-system]
|
|
53
53
|
requires = ["hatchling"]
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
# This file is maintained automatically by publish-homebrew.yaml in
|
|
1
|
+
# This file is maintained automatically by publish-homebrew.yaml in L337-org/docker-mcp.
|
|
2
2
|
# Do not edit by hand — changes will be overwritten on the next release.
|
|
3
3
|
class DockerMcpServer < Formula
|
|
4
4
|
desc "MCP server for managing Docker via the Docker SDK for Python"
|
|
5
|
-
homepage "https://github.com/
|
|
5
|
+
homepage "https://github.com/L337-org/docker-mcp"
|
|
6
6
|
version "${VERSION}"
|
|
7
7
|
license "MIT"
|
|
8
8
|
|
|
@@ -17,11 +17,11 @@ class DockerMcpServer < Formula
|
|
|
17
17
|
|
|
18
18
|
on_macos do
|
|
19
19
|
on_arm do
|
|
20
|
-
url "https://github.com/
|
|
20
|
+
url "https://github.com/L337-org/docker-mcp/releases/download/${TAG}/docker-mcp-server-${VERSION}-wheelhouse-macos-arm64.tar.gz"
|
|
21
21
|
sha256 "${SHA_ARM64}"
|
|
22
22
|
end
|
|
23
23
|
on_intel do
|
|
24
|
-
url "https://github.com/
|
|
24
|
+
url "https://github.com/L337-org/docker-mcp/releases/download/${TAG}/docker-mcp-server-${VERSION}-wheelhouse-macos-x86_64.tar.gz"
|
|
25
25
|
sha256 "${SHA_X86_64}"
|
|
26
26
|
end
|
|
27
27
|
end
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
|
|
3
|
-
"name": "io.github.
|
|
3
|
+
"name": "io.github.L337-org/docker-mcp-server",
|
|
4
4
|
"title": "Docker MCP Server",
|
|
5
5
|
"description": "Manage Docker (containers, images, Compose, Swarm, registries) via the Docker SDK and CLI.",
|
|
6
6
|
"repository": {
|
|
7
|
-
"url": "https://github.com/
|
|
7
|
+
"url": "https://github.com/L337-org/docker-mcp",
|
|
8
8
|
"source": "github"
|
|
9
9
|
},
|
|
10
10
|
"version": "1.9.0",
|
|
@@ -17,12 +17,12 @@
|
|
|
17
17
|
},
|
|
18
18
|
{
|
|
19
19
|
"registryType": "oci",
|
|
20
|
-
"identifier": "ghcr.io/
|
|
20
|
+
"identifier": "ghcr.io/l337-org/docker-mcp-server:1.9.0",
|
|
21
21
|
"transport": { "type": "stdio" }
|
|
22
22
|
},
|
|
23
23
|
{
|
|
24
24
|
"registryType": "mcpb",
|
|
25
|
-
"identifier": "https://github.com/
|
|
25
|
+
"identifier": "https://github.com/L337-org/docker-mcp/releases/download/v1.9.0/docker-mcp-server-1.9.0.mcpb",
|
|
26
26
|
"fileSha256": "0000000000000000000000000000000000000000000000000000000000000000",
|
|
27
27
|
"transport": { "type": "stdio" }
|
|
28
28
|
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
# We never init a swarm here (that would mutate the host); the module skips cleanly when the daemon
|
|
3
3
|
# isn't already a manager. run with: uv run pytest -m integration
|
|
4
4
|
|
|
5
|
+
import time
|
|
5
6
|
import uuid
|
|
6
7
|
|
|
7
8
|
import pytest
|
|
@@ -48,5 +49,16 @@ def test_stack_lifecycle(deployed_stack):
|
|
|
48
49
|
# Its single service is present.
|
|
49
50
|
services = stack_services(name)
|
|
50
51
|
assert any(svc.get("Name", "").startswith(name) for svc in services)
|
|
51
|
-
# stack_ps returns a list of tasks
|
|
52
|
-
|
|
52
|
+
# stack_ps returns a list of tasks. `docker stack ps` exits 1 ("nothing found in stack")
|
|
53
|
+
# until the scheduler has created the first task, so poll briefly before asserting.
|
|
54
|
+
deadline = time.monotonic() + 60
|
|
55
|
+
while True:
|
|
56
|
+
try:
|
|
57
|
+
tasks = stack_ps(name)
|
|
58
|
+
break
|
|
59
|
+
except RuntimeError as exc:
|
|
60
|
+
# Only the transient no-tasks-yet case is retryable; anything else is a real failure.
|
|
61
|
+
if "nothing found in stack" not in str(exc) or time.monotonic() > deadline:
|
|
62
|
+
raise
|
|
63
|
+
time.sleep(2)
|
|
64
|
+
assert isinstance(tasks, list)
|
|
@@ -282,7 +282,7 @@ ssh = [
|
|
|
282
282
|
|
|
283
283
|
[[package]]
|
|
284
284
|
name = "docker-mcp-server"
|
|
285
|
-
version = "2.1.
|
|
285
|
+
version = "2.1.2"
|
|
286
286
|
source = { editable = "." }
|
|
287
287
|
dependencies = [
|
|
288
288
|
{ name = "cryptography", marker = "platform_machine == 'x86_64' and sys_platform == 'darwin'" },
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"hooks": {
|
|
3
|
-
"PostToolUse": [
|
|
4
|
-
{
|
|
5
|
-
"matcher": "Edit|Write|MultiEdit",
|
|
6
|
-
"hooks": [
|
|
7
|
-
{
|
|
8
|
-
"type": "command",
|
|
9
|
-
"command": "python3 -c \"import json,sys; d=json.load(sys.stdin); fp=(d.get('tool_input') or {}).get('file_path',''); print(json.dumps({'hookSpecificOutput':{'hookEventName':'PostToolUse','additionalContext':'You edited CLAUDE.md \\u2014 MIRROR RULE: make the equivalent change in .github/copilot-instructions.md (it drives GitHub Copilot review of every PR). Treat the change as incomplete until both files reflect it.'}})) if fp.endswith('CLAUDE.md') else None\""
|
|
10
|
-
}
|
|
11
|
-
]
|
|
12
|
-
}
|
|
13
|
-
]
|
|
14
|
-
}
|
|
15
|
-
}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/.github/ISSUE_TEMPLATE/feature_request.md
RENAMED
|
File without changes
|
{docker_mcp_server-2.1.1 → docker_mcp_server-2.1.2}/.github/actions/file-failure-issue/action.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|