diff --git a/src/client/index.ts b/src/client/index.ts index a18b45d08..5649866ac 100644 --- a/src/client/index.ts +++ b/src/client/index.ts @@ -29,6 +29,8 @@ import { ListToolsResultSchema, EmptyResultSchema, LoggingLevel, + ListResourceTemplatesRequest, + ListResourceTemplatesResultSchema, } from "../types.js"; /** @@ -177,6 +179,17 @@ export class Client< ); } + async listResourceTemplates( + params?: ListResourceTemplatesRequest["params"], + onprogress?: ProgressCallback, + ) { + return this.request( + { method: "resources/templates/list", params }, + ListResourceTemplatesResultSchema, + onprogress, + ); + } + async readResource( params: ReadResourceRequest["params"], onprogress?: ProgressCallback, @@ -223,4 +236,8 @@ export class Client< onprogress, ); } + + async sendRootsListChanged() { + return this.notification({ method: "notifications/roots/list_changed" }); + } } diff --git a/src/server/index.ts b/src/server/index.ts index c6350fffe..dc5466251 100644 --- a/src/server/index.ts +++ b/src/server/index.ts @@ -23,6 +23,8 @@ import { EmptyResultSchema, LoggingMessageNotification, ResourceUpdatedNotification, + ListRootsRequest, + ListRootsResultSchema, } from "../types.js"; /** @@ -154,6 +156,17 @@ export class Server< ); } + async listRoots( + params?: ListRootsRequest["params"], + onprogress?: ProgressCallback, + ) { + return this.request( + { method: "roots/list", params }, + ListRootsResultSchema, + onprogress, + ); + } + async sendLoggingMessage(params: LoggingMessageNotification["params"]) { return this.notification({ method: "notifications/message", params }); } diff --git a/src/types.ts b/src/types.ts index 8fd478631..b22e8fb29 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,6 +1,6 @@ import { z } from "zod"; -export const PROTOCOL_VERSION = "2024-10-07"; +export const PROTOCOL_VERSION = "2024-11-05"; /* JSON-RPC types */ export const JSONRPC_VERSION = "2.0"; @@ -148,46 +148,6 @@ export const JSONRPCMessageSchema = z.union([ export const EmptyResultSchema = ResultSchema.strict(); /* Initialization */ -/** - * Text provided to or from an LLM. - */ -export const TextContentSchema = z - .object({ - type: z.literal("text"), - /** - * The text content of the message. - */ - text: z.string(), - }) - .passthrough(); - -/** - * An image provided to or from an LLM. - */ -export const ImageContentSchema = z - .object({ - type: z.literal("image"), - /** - * The base64-encoded image data. - */ - data: z.string().base64(), - /** - * The MIME type of the image. Different providers may support different image types. - */ - mimeType: z.string(), - }) - .passthrough(); - -/** - * Describes a message issued to or received from an LLM API. - */ -export const SamplingMessageSchema = z - .object({ - role: z.enum(["user", "assistant"]), - content: z.union([TextContentSchema, ImageContentSchema]), - }) - .passthrough(); - /** * Describes the name and version of an MCP implementation. */ @@ -211,6 +171,19 @@ export const ClientCapabilitiesSchema = z * Present if the client supports sampling from an LLM. */ sampling: z.optional(z.object({}).passthrough()), + /** + * Present if the client supports listing roots. + */ + roots: z.optional( + z + .object({ + /** + * Whether the client supports notifications for changes to the roots list. + */ + listChanged: z.optional(z.boolean()), + }) + .passthrough(), + ), }) .passthrough(); @@ -626,6 +599,60 @@ export const GetPromptRequestSchema = RequestSchema.extend({ }), }); +/** + * Text provided to or from an LLM. + */ +export const TextContentSchema = z + .object({ + type: z.literal("text"), + /** + * The text content of the message. + */ + text: z.string(), + }) + .passthrough(); + +/** + * An image provided to or from an LLM. + */ +export const ImageContentSchema = z + .object({ + type: z.literal("image"), + /** + * The base64-encoded image data. + */ + data: z.string().base64(), + /** + * The MIME type of the image. Different providers may support different image types. + */ + mimeType: z.string(), + }) + .passthrough(); + +/** + * The contents of a resource, embedded into a prompt or tool call result. + */ +export const EmbeddedResourceSchema = z + .object({ + type: z.literal("resource"), + resource: z.union([TextResourceContentsSchema, BlobResourceContentsSchema]), + }) + .passthrough(); + +/** + * Describes a message returned as part of a prompt. + */ +export const PromptMessageSchema = z + .object({ + role: z.enum(["user", "assistant"]), + content: z.union([ + TextContentSchema, + ImageContentSchema, + EmbeddedResourceSchema, + ]), + }) + .passthrough(); + /** * The server's response to a prompts/get request from the client. */ @@ -634,7 +661,7 @@ export const GetPromptResultSchema = ResultSchema.extend({ * An optional description for the prompt. */ description: z.optional(z.string()), - messages: z.array(SamplingMessageSchema), + messages: z.array(PromptMessageSchema), }); /** @@ -688,7 +715,10 @@ export const ListToolsResultSchema = PaginatedResultSchema.extend({ * The server's response to a tool call. */ export const CallToolResultSchema = ResultSchema.extend({ - toolResult: z.unknown(), + content: z.array( + z.union([TextContentSchema, ImageContentSchema, EmbeddedResourceSchema]), + ), + isError: z.boolean(), }); /** @@ -713,7 +743,16 @@ export const ToolListChangedNotificationSchema = NotificationSchema.extend({ /** * The severity of a log message. */ -export const LoggingLevelSchema = z.enum(["debug", "info", "warning", "error"]); +export const LoggingLevelSchema = z.enum([ + "debug", + "info", + "notice", + "warning", + "error", + "critical", + "alert", + "emergency", +]); /** * A request from the client to the server, to enable or adjust logging. @@ -752,6 +791,50 @@ export const LoggingMessageNotificationSchema = NotificationSchema.extend({ }); /* Sampling */ +/** + * Hints to use for model selection. + */ +export const ModelHintSchema = z.object({ + /** + * A hint for a model name. + */ + name: z.string().optional(), +}).passthrough(); + +/** + * The server's preferences for model selection, requested of the client during sampling. + */ +export const ModelPreferencesSchema = z + .object({ + /** + * Optional hints to use for model selection. + */ + hints: z.optional(z.array(ModelHintSchema)), + /** + * How much to prioritize cost when selecting a model. + */ + costPriority: z.optional(z.number().min(0).max(1)), + /** + * How much to prioritize sampling speed (latency) when selecting a model. + */ + speedPriority: z.optional(z.number().min(0).max(1)), + /** + * How much to prioritize intelligence and capabilities when selecting a model. + */ + intelligencePriority: z.optional(z.number().min(0).max(1)), + }) + .passthrough(); + +/** + * Describes a message issued to or received from an LLM API. + */ +export const SamplingMessageSchema = z + .object({ + role: z.enum(["user", "assistant"]), + content: z.union([TextContentSchema, ImageContentSchema]), + }) + .passthrough(); + /** * A request from the server to sample an LLM via the client. The client has full discretion over which model to select. The client should also inform the user before beginning sampling, to allow them to inspect the request (human in the loop) and decide whether to approve it. */ @@ -777,6 +860,10 @@ export const CreateMessageRequestSchema = RequestSchema.extend({ * Optional metadata to pass through to the LLM provider. The format of this metadata is provider-specific. */ metadata: z.optional(z.object({}).passthrough()), + /** + * The server's preferences for which model to select. + */ + modelPreferences: z.optional(ModelPreferencesSchema), }), }); @@ -791,7 +878,7 @@ export const CreateMessageResultSchema = ResultSchema.extend({ /** * The reason why sampling stopped. */ - stopReason: z.enum(["endTurn", "stopSequence", "maxTokens"]), + stopReason: z.optional(z.enum(["endTurn", "stopSequence", "maxTokens"]).or(z.string())), role: z.enum(["user", "assistant"]), content: z.discriminatedUnion("type", [ TextContentSchema, @@ -873,6 +960,44 @@ export const CompleteResultSchema = ResultSchema.extend({ .passthrough(), }); +/* Roots */ +/** + * Represents a root directory or file that the server can operate on. + */ +export const RootSchema = z + .object({ + /** + * The URI identifying the root. This *must* start with file:// for now. + */ + uri: z.string().startsWith("file://"), + /** + * An optional name for the root. + */ + name: z.optional(z.string()), + }) + .passthrough(); + +/** + * Sent from the server to request a list of root URIs from the client. + */ +export const ListRootsRequestSchema = RequestSchema.extend({ + method: z.literal("roots/list"), +}); + +/** + * The client's response to a roots/list request from the server. + */ +export const ListRootsResultSchema = ResultSchema.extend({ + roots: z.array(RootSchema), +}); + +/** + * A notification from the client to the server, informing it that the list of roots has changed. + */ +export const RootsListChangedNotificationSchema = NotificationSchema.extend({ + method: z.literal("notifications/roots/list_changed"), +}); + /* Client messages */ export const ClientRequestSchema = z.union([ PingRequestSchema, @@ -882,6 +1007,7 @@ export const ClientRequestSchema = z.union([ GetPromptRequestSchema, ListPromptsRequestSchema, ListResourcesRequestSchema, + ListResourceTemplatesRequestSchema, ReadResourceRequestSchema, SubscribeRequestSchema, UnsubscribeRequestSchema, @@ -892,16 +1018,20 @@ export const ClientRequestSchema = z.union([ export const ClientNotificationSchema = z.union([ ProgressNotificationSchema, InitializedNotificationSchema, + RootsListChangedNotificationSchema, ]); + export const ClientResultSchema = z.union([ EmptyResultSchema, CreateMessageResultSchema, + ListRootsResultSchema, ]); /* Server messages */ export const ServerRequestSchema = z.union([ PingRequestSchema, CreateMessageRequestSchema, + ListRootsRequestSchema, ]); export const ServerNotificationSchema = z.union([ @@ -920,6 +1050,7 @@ export const ServerResultSchema = z.union([ GetPromptResultSchema, ListPromptsResultSchema, ListResourcesResultSchema, + ListResourceTemplatesResultSchema, ReadResourceResultSchema, CallToolResultSchema, ListToolsResultSchema, @@ -1038,6 +1169,14 @@ export type PromptReference = z.infer; export type CompleteRequest = z.infer; export type CompleteResult = z.infer; +/* Roots */ +export type Root = z.infer; +export type ListRootsRequest = z.infer; +export type ListRootsResult = z.infer; +export type RootsListChangedNotification = z.infer< + typeof RootsListChangedNotificationSchema +>; + /* Client messages */ export type ClientRequest = z.infer; export type ClientNotification = z.infer;