Protocol Versions
Purpose and Scope
Protocol versioning in the TypeScript SDK is organized around eras, not only date-stamped revision strings. The docs define an era as a behavior family: revisions from 2024-10-07 through 2025-11-25 use the initialize handshake and belong to the legacy era, while the 2026-07-28 revision starts the modern era with server discovery, no initialize request, and a request envelope that includes metadata. This distinction matters because application code chooses how connection setup behaves, then treats the resulting connection as fixed for its lifetime.
Sources: docs/protocol-versions.md
The protocol-version page is intentionally positioned as a cross-cutting guide rather than as a client-only or server-only recipe. The sidebar places it after the Clients group and before Advanced topics, which matches its role: readers should already understand ordinary client connection and server serving flows before selecting fallback, probing, or revision pinning behavior. The LLM rendition generator also includes hand-written guide pages in sidebar order, so this page becomes part of the canonical guide corpus consumed by agents and generated markdown indexes.
Sources: docs/.vitepress/nav.ts, docs/.vitepress/llms.ts
Relevant Source Files
- docs/protocol-versions.md — Defines legacy and modern eras, client negotiation modes, probe behavior, pinning behavior, and the reader-facing explanation of how one SDK surface speaks both protocol families.
- docs/.vitepress/nav.ts — Places Protocol versions in the hand-written guide sidebar between the Clients and Advanced sections, showing where readers encounter it in the documentation flow.
- docs/.vitepress/llms.ts — Generates markdown renditions, llms.txt, and llms-full.txt from the sidebar order, preserving this page for agent-oriented documentation consumption.
- docs/_meta/CONVENTIONS.md — Documents the writing conventions for hand-written guide pages, including restrained prose, code-first recipes, and linking to protocol-version details rather than repeating era caveats inline.
- docs/.vitepress/theme/index.ts — Wires the v2 documentation site theme and banner into VitePress, providing the site shell in which the protocol-version page is published.
- docs/v1/.vitepress/theme/index.ts — Wires the v1 documentation theme and shared CSS, which supports parallel v1 and v2 documentation presentation without duplicating styling.
Era Model
The legacy era is the compatibility family for the older wire behavior. It opens with initialize, and the protocol-version docs explicitly group every revision from 2024-10-07 through 2025-11-25 into that behavior family. The modern era begins at 2026-07-28 and changes connection startup to server discovery. The important reader takeaway is that the SDK names these behavior families so code can ask for legacy, auto-detect modern support, or require the modern revision without forcing every call site to manually compare revision strings.
Sources: docs/protocol-versions.md
A connection chooses its era once, during connect. After that point, the selected era remains stable, and the documented getProtocolEra result is undefined before connection completion, then reports the chosen family afterward. This fixed decision boundary is useful for application design. Middleware, logging, request routing, and feature checks can treat the connection as belonging to one family after setup, instead of re-negotiating per request. It also prevents mixed assumptions where part of a request path expects initialize-era behavior while another part expects discovery-era metadata envelopes.
Sources: docs/protocol-versions.md
Client Negotiation Flow
Client-side negotiation is controlled by versionNegotiation. The default is legacy behavior, which means an absent mode or mode set to legacy performs the same 2025 initialize handshake without a discovery probe. Auto mode first probes with server/discover, then connects using whichever era the server supports. Against a modern-capable endpoint, the documented example prints modern. Against a 2025-only server, the same options fall back to initialize on the same connection, adding one round trip but not converting lack of discovery support into a failure.
Sources: docs/protocol-versions.md
Pinning is stricter than auto negotiation. When mode pins 2026-07-28, the client accepts that revision or rejects locally. The docs show the failure as a typed SdkError with code ERA_NEGOTIATION_FAILED when a 2025-only server does not advertise the pinned revision through server/discover. That behavior is an important compatibility control for adopters who depend on modern-era semantics. Use auto when you can operate against both eras; use a pin when your code requires discovery-era behavior and should fail before continuing with older wire assumptions.
Sources: docs/protocol-versions.md
import { Client, StreamableHTTPClientTransport } from '@modelcontextprotocol/client';
const client = new Client(
{ name: 'my-client', version: '1.0.0' },
{ versionNegotiation: { mode: 'auto' } }
);
await client.connect(new StreamableHTTPClientTransport(new URL('http://localhost:3000/mcp')));
console.log(client.getProtocolEra());Probe Controls and Failure Boundaries
The probe option bounds the discovery round trip used by auto mode and pin mode before ordinary connection setup proceeds. The documented fields are timeoutMs and maxRetries. timeoutMs defaults to the connection request timeout, and maxRetries defaults to no resend after timeout. The semantics are transport-aware: the docs call out stdio specifically, where a silent server is treated as legacy so connect can fall back to initialize on the same stream. That gives local process integrations a compatibility path without making discovery silence indistinguishable from a hard application error.
Sources: docs/protocol-versions.md
For HTTP-oriented serving, the practical design question is whether discovery failure should be recoverable. Auto mode is designed for mixed fleets and migration windows because a 2025-only endpoint remains usable. Pin mode is designed for hard requirements because it never falls back after a server fails to offer the requested modern revision. This distinction also affects observability. Auto negotiation should be logged as an era selection result, while pin failure is an actionable configuration or deployment mismatch rather than an ordinary server capability difference.
Sources: docs/protocol-versions.md
Documentation and Site Integration
The docs conventions file explains how guide pages should avoid repeating protocol-era caveats inline and instead link to the protocol-version page for depth. That convention gives this page a special role in the documentation system: it centralizes the vocabulary for legacy, modern, probe, pin, and fallback behavior. Other guides can stay focused on their task, such as serving HTTP or connecting a client, while this page provides the shared compatibility model. The result is a consistent reader path instead of scattered partial explanations across serving and client pages.
Sources: docs/_meta/CONVENTIONS.md, docs/protocol-versions.md
The VitePress theme files show that v2 and v1 documentation share a common presentation approach while keeping separate site roots. The v2 theme imports its banner and custom CSS directly, while the v1 theme reuses the v2 custom CSS through a relative import and notes that the styling is shared. For protocol-version readers, that separation reinforces the product boundary: the main branch documentation describes v2-era behavior and 2026-07-28 support, while v1 documentation remains available as a separate documentation surface.
Sources: docs/.vitepress/theme/index.ts, docs/v1/.vitepress/theme/index.ts
Compatibility Guidance
Choose legacy mode when byte-for-byte 2025 initialize behavior is the desired contract or when you are preserving older integrations while moving package boundaries. Choose auto mode when you operate clients across mixed servers and want the SDK to discover modern support opportunistically. Choose a 2026-07-28 pin when modern behavior is required for correctness and fallback would hide a deployment problem. After connect resolves, read getProtocolEra if you need to branch diagnostics, feature logging, or test assertions around the negotiated family.
Sources: docs/protocol-versions.md
When planning a migration, treat the protocol-version page as the entry point for connection behavior and the 2026-07-28 migration guide as the deeper checklist for adopting modern semantics. The official migration material states that v2 code does not put 2026-07-28 bytes on the wire by default; serving or speaking that revision is an explicit opt-in. That makes protocol negotiation a deployment choice, not an accidental side effect of installing v2 packages. Review serving pages next when deciding how one endpoint should accept both eras.
Sources: docs/protocol-versions.md, docs/.vitepress/nav.ts