Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
174 changes: 97 additions & 77 deletions packages/core/src/types/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1717,116 +1717,136 @@ export const CreateMessageResultWithToolsSchema = ResultSchema.extend({
/**
* Primitive schema definition for boolean fields.
*/
export const BooleanSchemaSchema = z.object({
type: z.literal('boolean'),
title: z.string().optional(),
description: z.string().optional(),
default: z.boolean().optional()
});
export const BooleanSchemaSchema = z
.object({
type: z.literal('boolean'),
title: z.string().optional(),
description: z.string().optional(),
default: z.boolean().optional()
})
.passthrough();

/**
* Primitive schema definition for string fields.
*/
export const StringSchemaSchema = z.object({
type: z.literal('string'),
title: z.string().optional(),
description: z.string().optional(),
minLength: z.number().optional(),
maxLength: z.number().optional(),
format: z.enum(['email', 'uri', 'date', 'date-time']).optional(),
default: z.string().optional()
});
export const StringSchemaSchema = z
.object({
type: z.literal('string'),
title: z.string().optional(),
description: z.string().optional(),
minLength: z.number().optional(),
maxLength: z.number().optional(),
format: z.enum(['email', 'uri', 'date', 'date-time']).optional(),
default: z.string().optional()
})
.passthrough();

/**
* Primitive schema definition for number fields.
*/
export const NumberSchemaSchema = z.object({
type: z.enum(['number', 'integer']),
title: z.string().optional(),
description: z.string().optional(),
minimum: z.number().optional(),
maximum: z.number().optional(),
default: z.number().optional()
});
export const NumberSchemaSchema = z
.object({
type: z.enum(['number', 'integer']),
title: z.string().optional(),
description: z.string().optional(),
minimum: z.number().optional(),
maximum: z.number().optional(),
default: z.number().optional()
})
.passthrough();

/**
* Schema for single-selection enumeration without display titles for options.
*/
export const UntitledSingleSelectEnumSchemaSchema = z.object({
type: z.literal('string'),
title: z.string().optional(),
description: z.string().optional(),
enum: z.array(z.string()),
default: z.string().optional()
});
export const UntitledSingleSelectEnumSchemaSchema = z
.object({
type: z.literal('string'),
title: z.string().optional(),
description: z.string().optional(),
enum: z.array(z.string()),
default: z.string().optional()
})
.passthrough();

/**
* Schema for single-selection enumeration with display titles for each option.
*/
export const TitledSingleSelectEnumSchemaSchema = z.object({
type: z.literal('string'),
title: z.string().optional(),
description: z.string().optional(),
oneOf: z.array(
z.object({
const: z.string(),
title: z.string()
})
),
default: z.string().optional()
});
export const TitledSingleSelectEnumSchemaSchema = z
.object({
type: z.literal('string'),
title: z.string().optional(),
description: z.string().optional(),
oneOf: z.array(
z.object({
const: z.string(),
title: z.string()
})
),
default: z.string().optional()
})
.passthrough();

/**
* Use {@linkcode TitledSingleSelectEnumSchema} instead.
* This interface will be removed in a future version.
*/
export const LegacyTitledEnumSchemaSchema = z.object({
type: z.literal('string'),
title: z.string().optional(),
description: z.string().optional(),
enum: z.array(z.string()),
enumNames: z.array(z.string()).optional(),
default: z.string().optional()
});
export const LegacyTitledEnumSchemaSchema = z
.object({
type: z.literal('string'),
title: z.string().optional(),
description: z.string().optional(),
enum: z.array(z.string()),
enumNames: z.array(z.string()).optional(),
default: z.string().optional()
})
.passthrough();

// Combined single selection enumeration
export const SingleSelectEnumSchemaSchema = z.union([UntitledSingleSelectEnumSchemaSchema, TitledSingleSelectEnumSchemaSchema]);

/**
* Schema for multiple-selection enumeration without display titles for options.
*/
export const UntitledMultiSelectEnumSchemaSchema = z.object({
type: z.literal('array'),
title: z.string().optional(),
description: z.string().optional(),
minItems: z.number().optional(),
maxItems: z.number().optional(),
items: z.object({
type: z.literal('string'),
enum: z.array(z.string())
}),
default: z.array(z.string()).optional()
});
export const UntitledMultiSelectEnumSchemaSchema = z
.object({
type: z.literal('array'),
title: z.string().optional(),
description: z.string().optional(),
minItems: z.number().optional(),
maxItems: z.number().optional(),
items: z
.object({
type: z.literal('string'),
enum: z.array(z.string())
})
.passthrough(),
default: z.array(z.string()).optional()
})
.passthrough();

/**
* Schema for multiple-selection enumeration with display titles for each option.
*/
export const TitledMultiSelectEnumSchemaSchema = z.object({
type: z.literal('array'),
title: z.string().optional(),
description: z.string().optional(),
minItems: z.number().optional(),
maxItems: z.number().optional(),
items: z.object({
anyOf: z.array(
z.object({
const: z.string(),
title: z.string()
export const TitledMultiSelectEnumSchemaSchema = z
.object({
type: z.literal('array'),
title: z.string().optional(),
description: z.string().optional(),
minItems: z.number().optional(),
maxItems: z.number().optional(),
items: z
.object({
anyOf: z.array(
z.object({
const: z.string(),
title: z.string()
})
)
})
)
}),
default: z.array(z.string()).optional()
});
.passthrough(),
default: z.array(z.string()).optional()
})
.passthrough();

/**
* Combined schema for multiple-selection enumeration
Expand Down
8 changes: 8 additions & 0 deletions packages/core/src/types/spec.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2879,6 +2879,7 @@ export interface StringSchema {
maxLength?: number;
format?: 'email' | 'uri' | 'date' | 'date-time';
default?: string;
[key: string]: unknown;
}

/**
Expand All @@ -2894,6 +2895,7 @@ export interface NumberSchema {
minimum?: number;
maximum?: number;
default?: number;
[key: string]: unknown;
}

/**
Expand All @@ -2907,6 +2909,7 @@ export interface BooleanSchema {
title?: string;
description?: string;
default?: boolean;
[key: string]: unknown;
}

/**
Expand Down Expand Up @@ -2935,6 +2938,7 @@ export interface UntitledSingleSelectEnumSchema {
* Optional default value.
*/
default?: string;
[key: string]: unknown;
}

/**
Expand Down Expand Up @@ -2972,6 +2976,7 @@ export interface TitledSingleSelectEnumSchema {
* Optional default value.
*/
default?: string;
[key: string]: unknown;
}

/**
Expand Down Expand Up @@ -3020,6 +3025,7 @@ export interface UntitledMultiSelectEnumSchema {
* Optional default value.
*/
default?: string[];
[key: string]: unknown;
}

/**
Expand Down Expand Up @@ -3070,6 +3076,7 @@ export interface TitledMultiSelectEnumSchema {
* Optional default value.
*/
default?: string[];
[key: string]: unknown;
}

/**
Expand All @@ -3095,6 +3102,7 @@ export interface LegacyTitledEnumSchema {
*/
enumNames?: string[];
default?: string;
[key: string]: unknown;
}

/**
Expand Down
2 changes: 0 additions & 2 deletions test/integration/test/server/elicitation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,6 @@ function testElicitationFlow(validatorProvider: typeof ajvProvider | typeof cfWo
age: { type: 'integer', minimum: 0, maximum: 150 },
street: { type: 'string' },
city: { type: 'string' },
// @ts-expect-error - pattern is not a valid property by MCP spec, however it is making use of the Ajv validator
zipCode: { type: 'string', pattern: '^[0-9]{5}$' },
newsletter: { type: 'boolean' },
notifications: { type: 'boolean' }
Expand Down Expand Up @@ -280,7 +279,6 @@ function testElicitationFlow(validatorProvider: typeof ajvProvider | typeof cfWo
requestedSchema: {
type: 'object',
properties: {
// @ts-expect-error - pattern is not a valid property by MCP spec, however it is making use of the Ajv validator
zipCode: { type: 'string', pattern: '^[0-9]{5}$' }
},
required: ['zipCode']
Expand Down
Loading