@yiyunet/dsh-mcp-client-manager

toolstested: passnpmMIT

DSH plugin: a settings panel to list, add, rewrite and toggle @deepseek-ai/dsh-mcp-client MCP rows — no more hand-writing them into cordis.patch.yml. Zero build, zero runtime dependencies.

下载量 / Downloads
896
依赖体积 / node_modules
0.18 MB
测试时间 / Tested
2026-11-07
DSH 版本 / Version
0.2.2-rc.1

Install

dsh plugin --profile web add @yiyunet/dsh-mcp-client-manager

Sandbox test results

StageResult
1 install✓
2 list✓
3 mount✓
4 boot—

Four stages run in an isolated sandbox: install (network on) → list → mount → boot (last three with no network).

README

@yiyunet/dsh-mcp-client-manager

简体中文 | [English](README.en.md)

DSH 插件:在 设置 → ANB 工具 提供「MCP 客户端」面板,用来管理挂在 @deepseek-ai/dsh-mcp-client

下的 MCP 服务器行 —— 列出 / 添加 / 改写 / 启停 / 删除,点保存才写盘,写完不重启宿主。

本插件最初为作者自用而写;现已发布到 npm(@yiyunet/dsh-mcp-client-manager),源码 MIT、按需自取。
能力边界与已知限制全部写在本文档里,不承诺文档之外的行为。

变更历史

版本 · 变更

1.1.0 · 设置面板并入「ANB 工具」栏目:面板不再独占一个设置导航项,改为注册进 anb.tool.tab(order 30);栏目壳(settings.section,id anb-toolbox)由本插件内置——随插件自带,不需要另外安装。壳是运行时单例:已有壳时让位、不重复登记,登记壳的插件被禁用后由本插件接管。栏目内标题行与说明文案含指向作者主页的链接。只装本插件时栏目里只有一个标签(选中态),不出现空壳。宿主侧零改动;升级须重启宿主

1.0.4 · 修表格横向溢出(实测反馈):根因是 1.0.3 给操作列加的 min-width: 300,把表格最小宽度顶过容器 → 尾部横线溢出卡片。改法:① 去掉该强制宽度,列宽回归内容自适应(修改|禁用|不可删仍同排,因为行内 flex 仍 nowrap);② 表格外套一层 overflow-x: auto 兜底——万一再超也只在本卡片内横向滚动;③ 服务名 / 行 id 加 ellipsis 截断(max-width: 200,悬停看全文);④ 文案:不可删(手写) → 不可删(悬停解释保留:手写行不能删、可改用禁用)

1.0.3 · ① 操作列强制单行(后于 1.0.4 取消强制宽度);② 修正 1.0.2 挪位编辑引入的括号配平错误;③ 端点/命令不在列表显示(会撑宽首列)——只保留在「修改」表单的 url 提示 + 悬停 title;首列小字恢复为仅「原手写行」

1.0.2 · ① 脱敏:回传浏览器的路径改为符号化($DSH_HOME\…),不再出现含用户名的绝对路径(list/state 均适用,单测加断言);② 表格规整:删除「端点 / 命令」整列,单元格禁折行;③ 手写行的「不可删」提示移到「禁用/启用」按钮之后(受管行为 修改 | 禁用 | [撤销覆盖] | 删除,手写行为 修改 | 禁用 | 不可删 | [撤销覆盖])

1.0.1 · 修 F6:状态列误读官方字段(应读 fiberPhase,且 FiberState 是数字枚举)→ 正常行被误报成"挂载/重连中";状态口径改大白话(已启用 / 已启用·未发现工具 / 已禁用 / 加载失败 / 未加载 / 配置冲突),工具数收进悬停提示;顶部备注重写为普通用户可读,并动态显示受管行的写入路径(list 回传 paths.homePatch)

1.0.0 · 首发:受管行(自有层)+ 手写行(官方通道)、三级 id 冲突检测、serverName 查重、漂移检测与两个逃生口、撤销覆盖、密钥永不出宿主


1. 它怎么工作(一层一张网)

层 · 文件 · 谁写 · 作用

真源(受管清单) · $DSH_HOME/mcp-manager/servers.json · 本插件 · 面板管理的服务器清单(含 url / env 等密钥字段,0600)

生成物(自有层) · $DSH_HOME/cordis.patch.yml · 本插件,全量重写 · 把受管行渲染成 MCP 行;home 层在 HMR 监听范围内 → 落盘即热生效

手写层 · profiles/<profile>/cordis.patch.yml · 手工编辑 / DSH 官方配置编辑器 · 不由本插件直接改写:改写与启停走官方通道(ctx.configEditor / ctx.pluginManager),而官方的写入落点就是本文件(见下)

两条写回路径,互不越界

🔎 找文件时别找错地方(本条最常被问)
本面板添加/删除的行写在 $DSH_HOME\cordis.patch.yml($DSH_HOME = DSH 安装/数据根,即 %USERPROFILE%\.dsh)——
不在 profiles\<profile>\cordis.patch.yml 里。
profiles\<profile>\cordis.patch.yml 只会有:① 你手写的那两行;② 面板改写它们时由 DSH 官方配置编辑器追加的覆盖行。
面板顶部显示的就是这个符号化路径(不显示含用户名的绝对路径)。
  • 受管行(行 id 前缀 mcpx-):新增 / 改写 / 启停 / 删除 → 写自有层文件。
  • 手写行(例如 mcp-sorftime、mcp-myserver):只能改写凭据族字段与启用/禁用;

不能删除、不能改 serverName / transport(要改请手工编辑 profile patch)。

改写走 ctx.configEditor.edit()(原子写 + 失败回滚 + 被更高层覆盖则拒写),

启停走 ctx.pluginManager.setPluginEnabled()。

⚠️ 手写行改写的落点(实测过一次,务必知道):官方配置编辑器只认顶层 - id: 行,且明确排除 insert 行

(DSH 源码 packages/boot/config-editor/src/index.ts:117-128)。我们的两行嵌在 - insert: [...] 里 → 于是:

  • 首次改写该行:在 profiles/<profile>/cordis.patch.yml 末尾追加一条顶层覆盖行(- id: … / name: … / config: …),

原 insert 行保持不变;覆盖行在同文件内靠后 → 优先级更高 → 生效的是它。

  • 之后再改同一行:命中那条覆盖行并原地更新,不会越堆越多。
  • 面板上该行会显示「手写」+已覆盖 标记,并多出一个「撤销覆盖」按钮 ——

它调用官方语义(next === inherited 时移除覆盖行),把该行还原成 insert 行的原值。

  • 后果提醒:面板没改过的行,你直接编辑 insert 行立刻生效;已被面板覆盖的行,改 insert 行不生效(被覆盖行压住),要先「撤销覆盖」。

为什么不让面板直接改 profile patch:官方编辑服务够不着嵌在 - insert: [...] 里的行,

自写 YAML 要自带解析器,而且文件写坏 = 下次启动起不来;自有层既避免解析(我们只写自己生成的内容),

又天然被 HMR 监听。


2. 安全口径(设计硬约束)

1. url 永不回传浏览器 —— 面板只显示 协议//主机/…,不含路径、查询串或任何 key 片段。

2. stdio 的 env 取值永不回传 —— 只回传键名与"已设置"。

3. 凭据族字段留空 = 保留原值(未改不重写),要改必须整段重填:url、command、env 属此类。

4. serverName 保存前查重(活动行 + 受管清单 + 本次草稿);重复会让后加载的那条加载失败。

5. 受管 id 强制 mcpx- 前缀 + 三级 id 冲突检测(活动行 / 受管清单 / 手写层文本弱扫)——

同 id 双声明会让官方把该行判成 unaddressable 并锁死开关。

6. 不做协议层探活:状态列 = 行阶段 + 工具数(mcp__<serverName>__* 计数),不代表链路健康

(断线重连期间工具仍会列出、调用才失败,这是 mcp-client 的既定行为)。


3. 安装

已发布 npm(最省事):dsh plugin --profile web add @yiyunet/dsh-mcp-client-manager;下列方式任选。

方式 A · 本地目录(推荐:你手上这份 clone / 解压出来的目录)

侧栏 插件 → 添加插件 → 粘贴本仓库所在目录的本地绝对路径 → 安装
# 若偏爱命令行(<本仓库> = 本插件目录的绝对路径)
dsh plugin --profile web add "<本仓库>"

方式 B · 直接从 GitHub 源安装

dsh plugin --profile web add github:yiyunet/dsh-mcp-client-manager
本包没有任何 prepare / 构建脚本,因此 git 源安装不会触发"构建脚本批准"那一关。
⚠️ 推测(未实测):方式 B 的可用性取决于你的包管理器版本与 dsh plugin 对 git 说明符的解析;失败请回方式 A。

本 profile patchReload: live,且 bundles 变化在 HMR 监听范围内 → 通常无需重启;

若设置里没出现「MCP 客户端」,重启一次宿主。

若 dsh 不在 PATH:可用 DSH 检出内的 CLI 入口 node <DSH 检出>/apps/cli/lib/bin.js plugin …,
或用 npx -p @deepseek-ai/dsh dsh plugin … 之类的等价形式(同样推测,未实测)。

4. 生效与验证

# · 动作 · 预期观察

1 · 打开 设置 → ANB 工具 · 栏目里出现「MCP 客户端」标签(只装本插件时它是唯一标签);标题行右侧有小字「AI原生突围」

2 · 打开面板 · 列出手写行(来源=手写,服务名下注「原手写行」),状态=已启用或已启用 · 未发现工具;端点掩码/命令已收进"服务名"格的悬停提示(表格只留 5 列:服务名 / 行 id / 来源 / 状态 / 操作)

3 · 添加(http 三字段)→ 保存 · $DSH_HOME/cordis.patch.yml 出现;列表新增 mcpx-*;MCP 工具在该行挂载后可用

4 · 添加(stdio,command/args/env)→ 保存 · 同上;env 值落盘但不回显

5 · 改手写行 url → 保存 · 来源列变「手写 + 已覆盖」;profiles/web/cordis.patch.yml 末尾多出一条顶层 - id: … / config: … 覆盖行(官方行为),原 insert 行不动;值立即生效

6 · 再改同一行一次 · 覆盖行原地更新,不新增第二条

7 · 点该行「撤销覆盖」 · 覆盖行被移除,值回到 insert 的原值;来源列恢复「手写」

8 · 禁用/启用手写行 · profile patch 出现/更新 disabled 覆盖

9 · 删除受管行 · 自有层文件该行消失,工具消失(手写行的"删除"按钮不存在)

10 · 漂移演练:手工编辑 $DSH_HOME/cordis.patch.yml · 面板转只读 + 两个处置按钮(重建 / 清空清单)

只读核对(⚠️ 输出含 key,别外传):

dsh --profile web --dump-config

纯函数自测 + 集成冒烟(不需要 DSH、不需要网络、不碰真实 $DSH_HOME):

cd <本仓库>
# 先做语法预检(零副作用,几秒钟;这一步能拦住任何手写笔误)
node --check plugin-src/host/index.mjs
node --check plugin-src/host/store.mjs
node --check plugin-src/host/validate.mjs
node --check plugin-src/host/adapter.mjs
node --check plugin-src/client/client.js
# 再跑三份测试(⚠️ 必须点明文件:Node 24 下 `node --test test` 会把 test 当模块加载而报 MODULE_NOT_FOUND)
node --test test/validate.test.mjs test/store.test.mjs test/host-smoke.mjs

host-smoke.mjs 会造一个假宿主(临时目录当 DSH_HOME)真跑一遍:list / 新增 / 查重 / 启停 / 删除

…(truncated)

Rendered from the README published on npm. Formatted only, not edited.

Versions

Published on npm::3,最后更新 2026-11-03

Links

GitHub · Homepage · npm

Same category