Skip to content

Commit 8d8891b

Browse files
committed
add troubleshooting guide
1 parent 5ce1eae commit 8d8891b

File tree

11 files changed

+202
-11
lines changed

11 files changed

+202
-11
lines changed

docs/client.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!-- Autogenerated by weave; DO NOT EDIT -->
2-
# Support for MCP Client Features
2+
# Support for MCP client features
33

44
1. [Roots](#roots)
55
1. [Sampling](#sampling)

docs/protocol.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!-- Autogenerated by weave; DO NOT EDIT -->
2-
# Support for the MCP Base protocol
2+
# Support for the MCP base protocol
33

44
1. [Lifecycle](#lifecycle)
55
1. [Transports](#transports)
@@ -48,7 +48,8 @@ func ExampleStreamableHTTPHandler() {
4848
// The SDK is currently permissive of some missing keys in "params".
4949
resp := mustPostMessage(`{"jsonrpc": "2.0", "id": 1, "method":"initialize", "params": {}}`, httpServer.URL)
5050
fmt.Println(resp)
51-
// Output: {"jsonrpc":"2.0","id":1,"result":{"capabilities":{"logging":{}},"protocolVersion":"2025-06-18","serverInfo":{"name":"server","version":"v0.1.0"}}}
51+
// Output:
52+
// {"jsonrpc":"2.0","id":1,"result":{"capabilities":{"logging":{}},"protocolVersion":"2025-06-18","serverInfo":{"name":"server","version":"v0.1.0"}}}
5253
}
5354
```
5455

docs/tools.md

Lines changed: 0 additions & 2 deletions
This file was deleted.

docs/troubleshooting.md

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,90 @@
11
<!-- Autogenerated by weave; DO NOT EDIT -->
22
# Troubleshooting
3+
4+
The Model Context Protocol is a complicated spec that leaves some room for
5+
interpretation. Client and server SDKs can behave differently, or can be more
6+
or less strict about their inputs. And of course, bugs happen.
7+
8+
When you encounter a problem using the Go SDK, these instructions can help
9+
collect information that will be useful in debugging. Please try to provide
10+
this information in a bug report, so that maintainers can more quickly
11+
understand what's going wrong.
12+
13+
And most of all, please do [file bugs](https://github.com/modelcontextprotocol/go-sdk/issues/new?template=bug_report.md).
14+
15+
## Using the MCP inspector
16+
17+
To debug an MCP server, you can use the [MCP
18+
inspector](https://modelcontextprotocol.io/legacy/tools/inspector). This is
19+
useful for testing your server and verifying that it works with the typescript
20+
SDK, as well as inspecting MCP traffic.
21+
22+
## Collecting MCP logs
23+
24+
For [stdio](protocol.md#stdio-transport) transport connections, you can also
25+
inspect MCP traffic using a `LoggingTransport`:
26+
27+
```go
28+
func ExampleLoggingTransport() {
29+
ctx := context.Background()
30+
t1, t2 := mcp.NewInMemoryTransports()
31+
server := mcp.NewServer(&mcp.Implementation{Name: "server", Version: "v0.0.1"}, nil)
32+
if _, err := server.Connect(ctx, t1, nil); err != nil {
33+
log.Fatal(err)
34+
}
35+
36+
client := mcp.NewClient(&mcp.Implementation{Name: "client", Version: "v0.0.1"}, nil)
37+
var b bytes.Buffer
38+
logTransport := &mcp.LoggingTransport{Transport: t2, Writer: &b}
39+
if _, err := client.Connect(ctx, logTransport, nil); err != nil {
40+
log.Fatal(err)
41+
}
42+
fmt.Println(b.String())
43+
// Output:
44+
// write: {"jsonrpc":"2.0","id":1,"method":"initialize","params":{"capabilities":{"roots":{"listChanged":true}},"clientInfo":{"name":"client","version":"v0.0.1"},"protocolVersion":"2025-06-18"}}
45+
// read: {"jsonrpc":"2.0","id":1,"result":{"capabilities":{"logging":{}},"protocolVersion":"2025-06-18","serverInfo":{"name":"server","version":"v0.0.1"}}}
46+
// write: {"jsonrpc":"2.0","method":"notifications/initialized","params":{}}
47+
48+
}
49+
```
50+
51+
That example uses a `bytes.Buffer`, but you can also log to a file, or to
52+
`os.Stderr`.
53+
54+
## Inspecting HTTP traffic
55+
56+
There are a couple different ways to investigate traffic to an HTTP transport
57+
([streamable](protocol.md#streamable-transport) or legacy SSE).
58+
59+
The first is to use an HTTP middleware:
60+
61+
```go
62+
func ExampleStreamableHTTPHandler_httpMiddleware() {
63+
server := mcp.NewServer(&mcp.Implementation{Name: "server", Version: "v0.1.0"}, nil)
64+
handler := mcp.NewStreamableHTTPHandler(func(r *http.Request) *mcp.Server {
65+
return server
66+
}, nil)
67+
loggingHandler := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
68+
// Example debugging; you could also capture the response.
69+
body, err := io.ReadAll(req.Body)
70+
if err != nil {
71+
log.Fatal(err)
72+
}
73+
req.Body.Close() // ignore error
74+
req.Body = io.NopCloser(bytes.NewBuffer(body))
75+
fmt.Println(req.Method, string(body))
76+
handler.ServeHTTP(w, req)
77+
})
78+
httpServer := httptest.NewServer(loggingHandler)
79+
defer httpServer.Close()
80+
81+
// The SDK is currently permissive of some missing keys in "params".
82+
mustPostMessage(`{"jsonrpc": "2.0", "id": 1, "method":"initialize", "params": {}}`, httpServer.URL)
83+
// Output:
84+
// POST {"jsonrpc": "2.0", "id": 1, "method":"initialize", "params": {}}
85+
}
86+
```
87+
88+
The second is to use a general purpose tool to inspect http traffic, such as
89+
[wireshark](https://www.wireshark.org/) or
90+
[tcpdump](https://linux.die.net/man/8/tcpdump).

internal/docs/client.src.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Support for MCP Client Features
1+
# Support for MCP client features
22

33
%toc
44

internal/docs/doc.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,9 @@
33
// license that can be found in the LICENSE file.
44

55
//go:generate go run golang.org/x/example/internal/cmd/weave@latest -o ../../docs/README.md ./README.src.md
6-
//go:generate go run golang.org/x/example/internal/cmd/weave@latest -o ../../docs/client.md ./client.src.md
76
//go:generate go run golang.org/x/example/internal/cmd/weave@latest -o ../../docs/protocol.md ./protocol.src.md
7+
//go:generate go run golang.org/x/example/internal/cmd/weave@latest -o ../../docs/client.md ./client.src.md
88
//go:generate go run golang.org/x/example/internal/cmd/weave@latest -o ../../docs/server.md ./server.src.md
9-
//go:generate go run golang.org/x/example/internal/cmd/weave@latest -o ../../docs/tools.md ./tools.src.md
109
//go:generate go run golang.org/x/example/internal/cmd/weave@latest -o ../../docs/troubleshooting.md ./troubleshooting.src.md
1110

1211
// The doc package generates the documentation at /doc, via go:generate.

internal/docs/protocol.src.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Support for the MCP Base protocol
1+
# Support for the MCP base protocol
22

33
%toc
44

internal/docs/tools.src.md

Lines changed: 0 additions & 1 deletion
This file was deleted.
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,42 @@
11
# Troubleshooting
2+
3+
The Model Context Protocol is a complicated spec that leaves some room for
4+
interpretation. Client and server SDKs can behave differently, or can be more
5+
or less strict about their inputs. And of course, bugs happen.
6+
7+
When you encounter a problem using the Go SDK, these instructions can help
8+
collect information that will be useful in debugging. Please try to provide
9+
this information in a bug report, so that maintainers can more quickly
10+
understand what's going wrong.
11+
12+
And most of all, please do [file bugs](https://github.com/modelcontextprotocol/go-sdk/issues/new?template=bug_report.md).
13+
14+
## Using the MCP inspector
15+
16+
To debug an MCP server, you can use the [MCP
17+
inspector](https://modelcontextprotocol.io/legacy/tools/inspector). This is
18+
useful for testing your server and verifying that it works with the typescript
19+
SDK, as well as inspecting MCP traffic.
20+
21+
## Collecting MCP logs
22+
23+
For [stdio](protocol.md#stdio-transport) transport connections, you can also
24+
inspect MCP traffic using a `LoggingTransport`:
25+
26+
%include ../../mcp/transport_example_test.go loggingtransport -
27+
28+
That example uses a `bytes.Buffer`, but you can also log to a file, or to
29+
`os.Stderr`.
30+
31+
## Inspecting HTTP traffic
32+
33+
There are a couple different ways to investigate traffic to an HTTP transport
34+
([streamable](protocol.md#streamable-transport) or legacy SSE).
35+
36+
The first is to use an HTTP middleware:
37+
38+
%include ../../mcp/streamable_example_test.go httpmiddleware -
39+
40+
The second is to use a general purpose tool to inspect http traffic, such as
41+
[wireshark](https://www.wireshark.org/) or
42+
[tcpdump](https://linux.die.net/man/8/tcpdump).

mcp/streamable_example_test.go

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
package mcp_test
66

77
import (
8+
"bytes"
89
"fmt"
910
"io"
1011
"log"
@@ -31,11 +32,40 @@ func ExampleStreamableHTTPHandler() {
3132
// The SDK is currently permissive of some missing keys in "params".
3233
resp := mustPostMessage(`{"jsonrpc": "2.0", "id": 1, "method":"initialize", "params": {}}`, httpServer.URL)
3334
fmt.Println(resp)
34-
// Output: {"jsonrpc":"2.0","id":1,"result":{"capabilities":{"logging":{}},"protocolVersion":"2025-06-18","serverInfo":{"name":"server","version":"v0.1.0"}}}
35+
// Output:
36+
// {"jsonrpc":"2.0","id":1,"result":{"capabilities":{"logging":{}},"protocolVersion":"2025-06-18","serverInfo":{"name":"server","version":"v0.1.0"}}}
3537
}
3638

3739
// !-streamablehandler
3840

41+
// !+httpmiddleware
42+
func ExampleStreamableHTTPHandler_httpMiddleware() {
43+
server := mcp.NewServer(&mcp.Implementation{Name: "server", Version: "v0.1.0"}, nil)
44+
handler := mcp.NewStreamableHTTPHandler(func(r *http.Request) *mcp.Server {
45+
return server
46+
}, nil)
47+
loggingHandler := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
48+
// Example debugging; you could also capture the response.
49+
body, err := io.ReadAll(req.Body)
50+
if err != nil {
51+
log.Fatal(err)
52+
}
53+
req.Body.Close() // ignore error
54+
req.Body = io.NopCloser(bytes.NewBuffer(body))
55+
fmt.Println(req.Method, string(body))
56+
handler.ServeHTTP(w, req)
57+
})
58+
httpServer := httptest.NewServer(loggingHandler)
59+
defer httpServer.Close()
60+
61+
// The SDK is currently permissive of some missing keys in "params".
62+
mustPostMessage(`{"jsonrpc": "2.0", "id": 1, "method":"initialize", "params": {}}`, httpServer.URL)
63+
// Output:
64+
// POST {"jsonrpc": "2.0", "id": 1, "method":"initialize", "params": {}}
65+
}
66+
67+
// !-httpmiddleware
68+
3969
func mustPostMessage(msg, url string) string {
4070
req := orFatal(http.NewRequest("POST", url, strings.NewReader(msg)))
4171
req.Header["Content-Type"] = []string{"application/json"}

0 commit comments

Comments
 (0)