修复 ccweb MCP 启动与重载并重新打包

This commit is contained in:
shiyue
2026-09-12 21:13:30 +08:00
parent 965aefe9a4
commit d9db66ca8f
10 changed files with 217 additions and 28 deletions

View File

@@ -0,0 +1,39 @@
# 调查发现
## 用户现象
- ccweb MCP 创建对话有时失败。
- 创建失败后重载 MCP 也挂载不上,导致当前对话不可继续使用。
- 截图中的 `$log-ccweb-title` 提示显示:当前会话没有提供 `ccweb_list_conversations``ccweb_set_title``wiznote_mcp_wiz_*` 工具,因此无法获取对话 ID无法安全写入 `/coding` 日志。
## 代码与运行证据
### 1. MCP 冷启动窗口固定为 10 秒
- `server.js:3528-3572``buildCcwebMcpRuntimeConfig()` 在 streamable HTTP 和 stdio 两条路径都固定写入 `startup_timeout_sec: 10`,工具调用窗口为 60 秒。
- 历史会话 `723ffd3f-71fc-42ee-87b6-768836316099``4c0f6be3-b46c-4ec0-b6f5-03c31188b7d8``5ed15712-312c-4d1b-b629-3d3a3c0d06a7` 均持久化了:`MCP client for ccweb timed out after 10 seconds`
- 同一批历史记录随后出现 `ccweb_list_conversations` 60 秒工具调用超时,说明客户端失败后仍可能继续尝试调用失效连接。
### 2. 创建对话成功不等于目标 MCP 已就绪
- `createMcpConversation()` 先通过 `createPersistentConversationSession()` 写入会话文件,再调用 `sendCrossConversationMessage()` 投递首条消息。
- `sendCrossConversationMessage()` 调用 `handleMessage()`Codex App 分支的 `handleCodexAppMessage()` 只登记 active turn 并异步执行 `startCodexAppTurn(...).catch(...)`,立即返回 `{ ok: true }`
- 因此创建接口返回的 `ok/status=running` 只表示“会话已落盘、首轮已开始”,不保证首轮完成,更不保证 ccweb MCP 已 ready。MCP 启动失败会在返回之后发生。
### 3. 重载状态关联存在 threadId 严格匹配竞态
- `handleReloadMcpApi()``markCodexAppMcpReloadPending()` 后调用无 thread 参数的 `config/mcpServer/reload`,并只等待 `CODEX_APP_MCP_RELOAD_STATUS_WAIT_MS = 1200` 毫秒。
- `codexAppMcpStatusTargetSessionIds()` 对 pending 会话要求 `statusRecord.threadId === pending.threadId`;不一致时直接跳过。
- `logs/process.old.log:6713-6721` 中,重载请求针对 `019ff161-...`,随后上报的是 `019fef64-...``019fef0f-...`,且全部 `targetSessions=0`。对应会话 `b73e4b07-4aaa-43d5-906b-413747a09f4b` 最终仍持久化为 `ccweb.status=starting/rawStatus=pending`
- `cleanupExpiredCodexAppMcpReloads()` 只删除内存 pending 映射,不会把持久化状态从 `starting/pending` 改成失败或可重试,因此会话在 UI 上长期像“挂载中”。
### 4. 当前环境可复现“并发启动时序差异”
- 当前调查会话的 `ccweb` 最终为 `ready`,但同一线程的 `playwright` 在 20 秒后失败,说明多个 MCP 并发启动时不同服务的 ready/fail 到达时间并不一致;固定 10 秒窗口和 1.2 秒重载等待会放大这个时序问题。
## 已实施修复
- `server.js``lib/agent-runtime.js`ccweb MCP 默认启动超时提高到 30 秒,工具超时和 reload 等待窗口支持环境变量覆盖reload 默认等待 35 秒。
- `server.js`reload pending 记录允许同一 app-server 的全局 reload 通知跨 threadId 关联;等待窗口结束仍未收到 ready/failed/cancelled 时,将持久化状态收敛为 `failed` 并标记可重试。
- `server.js`Codex App 创建对话结果附带当前 `mcpStatus`;首条消息投递失败时保留会话 ID、失败阶段和可重试标记避免“已创建的会话”被误认为完全不存在。
- `scripts/mock-codex-app-server.js``scripts/regression.js`:新增无关 threadId 和无最终状态通知的回归场景。

View File

@@ -0,0 +1,13 @@
# 调查进度
## 记录
- 2026-09-12建立本轮 scoped 排查计划;确认 codebase-memory 项目 `home-cc-web` 索引状态为 ready。
- 2026-09-12截图现象先记录为“当前会话 MCP 工具未注入/不可见”,待与创建和重载链路对照。
- 2026-09-12确认 `buildCcwebMcpRuntimeConfig()` 两条传输路径均固定 `startup_timeout_sec=10`;历史会话持久化了 ccweb 10 秒超时。
- 2026-09-12确认 `createMcpConversation()` 的首条消息通过 `handleCodexAppMessage()` 异步启动,接口返回不等待目标线程/MCP ready。
- 2026-09-12确认 reload 仅等待 1200ms状态通知按 threadId 严格关联;历史日志出现请求线程与上报线程不一致、`targetSessions=0`,导致会话持久化为 `starting/pending`
- 2026-09-12用户确认进入修复实施已将 ccweb MCP 启动超时、工具超时、reload 等待窗口改为可配置,默认分别为 30 秒、60 秒、35 秒。
- 2026-09-12已修正 reload 的跨 threadId 全局状态关联,并在等待窗口超时后持久化 `failed` 状态和可重试提示。
- 2026-09-12创建对话结果补充 Codex App MCP 状态;首条消息投递失败保留会话 ID、creationStatus 和 retryable 元数据。
- 2026-09-12mock + 完整 regression 已通过;未重启服务,待收尾清理临时清单。

View File

@@ -0,0 +1,25 @@
# ccweb MCP 创建对话失败与重载失败排查
## 目标
定位 ccweb MCP 创建新对话偶发失败、失败后重载 MCP 无法挂载的共同根因,判断是否需要修复代码并完成最小回归验证。
## 阶段
- [completed] 梳理现有 MCP 配置与重载回归入口
- [completed] 提高并配置 ccweb MCP 启动与重载等待窗口
- [completed] 修正重载状态的 threadId 关联与超时收敛
- [completed] 补充创建对话的 MCP 状态可见性与失败信息
- [completed] 补充回归断言并运行相关验证
- [completed] 清理临时清单并汇总交付风险
## 约束
- 使用 codebase-memory-mcp 做代码定位rg 只做行号与文本补充校验。
- 不覆盖用户已有未提交改动。
- 仅在确认根因且改动属于本问题范围时修改业务代码。
## 错误记录
| 错误 | 尝试 | 处理 |
|---|---:|---|