Sign inSign up

extremecanada/sonic-mcp-community-server

By extremecanada

โ€ขUpdated 3 months ago

Image
0

1.9K

extremecanada/sonic-mcp-community-server repository overview

โ SONiC MCP Community Server

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.


โ ๐Ÿ“‚ Before you pull โ€” host directories

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 dirWhat 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.


โ ๐Ÿš€ Quick start

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).


โ ๐Ÿงฑ docker-compose

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.


โ ๐Ÿ”‘ Environment variables

VariableDefaultPurpose
SONIC_DEFAULT_USERNAME / _PASSWORDadmin / YourPaSsWoRdSONiC factory defaults. Override per-host with SONIC_HOST_<IP_with_underscores>_USERNAME / _PASSWORD or in inventory.json.
SONIC_INVENTORY_PATHconfig/inventory.jsonFile-backed inventory. Hot-reloaded on mtime change.
MCP_MUTATIONS_ENABLED1Server-wide kill switch. 0 makes every MUTATION/DESTRUCTIVE tool return 403
SONIC_VERIFY_TLSfalseRESTCONF TLS verify (lab switches use self-signed)
SONIC_RESTCONF_PORT443mgmt-framework HTTPS port
SONIC_SSH_TIMEOUT_SECONDS20paramiko SSH timeout
MCP_LOG_LEVELINFOPython log level
CORS_ORIGINS""Comma-separated allowed origins, or *
SONIC_FABRIC_INTENT_PATHconfig/fabric_intent.jsonOverride path for validate_fabric_vs_intent

โ ๐Ÿ“‚ Volumes

MountPurposeMode
/app/configinventory.json + fabric_intent.json (both hot-reloaded; server can also write them via REST)rw
/app/logsmutations.jsonl โ€” the mutation audit trailrw required
/app/snapshotssave_fabric_snapshot / restore_fabric_snapshot outputrw required

Nothing lab-specific is baked into the image โ€” every credential, intent, and snapshot lives on the host.


โ ๐Ÿ”Œ Endpoints

PathPurpose
GET /toolsFull tool catalog (JSON array, 55 entries)
POST /invokeRun a tool. Body: {tool, inputs, confirm?}
GET /readyProbes every device on RESTCONF + SSH; 503 if nothing reachable
GET /healthLiveness
GET /metricsPrometheus scrape (tool invocation + fabric health gauges)
GET /fabric/intent / PUT /fabric/intentManage intent JSON
GET /inventory ยท PUT /inventoryRead / replace the inventory (passwords redacted on read)
POST /inventory/switches ยท DELETE /inventory/switches/{ip}Add-or-update / remove a single switch
POST /inventory/probeTransient RESTCONF + SSH probe with supplied creds (does not persist)

โ ๐Ÿ›ก๏ธ Safety tiers

Every mutation is triple-gated:

  1. MCP_MUTATIONS_ENABLED=0 โ†’ 403 on every write tool
  2. Per-tool requires_confirmation โ†’ client must send confirm=true
  3. Auto-mode allow-list โ†’ gates agentic callers

Every successful mutation lands in /app/logs/mutations.jsonl with pre/post state. rollback_mutation replays any reversible entry.


โ ๐Ÿงฐ Companion client

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.



โ โš ๏ธ Notes

  • This build has no auth on the REST API. Put it on a trusted network (VPN, Tailscale, Cloudflare Access, reverse-proxy with auth).
  • The container runs as non-root user mcp (uid 1000) with no-new-privileges. Host-side bind-mounts inherit that uid.
  • Tags: :latest, :<major>, :<major>.<minor>, :<full-semver>. Pin to an exact version in production.

Tag summary

Content type

Image

Digest

sha256:a7d8d2cfdโ€ฆ

Size

57.9 MB

Last updated

3 months ago

docker pull extremecanada/sonic-mcp-community-server