PrefectHQ/fastmcp · error · ValueError
mode must be 'legacy', 'auto', or one of {list(MODERN_PROTOC
Error message
mode must be 'legacy', 'auto', or one of {list(MODERN_PROTOCOL_VERSIONS)}; got {mode!r}{hint} What it means
Client.__init__ validates the mode parameter: it must be 'legacy', 'auto', or one of the modern protocol version strings in MODERN_PROTOCOL_VERSIONS. Anything else — including handshake-era version dates like '2025-03-26' — raises this ValueError; handshake-era values get an explicit hint to use mode='legacy'.
Source
Thrown at fastmcp_slim/fastmcp/client/client.py:456
verify: ssl.SSLContext | bool | str | None = None,
mode: ConnectMode = "auto",
prior_discover: mcp_types.DiscoverResult | None = None,
input_required_max_rounds: int = DEFAULT_INPUT_REQUIRED_MAX_ROUNDS,
cache: CacheConfig | bool | None = None,
extensions: Sequence[ClientExtension] | None = None,
result_claims: Mapping[str, Sequence[ResultClaim[Any]]] | None = None,
) -> None:
self.name = name or self.generate_name()
self.input_required_max_rounds = input_required_max_rounds
if mode not in ("legacy", "auto") and mode not in MODERN_PROTOCOL_VERSIONS:
hint = (
f" ({mode!r} is a handshake-era version; use mode='legacy')"
if mode in HANDSHAKE_PROTOCOL_VERSIONS
else ""
)
raise ValueError(
"mode must be 'legacy', 'auto', or one of "
f"{list(MODERN_PROTOCOL_VERSIONS)}; got {mode!r}{hint}"
)
self.mode: ConnectMode = mode
self._prior_discover = prior_discover
self.transport = cast(ClientTransportT, infer_transport(transport))
if verify is not None:
from fastmcp.client.transports.http import StreamableHttpTransport
from fastmcp.client.transports.sse import SSETransport
if isinstance(self.transport, StreamableHttpTransport | SSETransport):
self.transport.verify = verify
# Re-sync existing OAuth auth with the new verify setting,
# but only if the transport doesn't have a custom factory
# (which takes precedence and was already applied to OAuth).
if (View on GitHub (pinned to 1f02114297)
Solutions
- Use mode='auto' (default) or mode='legacy'.
- To pin a version, use one of the strings listed in the error message (values of MODERN_PROTOCOL_VERSIONS).
- If you passed a handshake-era date, replace it with mode='legacy' as the hint suggests.
- Check spelling/casing of the mode value.
Example fix
// before: handshake-era version pin rejected client = Client(url, mode='2025-03-26') // after client = Client(url, mode='legacy')
Defensive patterns
Strategy: validation
Validate before calling
from fastmcp.client.client import MODERN_PROTOCOL_VERSIONS
mode = '2025-03-26'
assert mode in ('legacy', 'auto', *MODERN_PROTOCOL_VERSIONS), f'invalid mode: {mode!r}' Type guard
from typing import Literal
from fastmcp.client.client import MODERN_PROTOCOL_VERSIONS
ValidMode = Literal['legacy', 'auto'] | str
def is_valid_mode(mode: ValidMode) -> bool:
return mode in ('legacy', 'auto') or mode in MODERN_PROTOCOL_VERSIONS Try / catch
try:
client = Client(url, mode=mode)
except ValueError as e:
if 'mode must be' in str(e):
mode = 'legacy' # or a listed modern version
client = Client(url, mode=mode)
else:
raise Prevention
- Only pass 'auto' (default), 'legacy', or a version string printed in the error (MODERN_PROTOCOL_VERSIONS).
- Never pin handshake-era protocol dates via mode; use mode='legacy' for those servers.
- Type-annotate mode as ConnectMode and validate config-sourced values at load time.
- Copy allowed values from the library, not from old documentation examples.
When it happens
Trigger: Passing mode=<anything not in {'legacy','auto'} ∪ MODERN_PROTOCOL_VERSIONS> to Client(...) or Client.new(...) — e.g. mode='2025-03-26' (handshake-era), mode='v4', mode=None, or a typo like mode='Legacy'.
Common situations: Copying a protocol date string from older MCP docs/examples; trying to pin a pre-modern protocol version; casing or spelling mistakes in 'legacy'/'auto'.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- a custom cache store requires CacheConfig.target_id for Fast
- OAuth provider has no server URL. Either pass mcp_url to OAu
- The 'verify' parameter is only supported for HTTP transports
- ClientGroup requires at least one client
- Protocol mode for server {name!r} must be a string
AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29).
Data as JSON: /api/errors/27c1dac43fc48aa9.
Report an issue: GitHub.