Skip to content

Commit 7b6060f

Browse files
committed
BaseRequestParamsSchema, BaseNotificationParamsSchema, RequestMetaSchema, structuredContent and metadata to have passthrough
1 parent c3cf0f8 commit 7b6060f

File tree

3 files changed

+66
-9
lines changed

3 files changed

+66
-9
lines changed

scripts/generateStrictTypes.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,16 @@ const patternsToKeepOpen = [
3636
/_meta: z\.optional\(z\.object\(\{\}\)\.strip\(\)\)/g,
3737
// Keep JSON Schema properties open as they can have arbitrary fields
3838
/properties: z\.optional\(z\.object\(\{\}\)\.strip\(\)\)/g,
39+
// Keep BaseRequestParamsSchema passthrough for JSON-RPC param compatibility
40+
/const BaseRequestParamsSchema = z\s*\n\s*\.object\([\s\S]*?\)\s*\n\s*\.strip\(\)/g,
41+
// Keep BaseNotificationParamsSchema passthrough for JSON-RPC param compatibility
42+
/const BaseNotificationParamsSchema = z\s*\n\s*\.object\([\s\S]*?\)\s*\n\s*\.strip\(\)/g,
43+
// Keep RequestMetaSchema passthrough for extensibility
44+
/const RequestMetaSchema = z\s*\n\s*\.object\([\s\S]*?\)\s*\n\s*\.strip\(\)/g,
45+
// Keep structuredContent passthrough for tool-specific output
46+
/structuredContent: z\.object\(\{\}\)\.strip\(\)\.optional\(\)/g,
47+
// Keep metadata passthrough for provider-specific data in sampling
48+
/metadata: z\.optional\(z\.object\(\{\}\)\.strip\(\)\)/g,
3949
];
4050

4151
// Revert strip back to passthrough for these special cases
@@ -48,10 +58,15 @@ patternsToKeepOpen.forEach(pattern => {
4858
// Add a comment explaining the difference
4959
const explanation = `
5060
/**
51-
* Note: The following fields remain open (using .passthrough()):
61+
* Note: The following remain open (using .passthrough()):
5262
* - experimental: Designed for protocol extensions
5363
* - _meta: Designed for arbitrary metadata
5464
* - properties: JSON Schema properties that can have arbitrary fields
65+
* - BaseRequestParamsSchema: Required for JSON-RPC param compatibility
66+
* - BaseNotificationParamsSchema: Required for JSON-RPC param compatibility
67+
* - RequestMetaSchema: Required for protocol extensibility
68+
* - structuredContent: Tool-specific output that can have arbitrary fields
69+
* - metadata: Provider-specific metadata in sampling requests
5570
*
5671
* All other objects use .strip() to remove unknown properties while
5772
* maintaining compatibility with extended protocols.

src/strictTypes.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,15 @@ import { z, ZodTypeAny } from "zod";
2929
import { AuthInfo } from "./server/auth/types.js";
3030

3131
/**
32-
* Note: The following fields remain open (using .passthrough()):
32+
* Note: The following remain open (using .passthrough()):
3333
* - experimental: Designed for protocol extensions
3434
* - _meta: Designed for arbitrary metadata
3535
* - properties: JSON Schema properties that can have arbitrary fields
36+
* - BaseRequestParamsSchema: Required for JSON-RPC param compatibility
37+
* - BaseNotificationParamsSchema: Required for JSON-RPC param compatibility
38+
* - RequestMetaSchema: Required for protocol extensibility
39+
* - structuredContent: Tool-specific output that can have arbitrary fields
40+
* - metadata: Provider-specific metadata in sampling requests
3641
*
3742
* All other objects use .strip() to remove unknown properties while
3843
* maintaining compatibility with extended protocols.
@@ -67,13 +72,13 @@ const RequestMetaSchema = z
6772
*/
6873
progressToken: z.optional(ProgressTokenSchema),
6974
})
70-
.strip();
75+
.passthrough();
7176

7277
const BaseRequestParamsSchema = z
7378
.object({
7479
_meta: z.optional(RequestMetaSchema),
7580
})
76-
.strip();
81+
.passthrough();
7782

7883
export const RequestSchema = z.object({
7984
method: z.string(),
@@ -88,7 +93,7 @@ const BaseNotificationParamsSchema = z
8893
*/
8994
_meta: z.optional(z.object({}).passthrough()),
9095
})
91-
.strip();
96+
.passthrough();
9297

9398
export const NotificationSchema = z.object({
9499
method: z.string(),
@@ -1005,7 +1010,7 @@ export const CallToolResultSchema = ResultSchema.extend({
10051010
*
10061011
* If the Tool defines an outputSchema, this field MUST be present in the result, and contain a JSON object that matches the schema.
10071012
*/
1008-
structuredContent: z.object({}).strip().optional(),
1013+
structuredContent: z.object({}).passthrough().optional(),
10091014

10101015
/**
10111016
* Whether the tool call ended in an error.
@@ -1171,7 +1176,7 @@ export const CreateMessageRequestSchema = RequestSchema.extend({
11711176
/**
11721177
* Optional metadata to pass through to the LLM provider. The format of this metadata is provider-specific.
11731178
*/
1174-
metadata: z.optional(z.object({}).strip()),
1179+
metadata: z.optional(z.object({}).passthrough()),
11751180
/**
11761181
* The server's preferences for which model to select.
11771182
*/

src/types.test.ts

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@ import {
55
ContentBlockSchema,
66
PromptMessageSchema,
77
CallToolResultSchema,
8-
CompleteRequestSchema
9-
} from "./types.js";
8+
CompleteRequestSchema,
9+
JSONRPCRequestSchema,
10+
ReadResourceRequestSchema
11+
} from "./strictTypes.js";
1012

1113
describe("Types", () => {
1214

@@ -312,4 +314,39 @@ describe("Types", () => {
312314
}
313315
});
314316
});
317+
318+
describe("JSONRPCRequest validation", () => {
319+
test("should preserve method-specific params for later validation", () => {
320+
// This test verifies that JSONRPCRequestSchema preserves method-specific
321+
// parameters (like 'uri' for resources/read) so they can be validated
322+
// by the specific request schema later in the processing pipeline.
323+
324+
const jsonRpcRequest = {
325+
jsonrpc: "2.0",
326+
id: 1,
327+
method: "resources/read",
328+
params: {
329+
uri: "file:///test.txt",
330+
_meta: { progressToken: "token" }
331+
}
332+
};
333+
334+
// Step 1: Validate as a generic JSON-RPC request
335+
const jsonRpcResult = JSONRPCRequestSchema.safeParse(jsonRpcRequest);
336+
expect(jsonRpcResult.success).toBe(true);
337+
338+
if (jsonRpcResult.success) {
339+
// The params should still contain method-specific fields like 'uri'
340+
// even though they're not defined in the base schema
341+
expect(jsonRpcResult.data.params).toBeDefined();
342+
const params = jsonRpcResult.data.params as { uri: string; _meta?: { progressToken?: string } };
343+
expect(params.uri).toBe("file:///test.txt");
344+
expect(params._meta?.progressToken).toBe("token");
345+
}
346+
347+
// Step 2: The same request should also validate as ReadResourceRequest
348+
const readResourceResult = ReadResourceRequestSchema.safeParse(jsonRpcRequest);
349+
expect(readResourceResult.success).toBe(true);
350+
});
351+
});
315352
});

0 commit comments

Comments
 (0)