Skip to content

feat!: implement SEP-2575 stateless MCP - #985

Open
devcrocod wants to merge 2 commits into
mainfrom
devcrocod/sep-2575-stateless-mcp
Open

feat!: implement SEP-2575 stateless MCP#985
devcrocod wants to merge 2 commits into
mainfrom
devcrocod/sep-2575-stateless-mcp

Conversation

@devcrocod

Copy link
Copy Markdown
Contributor

Implements SEP-2575 alongside the legacy handshake era.
Closes #815

  • Per-request _meta envelope; resultType on every result, cache hints (ttlMs/cacheScope)
  • Error codes -32020/-32021/-32022; -32002 no longer emitted
  • server/discover (auto-registered); era-gated method registry
  • Modern Streamable HTTP: POST-only, sessionless, deferred SSE commit
  • Client version negotiation (Legacy/Auto/Pin) + opt-in response cache

Breaking Changes

  • RequestResult.meta: JsonObject? -> ResultMeta?; resultType added to result data classes
  • LATEST_PROTOCOL_VERSION -> 2026-07-28, SUPPORTED_PROTOCOL_VERSIONS deprecated
  • Legacy-only methods answer -32601 on modern connections

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

- split the version registry into handshake and modern revisions
- add `resultType` and cache hints to results; result `meta` becomes `ResultMeta`
- add error codes -32020/-32021/-32022; stop emitting -32002
- add `server/discover`, registered on every server
- gate each method by the eras it exists in
- add modern Streamable HTTP: POST-only, sessionless, deferred SSE commit
- add client version negotiation (Legacy/Auto/Pin) and a response cache
@devcrocod
devcrocod requested review from e5l and a lite review from Copilot September 8, 2026 11:07

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

A verified logic issue in ClientConnectionImpl.isMessageAccepted can incorrectly allow log notifications when there is no current request context, which violates the request-scoped opt-in semantics.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Implements SEP-2575 stateless (request-scoped) MCP alongside the legacy initialize-handshake lifecycle. This updates core wire types/serialization, adds dual-era Streamable HTTP routing and classification, introduces discovery/version negotiation, and adds an opt-in client response cache.

Changes:

  • Add modern/request-scoped lifecycle support: per-request _meta envelope, server/discover, era-gated method surface, and updated error codes.
  • Update core result wire format: ResultMeta, resultType across results, and cache directives (ttlMs/cacheScope) on the spec-defined cacheable results.
  • Add client-side version negotiation (Legacy/Auto/Pin) and a response cache keyed by method/params + invalidated by list-changed notifications.
File summaries
File Description
kotlin-sdk-server/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/server/StreamableHttpServerTransportTest.kt Adjust handshake-era tests for version constant + result meta type.
kotlin-sdk-server/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/server/StatelessStreamableHttpSessionLifecycleTest.kt Update stateless HTTP lifecycle tests to use handshake version constant.
kotlin-sdk-server/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/server/ModernStreamableHttpTest.kt New tests asserting modern Streamable HTTP contract (status codes, headers, SSE commit behavior).
kotlin-sdk-server/src/commonTest/kotlin/io/modelcontextprotocol/kotlin/sdk/server/ServerSessionAssertCapabilityTest.kt Update tests for renamed handshake version constant.
kotlin-sdk-server/src/commonTest/kotlin/io/modelcontextprotocol/kotlin/sdk/server/InboundClassificationTest.kt New classifier rung-by-rung tests for modern-vs-legacy inbound routing.
kotlin-sdk-server/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/StreamableHttpServerTransport.kt Support dual-era entry by accepting pre-read body; tighten handshake-version validation; use ordered version comparison.
kotlin-sdk-server/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/ServerSession.kt Track negotiated handshake protocol version and expose server-info stamping configuration.
kotlin-sdk-server/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/Server.kt Add server/discover auto-registration; allow non-subscribing request-scoped sessions; modernize error mapping behavior.
kotlin-sdk-server/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/LoggingLevels.kt New helper to compute per-request allowed logging levels under modern lifecycle.
kotlin-sdk-server/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/KtorServer.kt Route a single POST endpoint across both lifecycles by classifying the body once.
kotlin-sdk-server/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/server/ClientConnection.kt Enforce per-request capability declaration + modern-era restrictions; update log filtering behavior.
kotlin-sdk-server/api/kotlin-sdk-server.api API dump updates for ServerOptions and ServerSession surface changes.
kotlin-sdk-core/src/commonTest/kotlin/io/modelcontextprotocol/kotlin/sdk/types/WireTest.kt New tests for lifecycle-specific outbound wire shaping and error code mapping.
kotlin-sdk-core/src/commonTest/kotlin/io/modelcontextprotocol/kotlin/sdk/types/ToolsTest.kt Update expected serialization for ResultMeta, resultType, and caching directives.
kotlin-sdk-core/src/commonTest/kotlin/io/modelcontextprotocol/kotlin/sdk/types/TasksTest.kt Update expected serialization for resultType + ResultMeta.
kotlin-sdk-core/src/commonTest/kotlin/io/modelcontextprotocol/kotlin/sdk/types/SamplingTest.kt Update expected serialization for resultType + ResultMeta.
kotlin-sdk-core/src/commonTest/kotlin/io/modelcontextprotocol/kotlin/sdk/types/RootsTest.kt Update expected serialization for resultType + ResultMeta.
kotlin-sdk-core/src/commonTest/kotlin/io/modelcontextprotocol/kotlin/sdk/types/ResultTypeTest.kt New tests for defaulting/validation of resultType across result types.
kotlin-sdk-core/src/commonTest/kotlin/io/modelcontextprotocol/kotlin/sdk/types/ResourcesTest.kt Update expected serialization for resultType + caching directives + ResultMeta.
kotlin-sdk-core/src/commonTest/kotlin/io/modelcontextprotocol/kotlin/sdk/types/RequestTest.kt Update request-meta tests to use envelope conversion and new meta APIs.
kotlin-sdk-core/src/commonTest/kotlin/io/modelcontextprotocol/kotlin/sdk/types/ProtocolVersionsTest.kt New tests ensuring version partitioning and ordering semantics.
kotlin-sdk-core/src/commonTest/kotlin/io/modelcontextprotocol/kotlin/sdk/types/PromptsTest.kt Update expected serialization for resultType + caching directives + ResultMeta.
kotlin-sdk-core/src/commonTest/kotlin/io/modelcontextprotocol/kotlin/sdk/types/MethodEraTest.kt New tests asserting which methods exist in which lifecycle.
kotlin-sdk-core/src/commonTest/kotlin/io/modelcontextprotocol/kotlin/sdk/types/JsonRpcTest.kt Update test to use ResultMeta for response meta.
kotlin-sdk-core/src/commonTest/kotlin/io/modelcontextprotocol/kotlin/sdk/types/InitializeTest.kt Update expected initialize wire shape (now includes resultType in typed form).
kotlin-sdk-core/src/commonTest/kotlin/io/modelcontextprotocol/kotlin/sdk/types/ElicitationTest.kt Update expected serialization for resultType + ResultMeta.
kotlin-sdk-core/src/commonTest/kotlin/io/modelcontextprotocol/kotlin/sdk/types/DiscoveryTest.kt Update discovery request/result parsing expectations for envelope + tolerant cache defaults.
kotlin-sdk-core/src/commonTest/kotlin/io/modelcontextprotocol/kotlin/sdk/types/CompletionTest.kt Update expected serialization for resultType + ResultMeta.
kotlin-sdk-core/src/commonTest/kotlin/io/modelcontextprotocol/kotlin/sdk/types/CommonTypeTest.kt Update tests for new latest version constants and deprecated union behavior.
kotlin-sdk-core/src/commonTest/kotlin/io/modelcontextprotocol/kotlin/sdk/types/CacheableResultTest.kt New tests covering cache directive defaults, validation, and round-tripping.
kotlin-sdk-core/src/commonTest/kotlin/io/modelcontextprotocol/kotlin/sdk/shared/ProtocolOutboundCancellationTest.kt Update handshake protocol version constant in tests.
kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/wire.kt New outbound wire shaping + inbound resultType validation helpers.
kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/UrlElicitationRequiredException.kt Keep deprecated code accepted while documenting modern removal context.
kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/tools.kt Add resultType, migrate meta to ResultMeta, implement cacheable result fields/validation.
kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/tasks.kt Add resultType, migrate meta to ResultMeta, update payload result meta extraction.
kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/serializers.kt Update polymorphic selection rules for empty/discovery/initialize result decoding.
kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/sampling.kt Add resultType + ResultMeta to sampling results.
kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/roots.kt Add resultType + ResultMeta to roots results.
kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/resources.kt Add resultType, cache directives, and ResultMeta to resource results (+ validation).
kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/request.kt Introduce COMPLETE_RESULT_TYPE, reshape RequestResult, add claimedProtocolVersion.
kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/prompts.kt Add resultType, cache directives, and ResultMeta to prompt results (+ validation).
kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/methods.kt Add per-method lifecycle availability declarations.
kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/mcpHeaders.kt New shared constants + header value encoding/decoding for MCP HTTP headers.
kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/McpException.kt Keep accepting deprecated peer error codes while documenting intent.
kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/jsonRpc.kt Add new spec-reserved error codes and deprecate retired ones.
kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/initialize.kt InitializeResult defaults to latest handshake version; add resultType + ResultMeta.
kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/era.kt New internal era model and method availability predicate.
kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/elicitation.kt Add resultType + ResultMeta to elicitation results.
kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/discovery.kt Discovery request/result types updated for request-scoped lifecycle + cache directives.
kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/completion.kt Add resultType + ResultMeta to completion results.
kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/common.kt Split protocol versions by lifecycle; add version ordering helpers; introduce ResultMeta.
kotlin-sdk-core/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types/caching.kt New cache directives model (CacheScope, CacheableResult).
kotlin-sdk-client/src/commonTest/kotlin/io/modelcontextprotocol/kotlin/sdk/client/VersionNegotiationTest.kt New tests for modern probe classifier and fallback/pin behavior.
kotlin-sdk-client/src/commonTest/kotlin/io/modelcontextprotocol/kotlin/sdk/client/streamable/http/StreamableHttpClientTransportTest.kt Update expectations for notifications: omit standard MCP headers.
kotlin-sdk-client/src/commonTest/kotlin/io/modelcontextprotocol/kotlin/sdk/client/ClientAssertCapabilityTest.kt Update handshake protocol version constant in tests.
kotlin-sdk-client/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/client/VersionNegotiation.kt New client-side discovery probe outcome classifier for lifecycle selection.
kotlin-sdk-client/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/client/StreamableHttpClientTransport.kt Use shared header constants/encoding; restrict standard headers to requests (not notifications).
kotlin-sdk-client/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/client/ResponseCache.kt New response cache store + invalidation logic driven by notifications.
integration-test/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/testing/ChannelTransportTest.kt Update handshake protocol version constant in integration tests.
integration-test/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/server/ServerSessionInitializeTest.kt Update handshake protocol version constant in integration tests.
integration-test/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/server/ServerResourceTemplateTest.kt Update expected error code for resource-not-found behavior.
integration-test/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/server/SamplingTest.kt Update capability enforcement expectations to structured McpException w/ missing-capability data.
integration-test/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/integration/streamablehttp/StreamableHttpSseReconnectTest.kt Update handshake protocol version constant for SSE reconnect.
integration-test/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/integration/streamablehttp/StreamableHttpIntegrationTest.kt Update handshake protocol version constant in client transport config.
integration-test/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/integration/streamablehttp/StreamableHttpHeartbeatIntegrationTest.kt Update handshake protocol version constant for heartbeat tests.
integration-test/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/integration/ResponseCacheTest.kt New end-to-end tests for client response cache reuse and invalidation behavior.
integration-test/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/integration/RequestScopedLifecycleTest.kt New end-to-end tests for request-scoped envelope semantics and modern-vs-legacy behavior.
integration-test/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/integration/ProtocolConcurrencyIntegrationTest.kt Update decoding path for results given new wire wrapper behavior.
integration-test/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/integration/ModernStreamableHttpStreamTest.kt New real-engine test asserting committed SSE stream ordering/completeness.
integration-test/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/integration/ModernStreamableHttpDisconnectTest.kt New real-engine tests for request-scoped cancellation/disconnect behavior.
integration-test/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/integration/MalformedEnvelopeFieldTest.kt New integration coverage for malformed optional envelope fields handling.
integration-test/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/integration/kotlin/AbstractResourceIntegrationTest.kt Update resource-not-found expectation to INVALID_PARAMS and document rationale.
integration-test/src/jvmTest/kotlin/io/modelcontextprotocol/kotlin/sdk/integration/EraInterleavingTest.kt New integration tests asserting per-request lifecycle interleaving over one connection.
integration-test/src/commonTest/kotlin/io/modelcontextprotocol/kotlin/sdk/client/ClientTest.kt Update legacy tests for protocol version constants + capability-missing exceptions + result read-back.
Review details
  • Files reviewed: 82/82 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +369 to +377
private suspend fun isMessageAccepted(level: LoggingLevel): Boolean {
val extra = currentRequestHandlerExtra()
// Outside a handler there is no request to have opted in, so nothing is deliverable on
// the request-scoped lifecycle and the connection-scoped filter applies on the other.
?: return session.protocolVersion?.let { isModernProtocolVersion(it) } != true &&
acceptedByLevelSetting(level)
if (level !in allowedLogLevels(extra.protocolVersion, extra.meta)) return false
return acceptedByLevelSetting(level)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement SEP-2575: Make MCP Stateless

2 participants