Skip to content

Commit f1c3238

Browse files
fix: restore extensibility for ToolAnnotations schema
The ToolAnnotations schema should allow additional properties per the MCP specification. The JSON Schema at: https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/schema/draft/schema.json does NOT include "additionalProperties": false for ToolAnnotations, which means additional properties are allowed by default per JSON Schema semantics. This was accidentally removed in commit f59996a (SEP-1319) when .passthrough() was dropped during schema cleanup. This broke consumers like Cloudflare's x402 integration that rely on extending annotations with custom fields (e.g., paymentHint, paymentPriceUSD). Using .catchall(z.unknown()) rather than .passthrough() for consistency with other schemas per commit 913ca2a.
1 parent 4318933 commit f1c3238

File tree

1 file changed

+41
-39
lines changed

1 file changed

+41
-39
lines changed

src/types.ts

Lines changed: 41 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -944,49 +944,51 @@ export const PromptListChangedNotificationSchema = NotificationSchema.extend({
944944
* Clients should never make tool use decisions based on ToolAnnotations
945945
* received from untrusted servers.
946946
*/
947-
export const ToolAnnotationsSchema = z.object({
948-
/**
949-
* A human-readable title for the tool.
950-
*/
951-
title: z.string().optional(),
947+
export const ToolAnnotationsSchema = z
948+
.object({
949+
/**
950+
* A human-readable title for the tool.
951+
*/
952+
title: z.string().optional(),
952953

953-
/**
954-
* If true, the tool does not modify its environment.
955-
*
956-
* Default: false
957-
*/
958-
readOnlyHint: z.boolean().optional(),
954+
/**
955+
* If true, the tool does not modify its environment.
956+
*
957+
* Default: false
958+
*/
959+
readOnlyHint: z.boolean().optional(),
959960

960-
/**
961-
* If true, the tool may perform destructive updates to its environment.
962-
* If false, the tool performs only additive updates.
963-
*
964-
* (This property is meaningful only when `readOnlyHint == false`)
965-
*
966-
* Default: true
967-
*/
968-
destructiveHint: z.boolean().optional(),
961+
/**
962+
* If true, the tool may perform destructive updates to its environment.
963+
* If false, the tool performs only additive updates.
964+
*
965+
* (This property is meaningful only when `readOnlyHint == false`)
966+
*
967+
* Default: true
968+
*/
969+
destructiveHint: z.boolean().optional(),
969970

970-
/**
971-
* If true, calling the tool repeatedly with the same arguments
972-
* will have no additional effect on the its environment.
973-
*
974-
* (This property is meaningful only when `readOnlyHint == false`)
975-
*
976-
* Default: false
977-
*/
978-
idempotentHint: z.boolean().optional(),
971+
/**
972+
* If true, calling the tool repeatedly with the same arguments
973+
* will have no additional effect on the its environment.
974+
*
975+
* (This property is meaningful only when `readOnlyHint == false`)
976+
*
977+
* Default: false
978+
*/
979+
idempotentHint: z.boolean().optional(),
979980

980-
/**
981-
* If true, this tool may interact with an "open world" of external
982-
* entities. If false, the tool's domain of interaction is closed.
983-
* For example, the world of a web search tool is open, whereas that
984-
* of a memory tool is not.
985-
*
986-
* Default: true
987-
*/
988-
openWorldHint: z.boolean().optional()
989-
});
981+
/**
982+
* If true, this tool may interact with an "open world" of external
983+
* entities. If false, the tool's domain of interaction is closed.
984+
* For example, the world of a web search tool is open, whereas that
985+
* of a memory tool is not.
986+
*
987+
* Default: true
988+
*/
989+
openWorldHint: z.boolean().optional()
990+
})
991+
.catchall(z.unknown());
990992

991993
/**
992994
* Definition for a tool the client can call.

0 commit comments

Comments
 (0)