3.5 KiB
3.5 KiB
调查发现
用户现象
- 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_conversations60 秒工具调用超时,说明客户端失败后仍可能继续尝试调用失效连接。
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 和无最终状态通知的回归场景。