dsh-mcp-status:在 Web GUI 侧边栏看清 MCP 服务器连接状态

前言

DSH 的理念是「一切皆插件」,MCP 服务器通常也是以插件形式挂进 profile 的。实际用下来有一个反复出现的问题:profile 里同时挂着多个 MCP 服务器,某次对话某条 mcp__<server>__* 工具调不通了,你很难快速判断是「这台服务器压根没连上」还是「连上之后又死了」。@deepseek-ai/dsh-mcp-client 本身不暴露连接状态,fiber 是 active 的不代表服务器活着,工具注册表里还有条目也不代表现在还通。

dsh-mcp-status 解决的就是这件事:在 Web GUI 侧边栏把每个 MCP 服务器的连接状态、工具数量、配置摊开,并支持原地开关和重连。下面介绍这个插件。

这是什么

sonettogu14/dsh-mcp-status(维护者 SonettoGu14,分类客户端)是 DeepSeek Harness Web GUI 的 MCP 服务器面板插件。它把宿主侧 ctx.loader.entries() 里所有 @deepseek-ai/dsh-mcp-client 行列出来——profile 补丁、home 补丁、插件包插入的行都算,与宿主实际在跑的一致——并给出连接状态、工具数量和配置,允许在不离开面板的前提下停用 / 启用、重试连接、单行测试连接。

它回答三个问题:有哪些 MCP 服务器;连上了没有;没连上的话为什么。

核心功能

1、侧边栏列出每个 MCP 服务器,显示状态、工具数、传输与地址、来源补丁文件、超时与重连策略。状态由四份证据组合推导,不是客户端自报。

2、原地开关与重连。开关只改写当前 profile 补丁文件里那一行的 disabled 字段:按缩进定位到 - id: <行 id> 之后的块,插入或删除一行 disabled: true,其余字节原样保留,采用临时文件 + rename 的原子写(保留原权限位)。写完后补丁监听会热重载该行,重载即重新连接;8 秒内没连上会主动 hmr.reconcileProfile([id]) 再排一次。不在可编辑补丁文件里的行(例如插件包插入的 drawio)显示「内置」,开关不可用。

3、「测试连接」用宿主同一份配置真做一次 JSON-RPC 握手(stdio 起进程 / http 打请求),把 ECONNREFUSED、HTTP 401、超时原文贴回行内。

4、状态同时喂给 system prompt 摘要与调用闸门:有服务器不可用时注册一个最多 6 行的健康摘要;mcp__<server>__* 的调用在派发前被判为不可用则拒绝,并给出可读原因。

面板提供四个同源路由:

GET  /api/dsh-mcp-status/servers   # 快照:状态、工具数、传输与地址、来源补丁文件
POST /api/dsh-mcp-status/toggle    # { id, enabled }:改补丁行,等热重载,返回新状态
POST /api/dsh-mcp-status/retry     # { id }:重新挂载这一行
POST /api/dsh-mcp-status/test      # { id }:真握手,返回协议版本 / serverInfo / 工具数 / 失败原因

写操作要求同源证明,所有路由只接受回环来源。

状态判定

状态由 lib/status.js 的 resolveStatus() 纯函数推导,每条结论都带依据,优先级从上到下:

顺序 条件 状态 reason
1 行被停用 已停用 disabled
2 loader fiber 失败 加载失败 fiber-failed
3 fiber 未就绪 启动中 pending
4 最近一次测试失败,且端口不通或结论在 probeAssertMs 内 不可达 probe-failed
5 streamable-http 端口拒绝连接 / 超时 不可达 tcp-refused
6 最近一次测试成功 已连接 connected
7 工具表读不到 已连接 unknown-tools(不下结论)
8 有工具 / 没有工具 已连接 / 未连接 connected / no-tools

第 8 条的 no-tools 刻意与 unreachable 分开:工具数为 0 可能只是这行挂在 per-agent 作用域、全局注册表看不见,当断线处理会误报也会误拦。每行 DTO 带 reason 与 evidence(fiber / tools / tcp / probe 四个信号及时间戳),展开区把依据压成一行。

调用闸门只有证据够新才拦:快照超过 2 × refreshMs 视为过期,pending、no-tools、disabled 一律放行。idle 不等于断线。

安装与启用

README 给出四种装法,任选其一:

# 1. npm(推荐):预构建包,不需要构建授权
dsh plugin --profile <profile> add dsh-mcp-status

# 2. 本地目录(开发用)
dsh plugin --profile <profile> add link:<本目录>

# 3. 从 GitHub
dsh plugin --profile <profile> add github:SonettoGu14/dsh-mcp-status

第四种是在 Harness 里用插件管理器的 install_bundle 指向本目录或本仓库。npm 包页:https://www.npmjs.com/package/dsh-mcp-status

安装后在侧边栏点「MCP 服务器」即可。卸载:

dsh plugin --profile <profile> remove dsh-mcp-status

配置与典型用法

配置写在本插件自己的 patch 行里:

- id: mcp-status
  name: dsh-mcp-status
  config:
    refreshMs: 10000        # 后台状态刷新周期(≥ 2000)
    startupWaitMs: 8000     # 开关/重试后等待连接就绪的上限
    probeAssertMs: 60000    # 测试失败后,结论压过实时探活的窗口
    probeTimeoutMs: 15000   # 「测试连接」整次超时
    promptHealth: true      # 是否把不可用写进 system prompt
    guardUnreachable: true  # 是否拦截发往不可用服务器的工具调用

典型操作流程:侧边栏点开某行,看状态徽标;是黄的(启动中)或红的(未连接 / 不可达 / 加载失败)时点「测试连接」,行内会贴回握手失败原文;确认是配置或进程问题后直接点开关或重试,不必再去翻补丁文件。系统 prompt 侧不用额外操作,不可用摘要会在健康时自动注销。

面板只读配置,不做新增与编辑;新增和编辑仍在「设置 → 插件 → MCP 服务器配置」。

兼容与依赖

  • 需要宿主组合了 webServer(Web GUI)与 @deepseek-ai/dsh-mcp-client(MCP 客户端),两者都是 DSH 自带包。
  • 包版本 0.2.0,许可证 MIT,要求 Node >=22.19.0。
  • 不依赖任何第三方运行时包:宿主半体只用 Node 内置模块,探测模块自己实现 MCP 握手。官方 @deepseek-ai/* 包一个都没有 import,因此 package.json 里没有 dependencies / peerDependencies。

适用场景与注意

适合用 DSH Web GUI、profile 里挂多个 MCP 服务器的人,用来替代「翻补丁文件 + 猜连接状态」的做法。需要留意:

  • 插件以当前 dsh 进程的权限运行,安装前应先检查源码与许可证(MIT)。
  • 停用 / 启用会改写当前 profile 补丁文件里那一行;如果该行由其它工具生成(例如同步 MCP 配置的第三方工具),那个工具下次整表重写时可能覆盖本次开关结果。
  • stdio 行没有端口可探,存活只能靠工具数 + 手动「测试连接」的结论。
  • 闸门可能误拦,尽管只拦「快照新鲜 + 端口确实拒绝连接 / 刚测过失败」;不放心就设 guardUnreachable: false,退回纯看板行为。
  • 状态是推导的,不是客户端自报的。真要让状态像 opencode 那样由客户端层拥有,需要上游 dsh-mcp-client 提供接口。

结尾

dsh-mcp-status 的价值在于把「MCP 服务器到底通不通」变成一个面板上可见、可操作的事实,而不是靠 fiber 状态和工具注册表间接猜。信息密度集中在状态判定表与四份证据上,开关写补丁的方式也刻意保守,不破坏原文件。

目录页:https://www.skillhub.cn/plugins/SonettoGu14/dsh-mcp-status

GitHub:https://github.com/SonettoGu14/dsh-mcp-status

羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

小夜