Arcane MCP
AI-powered Docker management server that enables natural language control of environments, containers, images, networks, volumes, and more through a unified Arcane API interface.
README
Arcane MCP
TypeScript MCP server for the Arcane Docker management API. Exposes a single arcane tool that routes all Docker environment, project, container, image, network, volume, system, registry, image-update, vulnerability, and GitOps operations through the Arcane service.
Overview
Arcane MCP wraps the Arcane REST API behind a Model Context Protocol interface. An AI agent calls the arcane tool with an action and subaction. The server authenticates the request, enforces a confirmation gate on destructive operations, routes to the appropriate backend service, and returns JSON.
The server ships two MCP tools:
| Tool | Purpose |
|---|---|
arcane |
Unified action/subaction router for all Arcane API operations |
arcane_help |
Returns the full action/subaction reference as formatted text |
Tools
arcane
Call this tool with action, subaction, and optional envId, id, and params.
{
"action": "container",
"subaction": "list",
"envId": "env-abc123"
}
Parameter rules
| Parameter | Type | Description |
|---|---|---|
action |
string (enum) | Resource family: environment, project, container, image, network, volume, system, image-update, vulnerability, registry, gitops |
subaction |
string (enum) | Operation to perform (see per-family tables below) |
envId |
string (optional) | Target environment ID. Required by all families except registry. For environment subactions, envId and id are interchangeable for single-resource ops. |
id |
string (optional) | Resource ID for single-resource operations (get, delete, etc.) |
params |
object (optional) | Operation-specific payload. Pass { "confirm": true } to authorize a destructive operation without elicitation. |
Destructive operation gate
Any operation in the DESTRUCTIVE set (listed per family below) is blocked unless one of three conditions is met:
ARCANE_MCP_ALLOW_DESTRUCTIVE=true— all destructive ops auto-confirm, no re-call needed.ARCANE_MCP_ALLOW_YOLO=true— skips the interactive elicitation prompt; the tool must still be re-called withparams: { "confirm": true }to proceed.- Default — if the MCP client supports elicitation forms, the server prompts the user interactively. If the client does not support elicitation, the server returns a prompt asking for a re-call with
params: { "confirm": true }.
Action families
environment
Top-level Docker host connections. envId and id are interchangeable for single-resource operations.
| Subaction | Description | Destructive |
|---|---|---|
list |
List all environments | |
get |
Get an environment by ID | |
create |
Create a new environment; pass params with apiUrl, apiKey, and optional name, enabled, isEdge |
|
update |
Update environment settings; pass params with fields to change |
|
delete |
Permanently delete an environment | yes |
test |
Test the environment's API connection |
Example:
{"action": "environment", "subaction": "list"}
{"action": "environment", "subaction": "get", "id": "env-abc123"}
{"action": "environment", "subaction": "create", "params": {"apiUrl": "https://host.example.com", "apiKey": "..."}}
{"action": "environment", "subaction": "delete", "id": "env-abc123", "params": {"confirm": true}}
project
Docker Compose stacks running inside an environment. Requires envId.
| Subaction | Description | Destructive |
|---|---|---|
list |
List all projects in the environment | |
get |
Get a project by ID | |
create |
Create a project; pass params with name, composeContent, and optional envContent |
|
update |
Update a project; pass params with composeContent, envContent, or name |
|
up |
Start a project (docker compose up) | |
down |
Stop a project (docker compose down) | yes |
restart |
Restart all containers in the project | yes |
pull |
Pull latest images without restarting | |
destroy |
Stop and remove containers, networks, volumes created by the compose file | yes |
redeploy |
Pull images and recreate the project | yes |
build |
Build images for the project; pass optional params with services, provider, push, load |
Example:
{"action": "project", "subaction": "list", "envId": "env-abc123"}
{"action": "project", "subaction": "up", "envId": "env-abc123", "id": "my-stack"}
{"action": "project", "subaction": "down", "envId": "env-abc123", "id": "my-stack", "params": {"confirm": true}}
{"action": "project", "subaction": "build", "envId": "env-abc123", "id": "my-stack", "params": {"services": ["web"], "push": true}}
container
Individual Docker containers inside an environment. Requires envId.
Note: container logs are not available via the Arcane REST API. Use the Arcane web UI or docker logs directly.
| Subaction | Description | Destructive |
|---|---|---|
list |
List all containers | |
get |
Get a container by ID | |
create |
Create a container; pass params with name, image, and optional cmd, env, ports, volumes, restartPolicy, labels, memory, cpus, privileged |
|
start |
Start a stopped container | |
stop |
Stop a running container | yes |
restart |
Restart a container | yes |
update |
Re-pull the container's image and recreate it using its existing config. No params accepted. | |
delete |
Remove a container | yes |
stats |
Get CPU, memory, and network stats for all containers in the environment |
Example:
{"action": "container", "subaction": "list", "envId": "env-abc123"}
{"action": "container", "subaction": "stats", "envId": "env-abc123"}
{"action": "container", "subaction": "stop", "envId": "env-abc123", "id": "container-id", "params": {"confirm": true}}
{"action": "container", "subaction": "create", "envId": "env-abc123", "params": {"name": "nginx", "image": "nginx:latest", "ports": {"80/tcp": [{"HostPort": "8080"}]}}}
image
Docker images available in an environment. Requires envId.
| Subaction | Description | Destructive |
|---|---|---|
list |
List all images | |
get |
Get an image by ID | |
pull |
Pull an image; pass params with imageName and optional tag |
|
delete |
Delete an image by ID | yes |
prune |
Remove all unused images | yes |
scan |
Scan an image for vulnerabilities (triggers Trivy scan) |
Example:
{"action": "image", "subaction": "list", "envId": "env-abc123"}
{"action": "image", "subaction": "pull", "envId": "env-abc123", "params": {"imageName": "nginx", "tag": "latest"}}
{"action": "image", "subaction": "scan", "envId": "env-abc123", "id": "sha256:abc..."}
{"action": "image", "subaction": "prune", "envId": "env-abc123", "params": {"confirm": true}}
network
Docker networks in an environment. Requires envId.
| Subaction | Description | Destructive |
|---|---|---|
list |
List all networks | |
get |
Get a network by ID | |
create |
Create a network; pass params with name and options (driver, internal, enableIPv6, labels) |
|
delete |
Delete a network by ID | yes |
prune |
Remove all unused networks | yes |
Example:
{"action": "network", "subaction": "list", "envId": "env-abc123"}
{"action": "network", "subaction": "create", "envId": "env-abc123", "params": {"name": "my-net", "options": {"driver": "bridge"}}}
{"action": "network", "subaction": "prune", "envId": "env-abc123", "params": {"confirm": true}}
volume
Docker volumes in an environment, with full backup and restore support. Requires envId.
| Subaction | Description | Destructive |
|---|---|---|
list |
List all volumes | |
get |
Get a volume by name | |
create |
Create a volume; pass params with name and optional driver, driverOpts, labels |
|
delete |
Delete a volume by name | yes |
prune |
Remove all unused volumes | yes |
browse |
Browse a volume's directory tree; pass optional params.path (relative, no .. allowed) |
|
list-backups |
List all backups for a volume; requires id (volume name) |
|
create-backup |
Create a new backup snapshot; requires id (volume name) |
|
delete-backup |
Delete a backup by ID; pass params.backupId |
yes |
restore |
Restore a volume to a backup state; requires id (volume name) and params.backupId |
yes |
restore-files |
Restore specific files from a backup; requires id, params.backupId, and params.paths (string array) |
yes |
Volume backup/restore workflow
- List available backups:
subaction=list-backups,id=<volumeName> - Create a new snapshot:
subaction=create-backup,id=<volumeName> - Inspect a backup's contents: use
list-backupsto get the backup ID, thenrestore-fileswithparams.paths - Full restore:
subaction=restore,id=<volumeName>,params: { backupId: "...", confirm: true } - Partial restore:
subaction=restore-files,id=<volumeName>,params: { backupId: "...", paths: ["data/config.json"], confirm: true } - Remove old snapshot:
subaction=delete-backup,params: { backupId: "...", confirm: true }
Example:
{"action": "volume", "subaction": "list-backups", "envId": "env-abc123", "id": "my-data-vol"}
{"action": "volume", "subaction": "create-backup", "envId": "env-abc123", "id": "my-data-vol"}
{"action": "volume", "subaction": "restore", "envId": "env-abc123", "id": "my-data-vol", "params": {"backupId": "bkp-xyz", "confirm": true}}
{"action": "volume", "subaction": "restore-files", "envId": "env-abc123", "id": "my-data-vol", "params": {"backupId": "bkp-xyz", "paths": ["etc/app.conf"], "confirm": true}}
{"action": "volume", "subaction": "browse", "envId": "env-abc123", "id": "my-data-vol", "params": {"path": "etc"}}
system
Docker daemon-level operations for an environment. Requires envId.
| Subaction | Description | Destructive |
|---|---|---|
docker-info |
Get Docker daemon info (version, runtime, resources) | |
start-all |
Start all projects in the environment | |
stop-all |
Stop all projects in the environment | yes |
prune |
Prune unused Docker resources; pass params with boolean flags: containers, images, networks, volumes, buildCache, dangling |
yes |
convert |
Convert a docker run command to Docker Compose YAML; pass params.dockerRunCommand |
Example:
{"action": "system", "subaction": "docker-info", "envId": "env-abc123"}
{"action": "system", "subaction": "prune", "envId": "env-abc123", "params": {"containers": true, "images": true, "networks": true, "volumes": false, "buildCache": true, "dangling": true, "confirm": true}}
{"action": "system", "subaction": "convert", "envId": "env-abc123", "params": {"dockerRunCommand": "docker run -d -p 80:80 nginx"}}
image-update
Check whether images have newer versions available. Requires envId. Long-running checks use a 120-second timeout.
| Subaction | Description |
|---|---|
check-all |
Check all images in the environment for updates; pass optional params.credentials for private registries |
check |
Check a single image; pass either id (Arcane image ID) or params.imageRef (e.g. nginx:latest) |
check-batch |
Check multiple images; pass params.imageRefs (string array) and optional params.credentials |
summary |
Get a summary count: total images, images with updates, digest-only updates, errors |
The check subaction resolves the target in this order: id (Arcane internal imageId) → params.imageRef (image reference string). Passing both is undefined behavior; use one or the other.
Example:
{"action": "image-update", "subaction": "summary", "envId": "env-abc123"}
{"action": "image-update", "subaction": "check", "envId": "env-abc123", "params": {"imageRef": "nginx:latest"}}
{"action": "image-update", "subaction": "check", "envId": "env-abc123", "id": "img-abc123"}
{"action": "image-update", "subaction": "check-batch", "envId": "env-abc123", "params": {"imageRefs": ["nginx:latest", "redis:7"]}}
{"action": "image-update", "subaction": "check-all", "envId": "env-abc123"}
vulnerability
Image vulnerability scanning powered by Trivy. Requires envId.
| Subaction | Description |
|---|---|
summary |
Get counts by severity (critical, high, medium, low, unknown) across all scanned images |
list |
List all vulnerability entries with full CVE detail |
scanner-status |
Get the Trivy scanner's current operational status |
ignore |
Add a vulnerability to the ignore list; pass params with imageId, vulnerabilityId, pkgName, and optional installedVersion, reason |
unignore |
Remove an ignore entry; pass id (ignoreId) |
list-ignored |
List all active ignore entries |
Example:
{"action": "vulnerability", "subaction": "summary", "envId": "env-abc123"}
{"action": "vulnerability", "subaction": "list", "envId": "env-abc123"}
{"action": "vulnerability", "subaction": "ignore", "envId": "env-abc123", "params": {"imageId": "img-abc", "vulnerabilityId": "CVE-2024-1234", "pkgName": "openssl", "reason": "mitigated"}}
{"action": "vulnerability", "subaction": "unignore", "envId": "env-abc123", "id": "ignore-entry-id"}
registry
Container registry credentials. Global resource — envId is not required and is ignored.
| Subaction | Description | Destructive |
|---|---|---|
list |
List all configured registries | |
get |
Get a registry by ID | |
create |
Add a registry; pass params with url, username, token, and optional description, enabled, insecure |
|
update |
Update a registry; pass id and params with fields to change (url, username, token, description, enabled, insecure) |
|
delete |
Remove a registry | yes |
test |
Test connectivity to the registry |
Example:
{"action": "registry", "subaction": "list"}
{"action": "registry", "subaction": "create", "params": {"url": "registry.example.com", "username": "myuser", "token": "...", "enabled": true}}
{"action": "registry", "subaction": "test", "id": "reg-abc123"}
{"action": "registry", "subaction": "delete", "id": "reg-abc123", "params": {"confirm": true}}
gitops
Git-backed Compose deployment syncs. Requires envId.
Warning: gitops:sync pulls from a remote repository and applies changes. This is a supply chain risk if the repository is compromised. Always confirm the sync target before proceeding.
| Subaction | Description | Destructive |
|---|---|---|
list |
List all GitOps sync configurations | |
get |
Get a sync configuration by ID | |
create |
Create a sync config; pass params with name, repositoryId, branch, composePath, and optional autoSync, syncInterval, projectName |
|
update |
Update a sync config; pass id and params with fields to change |
|
delete |
Delete a sync configuration | yes |
sync |
Trigger an immediate sync from the remote repository | yes |
status |
Get the sync's last run status, commit, and next scheduled run | |
browse |
Browse the repository's file tree; pass optional params.path |
GitOps workflow
- List existing syncs:
subaction=list - Check a sync's state:
subaction=status,id=<syncId> - Inspect repository contents:
subaction=browse,id=<syncId> - Trigger a sync:
subaction=sync,id=<syncId>,params: { confirm: true }
Example:
{"action": "gitops", "subaction": "list", "envId": "env-abc123"}
{"action": "gitops", "subaction": "status", "envId": "env-abc123", "id": "sync-abc123"}
{"action": "gitops", "subaction": "browse", "envId": "env-abc123", "id": "sync-abc123"}
{"action": "gitops", "subaction": "sync", "envId": "env-abc123", "id": "sync-abc123", "params": {"confirm": true}}
{"action": "gitops", "subaction": "create", "envId": "env-abc123", "params": {"name": "prod-stack", "repositoryId": "repo-abc", "branch": "main", "composePath": "stacks/web/docker-compose.yml", "autoSync": true, "syncInterval": 300}}
Destructive operations reference
The following 22 operations require confirmation before execution:
| Action | Subaction |
|---|---|
environment |
delete |
project |
down, restart, destroy, redeploy |
container |
stop, restart, delete |
image |
delete, prune |
network |
delete, prune |
volume |
delete, prune, delete-backup, restore, restore-files |
system |
prune, stop-all |
registry |
delete |
gitops |
delete, sync |
Installation
Plugin marketplace
/plugin marketplace add jmagar/claude-homelab
/plugin install arcane-mcp @jmagar-claude-homelab
Local development
npm install
npm run build
npm start
For watch mode:
just dev
Docker
just up
just logs
Configuration
Copy .env.example to .env and fill in the required values:
cp .env.example .env
chmod 600 .env
Environment variables
| Variable | Required | Default | Description |
|---|---|---|---|
ARCANE_API_URL |
yes | — | Base URL of your Arcane instance, e.g. https://arcane.example.com |
ARCANE_API_KEY |
yes | — | API key from Arcane Settings > API |
ARCANE_MCP_TOKEN |
yes | — | Bearer token for MCP server auth. Generate with: openssl rand -hex 32 |
ARCANE_MCP_BIND_PORT |
no | 3000 |
Internal container port the server binds to |
ARCANE_MCP_PORT |
no | 44332 |
Host-side Docker port mapping |
ARCANE_MCP_TRANSPORT |
no | http |
Transport mode: http or stdio |
ARCANE_MCP_AUTH_ENABLED |
no | true |
Set to false to disable Bearer auth (use only behind a trusted proxy) |
ARCANE_MCP_ALLOW_YOLO |
no | false |
true skips elicitation prompts; re-call with params: { confirm: true } is still required |
ARCANE_MCP_ALLOW_DESTRUCTIVE |
no | false |
true auto-confirms all destructive operations. Use only in fully trusted automated environments. |
LOG_LEVEL |
no | info |
Pino log level: trace, debug, info, warn, error |
Safety flag behavior
ARCANE_MCP_ALLOW_YOLO and ARCANE_MCP_ALLOW_DESTRUCTIVE control the confirmation gate independently:
- Both
false(default): destructive ops show an elicitation dialog (if the MCP client supports it) or return a prompt to re-call withparams: { confirm: true }. ALLOW_YOLO=true: skips the elicitation dialog. The agent must still re-call withparams: { confirm: true }.ALLOW_DESTRUCTIVE=true: bypasses the gate entirely. No re-call needed. Use in CI or fully automated pipelines only.
Authentication
All MCP endpoints require a Bearer token unless ARCANE_MCP_AUTH_ENABLED=false.
The following paths bypass authentication:
GET /health— health check, always unauthenticated/.well-known/*— RFC 9728 OAuth discovery endpoint; reserved for future OAuth resource metadata
All other paths, including /mcp, require Authorization: Bearer <ARCANE_MCP_TOKEN>.
Token comparison uses timingSafeEqual to prevent timing attacks.
Session management
The HTTP transport maintains per-session MCP server instances (up to 200 concurrent sessions). Sessions idle for more than 30 minutes are evicted. When the session cap is reached, the least-recently-used idle session is evicted first.
Clients that do not send an initialize request are bootstrapped into a pre-initialized session. These clients cannot use elicitation (the confirmation dialog) — they will always receive the "re-call with params: { confirm: true }" response for destructive operations.
Development commands
just dev # Start with watch-mode TypeScript compilation
just build # Compile TypeScript to dist/
just typecheck # Type-check without emitting
just lint # Run Biome linter
just fmt # Run Biome formatter
just test # Run unit tests with Vitest
just up # Start Docker Compose service
just down # Stop Docker Compose service
just logs # Tail container logs
just health # Check /health endpoint
just setup # Create .env from .env.example
just gen-token # Generate a random Bearer token
just clean # Remove dist/, .cache/, coverage/
Verification
After starting the server:
just typecheck
just lint
just test
just health
The health endpoint returns:
{"status": "ok", "service": "arcane-mcp"}
Related plugins
| Plugin | Category | Description |
|---|---|---|
| homelab-core | core | Core agents, commands, skills, and setup/health workflows for homelab management. |
| overseerr-mcp | media | Search movies and TV shows, submit requests, and monitor failed requests via Overseerr. |
| unraid-mcp | infrastructure | Query, monitor, and manage Unraid servers: Docker, VMs, array, parity, and live telemetry. |
| unifi-mcp | infrastructure | Monitor and manage UniFi devices, clients, firewall rules, and network health. |
| gotify-mcp | utilities | Send and manage push notifications via a self-hosted Gotify server. |
| swag-mcp | infrastructure | Create, edit, and manage SWAG nginx reverse proxy configurations. |
| synapse-mcp | infrastructure | Docker management (Flux) and SSH remote operations (Scout) across homelab hosts. |
| syslog-mcp | infrastructure | Receive, index, and search syslog streams from all homelab hosts via SQLite FTS5. |
| plugin-lab | dev-tools | Scaffold, review, align, and deploy homelab MCP plugins with agents and canonical templates. |
License
MIT
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.