SONiC MCP Server
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@SONiC MCP Servershow me the interface status on leaf-01"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
SONiC MCP Server — gNMI variant / pyGNMI
An MCP server that exposes a SONiC switch's gNMI interface as tools, so any MCP-capable LLM can read switch state and change configuration. It speaks gNMI natively in Python via pyGNMI — no external binary required — and serves MCP over Streamable HTTP, packaged as a portable Docker container you can run on any Docker host.
┌─────────────┐ Streamable HTTP ┌──────────────────────┐ gNMI/gRPC ┌──────────────┐
│ LLM client │ ─────────────────► │ sonic-mcp container │ ────────────► │ SONiC switch │
│ (Claude, │ POST /mcp │ FastMCP + pyGNMI │ :8080 │ gnmi/telemetry│
│ IDE, etc.) │ ◄───────────────── │ │ ◄──────────── │ container │
└─────────────┘ └──────────┬───────────┘ └──────────────┘
devices.yaml (bind-mounted)Security posture is lab-grade by default. gNMI runs insecure (plaintext), MCP auth is off, and writes execute live. An LLM with a write-enabled connection to your switches can disrupt the network
Quick start (Docker)
cp devices.example.yaml devices.yaml # then edit for your fabric
cp .env.example .env # set passwords referenced as ${VAR}
docker compose up --buildThe MCP endpoint comes up at http://127.0.0.1:8000/mcp and a health probe at
http://127.0.0.1:8000/health. The image carries no site data — devices.yaml
is bind-mounted and everything else is an env var, so the same image runs in any
environment.
Related MCP server: Packet Tracer MCP
Configure
devices.yaml is a validated list of switches. Credentials may be inlined (lab)
or referenced from the environment as ${VAR} so secrets stay out of the file:
devices:
- name: leaf-01
host: 10.0.0.11
port: 8080 # SONiC gnmi/telemetry default; build-specific
insecure: true # plaintext gRPC (no TLS)
username: admin
password: ${LEAF01_PASSWORD}
tags: [lab, leaf]
- name: spine-01
host: 10.0.0.1
read_only: true # refuses config changes regardless of server setting
tags: [prod, spine]Every tool takes a device argument that must match a name here — an LLM never
addresses a raw IP, so the read_only guard can't be sidestepped. Mark production
switches read_only: true.
Set the gNMI port. It's build-specific — commonly 8080, but 50051 / 6030 / 57400 are seen. The probe (below) confirms it.
Probe first — this is the gate
SONiC's OpenConfig coverage varies by branch, Set support is a compile-time
flag, and path semantics are discovered empirically. Before trusting any tool
against real hardware, run the standalone probe (needs only pip install pygnmi pyyaml):
python scripts/probe.py --inventory devices.yaml
python scripts/probe.py --inventory devices.yaml --test-write # LAB switches ONLYIt writes probe-results.json enumerating, per device: reachability, gNMI
version, supported models/encodings, which candidate paths return data, whether
Subscribe works, and (with --test-write) whether a reversible Set is accepted.
Local development (without Docker)
python3 -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]" # runtime + pytest/ruff
SONIC_MCP_INVENTORY_PATH=./devices.yaml python -m sonic_mcp # HTTP on :8000
SONIC_MCP_TRANSPORT=stdio SONIC_MCP_INVENTORY_PATH=./devices.yaml python -m sonic_mcp
pytest # 53 tests, no switch required
ruff check src testsConnect an LLM
Model-agnostic — anything that speaks MCP works.
HTTP client / orchestrator / automation — point your MCP client at
http://<host>:8000/mcp.
Claude Desktop (stdio) — edit
~/Library/Application Support/Claude/claude_desktop_config.json. Use the venv
Python that has the deps, and an absolute inventory path (Claude Desktop
launches with a minimal PATH):
{
"mcpServers": {
"sonic-gnmi": {
"command": "/abs/path/.venv/bin/python",
"args": ["-m", "sonic_mcp"],
"env": {
"SONIC_MCP_TRANSPORT": "stdio",
"SONIC_MCP_INVENTORY_PATH": "/abs/path/devices.yaml"
}
}
}
}Tools (19)
Call list_devices first to learn the valid device names (credential-free).
Group | Tools |
Discovery |
|
Read |
|
Telemetry |
|
Write |
|
Ops |
|
Escape hatches |
|
Safety model
Three independent rails stand between an LLM and a live switch:
Read-only refusal.
SONIC_MCP_READ_ONLY=truedisables every write server-wide; any device flaggedread_onlyrefuses writes regardless. The guard trips before a SetRequest is built.Dry-run. Every write tool accepts
dry_run; a dry run returns the exact SetRequest without touching the Set RPC.SONIC_MCP_DEFAULT_DRY_RUN=truemakes preview the default.Prior-state + backup. The client captures the targeted subtree before each write (inline undo); with
SONIC_MCP_AUTO_BACKUP=truea full-config snapshot is also written to the backup dir first.
Every mutation attempt — refused, dry-run, applied, or errored — is recorded to
the audit log (SONIC_MCP_AUDIT_LOG_PATH for a durable JSON-lines trail).
gNMI notes & caveats
Paths are OpenConfig xpaths. List keys use
[key=value]; the leadingmodule:prefix is the gNMI origin. OpenConfig (interfaces, platform) is gNMI's sweet spot.SONiC-native models may need an origin.
get_device_identity(DEVICE_METADATA) andcreate_vlan(VLAN) use SONiC YANG paths whose resolution is build-specific. Validate withget_capabilities/gnmi_get.No standard save. gNMI has no commit/save RPC and SONiC generally maps none — writes hit running config only. Persist with the CLI (
config save), or setSONIC_MCP_SAVE_PATHif your build maps one.Rollback is experimental. A
get --type configsnapshot is a list of notifications, not a set-ready tree, so replaying it as a Setreplacemay not round-trip. Prefer targetedgnmi_setreverts.
Environment variables
Every field in src/sonic_mcp/settings.py maps to a SONIC_MCP_-prefixed var;
the full annotated list is in .env.example. The most-used:
Var | Default | Purpose |
|
| inventory file path |
|
|
|
|
| MCP bind address |
|
| disable all write tools |
|
| make writes preview by default |
|
| snapshot running config before each write |
|
| snapshot directory |
| (unset) | JSON-lines change trail |
|
| per-RPC seconds |
|
| gNMI value encoding |
| (unset) | gNMI Set path that persists running→startup |
| (unset) | require |
Layout
src/sonic_mcp/ package (settings, inventory, gnmi, paths, safety, backup, context, server, tools/)
scripts/probe.py standalone pre-flight probe (the Phase 2 gate)
tests/ pytest suite (fake gNMI; no switch needed)
Dockerfile multi-stage, non-root
docker-compose.yml reference deployment
legacy/ the original single-file server.py (superseded; kept for reference)This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/owroc/sonic-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server