Treat 2026-07-28 as a released spec revision; keep draft for what comes after it - #495
Draft
pcarleton wants to merge 7 commits into
Draft
Treat 2026-07-28 as a released spec revision; keep draft for what comes after it#495pcarleton wants to merge 7 commits into
pcarleton wants to merge 7 commits into
Conversation
Adds schema/2026-07-28 to the sync script and re-vendors every version at 5f5440bb (the 2026-07-28 tag). draft and 2026-07-28 are identical there apart from doc links; the dated 2025-06-18/2025-11-25 schemas pick up the upstream NumberSchema generator fix (#3139).
…sion after it
2026-07-28 shipped, but the harness still modelled it as the draft:
LATEST_SPEC_VERSION was 2025-11-25 and DRAFT_PROTOCOL_VERSION doubled as
both the draft's wire string and its timeline identity. Now that the spec
repo's draft declares the same wire version as the release, those two roles
have to be separate things.
- DATED_SPEC_VERSIONS gains 2026-07-28 and LATEST_SPEC_VERSION points at it.
- DRAFT_SPEC_VERSION ('draft') is the timeline id after the latest release;
DRAFT_PROTOCOL_VERSION stays the draft's wire string (still 2026-07-28,
mirroring schema/draft/schema.ts). protocolVersionFor() maps a SpecVersion
to its wire string and is used wherever a version goes on the wire
(headers, _meta, supportedVersions, MCP_CONFORMANCE_PROTOCOL_VERSION).
- Without --spec-version each scenario now runs at the latest release if it
applies there, else the newest revision in its window (defaultSpecVersionFor),
so stateful-only scenarios keep the initialize wire and nothing is handed a
lifecycle it cannot speak.
- --spec-version draft and --suite draft still parse; each prints a one-line
note (2026-07-28 is released / the draft suite is currently empty).
- Wire-schema validation routes 2026-07-28 to its own vendored schema and
drops the NumberSchema erratum the re-vendored dated schemas no longer need.
- sdk-runner: specOverrides keys are dated versions; a draft run resolves its
overlay through the draft's wire version.
- Test helpers default to 2025-11-25 (what the bundled SDK client/server
speak) now that the latest release is stateless.
…rom predicates Every scenario tagged introducedIn/removedIn: DRAFT_PROTOCOL_VERSION covers a requirement that shipped (or was removed) in 2026-07-28, so tag them with the date. They join the default suites (active, auth, core) and tier scoring; the draft suites are left for genuinely unreleased requirements and are empty. In-scenario 'is this the draft?' checks become era/feature predicates so the next revision inherits them: isStateless(ctx) for lifecycle, specVersionAtLeast (v, '2026-07-28') for SEP-2106/2350/837 gating, and protocolVersionFor() for hand-built headers, _meta and mock supportedVersions. Scenario imports of spec-types/draft move to spec-types/2026-07-28. withRequiredDraftResultFields is renamed withRequiredResultFields; the vestigial specVersions field on the input-required-result scenarios is dropped. The example client keys its lifecycle off the wire version list and defaults to the latest release.
…equirement set Fixes #426. With 2026-07-28 dated, its scenarios count toward the tier matrix; only genuinely-draft and extension scenarios stay informational, and a scored scenario that also applies at the draft no longer shows up a second time in the informational columns. In URL mode with neither --requirements nor --spec-version, tier-check used to run the client leg as an unfiltered --suite all, which put the removed 2025-03-26 backcompat scenarios in the denominator and ran them on the wrong wire. It now scores against the latest shipped revision's frozen requirement set (requirements/2026-07-28.yaml) and says so on stderr; --requirements claims more revisions, --spec-version keeps the unfrozen per-version path.
README/--help/skill wording that described 2026-07-28 as 'the draft' now names it as a dated release, explains what --spec-version draft and --suite draft mean after a release, and documents the new no-flag defaults (per-scenario wire selection; tier-check scoring the latest requirement set). AGENTS.md gains a line on how to tag introducedIn for shipped vs draft-only requirements.
Tests that used DRAFT_PROTOCOL_VERSION to mean 'the stateless revision' pin '2026-07-28' explicitly, tests that relied on LATEST_SPEC_VERSION being stateful pin '2025-11-25', and the draft-suite/alias expectations follow the new DRAFT_SPEC_VERSION identity. New coverage: defaultSpecVersionFor, protocolVersionFor at the header/_meta/env boundaries under --spec-version draft, the draft→wire specOverrides lookup, and LATEST_SPEC_VERSION having a frozen requirement set. all-scenarios runs each fixture scenario at its default revision and again on 2025-11-25 when it spans both wires. draft-result-fields.test.ts is renamed required-result-fields.test.ts.
Promoting 2026-07-28 touched the schema list in three places and every help string that named a date. Derive them instead, so the next release is 'append the date to DATED_SPEC_VERSIONS, run sync-schema' plus the inherently per-release work (retag shipped scenarios, freeze a requirement set): - LATEST_SPEC_VERSION is the last DATED_SPEC_VERSIONS entry, not a second constant. - DRAFT_PROTOCOL_VERSION is read from the vendored schema/draft/schema.ts, so a draft marker bump upstream is just `npm run sync-schema`. - sync-schema vendors DATED_SPEC_VERSIONS + draft (no separate list) and generates src/spec-types/schemas.ts, the version -> JSON Schema map the wire validator imports; wire-schema.ts no longer hardcodes imports per version. - --spec-version/--requirements help and error text interpolate the version list instead of naming dates. - Tests that pinned exact list contents assert structure instead. - src/spec-types/README.md gains the spec lifecycle checklist (draft marker bump / new draft-only scenario / new release).
Member
Author
|
Cross-SDK matrix for this branch (
|
| SDK | SDK head | Status | Toolchain |
|---|---|---|---|
typescript-sdk |
5119ee7f |
✅ 73/73 checks | node 22.23.2, pnpm 10.26.1, npm 10.9.8 |
typescript-sdk-v1 |
12b42567 |
❌ 1 failed, 0 warnings / 73 checks | node 22.23.2, pnpm 12.3.4, npm 10.9.8 |
go-sdk |
a5026ea |
✅ 73/73 checks | go 1.27.1 |
python-sdk |
08a3bc8e |
✅ 73/73 checks | uv 0.12.10, python 3.12.3 |
python-sdk-v1 |
8c2fa6ea |
✅ 73/73 checks | uv 0.12.10, python 3.12.3 |
rust-sdk |
3023198 |
❌ server failed to start: Server exited with code 127 before tests completed | cargo 1.96.1, rustc 1.96.1 |
csharp-sdk |
df11d7da |
✅ 73/73 checks | dotnet 10.0.400 |
ruby-sdk |
8a24e50 |
✅ 73/73 checks | ruby 3.2.3, bundler 2.4.20 |
after (this branch)
| SDK | SDK head | Status | Toolchain |
|---|---|---|---|
typescript-sdk |
5119ee7f |
✅ 151/151 checks | node 22.23.2, pnpm 10.26.1, npm 10.9.8 |
typescript-sdk-v1 |
12b42567 |
❌ 1 failed, 0 warnings / 73 checks | node 22.23.2, pnpm 12.3.4, npm 10.9.8 |
go-sdk |
a5026ea |
❌ 48 failed, 6 warnings / 135 checks | go 1.27.1 |
python-sdk |
08a3bc8e |
✅ 151/151 checks | uv 0.12.10, python 3.12.3 |
python-sdk-v1 |
8c2fa6ea |
✅ 73/73 checks | uv 0.12.10, python 3.12.3 |
rust-sdk |
3023198 |
❌ server failed to start: Server exited with code 127 before tests completed | cargo 1.96.1, rustc 1.96.1 |
csharp-sdk |
df11d7da |
❌ 48 failed, 5 warnings / 134 checks | dotnet 10.0.400 |
ruby-sdk |
8a24e50 |
✅ 151/151 checks | ruby 3.2.3, bundler 2.4.20 |
server --requirements 2026-07-28
before (main)
| SDK | SDK head | Status | Toolchain |
|---|---|---|---|
typescript-sdk |
5119ee7f |
❌ 30 failed, 0 warnings / 193 checks | node 22.23.2, pnpm 10.26.1, npm 10.9.8 |
typescript-sdk-v1 |
12b42567 |
❌ 145 failed, 5 warnings / 156 checks | node 22.23.2, pnpm 12.3.4, npm 10.9.8 |
go-sdk |
a5026ea |
❌ 30 failed, 0 warnings / 194 checks | go 1.27.1 |
python-sdk |
08a3bc8e |
❌ 25 failed, 0 warnings / 193 checks | uv 0.12.10, python 3.12.3 |
python-sdk-v1 |
8c2fa6ea |
❌ 101 failed, 5 warnings / 156 checks | uv 0.12.10, python 3.12.3 |
rust-sdk |
3023198 |
❌ server failed to start: Server exited with code 127 before tests completed | cargo 1.96.1, rustc 1.96.1 |
csharp-sdk |
df11d7da |
❌ 11 failed, 2 warnings / 192 checks | dotnet 10.0.400 |
ruby-sdk |
8a24e50 |
❌ 38 failed, 0 warnings / 189 checks | ruby 3.2.3, bundler 2.4.20 |
after (this branch)
| SDK | SDK head | Status | Toolchain |
|---|---|---|---|
typescript-sdk |
5119ee7f |
❌ 30 failed, 0 warnings / 193 checks | node 22.23.2, pnpm 10.26.1, npm 10.9.8 |
typescript-sdk-v1 |
12b42567 |
❌ 145 failed, 5 warnings / 156 checks | node 22.23.2, pnpm 12.3.4, npm 10.9.8 |
go-sdk |
a5026ea |
❌ 30 failed, 0 warnings / 194 checks | go 1.27.1 |
python-sdk |
08a3bc8e |
❌ 25 failed, 0 warnings / 193 checks | uv 0.12.10, python 3.12.3 |
python-sdk-v1 |
8c2fa6ea |
❌ 101 failed, 5 warnings / 156 checks | uv 0.12.10, python 3.12.3 |
rust-sdk |
3023198 |
❌ server failed to start: Server exited with code 127 before tests completed | cargo 1.96.1, rustc 1.96.1 |
csharp-sdk |
df11d7da |
❌ 11 failed, 2 warnings / 192 checks | dotnet 10.0.400 |
ruby-sdk |
8a24e50 |
❌ 38 failed, 0 warnings / 189 checks | ruby 3.2.3, bundler 2.4.20 |
server --requirements 2025-11-25
before (main)
| SDK | SDK head | Status | Toolchain |
|---|---|---|---|
typescript-sdk |
5119ee7f |
✅ 84/84 checks | node 22.23.2, pnpm 10.26.1, npm 10.9.8 |
typescript-sdk-v1 |
12b42567 |
❌ 3 failed, 0 warnings / 81 checks | node 22.23.2, pnpm 12.3.4, npm 10.9.8 |
go-sdk |
a5026ea |
go 1.27.1 | |
python-sdk |
08a3bc8e |
✅ 84/84 checks | uv 0.12.10, python 3.12.3 |
python-sdk-v1 |
8c2fa6ea |
❌ 1 failed, 0 warnings / 78 checks | uv 0.12.10, python 3.12.3 |
rust-sdk |
3023198 |
❌ server failed to start: Server exited with code 127 before tests completed | cargo 1.96.1, rustc 1.96.1 |
csharp-sdk |
df11d7da |
✅ 80/80 checks | dotnet 10.0.400 |
ruby-sdk |
8a24e50 |
ruby 3.2.3, bundler 2.4.20 |
after (this branch)
| SDK | SDK head | Status | Toolchain |
|---|---|---|---|
typescript-sdk |
5119ee7f |
✅ 84/84 checks | node 22.23.2, pnpm 10.26.1, npm 10.9.8 |
typescript-sdk-v1 |
12b42567 |
❌ 3 failed, 0 warnings / 81 checks | node 22.23.2, pnpm 12.3.4, npm 10.9.8 |
go-sdk |
a5026ea |
go 1.27.1 | |
python-sdk |
08a3bc8e |
✅ 84/84 checks | uv 0.12.10, python 3.12.3 |
python-sdk-v1 |
8c2fa6ea |
❌ 1 failed, 0 warnings / 78 checks | uv 0.12.10, python 3.12.3 |
rust-sdk |
3023198 |
❌ server failed to start: Server exited with code 127 before tests completed | cargo 1.96.1, rustc 1.96.1 |
csharp-sdk |
df11d7da |
✅ 81/81 checks | dotnet 10.0.400 |
ruby-sdk |
8a24e50 |
ruby 3.2.3, bundler 2.4.20 |
client --requirements 2026-07-28
before (main)
| SDK | SDK head | Status | Toolchain |
|---|---|---|---|
typescript-sdk |
5119ee7f |
❌ 1 failed, 0 warnings / 453 checks | node 22.23.2, pnpm 10.26.1, npm 10.9.8 |
typescript-sdk-v1 |
12b42567 |
❌ 60 failed, 0 warnings / 268 checks | node 22.23.2, pnpm 12.3.4, npm 10.9.8 |
go-sdk |
a5026ea |
❌ 13 failed, 0 warnings / 457 checks | go 1.27.1 |
python-sdk |
08a3bc8e |
❌ 9 failed, 0 warnings / 469 checks | uv 0.12.10, python 3.12.3 |
python-sdk-v1 |
8c2fa6ea |
❌ 64 failed, 0 warnings / 368 checks | uv 0.12.10, python 3.12.3 |
rust-sdk |
3023198 |
❌ 92 failed, 0 warnings / 104 checks | cargo 1.96.1, rustc 1.96.1 |
csharp-sdk |
df11d7da |
❌ 11 failed, 1 warnings / 417 checks | dotnet 10.0.400 |
ruby-sdk |
8a24e50 |
❌ 9 failed, 0 warnings / 467 checks | ruby 3.2.3, bundler 2.4.20 |
after (this branch)
| SDK | SDK head | Status | Toolchain |
|---|---|---|---|
typescript-sdk |
5119ee7f |
❌ 1 failed, 0 warnings / 453 checks | node 22.23.2, pnpm 10.26.1, npm 10.9.8 |
typescript-sdk-v1 |
12b42567 |
❌ 60 failed, 0 warnings / 268 checks | node 22.23.2, pnpm 12.3.4, npm 10.9.8 |
go-sdk |
a5026ea |
❌ 13 failed, 0 warnings / 457 checks | go 1.27.1 |
python-sdk |
08a3bc8e |
❌ 9 failed, 0 warnings / 469 checks | uv 0.12.10, python 3.12.3 |
python-sdk-v1 |
8c2fa6ea |
❌ 64 failed, 0 warnings / 368 checks | uv 0.12.10, python 3.12.3 |
rust-sdk |
3023198 |
❌ 92 failed, 0 warnings / 104 checks | cargo 1.96.1, rustc 1.96.1 |
csharp-sdk |
df11d7da |
❌ 11 failed, 1 warnings / 417 checks | dotnet 10.0.400 |
ruby-sdk |
8a24e50 |
❌ 9 failed, 0 warnings / 467 checks | ruby 3.2.3, bundler 2.4.20 |
client --requirements 2025-11-25
before (main)
| SDK | SDK head | Status | Toolchain |
|---|---|---|---|
typescript-sdk |
5119ee7f |
❌ 1 failed, 0 warnings / 308 checks | node 22.23.2, pnpm 10.26.1, npm 10.9.8 |
typescript-sdk-v1 |
12b42567 |
❌ 13 failed, 0 warnings / 297 checks | node 22.23.2, pnpm 12.3.4, npm 10.9.8 |
go-sdk |
a5026ea |
❌ 13 failed, 0 warnings / 285 checks | go 1.27.1 |
python-sdk |
08a3bc8e |
❌ 9 failed, 0 warnings / 307 checks | uv 0.12.10, python 3.12.3 |
python-sdk-v1 |
8c2fa6ea |
❌ 14 failed, 0 warnings / 301 checks | uv 0.12.10, python 3.12.3 |
rust-sdk |
3023198 |
❌ 65 failed, 0 warnings / 65 checks | cargo 1.96.1, rustc 1.96.1 |
csharp-sdk |
df11d7da |
❌ 11 failed, 1 warnings / 283 checks | dotnet 10.0.400 |
ruby-sdk |
8a24e50 |
❌ 9 failed, 0 warnings / 302 checks | ruby 3.2.3, bundler 2.4.20 |
after (this branch)
| SDK | SDK head | Status | Toolchain |
|---|---|---|---|
typescript-sdk |
5119ee7f |
❌ 1 failed, 0 warnings / 308 checks | node 22.23.2, pnpm 10.26.1, npm 10.9.8 |
typescript-sdk-v1 |
12b42567 |
❌ 13 failed, 0 warnings / 297 checks | node 22.23.2, pnpm 12.3.4, npm 10.9.8 |
go-sdk |
a5026ea |
❌ 13 failed, 0 warnings / 285 checks | go 1.27.1 |
python-sdk |
08a3bc8e |
❌ 9 failed, 0 warnings / 307 checks | uv 0.12.10, python 3.12.3 |
python-sdk-v1 |
8c2fa6ea |
❌ 14 failed, 0 warnings / 301 checks | uv 0.12.10, python 3.12.3 |
rust-sdk |
3023198 |
❌ 65 failed, 0 warnings / 65 checks | cargo 1.96.1, rustc 1.96.1 |
csharp-sdk |
df11d7da |
❌ 11 failed, 1 warnings / 283 checks | dotnet 10.0.400 |
ruby-sdk |
8a24e50 |
❌ 9 failed, 0 warnings / 302 checks | ruby 3.2.3, bundler 2.4.20 |
client --suite core, no --spec-version
before (main)
| SDK | SDK head | Status | Toolchain |
|---|---|---|---|
typescript-sdk |
5119ee7f |
✅ 250/250 checks | node 22.23.2, pnpm 10.26.1, npm 10.9.8 |
typescript-sdk-v1 |
12b42567 |
✅ 270/270 checks | node 22.23.2, pnpm 12.3.4, npm 10.9.8 |
go-sdk |
a5026ea |
✅ 263/263 checks | go 1.27.1 |
python-sdk |
08a3bc8e |
✅ 238/238 checks | uv 0.12.10, python 3.12.3 |
python-sdk-v1 |
8c2fa6ea |
❌ 1 failed, 0 warnings / 238 checks | uv 0.12.10, python 3.12.3 |
rust-sdk |
3023198 |
❌ 50 failed, 0 warnings / 50 checks | cargo 1.96.1, rustc 1.96.1 |
csharp-sdk |
df11d7da |
✅ 229/229 checks | dotnet 10.0.400 |
ruby-sdk |
8a24e50 |
✅ 236/236 checks | ruby 3.2.3, bundler 2.4.20 |
after (this branch)
| SDK | SDK head | Status | Toolchain |
|---|---|---|---|
typescript-sdk |
5119ee7f |
✅ 356/356 checks | node 22.23.2, pnpm 10.26.1, npm 10.9.8 |
typescript-sdk-v1 |
12b42567 |
✅ 270/270 checks | node 22.23.2, pnpm 12.3.4, npm 10.9.8 |
go-sdk |
a5026ea |
✅ 394/394 checks | go 1.27.1 |
python-sdk |
08a3bc8e |
✅ 358/358 checks | uv 0.12.10, python 3.12.3 |
python-sdk-v1 |
8c2fa6ea |
❌ 1 failed, 0 warnings / 238 checks | uv 0.12.10, python 3.12.3 |
rust-sdk |
3023198 |
❌ 62 failed, 0 warnings / 64 checks | cargo 1.96.1, rustc 1.96.1 |
csharp-sdk |
df11d7da |
✅ 328/328 checks | dotnet 10.0.400 |
ruby-sdk |
8a24e50 |
✅ 362/362 checks | ruby 3.2.3, bundler 2.4.20 |
client --suite extensions
before (main)
| SDK | SDK head | Status | Toolchain |
|---|---|---|---|
typescript-sdk |
5119ee7f |
❌ 1 failed, 0 warnings / 49 checks | node 22.23.2, pnpm 10.26.1, npm 10.9.8 |
typescript-sdk-v1 |
12b42567 |
✅ 0/0 checks | node 22.23.2, pnpm 12.3.4, npm 10.9.8 |
go-sdk |
a5026ea |
❌ 13 failed, 0 warnings / 13 checks | go 1.27.1 |
python-sdk |
08a3bc8e |
❌ 9 failed, 0 warnings / 60 checks | uv 0.12.10, python 3.12.3 |
python-sdk-v1 |
8c2fa6ea |
✅ 0/0 checks | uv 0.12.10, python 3.12.3 |
rust-sdk |
3023198 |
❌ 13 failed, 0 warnings / 13 checks | cargo 1.96.1, rustc 1.96.1 |
csharp-sdk |
df11d7da |
❌ 9 failed, 1 warnings / 51 checks | dotnet 10.0.400 |
ruby-sdk |
8a24e50 |
❌ 9 failed, 0 warnings / 57 checks | ruby 3.2.3, bundler 2.4.20 |
after (this branch)
| SDK | SDK head | Status | Toolchain |
|---|---|---|---|
typescript-sdk |
5119ee7f |
❌ 1 failed, 0 warnings / 45 checks | node 22.23.2, pnpm 10.26.1, npm 10.9.8 |
typescript-sdk-v1 |
12b42567 |
✅ 0/0 checks | node 22.23.2, pnpm 12.3.4, npm 10.9.8 |
go-sdk |
a5026ea |
❌ 13 failed, 0 warnings / 13 checks | go 1.27.1 |
python-sdk |
08a3bc8e |
❌ 9 failed, 0 warnings / 59 checks | uv 0.12.10, python 3.12.3 |
python-sdk-v1 |
8c2fa6ea |
✅ 0/0 checks | uv 0.12.10, python 3.12.3 |
rust-sdk |
3023198 |
❌ 13 failed, 0 warnings / 13 checks | cargo 1.96.1, rustc 1.96.1 |
csharp-sdk |
df11d7da |
❌ 9 failed, 1 warnings / 45 checks | dotnet 10.0.400 |
ruby-sdk |
8a24e50 |
❌ 9 failed, 0 warnings / 56 checks | ruby 3.2.3, bundler 2.4.20 |
server --spec-version draft (after only)
| SDK | SDK head | Status | Toolchain |
|---|---|---|---|
typescript-sdk |
5119ee7f |
✅ 119/119 checks | node 22.23.2, pnpm 10.26.1, npm 10.9.8 |
typescript-sdk-v1 |
12b42567 |
❌ 95 failed, 5 warnings / 106 checks | node 22.23.2, pnpm 12.3.4, npm 10.9.8 |
go-sdk |
a5026ea |
✅ 120/120 checks | go 1.27.1 |
python-sdk |
08a3bc8e |
✅ 119/119 checks | uv 0.12.10, python 3.12.3 |
python-sdk-v1 |
8c2fa6ea |
❌ 62 failed, 5 warnings / 106 checks | uv 0.12.10, python 3.12.3 |
rust-sdk |
3023198 |
❌ server failed to start: Server exited with code 127 before tests completed | cargo 1.96.1, rustc 1.96.1 |
csharp-sdk |
df11d7da |
dotnet 10.0.400 | |
ruby-sdk |
8a24e50 |
✅ 119/119 checks | ruby 3.2.3, bundler 2.4.20 |
Notes:
- Every
--requirementsleg is identical per SDK and per scenario before/after (the failures shown there are baselined or not-scored entries and are the same on main). serverwith no flags: go-sdk and csharp-sdk fail the 17 newly-active 2026-07-28 scenarios plus the spanning ones because their defaultKNOWN_SDKSserver invocation is the stateful-era process; with--spec-version 2026-07-28,--spec-version draftor--requirementsthe stateless invocation is selected and they are green. Their own CI pins--spec-versionper leg.client --suite corewith no flags: every client passes the 11 added auth scenarios and the spanning scenarios at the 2026-07-28 wire; check counts differ because the stateless wire has no initialize checks.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #426.
Why
The 2026-07-28 specification revision was released on 2026-07-28, but the harness still modelled it as "the draft":
LATEST_SPEC_VERSIONwas2025-11-25,DRAFT_PROTOCOL_VERSION = '2026-07-28'served as both the draft's wire string and its identity on the spec timeline, every SEP-2575/2322/2243/2549/2468 scenario was taggedintroducedIn: DRAFT_PROTOCOL_VERSION, and tier-check filed all of them under "Informational (not scored)". #447 already frozerequirements/2026-07-28.yaml, so the--requirementspath treated the revision as shipped while everything else did not.We still want
draftto be something the suite can represent (the revision after the latest release), but it has to stop being shorthand for "the 2026-07-28 stateless era". The spec repo'sschema/draft/schema.tscurrently declares the sameLATEST_PROTOCOL_VERSION(2026-07-28) as the release, so the draft's identity and its wire string can no longer be one value.The second goal is that the next release should not need a PR this size. See "Next time" below.
What changes
Model (
src/types.ts)DATED_SPEC_VERSIONSgains2026-07-28;LATEST_SPEC_VERSIONis derived as its last entry. 2025-11-25 stays fully supported.DRAFT_SPEC_VERSION = 'draft'is the timeline identity of the unreleased revision after the latest release.SpecVersion = DatedSpecVersion | 'draft'.DRAFT_PROTOCOL_VERSIONis the draft's wireprotocolVersion, now read from the vendoredschema/draft/schema.ts(still2026-07-28today).protocolVersionFor(v)maps aSpecVersionto its wire string and is used everywhere a version goes on the wire: headers,_meta, mocksupportedVersions,MCP_CONFORMANCE_PROTOCOL_VERSION.isStatefulVersion/isStateless,specVersionAtLeast(v, '2026-07-28')) instead of=== DRAFT_PROTOCOL_VERSION, so the next revision inherits it.Scenarios
introducedIn: DRAFT_PROTOCOL_VERSIONtags become'2026-07-28'; all 15removedIn: DRAFT_PROTOCOL_VERSIONtags (initialize, sessions, ping, logging/setLevel, resources/subscribe, SSE resumption, elicitation defaults/enums, the sampling/elicitation/logging tool calls) becomeremovedIn: '2026-07-28'. Verified against the 2026-07-28 changelog.activegoes from 31 to 48 scenarios; the eleven 2026-07-28 auth scenarios (SEP-2468iss, SEP-2207 offline access, SEP-2352 migration, resource-mismatch) joinauth/core.--suite draft(client and server) is kept and is currently empty; it prints a one-line note saying so.spec-types/draftmove to the newly vendoredspec-types/2026-07-28.Defaults when
--spec-versionis omittedremovedIn: '2026-07-28'at2025-11-25, the 2025-03-26 backcompat pair at2025-03-26. Previously everything that was not draft-only ran at 2025-11-25. A server or client that only implements the stateful lifecycle should pass--spec-version 2025-11-25.CLI back-compat
--spec-version draftstill parses. It means "the revision after 2026-07-28": the same scenario set as--spec-version 2026-07-28plus any draft-only scenarios (none today), run at the draft's wire version (also2026-07-28today). It prints one stderr line noting that 2026-07-28 is a released revision.--suite draftstill parses; empty today, with a one-line note.--spec-version 2026-07-28and--requirements 2026-07-28keep their meaning; the former now selects 37 server scenarios instead of 20 because the 17 formerly-draft scenarios are no longer excluded fromactive.tier-check (#426)
draftandextensionare informational, and a scored scenario that also applies at the draft is not listed a second time under the informational columns.--requirementsnor--spec-versionnow scores against the latest shipped revision's frozen requirement set (requirements/2026-07-28.yaml) and says so on stderr, instead of an unfiltered--suite allclient leg that counted the removed 2025-03-26 backcompat scenarios and ran them on the wrong wire.--requirements 2025-11-25,2026-07-28claims both;--spec-versionkeeps the unfrozen per-version path.--sdkmode is unchanged (every shipped revision).Vendored schema
scripts/sync-schema.tsnow vendors everyDATED_SPEC_VERSIONSentry plusdraftand generatessrc/spec-types/schemas.ts(the version to JSON Schema map the wire validator imports). Everything is re-synced at the2026-07-28tag (5f5440bb), so2026-07-28validates against its own immutable schema. The re-vendored 2025-06-18/2025-11-25 schemas carry the upstream NumberSchema fix (modelcontextprotocol#3139), so the local erratum and its tripwire test are removed.sdk-runner
specOverrideskeys are dated versions; adraftrun resolves its overlay through the draft's wire version.Docs and tests
--help, the tier-audit skill and AGENTS.md (one new bullet on how to tagintroducedIn) describe 2026-07-28 as released anddraftas the revision after it;src/spec-types/README.mdgains the spec lifecycle checklist. Tests pin'2026-07-28'/'2025-11-25'explicitly where they meant "stateless" / "stateful"; the unit-test context helpers default to 2025-11-25 because that is what the bundled SDK client/server speak.Next time
After this PR the per-release edit set is:
DATED_SPEC_VERSIONS(LATEST_SPEC_VERSIONfollows).npm run sync-schema -- <release tag>(vendors the newschema/<date>, regeneratesschemas.ts;DRAFT_PROTOCOL_VERSIONtracks the vendored draft on its own).DRAFT_SPEC_VERSIONto the date inintroducedIn/removedIn.requirements/<date>.yaml.specOverridesentries for SDKs that need a different server invocation at the new wire.A draft marker bump upstream (e.g.
DRAFT-2026-v2) is step 2 alone. Help text, the draft notes, the stateless version lists, tier-check columns and the wire validator all derive fromDATED_SPEC_VERSIONS.Cross-SDK check (local
sdkmatrix, allKNOWN_SDKS, this branch vsmain)--requirements 2026-07-28and--requirements 2025-11-25, server and client legs: per-SDK, per-scenario results are identical before and after for typescript-sdk, typescript-sdk-v1, python-sdk, python-sdk-v1, go-sdk, csharp-sdk, ruby-sdk (rust-sdk did not build in the environment used, unrelated to this change). The tier path does not move.--mode serverwith no flags: typescript-sdk, python-sdk, ruby-sdk go from 73/73 to 151/151 checks (the 17 stateless scenarios now run); go-sdk and csharp-sdk fail those 17 plus the spanning scenarios because their defaultKNOWN_SDKSserver invocation is the stateful-era one andspecOverrides['2026-07-28']only applies when a version is requested.--spec-version 2026-07-28(ordraft) and--requirementspick the right invocation and are green; see the open question below.--mode client --suite corewith no flags: every Tier 1 client (typescript, go, python, csharp, ruby) passes the enlarged suite at 2026-07-28; the v1 lines stay pinned to 2025-11-25 and are unchanged.--mode server --spec-version draft: typescript 119/119, go 120/120, python 119/119, ruby 119/119, csharp 2 warnings, matching--spec-version 2026-07-28.Full tables are in the first comment.
SDK impact
server/clientwith no--spec-versionnow exercises 2026-07-28 scenarios at the stateless wire by default (spanning scenarios included). SDKs that only implement 2025-11-25, or whose conformance server speaks one era per process, should pin--spec-version(or use--requirements, which most already do). Expected-failures baselines keyed to the old default will see new scenario names.--spec-version draftkeeps working and now scores; switch to--spec-version 2026-07-28at leisure.--suite draftnow runs zero scenarios (with a note); switch to the default suite or--spec-version 2026-07-28.--requirementsusers andtier-check --sdk: no change.Open questions
sdk <name>with no version resolvespecOverrides[LATEST_SPEC_VERSION]so go-sdk/csharp-sdk start their stateless server by default? That would flip which half of the mixed default suite fails for them; the real fix is that a no-flag run against a one-era-per-process server is not meaningful, and--requirementsalready handles it per revision. Left as is here.client --suite authagainst it without--spec-version 2025-11-25reports failures forauth/scope-step-upandauth/scope-retry-limit. The scenarios themselves pass against every SDK client.Not in this PR
specReferences/src/seps/*.yamlURLs still point at/specification/draft/.... Those pages were restructured before the release (authorization split,transportstotransports/streamable-http,utilities/mrtrtopatterns/mrtr, ...), so moving them to/specification/2026-07-28/...is a page-and-anchor remap plus a traceability.json regen, not a rename. Follow-up.AI disclosure
Per the org AI contribution policy: this PR was written primarily by Claude Code (audit of the
draftusages, code changes, tests, the cross-SDK matrix runs and this description), working from my direction on the design (keepdraftas the revision after the latest release, promote 2026-07-28, make the next release a small diff). I have reviewed the changes and the before/after numbers come from real local runs.