Skip to content

Commit a97459d

Browse files
committed
Add lifecycle:envelope/discover/mode requirement entries and interaction tests
- 9 new requirement IDs in the Lifecycle section covering the per-request envelope, server/discover behaviour, and Client mode= policy - 10 interaction tests in tests/interaction/lowlevel/test_client_connect.py driving each via Client(server, mode=...) over in-memory and in-process ASGI
1 parent dcbe6e8 commit a97459d

2 files changed

Lines changed: 438 additions & 0 deletions

File tree

tests/interaction/_requirements.py

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,7 @@ def __post_init__(self) -> None:
250250
source=f"{SPEC_BASE_URL}/basic/lifecycle#initialization",
251251
behavior="The client's name, version, and title are visible to server handlers after initialization.",
252252
removed_in="2026-07-28",
253+
superseded_by="lifecycle:envelope:stamped-on-every-request",
253254
note="initialize handshake removed at 2026-07-28; per-request _meta envelope replaces it.",
254255
arm_exclusions=(ArmExclusion(reason="requires-session", transport="streamable-http-stateless"),),
255256
),
@@ -260,6 +261,7 @@ def __post_init__(self) -> None:
260261
"(sampling, elicitation, roots)."
261262
),
262263
removed_in="2026-07-28",
264+
superseded_by="lifecycle:envelope:stamped-on-every-request",
263265
note="initialize handshake removed at 2026-07-28; per-request _meta envelope replaces it.",
264266
arm_exclusions=(ArmExclusion(reason="requires-session", transport="streamable-http-stateless"),),
265267
),
@@ -393,6 +395,80 @@ def __post_init__(self) -> None:
393395
"hosting:http:legacy-no-modern-vocabulary covers the same vocabulary set"
394396
),
395397
),
398+
"lifecycle:envelope:stamped-on-every-request": Requirement(
399+
source=f"{SPEC_2026_BASE_URL}/basic#_meta",
400+
behavior=(
401+
"Every client→server request on a modern-negotiated session carries "
402+
"_meta.{protocolVersion,clientInfo,clientCapabilities}; notifications do not."
403+
),
404+
added_in="2026-07-28",
405+
supersedes=("lifecycle:initialize:client-info", "lifecycle:initialize:client-capabilities"),
406+
),
407+
"lifecycle:envelope:header-matches-meta": Requirement(
408+
source=f"{SPEC_2026_BASE_URL}/basic/transports/streamable-http#headers",
409+
behavior="On HTTP, the MCP-Protocol-Version header on every POST matches _meta.protocolVersion in the body.",
410+
transports=("streamable-http", "streamable-http-stateless"),
411+
added_in="2026-07-28",
412+
note="HTTP-only: the header is a streamable-http transport concern; stdio and in-memory carry no headers.",
413+
),
414+
"lifecycle:discover:basic": Requirement(
415+
source=f"{SPEC_2026_BASE_URL}/basic/lifecycle#discover",
416+
behavior=(
417+
"Calling discover() sends server/discover with no params and returns a typed DiscoverResult "
418+
"carrying protocolVersion, capabilities, serverInfo and the cache hint fields."
419+
),
420+
added_in="2026-07-28",
421+
),
422+
"lifecycle:discover:retry-on-32022": Requirement(
423+
source=f"{SPEC_2026_BASE_URL}/basic/lifecycle#version-errors",
424+
behavior=(
425+
"When server/discover returns -32022 UnsupportedProtocolVersion, the client retries once with "
426+
"the intersection of error.data.supported and its own modern versions; an empty intersection raises."
427+
),
428+
added_in="2026-07-28",
429+
),
430+
"lifecycle:discover:fallback-method-not-found": Requirement(
431+
source=f"{SPEC_2026_BASE_URL}/basic/transports/stdio#backward-compatibility",
432+
behavior=(
433+
"When server/discover returns -32601 (or HTTP 404), an auto-negotiating client falls back to "
434+
"the legacy initialize handshake and the connection succeeds at a handshake-era version."
435+
),
436+
added_in="2026-07-28",
437+
),
438+
"lifecycle:discover:network-error-raises": Requirement(
439+
source="sdk",
440+
behavior=(
441+
"An HTTP timeout, connection error, or non-404 4xx/5xx during server/discover raises to the "
442+
"caller without falling back to initialize."
443+
),
444+
transports=("streamable-http", "streamable-http-stateless"),
445+
added_in="2026-07-28",
446+
note="HTTP-only: distinguishes transport-level failures from the -32601 fallback signal.",
447+
),
448+
"lifecycle:mode:legacy-never-probes": Requirement(
449+
source="sdk",
450+
behavior=(
451+
"A Client constructed with mode='legacy' (the default) sends initialize as its first request "
452+
"and never sends server/discover."
453+
),
454+
added_in="2026-07-28",
455+
),
456+
"lifecycle:mode:pin-never-handshakes": Requirement(
457+
source="sdk",
458+
behavior=(
459+
"A Client constructed with mode='2026-07-28' sends no initialize and no server/discover; its "
460+
"first wire request is the caller's first call, carrying the full _meta envelope."
461+
),
462+
added_in="2026-07-28",
463+
),
464+
"lifecycle:mode:prior-discover-zero-rtt": Requirement(
465+
source="sdk",
466+
behavior=(
467+
"A Client constructed with prior_discover=<DiscoverResult> sends no negotiation traffic; "
468+
"server_info and capabilities are populated from the prior result."
469+
),
470+
added_in="2026-07-28",
471+
),
396472
# ═══════════════════════════════════════════════════════════════════════════
397473
# Protocol primitives: cancellation, timeout, progress, errors, _meta
398474
# ═══════════════════════════════════════════════════════════════════════════

0 commit comments

Comments
 (0)