Loading... # 修复 mcporter 与 n9e-mcp-server SSE 连接挂起问题 # 一、事件概述 ## 1. 事件背景 用户在使用 mcporter 调用 Nightingale MCP 工具时,程序出现挂起现象。mcporter list 显示 nightingale 服务为 offline 状态,执行 mcporter call nightingale.list_active_alerts 命令时程序无响应。 ## 2. 影响范围 ### A. 影响功能 - Nightingale MCP 工具调用全部失败 - 无法通过 MCP 协议访问 Nightingale 监控数据 - 影响 list_active_alerts、list_history_alerts 等所有监控工具 ### B. 影响时长 调试过程持续约 2 小时,涉及多次代码修改和验证 ## 3. 严重程度 P2 级问题,影响特定 MCP 服务器的可用性 # 二、事件时间线 ## 1. 问题发现(初始阶段) ### A. 现象描述 执行 mcporter list 时,nightingale 显示为 "offline — unable to reach server" ### B. 初步判断 根据计划文件,问题根源是配置不匹配:mcporter 配置使用 stdio 模式,但 n9e-mcp-server 已切换到 HTTP SSE 模式运行。 ## 2. 配置调整(第一阶段) ### A. 处理措施 修改 /home/jacky/.claude/config/mcporter.json,将 nightingale 从 stdio 模式改为 HTTP SSE 模式 ### B. 效果评估 问题未解决,mcporter list 仍显示 nightingale 为 offline ## 3. 用户关键反馈(第二阶段) ### A. 发现途径 用户注意到服务器日志中 session_id 为空字符串:session_id="" ### B. 用户提问 "from the log i see session_id is null, shall this is the problem?" ## 4. SessionID 调查(第三阶段) ### A. 调研方法 通过 zread 工具检查 go-sdk 源代码 mcp/sse.go ### B. 关键发现 在 sseServerConn 和 sseClientConn 的 SessionID 方法中发现以下注释: ```go // TODO(jba): get the session ID. (Not urgent because SSE transports have been removed from the spec.) func (s *sseServerConn) SessionID() string { return "" } ``` ### C. 结论 空的 session_id 是预期行为,SSE 传输已从 MCP 规范中移除,不是问题根源 ## 5. 真实问题定位(第四阶段) ### A. 处理措施 使用 curl 直接测试 SSE 端点,验证服务器是否正常响应 ### B. 关键发现 curl 测试成功,SSE 流程正常工作。问题在于 mcporter 的传输模式回退逻辑: - 尝试 Streamable HTTP 模式:失败,提示 "sessionid must be provided" - 回退到 SSE 模式:挂起 ## 6. 配置文件定位(第五阶段) ### A. 处理措施 搜索并确认 mcporter 的实际配置文件位置 ### B. 关键发现 mcporter 使用 /home/jacky/.mcporter/mcporter.json,而非 /home/jacky/.claude/config/mcporter.json ### C. 修复措施 更新正确的配置文件,将 URL 从远程地址改为本地地址 ## 7. Token 认证逻辑修复(第六阶段) ### A. 问题分析 检查 n9e-mcp-server 的 HTTP 处理代码,发现所有请求(包括 POST 到 session endpoint)都强制要求 token 认证 ### B. 问题根因 POST 请求到 /mcp?sessionid=XXX 时,这些请求应仅使用 sessionid 认证,不应再次验证 token ### C. 修复措施 修改 /mydata/code/mcp/n9e-mcp-server/internal/http_server.go,添加条件判断: ```go mainHandler.HandleFunc("/mcp", func(w http.ResponseWriter, r *http.Request) { // POST 请求带 sessionid 直接转发到 SSE handler if r.Method == http.MethodPost && r.URL.Query().Get("sessionid") != "" { sseHandler.ServeHTTP(w, r) return } // 其他请求需要 token 认证 token := r.URL.Query().Get("token") if token == "" { http.Error(w, "token parameter required", http.StatusUnauthorized) return } sseHandler.ServeHTTP(w, r) }) ``` ### D. 效果评估 mcporter list 成功显示 "nightingale (27 tools, 0.1s)",SSE 连接正常建立 ## 8. Nightingale API 401 问题(第七阶段) ### A. 现象描述 SSE 连接正常后,工具调用返回 "client error: 401 unauthorized" ### B. 处理措施 检查容器网络配置,发现容器 IP 为 172.30.0.2(Docker bridge 网络),而 Nightingale 服务器在 192.168.124.79 ### C. 修复措施 修改 docker-compose.yml,将 network_mode 改为 host 模式 ### D. 当前状态 仍返回 401 错误,问题根源是 Nightingale 服务器端的配置,需要在 config.toml 中启用 HTTP.TokenAuth.Enable = true ```mermaid sequenceDiagram participant M as mcporter participant C as 配置文件 participant S as n9e-mcp-server participant N as Nightingale API M->>C: 读取配置(错误位置) M->>S: 尝试 stdio 连接 S-->>M: 连接失败 M->>C: 读取配置(正确位置) M->>S: GET /mcp?token=xxx S->>S: 验证 token S-->>M: endpoint 事件 M->>S: POST /mcp?sessionid=XXX Note over S: token 验证拦截(问题) S-->>M: 401 unauthorized Note over S: 修复后:跳过 token 验证 M->>S: POST /mcp?sessionid=XXX S-->>M: SSE 消息 M->>N: 调用 API N-->>M: 401 unauthorized(服务器配置问题) ```  # 三、问题分析 ## 1. 直接原因 n9e-mcp-server 的 HTTP 处理器对所有请求强制执行 token 认证,包括已建立 SSE 会话的 POST 请求 ## 2. 根本原因(5 Whys 分析) ### A. 为什么出现这个问题? 代码未区分初始连接请求和会话请求,统一要求 token 认证 ### B. 为什么没有及时发现? 初始测试使用 GET 请求建立 SSE 连接,这种场景下 token 验证是正确的,问题仅在后续 POST 请求时暴露 ### C. 为什么 SSE 会话请求不需要 token? SSE 协议流程规定: 1. 初始 GET 请求使用 token 建立连接 2. 服务器返回 endpoint 事件,包含 sessionid 3. 后续 POST 请求仅使用 sessionid 作为认证依据 ### D. 为什么容器网络问题会影响 API 调用? Nightingale 服务器配置了 IP 白名单,容器 IP 不在白名单内 ### E. 为什么 401 问题仍未完全解决? 这是 Nightingale 服务器端的配置问题,不在 n9e-mcp-server 代码范围内 ## 3. 深层反思 - mcporter 的配置文件位置不符合预期(~/.mcporter/ 而非 ~/.claude/config/) - go-sdk 中 SessionID 返回空字符串的注释容易引发误解 - HTTP 服务器的认证逻辑需要区分不同类型的请求 # 四、解决方案 ## 1. 临时方案 ### A. 实施措施 无临时方案,问题根因明确,直接进行代码修复 ## 2. 永久方案 ### A. 代码层面改进 修改 http_server.go,对 POST 请求添加 sessionid 检查,跳过 token 认证 ### B. 配置层面改进 更新 mcporter 配置为正确的 HTTP SSE 模式,使用正确的配置文件路径 ### C. 网络层面改进 Docker 容器使用 host 网络模式,避免 IP 限制问题 ## 3. 预防措施 ### A. 代码审查 在代码 Review 时关注认证逻辑的边界条件 ### B. 文档完善 明确说明 mcporter 的配置文件位置 ### C. 测试覆盖 增加 SSE 会话请求的测试用例 # 五、经验总结 ## 1. 做得好的地方 - 通过 curl 测试隔离了问题范围 - 检查 go-sdk 源码确认了 session_id 行为的预期性 - 系统化排查流程,从配置到代码到网络 ## 2. 需要改进的地方 - 未尽早确认 mcporter 的配置文件位置 - 对 SSE 协议的认证流程理解不够深入 ## 3. 流程优化建议 - 建立 MCP 服务器调试 checklist - 明确各工具的配置文件位置规范 - 记录常见协议流程(SSE、stdio)的差异点 # 六、参考资料 1. [MCP 规范文档](https://spec.modelcontextprotocol.io/) 2. [go-sdk 源代码](https://github.com/modelcontextprotocol/go-sdk) 3. [Nightingale API 文档](https://flashcat.cloud/docs/content/flashcat-monitor/nightingale-v8/usecase/api/) 最后修改:2026 年 03 月 02 日 © 允许规范转载 赞 如果觉得我的文章对你有用,请随意赞赏