fast-agent opens every connection with a 2026-07-28 discover probe

Kind: idiosyncrasy · Status: current · Last verified: 2026-08-25 · Clients: fast-agent · Revisions: 2026-07-28, 2025-11-25

protocol_mode defaults to auto, both globally and per server. auto is passed straight through to the SDK's Client(mode=...), and the SDK's negotiate_auto sends server/discover proposing 2026-07-28 before anything else. Only when that probe fails does initialize follow.

So a server that has never seen a 2026-era client will now see one. The probe is not conditional on transport: stdio servers get it too.

What the probe does with a refusal

negotiate_auto is a denylist, not an allowlist. Every MCPError falls back to initialize except one case: -32022 UNSUPPORTED_PROTOCOL_VERSION whose supported list names modern versions and no handshake version. A -32601 METHOD_NOT_FOUND — what a pre-2026 server returns — falls back silently.

Two further cases also fall back rather than fail:

A -32022 from the fallback initialize triggers one re-probe instead of an error, on the reasoning that a client-side probe timeout can leave a slow server already locked to the modern era.

Non-MCPError exceptions — network failures, cancellation — propagate. An outage is never read as an era verdict.

The three modes

protocol_mode First request Fallback
auto (default) server/discover at 2026-07-28 initialize at 2025-11-25
modern server/discover at 2026-07-28 none — the connection fails
legacy initialize at 2025-11-25 none

modern is fast-agent's own subclass, _ForcedModernClient, which enters the client context only after a successful discover so a failed negotiation unwinds the transport cleanly. It is rejected in config validation when combined with the SSE transport.

legacy offers LATEST_HANDSHAKE_VERSION, which is 2025-11-25 in mcp-types 2.0.0. fast-agent never names a revision of its own; both ends of the range come from the SDK's version registry.

Why this matters for a support matrix

Every other client read so far has one negotiated revision, and recording it as preferredProtocolVersion describes what a server sees. fast-agent has two, and which one a given server sees is decided by the server. The top-level capability rows here describe the modern path; byProtocolVersion["2025-11-25"] records what differs when the fallback fires.

Sources