docs: add MCP debugging summary
This commit is contained in:
126
docs/mcp-debugging-summary.md
Normal file
126
docs/mcp-debugging-summary.md
Normal file
@@ -0,0 +1,126 @@
|
||||
# MCP 调试记录(Tao-Memory-Server / RikkaHub / Lucky)
|
||||
|
||||
> 目标:解决移动端 MCP 客户端(MOMERY‑PRO / RikkaHub)连接异常(-32000 / Connection closed)并完成握手与工具调用。
|
||||
> 项目路径:`/root/.openclaw/workspace/tao_mcp_go`
|
||||
> 反向代理:Lucky
|
||||
> 服务端口:5001
|
||||
|
||||
---
|
||||
|
||||
## 一、现象与症状
|
||||
|
||||
- 客户端能发起 `GET /mcp/sse` 与 `POST /mcp/message`,但出现:
|
||||
- `-32000: Connection closed`
|
||||
- POST 进入后端但 10~30s 超时后断开
|
||||
- initialize 反复重试,未进入 tools/list
|
||||
|
||||
---
|
||||
|
||||
## 二、关键问题定位 & 解决方案
|
||||
|
||||
### 1) JSON‑RPC initialize 返回格式不被客户端认可
|
||||
**现象**:initialize 请求到了,但客户端无后续动作(反复初始化)。
|
||||
|
||||
**解决**:
|
||||
- `MCPResponse.Result` 改为 `any`,允许返回 protocolVersion/capabilities 等结构。
|
||||
- 增加 initialize 返回:
|
||||
- `protocolVersion`
|
||||
- `capabilities.tools/resources/prompts`
|
||||
- `serverInfo`
|
||||
|
||||
### 2) CORS 预检/响应问题导致移动端丢弃响应
|
||||
**现象**:OPTIONS 或 POST 可能被丢弃,客户端视为连接失败。
|
||||
|
||||
**解决**:
|
||||
- `requireAuth` 中放行 `OPTIONS`,返回 200 + 允许头
|
||||
- `MessageHandler` 每次响应前统一设置:
|
||||
- `Access-Control-Allow-Origin: *`
|
||||
- `Access-Control-Allow-Methods: GET, POST, OPTIONS`
|
||||
- `Access-Control-Allow-Headers: Content-Type, Authorization`
|
||||
|
||||
### 3) SSE 端点返回错误导致路径拼接异常
|
||||
**现象**:客户端生成 /mcp/mcp 或 /mcp/https://…
|
||||
|
||||
**解决**:
|
||||
- 增加 `TAO_ENDPOINT_STYLE=message`,SSE 发送 `event: endpoint` 为 `message?token=...`
|
||||
|
||||
### 4) Lucky 反代缓冲导致 SSE 首包/POST 响应丢失
|
||||
**现象**:SSE 未及时下发 endpoint;POST 处理后客户端超时。
|
||||
|
||||
**解决**:
|
||||
- SSE 头加入:`X-Accel-Buffering: no`
|
||||
- SSE 建立后立即 `Flush()`
|
||||
- 心跳从 15s 调整为 5s
|
||||
|
||||
### 5) 协议版本不匹配导致客户端拒绝
|
||||
**现象**:客户端请求协议 2025‑06‑18,服务端返回 2024‑11‑05,握手失败。
|
||||
|
||||
**解决**:
|
||||
- initialize 返回 `protocolVersion: 2025-06-18`
|
||||
|
||||
### 6) 识别 notifications/initialized
|
||||
**现象**:握手成功后仍死循环。
|
||||
|
||||
**解决**:
|
||||
- 增加对 `notifications/initialized` 的处理与日志
|
||||
|
||||
### 7) POST 返回体被 Lucky 缓冲 / Chunked 不一致
|
||||
**现象**:POST 返回体被代理吞掉或不及时转发。
|
||||
|
||||
**尝试**:
|
||||
- 强制设置 `Content-Length`
|
||||
- 禁用缓冲 `X-Accel-Buffering: no`
|
||||
- 取消 `Connection: close`
|
||||
|
||||
> 此阶段仍存在“initialize 循环”问题,最终采用异步 SSE 方案解决。
|
||||
|
||||
---
|
||||
|
||||
## 三、终极解决方案:异步 SSE 通道模式(MCP 正式规范)
|
||||
|
||||
**核心思路**:
|
||||
- POST 只作为“投递箱”,立即返回 `202 Accepted`
|
||||
- 所有 JSON‑RPC 结果通过 SSE `event: message` 下发
|
||||
|
||||
**关键实现**:
|
||||
- `SSEHandler`:建立 `token -> chan` 的映射,并在 `select` 中写入 `event: message`
|
||||
- `MessageHandler`:读取 JSON 后立即 202,异步 `dispatchMCP()` 处理
|
||||
- `dispatchMCP()`:根据 method 生成响应,写入对应 token 的 SSE 通道
|
||||
|
||||
**日志验证**:
|
||||
- `[SSE Connect]` → SSE 已连
|
||||
- `[MCP POST]` → POST 到达
|
||||
- `[MCP Response] sent via SSE` → 回复已通过 SSE 下发
|
||||
- `[MCP Notify] initialized` → 客户端确认握手完成
|
||||
- `tools/list` 成功返回
|
||||
|
||||
---
|
||||
|
||||
## 四、最终生效状态(已验证)
|
||||
|
||||
日志证据显示握手完成:
|
||||
- initialize → notifications/initialized → tools/list
|
||||
- 全流程通过 SSE message 传输
|
||||
|
||||
---
|
||||
|
||||
## 五、关键配置(供后续复盘)
|
||||
|
||||
- 服务:`tao-mcp-go.service`
|
||||
- 端口:5001
|
||||
- 反代:Lucky
|
||||
- SSE URL:`https://mcp.good.xx.kg/mcp/sse?token=...`
|
||||
- Message URL:`https://mcp.good.xx.kg/mcp/message?token=...`
|
||||
|
||||
---
|
||||
|
||||
## 六、建议后续工作
|
||||
|
||||
1. 清理调试日志(POST body / SSE connect)
|
||||
2. 增加 tools/call 执行日志
|
||||
3. 在 README 中补充“异步 SSE 模式说明”
|
||||
4. 如需兼容同步模式,建议单独开新路由避免混用
|
||||
|
||||
---
|
||||
|
||||
> 本文档用于存档,建议上传到仓库 `docs/` 目录。
|
||||
Reference in New Issue
Block a user