Docker

The Zscaler MCP Server publishes an official Docker image to Docker Hub and to the Docker MCP Hub. The image is the recommended deployment artifact for:

  • Local development without polluting the host’s Python environment

  • Any HTTP-transport deployment (Cloud Run, Container Apps, Bedrock AgentCore, Kubernetes)

  • Reproducible CI / test environments

The image

The published image is:

zscaler/zscaler-mcp-server:latest      # most recent release
zscaler/zscaler-mcp-server:0.12.2      # specific release
zscaler/zscaler-mcp-server:master      # bleeding edge

Both amd64 and arm64 architectures are built — pull whichever your host runs.

Stdio transport (local MCP client)

The classic local-development pattern. Your MCP client (Claude Desktop, Cursor, etc.) spawns docker run as the MCP server command:

docker run -i --rm \
  --env-file /absolute/path/to/.env \
  zscaler/zscaler-mcp-server:latest

Equivalent MCP client config:

{
  "mcpServers": {
    "zscaler-mcp-server": {
      "command": "docker",
      "args": [
        "run", "-i", "--rm",
        "--env-file", "/absolute/path/to/.env",
        "zscaler/zscaler-mcp-server:latest"
      ]
    }
  }
}

The -i keeps stdin open so the MCP client can speak over it. --rm cleans up the container when the client disconnects.

Streamable-HTTP transport (remote agent)

For a long-running server that any number of MCP clients can connect to:

docker run -d --restart=unless-stopped \
  --name zscaler-mcp-server \
  -p 8000:8000 \
  --env-file /path/to/.env \
  zscaler/zscaler-mcp-server:latest \
  --transport streamable-http --host 0.0.0.0 --port 8000

The server listens on http://localhost:8000/mcp. From here, layer in authentication (MCP Client Authentication) and TLS (TLS and Hardening) for any deployment that isn’t localhost-only.

Making .env editable inside the container

docker run --env-file=./.env reads the host file once at docker run time and copies the values into the container’s Config.Env metadata. The host file is no longer linked to the running container — you could delete it and the container still holds the values.

For deployments where you want to update credentials without recreating the container, bind-mount the file:

docker run -d --restart=unless-stopped \
  --name zscaler-mcp-server \
  -p 8000:8000 \
  --env-file /path/to/.env \                # boot-time injection
  -v /path/to/.env:/app/.env:ro \           # live re-read on restart
  -e ZSCALER_MCP_DOTENV_PATH=/app/.env \
  zscaler/zscaler-mcp-server:latest \
  --transport streamable-http --host 0.0.0.0 --port 8000

To pick up host-side edits:

$EDITOR /path/to/.env
docker exec zscaler-mcp-server zscaler-mcp restart

See Process Lifecycle Management for the full lifecycle model.

The docker cp workflow

For a container already running without a bind mount, drop a .env in via docker cp:

docker cp ./.env zscaler-mcp-server:/app/.env
docker exec zscaler-mcp-server zscaler-mcp restart

The lifecycle subsystem detects the freshly-placed file (env-source classification: fresh-discovery) and the restart picks up the new credentials.

Generating an auth token from the image

For api-key mode deployments, the image can generate a fresh API key without you needing the package installed locally:

docker run --rm \
  --env-file /path/to/.env \
  zscaler/zscaler-mcp-server:latest \
  --generate-auth-token

Or via the Makefile shortcut on a clone of the repo:

make docker-generate-auth-token

Listing available tools

The image responds to --list-tools like any other invocation:

docker run --rm \
  --env-file /path/to/.env \
  zscaler/zscaler-mcp-server:latest \
  --list-tools

Useful for auditing what an image version exposes before connecting an agent.

Toolset selection

Toolset selection works exactly like the CLI — pass --toolsets or set ZSCALER_MCP_TOOLSETS in the env file:

docker run -i --rm \
  --env-file /path/to/.env \
  zscaler/zscaler-mcp-server:latest \
  --toolsets zia_url_filtering,zpa_app_segments

See Toolsets for the full toolset catalog.

Health and readiness

The HTTP transport exposes a health endpoint at GET /healthz (returns 200 OK if the server is up). Use it for Kubernetes livenessProbe / readinessProbe and for Cloud Run minimum-instance keep-alive.

Image hardening

The published image:

  • Runs as a non-root user

  • Includes only the Python runtime + the zscaler-mcp distribution

  • Does not bundle build tools, package managers, or shells beyond sh

  • Embeds the registry ownership label (io.modelcontextprotocol.server.name) for downstream registry checks

See also