Metadata-Version: 2.1
Name: ensp-nexus
Version: 0.2.1
Summary: A safe, user-friendly MCP and web control plane for Huawei eNSP
Author: NetOpt
License: BSL-1.1
Requires-Python: >=3.11
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Education
Classifier: Intended Audience :: Information Technology
Classifier: Operating System :: Microsoft :: Windows
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: System :: Networking
Requires-Dist: cryptography>=43.0
Requires-Dist: fastapi>=0.115
Requires-Dist: mcp[cli]>=1.26,<2
Requires-Dist: pydantic>=2.10
Requires-Dist: python-multipart>=0.0.18
Requires-Dist: uvicorn[standard]>=0.34
Project-URL: Homepage, https://github.com/quwentao2005/ensp-nexus
Description-Content-Type: text/markdown

<!--
mcp-name: io.github.quwentao2005/ensp-nexus
-->

# eNSP Nexus

eNSP Nexus 是一个本地优先、面向网络工程师与 AI Agent 的 Huawei eNSP
实验控制平面。它把实验文件、拓扑、设备配置、Console 会话、Web 终端与 MCP
工具统一在一个长期运行的工作区中。

当前版本的首选入口不是盲扫端口，而是导入完整 eNSP 实验文件夹：

1. 优先解析 `.topo`；
2. 读取每台设备的 `com_port`，精确探测非连续 Console 端口；
3. 按拓扑 UUID 优先匹配 `.efz/.zip/.cfg/.txt/.xml` 配置；
4. 自动命名、识别型号并保存在线设备；
5. 在 Web 拓扑中共享同一条后端 Console 会话；
6. 将结构化配置和完整文本暴露给 MCP，供 AI 分析与排障。

范围扫描和手动添加仍然保留，作为拓扑缺失或特殊实验的备用入口。

## 核心设计

### 实验文件是入口，不是永远正确的真相

- `.topo` 提供设备 UUID、名称、型号、坐标、链路、接口索引和 `com_port`。
- 配置匹配优先级为：UUID 目录 → `sysname` 精确匹配 → 规范化名称 → 路径名称。
- 同一个配置文件不会被错误复用给多台设备。
- 导入配置保存为 `imported` 快照；通过 Console 抓取的配置保存为 `live` 快照。
- 对设备执行非只读命令后，相关快照自动标记为 `stale`，不会继续伪装成当前状态。
- 用户或 AI 停止输入配置命令 3 秒后，倒计时会按设备防抖并静默刷新；期间继续输入会重置
  计时。Web 只显示小型同步状态，不弹出批量进度面板。
- `nexus_refresh_live_config` 与批量刷新使用隔离的临时采集连接，不依赖、不读写共享终端，
  获取配置并保存后立即断开。
- eNSP 会把同一 Console 端口的多客户端 I/O 镜像给已有客户端；刷新期间 API 会锁住该
  设备的共享写入口并抑制这段镜像输出，尾部字节排空后立即恢复，所以共享会话 ID、输出
  sequence 和用户终端内容保持不变，期间到达的用户命令只会短暂排队而不会丢失。
- MCP 按本机路径导入的实验可一键重新读取原文件夹；浏览器导入则需要用户重新选择文件夹。

### 一台设备只有一条共享会话

后端按设备 ID 去重连接。Web 拓扑悬浮终端、多设备终端页面和 MCP Agent
看到的是同一会话、同一输出序列和同一缓冲区：

- 单击拓扑设备：未连接时连接，已连接时直接复用；
- 多次打开同一设备不会重复 Telnet；
- 多个可拖动、可缩放的悬浮终端可以同时存在；
- 终端页可以多选设备、批量连接、批量下发和批量关闭；
- 只有明确的断开操作才关闭会话，切页或关闭悬浮窗不会断线；
- 每个终端不再设置转发输入框：聚焦终端画布后直接键入原始 Telnet 会话；
- 终端解释设备返回的回车、换行、退格和覆盖写入，输入光标跟随当前提示符，
  不再固定在窗口底部；
- 支持 Enter、退格、Tab、方向键、`Ctrl+C`、`Ctrl+Z` 和剪贴板粘贴；
- 选中文字后可以右键复制，右键菜单也可直接把剪贴板内容粘贴进当前会话；
- 连接建立时不会自动发送回车。

长驻 API 是唯一 Console 连接所有者。stdio MCP 的连接、命令、断开和实时配置
刷新都会通过本机 API 执行，不会在 MCP 子进程中另建 Telnet。交互终端严格共享
一条长连接；配置刷新则由 API 短暂建立隔离采集连接并在保存后关闭。因此使用 Agent
前应先运行 `scripts/start.ps1`。

### 终端直发，但操作过程完整留痕

发送前审查已经正式取消。用户和 AI 的输入直接进入共享 Telnet 会话，避免交互式
登录、密码和翻页场景被额外回车破坏。系统仍保留两层记录：

- 会话时间线按发生顺序保存连接、输入、命令、配置刷新和断开动作；
- 全局审计保存操作者、目标、风险分类和执行结果；
- 检测到密码提示时，下一次输入只记录 `<PASSWORD REDACTED>`，不保存明文；
- 配置类输入会把相应配置快照标记为 `stale`，供批量刷新筛选。
- 连续配置输入会重置 3 秒静默同步计时；完整刷新与单设备刷新保留用于处理 eNSP
  或其他 Telnet 客户端产生的外部变更。

## Web 工作台

### 首页 / 实验导入

- 文件夹选择器保留目录结构；
- `.topo` 始终优先上传；
- 分阶段上传显示文件数、字节数和处理状态；
- 导入完成后显示拓扑规模、配置覆盖率、精确端口探测结果与在线设备数。

### 拓扑工作区

- 根据 eNSP 坐标绘制设备和链路；
- “沉浸式全屏”让拓扑占满显示器，同时保留悬浮终端、配置抽屉和拓扑控件；
- 空白处拖拽平移、滚轮按鼠标位置缩放，并支持一键适应；
- 端口标签和拓扑备注可以分别显示或隐藏；
- 设备节点使用较小的半透明图标，链路两端显示可悬浮的接口圆点；
- 悬浮设备查看型号、Console、会话和配置新鲜度；悬浮端点查看二层/三层接口配置；
- 单击设备打开共享悬浮终端；
- 双击设备打开完整配置抽屉；
- 配置抽屉显示来源、采集时间、当前/过期状态，并支持内容搜索；
- 可批量刷新所有在线设备，或只刷新执行命令后标记为过期的设备；
- 日常 Web/MCP 配置会自动同步，因此界面不再提供容易造成重复操作的“刷新已变更配置”按钮；
- 可重新读取 MCP 导入实验的原始路径，浏览器导入实验则重新选择文件夹。

### 设备发现

- 首选按最新拓扑 `com_port` 精确探测；
- 保留自定义主机、起止端口的范围扫描；
- 保留手动添加；
- 扫描结果支持多选和批量保存；
- 已保存按钮为红色“已保存”，悬浮后变灰并显示“取消保存”；
- 设备清单支持多选、批量连接、批量关闭会话和批量取消保存。

### 多设备共享终端

- 多设备多窗格监看；
- 多选后批量连接、下发和断开；
- 每台设备持续显示共享输出，不因界面切换而重连；
- 窗格高度受控，长输出只在各自终端内部滚动；
- 单设备终端为原生直输，多设备批量下发仍保留独立的广播编辑器；
- 每条会话可打开带时间戳的操作时间线。

### 全局工作空间

- 左侧导航可折叠，状态会保存在本机浏览器；
- 拓扑悬浮终端使用视口级定位，可拖到拓扑以外的页面空间，切页不会关闭或重连；
- 全局“笔”按钮展开纯文本草稿本，可整理多行命令、复制全部并在本机持久保存；
- 设置页可新增、编辑和淘汰排障问题分类，每类都拥有自己的关键词与回答结构。

### 缓存优先排障与经验沉淀

- Agent 首先读取当前拓扑和最新配置缓存，按症状提取相关配置段，避免每次都串行执行实时命令；
- DHCP 等分类具有可验证的语义规则，例如接口 VPN 实例与全局地址池空间不一致；
- 只有缓存过期、证据冲突或置信度不足时才进入实时深度模式，并解释每条命令如何缩小范围；
- 无法完全确认或用于教学时，会给出抓包位置、过滤目标和预期报文；
- 排障回答在当前会话中完成，结尾询问是否生成经验文档；经用户确认后生成带接口号、
  IP/VLAN 标注拓扑、推理过程、协议原理、修复验证与抓包结果的自包含 HTML。

### 排障知识库

- Web 的“排障知识库”页面统一浏览自动生成的 HTML 经验文档和用户 Markdown 笔记；
- `.data/knowledge/experiences/` 和 `.data/knowledge/notes/` 是始终存在的默认目录：
  AI 未指定分类时分别把经验 HTML 和个人 Markdown 保存到这里；
- 用户可在知识库根目录或任意子目录中创建分类目录和 Markdown；左侧目录树的悬浮
  `+` 菜单负责新建与导入，不提供手工新建 HTML；
- 支持把目录或文档拖到另一目录，也支持从系统文件管理器直接拖入 `.html` / `.md`；
  导入内容会验证格式、大小和编码并统一保存为 UTF-8；
- 启动时会把旧版 `.data/troubleshooting-experiences/` 一次性迁移到新目录并删除旧目录，
  后续不再读取或使用旧路径；
- HTML 使用禁用脚本的隔离预览，Markdown 按纯文本解析，不执行嵌入的 HTML 或脚本；
- 页面提供紧凑搜索、目录折叠和右侧 Markdown 编辑器。

知识库使用 UTF-8、相对路径和 Python `pathlib`，可在不同安装路径及 Windows、
Linux、macOS 间复制使用。将整个 `.data/knowledge/` 复制到另一台机器的数据目录即可。
但 Huawei eNSP 桌面程序本身只支持 Windows；非 Windows 主机可以运行 MCP/API/Web
和阅读知识库，若要实际连接设备，则仍需访问一台正在运行 eNSP Console 的 Windows 主机。

## 支持的实验文件

| 类型 | 用途 |
|---|---|
| `.topo` | 设备、UUID、型号、坐标、链路、接口索引、`com_port` |
| `.efz` | 解析内嵌 ZIP 或原始 VRP 配置文本 |
| `.zip` | 查找 `vrpcfg`、`.cfg`、`.txt` 等配置内容 |
| `.cfg` / `.txt` | VRP 配置解析与全文索引 |
| `.xml` | PC/终端 IP、掩码、网关和 DNS |

VRP 解析结果包括 `sysname`、接口地址与描述、VLAN、静态路由、OSPF、ACL、
DHCP 地址池，以及 STP/LACP/VRRP/BGP/ISIS/MPLS/VPN 等特征标记。完整配置文本
也会保留，避免结构化解析丢失厂商命令细节。

## MCP 能力

服务器当前提供 31 个工具。

### 实验、拓扑与配置

| 工具 | 作用 |
|---|---|
| `nexus_import_lab_folder` | 从本机路径导入完整实验，按 UUID 匹配配置并按 `com_port` 精确探测 |
| `nexus_latest_lab` | 获取最新实验、设备、配置覆盖和共享会话 |
| `nexus_get_device_config` | 按拓扑 UUID 或设备名读取 `best/imported/live` 完整配置 |
| `nexus_search_configs` | 对最新实验配置全文搜索并返回命中行 |
| `nexus_network_config_analysis` | 汇总拓扑、接口、VLAN、路由协议和快照新鲜度 |
| `nexus_refresh_live_config` | 隔离临时连接采集并保存实时配置，用完即关 |
| `nexus_refresh_lab_configs` | 并发临时连接刷新全部或仅过期设备的实时配置 |
| `nexus_reload_lab_source` | 重新读取 MCP 导入实验的原始文件夹 |
| `nexus_import_topology` | 单独解析 XML/JSON/文本拓扑 |
| `nexus_topology_report` | 输出摘要、完整数据、Markdown 或 Mermaid |
| `nexus_prepare_troubleshooting` | 缓存优先分类问题并返回配置证据、确定性发现与深度模式建议 |
| `nexus_list_troubleshooting_categories` | 列出可动态维护的问题分类和回答结构 |
| `nexus_upsert_troubleshooting_category` | 新增或更新分类、关键词和回答结构 |
| `nexus_delete_troubleshooting_category` | 淘汰不合适的问题分类 |
| `nexus_save_troubleshooting_experience` | 用户确认后生成带标注拓扑的排障经验 HTML |

### 设备、会话与命令

| 工具 | 作用 |
|---|---|
| `nexus_start_web_console` | 从 MCP 自身定位项目，幂等启动 API/Web，并可直接打开浏览器 |
| `nexus_quick_start` | 返回当前推荐工作流 |
| `nexus_system_status` | 检查设备、实验、会话和直发契约 |
| `nexus_scan_ensp` | 备用的自定义范围扫描 |
| `nexus_register_device` | 手动保存或更新设备 |
| `nexus_list_devices` | 列出设备资产 |
| `nexus_connect` | 建立或复用设备唯一会话 |
| `nexus_list_sessions` | 列出共享会话 |
| `nexus_disconnect` | 明确断开会话 |
| `nexus_run_readonly` | 执行只读诊断 |
| `nexus_run_command` | 直接执行共享会话命令并记录时间线 |
| `nexus_terminal_input` | 精确发送文本、空回车、空格或控制字符 |
| `nexus_session_timeline` | 按时间查看用户与 AI 的会话操作顺序 |
| `nexus_add_credential` | 本机加密保存凭据 |
| `nexus_list_credentials` | 列出脱敏凭据元数据 |
| `nexus_audit_log` | 查看脱敏操作记录 |

资源：

- `nexus://topology/latest`
- `nexus://lab/latest`
- `nexus://configs/{topology_device_id}`
- `nexus://system/safety`

Prompt：

- `diagnose_ensp_device`

### MCP 自启动控制台

只要 stdio MCP 已经能被 Agent 调用，Agent 就不需要知道项目安装路径，也不应该扫描磁盘
寻找 `start.ps1`。推荐流程：

1. 调用 `nexus_system_status`；
2. 如果 `session_broker_online` 或 `web_console_online` 为 `false`，直接调用
   `nexus_start_web_console(open_browser=true)`；
3. 工具会根据 MCP 模块位置、MCP 工作目录和数据目录解析项目根目录，只启动缺失的服务，
   等待 API 与 Web 均可访问后返回 `http://localhost:3000/`；
4. 重复调用是幂等的，不会为已经在线的 API/Web 创建重复进程；
5. 启动失败时，返回缺失依赖或受限长度的启动日志摘要，不再让 Agent 盲目搜索文件系统。

首次安装仍需执行一次 `scripts/setup.ps1`。自启动工具负责日常运行与恢复，不会在后台擅自
下载安装依赖。

Windows 生产模式统一由 `scripts/start-production.mjs` 启动。该入口会修正 vinext 0.0.50
在 Windows 上用反斜杠建立静态资源索引、导致 `/assets/*.css` 与 `/assets/*.js` 返回
404 的问题；MCP 自启动、`scripts/start.ps1` 和 `pnpm start` 都使用同一入口。

## 安装与启动

要求：

- Windows 10/11
- Python 3.11 或 3.12
- Node.js 22+
- Huawei eNSP

```powershell
cd C:\study\app_dev\MCP_dev\NetOpt\ensp-nexus
powershell -ExecutionPolicy Bypass -File .\scripts\setup.ps1
.\scripts\start.ps1
```

Web 控制台和 API：

```text
http://localhost:3000
http://127.0.0.1:8765
http://127.0.0.1:8765/docs
```

停止服务：

```powershell
.\scripts\stop.ps1
```

## 配置 MCP 客户端

```json
{
  "mcpServers": {
    "ensp-nexus": {
      "command": "C:\\study\\app_dev\\MCP_dev\\NetOpt\\ensp-nexus\\.venv\\Scripts\\python.exe",
      "args": ["-m", "ensp_nexus.mcp_server"],
      "cwd": "C:\\study\\app_dev\\MCP_dev\\NetOpt\\ensp-nexus",
      "env": {
        "ENSP_NEXUS_DATA_DIR": "C:\\study\\app_dev\\MCP_dev\\NetOpt\\ensp-nexus\\.data",
        "ENSP_NEXUS_API_BASE": "http://127.0.0.1:8765"
      }
    }
  }
}
```

stdio 模式不会向 stdout 输出普通日志，避免污染 MCP 协议流。

## HTTP API 分组

- `/api/labs/upload/*`：分阶段文件夹上传、取消和完成导入；
- `/api/labs/latest`、`/api/labs/{id}/discover`、`reload-source`：实验、精确探测与源重载；
- `/api/configs/*`：配置读取、搜索、单台与批量实时刷新；
- `/api/knowledge/tree/*`：目录树新建、文档导入及目录/文档移动；
- `/api/devices/batch*`：批量保存和删除；
- `/api/sessions/*/input`、`batch-input`、`timeline`：直通输入与会话时间线；
- `/api/sessions/batch*`：批量连接、直通下发与断开；
- `/api/safety-mode`：兼容旧客户端，始终返回审查机制已退役；
- `/api/audit`：脱敏审计。

完整请求模型和响应结构以 [Swagger](http://127.0.0.1:8765/docs) 为准。

## 配置与安全边界

| 变量 | 默认值 | 说明 |
|---|---|---|
| `ENSP_NEXUS_HOST` | `127.0.0.1` | API 监听地址 |
| `ENSP_NEXUS_PORT` | `8765` | API 端口 |
| `ENSP_NEXUS_DATA_DIR` | `.data` | SQLite 和主密钥目录 |
| `ENSP_NEXUS_API_TOKEN` | 空 | 远程绑定时强制要求 |
| `ENSP_NEXUS_API_BASE` | `http://127.0.0.1:8765` | stdio MCP 访问唯一会话代理 |
| `ENSP_NEXUS_SCAN_MAX_PORTS` | `512` | 单次范围扫描上限 |
| `ENSP_NEXUS_CONFIRM_TTL` | `120` | 变更令牌有效秒数 |
| `ENSP_NEXUS_ALLOWED_NETWORKS` | 回环和 RFC1918 | 探测目标 allowlist |

远程绑定但未设置 Token 时，服务会拒绝启动。上传文件限制为实验总计 500 MB、
单文件 128 MB，路径会经过目录穿越检查。密码使用本机 Fernet 主密钥加密，API、
MCP 和审计列表均不会返回密码明文。

运行数据位于：

```text
.data/
├── ensp-nexus.sqlite3
└── master.key
```

请一起备份数据库和 `master.key`，并且不要提交 `.data`。

## 验证

```powershell
.\.venv\Scripts\python.exe -m unittest discover -s tests_py -v
.\.venv\Scripts\python.exe -m pytest -q
.\.venv\Scripts\python.exe -m ruff check --no-cache src tests_py scripts\mcp_smoke.py
pnpm run lint
pnpm run build
.\.venv\Scripts\python.exe scripts\mcp_smoke.py
.\scripts\doctor.ps1
```

`mcp_smoke.py` 默认使用临时数据库完成真实 stdio 握手、工具/资源枚举和工具调用；
如需检查指定数据目录，可设置 `ENSP_NEXUS_SMOKE_DATA_DIR`。

## 已知边界

- 浏览器不能把文件夹路径直接交给后端，因此 Web 采用保留相对路径的分阶段上传；
  MCP 可直接导入 Agent 有权限读取的本机目录。
- 关闭浏览器不会关闭 Console，会话由后端进程生命周期管理；服务重启后需要重新连接。
- 当前实时性策略是“命令后标记过期 + 按需抓取实时配置”，不会对所有设备持续轮询，
  以免实验规模较大时造成 Console 拥塞。
- Web 批量刷新提供设备级阶段、百分比、成功/失败状态与取消入口；同一设备的并发刷新
  会自动串行化，避免重复采集互相干扰。
- 复杂 AAA、验证码、SSH 跳板机不属于 eNSP Console 默认场景。
- 真实生产网络仍应增加组织级 RBAC、集中 Secret Store、审批流、回滚和变更窗口。
