Repository navigation
Description
This stems from a discord thread about the state of the v2026-07-28 spec for McpServer
For context, currently the McpServer is one spec behind on v2025-06-18 and there is another issue for adding the latest v2025-11-25 (#6157). However the current RC for v2026-07-28 throws a bit of a spanner in this as it will no longer be a progressive enhancement on top of the existing features but instead a bit of architectural shift toward a stateless protocol:
- the initialization handshake and protocol-level session are removed;
- protocol version and client capabilities are provided per request;
server/discoveradvertises supported versions and server capabilities;- some existing features are deprecated or moved into extensions;
- server-to-client interactions and HTTP behavior change.
This makes updating one shared set of MCP schemas increasingly difficult. Supporting one version by widening or replacing the current schemas risks changing the behavior expected by clients using another version.
Related work:
- Support MCP protocol version 2025-11-25 #6157 — support MCP protocol version
2025-11-25 - Add McpClient: Effect-native MCP client #6396 — add
McpClient, including2025-11-25server groundwork - Fix MCP Streamable HTTP transport compliance #6610 — Streamable HTTP transport compliance
- McpServer: no first-class support for MCP Apps (SEP-1865 / interactive UI resources) #6353 — MCP Apps / interactive UI suppor
Goal/Scope
Allow one McpServer endpoint to support multiple MCP protocol versions without combining incompatible versions into one permissive schema.
The server should declare the protocols it supports, then when a request arrives, the protocol version used by that client or request should determine:
- how the request is interpreted
- which lifecycle and capabilities apply
- which functionality is available
- the shape of the response returned to the client
Clients using different protocol versions should therefore be able to communicate with the same endpoint while each observes the schema and behavior defined by its selected version.
The protocol version must resolve the server to a specific wire shape and set of behaviors, rather than being metadata attached after the request has already been interpreted.
Initial built-in support would start at 2025-06-18. Older revisions can be considered separately if they are still needed and we can leave out the extensions for the time being until we have a clear direction.
Proposal
Allow an McpServer to declare the protocol versions it supports:
const Server = McpServer.layerHttp({
name: "Acme MCP",
version: "1.0.0",
path: "/mcp",
protocols: [
McpProtocol.v2026_07_28,
McpProtocol.v2025_11_25,
McpProtocol.v2025_06_18
]
})At a high level, each supported version would provide the protocol-specific interpretation of the server:
sequenceDiagram
participant Client as McpClient
participant Ingress as McpServer ingress
participant Protocol as Selected protocol behavior
participant Core as Shared MCP functionality
alt 2025-06-18 or 2025-11-25
Client->>Ingress: initialize with protocol version
Ingress->>Protocol: Select stateful protocol behavior
Protocol-->>Ingress: Version-specific initialize result
Ingress-->>Client: Negotiated version and session
Client->>Ingress: MCP request with session
else 2026-07-28
Client->>Ingress: MCP request with protocol version
Ingress->>Protocol: Select stateless protocol behavior
end
Protocol->>Protocol: Validate and decode request using selected schema
Protocol->>Core: Canonical MCP operation
Core-->>Protocol: Canonical result
Protocol->>Protocol: Encode result using the same selected schema
Protocol-->>Ingress: Version-specific response
Ingress-->>Client: Response matching the client's protocol version
Only one version-specific path is selected for a request. The same selection governs both request decoding and response encoding, so a request using 2025-06-18, for example, cannot be decoded or returned using the shape of 2025-11-25.
The shared MCP functionality represents what the server can do: tools, prompts, resources, and their handlers.
The version-specific behavior represents how a particular MCP specification exposes that functionality, including:
- request and response shapes
- capability representation
- initialization, discovery, and session behavior
- notifications and server-to-client interactions
- protocol-specific transport requirements
The exact implementation is open for discussion. One possible direction is a protocol adapter or similar boundary between the wire protocol and the shared server functionality. The important behavioral requirement is that protocol selection happens early enough that incompatible versions are interpreted independently, rather than being combined into one permissive schema.
For legacy protocols, selection may happen during initialization and remain associated with the session. For 2026-07-28, selection would instead happen per request using the version information carried by that request.
The questions I would like feedback on are:
- Does this describe the right behavioral boundary for supporting both stateful and stateless MCP revisions on one endpoint?
- Are there capabilities or lifecycle behaviors that cannot reasonably be projected from shared tools, prompts, and resources?
- Are there transport, authentication, or conformance requirements that should be considered before settling on an implementation?
Activity
lloydrichards commentedon Jul 25, 2026
I'm having quite a bit of success with the adapter-pattern here. What I've done and made is a
ProtocolAdaptorand aProtocolRegistrywhich can be used to build out differentRpcGroupfor the different protocols a server can support and then using the protocolVersion and clientId the request can be routed through the right group so the encoding and decoding are specific to the protocol.This is all hidden inside the McpServer so the client doesn't need to know whats happening but basically when a request for something like
tools/listis made, internally it checks the protocol version and then if supported will route it through the specific RpcGroupfor now I'll try keep this seem as small as possible and just stick with the current
v2025-06-18, but if it works then we can then parallelize the work for addingv2025-11-25andv2026-07-28without them stepping on each other 🤞