Skip to content

Commit 3fcf832

Browse files
committed
Turn on the 2026-07-28 column in the interaction-suite matrix
- SPEC_VERSIONS = ("2025-11-25", "2026-07-28"); node ids gain a -version suffix suite-wide - 13 lifecycle:initialize:* / lifecycle:version:* / initialized-notification / requests-before-initialized requirements get removed_in="2026-07-28" (the handshake does not exist at this revision) - 10 progress/logging requirements get a KnownFailure at 2026-07-28 (the modern entry does not yet stream handler-emitted notifications onto the per-request response; burns down once the SSE response mode lands) - protocol:progress:client-to-server gets a requires-session arm exclusion (a bare client->server notification has no route at the stateless entry) - 6 error-shape requirements get a modern-error-surface arm exclusion (the tests pin the legacy code-0/leaked-message divergence; the modern arm returns the spec-correct -32603; needs era-aware assertions to re-admit) [streamable-http-2026-07-28]: 60 pass, 8 xfail.
1 parent 7bf87f8 commit 3fcf832

2 files changed

Lines changed: 70 additions & 1 deletion

File tree

tests/interaction/_requirements.py

Lines changed: 69 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
"""A protocol version the suite parametrizes over. Both values are typed even though only one is
4646
on the active axis (SPEC_VERSIONS) until the 2026-07-28 implementation lands."""
4747

48-
SPEC_VERSIONS: tuple[SpecVersion, ...] = ("2025-11-25",)
48+
SPEC_VERSIONS: tuple[SpecVersion, ...] = ("2025-11-25", "2026-07-28")
4949
"""The active spec-version matrix axis, ordered oldest to newest. Every entry must be in KNOWN_PROTOCOL_VERSIONS."""
5050

5151
SPEC_BASE_URL = "https://modelcontextprotocol.io/specification/2025-11-25"
@@ -96,6 +96,12 @@
9696
"unimplemented."
9797
)
9898

99+
_MODERN_NOTIFY_DROP = (
100+
"SingleExchangeDispatcher.notify() no-ops on the modern streamable-http driver; handler-emitted "
101+
"logging/progress notifications never reach the per-request SSE response. Passes once SSE "
102+
"response mode lands."
103+
)
104+
99105

100106
@dataclass(frozen=True, kw_only=True)
101107
class Divergence:
@@ -212,29 +218,41 @@ def __post_init__(self) -> None:
212218
"Connecting sends initialize with the protocol version, client capabilities, and client "
213219
"info; the server responds with its own and the connection is established."
214220
),
221+
removed_in="2026-07-28",
222+
note="initialize handshake removed at 2026-07-28; per-request _meta envelope replaces it.",
215223
),
216224
"lifecycle:initialize:server-info": Requirement(
217225
source=f"{SPEC_BASE_URL}/basic/lifecycle#initialization",
218226
behavior="The initialize result identifies the server: name and version, plus title when declared.",
227+
removed_in="2026-07-28",
228+
note="initialize handshake removed at 2026-07-28; per-request _meta envelope replaces it.",
219229
),
220230
"lifecycle:initialize:instructions": Requirement(
221231
source=f"{SPEC_BASE_URL}/basic/lifecycle#initialization",
222232
behavior="A server may include an instructions string in the initialize result; the client exposes it.",
233+
removed_in="2026-07-28",
234+
note="initialize handshake removed at 2026-07-28; per-request _meta envelope replaces it.",
223235
),
224236
"lifecycle:initialize:capabilities:from-handlers": Requirement(
225237
source=f"{SPEC_BASE_URL}/basic/lifecycle#capability-negotiation",
226238
behavior=(
227239
"The server advertises a capability for each feature area it has a registered handler for, "
228240
"and omits the capability for areas it does not."
229241
),
242+
removed_in="2026-07-28",
243+
note="initialize handshake removed at 2026-07-28; per-request _meta envelope replaces it.",
230244
),
231245
"lifecycle:initialize:capabilities:minimal": Requirement(
232246
source=f"{SPEC_BASE_URL}/basic/lifecycle#capability-negotiation",
233247
behavior="A server with no feature handlers advertises no feature capabilities.",
248+
removed_in="2026-07-28",
249+
note="initialize handshake removed at 2026-07-28; per-request _meta envelope replaces it.",
234250
),
235251
"lifecycle:initialize:client-info": Requirement(
236252
source=f"{SPEC_BASE_URL}/basic/lifecycle#initialization",
237253
behavior="The client's name, version, and title are visible to server handlers after initialization.",
254+
removed_in="2026-07-28",
255+
note="initialize handshake removed at 2026-07-28; per-request _meta envelope replaces it.",
238256
arm_exclusions=(ArmExclusion(reason="requires-session", transport="streamable-http-stateless"),),
239257
),
240258
"lifecycle:initialize:client-capabilities": Requirement(
@@ -243,6 +261,8 @@ def __post_init__(self) -> None:
243261
"The client capabilities visible to the server reflect which client callbacks are configured "
244262
"(sampling, elicitation, roots)."
245263
),
264+
removed_in="2026-07-28",
265+
note="initialize handshake removed at 2026-07-28; per-request _meta envelope replaces it.",
246266
arm_exclusions=(ArmExclusion(reason="requires-session", transport="streamable-http-stateless"),),
247267
),
248268
"lifecycle:initialized-notification": Requirement(
@@ -251,6 +271,8 @@ def __post_init__(self) -> None:
251271
"After successful initialization, the client sends exactly one initialized notification, "
252272
"before any non-ping request."
253273
),
274+
removed_in="2026-07-28",
275+
note="initialize handshake removed at 2026-07-28; per-request _meta envelope replaces it.",
254276
),
255277
"lifecycle:ping": Requirement(
256278
source=f"{SPEC_BASE_URL}/basic/utilities/ping#behavior-requirements",
@@ -276,6 +298,8 @@ def __post_init__(self) -> None:
276298
behavior=(
277299
"A request other than ping sent before the initialization handshake completes is rejected with an error."
278300
),
301+
removed_in="2026-07-28",
302+
note="initialize handshake removed at 2026-07-28; per-request _meta envelope replaces it.",
279303
),
280304
"lifecycle:pre-initialization-ordering": Requirement(
281305
source=f"{SPEC_BASE_URL}/basic/lifecycle#initialization",
@@ -304,27 +328,35 @@ def __post_init__(self) -> None:
304328
"When the server returns an older supported protocol version, the client downgrades to it "
305329
"and the connection succeeds at that version."
306330
),
331+
removed_in="2026-07-28",
332+
note="initialize-time version negotiation removed at 2026-07-28; version carried per-request in _meta.",
307333
),
308334
"lifecycle:version:match": Requirement(
309335
source=f"{SPEC_BASE_URL}/basic/lifecycle#version-negotiation",
310336
behavior=(
311337
"When the server supports the requested protocol version it echoes that version in the "
312338
"initialize result, and the connection proceeds at that version."
313339
),
340+
removed_in="2026-07-28",
341+
note="initialize-time version negotiation removed at 2026-07-28; version carried per-request in _meta.",
314342
),
315343
"lifecycle:version:server-fallback-latest": Requirement(
316344
source=f"{SPEC_BASE_URL}/basic/lifecycle#version-negotiation",
317345
behavior=(
318346
"An initialize request carrying a protocol version the server does not support is answered "
319347
"with another version the server supports — the latest one — rather than an error."
320348
),
349+
removed_in="2026-07-28",
350+
note="initialize-time version negotiation removed at 2026-07-28; version carried per-request in _meta.",
321351
),
322352
"lifecycle:version:reject-unsupported": Requirement(
323353
source=f"{SPEC_BASE_URL}/basic/lifecycle#version-negotiation",
324354
behavior=(
325355
"A client that receives an initialize response carrying a protocol version it does not "
326356
"support fails initialization with an error rather than proceeding with the session."
327357
),
358+
removed_in="2026-07-28",
359+
note="initialize-time version negotiation removed at 2026-07-28; version carried per-request in _meta.",
328360
),
329361
"lifecycle:stateless:request-envelope": Requirement(
330362
source=f"{SPEC_2026_BASE_URL}/basic/lifecycle#stateless-operation",
@@ -482,6 +514,17 @@ def __post_init__(self) -> None:
482514
"leaks str(exc) as the error message."
483515
),
484516
),
517+
arm_exclusions=(
518+
ArmExclusion(
519+
reason="modern-error-surface",
520+
spec_version="2026-07-28",
521+
note=(
522+
"The modern entry maps Exception->INTERNAL_ERROR (-32603) with an opaque message, so the "
523+
"2026 arm SATISFIES this requirement; the test pins the legacy code-0 divergence and "
524+
"needs an era-aware assertion before re-admission."
525+
),
526+
),
527+
),
485528
),
486529
"protocol:error:invalid-params": Requirement(
487530
source=f"{SPEC_BASE_URL}/basic#responses",
@@ -537,6 +580,7 @@ def __post_init__(self) -> None:
537580
"Progress notifications emitted by a handler during a request are delivered to the caller's "
538581
"progress callback, in order, with their progress, total, and message."
539582
),
583+
known_failures=(KnownFailure(spec_version="2026-07-28", note=_MODERN_NOTIFY_DROP, issue=None),),
540584
),
541585
"protocol:progress:token-injected": Requirement(
542586
source=f"{SPEC_BASE_URL}/basic/utilities/progress#progress-flow",
@@ -549,6 +593,7 @@ def __post_init__(self) -> None:
549593
"protocol:progress:token-unique": Requirement(
550594
source=f"{SPEC_BASE_URL}/basic/utilities/progress#progress-flow",
551595
behavior=("Concurrent in-flight requests that each supply a progress callback carry distinct progress tokens."),
596+
known_failures=(KnownFailure(spec_version="2026-07-28", note=_MODERN_NOTIFY_DROP, issue=None),),
552597
),
553598
"protocol:progress:monotonic": Requirement(
554599
source=f"{SPEC_BASE_URL}/basic/utilities/progress#progress-flow",
@@ -561,6 +606,7 @@ def __post_init__(self) -> None:
561606
"handler that emits non-increasing values has them forwarded to the callback unchanged."
562607
),
563608
),
609+
known_failures=(KnownFailure(spec_version="2026-07-28", note=_MODERN_NOTIFY_DROP, issue=None),),
564610
),
565611
"protocol:progress:stops-after-completion": Requirement(
566612
source=f"{SPEC_BASE_URL}/basic/utilities/progress#behavior-requirements",
@@ -594,6 +640,7 @@ def __post_init__(self) -> None:
594640
"protocol:progress:client-to-server": Requirement(
595641
source=f"{SPEC_BASE_URL}/basic/utilities/progress#progress-flow",
596642
behavior="A progress notification sent by the client is delivered to the server's progress handler.",
643+
arm_exclusions=(ArmExclusion(reason="requires-session", spec_version="2026-07-28"),),
597644
),
598645
"protocol:timeout:basic": Requirement(
599646
source=f"{SPEC_BASE_URL}/basic/lifecycle#timeouts",
@@ -697,13 +744,15 @@ def __post_init__(self) -> None:
697744
"Log notifications emitted by a tool handler during execution reach the client's logging "
698745
"callback before the tool result returns."
699746
),
747+
known_failures=(KnownFailure(spec_version="2026-07-28", note=_MODERN_NOTIFY_DROP, issue=None),),
700748
),
701749
"tools:call:progress": Requirement(
702750
source=f"{SPEC_BASE_URL}/basic/utilities/progress#progress-flow",
703751
behavior=(
704752
"Progress notifications emitted by a tool handler reach the caller's progress callback before "
705753
"the tool result returns."
706754
),
755+
known_failures=(KnownFailure(spec_version="2026-07-28", note=_MODERN_NOTIFY_DROP, issue=None),),
707756
),
708757
"tools:call:sampling-roundtrip": Requirement(
709758
source=f"{SPEC_BASE_URL}/client/sampling#creating-messages",
@@ -924,12 +973,14 @@ def __post_init__(self) -> None:
924973
"The Context logging helpers (debug/info/warning/error) send log message notifications at the "
925974
"corresponding severity."
926975
),
976+
known_failures=(KnownFailure(spec_version="2026-07-28", note=_MODERN_NOTIFY_DROP, issue=None),),
927977
),
928978
"mcpserver:context:progress": Requirement(
929979
source="sdk",
930980
behavior=(
931981
"Context.report_progress sends a progress notification against the requesting client's progress token."
932982
),
983+
known_failures=(KnownFailure(spec_version="2026-07-28", note=_MODERN_NOTIFY_DROP, issue=None),),
933984
),
934985
"mcpserver:context:elicit": Requirement(
935986
source="sdk",
@@ -1091,6 +1142,7 @@ def __post_init__(self) -> None:
10911142
"mcpserver:resource:read-throws-surfaced": Requirement(
10921143
source="sdk",
10931144
behavior="A resource function that raises is surfaced to the caller as a JSON-RPC error response.",
1145+
arm_exclusions=(ArmExclusion(reason="modern-error-surface", spec_version="2026-07-28"),),
10941146
),
10951147
"mcpserver:resource:static": Requirement(
10961148
source="sdk",
@@ -1115,6 +1167,7 @@ def __post_init__(self) -> None:
11151167
"the low-level server converts to error code 0."
11161168
),
11171169
),
1170+
arm_exclusions=(ArmExclusion(reason="modern-error-surface", spec_version="2026-07-28"),),
11181171
),
11191172
# ═══════════════════════════════════════════════════════════════════════════
11201173
# Prompts
@@ -1145,6 +1198,7 @@ def __post_init__(self) -> None:
11451198
"which the low-level server converts to error code 0 with the exception text as the message."
11461199
),
11471200
),
1201+
arm_exclusions=(ArmExclusion(reason="modern-error-surface", spec_version="2026-07-28"),),
11481202
),
11491203
"prompts:get:multi-message": Requirement(
11501204
source=f"{SPEC_BASE_URL}/server/prompts#getting-a-prompt",
@@ -1187,6 +1241,7 @@ def __post_init__(self) -> None:
11871241
"mcpserver:prompt:args-validation": Requirement(
11881242
source=f"{SPEC_BASE_URL}/server/prompts#implementation-considerations",
11891243
behavior="prompts/get arguments that fail the prompt's argument schema are rejected before the function runs.",
1244+
arm_exclusions=(ArmExclusion(reason="modern-error-surface", spec_version="2026-07-28"),),
11901245
),
11911246
"mcpserver:prompt:decorated": Requirement(
11921247
source="sdk",
@@ -1218,6 +1273,7 @@ def __post_init__(self) -> None:
12181273
"ValueError, which the low-level server converts to error code 0."
12191274
),
12201275
),
1276+
arm_exclusions=(ArmExclusion(reason="modern-error-surface", spec_version="2026-07-28"),),
12211277
),
12221278
# ═══════════════════════════════════════════════════════════════════════════
12231279
# Completion
@@ -1284,13 +1340,15 @@ def __post_init__(self) -> None:
12841340
"logging:message:all-levels": Requirement(
12851341
source=f"{SPEC_BASE_URL}/server/utilities/logging#log-levels",
12861342
behavior="All eight RFC 5424 severity levels are deliverable as log message notifications.",
1343+
known_failures=(KnownFailure(spec_version="2026-07-28", note=_MODERN_NOTIFY_DROP, issue=None),),
12871344
),
12881345
"logging:message:fields": Requirement(
12891346
source=f"{SPEC_BASE_URL}/server/utilities/logging#log-message-notifications",
12901347
behavior=(
12911348
"A log message sent by a server handler is delivered to the client's logging callback with its "
12921349
"severity level, logger name, and data."
12931350
),
1351+
known_failures=(KnownFailure(spec_version="2026-07-28", note=_MODERN_NOTIFY_DROP, issue=None),),
12941352
),
12951353
"logging:message:filtered": Requirement(
12961354
source=f"{SPEC_BASE_URL}/server/utilities/logging#setting-log-level",
@@ -1910,6 +1968,16 @@ def __post_init__(self) -> None:
19101968
"client cannot learn that the set changed without polling."
19111969
),
19121970
),
1971+
known_failures=(
1972+
KnownFailure(
1973+
spec_version="2026-07-28",
1974+
note=(
1975+
"List-mutation assertions hold; only the sentinel ctx.info() never reaches the client. "
1976+
+ _MODERN_NOTIFY_DROP
1977+
),
1978+
issue=None,
1979+
),
1980+
),
19131981
),
19141982
# ═══════════════════════════════════════════════════════════════════════════
19151983
# Pagination

tests/interaction/mcpserver/test_context.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ async def whoami(ctx: Context) -> str:
121121
assert request_id
122122

123123

124+
@requirement("mcpserver:context:logging")
124125
@requirement("protocol:progress:no-token")
125126
async def test_report_progress_without_a_progress_token_sends_nothing(connect: Connect) -> None:
126127
"""When the caller supplied no progress callback, Context.report_progress is a silent no-op.

0 commit comments

Comments
 (0)