fix: support Zod 3.25 method literals (#2368)

This commit is contained in:
Matt 2026-06-25 14:59:16 +02:00 • committed by GitHub
commit 369513df7b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 77 additions and 42 deletions

View file

@ -53,15 +53,7 @@ import {
} from '../types.js';
import { AjvJsonSchemaValidator } from '../validation/ajv-provider.js';
import type { JsonSchemaType, JsonSchemaValidator, jsonSchemaValidator } from '../validation/types.js';
import {
AnyObjectSchema,
SchemaOutput,
getObjectShape,
isZ4Schema,
safeParse,
type ZodV3Internal,
type ZodV4Internal
} from '../server/zod-compat.js';
import { AnyObjectSchema, SchemaOutput, getLiteralValue, getObjectShape, safeParse } from '../server/zod-compat.js';
import type { RequestHandlerExtra } from '../shared/protocol.js';
import { ExperimentalClientTasks } from '../experimental/tasks/client.js';
import { assertToolsCallTaskCapability, assertClientRequestTaskCapability } from '../experimental/tasks/helpers.js';
@ -339,18 +331,7 @@ export class Client<
throw new Error('Schema is missing a method literal');
}
// Extract literal value using type-safe property access
let methodValue: unknown;
if (isZ4Schema(methodSchema)) {
const v4Schema = methodSchema as unknown as ZodV4Internal;
const v4Def = v4Schema._zod?.def;
methodValue = v4Def?.value ?? v4Schema.value;
} else {
const v3Schema = methodSchema as unknown as ZodV3Internal;
const legacyDef = v3Schema._def;
methodValue = legacyDef?.value ?? v3Schema.value;
}
const methodValue = getLiteralValue(methodSchema);
if (typeof methodValue !== 'string') {
throw new Error('Schema method literal must be a string');
}

View file

@ -44,15 +44,7 @@ import {
} from '../types.js';
import { AjvJsonSchemaValidator } from '../validation/ajv-provider.js';
import type { JsonSchemaType, jsonSchemaValidator } from '../validation/types.js';
import {
AnyObjectSchema,
getObjectShape,
isZ4Schema,
safeParse,
SchemaOutput,
type ZodV3Internal,
type ZodV4Internal
} from './zod-compat.js';
import { AnyObjectSchema, getLiteralValue, getObjectShape, safeParse, SchemaOutput } from './zod-compat.js';
import { RequestHandlerExtra } from '../shared/protocol.js';
import { ExperimentalServerTasks } from '../experimental/tasks/server.js';
import { assertToolsCallTaskCapability, assertClientRequestTaskCapability } from '../experimental/tasks/helpers.js';
@ -228,18 +220,7 @@ export class Server<
throw new Error('Schema is missing a method literal');
}
// Extract literal value using type-safe property access
let methodValue: unknown;
if (isZ4Schema(methodSchema)) {
const v4Schema = methodSchema as unknown as ZodV4Internal;
const v4Def = v4Schema._zod?.def;
methodValue = v4Def?.value ?? v4Schema.value;
} else {
const v3Schema = methodSchema as unknown as ZodV3Internal;
const legacyDef = v3Schema._def;
methodValue = legacyDef?.value ?? v3Schema.value;
}
const methodValue = getLiteralValue(methodSchema);
if (typeof methodValue !== 'string') {
throw new Error('Schema method literal must be a string');
}

View file

@ -0,0 +1,73 @@
import { Client } from '../../src/client/index.js';
import { Server } from '../../src/server/index.js';
import type { AnyObjectSchema, AnySchema } from '../../src/server/zod-compat.js';
import { getLiteralValue } from '../../src/server/zod-compat.js';
function requestSchemaWithValuesLiteral(method: string): AnyObjectSchema {
return {
_zod: {
def: {
type: 'object',
shape: {
method: {
_zod: {
def: {
type: 'literal',
values: [method]
}
}
}
}
}
}
} as unknown as AnyObjectSchema;
}
describe('Issue #1380: Zod 3.25.x v4 literal value shape', () => {
test('extracts literal values stored in _zod.def.values', () => {
const methodSchema = {
_zod: {
def: {
type: 'literal',
values: ['ping']
}
}
} as unknown as AnySchema;
expect(getLiteralValue(methodSchema)).toBe('ping');
});
test('registers server request handlers when the method literal uses _zod.def.values', () => {
const server = new Server(
{ name: 'test server', version: '1.0' },
{
capabilities: {
tools: {}
}
}
);
expect(() => {
server.setRequestHandler(requestSchemaWithValuesLiteral('tools/call'), () => ({
content: []
}));
}).not.toThrow();
});
test('registers client request handlers when the method literal uses _zod.def.values', () => {
const client = new Client(
{ name: 'test client', version: '1.0' },
{
capabilities: {
elicitation: {}
}
}
);
expect(() => {
client.setRequestHandler(requestSchemaWithValuesLiteral('elicitation/create'), () => ({
action: 'cancel'
}));
}).not.toThrow();
});
});