# dsh-scan-mcp ![dsh-scan-mcp banner](assets/dsh-scan-mcp-banner.svg) [![npm version](https://img.shields.io/npm/v/dsh-scan-mcp.svg)](https://www.npmjs.com/package/dsh-scan-mcp) [![npm downloads](https://img.shields.io/npm/dm/dsh-scan-mcp.svg)](https://www.npmjs.com/package/dsh-scan-mcp) [![license](https://img.shields.io/npm/l/dsh-scan-mcp.svg)](LICENSE) **DeepSeek Harness 的 Windows MCP 控制中心** —— 扫描本机编码 Agent(Claude Code / Codex / CodeBuddy) 配置中的 MCP 服务器,用真实的 MCP `initialize` 握手检测**真实连通性**(同时支持 **stdio** 与 **streamable-http** 两种传输协议),并可在界面上一键启用/停用。 [English README](./README.md) · [npm](https://www.npmjs.com/package/dsh-scan-mcp) · [GitHub](https://github.com/chenbin-dev/dsh-scan-mcp) ## 功能特性 - **自动扫描**:读取 Claude Code(`~/.claude.json`)、Codex(`~/.codex/config.toml`)、 CodeBuddy(`~/.codebuddy/mcp.json`)的 MCP 配置,跨 Agent 去重(同一 MCP 只显示一条,来源合并) - **真实连通性检测**:stdio 型启动实际进程、streamable-http 型发起真实 `initialize` 握手 (兼容 JSON 与 SSE 响应,支持配置 `headers` 认证透传);在线(绿)/ 离线(红)一目了然, 离线时展示具体失败原因与耗时 - **仅检测启用项**:只有开启的 MCP 才会被连接检测;停用的默认显示离线(「已停用(未启用,不检测连接)」), **绝不发起连接**;重新启用后自动重测 - **单独重连**:对任意 MCP 单点重测(停用项按钮置灰) - **滑动开关**:默认全部启用,可单独关闭/打开;状态持久化到 `~/.dsh/dsh-scan-mcp.json`(重启不丢) - **`/mcp` 弹出控制面板**:聊天框输入 `/mcp` 弹出模态面板(不是 AI 回复) - **设置页**:设置 → Windows MCP 控制中心(卡片布局) - **模型工具**:`mcp_discovered_catalog`(扫描 + 连通性检测,只读) ## 环境要求 - Windows(扫描的是 Windows 用户目录下的 Agent 配置) - DeepSeek Harness(DSH)**web** profile(`dsh web`) - Node.js ≥ 20(streamable-http 检测使用内置 fetch) ## 安装 任选其一(把 `` 换成你的 profile 名,如 `web`): ```bash # 1. 从 npm 安装(推荐) dsh plugin --profile add dsh-scan-mcp # 2. 从 GitHub 安装 dsh plugin --profile add https://github.com/chenbin-dev/dsh-scan-mcp.git # 3. 本地开发调试 dsh plugin --profile add /path/to/dsh-scan-mcp ``` 安装后**重启 profile**(如重新运行 `dsh web`)。本插件是静态 bundle:DSH 重启不丢失,也无需每次会话审批。 ## 使用 1. 任意会话输入 **`/mcp`** → 弹出 MCP 控制面板: - 汇总行:去重 MCP 数 · 在线 · 离线 · 已停用 · 诊断数 - 每个 MCP:名称、传输类型(stdio / streamable-http)· endpoint、● 在线 / ● 离线、 失败原因、**重连**按钮(已停用项置灰)、滑动开关 - 顶部:刷新扫描 / 关闭 2. 或打开 **设置 → Windows MCP 控制中心** 查看同样的内容(卡片式) 3. 模型侧可直接调用工具 `mcp_discovered_catalog` ## 扫描来源 | 来源 | 配置文件 | 解析方式 | |---|---|---| | Claude Code | `~/.claude.json` | JSON `mcpServers` 对象 | | Codex | `~/.codex/config.toml` | TOML `[mcp_servers.]` 小节 | | CodeBuddy | `~/.codebuddy/mcp.json` | JSON | 文件缺失/不可读会记入面板「诊断」计数,不影响其余扫描。想加更多来源?改 `src/index.js` 顶部的 `SOURCES` 数组即可(或提 PR / issue)。 ## 传输协议支持 - **stdio**:以 `command` + `args`(含 `env`)启动进程,stdin 发 `initialize`,从 stdout 等 JSON-RPC 响应 - **streamable-http**:向 `url` POST `initialize`,携带 `Content-Type: application/json` 与 `Accept: application/json, text/event-stream`; 兼容纯 JSON 与 SSE(`data:` 行)响应;配置中的 `headers`(如 `Authorization`)原样透传 ## 隐私与安全 - 插件**只展示环境变量 / header 的名称**,从不读取或展示凭据值;Token 仍留在你的 Agent 原始配置里 - 检测只是握手(`initialize`):**从不调用任何 MCP 工具**、检测完即终止进程不常驻、 **停用的 MCP 完全不被探测** - 状态文件 `~/.dsh/dsh-scan-mcp.json` 只记录 MCP id 与开关,不含任何凭据 ## 故障排查 **某 MCP 一直离线?** 点该行「重连」查看具体原因: - `ERR_MODULE_NOT_FOUND`:通常是 npx 缓存损坏。执行 `npm cache clean --force` (或删除 `%LocalAppData%\npm-cache\_npx\` 对应目录)后重连 - `npm ... 404`:包名不存在,改 Agent 配置里的包名(如 sequential-thinking 应为 `@modelcontextprotocol/server-sequential-thinking`) - `连接超时`(stdio):进程 20 秒内未响应 initialize(常见于需要代理的网络) - `HTTP 状态 404/405(该地址可能不是 MCP 端点)`:`url` 不是 MCP 端点或服务端未实现 MCP - `网络不可达 / 连接超时`(streamable-http):无法访问端点,检查网络/代理 - `未识别到 MCP initialize 响应`:返回内容非 JSON/SSE,端点可能需要 `headers` 认证 ## 开发 ``` dsh-scan-mcp/ ├── package.json # 插件元数据(dsh.bundle.patch / dsh.client) ├── cordis.patch.yml # bundle 补丁:插入插件行(id: wmcp) └── src/ ├── index.js # Host 半:扫描 + 握手检测 + HTTP RPC + 工具 + /mcp 命令 └── client.js # Client 半(浏览器):设置页 + 弹出面板 + 命令触发 ``` - Host 半是纯 ESM 模块(`export { name, inject, apply }`),只用 Node 内置能力 (`child_process` / `fs` / `fetch`);peer 依赖 `@deepseek-ai/dsh-tools` 由宿主提供 - Host ↔ Client 通过 HTTP RPC:`POST /__scan-mcp/scan|test|setEnabled` - 检测结果缓存 30 秒、并发 3、stdio 超时 20 秒 / http 超时 12 秒 - 语法检查:`node --check src/index.js && node --check src/client.js`(即 `npm test`) ## License [MIT](./LICENSE)