Docker
The Docker image is the recommended install for homelab and multi-client setups. The server runs as a long-running process and answers MCP calls over Streamable HTTP on port 3714. One container can serve Claude Desktop, Claude Code, Cursor, and Cline simultaneously.
Quickstart (stub mode)
Section titled “Quickstart (stub mode)”The HTTP transport is secure by default: it refuses to start without a bearer token. Mint one, pass it to the container, and use it on every MCP request. See the Authentication guide for the full model.
export MCP_UNIFI_TOKEN=$(openssl rand -hex 32)docker run --rm -p 3714:3714 \ -e STUB_MODE=true \ -e MCP_UNIFI_AUTH_TOKENS="$MCP_UNIFI_TOKEN" \ ghcr.io/pete-builds/mcp-unifi:latestThe server boots into stub mode, returns realistic mock data, and needs no UniFi hardware. Register it with any MCP client using Authorization: Bearer $MCP_UNIFI_TOKEN and start calling tools.
For throwaway local testing on loopback only, -e MCP_UNIFI_AUTH_REQUIRED=false skips auth entirely. Never use it on an interface reachable by anything else — every connected client gets admin-equivalent access to the controller.
docker-compose
Section titled “docker-compose”A working compose file lives in the repo at docker-compose.example.yml:
x-logging: &default-logging driver: json-file options: max-size: "10m" max-file: "3"
services: mcp-unifi: build: . image: mcp-unifi:dev container_name: mcp-unifi restart: unless-stopped read_only: true tmpfs: - /tmp:size=16M ports: - "${MCP_PORT:-3714}:${MCP_PORT:-3714}" env_file: - .env environment: MCP_HOST: "0.0.0.0" MCP_PORT: "${MCP_PORT:-3714}" TZ: "${TZ:-UTC}" LOG_FORMAT: "text" logging: *default-logging healthcheck: test: ["CMD", "python", "-m", "mcp_unifi.healthcheck"] interval: 30s timeout: 10s retries: 3 start_period: 10s security_opt: - no-new-privileges:trueThe example builds from local source. For the published image, change build: . to image: ghcr.io/pete-builds/mcp-unifi:latest and drop the build key.
The container runs as UID 1000, no shell, with a read-only root filesystem (/tmp is tmpfs) and no-new-privileges.
To also make the server unable to change anything on the controller, add MCP_UNIFI_READONLY=true to your .env. Mutating tools are then hidden from tools/list and refused on tools/call; reads are unaffected. Pair it with a read-only UniFi API key rather than treating either as sufficient alone — see the Security guide.
Verify
Section titled “Verify”Send a tools/list request to confirm the server is alive and the right modules are loaded. Include the bearer token you minted above:
curl -sS -X POST http://localhost:3714/mcp \ -H "Authorization: Bearer $MCP_UNIFI_TOKEN" \ -H 'Content-Type: application/json' \ -H 'Accept: application/json, text/event-stream' \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'You should see the Network tools listed. Enabling MCP_UNIFI_MODULES_ENABLED=network,protect adds Protect; network,protect,access adds Access on top. The always-current per-module count is in the Tool Manifest.
Switch to real mode
Section titled “Switch to real mode”When you have a gateway and an API key, drop stub mode and add the gateway env vars. Keep the auth token — it’s required for the HTTP transport regardless of stub/real mode:
docker run --rm -p 3714:3714 \ -e STUB_MODE=false \ -e UNIFI_HOST=192.168.1.1 \ -e UNIFI_API_KEY=<your-local-api-key> \ -e MCP_UNIFI_AUTH_TOKENS="$MCP_UNIFI_TOKEN" \ ghcr.io/pete-builds/mcp-unifi:latestGet the API key from Settings → Control Plane → Integrations → Create API Key in the gateway UI.
For multi-site setups (more than one controller), use the MCP_UNIFI_CONTROLLERS_FILE env var instead. See the Multi-Site Setup guide.
Enable Protect and Access
Section titled “Enable Protect and Access”Protect and Access are opt-in modules. Add them to MCP_UNIFI_MODULES_ENABLED:
docker run --rm -p 3714:3714 \ -e STUB_MODE=false \ -e UNIFI_HOST=192.168.1.1 \ -e UNIFI_API_KEY=<your-local-api-key> \ -e MCP_UNIFI_MODULES_ENABLED=network,protect,access \ -e UNIFI_ACCESS_HOST=192.168.1.1 \ -e UNIFI_ACCESS_API_KEY=<your-access-api-key> \ -e MCP_UNIFI_AUTH_TOKENS="$MCP_UNIFI_TOKEN" \ ghcr.io/pete-builds/mcp-unifi:latestAccess uses a separate API key generated on the Access controller’s developer settings. See the Protect Tools reference and the Access setup guide for the full surface.
Verify the image signature
Section titled “Verify the image signature”Published images are signed with cosign keyless OIDC. See the Security Model guide for the verification command and SBOM download.