dsh-mcp-manager
Manage MCP servers from inside DeepSeek Harness (DSH): add / enable / disable / remove / reconnect, authorize them with OAuth 2.1, keep their tokens alive with scheduled and after-expiry renewal, and browse every tool each server exposes — with its description — in one settings page.
本项目由 DeepSeek V4.1 Flash 生成 / This project was generated by DeepSeek V4.1 Flash.
功能 · 安装 · 使用 · OAuth 2.1 · 自动续期 · Agent 工具 · 架构 · 安全 · 测试 · 许可
English summaryA DSH plugin that owns the whole MCP server lifecycle: a Settings page under
Settings → Plugins → MCP Servers, six agent-callable tools (mcp_manager_*), a loopback
HTTP bridge for the page, and a built-in OAuth 2.1 client (RFC 9728 discovery, RFC 8414/OIDC
metadata, RFC 7591 dynamic client registration, authorization code + PKCE S256, RFC 8707
resource, refresh, sign-out, paste-token fallback) with a token renewal policy that is editable
in the UI and also self-heals after expiry. Tokens live only in the Harness credential store.
Generated by DeepSeek V4.1 Flash; review before production use.
为什么需要它
DSH 官方的 @deepseek-ai/dsh-mcp-client 每个实例只连一个服务器,清单要手写进
cordis.patch.yml;它只支持静态 headers,不做 OAuth;token 过期后也不会续期,连接会
一直带着过期令牌,直到下一次调用 401。这个插件把这三件事补齐,并且不重新实现 MCP 协议——
它编排真正的 mcp-client 子插件,所以被管理的服务器在 Harness 里就是普通 MCP 工具。
功能
| 能力 | 说明 |
|---|---|
| 服务器管理 | 添加 / 编辑 / 启用 / 停用 / 重连 / 移除;stdio(command/args/env/cwd)与 streamable-http(url/headers)都支持 |
| 工具浏览 | 每个服务器展开后列出全部工具:公共名 mcp__<服务器>__<工具>、工具描述、入参名;页面与 agent 都能查 |
| OAuth 2.1 | 受保护资源发现、授权服务器元数据、动态客户端注册、授权码 + PKCE S256、一次性 state、resource 指示符、刷新、粘贴令牌兜底、退出授权 |
| 定时续期 | 后台按策略检查(默认每 5 分钟),在到期前(默认 10 分钟)自动换令牌并重连;策略可在页面上改 |
| 过期后自动续期 | 已过期的令牌下一轮必续;更关键的是 401 自愈——某次 mcp__* 调用被判未授权时立即换令牌重连,下一次调用恢复正常 |
| 失败退避 | 续期失败按 30s → 60s → 120s …(上限为检查间隔)重试,不会每轮都打授权服务器 |
| 如实状态 | connected / no-tools / disabled / error / connecting,不猜测"连接成功" |
| 给 agent 的能力 | 6 个工具:mcp_manager_list / add / remove / set_enabled / tools / oauth |
| 凭证安全 | OAuth token 只写进 DSH 凭据库,不进配置、不进日志、不进页面 |
安装
方式 1:一条命令
git clone https://github.com/nekojackie/dsh-mcp-manager.git
dsh plugin --profile <profile> add /path/to/dsh-mcp-manager
dsh <profile>
dsh plugin add 会在 profile 里装包,并自动把 bundle 写进 dsh.profile.bundles;
mcp-manager 这行配置由 bundle 自带的 patch 插入,不用手写 YAML。
<profile>是~/.dsh/profiles/<名字>的名字,桌面版一般是desktop;dsh不在 PATH 时用应用目录下的resources/runtime/cli/bin/dsh(Windows 是dsh.cmd);- 装完在 设置 → 插件 里能看到
MCP Server Manager(行 idmcp-manager,状态 active), 旁边的 MCP 服务器 页签就是本插件的界面。
方式 2:让 DSH 自己装
把下面整段发给 DSH 助手即可,它自己会克隆、安装、重启并汇报:
帮我安装并启用 DSH 插件:https://github.com/nekojackie/dsh-mcp-manager
1. 把仓库克隆到任意目录(例如 ~/.dsh/plugins/dsh-mcp-manager;没有 git 就下载 ZIP 解压);
2. 执行 dsh plugin --profile <当前 profile> add <该目录绝对路径>;
如果 dsh 命令不可用,改用 plugin_manager 的 install_bundle,target 指向该目录;
3. 重启 DSH,确认「设置 → 插件」里插件行是 active、并出现「MCP 服务器」页签;
4. 用 mcp_manager_list 把当前 MCP 服务器清单贴给我;
5. 不要改动我已有的 MCP 服务器配置。
这是 AI 生成的插件,OAuth token 会写进 DSH 凭据库,安装前可以先看一眼下面的「安全说明」。
使用
设置界面
设置 → 插件 → MCP 服务器(与 "全部" 页签并列):
- 每张卡片:名称、传输方式、命令或 URL、状态点、工具数、启用开关、刷新 / 重连 / 编辑 / 移除;
- 展开卡片:该服务器的每个工具 + 描述 + 入参;
- 自动续期设置(可折叠):启用开关、检查间隔(秒)、提前续期(秒)、"过期后仍自动续期"、保存 / 恢复默认;
- 授权成功后卡片会自己跟上:已授权 → 正在连接… → 工具数量,不需要手点刷新。
直接改配置
清单与续期策略都保存在本插件这一行的 config 里:
- id: mcp-manager
name: dsh-mcp-manager
config:
refreshIntervalMs: 300000 # 检查周期,0 = 关闭,默认 5 分钟
refreshLeadMs: 600000 # 提前多久续期,默认 10 分钟
refreshOnExpiry: true # 过期后仍自动续期(默认开)
servers:
- name: demo # ^[A-Za-z0-9_-]{1,32}$,同时是工具前缀
enabled: true
transport: stdio
command: npx
args: ['-y', '@modelcontextprotocol/server-everything']
env: {}
cwd: ''
toolCallTimeoutMs: 60000
failOnStartupError: false
- name: docs
enabled: true
transport: streamable-http
url: http://127.0.0.1:3000/mcp
headers: {}
oauth:
enabled: true # 需要 OAuth 时
scopes: [] # 留空 = 用服务器元数据里的 required_scopes
clientId: '' # 留空 = 动态客户端注册
服务器字段:name enabled transport command args env cwd url headers
toolCallTimeoutMs failOnStartupError oauth{enabled,scopes,clientId,clientSecret,resourceMetadataUrl,authorizationServer}。
OAuth 2.1 授权
受 OAuth 保护的 streamable-http 服务器(其 /.well-known/oauth-protected-resource 会声明
authorization_servers 与 required_scopes)不再需要手工复制 token:
- 编辑服务器,勾选 使用 OAuth 授权,保存;
- 卡片上点 授权(浏览器) → 插件完成发现 + 动态注册 + PKCE,返回授权链接并在浏览器打开;
- 在授权页同意后回跳到
http://127.0.0.1:<DSH 端口>/api/dsh-mcp-manager/oauth/callback; - 插件换取 token(存进凭据库)、重连该服务器,工具随即出现。
| 其它操作 | 行为 |
|---|---|
| 粘贴令牌 | 已有 access token 时的兜底;存为非过期授权 |
| 刷新令牌 | 立即用 refresh_token 换新并重连 |
| 全部续期 | 对所有已授权服务器强制续期一遍 |
| 退出授权 | 删除本地授权记录并断开 |
- 授权链接 10 分钟有效、
state一次性;重复打开会提示"已使用",重新点授权即可(会顶掉旧尝试)。 - 令牌过期前 60 秒内的下一次连接也会兜底刷新。
- 刷新失败(
invalid_grant)会清掉本地记录并把状态显示为未授权,不会静默失联。
自动续期
| 触发 | 行为 |
|---|---|
| 定时 | 每 refreshIntervalMs 检查,expiresAt 进入 refreshLeadMs 窗口即续期 + 重连 |
| 已过期 | 过期但仍有 refresh_token 的授权,下一轮必定续期 |
| 过期自愈 | mcp__* 调用返回 401/unauthorized/invalid_token/token expired 等时,立刻续期 + 重连(每台 30s 最多一次,最多 3 次,30/60/120s 退避) |
页面会显示当前策略、上次续期时间、下次检查时间,以及"上次续期触发:定时 / 过期后自愈 / 手动"。
Agent 工具
| 工具 | 作用 |
|---|---|
mcp_manager_list |
列出受管服务器:传输、地址、状态、工具数、启动错误 |
mcp_manager_add |
新增或替换(同名覆盖)一台服务器;含 oauth 设置 |
mcp_manager_remove |
移除服务器及其配置 |
mcp_manager_set_enabled |
启用 / 停用(保留配置) |
mcp_manager_tools |
列出已注册的 MCP 工具:公共名、描述、入参名,可按服务器过滤 |
mcp_manager_oauth |
status / authorize / paste-token / refresh / refresh-all / signout |
架构
lib/index.js Host 半边:清单校验与持久化(configEditor)、子插件编排(ctx.plugin 真 mcp-client)、
6 个 agent 工具、12 条回环桥接路由(11 POST + GET 回调)、续期定时器与 401 自愈
lib/oauth.js OAuth 2.1 引擎:仅 node:crypto + 全局 fetch;发现 / 注册 / PKCE / 换取 / 刷新 / 凭据读写
lib/client.js Web 半边:settings.plugins.tab 页签,纯 JS(无构建、无 Harness 内部包依赖)
docs/*.md 实现契约(v1 基础 / OAuth / 定时续期 / 可编辑策略),Host 与 Web 两半的字段与接口
fixtures/*.mjs 本地测试夹具:假 MCP 服务器(stdio / HTTP)、OAuth 授权服务器 + 受保护 MCP、引擎端到端断言
数据流:页面 ⇄ POST /api/dsh-mcp-manager/*(仅回环)⇄ Host;Host 用 configEditor 写 profile patch 并
触发 Loader 重载,用 ctx.plugin() 把每个启用的服务器实例化为一个真正的 mcp-client,用
ctx.tools.schemas() 汇总 mcp__* 工具。
安全说明
- OAuth token 只进 DSH 凭据库
~/.dsh/.credentials.yaml,记录键mcp-manager/<slug>(服务器名docs→mcp-manager/docs)。不写进cordis.patch.yml、不返回给页面、不进 agent 上下文、不写日志。 - 页面拿到的只有:是否已授权、过期时间、scope、
clientSecretSet(是否已保存)。 - 桥接路由只接受回环请求;除 OAuth 回调(GET,仅回环)外均只接受 POST。
clientSecret、headers、env属于配置,会留在 profile patch 里——共享机器请优先用凭据中心的环境变量。- 授权页会展示
client_id与 PKCE challenge;请不要把授权链接转发给别人。
已知限制
- OAuth 仅实现授权码 + PKCE 流程;依赖授权服务器支持动态客户端注册,否则需在表单里填
clientId。 client_credentials、设备码等流程不支持。- 过期自愈依赖错误文本能看出是鉴权问题(401/403/unauthorized/invalid_token/token expired 等); 服务端如果只回自定义错误,则只能等下一轮定时续期。
- 修改清单或续期策略都会重载插件,因此所有服务器会重连一次;"重连"按钮是单服务器路径。
- 停用的服务器不续期。
- 续期成功会重连该服务器(旧连接带着旧令牌),会有约半秒的重连窗口。
- 页面外观未做逐像素比对;逻辑与桥接行为有端到端测试。
开发与测试
仓库自带夹具,不需要外网:
# 1) OAuth 引擎端到端(会自己起授权服务器与受保护 MCP)
node fixtures/oauth-mcp-rig.mjs 8792 &
node fixtures/verify-oauth-engine.mjs 8792
# → 44 项断言:发现 / 动态注册 / PKCE / state / 回调换取 / Bearer 注入 / 过期刷新 /
# invalid_grant 清库 / 粘贴令牌 / 退出 / 重放拒绝
# 2) 无鉴权的 MCP 服务器(stdio 与 HTTP),用来验证管理器本身
node fixtures/mock-mcp-server.mjs # stdio
node fixtures/mock-mcp-http.mjs 8791 # streamable-http,路径 /mcp
语法检查:node --check lib/index.js、node --check lib/client.js、node --check lib/oauth.js
(三个文件都没有构建步骤)。
兼容性
- 开发与验证环境:DSH
0.2.1-rc.2、Node 24 / Windows 11;使用 Node >= 20 的语法与 API。 - 依赖 Harness 提供的
@deepseek-ai/dsh-mcp-client(运行时动态导入,不打包)。 - 回环回调天然适配桌面端;远程/容器部署时授权回跳地址需能访问
127.0.0.1:<端口>。
许可
声明
本项目由 DeepSeek V4.1 Flash 生成,包含 AI 生成的代码与文档。它按"现状"提供,不附带任何担保; 涉及 OAuth 凭证、远程服务器与配置写入,请在正式环境使用前自行审阅并做好备份。
No comments yet. Be the first to write one.