Target branch: 2026-07-28-protocol-support
Requires:
Server accepts 2026-07-28 clients and 2025-xx clients on the same endpoint. Each request is served by the rules of its own protocol revision. Legacy clients see no change in behaviour.
Era selection
- A request is a 2026-07-28 request when it carries
_meta["io.modelcontextprotocol/protocolVersion"], when its MCP-Protocol-Version header names a stateless version, or when it uses a method that exists only in 2026-07-28, every other request is legacy
- On stdio there are no headers so
_meta and the method decide
- The server never uses an earlier request to interpret the current one
Modern request validation
- A request without
_meta.protocolVersion or _meta.clientCapabilities fails with -32602.
- A version in the header that differs from the version in `_meta`` fails with -32020.
- A version chimp does not support fails with -32022, with supported and requested in the error data.
- Any unknown method fail with -32601. notifications/initialized is not accepted.
- Over HTTP, validation errors return 400 and unknown methods return 404, as a plain JSON error and never as an SSE stream, every error response echoes the request id
server/discover
- The server answers with supported version (stateless version only), capabilities, instructions, cache hints and server info
Modern results
- Every result carries
resultType: complete and _meta.serverInfo
- The cacheable results (
tools/list, prompts/list, resources/list, resources/templates/list, resources/read, server/discover) carry TTL and cache scope, with 0 and private as fixed defaults
- An unknown resource fails with -32602 and
data.uri, legacy requests keep -32002.
notifications/message is sent only when the request carried _meta.logLevel, and only at or above that level
Request facts for handlers
- A tool, prompt or resource handler can read the request's protocol version, client capabilities, client info and log level via server context
Coverage
- The rules above hold for the sync and streaming servers, over HTTP and stdio, on ZIO, Ox and Pekko
- The conformance server offers the fixture tools
test_missing_capability and test_logging_tool
Spec:
Basic - Statelessness
Basic - _meta
Basic - Error Codes
Versioning - Protocol Version Negotiation
Versioning - Backward Compatibility
Streamable HTTP - Protocol Version Header
Streamable HTTP - Standard Request Headers
Streamable HTTP - Server Validation
Streamable HTTP - Earlier Streamable HTTP Revisions
stdio - Request Metadata
server/discover
Caching - Cacheable Results
Resources - Error Handling
Logging - Per-request log level
Conformance scenarios that must pass after this task:
- Server:
caching, sep-2164-resource-not-found, dns-rebinding-protection, completion-complete, tools-list,
tools-call-simple-text, tools-call-image, tools-call-audio, tools-call-embedded-resource,
tools-call-mixed-content, tools-call-error, tools-call-with-progress, server-sse-multiple-streams,
resources-list, resources-read-text, resources-read-binary, resources-templates-read, prompts-list,
prompts-get-simple, prompts-get-with-args, prompts-get-embedded-resource, prompts-get-with-image,
input-required-result-unsupported-methods. They leave the 2026-07-28 baseline.
Docs: yes.
- New page
docs/server/protocol.md (added to the toctree): supported versions, how the server selects the wire per
request, what a handler can read from the request context, the 400 and 404 mapping, no sessions
and no GET or DELETE, the resource error codes per era
Target branch: 2026-07-28-protocol-support
Requires:
Server accepts 2026-07-28 clients and 2025-xx clients on the same endpoint. Each request is served by the rules of its own protocol revision. Legacy clients see no change in behaviour.
Era selection
_meta["io.modelcontextprotocol/protocolVersion"], when itsMCP-Protocol-Versionheader names a stateless version, or when it uses a method that exists only in2026-07-28, every other request is legacy_metaand the method decideModern request validation
_meta.protocolVersionor_meta.clientCapabilitiesfails with -32602.server/discoverModern results
resultType: completeand_meta.serverInfotools/list,prompts/list,resources/list,resources/templates/list,resources/read,server/discover) carry TTL and cache scope, with 0 and private as fixed defaultsdata.uri, legacy requests keep -32002.notifications/messageis sent only when the request carried_meta.logLevel, and only at or above that levelRequest facts for handlers
Coverage
test_missing_capabilityandtest_logging_toolSpec:
Basic - Statelessness
Basic - _meta
Basic - Error Codes
Versioning - Protocol Version Negotiation
Versioning - Backward Compatibility
Streamable HTTP - Protocol Version Header
Streamable HTTP - Standard Request Headers
Streamable HTTP - Server Validation
Streamable HTTP - Earlier Streamable HTTP Revisions
stdio - Request Metadata
server/discover
Caching - Cacheable Results
Resources - Error Handling
Logging - Per-request log level
Conformance scenarios that must pass after this task:
caching,sep-2164-resource-not-found,dns-rebinding-protection,completion-complete,tools-list,tools-call-simple-text,tools-call-image,tools-call-audio,tools-call-embedded-resource,tools-call-mixed-content,tools-call-error,tools-call-with-progress,server-sse-multiple-streams,resources-list,resources-read-text,resources-read-binary,resources-templates-read,prompts-list,prompts-get-simple,prompts-get-with-args,prompts-get-embedded-resource,prompts-get-with-image,input-required-result-unsupported-methods. They leave the 2026-07-28 baseline.Docs: yes.
docs/server/protocol.md(added to the toctree): supported versions, how the server selects the wire perrequest, what a handler can read from the request context, the 400 and 404 mapping, no sessions
and no GET or DELETE, the resource error codes per era