Skip to content

Commit ddcbe11

Browse files
ochafikclaude
andcommitted
feat: add Base64 validation and re-export content schemas
Add Base64 field overrides in ts-morph for: - ImageContentSchema.data - AudioContentSchema.data - BlobResourceContentsSchema.blob Re-export 9 more schemas from generated: - TextContentSchema, ImageContentSchema, AudioContentSchema - EmbeddedResourceSchema, ResourceLinkSchema, ContentBlockSchema - ResourceContentsSchema, TextResourceContentsSchema, BlobResourceContentsSchema Total schemas re-exported: 31 Lines saved: ~340 (2600 → 2261) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent e9d8bc1 commit ddcbe11

File tree

3 files changed

+78
-166
lines changed

3 files changed

+78
-166
lines changed

scripts/generate-schemas.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,15 @@ const SCHEMA_TEST_OUTPUT_FILE = join(GENERATED_DIR, 'sdk.schemas.zod.test.ts');
5252
// Configuration: Field-level validation overrides
5353
// =============================================================================
5454

55+
/**
56+
* Base64 validation expression - validates that a string is valid base64.
57+
* Used for image data, audio data, and blob contents.
58+
*/
59+
const BASE64_VALIDATOR = `z.string().refine(
60+
(val) => { try { atob(val); return true; } catch { return false; } },
61+
{ message: 'Invalid base64 string' }
62+
)`;
63+
5564
/**
5665
* Field-level overrides for enhanced validation.
5766
* These replace generated z.string() with more specific validators.
@@ -62,6 +71,16 @@ const FIELD_OVERRIDES: Record<string, Record<string, string>> = {
6271
},
6372
'RootSchema': {
6473
'uri': 'z.string().startsWith("file://")'
74+
},
75+
// Base64 validation for binary content
76+
'ImageContentSchema': {
77+
'data': BASE64_VALIDATOR
78+
},
79+
'AudioContentSchema': {
80+
'data': BASE64_VALIDATOR
81+
},
82+
'BlobResourceContentsSchema': {
83+
'blob': BASE64_VALIDATOR
6584
}
6685
};
6786

src/generated/sdk.schemas.ts

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -738,7 +738,17 @@ export const BlobResourceContentsSchema = ResourceContentsSchema.extend({
738738
*
739739
* @format byte
740740
*/
741-
blob: z.string()
741+
blob: z.string().refine(
742+
val => {
743+
try {
744+
atob(val);
745+
return true;
746+
} catch {
747+
return false;
748+
}
749+
},
750+
{ message: 'Invalid base64 string' }
751+
)
742752
});
743753

744754
/* Prompts */
@@ -1296,7 +1306,17 @@ export const ImageContentSchema = z.object({
12961306
*
12971307
* @format byte
12981308
*/
1299-
data: z.string(),
1309+
data: z.string().refine(
1310+
val => {
1311+
try {
1312+
atob(val);
1313+
return true;
1314+
} catch {
1315+
return false;
1316+
}
1317+
},
1318+
{ message: 'Invalid base64 string' }
1319+
),
13001320
/**
13011321
* The MIME type of the image. Different providers may support different image types.
13021322
*/
@@ -1323,7 +1343,17 @@ export const AudioContentSchema = z.object({
13231343
*
13241344
* @format byte
13251345
*/
1326-
data: z.string(),
1346+
data: z.string().refine(
1347+
val => {
1348+
try {
1349+
atob(val);
1350+
return true;
1351+
} catch {
1352+
return false;
1353+
}
1354+
},
1355+
{ message: 'Invalid base64 string' }
1356+
),
13271357
/**
13281358
* The MIME type of the audio. Different providers may support different audio types.
13291359
*/

src/types.ts

Lines changed: 26 additions & 163 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,20 @@ import {
3737
// Elicitation primitive schemas
3838
BooleanSchemaSchema,
3939
NumberSchemaSchema,
40-
// Schemas with enhanced validation (datetime, startsWith)
40+
// Schemas with enhanced validation (datetime, startsWith, base64)
4141
AnnotationsSchema,
4242
RootSchema,
43+
// Content schemas (with Base64 validation for data/blob fields)
44+
TextContentSchema,
45+
ImageContentSchema,
46+
AudioContentSchema,
47+
EmbeddedResourceSchema,
48+
ResourceLinkSchema,
49+
ContentBlockSchema,
50+
// Resource content schemas
51+
ResourceContentsSchema,
52+
TextResourceContentsSchema,
53+
BlobResourceContentsSchema,
4354
} from './generated/sdk.schemas.js';
4455

4556
export {
@@ -65,6 +76,15 @@ export {
6576
NumberSchemaSchema,
6677
AnnotationsSchema,
6778
RootSchema,
79+
TextContentSchema,
80+
ImageContentSchema,
81+
AudioContentSchema,
82+
EmbeddedResourceSchema,
83+
ResourceLinkSchema,
84+
ContentBlockSchema,
85+
ResourceContentsSchema,
86+
TextResourceContentsSchema,
87+
BlobResourceContentsSchema,
6888
};
6989

7090
export const LATEST_PROTOCOL_VERSION = '2025-11-25';
@@ -718,59 +738,8 @@ export const CancelTaskRequestSchema = RequestSchema.extend({
718738
export const CancelTaskResultSchema = ResultSchema.merge(TaskSchema);
719739

720740
/* Resources */
721-
/**
722-
* The contents of a specific resource or sub-resource.
723-
*/
724-
export const ResourceContentsSchema = z.object({
725-
/**
726-
* The URI of this resource.
727-
*/
728-
uri: z.string(),
729-
/**
730-
* The MIME type of this resource, if known.
731-
*/
732-
mimeType: z.optional(z.string()),
733-
/**
734-
* See [MCP specification](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/47339c03c143bb4ec01a26e721a1b8fe66634ebe/docs/specification/draft/basic/index.mdx#general-fields)
735-
* for notes on _meta usage.
736-
*/
737-
_meta: z.record(z.string(), z.unknown()).optional()
738-
});
739-
740-
export const TextResourceContentsSchema = ResourceContentsSchema.extend({
741-
/**
742-
* The text of the item. This must only be set if the item can actually be represented as text (not binary data).
743-
*/
744-
text: z.string()
745-
});
746-
747-
/**
748-
* A Zod schema for validating Base64 strings that is more performant and
749-
* robust for very large inputs than the default regex-based check. It avoids
750-
* stack overflows by using the native `atob` function for validation.
751-
*/
752-
const Base64Schema = z.string().refine(
753-
val => {
754-
try {
755-
// atob throws a DOMException if the string contains characters
756-
// that are not part of the Base64 character set.
757-
atob(val);
758-
return true;
759-
} catch {
760-
return false;
761-
}
762-
},
763-
{ message: 'Invalid Base64 string' }
764-
);
765-
766-
export const BlobResourceContentsSchema = ResourceContentsSchema.extend({
767-
/**
768-
* A base64-encoded string representing the binary data of the item.
769-
*/
770-
blob: Base64Schema
771-
});
772-
773-
// Note: AnnotationsSchema is re-exported from generated with z.iso.datetime validation.
741+
// Note: ResourceContentsSchema, TextResourceContentsSchema, BlobResourceContentsSchema
742+
// are re-exported from generated with Base64 validation.
774743

775744
/**
776745
* A known resource that the server is capable of reading.
@@ -1018,79 +987,8 @@ export const GetPromptRequestSchema = RequestSchema.extend({
1018987
params: GetPromptRequestParamsSchema
1019988
});
1020989

1021-
/**
1022-
* Text provided to or from an LLM.
1023-
*/
1024-
export const TextContentSchema = z.object({
1025-
type: z.literal('text'),
1026-
/**
1027-
* The text content of the message.
1028-
*/
1029-
text: z.string(),
1030-
1031-
/**
1032-
* Optional annotations for the client.
1033-
*/
1034-
annotations: AnnotationsSchema.optional(),
1035-
1036-
/**
1037-
* See [MCP specification](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/47339c03c143bb4ec01a26e721a1b8fe66634ebe/docs/specification/draft/basic/index.mdx#general-fields)
1038-
* for notes on _meta usage.
1039-
*/
1040-
_meta: z.record(z.string(), z.unknown()).optional()
1041-
});
1042-
1043-
/**
1044-
* An image provided to or from an LLM.
1045-
*/
1046-
export const ImageContentSchema = z.object({
1047-
type: z.literal('image'),
1048-
/**
1049-
* The base64-encoded image data.
1050-
*/
1051-
data: Base64Schema,
1052-
/**
1053-
* The MIME type of the image. Different providers may support different image types.
1054-
*/
1055-
mimeType: z.string(),
1056-
1057-
/**
1058-
* Optional annotations for the client.
1059-
*/
1060-
annotations: AnnotationsSchema.optional(),
1061-
1062-
/**
1063-
* See [MCP specification](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/47339c03c143bb4ec01a26e721a1b8fe66634ebe/docs/specification/draft/basic/index.mdx#general-fields)
1064-
* for notes on _meta usage.
1065-
*/
1066-
_meta: z.record(z.string(), z.unknown()).optional()
1067-
});
1068-
1069-
/**
1070-
* An Audio provided to or from an LLM.
1071-
*/
1072-
export const AudioContentSchema = z.object({
1073-
type: z.literal('audio'),
1074-
/**
1075-
* The base64-encoded audio data.
1076-
*/
1077-
data: Base64Schema,
1078-
/**
1079-
* The MIME type of the audio. Different providers may support different audio types.
1080-
*/
1081-
mimeType: z.string(),
1082-
1083-
/**
1084-
* Optional annotations for the client.
1085-
*/
1086-
annotations: AnnotationsSchema.optional(),
1087-
1088-
/**
1089-
* See [MCP specification](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/47339c03c143bb4ec01a26e721a1b8fe66634ebe/docs/specification/draft/basic/index.mdx#general-fields)
1090-
* for notes on _meta usage.
1091-
*/
1092-
_meta: z.record(z.string(), z.unknown()).optional()
1093-
});
990+
// Note: TextContentSchema, ImageContentSchema, AudioContentSchema are re-exported
991+
// from generated with Base64 validation for data fields.
1094992

1095993
/**
1096994
* A tool call request from an assistant (LLM).
@@ -1120,42 +1018,7 @@ export const ToolUseContentSchema = z.object({
11201018
_meta: z.record(z.string(), z.unknown()).optional()
11211019
});
11221020

1123-
/**
1124-
* The contents of a resource, embedded into a prompt or tool call result.
1125-
*/
1126-
export const EmbeddedResourceSchema = z.object({
1127-
type: z.literal('resource'),
1128-
resource: z.union([TextResourceContentsSchema, BlobResourceContentsSchema]),
1129-
/**
1130-
* Optional annotations for the client.
1131-
*/
1132-
annotations: AnnotationsSchema.optional(),
1133-
/**
1134-
* See [MCP specification](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/47339c03c143bb4ec01a26e721a1b8fe66634ebe/docs/specification/draft/basic/index.mdx#general-fields)
1135-
* for notes on _meta usage.
1136-
*/
1137-
_meta: z.record(z.string(), z.unknown()).optional()
1138-
});
1139-
1140-
/**
1141-
* A resource that the server is capable of reading, included in a prompt or tool call result.
1142-
*
1143-
* Note: resource links returned by tools are not guaranteed to appear in the results of `resources/list` requests.
1144-
*/
1145-
export const ResourceLinkSchema = ResourceSchema.extend({
1146-
type: z.literal('resource_link')
1147-
});
1148-
1149-
/**
1150-
* A content block that can be used in prompts and tool results.
1151-
*/
1152-
export const ContentBlockSchema = z.union([
1153-
TextContentSchema,
1154-
ImageContentSchema,
1155-
AudioContentSchema,
1156-
ResourceLinkSchema,
1157-
EmbeddedResourceSchema
1158-
]);
1021+
// Note: EmbeddedResourceSchema, ResourceLinkSchema, ContentBlockSchema are re-exported from generated.
11591022

11601023
/**
11611024
* Describes a message returned as part of a prompt.

0 commit comments

Comments
 (0)