@@ -802,7 +802,7 @@ describe('outputSchema validation', () => {
802802 server . setRequestHandler ( CallToolRequestSchema , async ( request ) => {
803803 if ( request . params . name === 'test-tool' ) {
804804 return {
805- structuredContent : JSON . stringify ( { result : 'success' , count : 42 } ) ,
805+ structuredContent : { result : 'success' , count : 42 } ,
806806 } ;
807807 }
808808 throw new Error ( 'Unknown tool' ) ;
@@ -825,7 +825,7 @@ describe('outputSchema validation', () => {
825825
826826 // Call the tool - should validate successfully
827827 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 } ) ;
829829 } ) ;
830830
831831 test ( 'should throw error when structuredContent does not match schema' , async ( ) => {
@@ -874,7 +874,7 @@ describe('outputSchema validation', () => {
874874 if ( request . params . name === 'test-tool' ) {
875875 // Return invalid structured content (count is string instead of number)
876876 return {
877- structuredContent : JSON . stringify ( { result : 'success' , count : 'not a number' } ) ,
877+ structuredContent : { result : 'success' , count : 'not a number' } ,
878878 } ;
879879 }
880880 throw new Error ( 'Unknown tool' ) ;
@@ -1094,15 +1094,15 @@ describe('outputSchema validation', () => {
10941094 server . setRequestHandler ( CallToolRequestSchema , async ( request ) => {
10951095 if ( request . params . name === 'complex-tool' ) {
10961096 return {
1097- structuredContent : JSON . stringify ( {
1097+ structuredContent : {
10981098 name : 'John Doe' ,
10991099 age : 30 ,
11001100 active : true ,
11011101 tags : [ 'user' , 'admin' ] ,
11021102 metadata : {
11031103 created : '2023-01-01T00:00:00Z' ,
11041104 } ,
1105- } ) ,
1105+ } ,
11061106 } ;
11071107 }
11081108 throw new Error ( 'Unknown tool' ) ;
@@ -1126,9 +1126,9 @@ describe('outputSchema validation', () => {
11261126 // Call the tool - should validate successfully
11271127 const result = await client . callTool ( { name : 'complex-tool' } ) ;
11281128 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 ) ;
11321132 } ) ;
11331133
11341134 test ( 'should fail validation with additional properties when not allowed' , async ( ) => {
@@ -1176,10 +1176,10 @@ describe('outputSchema validation', () => {
11761176 if ( request . params . name === 'strict-tool' ) {
11771177 // Return structured content with extra property
11781178 return {
1179- structuredContent : JSON . stringify ( {
1179+ structuredContent : {
11801180 name : 'John' ,
11811181 extraField : 'not allowed' ,
1182- } ) ,
1182+ } ,
11831183 } ;
11841184 }
11851185 throw new Error ( 'Unknown tool' ) ;
@@ -1205,4 +1205,137 @@ describe('outputSchema validation', () => {
12051205 / 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 /
12061206 ) ;
12071207 } ) ;
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+ } ) ;
12081341} ) ;
0 commit comments