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:
        yield

View on GitHub (pinned to 1f02114297)

Solutions

  1. Nothing is broken client-side: the SDK automatically falls back to the initialize handshake; verify the connection works after connect.
  2. If the fallback is unwanted, force mode='legacy' to skip the modern probe entirely.
  3. Update the server to a version whose server/discover result is conformant with the modern protocol version.
  4. 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

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

Related errors


AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29). Data as JSON: /api/errors/bab4021c8a96ae77. Report an issue: GitHub.