@@ -36,9 +36,7 @@ import {
3636 type ClientCapabilityServiceOffer ,
3737} from "@maka/runtime-host/protocol" ;
3838import { validateTypes } from '@ai-sdk/provider-utils' ;
39- import Ajv , { type AnySchema , type ValidateFunction } from 'ajv' ;
40- import Ajv2019 from 'ajv/dist/2019.js' ;
41- import Ajv2020 from 'ajv/dist/2020.js' ;
39+ import Ajv2020 , { type AnySchema , type ValidateFunction } from 'ajv/dist/2020.js' ;
4240import { toJSONSchema , z } from "zod" ;
4341import { withBrowserOriginAdmission } from './browser/browser-origin-admission.js' ;
4442import type { DesktopTargetScope } from '../shared/runtime-host-identity.js' ;
@@ -489,35 +487,30 @@ interface JsonSchemaWrapper {
489487}
490488
491489// -- JSON Schema argument validation -------------------------------------------
490+ //
491+ // Validation runs against the projected (advertised) schema, not the raw
492+ // MCP schema, so any constraint expressed via non-whitelisted keywords
493+ // (if/then/else, contains, dependentRequired, …) is dropped before Ajv
494+ // sees it. The downstream MCP server re-validates against the full schema.
492495
493496const jsonSchemaValidatorOptions = {
494497 allErrors : true ,
495498 strict : false ,
496499 validateFormats : false ,
497500} as const ;
498- const draft7Validator = new Ajv ( jsonSchemaValidatorOptions ) ;
499- const draft2019Validator = new Ajv2019 ( jsonSchemaValidatorOptions ) ;
500- const draft2020Validator = new Ajv2020 ( jsonSchemaValidatorOptions ) ;
501+ const schemaValidator = new Ajv2020 ( jsonSchemaValidatorOptions ) ;
501502const compiledSchemas = new WeakMap < object , ValidateFunction > ( ) ;
502503
503- function compileJsonSchema ( schema : unknown ) : ValidateFunction | undefined {
504- if ( typeof schema === 'boolean' ) return draft2020Validator . compile ( schema ) ;
505- if ( typeof schema !== 'object' || schema === null || Array . isArray ( schema ) )
506- return undefined ;
507- const cached = compiledSchemas . get ( schema ) ;
504+ function compileJsonSchema (
505+ rawSchema : object ,
506+ projected : Record < string , unknown > ,
507+ ) : ValidateFunction | undefined {
508+ const cached = compiledSchemas . get ( rawSchema ) ;
508509 if ( cached ) return cached ;
509- const declaredDialect = (
510- schema as { readonly $schema ?: unknown }
511- ) . $schema ;
512- const dialect =
513- typeof declaredDialect === 'string' ? declaredDialect : '' ;
514- const validator = dialect . includes ( 'draft-07' )
515- ? draft7Validator
516- : dialect . includes ( '2019-09' )
517- ? draft2019Validator
518- : draft2020Validator ;
519- const compiled = validator . compile ( schema as AnySchema ) ;
520- compiledSchemas . set ( schema , compiled ) ;
510+ if ( typeof projected !== 'object' || projected === null || Array . isArray ( projected ) )
511+ return undefined ;
512+ const compiled = schemaValidator . compile ( projected as AnySchema ) ;
513+ compiledSchemas . set ( rawSchema , compiled ) ;
521514 return compiled ;
522515}
523516
@@ -540,10 +533,9 @@ async function parseNativeToolArguments(
540533 // jsonSchema() wrappers: compile the projected schema and validate.
541534 const wrapper = parameters as JsonSchemaWrapper | undefined ;
542535 if ( wrapper ?. jsonSchema ) {
543- const projected = projectToolInputSchema (
544- wrapper . jsonSchema as Record < string , unknown > ,
545- ) ;
546- const validator = compileJsonSchema ( projected ) ;
536+ const raw = wrapper . jsonSchema as Record < string , unknown > ;
537+ const projected = projectToolInputSchema ( raw ) ;
538+ const validator = compileJsonSchema ( raw , projected ) ;
547539 if ( ! validator || validator ( args ) ) return args ;
548540 throw new Error (
549541 `Invalid arguments: ${ schemaErrorSummary ( validator . errors ) } ` ,
0 commit comments