迭代18归档: 需求 R-020 移入已完成(验收通过)+ 迭代复盘 + 索引更新

This commit is contained in:
2026-09-09 09:03:48 +08:00
parent c700f2f760
commit 8782aa9c50
3 changed files with 61 additions and 4 deletions
@@ -0,0 +1,53 @@
# 迭代复盘: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-clientserverName 固定 QMT_Bridge_MCPurl 自动派生自激活连接 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+/mcpQ3 |
| 3 | 激活切换联动 | ✅ 切 QMT_CYY → 192.168.3.43:8610/mcp connected;切回 GEMWIN 恢复 |
| 4 | 删除激活自动切默认 + MCP 重挂 | ✅ 删死地址连接 → 自动切默认 GEMWIN → MCP 恢复 connected + 10 工具 |
| 5 | 失败不崩(Q5) | ✅ 激活死地址 → state=errorfetch failed),插件其余功能正常 |
| 6 | mcp-statusrefresh=检测按钮语义) | ✅ 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 近一个月日 K30 根 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.2registry 有)加为 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.jsmcp-status + activate/update/remove 三热切换点 resync);api/market.jssync-status.mcp 域);客户端 SyncIndicators(四灯 + MCP+ SettingsSectionMCP 状态条 + 检测按钮);tsdown 增 mcp 域入口;
5. **宿主迁移(老师执行,验收方确认)**cordis.patch.yml 受管块清空 + dsh-skill-mcp-panel 卸载 + 宿主重启 → 神之一手实例接管;
6. **验收**:服务端 8 项 + MCP 实测 + 构建全绿(上表);
7. **提交推送**c700f2f(迭代1816 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 定稿时标注"如需…于定稿时补充"未触发)