netdiag-mcp
README.md
# netdiag-mcp
**把交换机、服务器、终端的命令行,变成智能体可以直接调用的诊断工具。**
一个基于 [Model Context Protocol](https://modelcontextprotocol.io) 的网络设备调试服务:通过 **SSH** 或
**串口 Console** 连上设备,自动识别厂商、自动翻页、把字节流清洗成可读文本,再以 **28 个 MCP 工具**
的形式暴露给 Claude Code / Cursor / Cherry Studio / 自研 Agent。
```
┌──────────────┐ MCP (stdio / HTTP) ┌──────────────┐ SSH / Serial ┌─────────────┐
│ 智能体/客户端 │ ◀────────────────────▶ │ netdiag-mcp │ ◀──────────────▶ │ 交换机/服务器 │
└──────────────┘ tools·resources·prompts└──────────────┘ 交互式 CLI └─────────────┘
```
---
## 为什么需要它
智能体默认只会「跑一条命令拿 stdout」,但网络设备不是这样工作的:
| 现实问题 | netdiag-mcp 的处理 |
|---|---|
| `display`/`show` 长输出停在 `---- More ----` | 自动送空格翻页,最多 `NETDIAG_MAX_PAGES` 次 |
| 输出里混着命令回显、ANSI 颜色、`\b` 覆盖 | 统一清洗,只留正文 |
| 设备不告诉你「打完了」 | 提示符正则识别 + 静默窗口(settle)双重判定 |
| 华为 `display` / 思科 `show` / 锐捷 `show ip route` 写法不同 | 厂商适配层把「看接口」「ping」等语义翻译成对应命令 |
| 部分设备只有 Console 口能用 | pyserial 串口传输 + 交互式登录(Username/Password/enable) |
| 中文设备输出是 GBK | UTF-8 → GB18030 → Big5 自适应解码 |
| 设备反问 `[Y/N]` / 要口令 | 不擅自回答,返回 `interactive_prompt` 交还给智能体 |
| 一条 `reload` 就能把生产网打瘫 | 三级命令分级 + 默认拦截破坏性命令 + 审计日志 |
---
## 特性
- **双传输**:SSH 交互式 shell(paramiko)与串口 Console(pyserial,支持 DTR/RTS、BREAK)
- **多厂商**:华为 VRP、H3C Comware、Cisco IOS/IOS-XE、Cisco NX-OS、锐捷 RGOS、Juniper Junos、Linux
- **会话常驻**:`session_id` 贯穿整个排障过程,登录态、`enable`、`system-view` 视图都保持
- **结构化诊断**:接口、ARP/MAC/路由表、ping/traceroute、日志、CPU/内存、运行配置,返回统一 JSON
- **一键巡检**:`health_check` 汇总「事实 + 疑点 + 建议下一步」,而不是丢一堆原始文本
- **阻塞等待**:`read_output(wait_for="login:")` 等设备重启回连,一次调用替代轮询
- **安全默认**:只读放行、写操作需显式开启、破坏性命令需二次确认,全程 JSONL 审计 + 凭据脱敏
- **配置下发预演**:`configure_commands(dry_run=true)` 先出计划与裁决,人确认后再执行
- **可测试**:内置 `FakeTransport` 假终端,无需真机即可验证翻页/提示符/编码逻辑(67 个单元测试)
---
## 快速开始
### 1. 安装依赖
```bash
cd "./MCP-网络检测工具"
pip install -r requirements.txt
# 或安装为命令:pip install -e .
```
### 2. 自检
```bash
python -m netdiag_mcp --selftest
```
会打印依赖版本、安全模式、设备清单来源、28 个已注册工具,并跑完单元测试。
### 3. 配置设备(可选)
```bash
copy config\devices.example.json config\devices.json # Windows
```
编辑 `config/devices.json`,把示例地址换成真实设备;口令建议写 `${环境变量名}` 占位符:
```json
{
"devices": {
"core-sw1": {
"transport": "ssh",
"host": "192.168.1.2",
"username": "netops",
"password": "${CORE_SW1_PASSWORD}",
"vendor": "huawei"
},
"console-router": {
"transport": "serial",
"serial_port": "COM6",
"baudrate": 9600,
"username": "admin",
"password": "${CONSOLE_R1_PASSWORD}"
}
}
}
```
### 4. 启动
```bash
python -m netdiag_mcp # stdio(给 MCP 客户端调用)
python -m netdiag_mcp --transport streamable-http --port 8931 # 远程共享
python -m netdiag_mcp --list-devices # 打印设备清单
python -m netdiag_mcp --list-ports # 找 Console 线接在哪个串口
```
---
## 接入第三方智能体
### Claude Desktop / Claude Code
`.mcp.json`(项目根)或 `claude_desktop_config.json`:
```json
{
"mcpServers": {
"netdiag": {
"command": "python",
"args": ["-m", "netdiag_mcp"],
"cwd": "D:/桌面/MCP-网络检测工具",
"env": {
"PYTHONPATH": "D:/桌面/MCP-网络检测工具",
"NETDIAG_MODE": "guarded",
"NETDIAG_ALLOW_WRITE": "0",
"CORE_SW1_PASSWORD": "你的口令"
}
}
}
}
```
### Cursor / Cherry Studio / 其他支持 MCP 的客户端
同上,填入 `command`、`args`、`cwd`、`env` 即可;不支持 `cwd` 的客户端请把
`d:/桌面/MCP-网络检测工具` 加进 `env.PYTHONPATH`。
### HTTP 模式(跨机器共享)
```bash
python -m netdiag_mcp --transport streamable-http --host 0.0.0.0 --port 8931
# 客户端连接 http://<本机IP>:8931/mcp
```
### 自研 Agent
任何 MCP SDK 都能直接用。接入后建议的第一步:
```text
list_devices → open_session(device="core-sw1") → health_check(session_id)
```
详见 [docs/integration.md](docs/integration.md)。
---
## 工具清单(28 个)
### 会话管理
| 工具 | 作用 |
|---|---|
| `server_info` | 运行配置、安全模式、日志位置、活跃会话数 |
| `list_devices` | 设备清单(脱敏) |
| `reload_devices` | 改完 devices.json 热加载 |
| `list_serial_ports` | 枚举本机串口(COM6、/dev/ttyUSB0…) |
| `open_session` | 建立 SSH/串口会话,自动识别厂商、关分页 |
| `list_sessions` / `close_session` | 查看 / 释放会话 |
| `login` | 自动应答 Username / Password / enable |
### 命令执行
| 工具 | 作用 |
|---|---|
| `send_command` | 执行单条命令,返回清洗后输出 |
| `send_commands` | 顺序批量执行,逐条返回 |
| `send_raw` | 原始输入(`y\n`、`\x03` Ctrl+C、`\x20` 翻页) |
| `read_output` | 读主动输出,可 `wait_for` 正则阻塞 |
| `get_history` | 回看本会话最近命令 |
| `save_transcript` | 导出会话全文 |
### 结构化诊断
| 工具 | 作用 |
|---|---|
| `detect_device` | 重新识别厂商/命令族/提示符 |
| `get_interfaces` | 接口状态;`detail=true` + `ifname` 看错包 |
| `run_ping` / `run_traceroute` | 从设备侧测连通性与路径 |
| `get_arp_table` / `get_mac_table` / `get_route_table` | ARP / MAC / 路由表 |
| `get_logs` | 日志缓冲区 |
| `get_system_health` | CPU / 内存 / 运行时长 |
| `get_running_config` | 运行配置(只读) |
| `run_diagnostic` | 按归一化动作名执行(VLAN/LLDP/NTP/环境…) |
| `health_check` | 一键巡检 + 疑点分析 |
### 变更(默认关闭)
| 工具 | 作用 |
|---|---|
| `configure_commands` | 配置视图批量下发,**默认 dry_run 预演** |
| `save_config` | 保存配置,需 `confirm=true` |
同时提供资源 `netdiag://devices`、`netdiag://sessions`、`netdiag://sessions/{session_id}`,
以及提示词 `network_troubleshoot`、`config_change_review`。
---
## 安全模型
| 级别 | 例子 | readonly | guarded(默认) | full |
|---|---|---|---|---|
| `read` | `display version`、`show ip route`、`ping`、`ip neigh` | ✅ | ✅ | ✅ |
| `unknown` | 厂商私有诊断命令 | ❌ | ✅ | ✅ |
| `write` | `system-view`、`configure terminal`、`save` | ❌ | 需 `NETDIAG_ALLOW_WRITE=1` | ✅ |
| `destructive` | `reload`、`erase`、`shutdown`、`write erase`、`rm -rf` | ❌ | 需 `allow_dangerous=true` | 需 `allow_dangerous=true` |
- 每条命令(含多行命令的每一行)都会过一遍裁决,取最高风险级别
- 被拒绝时返回结构化原因与开启方式,智能体能自己纠正而不是空转
- 审计日志:`logs/audit-YYYYMMDD.jsonl`(JSONL,可 `jq` 过滤)
- 会话全文:`logs/transcripts/<session_id>.log`
- 凭据脱敏:`password=`、`Authorization:`、PEM 私钥写入前一律 `[REDACTED]`
- 密码不落磁盘:`devices.json` 里写 `${ENV_NAME}`,由环境变量注入
---
## 典型场景
**1. 端口不通**
```text
open_session(device="core-sw1")
→ get_interfaces() # 端口 up/down、错包
→ get_mac_table() # 终端挂在哪个口
→ run_ping(target="10.0.0.5") # 从设备侧确认三层可达
→ get_logs() # 对应时间点的 up/down 记录
```
**2. 设备重启后等回连(串口)**
```text
open_session(transport="serial", serial_port="COM6", baudrate=9600)
send_command("reboot", allow_dangerous=true)
read_output(wait_for="login:|Username:", timeout=180) # 一次调用等 3 分钟,不轮询
login(username="admin", password="...")
```
**3. 改配置前预演**
```text
configure_commands(session_id, ["interface Gi0/1", "description uplink"], dry_run=true)
# 人工确认 plan 与拦截项
configure_commands(session_id, [...], dry_run=false)
get_running_config() # 复核
save_config(confirm=true)
```
---
## 目录结构
```
MCP-网络检测工具/
├── netdiag_mcp/
│ ├── __main__.py # CLI:stdio/http 启动、--selftest、--list-devices/ports
│ ├── server.py # FastMCP 装配:工具 + 资源 + 提示词 + 服务说明
│ ├── runtime.py # 单例:设置、设备清单、审计器、会话管理器
│ ├── config.py # NETDIAG_* 环境变量 + devices.json 加载(含 ${ENV} 展开)
│ ├── models.py # DeviceEntry / SessionInfo / CommandResult
│ ├── core/
│ │ ├── session.py # 交互引擎:提示符、翻页、静默判定、登录、会话管理
│ │ ├── cleaning.py # ANSI/回显/退格/分页符清洗,编码自适应,截断
│ │ ├── safety.py # 三级命令分级与模式门控
│ │ └── audit.py # JSONL 审计 + 会话全文 + 脱敏
│ ├── transports/ # ssh.py / serial.py / fake.py(测试) / base.py
│ ├── vendors/ # profiles.py(命令模板) / detect.py(指纹识别)
│ └── tools/ # session/exec/diag/config 四组 MCP 工具
├── config/devices.example.json
├── tests/ # 67 个单元测试(含假终端端到端)
├── docs/usage.md # 详细用法与厂商命令映射
├── docs/integration.md # 第三方智能体接入
└── .env.example
```
---
## 开发与测试
```bash
python -m unittest discover -s tests -t . -v # 全部单元测试
python -m netdiag_mcp --selftest # 依赖 + 配置 + 工具 + 测试
```
测试不需要真机:`netdiag_mcp/transports/fake.py` 可脚本化出一台虚拟交换机,
支持命令回显、`---- More ----` 分页、GBK 编码、交互式提问。
### 网段使用情况报告(离线链路)
`send_command` / `get_arp_table` / `get_mac_table` 这些只读工具已经把采集环节覆盖了,
把结果依次喂给本地脚本,即可产出「IP 使用明细 / 空闲地址 / 重复 MAC」多 Sheet 报告。
这类脚本与具体现场的网段划分、VLAN 规划强耦合,**不随本仓库发布**,
按需自行实现即可(参考实现思路见 `docs/usage.md`)。
---
## 已知限制
- 一次性 `read_output` 只保留本次调用期间到达的数据,不缓存历史输出(要用 `get_history` 或会话记录)
- 厂商私有命令未适配时返回明确提示,需要 `send_command` 手敲原生命令
- Windows 下串口为独占资源,串口助手/超级终端占用时无法打开(错误信息会列出可用端口)
- 暂不支持 Telnet、SNMP、NETCONF(见 Roadmap)
- HTTP 模式默认无认证,跨机器暴露前请置于内网或反向代理之后
## Roadmap
- [ ] Telnet 传输、SSH 跳板(ProxyJump)
- [ ] 命令输出结构化解析(接口表 → JSON 数组,供智能体直接计算)
- [ ] 批量多设备巡检(并发 + 汇总报告)
- [ ] 配置 diff 与回滚模板
- [ ] HTTP 模式接入 Bearer Token 认证
## 设计参考
- [raychao-oao/pty-mcp](https://github.com/raychao-oao/pty-mcp):`wait_for` 阻塞读输出、会话常驻、审计脱敏的设计范式
- [bvisible/mcp-ssh-manager](https://github.com/bvisible/mcp-ssh-manager):SSH 工具的会话管理与安全默认
- [modelcontextprotocol/python-sdk](https://github.com/modelcontextprotocol/python-sdk):FastMCP 工具/资源/提示词注册方式
## License
[MIT](LICENSE)
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues