@@ -23,6 +23,7 @@ import (
23
23
"github.com/google/go-cmp/cmp"
24
24
"github.com/google/go-cmp/cmp/cmpopts"
25
25
"github.com/modelcontextprotocol/go-sdk/internal/jsonrpc2"
26
+ "github.com/modelcontextprotocol/go-sdk/jsonrpc"
26
27
"golang.org/x/tools/txtar"
27
28
)
28
29
@@ -46,12 +47,12 @@ var update = flag.Bool("update", false, "if set, update conformance test data")
46
47
// with -update to have the test runner update the expected output, which may
47
48
// be client or server depending on the perspective of the test.
48
49
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
55
56
}
56
57
57
58
// TODO(rfindley): add client conformance tests.
@@ -100,10 +101,36 @@ func TestServerConformance(t *testing.T) {
100
101
func runServerTest (t * testing.T , test * conformanceTest ) {
101
102
ctx := t .Context ()
102
103
// 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
+ }
107
134
108
135
// Connect the server, and connect the client stream,
109
136
// but don't connect an actual client.
@@ -117,24 +144,24 @@ func runServerTest(t *testing.T, test *conformanceTest) {
117
144
t .Fatal (err )
118
145
}
119
146
120
- writeMsg := func (msg JSONRPCMessage ) {
147
+ writeMsg := func (msg jsonrpc. Message ) {
121
148
if err := cStream .Write (ctx , msg ); err != nil {
122
149
t .Fatalf ("Write failed: %v" , err )
123
150
}
124
151
}
125
152
126
153
var (
127
- serverMessages []JSONRPCMessage
128
- outRequests []* JSONRPCRequest
129
- outResponses []* JSONRPCResponse
154
+ serverMessages []jsonrpc. Message
155
+ outRequests []* jsonrpc. Request
156
+ outResponses []* jsonrpc. Response
130
157
)
131
158
132
159
// Separate client requests and responses; we use them differently.
133
160
for _ , msg := range test .client {
134
161
switch msg := msg .(type ) {
135
- case * JSONRPCRequest :
162
+ case * jsonrpc. Request :
136
163
outRequests = append (outRequests , msg )
137
- case * JSONRPCResponse :
164
+ case * jsonrpc. Response :
138
165
outResponses = append (outResponses , msg )
139
166
default :
140
167
t .Fatalf ("bad message type %T" , msg )
@@ -143,7 +170,7 @@ func runServerTest(t *testing.T, test *conformanceTest) {
143
170
144
171
// nextResponse handles incoming requests and notifications, and returns the
145
172
// next incoming response.
146
- nextResponse := func () (* JSONRPCResponse , error , bool ) {
173
+ nextResponse := func () (* jsonrpc. Response , error , bool ) {
147
174
for {
148
175
msg , err := cStream .Read (ctx )
149
176
if err != nil {
@@ -156,7 +183,7 @@ func runServerTest(t *testing.T, test *conformanceTest) {
156
183
return nil , err , false
157
184
}
158
185
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 () {
160
187
// Pair up the next outgoing response with this request.
161
188
// We assume requests arrive in the same order every time.
162
189
if len (outResponses ) == 0 {
@@ -167,7 +194,7 @@ func runServerTest(t *testing.T, test *conformanceTest) {
167
194
outResponses = outResponses [1 :]
168
195
continue
169
196
}
170
- return msg .(* JSONRPCResponse ), nil , true
197
+ return msg .(* jsonrpc. Response ), nil , true
171
198
}
172
199
}
173
200
@@ -191,7 +218,7 @@ func runServerTest(t *testing.T, test *conformanceTest) {
191
218
// There might be more notifications or requests, but there shouldn't be more
192
219
// responses.
193
220
// Run this in a goroutine so the current thread can wait for it.
194
- var extra * JSONRPCResponse
221
+ var extra * jsonrpc. Response
195
222
go func () {
196
223
extra , err , _ = nextResponse ()
197
224
}()
@@ -240,8 +267,8 @@ func runServerTest(t *testing.T, test *conformanceTest) {
240
267
t .Fatalf ("os.WriteFile(%q) failed: %v" , test .path , err )
241
268
}
242
269
} 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 {
245
272
encoded , err := jsonrpc2 .EncodeIndent (msg , "" , "\t " )
246
273
if err != nil {
247
274
t .Fatal (err )
@@ -271,9 +298,9 @@ func loadConformanceTest(dir, path string) (*conformanceTest, error) {
271
298
}
272
299
273
300
// decodeMessages loads JSON-RPC messages from the archive file.
274
- decodeMessages := func (data []byte ) ([]JSONRPCMessage , error ) {
301
+ decodeMessages := func (data []byte ) ([]jsonrpc. Message , error ) {
275
302
dec := json .NewDecoder (bytes .NewReader (data ))
276
- var res []JSONRPCMessage
303
+ var res []jsonrpc. Message
277
304
for dec .More () {
278
305
var raw json.RawMessage
279
306
if err := dec .Decode (& raw ); err != nil {
0 commit comments