-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Type generics for CallToolResult - Require 'structuredContent' if 'outputSchema' defined. #859
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 5 commits
85510c2
7023152
0094b67
eef9e7e
6123acc
58d6fbe
62abfee
47f569e
dbd9945
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -41,6 +41,8 @@ import { | |
ServerRequest, | ||
ServerNotification, | ||
ToolAnnotations, | ||
CallToolResultUnstructured, | ||
CallToolResultStructured, | ||
} from "../types.js"; | ||
import { Completable, CompletableDef } from "./completable.js"; | ||
import { UriTemplate, Variables } from "../shared/uriTemplate.js"; | ||
|
@@ -920,7 +922,7 @@ export class McpServer { | |
/** | ||
* Registers a tool with a config object and callback. | ||
*/ | ||
registerTool<InputArgs extends ZodRawShape, OutputArgs extends ZodRawShape>( | ||
registerTool<InputArgs extends ZodRawShape, OutputArgs extends ZodRawShape | undefined>( | ||
name: string, | ||
config: { | ||
title?: string; | ||
|
@@ -929,7 +931,7 @@ export class McpServer { | |
outputSchema?: OutputArgs; | ||
annotations?: ToolAnnotations; | ||
}, | ||
cb: ToolCallback<InputArgs> | ||
cb: ToolCallback<InputArgs, OutputArgs> | ||
): RegisteredTool { | ||
if (this._registeredTools[name]) { | ||
throw new Error(`Tool ${name} is already registered`); | ||
|
@@ -1148,13 +1150,21 @@ export class ResourceTemplate { | |
* - `content` if the tool does not have an outputSchema | ||
|
||
* - Both fields are optional but typically one should be provided | ||
*/ | ||
export type ToolCallback<Args extends undefined | ZodRawShape = undefined> = | ||
Args extends ZodRawShape | ||
export type ToolCallback<InputArgs extends undefined | ZodRawShape = undefined, OutputArgs extends undefined | ZodRawShape = undefined> = | ||
InputArgs extends ZodRawShape | ||
? ( | ||
args: z.objectOutputType<Args, ZodTypeAny>, | ||
args: z.objectOutputType<InputArgs, ZodTypeAny>, | ||
extra: RequestHandlerExtra<ServerRequest, ServerNotification>, | ||
) => CallToolResult | Promise<CallToolResult> | ||
: (extra: RequestHandlerExtra<ServerRequest, ServerNotification>) => CallToolResult | Promise<CallToolResult>; | ||
) => OutputArgs extends ZodRawShape | ||
|
||
? CallToolResultStructured<OutputArgs> | Promise<CallToolResultStructured<OutputArgs>> | ||
: OutputArgs extends undefined | ||
? CallToolResultUnstructured | Promise<CallToolResultUnstructured> | ||
: never | ||
: (extra: RequestHandlerExtra<ServerRequest, ServerNotification>) => OutputArgs extends ZodRawShape | ||
? CallToolResultStructured<OutputArgs> | Promise<CallToolResultStructured<OutputArgs>> | ||
: OutputArgs extends undefined | ||
? CallToolResultUnstructured | Promise<CallToolResultUnstructured> | ||
: never; | ||
|
||
export type RegisteredTool = { | ||
title?: string; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
import { z, ZodTypeAny } from "zod"; | ||
import { z, ZodRawShape, ZodTypeAny } from "zod"; | ||
import { AuthInfo } from "./server/auth/types.js"; | ||
|
||
export const LATEST_PROTOCOL_VERSION = "2025-06-18"; | ||
|
@@ -951,25 +951,14 @@ export const ListToolsResultSchema = PaginatedResultSchema.extend({ | |
tools: z.array(ToolSchema), | ||
}); | ||
|
||
/** | ||
* The server's response to a tool call. | ||
*/ | ||
export const CallToolResultSchema = ResultSchema.extend({ | ||
export const CallToolResultUnstructuredSchema = ResultSchema.extend({ | ||
/** | ||
* A list of content objects that represent the result of the tool call. | ||
* | ||
* If the Tool does not define an outputSchema, this field MUST be present in the result. | ||
* For backwards compatibility, this field is always present, but it may be empty. | ||
*/ | ||
content: z.array(ContentBlockSchema).default([]), | ||
|
||
/** | ||
* An object containing structured tool output. | ||
* | ||
* If the Tool defines an outputSchema, this field MUST be present in the result, and contain a JSON object that matches the schema. | ||
*/ | ||
structuredContent: z.object({}).passthrough().optional(), | ||
|
||
/** | ||
* Whether the tool call ended in an error. | ||
* | ||
|
@@ -987,6 +976,17 @@ export const CallToolResultSchema = ResultSchema.extend({ | |
isError: z.optional(z.boolean()), | ||
}); | ||
|
||
export const CallToolResultStructuredSchema = CallToolResultUnstructuredSchema.extend({ | ||
/** | ||
* An object containing structured tool output. | ||
* | ||
* If the Tool defines an outputSchema, this field MUST be present in the result, and contain a JSON object that matches the schema. | ||
*/ | ||
structuredContent: z.object({}).passthrough().optional(), | ||
}); | ||
|
||
export const CallToolResultSchema = z.union([CallToolResultUnstructuredSchema, CallToolResultStructuredSchema]); | ||
|
||
/** | ||
* CallToolResultSchema extended with backwards compatibility to protocol version 2024-10-07. | ||
*/ | ||
|
@@ -1595,6 +1595,10 @@ export type Tool = Infer<typeof ToolSchema>; | |
export type ListToolsRequest = Infer<typeof ListToolsRequestSchema>; | ||
export type ListToolsResult = Infer<typeof ListToolsResultSchema>; | ||
export type CallToolResult = Infer<typeof CallToolResultSchema>; | ||
export type CallToolResultUnstructured = Infer<typeof CallToolResultUnstructuredSchema>; | ||
export type CallToolResultStructured<OArgs extends ZodRawShape> = Infer<typeof CallToolResultStructuredSchema> & { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you keep the unabbreviated name OutputArgs used elsewhere for consistency? (although arguably these should be InputType, OutputType, the args concept is redundant w/ input and at odds w/ outputs) |
||
structuredContent: z.infer<z.ZodObject<OArgs, 'strip'>>; | ||
|
||
} | ||
export type CompatibilityCallToolResult = Infer<typeof CompatibilityCallToolResultSchema>; | ||
export type CallToolRequest = Infer<typeof CallToolRequestSchema>; | ||
export type ToolListChangedNotification = Infer<typeof ToolListChangedNotificationSchema>; | ||
|
Uh oh!
There was an error while loading. Please reload this page.