From cdbeeaf57340ddd42097e954b89d95a7f42f2cd3 Mon Sep 17 00:00:00 2001 From: seongwon seo Date: Thu, 4 Dec 2025 18:03:40 +0900 Subject: [PATCH] fix: improve Zod v4 optional schema detection - Prioritize `isOptional()` method check in isSchemaOptional to support both Zod v3 and v4 consistently. - Add `typeName` check for Zod v4 internal definitions to correctly identify optional schemas. - Fixes an issue where optional tool arguments were incorrectly marked as required in the generated JSON schema. --- src/server/zod-compat.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/server/zod-compat.ts b/src/server/zod-compat.ts index 04ee5361f..f73e0e183 100644 --- a/src/server/zod-compat.ts +++ b/src/server/zod-compat.ts @@ -32,6 +32,7 @@ export interface ZodV4Internal { _zod?: { def?: { type?: string; + typeName?: string; value?: unknown; values?: unknown[]; shape?: Record | (() => Record); @@ -236,15 +237,16 @@ export function getSchemaDescription(schema: AnySchema): string | undefined { * Works with both Zod v3 and v4. */ export function isSchemaOptional(schema: AnySchema): boolean { + // Check for isOptional method first (works for both v3 and v4 usually) + if (typeof (schema as { isOptional?: () => boolean }).isOptional === 'function') { + return (schema as { isOptional: () => boolean }).isOptional(); + } + if (isZ4Schema(schema)) { const v4Schema = schema as unknown as ZodV4Internal; - return v4Schema._zod?.def?.type === 'optional'; + return v4Schema._zod?.def?.type === 'optional' || v4Schema._zod?.def?.typeName === 'ZodOptional'; } const v3Schema = schema as unknown as ZodV3Internal; - // v3 has isOptional() method - if (typeof (schema as { isOptional?: () => boolean }).isOptional === 'function') { - return (schema as { isOptional: () => boolean }).isOptional(); - } return v3Schema._def?.typeName === 'ZodOptional'; }