SONiC MCP Server
An MCP server that exposes a SONiC switch's gNMI interface as tools, enabling LLMs to read switch state and change configuration.
README
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 --build
The 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.
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 ONLY
It 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 tests
Connect 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 | list_devices, get_capabilities |
| Read | get_interface_status, get_interface_counters, get_lldp_neighbors, get_bgp_neighbors, get_environment, get_device_identity, get_config |
| Telemetry | subscribe_telemetry (bounded by sample count and wall-clock) |
| Write | set_interface_admin, configure_interface_ip, create_vlan |
| Ops | backup_config, diff_config, rollback_config, save_config |
| Escape hatches | gnmi_get, gnmi_set |
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 |
|---|---|---|
SONIC_MCP_INVENTORY_PATH |
/config/devices.yaml |
inventory file path |
SONIC_MCP_TRANSPORT |
http |
http or stdio |
SONIC_MCP_HOST / SONIC_MCP_PORT |
0.0.0.0 / 8000 |
MCP bind address |
SONIC_MCP_READ_ONLY |
false |
disable all write tools |
SONIC_MCP_DEFAULT_DRY_RUN |
false |
make writes preview by default |
SONIC_MCP_AUTO_BACKUP |
true |
snapshot running config before each write |
SONIC_MCP_BACKUP_DIR |
/config/backups |
snapshot directory |
SONIC_MCP_AUDIT_LOG_PATH |
(unset) | JSON-lines change trail |
SONIC_MCP_GNMI_TIMEOUT |
15 |
per-RPC seconds |
SONIC_MCP_ENCODING |
json_ietf |
gNMI value encoding |
SONIC_MCP_SAVE_PATH |
(unset) | gNMI Set path that persists running→startup |
SONIC_MCP_AUTH_TOKEN |
(unset) | require Authorization: Bearer <token> |
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)
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.
Neon Database
MCP server for interacting with Neon Management API and databases
E2B
Using MCP to run code via e2b.
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.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.