rohitg00/ai-engineering-from-scratch · error · RuntimeError

{peer.name}: unsupported legacy protocol revision

Error message

{peer.name}: unsupported legacy protocol revision

What it means

The legacy initialize succeeded but the protocolVersion in the result is not in the client's supported_legacy set. The client only speaks an explicit allowlist of legacy revisions and refuses to proceed with one it has not been configured to accept.

Source

Thrown at phases/13-tools-and-protocols/08-building-an-mcp-client/code/main.py:389

            raise RuntimeError(f"{peer.name}: bounded legacy probe failed closed") from exc
        if not isinstance(response, dict):
            raise RuntimeError(f"{peer.name}: bounded legacy probe returned no result")
        kind, payload = decode_rpc_response(response, request_id)
        if kind != "result":
            raise RuntimeError(f"{peer.name}: legacy initialize returned an error")
        result = payload
        version = result.get("protocolVersion")
        capabilities = result.get("capabilities")
        server_info = result.get("serverInfo")
        valid_server_info = (
            isinstance(server_info, dict)
            and isinstance(server_info.get("name"), str)
            and bool(server_info["name"])
            and isinstance(server_info.get("version"), str)
            and bool(server_info["version"])
        )
        if version not in self.supported_legacy:
            raise RuntimeError(f"{peer.name}: unsupported legacy protocol revision")
        if not isinstance(capabilities, dict) or not valid_server_info:
            raise RuntimeError(f"{peer.name}: malformed legacy initialize result")
        peer.era = "legacy"
        peer.protocol_version = version
        peer.capabilities = capabilities
        peer.server_info = server_info
        peer.available = True
        self._send(
            peer,
            {"jsonrpc": "2.0", "method": "notifications/initialized", "params": {}}
        )

    def _connect_peer(self, peer: Peer) -> None:
        if peer.available and peer.era in {"modern", "legacy"}:
            return
        request_id = self._new_id()
        probe = modern_request(
            request_id,

View on GitHub (pinned to 39ea8a1c6d)

Solutions

  1. Check what protocolVersion the server returned and compare with client.supported_legacy
  2. Add the server's revision to supported_legacy if it is actually safe to use
  3. Upgrade the server to a revision the client already allows
  4. Disable legacy for this peer and require a modern handshake

Example fix

// before
client = McpClient(..., supported_legacy={"2024-11-05"})

// after
client = McpClient(..., supported_legacy={"2024-11-05", "2025-03-26"})
Defensive patterns

Strategy: validation

Validate before calling

advertised = probe_server_protocol_version(peer)
if advertised not in client.supported_legacy:
    align_versions(client, peer)  # widen set or upgrade server before connect

Type guard

null

Try / catch

try:
    client.connect_all()
except RuntimeError as e:
    if "unsupported legacy protocol revision" in str(e):
        client.supported_legacy.add(reported_version(peer))

Prevention

When it happens

Trigger: result.get('protocolVersion') from a successful legacy initialize returns a version string absent from self.supported_legacy.

Common situations: Server running a much older or newer legacy revision than the client anticipates; client's supported_legacy not updated after a server upgrade; server reporting an ad-hoc version string.

Related errors


AI-assisted analysis of rohitg00/ai-engineering-from-scratch@39ea8a1c6d (2026-08-26). Data as JSON: /api/errors/8702484ae488cad5. Report an issue: GitHub.