diff --git a/.github/workflows/shared.yml b/.github/workflows/shared.yml index 852ffc3850..efea5a7463 100644 --- a/.github/workflows/shared.yml +++ b/.github/workflows/shared.yml @@ -30,6 +30,11 @@ jobs: env: SKIP: no-commit-to-branch,readme-v1-frozen + - name: Surface types match vendored schema + run: | + uv sync --group codegen --frozen + uv run --group codegen python scripts/gen_surface_types.py --check + # TODO(Max): Drop this in v2. Deliberate updates (e.g. the v2 status # banner) go through the 'override-readme-freeze' label. - name: Check README.md is not modified diff --git a/docs/migration.md b/docs/migration.md index f6170d0e1e..36f7b29430 100644 --- a/docs/migration.md +++ b/docs/migration.md @@ -221,6 +221,10 @@ Common renames: Because `populate_by_name=True` is set, the old camelCase names still work as constructor kwargs (e.g., `Tool(inputSchema={...})` is accepted), but attribute access must use snake_case (`tool.input_schema`). +### Results now serialize `resultType` and cache-directive defaults + +Serialized results now include `resultType` by default (and `ttlMs`/`cacheScope` on cacheable results). Peers ignore unknown result fields, so this interoperates across protocol versions, but tests or recorded fixtures that compare exact serialized payloads need the new keys added. + ### `args` parameter removed from `ClientSessionGroup.call_tool()` The deprecated `args` parameter has been removed from `ClientSessionGroup.call_tool()`. Use `arguments` instead. @@ -1181,7 +1185,7 @@ Behavior changes: ### Experimental Tasks support removed -Tasks (SEP-1686) have been removed from the MCP specification and are no longer part of this SDK. The `mcp.client.experimental`, `mcp.server.experimental`, `mcp.shared.experimental`, and `mcp.server.lowlevel.experimental` modules have been removed, along with all `Task*` types, the `tasks` capability fields, `Tool.execution`, and the `experimental` properties on `ClientSession`, `ServerSession`, `Server`, and `ServerRequestContext`. +Tasks (SEP-1686) have been removed from the MCP specification and are no longer part of this SDK. The `mcp.client.experimental`, `mcp.server.experimental`, `mcp.shared.experimental`, and `mcp.server.lowlevel.experimental` modules have been removed, along with the `experimental` properties on `ClientSession`, `ServerSession`, `Server`, and `ServerRequestContext`. The corresponding `Task*` types remain in `mcp.types` as types-only definitions. Tasks are expected to return as a separate MCP extension in a future release. @@ -1227,6 +1231,10 @@ If you relied on extra fields round-tripping through MCP types, move that data i ## New Features +### 2025-11-25 and 2026-07-28 protocol fields modeled + +`mcp.types` models the 2025-11-25 and 2026-07-28 protocol fields (e.g. `resultType`, `ttlMs`/`cacheScope` on cacheable results, `inputResponses`/`requestState` on retried requests), so inbound payloads carrying these keys parse into typed fields and round-trip. Most are optional with `None` defaults; the result-directive fields carry serialized defaults - see [Results now serialize `resultType` and cache-directive defaults](#results-now-serialize-resulttype-and-cache-directive-defaults). + ### `streamable_http_app()` available on lowlevel Server The `streamable_http_app()` method is now available directly on the lowlevel `Server` class, not just `MCPServer`. This allows using the streamable HTTP transport without the MCPServer wrapper. diff --git a/pyproject.toml b/pyproject.toml index 749af47ab6..2ea5cf1a08 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -104,6 +104,7 @@ docs = [ "mkdocs-material[imaging]>=9.5.45", "mkdocstrings-python>=2.0.1", ] +codegen = ["datamodel-code-generator==0.57.0"] [build-system] requires = ["hatchling", "uv-dynamic-versioning"] diff --git a/schema/2025-11-25.json b/schema/2025-11-25.json new file mode 100644 index 0000000000..4956c09fef --- /dev/null +++ b/schema/2025-11-25.json @@ -0,0 +1,4057 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$defs": { + "Annotations": { + "description": "Optional annotations for the client. The client can use annotations to inform how objects are used or displayed", + "properties": { + "audience": { + "description": "Describes who the intended audience of this object or data is.\n\nIt can include multiple entries to indicate content useful for multiple audiences (e.g., `[\"user\", \"assistant\"]`).", + "items": { + "$ref": "#/$defs/Role" + }, + "type": "array" + }, + "lastModified": { + "description": "The moment the resource was last modified, as an ISO 8601 formatted string.\n\nShould be an ISO 8601 formatted string (e.g., \"2025-01-12T15:00:58Z\").\n\nExamples: last activity timestamp in an open file, timestamp when the resource\nwas attached, etc.", + "type": "string" + }, + "priority": { + "description": "Describes how important this data is for operating the server.\n\nA value of 1 means \"most important,\" and indicates that the data is\neffectively required, while 0 means \"least important,\" and indicates that\nthe data is entirely optional.", + "maximum": 1, + "minimum": 0, + "type": "number" + } + }, + "type": "object" + }, + "AudioContent": { + "description": "Audio provided to or from an LLM.", + "properties": { + "_meta": { + "additionalProperties": {}, + "description": "See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage.", + "type": "object" + }, + "annotations": { + "$ref": "#/$defs/Annotations", + "description": "Optional annotations for the client." + }, + "data": { + "description": "The base64-encoded audio data.", + "format": "byte", + "type": "string" + }, + "mimeType": { + "description": "The MIME type of the audio. Different providers may support different audio types.", + "type": "string" + }, + "type": { + "const": "audio", + "type": "string" + } + }, + "required": [ + "data", + "mimeType", + "type" + ], + "type": "object" + }, + "BaseMetadata": { + "description": "Base interface for metadata with name (identifier) and title (display name) properties.", + "properties": { + "name": { + "description": "Intended for programmatic or logical use, but used as a display name in past specs or fallback (if title isn't present).", + "type": "string" + }, + "title": { + "description": "Intended for UI and end-user contexts — optimized to be human-readable and easily understood,\neven by those unfamiliar with domain-specific terminology.\n\nIf not provided, the name should be used for display (except for Tool,\nwhere `annotations.title` should be given precedence over using `name`,\nif present).", + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "BlobResourceContents": { + "properties": { + "_meta": { + "additionalProperties": {}, + "description": "See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage.", + "type": "object" + }, + "blob": { + "description": "A base64-encoded string representing the binary data of the item.", + "format": "byte", + "type": "string" + }, + "mimeType": { + "description": "The MIME type of this resource, if known.", + "type": "string" + }, + "uri": { + "description": "The URI of this resource.", + "format": "uri", + "type": "string" + } + }, + "required": [ + "blob", + "uri" + ], + "type": "object" + }, + "BooleanSchema": { + "properties": { + "default": { + "type": "boolean" + }, + "description": { + "type": "string" + }, + "title": { + "type": "string" + }, + "type": { + "const": "boolean", + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + }, + "CallToolRequest": { + "description": "Used by the client to invoke a tool provided by the server.", + "properties": { + "id": { + "$ref": "#/$defs/RequestId" + }, + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "method": { + "const": "tools/call", + "type": "string" + }, + "params": { + "$ref": "#/$defs/CallToolRequestParams" + } + }, + "required": [ + "id", + "jsonrpc", + "method", + "params" + ], + "type": "object" + }, + "CallToolRequestParams": { + "description": "Parameters for a `tools/call` request.", + "properties": { + "_meta": { + "additionalProperties": {}, + "description": "See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage.", + "properties": { + "progressToken": { + "$ref": "#/$defs/ProgressToken", + "description": "If specified, the caller is requesting out-of-band progress notifications for this request (as represented by notifications/progress). The value of this parameter is an opaque token that will be attached to any subsequent notifications. The receiver is not obligated to provide these notifications." + } + }, + "type": "object" + }, + "arguments": { + "additionalProperties": {}, + "description": "Arguments to use for the tool call.", + "type": "object" + }, + "name": { + "description": "The name of the tool.", + "type": "string" + }, + "task": { + "$ref": "#/$defs/TaskMetadata", + "description": "If specified, the caller is requesting task-augmented execution for this request.\nThe request will return a CreateTaskResult immediately, and the actual result can be\nretrieved later via tasks/result.\n\nTask augmentation is subject to capability negotiation - receivers MUST declare support\nfor task augmentation of specific request types in their capabilities." + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "CallToolResult": { + "description": "The server's response to a tool call.", + "properties": { + "_meta": { + "additionalProperties": {}, + "description": "See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage.", + "type": "object" + }, + "content": { + "description": "A list of content objects that represent the unstructured result of the tool call.", + "items": { + "$ref": "#/$defs/ContentBlock" + }, + "type": "array" + }, + "isError": { + "description": "Whether the tool call ended in an error.\n\nIf not set, this is assumed to be false (the call was successful).\n\nAny errors that originate from the tool SHOULD be reported inside the result\nobject, with `isError` set to true, _not_ as an MCP protocol-level error\nresponse. Otherwise, the LLM would not be able to see that an error occurred\nand self-correct.\n\nHowever, any errors in _finding_ the tool, an error indicating that the\nserver does not support tool calls, or any other exceptional conditions,\nshould be reported as an MCP error response.", + "type": "boolean" + }, + "structuredContent": { + "additionalProperties": {}, + "description": "An optional JSON object that represents the structured result of the tool call.", + "type": "object" + } + }, + "required": [ + "content" + ], + "type": "object" + }, + "CancelTaskRequest": { + "description": "A request to cancel a task.", + "properties": { + "id": { + "$ref": "#/$defs/RequestId" + }, + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "method": { + "const": "tasks/cancel", + "type": "string" + }, + "params": { + "properties": { + "taskId": { + "description": "The task identifier to cancel.", + "type": "string" + } + }, + "required": [ + "taskId" + ], + "type": "object" + } + }, + "required": [ + "id", + "jsonrpc", + "method", + "params" + ], + "type": "object" + }, + "CancelTaskResult": { + "allOf": [ + { + "$ref": "#/$defs/Result" + }, + { + "$ref": "#/$defs/Task" + } + ], + "description": "The response to a tasks/cancel request." + }, + "CancelledNotification": { + "description": "This notification can be sent by either side to indicate that it is cancelling a previously-issued request.\n\nThe request SHOULD still be in-flight, but due to communication latency, it is always possible that this notification MAY arrive after the request has already finished.\n\nThis notification indicates that the result will be unused, so any associated processing SHOULD cease.\n\nA client MUST NOT attempt to cancel its `initialize` request.\n\nFor task cancellation, use the `tasks/cancel` request instead of this notification.", + "properties": { + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "method": { + "const": "notifications/cancelled", + "type": "string" + }, + "params": { + "$ref": "#/$defs/CancelledNotificationParams" + } + }, + "required": [ + "jsonrpc", + "method", + "params" + ], + "type": "object" + }, + "CancelledNotificationParams": { + "description": "Parameters for a `notifications/cancelled` notification.", + "properties": { + "_meta": { + "additionalProperties": {}, + "description": "See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage.", + "type": "object" + }, + "reason": { + "description": "An optional string describing the reason for the cancellation. This MAY be logged or presented to the user.", + "type": "string" + }, + "requestId": { + "$ref": "#/$defs/RequestId", + "description": "The ID of the request to cancel.\n\nThis MUST correspond to the ID of a request previously issued in the same direction.\nThis MUST be provided for cancelling non-task requests.\nThis MUST NOT be used for cancelling tasks (use the `tasks/cancel` request instead)." + } + }, + "type": "object" + }, + "ClientCapabilities": { + "description": "Capabilities a client may support. Known capabilities are defined here, in this schema, but this is not a closed set: any client can define its own, additional capabilities.", + "properties": { + "elicitation": { + "description": "Present if the client supports elicitation from the server.", + "properties": { + "form": { + "additionalProperties": true, + "properties": {}, + "type": "object" + }, + "url": { + "additionalProperties": true, + "properties": {}, + "type": "object" + } + }, + "type": "object" + }, + "experimental": { + "additionalProperties": { + "additionalProperties": true, + "properties": {}, + "type": "object" + }, + "description": "Experimental, non-standard capabilities that the client supports.", + "type": "object" + }, + "roots": { + "description": "Present if the client supports listing roots.", + "properties": { + "listChanged": { + "description": "Whether the client supports notifications for changes to the roots list.", + "type": "boolean" + } + }, + "type": "object" + }, + "sampling": { + "description": "Present if the client supports sampling from an LLM.", + "properties": { + "context": { + "additionalProperties": true, + "description": "Whether the client supports context inclusion via includeContext parameter.\nIf not declared, servers SHOULD only use `includeContext: \"none\"` (or omit it).", + "properties": {}, + "type": "object" + }, + "tools": { + "additionalProperties": true, + "description": "Whether the client supports tool use via tools and toolChoice parameters.", + "properties": {}, + "type": "object" + } + }, + "type": "object" + }, + "tasks": { + "description": "Present if the client supports task-augmented requests.", + "properties": { + "cancel": { + "additionalProperties": true, + "description": "Whether this client supports tasks/cancel.", + "properties": {}, + "type": "object" + }, + "list": { + "additionalProperties": true, + "description": "Whether this client supports tasks/list.", + "properties": {}, + "type": "object" + }, + "requests": { + "description": "Specifies which request types can be augmented with tasks.", + "properties": { + "elicitation": { + "description": "Task support for elicitation-related requests.", + "properties": { + "create": { + "additionalProperties": true, + "description": "Whether the client supports task-augmented elicitation/create requests.", + "properties": {}, + "type": "object" + } + }, + "type": "object" + }, + "sampling": { + "description": "Task support for sampling-related requests.", + "properties": { + "createMessage": { + "additionalProperties": true, + "description": "Whether the client supports task-augmented sampling/createMessage requests.", + "properties": {}, + "type": "object" + } + }, + "type": "object" + } + }, + "type": "object" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "ClientNotification": { + "anyOf": [ + { + "$ref": "#/$defs/CancelledNotification" + }, + { + "$ref": "#/$defs/InitializedNotification" + }, + { + "$ref": "#/$defs/ProgressNotification" + }, + { + "$ref": "#/$defs/TaskStatusNotification" + }, + { + "$ref": "#/$defs/RootsListChangedNotification" + } + ] + }, + "ClientRequest": { + "anyOf": [ + { + "$ref": "#/$defs/InitializeRequest" + }, + { + "$ref": "#/$defs/PingRequest" + }, + { + "$ref": "#/$defs/ListResourcesRequest" + }, + { + "$ref": "#/$defs/ListResourceTemplatesRequest" + }, + { + "$ref": "#/$defs/ReadResourceRequest" + }, + { + "$ref": "#/$defs/SubscribeRequest" + }, + { + "$ref": "#/$defs/UnsubscribeRequest" + }, + { + "$ref": "#/$defs/ListPromptsRequest" + }, + { + "$ref": "#/$defs/GetPromptRequest" + }, + { + "$ref": "#/$defs/ListToolsRequest" + }, + { + "$ref": "#/$defs/CallToolRequest" + }, + { + "$ref": "#/$defs/GetTaskRequest" + }, + { + "$ref": "#/$defs/GetTaskPayloadRequest" + }, + { + "$ref": "#/$defs/CancelTaskRequest" + }, + { + "$ref": "#/$defs/ListTasksRequest" + }, + { + "$ref": "#/$defs/SetLevelRequest" + }, + { + "$ref": "#/$defs/CompleteRequest" + } + ] + }, + "ClientResult": { + "anyOf": [ + { + "$ref": "#/$defs/Result" + }, + { + "$ref": "#/$defs/GetTaskResult", + "description": "The response to a tasks/get request." + }, + { + "$ref": "#/$defs/GetTaskPayloadResult" + }, + { + "$ref": "#/$defs/CancelTaskResult", + "description": "The response to a tasks/cancel request." + }, + { + "$ref": "#/$defs/ListTasksResult" + }, + { + "$ref": "#/$defs/CreateMessageResult" + }, + { + "$ref": "#/$defs/ListRootsResult" + }, + { + "$ref": "#/$defs/ElicitResult" + } + ] + }, + "CompleteRequest": { + "description": "A request from the client to the server, to ask for completion options.", + "properties": { + "id": { + "$ref": "#/$defs/RequestId" + }, + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "method": { + "const": "completion/complete", + "type": "string" + }, + "params": { + "$ref": "#/$defs/CompleteRequestParams" + } + }, + "required": [ + "id", + "jsonrpc", + "method", + "params" + ], + "type": "object" + }, + "CompleteRequestParams": { + "description": "Parameters for a `completion/complete` request.", + "properties": { + "_meta": { + "additionalProperties": {}, + "description": "See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage.", + "properties": { + "progressToken": { + "$ref": "#/$defs/ProgressToken", + "description": "If specified, the caller is requesting out-of-band progress notifications for this request (as represented by notifications/progress). The value of this parameter is an opaque token that will be attached to any subsequent notifications. The receiver is not obligated to provide these notifications." + } + }, + "type": "object" + }, + "argument": { + "description": "The argument's information", + "properties": { + "name": { + "description": "The name of the argument", + "type": "string" + }, + "value": { + "description": "The value of the argument to use for completion matching.", + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "context": { + "description": "Additional, optional context for completions", + "properties": { + "arguments": { + "additionalProperties": { + "type": "string" + }, + "description": "Previously-resolved variables in a URI template or prompt.", + "type": "object" + } + }, + "type": "object" + }, + "ref": { + "anyOf": [ + { + "$ref": "#/$defs/PromptReference" + }, + { + "$ref": "#/$defs/ResourceTemplateReference" + } + ] + } + }, + "required": [ + "argument", + "ref" + ], + "type": "object" + }, + "CompleteResult": { + "description": "The server's response to a completion/complete request", + "properties": { + "_meta": { + "additionalProperties": {}, + "description": "See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage.", + "type": "object" + }, + "completion": { + "properties": { + "hasMore": { + "description": "Indicates whether there are additional completion options beyond those provided in the current response, even if the exact total is unknown.", + "type": "boolean" + }, + "total": { + "description": "The total number of completion options available. This can exceed the number of values actually sent in the response.", + "type": "integer" + }, + "values": { + "description": "An array of completion values. Must not exceed 100 items.", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "values" + ], + "type": "object" + } + }, + "required": [ + "completion" + ], + "type": "object" + }, + "ContentBlock": { + "anyOf": [ + { + "$ref": "#/$defs/TextContent" + }, + { + "$ref": "#/$defs/ImageContent" + }, + { + "$ref": "#/$defs/AudioContent" + }, + { + "$ref": "#/$defs/ResourceLink" + }, + { + "$ref": "#/$defs/EmbeddedResource" + } + ] + }, + "CreateMessageRequest": { + "description": "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.", + "properties": { + "id": { + "$ref": "#/$defs/RequestId" + }, + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "method": { + "const": "sampling/createMessage", + "type": "string" + }, + "params": { + "$ref": "#/$defs/CreateMessageRequestParams" + } + }, + "required": [ + "id", + "jsonrpc", + "method", + "params" + ], + "type": "object" + }, + "CreateMessageRequestParams": { + "description": "Parameters for a `sampling/createMessage` request.", + "properties": { + "_meta": { + "additionalProperties": {}, + "description": "See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage.", + "properties": { + "progressToken": { + "$ref": "#/$defs/ProgressToken", + "description": "If specified, the caller is requesting out-of-band progress notifications for this request (as represented by notifications/progress). The value of this parameter is an opaque token that will be attached to any subsequent notifications. The receiver is not obligated to provide these notifications." + } + }, + "type": "object" + }, + "includeContext": { + "description": "A request to include context from one or more MCP servers (including the caller), to be attached to the prompt.\nThe client MAY ignore this request.\n\nDefault is \"none\". Values \"thisServer\" and \"allServers\" are soft-deprecated. Servers SHOULD only use these values if the client\ndeclares ClientCapabilities.sampling.context. These values may be removed in future spec releases.", + "enum": [ + "allServers", + "none", + "thisServer" + ], + "type": "string" + }, + "maxTokens": { + "description": "The requested maximum number of tokens to sample (to prevent runaway completions).\n\nThe client MAY choose to sample fewer tokens than the requested maximum.", + "type": "integer" + }, + "messages": { + "items": { + "$ref": "#/$defs/SamplingMessage" + }, + "type": "array" + }, + "metadata": { + "additionalProperties": true, + "description": "Optional metadata to pass through to the LLM provider. The format of this metadata is provider-specific.", + "properties": {}, + "type": "object" + }, + "modelPreferences": { + "$ref": "#/$defs/ModelPreferences", + "description": "The server's preferences for which model to select. The client MAY ignore these preferences." + }, + "stopSequences": { + "items": { + "type": "string" + }, + "type": "array" + }, + "systemPrompt": { + "description": "An optional system prompt the server wants to use for sampling. The client MAY modify or omit this prompt.", + "type": "string" + }, + "task": { + "$ref": "#/$defs/TaskMetadata", + "description": "If specified, the caller is requesting task-augmented execution for this request.\nThe request will return a CreateTaskResult immediately, and the actual result can be\nretrieved later via tasks/result.\n\nTask augmentation is subject to capability negotiation - receivers MUST declare support\nfor task augmentation of specific request types in their capabilities." + }, + "temperature": { + "type": "number" + }, + "toolChoice": { + "$ref": "#/$defs/ToolChoice", + "description": "Controls how the model uses tools.\nThe client MUST return an error if this field is provided but ClientCapabilities.sampling.tools is not declared.\nDefault is `{ mode: \"auto\" }`." + }, + "tools": { + "description": "Tools that the model may use during generation.\nThe client MUST return an error if this field is provided but ClientCapabilities.sampling.tools is not declared.", + "items": { + "$ref": "#/$defs/Tool" + }, + "type": "array" + } + }, + "required": [ + "maxTokens", + "messages" + ], + "type": "object" + }, + "CreateMessageResult": { + "description": "The client's response to a sampling/createMessage request from the server.\nThe client should inform the user before returning the sampled message, to allow them\nto inspect the response (human in the loop) and decide whether to allow the server to see it.", + "properties": { + "_meta": { + "additionalProperties": {}, + "description": "See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage.", + "type": "object" + }, + "content": { + "anyOf": [ + { + "$ref": "#/$defs/TextContent" + }, + { + "$ref": "#/$defs/ImageContent" + }, + { + "$ref": "#/$defs/AudioContent" + }, + { + "$ref": "#/$defs/ToolUseContent" + }, + { + "$ref": "#/$defs/ToolResultContent" + }, + { + "items": { + "$ref": "#/$defs/SamplingMessageContentBlock" + }, + "type": "array" + } + ] + }, + "model": { + "description": "The name of the model that generated the message.", + "type": "string" + }, + "role": { + "$ref": "#/$defs/Role" + }, + "stopReason": { + "description": "The reason why sampling stopped, if known.\n\nStandard values:\n- \"endTurn\": Natural end of the assistant's turn\n- \"stopSequence\": A stop sequence was encountered\n- \"maxTokens\": Maximum token limit was reached\n- \"toolUse\": The model wants to use one or more tools\n\nThis field is an open string to allow for provider-specific stop reasons.", + "type": "string" + } + }, + "required": [ + "content", + "model", + "role" + ], + "type": "object" + }, + "CreateTaskResult": { + "description": "A response to a task-augmented request.", + "properties": { + "_meta": { + "additionalProperties": {}, + "description": "See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage.", + "type": "object" + }, + "task": { + "$ref": "#/$defs/Task" + } + }, + "required": [ + "task" + ], + "type": "object" + }, + "Cursor": { + "description": "An opaque token used to represent a cursor for pagination.", + "type": "string" + }, + "ElicitRequest": { + "description": "A request from the server to elicit additional information from the user via the client.", + "properties": { + "id": { + "$ref": "#/$defs/RequestId" + }, + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "method": { + "const": "elicitation/create", + "type": "string" + }, + "params": { + "$ref": "#/$defs/ElicitRequestParams" + } + }, + "required": [ + "id", + "jsonrpc", + "method", + "params" + ], + "type": "object" + }, + "ElicitRequestFormParams": { + "description": "The parameters for a request to elicit non-sensitive information from the user via a form in the client.", + "properties": { + "_meta": { + "additionalProperties": {}, + "description": "See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage.", + "properties": { + "progressToken": { + "$ref": "#/$defs/ProgressToken", + "description": "If specified, the caller is requesting out-of-band progress notifications for this request (as represented by notifications/progress). The value of this parameter is an opaque token that will be attached to any subsequent notifications. The receiver is not obligated to provide these notifications." + } + }, + "type": "object" + }, + "message": { + "description": "The message to present to the user describing what information is being requested.", + "type": "string" + }, + "mode": { + "const": "form", + "description": "The elicitation mode.", + "type": "string" + }, + "requestedSchema": { + "description": "A restricted subset of JSON Schema.\nOnly top-level properties are allowed, without nesting.", + "properties": { + "$schema": { + "type": "string" + }, + "properties": { + "additionalProperties": { + "$ref": "#/$defs/PrimitiveSchemaDefinition" + }, + "type": "object" + }, + "required": { + "items": { + "type": "string" + }, + "type": "array" + }, + "type": { + "const": "object", + "type": "string" + } + }, + "required": [ + "properties", + "type" + ], + "type": "object" + }, + "task": { + "$ref": "#/$defs/TaskMetadata", + "description": "If specified, the caller is requesting task-augmented execution for this request.\nThe request will return a CreateTaskResult immediately, and the actual result can be\nretrieved later via tasks/result.\n\nTask augmentation is subject to capability negotiation - receivers MUST declare support\nfor task augmentation of specific request types in their capabilities." + } + }, + "required": [ + "message", + "requestedSchema" + ], + "type": "object" + }, + "ElicitRequestParams": { + "anyOf": [ + { + "$ref": "#/$defs/ElicitRequestURLParams" + }, + { + "$ref": "#/$defs/ElicitRequestFormParams" + } + ], + "description": "The parameters for a request to elicit additional information from the user via the client." + }, + "ElicitRequestURLParams": { + "description": "The parameters for a request to elicit information from the user via a URL in the client.", + "properties": { + "_meta": { + "additionalProperties": {}, + "description": "See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage.", + "properties": { + "progressToken": { + "$ref": "#/$defs/ProgressToken", + "description": "If specified, the caller is requesting out-of-band progress notifications for this request (as represented by notifications/progress). The value of this parameter is an opaque token that will be attached to any subsequent notifications. The receiver is not obligated to provide these notifications." + } + }, + "type": "object" + }, + "elicitationId": { + "description": "The ID of the elicitation, which must be unique within the context of the server.\nThe client MUST treat this ID as an opaque value.", + "type": "string" + }, + "message": { + "description": "The message to present to the user explaining why the interaction is needed.", + "type": "string" + }, + "mode": { + "const": "url", + "description": "The elicitation mode.", + "type": "string" + }, + "task": { + "$ref": "#/$defs/TaskMetadata", + "description": "If specified, the caller is requesting task-augmented execution for this request.\nThe request will return a CreateTaskResult immediately, and the actual result can be\nretrieved later via tasks/result.\n\nTask augmentation is subject to capability negotiation - receivers MUST declare support\nfor task augmentation of specific request types in their capabilities." + }, + "url": { + "description": "The URL that the user should navigate to.", + "format": "uri", + "type": "string" + } + }, + "required": [ + "elicitationId", + "message", + "mode", + "url" + ], + "type": "object" + }, + "ElicitResult": { + "description": "The client's response to an elicitation request.", + "properties": { + "_meta": { + "additionalProperties": {}, + "description": "See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage.", + "type": "object" + }, + "action": { + "description": "The user action in response to the elicitation.\n- \"accept\": User submitted the form/confirmed the action\n- \"decline\": User explicitly decline the action\n- \"cancel\": User dismissed without making an explicit choice", + "enum": [ + "accept", + "cancel", + "decline" + ], + "type": "string" + }, + "content": { + "additionalProperties": { + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": [ + "string", + "integer", + "boolean" + ] + } + ] + }, + "description": "The submitted form data, only present when action is \"accept\" and mode was \"form\".\nContains values matching the requested schema.\nOmitted for out-of-band mode responses.", + "type": "object" + } + }, + "required": [ + "action" + ], + "type": "object" + }, + "ElicitationCompleteNotification": { + "description": "An optional notification from the server to the client, informing it of a completion of a out-of-band elicitation request.", + "properties": { + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "method": { + "const": "notifications/elicitation/complete", + "type": "string" + }, + "params": { + "properties": { + "elicitationId": { + "description": "The ID of the elicitation that completed.", + "type": "string" + } + }, + "required": [ + "elicitationId" + ], + "type": "object" + } + }, + "required": [ + "jsonrpc", + "method", + "params" + ], + "type": "object" + }, + "EmbeddedResource": { + "description": "The contents of a resource, embedded into a prompt or tool call result.\n\nIt is up to the client how best to render embedded resources for the benefit\nof the LLM and/or the user.", + "properties": { + "_meta": { + "additionalProperties": {}, + "description": "See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage.", + "type": "object" + }, + "annotations": { + "$ref": "#/$defs/Annotations", + "description": "Optional annotations for the client." + }, + "resource": { + "anyOf": [ + { + "$ref": "#/$defs/TextResourceContents" + }, + { + "$ref": "#/$defs/BlobResourceContents" + } + ] + }, + "type": { + "const": "resource", + "type": "string" + } + }, + "required": [ + "resource", + "type" + ], + "type": "object" + }, + "EmptyResult": { + "$ref": "#/$defs/Result" + }, + "EnumSchema": { + "anyOf": [ + { + "$ref": "#/$defs/UntitledSingleSelectEnumSchema" + }, + { + "$ref": "#/$defs/TitledSingleSelectEnumSchema" + }, + { + "$ref": "#/$defs/UntitledMultiSelectEnumSchema" + }, + { + "$ref": "#/$defs/TitledMultiSelectEnumSchema" + }, + { + "$ref": "#/$defs/LegacyTitledEnumSchema" + } + ] + }, + "Error": { + "properties": { + "code": { + "description": "The error type that occurred.", + "type": "integer" + }, + "data": { + "description": "Additional information about the error. The value of this member is defined by the sender (e.g. detailed error information, nested errors etc.)." + }, + "message": { + "description": "A short description of the error. The message SHOULD be limited to a concise single sentence.", + "type": "string" + } + }, + "required": [ + "code", + "message" + ], + "type": "object" + }, + "GetPromptRequest": { + "description": "Used by the client to get a prompt provided by the server.", + "properties": { + "id": { + "$ref": "#/$defs/RequestId" + }, + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "method": { + "const": "prompts/get", + "type": "string" + }, + "params": { + "$ref": "#/$defs/GetPromptRequestParams" + } + }, + "required": [ + "id", + "jsonrpc", + "method", + "params" + ], + "type": "object" + }, + "GetPromptRequestParams": { + "description": "Parameters for a `prompts/get` request.", + "properties": { + "_meta": { + "additionalProperties": {}, + "description": "See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage.", + "properties": { + "progressToken": { + "$ref": "#/$defs/ProgressToken", + "description": "If specified, the caller is requesting out-of-band progress notifications for this request (as represented by notifications/progress). The value of this parameter is an opaque token that will be attached to any subsequent notifications. The receiver is not obligated to provide these notifications." + } + }, + "type": "object" + }, + "arguments": { + "additionalProperties": { + "type": "string" + }, + "description": "Arguments to use for templating the prompt.", + "type": "object" + }, + "name": { + "description": "The name of the prompt or prompt template.", + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "GetPromptResult": { + "description": "The server's response to a prompts/get request from the client.", + "properties": { + "_meta": { + "additionalProperties": {}, + "description": "See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage.", + "type": "object" + }, + "description": { + "description": "An optional description for the prompt.", + "type": "string" + }, + "messages": { + "items": { + "$ref": "#/$defs/PromptMessage" + }, + "type": "array" + } + }, + "required": [ + "messages" + ], + "type": "object" + }, + "GetTaskPayloadRequest": { + "description": "A request to retrieve the result of a completed task.", + "properties": { + "id": { + "$ref": "#/$defs/RequestId" + }, + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "method": { + "const": "tasks/result", + "type": "string" + }, + "params": { + "properties": { + "taskId": { + "description": "The task identifier to retrieve results for.", + "type": "string" + } + }, + "required": [ + "taskId" + ], + "type": "object" + } + }, + "required": [ + "id", + "jsonrpc", + "method", + "params" + ], + "type": "object" + }, + "GetTaskPayloadResult": { + "additionalProperties": {}, + "description": "The response to a tasks/result request.\nThe structure matches the result type of the original request.\nFor example, a tools/call task would return the CallToolResult structure.", + "properties": { + "_meta": { + "additionalProperties": {}, + "description": "See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage.", + "type": "object" + } + }, + "type": "object" + }, + "GetTaskRequest": { + "description": "A request to retrieve the state of a task.", + "properties": { + "id": { + "$ref": "#/$defs/RequestId" + }, + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "method": { + "const": "tasks/get", + "type": "string" + }, + "params": { + "properties": { + "taskId": { + "description": "The task identifier to query.", + "type": "string" + } + }, + "required": [ + "taskId" + ], + "type": "object" + } + }, + "required": [ + "id", + "jsonrpc", + "method", + "params" + ], + "type": "object" + }, + "GetTaskResult": { + "allOf": [ + { + "$ref": "#/$defs/Result" + }, + { + "$ref": "#/$defs/Task" + } + ], + "description": "The response to a tasks/get request." + }, + "Icon": { + "description": "An optionally-sized icon that can be displayed in a user interface.", + "properties": { + "mimeType": { + "description": "Optional MIME type override if the source MIME type is missing or generic.\nFor example: `\"image/png\"`, `\"image/jpeg\"`, or `\"image/svg+xml\"`.", + "type": "string" + }, + "sizes": { + "description": "Optional array of strings that specify sizes at which the icon can be used.\nEach string should be in WxH format (e.g., `\"48x48\"`, `\"96x96\"`) or `\"any\"` for scalable formats like SVG.\n\nIf not provided, the client should assume that the icon can be used at any size.", + "items": { + "type": "string" + }, + "type": "array" + }, + "src": { + "description": "A standard URI pointing to an icon resource. May be an HTTP/HTTPS URL or a\n`data:` URI with Base64-encoded image data.\n\nConsumers SHOULD takes steps to ensure URLs serving icons are from the\nsame domain as the client/server or a trusted domain.\n\nConsumers SHOULD take appropriate precautions when consuming SVGs as they can contain\nexecutable JavaScript.", + "format": "uri", + "type": "string" + }, + "theme": { + "description": "Optional specifier for the theme this icon is designed for. `light` indicates\nthe icon is designed to be used with a light background, and `dark` indicates\nthe icon is designed to be used with a dark background.\n\nIf not provided, the client should assume the icon can be used with any theme.", + "enum": [ + "dark", + "light" + ], + "type": "string" + } + }, + "required": [ + "src" + ], + "type": "object" + }, + "Icons": { + "description": "Base interface to add `icons` property.", + "properties": { + "icons": { + "description": "Optional set of sized icons that the client can display in a user interface.\n\nClients that support rendering icons MUST support at least the following MIME types:\n- `image/png` - PNG images (safe, universal compatibility)\n- `image/jpeg` (and `image/jpg`) - JPEG images (safe, universal compatibility)\n\nClients that support rendering icons SHOULD also support:\n- `image/svg+xml` - SVG images (scalable but requires security precautions)\n- `image/webp` - WebP images (modern, efficient format)", + "items": { + "$ref": "#/$defs/Icon" + }, + "type": "array" + } + }, + "type": "object" + }, + "ImageContent": { + "description": "An image provided to or from an LLM.", + "properties": { + "_meta": { + "additionalProperties": {}, + "description": "See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage.", + "type": "object" + }, + "annotations": { + "$ref": "#/$defs/Annotations", + "description": "Optional annotations for the client." + }, + "data": { + "description": "The base64-encoded image data.", + "format": "byte", + "type": "string" + }, + "mimeType": { + "description": "The MIME type of the image. Different providers may support different image types.", + "type": "string" + }, + "type": { + "const": "image", + "type": "string" + } + }, + "required": [ + "data", + "mimeType", + "type" + ], + "type": "object" + }, + "Implementation": { + "description": "Describes the MCP implementation.", + "properties": { + "description": { + "description": "An optional human-readable description of what this implementation does.\n\nThis can be used by clients or servers to provide context about their purpose\nand capabilities. For example, a server might describe the types of resources\nor tools it provides, while a client might describe its intended use case.", + "type": "string" + }, + "icons": { + "description": "Optional set of sized icons that the client can display in a user interface.\n\nClients that support rendering icons MUST support at least the following MIME types:\n- `image/png` - PNG images (safe, universal compatibility)\n- `image/jpeg` (and `image/jpg`) - JPEG images (safe, universal compatibility)\n\nClients that support rendering icons SHOULD also support:\n- `image/svg+xml` - SVG images (scalable but requires security precautions)\n- `image/webp` - WebP images (modern, efficient format)", + "items": { + "$ref": "#/$defs/Icon" + }, + "type": "array" + }, + "name": { + "description": "Intended for programmatic or logical use, but used as a display name in past specs or fallback (if title isn't present).", + "type": "string" + }, + "title": { + "description": "Intended for UI and end-user contexts — optimized to be human-readable and easily understood,\neven by those unfamiliar with domain-specific terminology.\n\nIf not provided, the name should be used for display (except for Tool,\nwhere `annotations.title` should be given precedence over using `name`,\nif present).", + "type": "string" + }, + "version": { + "type": "string" + }, + "websiteUrl": { + "description": "An optional URL of the website for this implementation.", + "format": "uri", + "type": "string" + } + }, + "required": [ + "name", + "version" + ], + "type": "object" + }, + "InitializeRequest": { + "description": "This request is sent from the client to the server when it first connects, asking it to begin initialization.", + "properties": { + "id": { + "$ref": "#/$defs/RequestId" + }, + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "method": { + "const": "initialize", + "type": "string" + }, + "params": { + "$ref": "#/$defs/InitializeRequestParams" + } + }, + "required": [ + "id", + "jsonrpc", + "method", + "params" + ], + "type": "object" + }, + "InitializeRequestParams": { + "description": "Parameters for an `initialize` request.", + "properties": { + "_meta": { + "additionalProperties": {}, + "description": "See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage.", + "properties": { + "progressToken": { + "$ref": "#/$defs/ProgressToken", + "description": "If specified, the caller is requesting out-of-band progress notifications for this request (as represented by notifications/progress). The value of this parameter is an opaque token that will be attached to any subsequent notifications. The receiver is not obligated to provide these notifications." + } + }, + "type": "object" + }, + "capabilities": { + "$ref": "#/$defs/ClientCapabilities" + }, + "clientInfo": { + "$ref": "#/$defs/Implementation" + }, + "protocolVersion": { + "description": "The latest version of the Model Context Protocol that the client supports. The client MAY decide to support older versions as well.", + "type": "string" + } + }, + "required": [ + "capabilities", + "clientInfo", + "protocolVersion" + ], + "type": "object" + }, + "InitializeResult": { + "description": "After receiving an initialize request from the client, the server sends this response.", + "properties": { + "_meta": { + "additionalProperties": {}, + "description": "See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage.", + "type": "object" + }, + "capabilities": { + "$ref": "#/$defs/ServerCapabilities" + }, + "instructions": { + "description": "Instructions describing how to use the server and its features.\n\nThis can be used by clients to improve the LLM's understanding of available tools, resources, etc. It can be thought of like a \"hint\" to the model. For example, this information MAY be added to the system prompt.", + "type": "string" + }, + "protocolVersion": { + "description": "The version of the Model Context Protocol that the server wants to use. This may not match the version that the client requested. If the client cannot support this version, it MUST disconnect.", + "type": "string" + }, + "serverInfo": { + "$ref": "#/$defs/Implementation" + } + }, + "required": [ + "capabilities", + "protocolVersion", + "serverInfo" + ], + "type": "object" + }, + "InitializedNotification": { + "description": "This notification is sent from the client to the server after initialization has finished.", + "properties": { + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "method": { + "const": "notifications/initialized", + "type": "string" + }, + "params": { + "$ref": "#/$defs/NotificationParams" + } + }, + "required": [ + "jsonrpc", + "method" + ], + "type": "object" + }, + "JSONRPCErrorResponse": { + "description": "A response to a request that indicates an error occurred.", + "properties": { + "error": { + "$ref": "#/$defs/Error" + }, + "id": { + "$ref": "#/$defs/RequestId" + }, + "jsonrpc": { + "const": "2.0", + "type": "string" + } + }, + "required": [ + "error", + "jsonrpc" + ], + "type": "object" + }, + "JSONRPCMessage": { + "anyOf": [ + { + "$ref": "#/$defs/JSONRPCRequest" + }, + { + "$ref": "#/$defs/JSONRPCNotification" + }, + { + "$ref": "#/$defs/JSONRPCResultResponse" + }, + { + "$ref": "#/$defs/JSONRPCErrorResponse" + } + ], + "description": "Refers to any valid JSON-RPC object that can be decoded off the wire, or encoded to be sent." + }, + "JSONRPCNotification": { + "description": "A notification which does not expect a response.", + "properties": { + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "method": { + "type": "string" + }, + "params": { + "additionalProperties": {}, + "type": "object" + } + }, + "required": [ + "jsonrpc", + "method" + ], + "type": "object" + }, + "JSONRPCRequest": { + "description": "A request that expects a response.", + "properties": { + "id": { + "$ref": "#/$defs/RequestId" + }, + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "method": { + "type": "string" + }, + "params": { + "additionalProperties": {}, + "type": "object" + } + }, + "required": [ + "id", + "jsonrpc", + "method" + ], + "type": "object" + }, + "JSONRPCResponse": { + "anyOf": [ + { + "$ref": "#/$defs/JSONRPCResultResponse" + }, + { + "$ref": "#/$defs/JSONRPCErrorResponse" + } + ], + "description": "A response to a request, containing either the result or error." + }, + "JSONRPCResultResponse": { + "description": "A successful (non-error) response to a request.", + "properties": { + "id": { + "$ref": "#/$defs/RequestId" + }, + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "result": { + "$ref": "#/$defs/Result" + } + }, + "required": [ + "id", + "jsonrpc", + "result" + ], + "type": "object" + }, + "LegacyTitledEnumSchema": { + "description": "Use TitledSingleSelectEnumSchema instead.\nThis interface will be removed in a future version.", + "properties": { + "default": { + "type": "string" + }, + "description": { + "type": "string" + }, + "enum": { + "items": { + "type": "string" + }, + "type": "array" + }, + "enumNames": { + "description": "(Legacy) Display names for enum values.\nNon-standard according to JSON schema 2020-12.", + "items": { + "type": "string" + }, + "type": "array" + }, + "title": { + "type": "string" + }, + "type": { + "const": "string", + "type": "string" + } + }, + "required": [ + "enum", + "type" + ], + "type": "object" + }, + "ListPromptsRequest": { + "description": "Sent from the client to request a list of prompts and prompt templates the server has.", + "properties": { + "id": { + "$ref": "#/$defs/RequestId" + }, + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "method": { + "const": "prompts/list", + "type": "string" + }, + "params": { + "$ref": "#/$defs/PaginatedRequestParams" + } + }, + "required": [ + "id", + "jsonrpc", + "method" + ], + "type": "object" + }, + "ListPromptsResult": { + "description": "The server's response to a prompts/list request from the client.", + "properties": { + "_meta": { + "additionalProperties": {}, + "description": "See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage.", + "type": "object" + }, + "nextCursor": { + "description": "An opaque token representing the pagination position after the last returned result.\nIf present, there may be more results available.", + "type": "string" + }, + "prompts": { + "items": { + "$ref": "#/$defs/Prompt" + }, + "type": "array" + } + }, + "required": [ + "prompts" + ], + "type": "object" + }, + "ListResourceTemplatesRequest": { + "description": "Sent from the client to request a list of resource templates the server has.", + "properties": { + "id": { + "$ref": "#/$defs/RequestId" + }, + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "method": { + "const": "resources/templates/list", + "type": "string" + }, + "params": { + "$ref": "#/$defs/PaginatedRequestParams" + } + }, + "required": [ + "id", + "jsonrpc", + "method" + ], + "type": "object" + }, + "ListResourceTemplatesResult": { + "description": "The server's response to a resources/templates/list request from the client.", + "properties": { + "_meta": { + "additionalProperties": {}, + "description": "See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage.", + "type": "object" + }, + "nextCursor": { + "description": "An opaque token representing the pagination position after the last returned result.\nIf present, there may be more results available.", + "type": "string" + }, + "resourceTemplates": { + "items": { + "$ref": "#/$defs/ResourceTemplate" + }, + "type": "array" + } + }, + "required": [ + "resourceTemplates" + ], + "type": "object" + }, + "ListResourcesRequest": { + "description": "Sent from the client to request a list of resources the server has.", + "properties": { + "id": { + "$ref": "#/$defs/RequestId" + }, + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "method": { + "const": "resources/list", + "type": "string" + }, + "params": { + "$ref": "#/$defs/PaginatedRequestParams" + } + }, + "required": [ + "id", + "jsonrpc", + "method" + ], + "type": "object" + }, + "ListResourcesResult": { + "description": "The server's response to a resources/list request from the client.", + "properties": { + "_meta": { + "additionalProperties": {}, + "description": "See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage.", + "type": "object" + }, + "nextCursor": { + "description": "An opaque token representing the pagination position after the last returned result.\nIf present, there may be more results available.", + "type": "string" + }, + "resources": { + "items": { + "$ref": "#/$defs/Resource" + }, + "type": "array" + } + }, + "required": [ + "resources" + ], + "type": "object" + }, + "ListRootsRequest": { + "description": "Sent from the server to request a list of root URIs from the client. Roots allow\nservers to ask for specific directories or files to operate on. A common example\nfor roots is providing a set of repositories or directories a server should operate\non.\n\nThis request is typically used when the server needs to understand the file system\nstructure or access specific locations that the client has permission to read from.", + "properties": { + "id": { + "$ref": "#/$defs/RequestId" + }, + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "method": { + "const": "roots/list", + "type": "string" + }, + "params": { + "$ref": "#/$defs/RequestParams" + } + }, + "required": [ + "id", + "jsonrpc", + "method" + ], + "type": "object" + }, + "ListRootsResult": { + "description": "The client's response to a roots/list request from the server.\nThis result contains an array of Root objects, each representing a root directory\nor file that the server can operate on.", + "properties": { + "_meta": { + "additionalProperties": {}, + "description": "See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage.", + "type": "object" + }, + "roots": { + "items": { + "$ref": "#/$defs/Root" + }, + "type": "array" + } + }, + "required": [ + "roots" + ], + "type": "object" + }, + "ListTasksRequest": { + "description": "A request to retrieve a list of tasks.", + "properties": { + "id": { + "$ref": "#/$defs/RequestId" + }, + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "method": { + "const": "tasks/list", + "type": "string" + }, + "params": { + "$ref": "#/$defs/PaginatedRequestParams" + } + }, + "required": [ + "id", + "jsonrpc", + "method" + ], + "type": "object" + }, + "ListTasksResult": { + "description": "The response to a tasks/list request.", + "properties": { + "_meta": { + "additionalProperties": {}, + "description": "See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage.", + "type": "object" + }, + "nextCursor": { + "description": "An opaque token representing the pagination position after the last returned result.\nIf present, there may be more results available.", + "type": "string" + }, + "tasks": { + "items": { + "$ref": "#/$defs/Task" + }, + "type": "array" + } + }, + "required": [ + "tasks" + ], + "type": "object" + }, + "ListToolsRequest": { + "description": "Sent from the client to request a list of tools the server has.", + "properties": { + "id": { + "$ref": "#/$defs/RequestId" + }, + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "method": { + "const": "tools/list", + "type": "string" + }, + "params": { + "$ref": "#/$defs/PaginatedRequestParams" + } + }, + "required": [ + "id", + "jsonrpc", + "method" + ], + "type": "object" + }, + "ListToolsResult": { + "description": "The server's response to a tools/list request from the client.", + "properties": { + "_meta": { + "additionalProperties": {}, + "description": "See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage.", + "type": "object" + }, + "nextCursor": { + "description": "An opaque token representing the pagination position after the last returned result.\nIf present, there may be more results available.", + "type": "string" + }, + "tools": { + "items": { + "$ref": "#/$defs/Tool" + }, + "type": "array" + } + }, + "required": [ + "tools" + ], + "type": "object" + }, + "LoggingLevel": { + "description": "The severity of a log message.\n\nThese map to syslog message severities, as specified in RFC-5424:\nhttps://datatracker.ietf.org/doc/html/rfc5424#section-6.2.1", + "enum": [ + "alert", + "critical", + "debug", + "emergency", + "error", + "info", + "notice", + "warning" + ], + "type": "string" + }, + "LoggingMessageNotification": { + "description": "JSONRPCNotification of a log message passed from server to client. If no logging/setLevel request has been sent from the client, the server MAY decide which messages to send automatically.", + "properties": { + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "method": { + "const": "notifications/message", + "type": "string" + }, + "params": { + "$ref": "#/$defs/LoggingMessageNotificationParams" + } + }, + "required": [ + "jsonrpc", + "method", + "params" + ], + "type": "object" + }, + "LoggingMessageNotificationParams": { + "description": "Parameters for a `notifications/message` notification.", + "properties": { + "_meta": { + "additionalProperties": {}, + "description": "See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage.", + "type": "object" + }, + "data": { + "description": "The data to be logged, such as a string message or an object. Any JSON serializable type is allowed here." + }, + "level": { + "$ref": "#/$defs/LoggingLevel", + "description": "The severity of this log message." + }, + "logger": { + "description": "An optional name of the logger issuing this message.", + "type": "string" + } + }, + "required": [ + "data", + "level" + ], + "type": "object" + }, + "ModelHint": { + "description": "Hints to use for model selection.\n\nKeys not declared here are currently left unspecified by the spec and are up\nto the client to interpret.", + "properties": { + "name": { + "description": "A hint for a model name.\n\nThe client SHOULD treat this as a substring of a model name; for example:\n - `claude-3-5-sonnet` should match `claude-3-5-sonnet-20241022`\n - `sonnet` should match `claude-3-5-sonnet-20241022`, `claude-3-sonnet-20240229`, etc.\n - `claude` should match any Claude model\n\nThe client MAY also map the string to a different provider's model name or a different model family, as long as it fills a similar niche; for example:\n - `gemini-1.5-flash` could match `claude-3-haiku-20240307`", + "type": "string" + } + }, + "type": "object" + }, + "ModelPreferences": { + "description": "The server's preferences for model selection, requested of the client during sampling.\n\nBecause LLMs can vary along multiple dimensions, choosing the \"best\" model is\nrarely straightforward. Different models excel in different areas—some are\nfaster but less capable, others are more capable but more expensive, and so\non. This interface allows servers to express their priorities across multiple\ndimensions to help clients make an appropriate selection for their use case.\n\nThese preferences are always advisory. The client MAY ignore them. It is also\nup to the client to decide how to interpret these preferences and how to\nbalance them against other considerations.", + "properties": { + "costPriority": { + "description": "How much to prioritize cost when selecting a model. A value of 0 means cost\nis not important, while a value of 1 means cost is the most important\nfactor.", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "hints": { + "description": "Optional hints to use for model selection.\n\nIf multiple hints are specified, the client MUST evaluate them in order\n(such that the first match is taken).\n\nThe client SHOULD prioritize these hints over the numeric priorities, but\nMAY still use the priorities to select from ambiguous matches.", + "items": { + "$ref": "#/$defs/ModelHint" + }, + "type": "array" + }, + "intelligencePriority": { + "description": "How much to prioritize intelligence and capabilities when selecting a\nmodel. A value of 0 means intelligence is not important, while a value of 1\nmeans intelligence is the most important factor.", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "speedPriority": { + "description": "How much to prioritize sampling speed (latency) when selecting a model. A\nvalue of 0 means speed is not important, while a value of 1 means speed is\nthe most important factor.", + "maximum": 1, + "minimum": 0, + "type": "number" + } + }, + "type": "object" + }, + "MultiSelectEnumSchema": { + "anyOf": [ + { + "$ref": "#/$defs/UntitledMultiSelectEnumSchema" + }, + { + "$ref": "#/$defs/TitledMultiSelectEnumSchema" + } + ] + }, + "Notification": { + "properties": { + "method": { + "type": "string" + }, + "params": { + "additionalProperties": {}, + "type": "object" + } + }, + "required": [ + "method" + ], + "type": "object" + }, + "NotificationParams": { + "properties": { + "_meta": { + "additionalProperties": {}, + "description": "See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage.", + "type": "object" + } + }, + "type": "object" + }, + "NumberSchema": { + "properties": { + "default": { + "type": "integer" + }, + "description": { + "type": "string" + }, + "maximum": { + "type": "integer" + }, + "minimum": { + "type": "integer" + }, + "title": { + "type": "string" + }, + "type": { + "enum": [ + "integer", + "number" + ], + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + }, + "PaginatedRequest": { + "properties": { + "id": { + "$ref": "#/$defs/RequestId" + }, + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "method": { + "type": "string" + }, + "params": { + "$ref": "#/$defs/PaginatedRequestParams" + } + }, + "required": [ + "id", + "jsonrpc", + "method" + ], + "type": "object" + }, + "PaginatedRequestParams": { + "description": "Common parameters for paginated requests.", + "properties": { + "_meta": { + "additionalProperties": {}, + "description": "See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage.", + "properties": { + "progressToken": { + "$ref": "#/$defs/ProgressToken", + "description": "If specified, the caller is requesting out-of-band progress notifications for this request (as represented by notifications/progress). The value of this parameter is an opaque token that will be attached to any subsequent notifications. The receiver is not obligated to provide these notifications." + } + }, + "type": "object" + }, + "cursor": { + "description": "An opaque token representing the current pagination position.\nIf provided, the server should return results starting after this cursor.", + "type": "string" + } + }, + "type": "object" + }, + "PaginatedResult": { + "properties": { + "_meta": { + "additionalProperties": {}, + "description": "See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage.", + "type": "object" + }, + "nextCursor": { + "description": "An opaque token representing the pagination position after the last returned result.\nIf present, there may be more results available.", + "type": "string" + } + }, + "type": "object" + }, + "PingRequest": { + "description": "A ping, issued by either the server or the client, to check that the other party is still alive. The receiver must promptly respond, or else may be disconnected.", + "properties": { + "id": { + "$ref": "#/$defs/RequestId" + }, + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "method": { + "const": "ping", + "type": "string" + }, + "params": { + "$ref": "#/$defs/RequestParams" + } + }, + "required": [ + "id", + "jsonrpc", + "method" + ], + "type": "object" + }, + "PrimitiveSchemaDefinition": { + "anyOf": [ + { + "$ref": "#/$defs/StringSchema" + }, + { + "$ref": "#/$defs/NumberSchema" + }, + { + "$ref": "#/$defs/BooleanSchema" + }, + { + "$ref": "#/$defs/UntitledSingleSelectEnumSchema" + }, + { + "$ref": "#/$defs/TitledSingleSelectEnumSchema" + }, + { + "$ref": "#/$defs/UntitledMultiSelectEnumSchema" + }, + { + "$ref": "#/$defs/TitledMultiSelectEnumSchema" + }, + { + "$ref": "#/$defs/LegacyTitledEnumSchema" + } + ], + "description": "Restricted schema definitions that only allow primitive types\nwithout nested objects or arrays." + }, + "ProgressNotification": { + "description": "An out-of-band notification used to inform the receiver of a progress update for a long-running request.", + "properties": { + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "method": { + "const": "notifications/progress", + "type": "string" + }, + "params": { + "$ref": "#/$defs/ProgressNotificationParams" + } + }, + "required": [ + "jsonrpc", + "method", + "params" + ], + "type": "object" + }, + "ProgressNotificationParams": { + "description": "Parameters for a `notifications/progress` notification.", + "properties": { + "_meta": { + "additionalProperties": {}, + "description": "See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage.", + "type": "object" + }, + "message": { + "description": "An optional message describing the current progress.", + "type": "string" + }, + "progress": { + "description": "The progress thus far. This should increase every time progress is made, even if the total is unknown.", + "type": "number" + }, + "progressToken": { + "$ref": "#/$defs/ProgressToken", + "description": "The progress token which was given in the initial request, used to associate this notification with the request that is proceeding." + }, + "total": { + "description": "Total number of items to process (or total progress required), if known.", + "type": "number" + } + }, + "required": [ + "progress", + "progressToken" + ], + "type": "object" + }, + "ProgressToken": { + "description": "A progress token, used to associate progress notifications with the original request.", + "type": [ + "string", + "integer" + ] + }, + "Prompt": { + "description": "A prompt or prompt template that the server offers.", + "properties": { + "_meta": { + "additionalProperties": {}, + "description": "See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage.", + "type": "object" + }, + "arguments": { + "description": "A list of arguments to use for templating the prompt.", + "items": { + "$ref": "#/$defs/PromptArgument" + }, + "type": "array" + }, + "description": { + "description": "An optional description of what this prompt provides", + "type": "string" + }, + "icons": { + "description": "Optional set of sized icons that the client can display in a user interface.\n\nClients that support rendering icons MUST support at least the following MIME types:\n- `image/png` - PNG images (safe, universal compatibility)\n- `image/jpeg` (and `image/jpg`) - JPEG images (safe, universal compatibility)\n\nClients that support rendering icons SHOULD also support:\n- `image/svg+xml` - SVG images (scalable but requires security precautions)\n- `image/webp` - WebP images (modern, efficient format)", + "items": { + "$ref": "#/$defs/Icon" + }, + "type": "array" + }, + "name": { + "description": "Intended for programmatic or logical use, but used as a display name in past specs or fallback (if title isn't present).", + "type": "string" + }, + "title": { + "description": "Intended for UI and end-user contexts — optimized to be human-readable and easily understood,\neven by those unfamiliar with domain-specific terminology.\n\nIf not provided, the name should be used for display (except for Tool,\nwhere `annotations.title` should be given precedence over using `name`,\nif present).", + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "PromptArgument": { + "description": "Describes an argument that a prompt can accept.", + "properties": { + "description": { + "description": "A human-readable description of the argument.", + "type": "string" + }, + "name": { + "description": "Intended for programmatic or logical use, but used as a display name in past specs or fallback (if title isn't present).", + "type": "string" + }, + "required": { + "description": "Whether this argument must be provided.", + "type": "boolean" + }, + "title": { + "description": "Intended for UI and end-user contexts — optimized to be human-readable and easily understood,\neven by those unfamiliar with domain-specific terminology.\n\nIf not provided, the name should be used for display (except for Tool,\nwhere `annotations.title` should be given precedence over using `name`,\nif present).", + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "PromptListChangedNotification": { + "description": "An optional notification from the server to the client, informing it that the list of prompts it offers has changed. This may be issued by servers without any previous subscription from the client.", + "properties": { + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "method": { + "const": "notifications/prompts/list_changed", + "type": "string" + }, + "params": { + "$ref": "#/$defs/NotificationParams" + } + }, + "required": [ + "jsonrpc", + "method" + ], + "type": "object" + }, + "PromptMessage": { + "description": "Describes a message returned as part of a prompt.\n\nThis is similar to `SamplingMessage`, but also supports the embedding of\nresources from the MCP server.", + "properties": { + "content": { + "$ref": "#/$defs/ContentBlock" + }, + "role": { + "$ref": "#/$defs/Role" + } + }, + "required": [ + "content", + "role" + ], + "type": "object" + }, + "PromptReference": { + "description": "Identifies a prompt.", + "properties": { + "name": { + "description": "Intended for programmatic or logical use, but used as a display name in past specs or fallback (if title isn't present).", + "type": "string" + }, + "title": { + "description": "Intended for UI and end-user contexts — optimized to be human-readable and easily understood,\neven by those unfamiliar with domain-specific terminology.\n\nIf not provided, the name should be used for display (except for Tool,\nwhere `annotations.title` should be given precedence over using `name`,\nif present).", + "type": "string" + }, + "type": { + "const": "ref/prompt", + "type": "string" + } + }, + "required": [ + "name", + "type" + ], + "type": "object" + }, + "ReadResourceRequest": { + "description": "Sent from the client to the server, to read a specific resource URI.", + "properties": { + "id": { + "$ref": "#/$defs/RequestId" + }, + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "method": { + "const": "resources/read", + "type": "string" + }, + "params": { + "$ref": "#/$defs/ReadResourceRequestParams" + } + }, + "required": [ + "id", + "jsonrpc", + "method", + "params" + ], + "type": "object" + }, + "ReadResourceRequestParams": { + "description": "Parameters for a `resources/read` request.", + "properties": { + "_meta": { + "additionalProperties": {}, + "description": "See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage.", + "properties": { + "progressToken": { + "$ref": "#/$defs/ProgressToken", + "description": "If specified, the caller is requesting out-of-band progress notifications for this request (as represented by notifications/progress). The value of this parameter is an opaque token that will be attached to any subsequent notifications. The receiver is not obligated to provide these notifications." + } + }, + "type": "object" + }, + "uri": { + "description": "The URI of the resource. The URI can use any protocol; it is up to the server how to interpret it.", + "format": "uri", + "type": "string" + } + }, + "required": [ + "uri" + ], + "type": "object" + }, + "ReadResourceResult": { + "description": "The server's response to a resources/read request from the client.", + "properties": { + "_meta": { + "additionalProperties": {}, + "description": "See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage.", + "type": "object" + }, + "contents": { + "items": { + "anyOf": [ + { + "$ref": "#/$defs/TextResourceContents" + }, + { + "$ref": "#/$defs/BlobResourceContents" + } + ] + }, + "type": "array" + } + }, + "required": [ + "contents" + ], + "type": "object" + }, + "RelatedTaskMetadata": { + "description": "Metadata for associating messages with a task.\nInclude this in the `_meta` field under the key `io.modelcontextprotocol/related-task`.", + "properties": { + "taskId": { + "description": "The task identifier this message is associated with.", + "type": "string" + } + }, + "required": [ + "taskId" + ], + "type": "object" + }, + "Request": { + "properties": { + "method": { + "type": "string" + }, + "params": { + "additionalProperties": {}, + "type": "object" + } + }, + "required": [ + "method" + ], + "type": "object" + }, + "RequestId": { + "description": "A uniquely identifying ID for a request in JSON-RPC.", + "type": [ + "string", + "integer" + ] + }, + "RequestParams": { + "description": "Common params for any request.", + "properties": { + "_meta": { + "additionalProperties": {}, + "description": "See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage.", + "properties": { + "progressToken": { + "$ref": "#/$defs/ProgressToken", + "description": "If specified, the caller is requesting out-of-band progress notifications for this request (as represented by notifications/progress). The value of this parameter is an opaque token that will be attached to any subsequent notifications. The receiver is not obligated to provide these notifications." + } + }, + "type": "object" + } + }, + "type": "object" + }, + "Resource": { + "description": "A known resource that the server is capable of reading.", + "properties": { + "_meta": { + "additionalProperties": {}, + "description": "See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage.", + "type": "object" + }, + "annotations": { + "$ref": "#/$defs/Annotations", + "description": "Optional annotations for the client." + }, + "description": { + "description": "A description of what this resource represents.\n\nThis can be used by clients to improve the LLM's understanding of available resources. It can be thought of like a \"hint\" to the model.", + "type": "string" + }, + "icons": { + "description": "Optional set of sized icons that the client can display in a user interface.\n\nClients that support rendering icons MUST support at least the following MIME types:\n- `image/png` - PNG images (safe, universal compatibility)\n- `image/jpeg` (and `image/jpg`) - JPEG images (safe, universal compatibility)\n\nClients that support rendering icons SHOULD also support:\n- `image/svg+xml` - SVG images (scalable but requires security precautions)\n- `image/webp` - WebP images (modern, efficient format)", + "items": { + "$ref": "#/$defs/Icon" + }, + "type": "array" + }, + "mimeType": { + "description": "The MIME type of this resource, if known.", + "type": "string" + }, + "name": { + "description": "Intended for programmatic or logical use, but used as a display name in past specs or fallback (if title isn't present).", + "type": "string" + }, + "size": { + "description": "The size of the raw resource content, in bytes (i.e., before base64 encoding or any tokenization), if known.\n\nThis can be used by Hosts to display file sizes and estimate context window usage.", + "type": "integer" + }, + "title": { + "description": "Intended for UI and end-user contexts — optimized to be human-readable and easily understood,\neven by those unfamiliar with domain-specific terminology.\n\nIf not provided, the name should be used for display (except for Tool,\nwhere `annotations.title` should be given precedence over using `name`,\nif present).", + "type": "string" + }, + "uri": { + "description": "The URI of this resource.", + "format": "uri", + "type": "string" + } + }, + "required": [ + "name", + "uri" + ], + "type": "object" + }, + "ResourceContents": { + "description": "The contents of a specific resource or sub-resource.", + "properties": { + "_meta": { + "additionalProperties": {}, + "description": "See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage.", + "type": "object" + }, + "mimeType": { + "description": "The MIME type of this resource, if known.", + "type": "string" + }, + "uri": { + "description": "The URI of this resource.", + "format": "uri", + "type": "string" + } + }, + "required": [ + "uri" + ], + "type": "object" + }, + "ResourceLink": { + "description": "A resource that the server is capable of reading, included in a prompt or tool call result.\n\nNote: resource links returned by tools are not guaranteed to appear in the results of `resources/list` requests.", + "properties": { + "_meta": { + "additionalProperties": {}, + "description": "See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage.", + "type": "object" + }, + "annotations": { + "$ref": "#/$defs/Annotations", + "description": "Optional annotations for the client." + }, + "description": { + "description": "A description of what this resource represents.\n\nThis can be used by clients to improve the LLM's understanding of available resources. It can be thought of like a \"hint\" to the model.", + "type": "string" + }, + "icons": { + "description": "Optional set of sized icons that the client can display in a user interface.\n\nClients that support rendering icons MUST support at least the following MIME types:\n- `image/png` - PNG images (safe, universal compatibility)\n- `image/jpeg` (and `image/jpg`) - JPEG images (safe, universal compatibility)\n\nClients that support rendering icons SHOULD also support:\n- `image/svg+xml` - SVG images (scalable but requires security precautions)\n- `image/webp` - WebP images (modern, efficient format)", + "items": { + "$ref": "#/$defs/Icon" + }, + "type": "array" + }, + "mimeType": { + "description": "The MIME type of this resource, if known.", + "type": "string" + }, + "name": { + "description": "Intended for programmatic or logical use, but used as a display name in past specs or fallback (if title isn't present).", + "type": "string" + }, + "size": { + "description": "The size of the raw resource content, in bytes (i.e., before base64 encoding or any tokenization), if known.\n\nThis can be used by Hosts to display file sizes and estimate context window usage.", + "type": "integer" + }, + "title": { + "description": "Intended for UI and end-user contexts — optimized to be human-readable and easily understood,\neven by those unfamiliar with domain-specific terminology.\n\nIf not provided, the name should be used for display (except for Tool,\nwhere `annotations.title` should be given precedence over using `name`,\nif present).", + "type": "string" + }, + "type": { + "const": "resource_link", + "type": "string" + }, + "uri": { + "description": "The URI of this resource.", + "format": "uri", + "type": "string" + } + }, + "required": [ + "name", + "type", + "uri" + ], + "type": "object" + }, + "ResourceListChangedNotification": { + "description": "An optional notification from the server to the client, informing it that the list of resources it can read from has changed. This may be issued by servers without any previous subscription from the client.", + "properties": { + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "method": { + "const": "notifications/resources/list_changed", + "type": "string" + }, + "params": { + "$ref": "#/$defs/NotificationParams" + } + }, + "required": [ + "jsonrpc", + "method" + ], + "type": "object" + }, + "ResourceRequestParams": { + "description": "Common parameters when working with resources.", + "properties": { + "_meta": { + "additionalProperties": {}, + "description": "See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage.", + "properties": { + "progressToken": { + "$ref": "#/$defs/ProgressToken", + "description": "If specified, the caller is requesting out-of-band progress notifications for this request (as represented by notifications/progress). The value of this parameter is an opaque token that will be attached to any subsequent notifications. The receiver is not obligated to provide these notifications." + } + }, + "type": "object" + }, + "uri": { + "description": "The URI of the resource. The URI can use any protocol; it is up to the server how to interpret it.", + "format": "uri", + "type": "string" + } + }, + "required": [ + "uri" + ], + "type": "object" + }, + "ResourceTemplate": { + "description": "A template description for resources available on the server.", + "properties": { + "_meta": { + "additionalProperties": {}, + "description": "See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage.", + "type": "object" + }, + "annotations": { + "$ref": "#/$defs/Annotations", + "description": "Optional annotations for the client." + }, + "description": { + "description": "A description of what this template is for.\n\nThis can be used by clients to improve the LLM's understanding of available resources. It can be thought of like a \"hint\" to the model.", + "type": "string" + }, + "icons": { + "description": "Optional set of sized icons that the client can display in a user interface.\n\nClients that support rendering icons MUST support at least the following MIME types:\n- `image/png` - PNG images (safe, universal compatibility)\n- `image/jpeg` (and `image/jpg`) - JPEG images (safe, universal compatibility)\n\nClients that support rendering icons SHOULD also support:\n- `image/svg+xml` - SVG images (scalable but requires security precautions)\n- `image/webp` - WebP images (modern, efficient format)", + "items": { + "$ref": "#/$defs/Icon" + }, + "type": "array" + }, + "mimeType": { + "description": "The MIME type for all resources that match this template. This should only be included if all resources matching this template have the same type.", + "type": "string" + }, + "name": { + "description": "Intended for programmatic or logical use, but used as a display name in past specs or fallback (if title isn't present).", + "type": "string" + }, + "title": { + "description": "Intended for UI and end-user contexts — optimized to be human-readable and easily understood,\neven by those unfamiliar with domain-specific terminology.\n\nIf not provided, the name should be used for display (except for Tool,\nwhere `annotations.title` should be given precedence over using `name`,\nif present).", + "type": "string" + }, + "uriTemplate": { + "description": "A URI template (according to RFC 6570) that can be used to construct resource URIs.", + "format": "uri-template", + "type": "string" + } + }, + "required": [ + "name", + "uriTemplate" + ], + "type": "object" + }, + "ResourceTemplateReference": { + "description": "A reference to a resource or resource template definition.", + "properties": { + "type": { + "const": "ref/resource", + "type": "string" + }, + "uri": { + "description": "The URI or URI template of the resource.", + "format": "uri-template", + "type": "string" + } + }, + "required": [ + "type", + "uri" + ], + "type": "object" + }, + "ResourceUpdatedNotification": { + "description": "A notification from the server to the client, informing it that a resource has changed and may need to be read again. This should only be sent if the client previously sent a resources/subscribe request.", + "properties": { + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "method": { + "const": "notifications/resources/updated", + "type": "string" + }, + "params": { + "$ref": "#/$defs/ResourceUpdatedNotificationParams" + } + }, + "required": [ + "jsonrpc", + "method", + "params" + ], + "type": "object" + }, + "ResourceUpdatedNotificationParams": { + "description": "Parameters for a `notifications/resources/updated` notification.", + "properties": { + "_meta": { + "additionalProperties": {}, + "description": "See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage.", + "type": "object" + }, + "uri": { + "description": "The URI of the resource that has been updated. This might be a sub-resource of the one that the client actually subscribed to.", + "format": "uri", + "type": "string" + } + }, + "required": [ + "uri" + ], + "type": "object" + }, + "Result": { + "additionalProperties": {}, + "properties": { + "_meta": { + "additionalProperties": {}, + "description": "See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage.", + "type": "object" + } + }, + "type": "object" + }, + "Role": { + "description": "The sender or recipient of messages and data in a conversation.", + "enum": [ + "assistant", + "user" + ], + "type": "string" + }, + "Root": { + "description": "Represents a root directory or file that the server can operate on.", + "properties": { + "_meta": { + "additionalProperties": {}, + "description": "See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage.", + "type": "object" + }, + "name": { + "description": "An optional name for the root. This can be used to provide a human-readable\nidentifier for the root, which may be useful for display purposes or for\nreferencing the root in other parts of the application.", + "type": "string" + }, + "uri": { + "description": "The URI identifying the root. This *must* start with file:// for now.\nThis restriction may be relaxed in future versions of the protocol to allow\nother URI schemes.", + "format": "uri", + "type": "string" + } + }, + "required": [ + "uri" + ], + "type": "object" + }, + "RootsListChangedNotification": { + "description": "A notification from the client to the server, informing it that the list of roots has changed.\nThis notification should be sent whenever the client adds, removes, or modifies any root.\nThe server should then request an updated list of roots using the ListRootsRequest.", + "properties": { + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "method": { + "const": "notifications/roots/list_changed", + "type": "string" + }, + "params": { + "$ref": "#/$defs/NotificationParams" + } + }, + "required": [ + "jsonrpc", + "method" + ], + "type": "object" + }, + "SamplingMessage": { + "description": "Describes a message issued to or received from an LLM API.", + "properties": { + "_meta": { + "additionalProperties": {}, + "description": "See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage.", + "type": "object" + }, + "content": { + "anyOf": [ + { + "$ref": "#/$defs/TextContent" + }, + { + "$ref": "#/$defs/ImageContent" + }, + { + "$ref": "#/$defs/AudioContent" + }, + { + "$ref": "#/$defs/ToolUseContent" + }, + { + "$ref": "#/$defs/ToolResultContent" + }, + { + "items": { + "$ref": "#/$defs/SamplingMessageContentBlock" + }, + "type": "array" + } + ] + }, + "role": { + "$ref": "#/$defs/Role" + } + }, + "required": [ + "content", + "role" + ], + "type": "object" + }, + "SamplingMessageContentBlock": { + "anyOf": [ + { + "$ref": "#/$defs/TextContent" + }, + { + "$ref": "#/$defs/ImageContent" + }, + { + "$ref": "#/$defs/AudioContent" + }, + { + "$ref": "#/$defs/ToolUseContent" + }, + { + "$ref": "#/$defs/ToolResultContent" + } + ] + }, + "ServerCapabilities": { + "description": "Capabilities that a server may support. Known capabilities are defined here, in this schema, but this is not a closed set: any server can define its own, additional capabilities.", + "properties": { + "completions": { + "additionalProperties": true, + "description": "Present if the server supports argument autocompletion suggestions.", + "properties": {}, + "type": "object" + }, + "experimental": { + "additionalProperties": { + "additionalProperties": true, + "properties": {}, + "type": "object" + }, + "description": "Experimental, non-standard capabilities that the server supports.", + "type": "object" + }, + "logging": { + "additionalProperties": true, + "description": "Present if the server supports sending log messages to the client.", + "properties": {}, + "type": "object" + }, + "prompts": { + "description": "Present if the server offers any prompt templates.", + "properties": { + "listChanged": { + "description": "Whether this server supports notifications for changes to the prompt list.", + "type": "boolean" + } + }, + "type": "object" + }, + "resources": { + "description": "Present if the server offers any resources to read.", + "properties": { + "listChanged": { + "description": "Whether this server supports notifications for changes to the resource list.", + "type": "boolean" + }, + "subscribe": { + "description": "Whether this server supports subscribing to resource updates.", + "type": "boolean" + } + }, + "type": "object" + }, + "tasks": { + "description": "Present if the server supports task-augmented requests.", + "properties": { + "cancel": { + "additionalProperties": true, + "description": "Whether this server supports tasks/cancel.", + "properties": {}, + "type": "object" + }, + "list": { + "additionalProperties": true, + "description": "Whether this server supports tasks/list.", + "properties": {}, + "type": "object" + }, + "requests": { + "description": "Specifies which request types can be augmented with tasks.", + "properties": { + "tools": { + "description": "Task support for tool-related requests.", + "properties": { + "call": { + "additionalProperties": true, + "description": "Whether the server supports task-augmented tools/call requests.", + "properties": {}, + "type": "object" + } + }, + "type": "object" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "tools": { + "description": "Present if the server offers any tools to call.", + "properties": { + "listChanged": { + "description": "Whether this server supports notifications for changes to the tool list.", + "type": "boolean" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "ServerNotification": { + "anyOf": [ + { + "$ref": "#/$defs/CancelledNotification" + }, + { + "$ref": "#/$defs/ProgressNotification" + }, + { + "$ref": "#/$defs/ResourceListChangedNotification" + }, + { + "$ref": "#/$defs/ResourceUpdatedNotification" + }, + { + "$ref": "#/$defs/PromptListChangedNotification" + }, + { + "$ref": "#/$defs/ToolListChangedNotification" + }, + { + "$ref": "#/$defs/TaskStatusNotification" + }, + { + "$ref": "#/$defs/LoggingMessageNotification" + }, + { + "$ref": "#/$defs/ElicitationCompleteNotification" + } + ] + }, + "ServerRequest": { + "anyOf": [ + { + "$ref": "#/$defs/PingRequest" + }, + { + "$ref": "#/$defs/GetTaskRequest" + }, + { + "$ref": "#/$defs/GetTaskPayloadRequest" + }, + { + "$ref": "#/$defs/CancelTaskRequest" + }, + { + "$ref": "#/$defs/ListTasksRequest" + }, + { + "$ref": "#/$defs/CreateMessageRequest" + }, + { + "$ref": "#/$defs/ListRootsRequest" + }, + { + "$ref": "#/$defs/ElicitRequest" + } + ] + }, + "ServerResult": { + "anyOf": [ + { + "$ref": "#/$defs/Result" + }, + { + "$ref": "#/$defs/InitializeResult" + }, + { + "$ref": "#/$defs/ListResourcesResult" + }, + { + "$ref": "#/$defs/ListResourceTemplatesResult" + }, + { + "$ref": "#/$defs/ReadResourceResult" + }, + { + "$ref": "#/$defs/ListPromptsResult" + }, + { + "$ref": "#/$defs/GetPromptResult" + }, + { + "$ref": "#/$defs/ListToolsResult" + }, + { + "$ref": "#/$defs/CallToolResult" + }, + { + "$ref": "#/$defs/GetTaskResult", + "description": "The response to a tasks/get request." + }, + { + "$ref": "#/$defs/GetTaskPayloadResult" + }, + { + "$ref": "#/$defs/CancelTaskResult", + "description": "The response to a tasks/cancel request." + }, + { + "$ref": "#/$defs/ListTasksResult" + }, + { + "$ref": "#/$defs/CompleteResult" + } + ] + }, + "SetLevelRequest": { + "description": "A request from the client to the server, to enable or adjust logging.", + "properties": { + "id": { + "$ref": "#/$defs/RequestId" + }, + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "method": { + "const": "logging/setLevel", + "type": "string" + }, + "params": { + "$ref": "#/$defs/SetLevelRequestParams" + } + }, + "required": [ + "id", + "jsonrpc", + "method", + "params" + ], + "type": "object" + }, + "SetLevelRequestParams": { + "description": "Parameters for a `logging/setLevel` request.", + "properties": { + "_meta": { + "additionalProperties": {}, + "description": "See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage.", + "properties": { + "progressToken": { + "$ref": "#/$defs/ProgressToken", + "description": "If specified, the caller is requesting out-of-band progress notifications for this request (as represented by notifications/progress). The value of this parameter is an opaque token that will be attached to any subsequent notifications. The receiver is not obligated to provide these notifications." + } + }, + "type": "object" + }, + "level": { + "$ref": "#/$defs/LoggingLevel", + "description": "The level of logging that the client wants to receive from the server. The server should send all logs at this level and higher (i.e., more severe) to the client as notifications/message." + } + }, + "required": [ + "level" + ], + "type": "object" + }, + "SingleSelectEnumSchema": { + "anyOf": [ + { + "$ref": "#/$defs/UntitledSingleSelectEnumSchema" + }, + { + "$ref": "#/$defs/TitledSingleSelectEnumSchema" + } + ] + }, + "StringSchema": { + "properties": { + "default": { + "type": "string" + }, + "description": { + "type": "string" + }, + "format": { + "enum": [ + "date", + "date-time", + "email", + "uri" + ], + "type": "string" + }, + "maxLength": { + "type": "integer" + }, + "minLength": { + "type": "integer" + }, + "title": { + "type": "string" + }, + "type": { + "const": "string", + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + }, + "SubscribeRequest": { + "description": "Sent from the client to request resources/updated notifications from the server whenever a particular resource changes.", + "properties": { + "id": { + "$ref": "#/$defs/RequestId" + }, + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "method": { + "const": "resources/subscribe", + "type": "string" + }, + "params": { + "$ref": "#/$defs/SubscribeRequestParams" + } + }, + "required": [ + "id", + "jsonrpc", + "method", + "params" + ], + "type": "object" + }, + "SubscribeRequestParams": { + "description": "Parameters for a `resources/subscribe` request.", + "properties": { + "_meta": { + "additionalProperties": {}, + "description": "See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage.", + "properties": { + "progressToken": { + "$ref": "#/$defs/ProgressToken", + "description": "If specified, the caller is requesting out-of-band progress notifications for this request (as represented by notifications/progress). The value of this parameter is an opaque token that will be attached to any subsequent notifications. The receiver is not obligated to provide these notifications." + } + }, + "type": "object" + }, + "uri": { + "description": "The URI of the resource. The URI can use any protocol; it is up to the server how to interpret it.", + "format": "uri", + "type": "string" + } + }, + "required": [ + "uri" + ], + "type": "object" + }, + "Task": { + "description": "Data associated with a task.", + "properties": { + "createdAt": { + "description": "ISO 8601 timestamp when the task was created.", + "type": "string" + }, + "lastUpdatedAt": { + "description": "ISO 8601 timestamp when the task was last updated.", + "type": "string" + }, + "pollInterval": { + "description": "Suggested polling interval in milliseconds.", + "type": "integer" + }, + "status": { + "$ref": "#/$defs/TaskStatus", + "description": "Current task state." + }, + "statusMessage": { + "description": "Optional human-readable message describing the current task state.\nThis can provide context for any status, including:\n- Reasons for \"cancelled\" status\n- Summaries for \"completed\" status\n- Diagnostic information for \"failed\" status (e.g., error details, what went wrong)", + "type": "string" + }, + "taskId": { + "description": "The task identifier.", + "type": "string" + }, + "ttl": { + "description": "Actual retention duration from creation in milliseconds, null for unlimited.", + "type": [ + "integer", + "null" + ] + } + }, + "required": [ + "createdAt", + "lastUpdatedAt", + "status", + "taskId", + "ttl" + ], + "type": "object" + }, + "TaskAugmentedRequestParams": { + "description": "Common params for any task-augmented request.", + "properties": { + "_meta": { + "additionalProperties": {}, + "description": "See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage.", + "properties": { + "progressToken": { + "$ref": "#/$defs/ProgressToken", + "description": "If specified, the caller is requesting out-of-band progress notifications for this request (as represented by notifications/progress). The value of this parameter is an opaque token that will be attached to any subsequent notifications. The receiver is not obligated to provide these notifications." + } + }, + "type": "object" + }, + "task": { + "$ref": "#/$defs/TaskMetadata", + "description": "If specified, the caller is requesting task-augmented execution for this request.\nThe request will return a CreateTaskResult immediately, and the actual result can be\nretrieved later via tasks/result.\n\nTask augmentation is subject to capability negotiation - receivers MUST declare support\nfor task augmentation of specific request types in their capabilities." + } + }, + "type": "object" + }, + "TaskMetadata": { + "description": "Metadata for augmenting a request with task execution.\nInclude this in the `task` field of the request parameters.", + "properties": { + "ttl": { + "description": "Requested duration in milliseconds to retain task from creation.", + "type": "integer" + } + }, + "type": "object" + }, + "TaskStatus": { + "description": "The status of a task.", + "enum": [ + "cancelled", + "completed", + "failed", + "input_required", + "working" + ], + "type": "string" + }, + "TaskStatusNotification": { + "description": "An optional notification from the receiver to the requestor, informing them that a task's status has changed. Receivers are not required to send these notifications.", + "properties": { + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "method": { + "const": "notifications/tasks/status", + "type": "string" + }, + "params": { + "$ref": "#/$defs/TaskStatusNotificationParams" + } + }, + "required": [ + "jsonrpc", + "method", + "params" + ], + "type": "object" + }, + "TaskStatusNotificationParams": { + "allOf": [ + { + "$ref": "#/$defs/NotificationParams" + }, + { + "$ref": "#/$defs/Task" + } + ], + "description": "Parameters for a `notifications/tasks/status` notification." + }, + "TextContent": { + "description": "Text provided to or from an LLM.", + "properties": { + "_meta": { + "additionalProperties": {}, + "description": "See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage.", + "type": "object" + }, + "annotations": { + "$ref": "#/$defs/Annotations", + "description": "Optional annotations for the client." + }, + "text": { + "description": "The text content of the message.", + "type": "string" + }, + "type": { + "const": "text", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "type": "object" + }, + "TextResourceContents": { + "properties": { + "_meta": { + "additionalProperties": {}, + "description": "See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage.", + "type": "object" + }, + "mimeType": { + "description": "The MIME type of this resource, if known.", + "type": "string" + }, + "text": { + "description": "The text of the item. This must only be set if the item can actually be represented as text (not binary data).", + "type": "string" + }, + "uri": { + "description": "The URI of this resource.", + "format": "uri", + "type": "string" + } + }, + "required": [ + "text", + "uri" + ], + "type": "object" + }, + "TitledMultiSelectEnumSchema": { + "description": "Schema for multiple-selection enumeration with display titles for each option.", + "properties": { + "default": { + "description": "Optional default value.", + "items": { + "type": "string" + }, + "type": "array" + }, + "description": { + "description": "Optional description for the enum field.", + "type": "string" + }, + "items": { + "description": "Schema for array items with enum options and display labels.", + "properties": { + "anyOf": { + "description": "Array of enum options with values and display labels.", + "items": { + "properties": { + "const": { + "description": "The constant enum value.", + "type": "string" + }, + "title": { + "description": "Display title for this option.", + "type": "string" + } + }, + "required": [ + "const", + "title" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "anyOf" + ], + "type": "object" + }, + "maxItems": { + "description": "Maximum number of items to select.", + "type": "integer" + }, + "minItems": { + "description": "Minimum number of items to select.", + "type": "integer" + }, + "title": { + "description": "Optional title for the enum field.", + "type": "string" + }, + "type": { + "const": "array", + "type": "string" + } + }, + "required": [ + "items", + "type" + ], + "type": "object" + }, + "TitledSingleSelectEnumSchema": { + "description": "Schema for single-selection enumeration with display titles for each option.", + "properties": { + "default": { + "description": "Optional default value.", + "type": "string" + }, + "description": { + "description": "Optional description for the enum field.", + "type": "string" + }, + "oneOf": { + "description": "Array of enum options with values and display labels.", + "items": { + "properties": { + "const": { + "description": "The enum value.", + "type": "string" + }, + "title": { + "description": "Display label for this option.", + "type": "string" + } + }, + "required": [ + "const", + "title" + ], + "type": "object" + }, + "type": "array" + }, + "title": { + "description": "Optional title for the enum field.", + "type": "string" + }, + "type": { + "const": "string", + "type": "string" + } + }, + "required": [ + "oneOf", + "type" + ], + "type": "object" + }, + "Tool": { + "description": "Definition for a tool the client can call.", + "properties": { + "_meta": { + "additionalProperties": {}, + "description": "See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage.", + "type": "object" + }, + "annotations": { + "$ref": "#/$defs/ToolAnnotations", + "description": "Optional additional tool information.\n\nDisplay name precedence order is: title, annotations.title, then name." + }, + "description": { + "description": "A human-readable description of the tool.\n\nThis can be used by clients to improve the LLM's understanding of available tools. It can be thought of like a \"hint\" to the model.", + "type": "string" + }, + "execution": { + "$ref": "#/$defs/ToolExecution", + "description": "Execution-related properties for this tool." + }, + "icons": { + "description": "Optional set of sized icons that the client can display in a user interface.\n\nClients that support rendering icons MUST support at least the following MIME types:\n- `image/png` - PNG images (safe, universal compatibility)\n- `image/jpeg` (and `image/jpg`) - JPEG images (safe, universal compatibility)\n\nClients that support rendering icons SHOULD also support:\n- `image/svg+xml` - SVG images (scalable but requires security precautions)\n- `image/webp` - WebP images (modern, efficient format)", + "items": { + "$ref": "#/$defs/Icon" + }, + "type": "array" + }, + "inputSchema": { + "description": "A JSON Schema object defining the expected parameters for the tool.", + "properties": { + "$schema": { + "type": "string" + }, + "properties": { + "additionalProperties": { + "additionalProperties": true, + "properties": {}, + "type": "object" + }, + "type": "object" + }, + "required": { + "items": { + "type": "string" + }, + "type": "array" + }, + "type": { + "const": "object", + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + }, + "name": { + "description": "Intended for programmatic or logical use, but used as a display name in past specs or fallback (if title isn't present).", + "type": "string" + }, + "outputSchema": { + "description": "An optional JSON Schema object defining the structure of the tool's output returned in\nthe structuredContent field of a CallToolResult.\n\nDefaults to JSON Schema 2020-12 when no explicit $schema is provided.\nCurrently restricted to type: \"object\" at the root level.", + "properties": { + "$schema": { + "type": "string" + }, + "properties": { + "additionalProperties": { + "additionalProperties": true, + "properties": {}, + "type": "object" + }, + "type": "object" + }, + "required": { + "items": { + "type": "string" + }, + "type": "array" + }, + "type": { + "const": "object", + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + }, + "title": { + "description": "Intended for UI and end-user contexts — optimized to be human-readable and easily understood,\neven by those unfamiliar with domain-specific terminology.\n\nIf not provided, the name should be used for display (except for Tool,\nwhere `annotations.title` should be given precedence over using `name`,\nif present).", + "type": "string" + } + }, + "required": [ + "inputSchema", + "name" + ], + "type": "object" + }, + "ToolAnnotations": { + "description": "Additional properties describing a Tool to clients.\n\nNOTE: all properties in ToolAnnotations are **hints**.\nThey are not guaranteed to provide a faithful description of\ntool behavior (including descriptive properties like `title`).\n\nClients should never make tool use decisions based on ToolAnnotations\nreceived from untrusted servers.", + "properties": { + "destructiveHint": { + "description": "If true, the tool may perform destructive updates to its environment.\nIf false, the tool performs only additive updates.\n\n(This property is meaningful only when `readOnlyHint == false`)\n\nDefault: true", + "type": "boolean" + }, + "idempotentHint": { + "description": "If true, calling the tool repeatedly with the same arguments\nwill have no additional effect on its environment.\n\n(This property is meaningful only when `readOnlyHint == false`)\n\nDefault: false", + "type": "boolean" + }, + "openWorldHint": { + "description": "If true, this tool may interact with an \"open world\" of external\nentities. If false, the tool's domain of interaction is closed.\nFor example, the world of a web search tool is open, whereas that\nof a memory tool is not.\n\nDefault: true", + "type": "boolean" + }, + "readOnlyHint": { + "description": "If true, the tool does not modify its environment.\n\nDefault: false", + "type": "boolean" + }, + "title": { + "description": "A human-readable title for the tool.", + "type": "string" + } + }, + "type": "object" + }, + "ToolChoice": { + "description": "Controls tool selection behavior for sampling requests.", + "properties": { + "mode": { + "description": "Controls the tool use ability of the model:\n- \"auto\": Model decides whether to use tools (default)\n- \"required\": Model MUST use at least one tool before completing\n- \"none\": Model MUST NOT use any tools", + "enum": [ + "auto", + "none", + "required" + ], + "type": "string" + } + }, + "type": "object" + }, + "ToolExecution": { + "description": "Execution-related properties for a tool.", + "properties": { + "taskSupport": { + "description": "Indicates whether this tool supports task-augmented execution.\nThis allows clients to handle long-running operations through polling\nthe task system.\n\n- \"forbidden\": Tool does not support task-augmented execution (default when absent)\n- \"optional\": Tool may support task-augmented execution\n- \"required\": Tool requires task-augmented execution\n\nDefault: \"forbidden\"", + "enum": [ + "forbidden", + "optional", + "required" + ], + "type": "string" + } + }, + "type": "object" + }, + "ToolListChangedNotification": { + "description": "An optional notification from the server to the client, informing it that the list of tools it offers has changed. This may be issued by servers without any previous subscription from the client.", + "properties": { + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "method": { + "const": "notifications/tools/list_changed", + "type": "string" + }, + "params": { + "$ref": "#/$defs/NotificationParams" + } + }, + "required": [ + "jsonrpc", + "method" + ], + "type": "object" + }, + "ToolResultContent": { + "description": "The result of a tool use, provided by the user back to the assistant.", + "properties": { + "_meta": { + "additionalProperties": {}, + "description": "Optional metadata about the tool result. Clients SHOULD preserve this field when\nincluding tool results in subsequent sampling requests to enable caching optimizations.\n\nSee [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage.", + "type": "object" + }, + "content": { + "description": "The unstructured result content of the tool use.\n\nThis has the same format as CallToolResult.content and can include text, images,\naudio, resource links, and embedded resources.", + "items": { + "$ref": "#/$defs/ContentBlock" + }, + "type": "array" + }, + "isError": { + "description": "Whether the tool use resulted in an error.\n\nIf true, the content typically describes the error that occurred.\nDefault: false", + "type": "boolean" + }, + "structuredContent": { + "additionalProperties": {}, + "description": "An optional structured result object.\n\nIf the tool defined an outputSchema, this SHOULD conform to that schema.", + "type": "object" + }, + "toolUseId": { + "description": "The ID of the tool use this result corresponds to.\n\nThis MUST match the ID from a previous ToolUseContent.", + "type": "string" + }, + "type": { + "const": "tool_result", + "type": "string" + } + }, + "required": [ + "content", + "toolUseId", + "type" + ], + "type": "object" + }, + "ToolUseContent": { + "description": "A request from the assistant to call a tool.", + "properties": { + "_meta": { + "additionalProperties": {}, + "description": "Optional metadata about the tool use. Clients SHOULD preserve this field when\nincluding tool uses in subsequent sampling requests to enable caching optimizations.\n\nSee [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage.", + "type": "object" + }, + "id": { + "description": "A unique identifier for this tool use.\n\nThis ID is used to match tool results to their corresponding tool uses.", + "type": "string" + }, + "input": { + "additionalProperties": {}, + "description": "The arguments to pass to the tool, conforming to the tool's input schema.", + "type": "object" + }, + "name": { + "description": "The name of the tool to call.", + "type": "string" + }, + "type": { + "const": "tool_use", + "type": "string" + } + }, + "required": [ + "id", + "input", + "name", + "type" + ], + "type": "object" + }, + "URLElicitationRequiredError": { + "description": "An error response that indicates that the server requires the client to provide additional information via an elicitation request.", + "properties": { + "error": { + "allOf": [ + { + "$ref": "#/$defs/Error" + }, + { + "properties": { + "code": { + "const": -32042, + "type": "integer" + }, + "data": { + "additionalProperties": {}, + "properties": { + "elicitations": { + "items": { + "$ref": "#/$defs/ElicitRequestURLParams" + }, + "type": "array" + } + }, + "required": [ + "elicitations" + ], + "type": "object" + } + }, + "required": [ + "code", + "data" + ], + "type": "object" + } + ] + }, + "id": { + "$ref": "#/$defs/RequestId" + }, + "jsonrpc": { + "const": "2.0", + "type": "string" + } + }, + "required": [ + "error", + "jsonrpc" + ], + "type": "object" + }, + "UnsubscribeRequest": { + "description": "Sent from the client to request cancellation of resources/updated notifications from the server. This should follow a previous resources/subscribe request.", + "properties": { + "id": { + "$ref": "#/$defs/RequestId" + }, + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "method": { + "const": "resources/unsubscribe", + "type": "string" + }, + "params": { + "$ref": "#/$defs/UnsubscribeRequestParams" + } + }, + "required": [ + "id", + "jsonrpc", + "method", + "params" + ], + "type": "object" + }, + "UnsubscribeRequestParams": { + "description": "Parameters for a `resources/unsubscribe` request.", + "properties": { + "_meta": { + "additionalProperties": {}, + "description": "See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage.", + "properties": { + "progressToken": { + "$ref": "#/$defs/ProgressToken", + "description": "If specified, the caller is requesting out-of-band progress notifications for this request (as represented by notifications/progress). The value of this parameter is an opaque token that will be attached to any subsequent notifications. The receiver is not obligated to provide these notifications." + } + }, + "type": "object" + }, + "uri": { + "description": "The URI of the resource. The URI can use any protocol; it is up to the server how to interpret it.", + "format": "uri", + "type": "string" + } + }, + "required": [ + "uri" + ], + "type": "object" + }, + "UntitledMultiSelectEnumSchema": { + "description": "Schema for multiple-selection enumeration without display titles for options.", + "properties": { + "default": { + "description": "Optional default value.", + "items": { + "type": "string" + }, + "type": "array" + }, + "description": { + "description": "Optional description for the enum field.", + "type": "string" + }, + "items": { + "description": "Schema for the array items.", + "properties": { + "enum": { + "description": "Array of enum values to choose from.", + "items": { + "type": "string" + }, + "type": "array" + }, + "type": { + "const": "string", + "type": "string" + } + }, + "required": [ + "enum", + "type" + ], + "type": "object" + }, + "maxItems": { + "description": "Maximum number of items to select.", + "type": "integer" + }, + "minItems": { + "description": "Minimum number of items to select.", + "type": "integer" + }, + "title": { + "description": "Optional title for the enum field.", + "type": "string" + }, + "type": { + "const": "array", + "type": "string" + } + }, + "required": [ + "items", + "type" + ], + "type": "object" + }, + "UntitledSingleSelectEnumSchema": { + "description": "Schema for single-selection enumeration without display titles for options.", + "properties": { + "default": { + "description": "Optional default value.", + "type": "string" + }, + "description": { + "description": "Optional description for the enum field.", + "type": "string" + }, + "enum": { + "description": "Array of enum values to choose from.", + "items": { + "type": "string" + }, + "type": "array" + }, + "title": { + "description": "Optional title for the enum field.", + "type": "string" + }, + "type": { + "const": "string", + "type": "string" + } + }, + "required": [ + "enum", + "type" + ], + "type": "object" + } + } +} diff --git a/schema/2026-07-28.json b/schema/2026-07-28.json new file mode 100644 index 0000000000..2bfbcfa233 --- /dev/null +++ b/schema/2026-07-28.json @@ -0,0 +1,3873 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$defs": { + "Annotations": { + "description": "Optional annotations for the client. The client can use annotations to inform how objects are used or displayed", + "properties": { + "audience": { + "description": "Describes who the intended audience of this object or data is.\n\nIt can include multiple entries to indicate content useful for multiple audiences (e.g., `[\"user\", \"assistant\"]`).", + "items": { + "$ref": "#/$defs/Role" + }, + "type": "array" + }, + "lastModified": { + "description": "The moment the resource was last modified, as an ISO 8601 formatted string.\n\nShould be an ISO 8601 formatted string (e.g., \"2025-01-12T15:00:58Z\").\n\nExamples: last activity timestamp in an open file, timestamp when the resource\nwas attached, etc.", + "type": "string" + }, + "priority": { + "description": "Describes how important this data is for operating the server.\n\nA value of 1 means \"most important,\" and indicates that the data is\neffectively required, while 0 means \"least important,\" and indicates that\nthe data is entirely optional.", + "maximum": 1, + "minimum": 0, + "type": "number" + } + }, + "type": "object" + }, + "AudioContent": { + "description": "Audio provided to or from an LLM.", + "properties": { + "_meta": { + "$ref": "#/$defs/MetaObject" + }, + "annotations": { + "$ref": "#/$defs/Annotations", + "description": "Optional annotations for the client." + }, + "data": { + "description": "The base64-encoded audio data.", + "format": "byte", + "type": "string" + }, + "mimeType": { + "description": "The MIME type of the audio. Different providers may support different audio types.", + "type": "string" + }, + "type": { + "const": "audio", + "type": "string" + } + }, + "required": [ + "data", + "mimeType", + "type" + ], + "type": "object" + }, + "BaseMetadata": { + "description": "Base interface for metadata with name (identifier) and title (display name) properties.", + "properties": { + "name": { + "description": "Intended for programmatic or logical use, but used as a display name in past specs or fallback (if title isn't present).", + "type": "string" + }, + "title": { + "description": "Intended for UI and end-user contexts — optimized to be human-readable and easily understood,\neven by those unfamiliar with domain-specific terminology.\n\nIf not provided, the name should be used for display (except for {@link Tool},\nwhere `annotations.title` should be given precedence over using `name`,\nif present).", + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "BlobResourceContents": { + "properties": { + "_meta": { + "$ref": "#/$defs/MetaObject" + }, + "blob": { + "description": "A base64-encoded string representing the binary data of the item.", + "format": "byte", + "type": "string" + }, + "mimeType": { + "description": "The MIME type of this resource, if known.", + "type": "string" + }, + "uri": { + "description": "The URI of this resource.", + "format": "uri", + "type": "string" + } + }, + "required": [ + "blob", + "uri" + ], + "type": "object" + }, + "BooleanSchema": { + "properties": { + "default": { + "type": "boolean" + }, + "description": { + "type": "string" + }, + "title": { + "type": "string" + }, + "type": { + "const": "boolean", + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + }, + "CacheableResult": { + "description": "A result that supports a time-to-live (TTL) hint for client-side caching.", + "properties": { + "_meta": { + "$ref": "#/$defs/MetaObject" + }, + "cacheScope": { + "description": "Indicates the intended scope of the cached response, analogous to HTTP\n`Cache-Control: public` vs `Cache-Control: private`.\n\n- `\"public\"`: Any client or intermediary (e.g., shared gateway, proxy)\n MAY cache the response and serve it to any user.\n- `\"private\"`: Only the requesting user's client MAY cache the response.\n Shared caches (e.g., multi-tenant gateways) MUST NOT serve a cached\n copy to a different user.", + "enum": [ + "private", + "public" + ], + "type": "string" + }, + "resultType": { + "description": "Indicates the type of the result, which allows the client to determine\nhow to parse the result object.\n\nServers implementing this protocol version MUST include this field.\nFor backward compatibility, when a client receives a result from a\nserver implementing an earlier protocol version (which does not include\n`resultType`), the client MUST treat the absent field as `\"complete\"`.", + "type": "string" + }, + "ttlMs": { + "description": "A hint from the server indicating how long (in milliseconds) the\nclient MAY cache this response before re-fetching. Semantics are\nanalogous to HTTP Cache-Control max-age.\n\n- If 0, The response SHOULD be considered immediately stale,\n The client MAY re-fetch every time the result is needed.\n- If positive, the client SHOULD consider the result fresh for this many\n milliseconds after receiving the response.", + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "cacheScope", + "resultType", + "ttlMs" + ], + "type": "object" + }, + "CallToolRequest": { + "description": "Used by the client to invoke a tool provided by the server.", + "properties": { + "id": { + "$ref": "#/$defs/RequestId" + }, + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "method": { + "const": "tools/call", + "type": "string" + }, + "params": { + "$ref": "#/$defs/CallToolRequestParams" + } + }, + "required": [ + "id", + "jsonrpc", + "method", + "params" + ], + "type": "object" + }, + "CallToolRequestParams": { + "description": "Parameters for a `tools/call` request.", + "properties": { + "_meta": { + "$ref": "#/$defs/RequestMetaObject" + }, + "arguments": { + "additionalProperties": {}, + "description": "Arguments to use for the tool call.", + "type": "object" + }, + "inputResponses": { + "$ref": "#/$defs/InputResponses" + }, + "name": { + "description": "The name of the tool.", + "type": "string" + }, + "requestState": { + "type": "string" + } + }, + "required": [ + "_meta", + "name" + ], + "type": "object" + }, + "CallToolResult": { + "description": "The result returned by the server for a {@link CallToolRequesttools/call} request.", + "properties": { + "_meta": { + "$ref": "#/$defs/MetaObject" + }, + "content": { + "description": "A list of content objects that represent the unstructured result of the tool call.", + "items": { + "$ref": "#/$defs/ContentBlock" + }, + "type": "array" + }, + "isError": { + "description": "Whether the tool call ended in an error.\n\nIf not set, this is assumed to be false (the call was successful).\n\nAny errors that originate from the tool SHOULD be reported inside the result\nobject, with `isError` set to true, _not_ as an MCP protocol-level error\nresponse. Otherwise, the LLM would not be able to see that an error occurred\nand self-correct.\n\nHowever, any errors in _finding_ the tool, an error indicating that the\nserver does not support tool calls, or any other exceptional conditions,\nshould be reported as an MCP error response.", + "type": "boolean" + }, + "resultType": { + "description": "Indicates the type of the result, which allows the client to determine\nhow to parse the result object.\n\nServers implementing this protocol version MUST include this field.\nFor backward compatibility, when a client receives a result from a\nserver implementing an earlier protocol version (which does not include\n`resultType`), the client MUST treat the absent field as `\"complete\"`.", + "type": "string" + }, + "structuredContent": { + "description": "An optional JSON value that represents the structured result of the tool call.\n\nThis can be any JSON value (object, array, string, number, boolean, or null)\nthat conforms to the tool's outputSchema if one is defined." + } + }, + "required": [ + "content", + "resultType" + ], + "type": "object" + }, + "CallToolResultResponse": { + "description": "A successful response from the server for a {@link CallToolRequesttools/call} request.", + "properties": { + "id": { + "$ref": "#/$defs/RequestId" + }, + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "result": { + "anyOf": [ + { + "$ref": "#/$defs/InputRequiredResult" + }, + { + "$ref": "#/$defs/CallToolResult" + } + ] + } + }, + "required": [ + "id", + "jsonrpc", + "result" + ], + "type": "object" + }, + "CancelledNotification": { + "description": "This notification can be sent by either side to indicate that it is cancelling a previously-issued request.\n\nThe request SHOULD still be in-flight, but due to communication latency, it is always possible that this notification MAY arrive after the request has already finished.\n\nThis notification indicates that the result will be unused, so any associated processing SHOULD cease.", + "properties": { + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "method": { + "const": "notifications/cancelled", + "type": "string" + }, + "params": { + "$ref": "#/$defs/CancelledNotificationParams" + } + }, + "required": [ + "jsonrpc", + "method", + "params" + ], + "type": "object" + }, + "CancelledNotificationParams": { + "description": "Parameters for a `notifications/cancelled` notification.", + "properties": { + "_meta": { + "$ref": "#/$defs/MetaObject" + }, + "reason": { + "description": "An optional string describing the reason for the cancellation. This MAY be logged or presented to the user.", + "type": "string" + }, + "requestId": { + "$ref": "#/$defs/RequestId", + "description": "The ID of the request to cancel.\n\nThis MUST correspond to the ID of a request previously issued in the same direction." + } + }, + "type": "object" + }, + "ClientCapabilities": { + "description": "Capabilities a client may support. Known capabilities are defined here, in this schema, but this is not a closed set: any client can define its own, additional capabilities.", + "properties": { + "elicitation": { + "description": "Present if the client supports elicitation from the server.", + "properties": { + "form": { + "$ref": "#/$defs/JSONObject" + }, + "url": { + "$ref": "#/$defs/JSONObject" + } + }, + "type": "object" + }, + "experimental": { + "additionalProperties": { + "$ref": "#/$defs/JSONObject" + }, + "description": "Experimental, non-standard capabilities that the client supports.", + "type": "object" + }, + "extensions": { + "additionalProperties": { + "$ref": "#/$defs/JSONObject" + }, + "description": "Optional MCP extensions that the client supports. Keys are extension identifiers\n(e.g., \"io.modelcontextprotocol/oauth-client-credentials\"), and values are\nper-extension settings objects. An empty object indicates support with no settings.", + "type": "object" + }, + "roots": { + "description": "Present if the client supports listing roots.", + "properties": {}, + "type": "object" + }, + "sampling": { + "description": "Present if the client supports sampling from an LLM.", + "properties": { + "context": { + "$ref": "#/$defs/JSONObject", + "description": "Whether the client supports context inclusion via `includeContext` parameter.\nIf not declared, servers SHOULD only use `includeContext: \"none\"` (or omit it)." + }, + "tools": { + "$ref": "#/$defs/JSONObject", + "description": "Whether the client supports tool use via `tools` and `toolChoice` parameters." + } + }, + "type": "object" + } + }, + "type": "object" + }, + "ClientNotification": { + "anyOf": [ + { + "$ref": "#/$defs/CancelledNotification" + }, + { + "$ref": "#/$defs/ProgressNotification" + } + ] + }, + "ClientRequest": { + "anyOf": [ + { + "$ref": "#/$defs/DiscoverRequest" + }, + { + "$ref": "#/$defs/ListResourcesRequest" + }, + { + "$ref": "#/$defs/ListResourceTemplatesRequest" + }, + { + "$ref": "#/$defs/ReadResourceRequest" + }, + { + "$ref": "#/$defs/SubscriptionsListenRequest" + }, + { + "$ref": "#/$defs/ListPromptsRequest" + }, + { + "$ref": "#/$defs/GetPromptRequest" + }, + { + "$ref": "#/$defs/ListToolsRequest" + }, + { + "$ref": "#/$defs/CallToolRequest" + }, + { + "$ref": "#/$defs/CompleteRequest" + } + ] + }, + "ClientResult": { + "$ref": "#/$defs/Result", + "description": "Common result fields." + }, + "CompleteRequest": { + "description": "A request from the client to the server, to ask for completion options.", + "properties": { + "id": { + "$ref": "#/$defs/RequestId" + }, + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "method": { + "const": "completion/complete", + "type": "string" + }, + "params": { + "$ref": "#/$defs/CompleteRequestParams" + } + }, + "required": [ + "id", + "jsonrpc", + "method", + "params" + ], + "type": "object" + }, + "CompleteRequestParams": { + "description": "Parameters for a `completion/complete` request.", + "properties": { + "_meta": { + "$ref": "#/$defs/RequestMetaObject" + }, + "argument": { + "description": "The argument's information", + "properties": { + "name": { + "description": "The name of the argument", + "type": "string" + }, + "value": { + "description": "The value of the argument to use for completion matching.", + "type": "string" + } + }, + "required": [ + "name", + "value" + ], + "type": "object" + }, + "context": { + "description": "Additional, optional context for completions", + "properties": { + "arguments": { + "additionalProperties": { + "type": "string" + }, + "description": "Previously-resolved variables in a URI template or prompt.", + "type": "object" + } + }, + "type": "object" + }, + "ref": { + "anyOf": [ + { + "$ref": "#/$defs/PromptReference" + }, + { + "$ref": "#/$defs/ResourceTemplateReference" + } + ] + } + }, + "required": [ + "_meta", + "argument", + "ref" + ], + "type": "object" + }, + "CompleteResult": { + "description": "The result returned by the server for a {@link CompleteRequestcompletion/complete} request.", + "properties": { + "_meta": { + "$ref": "#/$defs/MetaObject" + }, + "completion": { + "properties": { + "hasMore": { + "description": "Indicates whether there are additional completion options beyond those provided in the current response, even if the exact total is unknown.", + "type": "boolean" + }, + "total": { + "description": "The total number of completion options available. This can exceed the number of values actually sent in the response.", + "type": "integer" + }, + "values": { + "description": "An array of completion values. Must not exceed 100 items.", + "items": { + "type": "string" + }, + "maxItems": 100, + "type": "array" + } + }, + "required": [ + "values" + ], + "type": "object" + }, + "resultType": { + "description": "Indicates the type of the result, which allows the client to determine\nhow to parse the result object.\n\nServers implementing this protocol version MUST include this field.\nFor backward compatibility, when a client receives a result from a\nserver implementing an earlier protocol version (which does not include\n`resultType`), the client MUST treat the absent field as `\"complete\"`.", + "type": "string" + } + }, + "required": [ + "completion", + "resultType" + ], + "type": "object" + }, + "CompleteResultResponse": { + "description": "A successful response from the server for a {@link CompleteRequestcompletion/complete} request.", + "properties": { + "id": { + "$ref": "#/$defs/RequestId" + }, + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "result": { + "$ref": "#/$defs/CompleteResult" + } + }, + "required": [ + "id", + "jsonrpc", + "result" + ], + "type": "object" + }, + "ContentBlock": { + "anyOf": [ + { + "$ref": "#/$defs/TextContent" + }, + { + "$ref": "#/$defs/ImageContent" + }, + { + "$ref": "#/$defs/AudioContent" + }, + { + "$ref": "#/$defs/ResourceLink" + }, + { + "$ref": "#/$defs/EmbeddedResource" + } + ] + }, + "CreateMessageRequest": { + "description": "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.", + "properties": { + "method": { + "const": "sampling/createMessage", + "type": "string" + }, + "params": { + "$ref": "#/$defs/CreateMessageRequestParams" + } + }, + "required": [ + "method", + "params" + ], + "type": "object" + }, + "CreateMessageRequestParams": { + "description": "Parameters for a `sampling/createMessage` request.", + "properties": { + "includeContext": { + "description": "A request to include context from one or more MCP servers (including the caller), to be attached to the prompt.\nThe client MAY ignore this request.\n\nDefault is `\"none\"`. The values `\"thisServer\"` and `\"allServers\"` are deprecated (SEP-2596): servers SHOULD\nomit this field or use `\"none\"`, and SHOULD only use the deprecated values if the client declares\n{@link ClientCapabilities.sampling.context}.", + "enum": [ + "allServers", + "none", + "thisServer" + ], + "type": "string" + }, + "maxTokens": { + "description": "The requested maximum number of tokens to sample (to prevent runaway completions).\n\nThe client MAY choose to sample fewer tokens than the requested maximum.", + "type": "integer" + }, + "messages": { + "items": { + "$ref": "#/$defs/SamplingMessage" + }, + "type": "array" + }, + "metadata": { + "$ref": "#/$defs/JSONObject", + "description": "Optional metadata to pass through to the LLM provider. The format of this metadata is provider-specific." + }, + "modelPreferences": { + "$ref": "#/$defs/ModelPreferences", + "description": "The server's preferences for which model to select. The client MAY ignore these preferences." + }, + "stopSequences": { + "items": { + "type": "string" + }, + "type": "array" + }, + "systemPrompt": { + "description": "An optional system prompt the server wants to use for sampling. The client MAY modify or omit this prompt.", + "type": "string" + }, + "temperature": { + "type": "number" + }, + "toolChoice": { + "$ref": "#/$defs/ToolChoice", + "description": "Controls how the model uses tools.\nThe client MUST return an error if this field is provided but {@link ClientCapabilities.sampling.tools} is not declared.\nDefault is `{ mode: \"auto\" }`." + }, + "tools": { + "description": "Tools that the model may use during generation.\nThe client MUST return an error if this field is provided but {@link ClientCapabilities.sampling.tools} is not declared.", + "items": { + "$ref": "#/$defs/Tool" + }, + "type": "array" + } + }, + "required": [ + "maxTokens", + "messages" + ], + "type": "object" + }, + "CreateMessageResult": { + "description": "The result returned by the client for a {@link CreateMessageRequestsampling/createMessage} request.\nThe client should inform the user before returning the sampled message, to allow them\nto inspect the response (human in the loop) and decide whether to allow the server to see it.", + "properties": { + "_meta": { + "$ref": "#/$defs/MetaObject" + }, + "content": { + "anyOf": [ + { + "$ref": "#/$defs/TextContent" + }, + { + "$ref": "#/$defs/ImageContent" + }, + { + "$ref": "#/$defs/AudioContent" + }, + { + "$ref": "#/$defs/ToolUseContent" + }, + { + "$ref": "#/$defs/ToolResultContent" + }, + { + "items": { + "$ref": "#/$defs/SamplingMessageContentBlock" + }, + "type": "array" + } + ] + }, + "model": { + "description": "The name of the model that generated the message.", + "type": "string" + }, + "role": { + "$ref": "#/$defs/Role" + }, + "stopReason": { + "description": "The reason why sampling stopped, if known.\n\nStandard values:\n- `\"endTurn\"`: Natural end of the assistant's turn\n- `\"stopSequence\"`: A stop sequence was encountered\n- `\"maxTokens\"`: Maximum token limit was reached\n- `\"toolUse\"`: The model wants to use one or more tools\n\nThis field is an open string to allow for provider-specific stop reasons.", + "type": "string" + } + }, + "required": [ + "content", + "model", + "role" + ], + "type": "object" + }, + "Cursor": { + "description": "An opaque token used to represent a cursor for pagination.", + "type": "string" + }, + "DiscoverRequest": { + "description": "A request from the client asking the server to advertise its supported\nprotocol versions, capabilities, and other metadata. Servers **MUST**\nimplement `server/discover`. Clients **MAY** call it but are not required\nto — version negotiation can also happen inline via per-request `_meta`.", + "properties": { + "id": { + "$ref": "#/$defs/RequestId" + }, + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "method": { + "const": "server/discover", + "type": "string" + }, + "params": { + "$ref": "#/$defs/RequestParams" + } + }, + "required": [ + "id", + "jsonrpc", + "method", + "params" + ], + "type": "object" + }, + "DiscoverResult": { + "description": "The result returned by the server for a {@link DiscoverRequestserver/discover} request.", + "properties": { + "_meta": { + "$ref": "#/$defs/MetaObject" + }, + "cacheScope": { + "description": "Indicates the intended scope of the cached response, analogous to HTTP\n`Cache-Control: public` vs `Cache-Control: private`.\n\n- `\"public\"`: Any client or intermediary (e.g., shared gateway, proxy)\n MAY cache the response and serve it to any user.\n- `\"private\"`: Only the requesting user's client MAY cache the response.\n Shared caches (e.g., multi-tenant gateways) MUST NOT serve a cached\n copy to a different user.", + "enum": [ + "private", + "public" + ], + "type": "string" + }, + "capabilities": { + "$ref": "#/$defs/ServerCapabilities", + "description": "The capabilities of the server." + }, + "instructions": { + "description": "Natural-language guidance describing the server and its features.\n\nThis can be used by clients to improve an LLM's understanding of\navailable tools (e.g., by including it in a system prompt). It should\nfocus on information that helps the model use the server effectively\nand should not duplicate information already in tool descriptions.", + "type": "string" + }, + "resultType": { + "description": "Indicates the type of the result, which allows the client to determine\nhow to parse the result object.\n\nServers implementing this protocol version MUST include this field.\nFor backward compatibility, when a client receives a result from a\nserver implementing an earlier protocol version (which does not include\n`resultType`), the client MUST treat the absent field as `\"complete\"`.", + "type": "string" + }, + "serverInfo": { + "$ref": "#/$defs/Implementation", + "description": "Information about the server software implementation." + }, + "supportedVersions": { + "description": "MCP Protocol Versions this server supports. The client should choose a\nversion from this list for use in subsequent requests.", + "items": { + "type": "string" + }, + "type": "array" + }, + "ttlMs": { + "description": "A hint from the server indicating how long (in milliseconds) the\nclient MAY cache this response before re-fetching. Semantics are\nanalogous to HTTP Cache-Control max-age.\n\n- If 0, The response SHOULD be considered immediately stale,\n The client MAY re-fetch every time the result is needed.\n- If positive, the client SHOULD consider the result fresh for this many\n milliseconds after receiving the response.", + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "cacheScope", + "capabilities", + "resultType", + "serverInfo", + "supportedVersions", + "ttlMs" + ], + "type": "object" + }, + "DiscoverResultResponse": { + "description": "A successful response from the server for a {@link DiscoverRequestserver/discover} request.", + "properties": { + "id": { + "$ref": "#/$defs/RequestId" + }, + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "result": { + "$ref": "#/$defs/DiscoverResult" + } + }, + "required": [ + "id", + "jsonrpc", + "result" + ], + "type": "object" + }, + "ElicitRequest": { + "description": "A request from the server to elicit additional information from the user via the client.", + "properties": { + "method": { + "const": "elicitation/create", + "type": "string" + }, + "params": { + "$ref": "#/$defs/ElicitRequestParams" + } + }, + "required": [ + "method", + "params" + ], + "type": "object" + }, + "ElicitRequestFormParams": { + "description": "The parameters for a request to elicit non-sensitive information from the user via a form in the client.", + "properties": { + "message": { + "description": "The message to present to the user describing what information is being requested.", + "type": "string" + }, + "mode": { + "const": "form", + "description": "The elicitation mode.", + "type": "string" + }, + "requestedSchema": { + "description": "A restricted subset of JSON Schema.\nOnly top-level properties are allowed, without nesting.", + "properties": { + "$schema": { + "type": "string" + }, + "properties": { + "additionalProperties": { + "$ref": "#/$defs/PrimitiveSchemaDefinition" + }, + "type": "object" + }, + "required": { + "items": { + "type": "string" + }, + "type": "array" + }, + "type": { + "const": "object", + "type": "string" + } + }, + "required": [ + "properties", + "type" + ], + "type": "object" + } + }, + "required": [ + "message", + "requestedSchema" + ], + "type": "object" + }, + "ElicitRequestParams": { + "anyOf": [ + { + "$ref": "#/$defs/ElicitRequestFormParams" + }, + { + "$ref": "#/$defs/ElicitRequestURLParams" + } + ], + "description": "The parameters for a request to elicit additional information from the user via the client." + }, + "ElicitRequestURLParams": { + "description": "The parameters for a request to elicit information from the user via a URL in the client.", + "properties": { + "elicitationId": { + "description": "The ID of the elicitation, which must be unique within the context of the server.\nThe client MUST treat this ID as an opaque value.", + "type": "string" + }, + "message": { + "description": "The message to present to the user explaining why the interaction is needed.", + "type": "string" + }, + "mode": { + "const": "url", + "description": "The elicitation mode.", + "type": "string" + }, + "url": { + "description": "The URL that the user should navigate to.", + "format": "uri", + "type": "string" + } + }, + "required": [ + "elicitationId", + "message", + "mode", + "url" + ], + "type": "object" + }, + "ElicitResult": { + "description": "The result returned by the client for an {@link ElicitRequestelicitation/create} request.", + "properties": { + "action": { + "description": "The user action in response to the elicitation.\n- `\"accept\"`: User submitted the form/confirmed the action\n- `\"decline\"`: User explicitly declined the action\n- `\"cancel\"`: User dismissed without making an explicit choice", + "enum": [ + "accept", + "cancel", + "decline" + ], + "type": "string" + }, + "content": { + "additionalProperties": { + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": [ + "string", + "integer", + "boolean" + ] + } + ] + }, + "description": "The submitted form data, only present when action is `\"accept\"` and mode was `\"form\"`.\nContains values matching the requested schema.\nOmitted for out-of-band mode responses.", + "type": "object" + } + }, + "required": [ + "action" + ], + "type": "object" + }, + "ElicitationCompleteNotification": { + "description": "An optional notification from the server to the client, informing it of a completion of a out-of-band elicitation request.", + "properties": { + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "method": { + "const": "notifications/elicitation/complete", + "type": "string" + }, + "params": { + "properties": { + "elicitationId": { + "description": "The ID of the elicitation that completed.", + "type": "string" + } + }, + "required": [ + "elicitationId" + ], + "type": "object" + } + }, + "required": [ + "jsonrpc", + "method", + "params" + ], + "type": "object" + }, + "EmbeddedResource": { + "description": "The contents of a resource, embedded into a prompt or tool call result.\n\nIt is up to the client how best to render embedded resources for the benefit\nof the LLM and/or the user.", + "properties": { + "_meta": { + "$ref": "#/$defs/MetaObject" + }, + "annotations": { + "$ref": "#/$defs/Annotations", + "description": "Optional annotations for the client." + }, + "resource": { + "anyOf": [ + { + "$ref": "#/$defs/TextResourceContents" + }, + { + "$ref": "#/$defs/BlobResourceContents" + } + ] + }, + "type": { + "const": "resource", + "type": "string" + } + }, + "required": [ + "resource", + "type" + ], + "type": "object" + }, + "EmptyResult": { + "$ref": "#/$defs/Result", + "description": "Common result fields." + }, + "EnumSchema": { + "anyOf": [ + { + "$ref": "#/$defs/UntitledSingleSelectEnumSchema" + }, + { + "$ref": "#/$defs/TitledSingleSelectEnumSchema" + }, + { + "$ref": "#/$defs/UntitledMultiSelectEnumSchema" + }, + { + "$ref": "#/$defs/TitledMultiSelectEnumSchema" + }, + { + "$ref": "#/$defs/LegacyTitledEnumSchema" + } + ] + }, + "Error": { + "properties": { + "code": { + "description": "The error type that occurred.", + "type": "integer" + }, + "data": { + "description": "Additional information about the error. The value of this member is defined by the sender (e.g. detailed error information, nested errors etc.)." + }, + "message": { + "description": "A short description of the error. The message SHOULD be limited to a concise single sentence.", + "type": "string" + } + }, + "required": [ + "code", + "message" + ], + "type": "object" + }, + "GetPromptRequest": { + "description": "Used by the client to get a prompt provided by the server.", + "properties": { + "id": { + "$ref": "#/$defs/RequestId" + }, + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "method": { + "const": "prompts/get", + "type": "string" + }, + "params": { + "$ref": "#/$defs/GetPromptRequestParams" + } + }, + "required": [ + "id", + "jsonrpc", + "method", + "params" + ], + "type": "object" + }, + "GetPromptRequestParams": { + "description": "Parameters for a `prompts/get` request.", + "properties": { + "_meta": { + "$ref": "#/$defs/RequestMetaObject" + }, + "arguments": { + "additionalProperties": { + "type": "string" + }, + "description": "Arguments to use for templating the prompt.", + "type": "object" + }, + "inputResponses": { + "$ref": "#/$defs/InputResponses" + }, + "name": { + "description": "The name of the prompt or prompt template.", + "type": "string" + }, + "requestState": { + "type": "string" + } + }, + "required": [ + "_meta", + "name" + ], + "type": "object" + }, + "GetPromptResult": { + "description": "The result returned by the server for a {@link GetPromptRequestprompts/get} request.", + "properties": { + "_meta": { + "$ref": "#/$defs/MetaObject" + }, + "description": { + "description": "An optional description for the prompt.", + "type": "string" + }, + "messages": { + "items": { + "$ref": "#/$defs/PromptMessage" + }, + "type": "array" + }, + "resultType": { + "description": "Indicates the type of the result, which allows the client to determine\nhow to parse the result object.\n\nServers implementing this protocol version MUST include this field.\nFor backward compatibility, when a client receives a result from a\nserver implementing an earlier protocol version (which does not include\n`resultType`), the client MUST treat the absent field as `\"complete\"`.", + "type": "string" + } + }, + "required": [ + "messages", + "resultType" + ], + "type": "object" + }, + "GetPromptResultResponse": { + "description": "A successful response from the server for a {@link GetPromptRequestprompts/get} request.", + "properties": { + "id": { + "$ref": "#/$defs/RequestId" + }, + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "result": { + "anyOf": [ + { + "$ref": "#/$defs/InputRequiredResult" + }, + { + "$ref": "#/$defs/GetPromptResult" + } + ] + } + }, + "required": [ + "id", + "jsonrpc", + "result" + ], + "type": "object" + }, + "Icon": { + "description": "An optionally-sized icon that can be displayed in a user interface.", + "properties": { + "mimeType": { + "description": "Optional MIME type override if the source MIME type is missing or generic.\nFor example: `\"image/png\"`, `\"image/jpeg\"`, or `\"image/svg+xml\"`.", + "type": "string" + }, + "sizes": { + "description": "Optional array of strings that specify sizes at which the icon can be used.\nEach string should be in WxH format (e.g., `\"48x48\"`, `\"96x96\"`) or `\"any\"` for scalable formats like SVG.\n\nIf not provided, the client should assume that the icon can be used at any size.", + "items": { + "type": "string" + }, + "type": "array" + }, + "src": { + "description": "A standard URI pointing to an icon resource. May be an HTTP/HTTPS URL or a\n`data:` URI with Base64-encoded image data.\n\nConsumers SHOULD take steps to ensure URLs serving icons are from the\nsame domain as the client/server or a trusted domain.\n\nConsumers SHOULD take appropriate precautions when consuming SVGs as they can contain\nexecutable JavaScript.", + "format": "uri", + "type": "string" + }, + "theme": { + "description": "Optional specifier for the theme this icon is designed for. `\"light\"` indicates\nthe icon is designed to be used with a light background, and `\"dark\"` indicates\nthe icon is designed to be used with a dark background.\n\nIf not provided, the client should assume the icon can be used with any theme.", + "enum": [ + "dark", + "light" + ], + "type": "string" + } + }, + "required": [ + "src" + ], + "type": "object" + }, + "Icons": { + "description": "Base interface to add `icons` property.", + "properties": { + "icons": { + "description": "Optional set of sized icons that the client can display in a user interface.\n\nClients that support rendering icons MUST support at least the following MIME types:\n- `image/png` - PNG images (safe, universal compatibility)\n- `image/jpeg` (and `image/jpg`) - JPEG images (safe, universal compatibility)\n\nClients that support rendering icons SHOULD also support:\n- `image/svg+xml` - SVG images (scalable but requires security precautions)\n- `image/webp` - WebP images (modern, efficient format)", + "items": { + "$ref": "#/$defs/Icon" + }, + "type": "array" + } + }, + "type": "object" + }, + "ImageContent": { + "description": "An image provided to or from an LLM.", + "properties": { + "_meta": { + "$ref": "#/$defs/MetaObject" + }, + "annotations": { + "$ref": "#/$defs/Annotations", + "description": "Optional annotations for the client." + }, + "data": { + "description": "The base64-encoded image data.", + "format": "byte", + "type": "string" + }, + "mimeType": { + "description": "The MIME type of the image. Different providers may support different image types.", + "type": "string" + }, + "type": { + "const": "image", + "type": "string" + } + }, + "required": [ + "data", + "mimeType", + "type" + ], + "type": "object" + }, + "Implementation": { + "description": "Describes the MCP implementation.", + "properties": { + "description": { + "description": "An optional human-readable description of what this implementation does.\n\nThis can be used by clients or servers to provide context about their purpose\nand capabilities. For example, a server might describe the types of resources\nor tools it provides, while a client might describe its intended use case.", + "type": "string" + }, + "icons": { + "description": "Optional set of sized icons that the client can display in a user interface.\n\nClients that support rendering icons MUST support at least the following MIME types:\n- `image/png` - PNG images (safe, universal compatibility)\n- `image/jpeg` (and `image/jpg`) - JPEG images (safe, universal compatibility)\n\nClients that support rendering icons SHOULD also support:\n- `image/svg+xml` - SVG images (scalable but requires security precautions)\n- `image/webp` - WebP images (modern, efficient format)", + "items": { + "$ref": "#/$defs/Icon" + }, + "type": "array" + }, + "name": { + "description": "Intended for programmatic or logical use, but used as a display name in past specs or fallback (if title isn't present).", + "type": "string" + }, + "title": { + "description": "Intended for UI and end-user contexts — optimized to be human-readable and easily understood,\neven by those unfamiliar with domain-specific terminology.\n\nIf not provided, the name should be used for display (except for {@link Tool},\nwhere `annotations.title` should be given precedence over using `name`,\nif present).", + "type": "string" + }, + "version": { + "description": "The version of this implementation.", + "type": "string" + }, + "websiteUrl": { + "description": "An optional URL of the website for this implementation.", + "format": "uri", + "type": "string" + } + }, + "required": [ + "name", + "version" + ], + "type": "object" + }, + "InputRequest": { + "anyOf": [ + { + "$ref": "#/$defs/CreateMessageRequest" + }, + { + "$ref": "#/$defs/ListRootsRequest" + }, + { + "$ref": "#/$defs/ElicitRequest" + } + ] + }, + "InputRequests": { + "additionalProperties": { + "$ref": "#/$defs/InputRequest" + }, + "description": "A map of server-initiated requests that the client must fulfill.\nKeys are server-assigned identifiers; values are the request objects.", + "type": "object" + }, + "InputRequiredResult": { + "description": "An InputRequiredResult sent by the server to indicate that additional input is needed\nbefore the request can be completed.\n\nAt least one of `inputRequests` or `requestState` MUST be present.", + "properties": { + "_meta": { + "$ref": "#/$defs/MetaObject" + }, + "inputRequests": { + "$ref": "#/$defs/InputRequests" + }, + "requestState": { + "type": "string" + }, + "resultType": { + "description": "Indicates the type of the result, which allows the client to determine\nhow to parse the result object.\n\nServers implementing this protocol version MUST include this field.\nFor backward compatibility, when a client receives a result from a\nserver implementing an earlier protocol version (which does not include\n`resultType`), the client MUST treat the absent field as `\"complete\"`.", + "type": "string" + } + }, + "required": [ + "resultType" + ], + "type": "object" + }, + "InputResponse": { + "anyOf": [ + { + "$ref": "#/$defs/CreateMessageResult" + }, + { + "$ref": "#/$defs/ListRootsResult" + }, + { + "$ref": "#/$defs/ElicitResult" + } + ] + }, + "InputResponseRequestParams": { + "properties": { + "_meta": { + "$ref": "#/$defs/RequestMetaObject" + }, + "inputResponses": { + "$ref": "#/$defs/InputResponses" + }, + "requestState": { + "type": "string" + } + }, + "required": [ + "_meta" + ], + "type": "object" + }, + "InputResponses": { + "additionalProperties": { + "$ref": "#/$defs/InputResponse" + }, + "description": "A map of client responses to server-initiated requests.\nKeys correspond to the keys in the {@link InputRequests} map;\nvalues are the client's result for each request.", + "type": "object" + }, + "InternalError": { + "description": "A JSON-RPC error indicating that an internal error occurred on the receiver. This error is returned when the receiver encounters an unexpected condition that prevents it from fulfilling the request.", + "properties": { + "code": { + "const": -32603, + "description": "The error type that occurred.", + "type": "integer" + }, + "data": { + "description": "Additional information about the error. The value of this member is defined by the sender (e.g. detailed error information, nested errors etc.)." + }, + "message": { + "description": "A short description of the error. The message SHOULD be limited to a concise single sentence.", + "type": "string" + } + }, + "required": [ + "code", + "message" + ], + "type": "object" + }, + "InvalidParamsError": { + "description": "A JSON-RPC error indicating that the method parameters are invalid or malformed.\n\nIn MCP, this error is returned in various contexts when request parameters fail validation:\n\n- **Tools**: Unknown tool name or invalid tool arguments\n- **Prompts**: Unknown prompt name or missing required arguments\n- **Pagination**: Invalid or expired cursor values\n- **Logging**: Invalid log level\n- **Elicitation**: Server requests an elicitation mode not declared in client capabilities\n- **Sampling**: Missing tool result or tool results mixed with other content", + "properties": { + "code": { + "const": -32602, + "description": "The error type that occurred.", + "type": "integer" + }, + "data": { + "description": "Additional information about the error. The value of this member is defined by the sender (e.g. detailed error information, nested errors etc.)." + }, + "message": { + "description": "A short description of the error. The message SHOULD be limited to a concise single sentence.", + "type": "string" + } + }, + "required": [ + "code", + "message" + ], + "type": "object" + }, + "InvalidRequestError": { + "description": "A JSON-RPC error indicating that the request is not a valid request object. This error is returned when the message structure does not conform to the JSON-RPC 2.0 specification requirements for a request (e.g., missing required fields like `jsonrpc` or `method`, or using invalid types for these fields).", + "properties": { + "code": { + "const": -32600, + "description": "The error type that occurred.", + "type": "integer" + }, + "data": { + "description": "Additional information about the error. The value of this member is defined by the sender (e.g. detailed error information, nested errors etc.)." + }, + "message": { + "description": "A short description of the error. The message SHOULD be limited to a concise single sentence.", + "type": "string" + } + }, + "required": [ + "code", + "message" + ], + "type": "object" + }, + "JSONArray": { + "items": { + "$ref": "#/$defs/JSONValue" + }, + "type": "array" + }, + "JSONObject": { + "additionalProperties": { + "$ref": "#/$defs/JSONValue" + }, + "type": "object" + }, + "JSONRPCErrorResponse": { + "description": "A response to a request that indicates an error occurred.", + "properties": { + "error": { + "$ref": "#/$defs/Error" + }, + "id": { + "$ref": "#/$defs/RequestId" + }, + "jsonrpc": { + "const": "2.0", + "type": "string" + } + }, + "required": [ + "error", + "jsonrpc" + ], + "type": "object" + }, + "JSONRPCMessage": { + "anyOf": [ + { + "$ref": "#/$defs/JSONRPCRequest" + }, + { + "$ref": "#/$defs/JSONRPCNotification" + }, + { + "$ref": "#/$defs/JSONRPCResultResponse" + }, + { + "$ref": "#/$defs/JSONRPCErrorResponse" + } + ], + "description": "Refers to any valid JSON-RPC object that can be decoded off the wire, or encoded to be sent." + }, + "JSONRPCNotification": { + "description": "A notification which does not expect a response.", + "properties": { + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "method": { + "type": "string" + }, + "params": { + "additionalProperties": {}, + "type": "object" + } + }, + "required": [ + "jsonrpc", + "method" + ], + "type": "object" + }, + "JSONRPCRequest": { + "description": "A request that expects a response.", + "properties": { + "id": { + "$ref": "#/$defs/RequestId" + }, + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "method": { + "type": "string" + }, + "params": { + "additionalProperties": {}, + "type": "object" + } + }, + "required": [ + "id", + "jsonrpc", + "method" + ], + "type": "object" + }, + "JSONRPCResponse": { + "anyOf": [ + { + "$ref": "#/$defs/JSONRPCResultResponse" + }, + { + "$ref": "#/$defs/JSONRPCErrorResponse" + } + ], + "description": "A response to a request, containing either the result or error." + }, + "JSONRPCResultResponse": { + "description": "A successful (non-error) response to a request.", + "properties": { + "id": { + "$ref": "#/$defs/RequestId" + }, + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "result": { + "$ref": "#/$defs/Result" + } + }, + "required": [ + "id", + "jsonrpc", + "result" + ], + "type": "object" + }, + "JSONValue": { + "anyOf": [ + { + "$ref": "#/$defs/JSONObject" + }, + { + "items": { + "$ref": "#/$defs/JSONValue" + }, + "type": "array" + }, + { + "type": [ + "string", + "integer", + "boolean" + ] + } + ] + }, + "LegacyTitledEnumSchema": { + "description": "Use {@link TitledSingleSelectEnumSchema} instead.\nThis interface will be removed in a future version.", + "properties": { + "default": { + "type": "string" + }, + "description": { + "type": "string" + }, + "enum": { + "items": { + "type": "string" + }, + "type": "array" + }, + "enumNames": { + "description": "(Legacy) Display names for enum values.\nNon-standard according to JSON schema 2020-12.", + "items": { + "type": "string" + }, + "type": "array" + }, + "title": { + "type": "string" + }, + "type": { + "const": "string", + "type": "string" + } + }, + "required": [ + "enum", + "type" + ], + "type": "object" + }, + "ListPromptsRequest": { + "description": "Sent from the client to request a list of prompts and prompt templates the server has.", + "properties": { + "id": { + "$ref": "#/$defs/RequestId" + }, + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "method": { + "const": "prompts/list", + "type": "string" + }, + "params": { + "$ref": "#/$defs/PaginatedRequestParams" + } + }, + "required": [ + "id", + "jsonrpc", + "method", + "params" + ], + "type": "object" + }, + "ListPromptsResult": { + "description": "The result returned by the server for a {@link ListPromptsRequestprompts/list} request.", + "properties": { + "_meta": { + "$ref": "#/$defs/MetaObject" + }, + "cacheScope": { + "description": "Indicates the intended scope of the cached response, analogous to HTTP\n`Cache-Control: public` vs `Cache-Control: private`.\n\n- `\"public\"`: Any client or intermediary (e.g., shared gateway, proxy)\n MAY cache the response and serve it to any user.\n- `\"private\"`: Only the requesting user's client MAY cache the response.\n Shared caches (e.g., multi-tenant gateways) MUST NOT serve a cached\n copy to a different user.", + "enum": [ + "private", + "public" + ], + "type": "string" + }, + "nextCursor": { + "description": "An opaque token representing the pagination position after the last returned result.\nIf present, there may be more results available.", + "type": "string" + }, + "prompts": { + "items": { + "$ref": "#/$defs/Prompt" + }, + "type": "array" + }, + "resultType": { + "description": "Indicates the type of the result, which allows the client to determine\nhow to parse the result object.\n\nServers implementing this protocol version MUST include this field.\nFor backward compatibility, when a client receives a result from a\nserver implementing an earlier protocol version (which does not include\n`resultType`), the client MUST treat the absent field as `\"complete\"`.", + "type": "string" + }, + "ttlMs": { + "description": "A hint from the server indicating how long (in milliseconds) the\nclient MAY cache this response before re-fetching. Semantics are\nanalogous to HTTP Cache-Control max-age.\n\n- If 0, The response SHOULD be considered immediately stale,\n The client MAY re-fetch every time the result is needed.\n- If positive, the client SHOULD consider the result fresh for this many\n milliseconds after receiving the response.", + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "cacheScope", + "prompts", + "resultType", + "ttlMs" + ], + "type": "object" + }, + "ListPromptsResultResponse": { + "description": "A successful response from the server for a {@link ListPromptsRequestprompts/list} request.", + "properties": { + "id": { + "$ref": "#/$defs/RequestId" + }, + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "result": { + "$ref": "#/$defs/ListPromptsResult" + } + }, + "required": [ + "id", + "jsonrpc", + "result" + ], + "type": "object" + }, + "ListResourceTemplatesRequest": { + "description": "Sent from the client to request a list of resource templates the server has.", + "properties": { + "id": { + "$ref": "#/$defs/RequestId" + }, + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "method": { + "const": "resources/templates/list", + "type": "string" + }, + "params": { + "$ref": "#/$defs/PaginatedRequestParams" + } + }, + "required": [ + "id", + "jsonrpc", + "method", + "params" + ], + "type": "object" + }, + "ListResourceTemplatesResult": { + "description": "The result returned by the server for a {@link ListResourceTemplatesRequestresources/templates/list} request.", + "properties": { + "_meta": { + "$ref": "#/$defs/MetaObject" + }, + "cacheScope": { + "description": "Indicates the intended scope of the cached response, analogous to HTTP\n`Cache-Control: public` vs `Cache-Control: private`.\n\n- `\"public\"`: Any client or intermediary (e.g., shared gateway, proxy)\n MAY cache the response and serve it to any user.\n- `\"private\"`: Only the requesting user's client MAY cache the response.\n Shared caches (e.g., multi-tenant gateways) MUST NOT serve a cached\n copy to a different user.", + "enum": [ + "private", + "public" + ], + "type": "string" + }, + "nextCursor": { + "description": "An opaque token representing the pagination position after the last returned result.\nIf present, there may be more results available.", + "type": "string" + }, + "resourceTemplates": { + "items": { + "$ref": "#/$defs/ResourceTemplate" + }, + "type": "array" + }, + "resultType": { + "description": "Indicates the type of the result, which allows the client to determine\nhow to parse the result object.\n\nServers implementing this protocol version MUST include this field.\nFor backward compatibility, when a client receives a result from a\nserver implementing an earlier protocol version (which does not include\n`resultType`), the client MUST treat the absent field as `\"complete\"`.", + "type": "string" + }, + "ttlMs": { + "description": "A hint from the server indicating how long (in milliseconds) the\nclient MAY cache this response before re-fetching. Semantics are\nanalogous to HTTP Cache-Control max-age.\n\n- If 0, The response SHOULD be considered immediately stale,\n The client MAY re-fetch every time the result is needed.\n- If positive, the client SHOULD consider the result fresh for this many\n milliseconds after receiving the response.", + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "cacheScope", + "resourceTemplates", + "resultType", + "ttlMs" + ], + "type": "object" + }, + "ListResourceTemplatesResultResponse": { + "description": "A successful response from the server for a {@link ListResourceTemplatesRequestresources/templates/list} request.", + "properties": { + "id": { + "$ref": "#/$defs/RequestId" + }, + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "result": { + "$ref": "#/$defs/ListResourceTemplatesResult" + } + }, + "required": [ + "id", + "jsonrpc", + "result" + ], + "type": "object" + }, + "ListResourcesRequest": { + "description": "Sent from the client to request a list of resources the server has.", + "properties": { + "id": { + "$ref": "#/$defs/RequestId" + }, + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "method": { + "const": "resources/list", + "type": "string" + }, + "params": { + "$ref": "#/$defs/PaginatedRequestParams" + } + }, + "required": [ + "id", + "jsonrpc", + "method", + "params" + ], + "type": "object" + }, + "ListResourcesResult": { + "description": "The result returned by the server for a {@link ListResourcesRequestresources/list} request.", + "properties": { + "_meta": { + "$ref": "#/$defs/MetaObject" + }, + "cacheScope": { + "description": "Indicates the intended scope of the cached response, analogous to HTTP\n`Cache-Control: public` vs `Cache-Control: private`.\n\n- `\"public\"`: Any client or intermediary (e.g., shared gateway, proxy)\n MAY cache the response and serve it to any user.\n- `\"private\"`: Only the requesting user's client MAY cache the response.\n Shared caches (e.g., multi-tenant gateways) MUST NOT serve a cached\n copy to a different user.", + "enum": [ + "private", + "public" + ], + "type": "string" + }, + "nextCursor": { + "description": "An opaque token representing the pagination position after the last returned result.\nIf present, there may be more results available.", + "type": "string" + }, + "resources": { + "items": { + "$ref": "#/$defs/Resource" + }, + "type": "array" + }, + "resultType": { + "description": "Indicates the type of the result, which allows the client to determine\nhow to parse the result object.\n\nServers implementing this protocol version MUST include this field.\nFor backward compatibility, when a client receives a result from a\nserver implementing an earlier protocol version (which does not include\n`resultType`), the client MUST treat the absent field as `\"complete\"`.", + "type": "string" + }, + "ttlMs": { + "description": "A hint from the server indicating how long (in milliseconds) the\nclient MAY cache this response before re-fetching. Semantics are\nanalogous to HTTP Cache-Control max-age.\n\n- If 0, The response SHOULD be considered immediately stale,\n The client MAY re-fetch every time the result is needed.\n- If positive, the client SHOULD consider the result fresh for this many\n milliseconds after receiving the response.", + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "cacheScope", + "resources", + "resultType", + "ttlMs" + ], + "type": "object" + }, + "ListResourcesResultResponse": { + "description": "A successful response from the server for a {@link ListResourcesRequestresources/list} request.", + "properties": { + "id": { + "$ref": "#/$defs/RequestId" + }, + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "result": { + "$ref": "#/$defs/ListResourcesResult" + } + }, + "required": [ + "id", + "jsonrpc", + "result" + ], + "type": "object" + }, + "ListRootsRequest": { + "description": "Sent from the server to request a list of root URIs from the client. Roots allow\nservers to ask for specific directories or files to operate on. A common example\nfor roots is providing a set of repositories or directories a server should operate\non.\n\nThis request is typically used when the server needs to understand the file system\nstructure or access specific locations that the client has permission to read from.", + "properties": { + "method": { + "const": "roots/list", + "type": "string" + }, + "params": { + "$ref": "#/$defs/RequestParams" + } + }, + "required": [ + "method" + ], + "type": "object" + }, + "ListRootsResult": { + "description": "The result returned by the client for a {@link ListRootsRequestroots/list} request.\nThis result contains an array of {@link Root} objects, each representing a root directory\nor file that the server can operate on.", + "properties": { + "roots": { + "items": { + "$ref": "#/$defs/Root" + }, + "type": "array" + } + }, + "required": [ + "roots" + ], + "type": "object" + }, + "ListToolsRequest": { + "description": "Sent from the client to request a list of tools the server has.", + "properties": { + "id": { + "$ref": "#/$defs/RequestId" + }, + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "method": { + "const": "tools/list", + "type": "string" + }, + "params": { + "$ref": "#/$defs/PaginatedRequestParams" + } + }, + "required": [ + "id", + "jsonrpc", + "method", + "params" + ], + "type": "object" + }, + "ListToolsResult": { + "description": "The result returned by the server for a {@link ListToolsRequesttools/list} request.", + "properties": { + "_meta": { + "$ref": "#/$defs/MetaObject" + }, + "cacheScope": { + "description": "Indicates the intended scope of the cached response, analogous to HTTP\n`Cache-Control: public` vs `Cache-Control: private`.\n\n- `\"public\"`: Any client or intermediary (e.g., shared gateway, proxy)\n MAY cache the response and serve it to any user.\n- `\"private\"`: Only the requesting user's client MAY cache the response.\n Shared caches (e.g., multi-tenant gateways) MUST NOT serve a cached\n copy to a different user.", + "enum": [ + "private", + "public" + ], + "type": "string" + }, + "nextCursor": { + "description": "An opaque token representing the pagination position after the last returned result.\nIf present, there may be more results available.", + "type": "string" + }, + "resultType": { + "description": "Indicates the type of the result, which allows the client to determine\nhow to parse the result object.\n\nServers implementing this protocol version MUST include this field.\nFor backward compatibility, when a client receives a result from a\nserver implementing an earlier protocol version (which does not include\n`resultType`), the client MUST treat the absent field as `\"complete\"`.", + "type": "string" + }, + "tools": { + "items": { + "$ref": "#/$defs/Tool" + }, + "type": "array" + }, + "ttlMs": { + "description": "A hint from the server indicating how long (in milliseconds) the\nclient MAY cache this response before re-fetching. Semantics are\nanalogous to HTTP Cache-Control max-age.\n\n- If 0, The response SHOULD be considered immediately stale,\n The client MAY re-fetch every time the result is needed.\n- If positive, the client SHOULD consider the result fresh for this many\n milliseconds after receiving the response.", + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "cacheScope", + "resultType", + "tools", + "ttlMs" + ], + "type": "object" + }, + "ListToolsResultResponse": { + "description": "A successful response from the server for a {@link ListToolsRequesttools/list} request.", + "properties": { + "id": { + "$ref": "#/$defs/RequestId" + }, + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "result": { + "$ref": "#/$defs/ListToolsResult" + } + }, + "required": [ + "id", + "jsonrpc", + "result" + ], + "type": "object" + }, + "LoggingLevel": { + "description": "The severity of a log message.\n\nThese map to syslog message severities, as specified in RFC-5424:\nhttps://datatracker.ietf.org/doc/html/rfc5424#section-6.2.1", + "enum": [ + "alert", + "critical", + "debug", + "emergency", + "error", + "info", + "notice", + "warning" + ], + "type": "string" + }, + "LoggingMessageNotification": { + "description": "JSONRPCNotification of a log message passed from server to client. The client opts in by setting `\"io.modelcontextprotocol/logLevel\"` in a request's `_meta`.", + "properties": { + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "method": { + "const": "notifications/message", + "type": "string" + }, + "params": { + "$ref": "#/$defs/LoggingMessageNotificationParams" + } + }, + "required": [ + "jsonrpc", + "method", + "params" + ], + "type": "object" + }, + "LoggingMessageNotificationParams": { + "description": "Parameters for a `notifications/message` notification.", + "properties": { + "_meta": { + "$ref": "#/$defs/MetaObject" + }, + "data": { + "description": "The data to be logged, such as a string message or an object. Any JSON serializable type is allowed here." + }, + "level": { + "$ref": "#/$defs/LoggingLevel", + "description": "The severity of this log message." + }, + "logger": { + "description": "An optional name of the logger issuing this message.", + "type": "string" + } + }, + "required": [ + "data", + "level" + ], + "type": "object" + }, + "MetaObject": { + "description": "Represents the contents of a `_meta` field, which clients and servers use to attach additional metadata to their interactions.\n\nCertain key names are reserved by MCP for protocol-level metadata; implementations MUST NOT make assumptions about values at these keys. Additionally, specific schema definitions may reserve particular names for purpose-specific metadata, as declared in those definitions.\n\nValid keys have two segments:\n\n**Prefix:**\n- Optional — if specified, MUST be a series of _labels_ separated by dots (`.`), followed by a slash (`/`).\n- Labels MUST start with a letter and end with a letter or digit. Interior characters may be letters, digits, or hyphens (`-`).\n- Implementations SHOULD use reverse DNS notation (e.g., `com.example/` rather than `example.com/`).\n- Any prefix where the second label is `modelcontextprotocol` or `mcp` is **reserved** for MCP use. For example: `io.modelcontextprotocol/`, `dev.mcp/`, `org.modelcontextprotocol.api/`, and `com.mcp.tools/` are all reserved. However, `com.example.mcp/` is NOT reserved, as the second label is `example`.\n\n**Name:**\n- Unless empty, MUST start and end with an alphanumeric character (`[a-z0-9A-Z]`).\n- Interior characters may be alphanumeric, hyphens (`-`), underscores (`_`), or dots (`.`).", + "type": "object" + }, + "MethodNotFoundError": { + "description": "A JSON-RPC error indicating that the requested method does not exist or is not available.\n\nIn MCP, a server returns this error when a client invokes a method the server does not implement — either a genuinely unknown method, or one gated behind a server capability the server did not advertise (e.g., calling `prompts/list` when the `prompts` capability was not advertised).\n\nA request that requires a client capability the client did not declare is signalled instead by {@link MissingRequiredClientCapabilityError} (`-32003`).", + "properties": { + "code": { + "const": -32601, + "description": "The error type that occurred.", + "type": "integer" + }, + "data": { + "description": "Additional information about the error. The value of this member is defined by the sender (e.g. detailed error information, nested errors etc.)." + }, + "message": { + "description": "A short description of the error. The message SHOULD be limited to a concise single sentence.", + "type": "string" + } + }, + "required": [ + "code", + "message" + ], + "type": "object" + }, + "MissingRequiredClientCapabilityError": { + "description": "Returned when processing a request requires a capability the client did not\ndeclare in `clientCapabilities`. For HTTP, the response status code MUST be\n`400 Bad Request`.", + "properties": { + "error": { + "allOf": [ + { + "$ref": "#/$defs/Error" + }, + { + "properties": { + "code": { + "const": -32003, + "type": "integer" + }, + "data": { + "properties": { + "requiredCapabilities": { + "$ref": "#/$defs/ClientCapabilities", + "description": "The capabilities the server requires from the client to process this request." + } + }, + "required": [ + "requiredCapabilities" + ], + "type": "object" + } + }, + "required": [ + "code", + "data" + ], + "type": "object" + } + ] + }, + "id": { + "$ref": "#/$defs/RequestId" + }, + "jsonrpc": { + "const": "2.0", + "type": "string" + } + }, + "required": [ + "error", + "jsonrpc" + ], + "type": "object" + }, + "ModelHint": { + "description": "Hints to use for model selection.\n\nKeys not declared here are currently left unspecified by the spec and are up\nto the client to interpret.", + "properties": { + "name": { + "description": "A hint for a model name.\n\nThe client SHOULD treat this as a substring of a model name; for example:\n - `claude-3-5-sonnet` should match `claude-3-5-sonnet-20241022`\n - `sonnet` should match `claude-3-5-sonnet-20241022`, `claude-3-sonnet-20240229`, etc.\n - `claude` should match any Claude model\n\nThe client MAY also map the string to a different provider's model name or a different model family, as long as it fills a similar niche; for example:\n - `gemini-1.5-flash` could match `claude-3-haiku-20240307`", + "type": "string" + } + }, + "type": "object" + }, + "ModelPreferences": { + "description": "The server's preferences for model selection, requested of the client during sampling.\n\nBecause LLMs can vary along multiple dimensions, choosing the \"best\" model is\nrarely straightforward. Different models excel in different areas—some are\nfaster but less capable, others are more capable but more expensive, and so\non. This interface allows servers to express their priorities across multiple\ndimensions to help clients make an appropriate selection for their use case.\n\nThese preferences are always advisory. The client MAY ignore them. It is also\nup to the client to decide how to interpret these preferences and how to\nbalance them against other considerations.", + "properties": { + "costPriority": { + "description": "How much to prioritize cost when selecting a model. A value of 0 means cost\nis not important, while a value of 1 means cost is the most important\nfactor.", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "hints": { + "description": "Optional hints to use for model selection.\n\nIf multiple hints are specified, the client MUST evaluate them in order\n(such that the first match is taken).\n\nThe client SHOULD prioritize these hints over the numeric priorities, but\nMAY still use the priorities to select from ambiguous matches.", + "items": { + "$ref": "#/$defs/ModelHint" + }, + "type": "array" + }, + "intelligencePriority": { + "description": "How much to prioritize intelligence and capabilities when selecting a\nmodel. A value of 0 means intelligence is not important, while a value of 1\nmeans intelligence is the most important factor.", + "maximum": 1, + "minimum": 0, + "type": "number" + }, + "speedPriority": { + "description": "How much to prioritize sampling speed (latency) when selecting a model. A\nvalue of 0 means speed is not important, while a value of 1 means speed is\nthe most important factor.", + "maximum": 1, + "minimum": 0, + "type": "number" + } + }, + "type": "object" + }, + "MultiSelectEnumSchema": { + "anyOf": [ + { + "$ref": "#/$defs/UntitledMultiSelectEnumSchema" + }, + { + "$ref": "#/$defs/TitledMultiSelectEnumSchema" + } + ] + }, + "Notification": { + "properties": { + "method": { + "type": "string" + }, + "params": { + "additionalProperties": {}, + "type": "object" + } + }, + "required": [ + "method" + ], + "type": "object" + }, + "NotificationParams": { + "description": "Common params for any notification.", + "properties": { + "_meta": { + "$ref": "#/$defs/MetaObject" + } + }, + "type": "object" + }, + "NumberSchema": { + "properties": { + "default": { + "type": "number" + }, + "description": { + "type": "string" + }, + "maximum": { + "type": "number" + }, + "minimum": { + "type": "number" + }, + "title": { + "type": "string" + }, + "type": { + "enum": [ + "integer", + "number" + ], + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + }, + "PaginatedRequest": { + "properties": { + "id": { + "$ref": "#/$defs/RequestId" + }, + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "method": { + "type": "string" + }, + "params": { + "$ref": "#/$defs/PaginatedRequestParams" + } + }, + "required": [ + "id", + "jsonrpc", + "method", + "params" + ], + "type": "object" + }, + "PaginatedRequestParams": { + "description": "Common params for paginated requests.", + "properties": { + "_meta": { + "$ref": "#/$defs/RequestMetaObject" + }, + "cursor": { + "description": "An opaque token representing the current pagination position.\nIf provided, the server should return results starting after this cursor.", + "type": "string" + } + }, + "required": [ + "_meta" + ], + "type": "object" + }, + "PaginatedResult": { + "properties": { + "_meta": { + "$ref": "#/$defs/MetaObject" + }, + "nextCursor": { + "description": "An opaque token representing the pagination position after the last returned result.\nIf present, there may be more results available.", + "type": "string" + }, + "resultType": { + "description": "Indicates the type of the result, which allows the client to determine\nhow to parse the result object.\n\nServers implementing this protocol version MUST include this field.\nFor backward compatibility, when a client receives a result from a\nserver implementing an earlier protocol version (which does not include\n`resultType`), the client MUST treat the absent field as `\"complete\"`.", + "type": "string" + } + }, + "required": [ + "resultType" + ], + "type": "object" + }, + "ParseError": { + "description": "A JSON-RPC error indicating that invalid JSON was received by the server. This error is returned when the server cannot parse the JSON text of a message.", + "properties": { + "code": { + "const": -32700, + "description": "The error type that occurred.", + "type": "integer" + }, + "data": { + "description": "Additional information about the error. The value of this member is defined by the sender (e.g. detailed error information, nested errors etc.)." + }, + "message": { + "description": "A short description of the error. The message SHOULD be limited to a concise single sentence.", + "type": "string" + } + }, + "required": [ + "code", + "message" + ], + "type": "object" + }, + "PrimitiveSchemaDefinition": { + "anyOf": [ + { + "$ref": "#/$defs/StringSchema" + }, + { + "$ref": "#/$defs/NumberSchema" + }, + { + "$ref": "#/$defs/BooleanSchema" + }, + { + "$ref": "#/$defs/UntitledSingleSelectEnumSchema" + }, + { + "$ref": "#/$defs/TitledSingleSelectEnumSchema" + }, + { + "$ref": "#/$defs/UntitledMultiSelectEnumSchema" + }, + { + "$ref": "#/$defs/TitledMultiSelectEnumSchema" + }, + { + "$ref": "#/$defs/LegacyTitledEnumSchema" + } + ], + "description": "Restricted schema definitions that only allow primitive types\nwithout nested objects or arrays." + }, + "ProgressNotification": { + "description": "An out-of-band notification used to inform the receiver of a progress update for a long-running request.", + "properties": { + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "method": { + "const": "notifications/progress", + "type": "string" + }, + "params": { + "$ref": "#/$defs/ProgressNotificationParams" + } + }, + "required": [ + "jsonrpc", + "method", + "params" + ], + "type": "object" + }, + "ProgressNotificationParams": { + "description": "Parameters for a {@link ProgressNotificationnotifications/progress} notification.", + "properties": { + "_meta": { + "$ref": "#/$defs/MetaObject" + }, + "message": { + "description": "An optional message describing the current progress.", + "type": "string" + }, + "progress": { + "description": "The progress thus far. This should increase every time progress is made, even if the total is unknown.", + "type": "number" + }, + "progressToken": { + "$ref": "#/$defs/ProgressToken", + "description": "The progress token which was given in the initial request, used to associate this notification with the request that is proceeding." + }, + "total": { + "description": "Total number of items to process (or total progress required), if known.", + "type": "number" + } + }, + "required": [ + "progress", + "progressToken" + ], + "type": "object" + }, + "ProgressToken": { + "description": "A progress token, used to associate progress notifications with the original request.", + "type": [ + "string", + "integer" + ] + }, + "Prompt": { + "description": "A prompt or prompt template that the server offers.", + "properties": { + "_meta": { + "$ref": "#/$defs/MetaObject" + }, + "arguments": { + "description": "A list of arguments to use for templating the prompt.", + "items": { + "$ref": "#/$defs/PromptArgument" + }, + "type": "array" + }, + "description": { + "description": "An optional description of what this prompt provides", + "type": "string" + }, + "icons": { + "description": "Optional set of sized icons that the client can display in a user interface.\n\nClients that support rendering icons MUST support at least the following MIME types:\n- `image/png` - PNG images (safe, universal compatibility)\n- `image/jpeg` (and `image/jpg`) - JPEG images (safe, universal compatibility)\n\nClients that support rendering icons SHOULD also support:\n- `image/svg+xml` - SVG images (scalable but requires security precautions)\n- `image/webp` - WebP images (modern, efficient format)", + "items": { + "$ref": "#/$defs/Icon" + }, + "type": "array" + }, + "name": { + "description": "Intended for programmatic or logical use, but used as a display name in past specs or fallback (if title isn't present).", + "type": "string" + }, + "title": { + "description": "Intended for UI and end-user contexts — optimized to be human-readable and easily understood,\neven by those unfamiliar with domain-specific terminology.\n\nIf not provided, the name should be used for display (except for {@link Tool},\nwhere `annotations.title` should be given precedence over using `name`,\nif present).", + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "PromptArgument": { + "description": "Describes an argument that a prompt can accept.", + "properties": { + "description": { + "description": "A human-readable description of the argument.", + "type": "string" + }, + "name": { + "description": "Intended for programmatic or logical use, but used as a display name in past specs or fallback (if title isn't present).", + "type": "string" + }, + "required": { + "description": "Whether this argument must be provided.", + "type": "boolean" + }, + "title": { + "description": "Intended for UI and end-user contexts — optimized to be human-readable and easily understood,\neven by those unfamiliar with domain-specific terminology.\n\nIf not provided, the name should be used for display (except for {@link Tool},\nwhere `annotations.title` should be given precedence over using `name`,\nif present).", + "type": "string" + } + }, + "required": [ + "name" + ], + "type": "object" + }, + "PromptListChangedNotification": { + "description": "An optional notification from the server to the client, informing it that the list of prompts it offers has changed. This may be issued by servers without any previous subscription from the client.", + "properties": { + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "method": { + "const": "notifications/prompts/list_changed", + "type": "string" + }, + "params": { + "$ref": "#/$defs/NotificationParams" + } + }, + "required": [ + "jsonrpc", + "method" + ], + "type": "object" + }, + "PromptMessage": { + "description": "Describes a message returned as part of a prompt.\n\nThis is similar to {@link SamplingMessage}, but also supports the embedding of\nresources from the MCP server.", + "properties": { + "content": { + "$ref": "#/$defs/ContentBlock" + }, + "role": { + "$ref": "#/$defs/Role" + } + }, + "required": [ + "content", + "role" + ], + "type": "object" + }, + "PromptReference": { + "description": "Identifies a prompt.", + "properties": { + "name": { + "description": "Intended for programmatic or logical use, but used as a display name in past specs or fallback (if title isn't present).", + "type": "string" + }, + "title": { + "description": "Intended for UI and end-user contexts — optimized to be human-readable and easily understood,\neven by those unfamiliar with domain-specific terminology.\n\nIf not provided, the name should be used for display (except for {@link Tool},\nwhere `annotations.title` should be given precedence over using `name`,\nif present).", + "type": "string" + }, + "type": { + "const": "ref/prompt", + "type": "string" + } + }, + "required": [ + "name", + "type" + ], + "type": "object" + }, + "ReadResourceRequest": { + "description": "Sent from the client to the server, to read a specific resource URI.", + "properties": { + "id": { + "$ref": "#/$defs/RequestId" + }, + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "method": { + "const": "resources/read", + "type": "string" + }, + "params": { + "$ref": "#/$defs/ReadResourceRequestParams" + } + }, + "required": [ + "id", + "jsonrpc", + "method", + "params" + ], + "type": "object" + }, + "ReadResourceRequestParams": { + "description": "Parameters for a `resources/read` request.", + "properties": { + "_meta": { + "$ref": "#/$defs/RequestMetaObject" + }, + "inputResponses": { + "$ref": "#/$defs/InputResponses" + }, + "requestState": { + "type": "string" + }, + "uri": { + "description": "The URI of the resource. The URI can use any protocol; it is up to the server how to interpret it.", + "format": "uri", + "type": "string" + } + }, + "required": [ + "_meta", + "uri" + ], + "type": "object" + }, + "ReadResourceResult": { + "description": "The result returned by the server for a {@link ReadResourceRequestresources/read} request.", + "properties": { + "_meta": { + "$ref": "#/$defs/MetaObject" + }, + "cacheScope": { + "description": "Indicates the intended scope of the cached response, analogous to HTTP\n`Cache-Control: public` vs `Cache-Control: private`.\n\n- `\"public\"`: Any client or intermediary (e.g., shared gateway, proxy)\n MAY cache the response and serve it to any user.\n- `\"private\"`: Only the requesting user's client MAY cache the response.\n Shared caches (e.g., multi-tenant gateways) MUST NOT serve a cached\n copy to a different user.", + "enum": [ + "private", + "public" + ], + "type": "string" + }, + "contents": { + "items": { + "anyOf": [ + { + "$ref": "#/$defs/TextResourceContents" + }, + { + "$ref": "#/$defs/BlobResourceContents" + } + ] + }, + "type": "array" + }, + "resultType": { + "description": "Indicates the type of the result, which allows the client to determine\nhow to parse the result object.\n\nServers implementing this protocol version MUST include this field.\nFor backward compatibility, when a client receives a result from a\nserver implementing an earlier protocol version (which does not include\n`resultType`), the client MUST treat the absent field as `\"complete\"`.", + "type": "string" + }, + "ttlMs": { + "description": "A hint from the server indicating how long (in milliseconds) the\nclient MAY cache this response before re-fetching. Semantics are\nanalogous to HTTP Cache-Control max-age.\n\n- If 0, The response SHOULD be considered immediately stale,\n The client MAY re-fetch every time the result is needed.\n- If positive, the client SHOULD consider the result fresh for this many\n milliseconds after receiving the response.", + "minimum": 0, + "type": "integer" + } + }, + "required": [ + "cacheScope", + "contents", + "resultType", + "ttlMs" + ], + "type": "object" + }, + "ReadResourceResultResponse": { + "description": "A successful response from the server for a {@link ReadResourceRequestresources/read} request.", + "properties": { + "id": { + "$ref": "#/$defs/RequestId" + }, + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "result": { + "anyOf": [ + { + "$ref": "#/$defs/InputRequiredResult" + }, + { + "$ref": "#/$defs/ReadResourceResult" + } + ] + } + }, + "required": [ + "id", + "jsonrpc", + "result" + ], + "type": "object" + }, + "Request": { + "properties": { + "method": { + "type": "string" + }, + "params": { + "additionalProperties": {}, + "type": "object" + } + }, + "required": [ + "method" + ], + "type": "object" + }, + "RequestId": { + "description": "A uniquely identifying ID for a request in JSON-RPC.", + "type": [ + "string", + "integer" + ] + }, + "RequestMetaObject": { + "description": "Extends {@link MetaObject} with additional request-specific fields. All key naming rules from `MetaObject` apply.", + "properties": { + "io.modelcontextprotocol/clientCapabilities": { + "$ref": "#/$defs/ClientCapabilities", + "description": "The client's capabilities for this specific request. Required.\n\nCapabilities are declared per-request rather than once at initialization;\nan empty object means the client supports no optional capabilities.\nServers MUST NOT infer capabilities from prior requests." + }, + "io.modelcontextprotocol/clientInfo": { + "$ref": "#/$defs/Implementation", + "description": "Identifies the client software making the request. Required.\n\nThe {@link Implementation} schema requires `name` and `version`; other\nfields are optional." + }, + "io.modelcontextprotocol/logLevel": { + "$ref": "#/$defs/LoggingLevel", + "description": "The desired log level for this request. Optional.\n\nIf absent, the server MUST NOT send any {@link LoggingMessageNotificationnotifications/message}\nnotifications for this request. The client opts in to log messages by\nexplicitly setting a level. Replaces the former `logging/setLevel` RPC." + }, + "io.modelcontextprotocol/protocolVersion": { + "description": "The MCP Protocol Version being used for this request. Required.\n\nFor the HTTP transport, this value MUST match the `MCP-Protocol-Version`\nheader; otherwise the server MUST return a `400 Bad Request`. If the\nserver does not support the requested version, it MUST return an\n{@link UnsupportedProtocolVersionError}.", + "type": "string" + }, + "progressToken": { + "$ref": "#/$defs/ProgressToken", + "description": "If specified, the caller is requesting out-of-band progress notifications for this request (as represented by {@link ProgressNotificationnotifications/progress}). The value of this parameter is an opaque token that will be attached to any subsequent notifications. The receiver is not obligated to provide these notifications." + } + }, + "required": [ + "io.modelcontextprotocol/clientCapabilities", + "io.modelcontextprotocol/clientInfo", + "io.modelcontextprotocol/protocolVersion" + ], + "type": "object" + }, + "RequestParams": { + "description": "Common params for any request.", + "properties": { + "_meta": { + "$ref": "#/$defs/RequestMetaObject" + } + }, + "required": [ + "_meta" + ], + "type": "object" + }, + "Resource": { + "description": "A known resource that the server is capable of reading.", + "properties": { + "_meta": { + "$ref": "#/$defs/MetaObject" + }, + "annotations": { + "$ref": "#/$defs/Annotations", + "description": "Optional annotations for the client." + }, + "description": { + "description": "A description of what this resource represents.\n\nThis can be used by clients to improve the LLM's understanding of available resources. It can be thought of like a \"hint\" to the model.", + "type": "string" + }, + "icons": { + "description": "Optional set of sized icons that the client can display in a user interface.\n\nClients that support rendering icons MUST support at least the following MIME types:\n- `image/png` - PNG images (safe, universal compatibility)\n- `image/jpeg` (and `image/jpg`) - JPEG images (safe, universal compatibility)\n\nClients that support rendering icons SHOULD also support:\n- `image/svg+xml` - SVG images (scalable but requires security precautions)\n- `image/webp` - WebP images (modern, efficient format)", + "items": { + "$ref": "#/$defs/Icon" + }, + "type": "array" + }, + "mimeType": { + "description": "The MIME type of this resource, if known.", + "type": "string" + }, + "name": { + "description": "Intended for programmatic or logical use, but used as a display name in past specs or fallback (if title isn't present).", + "type": "string" + }, + "size": { + "description": "The size of the raw resource content, in bytes (i.e., before base64 encoding or any tokenization), if known.\n\nThis can be used by Hosts to display file sizes and estimate context window usage.", + "type": "integer" + }, + "title": { + "description": "Intended for UI and end-user contexts — optimized to be human-readable and easily understood,\neven by those unfamiliar with domain-specific terminology.\n\nIf not provided, the name should be used for display (except for {@link Tool},\nwhere `annotations.title` should be given precedence over using `name`,\nif present).", + "type": "string" + }, + "uri": { + "description": "The URI of this resource.", + "format": "uri", + "type": "string" + } + }, + "required": [ + "name", + "uri" + ], + "type": "object" + }, + "ResourceContents": { + "description": "The contents of a specific resource or sub-resource.", + "properties": { + "_meta": { + "$ref": "#/$defs/MetaObject" + }, + "mimeType": { + "description": "The MIME type of this resource, if known.", + "type": "string" + }, + "uri": { + "description": "The URI of this resource.", + "format": "uri", + "type": "string" + } + }, + "required": [ + "uri" + ], + "type": "object" + }, + "ResourceLink": { + "description": "A resource that the server is capable of reading, included in a prompt or tool call result.\n\nNote: resource links returned by tools are not guaranteed to appear in the results of {@link ListResourcesRequestresources/list} requests.", + "properties": { + "_meta": { + "$ref": "#/$defs/MetaObject" + }, + "annotations": { + "$ref": "#/$defs/Annotations", + "description": "Optional annotations for the client." + }, + "description": { + "description": "A description of what this resource represents.\n\nThis can be used by clients to improve the LLM's understanding of available resources. It can be thought of like a \"hint\" to the model.", + "type": "string" + }, + "icons": { + "description": "Optional set of sized icons that the client can display in a user interface.\n\nClients that support rendering icons MUST support at least the following MIME types:\n- `image/png` - PNG images (safe, universal compatibility)\n- `image/jpeg` (and `image/jpg`) - JPEG images (safe, universal compatibility)\n\nClients that support rendering icons SHOULD also support:\n- `image/svg+xml` - SVG images (scalable but requires security precautions)\n- `image/webp` - WebP images (modern, efficient format)", + "items": { + "$ref": "#/$defs/Icon" + }, + "type": "array" + }, + "mimeType": { + "description": "The MIME type of this resource, if known.", + "type": "string" + }, + "name": { + "description": "Intended for programmatic or logical use, but used as a display name in past specs or fallback (if title isn't present).", + "type": "string" + }, + "size": { + "description": "The size of the raw resource content, in bytes (i.e., before base64 encoding or any tokenization), if known.\n\nThis can be used by Hosts to display file sizes and estimate context window usage.", + "type": "integer" + }, + "title": { + "description": "Intended for UI and end-user contexts — optimized to be human-readable and easily understood,\neven by those unfamiliar with domain-specific terminology.\n\nIf not provided, the name should be used for display (except for {@link Tool},\nwhere `annotations.title` should be given precedence over using `name`,\nif present).", + "type": "string" + }, + "type": { + "const": "resource_link", + "type": "string" + }, + "uri": { + "description": "The URI of this resource.", + "format": "uri", + "type": "string" + } + }, + "required": [ + "name", + "type", + "uri" + ], + "type": "object" + }, + "ResourceListChangedNotification": { + "description": "An optional notification from the server to the client, informing it that the list of resources it can read from has changed. This may be issued by servers without any previous subscription from the client.", + "properties": { + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "method": { + "const": "notifications/resources/list_changed", + "type": "string" + }, + "params": { + "$ref": "#/$defs/NotificationParams" + } + }, + "required": [ + "jsonrpc", + "method" + ], + "type": "object" + }, + "ResourceRequestParams": { + "description": "Common params for resource-related requests.", + "properties": { + "_meta": { + "$ref": "#/$defs/RequestMetaObject" + }, + "uri": { + "description": "The URI of the resource. The URI can use any protocol; it is up to the server how to interpret it.", + "format": "uri", + "type": "string" + } + }, + "required": [ + "_meta", + "uri" + ], + "type": "object" + }, + "ResourceTemplate": { + "description": "A template description for resources available on the server.", + "properties": { + "_meta": { + "$ref": "#/$defs/MetaObject" + }, + "annotations": { + "$ref": "#/$defs/Annotations", + "description": "Optional annotations for the client." + }, + "description": { + "description": "A description of what this template is for.\n\nThis can be used by clients to improve the LLM's understanding of available resources. It can be thought of like a \"hint\" to the model.", + "type": "string" + }, + "icons": { + "description": "Optional set of sized icons that the client can display in a user interface.\n\nClients that support rendering icons MUST support at least the following MIME types:\n- `image/png` - PNG images (safe, universal compatibility)\n- `image/jpeg` (and `image/jpg`) - JPEG images (safe, universal compatibility)\n\nClients that support rendering icons SHOULD also support:\n- `image/svg+xml` - SVG images (scalable but requires security precautions)\n- `image/webp` - WebP images (modern, efficient format)", + "items": { + "$ref": "#/$defs/Icon" + }, + "type": "array" + }, + "mimeType": { + "description": "The MIME type for all resources that match this template. This should only be included if all resources matching this template have the same type.", + "type": "string" + }, + "name": { + "description": "Intended for programmatic or logical use, but used as a display name in past specs or fallback (if title isn't present).", + "type": "string" + }, + "title": { + "description": "Intended for UI and end-user contexts — optimized to be human-readable and easily understood,\neven by those unfamiliar with domain-specific terminology.\n\nIf not provided, the name should be used for display (except for {@link Tool},\nwhere `annotations.title` should be given precedence over using `name`,\nif present).", + "type": "string" + }, + "uriTemplate": { + "description": "A URI template (according to RFC 6570) that can be used to construct resource URIs.", + "format": "uri-template", + "type": "string" + } + }, + "required": [ + "name", + "uriTemplate" + ], + "type": "object" + }, + "ResourceTemplateReference": { + "description": "A reference to a resource or resource template definition.", + "properties": { + "type": { + "const": "ref/resource", + "type": "string" + }, + "uri": { + "description": "The URI or URI template of the resource.", + "format": "uri-template", + "type": "string" + } + }, + "required": [ + "type", + "uri" + ], + "type": "object" + }, + "ResourceUpdatedNotification": { + "description": "A notification from the server to the client, informing it that a resource has changed and may need to be read again. This is only sent for resources the client opted in to via the `resourceSubscriptions` field of a {@link SubscriptionsListenRequestsubscriptions/listen} request.", + "properties": { + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "method": { + "const": "notifications/resources/updated", + "type": "string" + }, + "params": { + "$ref": "#/$defs/ResourceUpdatedNotificationParams" + } + }, + "required": [ + "jsonrpc", + "method", + "params" + ], + "type": "object" + }, + "ResourceUpdatedNotificationParams": { + "description": "Parameters for a `notifications/resources/updated` notification.", + "properties": { + "_meta": { + "$ref": "#/$defs/MetaObject" + }, + "uri": { + "description": "The URI of the resource that has been updated. This might be a sub-resource of the one that the client actually subscribed to.", + "format": "uri", + "type": "string" + } + }, + "required": [ + "uri" + ], + "type": "object" + }, + "Result": { + "additionalProperties": {}, + "description": "Common result fields.", + "properties": { + "_meta": { + "$ref": "#/$defs/MetaObject" + }, + "resultType": { + "description": "Indicates the type of the result, which allows the client to determine\nhow to parse the result object.\n\nServers implementing this protocol version MUST include this field.\nFor backward compatibility, when a client receives a result from a\nserver implementing an earlier protocol version (which does not include\n`resultType`), the client MUST treat the absent field as `\"complete\"`.", + "type": "string" + } + }, + "required": [ + "resultType" + ], + "type": "object" + }, + "ResultType": { + "description": "Indicates the type of a {@link Result} object, allowing the client to\ndetermine how to parse the response.\n\ncomplete - the request completed successfully and the result contains the final content.\ninput_required - the request requires additional input and the result contains an {@link InputRequiredResult} object with instructions for the client to provide additional input before retrying the original request.", + "type": "string" + }, + "Role": { + "description": "The sender or recipient of messages and data in a conversation.", + "enum": [ + "assistant", + "user" + ], + "type": "string" + }, + "Root": { + "description": "Represents a root directory or file that the server can operate on.", + "properties": { + "_meta": { + "$ref": "#/$defs/MetaObject" + }, + "name": { + "description": "An optional name for the root. This can be used to provide a human-readable\nidentifier for the root, which may be useful for display purposes or for\nreferencing the root in other parts of the application.", + "type": "string" + }, + "uri": { + "description": "The URI identifying the root. This *must* start with `file://` for now.\nThis restriction may be relaxed in future versions of the protocol to allow\nother URI schemes.", + "format": "uri", + "type": "string" + } + }, + "required": [ + "uri" + ], + "type": "object" + }, + "SamplingMessage": { + "description": "Describes a message issued to or received from an LLM API.", + "properties": { + "_meta": { + "$ref": "#/$defs/MetaObject" + }, + "content": { + "anyOf": [ + { + "$ref": "#/$defs/TextContent" + }, + { + "$ref": "#/$defs/ImageContent" + }, + { + "$ref": "#/$defs/AudioContent" + }, + { + "$ref": "#/$defs/ToolUseContent" + }, + { + "$ref": "#/$defs/ToolResultContent" + }, + { + "items": { + "$ref": "#/$defs/SamplingMessageContentBlock" + }, + "type": "array" + } + ] + }, + "role": { + "$ref": "#/$defs/Role" + } + }, + "required": [ + "content", + "role" + ], + "type": "object" + }, + "SamplingMessageContentBlock": { + "anyOf": [ + { + "$ref": "#/$defs/TextContent" + }, + { + "$ref": "#/$defs/ImageContent" + }, + { + "$ref": "#/$defs/AudioContent" + }, + { + "$ref": "#/$defs/ToolUseContent" + }, + { + "$ref": "#/$defs/ToolResultContent" + } + ] + }, + "ServerCapabilities": { + "description": "Capabilities that a server may support. Known capabilities are defined here, in this schema, but this is not a closed set: any server can define its own, additional capabilities.", + "properties": { + "completions": { + "$ref": "#/$defs/JSONObject", + "description": "Present if the server supports argument autocompletion suggestions." + }, + "experimental": { + "additionalProperties": { + "$ref": "#/$defs/JSONObject" + }, + "description": "Experimental, non-standard capabilities that the server supports.", + "type": "object" + }, + "extensions": { + "additionalProperties": { + "$ref": "#/$defs/JSONObject" + }, + "description": "Optional MCP extensions that the server supports. Keys are extension identifiers\n(e.g., \"io.modelcontextprotocol/tasks\"), and values are per-extension settings\nobjects. An empty object indicates support with no settings.", + "type": "object" + }, + "logging": { + "$ref": "#/$defs/JSONObject", + "description": "Present if the server supports sending log messages to the client." + }, + "prompts": { + "description": "Present if the server offers any prompt templates.", + "properties": { + "listChanged": { + "description": "Whether this server supports notifications for changes to the prompt list.", + "type": "boolean" + } + }, + "type": "object" + }, + "resources": { + "description": "Present if the server offers any resources to read.", + "properties": { + "listChanged": { + "description": "Whether this server supports notifications for changes to the resource list.", + "type": "boolean" + }, + "subscribe": { + "description": "Whether this server supports subscribing to resource updates.", + "type": "boolean" + } + }, + "type": "object" + }, + "tools": { + "description": "Present if the server offers any tools to call.", + "properties": { + "listChanged": { + "description": "Whether this server supports notifications for changes to the tool list.", + "type": "boolean" + } + }, + "type": "object" + } + }, + "type": "object" + }, + "ServerNotification": { + "anyOf": [ + { + "$ref": "#/$defs/CancelledNotification" + }, + { + "$ref": "#/$defs/ProgressNotification" + }, + { + "$ref": "#/$defs/ResourceListChangedNotification" + }, + { + "$ref": "#/$defs/SubscriptionsAcknowledgedNotification" + }, + { + "$ref": "#/$defs/ResourceUpdatedNotification" + }, + { + "$ref": "#/$defs/PromptListChangedNotification" + }, + { + "$ref": "#/$defs/ToolListChangedNotification" + }, + { + "$ref": "#/$defs/LoggingMessageNotification" + }, + { + "$ref": "#/$defs/ElicitationCompleteNotification" + } + ] + }, + "ServerResult": { + "anyOf": [ + { + "$ref": "#/$defs/Result" + }, + { + "$ref": "#/$defs/InputRequiredResult" + }, + { + "$ref": "#/$defs/DiscoverResult" + }, + { + "$ref": "#/$defs/ListResourcesResult" + }, + { + "$ref": "#/$defs/ListResourceTemplatesResult" + }, + { + "$ref": "#/$defs/ReadResourceResult" + }, + { + "$ref": "#/$defs/ListPromptsResult" + }, + { + "$ref": "#/$defs/GetPromptResult" + }, + { + "$ref": "#/$defs/ListToolsResult" + }, + { + "$ref": "#/$defs/CallToolResult" + }, + { + "$ref": "#/$defs/CompleteResult" + } + ] + }, + "SingleSelectEnumSchema": { + "anyOf": [ + { + "$ref": "#/$defs/UntitledSingleSelectEnumSchema" + }, + { + "$ref": "#/$defs/TitledSingleSelectEnumSchema" + } + ] + }, + "StringSchema": { + "properties": { + "default": { + "type": "string" + }, + "description": { + "type": "string" + }, + "format": { + "enum": [ + "date", + "date-time", + "email", + "uri" + ], + "type": "string" + }, + "maxLength": { + "type": "integer" + }, + "minLength": { + "type": "integer" + }, + "title": { + "type": "string" + }, + "type": { + "const": "string", + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + }, + "SubscriptionFilter": { + "description": "The set of notification types a client may opt in to on a\n{@link SubscriptionsListenRequestsubscriptions/listen} request.\n\nEach notification type is **opt-in**; the server **MUST NOT** send\nnotification types the client has not explicitly requested here.", + "properties": { + "promptsListChanged": { + "description": "If true, receive {@link PromptListChangedNotificationnotifications/prompts/list_changed}.", + "type": "boolean" + }, + "resourceSubscriptions": { + "description": "Subscribe to {@link ResourceUpdatedNotificationnotifications/resources/updated} for these resource URIs.\nReplaces the former `resources/subscribe` RPC.", + "items": { + "type": "string" + }, + "type": "array" + }, + "resourcesListChanged": { + "description": "If true, receive {@link ResourceListChangedNotificationnotifications/resources/list_changed}.", + "type": "boolean" + }, + "toolsListChanged": { + "description": "If true, receive {@link ToolListChangedNotificationnotifications/tools/list_changed}.", + "type": "boolean" + } + }, + "type": "object" + }, + "SubscriptionsAcknowledgedNotification": { + "description": "Sent by the server as the first message on a\n{@link SubscriptionsListenRequestsubscriptions/listen} stream to acknowledge\nthat the subscription has been established and to report which notification\ntypes it agreed to honor.", + "properties": { + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "method": { + "const": "notifications/subscriptions/acknowledged", + "type": "string" + }, + "params": { + "$ref": "#/$defs/SubscriptionsAcknowledgedNotificationParams" + } + }, + "required": [ + "jsonrpc", + "method", + "params" + ], + "type": "object" + }, + "SubscriptionsAcknowledgedNotificationParams": { + "description": "Parameters for a {@link SubscriptionsAcknowledgedNotificationnotifications/subscriptions/acknowledged} notification.", + "properties": { + "_meta": { + "$ref": "#/$defs/MetaObject" + }, + "notifications": { + "$ref": "#/$defs/SubscriptionFilter", + "description": "The subset of requested notification types the server agreed to honor.\nOnly includes notification types the server actually supports; if the\nclient requested an unsupported type (e.g., `promptsListChanged` when\nthe server has no prompts), it is omitted from this set." + } + }, + "required": [ + "notifications" + ], + "type": "object" + }, + "SubscriptionsListenRequest": { + "description": "Sent from the client to open a long-lived channel for receiving notifications\noutside the context of a specific request. Replaces the previous HTTP GET\nendpoint and ensures consistent behavior between HTTP and STDIO.", + "properties": { + "id": { + "$ref": "#/$defs/RequestId" + }, + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "method": { + "const": "subscriptions/listen", + "type": "string" + }, + "params": { + "$ref": "#/$defs/SubscriptionsListenRequestParams" + } + }, + "required": [ + "id", + "jsonrpc", + "method", + "params" + ], + "type": "object" + }, + "SubscriptionsListenRequestParams": { + "description": "Parameters for a {@link SubscriptionsListenRequestsubscriptions/listen} request.", + "properties": { + "_meta": { + "$ref": "#/$defs/RequestMetaObject" + }, + "notifications": { + "$ref": "#/$defs/SubscriptionFilter", + "description": "The notifications the client opts in to on this stream. The server\n**MUST NOT** send notification types the client has not explicitly\nrequested." + } + }, + "required": [ + "_meta", + "notifications" + ], + "type": "object" + }, + "TextContent": { + "description": "Text provided to or from an LLM.", + "properties": { + "_meta": { + "$ref": "#/$defs/MetaObject" + }, + "annotations": { + "$ref": "#/$defs/Annotations", + "description": "Optional annotations for the client." + }, + "text": { + "description": "The text content of the message.", + "type": "string" + }, + "type": { + "const": "text", + "type": "string" + } + }, + "required": [ + "text", + "type" + ], + "type": "object" + }, + "TextResourceContents": { + "properties": { + "_meta": { + "$ref": "#/$defs/MetaObject" + }, + "mimeType": { + "description": "The MIME type of this resource, if known.", + "type": "string" + }, + "text": { + "description": "The text of the item. This must only be set if the item can actually be represented as text (not binary data).", + "type": "string" + }, + "uri": { + "description": "The URI of this resource.", + "format": "uri", + "type": "string" + } + }, + "required": [ + "text", + "uri" + ], + "type": "object" + }, + "TitledMultiSelectEnumSchema": { + "description": "Schema for multiple-selection enumeration with display titles for each option.", + "properties": { + "default": { + "description": "Optional default value.", + "items": { + "type": "string" + }, + "type": "array" + }, + "description": { + "description": "Optional description for the enum field.", + "type": "string" + }, + "items": { + "description": "Schema for array items with enum options and display labels.", + "properties": { + "anyOf": { + "description": "Array of enum options with values and display labels.", + "items": { + "properties": { + "const": { + "description": "The constant enum value.", + "type": "string" + }, + "title": { + "description": "Display title for this option.", + "type": "string" + } + }, + "required": [ + "const", + "title" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "anyOf" + ], + "type": "object" + }, + "maxItems": { + "description": "Maximum number of items to select.", + "type": "integer" + }, + "minItems": { + "description": "Minimum number of items to select.", + "type": "integer" + }, + "title": { + "description": "Optional title for the enum field.", + "type": "string" + }, + "type": { + "const": "array", + "type": "string" + } + }, + "required": [ + "items", + "type" + ], + "type": "object" + }, + "TitledSingleSelectEnumSchema": { + "description": "Schema for single-selection enumeration with display titles for each option.", + "properties": { + "default": { + "description": "Optional default value.", + "type": "string" + }, + "description": { + "description": "Optional description for the enum field.", + "type": "string" + }, + "oneOf": { + "description": "Array of enum options with values and display labels.", + "items": { + "properties": { + "const": { + "description": "The enum value.", + "type": "string" + }, + "title": { + "description": "Display label for this option.", + "type": "string" + } + }, + "required": [ + "const", + "title" + ], + "type": "object" + }, + "type": "array" + }, + "title": { + "description": "Optional title for the enum field.", + "type": "string" + }, + "type": { + "const": "string", + "type": "string" + } + }, + "required": [ + "oneOf", + "type" + ], + "type": "object" + }, + "Tool": { + "description": "Definition for a tool the client can call.", + "properties": { + "_meta": { + "$ref": "#/$defs/MetaObject" + }, + "annotations": { + "$ref": "#/$defs/ToolAnnotations", + "description": "Optional additional tool information.\n\nDisplay name precedence order is: `title`, `annotations.title`, then `name`." + }, + "description": { + "description": "A human-readable description of the tool.\n\nThis can be used by clients to improve the LLM's understanding of available tools. It can be thought of like a \"hint\" to the model.", + "type": "string" + }, + "icons": { + "description": "Optional set of sized icons that the client can display in a user interface.\n\nClients that support rendering icons MUST support at least the following MIME types:\n- `image/png` - PNG images (safe, universal compatibility)\n- `image/jpeg` (and `image/jpg`) - JPEG images (safe, universal compatibility)\n\nClients that support rendering icons SHOULD also support:\n- `image/svg+xml` - SVG images (scalable but requires security precautions)\n- `image/webp` - WebP images (modern, efficient format)", + "items": { + "$ref": "#/$defs/Icon" + }, + "type": "array" + }, + "inputSchema": { + "additionalProperties": {}, + "description": "A JSON Schema object defining the expected parameters for the tool.\n\nTool arguments are always JSON objects, so `type: \"object\"` is required at the root.\nBeyond that, any JSON Schema 2020-12 keyword may appear alongside `type` — including\ncomposition keywords (`oneOf`, `anyOf`, `allOf`, `not`), conditional keywords\n(`if`/`then`/`else`), reference keywords (`$ref`, `$defs`, `$anchor`), and any other\nstandard validation or annotation keywords.\n\nDefaults to JSON Schema 2020-12 when no explicit `$schema` is provided.", + "properties": { + "$schema": { + "type": "string" + }, + "type": { + "const": "object", + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + }, + "name": { + "description": "Intended for programmatic or logical use, but used as a display name in past specs or fallback (if title isn't present).", + "type": "string" + }, + "outputSchema": { + "additionalProperties": {}, + "description": "An optional JSON Schema object defining the structure of the tool's output returned in\nthe structuredContent field of a {@link CallToolResult}. This can be any valid JSON Schema 2020-12.\n\nDefaults to JSON Schema 2020-12 when no explicit `$schema` is provided.", + "properties": { + "$schema": { + "type": "string" + } + }, + "type": "object" + }, + "title": { + "description": "Intended for UI and end-user contexts — optimized to be human-readable and easily understood,\neven by those unfamiliar with domain-specific terminology.\n\nIf not provided, the name should be used for display (except for {@link Tool},\nwhere `annotations.title` should be given precedence over using `name`,\nif present).", + "type": "string" + } + }, + "required": [ + "inputSchema", + "name" + ], + "type": "object" + }, + "ToolAnnotations": { + "description": "Additional properties describing a {@link Tool} to clients.\n\nNOTE: all properties in `ToolAnnotations` are **hints**.\nThey are not guaranteed to provide a faithful description of\ntool behavior (including descriptive properties like `title`).\n\nClients should never make tool use decisions based on `ToolAnnotations`\nreceived from untrusted servers.", + "properties": { + "destructiveHint": { + "description": "If true, the tool may perform destructive updates to its environment.\nIf false, the tool performs only additive updates.\n\n(This property is meaningful only when `readOnlyHint == false`)\n\nDefault: true", + "type": "boolean" + }, + "idempotentHint": { + "description": "If true, calling the tool repeatedly with the same arguments\nwill have no additional effect on its environment.\n\n(This property is meaningful only when `readOnlyHint == false`)\n\nDefault: false", + "type": "boolean" + }, + "openWorldHint": { + "description": "If true, this tool may interact with an \"open world\" of external\nentities. If false, the tool's domain of interaction is closed.\nFor example, the world of a web search tool is open, whereas that\nof a memory tool is not.\n\nDefault: true", + "type": "boolean" + }, + "readOnlyHint": { + "description": "If true, the tool does not modify its environment.\n\nDefault: false", + "type": "boolean" + }, + "title": { + "description": "A human-readable title for the tool.", + "type": "string" + } + }, + "type": "object" + }, + "ToolChoice": { + "description": "Controls tool selection behavior for sampling requests.", + "properties": { + "mode": { + "description": "Controls the tool use ability of the model:\n- `\"auto\"`: Model decides whether to use tools (default)\n- `\"required\"`: Model MUST use at least one tool before completing\n- `\"none\"`: Model MUST NOT use any tools", + "enum": [ + "auto", + "none", + "required" + ], + "type": "string" + } + }, + "type": "object" + }, + "ToolListChangedNotification": { + "description": "An optional notification from the server to the client, informing it that the list of tools it offers has changed. This may be issued by servers without any previous subscription from the client.", + "properties": { + "jsonrpc": { + "const": "2.0", + "type": "string" + }, + "method": { + "const": "notifications/tools/list_changed", + "type": "string" + }, + "params": { + "$ref": "#/$defs/NotificationParams" + } + }, + "required": [ + "jsonrpc", + "method" + ], + "type": "object" + }, + "ToolResultContent": { + "description": "The result of a tool use, provided by the user back to the assistant.", + "properties": { + "_meta": { + "$ref": "#/$defs/MetaObject", + "description": "Optional metadata about the tool result. Clients SHOULD preserve this field when\nincluding tool results in subsequent sampling requests to enable caching optimizations." + }, + "content": { + "description": "The unstructured result content of the tool use.\n\nThis has the same format as {@link CallToolResult.content} and can include text, images,\naudio, resource links, and embedded resources.", + "items": { + "$ref": "#/$defs/ContentBlock" + }, + "type": "array" + }, + "isError": { + "description": "Whether the tool use resulted in an error.\n\nIf true, the content typically describes the error that occurred.\nDefault: false", + "type": "boolean" + }, + "structuredContent": { + "description": "An optional structured result value.\n\nThis can be any JSON value (object, array, string, number, boolean, or null).\nIf the tool defined an {@link Tool.outputSchema}, this SHOULD conform to that schema." + }, + "toolUseId": { + "description": "The ID of the tool use this result corresponds to.\n\nThis MUST match the ID from a previous {@link ToolUseContent}.", + "type": "string" + }, + "type": { + "const": "tool_result", + "type": "string" + } + }, + "required": [ + "content", + "toolUseId", + "type" + ], + "type": "object" + }, + "ToolUseContent": { + "description": "A request from the assistant to call a tool.", + "properties": { + "_meta": { + "$ref": "#/$defs/MetaObject", + "description": "Optional metadata about the tool use. Clients SHOULD preserve this field when\nincluding tool uses in subsequent sampling requests to enable caching optimizations." + }, + "id": { + "description": "A unique identifier for this tool use.\n\nThis ID is used to match tool results to their corresponding tool uses.", + "type": "string" + }, + "input": { + "additionalProperties": {}, + "description": "The arguments to pass to the tool, conforming to the tool's input schema.", + "type": "object" + }, + "name": { + "description": "The name of the tool to call.", + "type": "string" + }, + "type": { + "const": "tool_use", + "type": "string" + } + }, + "required": [ + "id", + "input", + "name", + "type" + ], + "type": "object" + }, + "UnsupportedProtocolVersionError": { + "description": "Returned when the request's protocol version is unknown to the server or\nunsupported (e.g., a known experimental or draft version the server has\nchosen not to implement). For HTTP, the response status code MUST be\n`400 Bad Request`.", + "properties": { + "error": { + "allOf": [ + { + "$ref": "#/$defs/Error" + }, + { + "properties": { + "code": { + "const": -32004, + "type": "integer" + }, + "data": { + "properties": { + "requested": { + "description": "The protocol version that was requested by the client.", + "type": "string" + }, + "supported": { + "description": "Protocol versions the server supports. The client should choose a\nmutually supported version from this list and retry.", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "requested", + "supported" + ], + "type": "object" + } + }, + "required": [ + "code", + "data" + ], + "type": "object" + } + ] + }, + "id": { + "$ref": "#/$defs/RequestId" + }, + "jsonrpc": { + "const": "2.0", + "type": "string" + } + }, + "required": [ + "error", + "jsonrpc" + ], + "type": "object" + }, + "UntitledMultiSelectEnumSchema": { + "description": "Schema for multiple-selection enumeration without display titles for options.", + "properties": { + "default": { + "description": "Optional default value.", + "items": { + "type": "string" + }, + "type": "array" + }, + "description": { + "description": "Optional description for the enum field.", + "type": "string" + }, + "items": { + "description": "Schema for the array items.", + "properties": { + "enum": { + "description": "Array of enum values to choose from.", + "items": { + "type": "string" + }, + "type": "array" + }, + "type": { + "const": "string", + "type": "string" + } + }, + "required": [ + "enum", + "type" + ], + "type": "object" + }, + "maxItems": { + "description": "Maximum number of items to select.", + "type": "integer" + }, + "minItems": { + "description": "Minimum number of items to select.", + "type": "integer" + }, + "title": { + "description": "Optional title for the enum field.", + "type": "string" + }, + "type": { + "const": "array", + "type": "string" + } + }, + "required": [ + "items", + "type" + ], + "type": "object" + }, + "UntitledSingleSelectEnumSchema": { + "description": "Schema for single-selection enumeration without display titles for options.", + "properties": { + "default": { + "description": "Optional default value.", + "type": "string" + }, + "description": { + "description": "Optional description for the enum field.", + "type": "string" + }, + "enum": { + "description": "Array of enum values to choose from.", + "items": { + "type": "string" + }, + "type": "array" + }, + "title": { + "description": "Optional title for the enum field.", + "type": "string" + }, + "type": { + "const": "string", + "type": "string" + } + }, + "required": [ + "enum", + "type" + ], + "type": "object" + } + } +} diff --git a/schema/PINNED.json b/schema/PINNED.json new file mode 100644 index 0000000000..f99c75abf0 --- /dev/null +++ b/schema/PINNED.json @@ -0,0 +1,14 @@ +[ + { + "protocol_version": "2025-11-25", + "source_path_in_spec_repo": "schema/2025-11-25/schema.json", + "spec_commit": "6d441518de8a9d5adbab0b10a76a667a63f90665", + "sha256": "4e01628360a2149892eab8f298ceee626d24a58862184eb8ec85d95b8f353e31" + }, + { + "protocol_version": "2026-07-28", + "source_path_in_spec_repo": "schema/draft/schema.json", + "spec_commit": "6d441518de8a9d5adbab0b10a76a667a63f90665", + "sha256": "bce2e7c9622bb0b449475ba6d8d80228c71190a09250e75dabd502b280ecf3cb" + } +] diff --git a/schema/README.md b/schema/README.md new file mode 100644 index 0000000000..829a0109f1 --- /dev/null +++ b/schema/README.md @@ -0,0 +1,12 @@ +# Vendored protocol schemas + +JSON Schema files for each protocol version the SDK has a wire-shape surface +package for, vendored from the [spec repository] at the commit recorded in +`PINNED.json`. `scripts/gen_surface_types.py` reads these to regenerate +`src/mcp/types/v/__init__.py`; CI runs the generator with `--check`. + +To bump: drop the new `schema.json` here as `.json`, update +the matching entry in `PINNED.json` (commit + sha256), and run +`uv run --group codegen python scripts/gen_surface_types.py`. + +[spec repository]: https://github.com/modelcontextprotocol/modelcontextprotocol diff --git a/scripts/gen_surface_types.py b/scripts/gen_surface_types.py new file mode 100644 index 0000000000..5125933e4c --- /dev/null +++ b/scripts/gen_surface_types.py @@ -0,0 +1,972 @@ +"""Regenerate the per-version wire-shape surface packages from vendored schemas. + +The two surfaces under ``src/mcp/types/v/__init__.py`` are pure +generator output: this script is the only writer. For each entry of +``schema/PINNED.json`` it verifies the vendored ``schema/.json`` +against the recorded sha256, runs ``datamodel-code-generator`` (installed via +the ``codegen`` dependency group), applies the post-processing passes +documented on each pass function below, runs ruff, imports the candidate to +audit definition names / field requiredness / ``_meta`` openness, and writes +the result. + +Usage (from the repo root):: + + uv run --group codegen python scripts/gen_surface_types.py [--check] + +``--check`` regenerates to a temp location and diffs against the committed +files; non-zero exit (with a unified diff) on any drift. +""" + +from __future__ import annotations + +import argparse +import ast +import difflib +import hashlib +import importlib.util +import json +import re +import shutil +import subprocess +import sys +import tempfile +import textwrap +import typing +from dataclasses import dataclass +from pathlib import Path +from types import ModuleType +from typing import Any + +from pydantic import BaseModel + +REPO_ROOT = Path(__file__).resolve().parent.parent +SCHEMA_DIR = REPO_ROOT / "schema" +PINNED_PATH = SCHEMA_DIR / "PINNED.json" +SRC_TYPES_DIR = REPO_ROOT / "src" / "mcp" / "types" + +_SRC_BASE_CLASS = "mcp.types._wire_base.WireModel" + +# {@link Target} or {@link Target | label}: emit the label when present. +_JSDOC_LINK_RE = re.compile(r"\{@link\s+(?:[^}|]+?\s*\|\s*)?([^}|]+?)\s*\}") +_GENERATOR_BANNER_RE = re.compile(r"\A# generated by datamodel-codegen:\n(# filename: [^\n]*\n)?\n*") +_FIELD_ALIAS_RE = re.compile(r"alias=['\"]([^'\"]+)['\"]") + +# Wire names whose referenced classes stay extra="allow": schema-open +# pass-through interiors whose unknown keys must survive revalidation. +_OPEN_INTERIOR_FIELD_ALIASES = frozenset({"inputSchema", "outputSchema"}) +_OPEN_INTERIOR_COMMENT = " # Stays open: schema keywords beyond the declared properties ride extra fields.\n" +_SUBSCRIPTION_FILTER_COMMENT = " # Stays open: filter contents are extensible on the wire.\n" + +# Names a relocated cyclic-alias block may reference besides its own members: +# anything else means relocation could break runtime evaluation order. +_RELOCATABLE_NAMES = frozenset( + {"Annotated", "Any", "Literal", "None", "Optional", "Union"} + | {"bool", "bytes", "dict", "float", "frozenset", "int", "list", "set", "str", "tuple"} +) + +# Per-version module docstrings (the generator emits these verbatim). +SRC_HEADERS: dict[str, str] = { + "2025-11-25": '''\ +"""Internal wire-shape models for protocol 2025-11-25. Not part of the public API. + +Generated by `scripts/gen_surface_types.py` from `schema/2025-11-25.json` +@ {spec_commit}. Do not edit; regenerate. Serves inbound validation for every +protocol version through 2025-11-25 (each earlier schema is a strict subset of +this one). Models default to `extra="ignore"`; the few kept open are commented +in place. See `mcp.types._wire_base` and `mcp.types.methods`. +""" +''', + "2026-07-28": '''\ +"""Internal wire-shape models for protocol 2026-07-28. Not part of the public API. + +Generated by `scripts/gen_surface_types.py` from `schema/2026-07-28.json` +@ {spec_commit}. Do not edit; regenerate. Schema-exact validators that the +wire-method maps in `mcp.types.methods` point inbound 2026-07-28 validation at. +Models use `extra="ignore"` (unknown keys accepted and dropped) unless commented +otherwise; see `mcp.types._wire_base`. +""" +''', +} + +# schema.ts -> schema.json renders TypeScript ``number`` as JSON Schema +# ``integer`` at these sites, so the generator emits ``int``-only annotations +# that reject the floats schema.ts permits. Each entry rewrites one field's +# annotation back to what schema.ts declares. +_NUMBER_PATCH_NOTE = " # schema.json renders this `number` as integer; widen per schema.ts so floats validate.\n" +FIELD_TYPE_PATCHES: dict[str, list[tuple[str, str, str]]] = { + "2025-11-25": [ + ("ElicitResult", "content", "dict[str, list[str] | str | int | float | bool] | None"), + ("NumberSchema", "default", "int | float | None"), + ("NumberSchema", "maximum", "int | float | None"), + ("NumberSchema", "minimum", "int | float | None"), + ], + "2026-07-28": [ + ("ElicitResult", "content", "dict[str, list[str] | str | int | float | bool] | None"), + ], +} + +# Same defect for the recursive JSONValue alias (2026 only): schema.json's +# primitive arm is string|integer|boolean where schema.ts has all six JSON +# types. Rewrites the TypeAliasType value string. +ALIAS_TYPE_PATCHES: dict[str, dict[str, str]] = { + "2026-07-28": {"JSONValue": "JSONObject | list[JSONValue] | str | int | float | bool | None"}, +} + +# Hand-written union aliases the wire-method maps reference by value; the +# schema has no named definition for "everything tools/call may return", so the +# generator emits the union inline on the response model and these name it. +EPILOGUES: dict[str, str] = { + "2026-07-28": '''\ +AnyCallToolResult: TypeAlias = CallToolResult | InputRequiredResult +"""Named alias for `CallToolResultResponse.result` so the wire-method maps can reference it as a value.""" + +AnyGetPromptResult: TypeAlias = GetPromptResult | InputRequiredResult +"""Everything a `prompts/get` response's `result` may be at this version.""" + +AnyReadResourceResult: TypeAlias = ReadResourceResult | InputRequiredResult +"""Everything a `resources/read` response's `result` may be at this version.""" +''', +} + + +class PipelineError(Exception): + """A stage of the pipeline failed; the message says which and why.""" + + +@dataclass +class Entry: + """One PINNED.json entry.""" + + protocol_version: str + source_path_in_spec_repo: str + spec_commit: str + sha256: str + + @property + def module(self) -> str: + return "v" + self.protocol_version.replace("-", "_") + + @property + def schema_file(self) -> Path: + return SCHEMA_DIR / f"{self.protocol_version}.json" + + @property + def target(self) -> Path: + return SRC_TYPES_DIR / self.module / "__init__.py" + + +def load_pinned() -> list[Entry]: + """Read schema/PINNED.json and verify each vendored file's sha256.""" + with PINNED_PATH.open() as f: + raw: list[dict[str, str]] = json.load(f) + entries = [Entry(**item) for item in raw] + for entry in entries: + if not entry.schema_file.is_file(): + raise PipelineError(f"{entry.protocol_version}: vendored schema {entry.schema_file} is missing") + actual = hashlib.sha256(entry.schema_file.read_bytes()).hexdigest() + if actual != entry.sha256: + raise PipelineError( + f"{entry.protocol_version}: sha256 mismatch for {entry.schema_file.name} " + f"(PINNED.json={entry.sha256}, on disk={actual})" + ) + return entries + + +def run_generator(schema_path: Path, output_path: Path) -> None: + """Run datamodel-code-generator (from the ``codegen`` dependency group).""" + exe = shutil.which("datamodel-codegen") + cmd = [exe] if exe else ["uv", "run", "--group", "codegen", "datamodel-codegen"] + result = subprocess.run( + [ + *cmd, + "--input", + str(schema_path), + "--input-file-type", + "jsonschema", + "--output", + str(output_path), + "--output-model-type", + "pydantic_v2.BaseModel", + "--target-python-version", + "3.10", + "--base-class", + _SRC_BASE_CLASS, + "--snake-case-field", + "--remove-special-field-name-prefix", + "--use-annotated", + "--use-field-description", + "--use-schema-description", + "--enum-field-as-literal", + "all", + "--use-union-operator", + "--use-double-quotes", + "--extra-fields", + "allow", + "--disable-timestamp", + ], + capture_output=True, + text=True, + ) + if result.returncode != 0 or not output_path.is_file(): + raise PipelineError(f"datamodel-codegen failed:\n{result.stderr.strip()}") + + +def _end_lineno(node: ast.stmt) -> int: + """End line of a statement (ast fills end_lineno for parsed code).""" + end = node.end_lineno + if end is None: + raise PipelineError(f"ast node at line {node.lineno} has no end_lineno") + return end + + +def _collect_rootmodel_aliases(tree: ast.Module) -> dict[str, tuple[ast.ClassDef, str]]: + """Map class name -> (node, unparsed RootModel type argument) for RootModel subclasses.""" + aliases: dict[str, tuple[ast.ClassDef, str]] = {} + for node in tree.body: + if not isinstance(node, ast.ClassDef) or len(node.bases) != 1: + continue + base = node.bases[0] + if isinstance(base, ast.Subscript) and isinstance(base.value, ast.Name) and base.value.id == "RootModel": + aliases[node.name] = (node, ast.unparse(base.slice)) + return aliases + + +def _find_recursive_aliases(aliases: dict[str, tuple[ast.ClassDef, str]]) -> set[str]: + """Names of alias classes that participate in a reference cycle.""" + + def refs(type_expr: str) -> set[str]: + bare = type_expr.replace("'", " ").replace('"', " ") + return {name for name in aliases if re.search(rf"\b{name}\b", bare)} + + cyclic: set[str] = set() + for name, (_, type_expr) in aliases.items(): + seen: set[str] = set() + stack = list(refs(type_expr)) + while stack: + current = stack.pop() + if current == name: + cyclic.add(name) + break + if current in seen or current not in aliases: + continue + seen.add(current) + stack.extend(refs(aliases[current][1])) + return cyclic + + +def _alias_statement(name: str, node: ast.ClassDef, alias_type: str, *, string_form: bool) -> str: + """One converted alias definition (docstring preserved as a trailing string).""" + if string_form: + value = alias_type.replace("'", "").replace('"', "") + text = f'{name} = TypeAliasType("{name}", "{value}")\n' + else: + text = f'{name} = TypeAliasType("{name}", {alias_type})\n' + docstring = ast.get_docstring(node) + if docstring and '"""' not in docstring: + text += '"""' + docstring + '"""\n' + return text + + +def _emit_cyclic_block( + ordered: list[str], aliases: dict[str, tuple[ast.ClassDef, str]], alias_patches: dict[str, str] +) -> str: + """Emit a group of mutually recursive aliases in the one form pyright accepts. + + Self-referencing members go first as a whole-string value (lazily parsed), + the rest follow in expression form so quoted references point backwards; + the caller relocates the whole block to just after the imports. Any + ``alias_patches`` entry overrides the generator's value (always emitted + string-form, with a leading comment). + """ + + def has_self_ref(name: str) -> bool: + bare = aliases[name][1].replace("'", " ").replace('"', " ") + return re.search(rf"\b{name}\b", bare) is not None + + string_members = [n for n in ordered if has_self_ref(n)] + expr_members = [n for n in ordered if not has_self_ref(n)] + parts: list[str] = [] + for name in [*string_members, *expr_members]: + node, generated = aliases[name] + if name in alias_patches: + parts.append( + "# schema.json renders the primitive arm without float/null; widen per schema.ts.\n" + + _alias_statement(name, node, alias_patches[name], string_form=True) + ) + else: + parts.append(_alias_statement(name, node, generated, string_form=name in string_members)) + return "\n\n".join(parts) + + +def _group_is_self_contained(cyclic: set[str], aliases: dict[str, tuple[ast.ClassDef, str]]) -> bool: + """True if the cyclic group references only its own members and builtins.""" + allowed = cyclic | _RELOCATABLE_NAMES + for name in cyclic: + bare = aliases[name][1].replace("'", " ").replace('"', " ") + identifiers = set(re.findall(r"[A-Za-z_][A-Za-z0-9_]*", bare)) + if not identifiers <= allowed: + return False + return True + + +def postprocess(source: str, alias_patches: dict[str, str]) -> tuple[str, list[str]]: + """Convert RootModel wrappers to aliases and clean up generator artifacts. + + Returns the rewritten source and the sorted recursive-alias names (for the + follow-up assertion that the relocated block survived). + """ + source = _GENERATOR_BANNER_RE.sub("", source) + tree = ast.parse(source) + lines = source.splitlines(keepends=True) + + aliases = _collect_rootmodel_aliases(tree) + cyclic = _find_recursive_aliases(aliases) + + converted = 0 + cyclic_in_order = [name for name in aliases if name in cyclic] + relocate = bool(cyclic) and _group_is_self_contained(cyclic, aliases) + replacements: list[tuple[int, int, str]] = [] # 1-based inclusive line ranges + for name, (node, alias_type) in aliases.items(): + if name == "Model" and alias_type == "Any": + # The generator's synthetic artifact for the schema's empty root. + replacements.append((node.lineno, _end_lineno(node), "")) + continue + if name in cyclic: + # The whole group is emitted as one block (see _emit_cyclic_block): + # relocated to just after the imports when self-contained, else at + # the first member's position. + if relocate or name != cyclic_in_order[0]: + new = "" + else: + new = _emit_cyclic_block(cyclic_in_order, aliases, alias_patches) + else: + new = f"{name}: TypeAlias = {alias_type}\n" + docstring = ast.get_docstring(node) + if docstring and '"""' not in docstring: + new += '"""' + docstring + '"""\n' + replacements.append((node.lineno, _end_lineno(node), new)) + converted += 1 + if relocate: + last_import_end = max(_end_lineno(node) for node in tree.body if isinstance(node, ast.Import | ast.ImportFrom)) + block = _emit_cyclic_block(cyclic_in_order, aliases, alias_patches) + # Pure insertion AFTER the last import line (start = end + 1), never a + # replacement of it: the import line itself may carry its own + # replacement (dropping RootModel), and two edits to one line range + # silently clobber each other. + replacements.append((last_import_end + 1, last_import_end, "\n" + block)) + + # Import fixes, on the same parsed tree: drop RootModel from the pydantic + # import, add TypeAlias / TypeAliasType where conversions need them. + need_type_alias = converted > len(cyclic) + need_type_alias_type = bool(cyclic) + typing_handled = False + for node in tree.body: + if not isinstance(node, ast.ImportFrom): + continue + if node.module == "pydantic": + names = [alias for alias in node.names if alias.name != "RootModel"] + text = ast.unparse(ast.ImportFrom(module="pydantic", names=names, level=0)) + "\n" if names else "" + replacements.append((node.lineno, _end_lineno(node), text)) + elif node.module == "typing": + typing_handled = True + names = list(node.names) + if need_type_alias and not any(alias.name == "TypeAlias" for alias in names): + names.append(ast.alias(name="TypeAlias")) + text = ast.unparse(ast.ImportFrom(module="typing", names=names, level=0)) + "\n" + if need_type_alias_type: + text += "from typing_extensions import TypeAliasType\n" + replacements.append((node.lineno, _end_lineno(node), text)) + if not typing_handled and (need_type_alias or need_type_alias_type): + extra = "from typing import TypeAlias\n" if need_type_alias else "" + if need_type_alias_type: + extra += "from typing_extensions import TypeAliasType\n" + for node in tree.body: + if isinstance(node, ast.ImportFrom) and node.module == "__future__": + replacements.append((node.lineno, _end_lineno(node), lines[node.lineno - 1] + extra)) + break + + for start, end, new in sorted(replacements, reverse=True): + lines[start - 1 : end] = [new] + source = "".join(lines) + + # model_rebuild() is only valid on classes; drop calls for converted names. + for name in [*aliases, "Model"]: + source = re.sub(rf"^{name}\.model_rebuild\(\)\n", "", source, flags=re.MULTILINE) + + source = _JSDOC_LINK_RE.sub(r"\1", source) + return source, sorted(cyclic) + + +def assert_alias_blocks_present(source: str, recursive: list[str]) -> None: + """Assert every recursive alias survived post-processing into the output.""" + for name in recursive: + if not re.search(rf'^{name} = TypeAliasType\("{name}"', source, flags=re.MULTILINE): + raise PipelineError(f"recursive alias {name!r} is missing from the post-processed output") + + +def downgrade_value_transforms(source: str) -> str: + """Replace value-transforming pydantic types with plain ``str``. + + URL normalization and base64 re-encoding change bytes on a validate -> + re-dump round trip; the wire models must reproduce input bytes exactly. + """ + source = re.sub(r"\b(AnyUrl|FileUrl|Base64Str)\b", "str", source) + match = re.search(r"^from pydantic import (.+)$", source, flags=re.MULTILINE) + if match: + names = [n.strip() for n in match.group(1).split(",")] + kept = [n for n in names if n != "str"] + source = source.replace(match.group(0), f"from pydantic import {', '.join(kept)}") + return source + + +def widen_structured_content(source: str) -> str: + """Widen typed ``structuredContent`` fields to ``Any`` (2026-07-28 only). + + The 2026-07-28 schema types the field as any JSON value; the 2025-11-25 + surface keeps the schema's ``dict[str, Any]`` so this pass is gated. + """ + tree = ast.parse(source) + lines = source.splitlines(keepends=True) + statements = [ + stmt + for node in tree.body + if isinstance(node, ast.ClassDef) + for stmt in node.body + if isinstance(stmt, ast.AnnAssign) + and isinstance(stmt.target, ast.Name) + and stmt.target.id == "structured_content" + ] + for stmt in sorted(statements, key=lambda s: s.lineno, reverse=True): + start, end = stmt.lineno, _end_lineno(stmt) + segment = "".join(lines[start - 1 : end]) + lines[start - 1 : end] = [segment.replace("dict[str, Any]", "Any")] + return "".join(lines) + + +def _class_field_aliases(node: ast.ClassDef) -> list[tuple[ast.AnnAssign, str, str]]: + """(statement, field name, wire alias) for every annotated field of a class.""" + out: list[tuple[ast.AnnAssign, str, str]] = [] + for stmt in node.body: + if not isinstance(stmt, ast.AnnAssign) or not isinstance(stmt.target, ast.Name): + continue + annotation_text = ast.unparse(stmt.annotation) + alias_match = _FIELD_ALIAS_RE.search(annotation_text) + alias = alias_match.group(1) if alias_match else stmt.target.id + out.append((stmt, stmt.target.id, alias)) + return out + + +def apply_field_type_patches(source: str, patches: list[tuple[str, str, str]]) -> str: + """Rewrite the annotations listed in ``FIELD_TYPE_PATCHES`` for one version. + + Each patch names a (class, field) and the replacement annotation; the + generator's annotation is found via AST and the new one is spliced into the + same line range with a one-line provenance comment above it. + """ + if not patches: + return source + tree = ast.parse(source) + lines = source.splitlines(keepends=True) + classes: dict[str, ast.ClassDef] = {n.name: n for n in tree.body if isinstance(n, ast.ClassDef)} + replacements: list[tuple[int, int, str]] = [] + for cls_name, field_name, new_annotation in patches: + node = classes.get(cls_name) + if node is None: + raise PipelineError(f"field-type patch targets missing class {cls_name}") + stmt = next( + (s for s, name, _ in _class_field_aliases(node) if name == field_name), + None, + ) + if stmt is None: + raise PipelineError(f"field-type patch targets missing field {cls_name}.{field_name}") + default = f" = {ast.unparse(stmt.value)}" if stmt.value is not None else "" + new = f"{_NUMBER_PATCH_NOTE} {field_name}: {new_annotation}{default}\n" + replacements.append((stmt.lineno, _end_lineno(stmt), new)) + for start, end, new in sorted(replacements, reverse=True): + lines[start - 1 : end] = [new] + return "".join(lines) + + +def flatten_inheritance(source: str) -> str: + """Flatten classes that subclass other generated classes. + + The generator emits subclassing where one definition narrows another; + pyright's dataclass-transform rules reject the narrowed overrides, and the + committed packages carry no suppressions. Flattening re-declares inherited + fields directly: base fields in base order, overrides in place, own fields + appended. + """ + tree = ast.parse(source) + lines = source.splitlines(keepends=True) + classes: dict[str, ast.ClassDef] = {n.name: n for n in tree.body if isinstance(n, ast.ClassDef)} + + def field_segments(node: ast.ClassDef) -> list[tuple[str, str]]: + segments: list[tuple[str, str]] = [] + body = list(node.body) + for index, stmt in enumerate(body): + if not isinstance(stmt, ast.AnnAssign) or not isinstance(stmt.target, ast.Name): + continue + end = _end_lineno(stmt) + if index + 1 < len(body): + nxt = body[index + 1] + if isinstance(nxt, ast.Expr) and isinstance(nxt.value, ast.Constant): + if isinstance(nxt.value.value, str): + end = _end_lineno(nxt) + segments.append((stmt.target.id, "".join(lines[stmt.lineno - 1 : end]))) + return segments + + resolved: dict[str, list[tuple[str, str]]] = {} + + def resolve(name: str) -> list[tuple[str, str]]: + if name in resolved: + return resolved[name] + node = classes[name] + base_names = [b.id for b in node.bases if isinstance(b, ast.Name) and b.id in classes] + merged: list[tuple[str, str]] = [] + for base in base_names: + for field_name, text in resolve(base): + if field_name not in {n for n, _ in merged}: + merged.append((field_name, text)) + for field_name, text in field_segments(node): + existing = [i for i, (n, _) in enumerate(merged) if n == field_name] + if existing: + merged[existing[0]] = (field_name, text) + else: + merged.append((field_name, text)) + resolved[name] = merged + return merged + + replacements: list[tuple[int, int, str]] = [] + for name, node in classes.items(): + generated_bases = [b.id for b in node.bases if isinstance(b, ast.Name) and b.id in classes] + if not generated_bases: + continue + parts: list[str] = [f"class {name}(WireModel):\n"] + if ast.get_docstring(node) is not None: + stmt = node.body[0] + parts.append("".join(lines[stmt.lineno - 1 : _end_lineno(stmt)])) + parts.extend( + "".join(lines[stmt.lineno - 1 : _end_lineno(stmt)]) + for stmt in node.body + if isinstance(stmt, ast.Assign) + and any(isinstance(t, ast.Name) and t.id == "model_config" for t in stmt.targets) + ) + parts.extend(text for _, text in resolve(name)) + replacements.append((node.lineno, _end_lineno(node), "".join(parts))) + + for start, end, new in sorted(replacements, reverse=True): + lines[start - 1 : end] = [new] + return "".join(lines) + + +def rebase_meta_carriers(source: str) -> tuple[str, list[str]]: + """Rebase classes referenced from ``_meta`` fields onto ``OpenWireModel``.""" + tree = ast.parse(source) + classes: dict[str, ast.ClassDef] = {n.name: n for n in tree.body if isinstance(n, ast.ClassDef)} + carriers: set[str] = set() + for node in classes.values(): + for stmt, _, alias in _class_field_aliases(node): + if alias != "_meta": + continue + annotation_text = ast.unparse(stmt.annotation) + carriers.update(name for name in classes if re.search(rf"\b{name}\b", annotation_text)) + for name in sorted(carriers): + source = re.sub( + rf"^class {name}\(WireModel\):$", + f"class {name}(OpenWireModel):", + source, + flags=re.MULTILINE, + ) + return source, sorted(carriers) + + +def apply_extra_policy(source: str, carriers: list[str]) -> str: + """Force ``extra="ignore"`` everywhere except the enumerated open classes.""" + tree = ast.parse(source) + lines = source.splitlines(keepends=True) + classes: dict[str, ast.ClassDef] = {n.name: n for n in tree.body if isinstance(n, ast.ClassDef)} + + keep_allow: set[str] = set() + for node in classes.values(): + for stmt, _, alias in _class_field_aliases(node): + if alias in _OPEN_INTERIOR_FIELD_ALIASES: + annotation_text = ast.unparse(stmt.annotation) + keep_allow.update(name for name in classes if re.search(rf"\b{name}\b", annotation_text)) + if "SubscriptionFilter" in classes: + keep_allow.add("SubscriptionFilter") + + replacements: list[tuple[int, int, str]] = [] + for name, node in classes.items(): + config_stmt = next( + ( + stmt + for stmt in node.body + if isinstance(stmt, ast.Assign) + and any(isinstance(t, ast.Name) and t.id == "model_config" for t in stmt.targets) + ), + None, + ) + if config_stmt is None: + continue + value = config_stmt.value + is_plain_allow = ( + isinstance(value, ast.Call) + and isinstance(value.func, ast.Name) + and value.func.id == "ConfigDict" + and len(value.keywords) == 1 + and value.keywords[0].arg == "extra" + and isinstance(value.keywords[0].value, ast.Constant) + and value.keywords[0].value.value == "allow" + ) + if not is_plain_allow: + raise PipelineError(f"unexpected model_config on {name}: {ast.unparse(config_stmt)}") + if name in keep_allow and name not in carriers: + comment = _SUBSCRIPTION_FILTER_COMMENT if name == "SubscriptionFilter" else _OPEN_INTERIOR_COMMENT + replacements.append((config_stmt.lineno, config_stmt.lineno - 1, comment)) + continue + remaining = [stmt for stmt in node.body if stmt is not config_stmt] + new = "" if remaining else " pass\n" + replacements.append((config_stmt.lineno, _end_lineno(config_stmt), new)) + + for start, end, new in sorted(replacements, reverse=True): + lines[start - 1 : end] = [new] + return "".join(lines) + + +def deterministic_synthetic_names(source: str) -> str: + """Rename counter-based synthetic classes after their single owner.""" + tree = ast.parse(source) + classes: dict[str, ast.ClassDef] = {n.name: n for n in tree.body if isinstance(n, ast.ClassDef)} + synthetic = {name for name in classes if re.fullmatch(r"(?:Params|Meta)\d*", name)} + references: dict[str, list[tuple[str, str]]] = {name: [] for name in synthetic} + for node in classes.values(): + for stmt, field_name, _ in _class_field_aliases(node): + annotation_text = ast.unparse(stmt.annotation) + for name in synthetic: + if re.search(rf"\b{name}\b", annotation_text): + references[name].append((node.name, field_name)) + + renames: dict[str, str] = {} + taken = set(classes) + for name in sorted(synthetic): + refs = references[name] + if len(refs) != 1: + continue + owner, field_name = refs[0] + suffix = {"params": "Params", "meta": "Meta"}.get(field_name) + if suffix is None: + continue + target = f"{owner}{suffix}" + if target in taken: + continue + renames[name] = target + taken.add(target) + + if renames: + pattern = re.compile(r"\b(" + "|".join(sorted(renames, key=len, reverse=True)) + r")\b") + source = pattern.sub(lambda m: renames[m.group(1)], source) + return source + + +def _join_class_docstring_summaries(source: str) -> str: + """Move each class docstring summary onto the opening quote line. + + The D212 fix, applied first so the long-line wrapping below stays in + charge of the resulting line length. + """ + tree = ast.parse(source) + lines = source.splitlines(keepends=True) + for node in tree.body: + if not isinstance(node, ast.ClassDef) or ast.get_docstring(node) is None: + continue + stmt = node.body[0] + first = lines[stmt.lineno - 1] + if first.strip() != '"""' or _end_lineno(stmt) == stmt.lineno: + continue + summary = lines[stmt.lineno].strip() + single_content = _end_lineno(stmt) == stmt.lineno + 2 + indent = first[: len(first) - len(first.lstrip())] + if single_content: + if len(indent) + len(summary) + 6 <= 120: + lines[stmt.lineno - 1] = f'{indent}"""{summary}"""\n' + lines[stmt.lineno] = "" + lines[stmt.lineno + 1] = "" + else: + wrapped = textwrap.wrap( + summary, + width=117, + initial_indent=indent + '"""', + subsequent_indent=indent, + break_long_words=False, + break_on_hyphens=False, + ) + lines[stmt.lineno - 1] = "".join(part + "\n" for part in wrapped) + lines[stmt.lineno] = "" + continue + lines[stmt.lineno - 1] = first.rstrip("\n") + summary + "\n" + lines[stmt.lineno] = "" + return "".join(lines) + + +def wrap_docstrings(source: str) -> str: + """Wrap docstring lines to the repo line length (no per-file E501 exemption).""" + source = _join_class_docstring_summaries(source) + out: list[str] = [] + in_docstring = False + for line in source.splitlines(keepends=True): + quotes = line.count('"""') + long = len(line.rstrip("\n")) > 120 + indent = line[: len(line) - len(line.lstrip())] + if not in_docstring: + if quotes == 1: + in_docstring = True + if long: + out.extend( + part + "\n" + for part in textwrap.wrap( + line.strip().removeprefix('"""'), + width=120, + initial_indent=indent + '"""', + subsequent_indent=indent, + break_long_words=False, + break_on_hyphens=False, + ) + ) + continue + out.append(line) + continue + if quotes: + in_docstring = False + out.append(line) + continue + if not long: + out.append(line) + continue + out.extend( + part + "\n" + for part in textwrap.wrap( + line.strip(), + width=120, + initial_indent=indent, + subsequent_indent=indent, + break_long_words=False, + break_on_hyphens=False, + ) + ) + return "".join(out) + + +def assert_only_wire_bases(source: str) -> None: + """Assert every class in the emitted package sits on one of the two bases.""" + tree = ast.parse(source) + for node in tree.body: + if not isinstance(node, ast.ClassDef): + continue + base_names = [ast.unparse(b) for b in node.bases] + if base_names not in (["WireModel"], ["OpenWireModel"]): + raise PipelineError(f"class {node.name} has unexpected bases {base_names} after the src passes") + + +def run_ruff(path: Path) -> None: + """ruff check --fix + format with the repo config; abort on any residual finding.""" + common = ["uv", "run", "--frozen", "ruff"] + fix = subprocess.run( + [*common, "check", "--no-cache", "--fix", "--exit-zero", str(path)], + cwd=REPO_ROOT, + capture_output=True, + text=True, + ) + if fix.returncode != 0: + raise PipelineError(f"ruff check --fix failed:\n{fix.stderr.strip()}") + fmt = subprocess.run([*common, "format", "--no-cache", str(path)], cwd=REPO_ROOT, capture_output=True, text=True) + if fmt.returncode != 0: + raise PipelineError(f"ruff format failed:\n{fmt.stderr.strip()}") + report = subprocess.run( + [*common, "check", "--no-cache", "--output-format", "json", "--exit-zero", str(path)], + cwd=REPO_ROOT, + capture_output=True, + text=True, + ) + if report.returncode != 0: + raise PipelineError(f"ruff check (report) failed:\n{report.stderr.strip()}") + findings: list[dict[str, Any]] = json.loads(report.stdout) + if findings: + details = "\n".join( + f" {f.get('code')}: {f.get('message')} (line {f.get('location', {}).get('row')})" for f in findings + ) + raise PipelineError(f"ruff residual findings in {path.name}:\n{details}") + + +def schema_defs(schema: dict[str, Any]) -> dict[str, Any]: + """The definitions table of a schema ($defs in 2020-12, definitions in draft-07).""" + defs = schema.get("$defs") or schema.get("definitions") + if not defs: + raise PipelineError("schema has no $defs/definitions table") + return defs + + +def import_candidate(path: Path, module: str) -> ModuleType: + """Import a staged candidate module under a private name.""" + name = f"_candidate_{module}" + spec = importlib.util.spec_from_file_location(name, path) + if spec is None or spec.loader is None: + raise PipelineError(f"cannot load candidate module from {path}") + mod = importlib.util.module_from_spec(spec) + sys.modules[name] = mod + spec.loader.exec_module(mod) + return mod + + +def audit_candidate(mod: ModuleType, schema: dict[str, Any], entry: Entry) -> None: + """Def-name + alias + requiredness audit; raises on any failure.""" + problems: list[str] = [] + for def_name, def_schema in schema_defs(schema).items(): + obj = getattr(mod, def_name, None) + if obj is None: + problems.append(f"def {def_name!r} does not resolve to a module attribute") + continue + if not (isinstance(obj, type) and issubclass(obj, BaseModel)): + continue + properties: dict[str, Any] = def_schema.get("properties", {}) + required: list[str] = def_schema.get("required", []) + fields_by_wire_name = { + (info.serialization_alias or info.alias or field_name): info + for field_name, info in obj.model_fields.items() + } + for prop_name in properties: + info = fields_by_wire_name.get(prop_name) + if info is None: + problems.append(f"{def_name}: no field with wire name {prop_name!r}") + continue + if info.is_required() != (prop_name in required): + problems.append( + f"{def_name}.{prop_name}: requiredness mismatch " + f"(model={info.is_required()}, schema={prop_name in required})" + ) + if problems: + raise PipelineError(f"{entry.protocol_version}: audit failed:\n" + "\n".join(f" - {p}" for p in problems)) + + +def _annotation_models(annotation: Any) -> list[type[BaseModel]]: + """Model classes appearing anywhere in an annotation.""" + if isinstance(annotation, type) and issubclass(annotation, BaseModel): + return [annotation] + found: list[type[BaseModel]] = [] + for arg in typing.get_args(annotation): + found.extend(_annotation_models(arg)) + return found + + +def audit_meta_carriers(mod: ModuleType, entry: Entry) -> None: + """Assert every ``_meta`` field is open: a dict, or an extra='allow' model.""" + problems: list[str] = [] + for name in dir(mod): + obj = getattr(mod, name) + if not (isinstance(obj, type) and issubclass(obj, BaseModel)): + continue + for field_name, info in obj.model_fields.items(): + if (info.serialization_alias or info.alias or field_name) != "_meta": + continue + problems.extend( + f"{name}._meta references {referenced.__name__}, which is not extra='allow'" + for referenced in _annotation_models(info.annotation) + if referenced.model_config.get("extra") != "allow" + ) + if problems: + raise PipelineError( + f"{entry.protocol_version}: _meta carrier audit failed:\n" + "\n".join(f" - {p}" for p in problems) + ) + + +def build_candidate(entry: Entry) -> str: + """Full pipeline for one entry; returns the formatted, audited source text.""" + schema: dict[str, Any] = json.loads(entry.schema_file.read_text()) + + with tempfile.TemporaryDirectory() as tmp: + raw_file = Path(tmp) / "raw.py" + run_generator(entry.schema_file, raw_file) + source, recursive = postprocess(raw_file.read_text(), ALIAS_TYPE_PATCHES.get(entry.protocol_version, {})) + assert_alias_blocks_present(source, recursive) + + source = downgrade_value_transforms(source) + if entry.protocol_version == "2026-07-28": + source = widen_structured_content(source) + source = flatten_inheritance(source) + source, carriers = rebase_meta_carriers(source) + if carriers: + source = source.replace( + "from mcp.types._wire_base import WireModel", + "from mcp.types._wire_base import OpenWireModel, WireModel", + ) + source = apply_extra_policy(source, carriers) + source = deterministic_synthetic_names(source) + source = apply_field_type_patches(source, FIELD_TYPE_PATCHES.get(entry.protocol_version, [])) + source = wrap_docstrings(source) + + epilogue = EPILOGUES.get(entry.protocol_version, "") + if epilogue: + # Before model_rebuild(), not after: pyright's evaluation order for the + # recursive TypeAliasType block at the top is sensitive to where the + # last cross-module-referenced symbol sits. + match = re.search(r"^\w+\.model_rebuild\(\)$", source, flags=re.MULTILINE) + cut = match.start() if match else len(source) + source = source[:cut] + epilogue + "\n\n" + source[cut:] + header = SRC_HEADERS[entry.protocol_version].format(spec_commit=entry.spec_commit) + + staging = SRC_TYPES_DIR / f"_staging_{entry.module}.py" + try: + staging.write_text(header + source) + run_ruff(staging) + candidate = staging.read_text() + assert_only_wire_bases(candidate) + mod = import_candidate(staging, entry.module) + audit_candidate(mod, schema, entry) + audit_meta_carriers(mod, entry) + finally: + staging.unlink(missing_ok=True) + return candidate + + +def main(argv: list[str] | None = None) -> int: + """CLI entry point.""" + parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter) + parser.add_argument("--check", action="store_true", help="diff regenerated output against committed files") + args = parser.parse_args(argv) + + if importlib.util.find_spec("mcp.types._wire_base") is None: + raise PipelineError("src/mcp/types/_wire_base.py (WireModel/OpenWireModel) is required") + + entries = load_pinned() + drifted: list[str] = [] + for entry in entries: + candidate = build_candidate(entry) + if args.check: + committed = entry.target.read_text() if entry.target.is_file() else "" + if committed == candidate: + print(f"{entry.protocol_version}: ok ({entry.target.relative_to(REPO_ROOT)})") + else: + drifted.append(entry.protocol_version) + diff = difflib.unified_diff( + committed.splitlines(keepends=True), + candidate.splitlines(keepends=True), + fromfile=str(entry.target.relative_to(REPO_ROOT)), + tofile="", + ) + sys.stderr.writelines(diff) + else: + entry.target.parent.mkdir(parents=True, exist_ok=True) + entry.target.write_text(candidate) + print(f"{entry.protocol_version}: wrote {entry.target.relative_to(REPO_ROOT)} ({len(candidate)} bytes)") + + if drifted: + print( + f"DRIFT: {drifted} differ from committed output; " + "run `uv run --group codegen python scripts/gen_surface_types.py`", + file=sys.stderr, + ) + return 1 + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/src/mcp/shared/version.py b/src/mcp/shared/version.py index 44154da365..2299de72ec 100644 --- a/src/mcp/shared/version.py +++ b/src/mcp/shared/version.py @@ -16,6 +16,7 @@ "2025-03-26", "2025-06-18", "2025-11-25", + "2026-07-28", ) """Every released protocol revision, oldest to newest.""" diff --git a/src/mcp/types/__init__.py b/src/mcp/types/__init__.py index b2d537fb70..7628f9ac20 100644 --- a/src/mcp/types/__init__.py +++ b/src/mcp/types/__init__.py @@ -1,22 +1,30 @@ """This module defines the types for the MCP protocol. Check the latest schema at: -https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/schema/2025-11-25/schema.json +https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/schema/draft/schema.json """ # Re-export everything from _types for backward compatibility from mcp.types._types import ( + CLIENT_CAPABILITIES_META_KEY, + CLIENT_INFO_META_KEY, DEFAULT_NEGOTIATED_VERSION, LATEST_PROTOCOL_VERSION, + LOG_LEVEL_META_KEY, + PROTOCOL_VERSION_META_KEY, Annotations, AudioContent, BaseMetadata, BlobResourceContents, + CacheableResult, CallToolRequest, CallToolRequestParams, CallToolResult, CancelledNotification, CancelledNotificationParams, + CancelTaskRequest, + CancelTaskRequestParams, + CancelTaskResult, ClientCapabilities, ClientNotification, ClientRequest, @@ -33,6 +41,9 @@ CreateMessageRequestParams, CreateMessageResult, CreateMessageResultWithTools, + CreateTaskResult, + DiscoverRequest, + DiscoverResult, ElicitationCapability, ElicitationRequiredErrorData, ElicitCompleteNotification, @@ -49,6 +60,12 @@ GetPromptRequest, GetPromptRequestParams, GetPromptResult, + GetTaskPayloadRequest, + GetTaskPayloadRequestParams, + GetTaskPayloadResult, + GetTaskRequest, + GetTaskRequestParams, + GetTaskResult, Icon, IconTheme, ImageContent, @@ -58,6 +75,12 @@ InitializeRequest, InitializeRequestParams, InitializeResult, + InputRequest, + InputRequests, + InputRequiredResult, + InputResponse, + InputResponseRequestParams, + InputResponses, ListPromptsRequest, ListPromptsResult, ListResourcesRequest, @@ -66,12 +89,15 @@ ListResourceTemplatesResult, ListRootsRequest, ListRootsResult, + ListTasksRequest, + ListTasksResult, ListToolsRequest, ListToolsResult, LoggingCapability, LoggingLevel, LoggingMessageNotification, LoggingMessageNotificationParams, + MissingRequiredClientCapabilityErrorData, ModelHint, ModelPreferences, Notification, @@ -92,6 +118,7 @@ ReadResourceRequest, ReadResourceRequestParams, ReadResourceResult, + RelatedTaskMetadata, Request, RequestParams, RequestParamsMeta, @@ -105,6 +132,7 @@ ResourceUpdatedNotification, ResourceUpdatedNotificationParams, Result, + ResultType, Role, Root, RootsCapability, @@ -124,17 +152,29 @@ StopReason, SubscribeRequest, SubscribeRequestParams, + SubscriptionFilter, + SubscriptionsAcknowledgedNotification, + SubscriptionsAcknowledgedNotificationParams, + SubscriptionsListenRequest, + SubscriptionsListenRequestParams, + Task, + TaskMetadata, + TaskStatus, + TaskStatusNotification, + TaskStatusNotificationParams, TextContent, TextResourceContents, Tool, ToolAnnotations, ToolChoice, + ToolExecution, ToolListChangedNotification, ToolResultContent, ToolsCapability, ToolUseContent, UnsubscribeRequest, UnsubscribeRequestParams, + UnsupportedProtocolVersionErrorData, UrlElicitationCapability, client_notification_adapter, client_request_adapter, @@ -150,9 +190,12 @@ INTERNAL_ERROR, INVALID_PARAMS, INVALID_REQUEST, + JSONRPC_VERSION, METHOD_NOT_FOUND, + MISSING_REQUIRED_CLIENT_CAPABILITY, PARSE_ERROR, REQUEST_TIMEOUT, + UNSUPPORTED_PROTOCOL_VERSION, URL_ELICITATION_REQUIRED, ErrorData, JSONRPCError, @@ -168,17 +211,28 @@ # Protocol version constants "LATEST_PROTOCOL_VERSION", "DEFAULT_NEGOTIATED_VERSION", + # Reserved request _meta keys + "PROTOCOL_VERSION_META_KEY", + "CLIENT_INFO_META_KEY", + "CLIENT_CAPABILITIES_META_KEY", + "LOG_LEVEL_META_KEY", # Type aliases and variables "ContentBlock", "ElicitRequestedSchema", "ElicitRequestParams", "IncludeContext", + "InputRequest", + "InputRequests", + "InputResponse", + "InputResponses", "LoggingLevel", "ProgressToken", + "ResultType", "Role", "SamplingContent", "SamplingMessageContentBlock", "StopReason", + "TaskStatus", # Base classes "BaseMetadata", "Request", @@ -186,10 +240,12 @@ "Result", "RequestParams", "RequestParamsMeta", + "InputResponseRequestParams", "NotificationParams", "PaginatedRequest", "PaginatedRequestParams", "PaginatedResult", + "CacheableResult", "EmptyResult", # Capabilities "ClientCapabilities", @@ -236,27 +292,40 @@ "ResourceTemplateReference", "Root", "SamplingMessage", + "SubscriptionFilter", + "Task", + "TaskMetadata", + "RelatedTaskMetadata", "Tool", "ToolAnnotations", "ToolChoice", + "ToolExecution", # Requests "CallToolRequest", "CallToolRequestParams", "CompleteRequest", "CompleteRequestParams", + "CancelTaskRequest", + "CancelTaskRequestParams", "CreateMessageRequest", "CreateMessageRequestParams", + "DiscoverRequest", "ElicitRequest", "ElicitRequestFormParams", "ElicitRequestURLParams", "GetPromptRequest", "GetPromptRequestParams", + "GetTaskPayloadRequest", + "GetTaskPayloadRequestParams", + "GetTaskRequest", + "GetTaskRequestParams", "InitializeRequest", "InitializeRequestParams", "ListPromptsRequest", "ListResourcesRequest", "ListResourceTemplatesRequest", "ListRootsRequest", + "ListTasksRequest", "ListToolsRequest", "PingRequest", "ReadResourceRequest", @@ -265,23 +334,35 @@ "SetLevelRequestParams", "SubscribeRequest", "SubscribeRequestParams", + "SubscriptionsListenRequest", + "SubscriptionsListenRequestParams", "UnsubscribeRequest", "UnsubscribeRequestParams", # Results "CallToolResult", + "CancelTaskResult", "CompleteResult", "CreateMessageResult", "CreateMessageResultWithTools", + "CreateTaskResult", + "DiscoverResult", "ElicitResult", "ElicitationRequiredErrorData", "GetPromptResult", + "GetTaskPayloadResult", + "GetTaskResult", "InitializeResult", + "InputRequiredResult", "ListPromptsResult", "ListResourcesResult", "ListResourceTemplatesResult", "ListRootsResult", + "ListTasksResult", "ListToolsResult", "ReadResourceResult", + # Error data payloads + "MissingRequiredClientCapabilityErrorData", + "UnsupportedProtocolVersionErrorData", # Notifications "CancelledNotification", "CancelledNotificationParams", @@ -297,6 +378,10 @@ "ResourceUpdatedNotification", "ResourceUpdatedNotificationParams", "RootsListChangedNotification", + "SubscriptionsAcknowledgedNotification", + "SubscriptionsAcknowledgedNotificationParams", + "TaskStatusNotification", + "TaskStatusNotificationParams", "ToolListChangedNotification", # Union types for request/response routing "ClientNotification", @@ -317,9 +402,12 @@ "INTERNAL_ERROR", "INVALID_PARAMS", "INVALID_REQUEST", + "JSONRPC_VERSION", "METHOD_NOT_FOUND", + "MISSING_REQUIRED_CLIENT_CAPABILITY", "PARSE_ERROR", "REQUEST_TIMEOUT", + "UNSUPPORTED_PROTOCOL_VERSION", "URL_ELICITATION_REQUIRED", "ErrorData", "JSONRPCError", diff --git a/src/mcp/types/_types.py b/src/mcp/types/_types.py index e9d39ef6f3..598448f4b2 100644 --- a/src/mcp/types/_types.py +++ b/src/mcp/types/_types.py @@ -1,20 +1,34 @@ +"""Version-superset MCP protocol models. + +One model per protocol construct, carrying every field from every supported +protocol version, so application code sees a single set of types regardless of +the negotiated version. Per-field docstrings note version availability. The +`mcp.types.v*` surface packages carry the schema-exact wire shapes. +""" + from __future__ import annotations -from typing import Annotated, Any, Generic, Literal, TypeAlias, TypeVar +from typing import Annotated, Any, Final, Generic, Literal, TypeAlias, TypeVar -from pydantic import BaseModel, ConfigDict, Field, FileUrl, TypeAdapter +from pydantic import ( + BaseModel, + ConfigDict, + Field, + FileUrl, + TypeAdapter, +) from pydantic.alias_generators import to_camel from typing_extensions import NotRequired, TypedDict from mcp.types.jsonrpc import RequestId -LATEST_PROTOCOL_VERSION = "2025-11-25" -"""The latest version of the Model Context Protocol. +LATEST_PROTOCOL_VERSION: Final[str] = "2025-11-25" +"""The newest protocol version this SDK can negotiate. -You can find the latest specification at https://modelcontextprotocol.io/specification/latest. +See https://modelcontextprotocol.io/specification/latest. """ -DEFAULT_NEGOTIATED_VERSION = "2025-03-26" +DEFAULT_NEGOTIATED_VERSION: Final[str] = "2025-03-26" """The default negotiated version of the Model Context Protocol when no version is specified. We need this to satisfy the MCP specification, which requires the server to assume a specific version if none is @@ -25,9 +39,12 @@ """ ProgressToken = str | int +"""A progress token, used to associate progress notifications with the original request.""" Role = Literal["user", "assistant"] +"""The sender or recipient of messages and data in a conversation.""" IconTheme = Literal["light", "dark"] +"""Theme an icon is designed for. Wire values of `Icon.theme` (2025-11-25+).""" class MCPModel(BaseModel): @@ -38,8 +55,33 @@ class MCPModel(BaseModel): Meta: TypeAlias = dict[str, Any] +PROTOCOL_VERSION_META_KEY = "io.modelcontextprotocol/protocolVersion" +"""Reserved request `_meta` key: the MCP protocol version for this request (2026-07-28). + +SDK-managed; for HTTP its value must match the `MCP-Protocol-Version` header. +""" + +CLIENT_INFO_META_KEY = "io.modelcontextprotocol/clientInfo" +"""Reserved request `_meta` key: the client `Implementation` (2026-07-28). SDK-managed.""" + +CLIENT_CAPABILITIES_META_KEY = "io.modelcontextprotocol/clientCapabilities" +"""Reserved request `_meta` key: per-request `ClientCapabilities` (2026-07-28). SDK-managed.""" + +LOG_LEVEL_META_KEY = "io.modelcontextprotocol/logLevel" +"""Reserved request `_meta` key: desired log level for this request (2026-07-28). + +Deprecated (with the rest of logging) by SEP-2577 in the same revision that +introduces it. If absent, the server must not send log notifications. +""" + class RequestParamsMeta(TypedDict, extra_items=Any): + """The `_meta` object on request params (schema name: `RequestMetaObject`). + + An open map: arbitrary keys round-trip via `extra_items=Any`. Read or set + the reserved `io.modelcontextprotocol/*` keys via the `*_META_KEY` constants. + """ + progress_token: NotRequired[ProgressToken] """ If specified, the caller requests out-of-band progress notifications for @@ -51,6 +93,13 @@ class RequestParamsMeta(TypedDict, extra_items=Any): class RequestParams(MCPModel): meta: RequestParamsMeta | None = Field(alias="_meta", default=None) + """Metadata reserved by MCP for protocol-level concerns (wire name `_meta`). + + Carries the optional progress token and, on 2026-07-28+ sessions, the + reserved `io.modelcontextprotocol/*` keys. Required on the wire for + 2026-07-28+ client requests; the session layer supplies the reserved + entries, so code sending through an SDK session leaves this unset. + """ class PaginatedRequestParams(RequestParams): @@ -75,7 +124,11 @@ class NotificationParams(MCPModel): class Request(MCPModel, Generic[RequestParamsT, MethodT]): - """Base class for JSON-RPC requests.""" + """Base class for JSON-RPC requests. + + The JSON-RPC envelope (`jsonrpc`, `id`) is attached by the session layer + (see `mcp.types.jsonrpc`), not carried here. + """ method: MethodT params: RequestParamsT @@ -85,6 +138,8 @@ class PaginatedRequest(Request[PaginatedRequestParams | None, MethodT], Generic[ """Base class for paginated requests, matching the schema's PaginatedRequest interface.""" params: PaginatedRequestParams | None = None + """Pagination params. Required on the 2026-07-28+ wire (because `_meta` is); + the session layer materializes it there. Optional on earlier versions.""" class Notification(MCPModel, Generic[NotificationParamsT, MethodT]): @@ -94,8 +149,23 @@ class Notification(MCPModel, Generic[NotificationParamsT, MethodT]): params: NotificationParamsT +ResultType = Literal["complete", "input_required"] | str +"""Tags a `Result` so the client knows how to parse it (2026-07-28). + +"complete" means the result is final; "input_required" means it is an +`InputRequiredResult`. The union is open (the tasks extension reserves "task"). +Absent `resultType` is equivalent to "complete". +""" + + class Result(MCPModel): - """Base class for JSON-RPC results.""" + """Base class for JSON-RPC results. + + `result_type` is declared per concrete subclass, not here, because defaults + differ: most results default to "complete", `EmptyResult` defaults to None + (so it dumps as `{}`; some peer SDKs strict-validate empty results), and + `InputRequiredResult` carries a literal. + """ meta: Meta | None = Field(alias="_meta", default=None) """ @@ -112,15 +182,42 @@ class PaginatedResult(Result): """ +class CacheableResult(Result): + """Base class for results that carry client-side caching directives (2026-07-28). + + Both fields are required on the 2026-07-28 wire and always serialized by + this SDK; older peers ignore the extra keys. The defaults are SDK choices + (the schema declares none). + """ + + ttl_ms: Annotated[int, Field(ge=0)] = 0 + """How long (ms) the client MAY cache this response, analogous to HTTP + `Cache-Control: max-age`. 0 means immediately stale.""" + + cache_scope: Literal["public", "private"] = "private" + """Analogous to HTTP `Cache-Control: public` vs `private`: "public" allows + shared caches to serve the response to any user; "private" forbids that.""" + + class EmptyResult(Result): - """A response that indicates success but carries no data.""" + """A result that indicates success but carries no data. + + `result_type` defaults to None so this dumps as `{}`: deployed TypeScript + and Rust SDK clients validate empty results strictly and reject extra keys. + The 2026-07-28 schema requires `resultType`, so code answering an empty + result on a 2026-07-28+ session must pass `result_type="complete"`. + """ + + result_type: ResultType | None = None + """None keeps the dump empty; see the class docstring.""" class BaseMetadata(MCPModel): - """Base class for entities with name and optional title fields.""" + """Base class for entities with a programmatic name and an optional display title.""" name: str - """The programmatic name of the entity.""" + """Intended for programmatic or logical use, but used as a display name in past + specs or fallback (if title isn't present).""" title: str | None = None """ @@ -134,35 +231,30 @@ class BaseMetadata(MCPModel): class Icon(MCPModel): - """An icon for display in user interfaces.""" + """An optionally-sized icon for display in a user interface (2025-11-25+).""" src: str - """URL or data URI for the icon.""" + """A standard URI pointing to an icon resource (`http(s):` or `data:`). + + Consumers SHOULD ensure icon URLs come from a trusted domain and SHOULD + take appropriate precautions when consuming SVGs (which can contain script). + """ mime_type: str | None = None - """Optional MIME type for the icon.""" + """Optional MIME type override if the source MIME type is missing or generic.""" sizes: list[str] | None = None - """Optional list of strings specifying icon dimensions (e.g., ["48x48", "96x96"]).""" + """Optional sizes this icon is available in: WxH (e.g. `"48x48"`) or `"any"`. + If not provided, assume the icon can be used at any size.""" theme: IconTheme | None = None - """Optional theme specifier. - - `"light"` indicates the icon is designed for a light background, `"dark"` indicates the icon - is designed for a dark background. - - See https://modelcontextprotocol.io/specification/2025-11-25/schema#icon for more details. - """ + """The theme this icon is designed for. If not provided, assume any theme.""" class Implementation(BaseMetadata): - """Describes the name and version of an MCP implementation.""" + """Describes the name and version of an MCP implementation (`clientInfo` / `serverInfo`).""" version: str - - title: str | None = None - """An optional human-readable title for this implementation.""" - description: str | None = None """An optional human-readable description of what this implementation does.""" @@ -170,11 +262,15 @@ class Implementation(BaseMetadata): """An optional URL of the website for this implementation.""" icons: list[Icon] | None = None - """An optional list of icons for this implementation.""" + """Optional set of sized icons that the client can display in a user interface.""" class RootsCapability(MCPModel): - """Capability for root operations.""" + """Capability for root operations. + + Deprecated in protocol 2026-07-28 (SEP-2577) but still carried there as an + empty object (`list_changed` exists only through 2025-11-25). + """ list_changed: bool | None = None """Whether the client supports notifications for changes to the roots list.""" @@ -201,7 +297,7 @@ class FormElicitationCapability(MCPModel): class UrlElicitationCapability(MCPModel): - """Capability for URL mode elicitation.""" + """Capability for URL mode elicitation (2025-11-25+).""" class ElicitationCapability(MCPModel): @@ -214,11 +310,11 @@ class ElicitationCapability(MCPModel): """Present if the client supports form mode elicitation.""" url: UrlElicitationCapability | None = None - """Present if the client supports URL mode elicitation.""" + """Present if the client supports URL mode elicitation (2025-11-25 and later).""" class SamplingCapability(MCPModel): - """Sampling capability structure, allowing fine-grained capability advertisement.""" + """Sampling capability structure. Deprecated in 2026-07-28 (SEP-2577); shape unchanged.""" context: SamplingContextCapability | None = None """ @@ -232,8 +328,55 @@ class SamplingCapability(MCPModel): """ +class TasksListCapability(MCPModel): + """Capability for tasks listing operations (2025-11-25 only).""" + + +class TasksCancelCapability(MCPModel): + """Capability for tasks cancel operations (2025-11-25 only).""" + + +class TasksCreateMessageCapability(MCPModel): + """Capability for task-augmented sampling/createMessage requests (2025-11-25 only).""" + + +class TasksSamplingCapability(MCPModel): + """Capability for task-augmented sampling operations (2025-11-25 only).""" + + create_message: TasksCreateMessageCapability | None = None + + +class TasksCreateElicitationCapability(MCPModel): + """Capability for task-augmented elicitation/create requests (2025-11-25 only).""" + + +class TasksElicitationCapability(MCPModel): + """Capability for task-augmented elicitation operations (2025-11-25 only).""" + + create: TasksCreateElicitationCapability | None = None + + +class ClientTasksRequestsCapability(MCPModel): + """Specifies which request types the client can augment with tasks (2025-11-25 only).""" + + sampling: TasksSamplingCapability | None = None + elicitation: TasksElicitationCapability | None = None + + +class ClientTasksCapability(MCPModel): + """Capability for client tasks operations (2025-11-25 only).""" + + list: TasksListCapability | None = None + cancel: TasksCancelCapability | None = None + requests: ClientTasksRequestsCapability | None = None + + class ClientCapabilities(MCPModel): - """Capabilities a client may support.""" + """Capabilities a client may support. + + Not a closed set: any client can define additional capabilities. Sent once in + `initialize` through 2025-11-25; per-request in `_meta` on 2026-07-28. + """ experimental: dict[str, dict[str, Any]] | None = None """Experimental, non-standard capabilities that the client supports.""" @@ -246,6 +389,27 @@ class ClientCapabilities(MCPModel): """Present if the client supports elicitation from the user.""" roots: RootsCapability | None = None """Present if the client supports listing roots.""" + extensions: dict[str, dict[str, Any]] | None = None + """MCP extensions the client supports (2026-07-28). Keys are extension + identifiers; values are per-extension settings (empty object = no settings).""" + tasks: ClientTasksCapability | None = None + """Present if the client supports task-augmented requests (2025-11-25 only).""" + + +class UnsupportedProtocolVersionErrorData(MCPModel): + """Error data for the -32004 unsupported-protocol-version error (2026-07-28).""" + + supported: list[str] + """Protocol versions the server supports; the client should pick one and retry.""" + + requested: str + + +class MissingRequiredClientCapabilityErrorData(MCPModel): + """Error data for the -32003 missing-required-client-capability error (2026-07-28).""" + + required_capabilities: ClientCapabilities + """The capabilities the server requires from the client to process this request.""" class PromptsCapability(MCPModel): @@ -279,14 +443,39 @@ class CompletionsCapability(MCPModel): """Capability for completions operations.""" +class TasksCallCapability(MCPModel): + """Capability for task-augmented tools/call requests (2025-11-25 only).""" + + +class TasksToolsCapability(MCPModel): + """Capability for task-augmented tool operations (2025-11-25 only).""" + + call: TasksCallCapability | None = None + + +class ServerTasksRequestsCapability(MCPModel): + """Specifies which request types the server can augment with tasks (2025-11-25 only).""" + + tools: TasksToolsCapability | None = None + + +class ServerTasksCapability(MCPModel): + """Capability for server tasks operations (2025-11-25 only).""" + + list: TasksListCapability | None = None + cancel: TasksCancelCapability | None = None + requests: ServerTasksRequestsCapability | None = None + + class ServerCapabilities(MCPModel): - """Capabilities that a server may support.""" + """Capabilities that a server may support. Not a closed set.""" experimental: dict[str, dict[str, Any]] | None = None """Experimental, non-standard capabilities that the server supports.""" logging: LoggingCapability | None = None - """Present if the server supports sending log messages to the client.""" + """Present if the server supports sending log messages to the client. + Deprecated in 2026-07-28 (SEP-2577).""" prompts: PromptsCapability | None = None """Present if the server offers any prompt templates.""" @@ -300,9 +489,19 @@ class ServerCapabilities(MCPModel): completions: CompletionsCapability | None = None """Present if the server offers autocompletion suggestions for prompts and resources.""" + extensions: dict[str, dict[str, Any]] | None = None + """MCP extensions the server supports (2026-07-28). Keys are extension + identifiers; values are per-extension settings (empty object = no settings).""" + + tasks: ServerTasksCapability | None = None + """Present if the server supports task-augmented requests (2025-11-25 only).""" + class InitializeRequestParams(RequestParams): - """Parameters for the initialize request.""" + """Parameters for the `initialize` request. + + Removed in protocol 2026-07-28; sent/received on sessions negotiating <= 2025-11-25. + """ protocol_version: str """The latest version of the Model Context Protocol that the client supports.""" @@ -313,6 +512,9 @@ class InitializeRequestParams(RequestParams): class InitializeRequest(Request[InitializeRequestParams, Literal["initialize"]]): """This request is sent from the client to the server when it first connects, asking it to begin initialization. + + Removed in protocol 2026-07-28; sent/received on sessions negotiating <= 2025-11-25. + On 2026-07-28 the handshake is `server/discover` plus per-request `_meta`. """ method: Literal["initialize"] = "initialize" @@ -320,19 +522,29 @@ class InitializeRequest(Request[InitializeRequestParams, Literal["initialize"]]) class InitializeResult(Result): - """After receiving an initialize request from the client, the server sends this.""" + """After receiving an initialize request from the client, the server sends this response. + + Removed in protocol 2026-07-28; sent/received on sessions negotiating <= 2025-11-25. + """ protocol_version: str - """The version of the Model Context Protocol that the server wants to use.""" + """The version of the Model Context Protocol that the server wants to use. + If the client cannot support this version, it MUST disconnect.""" capabilities: ServerCapabilities server_info: Implementation instructions: str | None = None - """Instructions describing how to use the server and its features.""" + """Instructions describing how to use the server and its features. + + Clients may use this to improve an LLM's understanding of available tools, + resources, etc., for example by adding it to the system prompt. + """ class InitializedNotification(Notification[NotificationParams | None, Literal["notifications/initialized"]]): """This notification is sent from the client to the server after initialization has finished. + + Removed in protocol 2026-07-28; sent/received on sessions negotiating <= 2025-11-25. """ method: Literal["notifications/initialized"] = "notifications/initialized" @@ -341,13 +553,181 @@ class InitializedNotification(Notification[NotificationParams | None, Literal["n class PingRequest(Request[RequestParams | None, Literal["ping"]]): """A ping, issued by either the server or the client, to check that the other party is - still alive. + still alive. The receiver must promptly respond, or else may be disconnected. + + Removed in protocol 2026-07-28; sent/received on sessions negotiating <= 2025-11-25. """ method: Literal["ping"] = "ping" params: RequestParams | None = None +class DiscoverRequest(Request[RequestParams | None, Literal["server/discover"]]): + """Asks the server to advertise its supported protocol versions, capabilities, + and other metadata (2026-07-28). + + Servers speaking 2026-07-28 MUST implement this; clients MAY call it but are + not required to (version negotiation can also happen via per-request `_meta`). + """ + + method: Literal["server/discover"] = "server/discover" + params: RequestParams | None = None + """Required on the 2026-07-28 wire (for `_meta`); the session layer materializes it.""" + + +class DiscoverResult(CacheableResult): + """The result returned by the server for a `server/discover` request (2026-07-28).""" + + supported_versions: list[str] + """MCP protocol versions this server supports; the client should pick one for subsequent requests.""" + + capabilities: ServerCapabilities + + server_info: Implementation + + instructions: str | None = None + """Natural-language guidance describing the server and its features, e.g. for + a system prompt. Should not duplicate information already in tool descriptions.""" + + result_type: ResultType = "complete" + """See `ResultType`. Always serialized; required on the 2026-07-28 wire, + ignored by older peers, and defaulted on inbound bodies that omit it.""" + + +# Tasks: introduced in 2025-11-25, removed from the core spec in 2026-07-28 +# (continuing as an extension). Defined here types-only; their methods are not +# in the request/notification unions below, so they are never dispatched. + + +class ToolExecution(MCPModel): + """Execution-related properties for a tool (2025-11-25 only).""" + + task_support: Literal["forbidden", "optional", "required"] | None = None + """Whether this tool supports task-augmented execution. Absent means "forbidden".""" + + +class TaskMetadata(MCPModel): + """Metadata for augmenting a request with task execution (the `task` params field; 2025-11-25 only).""" + + ttl: int | None = None + """Requested duration in milliseconds to retain task from creation.""" + + +class RelatedTaskMetadata(MCPModel): + """Associates a message with a task, via `_meta["io.modelcontextprotocol/related-task"]` (2025-11-25 only).""" + + task_id: str + + +TaskStatus = Literal["working", "input_required", "completed", "failed", "cancelled"] +"""The status of a task (2025-11-25 only).""" + + +class Task(MCPModel): + """Data associated with a task (2025-11-25 only).""" + + task_id: str + + status: TaskStatus + + status_message: str | None = None + """Optional human-readable message describing the current task state.""" + + created_at: str + """ISO 8601 timestamp when the task was created.""" + + last_updated_at: str + """ISO 8601 timestamp when the task was last updated.""" + + ttl: int | None + """Actual retention duration from creation in milliseconds, null for unlimited.""" + + poll_interval: int | None = None + """Suggested polling interval in milliseconds.""" + + +class CreateTaskResult(Result): + """A response to a task-augmented request (2025-11-25 only).""" + + task: Task + + +class GetTaskRequestParams(RequestParams): + task_id: str + + +class GetTaskRequest(Request[GetTaskRequestParams, Literal["tasks/get"]]): + """A request to retrieve the state of a task (2025-11-25 only).""" + + method: Literal["tasks/get"] = "tasks/get" + params: GetTaskRequestParams + + +class GetTaskResult(Result, Task): + """The response to a tasks/get request (2025-11-25 only).""" + + +class CancelTaskRequestParams(RequestParams): + task_id: str + + +class CancelTaskRequest(Request[CancelTaskRequestParams, Literal["tasks/cancel"]]): + """A request to cancel a task (2025-11-25 only).""" + + method: Literal["tasks/cancel"] = "tasks/cancel" + params: CancelTaskRequestParams + + +class CancelTaskResult(Result, Task): + """The response to a tasks/cancel request (2025-11-25 only).""" + + +class TaskStatusNotificationParams(NotificationParams, Task): + """Parameters for a `notifications/tasks/status` notification.""" + + +class TaskStatusNotification(Notification[TaskStatusNotificationParams, Literal["notifications/tasks/status"]]): + """An optional notification informing the requestor that a task's status has changed (2025-11-25 only).""" + + method: Literal["notifications/tasks/status"] = "notifications/tasks/status" + params: TaskStatusNotificationParams + + +class GetTaskPayloadRequestParams(RequestParams): + """Parameters for a tasks/result request.""" + + task_id: str + + +class GetTaskPayloadRequest(Request[GetTaskPayloadRequestParams, Literal["tasks/result"]]): + """A request to retrieve the result of a completed task (2025-11-25 only).""" + + method: Literal["tasks/result"] = "tasks/result" + params: GetTaskPayloadRequestParams + + +class GetTaskPayloadResult(Result): + """The response to a tasks/result request (2025-11-25 only). + + The structure matches the result type of the original request. The payload + arrives as extra wire fields, which `MCPModel` does not retain; validate the + response into the original request's result type (e.g. `CallToolResult`) + instead of this class. + """ + + +class ListTasksRequest(PaginatedRequest[Literal["tasks/list"]]): + """A request to retrieve a list of tasks (2025-11-25 only).""" + + method: Literal["tasks/list"] = "tasks/list" + + +class ListTasksResult(PaginatedResult): + """The response to a tasks/list request (2025-11-25 only).""" + + tasks: list[Task] + + class ProgressNotificationParams(NotificationParams): """Parameters for progress notifications.""" @@ -384,8 +764,17 @@ class ListResourcesRequest(PaginatedRequest[Literal["resources/list"]]): class Annotations(MCPModel): + """Optional annotations the client can use to inform how objects are used or displayed.""" + audience: list[Role] | None = None + """Who the intended audience is, e.g. `["user", "assistant"]`.""" + priority: Annotated[float, Field(ge=0.0, le=1.0)] | None = None + """How important this data is for operating the server: 1 means effectively + required, 0 means entirely optional.""" + + last_modified: str | None = None + """ISO 8601 timestamp of when the item was last modified.""" class Resource(BaseMetadata): @@ -407,15 +796,13 @@ class Resource(BaseMetadata): """ icons: list[Icon] | None = None - """An optional list of icons for this resource.""" + """Optional set of sized icons that the client can display in a user interface.""" annotations: Annotations | None = None + """Optional annotations for the client.""" meta: Meta | None = Field(alias="_meta", default=None) - """ - See [MCP specification](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/47339c03c143bb4ec01a26e721a1b8fe66634ebe/docs/specification/draft/basic/index.mdx#general-fields) - for notes on _meta usage. - """ + """See the MCP specification for notes on `_meta` usage.""" class ResourceTemplate(BaseMetadata): @@ -425,7 +812,7 @@ class ResourceTemplate(BaseMetadata): """A URI template (according to RFC 6570) that can be used to construct resource URIs.""" description: str | None = None - """A human-readable description of what this template is for.""" + """A description of what this template is for.""" mime_type: str | None = None """The MIME type for all resources that match this template. @@ -434,9 +821,10 @@ class ResourceTemplate(BaseMetadata): """ icons: list[Icon] | None = None - """An optional list of icons for this resource template.""" + """An optional set of sized icons that the client can display in a user interface.""" annotations: Annotations | None = None + """Optional annotations for the client.""" meta: Meta | None = Field(alias="_meta", default=None) """ @@ -445,10 +833,12 @@ class ResourceTemplate(BaseMetadata): """ -class ListResourcesResult(PaginatedResult): +class ListResourcesResult(PaginatedResult, CacheableResult): """The server's response to a resources/list request from the client.""" resources: list[Resource] + result_type: ResultType = "complete" + """See `ResultType`. Always serialized; older peers ignore it.""" class ListResourceTemplatesRequest(PaginatedRequest[Literal["resources/templates/list"]]): @@ -457,19 +847,33 @@ class ListResourceTemplatesRequest(PaginatedRequest[Literal["resources/templates method: Literal["resources/templates/list"] = "resources/templates/list" -class ListResourceTemplatesResult(PaginatedResult): +class ListResourceTemplatesResult(PaginatedResult, CacheableResult): """The server's response to a resources/templates/list request from the client.""" resource_templates: list[ResourceTemplate] + result_type: ResultType = "complete" + """See `ResultType`. Always serialized; older peers ignore it.""" -class ReadResourceRequestParams(RequestParams): - """Parameters for reading a resource.""" +class InputResponseRequestParams(RequestParams): + """Base params for client requests that can carry responses to a server's + input requests (2026-07-28 multi-round-trip flow). + When a request returns an `InputRequiredResult`, the client retries the + original request with these fields populated. + """ + + input_responses: InputResponses | None = None + """Responses to the server's `InputRequiredResult.input_requests`, keyed identically.""" + request_state: str | None = None + """Opaque state from the `InputRequiredResult`, passed back verbatim on retry.""" + + +class ReadResourceRequestParams(InputResponseRequestParams): uri: str """ - The URI of the resource to read. The URI can use any protocol; it is up to the - server how to interpret it. + The URI of the resource. The URI can use any protocol; it is up to the server + how to interpret it. """ @@ -511,10 +915,14 @@ class BlobResourceContents(ResourceContents): """A base64-encoded string representing the binary data of the item.""" -class ReadResourceResult(Result): +class ReadResourceResult(CacheableResult): """The server's response to a resources/read request from the client.""" contents: list[TextResourceContents | BlobResourceContents] + """The contents of the resource or sub-resources that were read.""" + + result_type: ResultType = "complete" + """See `ResultType`. Always serialized; older peers ignore it.""" class ResourceListChangedNotification( @@ -522,6 +930,9 @@ class ResourceListChangedNotification( ): """An optional notification from the server to the client, informing it that the list of resources it can read from has changed. + + May be sent spontaneously through 2025-11-25; on 2026-07-28 sessions the + client must opt in via `subscriptions/listen`. """ method: Literal["notifications/resources/list_changed"] = "notifications/resources/list_changed" @@ -529,7 +940,10 @@ class ResourceListChangedNotification( class SubscribeRequestParams(RequestParams): - """Parameters for subscribing to a resource.""" + """Parameters for subscribing to a resource. + + Removed in protocol 2026-07-28; sent/received on sessions negotiating <= 2025-11-25. + """ uri: str """ @@ -541,6 +955,9 @@ class SubscribeRequestParams(RequestParams): class SubscribeRequest(Request[SubscribeRequestParams, Literal["resources/subscribe"]]): """Sent from the client to request resources/updated notifications from the server whenever a particular resource changes. + + Removed in protocol 2026-07-28; sent/received on sessions negotiating <= 2025-11-25. + On 2026-07-28 use `subscriptions/listen` instead. """ method: Literal["resources/subscribe"] = "resources/subscribe" @@ -548,15 +965,21 @@ class SubscribeRequest(Request[SubscribeRequestParams, Literal["resources/subscr class UnsubscribeRequestParams(RequestParams): - """Parameters for unsubscribing from a resource.""" + """Parameters for a resources/unsubscribe request. + + Removed in protocol 2026-07-28; sent/received on sessions negotiating <= 2025-11-25. + """ uri: str """The URI of the resource to unsubscribe from.""" class UnsubscribeRequest(Request[UnsubscribeRequestParams, Literal["resources/unsubscribe"]]): - """Sent from the client to request cancellation of resources/updated notifications from - the server. + """Sent from the client to request cancellation of resources/updated notifications + from the server. This should follow a previous resources/subscribe request. + + Removed in protocol 2026-07-28; sent/received on sessions negotiating <= 2025-11-25. + On 2026-07-28 use `subscriptions/listen` instead. """ method: Literal["resources/unsubscribe"] = "resources/unsubscribe" @@ -564,8 +987,6 @@ class UnsubscribeRequest(Request[UnsubscribeRequestParams, Literal["resources/un class ResourceUpdatedNotificationParams(NotificationParams): - """Parameters for resource update notifications.""" - uri: str """ The URI of the resource that has been updated. This might be a sub-resource of the @@ -578,23 +999,82 @@ class ResourceUpdatedNotification( ): """A notification from the server to the client, informing it that a resource has changed and may need to be read again. + + Only sent if the client subscribed: via `resources/subscribe` through + 2025-11-25, or `subscriptions/listen` on 2026-07-28. """ method: Literal["notifications/resources/updated"] = "notifications/resources/updated" params: ResourceUpdatedNotificationParams +class SubscriptionFilter(MCPModel): + """The set of notification types a client opts in to via `subscriptions/listen` (2026-07-28). + + Each type is opt-in; the server MUST NOT send types not requested here. + Echoed back in `notifications/subscriptions/acknowledged` as the subset the + server agreed to honor. Extensions merge additional keys (e.g. `taskIds`), + so unknown keys round-trip. + """ + + model_config = ConfigDict(alias_generator=to_camel, populate_by_name=True, extra="allow") + + tools_list_changed: bool | None = None + """If true, receive notifications/tools/list_changed.""" + + prompts_list_changed: bool | None = None + """If true, receive notifications/prompts/list_changed.""" + + resources_list_changed: bool | None = None + """If true, receive notifications/resources/list_changed.""" + + resource_subscriptions: list[str] | None = None + """Subscribe to notifications/resources/updated for these resource URIs.""" + + +class SubscriptionsListenRequestParams(RequestParams): + notifications: SubscriptionFilter + """The notifications the client opts in to on this stream.""" + + +class SubscriptionsListenRequest(Request[SubscriptionsListenRequestParams, Literal["subscriptions/listen"]]): + """Opens a long-lived channel for receiving notifications outside the context + of a specific request (2026-07-28). + """ + + method: Literal["subscriptions/listen"] = "subscriptions/listen" + params: SubscriptionsListenRequestParams + + +class SubscriptionsAcknowledgedNotificationParams(NotificationParams): + notifications: SubscriptionFilter + """The subset of requested notification types the server agreed to honor. + Unsupported types are omitted.""" + + +class SubscriptionsAcknowledgedNotification( + Notification[ + SubscriptionsAcknowledgedNotificationParams, + Literal["notifications/subscriptions/acknowledged"], + ] +): + """First message on a `subscriptions/listen` stream: acknowledges the + subscription and reports which notification types the server will honor (2026-07-28). + """ + + method: Literal["notifications/subscriptions/acknowledged"] = "notifications/subscriptions/acknowledged" + params: SubscriptionsAcknowledgedNotificationParams + + class ListPromptsRequest(PaginatedRequest[Literal["prompts/list"]]): - """Sent from the client to request a list of prompts and prompt templates.""" + """Sent from the client to request a list of prompts and prompt templates the server has.""" method: Literal["prompts/list"] = "prompts/list" -class PromptArgument(MCPModel): - """An argument for a prompt template.""" +class PromptArgument(BaseMetadata): + """Describes an argument that a prompt can accept.""" - name: str - """The name of the argument.""" description: str | None = None """A human-readable description of the argument.""" required: bool | None = None @@ -617,15 +1097,15 @@ class Prompt(BaseMetadata): """ -class ListPromptsResult(PaginatedResult): +class ListPromptsResult(PaginatedResult, CacheableResult): """The server's response to a prompts/list request from the client.""" prompts: list[Prompt] + result_type: ResultType = "complete" + """See `ResultType`. Always serialized; older peers ignore it.""" -class GetPromptRequestParams(RequestParams): - """Parameters for getting a prompt.""" - +class GetPromptRequestParams(InputResponseRequestParams): name: str """The name of the prompt or prompt template.""" arguments: dict[str, str] | None = None @@ -640,12 +1120,13 @@ class GetPromptRequest(Request[GetPromptRequestParams, Literal["prompts/get"]]): class TextContent(MCPModel): - """Text content for a message.""" + """Text provided to or from an LLM.""" type: Literal["text"] = "text" text: str """The text content of the message.""" annotations: Annotations | None = None + """Optional annotations for the client.""" meta: Meta | None = Field(alias="_meta", default=None) """ See [MCP specification](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/47339c03c143bb4ec01a26e721a1b8fe66634ebe/docs/specification/draft/basic/index.mdx#general-fields) @@ -654,7 +1135,7 @@ class TextContent(MCPModel): class ImageContent(MCPModel): - """Image content for a message.""" + """An image provided to or from an LLM.""" type: Literal["image"] = "image" data: str @@ -665,15 +1146,13 @@ class ImageContent(MCPModel): image types. """ annotations: Annotations | None = None + """Optional annotations for the client.""" meta: Meta | None = Field(alias="_meta", default=None) - """ - See [MCP specification](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/47339c03c143bb4ec01a26e721a1b8fe66634ebe/docs/specification/draft/basic/index.mdx#general-fields) - for notes on _meta usage. - """ + """See the MCP specification's "General fields: _meta" section for notes on _meta usage.""" class AudioContent(MCPModel): - """Audio content for a message.""" + """Audio provided to or from an LLM.""" type: Literal["audio"] = "audio" data: str @@ -684,6 +1163,7 @@ class AudioContent(MCPModel): audio types. """ annotations: Annotations | None = None + """Optional annotations for the client.""" meta: Meta | None = Field(alias="_meta", default=None) """ See [MCP specification](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/47339c03c143bb4ec01a26e721a1b8fe66634ebe/docs/specification/draft/basic/index.mdx#general-fields) @@ -692,11 +1172,11 @@ class AudioContent(MCPModel): class ToolUseContent(MCPModel): - """Content representing an assistant's request to invoke a tool. + """An assistant's request to invoke a tool during sampling (2025-11-25+). - This content type appears in assistant messages when the LLM wants to call a tool - during sampling. The server should execute the tool and return a ToolResultContent - in the next user message. + Appears in `sampling/createMessage` results and replayed assistant messages. + The server should execute the tool and return a `ToolResultContent` in the + next user message. Deprecated in 2026-07-28 (SEP-2577). """ type: Literal["tool_use"] = "tool_use" @@ -712,48 +1192,45 @@ class ToolUseContent(MCPModel): """Arguments to pass to the tool. Must conform to the tool's inputSchema.""" meta: Meta | None = Field(alias="_meta", default=None) - """ - See [MCP specification](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/47339c03c143bb4ec01a26e721a1b8fe66634ebe/docs/specification/draft/basic/index.mdx#general-fields) - for notes on _meta usage. - """ + """Optional metadata. Clients SHOULD preserve this in subsequent sampling + requests to enable caching optimizations.""" class ToolResultContent(MCPModel): - """Content representing the result of a tool execution. + """The result of a tool use, provided by the user back to the assistant (2025-11-25+). - This content type appears in user messages as a response to a ToolUseContent - from the assistant. It contains the output of executing the requested tool. + Appears in sampling messages as a response to a `ToolUseContent` block. + Requires the `sampling.tools` client capability. Deprecated in 2026-07-28 (SEP-2577). """ type: Literal["tool_result"] = "tool_result" """Discriminator for tool result content.""" tool_use_id: str - """The unique identifier that corresponds to the tool call's id field.""" + """The `id` of the `ToolUseContent` this result corresponds to.""" content: list[ContentBlock] = [] - """ - A list of content objects representing the tool result. - Defaults to empty list if not provided. - """ + """The unstructured result content (same format as `CallToolResult.content`).""" - structured_content: dict[str, Any] | None = None - """ - Optional structured tool output that matches the tool's outputSchema (if defined). - """ + structured_content: Any = None + """An optional structured result value. Any JSON value on 2026-07-28; + restricted to a JSON object on 2025-11-25.""" is_error: bool | None = None - """Whether the tool execution resulted in an error.""" + """Whether the tool use resulted in an error. Absent is equivalent to false.""" meta: Meta | None = Field(alias="_meta", default=None) - """ - See [MCP specification](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/47339c03c143bb4ec01a26e721a1b8fe66634ebe/docs/specification/draft/basic/index.mdx#general-fields) - for notes on _meta usage. - """ + """Optional metadata. Clients SHOULD preserve this in subsequent sampling + requests to enable caching optimizations.""" SamplingMessageContentBlock: TypeAlias = TextContent | ImageContent | AudioContent | ToolUseContent | ToolResultContent -"""Content block types allowed in sampling messages.""" +"""Content block types allowed in sampling messages. + +This is the widest (2025-11-25+) membership; older sessions allow only a subset +on the wire. Serialization never narrows a value to fit; version gating is the +session layer's responsibility. Deprecated in 2026-07-28 (SEP-2577). +""" SamplingContent: TypeAlias = TextContent | ImageContent | AudioContent """Basic content types for sampling responses (without tool use). @@ -794,6 +1271,7 @@ class EmbeddedResource(MCPModel): type: Literal["resource"] = "resource" resource: TextResourceContents | BlobResourceContents annotations: Annotations | None = None + """Optional annotations for the client.""" meta: Meta | None = Field(alias="_meta", default=None) """ See [MCP specification](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/47339c03c143bb4ec01a26e721a1b8fe66634ebe/docs/specification/draft/basic/index.mdx#general-fields) @@ -815,7 +1293,10 @@ class ResourceLink(Resource): class PromptMessage(MCPModel): - """Describes a message returned as part of a prompt.""" + """Describes a message returned as part of a prompt. + + Similar to `SamplingMessage`, but also supports embedded resources. + """ role: Role content: ContentBlock @@ -827,6 +1308,10 @@ class GetPromptResult(Result): description: str | None = None """An optional description for the prompt.""" messages: list[PromptMessage] + """The messages composing the prompt, in the order they should be presented.""" + + result_type: ResultType = "complete" + """See `ResultType`. Always serialized; older peers ignore it.""" class PromptListChangedNotification( @@ -834,6 +1319,9 @@ class PromptListChangedNotification( ): """An optional notification from the server to the client, informing it that the list of prompts it offers has changed. + + May be sent spontaneously through 2025-11-25; on 2026-07-28 sessions the + client must opt in via `subscriptions/listen`. """ method: Literal["notifications/prompts/list_changed"] = "notifications/prompts/list_changed" @@ -898,34 +1386,43 @@ class Tool(BaseMetadata): description: str | None = None """A human-readable description of the tool.""" input_schema: dict[str, Any] - """A JSON Schema object defining the expected parameters for the tool.""" - output_schema: dict[str, Any] | None = None + """A JSON Schema object defining the expected parameters for the tool. + + `type: "object"` is required at the root. 2026-07-28 allows any JSON Schema + 2020-12 keyword; earlier versions define only `type`/`properties`/`required`. """ - An optional JSON Schema object defining the structure of the tool's output - returned in the structured_content field of a CallToolResult. + execution: ToolExecution | None = None + """Execution-related properties (2025-11-25 only; removed in 2026-07-28).""" + output_schema: dict[str, Any] | None = None + """An optional JSON Schema object defining the structure of the tool's output + returned in the `structured_content` field of a `CallToolResult`. + + Restricted to `type: "object"` at the root through 2025-11-25; any valid + JSON Schema 2020-12 on 2026-07-28. """ icons: list[Icon] | None = None - """An optional list of icons for this tool.""" + """Optional set of sized icons for display (2025-11-25+).""" annotations: ToolAnnotations | None = None - """Optional additional tool information.""" + """Optional additional tool information. + Display-name precedence: `title`, `annotations.title`, then `name`.""" meta: Meta | None = Field(alias="_meta", default=None) - """ - See [MCP specification](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/47339c03c143bb4ec01a26e721a1b8fe66634ebe/docs/specification/draft/basic/index.mdx#general-fields) - for notes on _meta usage. - """ + """See the MCP specification for notes on `_meta` usage.""" -class ListToolsResult(PaginatedResult): +class ListToolsResult(PaginatedResult, CacheableResult): """The server's response to a tools/list request from the client.""" tools: list[Tool] + result_type: ResultType = "complete" + """See `ResultType`. Always serialized; older peers ignore it.""" -class CallToolRequestParams(RequestParams): - """Parameters for calling a tool.""" +class CallToolRequestParams(InputResponseRequestParams): name: str arguments: dict[str, Any] | None = None + task: TaskMetadata | None = None + """If specified, the caller requests task-augmented execution (2025-11-25 only).""" class CallToolRequest(Request[CallToolRequestParams, Literal["tools/call"]]): @@ -936,17 +1433,35 @@ class CallToolRequest(Request[CallToolRequestParams, Literal["tools/call"]]): class CallToolResult(Result): - """The server's response to a tool call.""" + """The server's response to a tool call. + + Errors that originate from the tool SHOULD be reported inside the result + with `is_error` set to true, not as an MCP protocol-level error, so the LLM + can see and self-correct. Errors in finding the tool, or any other + exceptional condition, should be reported as an MCP error response. + """ content: list[ContentBlock] - structured_content: dict[str, Any] | None = None - """An optional JSON object that represents the structured result of the tool call.""" + """A list of content objects that represent the unstructured result of the tool call.""" + structured_content: Any = None + """An optional JSON value representing the structured result of the tool call. + + Any JSON value on 2026-07-28; restricted to a JSON object on 2025-06-18 and + 2025-11-25. + """ is_error: bool = False + """Whether the tool call ended in an error.""" + + result_type: ResultType = "complete" + """See `ResultType`. Always serialized; older peers ignore it.""" class ToolListChangedNotification(Notification[NotificationParams | None, Literal["notifications/tools/list_changed"]]): """An optional notification from the server to the client, informing it that the list of tools it offers has changed. + + May be sent spontaneously through 2025-11-25; on 2026-07-28 sessions the + client must opt in via `subscriptions/listen`. """ method: Literal["notifications/tools/list_changed"] = "notifications/tools/list_changed" @@ -954,25 +1469,36 @@ class ToolListChangedNotification(Notification[NotificationParams | None, Litera LoggingLevel = Literal["debug", "info", "notice", "warning", "error", "critical", "alert", "emergency"] +"""The severity of a log message. + +These map to syslog severities (RFC-5424 section 6.2.1). Logging is deprecated +in 2026-07-28 (SEP-2577); the level scale is unchanged across versions. +""" class SetLevelRequestParams(RequestParams): - """Parameters for setting the logging level.""" + """Parameters for setting the logging level. + + Removed in protocol 2026-07-28; sent/received on sessions negotiating <= 2025-11-25. + """ level: LoggingLevel - """The level of logging that the client wants to receive from the server.""" + """The level of logging that the client wants to receive from the server. + The server should send all logs at this level and higher (more severe).""" class SetLevelRequest(Request[SetLevelRequestParams, Literal["logging/setLevel"]]): - """A request from the client to the server, to enable or adjust logging.""" + """A request from the client to the server, to enable or adjust logging. + + Removed in protocol 2026-07-28; sent/received on sessions negotiating <= 2025-11-25. + On 2026-07-28 the client opts in per-request via `_meta` (`LOG_LEVEL_META_KEY`). + """ method: Literal["logging/setLevel"] = "logging/setLevel" params: SetLevelRequestParams class LoggingMessageNotificationParams(NotificationParams): - """Parameters for logging message notifications.""" - level: LoggingLevel """The severity of this log message.""" logger: str | None = None @@ -985,24 +1511,42 @@ class LoggingMessageNotificationParams(NotificationParams): class LoggingMessageNotification(Notification[LoggingMessageNotificationParams, Literal["notifications/message"]]): - """Notification of a log message passed from server to client.""" + """Notification of a log message passed from server to client. + + Through 2025-11-25 the client subscribes via `logging/setLevel`. On + 2026-07-28 the client opts in per-request via `_meta` (`LOG_LEVEL_META_KEY`) + and the server MUST NOT send this without it. Deprecated in 2026-07-28 (SEP-2577). + """ method: Literal["notifications/message"] = "notifications/message" params: LoggingMessageNotificationParams IncludeContext = Literal["none", "thisServer", "allServers"] +"""Scope of MCP-server context a sampling request asks the client to attach. + +"thisServer" and "allServers" are deprecated (SEP-2596). +""" class ModelHint(MCPModel): - """Hints to use for model selection.""" + """Hints to use for model selection. + + Keys not declared here are up to the client to interpret. Deprecated in + 2026-07-28 (SEP-2577) with the rest of sampling. + """ name: str | None = None - """A hint for a model name.""" + """A hint for a model name. + + The client SHOULD treat this as a substring (e.g. `sonnet` matches + `claude-3-5-sonnet-20241022`) and MAY map it to another provider's model + that fills a similar niche. + """ class ModelPreferences(MCPModel): - """The server's preferences for model selection, requested by the client during + """The server's preferences for model selection, requested of the client during sampling. Because LLMs can vary along multiple dimensions, choosing the "best" model is @@ -1014,6 +1558,8 @@ class ModelPreferences(MCPModel): These preferences are always advisory. The client MAY ignore them. It is also up to the client to decide how to interpret these preferences and how to balance them against other considerations. + + Deprecated in 2026-07-28 (SEP-2577) with the rest of sampling. """ hints: list[ModelHint] | None = None @@ -1050,25 +1596,24 @@ class ModelPreferences(MCPModel): class ToolChoice(MCPModel): - """Controls tool usage behavior during sampling. + """Controls tool selection behavior for sampling requests (2025-11-25+). - Allows the server to specify whether and how the LLM should use tools - in its response. + The client MUST return an error if this is received without the + `sampling.tools` capability. Absent means `{"mode": "auto"}`. """ mode: Literal["auto", "required", "none"] | None = None """ - Controls when tools are used: + Controls the tool use ability of the model: - "auto": Model decides whether to use tools (default) - "required": Model MUST use at least one tool before completing - - "none": Model should not use tools + - "none": Model MUST NOT use any tools """ class CreateMessageRequestParams(RequestParams): - """Parameters for creating a message.""" - messages: list[SamplingMessage] + """The conversation to sample from.""" model_preferences: ModelPreferences | None = None """ The server's preferences for which model to select. The client MAY ignore @@ -1078,35 +1623,44 @@ class CreateMessageRequestParams(RequestParams): """An optional system prompt the server wants to use for sampling.""" include_context: IncludeContext | None = None """ - A request to include context from one or more MCP servers (including the caller), to - be attached to the prompt. + A request to include context from one or more MCP servers (including the + caller), to be attached to the prompt. The client MAY ignore this request. + Default is "none". "thisServer" and "allServers" are deprecated (SEP-2596). """ temperature: float | None = None max_tokens: int """The maximum number of tokens to sample, as requested by the server.""" stop_sequences: list[str] | None = None metadata: dict[str, Any] | None = None - """Optional metadata to pass through to the LLM provider.""" + """Optional metadata to pass through to the LLM provider. Provider-specific.""" tools: list[Tool] | None = None - """ - Tool definitions for the LLM to use during sampling. - Requires clientCapabilities.sampling.tools to be present. - """ + """Tools the model may use during generation (2025-11-25+). Requires the + `sampling.tools` client capability.""" tool_choice: ToolChoice | None = None - """ - Controls tool usage behavior. - Requires clientCapabilities.sampling.tools and the tools parameter to be present. - """ + """Controls how the model uses tools (2025-11-25+). Requires the + `sampling.tools` client capability.""" + task: TaskMetadata | None = None + """If specified, the caller requests task-augmented execution (2025-11-25 only).""" class CreateMessageRequest(Request[CreateMessageRequestParams, Literal["sampling/createMessage"]]): - """A request from the server to sample an LLM via the client.""" + """A request from the server to sample an LLM via the client. + + The client has full discretion over which model to select and should inform + the user before sampling (human in the loop). A standalone JSON-RPC request + through 2025-11-25; on 2026-07-28 it is embedded in + `InputRequiredResult.input_requests` instead. Deprecated in 2026-07-28 (SEP-2577). + """ method: Literal["sampling/createMessage"] = "sampling/createMessage" params: CreateMessageRequestParams StopReason = Literal["endTurn", "stopSequence", "maxTokens", "toolUse"] | str +"""The reason why sampling stopped, if known. + +An open union to allow provider-specific stop reasons. "toolUse" is 2025-11-25+. +""" class CreateMessageResult(Result): @@ -1114,6 +1668,9 @@ class CreateMessageResult(Result): This is the backwards-compatible version that returns single content (no arrays). Used when the request does not include tools. + + On 2026-07-28 this travels embedded in an `InputResponses` map rather than + as a top-level JSON-RPC result. Deprecated in 2026-07-28 (SEP-2577). """ role: Role @@ -1129,7 +1686,7 @@ class CreateMessageResult(Result): class CreateMessageResultWithTools(Result): """The client's response to a sampling/createMessage request when tools were provided. - This version supports array content for tool use flows. + This version supports array content for tool use flows (2025-11-25 and later). """ role: Role @@ -1162,12 +1719,15 @@ class ResourceTemplateReference(MCPModel): """The URI or URI template of the resource.""" +# Not BaseMetadata: inheriting would reorder dump keys for existing callers. class PromptReference(MCPModel): """Identifies a prompt.""" type: Literal["ref/prompt"] = "ref/prompt" name: str """The name of the prompt or prompt template.""" + title: str | None = None + """Human-readable display title. If not provided, `name` should be used for display.""" class CompletionArgument(MCPModel): @@ -1187,9 +1747,8 @@ class CompletionContext(MCPModel): class CompleteRequestParams(RequestParams): - """Parameters for completion requests.""" - ref: ResourceTemplateReference | PromptReference + """The prompt or resource-template reference to complete against.""" argument: CompletionArgument context: CompletionContext | None = None """Additional, optional context for completions.""" @@ -1223,6 +1782,10 @@ class CompleteResult(Result): """The server's response to a completion/complete request.""" completion: Completion + """The completion values, with optional total / has-more pagination hints.""" + + result_type: ResultType = "complete" + """See `ResultType`. Always serialized; older peers ignore it.""" class ListRootsRequest(Request[RequestParams | None, Literal["roots/list"]]): @@ -1233,14 +1796,22 @@ class ListRootsRequest(Request[RequestParams | None, Literal["roots/list"]]): This request is typically used when the server needs to understand the file system structure or access specific locations that the client has permission to read from. + + A standalone JSON-RPC request through 2025-11-25; on 2026-07-28 it is + embedded in `InputRequiredResult.input_requests`. Deprecated in 2026-07-28 (SEP-2577). """ method: Literal["roots/list"] = "roots/list" params: RequestParams | None = None + """Stays optional on 2026-07-28 (reserved client `_meta` keys do not apply + to server-to-client payloads).""" class Root(MCPModel): - """Represents a root directory or file that the server can operate on.""" + """Represents a root directory or file that the server can operate on. + + Deprecated in 2026-07-28 (SEP-2577) with the rest of roots. + """ uri: FileUrl """ @@ -1264,8 +1835,11 @@ class Root(MCPModel): class ListRootsResult(Result): """The client's response to a roots/list request from the server. - This result contains an array of Root objects, each representing a root directory - or file that the server can operate on. + This result contains an array of Root objects, each representing a root + directory or file that the server can operate on. + + On 2026-07-28 this is carried as an `InputResponses` entry, not a JSON-RPC + result. Deprecated in 2026-07-28 (SEP-2577). """ roots: list[Root] @@ -1280,6 +1854,8 @@ class RootsListChangedNotification( This notification should be sent whenever the client adds, removes, or modifies any root. The server should then request an updated list of roots using the ListRootsRequest. + + Removed in protocol 2026-07-28; sent/received on sessions negotiating <= 2025-11-25. """ method: Literal["notifications/roots/list_changed"] = "notifications/roots/list_changed" @@ -1287,13 +1863,12 @@ class RootsListChangedNotification( class CancelledNotificationParams(NotificationParams): - """Parameters for cancellation notifications.""" - request_id: RequestId | None = None """ The ID of the request to cancel. This MUST correspond to the ID of a request previously issued in the same direction. + Required on the wire through 2025-06-18; optional from 2025-11-25. """ reason: str | None = None """An optional string describing the reason for the cancellation.""" @@ -1302,6 +1877,10 @@ class CancelledNotificationParams(NotificationParams): class CancelledNotification(Notification[CancelledNotificationParams, Literal["notifications/cancelled"]]): """This notification can be sent by either side to indicate that it is canceling a previously-issued request. + + The request SHOULD still be in-flight, but due to communication latency, it + is always possible that this notification MAY arrive after the request has + already finished. A client MUST NOT attempt to cancel its `initialize` request. """ method: Literal["notifications/cancelled"] = "notifications/cancelled" @@ -1325,39 +1904,17 @@ class ElicitCompleteNotification( URLElicitationRequiredError, update the user interface, or otherwise continue an interaction. However, because delivery of the notification is not guaranteed, clients must not wait indefinitely for a notification from the server. + + New in protocol 2025-11-25 with URL mode itself. """ method: Literal["notifications/elicitation/complete"] = "notifications/elicitation/complete" params: ElicitCompleteNotificationParams -ClientRequest = ( - PingRequest - | InitializeRequest - | CompleteRequest - | SetLevelRequest - | GetPromptRequest - | ListPromptsRequest - | ListResourcesRequest - | ListResourceTemplatesRequest - | ReadResourceRequest - | SubscribeRequest - | UnsubscribeRequest - | CallToolRequest - | ListToolsRequest -) -client_request_adapter = TypeAdapter[ClientRequest](ClientRequest) - - -ClientNotification = ( - CancelledNotification | ProgressNotification | InitializedNotification | RootsListChangedNotification -) -client_notification_adapter = TypeAdapter[ClientNotification](ClientNotification) - - -# Type for elicitation schema - a JSON Schema dict +# Kept as a raw JSON Schema dict so callers can hand it straight to a validator; +# the per-version packages model RequestedSchema/PrimitiveSchemaDefinition strictly. ElicitRequestedSchema: TypeAlias = dict[str, Any] -"""Schema for elicitation requests.""" class ElicitRequestFormParams(RequestParams): @@ -1379,12 +1936,15 @@ class ElicitRequestFormParams(RequestParams): Only top-level properties are allowed, without nesting. """ + task: TaskMetadata | None = None + """If specified, the caller requests task-augmented execution (2025-11-25 only).""" + class ElicitRequestURLParams(RequestParams): """Parameters for URL mode elicitation requests. URL mode directs users to external URLs for sensitive out-of-band interactions - like OAuth flows, credential collection, or payment processing. + like OAuth flows, credential collection, or payment processing. New in 2025-11-25. """ mode: Literal["url"] = "url" @@ -1402,6 +1962,9 @@ class ElicitRequestURLParams(RequestParams): The client MUST treat this ID as an opaque value. """ + task: TaskMetadata | None = None + """If specified, the caller requests task-augmented execution (2025-11-25 only).""" + # Union type for elicitation request parameters ElicitRequestParams: TypeAlias = ElicitRequestURLParams | ElicitRequestFormParams @@ -1409,7 +1972,7 @@ class ElicitRequestURLParams(RequestParams): class ElicitRequest(Request[ElicitRequestParams, Literal["elicitation/create"]]): - """A request from the server to elicit information from the client.""" + """A request from the server to elicit additional information from the user via the client.""" method: Literal["elicitation/create"] = "elicitation/create" params: ElicitRequestParams @@ -1432,25 +1995,130 @@ class ElicitResult(Result): Contains values matching the requested schema. Values can be strings, integers, floats, booleans, arrays of strings, or null. For URL mode, this field is omitted. + + The null value arm is superset leniency; the schema-exact surface types + declare no null arm. """ class ElicitationRequiredErrorData(MCPModel): - """Error data for URLElicitationRequiredError. + """Error data for the -32042 URL-elicitation-required error. Servers return this when a request cannot be processed until one or more URL mode elicitations are completed. + + Removed in protocol 2026-07-28; sent/received on sessions negotiating 2025-11-25. """ elicitations: list[ElicitRequestURLParams] """List of URL mode elicitations that must be completed.""" +InputRequest: TypeAlias = CreateMessageRequest | ListRootsRequest | ElicitRequest +"""A single server-initiated input request embedded in `InputRequiredResult` (2026-07-28). + +Discriminated by `method`. On 2026-07-28 these embedded payloads take the place +of standalone server-to-client JSON-RPC requests. +""" + +InputRequests: TypeAlias = dict[str, InputRequest] +"""A map of server-initiated requests that the client must fulfill (2026-07-28). + +Keys are server-assigned identifiers. Carried by `InputRequiredResult.input_requests` +and by the tasks extension. +""" + +InputResponse: TypeAlias = CreateMessageResult | CreateMessageResultWithTools | ListRootsResult | ElicitResult +"""A client response to a single server-initiated input request (2026-07-28). + +`CreateMessageResultWithTools` is this SDK's array-content split of the schema's +single `CreateMessageResult` arm; the wire union has three arms. +""" + +InputResponses: TypeAlias = dict[str, InputResponse] +"""A map of client responses to server-initiated input requests (2026-07-28). + +Keys match those of the `InputRequests` map the server sent. Also used by the +tasks extension's `tasks/update` params. +""" + + +class InputRequiredResult(Result): + """The server needs additional input before the original request can complete (2026-07-28). + + Returned in place of the normal result of an interactive client request + (`tools/call`, `prompts/get`, `resources/read`). The client fulfills + `input_requests` and retries the original request, carrying the responses + and the echoed `request_state`. At least one of those two fields is + present on the wire (spec MUST; not enforced by the model). + """ + + result_type: Literal["input_required"] = "input_required" + """Discriminating tag for the dual-result response unions.""" + + input_requests: InputRequests | None = None + """Requests the client must complete before retrying. Keys are server-assigned.""" + + request_state: str | None = None + """Opaque state to pass back verbatim when the client retries the original request.""" + + +# Forward refs to InputResponses; rebuild at import time rather than first use. +InputResponseRequestParams.model_rebuild() +ReadResourceRequestParams.model_rebuild() +GetPromptRequestParams.model_rebuild() +CallToolRequestParams.model_rebuild() + +# Top-level message unions: superset across all supported protocol versions. +# Per-version validity is recorded in `mcp.types.methods`, not enforced here. + +ClientRequest = ( + PingRequest + | InitializeRequest + | CompleteRequest + | SetLevelRequest + | GetPromptRequest + | ListPromptsRequest + | ListResourcesRequest + | ListResourceTemplatesRequest + | ReadResourceRequest + | SubscribeRequest + | UnsubscribeRequest + | CallToolRequest + | ListToolsRequest + | DiscoverRequest + | SubscriptionsListenRequest +) +"""Union of client-to-server request payloads across all supported protocol versions. + +The 2025-11-25 task requests are deliberately excluded (types-only). +""" + +client_request_adapter = TypeAdapter[ClientRequest](ClientRequest) + + +ClientNotification = ( + CancelledNotification | ProgressNotification | InitializedNotification | RootsListChangedNotification +) +"""Notifications sent from the client to the server. + +`TaskStatusNotification` is deliberately excluded (types-only). +""" + +client_notification_adapter = TypeAdapter[ClientNotification](ClientNotification) + + ClientResult = EmptyResult | CreateMessageResult | CreateMessageResultWithTools | ListRootsResult | ElicitResult client_result_adapter = TypeAdapter[ClientResult](ClientResult) ServerRequest = PingRequest | CreateMessageRequest | ListRootsRequest | ElicitRequest +"""Union of standalone JSON-RPC requests a server can send to a client. + +Live through 2025-11-25 only: 2026-07-28 has no server-to-client JSON-RPC +requests (these payloads are embedded in `InputRequiredResult` instead). +""" + server_request_adapter = TypeAdapter[ServerRequest](ServerRequest) @@ -1463,13 +2131,20 @@ class ElicitationRequiredErrorData(MCPModel): | ToolListChangedNotification | PromptListChangedNotification | ElicitCompleteNotification + | SubscriptionsAcknowledgedNotification ) +"""Union of server-to-client notification payloads across all supported protocol versions. + +`TaskStatusNotification` is deliberately excluded (types-only). +""" + server_notification_adapter = TypeAdapter[ServerNotification](ServerNotification) ServerResult = ( EmptyResult | InitializeResult + | DiscoverResult | CompleteResult | GetPromptResult | ListPromptsResult @@ -1478,5 +2153,11 @@ class ElicitationRequiredErrorData(MCPModel): | ReadResourceResult | CallToolResult | ListToolsResult + | InputRequiredResult ) +"""Union of every result payload a server can return for a client request. + +`InputRequiredResult` is deliberately last: both of its fields are optional, +so an earlier position would shadow other members during union resolution. +""" server_result_adapter = TypeAdapter[ServerResult](ServerResult) diff --git a/src/mcp/types/_wire_base.py b/src/mcp/types/_wire_base.py new file mode 100644 index 0000000000..d6a2e55f7a --- /dev/null +++ b/src/mcp/types/_wire_base.py @@ -0,0 +1,19 @@ +"""Shared pydantic bases for the `mcp.types.v*` wire-shape packages. + +No alias generator is configured: every wire name is an explicit +`Field(alias=...)` so each surface file shows exactly what goes on the wire. +""" + +from pydantic import BaseModel, ConfigDict + + +class WireModel(BaseModel): + """Base for surface-package models: unknown fields are accepted and dropped.""" + + model_config = ConfigDict(populate_by_name=True, extra="ignore") + + +class OpenWireModel(BaseModel): + """Base for `_meta` carrier models: unknown fields are retained for round-tripping.""" + + model_config = ConfigDict(populate_by_name=True, extra="allow") diff --git a/src/mcp/types/jsonrpc.py b/src/mcp/types/jsonrpc.py index 84304a37c1..990973833b 100644 --- a/src/mcp/types/jsonrpc.py +++ b/src/mcp/types/jsonrpc.py @@ -2,13 +2,16 @@ from __future__ import annotations -from typing import Annotated, Any, Literal +from typing import Annotated, Any, Final, Literal from pydantic import BaseModel, Field, TypeAdapter RequestId = Annotated[int, Field(strict=True)] | str """The ID of a JSON-RPC request.""" +JSONRPC_VERSION: Final[Literal["2.0"]] = "2.0" +"""The JSON-RPC version string carried by every MCP message envelope.""" + class JSONRPCRequest(BaseModel): """A JSON-RPC request that expects a response.""" @@ -27,9 +30,11 @@ class JSONRPCNotification(BaseModel): params: dict[str, Any] | None = None -# TODO(Marcelo): This is actually not correct. A JSONRPCResponse is the union of a successful response and an error. class JSONRPCResponse(BaseModel): - """A successful (non-error) response to a request.""" + """A successful (non-error) response to a request. + + Named `JSONRPCResultResponse` in the 2025-11-25+ schemas; the SDK keeps the original name. + """ jsonrpc: Literal["2.0"] id: RequestId @@ -38,18 +43,41 @@ class JSONRPCResponse(BaseModel): # MCP-specific error codes in the range [-32000, -32099] URL_ELICITATION_REQUIRED = -32042 -"""Error code indicating that a URL mode elicitation is required before the request can be processed.""" +"""A URL-mode elicitation is required before the request can be processed (protocol 2025-11-25 only).""" + +MISSING_REQUIRED_CLIENT_CAPABILITY = -32003 +"""The server requires a client capability the request did not declare (protocol 2026-07-28).""" -# SDK error codes +UNSUPPORTED_PROTOCOL_VERSION = -32004 +"""The request's protocol version is not supported by the server (protocol 2026-07-28).""" + +# SDK error codes: SDK-internal allocations in the JSON-RPC server-error range +# [-32000, -32099]; not defined by the MCP schema. New values must avoid codes +# the spec has allocated above. CONNECTION_CLOSED = -32000 +"""SDK-only: the connection closed before a response arrived; never emitted on the wire.""" + REQUEST_TIMEOUT = -32001 +"""SDK-only: a request timed out waiting for its response.""" # Standard JSON-RPC error codes PARSE_ERROR = -32700 +"""Standard JSON-RPC: invalid JSON was received.""" + INVALID_REQUEST = -32600 +"""Standard JSON-RPC: the message is not a valid request object.""" + METHOD_NOT_FOUND = -32601 +"""Standard JSON-RPC: the requested method does not exist or is not available.""" + INVALID_PARAMS = -32602 +"""Standard JSON-RPC: invalid method parameters.""" + INTERNAL_ERROR = -32603 +"""Standard JSON-RPC: an internal error occurred on the receiver. + +The SDK uses the generic `ErrorData` envelope; the schema's per-code wrapper types are not constructed. +""" class ErrorData(BaseModel): @@ -76,8 +104,15 @@ class JSONRPCError(BaseModel): jsonrpc: Literal["2.0"] id: RequestId | None + """The id of the request this error responds to. + + Required but nullable per JSON-RPC 2.0: `None` encodes `"id": null` (the id could not be determined). + """ + error: ErrorData JSONRPCMessage = JSONRPCRequest | JSONRPCNotification | JSONRPCResponse | JSONRPCError +"""Any JSON-RPC envelope that can be decoded off the wire or encoded to be sent.""" + jsonrpc_message_adapter: TypeAdapter[JSONRPCMessage] = TypeAdapter(JSONRPCMessage) diff --git a/src/mcp/types/methods.py b/src/mcp/types/methods.py new file mode 100644 index 0000000000..f3431b84ef --- /dev/null +++ b/src/mcp/types/methods.py @@ -0,0 +1,602 @@ +"""Per-version method maps and parse functions for inbound MCP traffic. + +Surface maps key `(method, version)` to schema-exact types (key absence is the +version gate); monolith maps key `method` to the version-free `mcp.types` models +user code receives. Session-layer wiring is a follow-up.""" + +from __future__ import annotations + +from collections.abc import Mapping +from functools import cache +from types import MappingProxyType, UnionType +from typing import Any, Final, TypeVar + +from pydantic import BaseModel, TypeAdapter + +import mcp.types as types +import mcp.types.v2025_11_25 as v2025 +import mcp.types.v2026_07_28 as v2026 +from mcp.shared.version import KNOWN_PROTOCOL_VERSIONS +from mcp.types._wire_base import WireModel + +__all__ = [ + "CLIENT_NOTIFICATIONS", + "CLIENT_REQUESTS", + "CLIENT_RESULTS", + "MONOLITH_NOTIFICATIONS", + "MONOLITH_REQUESTS", + "MONOLITH_RESULTS", + "SERVER_NOTIFICATIONS", + "SERVER_REQUESTS", + "SERVER_RESULTS", + "parse_client_notification", + "parse_client_request", + "parse_client_result", + "parse_server_notification", + "parse_server_request", + "parse_server_result", +] + + +# --- Surface maps: client-to-server --- + +CLIENT_REQUESTS: Final[Mapping[tuple[str, str], type[WireModel]]] = MappingProxyType( + { + # 2024-11-05 + ("completion/complete", "2024-11-05"): v2025.CompleteRequest, + ("initialize", "2024-11-05"): v2025.InitializeRequest, + ("logging/setLevel", "2024-11-05"): v2025.SetLevelRequest, + ("ping", "2024-11-05"): v2025.PingRequest, + ("prompts/get", "2024-11-05"): v2025.GetPromptRequest, + ("prompts/list", "2024-11-05"): v2025.ListPromptsRequest, + ("resources/list", "2024-11-05"): v2025.ListResourcesRequest, + ("resources/read", "2024-11-05"): v2025.ReadResourceRequest, + ("resources/subscribe", "2024-11-05"): v2025.SubscribeRequest, + ("resources/templates/list", "2024-11-05"): v2025.ListResourceTemplatesRequest, + ("resources/unsubscribe", "2024-11-05"): v2025.UnsubscribeRequest, + ("tools/call", "2024-11-05"): v2025.CallToolRequest, + ("tools/list", "2024-11-05"): v2025.ListToolsRequest, + # 2025-03-26 + ("completion/complete", "2025-03-26"): v2025.CompleteRequest, + ("initialize", "2025-03-26"): v2025.InitializeRequest, + ("logging/setLevel", "2025-03-26"): v2025.SetLevelRequest, + ("ping", "2025-03-26"): v2025.PingRequest, + ("prompts/get", "2025-03-26"): v2025.GetPromptRequest, + ("prompts/list", "2025-03-26"): v2025.ListPromptsRequest, + ("resources/list", "2025-03-26"): v2025.ListResourcesRequest, + ("resources/read", "2025-03-26"): v2025.ReadResourceRequest, + ("resources/subscribe", "2025-03-26"): v2025.SubscribeRequest, + ("resources/templates/list", "2025-03-26"): v2025.ListResourceTemplatesRequest, + ("resources/unsubscribe", "2025-03-26"): v2025.UnsubscribeRequest, + ("tools/call", "2025-03-26"): v2025.CallToolRequest, + ("tools/list", "2025-03-26"): v2025.ListToolsRequest, + # 2025-06-18 + ("completion/complete", "2025-06-18"): v2025.CompleteRequest, + ("initialize", "2025-06-18"): v2025.InitializeRequest, + ("logging/setLevel", "2025-06-18"): v2025.SetLevelRequest, + ("ping", "2025-06-18"): v2025.PingRequest, + ("prompts/get", "2025-06-18"): v2025.GetPromptRequest, + ("prompts/list", "2025-06-18"): v2025.ListPromptsRequest, + ("resources/list", "2025-06-18"): v2025.ListResourcesRequest, + ("resources/read", "2025-06-18"): v2025.ReadResourceRequest, + ("resources/subscribe", "2025-06-18"): v2025.SubscribeRequest, + ("resources/templates/list", "2025-06-18"): v2025.ListResourceTemplatesRequest, + ("resources/unsubscribe", "2025-06-18"): v2025.UnsubscribeRequest, + ("tools/call", "2025-06-18"): v2025.CallToolRequest, + ("tools/list", "2025-06-18"): v2025.ListToolsRequest, + # 2025-11-25 (tasks/* deliberately absent) + ("completion/complete", "2025-11-25"): v2025.CompleteRequest, + ("initialize", "2025-11-25"): v2025.InitializeRequest, + ("logging/setLevel", "2025-11-25"): v2025.SetLevelRequest, + ("ping", "2025-11-25"): v2025.PingRequest, + ("prompts/get", "2025-11-25"): v2025.GetPromptRequest, + ("prompts/list", "2025-11-25"): v2025.ListPromptsRequest, + ("resources/list", "2025-11-25"): v2025.ListResourcesRequest, + ("resources/read", "2025-11-25"): v2025.ReadResourceRequest, + ("resources/subscribe", "2025-11-25"): v2025.SubscribeRequest, + ("resources/templates/list", "2025-11-25"): v2025.ListResourceTemplatesRequest, + ("resources/unsubscribe", "2025-11-25"): v2025.UnsubscribeRequest, + ("tools/call", "2025-11-25"): v2025.CallToolRequest, + ("tools/list", "2025-11-25"): v2025.ListToolsRequest, + # 2026-07-28 (lifecycle, logging, subscribe pair removed; discover/listen added) + ("completion/complete", "2026-07-28"): v2026.CompleteRequest, + ("prompts/get", "2026-07-28"): v2026.GetPromptRequest, + ("prompts/list", "2026-07-28"): v2026.ListPromptsRequest, + ("resources/list", "2026-07-28"): v2026.ListResourcesRequest, + ("resources/read", "2026-07-28"): v2026.ReadResourceRequest, + ("resources/templates/list", "2026-07-28"): v2026.ListResourceTemplatesRequest, + ("server/discover", "2026-07-28"): v2026.DiscoverRequest, + ("subscriptions/listen", "2026-07-28"): v2026.SubscriptionsListenRequest, + ("tools/call", "2026-07-28"): v2026.CallToolRequest, + ("tools/list", "2026-07-28"): v2026.ListToolsRequest, + } +) + +CLIENT_NOTIFICATIONS: Final[Mapping[tuple[str, str], type[WireModel]]] = MappingProxyType( + { + # 2024-11-05 + ("notifications/cancelled", "2024-11-05"): v2025.CancelledNotification, + ("notifications/initialized", "2024-11-05"): v2025.InitializedNotification, + ("notifications/progress", "2024-11-05"): v2025.ProgressNotification, + ("notifications/roots/list_changed", "2024-11-05"): v2025.RootsListChangedNotification, + # 2025-03-26 + ("notifications/cancelled", "2025-03-26"): v2025.CancelledNotification, + ("notifications/initialized", "2025-03-26"): v2025.InitializedNotification, + ("notifications/progress", "2025-03-26"): v2025.ProgressNotification, + ("notifications/roots/list_changed", "2025-03-26"): v2025.RootsListChangedNotification, + # 2025-06-18 + ("notifications/cancelled", "2025-06-18"): v2025.CancelledNotification, + ("notifications/initialized", "2025-06-18"): v2025.InitializedNotification, + ("notifications/progress", "2025-06-18"): v2025.ProgressNotification, + ("notifications/roots/list_changed", "2025-06-18"): v2025.RootsListChangedNotification, + # 2025-11-25 (tasks/status deliberately absent) + ("notifications/cancelled", "2025-11-25"): v2025.CancelledNotification, + ("notifications/initialized", "2025-11-25"): v2025.InitializedNotification, + ("notifications/progress", "2025-11-25"): v2025.ProgressNotification, + ("notifications/roots/list_changed", "2025-11-25"): v2025.RootsListChangedNotification, + # 2026-07-28 (initialized and roots/list_changed removed) + ("notifications/cancelled", "2026-07-28"): v2026.CancelledNotification, + ("notifications/progress", "2026-07-28"): v2026.ProgressNotification, + } +) + + +# --- Surface maps: server-to-client --- + +SERVER_REQUESTS: Final[Mapping[tuple[str, str], type[WireModel]]] = MappingProxyType( + { + # 2024-11-05 + ("ping", "2024-11-05"): v2025.PingRequest, + ("roots/list", "2024-11-05"): v2025.ListRootsRequest, + ("sampling/createMessage", "2024-11-05"): v2025.CreateMessageRequest, + # 2025-03-26 + ("ping", "2025-03-26"): v2025.PingRequest, + ("roots/list", "2025-03-26"): v2025.ListRootsRequest, + ("sampling/createMessage", "2025-03-26"): v2025.CreateMessageRequest, + # 2025-06-18 (adds elicitation/create) + ("elicitation/create", "2025-06-18"): v2025.ElicitRequest, + ("ping", "2025-06-18"): v2025.PingRequest, + ("roots/list", "2025-06-18"): v2025.ListRootsRequest, + ("sampling/createMessage", "2025-06-18"): v2025.CreateMessageRequest, + # 2025-11-25 (tasks/* deliberately absent) + ("elicitation/create", "2025-11-25"): v2025.ElicitRequest, + ("ping", "2025-11-25"): v2025.PingRequest, + ("roots/list", "2025-11-25"): v2025.ListRootsRequest, + ("sampling/createMessage", "2025-11-25"): v2025.CreateMessageRequest, + # 2026-07-28: none (schema defines no ServerRequest union) + } +) + +SERVER_NOTIFICATIONS: Final[Mapping[tuple[str, str], type[WireModel]]] = MappingProxyType( + { + # 2024-11-05 + ("notifications/cancelled", "2024-11-05"): v2025.CancelledNotification, + ("notifications/message", "2024-11-05"): v2025.LoggingMessageNotification, + ("notifications/progress", "2024-11-05"): v2025.ProgressNotification, + ("notifications/prompts/list_changed", "2024-11-05"): v2025.PromptListChangedNotification, + ("notifications/resources/list_changed", "2024-11-05"): v2025.ResourceListChangedNotification, + ("notifications/resources/updated", "2024-11-05"): v2025.ResourceUpdatedNotification, + ("notifications/tools/list_changed", "2024-11-05"): v2025.ToolListChangedNotification, + # 2025-03-26 + ("notifications/cancelled", "2025-03-26"): v2025.CancelledNotification, + ("notifications/message", "2025-03-26"): v2025.LoggingMessageNotification, + ("notifications/progress", "2025-03-26"): v2025.ProgressNotification, + ("notifications/prompts/list_changed", "2025-03-26"): v2025.PromptListChangedNotification, + ("notifications/resources/list_changed", "2025-03-26"): v2025.ResourceListChangedNotification, + ("notifications/resources/updated", "2025-03-26"): v2025.ResourceUpdatedNotification, + ("notifications/tools/list_changed", "2025-03-26"): v2025.ToolListChangedNotification, + # 2025-06-18 + ("notifications/cancelled", "2025-06-18"): v2025.CancelledNotification, + ("notifications/message", "2025-06-18"): v2025.LoggingMessageNotification, + ("notifications/progress", "2025-06-18"): v2025.ProgressNotification, + ("notifications/prompts/list_changed", "2025-06-18"): v2025.PromptListChangedNotification, + ("notifications/resources/list_changed", "2025-06-18"): v2025.ResourceListChangedNotification, + ("notifications/resources/updated", "2025-06-18"): v2025.ResourceUpdatedNotification, + ("notifications/tools/list_changed", "2025-06-18"): v2025.ToolListChangedNotification, + # 2025-11-25 (adds elicitation/complete; tasks/status deliberately absent) + ("notifications/cancelled", "2025-11-25"): v2025.CancelledNotification, + ("notifications/elicitation/complete", "2025-11-25"): v2025.ElicitationCompleteNotification, + ("notifications/message", "2025-11-25"): v2025.LoggingMessageNotification, + ("notifications/progress", "2025-11-25"): v2025.ProgressNotification, + ("notifications/prompts/list_changed", "2025-11-25"): v2025.PromptListChangedNotification, + ("notifications/resources/list_changed", "2025-11-25"): v2025.ResourceListChangedNotification, + ("notifications/resources/updated", "2025-11-25"): v2025.ResourceUpdatedNotification, + ("notifications/tools/list_changed", "2025-11-25"): v2025.ToolListChangedNotification, + # 2026-07-28 (adds subscriptions/acknowledged) + ("notifications/cancelled", "2026-07-28"): v2026.CancelledNotification, + ("notifications/elicitation/complete", "2026-07-28"): v2026.ElicitationCompleteNotification, + ("notifications/message", "2026-07-28"): v2026.LoggingMessageNotification, + ("notifications/progress", "2026-07-28"): v2026.ProgressNotification, + ("notifications/prompts/list_changed", "2026-07-28"): v2026.PromptListChangedNotification, + ("notifications/resources/list_changed", "2026-07-28"): v2026.ResourceListChangedNotification, + ("notifications/resources/updated", "2026-07-28"): v2026.ResourceUpdatedNotification, + ("notifications/subscriptions/acknowledged", "2026-07-28"): v2026.SubscriptionsAcknowledgedNotification, + ("notifications/tools/list_changed", "2026-07-28"): v2026.ToolListChangedNotification, + } +) + + +# --- Surface maps: results --- + +SERVER_RESULTS: Final[Mapping[tuple[str, str], type[WireModel] | UnionType]] = MappingProxyType( + { + # 2024-11-05 + ("completion/complete", "2024-11-05"): v2025.CompleteResult, + ("initialize", "2024-11-05"): v2025.InitializeResult, + ("logging/setLevel", "2024-11-05"): v2025.EmptyResult, + ("ping", "2024-11-05"): v2025.EmptyResult, + ("prompts/get", "2024-11-05"): v2025.GetPromptResult, + ("prompts/list", "2024-11-05"): v2025.ListPromptsResult, + ("resources/list", "2024-11-05"): v2025.ListResourcesResult, + ("resources/read", "2024-11-05"): v2025.ReadResourceResult, + ("resources/subscribe", "2024-11-05"): v2025.EmptyResult, + ("resources/templates/list", "2024-11-05"): v2025.ListResourceTemplatesResult, + ("resources/unsubscribe", "2024-11-05"): v2025.EmptyResult, + ("tools/call", "2024-11-05"): v2025.CallToolResult, + ("tools/list", "2024-11-05"): v2025.ListToolsResult, + # 2025-03-26 + ("completion/complete", "2025-03-26"): v2025.CompleteResult, + ("initialize", "2025-03-26"): v2025.InitializeResult, + ("logging/setLevel", "2025-03-26"): v2025.EmptyResult, + ("ping", "2025-03-26"): v2025.EmptyResult, + ("prompts/get", "2025-03-26"): v2025.GetPromptResult, + ("prompts/list", "2025-03-26"): v2025.ListPromptsResult, + ("resources/list", "2025-03-26"): v2025.ListResourcesResult, + ("resources/read", "2025-03-26"): v2025.ReadResourceResult, + ("resources/subscribe", "2025-03-26"): v2025.EmptyResult, + ("resources/templates/list", "2025-03-26"): v2025.ListResourceTemplatesResult, + ("resources/unsubscribe", "2025-03-26"): v2025.EmptyResult, + ("tools/call", "2025-03-26"): v2025.CallToolResult, + ("tools/list", "2025-03-26"): v2025.ListToolsResult, + # 2025-06-18 + ("completion/complete", "2025-06-18"): v2025.CompleteResult, + ("initialize", "2025-06-18"): v2025.InitializeResult, + ("logging/setLevel", "2025-06-18"): v2025.EmptyResult, + ("ping", "2025-06-18"): v2025.EmptyResult, + ("prompts/get", "2025-06-18"): v2025.GetPromptResult, + ("prompts/list", "2025-06-18"): v2025.ListPromptsResult, + ("resources/list", "2025-06-18"): v2025.ListResourcesResult, + ("resources/read", "2025-06-18"): v2025.ReadResourceResult, + ("resources/subscribe", "2025-06-18"): v2025.EmptyResult, + ("resources/templates/list", "2025-06-18"): v2025.ListResourceTemplatesResult, + ("resources/unsubscribe", "2025-06-18"): v2025.EmptyResult, + ("tools/call", "2025-06-18"): v2025.CallToolResult, + ("tools/list", "2025-06-18"): v2025.ListToolsResult, + # 2025-11-25 + ("completion/complete", "2025-11-25"): v2025.CompleteResult, + ("initialize", "2025-11-25"): v2025.InitializeResult, + ("logging/setLevel", "2025-11-25"): v2025.EmptyResult, + ("ping", "2025-11-25"): v2025.EmptyResult, + ("prompts/get", "2025-11-25"): v2025.GetPromptResult, + ("prompts/list", "2025-11-25"): v2025.ListPromptsResult, + ("resources/list", "2025-11-25"): v2025.ListResourcesResult, + ("resources/read", "2025-11-25"): v2025.ReadResourceResult, + ("resources/subscribe", "2025-11-25"): v2025.EmptyResult, + ("resources/templates/list", "2025-11-25"): v2025.ListResourceTemplatesResult, + ("resources/unsubscribe", "2025-11-25"): v2025.EmptyResult, + ("tools/call", "2025-11-25"): v2025.CallToolResult, + ("tools/list", "2025-11-25"): v2025.ListToolsResult, + # 2026-07-28 (dual-result rows use the version's union aliases) + ("completion/complete", "2026-07-28"): v2026.CompleteResult, + ("prompts/get", "2026-07-28"): v2026.AnyGetPromptResult, + ("prompts/list", "2026-07-28"): v2026.ListPromptsResult, + ("resources/list", "2026-07-28"): v2026.ListResourcesResult, + ("resources/read", "2026-07-28"): v2026.AnyReadResourceResult, + ("resources/templates/list", "2026-07-28"): v2026.ListResourceTemplatesResult, + ("server/discover", "2026-07-28"): v2026.DiscoverResult, + ("subscriptions/listen", "2026-07-28"): v2026.EmptyResult, + ("tools/call", "2026-07-28"): v2026.AnyCallToolResult, + ("tools/list", "2026-07-28"): v2026.ListToolsResult, + } +) +"""Results servers send, keyed by the originating client request's (method, version).""" + +CLIENT_RESULTS: Final[Mapping[tuple[str, str], type[WireModel] | UnionType]] = MappingProxyType( + { + # 2024-11-05 + ("ping", "2024-11-05"): v2025.EmptyResult, + ("roots/list", "2024-11-05"): v2025.ListRootsResult, + ("sampling/createMessage", "2024-11-05"): v2025.CreateMessageResult, + # 2025-03-26 + ("ping", "2025-03-26"): v2025.EmptyResult, + ("roots/list", "2025-03-26"): v2025.ListRootsResult, + ("sampling/createMessage", "2025-03-26"): v2025.CreateMessageResult, + # 2025-06-18 + ("elicitation/create", "2025-06-18"): v2025.ElicitResult, + ("ping", "2025-06-18"): v2025.EmptyResult, + ("roots/list", "2025-06-18"): v2025.ListRootsResult, + ("sampling/createMessage", "2025-06-18"): v2025.CreateMessageResult, + # 2025-11-25 + ("elicitation/create", "2025-11-25"): v2025.ElicitResult, + ("ping", "2025-11-25"): v2025.EmptyResult, + ("roots/list", "2025-11-25"): v2025.ListRootsResult, + ("sampling/createMessage", "2025-11-25"): v2025.CreateMessageResult, + # 2026-07-28: none (no server-to-client requests at this version) + } +) +"""Results clients send, keyed by the originating server request's (method, version).""" + + +# --- Monolith maps --- + +MONOLITH_REQUESTS: Final[Mapping[str, type[types.Request[Any, Any]]]] = MappingProxyType( + { + "completion/complete": types.CompleteRequest, + "elicitation/create": types.ElicitRequest, + "initialize": types.InitializeRequest, + "logging/setLevel": types.SetLevelRequest, + "ping": types.PingRequest, + "prompts/get": types.GetPromptRequest, + "prompts/list": types.ListPromptsRequest, + "resources/list": types.ListResourcesRequest, + "resources/read": types.ReadResourceRequest, + "resources/subscribe": types.SubscribeRequest, + "resources/templates/list": types.ListResourceTemplatesRequest, + "resources/unsubscribe": types.UnsubscribeRequest, + "roots/list": types.ListRootsRequest, + "sampling/createMessage": types.CreateMessageRequest, + "server/discover": types.DiscoverRequest, + "subscriptions/listen": types.SubscriptionsListenRequest, + "tools/call": types.CallToolRequest, + "tools/list": types.ListToolsRequest, + } +) +"""Monolith request model per method, both directions.""" + +MONOLITH_NOTIFICATIONS: Final[Mapping[str, type[types.Notification[Any, Any]]]] = MappingProxyType( + { + "notifications/cancelled": types.CancelledNotification, + "notifications/elicitation/complete": types.ElicitCompleteNotification, + "notifications/initialized": types.InitializedNotification, + "notifications/message": types.LoggingMessageNotification, + "notifications/progress": types.ProgressNotification, + "notifications/prompts/list_changed": types.PromptListChangedNotification, + "notifications/resources/list_changed": types.ResourceListChangedNotification, + "notifications/resources/updated": types.ResourceUpdatedNotification, + "notifications/roots/list_changed": types.RootsListChangedNotification, + "notifications/subscriptions/acknowledged": types.SubscriptionsAcknowledgedNotification, + "notifications/tools/list_changed": types.ToolListChangedNotification, + } +) +"""Monolith notification model per method, both directions.""" + +MONOLITH_RESULTS: Final[Mapping[str, type[types.Result] | UnionType]] = MappingProxyType( + { + "completion/complete": types.CompleteResult, + "elicitation/create": types.ElicitResult, + "initialize": types.InitializeResult, + "logging/setLevel": types.EmptyResult, + "ping": types.EmptyResult, + "prompts/get": types.GetPromptResult | types.InputRequiredResult, + "prompts/list": types.ListPromptsResult, + "resources/list": types.ListResourcesResult, + "resources/read": types.ReadResourceResult | types.InputRequiredResult, + "resources/subscribe": types.EmptyResult, + "resources/templates/list": types.ListResourceTemplatesResult, + "resources/unsubscribe": types.EmptyResult, + "roots/list": types.ListRootsResult, + # Arm order load-bearing: a single-block body satisfies both arms and + # smart-union ties resolve leftmost. Pinned by tests/types/test_methods.py. + "sampling/createMessage": types.CreateMessageResult | types.CreateMessageResultWithTools, + "server/discover": types.DiscoverResult, + "subscriptions/listen": types.EmptyResult, + "tools/call": types.CallToolResult | types.InputRequiredResult, + "tools/list": types.ListToolsResult, + } +) +"""Monolith result model (or two-arm union) per request method.""" + + +# --- Parse functions --- + +# Envelope stubs merged into bodies for surface validation (surface classes are full frames). +_REQUEST_STUB: Final[Mapping[str, Any]] = MappingProxyType({"jsonrpc": "2.0", "id": 0}) +_NOTIFICATION_STUB: Final[Mapping[str, Any]] = MappingProxyType({"jsonrpc": "2.0"}) + + +def _check_known_version(version: str) -> None: + """Raise ValueError for unknown `version` so a typo cannot silently gate every method.""" + if version not in KNOWN_PROTOCOL_VERSIONS: + raise ValueError(f"version must be a known protocol version, got {version!r}") + + +def _body(method: str, params: Mapping[str, Any] | None) -> dict[str, Any]: + """Build a JSON-RPC body, omitting `params` when None.""" + body: dict[str, Any] = {"method": method} + if params is not None: + body["params"] = params + return body + + +@cache +def _adapter(target: type[BaseModel] | UnionType) -> TypeAdapter[Any]: + return TypeAdapter(target) + + +_MonolithT = TypeVar("_MonolithT") + + +def _monolith_row(monolith: Mapping[str, _MonolithT], method: str) -> _MonolithT: + """Look up `method` in `monolith`, raising RuntimeError on miss. + + Not KeyError: the surface row already matched, so a miss is inconsistent + extension maps and must not be caught by the session's `except KeyError` gate. + """ + try: + return monolith[method] + except KeyError: + raise RuntimeError(f"inconsistent extension maps: surface defines {method!r} but monolith does not") from None + + +def parse_client_request( + method: str, + version: str, + params: Mapping[str, Any] | None, + *, + surface: Mapping[tuple[str, str], type[WireModel]] = CLIENT_REQUESTS, + monolith: Mapping[str, type[types.Request[Any, Any]]] = MONOLITH_REQUESTS, +) -> types.Request[Any, Any]: + """Validate a client request against `surface`, then parse and return its `monolith` model. + + Args: + surface: `(method, version)` to schema-exact type map; the version-gate + lookup and shape check run against this. Pass an extended map to + admit custom methods. + monolith: `method` to version-free model map; the returned instance is + parsed from this row. Must cover every method `surface` admits. + + Raises: + ValueError: `version` is not a known protocol version. + KeyError: `(method, version)` is not in `surface` (the version gate). + pydantic.ValidationError: body fails surface or monolith validation. + RuntimeError: surface matched but `method` has no monolith row. + """ + _check_known_version(version) + surface_type = surface[(method, version)] + surface_type.model_validate({**_REQUEST_STUB, **_body(method, params)}, by_name=False) + return _monolith_row(monolith, method).model_validate(_body(method, params), by_name=False) + + +def parse_server_request( + method: str, + version: str, + params: Mapping[str, Any] | None, + *, + surface: Mapping[tuple[str, str], type[WireModel]] = SERVER_REQUESTS, + monolith: Mapping[str, type[types.Request[Any, Any]]] = MONOLITH_REQUESTS, +) -> types.Request[Any, Any]: + """Validate a server request against `surface`, then parse and return its `monolith` model. + + Args: + surface: `(method, version)` to schema-exact type map; the version-gate + lookup and shape check run against this. Pass an extended map to + admit custom methods. + monolith: `method` to version-free model map; the returned instance is + parsed from this row. Must cover every method `surface` admits. + + Raises: + ValueError: `version` is not a known protocol version. + KeyError: `(method, version)` is not in `surface` (the version gate). + pydantic.ValidationError: body fails surface or monolith validation. + RuntimeError: surface matched but `method` has no monolith row. + """ + _check_known_version(version) + surface_type = surface[(method, version)] + surface_type.model_validate({**_REQUEST_STUB, **_body(method, params)}, by_name=False) + return _monolith_row(monolith, method).model_validate(_body(method, params), by_name=False) + + +def parse_client_notification( + method: str, + version: str, + params: Mapping[str, Any] | None, + *, + surface: Mapping[tuple[str, str], type[WireModel]] = CLIENT_NOTIFICATIONS, + monolith: Mapping[str, type[types.Notification[Any, Any]]] = MONOLITH_NOTIFICATIONS, +) -> types.Notification[Any, Any]: + """Validate a client notification against `surface`, then parse and return its `monolith` model. + + Args: + surface: `(method, version)` to schema-exact type map; the version-gate + lookup and shape check run against this. Pass an extended map to + admit custom methods. + monolith: `method` to version-free model map; the returned instance is + parsed from this row. Must cover every method `surface` admits. + + Raises: + ValueError: `version` is not a known protocol version. + KeyError: `(method, version)` is not in `surface`. + pydantic.ValidationError: body fails surface or monolith validation. + RuntimeError: surface matched but `method` has no monolith row. + """ + _check_known_version(version) + surface_type = surface[(method, version)] + surface_type.model_validate({**_NOTIFICATION_STUB, **_body(method, params)}, by_name=False) + return _monolith_row(monolith, method).model_validate(_body(method, params), by_name=False) + + +def parse_server_notification( + method: str, + version: str, + params: Mapping[str, Any] | None, + *, + surface: Mapping[tuple[str, str], type[WireModel]] = SERVER_NOTIFICATIONS, + monolith: Mapping[str, type[types.Notification[Any, Any]]] = MONOLITH_NOTIFICATIONS, +) -> types.Notification[Any, Any]: + """Validate a server notification against `surface`, then parse and return its `monolith` model. + + Args: + surface: `(method, version)` to schema-exact type map; the version-gate + lookup and shape check run against this. Pass an extended map to + admit custom methods. + monolith: `method` to version-free model map; the returned instance is + parsed from this row. Must cover every method `surface` admits. + + Raises: + ValueError: `version` is not a known protocol version. + KeyError: `(method, version)` is not in `surface`. + pydantic.ValidationError: body fails surface or monolith validation. + RuntimeError: surface matched but `method` has no monolith row. + """ + _check_known_version(version) + surface_type = surface[(method, version)] + surface_type.model_validate({**_NOTIFICATION_STUB, **_body(method, params)}, by_name=False) + return _monolith_row(monolith, method).model_validate(_body(method, params), by_name=False) + + +def parse_server_result( + method: str, + version: str, + data: Mapping[str, Any], + *, + surface: Mapping[tuple[str, str], type[WireModel] | UnionType] = SERVER_RESULTS, + monolith: Mapping[str, type[types.Result] | UnionType] = MONOLITH_RESULTS, +) -> types.Result: + """Validate a server result against `surface`, then parse and return its `monolith` model. + + Args: + surface: `(method, version)` to schema-exact type map; the version-gate + lookup and shape check run against this. Pass an extended map to + admit custom methods. + monolith: `method` to version-free model map; the returned instance is + parsed from this row. Must cover every method `surface` admits. + + Raises: + ValueError: `version` is not a known protocol version. + KeyError: `(method, version)` is not in `surface`. + pydantic.ValidationError: result fails surface or monolith validation. + RuntimeError: surface matched but `method` has no monolith row. + """ + _check_known_version(version) + _adapter(surface[(method, version)]).validate_python(data, by_name=False) + result: types.Result = _adapter(_monolith_row(monolith, method)).validate_python(data, by_name=False) + return result + + +def parse_client_result( + method: str, + version: str, + data: Mapping[str, Any], + *, + surface: Mapping[tuple[str, str], type[WireModel] | UnionType] = CLIENT_RESULTS, + monolith: Mapping[str, type[types.Result] | UnionType] = MONOLITH_RESULTS, +) -> types.Result: + """Validate a client result against `surface`, then parse and return its `monolith` model. + + Args: + surface: `(method, version)` to schema-exact type map; the version-gate + lookup and shape check run against this. Pass an extended map to + admit custom methods. + monolith: `method` to version-free model map; the returned instance is + parsed from this row. Must cover every method `surface` admits. + + Raises: + ValueError: `version` is not a known protocol version. + KeyError: `(method, version)` is not in `surface`. + pydantic.ValidationError: result fails surface or monolith validation. + RuntimeError: surface matched but `method` has no monolith row. + """ + _check_known_version(version) + _adapter(surface[(method, version)]).validate_python(data, by_name=False) + result: types.Result = _adapter(_monolith_row(monolith, method)).validate_python(data, by_name=False) + return result diff --git a/src/mcp/types/v2025_11_25/__init__.py b/src/mcp/types/v2025_11_25/__init__.py new file mode 100644 index 0000000000..aeddcba6a6 --- /dev/null +++ b/src/mcp/types/v2025_11_25/__init__.py @@ -0,0 +1,2839 @@ +"""Internal wire-shape models for protocol 2025-11-25. Not part of the public API. + +Generated by `scripts/gen_surface_types.py` from `schema/2025-11-25.json` +@ 6d441518de8a9d5adbab0b10a76a667a63f90665. Do not edit; regenerate. Serves inbound validation for every +protocol version through 2025-11-25 (each earlier schema is a strict subset of +this one). Models default to `extra="ignore"`; the few kept open are commented +in place. See `mcp.types._wire_base` and `mcp.types.methods`. +""" + +from __future__ import annotations + +from typing import Annotated, Any, Literal, TypeAlias + +from pydantic import ConfigDict, Field + +from mcp.types._wire_base import OpenWireModel, WireModel + + +class BaseMetadata(WireModel): + """Base interface for metadata with name (identifier) and title (display name) properties.""" + + name: str + """ + Intended for programmatic or logical use, but used as a display name in past specs or fallback (if title isn't + present). + """ + title: str | None = None + """ + Intended for UI and end-user contexts — optimized to be human-readable and easily understood, + even by those unfamiliar with domain-specific terminology. + + If not provided, the name should be used for display (except for Tool, + where `annotations.title` should be given precedence over using `name`, + if present). + """ + + +class BlobResourceContents(WireModel): + meta: Annotated[dict[str, Any] | None, Field(alias="_meta")] = None + """ + See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage. + """ + blob: str + """ + A base64-encoded string representing the binary data of the item. + """ + mime_type: Annotated[str | None, Field(alias="mimeType")] = None + """ + The MIME type of this resource, if known. + """ + uri: str + """ + The URI of this resource. + """ + + +class BooleanSchema(WireModel): + default: bool | None = None + description: str | None = None + title: str | None = None + type: Literal["boolean"] + + +class CancelTaskRequestParams(WireModel): + task_id: Annotated[str, Field(alias="taskId")] + """ + The task identifier to cancel. + """ + + +class Elicitation(WireModel): + """Present if the client supports elicitation from the server.""" + + form: dict[str, Any] | None = None + url: dict[str, Any] | None = None + + +class Roots(WireModel): + """Present if the client supports listing roots.""" + + list_changed: Annotated[bool | None, Field(alias="listChanged")] = None + """ + Whether the client supports notifications for changes to the roots list. + """ + + +class Sampling(WireModel): + """Present if the client supports sampling from an LLM.""" + + context: dict[str, Any] | None = None + """ + Whether the client supports context inclusion via includeContext parameter. + If not declared, servers SHOULD only use `includeContext: "none"` (or omit it). + """ + tools: dict[str, Any] | None = None + """ + Whether the client supports tool use via tools and toolChoice parameters. + """ + + +class Elicitation1(WireModel): + """Task support for elicitation-related requests.""" + + create: dict[str, Any] | None = None + """ + Whether the client supports task-augmented elicitation/create requests. + """ + + +class Sampling1(WireModel): + """Task support for sampling-related requests.""" + + create_message: Annotated[dict[str, Any] | None, Field(alias="createMessage")] = None + """ + Whether the client supports task-augmented sampling/createMessage requests. + """ + + +class Requests(WireModel): + """Specifies which request types can be augmented with tasks.""" + + elicitation: Elicitation1 | None = None + """ + Task support for elicitation-related requests. + """ + sampling: Sampling1 | None = None + """ + Task support for sampling-related requests. + """ + + +class Tasks(WireModel): + """Present if the client supports task-augmented requests.""" + + cancel: dict[str, Any] | None = None + """ + Whether this client supports tasks/cancel. + """ + list: dict[str, Any] | None = None + """ + Whether this client supports tasks/list. + """ + requests: Requests | None = None + """ + Specifies which request types can be augmented with tasks. + """ + + +class ClientCapabilities(WireModel): + """Capabilities a client may support. Known capabilities are defined here, in this schema, but this is not a + closed set: any client can define its own, additional capabilities. + """ + + elicitation: Elicitation | None = None + """ + Present if the client supports elicitation from the server. + """ + experimental: dict[str, dict[str, Any]] | None = None + """ + Experimental, non-standard capabilities that the client supports. + """ + roots: Roots | None = None + """ + Present if the client supports listing roots. + """ + sampling: Sampling | None = None + """ + Present if the client supports sampling from an LLM. + """ + tasks: Tasks | None = None + """ + Present if the client supports task-augmented requests. + """ + + +class Argument(WireModel): + """The argument's information""" + + name: str + """ + The name of the argument + """ + value: str + """ + The value of the argument to use for completion matching. + """ + + +class Context(WireModel): + """Additional, optional context for completions""" + + arguments: dict[str, str] | None = None + """ + Previously-resolved variables in a URI template or prompt. + """ + + +class Completion(WireModel): + has_more: Annotated[bool | None, Field(alias="hasMore")] = None + """ + Indicates whether there are additional completion options beyond those provided in the current response, even if the + exact total is unknown. + """ + total: int | None = None + """ + The total number of completion options available. This can exceed the number of values actually sent in the + response. + """ + values: list[str] + """ + An array of completion values. Must not exceed 100 items. + """ + + +class CompleteResult(WireModel): + """The server's response to a completion/complete request""" + + meta: Annotated[dict[str, Any] | None, Field(alias="_meta")] = None + """ + See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage. + """ + completion: Completion + + +Cursor: TypeAlias = str + + +class ElicitResult(WireModel): + """The client's response to an elicitation request.""" + + meta: Annotated[dict[str, Any] | None, Field(alias="_meta")] = None + """ + See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage. + """ + action: Literal["accept", "cancel", "decline"] + """ + The user action in response to the elicitation. + - "accept": User submitted the form/confirmed the action + - "decline": User explicitly decline the action + - "cancel": User dismissed without making an explicit choice + """ + # schema.json renders this `number` as integer; widen per schema.ts so floats validate. + content: dict[str, list[str] | str | int | float | bool] | None = None + """ + The submitted form data, only present when action is "accept" and mode was "form". + Contains values matching the requested schema. + Omitted for out-of-band mode responses. + """ + + +class ElicitationCompleteNotificationParams(WireModel): + elicitation_id: Annotated[str, Field(alias="elicitationId")] + """ + The ID of the elicitation that completed. + """ + + +class ElicitationCompleteNotification(WireModel): + """An optional notification from the server to the client, informing it of a completion of a out-of-band + elicitation request. + """ + + jsonrpc: Literal["2.0"] + method: Literal["notifications/elicitation/complete"] + params: ElicitationCompleteNotificationParams + + +class Error(WireModel): + code: int + """ + The error type that occurred. + """ + data: Any | None = None + """ + Additional information about the error. The value of this member is defined by the sender (e.g. detailed error + information, nested errors etc.). + """ + message: str + """ + A short description of the error. The message SHOULD be limited to a concise single sentence. + """ + + +class GetTaskPayloadRequestParams(WireModel): + task_id: Annotated[str, Field(alias="taskId")] + """ + The task identifier to retrieve results for. + """ + + +class GetTaskPayloadResult(WireModel): + """The response to a tasks/result request. + The structure matches the result type of the original request. + For example, a tools/call task would return the CallToolResult structure. + """ + + meta: Annotated[dict[str, Any] | None, Field(alias="_meta")] = None + """ + See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage. + """ + + +class GetTaskRequestParams(WireModel): + task_id: Annotated[str, Field(alias="taskId")] + """ + The task identifier to query. + """ + + +class Icon(WireModel): + """An optionally-sized icon that can be displayed in a user interface.""" + + mime_type: Annotated[str | None, Field(alias="mimeType")] = None + """ + Optional MIME type override if the source MIME type is missing or generic. + For example: `"image/png"`, `"image/jpeg"`, or `"image/svg+xml"`. + """ + sizes: list[str] | None = None + """ + Optional array of strings that specify sizes at which the icon can be used. + Each string should be in WxH format (e.g., `"48x48"`, `"96x96"`) or `"any"` for scalable formats like SVG. + + If not provided, the client should assume that the icon can be used at any size. + """ + src: str + """ + A standard URI pointing to an icon resource. May be an HTTP/HTTPS URL or a + `data:` URI with Base64-encoded image data. + + Consumers SHOULD takes steps to ensure URLs serving icons are from the + same domain as the client/server or a trusted domain. + + Consumers SHOULD take appropriate precautions when consuming SVGs as they can contain + executable JavaScript. + """ + theme: Literal["dark", "light"] | None = None + """ + Optional specifier for the theme this icon is designed for. `light` indicates + the icon is designed to be used with a light background, and `dark` indicates + the icon is designed to be used with a dark background. + + If not provided, the client should assume the icon can be used with any theme. + """ + + +class Icons(WireModel): + """Base interface to add `icons` property.""" + + icons: list[Icon] | None = None + """ + Optional set of sized icons that the client can display in a user interface. + + Clients that support rendering icons MUST support at least the following MIME types: + - `image/png` - PNG images (safe, universal compatibility) + - `image/jpeg` (and `image/jpg`) - JPEG images (safe, universal compatibility) + + Clients that support rendering icons SHOULD also support: + - `image/svg+xml` - SVG images (scalable but requires security precautions) + - `image/webp` - WebP images (modern, efficient format) + """ + + +class Implementation(WireModel): + """Describes the MCP implementation.""" + + description: str | None = None + """ + An optional human-readable description of what this implementation does. + + This can be used by clients or servers to provide context about their purpose + and capabilities. For example, a server might describe the types of resources + or tools it provides, while a client might describe its intended use case. + """ + icons: list[Icon] | None = None + """ + Optional set of sized icons that the client can display in a user interface. + + Clients that support rendering icons MUST support at least the following MIME types: + - `image/png` - PNG images (safe, universal compatibility) + - `image/jpeg` (and `image/jpg`) - JPEG images (safe, universal compatibility) + + Clients that support rendering icons SHOULD also support: + - `image/svg+xml` - SVG images (scalable but requires security precautions) + - `image/webp` - WebP images (modern, efficient format) + """ + name: str + """ + Intended for programmatic or logical use, but used as a display name in past specs or fallback (if title isn't + present). + """ + title: str | None = None + """ + Intended for UI and end-user contexts — optimized to be human-readable and easily understood, + even by those unfamiliar with domain-specific terminology. + + If not provided, the name should be used for display (except for Tool, + where `annotations.title` should be given precedence over using `name`, + if present). + """ + version: str + website_url: Annotated[str | None, Field(alias="websiteUrl")] = None + """ + An optional URL of the website for this implementation. + """ + + +class JSONRPCNotification(WireModel): + """A notification which does not expect a response.""" + + jsonrpc: Literal["2.0"] + method: str + params: dict[str, Any] | None = None + + +class LegacyTitledEnumSchema(WireModel): + """Use TitledSingleSelectEnumSchema instead. + This interface will be removed in a future version. + """ + + default: str | None = None + description: str | None = None + enum: list[str] + enum_names: Annotated[list[str] | None, Field(alias="enumNames")] = None + """ + (Legacy) Display names for enum values. + Non-standard according to JSON schema 2020-12. + """ + title: str | None = None + type: Literal["string"] + + +LoggingLevel: TypeAlias = Literal["alert", "critical", "debug", "emergency", "error", "info", "notice", "warning"] + + +class LoggingMessageNotificationParams(WireModel): + """Parameters for a `notifications/message` notification.""" + + meta: Annotated[dict[str, Any] | None, Field(alias="_meta")] = None + """ + See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage. + """ + data: Any + """ + The data to be logged, such as a string message or an object. Any JSON serializable type is allowed here. + """ + level: LoggingLevel + """ + The severity of this log message. + """ + logger: str | None = None + """ + An optional name of the logger issuing this message. + """ + + +class ModelHint(WireModel): + """Hints to use for model selection. + + Keys not declared here are currently left unspecified by the spec and are up + to the client to interpret. + """ + + name: str | None = None + """ + A hint for a model name. + + The client SHOULD treat this as a substring of a model name; for example: + - `claude-3-5-sonnet` should match `claude-3-5-sonnet-20241022` + - `sonnet` should match `claude-3-5-sonnet-20241022`, `claude-3-sonnet-20240229`, etc. + - `claude` should match any Claude model + + The client MAY also map the string to a different provider's model name or a different model family, as long as it + fills a similar niche; for example: + - `gemini-1.5-flash` could match `claude-3-haiku-20240307` + """ + + +class ModelPreferences(WireModel): + """The server's preferences for model selection, requested of the client during sampling. + + Because LLMs can vary along multiple dimensions, choosing the "best" model is + rarely straightforward. Different models excel in different areas—some are + faster but less capable, others are more capable but more expensive, and so + on. This interface allows servers to express their priorities across multiple + dimensions to help clients make an appropriate selection for their use case. + + These preferences are always advisory. The client MAY ignore them. It is also + up to the client to decide how to interpret these preferences and how to + balance them against other considerations. + """ + + cost_priority: Annotated[float | None, Field(alias="costPriority", ge=0.0, le=1.0)] = None + """ + How much to prioritize cost when selecting a model. A value of 0 means cost + is not important, while a value of 1 means cost is the most important + factor. + """ + hints: list[ModelHint] | None = None + """ + Optional hints to use for model selection. + + If multiple hints are specified, the client MUST evaluate them in order + (such that the first match is taken). + + The client SHOULD prioritize these hints over the numeric priorities, but + MAY still use the priorities to select from ambiguous matches. + """ + intelligence_priority: Annotated[float | None, Field(alias="intelligencePriority", ge=0.0, le=1.0)] = None + """ + How much to prioritize intelligence and capabilities when selecting a + model. A value of 0 means intelligence is not important, while a value of 1 + means intelligence is the most important factor. + """ + speed_priority: Annotated[float | None, Field(alias="speedPriority", ge=0.0, le=1.0)] = None + """ + How much to prioritize sampling speed (latency) when selecting a model. A + value of 0 means speed is not important, while a value of 1 means speed is + the most important factor. + """ + + +class Notification(WireModel): + method: str + params: dict[str, Any] | None = None + + +class NotificationParams(WireModel): + meta: Annotated[dict[str, Any] | None, Field(alias="_meta")] = None + """ + See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage. + """ + + +class NumberSchema(WireModel): + # schema.json renders this `number` as integer; widen per schema.ts so floats validate. + default: int | float | None = None + description: str | None = None + # schema.json renders this `number` as integer; widen per schema.ts so floats validate. + maximum: int | float | None = None + # schema.json renders this `number` as integer; widen per schema.ts so floats validate. + minimum: int | float | None = None + title: str | None = None + type: Literal["integer", "number"] + + +class PaginatedResult(WireModel): + meta: Annotated[dict[str, Any] | None, Field(alias="_meta")] = None + """ + See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage. + """ + next_cursor: Annotated[str | None, Field(alias="nextCursor")] = None + """ + An opaque token representing the pagination position after the last returned result. + If present, there may be more results available. + """ + + +ProgressToken: TypeAlias = str | int + + +class PromptArgument(WireModel): + """Describes an argument that a prompt can accept.""" + + description: str | None = None + """ + A human-readable description of the argument. + """ + name: str + """ + Intended for programmatic or logical use, but used as a display name in past specs or fallback (if title isn't + present). + """ + required: bool | None = None + """ + Whether this argument must be provided. + """ + title: str | None = None + """ + Intended for UI and end-user contexts — optimized to be human-readable and easily understood, + even by those unfamiliar with domain-specific terminology. + + If not provided, the name should be used for display (except for Tool, + where `annotations.title` should be given precedence over using `name`, + if present). + """ + + +class PromptListChangedNotification(WireModel): + """An optional notification from the server to the client, informing it that the list of prompts it offers has + changed. This may be issued by servers without any previous subscription from the client. + """ + + jsonrpc: Literal["2.0"] + method: Literal["notifications/prompts/list_changed"] + params: NotificationParams | None = None + + +class PromptReference(WireModel): + """Identifies a prompt.""" + + name: str + """ + Intended for programmatic or logical use, but used as a display name in past specs or fallback (if title isn't + present). + """ + title: str | None = None + """ + Intended for UI and end-user contexts — optimized to be human-readable and easily understood, + even by those unfamiliar with domain-specific terminology. + + If not provided, the name should be used for display (except for Tool, + where `annotations.title` should be given precedence over using `name`, + if present). + """ + type: Literal["ref/prompt"] + + +class Meta(OpenWireModel): + """See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage.""" + + progress_token: Annotated[ProgressToken | None, Field(alias="progressToken")] = None + """ + If specified, the caller is requesting out-of-band progress notifications for this request (as represented by + notifications/progress). The value of this parameter is an opaque token that will be attached to any subsequent + notifications. The receiver is not obligated to provide these notifications. + """ + + +class ReadResourceRequestParams(WireModel): + """Parameters for a `resources/read` request.""" + + meta: Annotated[Meta | None, Field(alias="_meta")] = None + """ + See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage. + """ + uri: str + """ + The URI of the resource. The URI can use any protocol; it is up to the server how to interpret it. + """ + + +class RelatedTaskMetadata(WireModel): + """Metadata for associating messages with a task. + Include this in the `_meta` field under the key `io.modelcontextprotocol/related-task`. + """ + + task_id: Annotated[str, Field(alias="taskId")] + """ + The task identifier this message is associated with. + """ + + +class Request(WireModel): + method: str + params: dict[str, Any] | None = None + + +RequestId: TypeAlias = str | int + + +class RequestParams(WireModel): + """Common params for any request.""" + + meta: Annotated[Meta | None, Field(alias="_meta")] = None + """ + See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage. + """ + + +class ResourceContents(WireModel): + """The contents of a specific resource or sub-resource.""" + + meta: Annotated[dict[str, Any] | None, Field(alias="_meta")] = None + """ + See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage. + """ + mime_type: Annotated[str | None, Field(alias="mimeType")] = None + """ + The MIME type of this resource, if known. + """ + uri: str + """ + The URI of this resource. + """ + + +class ResourceListChangedNotification(WireModel): + """An optional notification from the server to the client, informing it that the list of resources it can read + from has changed. This may be issued by servers without any previous subscription from the client. + """ + + jsonrpc: Literal["2.0"] + method: Literal["notifications/resources/list_changed"] + params: NotificationParams | None = None + + +class ResourceRequestParams(WireModel): + """Common parameters when working with resources.""" + + meta: Annotated[Meta | None, Field(alias="_meta")] = None + """ + See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage. + """ + uri: str + """ + The URI of the resource. The URI can use any protocol; it is up to the server how to interpret it. + """ + + +class ResourceTemplateReference(WireModel): + """A reference to a resource or resource template definition.""" + + type: Literal["ref/resource"] + uri: str + """ + The URI or URI template of the resource. + """ + + +class ResourceUpdatedNotificationParams(WireModel): + """Parameters for a `notifications/resources/updated` notification.""" + + meta: Annotated[dict[str, Any] | None, Field(alias="_meta")] = None + """ + See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage. + """ + uri: str + """ + The URI of the resource that has been updated. This might be a sub-resource of the one that the client actually + subscribed to. + """ + + +class Result(WireModel): + meta: Annotated[dict[str, Any] | None, Field(alias="_meta")] = None + """ + See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage. + """ + + +Role: TypeAlias = Literal["assistant", "user"] + + +class Root(WireModel): + """Represents a root directory or file that the server can operate on.""" + + meta: Annotated[dict[str, Any] | None, Field(alias="_meta")] = None + """ + See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage. + """ + name: str | None = None + """ + An optional name for the root. This can be used to provide a human-readable + identifier for the root, which may be useful for display purposes or for + referencing the root in other parts of the application. + """ + uri: str + """ + The URI identifying the root. This *must* start with file:// for now. + This restriction may be relaxed in future versions of the protocol to allow + other URI schemes. + """ + + +class RootsListChangedNotification(WireModel): + """A notification from the client to the server, informing it that the list of roots has changed. + This notification should be sent whenever the client adds, removes, or modifies any root. + The server should then request an updated list of roots using the ListRootsRequest. + """ + + jsonrpc: Literal["2.0"] + method: Literal["notifications/roots/list_changed"] + params: NotificationParams | None = None + + +class Prompts(WireModel): + """Present if the server offers any prompt templates.""" + + list_changed: Annotated[bool | None, Field(alias="listChanged")] = None + """ + Whether this server supports notifications for changes to the prompt list. + """ + + +class Resources(WireModel): + """Present if the server offers any resources to read.""" + + list_changed: Annotated[bool | None, Field(alias="listChanged")] = None + """ + Whether this server supports notifications for changes to the resource list. + """ + subscribe: bool | None = None + """ + Whether this server supports subscribing to resource updates. + """ + + +class Tools(WireModel): + """Task support for tool-related requests.""" + + call: dict[str, Any] | None = None + """ + Whether the server supports task-augmented tools/call requests. + """ + + +class Requests1(WireModel): + """Specifies which request types can be augmented with tasks.""" + + tools: Tools | None = None + """ + Task support for tool-related requests. + """ + + +class Tasks1(WireModel): + """Present if the server supports task-augmented requests.""" + + cancel: dict[str, Any] | None = None + """ + Whether this server supports tasks/cancel. + """ + list: dict[str, Any] | None = None + """ + Whether this server supports tasks/list. + """ + requests: Requests1 | None = None + """ + Specifies which request types can be augmented with tasks. + """ + + +class Tools1(WireModel): + """Present if the server offers any tools to call.""" + + list_changed: Annotated[bool | None, Field(alias="listChanged")] = None + """ + Whether this server supports notifications for changes to the tool list. + """ + + +class ServerCapabilities(WireModel): + """Capabilities that a server may support. Known capabilities are defined here, in this schema, but this is not a + closed set: any server can define its own, additional capabilities. + """ + + completions: dict[str, Any] | None = None + """ + Present if the server supports argument autocompletion suggestions. + """ + experimental: dict[str, dict[str, Any]] | None = None + """ + Experimental, non-standard capabilities that the server supports. + """ + logging: dict[str, Any] | None = None + """ + Present if the server supports sending log messages to the client. + """ + prompts: Prompts | None = None + """ + Present if the server offers any prompt templates. + """ + resources: Resources | None = None + """ + Present if the server offers any resources to read. + """ + tasks: Tasks1 | None = None + """ + Present if the server supports task-augmented requests. + """ + tools: Tools1 | None = None + """ + Present if the server offers any tools to call. + """ + + +class SetLevelRequestParams(WireModel): + """Parameters for a `logging/setLevel` request.""" + + meta: Annotated[Meta | None, Field(alias="_meta")] = None + """ + See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage. + """ + level: LoggingLevel + """ + The level of logging that the client wants to receive from the server. The server should send all logs at this level + and higher (i.e., more severe) to the client as notifications/message. + """ + + +class StringSchema(WireModel): + default: str | None = None + description: str | None = None + format: Literal["date", "date-time", "email", "uri"] | None = None + max_length: Annotated[int | None, Field(alias="maxLength")] = None + min_length: Annotated[int | None, Field(alias="minLength")] = None + title: str | None = None + type: Literal["string"] + + +class SubscribeRequestParams(WireModel): + """Parameters for a `resources/subscribe` request.""" + + meta: Annotated[Meta | None, Field(alias="_meta")] = None + """ + See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage. + """ + uri: str + """ + The URI of the resource. The URI can use any protocol; it is up to the server how to interpret it. + """ + + +class TaskMetadata(WireModel): + """Metadata for augmenting a request with task execution. + Include this in the `task` field of the request parameters. + """ + + ttl: int | None = None + """ + Requested duration in milliseconds to retain task from creation. + """ + + +TaskStatus: TypeAlias = Literal["cancelled", "completed", "failed", "input_required", "working"] + + +class TextResourceContents(WireModel): + meta: Annotated[dict[str, Any] | None, Field(alias="_meta")] = None + """ + See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage. + """ + mime_type: Annotated[str | None, Field(alias="mimeType")] = None + """ + The MIME type of this resource, if known. + """ + text: str + """ + The text of the item. This must only be set if the item can actually be represented as text (not binary data). + """ + uri: str + """ + The URI of this resource. + """ + + +class AnyOfItem(WireModel): + const: str + """ + The constant enum value. + """ + title: str + """ + Display title for this option. + """ + + +class Items(WireModel): + """Schema for array items with enum options and display labels.""" + + any_of: Annotated[list[AnyOfItem], Field(alias="anyOf")] + """ + Array of enum options with values and display labels. + """ + + +class TitledMultiSelectEnumSchema(WireModel): + """Schema for multiple-selection enumeration with display titles for each option.""" + + default: list[str] | None = None + """ + Optional default value. + """ + description: str | None = None + """ + Optional description for the enum field. + """ + items: Items + """ + Schema for array items with enum options and display labels. + """ + max_items: Annotated[int | None, Field(alias="maxItems")] = None + """ + Maximum number of items to select. + """ + min_items: Annotated[int | None, Field(alias="minItems")] = None + """ + Minimum number of items to select. + """ + title: str | None = None + """ + Optional title for the enum field. + """ + type: Literal["array"] + + +class OneOfItem(WireModel): + const: str + """ + The enum value. + """ + title: str + """ + Display label for this option. + """ + + +class TitledSingleSelectEnumSchema(WireModel): + """Schema for single-selection enumeration with display titles for each option.""" + + default: str | None = None + """ + Optional default value. + """ + description: str | None = None + """ + Optional description for the enum field. + """ + one_of: Annotated[list[OneOfItem], Field(alias="oneOf")] + """ + Array of enum options with values and display labels. + """ + title: str | None = None + """ + Optional title for the enum field. + """ + type: Literal["string"] + + +class InputSchema(WireModel): + """A JSON Schema object defining the expected parameters for the tool.""" + + # Stays open: schema keywords beyond the declared properties ride extra fields. + model_config = ConfigDict( + extra="allow", + ) + schema_: Annotated[str | None, Field(alias="$schema")] = None + properties: dict[str, dict[str, Any]] | None = None + required: list[str] | None = None + type: Literal["object"] + + +class OutputSchema(WireModel): + """An optional JSON Schema object defining the structure of the tool's output returned in + the structuredContent field of a CallToolResult. + + Defaults to JSON Schema 2020-12 when no explicit $schema is provided. + Currently restricted to type: "object" at the root level. + """ + + # Stays open: schema keywords beyond the declared properties ride extra fields. + model_config = ConfigDict( + extra="allow", + ) + schema_: Annotated[str | None, Field(alias="$schema")] = None + properties: dict[str, dict[str, Any]] | None = None + required: list[str] | None = None + type: Literal["object"] + + +class ToolAnnotations(WireModel): + """Additional properties describing a Tool to clients. + + NOTE: all properties in ToolAnnotations are **hints**. + They are not guaranteed to provide a faithful description of + tool behavior (including descriptive properties like `title`). + + Clients should never make tool use decisions based on ToolAnnotations + received from untrusted servers. + """ + + destructive_hint: Annotated[bool | None, Field(alias="destructiveHint")] = None + """ + If true, the tool may perform destructive updates to its environment. + If false, the tool performs only additive updates. + + (This property is meaningful only when `readOnlyHint == false`) + + Default: true + """ + idempotent_hint: Annotated[bool | None, Field(alias="idempotentHint")] = None + """ + If true, calling the tool repeatedly with the same arguments + will have no additional effect on its environment. + + (This property is meaningful only when `readOnlyHint == false`) + + Default: false + """ + open_world_hint: Annotated[bool | None, Field(alias="openWorldHint")] = None + """ + If true, this tool may interact with an "open world" of external + entities. If false, the tool's domain of interaction is closed. + For example, the world of a web search tool is open, whereas that + of a memory tool is not. + + Default: true + """ + read_only_hint: Annotated[bool | None, Field(alias="readOnlyHint")] = None + """ + If true, the tool does not modify its environment. + + Default: false + """ + title: str | None = None + """ + A human-readable title for the tool. + """ + + +class ToolChoice(WireModel): + """Controls tool selection behavior for sampling requests.""" + + mode: Literal["auto", "none", "required"] | None = None + """ + Controls the tool use ability of the model: + - "auto": Model decides whether to use tools (default) + - "required": Model MUST use at least one tool before completing + - "none": Model MUST NOT use any tools + """ + + +class ToolExecution(WireModel): + """Execution-related properties for a tool.""" + + task_support: Annotated[Literal["forbidden", "optional", "required"] | None, Field(alias="taskSupport")] = None + """ + Indicates whether this tool supports task-augmented execution. + This allows clients to handle long-running operations through polling + the task system. + + - "forbidden": Tool does not support task-augmented execution (default when absent) + - "optional": Tool may support task-augmented execution + - "required": Tool requires task-augmented execution + + Default: "forbidden" + """ + + +class ToolListChangedNotification(WireModel): + """An optional notification from the server to the client, informing it that the list of tools it offers has + changed. This may be issued by servers without any previous subscription from the client. + """ + + jsonrpc: Literal["2.0"] + method: Literal["notifications/tools/list_changed"] + params: NotificationParams | None = None + + +class ToolUseContent(WireModel): + """A request from the assistant to call a tool.""" + + meta: Annotated[dict[str, Any] | None, Field(alias="_meta")] = None + """ + Optional metadata about the tool use. Clients SHOULD preserve this field when + including tool uses in subsequent sampling requests to enable caching optimizations. + + See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage. + """ + id: str + """ + A unique identifier for this tool use. + + This ID is used to match tool results to their corresponding tool uses. + """ + input: dict[str, Any] + """ + The arguments to pass to the tool, conforming to the tool's input schema. + """ + name: str + """ + The name of the tool to call. + """ + type: Literal["tool_use"] + + +class UnsubscribeRequestParams(WireModel): + """Parameters for a `resources/unsubscribe` request.""" + + meta: Annotated[Meta | None, Field(alias="_meta")] = None + """ + See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage. + """ + uri: str + """ + The URI of the resource. The URI can use any protocol; it is up to the server how to interpret it. + """ + + +class Items1(WireModel): + """Schema for the array items.""" + + enum: list[str] + """ + Array of enum values to choose from. + """ + type: Literal["string"] + + +class UntitledMultiSelectEnumSchema(WireModel): + """Schema for multiple-selection enumeration without display titles for options.""" + + default: list[str] | None = None + """ + Optional default value. + """ + description: str | None = None + """ + Optional description for the enum field. + """ + items: Items1 + """ + Schema for the array items. + """ + max_items: Annotated[int | None, Field(alias="maxItems")] = None + """ + Maximum number of items to select. + """ + min_items: Annotated[int | None, Field(alias="minItems")] = None + """ + Minimum number of items to select. + """ + title: str | None = None + """ + Optional title for the enum field. + """ + type: Literal["array"] + + +class UntitledSingleSelectEnumSchema(WireModel): + """Schema for single-selection enumeration without display titles for options.""" + + default: str | None = None + """ + Optional default value. + """ + description: str | None = None + """ + Optional description for the enum field. + """ + enum: list[str] + """ + Array of enum values to choose from. + """ + title: str | None = None + """ + Optional title for the enum field. + """ + type: Literal["string"] + + +class Annotations(WireModel): + """Optional annotations for the client. The client can use annotations to inform how objects are used or + displayed + """ + + audience: list[Role] | None = None + """ + Describes who the intended audience of this object or data is. + + It can include multiple entries to indicate content useful for multiple audiences (e.g., `["user", "assistant"]`). + """ + last_modified: Annotated[str | None, Field(alias="lastModified")] = None + """ + The moment the resource was last modified, as an ISO 8601 formatted string. + + Should be an ISO 8601 formatted string (e.g., "2025-01-12T15:00:58Z"). + + Examples: last activity timestamp in an open file, timestamp when the resource + was attached, etc. + """ + priority: Annotated[float | None, Field(ge=0.0, le=1.0)] = None + """ + Describes how important this data is for operating the server. + + A value of 1 means "most important," and indicates that the data is + effectively required, while 0 means "least important," and indicates that + the data is entirely optional. + """ + + +class AudioContent(WireModel): + """Audio provided to or from an LLM.""" + + meta: Annotated[dict[str, Any] | None, Field(alias="_meta")] = None + """ + See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage. + """ + annotations: Annotations | None = None + """ + Optional annotations for the client. + """ + data: str + """ + The base64-encoded audio data. + """ + mime_type: Annotated[str, Field(alias="mimeType")] + """ + The MIME type of the audio. Different providers may support different audio types. + """ + type: Literal["audio"] + + +class CallToolRequestParams(WireModel): + """Parameters for a `tools/call` request.""" + + meta: Annotated[Meta | None, Field(alias="_meta")] = None + """ + See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage. + """ + arguments: dict[str, Any] | None = None + """ + Arguments to use for the tool call. + """ + name: str + """ + The name of the tool. + """ + task: TaskMetadata | None = None + """ + If specified, the caller is requesting task-augmented execution for this request. + The request will return a CreateTaskResult immediately, and the actual result can be + retrieved later via tasks/result. + + Task augmentation is subject to capability negotiation - receivers MUST declare support + for task augmentation of specific request types in their capabilities. + """ + + +class CancelTaskRequest(WireModel): + """A request to cancel a task.""" + + id: RequestId + jsonrpc: Literal["2.0"] + method: Literal["tasks/cancel"] + params: CancelTaskRequestParams + + +class CancelledNotificationParams(WireModel): + """Parameters for a `notifications/cancelled` notification.""" + + meta: Annotated[dict[str, Any] | None, Field(alias="_meta")] = None + """ + See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage. + """ + reason: str | None = None + """ + An optional string describing the reason for the cancellation. This MAY be logged or presented to the user. + """ + request_id: Annotated[RequestId | None, Field(alias="requestId")] = None + """ + The ID of the request to cancel. + + This MUST correspond to the ID of a request previously issued in the same direction. + This MUST be provided for cancelling non-task requests. + This MUST NOT be used for cancelling tasks (use the `tasks/cancel` request instead). + """ + + +class CompleteRequestParams(WireModel): + """Parameters for a `completion/complete` request.""" + + meta: Annotated[Meta | None, Field(alias="_meta")] = None + """ + See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage. + """ + argument: Argument + """ + The argument's information + """ + context: Context | None = None + """ + Additional, optional context for completions + """ + ref: PromptReference | ResourceTemplateReference + + +class ElicitRequestURLParams(WireModel): + """The parameters for a request to elicit information from the user via a URL in the client.""" + + meta: Annotated[Meta | None, Field(alias="_meta")] = None + """ + See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage. + """ + elicitation_id: Annotated[str, Field(alias="elicitationId")] + """ + The ID of the elicitation, which must be unique within the context of the server. + The client MUST treat this ID as an opaque value. + """ + message: str + """ + The message to present to the user explaining why the interaction is needed. + """ + mode: Literal["url"] + """ + The elicitation mode. + """ + task: TaskMetadata | None = None + """ + If specified, the caller is requesting task-augmented execution for this request. + The request will return a CreateTaskResult immediately, and the actual result can be + retrieved later via tasks/result. + + Task augmentation is subject to capability negotiation - receivers MUST declare support + for task augmentation of specific request types in their capabilities. + """ + url: str + """ + The URL that the user should navigate to. + """ + + +class EmbeddedResource(WireModel): + """The contents of a resource, embedded into a prompt or tool call result. + + It is up to the client how best to render embedded resources for the benefit + of the LLM and/or the user. + """ + + meta: Annotated[dict[str, Any] | None, Field(alias="_meta")] = None + """ + See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage. + """ + annotations: Annotations | None = None + """ + Optional annotations for the client. + """ + resource: TextResourceContents | BlobResourceContents + type: Literal["resource"] + + +EmptyResult: TypeAlias = Result + + +EnumSchema: TypeAlias = ( + UntitledSingleSelectEnumSchema + | TitledSingleSelectEnumSchema + | UntitledMultiSelectEnumSchema + | TitledMultiSelectEnumSchema + | LegacyTitledEnumSchema +) + + +class GetPromptRequestParams(WireModel): + """Parameters for a `prompts/get` request.""" + + meta: Annotated[Meta | None, Field(alias="_meta")] = None + """ + See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage. + """ + arguments: dict[str, str] | None = None + """ + Arguments to use for templating the prompt. + """ + name: str + """ + The name of the prompt or prompt template. + """ + + +class GetTaskPayloadRequest(WireModel): + """A request to retrieve the result of a completed task.""" + + id: RequestId + jsonrpc: Literal["2.0"] + method: Literal["tasks/result"] + params: GetTaskPayloadRequestParams + + +class GetTaskRequest(WireModel): + """A request to retrieve the state of a task.""" + + id: RequestId + jsonrpc: Literal["2.0"] + method: Literal["tasks/get"] + params: GetTaskRequestParams + + +class ImageContent(WireModel): + """An image provided to or from an LLM.""" + + meta: Annotated[dict[str, Any] | None, Field(alias="_meta")] = None + """ + See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage. + """ + annotations: Annotations | None = None + """ + Optional annotations for the client. + """ + data: str + """ + The base64-encoded image data. + """ + mime_type: Annotated[str, Field(alias="mimeType")] + """ + The MIME type of the image. Different providers may support different image types. + """ + type: Literal["image"] + + +class InitializeRequestParams(WireModel): + """Parameters for an `initialize` request.""" + + meta: Annotated[Meta | None, Field(alias="_meta")] = None + """ + See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage. + """ + capabilities: ClientCapabilities + client_info: Annotated[Implementation, Field(alias="clientInfo")] + protocol_version: Annotated[str, Field(alias="protocolVersion")] + """ + The latest version of the Model Context Protocol that the client supports. The client MAY decide to support older + versions as well. + """ + + +class InitializeResult(WireModel): + """After receiving an initialize request from the client, the server sends this response.""" + + meta: Annotated[dict[str, Any] | None, Field(alias="_meta")] = None + """ + See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage. + """ + capabilities: ServerCapabilities + instructions: str | None = None + """ + Instructions describing how to use the server and its features. + + This can be used by clients to improve the LLM's understanding of available tools, resources, etc. It can be thought + of like a "hint" to the model. For example, this information MAY be added to the system prompt. + """ + protocol_version: Annotated[str, Field(alias="protocolVersion")] + """ + The version of the Model Context Protocol that the server wants to use. This may not match the version that the + client requested. If the client cannot support this version, it MUST disconnect. + """ + server_info: Annotated[Implementation, Field(alias="serverInfo")] + + +class InitializedNotification(WireModel): + """This notification is sent from the client to the server after initialization has finished.""" + + jsonrpc: Literal["2.0"] + method: Literal["notifications/initialized"] + params: NotificationParams | None = None + + +class JSONRPCErrorResponse(WireModel): + """A response to a request that indicates an error occurred.""" + + error: Error + id: RequestId | None = None + jsonrpc: Literal["2.0"] + + +class JSONRPCRequest(WireModel): + """A request that expects a response.""" + + id: RequestId + jsonrpc: Literal["2.0"] + method: str + params: dict[str, Any] | None = None + + +class JSONRPCResultResponse(WireModel): + """A successful (non-error) response to a request.""" + + id: RequestId + jsonrpc: Literal["2.0"] + result: Result + + +class ListRootsRequest(WireModel): + """Sent from the server to request a list of root URIs from the client. Roots allow + servers to ask for specific directories or files to operate on. A common example + for roots is providing a set of repositories or directories a server should operate + on. + + This request is typically used when the server needs to understand the file system + structure or access specific locations that the client has permission to read from. + """ + + id: RequestId + jsonrpc: Literal["2.0"] + method: Literal["roots/list"] + params: RequestParams | None = None + + +class ListRootsResult(WireModel): + """The client's response to a roots/list request from the server. + This result contains an array of Root objects, each representing a root directory + or file that the server can operate on. + """ + + meta: Annotated[dict[str, Any] | None, Field(alias="_meta")] = None + """ + See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage. + """ + roots: list[Root] + + +class LoggingMessageNotification(WireModel): + """JSONRPCNotification of a log message passed from server to client. If no logging/setLevel request has been + sent from the client, the server MAY decide which messages to send automatically. + """ + + jsonrpc: Literal["2.0"] + method: Literal["notifications/message"] + params: LoggingMessageNotificationParams + + +MultiSelectEnumSchema: TypeAlias = UntitledMultiSelectEnumSchema | TitledMultiSelectEnumSchema + + +class PaginatedRequestParams(WireModel): + """Common parameters for paginated requests.""" + + meta: Annotated[Meta | None, Field(alias="_meta")] = None + """ + See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage. + """ + cursor: str | None = None + """ + An opaque token representing the current pagination position. + If provided, the server should return results starting after this cursor. + """ + + +class PingRequest(WireModel): + """A ping, issued by either the server or the client, to check that the other party is still alive. The receiver + must promptly respond, or else may be disconnected. + """ + + id: RequestId + jsonrpc: Literal["2.0"] + method: Literal["ping"] + params: RequestParams | None = None + + +PrimitiveSchemaDefinition: TypeAlias = ( + StringSchema + | NumberSchema + | BooleanSchema + | UntitledSingleSelectEnumSchema + | TitledSingleSelectEnumSchema + | UntitledMultiSelectEnumSchema + | TitledMultiSelectEnumSchema + | LegacyTitledEnumSchema +) + + +class ProgressNotificationParams(WireModel): + """Parameters for a `notifications/progress` notification.""" + + meta: Annotated[dict[str, Any] | None, Field(alias="_meta")] = None + """ + See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage. + """ + message: str | None = None + """ + An optional message describing the current progress. + """ + progress: float + """ + The progress thus far. This should increase every time progress is made, even if the total is unknown. + """ + progress_token: Annotated[ProgressToken, Field(alias="progressToken")] + """ + The progress token which was given in the initial request, used to associate this notification with the request that + is proceeding. + """ + total: float | None = None + """ + Total number of items to process (or total progress required), if known. + """ + + +class Prompt(WireModel): + """A prompt or prompt template that the server offers.""" + + meta: Annotated[dict[str, Any] | None, Field(alias="_meta")] = None + """ + See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage. + """ + arguments: list[PromptArgument] | None = None + """ + A list of arguments to use for templating the prompt. + """ + description: str | None = None + """ + An optional description of what this prompt provides + """ + icons: list[Icon] | None = None + """ + Optional set of sized icons that the client can display in a user interface. + + Clients that support rendering icons MUST support at least the following MIME types: + - `image/png` - PNG images (safe, universal compatibility) + - `image/jpeg` (and `image/jpg`) - JPEG images (safe, universal compatibility) + + Clients that support rendering icons SHOULD also support: + - `image/svg+xml` - SVG images (scalable but requires security precautions) + - `image/webp` - WebP images (modern, efficient format) + """ + name: str + """ + Intended for programmatic or logical use, but used as a display name in past specs or fallback (if title isn't + present). + """ + title: str | None = None + """ + Intended for UI and end-user contexts — optimized to be human-readable and easily understood, + even by those unfamiliar with domain-specific terminology. + + If not provided, the name should be used for display (except for Tool, + where `annotations.title` should be given precedence over using `name`, + if present). + """ + + +class ReadResourceRequest(WireModel): + """Sent from the client to the server, to read a specific resource URI.""" + + id: RequestId + jsonrpc: Literal["2.0"] + method: Literal["resources/read"] + params: ReadResourceRequestParams + + +class ReadResourceResult(WireModel): + """The server's response to a resources/read request from the client.""" + + meta: Annotated[dict[str, Any] | None, Field(alias="_meta")] = None + """ + See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage. + """ + contents: list[TextResourceContents | BlobResourceContents] + + +class Resource(WireModel): + """A known resource that the server is capable of reading.""" + + meta: Annotated[dict[str, Any] | None, Field(alias="_meta")] = None + """ + See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage. + """ + annotations: Annotations | None = None + """ + Optional annotations for the client. + """ + description: str | None = None + """ + A description of what this resource represents. + + This can be used by clients to improve the LLM's understanding of available resources. It can be thought of like a + "hint" to the model. + """ + icons: list[Icon] | None = None + """ + Optional set of sized icons that the client can display in a user interface. + + Clients that support rendering icons MUST support at least the following MIME types: + - `image/png` - PNG images (safe, universal compatibility) + - `image/jpeg` (and `image/jpg`) - JPEG images (safe, universal compatibility) + + Clients that support rendering icons SHOULD also support: + - `image/svg+xml` - SVG images (scalable but requires security precautions) + - `image/webp` - WebP images (modern, efficient format) + """ + mime_type: Annotated[str | None, Field(alias="mimeType")] = None + """ + The MIME type of this resource, if known. + """ + name: str + """ + Intended for programmatic or logical use, but used as a display name in past specs or fallback (if title isn't + present). + """ + size: int | None = None + """ + The size of the raw resource content, in bytes (i.e., before base64 encoding or any tokenization), if known. + + This can be used by Hosts to display file sizes and estimate context window usage. + """ + title: str | None = None + """ + Intended for UI and end-user contexts — optimized to be human-readable and easily understood, + even by those unfamiliar with domain-specific terminology. + + If not provided, the name should be used for display (except for Tool, + where `annotations.title` should be given precedence over using `name`, + if present). + """ + uri: str + """ + The URI of this resource. + """ + + +class ResourceLink(WireModel): + """A resource that the server is capable of reading, included in a prompt or tool call result. + + Note: resource links returned by tools are not guaranteed to appear in the results of `resources/list` requests. + """ + + meta: Annotated[dict[str, Any] | None, Field(alias="_meta")] = None + """ + See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage. + """ + annotations: Annotations | None = None + """ + Optional annotations for the client. + """ + description: str | None = None + """ + A description of what this resource represents. + + This can be used by clients to improve the LLM's understanding of available resources. It can be thought of like a + "hint" to the model. + """ + icons: list[Icon] | None = None + """ + Optional set of sized icons that the client can display in a user interface. + + Clients that support rendering icons MUST support at least the following MIME types: + - `image/png` - PNG images (safe, universal compatibility) + - `image/jpeg` (and `image/jpg`) - JPEG images (safe, universal compatibility) + + Clients that support rendering icons SHOULD also support: + - `image/svg+xml` - SVG images (scalable but requires security precautions) + - `image/webp` - WebP images (modern, efficient format) + """ + mime_type: Annotated[str | None, Field(alias="mimeType")] = None + """ + The MIME type of this resource, if known. + """ + name: str + """ + Intended for programmatic or logical use, but used as a display name in past specs or fallback (if title isn't + present). + """ + size: int | None = None + """ + The size of the raw resource content, in bytes (i.e., before base64 encoding or any tokenization), if known. + + This can be used by Hosts to display file sizes and estimate context window usage. + """ + title: str | None = None + """ + Intended for UI and end-user contexts — optimized to be human-readable and easily understood, + even by those unfamiliar with domain-specific terminology. + + If not provided, the name should be used for display (except for Tool, + where `annotations.title` should be given precedence over using `name`, + if present). + """ + type: Literal["resource_link"] + uri: str + """ + The URI of this resource. + """ + + +class ResourceTemplate(WireModel): + """A template description for resources available on the server.""" + + meta: Annotated[dict[str, Any] | None, Field(alias="_meta")] = None + """ + See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage. + """ + annotations: Annotations | None = None + """ + Optional annotations for the client. + """ + description: str | None = None + """ + A description of what this template is for. + + This can be used by clients to improve the LLM's understanding of available resources. It can be thought of like a + "hint" to the model. + """ + icons: list[Icon] | None = None + """ + Optional set of sized icons that the client can display in a user interface. + + Clients that support rendering icons MUST support at least the following MIME types: + - `image/png` - PNG images (safe, universal compatibility) + - `image/jpeg` (and `image/jpg`) - JPEG images (safe, universal compatibility) + + Clients that support rendering icons SHOULD also support: + - `image/svg+xml` - SVG images (scalable but requires security precautions) + - `image/webp` - WebP images (modern, efficient format) + """ + mime_type: Annotated[str | None, Field(alias="mimeType")] = None + """ + The MIME type for all resources that match this template. This should only be included if all resources matching + this template have the same type. + """ + name: str + """ + Intended for programmatic or logical use, but used as a display name in past specs or fallback (if title isn't + present). + """ + title: str | None = None + """ + Intended for UI and end-user contexts — optimized to be human-readable and easily understood, + even by those unfamiliar with domain-specific terminology. + + If not provided, the name should be used for display (except for Tool, + where `annotations.title` should be given precedence over using `name`, + if present). + """ + uri_template: Annotated[str, Field(alias="uriTemplate")] + """ + A URI template (according to RFC 6570) that can be used to construct resource URIs. + """ + + +class ResourceUpdatedNotification(WireModel): + """A notification from the server to the client, informing it that a resource has changed and may need to be read + again. This should only be sent if the client previously sent a resources/subscribe request. + """ + + jsonrpc: Literal["2.0"] + method: Literal["notifications/resources/updated"] + params: ResourceUpdatedNotificationParams + + +class SetLevelRequest(WireModel): + """A request from the client to the server, to enable or adjust logging.""" + + id: RequestId + jsonrpc: Literal["2.0"] + method: Literal["logging/setLevel"] + params: SetLevelRequestParams + + +SingleSelectEnumSchema: TypeAlias = UntitledSingleSelectEnumSchema | TitledSingleSelectEnumSchema + + +class SubscribeRequest(WireModel): + """Sent from the client to request resources/updated notifications from the server whenever a particular resource + changes. + """ + + id: RequestId + jsonrpc: Literal["2.0"] + method: Literal["resources/subscribe"] + params: SubscribeRequestParams + + +class Task(WireModel): + """Data associated with a task.""" + + created_at: Annotated[str, Field(alias="createdAt")] + """ + ISO 8601 timestamp when the task was created. + """ + last_updated_at: Annotated[str, Field(alias="lastUpdatedAt")] + """ + ISO 8601 timestamp when the task was last updated. + """ + poll_interval: Annotated[int | None, Field(alias="pollInterval")] = None + """ + Suggested polling interval in milliseconds. + """ + status: TaskStatus + """ + Current task state. + """ + status_message: Annotated[str | None, Field(alias="statusMessage")] = None + """ + Optional human-readable message describing the current task state. + This can provide context for any status, including: + - Reasons for "cancelled" status + - Summaries for "completed" status + - Diagnostic information for "failed" status (e.g., error details, what went wrong) + """ + task_id: Annotated[str, Field(alias="taskId")] + """ + The task identifier. + """ + ttl: int | None + """ + Actual retention duration from creation in milliseconds, null for unlimited. + """ + + +class TaskAugmentedRequestParams(WireModel): + """Common params for any task-augmented request.""" + + meta: Annotated[Meta | None, Field(alias="_meta")] = None + """ + See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage. + """ + task: TaskMetadata | None = None + """ + If specified, the caller is requesting task-augmented execution for this request. + The request will return a CreateTaskResult immediately, and the actual result can be + retrieved later via tasks/result. + + Task augmentation is subject to capability negotiation - receivers MUST declare support + for task augmentation of specific request types in their capabilities. + """ + + +class TaskStatusNotificationParams(WireModel): + """Parameters for a `notifications/tasks/status` notification.""" + + meta: Annotated[dict[str, Any] | None, Field(alias="_meta")] = None + """ + See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage. + """ + created_at: Annotated[str, Field(alias="createdAt")] + """ + ISO 8601 timestamp when the task was created. + """ + last_updated_at: Annotated[str, Field(alias="lastUpdatedAt")] + """ + ISO 8601 timestamp when the task was last updated. + """ + poll_interval: Annotated[int | None, Field(alias="pollInterval")] = None + """ + Suggested polling interval in milliseconds. + """ + status: TaskStatus + """ + Current task state. + """ + status_message: Annotated[str | None, Field(alias="statusMessage")] = None + """ + Optional human-readable message describing the current task state. + This can provide context for any status, including: + - Reasons for "cancelled" status + - Summaries for "completed" status + - Diagnostic information for "failed" status (e.g., error details, what went wrong) + """ + task_id: Annotated[str, Field(alias="taskId")] + """ + The task identifier. + """ + ttl: int | None + """ + Actual retention duration from creation in milliseconds, null for unlimited. + """ + + +class TextContent(WireModel): + """Text provided to or from an LLM.""" + + meta: Annotated[dict[str, Any] | None, Field(alias="_meta")] = None + """ + See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage. + """ + annotations: Annotations | None = None + """ + Optional annotations for the client. + """ + text: str + """ + The text content of the message. + """ + type: Literal["text"] + + +class Tool(WireModel): + """Definition for a tool the client can call.""" + + meta: Annotated[dict[str, Any] | None, Field(alias="_meta")] = None + """ + See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage. + """ + annotations: ToolAnnotations | None = None + """ + Optional additional tool information. + + Display name precedence order is: title, annotations.title, then name. + """ + description: str | None = None + """ + A human-readable description of the tool. + + This can be used by clients to improve the LLM's understanding of available tools. It can be thought of like a + "hint" to the model. + """ + execution: ToolExecution | None = None + """ + Execution-related properties for this tool. + """ + icons: list[Icon] | None = None + """ + Optional set of sized icons that the client can display in a user interface. + + Clients that support rendering icons MUST support at least the following MIME types: + - `image/png` - PNG images (safe, universal compatibility) + - `image/jpeg` (and `image/jpg`) - JPEG images (safe, universal compatibility) + + Clients that support rendering icons SHOULD also support: + - `image/svg+xml` - SVG images (scalable but requires security precautions) + - `image/webp` - WebP images (modern, efficient format) + """ + input_schema: Annotated[InputSchema, Field(alias="inputSchema")] + """ + A JSON Schema object defining the expected parameters for the tool. + """ + name: str + """ + Intended for programmatic or logical use, but used as a display name in past specs or fallback (if title isn't + present). + """ + output_schema: Annotated[OutputSchema | None, Field(alias="outputSchema")] = None + """ + An optional JSON Schema object defining the structure of the tool's output returned in + the structuredContent field of a CallToolResult. + + Defaults to JSON Schema 2020-12 when no explicit $schema is provided. + Currently restricted to type: "object" at the root level. + """ + title: str | None = None + """ + Intended for UI and end-user contexts — optimized to be human-readable and easily understood, + even by those unfamiliar with domain-specific terminology. + + If not provided, the name should be used for display (except for Tool, + where `annotations.title` should be given precedence over using `name`, + if present). + """ + + +class Data(WireModel): + """Additional information about the error. The value of this member is defined by the sender (e.g. detailed error + information, nested errors etc.). + """ + + elicitations: list[ElicitRequestURLParams] + + +class Error1(WireModel): + code: Literal[-32042] + """ + The error type that occurred. + """ + data: Data + """ + Additional information about the error. The value of this member is defined by the sender (e.g. detailed error + information, nested errors etc.). + """ + message: str + """ + A short description of the error. The message SHOULD be limited to a concise single sentence. + """ + + +class URLElicitationRequiredError(WireModel): + """An error response that indicates that the server requires the client to provide additional information via an + elicitation request. + """ + + error: Error1 + id: RequestId | None = None + jsonrpc: Literal["2.0"] + + +class UnsubscribeRequest(WireModel): + """Sent from the client to request cancellation of resources/updated notifications from the server. This should + follow a previous resources/subscribe request. + """ + + id: RequestId + jsonrpc: Literal["2.0"] + method: Literal["resources/unsubscribe"] + params: UnsubscribeRequestParams + + +class CallToolRequest(WireModel): + """Used by the client to invoke a tool provided by the server.""" + + id: RequestId + jsonrpc: Literal["2.0"] + method: Literal["tools/call"] + params: CallToolRequestParams + + +class CancelTaskResult(WireModel): + """The response to a tasks/cancel request.""" + + meta: Annotated[dict[str, Any] | None, Field(alias="_meta")] = None + """ + See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage. + """ + created_at: Annotated[str, Field(alias="createdAt")] + """ + ISO 8601 timestamp when the task was created. + """ + last_updated_at: Annotated[str, Field(alias="lastUpdatedAt")] + """ + ISO 8601 timestamp when the task was last updated. + """ + poll_interval: Annotated[int | None, Field(alias="pollInterval")] = None + """ + Suggested polling interval in milliseconds. + """ + status: TaskStatus + """ + Current task state. + """ + status_message: Annotated[str | None, Field(alias="statusMessage")] = None + """ + Optional human-readable message describing the current task state. + This can provide context for any status, including: + - Reasons for "cancelled" status + - Summaries for "completed" status + - Diagnostic information for "failed" status (e.g., error details, what went wrong) + """ + task_id: Annotated[str, Field(alias="taskId")] + """ + The task identifier. + """ + ttl: int | None + """ + Actual retention duration from creation in milliseconds, null for unlimited. + """ + + +class CancelledNotification(WireModel): + """This notification can be sent by either side to indicate that it is cancelling a previously-issued request. + + The request SHOULD still be in-flight, but due to communication latency, it is always possible that this + notification MAY arrive after the request has already finished. + + This notification indicates that the result will be unused, so any associated processing SHOULD cease. + + A client MUST NOT attempt to cancel its `initialize` request. + + For task cancellation, use the `tasks/cancel` request instead of this notification. + """ + + jsonrpc: Literal["2.0"] + method: Literal["notifications/cancelled"] + params: CancelledNotificationParams + + +class CompleteRequest(WireModel): + """A request from the client to the server, to ask for completion options.""" + + id: RequestId + jsonrpc: Literal["2.0"] + method: Literal["completion/complete"] + params: CompleteRequestParams + + +ContentBlock: TypeAlias = TextContent | ImageContent | AudioContent | ResourceLink | EmbeddedResource + + +class CreateTaskResult(WireModel): + """A response to a task-augmented request.""" + + meta: Annotated[dict[str, Any] | None, Field(alias="_meta")] = None + """ + See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage. + """ + task: Task + + +class RequestedSchema(WireModel): + """A restricted subset of JSON Schema. + Only top-level properties are allowed, without nesting. + """ + + schema_: Annotated[str | None, Field(alias="$schema")] = None + properties: dict[str, PrimitiveSchemaDefinition] + required: list[str] | None = None + type: Literal["object"] + + +class ElicitRequestFormParams(WireModel): + """The parameters for a request to elicit non-sensitive information from the user via a form in the client.""" + + meta: Annotated[Meta | None, Field(alias="_meta")] = None + """ + See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage. + """ + message: str + """ + The message to present to the user describing what information is being requested. + """ + mode: Literal["form"] = "form" + """ + The elicitation mode. + """ + requested_schema: Annotated[RequestedSchema, Field(alias="requestedSchema")] + """ + A restricted subset of JSON Schema. + Only top-level properties are allowed, without nesting. + """ + task: TaskMetadata | None = None + """ + If specified, the caller is requesting task-augmented execution for this request. + The request will return a CreateTaskResult immediately, and the actual result can be + retrieved later via tasks/result. + + Task augmentation is subject to capability negotiation - receivers MUST declare support + for task augmentation of specific request types in their capabilities. + """ + + +ElicitRequestParams: TypeAlias = ElicitRequestURLParams | ElicitRequestFormParams + + +class GetPromptRequest(WireModel): + """Used by the client to get a prompt provided by the server.""" + + id: RequestId + jsonrpc: Literal["2.0"] + method: Literal["prompts/get"] + params: GetPromptRequestParams + + +class GetTaskResult(WireModel): + """The response to a tasks/get request.""" + + meta: Annotated[dict[str, Any] | None, Field(alias="_meta")] = None + """ + See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage. + """ + created_at: Annotated[str, Field(alias="createdAt")] + """ + ISO 8601 timestamp when the task was created. + """ + last_updated_at: Annotated[str, Field(alias="lastUpdatedAt")] + """ + ISO 8601 timestamp when the task was last updated. + """ + poll_interval: Annotated[int | None, Field(alias="pollInterval")] = None + """ + Suggested polling interval in milliseconds. + """ + status: TaskStatus + """ + Current task state. + """ + status_message: Annotated[str | None, Field(alias="statusMessage")] = None + """ + Optional human-readable message describing the current task state. + This can provide context for any status, including: + - Reasons for "cancelled" status + - Summaries for "completed" status + - Diagnostic information for "failed" status (e.g., error details, what went wrong) + """ + task_id: Annotated[str, Field(alias="taskId")] + """ + The task identifier. + """ + ttl: int | None + """ + Actual retention duration from creation in milliseconds, null for unlimited. + """ + + +class InitializeRequest(WireModel): + """This request is sent from the client to the server when it first connects, asking it to begin initialization.""" + + id: RequestId + jsonrpc: Literal["2.0"] + method: Literal["initialize"] + params: InitializeRequestParams + + +JSONRPCMessage: TypeAlias = JSONRPCRequest | JSONRPCNotification | JSONRPCResultResponse | JSONRPCErrorResponse + + +JSONRPCResponse: TypeAlias = JSONRPCResultResponse | JSONRPCErrorResponse + + +class ListPromptsRequest(WireModel): + """Sent from the client to request a list of prompts and prompt templates the server has.""" + + id: RequestId + jsonrpc: Literal["2.0"] + method: Literal["prompts/list"] + params: PaginatedRequestParams | None = None + + +class ListPromptsResult(WireModel): + """The server's response to a prompts/list request from the client.""" + + meta: Annotated[dict[str, Any] | None, Field(alias="_meta")] = None + """ + See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage. + """ + next_cursor: Annotated[str | None, Field(alias="nextCursor")] = None + """ + An opaque token representing the pagination position after the last returned result. + If present, there may be more results available. + """ + prompts: list[Prompt] + + +class ListResourceTemplatesRequest(WireModel): + """Sent from the client to request a list of resource templates the server has.""" + + id: RequestId + jsonrpc: Literal["2.0"] + method: Literal["resources/templates/list"] + params: PaginatedRequestParams | None = None + + +class ListResourceTemplatesResult(WireModel): + """The server's response to a resources/templates/list request from the client.""" + + meta: Annotated[dict[str, Any] | None, Field(alias="_meta")] = None + """ + See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage. + """ + next_cursor: Annotated[str | None, Field(alias="nextCursor")] = None + """ + An opaque token representing the pagination position after the last returned result. + If present, there may be more results available. + """ + resource_templates: Annotated[list[ResourceTemplate], Field(alias="resourceTemplates")] + + +class ListResourcesRequest(WireModel): + """Sent from the client to request a list of resources the server has.""" + + id: RequestId + jsonrpc: Literal["2.0"] + method: Literal["resources/list"] + params: PaginatedRequestParams | None = None + + +class ListResourcesResult(WireModel): + """The server's response to a resources/list request from the client.""" + + meta: Annotated[dict[str, Any] | None, Field(alias="_meta")] = None + """ + See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage. + """ + next_cursor: Annotated[str | None, Field(alias="nextCursor")] = None + """ + An opaque token representing the pagination position after the last returned result. + If present, there may be more results available. + """ + resources: list[Resource] + + +class ListTasksRequest(WireModel): + """A request to retrieve a list of tasks.""" + + id: RequestId + jsonrpc: Literal["2.0"] + method: Literal["tasks/list"] + params: PaginatedRequestParams | None = None + + +class ListTasksResult(WireModel): + """The response to a tasks/list request.""" + + meta: Annotated[dict[str, Any] | None, Field(alias="_meta")] = None + """ + See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage. + """ + next_cursor: Annotated[str | None, Field(alias="nextCursor")] = None + """ + An opaque token representing the pagination position after the last returned result. + If present, there may be more results available. + """ + tasks: list[Task] + + +class ListToolsRequest(WireModel): + """Sent from the client to request a list of tools the server has.""" + + id: RequestId + jsonrpc: Literal["2.0"] + method: Literal["tools/list"] + params: PaginatedRequestParams | None = None + + +class ListToolsResult(WireModel): + """The server's response to a tools/list request from the client.""" + + meta: Annotated[dict[str, Any] | None, Field(alias="_meta")] = None + """ + See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage. + """ + next_cursor: Annotated[str | None, Field(alias="nextCursor")] = None + """ + An opaque token representing the pagination position after the last returned result. + If present, there may be more results available. + """ + tools: list[Tool] + + +class PaginatedRequest(WireModel): + id: RequestId + jsonrpc: Literal["2.0"] + method: str + params: PaginatedRequestParams | None = None + + +class ProgressNotification(WireModel): + """An out-of-band notification used to inform the receiver of a progress update for a long-running request.""" + + jsonrpc: Literal["2.0"] + method: Literal["notifications/progress"] + params: ProgressNotificationParams + + +class PromptMessage(WireModel): + """Describes a message returned as part of a prompt. + + This is similar to `SamplingMessage`, but also supports the embedding of + resources from the MCP server. + """ + + content: ContentBlock + role: Role + + +class TaskStatusNotification(WireModel): + """An optional notification from the receiver to the requestor, informing them that a task's status has changed. + Receivers are not required to send these notifications. + """ + + jsonrpc: Literal["2.0"] + method: Literal["notifications/tasks/status"] + params: TaskStatusNotificationParams + + +class ToolResultContent(WireModel): + """The result of a tool use, provided by the user back to the assistant.""" + + meta: Annotated[dict[str, Any] | None, Field(alias="_meta")] = None + """ + Optional metadata about the tool result. Clients SHOULD preserve this field when + including tool results in subsequent sampling requests to enable caching optimizations. + + See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage. + """ + content: list[ContentBlock] + """ + The unstructured result content of the tool use. + + This has the same format as CallToolResult.content and can include text, images, + audio, resource links, and embedded resources. + """ + is_error: Annotated[bool | None, Field(alias="isError")] = None + """ + Whether the tool use resulted in an error. + + If true, the content typically describes the error that occurred. + Default: false + """ + structured_content: Annotated[dict[str, Any] | None, Field(alias="structuredContent")] = None + """ + An optional structured result object. + + If the tool defined an outputSchema, this SHOULD conform to that schema. + """ + tool_use_id: Annotated[str, Field(alias="toolUseId")] + """ + The ID of the tool use this result corresponds to. + + This MUST match the ID from a previous ToolUseContent. + """ + type: Literal["tool_result"] + + +class CallToolResult(WireModel): + """The server's response to a tool call.""" + + meta: Annotated[dict[str, Any] | None, Field(alias="_meta")] = None + """ + See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage. + """ + content: list[ContentBlock] + """ + A list of content objects that represent the unstructured result of the tool call. + """ + is_error: Annotated[bool | None, Field(alias="isError")] = None + """ + Whether the tool call ended in an error. + + If not set, this is assumed to be false (the call was successful). + + Any errors that originate from the tool SHOULD be reported inside the result + object, with `isError` set to true, _not_ as an MCP protocol-level error + response. Otherwise, the LLM would not be able to see that an error occurred + and self-correct. + + However, any errors in _finding_ the tool, an error indicating that the + server does not support tool calls, or any other exceptional conditions, + should be reported as an MCP error response. + """ + structured_content: Annotated[dict[str, Any] | None, Field(alias="structuredContent")] = None + """ + An optional JSON object that represents the structured result of the tool call. + """ + + +ClientNotification: TypeAlias = ( + CancelledNotification + | InitializedNotification + | ProgressNotification + | TaskStatusNotification + | RootsListChangedNotification +) + + +ClientRequest: TypeAlias = ( + InitializeRequest + | PingRequest + | ListResourcesRequest + | ListResourceTemplatesRequest + | ReadResourceRequest + | SubscribeRequest + | UnsubscribeRequest + | ListPromptsRequest + | GetPromptRequest + | ListToolsRequest + | CallToolRequest + | GetTaskRequest + | GetTaskPayloadRequest + | CancelTaskRequest + | ListTasksRequest + | SetLevelRequest + | CompleteRequest +) + + +class ElicitRequest(WireModel): + """A request from the server to elicit additional information from the user via the client.""" + + id: RequestId + jsonrpc: Literal["2.0"] + method: Literal["elicitation/create"] + params: ElicitRequestParams + + +class GetPromptResult(WireModel): + """The server's response to a prompts/get request from the client.""" + + meta: Annotated[dict[str, Any] | None, Field(alias="_meta")] = None + """ + See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage. + """ + description: str | None = None + """ + An optional description for the prompt. + """ + messages: list[PromptMessage] + + +SamplingMessageContentBlock: TypeAlias = TextContent | ImageContent | AudioContent | ToolUseContent | ToolResultContent + + +ServerNotification: TypeAlias = ( + CancelledNotification + | ProgressNotification + | ResourceListChangedNotification + | ResourceUpdatedNotification + | PromptListChangedNotification + | ToolListChangedNotification + | TaskStatusNotification + | LoggingMessageNotification + | ElicitationCompleteNotification +) + + +ServerResult: TypeAlias = ( + Result + | InitializeResult + | ListResourcesResult + | ListResourceTemplatesResult + | ReadResourceResult + | ListPromptsResult + | GetPromptResult + | ListToolsResult + | CallToolResult + | GetTaskResult + | GetTaskPayloadResult + | CancelTaskResult + | ListTasksResult + | CompleteResult +) + + +class CreateMessageResult(WireModel): + """The client's response to a sampling/createMessage request from the server. + The client should inform the user before returning the sampled message, to allow them + to inspect the response (human in the loop) and decide whether to allow the server to see it. + """ + + meta: Annotated[dict[str, Any] | None, Field(alias="_meta")] = None + """ + See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage. + """ + content: ( + TextContent + | ImageContent + | AudioContent + | ToolUseContent + | ToolResultContent + | list[SamplingMessageContentBlock] + ) + model: str + """ + The name of the model that generated the message. + """ + role: Role + stop_reason: Annotated[str | None, Field(alias="stopReason")] = None + """ + The reason why sampling stopped, if known. + + Standard values: + - "endTurn": Natural end of the assistant's turn + - "stopSequence": A stop sequence was encountered + - "maxTokens": Maximum token limit was reached + - "toolUse": The model wants to use one or more tools + + This field is an open string to allow for provider-specific stop reasons. + """ + + +class SamplingMessage(WireModel): + """Describes a message issued to or received from an LLM API.""" + + meta: Annotated[dict[str, Any] | None, Field(alias="_meta")] = None + """ + See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage. + """ + content: ( + TextContent + | ImageContent + | AudioContent + | ToolUseContent + | ToolResultContent + | list[SamplingMessageContentBlock] + ) + role: Role + + +ClientResult: TypeAlias = ( + Result + | GetTaskResult + | GetTaskPayloadResult + | CancelTaskResult + | ListTasksResult + | CreateMessageResult + | ListRootsResult + | ElicitResult +) + + +class CreateMessageRequestParams(WireModel): + """Parameters for a `sampling/createMessage` request.""" + + meta: Annotated[Meta | None, Field(alias="_meta")] = None + """ + See [General fields: `_meta`](/specification/2025-11-25/basic/index#meta) for notes on `_meta` usage. + """ + include_context: Annotated[ + Literal["allServers", "none", "thisServer"] | None, + Field(alias="includeContext"), + ] = None + """ + A request to include context from one or more MCP servers (including the caller), to be attached to the prompt. + The client MAY ignore this request. + + Default is "none". Values "thisServer" and "allServers" are soft-deprecated. Servers SHOULD only use these values if + the client + declares ClientCapabilities.sampling.context. These values may be removed in future spec releases. + """ + max_tokens: Annotated[int, Field(alias="maxTokens")] + """ + The requested maximum number of tokens to sample (to prevent runaway completions). + + The client MAY choose to sample fewer tokens than the requested maximum. + """ + messages: list[SamplingMessage] + metadata: dict[str, Any] | None = None + """ + Optional metadata to pass through to the LLM provider. The format of this metadata is provider-specific. + """ + model_preferences: Annotated[ModelPreferences | None, Field(alias="modelPreferences")] = None + """ + The server's preferences for which model to select. The client MAY ignore these preferences. + """ + stop_sequences: Annotated[list[str] | None, Field(alias="stopSequences")] = None + system_prompt: Annotated[str | None, Field(alias="systemPrompt")] = None + """ + An optional system prompt the server wants to use for sampling. The client MAY modify or omit this prompt. + """ + task: TaskMetadata | None = None + """ + If specified, the caller is requesting task-augmented execution for this request. + The request will return a CreateTaskResult immediately, and the actual result can be + retrieved later via tasks/result. + + Task augmentation is subject to capability negotiation - receivers MUST declare support + for task augmentation of specific request types in their capabilities. + """ + temperature: float | None = None + tool_choice: Annotated[ToolChoice | None, Field(alias="toolChoice")] = None + """ + Controls how the model uses tools. + The client MUST return an error if this field is provided but ClientCapabilities.sampling.tools is not declared. + Default is `{ mode: "auto" }`. + """ + tools: list[Tool] | None = None + """ + Tools that the model may use during generation. + The client MUST return an error if this field is provided but ClientCapabilities.sampling.tools is not declared. + """ + + +class CreateMessageRequest(WireModel): + """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. + """ + + id: RequestId + jsonrpc: Literal["2.0"] + method: Literal["sampling/createMessage"] + params: CreateMessageRequestParams + + +ServerRequest: TypeAlias = ( + PingRequest + | GetTaskRequest + | GetTaskPayloadRequest + | CancelTaskRequest + | ListTasksRequest + | CreateMessageRequest + | ListRootsRequest + | ElicitRequest +) diff --git a/src/mcp/types/v2026_07_28/__init__.py b/src/mcp/types/v2026_07_28/__init__.py new file mode 100644 index 0000000000..eb7d9dee9a --- /dev/null +++ b/src/mcp/types/v2026_07_28/__init__.py @@ -0,0 +1,2875 @@ +"""Internal wire-shape models for protocol 2026-07-28. Not part of the public API. + +Generated by `scripts/gen_surface_types.py` from `schema/2026-07-28.json` +@ 6d441518de8a9d5adbab0b10a76a667a63f90665. Do not edit; regenerate. Schema-exact validators that the +wire-method maps in `mcp.types.methods` point inbound 2026-07-28 validation at. +Models use `extra="ignore"` (unknown keys accepted and dropped) unless commented +otherwise; see `mcp.types._wire_base`. +""" + +from __future__ import annotations + +from typing import Annotated, Any, Literal, TypeAlias + +from pydantic import ConfigDict, Field +from typing_extensions import TypeAliasType + +from mcp.types._wire_base import OpenWireModel, WireModel + +# schema.json renders the primitive arm without float/null; widen per schema.ts. +JSONValue = TypeAliasType("JSONValue", "JSONObject | list[JSONValue] | str | int | float | bool | None") + + +JSONObject = TypeAliasType("JSONObject", dict[str, "JSONValue"]) + + +class BaseMetadata(WireModel): + """Base interface for metadata with name (identifier) and title (display name) properties.""" + + name: str + """ + Intended for programmatic or logical use, but used as a display name in past specs or fallback (if title isn't + present). + """ + title: str | None = None + """ + Intended for UI and end-user contexts — optimized to be human-readable and easily understood, + even by those unfamiliar with domain-specific terminology. + + If not provided, the name should be used for display (except for Tool, + where `annotations.title` should be given precedence over using `name`, + if present). + """ + + +class BooleanSchema(WireModel): + default: bool | None = None + description: str | None = None + title: str | None = None + type: Literal["boolean"] + + +class Argument(WireModel): + """The argument's information""" + + name: str + """ + The name of the argument + """ + value: str + """ + The value of the argument to use for completion matching. + """ + + +class Context(WireModel): + """Additional, optional context for completions""" + + arguments: dict[str, str] | None = None + """ + Previously-resolved variables in a URI template or prompt. + """ + + +class Completion(WireModel): + has_more: Annotated[bool | None, Field(alias="hasMore")] = None + """ + Indicates whether there are additional completion options beyond those provided in the current response, even if the + exact total is unknown. + """ + total: int | None = None + """ + The total number of completion options available. This can exceed the number of values actually sent in the + response. + """ + values: Annotated[list[str], Field(max_length=100)] + """ + An array of completion values. Must not exceed 100 items. + """ + + +Cursor: TypeAlias = str + + +class ElicitRequestURLParams(WireModel): + """The parameters for a request to elicit information from the user via a URL in the client.""" + + elicitation_id: Annotated[str, Field(alias="elicitationId")] + """ + The ID of the elicitation, which must be unique within the context of the server. + The client MUST treat this ID as an opaque value. + """ + message: str + """ + The message to present to the user explaining why the interaction is needed. + """ + mode: Literal["url"] + """ + The elicitation mode. + """ + url: str + """ + The URL that the user should navigate to. + """ + + +class ElicitResult(WireModel): + """The result returned by the client for an ElicitRequestelicitation/create request.""" + + action: Literal["accept", "cancel", "decline"] + """ + The user action in response to the elicitation. + - `"accept"`: User submitted the form/confirmed the action + - `"decline"`: User explicitly declined the action + - `"cancel"`: User dismissed without making an explicit choice + """ + # schema.json renders this `number` as integer; widen per schema.ts so floats validate. + content: dict[str, list[str] | str | int | float | bool] | None = None + """ + The submitted form data, only present when action is `"accept"` and mode was `"form"`. + Contains values matching the requested schema. + Omitted for out-of-band mode responses. + """ + + +class ElicitationCompleteNotificationParams(WireModel): + elicitation_id: Annotated[str, Field(alias="elicitationId")] + """ + The ID of the elicitation that completed. + """ + + +class ElicitationCompleteNotification(WireModel): + """An optional notification from the server to the client, informing it of a completion of a out-of-band + elicitation request. + """ + + jsonrpc: Literal["2.0"] + method: Literal["notifications/elicitation/complete"] + params: ElicitationCompleteNotificationParams + + +class Error(WireModel): + code: int + """ + The error type that occurred. + """ + data: Any | None = None + """ + Additional information about the error. The value of this member is defined by the sender (e.g. detailed error + information, nested errors etc.). + """ + message: str + """ + A short description of the error. The message SHOULD be limited to a concise single sentence. + """ + + +class Icon(WireModel): + """An optionally-sized icon that can be displayed in a user interface.""" + + mime_type: Annotated[str | None, Field(alias="mimeType")] = None + """ + Optional MIME type override if the source MIME type is missing or generic. + For example: `"image/png"`, `"image/jpeg"`, or `"image/svg+xml"`. + """ + sizes: list[str] | None = None + """ + Optional array of strings that specify sizes at which the icon can be used. + Each string should be in WxH format (e.g., `"48x48"`, `"96x96"`) or `"any"` for scalable formats like SVG. + + If not provided, the client should assume that the icon can be used at any size. + """ + src: str + """ + A standard URI pointing to an icon resource. May be an HTTP/HTTPS URL or a + `data:` URI with Base64-encoded image data. + + Consumers SHOULD take steps to ensure URLs serving icons are from the + same domain as the client/server or a trusted domain. + + Consumers SHOULD take appropriate precautions when consuming SVGs as they can contain + executable JavaScript. + """ + theme: Literal["dark", "light"] | None = None + """ + Optional specifier for the theme this icon is designed for. `"light"` indicates + the icon is designed to be used with a light background, and `"dark"` indicates + the icon is designed to be used with a dark background. + + If not provided, the client should assume the icon can be used with any theme. + """ + + +class Icons(WireModel): + """Base interface to add `icons` property.""" + + icons: list[Icon] | None = None + """ + Optional set of sized icons that the client can display in a user interface. + + Clients that support rendering icons MUST support at least the following MIME types: + - `image/png` - PNG images (safe, universal compatibility) + - `image/jpeg` (and `image/jpg`) - JPEG images (safe, universal compatibility) + + Clients that support rendering icons SHOULD also support: + - `image/svg+xml` - SVG images (scalable but requires security precautions) + - `image/webp` - WebP images (modern, efficient format) + """ + + +class Implementation(WireModel): + """Describes the MCP implementation.""" + + description: str | None = None + """ + An optional human-readable description of what this implementation does. + + This can be used by clients or servers to provide context about their purpose + and capabilities. For example, a server might describe the types of resources + or tools it provides, while a client might describe its intended use case. + """ + icons: list[Icon] | None = None + """ + Optional set of sized icons that the client can display in a user interface. + + Clients that support rendering icons MUST support at least the following MIME types: + - `image/png` - PNG images (safe, universal compatibility) + - `image/jpeg` (and `image/jpg`) - JPEG images (safe, universal compatibility) + + Clients that support rendering icons SHOULD also support: + - `image/svg+xml` - SVG images (scalable but requires security precautions) + - `image/webp` - WebP images (modern, efficient format) + """ + name: str + """ + Intended for programmatic or logical use, but used as a display name in past specs or fallback (if title isn't + present). + """ + title: str | None = None + """ + Intended for UI and end-user contexts — optimized to be human-readable and easily understood, + even by those unfamiliar with domain-specific terminology. + + If not provided, the name should be used for display (except for Tool, + where `annotations.title` should be given precedence over using `name`, + if present). + """ + version: str + """ + The version of this implementation. + """ + website_url: Annotated[str | None, Field(alias="websiteUrl")] = None + """ + An optional URL of the website for this implementation. + """ + + +class InternalError(WireModel): + """A JSON-RPC error indicating that an internal error occurred on the receiver. This error is returned when the + receiver encounters an unexpected condition that prevents it from fulfilling the request. + """ + + code: Literal[-32603] + """ + The error type that occurred. + """ + data: Any | None = None + """ + Additional information about the error. The value of this member is defined by the sender (e.g. detailed error + information, nested errors etc.). + """ + message: str + """ + A short description of the error. The message SHOULD be limited to a concise single sentence. + """ + + +class InvalidParamsError(WireModel): + """A JSON-RPC error indicating that the method parameters are invalid or malformed. + + In MCP, this error is returned in various contexts when request parameters fail validation: + + - **Tools**: Unknown tool name or invalid tool arguments + - **Prompts**: Unknown prompt name or missing required arguments + - **Pagination**: Invalid or expired cursor values + - **Logging**: Invalid log level + - **Elicitation**: Server requests an elicitation mode not declared in client capabilities + - **Sampling**: Missing tool result or tool results mixed with other content + """ + + code: Literal[-32602] + """ + The error type that occurred. + """ + data: Any | None = None + """ + Additional information about the error. The value of this member is defined by the sender (e.g. detailed error + information, nested errors etc.). + """ + message: str + """ + A short description of the error. The message SHOULD be limited to a concise single sentence. + """ + + +class InvalidRequestError(WireModel): + """A JSON-RPC error indicating that the request is not a valid request object. This error is returned when the + message structure does not conform to the JSON-RPC 2.0 specification requirements for a request (e.g., missing + required fields like `jsonrpc` or `method`, or using invalid types for these fields). + """ + + code: Literal[-32600] + """ + The error type that occurred. + """ + data: Any | None = None + """ + Additional information about the error. The value of this member is defined by the sender (e.g. detailed error + information, nested errors etc.). + """ + message: str + """ + A short description of the error. The message SHOULD be limited to a concise single sentence. + """ + + +class JSONRPCNotification(WireModel): + """A notification which does not expect a response.""" + + jsonrpc: Literal["2.0"] + method: str + params: dict[str, Any] | None = None + + +class LegacyTitledEnumSchema(WireModel): + """Use TitledSingleSelectEnumSchema instead. + This interface will be removed in a future version. + """ + + default: str | None = None + description: str | None = None + enum: list[str] + enum_names: Annotated[list[str] | None, Field(alias="enumNames")] = None + """ + (Legacy) Display names for enum values. + Non-standard according to JSON schema 2020-12. + """ + title: str | None = None + type: Literal["string"] + + +LoggingLevel: TypeAlias = Literal["alert", "critical", "debug", "emergency", "error", "info", "notice", "warning"] + + +class MetaObject(OpenWireModel): + """Represents the contents of a `_meta` field, which clients and servers use to attach additional metadata to their + interactions. + + Certain key names are reserved by MCP for protocol-level metadata; implementations MUST NOT make assumptions about + values at these keys. Additionally, specific schema definitions may reserve particular names for purpose-specific + metadata, as declared in those definitions. + + Valid keys have two segments: + + **Prefix:** + - Optional — if specified, MUST be a series of _labels_ separated by dots (`.`), followed by a slash (`/`). + - Labels MUST start with a letter and end with a letter or digit. Interior characters may be letters, digits, or + hyphens (`-`). + - Implementations SHOULD use reverse DNS notation (e.g., `com.example/` rather than `example.com/`). + - Any prefix where the second label is `modelcontextprotocol` or `mcp` is **reserved** for MCP use. For example: + `io.modelcontextprotocol/`, `dev.mcp/`, `org.modelcontextprotocol.api/`, and `com.mcp.tools/` are all reserved. + However, `com.example.mcp/` is NOT reserved, as the second label is `example`. + + **Name:** + - Unless empty, MUST start and end with an alphanumeric character (`[a-z0-9A-Z]`). + - Interior characters may be alphanumeric, hyphens (`-`), underscores (`_`), or dots (`.`). + """ + + +class MethodNotFoundError(WireModel): + """A JSON-RPC error indicating that the requested method does not exist or is not available. + + In MCP, a server returns this error when a client invokes a method the server does not implement — either a + genuinely unknown method, or one gated behind a server capability the server did not advertise (e.g., calling + `prompts/list` when the `prompts` capability was not advertised). + + A request that requires a client capability the client did not declare is signalled instead by + MissingRequiredClientCapabilityError (`-32003`). + """ + + code: Literal[-32601] + """ + The error type that occurred. + """ + data: Any | None = None + """ + Additional information about the error. The value of this member is defined by the sender (e.g. detailed error + information, nested errors etc.). + """ + message: str + """ + A short description of the error. The message SHOULD be limited to a concise single sentence. + """ + + +class ModelHint(WireModel): + """Hints to use for model selection. + + Keys not declared here are currently left unspecified by the spec and are up + to the client to interpret. + """ + + name: str | None = None + """ + A hint for a model name. + + The client SHOULD treat this as a substring of a model name; for example: + - `claude-3-5-sonnet` should match `claude-3-5-sonnet-20241022` + - `sonnet` should match `claude-3-5-sonnet-20241022`, `claude-3-sonnet-20240229`, etc. + - `claude` should match any Claude model + + The client MAY also map the string to a different provider's model name or a different model family, as long as it + fills a similar niche; for example: + - `gemini-1.5-flash` could match `claude-3-haiku-20240307` + """ + + +class ModelPreferences(WireModel): + """The server's preferences for model selection, requested of the client during sampling. + + Because LLMs can vary along multiple dimensions, choosing the "best" model is + rarely straightforward. Different models excel in different areas—some are + faster but less capable, others are more capable but more expensive, and so + on. This interface allows servers to express their priorities across multiple + dimensions to help clients make an appropriate selection for their use case. + + These preferences are always advisory. The client MAY ignore them. It is also + up to the client to decide how to interpret these preferences and how to + balance them against other considerations. + """ + + cost_priority: Annotated[float | None, Field(alias="costPriority", ge=0.0, le=1.0)] = None + """ + How much to prioritize cost when selecting a model. A value of 0 means cost + is not important, while a value of 1 means cost is the most important + factor. + """ + hints: list[ModelHint] | None = None + """ + Optional hints to use for model selection. + + If multiple hints are specified, the client MUST evaluate them in order + (such that the first match is taken). + + The client SHOULD prioritize these hints over the numeric priorities, but + MAY still use the priorities to select from ambiguous matches. + """ + intelligence_priority: Annotated[float | None, Field(alias="intelligencePriority", ge=0.0, le=1.0)] = None + """ + How much to prioritize intelligence and capabilities when selecting a + model. A value of 0 means intelligence is not important, while a value of 1 + means intelligence is the most important factor. + """ + speed_priority: Annotated[float | None, Field(alias="speedPriority", ge=0.0, le=1.0)] = None + """ + How much to prioritize sampling speed (latency) when selecting a model. A + value of 0 means speed is not important, while a value of 1 means speed is + the most important factor. + """ + + +class Notification(WireModel): + method: str + params: dict[str, Any] | None = None + + +class NotificationParams(WireModel): + """Common params for any notification.""" + + meta: Annotated[MetaObject | None, Field(alias="_meta")] = None + + +class NumberSchema(WireModel): + default: float | None = None + description: str | None = None + maximum: float | None = None + minimum: float | None = None + title: str | None = None + type: Literal["integer", "number"] + + +class PaginatedResult(WireModel): + meta: Annotated[MetaObject | None, Field(alias="_meta")] = None + next_cursor: Annotated[str | None, Field(alias="nextCursor")] = None + """ + An opaque token representing the pagination position after the last returned result. + If present, there may be more results available. + """ + result_type: Annotated[str, Field(alias="resultType")] + """ + Indicates the type of the result, which allows the client to determine + how to parse the result object. + + Servers implementing this protocol version MUST include this field. + For backward compatibility, when a client receives a result from a + server implementing an earlier protocol version (which does not include + `resultType`), the client MUST treat the absent field as `"complete"`. + """ + + +class ParseError(WireModel): + """A JSON-RPC error indicating that invalid JSON was received by the server. This error is returned when the + server cannot parse the JSON text of a message. + """ + + code: Literal[-32700] + """ + The error type that occurred. + """ + data: Any | None = None + """ + Additional information about the error. The value of this member is defined by the sender (e.g. detailed error + information, nested errors etc.). + """ + message: str + """ + A short description of the error. The message SHOULD be limited to a concise single sentence. + """ + + +ProgressToken: TypeAlias = str | int + + +class PromptArgument(WireModel): + """Describes an argument that a prompt can accept.""" + + description: str | None = None + """ + A human-readable description of the argument. + """ + name: str + """ + Intended for programmatic or logical use, but used as a display name in past specs or fallback (if title isn't + present). + """ + required: bool | None = None + """ + Whether this argument must be provided. + """ + title: str | None = None + """ + Intended for UI and end-user contexts — optimized to be human-readable and easily understood, + even by those unfamiliar with domain-specific terminology. + + If not provided, the name should be used for display (except for Tool, + where `annotations.title` should be given precedence over using `name`, + if present). + """ + + +class PromptListChangedNotification(WireModel): + """An optional notification from the server to the client, informing it that the list of prompts it offers has + changed. This may be issued by servers without any previous subscription from the client. + """ + + jsonrpc: Literal["2.0"] + method: Literal["notifications/prompts/list_changed"] + params: NotificationParams | None = None + + +class PromptReference(WireModel): + """Identifies a prompt.""" + + name: str + """ + Intended for programmatic or logical use, but used as a display name in past specs or fallback (if title isn't + present). + """ + title: str | None = None + """ + Intended for UI and end-user contexts — optimized to be human-readable and easily understood, + even by those unfamiliar with domain-specific terminology. + + If not provided, the name should be used for display (except for Tool, + where `annotations.title` should be given precedence over using `name`, + if present). + """ + type: Literal["ref/prompt"] + + +class Request(WireModel): + method: str + params: dict[str, Any] | None = None + + +RequestId: TypeAlias = str | int + + +class ResourceContents(WireModel): + """The contents of a specific resource or sub-resource.""" + + meta: Annotated[MetaObject | None, Field(alias="_meta")] = None + mime_type: Annotated[str | None, Field(alias="mimeType")] = None + """ + The MIME type of this resource, if known. + """ + uri: str + """ + The URI of this resource. + """ + + +class ResourceListChangedNotification(WireModel): + """An optional notification from the server to the client, informing it that the list of resources it can read + from has changed. This may be issued by servers without any previous subscription from the client. + """ + + jsonrpc: Literal["2.0"] + method: Literal["notifications/resources/list_changed"] + params: NotificationParams | None = None + + +class ResourceTemplateReference(WireModel): + """A reference to a resource or resource template definition.""" + + type: Literal["ref/resource"] + uri: str + """ + The URI or URI template of the resource. + """ + + +class ResourceUpdatedNotificationParams(WireModel): + """Parameters for a `notifications/resources/updated` notification.""" + + meta: Annotated[MetaObject | None, Field(alias="_meta")] = None + uri: str + """ + The URI of the resource that has been updated. This might be a sub-resource of the one that the client actually + subscribed to. + """ + + +class Result(WireModel): + """Common result fields.""" + + meta: Annotated[MetaObject | None, Field(alias="_meta")] = None + result_type: Annotated[str, Field(alias="resultType")] + """ + Indicates the type of the result, which allows the client to determine + how to parse the result object. + + Servers implementing this protocol version MUST include this field. + For backward compatibility, when a client receives a result from a + server implementing an earlier protocol version (which does not include + `resultType`), the client MUST treat the absent field as `"complete"`. + """ + + +ResultType: TypeAlias = str + + +Role: TypeAlias = Literal["assistant", "user"] + + +class Root(WireModel): + """Represents a root directory or file that the server can operate on.""" + + meta: Annotated[MetaObject | None, Field(alias="_meta")] = None + name: str | None = None + """ + An optional name for the root. This can be used to provide a human-readable + identifier for the root, which may be useful for display purposes or for + referencing the root in other parts of the application. + """ + uri: str + """ + The URI identifying the root. This *must* start with `file://` for now. + This restriction may be relaxed in future versions of the protocol to allow + other URI schemes. + """ + + +class Prompts(WireModel): + """Present if the server offers any prompt templates.""" + + list_changed: Annotated[bool | None, Field(alias="listChanged")] = None + """ + Whether this server supports notifications for changes to the prompt list. + """ + + +class Resources(WireModel): + """Present if the server offers any resources to read.""" + + list_changed: Annotated[bool | None, Field(alias="listChanged")] = None + """ + Whether this server supports notifications for changes to the resource list. + """ + subscribe: bool | None = None + """ + Whether this server supports subscribing to resource updates. + """ + + +class Tools(WireModel): + """Present if the server offers any tools to call.""" + + list_changed: Annotated[bool | None, Field(alias="listChanged")] = None + """ + Whether this server supports notifications for changes to the tool list. + """ + + +class StringSchema(WireModel): + default: str | None = None + description: str | None = None + format: Literal["date", "date-time", "email", "uri"] | None = None + max_length: Annotated[int | None, Field(alias="maxLength")] = None + min_length: Annotated[int | None, Field(alias="minLength")] = None + title: str | None = None + type: Literal["string"] + + +class SubscriptionFilter(WireModel): + """The set of notification types a client may opt in to on a + SubscriptionsListenRequestsubscriptions/listen request. + + Each notification type is **opt-in**; the server **MUST NOT** send + notification types the client has not explicitly requested here. + """ + + # Stays open: filter contents are extensible on the wire. + model_config = ConfigDict( + extra="allow", + ) + prompts_list_changed: Annotated[bool | None, Field(alias="promptsListChanged")] = None + """ + If true, receive PromptListChangedNotificationnotifications/prompts/list_changed. + """ + resource_subscriptions: Annotated[list[str] | None, Field(alias="resourceSubscriptions")] = None + """ + Subscribe to ResourceUpdatedNotificationnotifications/resources/updated for these resource URIs. + Replaces the former `resources/subscribe` RPC. + """ + resources_list_changed: Annotated[bool | None, Field(alias="resourcesListChanged")] = None + """ + If true, receive ResourceListChangedNotificationnotifications/resources/list_changed. + """ + tools_list_changed: Annotated[bool | None, Field(alias="toolsListChanged")] = None + """ + If true, receive ToolListChangedNotificationnotifications/tools/list_changed. + """ + + +class SubscriptionsAcknowledgedNotificationParams(WireModel): + """Parameters for a SubscriptionsAcknowledgedNotificationnotifications/subscriptions/acknowledged notification.""" + + meta: Annotated[MetaObject | None, Field(alias="_meta")] = None + notifications: SubscriptionFilter + """ + The subset of requested notification types the server agreed to honor. + Only includes notification types the server actually supports; if the + client requested an unsupported type (e.g., `promptsListChanged` when + the server has no prompts), it is omitted from this set. + """ + + +class TextResourceContents(WireModel): + meta: Annotated[MetaObject | None, Field(alias="_meta")] = None + mime_type: Annotated[str | None, Field(alias="mimeType")] = None + """ + The MIME type of this resource, if known. + """ + text: str + """ + The text of the item. This must only be set if the item can actually be represented as text (not binary data). + """ + uri: str + """ + The URI of this resource. + """ + + +class AnyOfItem(WireModel): + const: str + """ + The constant enum value. + """ + title: str + """ + Display title for this option. + """ + + +class Items(WireModel): + """Schema for array items with enum options and display labels.""" + + any_of: Annotated[list[AnyOfItem], Field(alias="anyOf")] + """ + Array of enum options with values and display labels. + """ + + +class TitledMultiSelectEnumSchema(WireModel): + """Schema for multiple-selection enumeration with display titles for each option.""" + + default: list[str] | None = None + """ + Optional default value. + """ + description: str | None = None + """ + Optional description for the enum field. + """ + items: Items + """ + Schema for array items with enum options and display labels. + """ + max_items: Annotated[int | None, Field(alias="maxItems")] = None + """ + Maximum number of items to select. + """ + min_items: Annotated[int | None, Field(alias="minItems")] = None + """ + Minimum number of items to select. + """ + title: str | None = None + """ + Optional title for the enum field. + """ + type: Literal["array"] + + +class OneOfItem(WireModel): + const: str + """ + The enum value. + """ + title: str + """ + Display label for this option. + """ + + +class TitledSingleSelectEnumSchema(WireModel): + """Schema for single-selection enumeration with display titles for each option.""" + + default: str | None = None + """ + Optional default value. + """ + description: str | None = None + """ + Optional description for the enum field. + """ + one_of: Annotated[list[OneOfItem], Field(alias="oneOf")] + """ + Array of enum options with values and display labels. + """ + title: str | None = None + """ + Optional title for the enum field. + """ + type: Literal["string"] + + +class InputSchema(WireModel): + """A JSON Schema object defining the expected parameters for the tool. + + Tool arguments are always JSON objects, so `type: "object"` is required at the root. + Beyond that, any JSON Schema 2020-12 keyword may appear alongside `type` — including + composition keywords (`oneOf`, `anyOf`, `allOf`, `not`), conditional keywords + (`if`/`then`/`else`), reference keywords (`$ref`, `$defs`, `$anchor`), and any other + standard validation or annotation keywords. + + Defaults to JSON Schema 2020-12 when no explicit `$schema` is provided. + """ + + # Stays open: schema keywords beyond the declared properties ride extra fields. + model_config = ConfigDict( + extra="allow", + ) + schema_: Annotated[str | None, Field(alias="$schema")] = None + type: Literal["object"] + + +class OutputSchema(WireModel): + """An optional JSON Schema object defining the structure of the tool's output returned in + the structuredContent field of a CallToolResult. This can be any valid JSON Schema 2020-12. + + Defaults to JSON Schema 2020-12 when no explicit `$schema` is provided. + """ + + # Stays open: schema keywords beyond the declared properties ride extra fields. + model_config = ConfigDict( + extra="allow", + ) + schema_: Annotated[str | None, Field(alias="$schema")] = None + + +class ToolAnnotations(WireModel): + """Additional properties describing a Tool to clients. + + NOTE: all properties in `ToolAnnotations` are **hints**. + They are not guaranteed to provide a faithful description of + tool behavior (including descriptive properties like `title`). + + Clients should never make tool use decisions based on `ToolAnnotations` + received from untrusted servers. + """ + + destructive_hint: Annotated[bool | None, Field(alias="destructiveHint")] = None + """ + If true, the tool may perform destructive updates to its environment. + If false, the tool performs only additive updates. + + (This property is meaningful only when `readOnlyHint == false`) + + Default: true + """ + idempotent_hint: Annotated[bool | None, Field(alias="idempotentHint")] = None + """ + If true, calling the tool repeatedly with the same arguments + will have no additional effect on its environment. + + (This property is meaningful only when `readOnlyHint == false`) + + Default: false + """ + open_world_hint: Annotated[bool | None, Field(alias="openWorldHint")] = None + """ + If true, this tool may interact with an "open world" of external + entities. If false, the tool's domain of interaction is closed. + For example, the world of a web search tool is open, whereas that + of a memory tool is not. + + Default: true + """ + read_only_hint: Annotated[bool | None, Field(alias="readOnlyHint")] = None + """ + If true, the tool does not modify its environment. + + Default: false + """ + title: str | None = None + """ + A human-readable title for the tool. + """ + + +class ToolChoice(WireModel): + """Controls tool selection behavior for sampling requests.""" + + mode: Literal["auto", "none", "required"] | None = None + """ + Controls the tool use ability of the model: + - `"auto"`: Model decides whether to use tools (default) + - `"required"`: Model MUST use at least one tool before completing + - `"none"`: Model MUST NOT use any tools + """ + + +class ToolListChangedNotification(WireModel): + """An optional notification from the server to the client, informing it that the list of tools it offers has + changed. This may be issued by servers without any previous subscription from the client. + """ + + jsonrpc: Literal["2.0"] + method: Literal["notifications/tools/list_changed"] + params: NotificationParams | None = None + + +class ToolUseContent(WireModel): + """A request from the assistant to call a tool.""" + + meta: Annotated[MetaObject | None, Field(alias="_meta")] = None + """ + Optional metadata about the tool use. Clients SHOULD preserve this field when + including tool uses in subsequent sampling requests to enable caching optimizations. + """ + id: str + """ + A unique identifier for this tool use. + + This ID is used to match tool results to their corresponding tool uses. + """ + input: dict[str, Any] + """ + The arguments to pass to the tool, conforming to the tool's input schema. + """ + name: str + """ + The name of the tool to call. + """ + type: Literal["tool_use"] + + +class Data1(WireModel): + """Additional information about the error. The value of this member is defined by the sender (e.g. detailed error + information, nested errors etc.). + """ + + requested: str + """ + The protocol version that was requested by the client. + """ + supported: list[str] + """ + Protocol versions the server supports. The client should choose a + mutually supported version from this list and retry. + """ + + +class Error2(WireModel): + code: Literal[-32004] + """ + The error type that occurred. + """ + data: Data1 + """ + Additional information about the error. The value of this member is defined by the sender (e.g. detailed error + information, nested errors etc.). + """ + message: str + """ + A short description of the error. The message SHOULD be limited to a concise single sentence. + """ + + +class UnsupportedProtocolVersionError(WireModel): + """Returned when the request's protocol version is unknown to the server or + unsupported (e.g., a known experimental or draft version the server has + chosen not to implement). For HTTP, the response status code MUST be + `400 Bad Request`. + """ + + error: Error2 + id: RequestId | None = None + jsonrpc: Literal["2.0"] + + +class Items1(WireModel): + """Schema for the array items.""" + + enum: list[str] + """ + Array of enum values to choose from. + """ + type: Literal["string"] + + +class UntitledMultiSelectEnumSchema(WireModel): + """Schema for multiple-selection enumeration without display titles for options.""" + + default: list[str] | None = None + """ + Optional default value. + """ + description: str | None = None + """ + Optional description for the enum field. + """ + items: Items1 + """ + Schema for the array items. + """ + max_items: Annotated[int | None, Field(alias="maxItems")] = None + """ + Maximum number of items to select. + """ + min_items: Annotated[int | None, Field(alias="minItems")] = None + """ + Minimum number of items to select. + """ + title: str | None = None + """ + Optional title for the enum field. + """ + type: Literal["array"] + + +class UntitledSingleSelectEnumSchema(WireModel): + """Schema for single-selection enumeration without display titles for options.""" + + default: str | None = None + """ + Optional default value. + """ + description: str | None = None + """ + Optional description for the enum field. + """ + enum: list[str] + """ + Array of enum values to choose from. + """ + title: str | None = None + """ + Optional title for the enum field. + """ + type: Literal["string"] + + +class Annotations(WireModel): + """Optional annotations for the client. The client can use annotations to inform how objects are used or + displayed + """ + + audience: list[Role] | None = None + """ + Describes who the intended audience of this object or data is. + + It can include multiple entries to indicate content useful for multiple audiences (e.g., `["user", "assistant"]`). + """ + last_modified: Annotated[str | None, Field(alias="lastModified")] = None + """ + The moment the resource was last modified, as an ISO 8601 formatted string. + + Should be an ISO 8601 formatted string (e.g., "2025-01-12T15:00:58Z"). + + Examples: last activity timestamp in an open file, timestamp when the resource + was attached, etc. + """ + priority: Annotated[float | None, Field(ge=0.0, le=1.0)] = None + """ + Describes how important this data is for operating the server. + + A value of 1 means "most important," and indicates that the data is + effectively required, while 0 means "least important," and indicates that + the data is entirely optional. + """ + + +class AudioContent(WireModel): + """Audio provided to or from an LLM.""" + + meta: Annotated[MetaObject | None, Field(alias="_meta")] = None + annotations: Annotations | None = None + """ + Optional annotations for the client. + """ + data: str + """ + The base64-encoded audio data. + """ + mime_type: Annotated[str, Field(alias="mimeType")] + """ + The MIME type of the audio. Different providers may support different audio types. + """ + type: Literal["audio"] + + +class BlobResourceContents(WireModel): + meta: Annotated[MetaObject | None, Field(alias="_meta")] = None + blob: str + """ + A base64-encoded string representing the binary data of the item. + """ + mime_type: Annotated[str | None, Field(alias="mimeType")] = None + """ + The MIME type of this resource, if known. + """ + uri: str + """ + The URI of this resource. + """ + + +class CacheableResult(WireModel): + """A result that supports a time-to-live (TTL) hint for client-side caching.""" + + meta: Annotated[MetaObject | None, Field(alias="_meta")] = None + cache_scope: Annotated[Literal["private", "public"], Field(alias="cacheScope")] + """ + Indicates the intended scope of the cached response, analogous to HTTP + `Cache-Control: public` vs `Cache-Control: private`. + + - `"public"`: Any client or intermediary (e.g., shared gateway, proxy) + MAY cache the response and serve it to any user. + - `"private"`: Only the requesting user's client MAY cache the response. + Shared caches (e.g., multi-tenant gateways) MUST NOT serve a cached + copy to a different user. + """ + result_type: Annotated[str, Field(alias="resultType")] + """ + Indicates the type of the result, which allows the client to determine + how to parse the result object. + + Servers implementing this protocol version MUST include this field. + For backward compatibility, when a client receives a result from a + server implementing an earlier protocol version (which does not include + `resultType`), the client MUST treat the absent field as `"complete"`. + """ + ttl_ms: Annotated[int, Field(alias="ttlMs", ge=0)] + """ + A hint from the server indicating how long (in milliseconds) the + client MAY cache this response before re-fetching. Semantics are + analogous to HTTP Cache-Control max-age. + + - If 0, The response SHOULD be considered immediately stale, + The client MAY re-fetch every time the result is needed. + - If positive, the client SHOULD consider the result fresh for this many + milliseconds after receiving the response. + """ + + +class CancelledNotificationParams(WireModel): + """Parameters for a `notifications/cancelled` notification.""" + + meta: Annotated[MetaObject | None, Field(alias="_meta")] = None + reason: str | None = None + """ + An optional string describing the reason for the cancellation. This MAY be logged or presented to the user. + """ + request_id: Annotated[RequestId | None, Field(alias="requestId")] = None + """ + The ID of the request to cancel. + + This MUST correspond to the ID of a request previously issued in the same direction. + """ + + +ClientResult: TypeAlias = Result + + +class CompleteResult(WireModel): + """The result returned by the server for a CompleteRequestcompletion/complete request.""" + + meta: Annotated[MetaObject | None, Field(alias="_meta")] = None + completion: Completion + result_type: Annotated[str, Field(alias="resultType")] + """ + Indicates the type of the result, which allows the client to determine + how to parse the result object. + + Servers implementing this protocol version MUST include this field. + For backward compatibility, when a client receives a result from a + server implementing an earlier protocol version (which does not include + `resultType`), the client MUST treat the absent field as `"complete"`. + """ + + +class CompleteResultResponse(WireModel): + """A successful response from the server for a CompleteRequestcompletion/complete request.""" + + id: RequestId + jsonrpc: Literal["2.0"] + result: CompleteResult + + +class EmbeddedResource(WireModel): + """The contents of a resource, embedded into a prompt or tool call result. + + It is up to the client how best to render embedded resources for the benefit + of the LLM and/or the user. + """ + + meta: Annotated[MetaObject | None, Field(alias="_meta")] = None + annotations: Annotations | None = None + """ + Optional annotations for the client. + """ + resource: TextResourceContents | BlobResourceContents + type: Literal["resource"] + + +EmptyResult: TypeAlias = Result + + +EnumSchema: TypeAlias = ( + UntitledSingleSelectEnumSchema + | TitledSingleSelectEnumSchema + | UntitledMultiSelectEnumSchema + | TitledMultiSelectEnumSchema + | LegacyTitledEnumSchema +) + + +class ImageContent(WireModel): + """An image provided to or from an LLM.""" + + meta: Annotated[MetaObject | None, Field(alias="_meta")] = None + annotations: Annotations | None = None + """ + Optional annotations for the client. + """ + data: str + """ + The base64-encoded image data. + """ + mime_type: Annotated[str, Field(alias="mimeType")] + """ + The MIME type of the image. Different providers may support different image types. + """ + type: Literal["image"] + + +class JSONRPCErrorResponse(WireModel): + """A response to a request that indicates an error occurred.""" + + error: Error + id: RequestId | None = None + jsonrpc: Literal["2.0"] + + +class JSONRPCRequest(WireModel): + """A request that expects a response.""" + + id: RequestId + jsonrpc: Literal["2.0"] + method: str + params: dict[str, Any] | None = None + + +class JSONRPCResultResponse(WireModel): + """A successful (non-error) response to a request.""" + + id: RequestId + jsonrpc: Literal["2.0"] + result: Result + + +class ListRootsResult(WireModel): + """The result returned by the client for a ListRootsRequestroots/list request. + This result contains an array of Root objects, each representing a root directory + or file that the server can operate on. + """ + + roots: list[Root] + + +class LoggingMessageNotificationParams(WireModel): + """Parameters for a `notifications/message` notification.""" + + meta: Annotated[MetaObject | None, Field(alias="_meta")] = None + data: Any + """ + The data to be logged, such as a string message or an object. Any JSON serializable type is allowed here. + """ + level: LoggingLevel + """ + The severity of this log message. + """ + logger: str | None = None + """ + An optional name of the logger issuing this message. + """ + + +MultiSelectEnumSchema: TypeAlias = UntitledMultiSelectEnumSchema | TitledMultiSelectEnumSchema + + +PrimitiveSchemaDefinition: TypeAlias = ( + StringSchema + | NumberSchema + | BooleanSchema + | UntitledSingleSelectEnumSchema + | TitledSingleSelectEnumSchema + | UntitledMultiSelectEnumSchema + | TitledMultiSelectEnumSchema + | LegacyTitledEnumSchema +) + + +class ProgressNotificationParams(WireModel): + """Parameters for a ProgressNotificationnotifications/progress notification.""" + + meta: Annotated[MetaObject | None, Field(alias="_meta")] = None + message: str | None = None + """ + An optional message describing the current progress. + """ + progress: float + """ + The progress thus far. This should increase every time progress is made, even if the total is unknown. + """ + progress_token: Annotated[ProgressToken, Field(alias="progressToken")] + """ + The progress token which was given in the initial request, used to associate this notification with the request that + is proceeding. + """ + total: float | None = None + """ + Total number of items to process (or total progress required), if known. + """ + + +class Prompt(WireModel): + """A prompt or prompt template that the server offers.""" + + meta: Annotated[MetaObject | None, Field(alias="_meta")] = None + arguments: list[PromptArgument] | None = None + """ + A list of arguments to use for templating the prompt. + """ + description: str | None = None + """ + An optional description of what this prompt provides + """ + icons: list[Icon] | None = None + """ + Optional set of sized icons that the client can display in a user interface. + + Clients that support rendering icons MUST support at least the following MIME types: + - `image/png` - PNG images (safe, universal compatibility) + - `image/jpeg` (and `image/jpg`) - JPEG images (safe, universal compatibility) + + Clients that support rendering icons SHOULD also support: + - `image/svg+xml` - SVG images (scalable but requires security precautions) + - `image/webp` - WebP images (modern, efficient format) + """ + name: str + """ + Intended for programmatic or logical use, but used as a display name in past specs or fallback (if title isn't + present). + """ + title: str | None = None + """ + Intended for UI and end-user contexts — optimized to be human-readable and easily understood, + even by those unfamiliar with domain-specific terminology. + + If not provided, the name should be used for display (except for Tool, + where `annotations.title` should be given precedence over using `name`, + if present). + """ + + +class ReadResourceResult(WireModel): + """The result returned by the server for a ReadResourceRequestresources/read request.""" + + meta: Annotated[MetaObject | None, Field(alias="_meta")] = None + cache_scope: Annotated[Literal["private", "public"], Field(alias="cacheScope")] + """ + Indicates the intended scope of the cached response, analogous to HTTP + `Cache-Control: public` vs `Cache-Control: private`. + + - `"public"`: Any client or intermediary (e.g., shared gateway, proxy) + MAY cache the response and serve it to any user. + - `"private"`: Only the requesting user's client MAY cache the response. + Shared caches (e.g., multi-tenant gateways) MUST NOT serve a cached + copy to a different user. + """ + contents: list[TextResourceContents | BlobResourceContents] + result_type: Annotated[str, Field(alias="resultType")] + """ + Indicates the type of the result, which allows the client to determine + how to parse the result object. + + Servers implementing this protocol version MUST include this field. + For backward compatibility, when a client receives a result from a + server implementing an earlier protocol version (which does not include + `resultType`), the client MUST treat the absent field as `"complete"`. + """ + ttl_ms: Annotated[int, Field(alias="ttlMs", ge=0)] + """ + A hint from the server indicating how long (in milliseconds) the + client MAY cache this response before re-fetching. Semantics are + analogous to HTTP Cache-Control max-age. + + - If 0, The response SHOULD be considered immediately stale, + The client MAY re-fetch every time the result is needed. + - If positive, the client SHOULD consider the result fresh for this many + milliseconds after receiving the response. + """ + + +class Resource(WireModel): + """A known resource that the server is capable of reading.""" + + meta: Annotated[MetaObject | None, Field(alias="_meta")] = None + annotations: Annotations | None = None + """ + Optional annotations for the client. + """ + description: str | None = None + """ + A description of what this resource represents. + + This can be used by clients to improve the LLM's understanding of available resources. It can be thought of like a + "hint" to the model. + """ + icons: list[Icon] | None = None + """ + Optional set of sized icons that the client can display in a user interface. + + Clients that support rendering icons MUST support at least the following MIME types: + - `image/png` - PNG images (safe, universal compatibility) + - `image/jpeg` (and `image/jpg`) - JPEG images (safe, universal compatibility) + + Clients that support rendering icons SHOULD also support: + - `image/svg+xml` - SVG images (scalable but requires security precautions) + - `image/webp` - WebP images (modern, efficient format) + """ + mime_type: Annotated[str | None, Field(alias="mimeType")] = None + """ + The MIME type of this resource, if known. + """ + name: str + """ + Intended for programmatic or logical use, but used as a display name in past specs or fallback (if title isn't + present). + """ + size: int | None = None + """ + The size of the raw resource content, in bytes (i.e., before base64 encoding or any tokenization), if known. + + This can be used by Hosts to display file sizes and estimate context window usage. + """ + title: str | None = None + """ + Intended for UI and end-user contexts — optimized to be human-readable and easily understood, + even by those unfamiliar with domain-specific terminology. + + If not provided, the name should be used for display (except for Tool, + where `annotations.title` should be given precedence over using `name`, + if present). + """ + uri: str + """ + The URI of this resource. + """ + + +class ResourceLink(WireModel): + """A resource that the server is capable of reading, included in a prompt or tool call result. + + Note: resource links returned by tools are not guaranteed to appear in the results of + ListResourcesRequestresources/list requests. + """ + + meta: Annotated[MetaObject | None, Field(alias="_meta")] = None + annotations: Annotations | None = None + """ + Optional annotations for the client. + """ + description: str | None = None + """ + A description of what this resource represents. + + This can be used by clients to improve the LLM's understanding of available resources. It can be thought of like a + "hint" to the model. + """ + icons: list[Icon] | None = None + """ + Optional set of sized icons that the client can display in a user interface. + + Clients that support rendering icons MUST support at least the following MIME types: + - `image/png` - PNG images (safe, universal compatibility) + - `image/jpeg` (and `image/jpg`) - JPEG images (safe, universal compatibility) + + Clients that support rendering icons SHOULD also support: + - `image/svg+xml` - SVG images (scalable but requires security precautions) + - `image/webp` - WebP images (modern, efficient format) + """ + mime_type: Annotated[str | None, Field(alias="mimeType")] = None + """ + The MIME type of this resource, if known. + """ + name: str + """ + Intended for programmatic or logical use, but used as a display name in past specs or fallback (if title isn't + present). + """ + size: int | None = None + """ + The size of the raw resource content, in bytes (i.e., before base64 encoding or any tokenization), if known. + + This can be used by Hosts to display file sizes and estimate context window usage. + """ + title: str | None = None + """ + Intended for UI and end-user contexts — optimized to be human-readable and easily understood, + even by those unfamiliar with domain-specific terminology. + + If not provided, the name should be used for display (except for Tool, + where `annotations.title` should be given precedence over using `name`, + if present). + """ + type: Literal["resource_link"] + uri: str + """ + The URI of this resource. + """ + + +class ResourceTemplate(WireModel): + """A template description for resources available on the server.""" + + meta: Annotated[MetaObject | None, Field(alias="_meta")] = None + annotations: Annotations | None = None + """ + Optional annotations for the client. + """ + description: str | None = None + """ + A description of what this template is for. + + This can be used by clients to improve the LLM's understanding of available resources. It can be thought of like a + "hint" to the model. + """ + icons: list[Icon] | None = None + """ + Optional set of sized icons that the client can display in a user interface. + + Clients that support rendering icons MUST support at least the following MIME types: + - `image/png` - PNG images (safe, universal compatibility) + - `image/jpeg` (and `image/jpg`) - JPEG images (safe, universal compatibility) + + Clients that support rendering icons SHOULD also support: + - `image/svg+xml` - SVG images (scalable but requires security precautions) + - `image/webp` - WebP images (modern, efficient format) + """ + mime_type: Annotated[str | None, Field(alias="mimeType")] = None + """ + The MIME type for all resources that match this template. This should only be included if all resources matching + this template have the same type. + """ + name: str + """ + Intended for programmatic or logical use, but used as a display name in past specs or fallback (if title isn't + present). + """ + title: str | None = None + """ + Intended for UI and end-user contexts — optimized to be human-readable and easily understood, + even by those unfamiliar with domain-specific terminology. + + If not provided, the name should be used for display (except for Tool, + where `annotations.title` should be given precedence over using `name`, + if present). + """ + uri_template: Annotated[str, Field(alias="uriTemplate")] + """ + A URI template (according to RFC 6570) that can be used to construct resource URIs. + """ + + +class ResourceUpdatedNotification(WireModel): + """A notification from the server to the client, informing it that a resource has changed and may need to be read + again. This is only sent for resources the client opted in to via the `resourceSubscriptions` field of a + SubscriptionsListenRequestsubscriptions/listen request. + """ + + jsonrpc: Literal["2.0"] + method: Literal["notifications/resources/updated"] + params: ResourceUpdatedNotificationParams + + +SingleSelectEnumSchema: TypeAlias = UntitledSingleSelectEnumSchema | TitledSingleSelectEnumSchema + + +class SubscriptionsAcknowledgedNotification(WireModel): + """Sent by the server as the first message on a + SubscriptionsListenRequestsubscriptions/listen stream to acknowledge + that the subscription has been established and to report which notification + types it agreed to honor. + """ + + jsonrpc: Literal["2.0"] + method: Literal["notifications/subscriptions/acknowledged"] + params: SubscriptionsAcknowledgedNotificationParams + + +class TextContent(WireModel): + """Text provided to or from an LLM.""" + + meta: Annotated[MetaObject | None, Field(alias="_meta")] = None + annotations: Annotations | None = None + """ + Optional annotations for the client. + """ + text: str + """ + The text content of the message. + """ + type: Literal["text"] + + +class Tool(WireModel): + """Definition for a tool the client can call.""" + + meta: Annotated[MetaObject | None, Field(alias="_meta")] = None + annotations: ToolAnnotations | None = None + """ + Optional additional tool information. + + Display name precedence order is: `title`, `annotations.title`, then `name`. + """ + description: str | None = None + """ + A human-readable description of the tool. + + This can be used by clients to improve the LLM's understanding of available tools. It can be thought of like a + "hint" to the model. + """ + icons: list[Icon] | None = None + """ + Optional set of sized icons that the client can display in a user interface. + + Clients that support rendering icons MUST support at least the following MIME types: + - `image/png` - PNG images (safe, universal compatibility) + - `image/jpeg` (and `image/jpg`) - JPEG images (safe, universal compatibility) + + Clients that support rendering icons SHOULD also support: + - `image/svg+xml` - SVG images (scalable but requires security precautions) + - `image/webp` - WebP images (modern, efficient format) + """ + input_schema: Annotated[InputSchema, Field(alias="inputSchema")] + """ + A JSON Schema object defining the expected parameters for the tool. + + Tool arguments are always JSON objects, so `type: "object"` is required at the root. + Beyond that, any JSON Schema 2020-12 keyword may appear alongside `type` — including + composition keywords (`oneOf`, `anyOf`, `allOf`, `not`), conditional keywords + (`if`/`then`/`else`), reference keywords (`$ref`, `$defs`, `$anchor`), and any other + standard validation or annotation keywords. + + Defaults to JSON Schema 2020-12 when no explicit `$schema` is provided. + """ + name: str + """ + Intended for programmatic or logical use, but used as a display name in past specs or fallback (if title isn't + present). + """ + output_schema: Annotated[OutputSchema | None, Field(alias="outputSchema")] = None + """ + An optional JSON Schema object defining the structure of the tool's output returned in + the structuredContent field of a CallToolResult. This can be any valid JSON Schema 2020-12. + + Defaults to JSON Schema 2020-12 when no explicit `$schema` is provided. + """ + title: str | None = None + """ + Intended for UI and end-user contexts — optimized to be human-readable and easily understood, + even by those unfamiliar with domain-specific terminology. + + If not provided, the name should be used for display (except for Tool, + where `annotations.title` should be given precedence over using `name`, + if present). + """ + + +class CancelledNotification(WireModel): + """This notification can be sent by either side to indicate that it is cancelling a previously-issued request. + + The request SHOULD still be in-flight, but due to communication latency, it is always possible that this + notification MAY arrive after the request has already finished. + + This notification indicates that the result will be unused, so any associated processing SHOULD cease. + """ + + jsonrpc: Literal["2.0"] + method: Literal["notifications/cancelled"] + params: CancelledNotificationParams + + +ContentBlock: TypeAlias = TextContent | ImageContent | AudioContent | ResourceLink | EmbeddedResource + + +class RequestedSchema(WireModel): + """A restricted subset of JSON Schema. + Only top-level properties are allowed, without nesting. + """ + + schema_: Annotated[str | None, Field(alias="$schema")] = None + properties: dict[str, PrimitiveSchemaDefinition] + required: list[str] | None = None + type: Literal["object"] + + +class ElicitRequestFormParams(WireModel): + """The parameters for a request to elicit non-sensitive information from the user via a form in the client.""" + + message: str + """ + The message to present to the user describing what information is being requested. + """ + mode: Literal["form"] = "form" + """ + The elicitation mode. + """ + requested_schema: Annotated[RequestedSchema, Field(alias="requestedSchema")] + """ + A restricted subset of JSON Schema. + Only top-level properties are allowed, without nesting. + """ + + +ElicitRequestParams: TypeAlias = ElicitRequestFormParams | ElicitRequestURLParams + + +JSONRPCMessage: TypeAlias = JSONRPCRequest | JSONRPCNotification | JSONRPCResultResponse | JSONRPCErrorResponse + + +JSONRPCResponse: TypeAlias = JSONRPCResultResponse | JSONRPCErrorResponse + + +class ListPromptsResult(WireModel): + """The result returned by the server for a ListPromptsRequestprompts/list request.""" + + meta: Annotated[MetaObject | None, Field(alias="_meta")] = None + cache_scope: Annotated[Literal["private", "public"], Field(alias="cacheScope")] + """ + Indicates the intended scope of the cached response, analogous to HTTP + `Cache-Control: public` vs `Cache-Control: private`. + + - `"public"`: Any client or intermediary (e.g., shared gateway, proxy) + MAY cache the response and serve it to any user. + - `"private"`: Only the requesting user's client MAY cache the response. + Shared caches (e.g., multi-tenant gateways) MUST NOT serve a cached + copy to a different user. + """ + next_cursor: Annotated[str | None, Field(alias="nextCursor")] = None + """ + An opaque token representing the pagination position after the last returned result. + If present, there may be more results available. + """ + prompts: list[Prompt] + result_type: Annotated[str, Field(alias="resultType")] + """ + Indicates the type of the result, which allows the client to determine + how to parse the result object. + + Servers implementing this protocol version MUST include this field. + For backward compatibility, when a client receives a result from a + server implementing an earlier protocol version (which does not include + `resultType`), the client MUST treat the absent field as `"complete"`. + """ + ttl_ms: Annotated[int, Field(alias="ttlMs", ge=0)] + """ + A hint from the server indicating how long (in milliseconds) the + client MAY cache this response before re-fetching. Semantics are + analogous to HTTP Cache-Control max-age. + + - If 0, The response SHOULD be considered immediately stale, + The client MAY re-fetch every time the result is needed. + - If positive, the client SHOULD consider the result fresh for this many + milliseconds after receiving the response. + """ + + +class ListPromptsResultResponse(WireModel): + """A successful response from the server for a ListPromptsRequestprompts/list request.""" + + id: RequestId + jsonrpc: Literal["2.0"] + result: ListPromptsResult + + +class ListResourceTemplatesResult(WireModel): + """The result returned by the server for a ListResourceTemplatesRequestresources/templates/list request.""" + + meta: Annotated[MetaObject | None, Field(alias="_meta")] = None + cache_scope: Annotated[Literal["private", "public"], Field(alias="cacheScope")] + """ + Indicates the intended scope of the cached response, analogous to HTTP + `Cache-Control: public` vs `Cache-Control: private`. + + - `"public"`: Any client or intermediary (e.g., shared gateway, proxy) + MAY cache the response and serve it to any user. + - `"private"`: Only the requesting user's client MAY cache the response. + Shared caches (e.g., multi-tenant gateways) MUST NOT serve a cached + copy to a different user. + """ + next_cursor: Annotated[str | None, Field(alias="nextCursor")] = None + """ + An opaque token representing the pagination position after the last returned result. + If present, there may be more results available. + """ + resource_templates: Annotated[list[ResourceTemplate], Field(alias="resourceTemplates")] + result_type: Annotated[str, Field(alias="resultType")] + """ + Indicates the type of the result, which allows the client to determine + how to parse the result object. + + Servers implementing this protocol version MUST include this field. + For backward compatibility, when a client receives a result from a + server implementing an earlier protocol version (which does not include + `resultType`), the client MUST treat the absent field as `"complete"`. + """ + ttl_ms: Annotated[int, Field(alias="ttlMs", ge=0)] + """ + A hint from the server indicating how long (in milliseconds) the + client MAY cache this response before re-fetching. Semantics are + analogous to HTTP Cache-Control max-age. + + - If 0, The response SHOULD be considered immediately stale, + The client MAY re-fetch every time the result is needed. + - If positive, the client SHOULD consider the result fresh for this many + milliseconds after receiving the response. + """ + + +class ListResourceTemplatesResultResponse(WireModel): + """A successful response from the server for a ListResourceTemplatesRequestresources/templates/list request.""" + + id: RequestId + jsonrpc: Literal["2.0"] + result: ListResourceTemplatesResult + + +class ListResourcesResult(WireModel): + """The result returned by the server for a ListResourcesRequestresources/list request.""" + + meta: Annotated[MetaObject | None, Field(alias="_meta")] = None + cache_scope: Annotated[Literal["private", "public"], Field(alias="cacheScope")] + """ + Indicates the intended scope of the cached response, analogous to HTTP + `Cache-Control: public` vs `Cache-Control: private`. + + - `"public"`: Any client or intermediary (e.g., shared gateway, proxy) + MAY cache the response and serve it to any user. + - `"private"`: Only the requesting user's client MAY cache the response. + Shared caches (e.g., multi-tenant gateways) MUST NOT serve a cached + copy to a different user. + """ + next_cursor: Annotated[str | None, Field(alias="nextCursor")] = None + """ + An opaque token representing the pagination position after the last returned result. + If present, there may be more results available. + """ + resources: list[Resource] + result_type: Annotated[str, Field(alias="resultType")] + """ + Indicates the type of the result, which allows the client to determine + how to parse the result object. + + Servers implementing this protocol version MUST include this field. + For backward compatibility, when a client receives a result from a + server implementing an earlier protocol version (which does not include + `resultType`), the client MUST treat the absent field as `"complete"`. + """ + ttl_ms: Annotated[int, Field(alias="ttlMs", ge=0)] + """ + A hint from the server indicating how long (in milliseconds) the + client MAY cache this response before re-fetching. Semantics are + analogous to HTTP Cache-Control max-age. + + - If 0, The response SHOULD be considered immediately stale, + The client MAY re-fetch every time the result is needed. + - If positive, the client SHOULD consider the result fresh for this many + milliseconds after receiving the response. + """ + + +class ListResourcesResultResponse(WireModel): + """A successful response from the server for a ListResourcesRequestresources/list request.""" + + id: RequestId + jsonrpc: Literal["2.0"] + result: ListResourcesResult + + +class ListToolsResult(WireModel): + """The result returned by the server for a ListToolsRequesttools/list request.""" + + meta: Annotated[MetaObject | None, Field(alias="_meta")] = None + cache_scope: Annotated[Literal["private", "public"], Field(alias="cacheScope")] + """ + Indicates the intended scope of the cached response, analogous to HTTP + `Cache-Control: public` vs `Cache-Control: private`. + + - `"public"`: Any client or intermediary (e.g., shared gateway, proxy) + MAY cache the response and serve it to any user. + - `"private"`: Only the requesting user's client MAY cache the response. + Shared caches (e.g., multi-tenant gateways) MUST NOT serve a cached + copy to a different user. + """ + next_cursor: Annotated[str | None, Field(alias="nextCursor")] = None + """ + An opaque token representing the pagination position after the last returned result. + If present, there may be more results available. + """ + result_type: Annotated[str, Field(alias="resultType")] + """ + Indicates the type of the result, which allows the client to determine + how to parse the result object. + + Servers implementing this protocol version MUST include this field. + For backward compatibility, when a client receives a result from a + server implementing an earlier protocol version (which does not include + `resultType`), the client MUST treat the absent field as `"complete"`. + """ + tools: list[Tool] + ttl_ms: Annotated[int, Field(alias="ttlMs", ge=0)] + """ + A hint from the server indicating how long (in milliseconds) the + client MAY cache this response before re-fetching. Semantics are + analogous to HTTP Cache-Control max-age. + + - If 0, The response SHOULD be considered immediately stale, + The client MAY re-fetch every time the result is needed. + - If positive, the client SHOULD consider the result fresh for this many + milliseconds after receiving the response. + """ + + +class ListToolsResultResponse(WireModel): + """A successful response from the server for a ListToolsRequesttools/list request.""" + + id: RequestId + jsonrpc: Literal["2.0"] + result: ListToolsResult + + +class LoggingMessageNotification(WireModel): + """JSONRPCNotification of a log message passed from server to client. The client opts in by setting + `"io.modelcontextprotocol/logLevel"` in a request's `_meta`. + """ + + jsonrpc: Literal["2.0"] + method: Literal["notifications/message"] + params: LoggingMessageNotificationParams + + +class ProgressNotification(WireModel): + """An out-of-band notification used to inform the receiver of a progress update for a long-running request.""" + + jsonrpc: Literal["2.0"] + method: Literal["notifications/progress"] + params: ProgressNotificationParams + + +class PromptMessage(WireModel): + """Describes a message returned as part of a prompt. + + This is similar to SamplingMessage, but also supports the embedding of + resources from the MCP server. + """ + + content: ContentBlock + role: Role + + +ServerNotification: TypeAlias = ( + CancelledNotification + | ProgressNotification + | ResourceListChangedNotification + | SubscriptionsAcknowledgedNotification + | ResourceUpdatedNotification + | PromptListChangedNotification + | ToolListChangedNotification + | LoggingMessageNotification + | ElicitationCompleteNotification +) + + +class ToolResultContent(WireModel): + """The result of a tool use, provided by the user back to the assistant.""" + + meta: Annotated[MetaObject | None, Field(alias="_meta")] = None + """ + Optional metadata about the tool result. Clients SHOULD preserve this field when + including tool results in subsequent sampling requests to enable caching optimizations. + """ + content: list[ContentBlock] + """ + The unstructured result content of the tool use. + + This has the same format as CallToolResult.content and can include text, images, + audio, resource links, and embedded resources. + """ + is_error: Annotated[bool | None, Field(alias="isError")] = None + """ + Whether the tool use resulted in an error. + + If true, the content typically describes the error that occurred. + Default: false + """ + structured_content: Annotated[Any | None, Field(alias="structuredContent")] = None + """ + An optional structured result value. + + This can be any JSON value (object, array, string, number, boolean, or null). + If the tool defined an Tool.outputSchema, this SHOULD conform to that schema. + """ + tool_use_id: Annotated[str, Field(alias="toolUseId")] + """ + The ID of the tool use this result corresponds to. + + This MUST match the ID from a previous ToolUseContent. + """ + type: Literal["tool_result"] + + +class CallToolResult(WireModel): + """The result returned by the server for a CallToolRequesttools/call request.""" + + meta: Annotated[MetaObject | None, Field(alias="_meta")] = None + content: list[ContentBlock] + """ + A list of content objects that represent the unstructured result of the tool call. + """ + is_error: Annotated[bool | None, Field(alias="isError")] = None + """ + Whether the tool call ended in an error. + + If not set, this is assumed to be false (the call was successful). + + Any errors that originate from the tool SHOULD be reported inside the result + object, with `isError` set to true, _not_ as an MCP protocol-level error + response. Otherwise, the LLM would not be able to see that an error occurred + and self-correct. + + However, any errors in _finding_ the tool, an error indicating that the + server does not support tool calls, or any other exceptional conditions, + should be reported as an MCP error response. + """ + result_type: Annotated[str, Field(alias="resultType")] + """ + Indicates the type of the result, which allows the client to determine + how to parse the result object. + + Servers implementing this protocol version MUST include this field. + For backward compatibility, when a client receives a result from a + server implementing an earlier protocol version (which does not include + `resultType`), the client MUST treat the absent field as `"complete"`. + """ + structured_content: Annotated[Any | None, Field(alias="structuredContent")] = None + """ + An optional JSON value that represents the structured result of the tool call. + + This can be any JSON value (object, array, string, number, boolean, or null) + that conforms to the tool's outputSchema if one is defined. + """ + + +ClientNotification: TypeAlias = CancelledNotification | ProgressNotification + + +class ElicitRequest(WireModel): + """A request from the server to elicit additional information from the user via the client.""" + + method: Literal["elicitation/create"] + params: ElicitRequestParams + + +class GetPromptResult(WireModel): + """The result returned by the server for a GetPromptRequestprompts/get request.""" + + meta: Annotated[MetaObject | None, Field(alias="_meta")] = None + description: str | None = None + """ + An optional description for the prompt. + """ + messages: list[PromptMessage] + result_type: Annotated[str, Field(alias="resultType")] + """ + Indicates the type of the result, which allows the client to determine + how to parse the result object. + + Servers implementing this protocol version MUST include this field. + For backward compatibility, when a client receives a result from a + server implementing an earlier protocol version (which does not include + `resultType`), the client MUST treat the absent field as `"complete"`. + """ + + +SamplingMessageContentBlock: TypeAlias = TextContent | ImageContent | AudioContent | ToolUseContent | ToolResultContent + + +class CreateMessageResult(WireModel): + """The result returned by the client for a CreateMessageRequestsampling/createMessage request. + The client should inform the user before returning the sampled message, to allow them + to inspect the response (human in the loop) and decide whether to allow the server to see it. + """ + + meta: Annotated[MetaObject | None, Field(alias="_meta")] = None + content: ( + TextContent + | ImageContent + | AudioContent + | ToolUseContent + | ToolResultContent + | list[SamplingMessageContentBlock] + ) + model: str + """ + The name of the model that generated the message. + """ + role: Role + stop_reason: Annotated[str | None, Field(alias="stopReason")] = None + """ + The reason why sampling stopped, if known. + + Standard values: + - `"endTurn"`: Natural end of the assistant's turn + - `"stopSequence"`: A stop sequence was encountered + - `"maxTokens"`: Maximum token limit was reached + - `"toolUse"`: The model wants to use one or more tools + + This field is an open string to allow for provider-specific stop reasons. + """ + + +InputResponse: TypeAlias = CreateMessageResult | ListRootsResult | ElicitResult + + +InputResponses: TypeAlias = dict[str, InputResponse] +"""A map of client responses to server-initiated requests. +Keys correspond to the keys in the InputRequests map; +values are the client's result for each request.""" + + +class SamplingMessage(WireModel): + """Describes a message issued to or received from an LLM API.""" + + meta: Annotated[MetaObject | None, Field(alias="_meta")] = None + content: ( + TextContent + | ImageContent + | AudioContent + | ToolUseContent + | ToolResultContent + | list[SamplingMessageContentBlock] + ) + role: Role + + +class CallToolRequest(WireModel): + """Used by the client to invoke a tool provided by the server.""" + + id: RequestId + jsonrpc: Literal["2.0"] + method: Literal["tools/call"] + params: CallToolRequestParams + + +class CallToolRequestParams(WireModel): + """Parameters for a `tools/call` request.""" + + meta: Annotated[RequestMetaObject, Field(alias="_meta")] + arguments: dict[str, Any] | None = None + """ + Arguments to use for the tool call. + """ + input_responses: Annotated[InputResponses | None, Field(alias="inputResponses")] = None + name: str + """ + The name of the tool. + """ + request_state: Annotated[str | None, Field(alias="requestState")] = None + + +class CallToolResultResponse(WireModel): + """A successful response from the server for a CallToolRequesttools/call request.""" + + id: RequestId + jsonrpc: Literal["2.0"] + result: InputRequiredResult | CallToolResult + + +class Elicitation(WireModel): + """Present if the client supports elicitation from the server.""" + + form: JSONObject | None = None + url: JSONObject | None = None + + +class Sampling(WireModel): + """Present if the client supports sampling from an LLM.""" + + context: JSONObject | None = None + """ + Whether the client supports context inclusion via `includeContext` parameter. + If not declared, servers SHOULD only use `includeContext: "none"` (or omit it). + """ + tools: JSONObject | None = None + """ + Whether the client supports tool use via `tools` and `toolChoice` parameters. + """ + + +class ClientCapabilities(WireModel): + """Capabilities a client may support. Known capabilities are defined here, in this schema, but this is not a + closed set: any client can define its own, additional capabilities. + """ + + elicitation: Elicitation | None = None + """ + Present if the client supports elicitation from the server. + """ + experimental: dict[str, JSONObject] | None = None + """ + Experimental, non-standard capabilities that the client supports. + """ + extensions: dict[str, JSONObject] | None = None + """ + Optional MCP extensions that the client supports. Keys are extension identifiers + (e.g., "io.modelcontextprotocol/oauth-client-credentials"), and values are + per-extension settings objects. An empty object indicates support with no settings. + """ + roots: dict[str, Any] | None = None + """ + Present if the client supports listing roots. + """ + sampling: Sampling | None = None + """ + Present if the client supports sampling from an LLM. + """ + + +class CompleteRequest(WireModel): + """A request from the client to the server, to ask for completion options.""" + + id: RequestId + jsonrpc: Literal["2.0"] + method: Literal["completion/complete"] + params: CompleteRequestParams + + +class CompleteRequestParams(WireModel): + """Parameters for a `completion/complete` request.""" + + meta: Annotated[RequestMetaObject, Field(alias="_meta")] + argument: Argument + """ + The argument's information + """ + context: Context | None = None + """ + Additional, optional context for completions + """ + ref: PromptReference | ResourceTemplateReference + + +class CreateMessageRequest(WireModel): + """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. + """ + + method: Literal["sampling/createMessage"] + params: CreateMessageRequestParams + + +class CreateMessageRequestParams(WireModel): + """Parameters for a `sampling/createMessage` request.""" + + include_context: Annotated[ + Literal["allServers", "none", "thisServer"] | None, + Field(alias="includeContext"), + ] = None + """ + A request to include context from one or more MCP servers (including the caller), to be attached to the prompt. + The client MAY ignore this request. + + Default is `"none"`. The values `"thisServer"` and `"allServers"` are deprecated (SEP-2596): servers SHOULD + omit this field or use `"none"`, and SHOULD only use the deprecated values if the client declares + ClientCapabilities.sampling.context. + """ + max_tokens: Annotated[int, Field(alias="maxTokens")] + """ + The requested maximum number of tokens to sample (to prevent runaway completions). + + The client MAY choose to sample fewer tokens than the requested maximum. + """ + messages: list[SamplingMessage] + metadata: JSONObject | None = None + """ + Optional metadata to pass through to the LLM provider. The format of this metadata is provider-specific. + """ + model_preferences: Annotated[ModelPreferences | None, Field(alias="modelPreferences")] = None + """ + The server's preferences for which model to select. The client MAY ignore these preferences. + """ + stop_sequences: Annotated[list[str] | None, Field(alias="stopSequences")] = None + system_prompt: Annotated[str | None, Field(alias="systemPrompt")] = None + """ + An optional system prompt the server wants to use for sampling. The client MAY modify or omit this prompt. + """ + temperature: float | None = None + tool_choice: Annotated[ToolChoice | None, Field(alias="toolChoice")] = None + """ + Controls how the model uses tools. + The client MUST return an error if this field is provided but ClientCapabilities.sampling.tools is not declared. + Default is `{ mode: "auto" }`. + """ + tools: list[Tool] | None = None + """ + Tools that the model may use during generation. + The client MUST return an error if this field is provided but ClientCapabilities.sampling.tools is not declared. + """ + + +class DiscoverRequest(WireModel): + """A request from the client asking the server to advertise its supported + protocol versions, capabilities, and other metadata. Servers **MUST** + implement `server/discover`. Clients **MAY** call it but are not required + to — version negotiation can also happen inline via per-request `_meta`. + """ + + id: RequestId + jsonrpc: Literal["2.0"] + method: Literal["server/discover"] + params: RequestParams + + +class DiscoverResult(WireModel): + """The result returned by the server for a DiscoverRequestserver/discover request.""" + + meta: Annotated[MetaObject | None, Field(alias="_meta")] = None + cache_scope: Annotated[Literal["private", "public"], Field(alias="cacheScope")] + """ + Indicates the intended scope of the cached response, analogous to HTTP + `Cache-Control: public` vs `Cache-Control: private`. + + - `"public"`: Any client or intermediary (e.g., shared gateway, proxy) + MAY cache the response and serve it to any user. + - `"private"`: Only the requesting user's client MAY cache the response. + Shared caches (e.g., multi-tenant gateways) MUST NOT serve a cached + copy to a different user. + """ + capabilities: ServerCapabilities + """ + The capabilities of the server. + """ + instructions: str | None = None + """ + Natural-language guidance describing the server and its features. + + This can be used by clients to improve an LLM's understanding of + available tools (e.g., by including it in a system prompt). It should + focus on information that helps the model use the server effectively + and should not duplicate information already in tool descriptions. + """ + result_type: Annotated[str, Field(alias="resultType")] + """ + Indicates the type of the result, which allows the client to determine + how to parse the result object. + + Servers implementing this protocol version MUST include this field. + For backward compatibility, when a client receives a result from a + server implementing an earlier protocol version (which does not include + `resultType`), the client MUST treat the absent field as `"complete"`. + """ + server_info: Annotated[Implementation, Field(alias="serverInfo")] + """ + Information about the server software implementation. + """ + supported_versions: Annotated[list[str], Field(alias="supportedVersions")] + """ + MCP Protocol Versions this server supports. The client should choose a + version from this list for use in subsequent requests. + """ + ttl_ms: Annotated[int, Field(alias="ttlMs", ge=0)] + """ + A hint from the server indicating how long (in milliseconds) the + client MAY cache this response before re-fetching. Semantics are + analogous to HTTP Cache-Control max-age. + + - If 0, The response SHOULD be considered immediately stale, + The client MAY re-fetch every time the result is needed. + - If positive, the client SHOULD consider the result fresh for this many + milliseconds after receiving the response. + """ + + +class DiscoverResultResponse(WireModel): + """A successful response from the server for a DiscoverRequestserver/discover request.""" + + id: RequestId + jsonrpc: Literal["2.0"] + result: DiscoverResult + + +class GetPromptRequest(WireModel): + """Used by the client to get a prompt provided by the server.""" + + id: RequestId + jsonrpc: Literal["2.0"] + method: Literal["prompts/get"] + params: GetPromptRequestParams + + +class GetPromptRequestParams(WireModel): + """Parameters for a `prompts/get` request.""" + + meta: Annotated[RequestMetaObject, Field(alias="_meta")] + arguments: dict[str, str] | None = None + """ + Arguments to use for templating the prompt. + """ + input_responses: Annotated[InputResponses | None, Field(alias="inputResponses")] = None + name: str + """ + The name of the prompt or prompt template. + """ + request_state: Annotated[str | None, Field(alias="requestState")] = None + + +class GetPromptResultResponse(WireModel): + """A successful response from the server for a GetPromptRequestprompts/get request.""" + + id: RequestId + jsonrpc: Literal["2.0"] + result: InputRequiredResult | GetPromptResult + + +class InputRequiredResult(WireModel): + """An InputRequiredResult sent by the server to indicate that additional input is needed + before the request can be completed. + + At least one of `inputRequests` or `requestState` MUST be present. + """ + + meta: Annotated[MetaObject | None, Field(alias="_meta")] = None + input_requests: Annotated[InputRequests | None, Field(alias="inputRequests")] = None + request_state: Annotated[str | None, Field(alias="requestState")] = None + result_type: Annotated[str, Field(alias="resultType")] + """ + Indicates the type of the result, which allows the client to determine + how to parse the result object. + + Servers implementing this protocol version MUST include this field. + For backward compatibility, when a client receives a result from a + server implementing an earlier protocol version (which does not include + `resultType`), the client MUST treat the absent field as `"complete"`. + """ + + +class InputResponseRequestParams(WireModel): + meta: Annotated[RequestMetaObject, Field(alias="_meta")] + input_responses: Annotated[InputResponses | None, Field(alias="inputResponses")] = None + request_state: Annotated[str | None, Field(alias="requestState")] = None + + +class ListPromptsRequest(WireModel): + """Sent from the client to request a list of prompts and prompt templates the server has.""" + + id: RequestId + jsonrpc: Literal["2.0"] + method: Literal["prompts/list"] + params: PaginatedRequestParams + + +class ListResourceTemplatesRequest(WireModel): + """Sent from the client to request a list of resource templates the server has.""" + + id: RequestId + jsonrpc: Literal["2.0"] + method: Literal["resources/templates/list"] + params: PaginatedRequestParams + + +class ListResourcesRequest(WireModel): + """Sent from the client to request a list of resources the server has.""" + + id: RequestId + jsonrpc: Literal["2.0"] + method: Literal["resources/list"] + params: PaginatedRequestParams + + +class ListRootsRequest(WireModel): + """Sent from the server to request a list of root URIs from the client. Roots allow + servers to ask for specific directories or files to operate on. A common example + for roots is providing a set of repositories or directories a server should operate + on. + + This request is typically used when the server needs to understand the file system + structure or access specific locations that the client has permission to read from. + """ + + method: Literal["roots/list"] + params: RequestParams | None = None + + +class ListToolsRequest(WireModel): + """Sent from the client to request a list of tools the server has.""" + + id: RequestId + jsonrpc: Literal["2.0"] + method: Literal["tools/list"] + params: PaginatedRequestParams + + +class Data(WireModel): + """Additional information about the error. The value of this member is defined by the sender (e.g. detailed error + information, nested errors etc.). + """ + + required_capabilities: Annotated[ClientCapabilities, Field(alias="requiredCapabilities")] + """ + The capabilities the server requires from the client to process this request. + """ + + +class Error1(WireModel): + code: Literal[-32003] + """ + The error type that occurred. + """ + data: Data + """ + Additional information about the error. The value of this member is defined by the sender (e.g. detailed error + information, nested errors etc.). + """ + message: str + """ + A short description of the error. The message SHOULD be limited to a concise single sentence. + """ + + +class MissingRequiredClientCapabilityError(WireModel): + """Returned when processing a request requires a capability the client did not + declare in `clientCapabilities`. For HTTP, the response status code MUST be + `400 Bad Request`. + """ + + error: Error1 + id: RequestId | None = None + jsonrpc: Literal["2.0"] + + +class PaginatedRequest(WireModel): + id: RequestId + jsonrpc: Literal["2.0"] + method: str + params: PaginatedRequestParams + + +class PaginatedRequestParams(WireModel): + """Common params for paginated requests.""" + + meta: Annotated[RequestMetaObject, Field(alias="_meta")] + cursor: str | None = None + """ + An opaque token representing the current pagination position. + If provided, the server should return results starting after this cursor. + """ + + +class ReadResourceRequest(WireModel): + """Sent from the client to the server, to read a specific resource URI.""" + + id: RequestId + jsonrpc: Literal["2.0"] + method: Literal["resources/read"] + params: ReadResourceRequestParams + + +class ReadResourceRequestParams(WireModel): + """Parameters for a `resources/read` request.""" + + meta: Annotated[RequestMetaObject, Field(alias="_meta")] + input_responses: Annotated[InputResponses | None, Field(alias="inputResponses")] = None + request_state: Annotated[str | None, Field(alias="requestState")] = None + uri: str + """ + The URI of the resource. The URI can use any protocol; it is up to the server how to interpret it. + """ + + +class ReadResourceResultResponse(WireModel): + """A successful response from the server for a ReadResourceRequestresources/read request.""" + + id: RequestId + jsonrpc: Literal["2.0"] + result: InputRequiredResult | ReadResourceResult + + +class RequestMetaObject(OpenWireModel): + """Extends MetaObject with additional request-specific fields. All key naming rules from `MetaObject` apply.""" + + io_modelcontextprotocol_client_capabilities: Annotated[ + ClientCapabilities, Field(alias="io.modelcontextprotocol/clientCapabilities") + ] + """ + The client's capabilities for this specific request. Required. + + Capabilities are declared per-request rather than once at initialization; + an empty object means the client supports no optional capabilities. + Servers MUST NOT infer capabilities from prior requests. + """ + io_modelcontextprotocol_client_info: Annotated[Implementation, Field(alias="io.modelcontextprotocol/clientInfo")] + """ + Identifies the client software making the request. Required. + + The Implementation schema requires `name` and `version`; other + fields are optional. + """ + io_modelcontextprotocol_log_level: Annotated[ + LoggingLevel | None, Field(alias="io.modelcontextprotocol/logLevel") + ] = None + """ + The desired log level for this request. Optional. + + If absent, the server MUST NOT send any LoggingMessageNotificationnotifications/message + notifications for this request. The client opts in to log messages by + explicitly setting a level. Replaces the former `logging/setLevel` RPC. + """ + io_modelcontextprotocol_protocol_version: Annotated[str, Field(alias="io.modelcontextprotocol/protocolVersion")] + """ + The MCP Protocol Version being used for this request. Required. + + For the HTTP transport, this value MUST match the `MCP-Protocol-Version` + header; otherwise the server MUST return a `400 Bad Request`. If the + server does not support the requested version, it MUST return an + UnsupportedProtocolVersionError. + """ + progress_token: Annotated[ProgressToken | None, Field(alias="progressToken")] = None + """ + If specified, the caller is requesting out-of-band progress notifications for this request (as represented by + ProgressNotificationnotifications/progress). The value of this parameter is an opaque token that will be attached to + any subsequent notifications. The receiver is not obligated to provide these notifications. + """ + + +class RequestParams(WireModel): + """Common params for any request.""" + + meta: Annotated[RequestMetaObject, Field(alias="_meta")] + + +class ResourceRequestParams(WireModel): + """Common params for resource-related requests.""" + + meta: Annotated[RequestMetaObject, Field(alias="_meta")] + uri: str + """ + The URI of the resource. The URI can use any protocol; it is up to the server how to interpret it. + """ + + +class ServerCapabilities(WireModel): + """Capabilities that a server may support. Known capabilities are defined here, in this schema, but this is not a + closed set: any server can define its own, additional capabilities. + """ + + completions: JSONObject | None = None + """ + Present if the server supports argument autocompletion suggestions. + """ + experimental: dict[str, JSONObject] | None = None + """ + Experimental, non-standard capabilities that the server supports. + """ + extensions: dict[str, JSONObject] | None = None + """ + Optional MCP extensions that the server supports. Keys are extension identifiers + (e.g., "io.modelcontextprotocol/tasks"), and values are per-extension settings + objects. An empty object indicates support with no settings. + """ + logging: JSONObject | None = None + """ + Present if the server supports sending log messages to the client. + """ + prompts: Prompts | None = None + """ + Present if the server offers any prompt templates. + """ + resources: Resources | None = None + """ + Present if the server offers any resources to read. + """ + tools: Tools | None = None + """ + Present if the server offers any tools to call. + """ + + +class SubscriptionsListenRequest(WireModel): + """Sent from the client to open a long-lived channel for receiving notifications + outside the context of a specific request. Replaces the previous HTTP GET + endpoint and ensures consistent behavior between HTTP and STDIO. + """ + + id: RequestId + jsonrpc: Literal["2.0"] + method: Literal["subscriptions/listen"] + params: SubscriptionsListenRequestParams + + +class SubscriptionsListenRequestParams(WireModel): + """Parameters for a SubscriptionsListenRequestsubscriptions/listen request.""" + + meta: Annotated[RequestMetaObject, Field(alias="_meta")] + notifications: SubscriptionFilter + """ + The notifications the client opts in to on this stream. The server + **MUST NOT** send notification types the client has not explicitly + requested. + """ + + +ServerResult: TypeAlias = ( + Result + | InputRequiredResult + | DiscoverResult + | ListResourcesResult + | ListResourceTemplatesResult + | ReadResourceResult + | ListPromptsResult + | GetPromptResult + | ListToolsResult + | CallToolResult + | CompleteResult +) + + +InputRequest: TypeAlias = CreateMessageRequest | ListRootsRequest | ElicitRequest + + +ClientRequest: TypeAlias = ( + DiscoverRequest + | ListResourcesRequest + | ListResourceTemplatesRequest + | ReadResourceRequest + | SubscriptionsListenRequest + | ListPromptsRequest + | GetPromptRequest + | ListToolsRequest + | CallToolRequest + | CompleteRequest +) + + +InputRequests: TypeAlias = dict[str, InputRequest] +"""A map of server-initiated requests that the client must fulfill. +Keys are server-assigned identifiers; values are the request objects.""" + + +JSONArray: TypeAlias = list["JSONValue"] + + +AnyCallToolResult: TypeAlias = CallToolResult | InputRequiredResult +"""Named alias for `CallToolResultResponse.result` so the wire-method maps can reference it as a value.""" + +AnyGetPromptResult: TypeAlias = GetPromptResult | InputRequiredResult +"""Everything a `prompts/get` response's `result` may be at this version.""" + +AnyReadResourceResult: TypeAlias = ReadResourceResult | InputRequiredResult +"""Everything a `resources/read` response's `result` may be at this version.""" + + +CallToolRequest.model_rebuild() +CallToolRequestParams.model_rebuild() +CallToolResultResponse.model_rebuild() +Elicitation.model_rebuild() +Sampling.model_rebuild() +ClientCapabilities.model_rebuild() +CompleteRequest.model_rebuild() +CompleteRequestParams.model_rebuild() +CreateMessageRequest.model_rebuild() +CreateMessageRequestParams.model_rebuild() +DiscoverRequest.model_rebuild() +DiscoverResult.model_rebuild() +GetPromptRequest.model_rebuild() +GetPromptRequestParams.model_rebuild() +GetPromptResultResponse.model_rebuild() +InputRequiredResult.model_rebuild() +InputResponseRequestParams.model_rebuild() +ListPromptsRequest.model_rebuild() +ListResourceTemplatesRequest.model_rebuild() +ListResourcesRequest.model_rebuild() +ListRootsRequest.model_rebuild() +ListToolsRequest.model_rebuild() +PaginatedRequest.model_rebuild() +PaginatedRequestParams.model_rebuild() +ReadResourceRequest.model_rebuild() +ReadResourceRequestParams.model_rebuild() +ServerCapabilities.model_rebuild() +SubscriptionsListenRequest.model_rebuild() diff --git a/tests/interaction/lowlevel/test_resources.py b/tests/interaction/lowlevel/test_resources.py index e42b69d7ec..a5a4bdc14d 100644 --- a/tests/interaction/lowlevel/test_resources.py +++ b/tests/interaction/lowlevel/test_resources.py @@ -81,7 +81,9 @@ async def list_resources( description="The project's front page.", mime_type="text/markdown", size=1024, - annotations=Annotations(audience=["user", "assistant"], priority=0.8), + annotations=Annotations( + audience=["user", "assistant"], priority=0.8, last_modified="2025-01-01T00:00:00Z" + ), icons=[Icon(src="https://example.com/readme.png", mime_type="image/png", sizes=["48x48"])], ), ] diff --git a/tests/interaction/transports/test_hosting_resume.py b/tests/interaction/transports/test_hosting_resume.py index c7945d56c3..b835c78024 100644 --- a/tests/interaction/transports/test_hosting_resume.py +++ b/tests/interaction/transports/test_hosting_resume.py @@ -108,6 +108,7 @@ async def test_a_post_sse_stream_begins_with_a_priming_event_and_stamps_every_ev "content": [{"type": "text", "text": "counted to 2"}], "structuredContent": {"result": "counted to 2"}, "isError": False, + "resultType": "complete", }, ) ) diff --git a/tests/server/test_session.py b/tests/server/test_session.py index 86ec507574..44aab6b33b 100644 --- a/tests/server/test_session.py +++ b/tests/server/test_session.py @@ -219,6 +219,6 @@ async def test_protocol_version_is_none_on_stateless_connection(): seen: list[str | None] = [] async with connected_runner(_runner_server(seen), initialized=False, stateless=True) as (client, runner): result = await client.send_raw_request("tools/list", None) - assert result == {"tools": []} + assert result == {"tools": [], "resultType": "complete", "ttlMs": 0, "cacheScope": "private"} assert seen == [None] assert runner.session.protocol_version is None diff --git a/tests/test_types.py b/tests/test_types.py index f424efdbf7..d604ef1bba 100644 --- a/tests/test_types.py +++ b/tests/test_types.py @@ -1,20 +1,34 @@ from typing import Any import pytest +from inline_snapshot import snapshot from mcp.types import ( LATEST_PROTOCOL_VERSION, + CallToolResult, ClientCapabilities, + CompleteResult, + Completion, CreateMessageRequestParams, CreateMessageResult, CreateMessageResultWithTools, + DiscoverResult, + EmptyResult, + GetPromptResult, Implementation, InitializeRequest, InitializeRequestParams, + InputRequiredResult, JSONRPCRequest, + ListPromptsResult, + ListResourcesResult, + ListResourceTemplatesResult, ListToolsResult, + ReadResourceResult, + Result, SamplingCapability, SamplingMessage, + ServerCapabilities, TextContent, Tool, ToolChoice, @@ -360,3 +374,61 @@ def test_list_tools_result_preserves_json_schema_2020_12_fields(): assert tool.input_schema["$schema"] == "https://json-schema.org/draft/2020-12/schema" assert "$defs" in tool.input_schema assert tool.input_schema["additionalProperties"] is False + + +def _wire_dump(result: Result) -> dict[str, Any]: + return result.model_dump(by_alias=True, mode="json", exclude_none=True) + + +def test_concrete_wire_results_always_dump_result_type_complete(): + """Required by 2026-07-28; older peers tolerate the extra key.""" + carriers: list[Result] = [ + CompleteResult(completion=Completion(values=[])), + GetPromptResult(messages=[]), + CallToolResult(content=[]), + ReadResourceResult(contents=[]), + ListPromptsResult(prompts=[]), + ListResourcesResult(resources=[]), + ListResourceTemplatesResult(resource_templates=[]), + ListToolsResult(tools=[]), + DiscoverResult( + supported_versions=["2026-07-28"], + capabilities=ServerCapabilities(), + server_info=Implementation(name="server", version="1.0"), + ), + ] + for result in carriers: + assert _wire_dump(result)["resultType"] == "complete", type(result).__name__ + + +def test_cacheable_results_always_dump_their_caching_directives(): + """Required by 2026-07-28; older peers tolerate the extra keys.""" + cacheable: list[Result] = [ + ReadResourceResult(contents=[]), + ListPromptsResult(prompts=[]), + ListResourceTemplatesResult(resource_templates=[]), + ListResourcesResult(resources=[]), + ListToolsResult(tools=[]), + DiscoverResult( + supported_versions=["2026-07-28"], + capabilities=ServerCapabilities(), + server_info=Implementation(name="server", version="1.0"), + ), + ] + for result in cacheable: + dumped = _wire_dump(result) + assert dumped["ttlMs"] == 0, type(result).__name__ + assert dumped["cacheScope"] == "private", type(result).__name__ + + +def test_empty_result_dumps_no_fields_by_default(): + """Deployed peers reject extra keys on empty results, so resultType is never volunteered.""" + assert _wire_dump(EmptyResult()) == snapshot({}) + + +def test_empty_result_dumps_result_type_only_when_explicitly_tagged(): + assert _wire_dump(EmptyResult(result_type="complete")) == snapshot({"resultType": "complete"}) + + +def test_input_required_result_dumps_its_discriminating_tag(): + assert _wire_dump(InputRequiredResult()) == snapshot({"resultType": "input_required"}) diff --git a/tests/types/__init__.py b/tests/types/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/types/test_methods.py b/tests/types/test_methods.py new file mode 100644 index 0000000000..423bafaf47 --- /dev/null +++ b/tests/types/test_methods.py @@ -0,0 +1,742 @@ +"""Tests for the wire-method maps and two-step parse functions in `mcp.types.methods`.""" + +import importlib.util +from collections.abc import Mapping +from types import MappingProxyType, UnionType +from typing import Any, get_args + +import pydantic +import pytest + +import mcp.types as types +import mcp.types.v2025_11_25 as v2025 +import mcp.types.v2026_07_28 as v2026 +from mcp.shared.version import KNOWN_PROTOCOL_VERSIONS +from mcp.types import methods +from mcp.types._wire_base import WireModel + +# Transcribed from each schema's ClientRequest/ServerRequest/ClientNotification/ +# ServerNotification unions, minus the tasks/* family (extensions register those). +EXPECTED_METHODS: dict[str, dict[str, frozenset[str]]] = { + "2024-11-05": { + "CLIENT_REQUESTS": frozenset( + { + "completion/complete", + "initialize", + "logging/setLevel", + "ping", + "prompts/get", + "prompts/list", + "resources/list", + "resources/read", + "resources/subscribe", + "resources/templates/list", + "resources/unsubscribe", + "tools/call", + "tools/list", + } + ), + "CLIENT_NOTIFICATIONS": frozenset( + { + "notifications/cancelled", + "notifications/initialized", + "notifications/progress", + "notifications/roots/list_changed", + } + ), + "SERVER_REQUESTS": frozenset({"ping", "roots/list", "sampling/createMessage"}), + "SERVER_NOTIFICATIONS": frozenset( + { + "notifications/cancelled", + "notifications/message", + "notifications/progress", + "notifications/prompts/list_changed", + "notifications/resources/list_changed", + "notifications/resources/updated", + "notifications/tools/list_changed", + } + ), + }, + "2025-03-26": { + "CLIENT_REQUESTS": frozenset( + { + "completion/complete", + "initialize", + "logging/setLevel", + "ping", + "prompts/get", + "prompts/list", + "resources/list", + "resources/read", + "resources/subscribe", + "resources/templates/list", + "resources/unsubscribe", + "tools/call", + "tools/list", + } + ), + "CLIENT_NOTIFICATIONS": frozenset( + { + "notifications/cancelled", + "notifications/initialized", + "notifications/progress", + "notifications/roots/list_changed", + } + ), + "SERVER_REQUESTS": frozenset({"ping", "roots/list", "sampling/createMessage"}), + "SERVER_NOTIFICATIONS": frozenset( + { + "notifications/cancelled", + "notifications/message", + "notifications/progress", + "notifications/prompts/list_changed", + "notifications/resources/list_changed", + "notifications/resources/updated", + "notifications/tools/list_changed", + } + ), + }, + "2025-06-18": { + "CLIENT_REQUESTS": frozenset( + { + "completion/complete", + "initialize", + "logging/setLevel", + "ping", + "prompts/get", + "prompts/list", + "resources/list", + "resources/read", + "resources/subscribe", + "resources/templates/list", + "resources/unsubscribe", + "tools/call", + "tools/list", + } + ), + "CLIENT_NOTIFICATIONS": frozenset( + { + "notifications/cancelled", + "notifications/initialized", + "notifications/progress", + "notifications/roots/list_changed", + } + ), + "SERVER_REQUESTS": frozenset({"elicitation/create", "ping", "roots/list", "sampling/createMessage"}), + "SERVER_NOTIFICATIONS": frozenset( + { + "notifications/cancelled", + "notifications/message", + "notifications/progress", + "notifications/prompts/list_changed", + "notifications/resources/list_changed", + "notifications/resources/updated", + "notifications/tools/list_changed", + } + ), + }, + "2025-11-25": { + "CLIENT_REQUESTS": frozenset( + { + "completion/complete", + "initialize", + "logging/setLevel", + "ping", + "prompts/get", + "prompts/list", + "resources/list", + "resources/read", + "resources/subscribe", + "resources/templates/list", + "resources/unsubscribe", + "tools/call", + "tools/list", + } + ), + "CLIENT_NOTIFICATIONS": frozenset( + { + "notifications/cancelled", + "notifications/initialized", + "notifications/progress", + "notifications/roots/list_changed", + } + ), + "SERVER_REQUESTS": frozenset({"elicitation/create", "ping", "roots/list", "sampling/createMessage"}), + "SERVER_NOTIFICATIONS": frozenset( + { + "notifications/cancelled", + "notifications/elicitation/complete", + "notifications/message", + "notifications/progress", + "notifications/prompts/list_changed", + "notifications/resources/list_changed", + "notifications/resources/updated", + "notifications/tools/list_changed", + } + ), + }, + "2026-07-28": { + "CLIENT_REQUESTS": frozenset( + { + "completion/complete", + "prompts/get", + "prompts/list", + "resources/list", + "resources/read", + "resources/templates/list", + "server/discover", + "subscriptions/listen", + "tools/call", + "tools/list", + } + ), + "CLIENT_NOTIFICATIONS": frozenset({"notifications/cancelled", "notifications/progress"}), + # No standalone server-to-client request channel at this version. + "SERVER_REQUESTS": frozenset(), + "SERVER_NOTIFICATIONS": frozenset( + { + "notifications/cancelled", + "notifications/elicitation/complete", + "notifications/message", + "notifications/progress", + "notifications/prompts/list_changed", + "notifications/resources/list_changed", + "notifications/resources/updated", + "notifications/subscriptions/acknowledged", + "notifications/tools/list_changed", + } + ), + }, +} + +# Pinned per (method, version): class identity, or exact arm tuple for unions. +EXPECTED_SERVER_RESULTS: dict[tuple[str, str], type[WireModel] | tuple[type[WireModel], ...]] = { + ("completion/complete", "2024-11-05"): v2025.CompleteResult, + ("initialize", "2024-11-05"): v2025.InitializeResult, + ("logging/setLevel", "2024-11-05"): v2025.EmptyResult, + ("ping", "2024-11-05"): v2025.EmptyResult, + ("prompts/get", "2024-11-05"): v2025.GetPromptResult, + ("prompts/list", "2024-11-05"): v2025.ListPromptsResult, + ("resources/list", "2024-11-05"): v2025.ListResourcesResult, + ("resources/read", "2024-11-05"): v2025.ReadResourceResult, + ("resources/subscribe", "2024-11-05"): v2025.EmptyResult, + ("resources/templates/list", "2024-11-05"): v2025.ListResourceTemplatesResult, + ("resources/unsubscribe", "2024-11-05"): v2025.EmptyResult, + ("tools/call", "2024-11-05"): v2025.CallToolResult, + ("tools/list", "2024-11-05"): v2025.ListToolsResult, + ("completion/complete", "2025-03-26"): v2025.CompleteResult, + ("initialize", "2025-03-26"): v2025.InitializeResult, + ("logging/setLevel", "2025-03-26"): v2025.EmptyResult, + ("ping", "2025-03-26"): v2025.EmptyResult, + ("prompts/get", "2025-03-26"): v2025.GetPromptResult, + ("prompts/list", "2025-03-26"): v2025.ListPromptsResult, + ("resources/list", "2025-03-26"): v2025.ListResourcesResult, + ("resources/read", "2025-03-26"): v2025.ReadResourceResult, + ("resources/subscribe", "2025-03-26"): v2025.EmptyResult, + ("resources/templates/list", "2025-03-26"): v2025.ListResourceTemplatesResult, + ("resources/unsubscribe", "2025-03-26"): v2025.EmptyResult, + ("tools/call", "2025-03-26"): v2025.CallToolResult, + ("tools/list", "2025-03-26"): v2025.ListToolsResult, + ("completion/complete", "2025-06-18"): v2025.CompleteResult, + ("initialize", "2025-06-18"): v2025.InitializeResult, + ("logging/setLevel", "2025-06-18"): v2025.EmptyResult, + ("ping", "2025-06-18"): v2025.EmptyResult, + ("prompts/get", "2025-06-18"): v2025.GetPromptResult, + ("prompts/list", "2025-06-18"): v2025.ListPromptsResult, + ("resources/list", "2025-06-18"): v2025.ListResourcesResult, + ("resources/read", "2025-06-18"): v2025.ReadResourceResult, + ("resources/subscribe", "2025-06-18"): v2025.EmptyResult, + ("resources/templates/list", "2025-06-18"): v2025.ListResourceTemplatesResult, + ("resources/unsubscribe", "2025-06-18"): v2025.EmptyResult, + ("tools/call", "2025-06-18"): v2025.CallToolResult, + ("tools/list", "2025-06-18"): v2025.ListToolsResult, + ("completion/complete", "2025-11-25"): v2025.CompleteResult, + ("initialize", "2025-11-25"): v2025.InitializeResult, + ("logging/setLevel", "2025-11-25"): v2025.EmptyResult, + ("ping", "2025-11-25"): v2025.EmptyResult, + ("prompts/get", "2025-11-25"): v2025.GetPromptResult, + ("prompts/list", "2025-11-25"): v2025.ListPromptsResult, + ("resources/list", "2025-11-25"): v2025.ListResourcesResult, + ("resources/read", "2025-11-25"): v2025.ReadResourceResult, + ("resources/subscribe", "2025-11-25"): v2025.EmptyResult, + ("resources/templates/list", "2025-11-25"): v2025.ListResourceTemplatesResult, + ("resources/unsubscribe", "2025-11-25"): v2025.EmptyResult, + ("tools/call", "2025-11-25"): v2025.CallToolResult, + ("tools/list", "2025-11-25"): v2025.ListToolsResult, + ("completion/complete", "2026-07-28"): v2026.CompleteResult, + ("prompts/get", "2026-07-28"): (v2026.GetPromptResult, v2026.InputRequiredResult), + ("prompts/list", "2026-07-28"): v2026.ListPromptsResult, + ("resources/list", "2026-07-28"): v2026.ListResourcesResult, + ("resources/read", "2026-07-28"): (v2026.ReadResourceResult, v2026.InputRequiredResult), + ("resources/templates/list", "2026-07-28"): v2026.ListResourceTemplatesResult, + ("server/discover", "2026-07-28"): v2026.DiscoverResult, + ("subscriptions/listen", "2026-07-28"): v2026.EmptyResult, + ("tools/call", "2026-07-28"): (v2026.CallToolResult, v2026.InputRequiredResult), + ("tools/list", "2026-07-28"): v2026.ListToolsResult, +} + +EXPECTED_CLIENT_RESULTS: dict[tuple[str, str], type[WireModel] | tuple[type[WireModel], ...]] = { + ("ping", "2024-11-05"): v2025.EmptyResult, + ("roots/list", "2024-11-05"): v2025.ListRootsResult, + ("sampling/createMessage", "2024-11-05"): v2025.CreateMessageResult, + ("ping", "2025-03-26"): v2025.EmptyResult, + ("roots/list", "2025-03-26"): v2025.ListRootsResult, + ("sampling/createMessage", "2025-03-26"): v2025.CreateMessageResult, + ("elicitation/create", "2025-06-18"): v2025.ElicitResult, + ("ping", "2025-06-18"): v2025.EmptyResult, + ("roots/list", "2025-06-18"): v2025.ListRootsResult, + ("sampling/createMessage", "2025-06-18"): v2025.CreateMessageResult, + ("elicitation/create", "2025-11-25"): v2025.ElicitResult, + ("ping", "2025-11-25"): v2025.EmptyResult, + ("roots/list", "2025-11-25"): v2025.ListRootsResult, + ("sampling/createMessage", "2025-11-25"): v2025.CreateMessageResult, +} + +EMPTY_SERVER_RESPONSE_METHODS = frozenset( + {"logging/setLevel", "ping", "resources/subscribe", "resources/unsubscribe", "subscriptions/listen"} +) +EMPTY_CLIENT_RESPONSE_METHODS = frozenset({"ping"}) + +# Pre-2026 versions share the 2025-11-25 surface package. +PACKAGE_BY_VERSION = { + "2024-11-05": "mcp.types.v2025_11_25", + "2025-03-26": "mcp.types.v2025_11_25", + "2025-06-18": "mcp.types.v2025_11_25", + "2025-11-25": "mcp.types.v2025_11_25", + "2026-07-28": "mcp.types.v2026_07_28", +} + +# The three reserved `params._meta` entries the 2026 surface requires on every request. +META_TRIPLE: dict[str, Any] = { + "io.modelcontextprotocol/protocolVersion": "2026-07-28", + "io.modelcontextprotocol/clientInfo": {"name": "client", "version": "1.0"}, + "io.modelcontextprotocol/clientCapabilities": {}, +} + +# One minimal valid params mapping per surface request class. +REQUEST_PARAMS_FIXTURES: dict[type[WireModel], dict[str, Any] | None] = { + v2025.CallToolRequest: {"name": "echo"}, + v2025.CompleteRequest: {"ref": {"type": "ref/prompt", "name": "p"}, "argument": {"name": "a", "value": "v"}}, + v2025.CreateMessageRequest: { + "messages": [{"role": "user", "content": {"type": "text", "text": "hi"}}], + "maxTokens": 100, + }, + v2025.ElicitRequest: {"message": "m", "requestedSchema": {"type": "object", "properties": {}}}, + v2025.GetPromptRequest: {"name": "greeting"}, + v2025.InitializeRequest: { + "protocolVersion": "2025-11-25", + "capabilities": {}, + "clientInfo": {"name": "client", "version": "1.0"}, + }, + v2025.ListPromptsRequest: None, + v2025.ListResourcesRequest: None, + v2025.ListResourceTemplatesRequest: None, + v2025.ListRootsRequest: None, + v2025.ListToolsRequest: None, + v2025.PingRequest: None, + v2025.ReadResourceRequest: {"uri": "https://example.com/resource"}, + v2025.SetLevelRequest: {"level": "info"}, + v2025.SubscribeRequest: {"uri": "https://example.com/resource"}, + v2025.UnsubscribeRequest: {"uri": "https://example.com/resource"}, + v2026.CallToolRequest: {"_meta": META_TRIPLE, "name": "echo"}, + v2026.CompleteRequest: { + "_meta": META_TRIPLE, + "ref": {"type": "ref/prompt", "name": "p"}, + "argument": {"name": "a", "value": "v"}, + }, + v2026.DiscoverRequest: {"_meta": META_TRIPLE}, + v2026.GetPromptRequest: {"_meta": META_TRIPLE, "name": "greeting"}, + v2026.ListPromptsRequest: {"_meta": META_TRIPLE}, + v2026.ListResourcesRequest: {"_meta": META_TRIPLE}, + v2026.ListResourceTemplatesRequest: {"_meta": META_TRIPLE}, + v2026.ListToolsRequest: {"_meta": META_TRIPLE}, + v2026.ReadResourceRequest: {"_meta": META_TRIPLE, "uri": "https://example.com/resource"}, + v2026.SubscriptionsListenRequest: {"_meta": META_TRIPLE, "notifications": {}}, +} + +NOTIFICATION_PARAMS_FIXTURES: dict[type[WireModel], dict[str, Any] | None] = { + v2025.CancelledNotification: {"requestId": 1}, + v2025.ElicitationCompleteNotification: {"elicitationId": "e1"}, + v2025.InitializedNotification: None, + v2025.LoggingMessageNotification: {"level": "info", "data": "x"}, + v2025.ProgressNotification: {"progressToken": 1, "progress": 0.5}, + v2025.PromptListChangedNotification: None, + v2025.ResourceListChangedNotification: None, + v2025.ResourceUpdatedNotification: {"uri": "https://example.com/resource"}, + v2025.RootsListChangedNotification: None, + v2025.ToolListChangedNotification: None, + v2026.CancelledNotification: {"requestId": 1}, + v2026.ElicitationCompleteNotification: {"elicitationId": "e1"}, + v2026.LoggingMessageNotification: {"level": "info", "data": "x"}, + v2026.ProgressNotification: {"progressToken": 1, "progress": 0.5}, + v2026.PromptListChangedNotification: None, + v2026.ResourceListChangedNotification: None, + v2026.ResourceUpdatedNotification: {"uri": "https://example.com/resource"}, + v2026.SubscriptionsAcknowledgedNotification: {"notifications": {}}, + v2026.ToolListChangedNotification: None, +} + +# One minimal valid result body per response row value (class or union alias). +RESULT_BODY_FIXTURES: dict[type[WireModel] | UnionType, dict[str, Any]] = { + v2025.CallToolResult: {"content": []}, + v2025.CompleteResult: {"completion": {"values": []}}, + v2025.CreateMessageResult: {"role": "assistant", "content": {"type": "text", "text": "hi"}, "model": "m"}, + v2025.ElicitResult: {"action": "accept"}, + v2025.EmptyResult: {}, + v2025.GetPromptResult: {"messages": []}, + v2025.InitializeResult: { + "protocolVersion": "2025-11-25", + "capabilities": {}, + "serverInfo": {"name": "server", "version": "1.0"}, + }, + v2025.ListPromptsResult: {"prompts": []}, + v2025.ListResourcesResult: {"resources": []}, + v2025.ListResourceTemplatesResult: {"resourceTemplates": []}, + v2025.ListRootsResult: {"roots": [{"uri": "file:///workspace"}]}, + v2025.ListToolsResult: {"tools": []}, + v2025.ReadResourceResult: {"contents": []}, + v2026.AnyCallToolResult: {"content": [], "resultType": "complete"}, + v2026.AnyGetPromptResult: {"messages": [], "resultType": "complete"}, + v2026.AnyReadResourceResult: {"contents": [], "resultType": "complete", "ttlMs": 0, "cacheScope": "private"}, + v2026.CompleteResult: {"completion": {"values": []}, "resultType": "complete"}, + v2026.DiscoverResult: { + "supportedVersions": ["2026-07-28"], + "capabilities": {}, + "serverInfo": {"name": "server", "version": "1.0"}, + "resultType": "complete", + "ttlMs": 0, + "cacheScope": "private", + }, + v2026.EmptyResult: {"resultType": "complete"}, + v2026.ListPromptsResult: {"prompts": [], "resultType": "complete", "ttlMs": 0, "cacheScope": "private"}, + v2026.ListResourcesResult: {"resources": [], "resultType": "complete", "ttlMs": 0, "cacheScope": "private"}, + v2026.ListResourceTemplatesResult: { + "resourceTemplates": [], + "resultType": "complete", + "ttlMs": 0, + "cacheScope": "private", + }, + v2026.ListToolsResult: {"tools": [], "resultType": "complete", "ttlMs": 0, "cacheScope": "private"}, +} + + +def test_maps_define_exactly_the_expected_methods_for_every_known_version(): + # Derive the version axis from KNOWN_PROTOCOL_VERSIONS so a new version + # without map rows fails here rather than gating every method at runtime. + assert set(EXPECTED_METHODS) == set(KNOWN_PROTOCOL_VERSIONS) + surface_maps: dict[str, Mapping[tuple[str, str], object]] = { + "CLIENT_REQUESTS": methods.CLIENT_REQUESTS, + "CLIENT_NOTIFICATIONS": methods.CLIENT_NOTIFICATIONS, + "SERVER_REQUESTS": methods.SERVER_REQUESTS, + "SERVER_NOTIFICATIONS": methods.SERVER_NOTIFICATIONS, + } + for version in KNOWN_PROTOCOL_VERSIONS: + for map_name, surface_map in surface_maps.items(): + derived = {method for (method, row_version) in surface_map if row_version == version} + assert derived == EXPECTED_METHODS[version][map_name], f"{map_name} at {version}" + + +def test_response_map_keys_mirror_the_request_map_keys(): + assert set(methods.SERVER_RESULTS) == set(methods.CLIENT_REQUESTS) + assert set(methods.CLIENT_RESULTS) == set(methods.SERVER_REQUESTS) + + +def test_response_row_values_match_the_pinned_classes_and_unions(): + """Only the known empty-response methods may be valued by the bare `EmptyResult`.""" + assert set(EXPECTED_SERVER_RESULTS) == set(methods.SERVER_RESULTS) + assert set(EXPECTED_CLIENT_RESULTS) == set(methods.CLIENT_RESULTS) + pinned = [ + (methods.SERVER_RESULTS, EXPECTED_SERVER_RESULTS, EMPTY_SERVER_RESPONSE_METHODS), + (methods.CLIENT_RESULTS, EXPECTED_CLIENT_RESULTS, EMPTY_CLIENT_RESPONSE_METHODS), + ] + for response_map, expected_rows, empty_methods in pinned: + for (method, version), expected in expected_rows.items(): + actual = response_map[(method, version)] + if isinstance(expected, tuple): + assert get_args(actual) == expected, f"{method} at {version}" + else: + assert actual is expected, f"{method} at {version}" + if method not in empty_methods: + assert actual is not v2025.EmptyResult, f"{method} at {version}" + assert actual is not v2026.EmptyResult, f"{method} at {version}" + + +def test_surface_keys_agree_with_their_classes_and_the_monolith_maps(): + """Each surface key's method matches its class's method literal, its monolith row, and its version's package.""" + request_maps: list[Mapping[tuple[str, str], type[WireModel]]] = [ + methods.CLIENT_REQUESTS, + methods.SERVER_REQUESTS, + ] + notification_maps: list[Mapping[tuple[str, str], type[WireModel]]] = [ + methods.CLIENT_NOTIFICATIONS, + methods.SERVER_NOTIFICATIONS, + ] + for surface_maps, monolith_map in ( + (request_maps, methods.MONOLITH_REQUESTS), + (notification_maps, methods.MONOLITH_NOTIFICATIONS), + ): + for surface_map in surface_maps: + for (method, version), surface_type in surface_map.items(): + assert method in monolith_map, f"{method} has no monolith row" + assert get_args(surface_type.model_fields["method"].annotation) == (method,) + assert get_args(monolith_map[method].model_fields["method"].annotation) == (method,) + assert surface_type.__module__ == PACKAGE_BY_VERSION[version], f"{method} at {version}" + for response_map in (methods.SERVER_RESULTS, methods.CLIENT_RESULTS): + for (method, version), row in response_map.items(): + assert method in methods.MONOLITH_RESULTS, f"{method} has no monolith row" + for arm in get_args(row) or (row,): + assert arm.__module__ == PACKAGE_BY_VERSION[version], f"{method} at {version}" + + +def _assign_item(mapping: Any) -> None: + mapping["new-key"] = None + + +def test_built_in_maps_are_immutable(): + map_names = [ + "CLIENT_NOTIFICATIONS", + "CLIENT_REQUESTS", + "CLIENT_RESULTS", + "MONOLITH_NOTIFICATIONS", + "MONOLITH_REQUESTS", + "MONOLITH_RESULTS", + "SERVER_NOTIFICATIONS", + "SERVER_REQUESTS", + "SERVER_RESULTS", + ] + for map_name in map_names: + built_in = getattr(methods, map_name) + assert isinstance(built_in, MappingProxyType), map_name + with pytest.raises(TypeError): + _assign_item(built_in) + + +def test_minimal_request_bodies_parse_through_every_request_row(): + for (method, version), surface_type in methods.CLIENT_REQUESTS.items(): + parsed = methods.parse_client_request(method, version, REQUEST_PARAMS_FIXTURES[surface_type]) + assert isinstance(parsed, types.Request), f"{method} at {version}" + for (method, version), surface_type in methods.SERVER_REQUESTS.items(): + parsed = methods.parse_server_request(method, version, REQUEST_PARAMS_FIXTURES[surface_type]) + assert isinstance(parsed, types.Request), f"{method} at {version}" + + +def test_minimal_notification_bodies_parse_through_every_notification_row(): + for (method, version), surface_type in methods.CLIENT_NOTIFICATIONS.items(): + parsed = methods.parse_client_notification(method, version, NOTIFICATION_PARAMS_FIXTURES[surface_type]) + assert isinstance(parsed, types.Notification), f"{method} at {version}" + for (method, version), surface_type in methods.SERVER_NOTIFICATIONS.items(): + parsed = methods.parse_server_notification(method, version, NOTIFICATION_PARAMS_FIXTURES[surface_type]) + assert isinstance(parsed, types.Notification), f"{method} at {version}" + + +def test_minimal_result_bodies_parse_through_every_result_row(): + for (method, version), row in methods.SERVER_RESULTS.items(): + parsed = methods.parse_server_result(method, version, RESULT_BODY_FIXTURES[row]) + assert isinstance(parsed, types.Result), f"{method} at {version}" + for (method, version), row in methods.CLIENT_RESULTS.items(): + parsed = methods.parse_client_result(method, version, RESULT_BODY_FIXTURES[row]) + assert isinstance(parsed, types.Result), f"{method} at {version}" + + +def test_non_file_root_uri_passes_the_surface_step_and_rejects_at_the_monolith_step(): + """The monolith's `Root.uri` is file-scheme only; the surfaces declare a plain string.""" + non_file_roots = {"roots": [{"uri": "https://example.com/x"}]} + # Surface step admits the body, so the two-step parse fails at the monolith step. + pydantic.TypeAdapter(v2025.ListRootsResult).validate_python(non_file_roots) + with pytest.raises(pydantic.ValidationError): + methods.parse_client_result("roots/list", "2025-11-25", non_file_roots) + + # Same divergence on the 2026 path that embeds a roots response. + retry_params = {"_meta": META_TRIPLE, "name": "echo", "inputResponses": {"r1": non_file_roots}} + frame = {"jsonrpc": "2.0", "id": 0, "method": "tools/call", "params": retry_params} + v2026.CallToolRequest.model_validate(frame, by_name=False) + with pytest.raises(pydantic.ValidationError): + methods.parse_client_request("tools/call", "2026-07-28", retry_params) + + file_roots = {"roots": [{"uri": "file:///workspace"}]} + assert isinstance(methods.parse_client_result("roots/list", "2025-11-25", file_roots), types.ListRootsResult) + retried = methods.parse_client_request( + "tools/call", "2026-07-28", {"_meta": META_TRIPLE, "name": "echo", "inputResponses": {"r1": file_roots}} + ) + assert isinstance(retried, types.CallToolRequest) + + +def test_absent_map_keys_raise_key_error_for_every_gate_shape(): + """Key absence is the version gate; the session layer maps it to `METHOD_NOT_FOUND`.""" + gated = [ + ("resources/subscribe", "2026-07-28"), # removed at this version + ("server/discover", "2025-11-25"), # not yet at this version + ("tasks/get", "2025-11-25"), # never built-in + ("sampling/createMessage", "2025-11-25"), # wrong direction + ] + for method, version in gated: + with pytest.raises(KeyError): + methods.parse_client_request(method, version, None) + with pytest.raises(KeyError): + methods.parse_server_request("ping", "2026-07-28", None) + + +def test_unknown_version_strings_raise_value_error_on_every_parse_function(): + body_parsers = [ + methods.parse_client_request, + methods.parse_server_request, + methods.parse_client_notification, + methods.parse_server_notification, + ] + for body_parser in body_parsers: + with pytest.raises(ValueError) as excinfo: + body_parser("ping", "2099-01-01", None) + assert "2099-01-01" in str(excinfo.value) + result_parsers = [methods.parse_server_result, methods.parse_client_result] + for result_parser in result_parsers: + with pytest.raises(ValueError) as excinfo: + result_parser("ping", "2099-01-01", {}) + assert "2099-01-01" in str(excinfo.value) + + +def test_2026_07_28_requests_missing_a_reserved_meta_entry_reject_as_missing(): + for absent_key in META_TRIPLE: + partial_meta = {key: value for key, value in META_TRIPLE.items() if key != absent_key} + with pytest.raises(pydantic.ValidationError) as excinfo: + methods.parse_client_request("tools/list", "2026-07-28", {"_meta": partial_meta}) + assert [error["loc"] for error in excinfo.value.errors() if error["type"] == "missing"] == [ + ("params", "_meta", absent_key) + ] + + +def test_2026_07_28_results_require_result_type(): + with pytest.raises(pydantic.ValidationError): + methods.parse_server_result("tools/call", "2026-07-28", {"content": []}) + with pytest.raises(pydantic.ValidationError): + methods.parse_server_result("subscriptions/listen", "2026-07-28", {}) + + +def test_empty_result_body_parses_at_versions_that_define_it(): + parsed = methods.parse_server_result("ping", "2025-11-25", {}) + assert isinstance(parsed, types.EmptyResult) + + +def test_2026_07_28_shaped_result_extras_pass_at_earlier_versions(): + """The earlier surface ignores unknown keys; the monolith preserves them on fields it declares.""" + parsed = methods.parse_server_result( + "tools/list", "2025-11-25", {"tools": [], "resultType": "complete", "ttlMs": 5, "cacheScope": "public"} + ) + assert isinstance(parsed, types.ListToolsResult) + assert parsed.result_type == "complete" + assert parsed.ttl_ms == 5 + assert parsed.cache_scope == "public" + + +def test_embedded_input_request_entries_without_method_reject_at_the_surface_step(): + """The monolith's embedded request classes default `method`, so only the surface step rejects this.""" + body = {"resultType": "input_required", "inputRequests": {"r1": {"params": None}}} + monolith_row = methods.MONOLITH_RESULTS["tools/call"] + monolith_only: types.Result = pydantic.TypeAdapter[Any](monolith_row).validate_python(body) + assert isinstance(monolith_only, types.InputRequiredResult) + with pytest.raises(pydantic.ValidationError): + methods.parse_server_result("tools/call", "2026-07-28", body) + + +def test_none_params_omit_the_key_so_required_params_reject(): + with pytest.raises(pydantic.ValidationError) as excinfo: + methods.parse_client_request("tools/call", "2025-11-25", None) + assert [error["loc"] for error in excinfo.value.errors() if error["type"] == "missing"] == [("params",)] + assert isinstance(methods.parse_client_request("ping", "2025-11-25", None), types.PingRequest) + + +def test_snake_case_spellings_of_required_aliased_fields_reject_as_missing(): + """Wire parsing is alias-only (`by_name=False`), at both the surface and monolith steps.""" + snake_params = {"messages": [{"role": "user", "content": {"type": "text", "text": "hi"}}], "max_tokens": 100} + with pytest.raises(pydantic.ValidationError) as excinfo: + methods.parse_server_request("sampling/createMessage", "2025-11-25", snake_params) + assert [error["loc"] for error in excinfo.value.errors() if error["type"] == "missing"] == [("params", "maxTokens")] + with pytest.raises(pydantic.ValidationError): + types.CreateMessageRequest.model_validate( + {"method": "sampling/createMessage", "params": snake_params}, by_name=False + ) + + +def test_extension_map_rows_parse_through_the_same_functions(): + extended_surface = {**methods.CLIENT_REQUESTS, ("tasks/get", "2025-11-25"): v2025.GetTaskRequest} + extended_monolith = {**methods.MONOLITH_REQUESTS, "tasks/get": types.GetTaskRequest} + parsed = methods.parse_client_request( + "tasks/get", "2025-11-25", {"taskId": "t1"}, surface=extended_surface, monolith=extended_monolith + ) + assert isinstance(parsed, types.GetTaskRequest) + assert parsed.params.task_id == "t1" + + +def test_inconsistent_extension_maps_raise_runtime_error_after_the_surface_hit(): + """Must not raise `KeyError`: the session layer treats that as the version gate.""" + extended_surface = {**methods.CLIENT_REQUESTS, ("tasks/get", "2025-11-25"): v2025.GetTaskRequest} + with pytest.raises(RuntimeError, match="inconsistent extension maps"): + methods.parse_client_request("tasks/get", "2025-11-25", {"taskId": "t1"}, surface=extended_surface) + + +def test_input_required_unions_discriminate_identically_in_both_arm_orders(): + complete_bodies: dict[str, dict[str, Any]] = { + "tools/call": {"content": []}, + "prompts/get": {"messages": []}, + "resources/read": {"contents": []}, + } + shared_bodies: list[dict[str, Any]] = [ + {"resultType": "input_required", "inputRequests": {"r1": {"method": "roots/list"}}}, + {"resultType": "input_required", "requestState": "blob"}, + ] + for method, complete_body in complete_bodies.items(): + row = methods.MONOLITH_RESULTS[method] + complete_arm, input_required_arm = get_args(row) + assert input_required_arm is types.InputRequiredResult + bodies: list[dict[str, Any]] = [ + complete_body, + {**complete_body, "resultType": "complete"}, + *shared_bodies, + {**complete_body, "resultType": "task"}, # open tag is preserved + {**complete_body, "resultType": "input_required"}, # complete shape plus the tag + ] + for body in bodies: + forward = pydantic.TypeAdapter[Any](complete_arm | input_required_arm).validate_python(body) + reversed_order = pydantic.TypeAdapter[Any](input_required_arm | complete_arm).validate_python(body) + assert type(forward) is type(reversed_order), f"{method}: {body}" + assert forward.result_type == reversed_order.result_type + through_row = pydantic.TypeAdapter[Any](row).validate_python(complete_body) + assert isinstance(through_row, complete_arm) + open_tagged = pydantic.TypeAdapter[Any](row).validate_python({**complete_body, "resultType": "task"}) + assert open_tagged.result_type == "task" + + +def test_sampling_union_keeps_the_complete_arm_first_because_order_is_load_bearing(): + """A single-block body satisfies both arms; smart-union ties resolve leftmost.""" + assert get_args(methods.MONOLITH_RESULTS["sampling/createMessage"]) == ( + types.CreateMessageResult, + types.CreateMessageResultWithTools, + ) + single_block: dict[str, Any] = {"role": "assistant", "content": {"type": "text", "text": "hi"}, "model": "m"} + through_row = methods.parse_client_result("sampling/createMessage", "2025-11-25", single_block) + assert type(through_row) is types.CreateMessageResult + reversed_union = pydantic.TypeAdapter[Any](types.CreateMessageResultWithTools | types.CreateMessageResult) + assert type(reversed_union.validate_python(single_block)) is types.CreateMessageResultWithTools + + array_body: dict[str, Any] = {"role": "assistant", "content": [{"type": "text", "text": "hi"}], "model": "m"} + tool_use_body: dict[str, Any] = { + "role": "assistant", + "content": {"type": "tool_use", "name": "t", "id": "c1", "input": {}}, + "model": "m", + } + for body in (array_body, tool_use_body): + parsed = methods.parse_client_result("sampling/createMessage", "2025-11-25", body) + assert type(parsed) is types.CreateMessageResultWithTools + + +def test_importing_the_module_builds_no_adapters_and_identical_rows_share_one(): + # Execute a fresh copy so the cache assertion is order-independent. + spec = importlib.util.find_spec("mcp.types.methods") + assert spec is not None and spec.loader is not None + fresh = importlib.util.module_from_spec(spec) + spec.loader.exec_module(fresh) + assert fresh._adapter.cache_info().currsize == 0 + fresh.parse_server_result("ping", "2025-11-25", {}) + assert fresh._adapter.cache_info().currsize == 2 + # Identical row values at another version: no new adapters. + fresh.parse_server_result("ping", "2024-11-05", {}) + assert fresh._adapter.cache_info().currsize == 2 diff --git a/tests/types/test_parity.py b/tests/types/test_parity.py new file mode 100644 index 0000000000..9212d038dc --- /dev/null +++ b/tests/types/test_parity.py @@ -0,0 +1,192 @@ +"""Assert every per-version surface model's wire fields are a subset of its `mcp.types` superset counterpart.""" + +from __future__ import annotations + +import inspect +from types import ModuleType + +import pytest +from pydantic import BaseModel + +import mcp.types as monolith +import mcp.types._types as _types +import mcp.types.v2025_11_25 as v2025_11_25 +import mcp.types.v2026_07_28 as v2026_07_28 + +SURFACES: tuple[ModuleType, ...] = (v2025_11_25, v2026_07_28) + +# Envelope fields the monolith models on `mcp.types.jsonrpc` instead of on each request/notification. +ENVELOPE_FIELDS: frozenset[str] = frozenset({"jsonrpc", "id"}) + +# Surface classes whose monolith counterpart has a different name (key: "."). +NAME_MAP: dict[str, type[BaseModel]] = { + # v2025_11_25 + "v2025_11_25.Argument": monolith.CompletionArgument, + "v2025_11_25.Context": monolith.CompletionContext, + "v2025_11_25.Data": monolith.ElicitationRequiredErrorData, + "v2025_11_25.Elicitation": monolith.ElicitationCapability, + "v2025_11_25.Elicitation1": _types.TasksElicitationCapability, + "v2025_11_25.ElicitationCompleteNotification": monolith.ElicitCompleteNotification, + "v2025_11_25.ElicitationCompleteNotificationParams": monolith.ElicitCompleteNotificationParams, + "v2025_11_25.Error": monolith.ErrorData, + "v2025_11_25.JSONRPCErrorResponse": monolith.JSONRPCError, + "v2025_11_25.JSONRPCResultResponse": monolith.JSONRPCResponse, + "v2025_11_25.Prompts": monolith.PromptsCapability, + "v2025_11_25.Requests": _types.ClientTasksRequestsCapability, + "v2025_11_25.Requests1": _types.ServerTasksRequestsCapability, + "v2025_11_25.Resources": monolith.ResourcesCapability, + "v2025_11_25.Roots": monolith.RootsCapability, + "v2025_11_25.Sampling": monolith.SamplingCapability, + "v2025_11_25.Sampling1": _types.TasksSamplingCapability, + "v2025_11_25.Tasks": _types.ClientTasksCapability, + "v2025_11_25.Tasks1": _types.ServerTasksCapability, + "v2025_11_25.Tools": _types.TasksToolsCapability, + "v2025_11_25.Tools1": monolith.ToolsCapability, + # v2026_07_28 + "v2026_07_28.Argument": monolith.CompletionArgument, + "v2026_07_28.Context": monolith.CompletionContext, + "v2026_07_28.Data": monolith.MissingRequiredClientCapabilityErrorData, + "v2026_07_28.Data1": monolith.UnsupportedProtocolVersionErrorData, + "v2026_07_28.Elicitation": monolith.ElicitationCapability, + "v2026_07_28.ElicitationCompleteNotification": monolith.ElicitCompleteNotification, + "v2026_07_28.ElicitationCompleteNotificationParams": monolith.ElicitCompleteNotificationParams, + "v2026_07_28.Error": monolith.ErrorData, + "v2026_07_28.JSONRPCErrorResponse": monolith.JSONRPCError, + "v2026_07_28.JSONRPCResultResponse": monolith.JSONRPCResponse, + "v2026_07_28.Prompts": monolith.PromptsCapability, + "v2026_07_28.Resources": monolith.ResourcesCapability, + "v2026_07_28.Sampling": monolith.SamplingCapability, + "v2026_07_28.Tools": monolith.ToolsCapability, +} + +# Surface classes with no monolith equivalent (envelope wrappers, JSON-Schema fragments modelled as `dict`). +SKIP: frozenset[str] = frozenset( + { + # v2025_11_25 + "v2025_11_25.AnyOfItem", + "v2025_11_25.BooleanSchema", + "v2025_11_25.Error1", + "v2025_11_25.Icons", + "v2025_11_25.InputSchema", + "v2025_11_25.Items", + "v2025_11_25.Items1", + "v2025_11_25.LegacyTitledEnumSchema", + "v2025_11_25.Meta", + "v2025_11_25.NumberSchema", + "v2025_11_25.OneOfItem", + "v2025_11_25.OutputSchema", + "v2025_11_25.RequestedSchema", + "v2025_11_25.ResourceRequestParams", + "v2025_11_25.StringSchema", + "v2025_11_25.TaskAugmentedRequestParams", + "v2025_11_25.TitledMultiSelectEnumSchema", + "v2025_11_25.TitledSingleSelectEnumSchema", + "v2025_11_25.URLElicitationRequiredError", + "v2025_11_25.UntitledMultiSelectEnumSchema", + "v2025_11_25.UntitledSingleSelectEnumSchema", + # v2026_07_28 + "v2026_07_28.AnyOfItem", + "v2026_07_28.BooleanSchema", + "v2026_07_28.CallToolResultResponse", + "v2026_07_28.CompleteResultResponse", + "v2026_07_28.DiscoverResultResponse", + "v2026_07_28.Error1", + "v2026_07_28.Error2", + "v2026_07_28.GetPromptResultResponse", + "v2026_07_28.Icons", + "v2026_07_28.InputSchema", + "v2026_07_28.InternalError", + "v2026_07_28.InvalidParamsError", + "v2026_07_28.InvalidRequestError", + "v2026_07_28.Items", + "v2026_07_28.Items1", + "v2026_07_28.LegacyTitledEnumSchema", + "v2026_07_28.ListPromptsResultResponse", + "v2026_07_28.ListResourceTemplatesResultResponse", + "v2026_07_28.ListResourcesResultResponse", + "v2026_07_28.ListToolsResultResponse", + "v2026_07_28.MetaObject", + "v2026_07_28.MethodNotFoundError", + "v2026_07_28.MissingRequiredClientCapabilityError", + "v2026_07_28.NumberSchema", + "v2026_07_28.OneOfItem", + "v2026_07_28.OutputSchema", + "v2026_07_28.ParseError", + "v2026_07_28.ReadResourceResultResponse", + "v2026_07_28.RequestMetaObject", + "v2026_07_28.RequestedSchema", + "v2026_07_28.ResourceRequestParams", + "v2026_07_28.StringSchema", + "v2026_07_28.TitledMultiSelectEnumSchema", + "v2026_07_28.TitledSingleSelectEnumSchema", + "v2026_07_28.UnsupportedProtocolVersionError", + "v2026_07_28.UntitledMultiSelectEnumSchema", + "v2026_07_28.UntitledSingleSelectEnumSchema", + } +) + +# Intentional gaps: (surface class, wire alias) -> reason the monolith omits the field. +_RESULT_TYPE_REASON = "resultType is declared on each concrete Result subclass, not the base" +FIELD_EXCEPTIONS: dict[tuple[type[BaseModel], str], str] = { + (v2026_07_28.Result, "resultType"): _RESULT_TYPE_REASON, + (v2026_07_28.PaginatedResult, "resultType"): _RESULT_TYPE_REASON, + (v2026_07_28.CacheableResult, "resultType"): _RESULT_TYPE_REASON, +} + + +def _wire_aliases(model: type[BaseModel]) -> set[str]: + return {field.alias or name for name, field in model.model_fields.items()} + + +def _surface_classes(module: ModuleType) -> list[tuple[str, type[BaseModel]]]: + tail = module.__name__.rsplit(".", 1)[-1] + out: list[tuple[str, type[BaseModel]]] = [] + for name, obj in vars(module).items(): + if not (inspect.isclass(obj) and issubclass(obj, BaseModel)): + continue + if obj.__module__ != module.__name__ or obj.__name__ != name: + continue # re-export or alias to another model + out.append((f"{tail}.{name}", obj)) + return out + + +def _matched_pairs() -> list[tuple[str, type[BaseModel], type[BaseModel]]]: + pairs: list[tuple[str, type[BaseModel], type[BaseModel]]] = [] + for module in SURFACES: + for qualname, surface_cls in _surface_classes(module): + if qualname in SKIP: + continue + mono_cls = ( + NAME_MAP.get(qualname) + or getattr(monolith, surface_cls.__name__, None) + or getattr(_types, surface_cls.__name__, None) + ) + assert isinstance(mono_cls, type) and issubclass(mono_cls, BaseModel), qualname + pairs.append((qualname, surface_cls, mono_cls)) + return pairs + + +@pytest.mark.parametrize( + "qualname,surface_cls,mono_cls", _matched_pairs(), ids=lambda v: v if isinstance(v, str) else "" +) +def test_monolith_is_superset_of_surface_fields( + qualname: str, surface_cls: type[BaseModel], mono_cls: type[BaseModel] +) -> None: + surface_fields = _wire_aliases(surface_cls) - ENVELOPE_FIELDS + excused = {alias for (cls, alias) in FIELD_EXCEPTIONS if cls is surface_cls} + missing = surface_fields - _wire_aliases(mono_cls) - excused + assert not missing, f"{qualname}: monolith {mono_cls.__name__} missing wire fields {sorted(missing)}" + + +def test_every_surface_class_is_accounted_for() -> None: + monolith_models = { + name + for name, obj in (vars(monolith) | vars(_types)).items() + if inspect.isclass(obj) and issubclass(obj, BaseModel) + } + surface = {q: cls.__name__ for module in SURFACES for q, cls in _surface_classes(module)} + auto_matched = {q for q, name in surface.items() if name in monolith_models} + unmapped = surface.keys() - auto_matched - NAME_MAP.keys() - SKIP + assert not unmapped, f"surface classes with no mapping: {sorted(unmapped)}" + stale = (NAME_MAP.keys() | SKIP) - surface.keys() + assert not stale, f"stale NAME_MAP/SKIP entries: {sorted(stale)}" diff --git a/tests/types/test_wire_frames.py b/tests/types/test_wire_frames.py new file mode 100644 index 0000000000..4badda6c31 --- /dev/null +++ b/tests/types/test_wire_frames.py @@ -0,0 +1,87 @@ +"""Snapshot pins for outbound JSON-RPC frames; a diff is a wire-visible change needing a deliberate decision.""" + +from typing import Any + +from inline_snapshot import snapshot +from pydantic import BaseModel + +from mcp.types import ( + METHOD_NOT_FOUND, + CallToolRequest, + CallToolRequestParams, + CallToolResult, + EmptyResult, + ErrorData, + InputRequiredResult, + JSONRPCError, + JSONRPCNotification, + JSONRPCRequest, + JSONRPCResponse, + ListRootsRequest, + ListToolsResult, + ProgressNotification, + ProgressNotificationParams, + TextContent, + Tool, +) + + +def _body(model: BaseModel) -> dict[str, Any]: + """Mirror the session layer's outbound payload dump.""" + return model.model_dump(by_alias=True, mode="json", exclude_none=True) + + +def _frame(envelope: BaseModel) -> str: + """Mirror the transports' frame serialization.""" + return envelope.model_dump_json(by_alias=True, exclude_unset=True) + + +def test_request_frame_carries_the_envelope_and_the_dumped_request_body(): + request = CallToolRequest(params=CallToolRequestParams(name="echo", arguments={"text": "hi"})) + frame = JSONRPCRequest(jsonrpc="2.0", id=1, **_body(request)) + assert _frame(frame) == snapshot( + '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"echo","arguments":{"text":"hi"}}}' + ) + + +def test_notification_frame_has_no_id_and_carries_the_dumped_params(): + notification = ProgressNotification(params=ProgressNotificationParams(progress_token="t1", progress=0.5)) + frame = JSONRPCNotification(jsonrpc="2.0", **_body(notification)) + assert _frame(frame) == snapshot( + '{"jsonrpc":"2.0","method":"notifications/progress","params":{"progressToken":"t1","progress":0.5}}' + ) + + +def test_non_empty_result_frame_always_dumps_result_type_complete(): + result = CallToolResult(content=[TextContent(text="ok")]) + frame = JSONRPCResponse(jsonrpc="2.0", id=1, result=_body(result)) + assert _frame(frame) == snapshot( + '{"jsonrpc":"2.0","id":1,"result":{"content":[{"type":"text","text":"ok"}],"isError":false,"resultType":"complete"}}' + ) + + +def test_cacheable_list_result_frame_always_dumps_its_caching_directives(): + result = ListToolsResult(tools=[Tool(name="echo", input_schema={"type": "object"})]) + frame = JSONRPCResponse(jsonrpc="2.0", id=2, result=_body(result)) + assert _frame(frame) == snapshot( + '{"jsonrpc":"2.0","id":2,"result":{"ttlMs":0,"cacheScope":"private","tools":[{"name":"echo","inputSchema":{"type":"object"}}],"resultType":"complete"}}' + ) + + +def test_empty_result_frame_dumps_an_empty_result_object(): + """Deployed peers reject extra keys on empty results, so the SDK omits resultType here.""" + frame = JSONRPCResponse(jsonrpc="2.0", id=3, result=_body(EmptyResult())) + assert _frame(frame) == snapshot('{"jsonrpc":"2.0","id":3,"result":{}}') + + +def test_input_required_result_frame_carries_the_tag_and_the_embedded_requests(): + result = InputRequiredResult(input_requests={"r1": ListRootsRequest()}, request_state="s1") + frame = JSONRPCResponse(jsonrpc="2.0", id=4, result=_body(result)) + assert _frame(frame) == snapshot( + '{"jsonrpc":"2.0","id":4,"result":{"resultType":"input_required","inputRequests":{"r1":{"method":"roots/list"}},"requestState":"s1"}}' + ) + + +def test_error_frame_wraps_error_data_in_the_jsonrpc_envelope(): + frame = JSONRPCError(jsonrpc="2.0", id=5, error=ErrorData(code=METHOD_NOT_FOUND, message="Method not found")) + assert _frame(frame) == snapshot('{"jsonrpc":"2.0","id":5,"error":{"code":-32601,"message":"Method not found"}}') diff --git a/uv.lock b/uv.lock index b9755c382b..7970d1cc2d 100644 --- a/uv.lock +++ b/uv.lock @@ -62,6 +62,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/6f/12/e5e0282d673bb9746bacfb6e2dba8719989d3660cdb2ea79aee9a9651afb/anyio-4.10.0-py3-none-any.whl", hash = "sha256:60e474ac86736bbfd6f210f7a61218939c318f43f9972497381f1c5e930ed3d1", size = 107213, upload-time = "2025-08-04T08:54:24.882Z" }, ] +[[package]] +name = "argcomplete" +version = "3.6.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/38/61/0b9ae6399dd4a58d8c1b1dc5a27d6f2808023d0b5dd3104bb99f45a33ff6/argcomplete-3.6.3.tar.gz", hash = "sha256:62e8ed4fd6a45864acc8235409461b72c9a28ee785a2011cc5eb78318786c89c", size = 73754, upload-time = "2025-10-20T03:33:34.741Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/74/f5/9373290775639cb67a2fce7f629a1c240dce9f12fe927bc32b2736e16dfc/argcomplete-3.6.3-py3-none-any.whl", hash = "sha256:f5007b3a600ccac5d25bbce33089211dfd49eab4a7718da3f10e3082525a92ce", size = 43846, upload-time = "2025-10-20T03:33:33.021Z" }, +] + [[package]] name = "asttokens" version = "3.0.0" @@ -528,6 +537,26 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/21/0e/8459ca4413e1a21a06c97d134bfaf18adfd27cea068813dc0faae06cbf00/cssselect2-0.9.0-py3-none-any.whl", hash = "sha256:6a99e5f91f9a016a304dd929b0966ca464bcfda15177b6fb4a118fc0fb5d9563", size = 15453, upload-time = "2026-02-12T17:16:38.317Z" }, ] +[[package]] +name = "datamodel-code-generator" +version = "0.57.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "argcomplete" }, + { name = "black" }, + { name = "genson" }, + { name = "inflect" }, + { name = "isort" }, + { name = "jinja2" }, + { name = "pydantic" }, + { name = "pyyaml" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5d/44/87d5980f813a1e323c5d726b3ac5fec8c915ce8a77fcdceaf9c00457dbae/datamodel_code_generator-0.57.0.tar.gz", hash = "sha256:0eda778ea06eaa476e542a5f1fe1d14cc3bbf686edb33a0ad6151c7d19089906", size = 932941, upload-time = "2026-05-07T16:21:55.819Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c5/c1/4fb9a44bb4a305b860c5a5b1866dcccfac3b76f5f170a9e68fc7733e16d2/datamodel_code_generator-0.57.0-py3-none-any.whl", hash = "sha256:d26bf5defe5154493d0aa5a822b7725332b9e9dd2abccc2f8856052286aa83b5", size = 259343, upload-time = "2026-05-07T16:21:53.823Z" }, +] + [[package]] name = "defusedxml" version = "0.7.1" @@ -576,6 +605,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl", hash = "sha256:760643d3452b4d777d295bb167ccc74c64a81df23fb5e08eff250c425a4b2017", size = 28317, upload-time = "2025-09-01T09:48:08.5Z" }, ] +[[package]] +name = "genson" +version = "1.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c5/cf/2303c8ad276dcf5ee2ad6cf69c4338fd86ef0f471a5207b069adf7a393cf/genson-1.3.0.tar.gz", hash = "sha256:e02db9ac2e3fd29e65b5286f7135762e2cd8a986537c075b06fc5f1517308e37", size = 34919, upload-time = "2024-05-15T22:08:49.123Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f8/5c/e226de133afd8bb267ec27eead9ae3d784b95b39a287ed404caab39a5f50/genson-1.3.0-py3-none-any.whl", hash = "sha256:468feccd00274cc7e4c09e84b08704270ba8d95232aa280f65b986139cec67f7", size = 21470, upload-time = "2024-05-15T22:08:47.056Z" }, +] + [[package]] name = "ghp-import" version = "2.1.0" @@ -679,6 +717,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fa/5e/f8e9a1d23b9c20a551a8a02ea3637b4642e22c2626e3a13a9a29cdea99eb/importlib_metadata-8.7.1-py3-none-any.whl", hash = "sha256:5a1f80bf1daa489495071efbb095d75a634cf28a8bc299581244063b53176151", size = 27865, upload-time = "2025-12-21T10:00:18.329Z" }, ] +[[package]] +name = "inflect" +version = "7.5.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "more-itertools" }, + { name = "typeguard" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/78/c6/943357d44a21fd995723d07ccaddd78023eace03c1846049a2645d4324a3/inflect-7.5.0.tar.gz", hash = "sha256:faf19801c3742ed5a05a8ce388e0d8fe1a07f8d095c82201eb904f5d27ad571f", size = 73751, upload-time = "2024-12-28T17:11:18.897Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8a/eb/427ed2b20a38a4ee29f24dbe4ae2dafab198674fe9a85e3d6adf9e5f5f41/inflect-7.5.0-py3-none-any.whl", hash = "sha256:2aea70e5e70c35d8350b8097396ec155ffd68def678c7ff97f51aa69c1d92344", size = 35197, upload-time = "2024-12-28T17:11:15.931Z" }, +] + [[package]] name = "iniconfig" version = "2.1.0" @@ -704,6 +755,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e6/04/190b336a006d4e1275c2dde1bf953336e818d18b779f24947579bb4ba48d/inline_snapshot-0.28.0-py3-none-any.whl", hash = "sha256:9988f82ee5e719445bbc437d0dc01e0a3c4c94f0ba910f8ad8b573cf15aa8348", size = 69026, upload-time = "2025-08-24T21:48:02.342Z" }, ] +[[package]] +name = "isort" +version = "8.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ef/7c/ec4ab396d31b3b395e2e999c8f46dec78c5e29209fac49d1f4dace04041d/isort-8.0.1.tar.gz", hash = "sha256:171ac4ff559cdc060bcfff550bc8404a486fee0caab245679c2abe7cb253c78d", size = 769592, upload-time = "2026-02-28T10:08:20.685Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3e/95/c7c34aa53c16353c56d0b802fba48d5f5caa2cdee7958acbcb795c830416/isort-8.0.1-py3-none-any.whl", hash = "sha256:28b89bc70f751b559aeca209e6120393d43fbe2490de0559662be7a9787e3d75", size = 89733, upload-time = "2026-02-28T10:08:19.466Z" }, +] + [[package]] name = "jinja2" version = "3.1.6" @@ -872,6 +932,9 @@ rich = [ ] [package.dev-dependencies] +codegen = [ + { name = "datamodel-code-generator" }, +] dev = [ { name = "coverage", extra = ["toml"] }, { name = "dirty-equals" }, @@ -925,6 +988,7 @@ requires-dist = [ provides-extras = ["cli", "rich"] [package.metadata.requires-dev] +codegen = [{ name = "datamodel-code-generator", specifier = "==0.57.0" }] dev = [ { name = "coverage", extras = ["toml"], specifier = ">=7.10.7,<=7.13" }, { name = "dirty-equals", specifier = ">=0.9.0" }, @@ -1559,6 +1623,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/81/06/c5f8deba7d2cbdfa7967a716ae801aa9ca5f734b8f54fd473ef77a088dbe/mkdocstrings_python-2.0.1-py3-none-any.whl", hash = "sha256:66ecff45c5f8b71bf174e11d49afc845c2dfc7fc0ab17a86b6b337e0f24d8d90", size = 105055, upload-time = "2025-12-03T14:26:10.184Z" }, ] +[[package]] +name = "more-itertools" +version = "11.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/de/1d/f4da6f02cdffe04d6362210b807146a26044c88d839208aec273bb0d9184/more_itertools-11.1.0.tar.gz", hash = "sha256:48e8f4d9e7e5878571ecf6f2b4e57634f93cd474cc8cfbd2376f2d11b396e30d", size = 145772, upload-time = "2026-05-22T14:14:29.909Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e8/3d/1087453384dbde46a8c7f9356eead2c58be8a7bf156bca40243377c85715/more_itertools-11.1.0-py3-none-any.whl", hash = "sha256:4b65538ae22f6fed0ce4874efd317463a7489796a0939fa66824dd542125a192", size = 72226, upload-time = "2026-05-22T14:14:28.824Z" }, +] + [[package]] name = "mypy-extensions" version = "1.1.0" @@ -2655,6 +2728,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/31/5b/94237a3485620dbff9741df02ff6d8acaa5fdec67d81ab3f62e4d8511bf7/trio-0.31.0-py3-none-any.whl", hash = "sha256:b5d14cd6293d79298b49c3485ffd9c07e3ce03a6da8c7dfbe0cb3dd7dc9a4774", size = 512679, upload-time = "2025-09-09T15:17:13.821Z" }, ] +[[package]] +name = "typeguard" +version = "4.5.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/67/1c/dfba5c4633cafc4c701f237d2ba63b416805047fd6d96aab4cfc40969f98/typeguard-4.5.2.tar.gz", hash = "sha256:5a16dcac23502039299c97c8941651bc33d7ea8cc4b2f7d6bbb1b528f6eea423", size = 80240, upload-time = "2026-05-14T12:59:40.857Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5b/29/74eeb4d3f3ae61ca096b018ad486b3b3c74b17bec09ab4edab721cbefec3/typeguard-4.5.2-py3-none-any.whl", hash = "sha256:fcf9de18bd945cdb4c7b996e12b4c51ce83f92f191314a6d7cf1739586ec98cf", size = 36748, upload-time = "2026-05-14T12:59:39.473Z" }, +] + [[package]] name = "typer" version = "0.17.4"