
Cisco SD-WAN MCP Server
io.github.pcDamascenoPublished by GitHub account pcDamascenov0.1.0Updated Oct 24, 2026
MCP server for Cisco Catalyst SD-WAN (vManage): fabric inventory, device health, alarms, policies.
Overview
MCP server for Cisco Catalyst SD-WAN Manager (vManage) that lets an assistant query fabric inventory, device health, alarms and policies.
- What you can do
- Inventory and summaries: list devices, fetch one device, get a fabric summary and provisioned inventory.
- When to use it
- Use it when you need quick, evidence-backed answers about a Cisco Catalyst SD-WAN fabric in chat: inventory checks, branch outage triage, alarm and path-quality review, or template and config-group change review. Read-only by default, suited to daily operations and troubleshooting.
- Requirements
- Python 3.11+ with uv or pip, run via uvx or as a local process; a reachable vManage and an account on it, configured through SDWAN_VMANAGE_URL, SDWAN_USERNAME and SDWAN_PASSWORD; SDWAN_CA_BUNDLE for a private CA.
Installation
In SourceWeft
- Open Cisco SD-WAN MCP Server in the dashboard and add it to a workspace.
- Enable the server for the chats that should use its tools.
Desktop only via STDIO. STDIO servers start a local process, so they need the SourceWeft desktop host.
Other MCP clients
Follow the launch instructions in the repository.
README
Cisco SD-WAN MCP Server
[PyPI] [Python] [License: MIT] [MCP Registry]
cisco-sdwan-mcp is an MCP server for
Cisco Catalyst SD-WAN Manager (vManage), built with
FastMCP.
It gives an LLM client a working view of your SD-WAN fabric — inventory, device health, control and data plane state, alarms, path quality, templates and policies — so you can ask "why is the Frankfurt branch down?" and get an answer backed by real controller data instead of a guess.
Read-only by default. The configuration-changing tools are not registered unless you explicitly enable them, and even then every call requires a human to approve it.
Contents
- What you get
- Quickstart
- Configuration
- Write protection
- Tool reference
- Prompts
- Resources
- Connecting an MCP client
- Transports
- Authenticating MCP clients
- Docker
- Deploying
- Adding your own tools
- Testing
- Troubleshooting
- Project structure
What you get
Plus four workflow prompts and three resources.
Three design decisions are worth knowing up front, because they shape every tool:
- Responses are projected, not dumped. A vManage device record carries 60+
fields; a 200-device fabric would bury a model's context. Each tool returns
the fields that answer the question and accepts
detailed=truewhen you want everything. - Counts always accompany results. Every list reports
count(what matched) alongsidereturned(what you got), so "3 devices are down" is never confused with "3 devices are down in the first 100 I looked at". - Failures come back as answers. A wrong password, an unreachable controller or an unknown hostname returns a readable message — often with the valid options — rather than raising. The model can then correct itself or tell you exactly what to fix.
Quickstart
Prerequisites
- Python 3.11+
- uv (recommended) or pip
- A reachable Cisco Catalyst SD-WAN Manager (vManage) and an account on it
Make a dedicated vManage account. Give it a read-only role to start. The account's privileges are the real security boundary — see Write protection.
Install
From PyPI, if you only want to run it:
From a checkout, if you want to change it:
Configure
The three settings you must fill in:
The server reads .env from the repository root at startup — set
SDWAN_ENV_FILE to load a different file. Variables already present in the
environment (compose env_file, Kubernetes secrets) are never overwritten by
it, and the startup log names the file it used.
Run
The server starts over HTTP on 0.0.0.0:8000. The MCP endpoint is at
http://localhost:8000/mcp, a health probe at http://localhost:8000/healthz,
and this README at http://localhost:8000/.
Startup logs confirm what it will talk to before any client connects:
First call
Point an MCP client at it (see Connecting an MCP client)
and ask for get_fabric_summary. It is one round trip and exercises
authentication, TLS and reachability at once:
Configuration
Everything is environment-driven; .env.example is the annotated reference.
vManage connection
Server
SDWAN_USERNAME/SDWAN_PASSWORDauthenticate this server to vManage.MCP_AUTHgoverns how clients authenticate to this server. They are unrelated, and you generally want both.
TLS
vManage very often presents a self-signed or private-CA certificate. In descending order of preference:
- Point
SDWAN_CA_BUNDLEat the controller's CA — verification stays on. - Add the CA to
certificates/, which the Docker build installs into the container trust store automatically. - Only as a last resort, on a lab you control, set
SDWAN_VERIFY_SSL=false. The server logs a warning naming the host each time it does this, because it means anything on the path can read the credentials.
Write protection
The tools that change configuration are gated twice.
Gate 1 — registration. With SDWAN_ENABLE_WRITES unset or false, the
module holding them is never imported. They do not appear in the tool list, so
a model cannot call them by mistake, misinterpretation or prompt injection.
The server is read-only by construction, not by policy.
Gate 2 — confirmation. With writes enabled, each call still asks the user
through MCP elicitation, naming the template or policy and the devices
affected, before anything reaches vManage. Clients that do not implement
elicitation cannot silently proceed — the call is refused unless the caller
passes confirm=true, which puts the decision in a human's hands either way.
The vManage account is the real boundary.
SDWAN_ENABLE_WRITEScontrols which tools exist in this server; it does nothing about what the account can do through any other path. If a change must be impossible, use a read-only vManage role — do not rely on this flag alone.
vManage applies configuration asynchronously: a write returns a task_id,
meaning accepted, not applied. Poll get_task_status(task_id) until it
reports done.
The intended flow for a template push, with a review step in the middle:
And for a config-group fabric, where edits and deploys are separate steps:
Tool reference
Every tool takes limit (cap on records) and most take detailed (return all
vManage fields instead of the summary set).
Inventory
Device health
These poll the device through vManage, so they reflect live state but cost a
round trip to the edge. Prefer check_device_health over three separate calls.
Alarms and events
Path quality
These read vManage's statistics database — fast, but only as fresh as the last collection cycle (30 minutes on most deployments). For live state, use the device health tools.
Templates and policy
Config groups and feature profiles
The UX-2.0 configuration model: a config group bundles feature profiles
(system, transport, service, cli, policy-object), each profile holds parcels
— the actual configuration payloads — and a device belongs to at most one
group. On a fabric managed this way the template endpoints report nothing
useful; these tools are the equivalent surface. vManage reports membership on
the WAN-edge inventory as "managed-by": "Config-Group <name>", which is also
what get_device and list_inventory surface.
With writes enabled, the config-group counterparts to a template push are
update_parcel (edit structured knobs read-modify-write), update_cli_addon_config
(append/replace raw IOS-XE lines in a CLI add-on profile, returns a diff) and
deploy_config_group (push the group to named member devices — the only step
that touches production). Edits mark members configGroupUpToDate: false
until deployed. attach_device_template refuses devices a config group
manages, so the two configuration models cannot fight over a device.
Prompts
Reusable workflows that encode the order an engineer actually works in — control plane before data plane, evidence before conclusions.
Resources
Connecting an MCP client
Claude Desktop (claude_desktop_config.json)
VS Code (GitHub Copilot) — .vscode/mcp.json
With token auth enabled
With an OAuth mode (github, google, oauth-proxy, …) no header is needed —
MCP clients discover the flow and open the login screen themselves.
stdio (local subprocess)
From PyPI — nothing to clone, uvx fetches the package on first run:
From a checkout:
Transports: HTTP vs stdio
- HTTP (default) — the deployment transport. Serves many clients
concurrently, works behind load balancers, and is the only transport where
MCP_AUTHapplies. Everything indeploy/assumes it. - stdio — for local single-user use where a desktop client spawns the
server as a subprocess. No network listener, so
MCP_HOST/MCP_PORTandMCP_AUTHdo not apply; the process is secured by your OS user.
Deploying anywhere or serving multiple users → HTTP. One client on your own machine → either works.
Authenticating MCP clients
Authentication of clients to this server is off by default and selected at
startup with MCP_AUTH. The factory lives in cisco_sdwan_mcp/auth.py; all modes are
backed by FastMCP's built-in providers.
The full variable reference for every mode is in .env.example.
Notes:
- Auth applies to the HTTP transport only.
/healthzand/stay public — probes and humans don't carry tokens; the MCP endpoint returns401without a valid token.- OAuth flows require HTTPS on the public URL in production.
- To add your own scheme, write a builder in
cisco_sdwan_mcp/auth.pyand register it in_BUILDERS(provider docs).
A server exposing your WAN topology should not run
MCP_AUTH=noneon a reachable network. Seedeploy/README.md.
Docker
Or manually:
Helper scripts build the image, replace any container of the same name, and
start the server at http://localhost:8000/mcp, passing your .env through:
The image includes a HEALTHCHECK against /healthz, so docker ps shows
container health out of the box.
Corporate CA certificates
Drop any .crt/.pem root CA files into certificates/. The build adds them
to the container trust store and runs update-ca-certificates automatically —
which covers both a TLS-intercepting proxy and a vManage certificate signed
by your internal CA. Leave the directory empty if you don't need it.
For a proxy, HTTP_PROXY/HTTPS_PROXY/NO_PROXY are predefined Docker build
args and need no Dockerfile edits:
Deploying
The container is a plain HTTP server on port 8000 with a /healthz probe, so
it runs anywhere. deploy/ ships raw Kubernetes manifests, a Helm chart, a
Styrmin driver and a Cloud Run service definition — see
deploy/README.md for full walkthroughs, including the
SD-WAN-specific parts: reaching a management-network controller from the cloud,
private-CA handling, and vManage's per-account session limits.
This repository is also a Styrmin
Application Driver — driver.styrmin.yml and values.j2.yml at the root are
what Styrmin reads when it clones it. See
deploy/styrmin.md.
/healthz deliberately does not check vManage. A brief controller outage
should not restart pods — tools report the problem per call, and the server
recovers on its own.
Adding your own tools
Capabilities live in three packages, one module per concern. Each package's
__init__.py imports its modules so the decorators run — add a module, add one
import line.
Then add my_tools to the import list in cisco_sdwan_mcp/tools/__init__.py.
Use @sdwan_tool rather than @mcp.tool — it registers the tool and
converts SD-WAN failures into a readable {"error", "message"} result. Reach
for the shared helpers rather than reimplementing them:
The docstring is what the model reads to decide whether to call your tool —
say what question it answers, not just which endpoint it hits. Keep write
operations in config_tools.py so the registration gate keeps covering them.
Testing
The suite runs against a fake vManage (httpx.MockTransport) rather than a
live controller, so it covers the things that actually break in the field:
- the login handshake, including vManage answering a failed login with HTTP 200 and an HTML body
- CSRF token handling, and controllers older than 19.2 that have no token endpoint
- session expiry mid-session → one transparent re-login and retry
- error translation: unreachable host, timeout, 403, non-JSON response
- every read tool's filtering, projection and truncation
- the write gate, verified in a fresh interpreter: the configuration tools are
absent without
SDWAN_ENABLE_WRITES=trueand present with it - write confirmation: declining, or a client that cannot prompt, must not produce an HTTP call to vManage
tests/conftest.py holds the fake controller; use it as the pattern for your
own tools.
Troubleshooting
Set LOG_LEVEL=DEBUG for more detail. Note that vManage error bodies can be
verbose — check what yours returns before enabling debug logs in a shared
environment.
Project structure
Resources
License
Source: README.md at commit 6531275
Tools
0Version history
1- v0.1.0LatestSep 16, 2026
Score
50% of the applicable checks met
How complete this listing is, computed from the registry entry, the endpoint and public sources. Not a rating of the server and not a statement that it is safe or working today: reachability is a dated check, and no installs or reviews go into the score.
- Reached in the last 30 days25 pts
Keep the endpoint answering the MCP handshake; SourceWeft probes it every 30 days.
- Auth declared10 pts
Declare the credential headers in the registry entry, or keep the endpoint answering the probe so its auth can be classified.
- Tools listed15 pts
Answer tools/list without a credential, or ship a package that starts in a sandbox without one.
- DescriptionRequired15 pts
- Logo10 pts
- Documentation15 pts
- License10 pts