This PR implements the latest changes introduced by https://github.com/modelcontextprotocol/modelcontextprotocol/pull/3002
97 lines
3.8 KiB
Markdown
97 lines
3.8 KiB
Markdown
<!-- Autogenerated by weave; DO NOT EDIT -->
|
|
# Troubleshooting
|
|
|
|
The Model Context Protocol is a complicated spec that leaves some room for
|
|
interpretation. Client and server SDKs can behave differently, or can be more
|
|
or less strict about their inputs. And of course, bugs happen.
|
|
|
|
When you encounter a problem using the Go SDK, these instructions can help
|
|
collect information that will be useful in debugging. Please try to provide
|
|
this information in a bug report, so that maintainers can more quickly
|
|
understand what's going wrong.
|
|
|
|
And most of all, please do [file bugs](https://github.com/modelcontextprotocol/go-sdk/issues/new?template=bug_report.md).
|
|
|
|
## Using the MCP inspector
|
|
|
|
To debug an MCP server, you can use the [MCP
|
|
inspector](https://modelcontextprotocol.io/legacy/tools/inspector). This is
|
|
useful for testing your server and verifying that it works with the typescript
|
|
SDK, as well as inspecting MCP traffic.
|
|
|
|
## Collecting MCP logs
|
|
|
|
For [stdio](protocol.md#stdio-transport) transport connections, you can also
|
|
inspect MCP traffic using a `LoggingTransport`:
|
|
|
|
```go
|
|
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)
|
|
}
|
|
|
|
// Output:
|
|
// 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"}}}
|
|
}
|
|
```
|
|
|
|
That example uses a `bytes.Buffer`, but you can also log to a file, or to
|
|
`os.Stderr`.
|
|
|
|
## Inspecting HTTP traffic
|
|
|
|
There are a couple different ways to investigate traffic to an HTTP transport
|
|
([streamable](protocol.md#streamable-transport) or legacy SSE).
|
|
|
|
The first is to use an HTTP middleware:
|
|
|
|
```go
|
|
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": {}}
|
|
}
|
|
```
|
|
|
|
The second is to use a general purpose tool to inspect http traffic, such as
|
|
[wireshark](https://www.wireshark.org/) or
|
|
[tcpdump](https://linux.die.net/man/8/tcpdump).
|