Skip to content

Commit 287dfbc

Browse files
committed
test: expect invalid tool args protocol errors
1 parent 7a1412c commit 287dfbc

3 files changed

Lines changed: 67 additions & 91 deletions

File tree

test/e2e/requirements.ts

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2375,12 +2375,7 @@ export const REQUIREMENTS: Record<string, Requirement> = {
23752375
'standardschema:tool:invalid-args-rejected': {
23762376
source: 'sdk',
23772377
behavior:
2378-
'tools/call arguments that fail the registered Standard Schema validation are rejected with JSON-RPC -32602 (Input validation error) and the tool handler is not invoked.',
2379-
knownFailures: [
2380-
{
2381-
note: "McpServer's tools/call handler catches the input-validation ProtocolError (-32602) and returns it as an isError result, so callTool() resolves instead of rejecting; the handler is still not invoked."
2382-
}
2383-
]
2378+
'tools/call arguments that fail the registered Standard Schema validation are rejected with JSON-RPC -32602 (Input validation error) and the tool handler is not invoked.'
23842379
},
23852380
'validators:from-json-schema:tool-roundtrip': {
23862381
source: 'sdk',
@@ -2390,12 +2385,7 @@ export const REQUIREMENTS: Record<string, Requirement> = {
23902385
'validators:from-json-schema:invalid-args-rejected': {
23912386
source: 'sdk',
23922387
behavior:
2393-
'tools/call arguments violating the JSON Schema wrapped by fromJsonSchema() are rejected with JSON-RPC -32602 and the handler is not invoked.',
2394-
knownFailures: [
2395-
{
2396-
note: "McpServer's tools/call handler catches the input-validation ProtocolError (-32602) and returns it as an isError result, so callTool() resolves instead of rejecting; the handler is still not invoked."
2397-
}
2398-
]
2388+
'tools/call arguments violating the JSON Schema wrapped by fromJsonSchema() are rejected with JSON-RPC -32602 and the handler is not invoked.'
23992389
},
24002390
'validators:custom-validator:override': {
24012391
source: 'sdk',

test/e2e/scenarios/tools.test.ts

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1064,14 +1064,16 @@ verifies('mcpserver:tool:input-validation', async ({ transport }: TestArgs) => {
10641064
expect(ok.isError).toBeFalsy();
10651065
expect(handlerCalls.n).toBe(1);
10661066

1067-
const wrongType = await client.callTool({ name: 'typed', arguments: { prompt: 123 } });
1068-
expect(wrongType.isError).toBe(true);
1069-
expect(wrongType.content).toEqual([{ type: 'text', text: expect.stringMatching(/invalid|validation/i) }]);
1067+
await expect(client.callTool({ name: 'typed', arguments: { prompt: 123 } })).rejects.toMatchObject({
1068+
code: ProtocolErrorCode.InvalidParams,
1069+
message: expect.stringMatching(/invalid|validation/i)
1070+
});
10701071
expect(handlerCalls.n).toBe(1);
10711072

1072-
const missing = await client.callTool({ name: 'typed', arguments: {} });
1073-
expect(missing.isError).toBe(true);
1074-
expect(missing.content).toEqual([{ type: 'text', text: expect.stringMatching(/invalid|validation|required/i) }]);
1073+
await expect(client.callTool({ name: 'typed', arguments: {} })).rejects.toMatchObject({
1074+
code: ProtocolErrorCode.InvalidParams,
1075+
message: expect.stringMatching(/invalid|validation|required/i)
1076+
});
10751077
expect(handlerCalls.n).toBe(1);
10761078
});
10771079

@@ -1200,14 +1202,18 @@ verifies('typescript:mcpserver:tool:schema-variants', async ({ transport }: Test
12001202
expect(coerced.content).toEqual([{ type: 'text', text: 'coerced:7' }]);
12011203

12021204
// Rejections — proves parse() actually runs for each shape.
1203-
const unionRejected = await client.callTool({ name: 'zod-union', arguments: { kind: 'a', a: 123 } });
1204-
expect(unionRejected.isError).toBe(true);
1205-
const intersectionRejected = await client.callTool({ name: 'zod-intersection', arguments: { left: 'L' } });
1206-
expect(intersectionRejected.isError).toBe(true);
1207-
const nestedRejected = await client.callTool({ name: 'zod-nested', arguments: { outer: { inner: { value: 'x' } } } });
1208-
expect(nestedRejected.isError).toBe(true);
1209-
const coerceRejected = await client.callTool({ name: 'zod-coerce', arguments: { n: '-3' } });
1210-
expect(coerceRejected.isError).toBe(true);
1205+
await expect(client.callTool({ name: 'zod-union', arguments: { kind: 'a', a: 123 } })).rejects.toMatchObject({
1206+
code: ProtocolErrorCode.InvalidParams
1207+
});
1208+
await expect(client.callTool({ name: 'zod-intersection', arguments: { left: 'L' } })).rejects.toMatchObject({
1209+
code: ProtocolErrorCode.InvalidParams
1210+
});
1211+
await expect(client.callTool({ name: 'zod-nested', arguments: { outer: { inner: { value: 'x' } } } })).rejects.toMatchObject({
1212+
code: ProtocolErrorCode.InvalidParams
1213+
});
1214+
await expect(client.callTool({ name: 'zod-coerce', arguments: { n: '-3' } })).rejects.toMatchObject({
1215+
code: ProtocolErrorCode.InvalidParams
1216+
});
12111217
});
12121218

12131219
verifies('typescript:mcpserver:tool:extra', async ({ transport }: TestArgs) => {

test/integration/test/server/mcp.test.ts

Lines changed: 45 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1212,26 +1212,21 @@ describe('Zod v4', () => {
12121212

12131213
await Promise.all([client.connect(clientTransport), mcpServer.server.connect(serverTransport)]);
12141214

1215-
const result = await client.request({
1216-
method: 'tools/call',
1217-
params: {
1218-
name: 'test',
1219-
arguments: {
1215+
await expect(
1216+
client.request({
1217+
method: 'tools/call',
1218+
params: {
12201219
name: 'test',
1221-
value: 'not a number'
1220+
arguments: {
1221+
name: 'test',
1222+
value: 'not a number'
1223+
}
12221224
}
1223-
}
1225+
})
1226+
).rejects.toMatchObject({
1227+
code: ProtocolErrorCode.InvalidParams,
1228+
message: expect.stringContaining('Input validation error: Invalid arguments for tool test')
12241229
});
1225-
1226-
expect(result.isError).toBe(true);
1227-
expect(result.content).toEqual(
1228-
expect.arrayContaining([
1229-
{
1230-
type: 'text',
1231-
text: expect.stringContaining('Input validation error: Invalid arguments for tool test')
1232-
}
1233-
])
1234-
);
12351230
});
12361231

12371232
/***
@@ -5149,23 +5144,18 @@ describe('Zod v4', () => {
51495144
await server.connect(serverTransport);
51505145
await client.connect(clientTransport);
51515146

5152-
const invalidTypeResult = await client.callTool({
5153-
name: 'union-test',
5154-
arguments: {
5155-
type: 'a',
5156-
value: 123
5157-
}
5147+
await expect(
5148+
client.callTool({
5149+
name: 'union-test',
5150+
arguments: {
5151+
type: 'a',
5152+
value: 123
5153+
}
5154+
})
5155+
).rejects.toMatchObject({
5156+
code: ProtocolErrorCode.InvalidParams,
5157+
message: expect.stringContaining('Input validation error')
51585158
});
5159-
5160-
expect(invalidTypeResult.isError).toBe(true);
5161-
expect(invalidTypeResult.content).toEqual(
5162-
expect.arrayContaining([
5163-
expect.objectContaining({
5164-
type: 'text',
5165-
text: expect.stringContaining('Input validation error')
5166-
})
5167-
])
5168-
);
51695159
});
51705160
});
51715161

@@ -6407,41 +6397,31 @@ describe('Zod v4', () => {
64076397
await server.connect(serverTransport);
64086398
await client.connect(clientTransport);
64096399

6410-
const invalidTypeResult = await client.callTool({
6411-
name: 'union-test',
6412-
arguments: {
6413-
type: 'a',
6414-
value: 123
6415-
}
6400+
await expect(
6401+
client.callTool({
6402+
name: 'union-test',
6403+
arguments: {
6404+
type: 'a',
6405+
value: 123
6406+
}
6407+
})
6408+
).rejects.toMatchObject({
6409+
code: ProtocolErrorCode.InvalidParams,
6410+
message: expect.stringContaining('Input validation error')
64166411
});
64176412

6418-
expect(invalidTypeResult.isError).toBe(true);
6419-
expect(invalidTypeResult.content).toEqual(
6420-
expect.arrayContaining([
6421-
expect.objectContaining({
6422-
type: 'text',
6423-
text: expect.stringContaining('Input validation error')
6424-
})
6425-
])
6426-
);
6427-
6428-
const invalidDiscriminatorResult = await client.callTool({
6429-
name: 'union-test',
6430-
arguments: {
6431-
type: 'c',
6432-
value: 'test'
6433-
}
6413+
await expect(
6414+
client.callTool({
6415+
name: 'union-test',
6416+
arguments: {
6417+
type: 'c',
6418+
value: 'test'
6419+
}
6420+
})
6421+
).rejects.toMatchObject({
6422+
code: ProtocolErrorCode.InvalidParams,
6423+
message: expect.stringContaining('Input validation error')
64346424
});
6435-
6436-
expect(invalidDiscriminatorResult.isError).toBe(true);
6437-
expect(invalidDiscriminatorResult.content).toEqual(
6438-
expect.arrayContaining([
6439-
expect.objectContaining({
6440-
type: 'text',
6441-
text: expect.stringContaining('Input validation error')
6442-
})
6443-
])
6444-
);
64456425
});
64466426
});
64476427

0 commit comments

Comments
 (0)