dsh-mcp-manager
Verified@hualiong/dsh-mcp-manager · v0.1.7 · MIT · Web UI
MCP visual manager plugin for DeepSeek Harness: inspect installed/enabled MCP servers, add/remove, enable/disable and view live connection status from the web GUI.
Install
dsh plugin add @hualiong/dsh-mcp-manager Confirm the layer applied with dsh --profile default --dump-config — see the install guide.
Source
Tags
Readme
dsh-mcp-manager
查看列表 新增删除 启用停用 连接状态 OAuth 自动接入 中英双语DeepSeek Harness DSH Desktop设置 → MCP 一站管理 DSH 里的所有 MCP 服务器,
无需再手改
cordis.patch.yml —— 所有修改即改即生效(HMR 热应用)。
✨ 功能一览
- 📋 服务器列表:列出所有已装的 MCP 服务器 —— 名称、实时状态、传输方式、启用开关与已注册工具数
- ➕ 新增 / ➖ 删除:表单添加服务器,两种传输方式(
Streamable HTTP/STDIO);HTTP 支持请求头与超时,STDIO 支持命令、启动参数、环境变量与工作目录;带格式与重名校验,一键删除 - 🔐 OAuth 自动接入:HTTP 服务器不需要你回答「它要不要 OAuth」。保存时管理器只发一个不带凭据的探测请求,需要授权的行才交给 OAuth 桥(走 RFC 9728 发现 + 动态注册 + 浏览器授权 + 令牌刷新),其余行一律用 DSH 内置客户端——不装第三方插件也能管理所有非 OAuth 的 MCP
- 🔌 启用 / 停用:随时切换,工具随之热连接 / 热断开
- 📶 连接状态:每张卡片一个实时状态胶囊 ——
未加载/等待中/加载中/N 个工具(已连接)/无工具/失败/已停用/卸载中,由宿主事件流推送,无需手动刷新 - ✏️ 编辑:在卡片原位展开表单,保存即应用
- 🌏 多语言:界面文案跟随 DSH 语言(zh / en)实时切换
- 💾 持久化:所有修改写入 profile 的
cordis.patch.yml,重启后保留;页面底部显示文件路径
🧭 设计说明:为什么面板里没有 OAuth 开关
选哪个桥由插件自己判断,与用户无关。默认是内置客户端——只有探测确认需要 OAuth 的行,才会用到那个第三方插件:
| 传输方式 | 归属包 | 判定 |
|---|---|---|
STDIO |
@deepseek-ai/dsh-mcp-client(DSH 内置) |
直接判定,不发任何请求。子进程不可能需要 OAuth |
带 Authorization 请求头的 HTTP |
同上(内置) | 直接判定,不发任何请求。你自己带令牌,就不该让 OAuth 插手(Authorization 是 OAuth 令牌用的同一个头,SDK 会让行内配置覆盖它) |
| 其余 HTTP | 探测决定 | 401 + WWW-Authenticate: Bearer → @hualiong/dsh-oauth-mcp-client;其它任何响应 → 内置客户端 |
探测就是一个 5 秒超时的 GET,只看响应状态码与 WWW-Authenticate 头,不发 MCP 协议消息、不建会话、不带凭据。三种结果都会在页面上给一行提示。走偏了有两种自然的纠正方式,都不需要额外开关:
- 服务器要求 OAuth,但保存时它正好没连上(探测报「无法验证」,按内置客户端接入):等它可达后重新保存一次,归属会被重新判定并改写。
- 如果你自己的固定令牌服务器被判成了 OAuth:在表单里填上
Authorization请求头,该行立刻回到内置客户端。
两种情况在界面上完全一样,你不需要选。编辑会重新探测,所以归属也可能随之改变(这正是上面第一条纠正方式)。
没装 HTTP 桥怎么办:行照常写入(先加行、后装插件是合理路径),但会以「停用」状态保存——这样重启 DSH 时它不会去加载一个不存在的包。卡片上的开关同时会置灰、打不开(宿主也会拒绝这次开启),保存时页面直接给一行警告说明缺哪个包:
- 装
@hualiong/dsh-oauth-mcp-client - 重启 DSH
- 打开那个开关 —— 不需要重新保存这一行
普通 HTTP / STDIO / 自带令牌的行完全不碰这条路径。
其余 OAuth 相关的字段也不在表单里:
| 字段 | 默认 |
|---|---|
credentialRef |
由插件 ID 推导:转大写、非字母数字换成 _(如 oauth-mcp-cloudflare → OAUTH_MCP_CLOUDFLARE),必要时前缀 MCP_。令牌就存在这个 Harness 凭据名下 |
callbackPort |
固定 45179(不是随机端口,这样 redirect_uri 跨重启稳定,令牌不用反复重新注册)。被占用时退回临时端口并写一条警告;同时跑多个 OAuth 服务器请各自指定 callbackPort |
scope / authorizationTimeoutMs |
由服务器元数据 / 5 分钟兜底 |
想改这些值,直接编辑 profile 的 cordis.patch.yml —— 面板不做覆盖,编辑已有行时会原样保留。
🚀 安装
前置:DSH 已装好(dsh web 能正常运行)。
- 只想管理
STDIO或普通Streamable HTTP(含自带令牌的)MCP:什么都不用额外装,内置客户端就够了。 - 有需要 OAuth 授权的 HTTP MCP:再装 HTTP 桥,只有这些行会用到它:
dsh plugin --profile desktop add @hualiong/dsh-oauth-mcp-client
从本地 checkout 安装(开发 / 自用)
dsh plugin --profile desktop add "link:C:/绝对路径/dsh-mcp-manager"
也可以直接跑仓库里的脚本,它会自动识别本地 checkout 并用 link: 装好:
bash scripts/install.sh # macOS / Linux
powershell -ExecutionPolicy Bypass -File .\scripts\install.ps1 # Windows
从 npm 安装
dsh plugin --profile desktop add @hualiong/dsh-mcp-manager
dsh plugin add会自动完成三件事:登记依赖 → 识别包内dsh.bundle.patch(cordis.patch.yml)→ 注册进dsh.profile.bundles挂载,无需手改cordis.patch.yml。 profile 名按实际部署填:桌面版用desktop,命令行dsh web用web。
装完硬刷新浏览器(Cmd/Ctrl+Shift+R),打开 设置 → MCP 即可看到管理页。若未出现 MCP 页签,重启一次 DSH(宿主半边首次挂载需要)。
更新 / 卸载
本地 checkout:git pull 后 pnpm build。前端改动(lib/client.js)会被客户端 HMR 直接热替换,浏览器里立刻生效;宿主改动(lib/index.js)不在默认 HMR 监听范围内,需要重启一次 DSH(或在「设置 → 插件」里把本插件关掉再打开)。
npm 安装:重跑一次 dsh plugin --profile <profile> add @hualiong/dsh-mcp-manager。
卸载:dsh plugin --profile <profile> remove @hualiong/dsh-mcp-manager;若曾在 cordis.patch.yml 里手写过挂载行,一并删掉那段 - insert: ... mcp-manager ...。
常见问题
| 现象 | 原因与解决 |
|---|---|
| 装完没看到 MCP 页签 | 硬刷新(Cmd/Ctrl+Shift+R);仍没有就重启 DSH 一次(宿主半边首次挂载需要)。 |
| 页面出现两个 MCP 页签 | 双挂载:cordis.patch.yml 里还留着旧的手动挂载行,删掉那段 - insert: … mcp-manager …(scripts/remove-manual-mount.mjs 可代劳)。 |
| 新增需要授权的 HTTP 服务器 | 保存时会提示缺 @hualiong/dsh-oauth-mcp-client,该行以停用状态保存、开关置灰打不开;装上插件重启 DSH 后直接打开开关即可,不用重新保存。 |
需要浏览器授权的服务器停在 无工具 |
首次要授权:桥会自动打开默认浏览器,等待回环回调(默认 5 分钟);看宿主日志里的进度。授权完成后状态会自动变成 N 个工具。 |
| 改完配置没生效 | 所有修改都走 HMR 热应用,等 1–2 秒即自动刷新;页面右上角也可手动刷新。 |
| 想让某行固定用自己的令牌 | 在「请求头」里加一行,名称填 Authorization、值填 Bearer <token>,该行就会交给内置客户端,不参与 OAuth。 |
📖 使用说明
打开 设置 → MCP:
- 添加服务器:填写 插件 ID、
serverName、传输方式及对应字段。Streamable HTTP:URL(+ 请求头、超时);STDIO:命令、参数(每行一个)、环境变量(KEY=VALUE,每行一个)、工作目录。
- 面板做格式与重名校验,重复的 id /
serverName会被拒绝,错误直接标在对应字段下方。 - 编辑在卡片原位展开,表单字段与添加时完全一致;保存时会重新探测,因此归属桥可能在编辑后改变(这正是「服务器后来才可达」时的纠正路径)。
- 每张卡片显示实时状态、传输方式、被编辑的补丁文件路径,可执行 启用 / 停用、编辑、删除。
- 传输方式标签是写死的属性,不随连接状态变化;
未加载/等待中/加载中这类中间态只在状态标签上出现。
⚙️ 配置
插件在 loader 里的行配置支持一个可选字段:
| 字段 | 说明 |
|---|---|
patchFile |
要编辑的用户补丁层绝对路径。默认 $DSH_HOME/profiles/web/cordis.patch.yml。 |
桌面版建议在 profile 补丁里显式指定,例如:
- id: mcp-manager
name: '@hualiong/dsh-mcp-manager'
config:
patchFile: C:\Users\<你>\.dsh\profiles\desktop\cordis.patch.yml
🏗️ 项目结构
cordis.patch.yml # bundle 层:把本插件挂进 profile(dsh.bundle.patch 指向它)
src/
index.ts # 宿主半边:/mcp-manager 路由 + SSE 变更流 + 端点分发
patch.ts # cordis.patch.yml 读写(insert 行 / 覆盖行 / disabled)
detect.ts # 保存时的一次性探测:401 + Bearer 挑战 ⇒ 这行需要 OAuth
status.ts # 遍历 loader + tools,投影出每台服务器的状态与工具数
validate.ts # 与两个桥接包 schema 对齐的字段级校验
shared.ts # 主进程 / 浏览器共用类型与常量(含两个桥接包名)
client/
index.tsx # 浏览器半边:注册 设置 → MCP 页(settings.section 槽位)
McpManagerSection.tsx # 页面本体:服务器列表 + 添加/编辑表单
locales.ts # zh / en 文案
rpc.ts # 对 /mcp-manager 的 fetch 客户端
dsh-client-runtime.d.ts
scripts/
build.mjs # esbuild:lib/index.js(宿主)+ lib/client.js(ModuleLoader bundle)
install.sh / install.ps1
remove-manual-mount.mjs
test/ # node:test:路由契约、补丁读写、状态投影
lib/ # 构建产物(已入库,GitHub 源安装可直接用)
配套仓库:dsh-oauth-mcp-client(HTTP 桥,OAuth 感知,浏览器授权 + 凭据持久化)。
🔧 开发
pnpm install
pnpm build # esbuild:lib/index.js(宿主)+ lib/client.js(ModuleLoader bundle)
pnpm typecheck # tsc --noEmit(@deepseek-ai/* 的类型来自 devDependencies)
pnpm test # node --test:宿主半边的路由契约 / 补丁读写 / 状态投影
改了源码记得 pnpm build 并把新的 lib/ 一并提交(仓库刻意入库构建产物,方便 GitHub 源直接安装)。
许可证
MIT,见 LICENSE(保留原作者的版权声明)。