Fix optional argument handling in prompts for Zod V4 (#1199)

Co-authored-by: Matt <77928207+mattzcarey@users.noreply.github.com>
This commit is contained in:
Filip Bartuska 2025-12-01 13:10:52 +01:00 • committed by GitHub
commit 5aaf6ee67e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 48 additions and 3 deletions

View file

@ -3879,6 +3879,51 @@ describe.each(zodTestMatrix)('$zodVersionLabel', (entry: ZodMatrixEntry) => {
expect(result.resources[0].description).toBe('Overridden description');
expect(result.resources[0].mimeType).toBe('text/markdown');
});
test('should support optional prompt arguments', async () => {
const mcpServer = new McpServer({
name: 'test server',
version: '1.0'
});
const client = new Client({
name: 'test client',
version: '1.0'
});
mcpServer.registerPrompt(
'test-prompt',
{
argsSchema: {
name: z.string().optional()
}
},
() => ({
messages: []
})
);
const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
await Promise.all([client.connect(clientTransport), mcpServer.server.connect(serverTransport)]);
const result = await client.request(
{
method: 'prompts/list'
},
ListPromptsResultSchema
);
expect(result.prompts).toHaveLength(1);
expect(result.prompts[0].name).toBe('test-prompt');
expect(result.prompts[0].arguments).toEqual([
{
name: 'name',
description: undefined,
required: false
}
]);
});
});
describe('Tool title precedence', () => {

View file

@ -31,7 +31,7 @@ export interface ZodV3Internal {
export interface ZodV4Internal {
_zod?: {
def?: {
typeName?: string;
type?: string;
value?: unknown;
values?: unknown[];
shape?: Record<string, AnySchema> | (() => Record<string, AnySchema>);
@ -175,7 +175,7 @@ export function normalizeObjectSchema(schema: AnySchema | ZodRawShapeCompat | un
// Check if it's a v4 object
const v4Schema = schema as unknown as ZodV4Internal;
const def = v4Schema._zod?.def;
if (def && (def.typeName === 'object' || def.shape !== undefined)) {
if (def && (def.type === 'object' || def.shape !== undefined)) {
return schema as AnyObjectSchema;
}
} else {
@ -238,7 +238,7 @@ export function getSchemaDescription(schema: AnySchema): string | undefined {
export function isSchemaOptional(schema: AnySchema): boolean {
if (isZ4Schema(schema)) {
const v4Schema = schema as unknown as ZodV4Internal;
return v4Schema._zod?.def?.typeName === 'ZodOptional';
return v4Schema._zod?.def?.type === 'optional';
}
const v3Schema = schema as unknown as ZodV3Internal;
// v3 has isOptional() method