# 迭代复盘:18-QMTBridgeMCP内建 > 复盘日期:2026-09-08 | 迭代状态:**验收通过(2026-09-08)** —— 口径:服务端自动化验收全绿 + MCP 工具端到端实测 + UI 接线核验(构建产物含新控件)+ 真实调用顺带确认(老师参与验收:重启宿主 / 指令修正 / MCP 实测) > 关联需求:R-020(已定稿,2026-09-08)| 关联计划:PLAN-018 ## 结果 迭代 18 达成(R-020 全范围):**QMT Bridge MCP 能力内建**——神之一手在 apply 内动态挂载 DSH 官方 @deepseek-ai/dsh-mcp-client(serverName 固定 QMT_Bridge_MCP,url 自动派生自激活连接 baseUrl+/mcp;挂载/切换/卸载/状态全由神之一手插件内管理);**三方依赖移除**(dsh-skill-mcp-panel 卸载 + 宿主 cordis.patch.yml 受管块清空);MCP 生命周期随 QMT 连接配置增删改与激活切换联动;状态出口 ×2(设置页「QMT 连接配置」MCP 状态条 + 会话头部指示灯区新增「MCP」灯);失败不崩(failOnStartupError:false + reconnect + 挂载 catch)。REST 直连架构不变(技术约束-003)。 ## 验收证据(2026-09-08 实测) | # | 验收项 | 结果 | |---|---|---| | 1 | 移除宿主受管块后工具仍可用 | ✅ cordis.patch.yml 清空 []、panel 已卸载;mcp__QMT_Bridge_MCP__qmt_list_apis 实际调用成功(QMT Bridge v2.0.0 返回) | | 2 | MCP url 随激活自动派生 | ✅ 100.110.38.78:8610/mcp(激活 baseUrl+/mcp,Q3) | | 3 | 激活切换联动 | ✅ 切 QMT_CYY → 192.168.3.43:8610/mcp connected;切回 GEMWIN 恢复 | | 4 | 删除激活自动切默认 + MCP 重挂 | ✅ 删死地址连接 → 自动切默认 GEMWIN → MCP 恢复 connected + 10 工具 | | 5 | 失败不崩(Q5) | ✅ 激活死地址 → state=error(fetch failed),插件其余功能正常 | | 6 | mcp-status(refresh=检测按钮语义) | ✅ refresh:true 即时探测 connected + 10 | | 7 | sync-status.mcp 域(头部灯数据源) | ✅ state/url/mounted/toolCount/latencyMs/checkedAt 齐全 | | 8 | 客户端接线 | ✅ build 产物含「MCP」指示灯 + 设置页「检测 MCP」按钮 + header.actions/settings.section 注册 | | 9 | MCP 工具端到端实测 | ✅ qmt_kline 取 000333.SZ 近一个月日 K(30 根 OHLCV,区间 -4.27%) | | 10 | 构建 | ✅ typecheck + pnpm build 通过(lib/mcp/QmtMcpManager.js 产出) | ## 过程事实 1. **需求讨论定稿**:老师指令(2026-09-08)→ R-020 登记 → Q1-Q6 逐项拍板(只挂激活连接 / 移除三方 / url 自动派生 / 双状态出口 / 失败重连采纳 / 不做通用 MCP 管理); 2. **老师指令修正(关键)**:AI 一度把「动态挂载官方 dsh-mcp-client」误读为要自研协议,先撤依赖后澄清——老师明确:不要的是**三方 dsh-skill-mcp-panel**,**官方 @deepseek-ai/dsh-mcp-client 可以依赖**;文档同步更正(R-020 / PLAN-018 / 迭代目标 / 索引); 3. **依赖可行性实证(PLAN-018 步骤 1)**:@deepseek-ai/dsh-mcp-client@0.1.1-rc.2(registry 有)加为 dependencies,从插件 lib 实证可 import,模块导出 {name:mcp-client, inject:[tools], apply, Config} → ctx.plugin() 动态挂载可行(mcp_router 同款路径);@modelcontextprotocol/sdk@1.30.0 供独立状态探测(dsh-mcp-client 不暴露状态 API); 4. **实现**:src/mcp/QmtMcpManager.js(挂/卸/resync/probe/getStatus/dispose);index.js 接线(start + dispose + registerApi runtime);api/qmt-connections.js(mcp-status + activate/update/remove 三热切换点 resync);api/market.js(sync-status.mcp 域);客户端 SyncIndicators(四灯 + MCP)+ SettingsSection(MCP 状态条 + 检测按钮);tsdown 增 mcp 域入口; 5. **宿主迁移(老师执行,验收方确认)**:cordis.patch.yml 受管块清空 + dsh-skill-mcp-panel 卸载 + 宿主重启 → 神之一手实例接管; 6. **验收**:服务端 8 项 + MCP 实测 + 构建全绿(上表); 7. **提交推送**:c700f2f(迭代18,16 files)+ 9382ace(迭代17 遗留文档补提交)→ origin/main。 ## 经验教训(复盘沉淀) ### 1. 「去掉对三方插件的依赖」要先问清:依赖边界到底指哪一层 AI 把老师「不希望依赖三方插件来加入 MCP 能力」误推到「也不能依赖 DSH 官方 mcp-client → 要自研 MCP 协议」,先动手撤了官方依赖、准备重造轮子;老师澄清后回撤。沉淀:**需求里「不依赖 X」先精确定位 X 是谁(管理面板 vs 执行插件),并确认官方能力是否允许复用;架构岔路口先问一句,别先动手拆**。 ### 2. 动态挂载子插件 = ctx.plugin(module, config),前提是模块在插件依赖树内可解析 mcp_router 实证了「import 官方模块 → ctx.plugin()」路径;one-divine-lot 照做时关键前置是把官方模块加进自己的 dependencies(而非 peer 裸声明),并用 createRequire 从插件 lib 路径实证解析成功再动代码。沉淀:**动态挂载依赖模块时,先验证「插件运行路径能解析到模块」这个前置条件(技术约束-003 语义外的新增实践)**。 ### 3. 状态查询与连接管理分离:dsh-mcp-client 不暴露状态 API 官方插件只管连接与工具注册,无状态查询口 → 用 @modelcontextprotocol/sdk 独立只读探测(initialize + tools/list 拿工具数/延迟),与官方自管连接互不干扰。沉淀:**外部能力库若不开状态口,用协议级只读探测补状态出口,不试图扒内部字段**。 ### 4. 验收期间临时造数要小心「先清后补」 用死地址测失败语义时两次 add 同名 TEST-DEAD 未清理(返回结构读错导致 id 取空),留下两条残留连接;发现后立即清理、用正确返回结构重测。沉淀:**验收脚本对临时数据的增删要成对且校验返回值;测试前后核对连接列表与激活态**。 ## 关联 - R-020(已定稿 → 已实现 → 本迭代验收通过);宿主三方 dsh-skill-mcp-panel 已移除(其「技能/MCP」设置菜单与受管块职责移交完成) - 新增依赖:@deepseek-ai/dsh-mcp-client@0.1.1-rc.2、@modelcontextprotocol/sdk@1.30.0 - 若需新增设计约束条目(如「插件内建 MCP 客户端注册规范」)——本迭代未新增,留待后续讨论(R-020 定稿时标注"如需…于定稿时补充"未触发)