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)
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。