netops-mcp
by uxaaz
README.md
# netops-mcp
网络运维 MCP 工具包:**Node.js + Python 双栈实现**,把「设备巡检 → 日志诊断 → 配置草稿 → 工单建单/流转」沉淀成 5 个
结构化 MCP 工具,供 LLM / Agent 通过 [Model Context Protocol](https://modelcontextprotocol.io) 调用。
配套 Skill 说明见 [`skill/SKILL.md`](skill/SKILL.md)。
## 一键演示
```powershell
.\demo.ps1
```
依次跑 Node 13 用例、Python 13 用例、跨实现一致性比对(输出示例存档在 [`docs/demo-output.txt`](docs/demo-output.txt))。
## 为什么做这个
运维场景里模型最容易出两类错:一是**编造设备状态**("CPU 大概 60% 吧"),二是**凭印象写配置命令**。
本项目用工具把这些事实固定下来——设备台账、端口状态、配置模板、工单状态机都在代码里,模型只能查询和提交,
不能凭空生成。同时提供 Node.js 与 Python 两套同构实现,用来验证「同一套工具契约在不同运行时下行为一致」。
## 特性
- **5 个工具**:`net_inspect_device`、`net_cfg_draft`、`net_log_analyze`、`net_ticket_create`、`net_ticket_update`
- **手写 JSON-RPC 2.0 over stdio**:零运行时依赖(Node ≥ 18 / Python ≥ 3.10 标准库即可),协议版本 `2024-11-05`
- **结构化错误码**:`DEVICE_NOT_FOUND` / `INVALID_ARGS` / `INVALID_TRANSITION` / `TICKET_NOT_FOUND` / `TOOL_NOT_FOUND`
- **工单状态机**:`OPEN → ACK → FIXED → CLOSED`,非法跳转直接拒绝(`INVALID_TRANSITION`)
- **双栈一致性对拍**:13 条用例在两套实现上全部通过、字段与错误码一致,自动生成 `compat-report.json`
- **可测**:分发逻辑与 stdio 解耦(`createMcpServer` / `process_line`),测试不依赖子进程管道
## 目录结构
```
netops-mcp/
├── node/
│ ├── tools.mjs # 设备台账 + 5 个工具实现 + 工具 schema
│ ├── server.mjs # MCP 服务器:JSON-RPC over stdio,导出 createMcpServer 便于测试
│ └── test-client.mjs # 13 条用例(内存流驱动)
├── python/
│ ├── tools.py # 与 Node 侧同构的工具实现
│ ├── server.py # JSON-RPC 分发,导出 process_line 便于测试
│ └── test_client.py # 同一套 13 条用例
├── skill/
│ └── SKILL.md # Skill 描述:何时用、怎么调、错误码、Token 控制
├── compat_check.py # 双栈报告对拍 → compat-report.json
├── test-report.json # Node 侧测试报告
├── test-report-python.json# Python 侧测试报告
└── compat-report.json # 一致性报告
```
## 快速开始
### Node.js
```bash
node node/server.mjs # 启动 stdio 服务
node node/test-client.mjs # 跑测试(13 条)
```
### Python
```bash
python python/server.py # 启动 stdio 服务
python python/test_client.py # 跑测试(13 条)
python compat_check.py # 对拍两份报告,生成兼容性结论
```
### 手动发一条 JSON-RPC
```bash
echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"curl","version":"0"}}}' | node node/server.mjs
```
## 工具契约
| 工具 | 必填参数 | 成功返回(要点) |
| --- | --- | --- |
| `net_inspect_device` | `device` | `cpuPercent` `memPercent` `temperatureC` `optical{rxDbm}` `ports[]` `health` `warnings[]` |
| `net_cfg_draft` | `platform` `task` `spec` | `config`(配置文本) `warnings[]` |
| `net_log_analyze` | `log` | `categories[{category,evidence,suggestion}]` `summary` |
| `net_ticket_create` | `title` `severity` | `ticket{id,status,slaHours,history[]}` |
| `net_ticket_update` | `ticketId` `to` | 更新后的 `ticket` |
规则细节:
- 巡检:光模块收光功率 `< -15 dBm` 触发告警;存在 `down` 端口时 `health = WARN`
- 配置草稿:`vlanId` 限 1–4094;ACL 编号限 2000–3999;华为/思科语法分别生成;只产出文本,不下发
- 日志分析:5 条规则(链路断链 / 光模块光衰 / 通讯超时 / 弱口令与高危端口 / 物理层错包)
- 工单:`P1/P2/P3 → SLA 2/8/24 小时`,工单号 `WO-YYYYMMDD-NNN`
## 测试结果
Node.js 侧(`test-report.json`):
```
结果:13/13 通过
```
Python 侧(`test-report-python.json`):
```
结果:13/13 通过
```
双栈一致性(`compat-report.json`):
```
一致性:13/13(100.0%)
```
| # | 用例 | Node.js | Python | 一致 |
|---|------|---------|--------|------|
| 1 | initialize 握手 | PASS | PASS | ✅ |
| 2 | ping 保活 | PASS | PASS | ✅ |
| 3 | tools/list 返回 5 个工具且 schema 完整 | PASS | PASS | ✅ |
| 4 | net_inspect_device 正常设备 | PASS | PASS | ✅ |
| 5 | net_inspect_device 未知设备返回 DEVICE_NOT_FOUND | PASS | PASS | ✅ |
| 6 | net_cfg_draft 生成 VLAN 配置 | PASS | PASS | ✅ |
| 7 | 非法 vlanId 返回 INVALID_ARGS | PASS | PASS | ✅ |
| 8 | net_log_analyze 识别断链与光衰 | PASS | PASS | ✅ |
| 9 | net_ticket_create 创建 P1 工单(SLA 2h) | PASS | PASS | ✅ |
| 10 | 工单 OPEN→ACK 流转 | PASS | PASS | ✅ |
| 11 | 工单非法流转 ACK→CLOSED 被拒绝 | PASS | PASS | ✅ |
| 12 | 未知工具返回 TOOL_NOT_FOUND | PASS | PASS | ✅ |
| 13 | 非法 JSON 返回 -32700 Parse error | PASS | PASS | ✅ |
## 接入 MCP 客户端
Claude Desktop / Cursor 等客户端的 `mcpServers` 配置(Node 侧):
```json
{
"mcpServers": {
"netops-mcp": {
"command": "node",
"args": ["A:/path/to/netops-mcp/node/server.mjs"]
}
}
}
```
Python 侧:
```json
{
"mcpServers": {
"netops-mcp": {
"command": "python",
"args": ["A:/path/to/netops-mcp/python/server.py"]
}
}
}
```
## 设计说明
**为什么手写 JSON-RPC 而不引入官方 SDK?** MCP 的 stdio 传输就是「一行一个 JSON」,`initialize` / `ping` /
`tools/list` / `tools/call` 四个方法足够覆盖工具型服务。手写让协议细节(版本协商、错误码、通知不回包)透明可见,
也便于在同样 200 行内实现两套同构代码做对照。
**为什么把分发逻辑和 stdio 解耦?** 测试时不需要 spawn 子进程、不需要管道与超时控制,直接把字符串喂给
`createMcpServer` / `process_line` 就能断言返回,测试稳定且秒级完成。
**为什么设备数据是模拟的?** 这是作品集项目,不接触真实生产网络。台账结构参照华为/华三设备实际输出字段设计,
真实接入时只需替换 `tools.mjs` / `tools.py` 里 `DEVICES` 的取数来源(SSH/SNMP/Syslog),工具契约与上层 Agent 无需改动。
## 边界
- 不做真实设备连接与配置下发(`net_cfg_draft` 只产出文本)
- 工单存内存,进程结束即丢失;真实场景应接数据库与工单系统
- 未实现 `resources` / `prompts` 能力,仅 `tools`
- 未实现流式进度通知(`notifications/progress`)
## 后续计划
- 接 SQLite/PostgreSQL 持久化工单与巡检历史
- 增加 `net_scan_subnet`(批量巡检)与 `net_config_diff`(配置变更比对)
- 用官方 SDK 再实现一版,与本实现做协议层对拍
## License
MIT
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues