diff --git a/.changeset/elicit-string-pattern.md b/.changeset/elicit-string-pattern.md new file mode 100644 index 000000000..44e5e120d --- /dev/null +++ b/.changeset/elicit-string-pattern.md @@ -0,0 +1,5 @@ +--- +'@modelcontextprotocol/core': patch +--- + +Preserve `pattern` constraints on elicitation string property schemas during request validation. diff --git a/packages/core/src/types/schemas.ts b/packages/core/src/types/schemas.ts index a243c1b82..0610a9c7b 100644 --- a/packages/core/src/types/schemas.ts +++ b/packages/core/src/types/schemas.ts @@ -1733,6 +1733,7 @@ export const StringSchemaSchema = z.object({ description: z.string().optional(), minLength: z.number().optional(), maxLength: z.number().optional(), + pattern: z.string().optional(), format: z.enum(['email', 'uri', 'date', 'date-time']).optional(), default: z.string().optional() }); diff --git a/packages/core/test/spec.types.test.ts b/packages/core/test/spec.types.test.ts index d26a4cd70..9a60b59db 100644 --- a/packages/core/test/spec.types.test.ts +++ b/packages/core/test/spec.types.test.ts @@ -868,6 +868,7 @@ type _K_EmbeddedResource = Assert>; type _K_PromptMessage = Assert>; type _K_BooleanSchema = Assert>; +// @ts-expect-error The written 2025-11-25 elicitation spec includes StringSchema.pattern, but generated spec types lag it. type _K_StringSchema = Assert>; type _K_NumberSchema = Assert>; type _K_UntitledSingleSelectEnumSchema = Assert< diff --git a/packages/core/test/types.test.ts b/packages/core/test/types.test.ts index 9383f7d5e..108af85bf 100644 --- a/packages/core/test/types.test.ts +++ b/packages/core/test/types.test.ts @@ -11,6 +11,7 @@ import { PromptMessageSchema, ResourceLinkSchema, SamplingMessageSchema, + StringSchemaSchema, SUPPORTED_PROTOCOL_VERSIONS, ToolChoiceSchema, ToolResultContentSchema, @@ -986,6 +987,18 @@ describe('Types', () => { }); describe('ElicitRequestFormParamsSchema', () => { + test('preserves string pattern constraints in property schemas', () => { + const stringResult = StringSchemaSchema.safeParse({ + type: 'string', + pattern: '^[A-Za-z]+$' + }); + + expect(stringResult.success).toBe(true); + if (stringResult.success) { + expect(stringResult.data.pattern).toBe('^[A-Za-z]+$'); + } + }); + test('accepts requestedSchema with extra JSON Schema metadata keys', () => { // Mirrors what z.toJSONSchema() emits — includes $schema, additionalProperties, etc. // See https://github.com/modelcontextprotocol/typescript-sdk/issues/1362 @@ -995,7 +1008,7 @@ describe('Types', () => { $schema: 'https://json-schema.org/draft/2020-12/schema', type: 'object', properties: { - name: { type: 'string' } + name: { type: 'string', pattern: '^[A-Za-z]+$' } }, required: ['name'], additionalProperties: false @@ -1008,6 +1021,9 @@ describe('Types', () => { expect(result.data.requestedSchema.type).toBe('object'); expect(result.data.requestedSchema.$schema).toBe('https://json-schema.org/draft/2020-12/schema'); expect(result.data.requestedSchema.additionalProperties).toBe(false); + expect(result.data.requestedSchema.properties.name).toEqual( + expect.objectContaining({ type: 'string', pattern: '^[A-Za-z]+$' }) + ); } }); });