PrefectHQ/fastmcp · warning · MCPError
INVALID_PARAMS
INVALID_PARAMS
Error message
server/discover result is not conformant with {version}; treating the server as handshake-era What it means
In 'auto' connect mode the client probes server/discover at the newest modern version; the probe result must satisfy the strict per-version schema (resultType/ttlMs/cacheScope required) that will govern later calls. A result that parses loosely but fails validate_server_result is rejected via MCPError(INVALID_PARAMS) so negotiate_auto falls back to the classic initialize handshake instead of adopting an era the server cannot actually serve.
Source
Thrown at fastmcp_slim/fastmcp/client/client.py:175
for a server with no ``server/discover`` at all.
"""
send_discover = session.send_discover
async def _checked_send_discover(version: str) -> dict[str, Any]:
raw = await send_discover(version)
try:
validate_server_result("server/discover", version, raw)
except ValidationError as e:
# Ordered before the ValueError arm below: pydantic's ValidationError
# subclasses ValueError, so a broader clause first would swallow it.
logger.debug(
"server/discover at %s is not %s-conformant (%s); "
"falling back to the initialize handshake",
version,
version,
e,
)
raise MCPError(
code=mcp_types.INVALID_PARAMS,
message=(
f"server/discover result is not conformant with {version}; "
"treating the server as handshake-era"
),
) from e
except (KeyError, ValueError):
# No schema on file for this method/version pair, so there is nothing to
# judge the probe against; leave the verdict to negotiate_auto's parse.
return raw
return raw
# A transport may itself have installed a `send_discover` override, so restore
# whatever was there rather than assuming the class attribute.
had_own = "send_discover" in vars(session)
session.send_discover = _checked_send_discover # ty: ignore[invalid-assignment]
try:
yieldView on GitHub (pinned to 1f02114297)
Solutions
- Nothing is broken client-side: the SDK automatically falls back to the initialize handshake; verify the connection works after connect.
- If the fallback is unwanted, force mode='legacy' to skip the modern probe entirely.
- Update the server to a version whose server/discover result is conformant with the modern protocol version.
- Enable debug logging to inspect the validation error (pydantic ValidationError) if you are developing the server.
Example fix
// before: auto probing hits a non-conformant server
client = Client('https://mcp.example.com/mcp', mode='auto')
// after: skip the modern probe for a handshake-era server
client = Client('https://mcp.example.com/mcp', mode='legacy') Defensive patterns
Strategy: fallback
Try / catch
try:
async with client: # mode='auto': SDK falls back to initialize handshake automatically
await client.list_tools()
except Exception as e:
from mcp import McpError
if isinstance(e, McpError) and e.error.code == -32602: # INVALID_PARAMS
client = Client(url, mode='legacy') # force handshake-era path
async with client:
await client.list_tools() Prevention
- Keep client and server SDK versions aligned with the same MCP protocol generation.
- For known handshake-era servers, opt into mode='legacy' explicitly instead of relying on the probe fallback.
- If you develop a server, validate its server/discover payload against the strict per-version schema (resultType/ttlMs/cacheScope).
- Enable debug logging during connect to see the underlying ValidationError early.
When it happens
Trigger: Connecting with mode='auto' (the default) to a server that responds to server/discover with a result missing required fields (or wrong shape) for the probed modern version — e.g. a partially-implemented or handshake-era server that answers the probe non-conformantly.
Common situations: Server upgraded/downgraded between MCP spec versions; a proxy or mocked server returning a simplified discover payload; third-party server implementing an older draft of the modern protocol surface.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- The client negotiated a modern protocol era (server/discover
- logging/setLevel is not available on MCP 2026-07-28 connecti
- [{self.name}] Reached auto-pagination limit ({max_pages} pag
- [{self.name}] Reached auto-pagination limit ({max_pages} pag
- [{self.name}] Reached auto-pagination limit ({max_pages} pag
AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29).
Data as JSON: /api/errors/bab4021c8a96ae77.
Report an issue: GitHub.