Skip to content

Commit 4709c71

Browse files
committed
Register 2026-07-28 stateless requirements in the interaction-suite manifest
Eleven new entries: nine with added_in="2026-07-28" sourced from SPEC_2026_BASE_URL, plus the two cross-era guard entries (protocol-version-rejection-literal, legacy-no-modern-vocabulary). Each transports-restricted entry carries a note per the manifest invariant. Claude-Session: https://claude.ai/code/session_017S3aJaxEHeMvftp6whnHWK
1 parent 10a4208 commit 4709c71

1 file changed

Lines changed: 101 additions & 0 deletions

File tree

tests/interaction/_requirements.py

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,34 @@ def __post_init__(self) -> None:
319319
"support fails initialization with an error rather than proceeding with the session."
320320
),
321321
),
322+
"lifecycle:stateless:request-envelope": Requirement(
323+
source=f"{SPEC_2026_BASE_URL}/basic/lifecycle#stateless-operation",
324+
behavior=(
325+
"At protocol_version 2026-07-28, every request carries io.modelcontextprotocol/protocolVersion, "
326+
"/clientInfo, and /clientCapabilities in params._meta; no initialize handshake occurs."
327+
),
328+
added_in="2026-07-28",
329+
),
330+
"lifecycle:stateless:no-initialize": Requirement(
331+
source=f"{SPEC_2026_BASE_URL}/basic/lifecycle#stateless-operation",
332+
behavior="A ClientSession pinned to 2026-07-28 rejects initialize() before any frame is sent.",
333+
added_in="2026-07-28",
334+
),
335+
"lifecycle:stateless:caller-meta-preserved": Requirement(
336+
source=f"{SPEC_2026_BASE_URL}/basic/lifecycle#stateless-operation",
337+
behavior=(
338+
"Caller-supplied _meta keys on a request survive the per-request envelope merge: the "
339+
"io.modelcontextprotocol/* keys are added alongside, never overwriting the caller's keys."
340+
),
341+
added_in="2026-07-28",
342+
),
343+
"lifecycle:stateless:unpinned-legacy-wire": Requirement(
344+
source=f"{SPEC_2026_BASE_URL}/basic/versioning",
345+
behavior=(
346+
"An unpinned session that negotiates an earlier protocol version emits no 2026-07-28 "
347+
"vocabulary on any JSON-RPC frame in either direction."
348+
),
349+
),
322350
# ═══════════════════════════════════════════════════════════════════════════
323351
# Protocol primitives: cancellation, timeout, progress, errors, _meta
324352
# ═══════════════════════════════════════════════════════════════════════════
@@ -2861,6 +2889,57 @@ def __post_init__(self) -> None:
28612889
removed_in="2026-07-28",
28622890
note="removed in 2026-07-28 (SEP-2575); the standalone GET endpoint is replaced by subscriptions/listen.",
28632891
),
2892+
"hosting:http:protocol-version-rejection-literal": Requirement(
2893+
source="sdk",
2894+
behavior=(
2895+
"The legacy streamable-HTTP transport's version-rejection body contains the literal substring "
2896+
"'Unsupported protocol version', which other-SDK clients substring-match during negotiation."
2897+
),
2898+
transports=("streamable-http",),
2899+
note=(
2900+
"Only observable over streamable HTTP: cross-SDK clients sniff this exact substring in the rejection body."
2901+
),
2902+
),
2903+
"hosting:http:legacy-no-modern-vocabulary": Requirement(
2904+
source=f"{SPEC_2026_BASE_URL}/basic/versioning",
2905+
behavior=(
2906+
"A 2025-era streamable-HTTP exchange carries none of the 2026-07-28 wire vocabulary "
2907+
"(resultType, ttlMs, cacheScope, io.modelcontextprotocol/* _meta keys, the 2026-07-28 "
2908+
"version string, or Mcp-Method/Mcp-Name/Mcp-Param-* headers)."
2909+
),
2910+
transports=("streamable-http",),
2911+
note=(
2912+
"Only observable over streamable HTTP: the assertion records HTTP headers and SSE frames "
2913+
"at the transport seam."
2914+
),
2915+
),
2916+
"hosting:http:modern:tools-call-stateless": Requirement(
2917+
source=f"{SPEC_2026_BASE_URL}/basic/transports/streamable-http",
2918+
behavior=(
2919+
"A 2026-07-28 tools/call POST is served without an initialize handshake and returns a "
2920+
"result body carrying resultType: complete."
2921+
),
2922+
added_in="2026-07-28",
2923+
transports=("streamable-http",),
2924+
note=(
2925+
"Only observable over streamable HTTP: the modern entry handles a 2026-07-28 POST without "
2926+
"an initialize handshake."
2927+
),
2928+
),
2929+
"hosting:http:modern:no-session-id": Requirement(
2930+
source=f"{SPEC_2026_BASE_URL}/basic/transports/streamable-http",
2931+
behavior="A 2026-07-28 response never carries an Mcp-Session-Id header.",
2932+
added_in="2026-07-28",
2933+
transports=("streamable-http",),
2934+
note="Only observable over streamable HTTP: Mcp-Session-Id is a streamable-HTTP response header.",
2935+
),
2936+
"hosting:http:modern:initialize-removed": Requirement(
2937+
source=f"{SPEC_2026_BASE_URL}/basic/index",
2938+
behavior="A 2026-07-28 initialize request is answered with METHOD_NOT_FOUND.",
2939+
added_in="2026-07-28",
2940+
transports=("streamable-http",),
2941+
note=("Only observable over streamable HTTP: the modern entry's method registry omits initialize."),
2942+
),
28642943
# ═══════════════════════════════════════════════════════════════════════════
28652944
# Client transport: streamable HTTP
28662945
# ═══════════════════════════════════════════════════════════════════════════
@@ -3034,6 +3113,28 @@ def __post_init__(self) -> None:
30343113
removed_in="2026-07-28",
30353114
note="removed in 2026-07-28 (SEP-2567); session DELETE removed with Mcp-Session-Id, no replacement.",
30363115
),
3116+
"client-transport:http:body-derived-headers": Requirement(
3117+
source=f"{SPEC_2026_BASE_URL}/basic/transports#stateless-request-headers",
3118+
behavior=(
3119+
"An envelope-bearing request body yields MCP-Protocol-Version, Mcp-Method, and (for tools/call) "
3120+
"Mcp-Name headers on the outgoing HTTP request; a body without the envelope yields none."
3121+
),
3122+
added_in="2026-07-28",
3123+
transports=("streamable-http",),
3124+
note="Only observable over streamable HTTP: headers are derived from the body envelope at the transport seam.",
3125+
),
3126+
"client-transport:http:mcp-name-encoding": Requirement(
3127+
source=f"{SPEC_2026_BASE_URL}/basic/transports#stateless-request-headers",
3128+
behavior=(
3129+
"Mcp-Name header values that are not safe for an HTTP field are wrapped in the =?base64?...?= "
3130+
"sentinel; printable-ASCII values pass verbatim."
3131+
),
3132+
added_in="2026-07-28",
3133+
transports=("streamable-http",),
3134+
note=(
3135+
"Only observable over streamable HTTP: the Base64-sentinel encoding is the spec's HTTP header-safety rule."
3136+
),
3137+
),
30373138
# ═══════════════════════════════════════════════════════════════════════════
30383139
# Client auth
30393140
# ═══════════════════════════════════════════════════════════════════════════

0 commit comments

Comments
 (0)