Files
cc-web/.planning/2026-09-12-ccweb-mcp-create-failure/findings.md

40 lines
3.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 调查发现
## 用户现象
- 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 和无最终状态通知的回归场景。