关于 Cisco SD-WAN MCP Server
为 MCP 客户端公开 Cisco Catalyst SD-WAN Manager(vManage)组网信息的服务。可查询设备状态、告警、路径质量、模板和策略;配置变更工具默认禁用。
主要功能
- 01设备与组网清单
- 02设备运行状况检查
- 03告警与事件查询
- 04隧道质量调查
- 05模板与策略查询
- 06可选启用并确认变更工具
适用场景
- 01排查无法连接的分支设备
- 02检查 SD-WAN 告警和事件
- 03定位质量下降的隧道
- 04变更配置前查看模板
MCP 相关
该 MCP 服务通过工具和资源提供 vManage 的设备清单、健康信息、告警、路径质量、模板及策略。启用配置变更工具后,每次操作仍需用户确认。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
uvx cisco-sdwan-mcpSDWAN_VMANAGE_URLCisco Catalyst SD-WAN Manager URL, e.g. https://vmanage.example.com:8443SDWAN_USERNAMEvManage username. Use a dedicated read-only account.SDWAN_PASSWORD密钥vManage password for SDWAN_USERNAME.MCP_TRANSPORTMust be stdio for this install. The server itself defaults to http; set http only when deploying it as a service.SDWAN_VERIFY_SSLVerify the vManage TLS certificate. Prefer SDWAN_CA_BUNDLE over disabling this.SDWAN_CA_BUNDLEPath to a CA bundle for a private-CA or self-signed vManage certificate.SDWAN_ENABLE_WRITESRegister the configuration-changing tools. Read-only when unset.本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
Cisco SD-WAN MCP Server
cisco-sdwan-mcp 是一个面向 Cisco Catalyst SD-WAN Manager (vManage) 的 MCP 服务,基于
FastMCP 构建。
它让大模型客户端能够查看你的 SD-WAN 网络结构,包括设备清单、 设备运行状况、控制平面和数据平面状态、警报、路径质量、模板 和策略——因此你可以询问“法兰克福分支为什么宕机?”,并获得基于真实控制器数据而非猜测的回答。
默认只读。 除非你明确启用,否则不会注册会更改配置的工具; 即使启用,每次调用也都需要人工批准。
目录
你将获得什么
| 领域 | 工具 |
|---|---|
| 设备清单 | list_devices、get_device、get_fabric_summary、list_inventory |
| 设备运行状况 | check_device_health、get_system_status、get_control_connections、get_bfd_sessions、get_omp_peers、get_interfaces |
| 警报和事件 | get_alarm_summary、list_alarms、list_events |
| 路径质量 | find_degraded_tunnels、get_tunnel_statistics、get_interface_statistics |
| 模板和策略 | list_device_templates、get_device_template、list_feature_templates、list_policies、get_template_input_variables |
| 配置组和配置文件 | list_config_groups、get_config_group、get_device_config_group、get_config_group_device_variables、list_feature_profiles、get_feature_profile、get_parcel、get_parcel_schema、get_device_running_config |
| 配置 (选择启用) | attach_device_template、activate_vsmart_policy、update_parcel、update_cli_addon_config、deploy_config_group、get_task_status |
有三项设计决策值得提前了解,因为它们影响每个工具:
- 返回的是筛选后的结果,而非原始数据。 vManage 设备记录包含 60 多个字段;200 台设备的网络会占满模型的上下文。每个工具只返回回答问题所需的字段;如果需要全部字段,可设置
detailed=true。 - 结果始终附带计数。 每个列表都会同时报告
count(匹配数量)和returned(返回数量),这样“有 3 台设备宕机”就不会被误解为“我查看的前 100 台设备中有 3 台宕机”。 - 失败会以答案的形式返回。 密码错误、控制器无法访问或主机名未知时,会返回易读的消息——通常还会提供有效选项——而不是抛出异常。模型随后可以自行修正,或准确告知你需要修复什么。
快速开始
前置条件
- Python 3.11+
- uv(推荐)或 pip
- 可访问的 Cisco Catalyst SD-WAN Manager(vManage)及其账号
请创建专用的 vManage 账号。 刚开始时为其分配只读角色。 账号权限才是真正的安全边界——请参阅 写入保护。
安装
如果只想运行,可从 PyPI 安装:
uvx cisco-sdwan-mcp # no install, run it straight
pip install cisco-sdwan-mcp
如果想修改代码,可从代码库检出:
git clone https://github.com/pcDamasceno/cisco-sdwan-mcp.git
cd cisco-sdwan-mcp
# with uv (recommended)
uv sync --extra dev
# with pip
pip install -e ".[dev]"
配置
cp .env.example .env
必须填写以下三项设置:
SDWAN_VMANAGE_URL=https://vmanage.example.com:8443
SDWAN_USERNAME=automation-readonly
SDWAN_PASSWORD=...
服务启动时会从代码库根目录读取 .env——设置
SDWAN_ENV_FILE 可加载其他文件。环境中已有的变量(compose env_file、Kubernetes 密钥)不会被覆盖,启动日志会显示所用文件的名称。
运行
uv run python -m cisco_sdwan_mcp.server # or: python -m cisco_sdwan_mcp.server
服务会通过 HTTP 在 0.0.0.0:8000 上启动。MCP 端点位于
http://localhost:8000/mcp,健康探测端点位于 http://localhost:8000/healthz,
此 README 位于 http://localhost:8000/。
在任何客户端连接之前,启动日志会确认服务将连接的目标:
INFO cisco_sdwan_mcp.server: vManage controller: vmanage.example.com:8443 (user automation-readonly, TLS verify: True)
INFO cisco_sdwan_mcp.server: Write tools: disabled (read-only)
首次调用
将 MCP 客户端连接到此服务(请参阅连接 MCP 客户端),并调用 get_fabric_summary。此调用只需一次往返,即可同时验证身份验证、TLS 和连通性:
{
"total_devices": 42,
"by_type": {"vedge": 38, "vsmart": 2, "vbond": 1, "vmanage": 1},
"by_reachability": {"reachable": 40, "unreachable": 2},
"unreachable_count": 2,
"unreachable_devices": [{"host-name": "BR2-EDGE1", "system-ip": "10.0.0.12", "site-id": "1002"}]
}
配置
所有配置均通过环境变量设置;.env.example 是带注释的参考文件。
vManage 连接
| 变量 | 默认值 | 说明 |
|---|---|---|
SDWAN_VMANAGE_URL | — | 控制器 URL,例如 https://vmanage.example.com:8443。必填(或使用 SDWAN_VMANAGE_HOST) |
SDWAN_VMANAGE_HOST | — | 主机名,用于替代完整 URL |
SDWAN_VMANAGE_PORT | 443 | 使用 SDWAN_VMANAGE_HOST 时的端口 |
SDWAN_USERNAME | — | vManage 用户名。必填 |
SDWAN_PASSWORD | — | vManage 密码。必填 |
SDWAN_VERIFY_SSL | true | TLS 证书验证 |
SDWAN_CA_BUNDLE | — | CA 证书包的路径——私有 CA 的正确配置方式 |
SDWAN_TIMEOUT | 60 | 等待 vManage 的秒数 |
SDWAN_PAGE_SIZE | 100 | 每次工具调用返回记录数的默认上限 |
SDWAN_ENABLE_WRITES | false | 注册配置工具——见下文 |
服务端
| 变量 | 默认值 | 说明 |
|---|---|---|
MCP_SERVER_NAME | cisco-sdwan-mcp | 向 MCP 客户端公布的名称 |
MCP_TRANSPORT | http | http 或 stdio |
MCP_HOST | 0.0.0.0 | 绑定地址(仅限 HTTP) |
MCP_PORT | 8000 | 绑定端口(仅限 HTTP) |
MCP_AUTH | none | MCP 客户端向此服务进行身份验证的方式 |
LOG_LEVEL | INFO | Python 日志级别 |
SDWAN_USERNAME/SDWAN_PASSWORD用于此服务向 vManage 进行身份验证。MCP_AUTH决定客户端如何向此服务进行身份验证。二者互不相关,通常两者都需要配置。
TLS
vManage 经常会提供自签名证书或私有 CA 证书。按优先顺序从高到低:
- 将
SDWAN_CA_BUNDLE指向控制器的 CA——保持启用证书验证。 - 将 CA 添加到
certificates/,Docker 构建会自动将其安装到容器信任存储中。 - 只有在最后迫不得已时,才在你控制的实验环境中设置
SDWAN_VERIFY_SSL=false。 每次执行此操作时,服务都会记录一条警告并注明主机名,因为这意味着路径上的任何对象都可能读取凭据。
写入保护
更改配置的工具受到双重限制。
限制 1 — 注册。 当 SDWAN_ENABLE_WRITES 未设置或为 false 时,包含这些工具的模块永远不会被导入。它们不会出现在工具列表中,因此模型无法因误操作、误解或提示注入而调用它们。该服务从构造上就是只读的,而非依靠策略限制。
限制 2 — 确认。 启用写入后,每次调用仍会通过 MCP elicitation 向用户征求确认,明确说明模板或策略以及受影响的设备,然后才会将任何内容发送到 vManage。不支持 elicitation 的客户端无法悄悄继续操作——除非调用方传入 confirm=true,否则调用会被拒绝;无论哪种情况,决定权都在人工手中。
SDWAN_ENABLE_WRITES=true uv run python -m cisco_sdwan_mcp.server
WARNING cisco_sdwan_mcp.tools: SDWAN_ENABLE_WRITES=true — configuration-changing tools are registered.
Each one still requires explicit user confirmation before it runs.
vManage 账户才是真正的边界。
SDWAN_ENABLE_WRITES控制的是此服务中有哪些工具;它无法限制该账户通过其他途径执行的操作。如果必须确保某项更改不可能发生,请使用只读 vManage 角色——不要只依赖此标志。
vManage 会异步应用配置:写入操作返回 task_id,表示已接受,而非已应用。轮询 get_task_status(task_id),直到状态显示已完成。
模板推送的预期流程,中间包含审核步骤:
list_device_templates → find the template
get_device_template → see what it configures and who has it
get_template_input_variables → the exact per-device values (read-only preview)
check_device_health → never push to an already-broken device
attach_device_template → asks for approval, returns a task_id
get_task_status → confirm it actually landed
对于配置组架构,编辑和部署是分开的步骤:
get_device_config_group → which group owns the device
get_feature_profile / get_parcel → find the parcel and its current values
get_parcel_schema → which parcel a setting lives in, and its shape
update_parcel → asks for approval; changes intent only
get_device_running_config → snapshot before the push
deploy_config_group → asks for approval, returns a task_id
get_task_status → confirm it landed, then re-diff the running config
工具参考
每个工具都接受 limit(记录数上限),大多数工具还接受 detailed(返回 vManage 的所有字段,而非摘要字段集)。
设备清单
| 工具 | 可解答的问题 |
|---|---|
get_fabric_summary() | 按类型、可达性和版本统计设备数量,并列出所有不可达设备。遇到开放式问题时,从这里开始。 |
list_devices(device_type, reachability, site_id) | vManage 当前正在与之通信的设备。 |
get_device(device) | 获取单台设备的完整记录。接受主机名、系统 IP 或机箱编号。 |
list_inventory(category, unattached_only) | 所有已置备设备,包括从未完成上线、证书无效或未关联模板的设备。 |
设备运行状况
| 工具 | 可解答的问题 |
|---|---|
check_device_health(device) | 一次调用完成初步排查——系统状态、控制连接和 BFD,并提供指出问题所在的 problems 列表。 |
get_system_status(device) | 运行时间、CPU、内存、磁盘、上次重启原因。 |
get_control_connections(device) | 与 vSmart/vBond/vManage 的连接。设备无法启动时,优先检查此项。 |
get_bfd_sessions(device, state) | 到其他边缘设备的数据平面隧道。站点可以连接控制器但彼此无法通信时,检查此项。 |
get_omp_peers(device) | OMP 对等状态——控制连接正常但 OMP 断开意味着没有覆盖网络路由。 |
get_interfaces(device, vpn_id, interface_name) | 接口状态、寻址信息和错误计数器。 |
这些工具通过 vManage 轮询设备,因此反映的是实时状态,但会产生一次到边缘设备的往返通信。与其分开调用 3 次,不如优先使用 check_device_health。
警报和事件
| 工具 | 可解答的问题 |
|---|---|
get_alarm_summary(hours) | 按严重程度和组件统计数量、列出最常见规则及受影响最多的设备。开销低——列出警报前先调用。 |
list_alarms(hours, severity, active_only) | 获取警报本身。 |
list_events(hours, severity, component) | 原始事件流——噪声较多,但能显示从未升级为警报的连接抖动和状态转换。 |
链路质量
| 工具 | 可解答的问题 |
|---|---|
find_degraded_tunnels(hours, max_loss_percent, max_latency_ms, max_jitter_ms) | 查找超出阈值的隧道,按问题严重程度从高到低排列,并说明各隧道超出了哪个阈值。 |
get_tunnel_statistics(device, hours) | 获取每条隧道的原始丢包、延迟、抖动和 vQoE 数据。 |
get_interface_statistics(device, hours, interface_name) | 获取历史吞吐量和错误计数器。 |
这些工具读取 vManage 的统计数据库——速度快,但数据新鲜度取决于上次采集周期(大多数部署中为 30 分钟)。如需查看实时状态,请使用设备运行状况工具。
模板和策略
| 工具 | 说明 |
|---|---|
list_device_templates(device_type, attached_only) | 模板及其关联数量。 |
get_device_template(template_id) | 单个模板的定义及关联的设备。 |
list_feature_templates(template_type) | 构建模块。 |
list_policies(policy_scope) | 集中式(vSmart)或本地化策略,以及当前生效的策略。 |
get_template_input_variables(template_id, device_ids) | 只读预览关联操作将推送的值。 |
配置组和功能配置文件
UX-2.0 配置模型:一个配置组包含多个功能配置文件
(系统、传输、服务、CLI、策略对象),每个配置文件包含
配置块——即实际的配置负载——而一台设备最多只能属于一个
配置组。在以这种方式管理的网络结构中,模板端点不会返回有用的信息;
这些工具提供了相应的功能。vManage 会在 WAN 边缘设备清单中以 "managed-by": "Config-Group <name>" 报告成员关系,get_device 和 list_inventory 也会显示此信息。
| 工具 | 说明 |
|---|---|
list_config_groups() | 配置组、其配置文件、设备数量及最新状态。 |
get_config_group(group) | 按名称或 ID 获取单个配置组,以及其成员设备和等待部署的设备。 |
get_device_config_group(device) | 查看管理设备的配置组,从而判断模板是否必须避开该设备。 |
get_config_group_device_variables(group, device_ids) | 部署操作将解析的各设备对应值;这是 get_template_input_variables 的配置组版本。 |
list_feature_profiles(profile_type) | 指定类型的配置文件,或全部五种类型。 |
get_feature_profile(profile_type, profile_id) | 配置块树,其中每个节点都带有可直接使用的 parcelPath。 |
get_parcel(profile_type, profile_id, parcel_path, parcel_id) | 单个配置块的负载——实际配置项。 |
get_parcel_schema(profile_type, parcel_path) | 配置块类型可包含的所有字段;编辑前请先查看。 |
get_device_running_config(device) | 设备当前的配置,用于部署前后差异对比。 |
启用写入后,与模板推送对应的配置组操作包括
update_parcel(编辑结构化配置项,采用读取-修改-写入方式)、update_cli_addon_config
(在 CLI 附加配置文件中追加或替换原始 IOS-XE 行,并返回差异)以及
deploy_config_group(将配置组推送到指定成员设备——唯一会影响生产环境的步骤)。编辑会将成员标记为 configGroupUpToDate: false,直到完成部署。attach_device_template 会拒绝由配置组管理的设备,因此两种配置模型不会争抢同一台设备。
提示词
可重复使用的工作流,用于编码工程师实际采用的操作顺序—— 先控制平面,再数据平面;先收集证据,再得出结论。
| 提示词 | 用途 |
|---|---|
troubleshoot_device(device, symptom) | 结构化设备排查,遇到首个真实原因时停止 |
fabric_health_report(hours) | 全网报告:设备、告警、路径质量和建议 |
analyse_path_quality(hours, site) | 隧道性能分析,按颜色/站点/设备归类,以定位原因 |
review_template_change(template_id) | 变更前审查,明确给出继续/停止建议——只提供建议,不会关联模板 |
资源
| URI | 内容 |
|---|---|
sdwan://config | 当前生效的连接设置——控制器、用户、TLS 模式,以及是否启用了写入。绝不包含密码。 |
sdwan://devices | 当前网络结构清单,包含各设备状态 |
sdwan://device/{identifier} | 按主机名或系统 IP 查询单台设备的完整记录 |
连接 MCP 客户端
Claude Desktop(claude_desktop_config.json)
{
"mcpServers": {
"cisco-sdwan": {
"url": "http://localhost:8000/mcp"
}
}
}
VS Code(GitHub Copilot)— .vscode/mcp.json
{
"servers": {
"cisco-sdwan": {
"type": "http",
"url": "http://localhost:8000/mcp"
}
}
}
启用令牌身份验证时
{
"mcpServers": {
"cisco-sdwan": {
"url": "http://localhost:8000/mcp",
"headers": { "Authorization": "Bearer dev-token" }
}
}
}
使用 OAuth 模式(github、google、oauth-proxy 等)时,无需提供标头——
MCP 客户端会自行发现身份验证流程并打开登录界面。
stdio(本地子进程)
从 PyPI 获取——无需克隆,首次运行时 uvx 会获取软件包:
{
"mcpServers": {
"cisco-sdwan": {
"command": "uvx",
"args": ["cisco-sdwan-mcp"],
"env": {
"MCP_TRANSPORT": "stdio",
"SDWAN_VMANAGE_URL": "https://vmanage.example.com:8443",
"SDWAN_USERNAME": "automation-readonly",
"SDWAN_PASSWORD": "..."
}
}
}
}
从检出目录运行:
{
"mcpServers": {
"cisco-sdwan": {
"command": "uv",
"args": ["run", "python", "-m", "cisco_sdwan_mcp.server"],
"cwd": "/absolute/path/to/cisco-sdwan-mcp",
"env": {
"MCP_TRANSPORT": "stdio",
"SDWAN_VMANAGE_URL": "https://vmanage.example.com:8443",
"SDWAN_USERNAME": "automation-readonly",
"SDWAN_PASSWORD": "..."
}
}
}
}
传输方式:HTTP 与 stdio
- HTTP(默认) — 用于部署的传输方式。可同时为多个客户端提供服务,支持在负载均衡器后运行,并且只有此传输方式会应用
MCP_AUTH。deploy/中的所有内容都以此为前提。 - stdio — 适用于本地单用户场景,此时桌面客户端会将服务作为子进程启动。没有网络监听,因此不适用
MCP_HOST/MCP_PORT和MCP_AUTH;该进程由你的操作系统用户账户提供安全保护。
MCP_TRANSPORT=stdio uv run python -m cisco_sdwan_mcp.server
部署到任何地方或为多个用户提供服务 → 使用 HTTP。在自己的机器上供一个客户端使用 → 两种方式均可。
验证 MCP 客户端
默认情况下,不会验证客户端向此服务发起的请求;启动时通过 MCP_AUTH 选择验证方式。工厂函数位于 cisco_sdwan_mcp/auth.py;所有模式都基于 FastMCP 内置的提供程序。
MCP_AUTH | 使用场景 |
|---|---|
none(默认) | 本地开发,或通过网络层保护(IAM、VPN、mTLS) |
static | 固定的 bearer 令牌——仅用于快速测试,绝不可用于生产环境 |
jwt | 你已有 IdP 用于签发 JWT(Keycloak、Okta、Entra ID、Cognito……) |
introspection | 你的 IdP 签发不透明令牌(RFC 7662) |
oauth-proxy | 通过任意 OAuth 提供程序实现完整的 OAuth 2.1 登录流程 |
github、google、azure、auth0、workos | 通过托管身份提供程序实现完整登录流程,且已预先配置 |
# Development tokens (never in production — tokens sit in plain env vars)
MCP_AUTH=static MCP_AUTH_STATIC_TOKENS=dev-token uv run python -m cisco_sdwan_mcp.server
# JWT via your IdP's JWKS endpoint
MCP_AUTH=jwt
MCP_AUTH_JWKS_URI=https://idp.example.com/realms/main/protocol/openid-connect/certs
MCP_AUTH_ISSUER=https://idp.example.com/realms/main
MCP_AUTH_AUDIENCE=cisco-sdwan-mcp
所有模式的完整变量参考请见 .env.example。
注意:
- 验证仅适用于 HTTP 传输方式。
/healthz和/始终公开——探针和用户不会携带令牌;MCP 端点在没有有效令牌时会返回401。- 在生产环境中,OAuth 流程要求公开 URL 使用 HTTPS。
- 如需添加自己的方案,请在
cisco_sdwan_mcp/auth.py中编写构建器,并在_BUILDERS中注册(提供程序文档)。
暴露 WAN 拓扑的服务不应在可访问的网络上以
MCP_AUTH=none运行。请参阅deploy/README.md。
Docker
cp .env.example .env # fill in vManage URL and credentials
docker compose up -d --build
或者手动操作:
docker build -t cisco-sdwan-mcp .
docker run -p 8000:8000 \
-e SDWAN_VMANAGE_URL=https://vmanage.example.com:8443 \
-e SDWAN_USERNAME=automation-readonly \
-e SDWAN_PASSWORD=... \
cisco-sdwan-mcp
辅助脚本会构建镜像、替换任何同名容器,并启动服务,使其可通过 http://localhost:8000/mcp 访问,同时传入你的 .env:
bash scripts/run_docker.sh # Linux/macOS
.\scripts\run_docker.ps1 # Windows PowerShell
镜像包含针对 /healthz 的 HEALTHCHECK,因此 docker ps 开箱即用即可显示容器健康状态。
企业 CA 证书
将任意 .crt/.pem 根 CA 文件放入 certificates/。构建过程会将其添加到容器信任存储,并自动运行 update-ca-certificates——这同时适用于拦截 TLS 的代理和由内部 CA 签名的 vManage 证书。如果不需要,请将此目录留空。
使用代理时,HTTP_PROXY/HTTPS_PROXY/NO_PROXY 是预定义的 Docker 构建参数,无需修改 Dockerfile:
docker build --build-arg HTTPS_PROXY=http://proxy.example.com:8080 -t cisco-sdwan-mcp .
docker run -p 8000:8000 -e HTTPS_PROXY=http://proxy.example.com:8080 cisco-sdwan-mcp
部署
此容器是在端口 8000 上运行的普通 HTTP 服务,带有 /healthz 探针,因此可以在任何地方运行。deploy/ 提供原始 Kubernetes 清单、Helm chart、Styrmin 驱动程序和 Cloud Run 服务定义——完整操作指南请参阅 deploy/README.md,其中也包括 SD-WAN 专属内容:从云端访问管理网络控制器、处理私有 CA,以及 vManage 的每账户会话限制。
kubectl apply -k deploy/kubernetes
helm install sdwan-mcp oci://ghcr.io/pcdamasceno/charts/cisco-sdwan-mcp \
--set sdwan.vmanageUrl=https://vmanage.example.com:8443
gcloud run services replace deploy/cloud-run-service.yaml --region europe-west3
此代码库也是一个 Styrmin 应用驱动程序——Styrmin 克隆此代码库时会读取根目录下的 driver.styrmin.yml 和 values.j2.yml。请参阅 deploy/styrmin.md。
/healthz 有意不检查 vManage。短暂的控制器故障不应导致 Pod 重启——工具会在每次调用时报告问题,服务也会自行恢复。
添加自定义工具
功能分布在三个包中,每个包对应一个关注点的模块。每个包的
__init__.py 都会导入其模块,以便运行装饰器——添加一个模块,再添加一
行导入语句。
# cisco_sdwan_mcp/tools/my_tools.py
from cisco_sdwan_mcp.sdwan.client import get_client
from cisco_sdwan_mcp.sdwan.formatting import envelope, project
from cisco_sdwan_mcp.tools._helpers import resolve_device_id, sdwan_tool
@sdwan_tool
async def get_dhcp_leases(device: str, limit: int = 100) -> dict:
"""Show DHCP leases the device is serving.
Args:
device: Hostname, system IP or chassis number.
limit: Maximum leases to return.
"""
system_ip = await resolve_device_id(device)
client = await get_client()
records = await client.get_data(
"/dataservice/device/dhcp/server", {"deviceId": system_ip}
)
fields = ("ifname", "address", "client-id", "state", "expires")
return envelope(project(records, fields), limit=limit, device=device)
然后将 my_tools 添加到 cisco_sdwan_mcp/tools/__init__.py 的导入列表中。
使用 @sdwan_tool,而不是 @mcp.tool——它不仅会注册工具,还会将
SD-WAN 故障转换为易读的 {"error", "message"} 结果。优先使用共享辅助函数,
而不是重新实现:
| 辅助函数 | 用途 |
|---|---|
resolve_device_id(device) | 将主机名 / 系统 IP / 机箱转换为 vManage 实时端点所需的系统 IP |
client.get_data(path, params) | 发起 GET 请求并解包 vManage 的 {"data": [...]} 信封 |
project(records, fields) | 将宽泛的记录精简为重要内容 |
envelope(records, limit=...) | 添加 count/returned/截断说明 |
build_query(hours=..., rules=...) | 构建告警 / 事件 / 统计数据所需的 JSON query 参数 |
count_by(records, field) | 按字段汇总计数 |
模型会读取文档字符串,以决定是否调用你的工具——说明它能回答什么问题,
而不只是它调用了哪个端点。将写操作放在 config_tools.py 中,以便注册
门控机制继续覆盖这些操作。
测试
uv run pytest # or: pytest
测试套件使用伪造的 vManage(httpx.MockTransport)运行,而不是连接到
真实控制器,因此能覆盖实际部署中容易出问题的情况:
- 登录握手,包括 vManage 使用 HTTP 200 和 HTML 正文回应失败的登录
- CSRF 令牌处理,以及没有令牌端点的 19.2 之前版本控制器
- 会话中途过期 → 自动重新登录并重试一次
- 错误转换:主机无法访问、超时、403、非 JSON 响应
- 每个读取工具的筛选、投影和截断
- 写操作门控,在全新解释器中验证:未设置
SDWAN_ENABLE_WRITES=true时配置工具不可用,设置后则可用 - 写操作确认:拒绝确认,或客户端无法提示时,不得向 vManage 发起 HTTP 请求
tests/conftest.py 中包含伪造控制器;请将其作为编写自定义工具的范例。
故障排查
| 症状 | 原因和解决方法 |
|---|---|
ConfigurationError: No controller configured | 未设置 SDWAN_VMANAGE_URL(或 SDWAN_VMANAGE_HOST)。 |
AuthenticationError: rejected the credentials | 用户名或密码错误,或者账户已锁定。密码错误时,vManage 会返回包含登录页面的 HTTP 200 响应,客户端会检测到这种情况并将其报告为身份验证失败。 |
AuthenticationError: may lack the required role | 身份验证成功,但该账户没有访问此端点的权限。模板和策略端点需要的权限不止只读角色。 |
AuthenticationError: issued no JSESSIONID cookie | URL 指向的是会剥离 Cookie 的代理,而不是 vManage 本身。 |
APIError: cannot reach <host> | DNS、路由、防火墙或端口错误。vManage 通常监听 8443,而不是 443。 |
APIError: timed out after 60s | 实时端点会轮询设备本身。请调高 SDWAN_TIMEOUT,或将查询范围限定为一台设备。 |
| TLS / 证书验证失败 | 使用的是私有 CA。请设置 SDWAN_CA_BUNDLE,或将 CA 添加到 certificates/。SDWAN_VERIFY_SSL=false 仅可作为实验环境中的最后手段。 |
APIError: response was not valid JSON | 此 vManage 版本上不存在该端点;API 路径因版本而异。 |
| 写入工具“不存在” | 这是预期行为:SDWAN_ENABLE_WRITES 未设置为 true。 |
写入返回 applied: false,并提示 confirm=True | 客户端不支持 MCP elicitation,因此无法请求你批准。 |
| 所有结果均为空,且没有错误 | 该账户可能受限于没有设备的租户或设备组。请检查 sdwan://config 并尝试 list_inventory。 |
设置 LOG_LEVEL=DEBUG 可查看更多详情。请注意,vManage 的错误正文可能很冗长;在共享环境中启用调试日志前,请先检查实际返回的内容。
项目结构
.
├── cisco_sdwan_mcp/
│ ├── mcp.py ← Shared FastMCP instance, auth wiring, /healthz
│ ├── auth.py ← MCP client authentication factory (MCP_AUTH)
│ ├── server.py ← Entry point: transport selection, startup logging
│ ├── sdwan/ ← vManage integration layer (no MCP knowledge)
│ │ ├── config.py ← SDWAN_* settings
│ │ ├── client.py ← Async client: login, CSRF, session recovery
│ │ ├── formatting.py ← Projection, envelopes, vManage query builder
│ │ └── errors.py ← Exception hierarchy
│ ├── tools/
│ │ ├── _helpers.py ← @sdwan_tool, device resolution
│ │ ├── inventory_tools.py ← Devices and fabric summary
│ │ ├── monitoring_tools.py ← Control plane, BFD, OMP, interfaces, health
│ │ ├── alarm_tools.py ← Alarms and events
│ │ ├── statistics_tools.py ← Tunnel and interface statistics
│ │ ├── template_tools.py ← Templates and policies (read-only)
│ │ ├── config_group_tools.py ← Config groups, feature profiles, parcels (read-only)
│ │ ├── config_tools.py ← Template/policy writes — imported only when enabled
│ │ └── config_group_write_tools.py ← Parcel/CLI/deploy writes — same gate
│ ├── resources/sdwan_resources.py
│ └── prompts/sdwan_prompts.py
├── tests/
│ ├── conftest.py ← Fake vManage (httpx.MockTransport)
│ ├── sample_data.py ← Representative vManage payloads
│ ├── test_client.py ← Login, session recovery, error translation
│ ├── test_formatting.py ← Projection, envelopes, query building
│ ├── test_tools.py ← Read tools via the in-memory MCP client
│ ├── test_config_tools.py ← The write confirmation gate
│ ├── test_config_group_tools.py← Config-group reads, writes and the template guardrail
│ ├── test_server.py ← Registration, the write gate, public routes
│ └── test_auth.py ← MCP client auth factory
├── deploy/ ← Kubernetes + Cloud Run
├── scripts/ ← Docker helper scripts (bash / PowerShell)
├── certificates/ ← Drop-in CA certificates for Docker builds
├── .env.example ← Annotated reference of every variable
├── docker-compose.yml
├── Dockerfile
└── pyproject.toml
资源
许可证
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。