Skip to content

Commit bb7a377

Browse files
committed
fix(server): reject unsupported elicitation schema keywords
1 parent 1580662 commit bb7a377

2 files changed

Lines changed: 59 additions & 0 deletions

File tree

packages/server/src/server/server.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,28 @@ export type ServerOptions = ProtocolOptions & {
8686
jsonSchemaValidator?: jsonSchemaValidator;
8787
};
8888

89+
function isJsonObject(value: unknown): value is Record<string, unknown> {
90+
return typeof value === 'object' && value !== null && !Array.isArray(value);
91+
}
92+
93+
function findStrippedJsonSchemaPaths(original: unknown, parsed: unknown, path = ''): string[] {
94+
if (Array.isArray(original) && Array.isArray(parsed)) {
95+
return original.flatMap((item, index) => findStrippedJsonSchemaPaths(item, parsed[index], `${path}[${index}]`));
96+
}
97+
98+
if (!isJsonObject(original) || !isJsonObject(parsed)) {
99+
return [];
100+
}
101+
102+
return Object.entries(original).flatMap(([key, value]) => {
103+
const childPath = path ? `${path}.${key}` : key;
104+
if (!Object.prototype.hasOwnProperty.call(parsed, key)) {
105+
return [childPath];
106+
}
107+
return findStrippedJsonSchemaPaths(value, parsed[key], childPath);
108+
});
109+
}
110+
89111
/**
90112
* An MCP server on top of a pluggable transport.
91113
*
@@ -625,6 +647,13 @@ export class Server extends Protocol<ServerContext> {
625647
`Elicitation requestedSchema only supports flat primitive properties (string, number, integer, boolean, and string enums): ${parsedParams.error.message}`
626648
);
627649
}
650+
const strippedSchemaPaths = findStrippedJsonSchemaPaths(normalizedParams.requestedSchema, parsedParams.data.requestedSchema);
651+
if (strippedSchemaPaths.length > 0) {
652+
throw new ProtocolError(
653+
ProtocolErrorCode.InvalidParams,
654+
`Elicitation requestedSchema contains unsupported JSON Schema keyword(s) after Standard Schema conversion: ${strippedSchemaPaths.join(', ')}`
655+
);
656+
}
628657
return { params: parsedParams.data, standardSchema };
629658
}
630659

packages/server/test/server/jsonSchemaValidatorOverride.test.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,36 @@ describe('server JSON Schema validator overrides', () => {
220220
).rejects.toThrow(/format/);
221221
expect(sawElicitationRequest).toBe(false);
222222

223+
await expect(
224+
server.elicitInput({
225+
message: 'What is your code?',
226+
requestedSchema: z.object({
227+
code: z.string().regex(/^[A-Z]{3}$/)
228+
})
229+
})
230+
).rejects.toThrow(/properties\.code\.pattern/);
231+
expect(sawElicitationRequest).toBe(false);
232+
233+
await expect(
234+
server.elicitInput({
235+
message: 'How many?',
236+
requestedSchema: z.object({
237+
count: z.number().multipleOf(2)
238+
})
239+
})
240+
).rejects.toThrow(/properties\.count\.multipleOf/);
241+
expect(sawElicitationRequest).toBe(false);
242+
243+
await expect(
244+
server.elicitInput({
245+
message: 'How many?',
246+
requestedSchema: z.object({
247+
count: z.number().gt(0)
248+
})
249+
})
250+
).rejects.toThrow(/properties\.count\.exclusiveMinimum/);
251+
expect(sawElicitationRequest).toBe(false);
252+
223253
await server.close();
224254
await clientTransport.close();
225255
});

0 commit comments

Comments
 (0)