diff --git a/docs/protocol/v2/draft/initialization.mdx b/docs/protocol/v2/draft/initialization.mdx index 0e022589f..8254d6075 100644 --- a/docs/protocol/v2/draft/initialization.mdx +++ b/docs/protocol/v2/draft/initialization.mdx @@ -65,8 +65,8 @@ The Agent **MUST** respond with the chosen [protocol version](#protocol-version) "embeddedContext": {} }, "mcp": { - "http": {}, - "sse": {} + "stdio": {}, + "http": {} } }, "agentInfo": { @@ -156,21 +156,18 @@ Optionally, they **MAY** support richer types of [content](/protocol/v2/draft/co #### MCP capabilities + + The Agent supports connecting to MCP servers over stdio. Omitted or `null` + means the Agent does not advertise support. Supplying `{}` means the Agent + supports stdio MCP server transports. + + The Agent supports connecting to MCP servers over HTTP. Omitted or `null` means the Agent does not advertise support. Supplying `{}` means the Agent supports HTTP MCP server transports. - - The Agent supports connecting to MCP servers over SSE. Omitted or `null` means - the Agent does not advertise support. Supplying `{}` means the Agent supports - SSE MCP server transports. - -Note: This transport has been deprecated by the MCP spec. - - - #### Authentication Capabilities diff --git a/docs/protocol/v2/draft/schema.mdx b/docs/protocol/v2/draft/schema.mdx index eddb7f217..0bc1d8673 100644 --- a/docs/protocol/v2/draft/schema.mdx +++ b/docs/protocol/v2/draft/schema.mdx @@ -4110,11 +4110,11 @@ Optional. Omitted or `null` both mean the agent does not advertise support. Supplying `\{\}` means the agent supports HTTP MCP server transports. -McpSseCapabilities | null} > - Agent supports `McpServer::Sse`. +McpStdioCapabilities | null} > + Agent supports `McpServer::Stdio`. Optional. Omitted or `null` both mean the agent does not advertise support. -Supplying `\{\}` means the agent supports SSE MCP server transports. +Supplying `\{\}` means the agent supports stdio MCP server transports. @@ -4189,37 +4189,6 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v2/d - -SSE transport configuration - -Only available when the Agent capabilities include `mcp.sse`. - - - - - The _meta property is reserved by ACP to allow clients and agents to attach additional -metadata to their interactions. Implementations MUST NOT make assumptions about values at -these keys. - -See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v2/draft/extensibility) - - -HttpHeader[]} required> - HTTP headers to set when making requests to the MCP server. - - - Human-readable name identifying this MCP server. - - - The discriminator value. Must be `"sse"`. - - - URL to the MCP server. - - - - - **UNSTABLE** @@ -4257,10 +4226,10 @@ on the same ACP connection. - + Stdio transport configuration -All Agents MUST support this transport. +Only available when the Agent capabilities include `mcp.stdio`. @@ -4284,6 +4253,34 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v2/d Human-readable name identifying this MCP server. + + The discriminator value. Must be `"stdio"`. + + + + + + +Custom or future MCP server transport configuration. + +Values beginning with `_` are reserved for implementation-specific +extensions. Unknown values that do not begin with `_` are reserved for +future ACP variants. + +Receivers that do not understand this transport should preserve the raw +payload when storing, replaying, proxying, or forwarding session setup +data, and otherwise ignore it or reject the server configuration. + + + + + Custom or future MCP server transport type. + +Values beginning with `_` are reserved for implementation-specific +extensions. Unknown values that do not begin with `_` are reserved for +future ACP variants. + + @@ -4362,32 +4359,6 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v2/d URL to the MCP server. -## McpServerSse - -SSE transport configuration for MCP. - -**Type:** Object - -**Properties:** - - - The _meta property is reserved by ACP to allow clients and agents to attach additional -metadata to their interactions. Implementations MUST NOT make assumptions about values at -these keys. - -See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v2/draft/extensibility) - - -HttpHeader[]} required> - HTTP headers to set when making requests to the MCP server. - - - Human-readable name identifying this MCP server. - - - URL to the MCP server. - - ## McpServerStdio Stdio transport configuration for MCP. @@ -4417,11 +4388,11 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v2/d Human-readable name identifying this MCP server. -## McpSseCapabilities +## McpStdioCapabilities -Capabilities for SSE MCP server transports. +Capabilities for stdio MCP server transports. -Supplying `\{\}` means the agent supports SSE MCP server transports. +Supplying `\{\}` means the agent supports stdio MCP server transports. **Type:** Object diff --git a/docs/protocol/v2/draft/session-setup.mdx b/docs/protocol/v2/draft/session-setup.mdx index 8b1fe3fb5..79283e3d3 100644 --- a/docs/protocol/v2/draft/session-setup.mdx +++ b/docs/protocol/v2/draft/session-setup.mdx @@ -60,6 +60,7 @@ Clients create a new session by calling the `session/new` method with: "cwd": "/home/user/project", "mcpServers": [ { + "type": "stdio", "name": "workspace-tools", "command": "/path/to/mcp-server", "args": ["--stdio"], @@ -125,6 +126,7 @@ To load an existing session, Clients **MUST** call the `session/load` method wit "cwd": "/home/user/project", "mcpServers": [ { + "type": "stdio", "name": "workspace-tools", "command": "/path/to/mcp-server", "args": ["--mode", "workspace"], @@ -244,6 +246,7 @@ To resume an existing session without replaying prior messages, Clients "cwd": "/home/user/project", "mcpServers": [ { + "type": "stdio", "name": "workspace-tools", "command": "/path/to/mcp-server", "args": ["--mode", "workspace"], @@ -397,15 +400,19 @@ When `session.additionalDirectories` is in use, the session's effective root set The [Model Context Protocol (MCP)](https://modelcontextprotocol.io) allows Agents to access external tools and data sources. When creating a session, Clients **MAY** include connection details for MCP servers that the Agent should connect to. -MCP servers can be connected to using different transports. All Agents **MUST** support the stdio transport, while HTTP and SSE transports are optional capabilities that can be checked during initialization. - -While they are not required to by the spec, new Agents **SHOULD** support the HTTP transport to ensure compatibility with modern MCP servers. +MCP servers can be connected to using different transports. Agents advertise supported transports during initialization using `mcp.stdio`, `mcp.http`, and any extension-specific transport capabilities. ### Transport Types +Every MCP server object has a `type` discriminator that identifies its transport. Custom implementation-specific transport types **MUST** begin with `_`; unknown non-underscore transport types are reserved for future ACP variants. + #### Stdio Transport -All Agents **MUST** support connecting to MCP servers via stdio (standard input/output). This is the default transport mechanism. +When the Agent supports `mcp.stdio`, Clients can specify MCP servers configurations using the stdio transport. + + + Must be `"stdio"` to indicate stdio transport + A human-readable identifier for the server @@ -436,6 +443,7 @@ Example stdio transport configuration: ```json { + "type": "stdio", "name": "workspace-tools", "command": "/path/to/mcp-server", "args": ["--stdio"], @@ -497,56 +505,9 @@ Example HTTP transport configuration: } ``` -#### SSE Transport - -When the Agent supports `mcp.sse`, Clients can specify MCP servers configurations using the SSE transport. - -This transport was deprecated by the MCP spec. - - - Must be `"sse"` to indicate SSE transport - - - - A human-readable identifier for the server - - - - The URL of the SSE endpoint - - - - HTTP headers to include when establishing the SSE connection - - - - The name of the HTTP header. - - - The value to set for the HTTP header. - - - - -Example SSE transport configuration: - -```json -{ - "type": "sse", - "name": "event-stream", - "url": "https://events.example.com/mcp", - "headers": [ - { - "name": "X-API-Key", - "value": "apikey456" - } - ] -} -``` - ### Checking Transport Support -Before using HTTP or SSE transports, Clients **MUST** verify the Agent's capabilities during initialization: +Before using stdio or HTTP transports, Clients **MUST** verify the Agent's capabilities during initialization: ```json highlight={7-10} { @@ -556,16 +517,16 @@ Before using HTTP or SSE transports, Clients **MUST** verify the Agent's capabil "protocolVersion": 2, "capabilities": { "mcp": { - "http": {}, - "sse": {} + "stdio": {}, + "http": {} } } } } ``` +If `mcp.stdio` is omitted or `null`, the Agent does not support stdio transport. If `mcp.http` is omitted or `null`, the Agent does not support HTTP transport. -If `mcp.sse` is omitted or `null`, the Agent does not support SSE transport. Supplying `{}` means the Agent supports the corresponding transport. Agents **SHOULD** connect to all MCP servers specified by the Client. diff --git a/docs/protocol/v2/initialization.mdx b/docs/protocol/v2/initialization.mdx index c0bb62abd..209fdea0f 100644 --- a/docs/protocol/v2/initialization.mdx +++ b/docs/protocol/v2/initialization.mdx @@ -65,8 +65,8 @@ The Agent **MUST** respond with the chosen [protocol version](#protocol-version) "embeddedContext": {} }, "mcp": { - "http": {}, - "sse": {} + "stdio": {}, + "http": {} } }, "agentInfo": { @@ -157,21 +157,18 @@ Optionally, they **MAY** support richer types of [content](/protocol/v2/content) #### MCP capabilities + + The Agent supports connecting to MCP servers over stdio. Omitted or `null` + means the Agent does not advertise support. Supplying `{}` means the Agent + supports stdio MCP server transports. + + The Agent supports connecting to MCP servers over HTTP. Omitted or `null` means the Agent does not advertise support. Supplying `{}` means the Agent supports HTTP MCP server transports. - - The Agent supports connecting to MCP servers over SSE. Omitted or `null` means - the Agent does not advertise support. Supplying `{}` means the Agent supports - SSE MCP server transports. - -Note: This transport has been deprecated by the MCP spec. - - - #### Authentication Capabilities diff --git a/docs/protocol/v2/schema.mdx b/docs/protocol/v2/schema.mdx index bdfe06b7e..2364f8682 100644 --- a/docs/protocol/v2/schema.mdx +++ b/docs/protocol/v2/schema.mdx @@ -1790,11 +1790,11 @@ Optional. Omitted or `null` both mean the agent does not advertise support. Supplying `\{\}` means the agent supports HTTP MCP server transports. -McpSseCapabilities | null} > - Agent supports `McpServer::Sse`. +McpStdioCapabilities | null} > + Agent supports `McpServer::Stdio`. Optional. Omitted or `null` both mean the agent does not advertise support. -Supplying `\{\}` means the agent supports SSE MCP server transports. +Supplying `\{\}` means the agent supports stdio MCP server transports. @@ -1859,41 +1859,10 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v2/e - -SSE transport configuration - -Only available when the Agent capabilities include `mcp.sse`. - - - - - The _meta property is reserved by ACP to allow clients and agents to attach additional -metadata to their interactions. Implementations MUST NOT make assumptions about values at -these keys. - -See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v2/extensibility) - - -HttpHeader[]} required> - HTTP headers to set when making requests to the MCP server. - - - Human-readable name identifying this MCP server. - - - The discriminator value. Must be `"sse"`. - - - URL to the MCP server. - - - - - - + Stdio transport configuration -All Agents MUST support this transport. +Only available when the Agent capabilities include `mcp.stdio`. @@ -1917,39 +1886,41 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v2/e Human-readable name identifying this MCP server. + + The discriminator value. Must be `"stdio"`. + -## McpServerHttp + +Custom or future MCP server transport configuration. -HTTP transport configuration for MCP. +Values beginning with `_` are reserved for implementation-specific +extensions. Unknown values that do not begin with `_` are reserved for +future ACP variants. -**Type:** Object +Receivers that do not understand this transport should preserve the raw +payload when storing, replaying, proxying, or forwarding session setup +data, and otherwise ignore it or reject the server configuration. -**Properties:** + - - The _meta property is reserved by ACP to allow clients and agents to attach additional -metadata to their interactions. Implementations MUST NOT make assumptions about values at -these keys. + + Custom or future MCP server transport type. -See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v2/extensibility) +Values beginning with `_` are reserved for implementation-specific +extensions. Unknown values that do not begin with `_` are reserved for +future ACP variants. -HttpHeader[]} required> - HTTP headers to set when making requests to the MCP server. - - - Human-readable name identifying this MCP server. - - - URL to the MCP server. + + -## McpServerSse +## McpServerHttp -SSE transport configuration for MCP. +HTTP transport configuration for MCP. **Type:** Object @@ -2002,11 +1973,11 @@ See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/v2/e Human-readable name identifying this MCP server. -## McpSseCapabilities +## McpStdioCapabilities -Capabilities for SSE MCP server transports. +Capabilities for stdio MCP server transports. -Supplying `\{\}` means the agent supports SSE MCP server transports. +Supplying `\{\}` means the agent supports stdio MCP server transports. **Type:** Object diff --git a/docs/protocol/v2/session-setup.mdx b/docs/protocol/v2/session-setup.mdx index 16c02a8fb..664f9d72a 100644 --- a/docs/protocol/v2/session-setup.mdx +++ b/docs/protocol/v2/session-setup.mdx @@ -58,6 +58,7 @@ Clients create a new session by calling the `session/new` method with: "cwd": "/home/user/project", "mcpServers": [ { + "type": "stdio", "name": "workspace-tools", "command": "/path/to/mcp-server", "args": ["--stdio"], @@ -123,6 +124,7 @@ To load an existing session, Clients **MUST** call the `session/load` method wit "cwd": "/home/user/project", "mcpServers": [ { + "type": "stdio", "name": "workspace-tools", "command": "/path/to/mcp-server", "args": ["--mode", "workspace"], @@ -228,6 +230,7 @@ To resume an existing session without replaying prior messages, Clients **MUST** "cwd": "/home/user/project", "mcpServers": [ { + "type": "stdio", "name": "workspace-tools", "command": "/path/to/mcp-server", "args": ["--mode", "workspace"], @@ -369,15 +372,19 @@ When `session.additionalDirectories` is in use, the session's effective root set The [Model Context Protocol (MCP)](https://modelcontextprotocol.io) allows Agents to access external tools and data sources. When creating a session, Clients **MAY** include connection details for MCP servers that the Agent should connect to. -MCP servers can be connected to using different transports. All Agents **MUST** support the stdio transport, while HTTP and SSE transports are optional capabilities that can be checked during initialization. - -While they are not required to by the spec, new Agents **SHOULD** support the HTTP transport to ensure compatibility with modern MCP servers. +MCP servers can be connected to using different transports. Agents advertise supported transports during initialization using `mcp.stdio`, `mcp.http`, and any extension-specific transport capabilities. ### Transport Types +Every MCP server object has a `type` discriminator that identifies its transport. Custom implementation-specific transport types **MUST** begin with `_`; unknown non-underscore transport types are reserved for future ACP variants. + #### Stdio Transport -All Agents **MUST** support connecting to MCP servers via stdio (standard input/output). This is the default transport mechanism. +When the Agent supports `mcp.stdio`, Clients can specify MCP servers configurations using the stdio transport. + + + Must be `"stdio"` to indicate stdio transport + A human-readable identifier for the server @@ -408,6 +415,7 @@ Example stdio transport configuration: ```json { + "type": "stdio", "name": "workspace-tools", "command": "/path/to/mcp-server", "args": ["--stdio"], @@ -469,56 +477,9 @@ Example HTTP transport configuration: } ``` -#### SSE Transport - -When the Agent supports `mcp.sse`, Clients can specify MCP servers configurations using the SSE transport. - -This transport was deprecated by the MCP spec. - - - Must be `"sse"` to indicate SSE transport - - - - A human-readable identifier for the server - - - - The URL of the SSE endpoint - - - - HTTP headers to include when establishing the SSE connection - - - - The name of the HTTP header. - - - The value to set for the HTTP header. - - - - -Example SSE transport configuration: - -```json -{ - "type": "sse", - "name": "event-stream", - "url": "https://events.example.com/mcp", - "headers": [ - { - "name": "X-API-Key", - "value": "apikey456" - } - ] -} -``` - ### Checking Transport Support -Before using HTTP or SSE transports, Clients **MUST** verify the Agent's capabilities during initialization: +Before using stdio or HTTP transports, Clients **MUST** verify the Agent's capabilities during initialization: ```json highlight={7-10} { @@ -528,16 +489,16 @@ Before using HTTP or SSE transports, Clients **MUST** verify the Agent's capabil "protocolVersion": 2, "capabilities": { "mcp": { - "http": {}, - "sse": {} + "stdio": {}, + "http": {} } } } } ``` +If `mcp.stdio` is omitted or `null`, the Agent does not support stdio transport. If `mcp.http` is omitted or `null`, the Agent does not support HTTP transport. -If `mcp.sse` is omitted or `null`, the Agent does not support SSE transport. Supplying `{}` means the Agent supports the corresponding transport. Agents **SHOULD** connect to all MCP servers specified by the Client. diff --git a/docs/rfds/v2/overview.mdx b/docs/rfds/v2/overview.mdx index 092f3ecc7..999533937 100644 --- a/docs/rfds/v2/overview.mdx +++ b/docs/rfds/v2/overview.mdx @@ -49,12 +49,18 @@ Other RFDs will progress separately and are not dependent on breaking changes (s - Use concise capability group names such as `prompt`, `mcp`, `session`, and `auth`, replacing names like `promptCapabilities`, `mcpCapabilities`, and `sessionCapabilities`. - Move `loadSession` into the session capability group as `session.load`. - Represent support markers as capability objects instead of booleans. Supplying `{}` means supported, while omission or `null` means unsupported. Booleans remain appropriate for actual data or configuration inside an already-advertised capability. +- Align MCP server transports with the current MCP transport model: + - Remove the deprecated HTTP+SSE MCP transport from v2. + - Make stdio an explicit `mcp.stdio` capability so Agents that cannot launch local subprocesses can opt out. + - Require MCP server configurations to include a `type` discriminator, including `type: "stdio"`, so unknown future transports can be preserved as extension/future variants. + - Keep HTTP as the remote MCP server transport capability. ### RFDs to be Written Changes under consideration that still need to be drafted or moved to draft: - Capabilities: decide whether any additional capability groups should become required. +- Audit remaining enums and clean up any "untagged" enum variants that still block graceful handling of new variants. - Streaming/Non-streaming consistency: Offer both options for both messages and tool calls - Also Terminal Output type for streaming terminal output from an agent - Expand diff types (delete, move) @@ -94,7 +100,7 @@ With the needed breaking changes, as much as possible I am targeting having a co ## Revision history -- 2026-06-05: Recorded the v2 capability cleanup: unified initialize capability fields, shorter capability group names, `session.load`, and object-shaped support markers. +- 2026-06-05: Recorded the v2 capability cleanup: unified initialize capability fields, shorter capability group names, `session.load`, object-shaped support markers, explicit `mcp.stdio`, removal of deprecated MCP SSE transport, and tagged MCP server transport configs. - 2026-06-02: Recorded the v2 decision to follow JSON-RPC 2.0 batch request and notification behavior. - 2026-06-02: Recorded the v2 decision to remove Client filesystem and terminal execution capabilities, methods, and terminal tool-call content. - 2026-06-02: Added the v2 Plan Variants RFD to make item-based `plan_update` the default v2 plan shape. diff --git a/schema/schema.v2.unstable.json b/schema/schema.v2.unstable.json index fa24cabbc..dde93b661 100644 --- a/schema/schema.v2.unstable.json +++ b/schema/schema.v2.unstable.json @@ -3359,16 +3359,16 @@ "description": "Agent supports [`McpServer::Http`].\n\nOptional. Omitted or `null` both mean the agent does not advertise support.\nSupplying `{}` means the agent supports HTTP MCP server transports.", "x-deserialize-default-on-error": true }, - "sse": { + "stdio": { "anyOf": [ { - "$ref": "#/$defs/McpSseCapabilities" + "$ref": "#/$defs/McpStdioCapabilities" }, { "type": "null" } ], - "description": "Agent supports [`McpServer::Sse`].\n\nOptional. Omitted or `null` both mean the agent does not advertise support.\nSupplying `{}` means the agent supports SSE MCP server transports.", + "description": "Agent supports [`McpServer::Stdio`].\n\nOptional. Omitted or `null` both mean the agent does not advertise support.\nSupplying `{}` means the agent supports stdio MCP server transports.", "x-deserialize-default-on-error": true } }, @@ -3410,13 +3410,13 @@ { "allOf": [ { - "$ref": "#/$defs/McpServerSse" + "$ref": "#/$defs/McpServerAcp" } ], - "description": "SSE transport configuration\n\nOnly available when the Agent capabilities include `mcp.sse`.", + "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nACP transport configuration\n\nOnly available when the Agent capabilities include `mcp.acp`.\nThe MCP server is provided by an ACP component and communicates over the ACP channel.", "properties": { "type": { - "const": "sse", + "const": "acp", "type": "string" } }, @@ -3426,13 +3426,13 @@ { "allOf": [ { - "$ref": "#/$defs/McpServerAcp" + "$ref": "#/$defs/McpServerStdio" } ], - "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nACP transport configuration\n\nOnly available when the Agent capabilities include `mcp.acp`.\nThe MCP server is provided by an ACP component and communicates over the ACP channel.", + "description": "Stdio transport configuration\n\nOnly available when the Agent capabilities include `mcp.stdio`.", "properties": { "type": { - "const": "acp", + "const": "stdio", "type": "string" } }, @@ -3440,16 +3440,57 @@ "type": "object" }, { - "allOf": [ - { - "$ref": "#/$defs/McpServerStdio" + "additionalProperties": true, + "description": "Custom or future MCP server transport configuration.\n\nValues beginning with `_` are reserved for implementation-specific\nextensions. Unknown values that do not begin with `_` are reserved for\nfuture ACP variants.\n\nReceivers that do not understand this transport should preserve the raw\npayload when storing, replaying, proxying, or forwarding session setup\ndata, and otherwise ignore it or reject the server configuration.", + "not": { + "anyOf": [ + { + "properties": { + "type": { + "const": "http", + "type": "string" + } + }, + "required": ["type"], + "type": "object" + }, + { + "properties": { + "type": { + "const": "stdio", + "type": "string" + } + }, + "required": ["type"], + "type": "object" + }, + { + "properties": { + "type": { + "const": "acp", + "type": "string" + } + }, + "required": ["type"], + "type": "object" + } + ] + }, + "properties": { + "type": { + "description": "Custom or future MCP server transport type.\n\nValues beginning with `_` are reserved for implementation-specific\nextensions. Unknown values that do not begin with `_` are reserved for\nfuture ACP variants.", + "type": "string" } - ], - "description": "Stdio transport configuration\n\nAll Agents MUST support this transport.", - "title": "stdio" + }, + "required": ["type"], + "title": "other", + "type": "object" } ], - "description": "Configuration for connecting to an MCP (Model Context Protocol) server.\n\nMCP servers provide tools and context that the agent can use when\nprocessing prompts.\n\nSee protocol docs: [MCP Servers](https://agentclientprotocol.com/protocol/session-setup#mcp-servers)" + "description": "Configuration for connecting to an MCP (Model Context Protocol) server.\n\nMCP servers provide tools and context that the agent can use when\nprocessing prompts.\n\nSee protocol docs: [MCP Servers](https://agentclientprotocol.com/protocol/session-setup#mcp-servers)", + "discriminator": { + "propertyName": "type" + } }, "McpServerAcp": { "description": "**UNSTABLE**\n\nThis capability is not part of the spec yet, and may be removed or changed at any point.\n\nACP transport configuration for MCP.\n\nThe MCP server is provided by an ACP component and communicates over the ACP channel\nusing `mcp/connect`, `mcp/message`, and `mcp/disconnect`.", @@ -3506,33 +3547,6 @@ "required": ["name", "url", "headers"], "type": "object" }, - "McpServerSse": { - "description": "SSE transport configuration for MCP.", - "properties": { - "_meta": { - "additionalProperties": true, - "description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)", - "type": ["object", "null"] - }, - "headers": { - "description": "HTTP headers to set when making requests to the MCP server.", - "items": { - "$ref": "#/$defs/HttpHeader" - }, - "type": "array" - }, - "name": { - "description": "Human-readable name identifying this MCP server.", - "type": "string" - }, - "url": { - "description": "URL to the MCP server.", - "type": "string" - } - }, - "required": ["name", "url", "headers"], - "type": "object" - }, "McpServerStdio": { "description": "Stdio transport configuration for MCP.", "properties": { @@ -3567,8 +3581,8 @@ "required": ["name", "command", "args", "env"], "type": "object" }, - "McpSseCapabilities": { - "description": "Capabilities for SSE MCP server transports.\n\nSupplying `{}` means the agent supports SSE MCP server transports.", + "McpStdioCapabilities": { + "description": "Capabilities for stdio MCP server transports.\n\nSupplying `{}` means the agent supports stdio MCP server transports.", "properties": { "_meta": { "additionalProperties": true, diff --git a/src/v2/agent.rs b/src/v2/agent.rs index febfe688a..5f8da3a6b 100644 --- a/src/v2/agent.rs +++ b/src/v2/agent.rs @@ -2642,16 +2642,13 @@ impl SetSessionConfigOptionResponse { /// See protocol docs: [MCP Servers](https://agentclientprotocol.com/protocol/session-setup#mcp-servers) #[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] #[serde(tag = "type", rename_all = "snake_case")] +#[schemars(extend("discriminator" = {"propertyName": "type"}))] #[non_exhaustive] pub enum McpServer { /// HTTP transport configuration /// /// Only available when the Agent capabilities include `mcp.http`. Http(McpServerHttp), - /// SSE transport configuration - /// - /// Only available when the Agent capabilities include `mcp.sse`. - Sse(McpServerSse), /// **UNSTABLE** /// /// This capability is not part of the spec yet, and may be removed or changed at any point. @@ -2664,68 +2661,102 @@ pub enum McpServer { Acp(McpServerAcp), /// Stdio transport configuration /// - /// All Agents MUST support this transport. - #[serde(untagged)] + /// Only available when the Agent capabilities include `mcp.stdio`. Stdio(McpServerStdio), + /// Custom or future MCP server transport configuration. + /// + /// Values beginning with `_` are reserved for implementation-specific + /// extensions. Unknown values that do not begin with `_` are reserved for + /// future ACP variants. + /// + /// Receivers that do not understand this transport should preserve the raw + /// payload when storing, replaying, proxying, or forwarding session setup + /// data, and otherwise ignore it or reject the server configuration. + #[serde(untagged)] + Other(OtherMcpServer), } -/// HTTP transport configuration for MCP. -#[skip_serializing_none] -#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] +/// Custom or future MCP server transport payload. +#[derive(Debug, Clone, Serialize, JsonSchema, PartialEq, Eq)] +#[schemars(inline)] +#[schemars(transform = other_mcp_server_schema)] #[serde(rename_all = "camelCase")] #[non_exhaustive] -pub struct McpServerHttp { - /// Human-readable name identifying this MCP server. - pub name: String, - /// URL to the MCP server. - pub url: String, - /// HTTP headers to set when making requests to the MCP server. - pub headers: Vec, - /// The _meta property is reserved by ACP to allow clients and agents to attach additional - /// metadata to their interactions. Implementations MUST NOT make assumptions about values at - /// these keys. +pub struct OtherMcpServer { + /// Custom or future MCP server transport type. /// - /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) - #[serde(rename = "_meta")] - pub meta: Option, + /// Values beginning with `_` are reserved for implementation-specific + /// extensions. Unknown values that do not begin with `_` are reserved for + /// future ACP variants. + #[serde(rename = "type")] + pub type_: String, + /// Additional fields from the unknown MCP server transport payload. + #[serde(flatten)] + pub fields: BTreeMap, } -impl McpServerHttp { +impl OtherMcpServer { #[must_use] - pub fn new(name: impl Into, url: impl Into) -> Self { + pub fn new(type_: impl Into, mut fields: BTreeMap) -> Self { + fields.remove("type"); Self { - name: name.into(), - url: url.into(), - headers: Vec::new(), - meta: None, + type_: type_.into(), + fields, } } +} - /// HTTP headers to set when making requests to the MCP server. - #[must_use] - pub fn headers(mut self, headers: Vec) -> Self { - self.headers = headers; - self +impl<'de> Deserialize<'de> for OtherMcpServer { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let mut fields = BTreeMap::::deserialize(deserializer)?; + let type_ = fields + .remove("type") + .ok_or_else(|| serde::de::Error::missing_field("type"))?; + let serde_json::Value::String(type_) = type_ else { + return Err(serde::de::Error::custom("`type` must be a string")); + }; + + if is_known_mcp_server_type(&type_) { + return Err(serde::de::Error::custom(format!( + "known MCP server transport `{type_}` did not match its schema" + ))); + } + + Ok(Self { type_, fields }) } +} - /// The _meta property is reserved by ACP to allow clients and agents to attach additional - /// metadata to their interactions. Implementations MUST NOT make assumptions about values at - /// these keys. - /// - /// See protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility) - #[must_use] - pub fn meta(mut self, meta: impl IntoOption) -> Self { - self.meta = meta.into_option(); - self +fn is_known_mcp_server_type(type_: &str) -> bool { + match type_ { + "http" | "stdio" => true, + #[cfg(feature = "unstable_mcp_over_acp")] + "acp" => true, + _ => false, } } -/// SSE transport configuration for MCP. +fn other_mcp_server_schema(schema: &mut Schema) { + super::schema_util::reject_known_string_discriminators( + schema, + "type", + &[ + "http", + "stdio", + #[cfg(feature = "unstable_mcp_over_acp")] + "acp", + ], + ); +} + +/// HTTP transport configuration for MCP. #[skip_serializing_none] #[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] #[serde(rename_all = "camelCase")] #[non_exhaustive] -pub struct McpServerSse { +pub struct McpServerHttp { /// Human-readable name identifying this MCP server. pub name: String, /// URL to the MCP server. @@ -2741,7 +2772,7 @@ pub struct McpServerSse { pub meta: Option, } -impl McpServerSse { +impl McpServerHttp { #[must_use] pub fn new(name: impl Into, url: impl Into) -> Self { Self { @@ -4441,22 +4472,22 @@ impl PromptEmbeddedContextCapabilities { #[serde(rename_all = "camelCase")] #[non_exhaustive] pub struct McpCapabilities { - /// Agent supports [`McpServer::Http`]. + /// Agent supports [`McpServer::Stdio`]. /// /// Optional. Omitted or `null` both mean the agent does not advertise support. - /// Supplying `{}` means the agent supports HTTP MCP server transports. + /// Supplying `{}` means the agent supports stdio MCP server transports. #[serde_as(deserialize_as = "DefaultOnError")] #[schemars(extend("x-deserialize-default-on-error" = true))] #[serde(default)] - pub http: Option, - /// Agent supports [`McpServer::Sse`]. + pub stdio: Option, + /// Agent supports [`McpServer::Http`]. /// /// Optional. Omitted or `null` both mean the agent does not advertise support. - /// Supplying `{}` means the agent supports SSE MCP server transports. + /// Supplying `{}` means the agent supports HTTP MCP server transports. #[serde_as(deserialize_as = "DefaultOnError")] #[schemars(extend("x-deserialize-default-on-error" = true))] #[serde(default)] - pub sse: Option, + pub http: Option, /// **UNSTABLE** /// /// This capability is not part of the spec yet, and may be removed or changed at any point. @@ -4485,23 +4516,23 @@ impl McpCapabilities { Self::default() } - /// Agent supports [`McpServer::Http`]. + /// Agent supports [`McpServer::Stdio`]. /// /// Omitted or `null` both mean the agent does not advertise support. - /// Supplying `{}` means the agent supports HTTP MCP server transports. + /// Supplying `{}` means the agent supports stdio MCP server transports. #[must_use] - pub fn http(mut self, http: impl IntoOption) -> Self { - self.http = http.into_option(); + pub fn stdio(mut self, stdio: impl IntoOption) -> Self { + self.stdio = stdio.into_option(); self } - /// Agent supports [`McpServer::Sse`]. + /// Agent supports [`McpServer::Http`]. /// /// Omitted or `null` both mean the agent does not advertise support. - /// Supplying `{}` means the agent supports SSE MCP server transports. + /// Supplying `{}` means the agent supports HTTP MCP server transports. #[must_use] - pub fn sse(mut self, sse: impl IntoOption) -> Self { - self.sse = sse.into_option(); + pub fn http(mut self, http: impl IntoOption) -> Self { + self.http = http.into_option(); self } @@ -4532,13 +4563,13 @@ impl McpCapabilities { } } -/// Capabilities for HTTP MCP server transports. +/// Capabilities for stdio MCP server transports. /// -/// Supplying `{}` means the agent supports HTTP MCP server transports. +/// Supplying `{}` means the agent supports stdio MCP server transports. #[skip_serializing_none] #[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] #[non_exhaustive] -pub struct McpHttpCapabilities { +pub struct McpStdioCapabilities { /// The _meta property is reserved by ACP to allow clients and agents to attach additional /// metadata to their interactions. Implementations MUST NOT make assumptions about values at /// these keys. @@ -4548,7 +4579,7 @@ pub struct McpHttpCapabilities { pub meta: Option, } -impl McpHttpCapabilities { +impl McpStdioCapabilities { #[must_use] pub fn new() -> Self { Self::default() @@ -4566,13 +4597,13 @@ impl McpHttpCapabilities { } } -/// Capabilities for SSE MCP server transports. +/// Capabilities for HTTP MCP server transports. /// -/// Supplying `{}` means the agent supports SSE MCP server transports. +/// Supplying `{}` means the agent supports HTTP MCP server transports. #[skip_serializing_none] #[derive(Default, Debug, Clone, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] #[non_exhaustive] -pub struct McpSseCapabilities { +pub struct McpHttpCapabilities { /// The _meta property is reserved by ACP to allow clients and agents to attach additional /// metadata to their interactions. Implementations MUST NOT make assumptions about values at /// these keys. @@ -4582,7 +4613,7 @@ pub struct McpSseCapabilities { pub meta: Option, } -impl McpSseCapabilities { +impl McpHttpCapabilities { #[must_use] pub fn new() -> Self { Self::default() @@ -5224,6 +5255,7 @@ mod test_serialization { assert_eq!( json, json!({ + "type": "stdio", "name": "test-server", "command": "/usr/bin/server", "args": ["--port", "3000"], @@ -5256,6 +5288,51 @@ mod test_serialization { } } + #[test] + fn test_mcp_server_unknown_transport_serialization() { + let json = json!({ + "type": "websocket", + "name": "future-server", + "url": "wss://example.com/mcp", + "protocolVersion": "2026-01-01" + }); + + let deserialized: McpServer = serde_json::from_value(json.clone()).unwrap(); + let McpServer::Other(OtherMcpServer { type_, fields }) = &deserialized else { + panic!("Expected Other variant"); + }; + + assert_eq!(type_, "websocket"); + assert_eq!(fields["name"], "future-server"); + assert_eq!(fields["url"], "wss://example.com/mcp"); + assert_eq!(fields["protocolVersion"], "2026-01-01"); + assert_eq!(serde_json::to_value(&deserialized).unwrap(), json); + } + + #[test] + fn test_mcp_server_stdio_requires_type() { + let result = serde_json::from_value::(json!({ + "name": "test-server", + "command": "/usr/bin/server", + "args": [], + "env": [] + })); + + assert!(result.is_err()); + } + + #[test] + fn test_mcp_server_unknown_does_not_hide_malformed_known_transport() { + let result = serde_json::from_value::(json!({ + "type": "stdio", + "name": "test-server", + "args": [], + "env": [] + })); + + assert!(result.is_err()); + } + #[test] fn test_mcp_server_http_serialization() { let server = McpServer::Http( @@ -5325,47 +5402,6 @@ mod test_serialization { ); } - #[test] - fn test_mcp_server_sse_serialization() { - let server = McpServer::Sse( - McpServerSse::new("sse-server", "https://sse.example.com/events") - .headers(vec![HttpHeader::new("X-API-Key", "apikey456")]), - ); - - let json = serde_json::to_value(&server).unwrap(); - assert_eq!( - json, - json!({ - "type": "sse", - "name": "sse-server", - "url": "https://sse.example.com/events", - "headers": [ - { - "name": "X-API-Key", - "value": "apikey456" - } - ] - }) - ); - - let deserialized: McpServer = serde_json::from_value(json).unwrap(); - match deserialized { - McpServer::Sse(McpServerSse { - name, - url, - headers, - meta: _, - }) => { - assert_eq!(name, "sse-server"); - assert_eq!(url, "https://sse.example.com/events"); - assert_eq!(headers.len(), 1); - assert_eq!(headers[0].name, "X-API-Key"); - assert_eq!(headers[0].value, "apikey456"); - } - _ => panic!("Expected Sse variant"), - } - } - #[test] fn test_session_config_option_category_known_variants() { // Test serialization of known variants @@ -6428,24 +6464,24 @@ mod test_serialization { #[test] fn test_mcp_capabilities_serialize_supported_transports_as_objects() { let caps = McpCapabilities::new() - .http(McpHttpCapabilities::new()) - .sse(McpSseCapabilities::new()); + .stdio(McpStdioCapabilities::new()) + .http(McpHttpCapabilities::new()); assert_eq!( serde_json::to_value(&caps).unwrap(), json!({ - "http": {}, - "sse": {} + "stdio": {}, + "http": {} }) ); let deserialized: McpCapabilities = serde_json::from_value(json!({ - "http": null, - "sse": false + "stdio": null, + "http": false })) .unwrap(); + assert!(deserialized.stdio.is_none()); assert!(deserialized.http.is_none()); - assert!(deserialized.sse.is_none()); } #[cfg(feature = "unstable_mcp_over_acp")] diff --git a/src/v2/conversion.rs b/src/v2/conversion.rs index 90d1cf608..178e251e1 100644 --- a/src/v2/conversion.rs +++ b/src/v2/conversion.rs @@ -3818,10 +3818,10 @@ impl IntoV1 for super::McpServer { fn into_v1(self) -> Result { Ok(match self { Self::Http(value) => crate::v1::McpServer::Http(value.into_v1()?), - Self::Sse(value) => crate::v1::McpServer::Sse(value.into_v1()?), #[cfg(feature = "unstable_mcp_over_acp")] Self::Acp(value) => crate::v1::McpServer::Acp(value.into_v1()?), Self::Stdio(value) => crate::v1::McpServer::Stdio(value.into_v1()?), + Self::Other(value) => return Err(unknown_v2_enum_variant("McpServer", &value.type_)), }) } } @@ -3832,7 +3832,7 @@ impl IntoV2 for crate::v1::McpServer { fn into_v2(self) -> Result { Ok(match self { Self::Http(value) => super::McpServer::Http(value.into_v2()?), - Self::Sse(value) => super::McpServer::Sse(value.into_v2()?), + Self::Sse(_) => return Err(removed_v1_enum_variant("McpServer", "sse")), #[cfg(feature = "unstable_mcp_over_acp")] Self::Acp(value) => super::McpServer::Acp(value.into_v2()?), Self::Stdio(value) => super::McpServer::Stdio(value.into_v2()?), @@ -3878,44 +3878,6 @@ impl IntoV2 for crate::v1::McpServerHttp { } } -impl IntoV1 for super::McpServerSse { - type Output = crate::v1::McpServerSse; - - fn into_v1(self) -> Result { - let Self { - name, - url, - headers, - meta, - } = self; - Ok(crate::v1::McpServerSse { - name: name.into_v1()?, - url: url.into_v1()?, - headers: headers.into_v1()?, - meta: meta.into_v1()?, - }) - } -} - -impl IntoV2 for crate::v1::McpServerSse { - type Output = super::McpServerSse; - - fn into_v2(self) -> Result { - let Self { - name, - url, - headers, - meta, - } = self; - Ok(super::McpServerSse { - name: name.into_v2()?, - url: url.into_v2()?, - headers: headers.into_v2()?, - meta: meta.into_v2()?, - }) - } -} - #[cfg(feature = "unstable_mcp_over_acp")] impl IntoV1 for super::McpServerAcpId { type Output = crate::v1::McpServerAcpId; @@ -4828,15 +4790,15 @@ impl IntoV1 for super::McpCapabilities { fn into_v1(self) -> Result { let Self { + stdio: _, http, - sse, #[cfg(feature = "unstable_mcp_over_acp")] acp, meta, } = self; Ok(crate::v1::McpCapabilities { http: http.is_some(), - sse: sse.is_some(), + sse: false, #[cfg(feature = "unstable_mcp_over_acp")] acp: acp.is_some(), meta: meta.into_v1()?, @@ -4850,14 +4812,14 @@ impl IntoV2 for crate::v1::McpCapabilities { fn into_v2(self) -> Result { let Self { http, - sse, + sse: _, #[cfg(feature = "unstable_mcp_over_acp")] acp, meta, } = self; Ok(super::McpCapabilities { + stdio: Some(super::McpStdioCapabilities::new()), http: http.then(super::McpHttpCapabilities::new), - sse: sse.then(super::McpSseCapabilities::new), #[cfg(feature = "unstable_mcp_over_acp")] acp: acp.then(super::McpAcpCapabilities::new), meta: meta.into_v2()?, @@ -8715,18 +8677,19 @@ mod tests { } #[test] - fn v1_mcp_capability_bools_convert_to_v2_objects() { + fn v1_mcp_capabilities_convert_to_v2_transport_objects() { let v1_capabilities = v1::McpCapabilities::new().http(true).sse(true); let v2_capabilities: v2::McpCapabilities = v1_to_v2(v1_capabilities).expect("v1 -> v2 conversion"); let v2_json = serde_json::to_value(&v2_capabilities).expect("v2 serialize"); + assert_eq!(v2_json.pointer("/stdio"), Some(&serde_json::json!({}))); assert_eq!(v2_json.pointer("/http"), Some(&serde_json::json!({}))); - assert_eq!(v2_json.pointer("/sse"), Some(&serde_json::json!({}))); + assert_eq!(v2_json.pointer("/sse"), None); let v1_after: v1::McpCapabilities = v2_to_v1(v2_capabilities).expect("v2 -> v1 conversion"); assert!(v1_after.http); - assert!(v1_after.sse); + assert!(!v1_after.sse); } #[cfg(feature = "unstable_mcp_over_acp")] @@ -8870,16 +8833,53 @@ mod tests { ); } + #[test] + fn v1_mcp_sse_transport_does_not_convert_to_v2() { + assert_v1_to_v2_error( + v1::McpServer::Sse(v1::McpServerSse::new("events", "https://example.com/sse")), + "v1 McpServer variant `sse` cannot be represented in v2", + ); + } + + #[test] + fn v2_unknown_mcp_transport_does_not_convert_to_v1() { + assert_v2_to_v1_error( + v2::McpServer::Other(v2::OtherMcpServer::new("websocket", Default::default())), + "v2 McpServer variant `websocket` cannot be represented in v1", + ); + } + #[test] fn round_trips_new_session_request_with_mcp_variants() { let request = v1::NewSessionRequest::new("/workspace").mcp_servers(vec![ v1::McpServer::Stdio(v1::McpServerStdio::new("local", "/usr/bin/mcp")), v1::McpServer::Http(v1::McpServerHttp::new("remote", "https://example.com")), - v1::McpServer::Sse(v1::McpServerSse::new("events", "https://example.com/sse")), ]); assert_v1_round_trip::(request.clone()); - assert_json_eq_after_v1_to_v2::(request); + + let v2_request: v2::NewSessionRequest = v1_to_v2(request).expect("v1 -> v2 conversion"); + assert_eq!( + serde_json::to_value(&v2_request).expect("v2 serialize"), + serde_json::json!({ + "cwd": "/workspace", + "mcpServers": [ + { + "type": "stdio", + "name": "local", + "command": "/usr/bin/mcp", + "args": [], + "env": [] + }, + { + "type": "http", + "name": "remote", + "url": "https://example.com", + "headers": [] + } + ] + }) + ); } #[test]