Bundle
dsh-ikuai-mcp
DSH plugin: control iKuai (爱快) soft routers over their JSON API. Zero-dependency Node MCP stdio server exposing 11 read tools plus a write-gated generic API call; iKuai credentials live in the DSH credential store (mcp__ikuai__*).
- Source
- MingShi350
- License
- MIT
- Updated
- Updated 9 days ago
Readme
# dsh-ikuai-mcp
在 DeepSeek Harness (DSH) 里控制爱快 (iKuai) 软路由。纯 Node 零依赖的 MCP stdio server + DSH 宿主半:
模型侧出现 11 个 `mcp__ikuai__*` 工具,另有 3 个宿主工具(`ikuai_credentials_status` /
`ikuai_set_credentials` / `ikuai_ping`)。写操作默认关闭。
- 只读:系统状态、LAN/WAN 接口、在线终端、DHCP 地址池与绑定、DNS、静态路由、VLAN、DDNS、端口映射
- 通用读写 `ikuai_api_call`:需 `IKUAI_ALLOW_WRITES=1`,且每次调用传 `confirm: true`
- 连接参数存 DSH 凭据中心,改密码/换 IP 不用重启 DSH
- 默认 `https://192.168.1.1`(爱快出厂 LAN 地址),用户名 `admin`
---
## 安装
> 用法:把这个仓库地址(或本地目录)发给你 DSH 里的 AI,说一句「按 README 的安装一节把 dsh-ikuai-mcp 装好」。
### 交给 DSH 里的 AI(照做即可)
1. **安装进 profile**(三选一,把占位符换成实际值):
```bash
dsh plugin --profile web add /绝对路径/dsh-ikuai-mcp # 本地目录(必须是绝对路径)
dsh plugin --profile web add github:MingShi350/dsh-ikuai-mcp # GitHub
dsh plugin --profile web add dsh-ikuai-mcp # npm
```
2. **确认写进了 profile**(`bundles` 里应出现 `dsh-ikuai-mcp`):
```bash
node -e 'const p=require(process.env.HOME+"/.dsh/profiles/web/package.json");console.log(p.dsh.profile.bundles.filter(b=>b.includes("ikuai")))'
```
3. **重启 dsh web**。这一步交给用户做,agent 不要 `kill` 宿主进程(会中断当前会话)。
装了 dshmarket 的话,界面上的「待重启」提示旁有一键重启。
4. **配置连接参数**(见下一节)。**不要猜 IP 和密码,问用户要。**
5. **验证**:调用 `ikuai_credentials_status`,再调用 `ikuai_ping`。
### 判断装好没有
| 现象 | 含义 | 处理 |
| --- | --- | --- |
| 工具列表里出现 11 个 `mcp__ikuai__*` | 装好了 | 去配置连接参数 |
| 只有 `ikuai_credentials_status` / `ikuai_set_credentials` / `ikuai_ping` | 宿主半起来了,MCP 那一行没起 | 看 `mcp-server:ikuai` 开关是否被关;确认第 2 步的 `bundles` 里有它;确认重启过 |
| 一个都没有 | 插件没装上 | 回到第 1 步 |
### 原理(手工安装时才需要看)
`package.json` 的 `dsh.bundle.patch` 指向 `cordis.patch.yml`,里面的 `- insert:` 两行分别是宿主半和
`@deepseek-ai/dsh-mcp-client`(以 stdio 挂载 `server/ikuai-mcp-server.mjs`)。`dsh plugin add` 会自动把包名
追加进 `~/.dsh/profiles/<profile>/dsh.profile.bundles`,启动时装配;不想装包也可以手工把那两行并进
profile 的 `cordis.patch.yml`。
---
## 配置:改爱快 IP / 加账号密码
取值优先级:**环境变量 > DSH 凭据中心 > 默认值**。默认值:
| 键 | 默认值 | 说明 |
| --- | --- | --- |
| `IKUAI_URL` | `https://192.168.1.1` | 爱快 web 管理地址;只写 `192.168.1.1` 会自动补 `https://` |
| `IKUAI_USERNAME` | `admin` | web 登录用户名 |
| `IKUAI_PASSWORD` | 空 | 必须配,否则工具直接报「未配置 IKUAI_PASSWORD」 |
### 改 IP
先用浏览器确认管理地址能打开:默认 `192.168.1.1`;改过 LAN 网段就用改后的地址;端口不是 80/443 要带上,
例如 `http://192.168.1.1:81`。然后任选一种:
**A. 让 agent 调工具写进凭据中心(不用重启)**
```
ikuai_set_credentials { "url": "192.168.1.1", "username": "admin", "password": "你的web登录密码" }
```
会先归一化地址 → 再用这组参数试连一次 → 成功才写入。连不上就不落盘(确需强存加 `"allowUnverified": true`)。
写入后 **5 秒内生效**。
**B. 在 GUI 里填(推荐,密码不进对话记录)**
设置 → 凭据中心 → 新增 `IKUAI_URL`(值如 `192.168.1.1`),同样方式加 `IKUAI_USERNAME`、`IKUAI_PASSWORD`。
**C. 环境变量**
给启动 DSH 的进程设 `IKUAI_URL=http://192.168.1.1`,需重启。注意环境变量**优先于**凭据中心,
设了之后在凭据中心改同名值不生效。
### 加账号密码
密码就是你登录爱快 web 管理页的那个密码。
- **推荐**:设置 → 凭据中心 → 加 `IKUAI_PASSWORD`(明文只存 `~/.dsh/.credentials.yaml`,权限 0600,不进对话记录)
- 或者调 `ikuai_set_credentials { "password": "..." }` —— 该参数是明文,**会留在会话记录里**,能用 GUI 就用 GUI
### 验证
```text
ikuai_credentials_status → 四项生效值与来源(env / 凭据中心 / 默认值)
ikuai_ping → ✅ 登录成功:192.168.1.1(用户 admin)
mcp__ikuai__ikuai_status → CPU / 内存 / 在线终端数
```
`ikuai_ping` 结果对照:
| 返回 | 含义 |
| --- | --- |
| `✅ 登录成功:…` | 通了 |
| `❌ 登录失败:code=1005 账号或密码错误` | 用户名/密码不对 |
| `❌ 连接失败:connect ECONNREFUSED …` | 地址或端口不对 |
| `❌ …响应不是 JSON(地址可能不是爱快 web 管理端口)` | 这个端口不是爱快管理页 |
### 什么时候要重启
| 改的是 | 重启? |
| --- | --- |
| 凭据中心里的 `IKUAI_*` | 不用(每次调用重读,5s 缓存) |
| `server/*.mjs` 代码 | 重挂 MCP 子进程:能力面板把 `mcp-server:ikuai` 关掉再打开,或 kill `server/ikuai-mcp-server.mjs`(配了 reconnect 会自动拉起) |
| `lib/index.mjs` 或 `cordis.patch.yml` | 重启 dsh web |
---
## 写权限(默认只读)
任何非 `show/get/list/query/search` 的调用默认被拒。开启方式二选一,都不用重启:
1. **推荐**:设置 → 凭据中心 添加 `IKUAI_ALLOW_WRITES = 1`(5s 生效;改回 `0` 立刻恢复只读)
2. 给 DSH 进程设 `IKUAI_ALLOW_WRITES=1`(需重启)
开启后每次写仍要传 `"confirm": true`;插件不提供「让模型自己开写权限」的工具。写之前先 `show` 拿原记录
(含 `id`/`uuid`),改字段后 `edit` 回写。排序参数必须大写(`ORDER_BY` + `ORDER`),小写会被静默忽略。
---
## 工具清单
| 工具 | `func_name` | 说明 |
| --- | --- | --- |
| `ikuai_status` | `homepage` | CPU/内存/温度/在线终端数/连接数/运行时长/WAN 线路 |
| `ikuai_interfaces` | `lan` | 物理端口、上下线、netinfo(内外网 IP/网关)、VLAN 失败项 |
| `ikuai_online_devices` | `monitor_lanip` | 在线终端:IP/MAC/名称/流量/连接数;分页 + `order_by`/`order` |
| `ikuai_dhcp_pools` | `dhcp_server` | 各 LAN/VLAN 地址池、租期、网关、DNS |
| `ikuai_dhcp_bindings` | `dhcp_static` | 静态绑定 + 动态租约混合列表(`static_status`: 1=静态) |
| `ikuai_dns_config` | `dns` | 本机 DNS 开关、上游 DNS、代理规则、缓存 |
| `ikuai_static_routes` | `static_rt` + `static_rt_table` | 用户静态路由规则 + 生效路由表 |
| `ikuai_vlan_config` | `vlan` | VLAN ID/名称/成员端口/tag |
| `ikuai_ddns_config` | `ddns` | DDNS 配置与最近解析 IP(密码/AK 已脱敏) |
| `ikuai_port_mapping` | `dnat` + `netmap` + `upnpd_leases` | 端口映射、1:1 映射、UPnP 租约 |
| `ikuai_api_call` | 任意 | 通用读写兜底(ACL/QoS/流控/域名黑名单/syslog 等) |
**V3 → V4 模块名**:V4 改了名,用旧名会 `code=1003 Access denied` ——
`dhcp_addr_bind`→`dhcp_static`、`port_mapping`→`dnat`、`upnp`→`upnpd`、`static_routing`→`static_rt`、
`mac_bind`→`acl_mac`/`mac_comment`。插件会自动回退候选名。
注意 V4 对不存在的模块也回同样的 `1003`,无法与「无权限」区分。
---
## 安全
- 爱快用自签证书,客户端必须放开证书校验;**只在受信内网用**,不要指向公网设备。
- 密码明文存 `~/.dsh/.credentials.yaml`(0600)。插件不把凭据写进 `process.env`。
- 结果按字段名**尽力**脱敏:`pass|pwd|secret|token|credential|api_key|access_key`、以 `key` 结尾的字段,
以及 `LTAI…`/`AKIA…` 形式的云 AccessKeyId;不认识的字段名原样返回,别当脱敏网关用。
- 写操作能改坏网络(DHCP、路由、端口映射),所以默认只读 + 每次 `confirm`。
---
## 自测
离线,不需要路由器也不需要凭据:
```bash
npm test
node tests/mock-test.mjs # 握手、11 工具、会话过期重登、写请求不重放、写闸门、脱敏、坏地址不崩
node tests/host-test.mjs # 宿主半:env 不被污染、来源标注、set_credentials 校验与先试连后落盘
```
---
## 排错
| 现象 | 处理 |
| --- | --- |
| 看不到 `mcp__ikuai__*` | 能力面板 `mcp-server:ikuai` 是否被关;`bundles` 里有没有它;是否重启过 |
| 报「未配置 IKUAI_PASSWORD」 | 凭据中心里加 `IKUAI_PASSWORD` |
| 报 `code=1005` | 用户名/密码不对;若该值来自环境变量,改完要重启 |
| 报 `ECONNREFUSED` / 超时 | 地址或端口不对,先确认浏览器能打开该地址 |
| 改配置没生效 | 凭据中心的值 5s 内生效;若存在同名环境变量,它会盖住凭据中心 |
| 写操作被拒 | 默认只读,见「写权限」;并确认传了 `confirm: true` |
---
## 已知限制
- 写操作只有通用透传,没有为 DHCP/DNS/路由写专用写工具(字段名随固件变化)。
- 未覆盖 Docker / QEMU / 行为审计 / AC 管理 / SD-WAN,用 `ikuai_api_call` 直接调 `func_name`。
- 会话 10 分钟重登一次;爱快并发登录会互相顶号,别同时开着 web UI 做写操作。
- 部分字段是设备回吐的原始字节(如 DHCP 租约的 `hostname`),按 UTF-8 解可能是乱码。
- 大结果不裁剪:`ikuai_online_devices` 默认 100 行 × 约 50 字段,按需调小 `limit`。
- 仅在 iKuai V4 (4.0.311 x64) 上完整实测;V3 走候选名回退,未逐项验证。
---
## 许可与致谢
MIT,见 [LICENSE](LICENSE)。作者:[MingShi350](https://github.com/MingShi350)。
API 用法与 `func_name` 清单参考 [beck-8/ikuai-mcp](https://github.com/beck-8/ikuai-mcp)(MIT,© 2026 Beck),
本项目是独立的 Node 实现,详见 [THIRD-PARTY-NOTICES.md](THIRD-PARTY-NOTICES.md)。
Install
dsh plugin --profile web add github:MingShi350/dsh-ikuai-mcp
Profile: web
With the hub plugin installed, ask your agent to install it by name — it resolves the same plan shown here.
dsh plugin --profile web add github:stvlynn/dsh.fish#path:packages/dsh-plugin-hub
install dsh-ikuai-mcp from the hub
- This source has no pinned commit, so a later push upstream changes what installs. Prefer pinning a commit.