Skip to content

Docker

The image is ghcr.io/jmrplens/arcane-mcp, published by the release workflow for every version, and also docker.io/jmrplens/arcane-mcp with the same digest once the Docker Hub repository is set up. It is the static binary on gcr.io/distroless/static-debian12:nonroot: no shell, no package manager, running as the non-root user 65532. Nothing is published until the first release; see Installation.

Docker, or any runtime that runs OCI images (Podman, containerd), on a linux/amd64 or linux/arm64 host or VM (Docker Desktop on macOS and Windows included).

TagMeaning
X.Y.ZOne release; never moves
X.YMoves with a release of that minor line only when it is the newest release overall
latestThe newest release; a backport (a release older than the newest) moves neither X.Y nor latest

Each tag is a multi-platform index for linux/amd64 and linux/arm64; Docker pulls the one for your machine.

Terminal window
docker pull ghcr.io/jmrplens/arcane-mcp:X.Y.Z
docker run --rm ghcr.io/jmrplens/arcane-mcp:X.Y.Z --version

Until the first release, build the image from a clone of the repository: docker build -t arcane-mcp ., and use arcane-mcp as the image name below.

The client starts the container for each session and talks to it over standard input and output:

{
"mcpServers": {
"arcane": {
"command": "docker",
"args": ["run", "-i", "--rm", "-e", "ARCANE_URL", "-e", "ARCANE_API_KEY", "ghcr.io/jmrplens/arcane-mcp:X.Y.Z"],
"env": {
"ARCANE_URL": "https://arcane.example.com",
"ARCANE_API_KEY": "<your Arcane API key>"
}
}
}
}
  • Keep -i (the protocol travels over standard input) and never add -t or -d.
  • -e NAME without a value forwards that variable from the environment the client starts docker with, so the values stay in env and out of the arguments. Every other setting (ARCANE_MCP_TOOL_SURFACE, ARCANE_MCP_READ_ONLY…) needs its own -e NAME and a value in env.
  • ARCANE_URL must be reachable from inside the container: localhost there is the container itself. Use the host’s name, host.docker.internal (Docker Desktop) or --network host (Linux).
  • The container does not see a .env file in your working directory.

Every client’s Docker entry is on Client setup.

With ARCANE_MCP_HTTP_ADDR set, the container serves Streamable HTTP on /mcp instead of stdio, for several clients at once:

Terminal window
export ARCANE_MCP_HTTP_TOKEN=$(openssl rand -hex 32)
docker run -d --name arcane-mcp -p 127.0.0.1:8080:8080 \
-e ARCANE_URL=https://arcane.example.com \
-e ARCANE_MCP_HTTP_ADDR=:8080 \
-e ARCANE_MCP_HTTP_ALLOW_PLAINTEXT=true \
-e ARCANE_MCP_HTTP_TOKEN \
ghcr.io/jmrplens/arcane-mcp:X.Y.Z

ARCANE_MCP_HTTP_ALLOW_PLAINTEXT=true says that plain HTTP on the container’s :8080 is intended: inside the container the server binds every interface, but the port is published on the host’s loopback only. Without it the server logs a warning at startup; see Plain HTTP and the hardened mode.

Compose files next to Arcane, reverse proxies, TLS and unix sockets are on HTTP deployment.

The image has a HEALTHCHECK that runs arcane-mcp --probe every 30 seconds: an HTTP container turns healthy once /healthz answers, and a stdio container counts as healthy while it runs (it has no listener to ask). Nothing needs configuring; see Listener, probes and shutdown.

Use an X.Y.Z tag in anything you depend on, or pin the digest the release publishes: ghcr.io/jmrplens/arcane-mcp:X.Y.Z@sha256:<digest> (the MCP Registry entry pins the image that way). latest moves with every release.

The index and both platform images are signed keyless with cosign and carry SLSA provenance and SPDX SBOM attestations. The commands are under Verifying a release.

Pull the newer tag and change it in the client’s entry (with --rm, each session starts a fresh container); for an HTTP service, recreate the container with the new tag. To remove the image: docker image rm ghcr.io/jmrplens/arcane-mcp:X.Y.Z.