Hmbown/CodeWhale · error

MCP server ' ': unsupported protocol version ' '…

Error message

MCP server '{server_name}': unsupported protocol version '{protocol_version}' (supported: {})

What it means

After the initialize handshake, validate_initialize_result checks that the server's protocolVersion is one of MCP_SUPPORTED_PROTOCOL_VERSIONS — the dated revisions this client implements. Negotiation per spec: the client advertises the newest revision and accepts any dated revision it still supports; anything else aborts the connection with this error.

Solutions

  1. Upgrade codewhale (the client) so its MCP_SUPPORTED_PROTOCOL_VERSIONS includes the server's revision
  2. Downgrade or update the MCP server to one speaking a supported dated revision
  3. Fix a misconfigured server that reports a bogus version string instead of a spec date

Example fix

// before (server)
"protocolVersion": "1.0"
// after (server echoes a supported dated revision)
"protocolVersion": "2025-06-18"
Defensive patterns

Strategy: try-catch

Validate before calling

const SUPPORTED: &[&str] = &["2024-11-05", "2025-03-26", "2025-06-18"];
// check the server's advertised version from its manifest/docs before spawning
fn protocol_supported(v: &str) -> bool { SUPPORTED.contains(&v) }

Type guard

fn is_supported_protocol(v: &str) -> bool {
    ["2024-11-05", "2025-03-26", "2025-06-18"].contains(&v)
}

Try / catch

match client.spawn(config).await {
    Ok(handle) => use(handle),
    Err(e) if e.to_string().contains("unsupported protocol version") => {
        eprintln!("server speaks an unsupported MCP revision; upgrade client or server");
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: spawn_with_timeouts completes an initialize request and the server replies with a protocolVersion that is missing from MCP_SUPPORTED_PROTOCOL_VERSIONS — too old, too new, or a non-dated value like "1.0" or "latest".

Common situations: Server built against a newer MCP spec revision than the client supports; very old server pinned to a retired revision; server hardcoding a wrong version string instead of echoing a negotiated one.

Understand the failure class

Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/67ba9ffa0da883d6. Report an issue: GitHub.

Appendix: source

Thrown at crates/mcp/src/stdio_client.rs:440

}

fn validate_initialize_result(
    server_name: &str,
    result: &Value,
) -> Result<Option<ServerCapabilities>> {
    let response = result.as_object().with_context(|| {
        format!("MCP server '{server_name}': initialize result must be an object")
    })?;
    let protocol_version = response
        .get("protocolVersion")
        .and_then(Value::as_str)
        .with_context(|| {
            format!("MCP server '{server_name}': initialize result omitted protocolVersion")
        })?;
    // Negotiation per spec: we advertise the newest revision and accept any
    // dated revision we still implement; anything else ends the handshake.
    if !MCP_SUPPORTED_PROTOCOL_VERSIONS.contains(&protocol_version) {
        bail!(
            "MCP server '{server_name}': unsupported protocol version '{protocol_version}' (supported: {})",
            MCP_SUPPORTED_PROTOCOL_VERSIONS.join(", ")
        );
    }

    let server_info = response
        .get("serverInfo")
        .and_then(Value::as_object)
        .with_context(|| {
            format!("MCP server '{server_name}': initialize result omitted serverInfo")
        })?;
    for field in ["name", "version"] {
        if !server_info.get(field).is_some_and(Value::is_string) {
            bail!("MCP server '{server_name}': initialize serverInfo.{field} must be a string");
        }
    }

    match response.get("capabilities") {

View on GitHub (pinned to 73e0f67d83)