DSH Plugins Marketplace

DSH Plugins

Plugins

/

dsh-mcp-manager

d

dsh-mcp-manager

Manifest valid

DeepSeek Harness bundle: manage MCP servers — list, probe, add from pasted project references, toggle, remove, rotate credentials. Official dsh-mcp-client contract compliant.

UI (client)hasBundlePatch

@dsh-contrib/dsh-mcp-manager

English | 中文

对登记在 DSH patch 文件中的 MCP 服务器条目提供搜索、查看、探测、安装、编辑、启停、删除与凭据轮换。条目格式遵循官方 @deepseek-ai/dsh-mcp-client 的配置契约,全部写入经过同一条带守卫的管线。

概述

在 DSH 中新增一台 MCP 服务器通常意味着手工编辑 ~/.dsh/cordis.patch.yml:新增条目必须置于 insert: 列表内,serverName 在作用域内唯一,凭据不得以明文写入 patch。任一处不符都会导致条目不被挂载,或使配置重载失败。

本包把这一过程收敛为受校验的操作。写入先经过 DSH 自身加载器与官方字段规则校验,通过后才以原子方式落盘并保留 .bak 备份;未通过校验的候选内容不会触及实际文件。

同一套引擎驱动三个界面:Agent 工具(mcp_manager_*)、命令行(cli/mcp.js)与 Web 面板。凭据轮换仅在 Agent 工具与命令行中提供,面板不允许写入原始 !!js 表达式。

市场以官方 MCP Registry 为唯一目录源:搜索、看详情、安装,写入走的仍是同一条管线。市场不引入任何绕过路径,也不假装条目经过审核——registry 是任何人可发布的。

目录


使用本包

安装:把下面一行交给 agent,或在 Web 侧边栏的插件页中安装同一地址。

plugin_manager install_bundle https://github.com/shiliu153/dsh-mcp-manager

安装完成后 mcp_manager_* 工具即可用。验证方式是调用 mcp_manager_list:该调用返回列表即表示插件已挂载,列表为空同样算通过——本包不预设用户已登记任何服务器,新环境下的空列表是正常结果。

支持的输入格式

mcp_manager_add 与命令行 add 接受四种粘贴形式,serverName 由输入自动推导,可在预演阶段调整。

粘贴内容示例
npm 包名@modelcontextprotocol/server-memory
GitHub 仓库https://github.com/modelcontextprotocol/servers
MCP 端点https://mcp.example.com/mcp
JSON 配置{"command":"npx","args":["-y","@upstash/context7-mcp"]}

Agent 工具

安装后以下九个工具对 agent 可用。写入类工具默认只执行预演:先返回将要写入的内容与各项校验结果,确认无误后再以 confirm: true 重新调用。

工具用途需确认
mcp_manager_list列出已登记服务器,凭据值已掩码—
mcp_manager_search搜索官方 MCP Registry,报告可安装性、执行面与缺口—
mcp_manager_probe对单台或全部服务器执行真实握手—
mcp_manager_validate按官方 mcp-client 规则校验条目—
mcp_manager_credential定位、掩码显示或轮换凭据文件—
mcp_manager_add从粘贴的地址新增服务器;source: "registry" 时输入按 registry 名解释是
mcp_manager_update替换某条目的 config: 子树是
mcp_manager_toggle启用或禁用条目是
mcp_manager_remove移除条目是

命令行

零外部依赖,与 Agent 工具共用同一套引擎,无需 harness 即可运行。

node cli/mcp.js list [--json]
node cli/mcp.js probe [--id <id>] [--timeout 60]
node cli/mcp.js search <query> [--limit 20] [--cursor <c>] [--json]
node cli/mcp.js install <registry-name> [--version <v>] [--yes] [--no-probe]
node cli/mcp.js add "<npm-package | github-url | mcp-url | json>" [--yes] [--no-probe]
node cli/mcp.js show <id> [--json] [--masked]
node cli/mcp.js edit <id> [--config <file>] [--yes]      # 省略 --config 时读取 stdin
node cli/mcp.js enable|disable <id> --yes
node cli/mcp.js remove <id> --yes
node cli/mcp.js credential <id> get|set <value>
node cli/mcp.js validate <id>
node cli/mcp.js schema
参数含义
--file <path>指定 patch 文件;缺省为 $DSH_HOME/cordis.patch.yml 或 ~/.dsh/cordis.patch.yml。
--json输出机器可读结果(list、show、search)。
--yes跳过确认。
--maskedshow 时以占位符替换 !!js 表达式。
--registry-base <url>search / install 使用的 registry 基址,缺省为官方 registry。

退出码:0 成功,1 失败,2 用法错误。

Web 面板

启用本包后,侧边栏插件页下的 DSH MCP 管理器 列出已登记服务器。每行显示状态点、id、serverName、传输方式,以及命令行或 URL。

状态点直接读取 harness 的 MCP 资源注册表,因此「已配置」与「实际已连接」在界面上是两个不同的状态:

显示悬停提示含义
绿色圆点已连接服务器进程存活,可正常调用
橙色圆点已启用 · 未连接条目已启用,但未连上
灰色圆点已禁用条目被停用
空心圆环连接状态不可用无法读取 harness 的实时注册表

每行可执行的操作:

  • 探测——执行真实握手,报告工具数量或失败原因。列表不做自动探测,因此可以即时打开;面板头部的一键探测可一次并发探测全部服务器。
  • 编辑——展开文本域,内容为该行自身的 config: 子树 YAML,含注释、键序与 !!js 引用。校验并预览按官方规则预演变更,写入通过带守卫的管线应用变更并探测结果。
  • 启用 / 禁用开关,以及一次内联确认的删除。
  • 新增服务器——粘贴上述四种格式之一,点击解析生成预览,确认将要追加的 YAML 内容后再写入。
  • 刷新——重新读取 patch 文件与实时连接状态。

市场

面板顶部有两个标签:已安装(上述视图)与市场。市场是只读的发现面,不触盘写。

搜索走官方 registry。它只匹配名称(反域名,如 ai.ankimcp/anki-mcp-server),不匹配描述——所以搜 anki 也会带回 banking-*。返回页会在本地按标题与描述重排,把精确命中提上来,界面上也如实标注这一点。

点开一条结果,执行面是不可折叠的:

  • stdio 条目逐字显示将要执行的完整命令行,等宽字体,例如 npx -y @ankimcp/anki-mcp-server@0.27.0;
  • 远程条目逐字显示将要连接的 URL;
  • 运行时不在 PATH 上时红字标注。

同一屏还列出出处(发布者、registry 名、版本、仓库与主页链接、是否已弃用)与还缺哪些凭据。

勾选框只在 stdio 条目上出现。 npx -y <任意包> 是在本机执行任意代码;远程 URL 只是把查询发给第三方,与使用任何 Web API 同级。对两者都要求勾选,只会训练用户无脑点过,反而削弱真正重要的那一道。需要凭据、运行时缺失、条目已弃用都用醒目警告表达,不额外加闸。

市场不写入凭据。 需要秘密的条目照常可装,但秘密字段被省略而不是填占位值——patch 里永远不会出现假凭据。装完后首次探测会返回 401,这正是"你还没补凭据"的准确信号;用 dsh-mcp credential <id> set <值> 或让 agent 调用 mcp_manager_credential 补上。

不支持的条目直接不显示:sse 传输(DSH 的 mcp-client 不认),以及 cargo / nuget / mcpb 包类型。

已安装标记与版本漂移:市场按推导出的 serverName(首选)或执行面(用户改过名字时)认出已经装过的服务器,并标出「已安装」。漂移只在条目钉住版本时才可能判断——市场安装的条目会钉版本,而 add 路径写的是不钉版本的 npx -y <pkg>,后者会如实显示「版本未钉住,无法比对」,不会假装已是最新。更新走既有的 mcp_manager_update 管线,仍需确认。

面板通过 ctx.connection.registerFetchRoute 在 /api/dsh-mcp-manager/ 下注册精确的 Fetch 路由,因此 harness 自身的 Host/Origin 校验与浏览器会话认证先于任何处理函数执行。面板自身不实现信任边界,所有写入都经过与命令行相同的带守卫管线。


理解实现

实现细节——点击展开

写入的配置条目

条目严格遵循官方 @deepseek-ai/dsh-mcp-client 契约:

- insert:
    - id: mcp-<serverName>
      name: '@deepseek-ai/dsh-mcp-client'
      config:
        serverName: <serverName>      # [A-Za-z0-9_-]{1,32},需唯一
        transport: stdio              # 或 streamable-http
        command: npx                  # 仅 stdio
        args: ['-y', '<package>']
        failOnStartupError: true      # 本包写入的条目默认值

新增服务器必须置于独立的 insert: 列表内。顶层裸条目用于按 id 覆盖已有条目;若其不匹配任何现有条目,加载器会告警并跳过,因此追加一个裸条目不会挂载新服务器。

密钥不写入 patch:工具将其存入凭据文件,并以 !!js 表达式引用,与官方 GitHub 条目采用同一模式。DSH 会热重载 patch,新增或修改的服务器在当前会话即可使用。

编辑操作只替换指定条目的 config: 子树,其余内容保持不变:条目上方的注释块、- id:、name: 与 disabled: 行,以及其他所有条目都逐字节一致。读出一个子树后原样写回可精确复现文件内容,这一点由测试套件断言。

安全模型

  • 写入目标为 home 覆盖层 ~/.dsh/cordis.patch.yml。官方组合顺序:bundle patches → profile patch → home patch → --patch。
  • 显式确认:每次变更都要求 confirm: true 或 --yes;删除、启停与编辑保留前一份文件的 .bak。
  • 四重校验:候选内容须能在 DSH 自身加载器下解析、符合官方字段规则、不含硬编码密钥,且所有 serverName 保持唯一。
  • 写入前后双重把关:新增操作在写入前后各校验一次——候选行必须位于 insert 列表内、能通过加载器解析出 serverName、且不与已登记项重名。写入后针对已持久化的行再次执行同一检查,因此 probe OK 只可能描述确实存在于文件中的条目。
  • 并发写入保护:面板在编辑期间以原始文本持有内容,写入时回传所读文件的 mtime;文件在此期间被修改则以 file_changed 拒绝,不覆盖对方的改动。
  • 探测只读:探测不启动浏览器,也不将凭据发送到服务器自身端点之外的任何位置。
  • !!js 求值:探测按 harness 的方式先解析 !!js 值再发送。加载器返回的是惰性的 { __jsExpr } 标记对象,直接转发会使以表达式写入的凭据以 Authorization: [object Object] 到达服务器并返回 400,将有效凭据误报为格式错误。无法求值的表达式按名称报告,不转发。

所有写入共用同一条带守卫的管线:

读取原文件 → 在候选副本上执行文本手术 → DSH 加载器校验 → mtime 复核 → .bak 备份 → 原子替换

项目结构

lib/ 为共享实现,cli/、index.js 与 client.js 是它的三种入口。

index.js            宿主插件入口:在 ctx.tools 注册 mcp_manager_* 工具,
                    并在存在 web profile 时通过 ctx.connection 注册面板路由
client.js           浏览器端面板(单文件,由 /plugins/<id>/client.js 直接提供)
cli/mcp.js          命令行入口
lib/                共享引擎
  dump.js           经 DSH 自身加载器结构化读取 patch 文件
  jsexpr.js         !!js 值的运行时求值
  patchfile.js      带守卫的写入管线(手术 → 校验 → mtime 复核 → .bak → 原子替换)
  surgery.js        保留注释的文本手术:增删条目、启停、替换 config 子树
  rules.js          官方 dsh-mcp-client 条目字段规则
  resolve.js        将粘贴的项目地址解析为官方 patch 条目
  registry.js       与官方 MCP Registry 对话(超时、响应体上限、重试、TTL 缓存)
  market.js         registry 条目 → 候选条目;已安装识别与版本漂移(纯函数)
  probe.js          真实 MCP 握手(stdio 与 streamable-http)
  rows.js           行筛选与凭据掩码(命令行、宿主工具与面板共用同一实现)
  update.js         编辑策略:!!js 占位符协议与语义闸门
  server.js         面板的 Fetch 路由
  tools-bridge.js   官方工具定义形态与管理器库之间的桥接
  subprocess.js     最小化同步子进程辅助
locale/             面板文案(en / zh)
assets/skills/      随包提供的 Agent 技能定义(置于 ~/.dsh/skills/ 后生效)
cordis.patch.yml    本包自身的 patch,用于注册 dsh-mcp-manager
docs/official/      从已安装的 DSH app.asar 中提取的官方规则

rows.js 的掩码实现只有一份:若出现漂移副本,凭据会泄漏到浏览器。lib/ 保持零外部依赖,便于测试与在命令行中独立运行。


进一步探索

  • 官方 @deepseek-ai/dsh-mcp-client 条目规则——docs/official/。
  • 本包的设计与实施计划——docs/specs/、docs/plans/,端到端实测记录见 docs/records/。
  • 随包 Agent 技能——assets/skills/dsh-mcp-manager/SKILL.md。

已知限制与延期工作

  • 面板不写入 !!js 表达式。Loader 在运行时对表达式求值,等同于在 harness 进程中执行代码,因此面板只提交不透明占位符(Authorization: !!js «0»),由宿主原样回填。凭据轮换与表达式改动需经命令行或 Agent 工具。
  • 面板中携带硬编码密钥的条目为只读,需经命令行或 Agent 工具处理。
  • 版本漂移只能对钉住版本的条目判断。市场安装的条目会钉版本;add 路径与手工写入的 npx -y <pkg> 没有版本锚点,市场会显示「版本未钉住,无法比对」而不是猜一个结论。
  • 已安装识别是推断的,不是记录的。mcp-client 的 config 字段表固定,塞不进一个「来源」字段,所以市场靠 serverName 与执行面比对。用户既改了名字又改了 args 就会认不出来——这是漏报,不会误报。
  • 官方 registry 的搜索端点延迟波动很大。实测(2026-10-13)/v0/servers?search=… 单次耗时在 1.2s 到 30s 之间,并偶发 HTTP 500。因此默认超时为 30s 且对 5xx 重试一次;registry 不可达时市场显示离线,已安装视图与探测完全不受影响。
  • registry 的元数据可能是错的,市场无法识别。实测 ai.ankimcp/anki-mcp-server 声明 transport: {type: "stdio"},而该包实际是个绑定 127.0.0.1:3000 的 HTTP 服务器,从不读取 stdin——作为 stdio 条目必然失败。市场只能照抄 registry 的声明。这种情况下探测会给出提示:进程打印了 http(s) 端点却始终没有 stdio 应答,并附上该进程自己的输出。
  • 编辑只作用于条目的 config: 子树。id 与 name 不经此路径修改,disabled 由 mcp_manager_toggle 负责。
  • 本包自身的代码更新需要重启进程以加载新的 JavaScript 模块版本;HMR 只覆盖配置重载,不覆盖模块代码替换。
  • 命令行与 Agent 工具可以写入原始 !!js 文本,其信任级别与手工编辑 patch 文件相同。

失败行为

拒绝发生在写入之前,实际 patch 文件保持不变。

情形处理方式
候选内容无法通过 DSH 加载器解析拒绝写入,保留 .candidate 供查看;实际文件不变。
候选内容违反官方字段规则拒绝写入,只报告原因,删除 .candidate;实际文件不变。
候选内容含硬编码密钥同上。
候选 serverName 与已登记项重名拒绝写入并报告重名;实际文件逐字节不变。
面板写入时文件已被外部修改以 file_changed 拒绝,提示重新加载后再改。
探测失败报告进程启动失败、超时、HTTP 状态码或工具列表;不修改任何内容。

探测失败不会改动条目,修复方式是按结果修正配置(启停、改配置、重新添加),而非重复添加同一 serverName——官方加载器在单一作用域内拒绝重名。


开发备注

维护者的工作上下文——点击展开
node --test "test/*.test.mjs"   # 296 个测试,零依赖
node -e "import('./scripts/check-bundle.mjs').then(m => console.log(m.checkBundle('.')))"

官方规则以 vendored 形式存放于 docs/official/,提取自已安装的 DSH app.asar,来源说明见 docs/official/README.md。

Comments

Loading…