49b9bb6724
Deploy Docs / deploy-docs (push) Failing after 1s
Conformance Tests / client-conformance (push) Failing after 3s
Conformance Tests / server-conformance (push) Failing after 1s
GitHub Actions Security Analysis / zizmor (push) Failing after 1s
CI / checks (push) Failing after 59m20s
CI / all-green (push) Waiting to run
dual-era
One server factory, both protocol eras. A mode="legacy" client runs the
initialize handshake; a mode="auto" client probes server/discover and
adopts the 2026 stateless era — the same greet tool answers both and reports
which era served it via ctx.request_context.protocol_version. Start here
when migrating a v1 server: the entry owns the era decision, the server body
stays era-agnostic.
Run it
# over HTTP — the same /mcp endpoint serves both eras; the client self-hosts
# the server on a free port, runs, then tears it down
uv run python -m stories.dual_era.client --http
# same, against the lowlevel-API server variant
uv run python -m stories.dual_era.client --http --server server_lowlevel
The bare stdio invocation (uv run python -m stories.dual_era.client) is
legacy-only until the SDK's stdio entry can negotiate the era, so the modern
leg fails there today — run over --http.
What to look at
client.py— both connections are visible, against the sametargets()factory:Client(targets(), mode=mode)(default"auto", the discover-then-fallback ladder) andClient(targets(), mode="legacy")(forces theinitializehandshake). The era decision is one explicitmode=argument at construction; no date strings appear in the body.client.py—client.protocol_version/client.server_info/client.server_capabilitiesare era-neutral: populated byinitializeorserver/discover, whichever ran.server.py—ctx.request_context.protocol_versionis the era branch key (lowlevel:ctx.protocol_versiondirectly). Compare againstMODERN_PROTOCOL_VERSIONS, never a date literal.- Where to read the negotiated version. One value, three read paths:
client.protocol_versionon the client after connect;ctx.protocol_versioninside a lowlevel handler;ctx.request_context.protocol_versioninside anMCPServerhandler.
Caveats
ctx.request_context.protocol_versionis the current way to read the negotiated version; a later release will shorten it toctx.transport.*.- Over HTTP the built-in era branch is currently header-only — a 2026 client
that omits the
MCP-Protocol-Versionheader is mis-routed to the legacy path. The body-primary classifier lands in a later release.
Spec
See also
legacy_routing/ (route eras yourself), reconnect/ (persist DiscoverResult
for zero-RTT reconnect).