Go SDK MCP 故障排查实战:MCP Inspector、LoggingTransport 与 HTTP 流量捕获

Go SDK MCP 故障排查实战:MCP Inspector、LoggingTransport 与 HTTP 流量捕获 Go SDK MCP 故障排查实战MCP Inspector、LoggingTransport 与 HTTP 流量捕获【免费下载链接】go-sdkThe official Go SDK for Model Context Protocol servers and clients. Maintained in collaboration with Google.项目地址: https://gitcode.com/GitHub_Trending/gosdk23/go-sdkModel Context ProtocolMCP规范复杂且存在一定的解释空间不同客户端/服务端 SDK 对输入的严格程度也不一致再加上不可避免的 bug接入 go-sdk 时难免会遇到问题。本篇指南以仓库中的 troubleshooting.src.md 为骨架结合mcp包的源码与示例测试完整讲解三套调试手段用 MCP Inspector 验证服务器行为、用LoggingTransport收集 JSON-RPC 级别的 MCP 日志、以及用 HTTP 中间件或抓包工具检查 HTTP 传输流量。读完你将能够自主定位客户端与服务端之间的协议偏差并写出信息完整、可供维护者快速复现的 bug 报告。为什么需要系统化排查MCP 是一个允许留白的协议规范中的某些行为可以被不同实现以不同方式解释客户端 SDK 与服务端 SDK 可能行为不一致也可能对输入宽松或严格程度不一。当使用 Go SDK 遇到问题时仅凭报错信息往往难以定位因为问题可能出在JSON-RPC 消息本身的编解码transport 层stdio / streamable / SSE的会话与流处理协议版本的协商SDK 支持2026-07-28、2025-11-25、2025-06-18、2025-03-26、2024-11-05等多个版本见 transport_example_test.go 中的输出样例双方对 capabilities、日志级别等元数据的理解差异。因此官方文档给出的首要建议是收集信息再提 bug。在向维护者提交问题时请尽量附带下文所述的日志与流量证据这样能显著加快问题定位速度。使用 MCP Inspector 调试服务器[MCP Inspector] 是官方提供的交互式调试工具。它的核心价值在于以可视化方式测试你的 MCP 服务器验证其行为是否符合预期验证服务器与 TypeScript SDK 的互操作性spec 允许解释空间跨 SDK 验证能暴露实现差异直接查看 MCP 请求/响应流量观察每个 JSON-RPC 消息的完整内容。适用场景服务器能启动但表现异常、需要确认某个工具/资源/提示词是否按协议返回、或者想快速验证新写的 handler 是否被正确注册。Inspector 是黑盒视角的第一道检查适合在深入代码之前快速缩小问题范围。收集 MCP 日志LoggingTransport对于 stdio 传输客户端通过CommandTransport启动子进程、服务端通过StdioTransport连接当前进程的 stdin/stdout双方以换行分隔的 JSON 通信这类看不见网络包的连接SDK 提供了LoggingTransport来拦截并记录经过 transport 的每一条 JSON-RPC 消息。使用示例以下完整示例来自 transport_example_test.go它用内存传输NewInMemoryTransports演示了LoggingTransport的接入方式——只需把LoggingTransport包在原始 transport 外面即可func ExampleLoggingTransport() { ctx : context.Background() t1, t2 : mcp.NewInMemoryTransports() server : mcp.NewServer(mcp.Implementation{Name: server, Version: v0.0.1}, nil) serverSession, err : server.Connect(ctx, t1, nil) if err ! nil { log.Fatal(err) } defer serverSession.Close() client : mcp.NewClient(mcp.Implementation{Name: client, Version: v0.0.1}, nil) var b bytes.Buffer logTransport : mcp.LoggingTransport{Transport: t2, Writer: b} clientSession, err : client.Connect(ctx, logTransport, nil) if err ! nil { log.Fatal(err) } defer clientSession.Close() // Sort for stability: reads are concurrent to writes. for _, line : range slices.Sorted(strings.SplitSeq(b.String(), \n)) { fmt.Println(line) } }LoggingTransport只有两个字段Transport被包装的原始传输和Writer日志写入目标。示例输出大致如下每条消息一行前缀标明方向read: {jsonrpc:2.0,id:1,result:{resultType:complete,_meta:{io.modelcontextprotocol/serverInfo:{name:server,version:v0.0.1}},ttlMs:0,cacheScope:public,supportedVersions:[2026-07-28,2025-11-25,2025-06-18,2025-03-26,2024-11-05],capabilities:{logging:{}}}} write: {jsonrpc:2.0,id:1,method:server/discover,params:{_meta:{io.modelcontextprotocol/clientCapabilities:{roots:{listChanged:true}},io.modelcontextprotocol/clientInfo:{name:client,version:v0.0.1},io.modelcontextprotocol/protocolVersion:2026-07-28}}}示例中使用bytes.Buffer把日志暂存在内存里实际排查时你也可以写入文件如os.Create(mcp.log)便于长期留存与比对写入os.Stderr让日志直接汇入终端/日志采集系统。提示在真实 stdio 场景中把LoggingTransport包在mcp.CommandTransport外层即可捕获客户端发出的每个请求与服务端返回的每条响应服务端侧同样可包在StdioTransport外层。实现原理一个可插拔的流中间件从源码看LoggingTransport是一个符合Transport接口的装饰器// A LoggingTransport is a [Transport] that delegates to another transport, // writing RPC logs to an io.Writer. type LoggingTransport struct { Transport Transport Writer io.Writer }Connect时它先连接底层 transport再返回一个包装后的loggingConntransport.go。真正的记录逻辑在Read/Write两个流中间件方法中transport.goRead读取底层消息成功后用jsonrpc2.EncodeMessage序列化并以read: json格式写出失败则输出read error: ...Write写出消息成功后以write: json记录失败则输出write error: ...序列化失败时会记录LoggingTransport: failed to marshal: ...内部通过sync.Mutex保证并发读写时日志行不交错。这意味着你看到的就是实际在线路上传输的原始 JSON-RPC 消息——包括_meta元数据、协议版本协商、capabilities 等细节是定位客户端发的和服务器收到的不一样协议版本不匹配capabilities 缺失等问题的第一手证据。该类型也在mcp包的测试中被直接使用见 mcp_test.go说明其行为有测试用例保障。检查 HTTP 流量streamable / SSE 传输对于基于 HTTP 的传输——streamable transport由StreamableHTTPHandler、StreamableServerTransport、StreamableClientTransport三个类型实现以及 Legacy SSE transportSSEHandler、SSEServerTransport、SSEClientTransport——有两类检查手段。方式一HTTP 中间件以下完整示例来自 streamable_example_test.go。思路是在StreamableHTTPHandler外面再包一层http.HandlerFunc在转发给真正的 handler 之前读取并打印请求体注意读取后要用io.NopCloser恢复 body保证后续 handler 仍能正常读取func ExampleStreamableHTTPHandler_middleware() { server : mcp.NewServer(mcp.Implementation{Name: server, Version: v0.1.0}, nil) handler : mcp.NewStreamableHTTPHandler(func(r *http.Request) *mcp.Server { return server }, mcp.StreamableHTTPOptions{Stateless: true}) loggingHandler : http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { // Example debugging; you could also capture the response. body, err : io.ReadAll(req.Body) if err ! nil { log.Fatal(err) } req.Body.Close() // ignore error req.Body io.NopCloser(bytes.NewBuffer(body)) fmt.Println(req.Method, string(body)) handler.ServeHTTP(w, req) }) httpServer : httptest.NewServer(loggingHandler) defer httpServer.Close() // The SDK is currently permissive of some missing keys in params. mustPostMessage({jsonrpc: 2.0, id: 1, method:initialize, params: {}}, httpServer.URL) // Output: // POST {jsonrpc: 2.0, id: 1, method:initialize, params: {}} }输出示例POST {jsonrpc: 2.0, id: 1, method:initialize, params: {}}这种做法的优势是与具体服务器框架无关、可随服务一起部署你可以在中间件里记录请求方法、URL、请求体也可以像代码注释提示的那样capture the response包装ResponseWriter记录响应体甚至统计耗时。仓库中的 examples/http/logging_middleware.go 还演示了基于 SDKmcp.Middleware接口在应用层记录每次方法调用的会话 ID、方法名、耗时与错误状态与 transport 层的 HTTP 中间件互补。方式二通用抓包工具中间件只覆盖你自己部署的服务端或你自己代码里的客户端。如果要观察完整链路——包括客户端与服务器之间的真实网络交互、TLS 握手、HTTP/1.1 与 HTTP/2 的差异、长连接与 SSE 流的分帧行为——可以使用通用的抓包/流量分析工具Wireshark图形化界面可过滤 HTTP 流量并逐帧查看请求/响应头与正文适合分析 SSE 流式响应的事件帧tcpdump命令行抓包适合在服务器或容器内快速抓取原始报文配合-w导出 pcap 文件供 Wireshark 离线分析。对于 streamable 传输特别值得关注的是text/event-stream响应中消息的分帧、会话 ID 的传递以及 2026-07-28 及以后协议版本的 MCP 专用 HTTP 头如Mcp-Protocol-Version、Mcp-Session-Id、Mcp-Method、Mcp-Name详见 protocol.src.md 中的说明——这些细节只有抓包或 HTTP 中间件才能完整呈现。排查时的补充提示区分两类日志LoggingTransport记录的是 transport 层 JSON-RPC 消息排查协议问题用SDK 另有面向 MCP 规范 logging 特性的LoggingHandlerslog.Handler实现见 logging.go它把服务器应用日志通过logging/notification推送给客户端两者不要混淆。logging 特性已弃用从协议版本2026-07-28起SEP-2577logging 特性进入弃用窗口至少十二个月内仍可用相关类型如LoggingHandlerOptions已被标记为 Deprecated见 logging.go。排查时优先使用本文介绍的 transport/HTTP 层手段。多协议版本协商日志中supportedVersions字段列出了 SDK 支持的协议版本列表如果客户端与服务器协商出的版本不一致往往是诸多诡异行为的根源抓到的原始消息能直接证实这一点。如何提交一份有效的 bug 报告官方排查文档强调遇到问题请务必提 bug在 go-sdk 仓库的 Issues 中选用 bug report 模板提交。一份高质量报告应包含复现步骤环境Go 版本、操作系统、客户端/服务器代码的 minimal 复现MCP 日志使用LoggingTransport捕获的read:/write:原始 JSON-RPC 消息HTTP 流量中间件打印的请求/响应或 tcpdump/Wireshark 抓包结果预期行为与实际行为的对比描述协议版本信息协商结果、supportedVersions列表。信息越完整维护者越能快速定位问题——这正是本文所有调试手段的最终目的。小结先用MCP Inspector做黑盒验证确认服务器整体行为与跨 SDK 互操作性对stdio连接用LoggingTransport捕获逐条 JSON-RPC 消息可写bytes.Buffer、文件或os.Stderr对streamable / SSE连接用 HTTP 中间件可同时记录请求与响应或 Wireshark/tcpdump 抓包将收集到的日志、流量与复现步骤一并写入 bug 报告交给维护者。上述所有示例均为仓库内可运行、有断言输出的 Go 示例测试transport_example_test.go、streamable_example_test.go你可以直接复制到自己的调试代码中按需改造。【免费下载链接】go-sdkThe official Go SDK for Model Context Protocol servers and clients. Maintained in collaboration with Google.项目地址: https://gitcode.com/GitHub_Trending/gosdk23/go-sdk创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考