feat: dual-era support for the 2026-07-28 protocol version - #238
feat: dual-era support for the 2026-07-28 protocol version#238sideeffffect wants to merge 6 commits into
Conversation
Make chimp a dual-era server: alongside the legacy initialize handshake (2025-11-25 and earlier), it now speaks the modern 2026-07-28 revision, where each request carries its protocol version in _meta. - ProtocolVersion.V2026_07_28 + a `supported` list; `Latest` still points at the latest legacy revision used by the initialize handshake. - server/discover returns a DiscoverResult (supported versions, capabilities, serverInfo in _meta), so a modern/dual-era client no longer gets an error from a chimp server (addresses the softwaremill#235 review). - A request declaring an unsupported protocol version in _meta[io.modelcontextprotocol/protocolVersion] is rejected with UnsupportedProtocolVersion (-32022) listing the supported versions. - New protocol types (DiscoverResult, CacheScope, ProtocolMeta) are validated against the official 2026-07-28 JSON schema (Schema2026ConformanceSpec), following the existing schema-conformance convention; the 2025-11-25 types are left untouched. WIP: modern client mode, HTTP transport-level validation (headers / 400 semantics), resultType on all results, and packaging extensions (e.g. Tasks) as separate modules are follow-ups. Groundwork for softwaremill#163. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Keep the domain type while the wire stays integer milliseconds, via a file-private millis codec. supportedVersions stays List[String] on purpose: the field must carry version strings the receiver may not recognise (a newer peer), which a closed ProtocolVersion enum would reject on decode. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Parses the raw supportedVersions strings into Either[String, ProtocolVersion]: Right for a known version, Left with the raw string for an unrecognised one, so callers get the typed view without the wire field rejecting newer versions. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Hello @kubinio123 , what do this about adding support for dual-era like this? |
|
Relevant field data point if useful: I maintain a 2026-07-28-only (not dual-era) MCP server implementation, and one thing worth testing explicitly once We went the other direction on the design question this PR is solving (latest-only rather than dual-era — wrote up the tradeoff here if the reasoning is useful as a comparison point, not a suggestion to change course) — dual-era is clearly the more correct choice for a general-purpose client-facing library like this, ours was a narrower bet made for a specific reason. |
Assert that a classic initialize (and any request whose _meta omits the modern protocol version) is served via the legacy handshake, not rejected with UnsupportedProtocolVersion (-32022) — the official-SDK-client interop path that surfaces first in practice. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
@sideeffffect thanks for sending this in. I took some time to plan out the work for implementing the 2026-07-28 support in general and created several issues with with a common label https://github.com/softwaremill/chimp/issues?q=state%3Aopen%20label%3A%222026-07-28%20version%20support%22. I would like to avoid any issues we might might have with stable implementation we have on I created those issues so that it's easier for us to keep track of the progress and for contributors like you to participate. For this PR, I think it pretty much implements #239 and #240, would you consider taking a look at those two? |
|
@deemwario I know some SDK did this the hard way, but there are couple of them (like Rust) that support both versions, let's see how that plays out for chimp. |
…softwaremill#240) T1: make V2026_07_28 the Latest, add LatestLegacy (V2025_11_25) which the initialize negotiation answers, and add release ordering so code can branch with `version >= V2026_07_28`. The client and legacy handshake keep proposing the latest legacy version. T2: extract SchemaConformance as a shared trait parameterised by the schema resource path, with one concrete spec per version (SchemaConformanceSpec for 2025-11-25, Schema2026ConformanceSpec for 2026-07-28). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The Pekko, Ox and ZIO streaming HTTP transports defaulted `protocolVersion`
to `ProtocolVersion.Latest` (2026-07-28), so their GET SSE stream carried
`MCP-Protocol-Version: 2026-07-28`. A legacy (2025-11-25-era) server rejects
that with HTTP 400 ("Unsupported protocol version"), which broke every HTTP
integration test in these modules.
Align them with the base `ClientHttpTransport`, which already defaults to
`ProtocolVersion.LatestLegacy`, and update the Pekko/ZIO HTTP integration
specs that explicitly passed `Latest` to the test server.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
re-targeted to the new branch. Please let me know if you'd like to see further changes @kubinio123 🙏 |
Targets the
2026-07-28-protocol-supportbranch. Groundwork for dual-era (legacy + modern) support, aligned with the granular tickets.Covers
V2026_07_28added and madeLatest;LatestLegacy = V2025_11_25is what theinitializenegotiation answers; cases are ordered by release so code can branch withversion >= V2026_07_28. The client and legacy handshake keep proposing the latest legacy version (modern client mode is a later ticket).schema/2026-07-28/schema.jsonbundled;SchemaConformanceextracted as a shared trait parameterised by the schema resource path, with one concrete spec per version (SchemaConformanceSpec→ 2025-11-25,Schema2026ConformanceSpec→ 2026-07-28, coveringDiscoverResultand the-32022envelope).Also included (later tickets — happy to split out if you'd prefer 1:1 with the issues)
server/discover→DiscoverResult(supported versions, capabilities,serverInfoin_meta)._meta[io.modelcontextprotocol/protocolVersion]unsupported →UnsupportedProtocolVersion(-32022); a legacy request without it is served via the handshake (explicit tests).DiscoverResult.ttlMs: FiniteDuration,CacheScope) with the wire kept spec-exact;getSupportedVersionsparsessupportedVersionsintoEither[String, ProtocolVersion].supportedVersionsstaysList[String]on the wire on purpose (a peer may advertise a newer version the closed enum would reject on decode).Local gate green (scalafmt, compile, docs, core/server/client unit suites). WIP.
🤖 Generated with Claude Code