Skip to content

Commit de4b788

Browse files
authored
mcp: fix conformance tests (#132)
- Use new AddXXX API. - Update goldens to reflect new capability logic. Fixes #131.
1 parent bf7e518 commit de4b788

File tree

7 files changed

+70
-75
lines changed

7 files changed

+70
-75
lines changed

mcp/conformance_test.go

Lines changed: 51 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"github.com/google/go-cmp/cmp"
2424
"github.com/google/go-cmp/cmp/cmpopts"
2525
"github.com/modelcontextprotocol/go-sdk/internal/jsonrpc2"
26+
"github.com/modelcontextprotocol/go-sdk/jsonrpc"
2627
"golang.org/x/tools/txtar"
2728
)
2829

@@ -46,12 +47,12 @@ var update = flag.Bool("update", false, "if set, update conformance test data")
4647
// with -update to have the test runner update the expected output, which may
4748
// be client or server depending on the perspective of the test.
4849
type conformanceTest struct {
49-
name string // test name
50-
path string // path to test file
51-
archive *txtar.Archive // raw archive, for updating
52-
tools, prompts, resources []string // named features to include
53-
client []JSONRPCMessage // client messages
54-
server []JSONRPCMessage // server messages
50+
name string // test name
51+
path string // path to test file
52+
archive *txtar.Archive // raw archive, for updating
53+
tools, prompts, resources []string // named features to include
54+
client []jsonrpc.Message // client messages
55+
server []jsonrpc.Message // server messages
5556
}
5657

5758
// TODO(rfindley): add client conformance tests.
@@ -100,10 +101,36 @@ func TestServerConformance(t *testing.T) {
100101
func runServerTest(t *testing.T, test *conformanceTest) {
101102
ctx := t.Context()
102103
// Construct the server based on features listed in the test.
103-
s := NewServer("testServer", "v1.0.0", nil)
104-
add(tools, s.AddTools, test.tools...)
105-
add(prompts, s.AddPrompts, test.prompts...)
106-
add(resources, s.AddResources, test.resources...)
104+
s := NewServer(&Implementation{Name: "testServer", Version: "v1.0.0"}, nil)
105+
for _, tn := range test.tools {
106+
switch tn {
107+
case "greet":
108+
AddTool(s, &Tool{
109+
Name: "greet",
110+
Description: "say hi",
111+
}, sayHi)
112+
default:
113+
t.Fatalf("unknown tool %q", tn)
114+
}
115+
}
116+
for _, pn := range test.prompts {
117+
switch pn {
118+
case "code_review":
119+
s.AddPrompt(codeReviewPrompt, codReviewPromptHandler)
120+
default:
121+
t.Fatalf("unknown prompt %q", pn)
122+
}
123+
}
124+
for _, rn := range test.resources {
125+
switch rn {
126+
case "info.txt":
127+
s.AddResource(resource1, readHandler)
128+
case "info":
129+
s.AddResource(resource3, handleEmbeddedResource)
130+
default:
131+
t.Fatalf("unknown resource %q", rn)
132+
}
133+
}
107134

108135
// Connect the server, and connect the client stream,
109136
// but don't connect an actual client.
@@ -117,24 +144,24 @@ func runServerTest(t *testing.T, test *conformanceTest) {
117144
t.Fatal(err)
118145
}
119146

120-
writeMsg := func(msg JSONRPCMessage) {
147+
writeMsg := func(msg jsonrpc.Message) {
121148
if err := cStream.Write(ctx, msg); err != nil {
122149
t.Fatalf("Write failed: %v", err)
123150
}
124151
}
125152

126153
var (
127-
serverMessages []JSONRPCMessage
128-
outRequests []*JSONRPCRequest
129-
outResponses []*JSONRPCResponse
154+
serverMessages []jsonrpc.Message
155+
outRequests []*jsonrpc.Request
156+
outResponses []*jsonrpc.Response
130157
)
131158

132159
// Separate client requests and responses; we use them differently.
133160
for _, msg := range test.client {
134161
switch msg := msg.(type) {
135-
case *JSONRPCRequest:
162+
case *jsonrpc.Request:
136163
outRequests = append(outRequests, msg)
137-
case *JSONRPCResponse:
164+
case *jsonrpc.Response:
138165
outResponses = append(outResponses, msg)
139166
default:
140167
t.Fatalf("bad message type %T", msg)
@@ -143,7 +170,7 @@ func runServerTest(t *testing.T, test *conformanceTest) {
143170

144171
// nextResponse handles incoming requests and notifications, and returns the
145172
// next incoming response.
146-
nextResponse := func() (*JSONRPCResponse, error, bool) {
173+
nextResponse := func() (*jsonrpc.Response, error, bool) {
147174
for {
148175
msg, err := cStream.Read(ctx)
149176
if err != nil {
@@ -156,7 +183,7 @@ func runServerTest(t *testing.T, test *conformanceTest) {
156183
return nil, err, false
157184
}
158185
serverMessages = append(serverMessages, msg)
159-
if req, ok := msg.(*JSONRPCRequest); ok && req.ID.IsValid() {
186+
if req, ok := msg.(*jsonrpc.Request); ok && req.ID.IsValid() {
160187
// Pair up the next outgoing response with this request.
161188
// We assume requests arrive in the same order every time.
162189
if len(outResponses) == 0 {
@@ -167,7 +194,7 @@ func runServerTest(t *testing.T, test *conformanceTest) {
167194
outResponses = outResponses[1:]
168195
continue
169196
}
170-
return msg.(*JSONRPCResponse), nil, true
197+
return msg.(*jsonrpc.Response), nil, true
171198
}
172199
}
173200

@@ -191,7 +218,7 @@ func runServerTest(t *testing.T, test *conformanceTest) {
191218
// There might be more notifications or requests, but there shouldn't be more
192219
// responses.
193220
// Run this in a goroutine so the current thread can wait for it.
194-
var extra *JSONRPCResponse
221+
var extra *jsonrpc.Response
195222
go func() {
196223
extra, err, _ = nextResponse()
197224
}()
@@ -240,8 +267,8 @@ func runServerTest(t *testing.T, test *conformanceTest) {
240267
t.Fatalf("os.WriteFile(%q) failed: %v", test.path, err)
241268
}
242269
} else {
243-
// JSONRPCMessages are not comparable, so we instead compare lines of JSON.
244-
transform := cmpopts.AcyclicTransformer("toJSON", func(msg JSONRPCMessage) []string {
270+
// jsonrpc.Messages are not comparable, so we instead compare lines of JSON.
271+
transform := cmpopts.AcyclicTransformer("toJSON", func(msg jsonrpc.Message) []string {
245272
encoded, err := jsonrpc2.EncodeIndent(msg, "", "\t")
246273
if err != nil {
247274
t.Fatal(err)
@@ -271,9 +298,9 @@ func loadConformanceTest(dir, path string) (*conformanceTest, error) {
271298
}
272299

273300
// decodeMessages loads JSON-RPC messages from the archive file.
274-
decodeMessages := func(data []byte) ([]JSONRPCMessage, error) {
301+
decodeMessages := func(data []byte) ([]jsonrpc.Message, error) {
275302
dec := json.NewDecoder(bytes.NewReader(data))
276-
var res []JSONRPCMessage
303+
var res []jsonrpc.Message
277304
for dec.More() {
278305
var raw json.RawMessage
279306
if err := dec.Decode(&raw); err != nil {

mcp/mcp_test.go

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,21 @@ func sayHi(ctx context.Context, ss *ServerSession, params *CallToolParamsFor[hiP
3939
return &CallToolResultFor[any]{Content: []Content{&TextContent{Text: "hi " + params.Arguments.Name}}}, nil
4040
}
4141

42+
var codeReviewPrompt = &Prompt{
43+
Name: "code_review",
44+
Description: "do a code review",
45+
Arguments: []*PromptArgument{{Name: "Code", Required: true}},
46+
}
47+
48+
func codReviewPromptHandler(_ context.Context, _ *ServerSession, params *GetPromptParams) (*GetPromptResult, error) {
49+
return &GetPromptResult{
50+
Description: "Code review prompt",
51+
Messages: []*PromptMessage{
52+
{Role: "user", Content: &TextContent{Text: "Please review the following code: " + params.Arguments["Code"]}},
53+
},
54+
}, nil
55+
}
56+
4257
func TestEndToEnd(t *testing.T) {
4358
ctx := context.Background()
4459
var ct, st Transport = NewInMemoryTransports()
@@ -73,18 +88,7 @@ func TestEndToEnd(t *testing.T) {
7388
func(context.Context, *ServerSession, *CallToolParamsFor[map[string]any]) (*CallToolResult, error) {
7489
return nil, errTestFailure
7590
})
76-
s.AddPrompt(&Prompt{
77-
Name: "code_review",
78-
Description: "do a code review",
79-
Arguments: []*PromptArgument{{Name: "Code", Required: true}},
80-
}, func(_ context.Context, _ *ServerSession, params *GetPromptParams) (*GetPromptResult, error) {
81-
return &GetPromptResult{
82-
Description: "Code review prompt",
83-
Messages: []*PromptMessage{
84-
{Role: "user", Content: &TextContent{Text: "Please review the following code: " + params.Arguments["Code"]}},
85-
},
86-
}, nil
87-
})
91+
s.AddPrompt(codeReviewPrompt, codReviewPromptHandler)
8892
s.AddPrompt(&Prompt{Name: "fail"}, func(_ context.Context, _ *ServerSession, _ *GetPromptParams) (*GetPromptResult, error) {
8993
return nil, errTestFailure
9094
})

mcp/testdata/conformance/server/prompts.txtar

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,6 @@ code_review
2929
"logging": {},
3030
"prompts": {
3131
"listChanged": true
32-
},
33-
"resources": {
34-
"listChanged": true
35-
},
36-
"tools": {
37-
"listChanged": true
3832
}
3933
},
4034
"protocolVersion": "2024-11-05",

mcp/testdata/conformance/server/resources.txtar

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,14 +47,8 @@ info.txt
4747
"capabilities": {
4848
"completions": {},
4949
"logging": {},
50-
"prompts": {
51-
"listChanged": true
52-
},
5350
"resources": {
5451
"listChanged": true
55-
},
56-
"tools": {
57-
"listChanged": true
5852
}
5953
},
6054
"protocolVersion": "2024-11-05",

mcp/testdata/conformance/server/tools.txtar

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,6 @@ greet
3030
"capabilities": {
3131
"completions": {},
3232
"logging": {},
33-
"prompts": {
34-
"listChanged": true
35-
},
36-
"resources": {
37-
"listChanged": true
38-
},
3933
"tools": {
4034
"listChanged": true
4135
}

mcp/testdata/conformance/server/version-latest.txtar

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,18 +19,9 @@ response with its latest supported version.
1919
"result": {
2020
"capabilities": {
2121
"completions": {},
22-
"logging": {},
23-
"prompts": {
24-
"listChanged": true
25-
},
26-
"resources": {
27-
"listChanged": true
28-
},
29-
"tools": {
30-
"listChanged": true
31-
}
22+
"logging": {}
3223
},
33-
"protocolVersion": "2025-03-26",
24+
"protocolVersion": "2025-06-18",
3425
"serverInfo": {
3526
"name": "testServer",
3627
"version": "v1.0.0"

mcp/testdata/conformance/server/version-older.txtar

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,7 @@ support.
1919
"result": {
2020
"capabilities": {
2121
"completions": {},
22-
"logging": {},
23-
"prompts": {
24-
"listChanged": true
25-
},
26-
"resources": {
27-
"listChanged": true
28-
},
29-
"tools": {
30-
"listChanged": true
31-
}
22+
"logging": {}
3223
},
3324
"protocolVersion": "2024-11-05",
3425
"serverInfo": {

0 commit comments

Comments
 (0)