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