mcp server
dsh-mcp-manager
Manage MCP servers inside DeepSeek Harness: enable/disable, OAuth 2.1 authorization, scheduled + after-expiry token renewal, and a tool browser with descriptions. Generated by DeepSeek V4.1 Flash.
Set up
Runs on your computer. Pick your agent and operating system.
This project does not publish an install method we can turn into a config. Follow the README instead.
README
synced Oct 26, 2026dsh-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 工具 · 架构 · 安全 · 测试 · 许可
A 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 凭证、远程服务器与配置写入,请在正式环境使用前自行审阅并做好备份。