A Model Context Protocol (MCP) server for SONiC switches. Exposes 55 tools โ reads, mutations, fabric-level diagnostics, and LLDP-based inventory discovery โ that any AI agent or plain HTTP client can use to inspect and safely change a SONiC fabric.
Pair with extremecanada/sonic-mcp-community-clientโ for the web UI.
The image runs as non-root user mcp (uid 1000). If a bind-mount
source doesn't exist when the container starts, Docker creates it as
root and the container user can't write to it. Symptoms: adding a
switch via the UI returns 500, mutations.jsonl never appears, snapshot
saves fail silently. Pre-create the dirs yourself so they land with
sensible ownership:
mkdir -p config logs snapshots
# Most dev machines already have uid 1000 as the first user โ check:
id -u # if this prints 1000, you're done
# If your uid is different, align ownership with the container user:
sudo chown -R 1000:1000 config logs snapshots
| Host dir | What lives there |
|---|---|
./config/ | inventory.json + fabric_intent.json (live-editable) |
./logs/ | mutations.jsonl โ append-only mutation ledger |
./snapshots/ | save_fabric_snapshot / restore_fabric_snapshot output |
./config/ holds the operator's lab definition โ back this up.
./logs/mutations.jsonl is the audit trail โ keep it on durable storage.
docker pull extremecanada/sonic-mcp-community-server:latest
docker run -d --name sonic-mcp \
-p 8000:8000 \
-e SONIC_DEFAULT_USERNAME=admin \
-e SONIC_DEFAULT_PASSWORD=YourPaSsWoRd \
-e MCP_MUTATIONS_ENABLED=1 \
-v $(pwd)/config:/app/config \
-v $(pwd)/logs:/app/logs \
-v $(pwd)/snapshots:/app/snapshots \
extremecanada/sonic-mcp-community-server:latest
curl http://localhost:8000/tools | jq 'length' # โ 55
That's it. Point it at any SONiC switch reachable from the container
over RESTCONF (:443) and SSH (:22).
services:
mcp:
image: extremecanada/sonic-mcp-community-server:latest
container_name: sonic-mcp
restart: unless-stopped
ports: ["8000:8000"]
env_file: .env
volumes:
- ./config:/app/config # inventory.json + fabric_intent.json (hot-reloaded)
- ./logs:/app/logs # mutation ledger (JSONL)
- ./snapshots:/app/snapshots # saved config_db.json dumps
environment:
- SONIC_INVENTORY_PATH=/app/config/inventory.json
- SONIC_FABRIC_INTENT_PATH=/app/config/fabric_intent.json
Create .env alongside:
SONIC_DEFAULT_USERNAME=admin
SONIC_DEFAULT_PASSWORD=YourPaSsWoRd
MCP_MUTATIONS_ENABLED=1
SONIC_VERIFY_TLS=false
Then: docker compose up -d.
| Variable | Default | Purpose |
|---|---|---|
SONIC_DEFAULT_USERNAME / _PASSWORD | admin / YourPaSsWoRd | SONiC factory defaults. Override per-host with SONIC_HOST_<IP_with_underscores>_USERNAME / _PASSWORD or in inventory.json. |
SONIC_INVENTORY_PATH | config/inventory.json | File-backed inventory. Hot-reloaded on mtime change. |
MCP_MUTATIONS_ENABLED | 1 | Server-wide kill switch. 0 makes every MUTATION/DESTRUCTIVE tool return 403 |
SONIC_VERIFY_TLS | false | RESTCONF TLS verify (lab switches use self-signed) |
SONIC_RESTCONF_PORT | 443 | mgmt-framework HTTPS port |
SONIC_SSH_TIMEOUT_SECONDS | 20 | paramiko SSH timeout |
MCP_LOG_LEVEL | INFO | Python log level |
CORS_ORIGINS | "" | Comma-separated allowed origins, or * |
SONIC_FABRIC_INTENT_PATH | config/fabric_intent.json | Override path for validate_fabric_vs_intent |
| Mount | Purpose | Mode |
|---|---|---|
/app/config | inventory.json + fabric_intent.json (both hot-reloaded; server can also write them via REST) | rw |
/app/logs | mutations.jsonl โ the mutation audit trail | rw required |
/app/snapshots | save_fabric_snapshot / restore_fabric_snapshot output | rw required |
Nothing lab-specific is baked into the image โ every credential, intent, and snapshot lives on the host.
| Path | Purpose |
|---|---|
GET /tools | Full tool catalog (JSON array, 55 entries) |
POST /invoke | Run a tool. Body: {tool, inputs, confirm?} |
GET /ready | Probes every device on RESTCONF + SSH; 503 if nothing reachable |
GET /health | Liveness |
GET /metrics | Prometheus scrape (tool invocation + fabric health gauges) |
GET /fabric/intent / PUT /fabric/intent | Manage intent JSON |
GET /inventory ยท PUT /inventory | Read / replace the inventory (passwords redacted on read) |
POST /inventory/switches ยท DELETE /inventory/switches/{ip} | Add-or-update / remove a single switch |
POST /inventory/probe | Transient RESTCONF + SSH probe with supplied creds (does not persist) |
Every mutation is triple-gated:
MCP_MUTATIONS_ENABLED=0 โ 403 on every write toolrequires_confirmation โ client must send confirm=trueEvery successful mutation lands in /app/logs/mutations.jsonl with
pre/post state. rollback_mutation replays any reversible entry.
The web UI with fabric graph, AI console, mutation-confirm modal, command palette, intent editor, and row actions is a separate image:
docker pull extremecanada/sonic-mcp-community-client:latest
See extremecanada/sonic-mcp-community-clientโ
for its own quickstart.
extremecanada/sonic-mcp-community-clientโ mcp (uid 1000) with
no-new-privileges. Host-side bind-mounts inherit that uid.:latest, :<major>, :<major>.<minor>, :<full-semver>.
Pin to an exact version in production.Content type
Image
Digest
sha256:a7d8d2cfdโฆ
Size
57.9 MB
Last updated
3 months ago
docker pull extremecanada/sonic-mcp-community-server