cisco-iosxe-mcp

cisco-iosxe-mcp

MCP server that exposes Cisco IOS-XE devices as tools for LLM clients, enabling safe configuration changes with revert timer and connectivity verification.

Category
访问服务器

README

cisco-iosxe-mcp

An MCP server that exposes Cisco IOS-XE devices as tools an LLM client can call. Named operational reads, plus a configuration-change path that shows the exact command list, applies it under configure terminal revert timer, verifies the device still answers on a new session, and only then confirms.

It speaks MCP over Streamable HTTP, so it runs as its own service on the network rather than as a local subprocess of one client. Transport to the device is the IOS-XE CLI over SSH, via scrapli.

Built for universal-network-director, a chat-driven multi-vendor network manager with a human approval gate on every write — but it is a standalone MCP server and works with any MCP client.

Not affiliated with, endorsed by, or supported by Cisco Systems, Inc. "Cisco" and "IOS-XE" are trademarks of their respective owners and are used here only to describe what this software talks to.


The safety model

Two-step, same shape as the Junos path — with one honest difference you have to understand before using it.

Step 1 — preview shows the command list, not a diff

preview_config_change returns the exact commands that would be sent, the device they'd go to, and the current state of the lines they touch. You approve that.

This is weaker than a Junos show | compare. Junos loads a candidate config and the device computes the real diff; IOS-XE has no candidate configuration, so there is nothing to ask the device to diff against. The preview here is the change as written, checked against what's currently configured — not the device's own account of what would result. Read the commands, not just the summary.

Step 2 — apply under a revert timer

write_apply_config_block takes only a preview id — it cannot apply anything that wasn't previewed. The commands go in under configure terminal revert timer <n>: live immediately, but IOS-XE rolls the configuration back automatically unless a configure confirm arrives in time. This server then reconnects on a new SSH session to prove the device is still reachable, and confirms only if it is. Lock yourself out and the box undoes the change.

Device prerequisite Junos does not have: the IOS archive feature must be configured (archive / path ...) or the revert timer has no rollback point and the safety net silently isn't there. get_archive_status reports this per device, and write_apply_config_block refuses when it's missing rather than applying unprotected.

There is deliberately no free-form command tool. Every operational read runs a command built from a fixed template plus validated arguments. The one place the model composes text freely — a configuration block — is gated, shown to a human verbatim, and applied under the revert timer.


Read this before you point it at production

Three of the nineteen tools change state, and this server does not ask before executing them. The write_ prefix is a convention so your client can gate them.

Tool What it does Risk
write_apply_config_block Applies a previewed command list Whatever the commands say. Behind a revert timer with reachability verification — but only if archive is configured.
write_save_config Copies running-config to startup-config Writes no new configuration — it makes the current one survive a reload, including changes you were still deciding about.
write_reload_device Reboots the device, optionally after a delay Takes the device down. Not revertible. Unsaved configuration is lost; saved configuration comes back.

Note the asymmetry the prefix encodes: write_ means "a human must approve this", not "this edits the configuration". write_save_config adds no configuration at all, and is gated because making a change permanent is a decision someone should take deliberately.

cancel_reload is ungated on purpose — it is a recovery action, and requiring an approval round-trip to stop a pending reboot is the wrong trade.

Scope the device account read-only unless you specifically intend the writes to work. That control lives on the device, not in this code.

The MCP endpoint has no authentication

This server exposes its tools to anyone who can reach its port. There is no token, no client auth, no TLS on the MCP side.

MCP_HOST defaults to 127.0.0.1 for that reason. The container image sets 0.0.0.0 because it has to, which means publishing the container's port puts an unauthenticated path to your routers on that interface. Keep it on an internal network with the client, or terminate TLS and authentication in front of it.


Device inventory

Device credentials live in a JSON file mounted read-only into the container — never baked into the image, never committed. It holds plaintext SSH credentials, so chmod 600 it and own it as the uid the container runs as.

Same shape as the Junos gateway's inventory, so there is one format to learn, plus an optional enable_password:

{
  "csr-lab": {
    "ip": "192.0.2.53",
    "port": 22,
    "username": "automation",
    "auth": { "type": "password", "password": "..." }
  }
}

enable_password is read only if a device actually needs it — an account that is already privilege 15 lands at # and needs no secondary escalation.

Use a different file from the Junos gateway's. Separate containers holding separate credentials is the reason the servers are split at all: a bug in this one cannot reach your firewalls.

Container uid. The image creates a uid-1000 passwd entry deliberately. scrapli's system transport execs the ssh binary, and OpenSSH refuses to run when the calling uid has no /etc/passwd entry — the symptom is a misleading "EOF reading from transport" rather than anything naming the cause.

Running it

docker build -t cisco-iosxe-mcp .
docker run --rm \
  -v "$PWD/secrets/devices.json:/app/config/devices.json:ro" \
  --user 1000:1000 \
  -p 127.0.0.1:8004:8004 \
  cisco-iosxe-mcp
Variable Default Meaning
CISCO_DEVICES_FILE /app/config/devices.json Device inventory path
CISCO_PREVIEW_TTL 1800 Seconds a preview stays applicable
MCP_HOST 127.0.0.1 Bind address (the image sets 0.0.0.0)
MCP_PORT 8004 Bind port

Tests

docker run --rm cisco-iosxe-mcp python test_arg_validation.py
docker run --rm cisco-iosxe-mcp python test_reload.py

Both are offline — no device contact, no credentials needed. test_reload.py replays the exact bytes a real IOS-XE box sent for reload in 5, reload cancel and the confirmation prompts, including the case where the save prompt never appears.

Tool reference

TOOLS.md has the tool-by-tool reference: arguments, what each one returns, which need approval, and the reasoning behind the gate design.

License

Apache-2.0. See LICENSE.

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选