@@ -43,8 +43,7 @@ import {
43
43
ErrorCode ,
44
44
McpError ,
45
45
} from "../types.js" ;
46
- import { z } from "zod" ;
47
- import { JsonSchema , parseSchema } from "json-schema-to-zod" ;
46
+ import { Ajv , type ValidateFunction } from "ajv" ;
48
47
49
48
export type ClientOptions = ProtocolOptions & {
50
49
/**
@@ -91,7 +90,8 @@ export class Client<
91
90
private _serverVersion ?: Implementation ;
92
91
private _capabilities : ClientCapabilities ;
93
92
private _instructions ?: string ;
94
- private _cachedToolOutputSchemas : Map < string , z . ZodTypeAny > = new Map ( ) ;
93
+ private _cachedToolOutputValidators : Map < string , ValidateFunction > = new Map ( ) ;
94
+ private _ajv : InstanceType < typeof Ajv > ;
95
95
96
96
/**
97
97
* Initializes this client with the given name and version information.
@@ -102,6 +102,7 @@ export class Client<
102
102
) {
103
103
super ( options ) ;
104
104
this . _capabilities = options ?. capabilities ?? { } ;
105
+ this . _ajv = new Ajv ( { strict : false , validateFormats : true } ) ;
105
106
}
106
107
107
108
/**
@@ -426,8 +427,8 @@ export class Client<
426
427
) ;
427
428
428
429
// Check if the tool has an outputSchema
429
- const outputSchema = this . getToolOutputSchema ( params . name ) ;
430
- if ( outputSchema ) {
430
+ const validator = this . getToolOutputValidator ( params . name ) ;
431
+ if ( validator ) {
431
432
// If tool has outputSchema, it MUST return structuredContent (unless it's an error)
432
433
if ( ! result . structuredContent && ! result . isError ) {
433
434
throw new McpError (
@@ -440,12 +441,12 @@ export class Client<
440
441
if ( result . structuredContent ) {
441
442
try {
442
443
// Validate the structured content (which is already an object) against the schema
443
- const validationResult = outputSchema . safeParse ( result . structuredContent ) ;
444
+ const isValid = validator ( result . structuredContent ) ;
444
445
445
- if ( ! validationResult . success ) {
446
+ if ( ! isValid ) {
446
447
throw new McpError (
447
448
ErrorCode . InvalidParams ,
448
- `Structured content does not match the tool's output schema: ${ validationResult . error . message } `
449
+ `Structured content does not match the tool's output schema: ${ this . _ajv . errorsText ( validator . errors ) } `
449
450
) ;
450
451
}
451
452
} catch ( error ) {
@@ -458,41 +459,29 @@ export class Client<
458
459
) ;
459
460
}
460
461
}
461
- } else {
462
- // If tool doesn't have outputSchema, it MUST NOT return structuredContent
463
- if ( result . structuredContent ) {
464
- throw new McpError (
465
- ErrorCode . InvalidRequest ,
466
- `Tool without outputSchema cannot return structuredContent`
467
- ) ;
468
- }
469
462
}
470
463
471
464
return result ;
472
465
}
473
466
474
467
private cacheToolOutputSchemas ( tools : Tool [ ] ) {
475
- this . _cachedToolOutputSchemas . clear ( ) ;
468
+ this . _cachedToolOutputValidators . clear ( ) ;
476
469
477
470
for ( const tool of tools ) {
478
- // If the tool has an outputSchema, create and cache the Zod schema
471
+ // If the tool has an outputSchema, create and cache the Ajv validator
479
472
if ( tool . outputSchema ) {
480
473
try {
481
- const zodSchemaCode = parseSchema ( tool . outputSchema as JsonSchema ) ;
482
- // The library returns a string of Zod code, we need to evaluate it
483
- // Using Function constructor to safely evaluate the Zod schema
484
- const createSchema = new Function ( 'z' , `return ${ zodSchemaCode } ` ) ;
485
- const zodSchema = createSchema ( z ) ;
486
- this . _cachedToolOutputSchemas . set ( tool . name , zodSchema ) ;
474
+ const validator = this . _ajv . compile ( tool . outputSchema ) ;
475
+ this . _cachedToolOutputValidators . set ( tool . name , validator ) ;
487
476
} catch ( error ) {
488
- console . warn ( `Failed to create Zod schema for tool ${ tool . name } : ${ error } ` ) ;
477
+ console . warn ( `Failed to compile output schema for tool ${ tool . name } : ${ error } ` ) ;
489
478
}
490
479
}
491
480
}
492
481
}
493
482
494
- private getToolOutputSchema ( toolName : string ) : z . ZodTypeAny | undefined {
495
- return this . _cachedToolOutputSchemas . get ( toolName ) ;
483
+ private getToolOutputValidator ( toolName : string ) : ValidateFunction | undefined {
484
+ return this . _cachedToolOutputValidators . get ( toolName ) ;
496
485
}
497
486
498
487
async listTools (
0 commit comments