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(照做即可)
- 安装进 profile(三选一,把占位符换成实际值):
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
- 确认写进了 profile(
bundles里应出现dsh-ikuai-mcp):
node -e 'const p=require(process.env.HOME+"/.dsh/profiles/web/package.json");console.log(p.dsh.profile.bundles.filter(b=>b.includes("ikuai")))'
重启 dsh web。这一步交给用户做,agent 不要
kill宿主进程(会中断当前会话)。 装了 dshmarket 的话,界面上的「待重启」提示旁有一键重启。配置连接参数(见下一节)。不要猜 IP 和密码,问用户要。
验证:调用
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
验证
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 的调用默认被拒。开启方式二选一,都不用重启:
- 推荐:设置 → 凭据中心 添加
IKUAI_ALLOW_WRITES = 1(5s 生效;改回0立刻恢复只读) - 给 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。
自测
离线,不需要路由器也不需要凭据:
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。作者:MingShi350。
API 用法与 func_name 清单参考 beck-8/ikuai-mcp(MIT,© 2026 Beck),
本项目是独立的 Node 实现,详见 THIRD-PARTY-NOTICES.md。
No comments yet. Be the first to write one.