🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

MCP 服务器管理 sunshaobei/dsh-mcp-manager

DeepSeek Harness
sunshaobei5 天前有提交已提供中文文档扫描:含敏感能力

按工作目录管理 MCP 服务器并热加载配置

30/100
综合分
0
GitHub 星标
—
npm 周下载
—/5
用户评分

数据截至 2026/10/27 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add sunshaobei/dsh-mcp-manager
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:仅索引
是什么
dsh 原生插件 · market
装得上吗
本站尚未做安装检查
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 5 天前
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。

读写/删除本地文件发起外部网络请求
查看扫描证据(共 61 处,展示前 19 条)
  • 写入本地文件
    lib/index.js:176
    await mkdir(dir, mode === null ? { recursive: true } : { recursive: true, mode });
  • 写入本地文件
    lib/index.js:183
    await writeFile(temporary, data, mode === null ? { encoding: "utf8" } : { encoding: "utf8", mode });
  • 写入本地文件
    lib/index.js:184
    await rename(temporary, file);
  • 删除本地文件
    lib/index.js:186
    await rm(temporary, { force: true }).catch(() => void 0);
  • 读取本地文件
    lib/index.js:201
    return await readFile(file, "utf8");
  • 读取本地文件
    lib/index.js:2422
    if (!existsSync2(dir))
  • 写入本地文件
    lib/index.js:2423
    await mkdir2(dir, { recursive: true });
  • 写入本地文件
    lib/index.js:2426
    await writeFile2(tmp, data, "utf8");
  • 写入本地文件
    lib/index.js:2427
    await rename2(tmp, file);
  • 删除本地文件
    lib/index.js:2429
    await rm2(tmp, { force: true }).catch(() => void 0);
  • 读取本地文件
    lib/index.js:3887
    const hasProjectDsh = existsSync3(dotDsh) && resolve(dotDsh) !== home;
  • 读取本地文件
    lib/index.js:3888
    if (existsSync3(join5(current, ".git")) || hasProjectDsh || existsSync3(join5(current, ".mcp.json"))) {
  • 读取本地文件
    lib/index.js:4250
    text = await readFile2(filePath, "utf8");
  • 读取本地文件
    lib/index.js:5063
    if (!existsSync4(dir))
  • 删除本地文件
    lib/index.js:5070
    await rm3(tmp, { force: true }).catch(() => void 0);
  • 删除本地文件
    lib/index.js:5320
    await rm3(opts.cachePath, { force: true }).catch(() => {
  • 删除本地文件
    lib/index.js:5329
    await rm3(tmp, { force: true }).catch(() => {
  • 删除本地文件
    lib/index.js:7798
    rmSync(tmpPath, { force: true });
  • 发起网络请求
    lib/client.js:285
    const response = await fetch(path, merged);
扫描于 2026/11/1(0 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

依赖的 DSH / Cordis 模块
@deepseek-ai/cordis@deepseek-ai/dsh-agent@deepseek-ai/dsh-api-session-controller@deepseek-ai/dsh-client-locale@deepseek-ai/dsh-client-store@deepseek-ai/dsh-client-ui-plugin-manager@deepseek-ai/dsh-client-ui-renderer@deepseek-ai/dsh-client-ui-session@deepseek-ai/dsh-client-ui-settings@deepseek-ai/dsh-client-ui-slots@deepseek-ai/dsh-host-webserver@deepseek-ai/dsh-llm
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

README

由 DeepSeek 最新模型翻译生成
dsh-mcp-manager DSH(DeepSeek Harness)的 MCP 服务器管理插件:会话界面右上角浮窗 + 分级面板 + 快速接入(手工表单 + 粘贴 mcpServers JSON 导入,不预设任何服务器)。 连接与协议交官方 @deepseek-ai/dsh-mcp-client(宿主 cordis loader 按包名装载到 dsh 安装内的副本),本插件只留配置面与模型可见面;官方客户端不随包分发,也无需额外安装。 模型可见面只有四个原子工具(ws_mcp_list / ws_mcp_detail / ws_mcp_search / ws_mcp_call):项目级、全局级与运行时注入的封装定义条目一律经中间层访问,两级发现(ws_mcp_list 完整盘点 → ws_mcp_detail 按需拉完整 schema);cwd 无项目时回落全局虚拟 root @global。宿主仍按 mcp__<id>__<tool> 注册工具(id 是本次装配按 (工作空间, 服务器名) 分配的不透明短串,不能由服务器名推导),但这些名字会被从模型的工具列表中摘除,禁止直呼。 两级配置文件中的服务器列表(增删/启停/改配置)支持热加载、即时生效,无需重启。
展开完整文档(README 剩余 1 节)
dsh-mcp-manager

DSH(DeepSeek Harness)的 MCP 服务器管理插件:会话界面右上角浮窗 + 分级面板 + 快速接入(手工表单 + 粘贴 mcpServers JSON 导入,不预设任何服务器)。
连接与协议交官方 @deepseek-ai/dsh-mcp-client(宿主 cordis loader 按包名装载到 dsh 安装内的副本),本插件只留配置面与模型可见面;官方客户端不随包分发,也无需额外安装。

模型可见面只有四个原子工具(ws_mcp_list / ws_mcp_detail / ws_mcp_search / ws_mcp_call):项目级、全局级与运行时注入的封装定义条目一律经中间层访问,两级发现(ws_mcp_list 完整盘点 → ws_mcp_detail 按需拉完整 schema);cwd 无项目时回落全局虚拟 root @global。宿主仍按 mcp__<id>__<tool> 注册工具(id 是本次装配按 (工作空间, 服务器名) 分配的不透明短串,不能由服务器名推导),但这些名字会被从模型的工具列表中摘除,禁止直呼。
两级配置文件中的服务器列表(增删/启停/改配置)支持热加载、即时生效,无需重启。
(middleware / middlewarePolicy 两个配置键已在 #767 笔 2 废除——旧配置里写了不生效、也不会被本插件改写。)

升级后历史会话打不开?
当前版本只生成 producer-owned V4 source;旧 source 仅通过一次性维护脚本处理,详见升级与历史会话边界。

一键安装

dsh plugin --profile web add dsh-mcp-manager

安装 / 卸载 / 更新后都需重启一次 dsh web(bundle 层只在启动时组合)生效。

核心优势

- 上下文成本可控:全部 MCP 经中间层收敛,模型面只占 ws_mcp_list / ws_mcp_detail / ws_mcp_search / ws_mcp_call 四个原子工具位——接多少台服务器、多少个工具都不膨胀系统提示词(两级发现:ws_mcp_list 完整盘点 → ws_mcp_detail 按需拉完整 schema)
- 分工作目录维护:项目级配置 <项目根>/.dsh/dsh-mcp-manager/mcp.json 随仓库走、可提交 git 团队共享;全局配置 <DSH_HOME>/dsh-mcp-manager/mcp.json 常连;切换会话自动加载当前目录的 MCP 集
- 工作空间隔离:中间层以会话 cwd 路由到对应连接池,server 全名一致性校验防跨空间串台;不同目录注入同名 server 也互不冲突
- 安全的默认值:配置只存 ${ENV} 引用、不落盘密钥本身(0600 权限 + 原子写入); stdio 子进程环境净化,宿主凭据形状变量不透传;目录摘要与错误路径经 redactor 脱敏
- 运维省心:运行中/连接中/失败等分级状态一目了然;断线有界指数退避自动重连;调用超时可按 server 覆盖(toolCallTimeoutMs),中间层调用按在用服务器的最大值 + 25s 内部尾结算(默认 15s + 25s = 40s)

安装

前提:已安装 DeepSeek Harness 且 dsh web 可正常启动(未全局安装 dsh 见下方「未全局安装 dsh」)。

安装插件(add)

dsh plugin --profile web add dsh-mcp-manager

卸载插件(remove)

dsh plugin --profile web remove dsh-mcp-manager

更新插件(update)

dsh plugin --profile web update dsh-mcp-manager

安装 / 卸载 / 更新后都需重启一次 dsh web(bundle 层只在启动时组合)生效。

指定版本号(@version)

省略 @版本号 即安装默认 latest(推荐)。仅当 registry 尚未同步到最新、或最新版在你的环境有问题时,在包名后追加 @版本号:

dsh plugin --profile web add dsh-mcp-manager@<版本号>

未全局安装 dsh

若本机没有全局 dsh 命令,用 npx 临时拉起(底层调用 pnpm,仍需本机装好 pnpm 与 Node.js):

npx @deepseek-ai/dsh plugin --profile web add dsh-mcp-manager
npx @deepseek-ai/dsh plugin --profile web remove dsh-mcp-manager
npx @deepseek-ai/dsh plugin --profile web update dsh-mcp-manager

能力

| 能力 | 说明 |
| 右上角浮窗 | 状态点 + 计数摘要(MCP 2/3),点击展开下拉面板;随会话切换自动刷新 |
| 项目级 MCP | 服务器分「项目级 / 全局」两级:项目级存 <项目根>/.dsh/dsh-mcp-manager/mcp.json(随项目走、可提交 git),全局存 <DSH_HOME>/dsh-mcp-manager/mcp.json 常连 |
| 分级展示 | 运行中 / 连接中 / 重连中 / 未连接 / 已停用 / 失败;每台显示传输、端点、工具数;客户端未知状态按「未连接」投影、不丢卡(C13 统一口径) |
| 服务器管理 | 增删改查(可选项目级/全局)、连接 / 断开 / 重连;配置版本化 JSON,原子写入 |
| 两种传输 | stdio(本地子进程,env 支持 ${ENV} 引用)与 streamable-http(远程,header 支持 ${ENV} 引用,自动回传 Mcp-Session-Id) |
| JSON 导入 | 粘贴 mcpServers JSON 文本导入(仅 JSON 格式;不扫描任何应用配置文件) |
| 模型工具 | 全部服务器(项目级 / 全局 / runtime 注入)一律经中间层四个原子工具访问:ws_mcp_list / ws_mcp_detail / ws_mcp_search / ws_mcp_call,不同工作空间互不冲突;宿主注册名 mcp__<id>__<tool>(id 按 (工作空间, 服务器名) 随机分配、同一次装配内稳定、不透明;工具名仍受 64 字符 / [A-Za-z0-9_-] / 冲突哈希后缀约束)会被从模型工具列表摘除——模型不可见、不得直呼 |
| 工作空间隔离 | 中间层按调用方会话当前 cwd 路由到对应工作空间的连接池;server 全名 @<root>/<server> 一致性校验防跨空间串台 |
| 断线重连 | 有界指数退避(500ms 起、30s 上限、10 次后停止后台重试;用户手动连接或 ws_mcp_call 触发可再试) |
| 结果体积 | 本包不做结果截断,工具结果原样返回。目录装箱限额(每工具 4KB / 总 256KB)约束的是目录、不是执行结果;需要限长请在 MCP 服务器侧或宿主 compaction 策略里做 |
| 超时下探 | 工具调用超时默认 60s → 15s(可按服务器 toolCallTimeoutMs 覆盖);中间层 ws_mcp_call 按在用服务器最大值 + 25s 内部尾结算,不是固定值 |
| 状态推送自愈 | SSE 通道共享 sse-hub(#515):服务端每 30s data ping 心跳 + stalled 超窗回收 + maxAge 轮换(120min 无业务帧主动断开);客户端 60s 无帧即关旧建新(watchdog)、页面回前台重建 SSE 并 POST resume 做非强制可用性恢复(携带本次会话 cwd,服务端固定本次 root;旧无 body 请求回落既有绑定);SSE 连续失败降级 10s 轮询,期间每 5 个轮询周期自动探测恢复推送(C2,页面失联自愈)——移动端切后台被静默掐断的半开连接由客户端自愈 + 服务端确定性回收,不堆积僵尸连接。自动恢复复用官方管理机制的已存在状态投影与在途去重,不强制重建健康/connecting/reconnecting 连接;不声称检测真实健康(有工具注册的健康连接与半开连接无法实时区分),半开仍由用户显式重连恢复 |

配置(浮窗位置)

配置页入口:Plugin Manager → dsh-mcp-manager → Configure。浮窗按钮(MCP 胶囊)的位置与偏移(position / offset)在此保存,canonical row id 为 dsh-mcp-manager,settings namespace 为 dsh-mcp-manager,保存后即时生效。

非回环 LAN 地址(例如 192.168.:3081)默认不提供持久化设置面,Configure 按钮按 DSH 安全策略隐藏;请从 127.0.0.1:3080 / 127.0.0.1:3081 或 SSH 回环隧道管理。只有在可信 LAN、明确接受共享控制面风险时,才通过 dsh-lan-proxy 的 ownsHostCompat 恢复远程设置入口。

| 键 | 值域 | 默认 |
| position | top-right(右上,默认)/ top-left(左上)/ bottom-right(右下)/ bottom-left(左下) | top-right |
| offset.x | 非负整数(水平偏移,单位 px) | 8 |
| offset.y | 非负整数(垂直偏移,单位 px) | 8 |
| offset.blankY | 非负整数(空白会话垂直偏移,单位 px) | 40 |
| zIndexBase | 整数,clamp 到 1–9000(浮窗层级基准;胶囊与点击后弹出的主面板同取该配置值,模态管理面板不受影响) | 10 |

Settings namespace

DSH 官方 importer 会按同名 section 直接导入 dsh-mcp-manager;本插件不再运行第二套 namespace migration。settings.yaml.imported 仅为已消费文档的审计副本,不应整体复制。

当 position = bottom-right 或 bottom-left 时,下拉面板会在胶囊上方展开(底部锚点向上弹出),不溢出视口、内容完整可见可点击;顶部锚点向下展开(历史行为,默认不变)。

移动端 / 平板端适配(issue #128):断点判定基准是会话容器(conversationHost)的视口宽度而非窗口媒体查询——窄屏(≤480px,手机竖屏 / 极窄分栏)下面板近全屏宽、服务器卡片重排、操作按钮触控目标加大到 ≈44px;平板档(≤834px)过渡;桌面维持现状。
浮窗最终坐标经 JS 视口 clamp(safe-area 语义:宿主无 viewport-fit=cover,
env(safe-area-inset-) 恒 0 时自然退化为普通 clamp);软键盘弹出经
visualViewport resize 跟随,横竖屏切换后下一帧重算。

跨包避让契约(源自 issue #116,不可回退):本插件浮窗默认 top-right 且距顶 8px、高约 26px;dsh-provider-usage 用量胶囊依赖这一默认位置以 offsetY: 48 在其正下方让位(两胶囊默认互不重叠)。修改本插件默认锚点 / 垂直偏移会使该避让失效,属跨包行为契约,回退前须同步调整 provider-usage 默认值。

在设置页保存后即时生效,无需重启 dsh web、也无需手动刷新页面:宿主端经既有 SSE events 通道推送一变,客户端自动重新拉取 /api/dsh-mcp/config 并就地更新浮窗位置。

配置(中间层)

全部 MCP 经中间层访问(单池,没有模式开关):任何服务器都不产生模型可见的 mcp__ 直呼工具,统一经四个原子工具访问(两级发现,业界标准形态)—— ws_mcp_list(完整盘点当前工作空间全部服务器 + 每台完整工具清单,不受 ws_mcp_search 的 limit 截断;支持按 server 全名或裸名过滤,perServerLimit 是每服务器工具条数上限,默认 50、上限 500,超限时置 toolsTruncated;空返回附明确 message,带 server 过滤且 0 命中时,message 归因到过滤条件并列出可见项目级服务器)/ ws_mcp_detail(按 @<root>/<server> + tool 裸名精确查询单工具完整 inputSchema,错误分三种:发现失败附原因 / 服务器未连接或未发现 / 工具不存在)/ ws_mcp_search(关键词检索,先搜后调,输出 truncated 标志提示结果是否因 limit 截断)/ ws_mcp_call(按 @<root>/<server> 全名调用,参数 schema 用 ws_mcp_detail 核对),执行时按调用方会话当前 cwd 路由到对应工作空间连接池,不同工作空间注入不同 MCP、无命名冲突;cwd 无项目时回落全局虚拟 root @global,list/search/detail 恒合并查询「项目 root 单元 + @global 单元」,call 放行 @global root(全局配置跨工作空间共享,语义成立)。宿主注册名形如 mcp__<id>__<tool>,id 不透明、以工具清单为准;它只作内部标识(模型工具列表里看不到),封装定义条目(toolDefinitions)只经 ws_mcp_call 按 @<root>/<server> 触达。
注:全局服务器增删改后需重启或触发会话触达才刷新目录(既有行为)。

顶层配置键(Config schema)

顶层键(packages/dsh-mcp-manager/src/server/config/config-schema.ts 的 Config)默认值与语义:

| 键 | 默认值 | 语义 |
| enabled | true | 是否启用本插件(插件级总开关)。 |
| announceToAgent | true | 是否向智能体宣告插件(能力清单由 <available_mcp_servers> 承担)。 |
| storePath | 留空(默认 <DSH_HOME>/dsh-mcp-manager/mcp.json) | 全局服务器配置路径,留空用默认路径。 |
| announceCatalog | true | 是否注入 MCP 能力目录(<available_mcp_servers>)。 |
| catalogMaxEntries | 6 | 目录注入条目上限。 |
| debug.callStats | false | 是否开启调用统计调试与落盘(默认关闭,仅可通过配置文件开启;详见下节“调用统计与 Debug 模式”)。 |
| debug.statsFile | 留空(默认 <DSH_HOME>/dsh-mcp-manager/stats.json) | 统计落盘路径,留空使用默认路径。 |
| ui | 见“配置(浮窗位置)”节(position 默认 top-right;offset.x / offset.y 默认 8,blankY 默认 40;zIndexBase 默认 10,clamp 到 1–9000) | 浮窗位置与层级配置,详见“配置(浮窗位置)”节。 |

已废除的配置键(#767 笔 2):middleware(off / project / all 三档模式)与 middlewarePolicy(allowTools / denyTools 策略)。设置页的模式下拉已删除;旧配置里写了这两个键不报错也不生效(键被原样带过、没有任何消费者),本插件也不会改写用户的配置文件。工具级禁用是唯一的准入裁决。

已退役的实现:S1-5c 自研连接栈退役(runtime/supervisor.ts、runtime/reconnect.ts 等四文件整体退役,连接改走官方引擎);W11b2a src/types 与 src/integration 删除(无迁移动作)。

工具级禁用(浮窗)

- 服务器卡片的「工具(N)」折叠区展开后为 checkbox 列表,逐个启停,点击即经 PATCH /api/dsh-mcp/tool-disable 持久化(落盘 <DSH_HOME>/dsh-mcp-manager/user-state.json 的 disabledTools,合并写盘、重启保留);
- 语义:项目级与全局级服务器的工具都可禁用(单池后两类都经中间层;全局记录以 @global 为 key 跨工作空间共享);默认全部启用;
- 工具级禁用独立于服务器级 enabled 开关(服务器级复活不清工具级状态);
- 作用于 mcp-manager 管辖的全部 MCP 工具(mcp__ 前缀直呼与中间层 ws_mcp_* 一致生效,runtime 封装工具同样受控);插件侧自行声明的纪律裸名工具不受影响;
- 超长工具名(>64 字符哈希后缀)不可逆 → 按未知 server 处理,不禁用/不误禁;
- 浮窗与管理面板的「项目级」「全局级」分组都渲染工具开关(单池后两类都经中间层,全局组的开关同样生效);
- 浮窗与管理面板均按「项目级 / 全局级」两大分组展示(各自内部再按连接状态);
- 全名形态 @@global/<name> 或 @<绝对路径>/<name>(与宿主 parseFullServerName 归一化一致);宿主重启后 projectRoot 暂缺时客户端防御性跳过提交(不发送非法 @/name,C6);浮窗与管理面板的连接 / 断开 / 重连 / 启停操作携带当前会话 cwd,宿主重启场景可自愈恢复会话(C7)。

路由(全部 loopback 围栏)

| 路由 | 说明 |
| /api/dsh-mcp/health | 健康检查(注意与目录名不同) |
| /api/dsh-mcp/tool-disable | 工具级禁用开关(PATCH,loopback-only) |
| /api/dsh-mcp/ | 服务器管理 / 连接控制 / 工具清单 / SSE 事件等 |

运行时注入(registerServer.toolDefinitions)

其他插件可经 ctx.mcpManager.registerServer 运行时注册 MCP 服务器(内存态不落盘,同名幂等)。注册入参支持可选 toolDefinitions(调用方封装工具定义,ToolDefinition[],工具名用裸名):

- 有 toolDefinitions:该服务器工具全部用封装定义注册——execute 来自调用方(调用方可先做预处理再内部转发底层命令),跳过远端 schema 投影与通用 callTool,底层真实实现不外泄;
- 没有:维持现状(远端 schema + 通用 callTool),其他服务器零影响;
- 模型不可见 mcp__ 直呼工具:只经 ws_mcp_call 用裸名调用(@<root>/<server> + 裸名;封装的 execute 是调用方 JS,没有远端实现可直呼)。调用名派生仍走 publicToolName(64 字符 / 哈希后缀规则不变),但它只作为中间层 callTool 的转发名;
- 工具级禁用 / 可见性 / 能力目录对封装工具照常生效(按服务器 + 工具名判定,与 mcp__ 前缀工具同口径);
- 仅运行时注入面(runtimeRegistry)消费,不随 store 落盘、不随 mcpServers 导入透传。

await ctx.mcpManager.registerServer({
name: "my-mcp",
transport: "stdio",
command: "my-mcp-server",
args: ["serve", "--mcp"],
toolDefinitions: [
{
name: "my_tool", // 裸名 description: "调用方自定义的封装工具",
parameters: { type: "object", properties: { query: { type: "string" } }, required: ["query"] },
output: { schema: { ... }, render(args, value) { ... } },
execute: async (args) => { await prepare(); return forwarded; }, // 内部转发,不外泄
},
],
});

会话加载与工作区开关

MCP 连接检查在应用启动后于后台预热全局配置及官方工作区列表中的项目;配置编辑保存或来源文件变化时更新相应连接。切换会话只读取对应工作区的缓存快照,不等待 MCP 连接、发现或重试,也不重新检查已预热的连接。应用启动后新添加的工作区会在后台首次准备。

全局 MCP 的连接由应用共享,但启用开关按工作区持久化:在 A 工作区关闭不会影响 B 工作区。该开关同时约束界面、目录注入、搜索、详情和工具执行。快速切换时使用目标工作区的快照,尚无缓存时暂不显示计数;旧工作区的迟到响应不会覆盖当前界面。

数据与安全

- 服务器配置:<DSH_HOME>/dsh-mcp-manager/mcp.json(仅存 ${ENV} 引用,不落盘密钥本身);落盘 0600 权限 + 同目录临时文件原子替换;Windows 上替换遇到 EPERM / EBUSY 时会有界异步重试,重试期间检测到外部修改则中止以保留外部内容
- 所有 /api/dsh-mcp/ 路由仅限 loopback 访问(非回环 403 / 方法错 405)
- stdio 子进程环境净化(官方 dsh-mcp-client 口径):净化只作用于继承的父环境——凭据词根(KEY / PASSWORD / SECRET / TOKEN)与全部 DSH_ 变量从父环境摘掉,避免把宿主机密隐式透传给 MCP 子进程;用户在配置里显式声明的 env 原样传给子进程(显式层在净化之后合并)——env 不是脱敏面,要隔离就别往里写凭据
- stdio 子进程继承宿主权限:MCP 服务器命令在宿主进程权限下执行,仅配置可信的服务器。信任边界:同进程插件注入(ctx.mcpManager.registerServer)与宿主同权限、不构成提权;随仓库提交的项目级 mcp.json 才是需要你审慎对待的那一面
- 统计只落元数据:debug 统计(debug.callStats)记录调用次数/时长/成败与渐进式披露漏斗;搜索词只以 SHA-256 哈希桶落盘(h:<12 位 hex>,空查询为 <empty>),旧版本落的明文键在读回时丢弃(丢弃发生在读回那一刻,下次落盘即不再写回;若统计此后无活动,旧明文键会留到下一次有活动为止)。哈希是假名化不是匿名:搜索词熵低,仍有字典攻击面。漏斗的另两维仍落明文:ws_mcp_list 的 server 过滤项、ws_mcp_detail 的 server/tool——它们是服务器与工具名,本就在配置面与目录面里,不是自由文本
- MCP 工具在真实服务器上执行,先确认再操作;工具结果原样返回,可能含敏感信息;工具描述/结果按不可信输入对待
- 注入信任分级:远端工具描述/结果为不可信输入,仅展示与传参,不作指令执行;本地配置与用户显式操作为可信
- 工作空间隔离(中间层):路由以调用方会话当前 cwd 为唯一输入;server 全名一致性校验(参数声明的 root ≠ 路由 root → 拒绝)防跨空间串台;工具级禁用表按 @<root>/<server> 全名或裸名裁决(全名优先;@global 记录跨工作空间共享)
- 中间层工具只读边界:ws_mcp_list / ws_mcp_detail / ws_mcp_search 不执行远端工具,但首次触达某工作空间时会创建连接单元并触发后台建连(不等同于纯本地读);ws_mcp_call 是唯一执行远端工具的入口,并受工具级禁用表约束;ws_mcp_call 错误消息按「显式 + 下一步」规范给出(确认 server 连接 / 用 ws_mcp_detail 核对参数 / 检查工具级禁用状态)
- 禁直呼是机器强制的(#1014):mcp__<id>__<tool> 是内部注册名,pre-execute guard 默认拒绝一切非我方转发的 mcp__ 直呼——不再依赖模型遵守提示词,也不依赖声明面遮蔽(连接翻转期遮蔽必有泄漏窗口)。唯一放行位是宿主赋予的飞行中 token:本包 ws_mcp_call → dispatch → ctx.tools.execute 的子调用凭 parent 放行,结算即摘除,同一 token 重放会被拒。拒绝文案指路 ws_mcp_call,并写明不要重试本次调用。
- 工具级禁用(三入口一致):ws_mcp_call(callTool 查禁用表)、 pre-execute guard(mcp__ 前缀直呼工具)、插件侧声明的纪律裸名工具,统一走 isToolDenied 裁决;禁用只作用于 mcp__ 前缀工具,拒绝原因附语义声明;禁用记录写在 <DSH_HOME>/dsh-mcp-manager/user-state.json 的 disabledTools(@global key 跨工作空间共享,合并写盘,不整表覆盖)
- 凭据脱敏:目录摘要与错误路径经 redactor 处理,把 env/headers/URL 用户信息(username/password/searchParams)等凭据形状替换为 [REDACTED];URL 主机与路径中无凭据的部分保留可读(可诊断性,B8 口径);percent-encoding 的 raw 形态与 decoded 形态双注册,防编码绕过;supervisor/manager 错误日志与 HTTP body 同口径脱敏
- 调用统计与 Debug 模式(Metadata-Only):默认关闭;启用后把 MCP 调用指标与渐进式披露漏斗防抖原子持久化至 <DSH_HOME>/dsh-mcp-manager/stats.json,且控制台输出单行跟踪;严格不持久化用户 arguments 与返回 content
- 能力目录注入含来源标注与「不代表当前连接状态」说明
- 能力目录 source:dsh-mcp-manager 是 canonical row/settings 条目 id;目录消息的当前业务格式是 producer-owned V4:{ kind: "plugin:dsh-mcp-manager", form: "snapshot", sections: [{ name: "mcp-catalog", text }] }

升级与历史会话边界

当前写入与业务读取只认 producer-owned V4;本包不提供旧 V0/V2/V3 parser,也不把旧格式写成业务兼容。

旧 mcp-catalog source 属于一次性维护责任。scripts/maintenance/repair-mcp-catalog-sessions.mjs 只把旧 source 元数据修为 V3 wrapper,保留消息正文与事件序列;它不写 V4,也不实现或伪造 v3→v4 迁移。修复后由目标 dsh(版本见 catalog)的官方迁移链依次恢复旧产物并转为 V4,当前 V4 产物不动。

先停止 dsh web;默认预演,只列出受影响会话
node scripts/maintenance/repair-mcp-catalog-sessions.mjs

核对后落盘;自动备份,随后重启 dsh web
node scripts/maintenance/repair-mcp-catalog-sessions.mjs --apply

默认处理 v0/v1/v2 与 v3 中残留的旧 source;--legacy-only 只处理 v0/v1/v2。脚本幂等,可用 --home 或 DSH_HOME 指定目录、用 --session <id> 限定单个会话。

验证

测试单份维护、变异自动覆盖:单元测试只维护 test/.test.ts(import "../lib/index.js" 测产物);stryker 经 lib→src hook 复用同一份断言,无需手工同步副本。

健康检查(回环)
curl -s http://127.0.0.1:3080/api/dsh-mcp/health

源码在 src/,改后必须 build
pnpm --filter dsh-mcp-manager build
pnpm --filter dsh-mcp-manager test

已知限制

- mcp__ 注册名只作内部标识:服务器由官方 dsh-mcp-client 装载,宿主注册名为 mcp__<id>__<tool>,id 是按 (工作空间, 服务器名) 分配的 随机短串(同一次插件装配内稳定;插件重载或宿主重启后变化;不透明,不能由服务器名推导)。这些名字会被从模型工具列表摘除,模型经 ws_mcp_call 转发触达——不要在任何脚本或提示词里写死工具名,一律用 ws_mcp_list / ws_mcp_detail 取名字
- 不订阅 MCP 的 tools/list_changed 通知(无 SSE 长连接);工具列表变化在重连 / 手动刷新时重新同步
- 中间层目录是「采集边界内的 last-good 快照」(单服务器 ≤512 工具 / ≤256KB 总量),发现失败时 list 透出 unavailable 原因
- 仅桥接工具能力;MCP 的 resources 与 prompts 尚无 harness 消费接口
- 多标签页各自绑定不同会话时,项目级 MCP 只能跟随一个会话(issue #1028 未解决项):宿主 projectRoot 是单例,多个页签会互相覆盖,且每次切回前台的 rebindSession 会放大覆盖。本包不自行仲裁「哪个页签优先」。
- 读不到当前会话时保持既有绑定、不做清空(#1028):官方会话快照就绪前、或该页签暂未被官方 mainView 持有时,本包判定为「未知」并不向宿主发送 cwd:""——未知不等于无项目,误清会造成面板只剩全局条目、项目级导入报 no active project session。告警口径:首帧未知是官方快照尚未就绪的竞态(每次冷启动必现),不告警;只有「已解析过又读不到」或「连续多帧仍读不到」才打一次告警,以免正常态与异常态显示同一条黄警而丢掉判别价值。
- 切回前台的自动恢复是非强制的(#1120),不是用户显式强制重连:复用官方管理机制的已存在状态投影与 per-root/server 在途去重,不以每次 visibilitychange 为由 dispose/restart;connected/connecting/reconnecting 保留现有代际与官方退避, entry 缺失与真正失败走正常路径恢复,userDisabled 绝不复活。官方挂载层只提供 ready/disposed/工具注册面,有工具注册的健康连接与半开连接无法实时区分——自动恢复不声称已检测真实健康、不发自研 ping;半开仍可由用户显式重连恢复。resume 携带本次会话 cwd,服务端在本次调用中解析并固定 root(旧无 body 请求回落既有绑定,新请求明确无工作区即 cwd:"" 固定 @global,不回落到别人的 projectRoot);客户端恢复节流按 cwd 分键覆盖 resume,不同 cwd 的恢复不互吞。
- 依赖 Node ≥ 20

类型依赖

宿主端与客户端类型均来自官方 @deepseek-ai/* 包(cordis / dsh-host-webserver / dsh-agent / dsh-tools / dsh-system-prompt / dsh-llm / dsh-client-ui-slots / dsh-api-session-controller / dsh-client-ui-session,版本统一锁在仓库 pnpm-workspace.yaml catalog,随 DSH 发布节奏升级):仅 import type 编译期使用,编译产物零官方运行时导入。包以 optional peerDependencies 声明这一宿主耦合;对插件做类型检查的消费者需可解析这些官方包(跳过类型检查则无影响)。

客户端的「当前会话」读数经 src/client/core/current-session.ts 单一接缝,判据用官方口径 retainedBy.mainView > 0 并以官方 SessionListState / SessionSummary 类型锚定(不自建镜像类型):DSH 0.1.7-rc.2 起会话列表快照已删除 current 字段,官方 ISessions 也不提供「当前会话」访问器,因此不再自造 {current, byId} 形状。

License

MIT

0.3.0 变更摘要

- 包名去 scope:@wingsky-1/dsh-mcp-manager → dsh-mcp-manager(identity / 数据目录 / 文档全量同步)
- JSON 导入支持完整文件:自动解包 { "mcpServers": {...} } 顶层包裹
- 服务器名允许内部空格(SERVER_NAME_PATTERN 放宽),Figma AI Bridge 类名字原生合法
- /api/dsh-mcp/import/json 新增 { path } 导入:服务端直接读 mcp.json(支持 ~ 展开)
- Web 面板 Quick add 新增「从 mcp.json 文件导入」路径输入与按钮
预览分享卡片长什么样 ↓sunshaobei/dsh-mcp-manager
分享 · DeepSeek Harness Hub
sunshaobei/dsh-mcp-manager

按工作目录管理 MCP 服务器并热加载配置

回到顶部