@@ -802,7 +802,7 @@ describe('outputSchema validation', () => {
802
802
server . setRequestHandler ( CallToolRequestSchema , async ( request ) => {
803
803
if ( request . params . name === 'test-tool' ) {
804
804
return {
805
- structuredContent : JSON . stringify ( { result : 'success' , count : 42 } ) ,
805
+ structuredContent : { result : 'success' , count : 42 } ,
806
806
} ;
807
807
}
808
808
throw new Error ( 'Unknown tool' ) ;
@@ -825,7 +825,7 @@ describe('outputSchema validation', () => {
825
825
826
826
// Call the tool - should validate successfully
827
827
const result = await client . callTool ( { name : 'test-tool' } ) ;
828
- expect ( result . structuredContent ) . toBe ( '{" result":" success"," count":42}' ) ;
828
+ expect ( result . structuredContent ) . toEqual ( { result : ' success' , count : 42 } ) ;
829
829
} ) ;
830
830
831
831
test ( 'should throw error when structuredContent does not match schema' , async ( ) => {
@@ -874,7 +874,7 @@ describe('outputSchema validation', () => {
874
874
if ( request . params . name === 'test-tool' ) {
875
875
// Return invalid structured content (count is string instead of number)
876
876
return {
877
- structuredContent : JSON . stringify ( { result : 'success' , count : 'not a number' } ) ,
877
+ structuredContent : { result : 'success' , count : 'not a number' } ,
878
878
} ;
879
879
}
880
880
throw new Error ( 'Unknown tool' ) ;
@@ -1094,15 +1094,15 @@ describe('outputSchema validation', () => {
1094
1094
server . setRequestHandler ( CallToolRequestSchema , async ( request ) => {
1095
1095
if ( request . params . name === 'complex-tool' ) {
1096
1096
return {
1097
- structuredContent : JSON . stringify ( {
1097
+ structuredContent : {
1098
1098
name : 'John Doe' ,
1099
1099
age : 30 ,
1100
1100
active : true ,
1101
1101
tags : [ 'user' , 'admin' ] ,
1102
1102
metadata : {
1103
1103
created : '2023-01-01T00:00:00Z' ,
1104
1104
} ,
1105
- } ) ,
1105
+ } ,
1106
1106
} ;
1107
1107
}
1108
1108
throw new Error ( 'Unknown tool' ) ;
@@ -1126,9 +1126,9 @@ describe('outputSchema validation', () => {
1126
1126
// Call the tool - should validate successfully
1127
1127
const result = await client . callTool ( { name : 'complex-tool' } ) ;
1128
1128
expect ( result . structuredContent ) . toBeDefined ( ) ;
1129
- const parsedContent = JSON . parse ( result . structuredContent as string ) ;
1130
- expect ( parsedContent . name ) . toBe ( 'John Doe' ) ;
1131
- expect ( parsedContent . age ) . toBe ( 30 ) ;
1129
+ const structuredContent = result . structuredContent as { name : string ; age : number } ;
1130
+ expect ( structuredContent . name ) . toBe ( 'John Doe' ) ;
1131
+ expect ( structuredContent . age ) . toBe ( 30 ) ;
1132
1132
} ) ;
1133
1133
1134
1134
test ( 'should fail validation with additional properties when not allowed' , async ( ) => {
@@ -1176,10 +1176,10 @@ describe('outputSchema validation', () => {
1176
1176
if ( request . params . name === 'strict-tool' ) {
1177
1177
// Return structured content with extra property
1178
1178
return {
1179
- structuredContent : JSON . stringify ( {
1179
+ structuredContent : {
1180
1180
name : 'John' ,
1181
1181
extraField : 'not allowed' ,
1182
- } ) ,
1182
+ } ,
1183
1183
} ;
1184
1184
}
1185
1185
throw new Error ( 'Unknown tool' ) ;
@@ -1205,4 +1205,137 @@ describe('outputSchema validation', () => {
1205
1205
/ S t r u c t u r e d c o n t e n t d o e s n o t m a t c h t h e t o o l ' s o u t p u t s c h e m a /
1206
1206
) ;
1207
1207
} ) ;
1208
+
1209
+ test ( 'should throw error when tool without outputSchema returns structuredContent' , async ( ) => {
1210
+ const server = new Server ( {
1211
+ name : 'test-server' ,
1212
+ version : '1.0.0' ,
1213
+ } , {
1214
+ capabilities : {
1215
+ tools : { } ,
1216
+ } ,
1217
+ } ) ;
1218
+
1219
+ // Set up server handlers
1220
+ server . setRequestHandler ( InitializeRequestSchema , async ( request ) => ( {
1221
+ protocolVersion : request . params . protocolVersion ,
1222
+ capabilities : { } ,
1223
+ serverInfo : {
1224
+ name : 'test-server' ,
1225
+ version : '1.0.0' ,
1226
+ }
1227
+ } ) ) ;
1228
+
1229
+ server . setRequestHandler ( ListToolsRequestSchema , async ( ) => ( {
1230
+ tools : [
1231
+ {
1232
+ name : 'test-tool' ,
1233
+ description : 'A test tool' ,
1234
+ inputSchema : {
1235
+ type : 'object' ,
1236
+ properties : { } ,
1237
+ } ,
1238
+ // No outputSchema defined
1239
+ } ,
1240
+ ] ,
1241
+ } ) ) ;
1242
+
1243
+ server . setRequestHandler ( CallToolRequestSchema , async ( request ) => {
1244
+ if ( request . params . name === 'test-tool' ) {
1245
+ // Incorrectly return structuredContent for a tool without outputSchema
1246
+ return {
1247
+ structuredContent : { result : 'This should not be allowed' } ,
1248
+ } ;
1249
+ }
1250
+ throw new Error ( 'Unknown tool' ) ;
1251
+ } ) ;
1252
+
1253
+ const client = new Client ( {
1254
+ name : 'test-client' ,
1255
+ version : '1.0.0' ,
1256
+ } ) ;
1257
+
1258
+ const [ clientTransport , serverTransport ] = InMemoryTransport . createLinkedPair ( ) ;
1259
+
1260
+ await Promise . all ( [
1261
+ client . connect ( clientTransport ) ,
1262
+ server . connect ( serverTransport ) ,
1263
+ ] ) ;
1264
+
1265
+ // List tools to cache the schemas
1266
+ await client . listTools ( ) ;
1267
+
1268
+ // Call the tool - should throw validation error
1269
+ await expect ( client . callTool ( { name : 'test-tool' } ) ) . rejects . toThrow (
1270
+ / T o o l w i t h o u t o u t p u t S c h e m a c a n n o t r e t u r n s t r u c t u r e d C o n t e n t /
1271
+ ) ;
1272
+ } ) ;
1273
+
1274
+ test ( 'should throw error when structuredContent is not an object' , async ( ) => {
1275
+ const server = new Server ( {
1276
+ name : 'test-server' ,
1277
+ version : '1.0.0' ,
1278
+ } , {
1279
+ capabilities : {
1280
+ tools : { } ,
1281
+ } ,
1282
+ } ) ;
1283
+
1284
+ // Set up server handlers
1285
+ server . setRequestHandler ( InitializeRequestSchema , async ( request ) => ( {
1286
+ protocolVersion : request . params . protocolVersion ,
1287
+ capabilities : { } ,
1288
+ serverInfo : {
1289
+ name : 'test-server' ,
1290
+ version : '1.0.0' ,
1291
+ }
1292
+ } ) ) ;
1293
+
1294
+ server . setRequestHandler ( ListToolsRequestSchema , async ( ) => ( {
1295
+ tools : [
1296
+ {
1297
+ name : 'test-tool' ,
1298
+ description : 'A test tool' ,
1299
+ inputSchema : {
1300
+ type : 'object' ,
1301
+ properties : { } ,
1302
+ } ,
1303
+ outputSchema : {
1304
+ type : 'object' ,
1305
+ properties : {
1306
+ result : { type : 'string' } ,
1307
+ } ,
1308
+ } ,
1309
+ } ,
1310
+ ] ,
1311
+ } ) ) ;
1312
+
1313
+ server . setRequestHandler ( CallToolRequestSchema , async ( request ) => {
1314
+ if ( request . params . name === 'test-tool' ) {
1315
+ // Try to return a non-object value as structuredContent
1316
+ return {
1317
+ structuredContent : "This should be an object, not a string" as any ,
1318
+ } ;
1319
+ }
1320
+ throw new Error ( 'Unknown tool' ) ;
1321
+ } ) ;
1322
+
1323
+ const client = new Client ( {
1324
+ name : 'test-client' ,
1325
+ version : '1.0.0' ,
1326
+ } ) ;
1327
+
1328
+ const [ clientTransport , serverTransport ] = InMemoryTransport . createLinkedPair ( ) ;
1329
+
1330
+ await Promise . all ( [
1331
+ client . connect ( clientTransport ) ,
1332
+ server . connect ( serverTransport ) ,
1333
+ ] ) ;
1334
+
1335
+ // List tools to cache the schemas
1336
+ await client . listTools ( ) ;
1337
+
1338
+ // Call the tool - should throw validation error
1339
+ await expect ( client . callTool ( { name : 'test-tool' } ) ) . rejects . toThrow ( ) ;
1340
+ } ) ;
1208
1341
} ) ;
0 commit comments