Hmbown/CodeWhale · error · anyhow::Error
MCP server ' ' negotiated unsupported protocol version ' '…
Error message
MCP server '{}' negotiated unsupported protocol version '{negotiated}' (supported: {}) What it means
After extracting the server's protocolVersion, the client checks it against MCP_SUPPORTED_PROTOCOL_VERSIONS (the dated revisions this client still implements). A server proposing a version outside that set ends the handshake, since message schemas may differ across revisions and the client refuses to guess compatibility.
Solutions
- Upgrade the MCP client (this application) to a build supporting the server's protocol revision.
- Downgrade or reconfigure the server to advertise one of the supported versions listed in the error message.
- If you own the server, have it propose a version from the supported list (spec-compliant servers accept the client's requested version).
- Check MCP_SUPPORTED_PROTOCOL_VERSIONS in the code and align server and client deployments to the same revision.
Example fix
// before (server-side) "protocolVersion": "1999-01-01" // after "protocolVersion": "2025-06-18" // a version in the client's supported set
Defensive patterns
Strategy: try-catch
Validate before calling
// preflight the negotiated version against the client's supported set
let version = probe_initialize(endpoint).await?.protocolVersion;
if !SUPPORTED_VERSIONS.contains(&version.as_str()) {
return Err(format!("server speaks {version}; client supports {SUPPORTED_VERSIONS:?}"));
} Type guard
fn is_supported_version(v: &str) -> bool {
MCP_SUPPORTED_PROTOCOL_VERSIONS.contains(&v)
} Try / catch
match client.initialize().await {
Err(e) if e.to_string().contains("negotiated unsupported protocol version") => {
warn!("version mismatch; upgrading client or downgrading server required");
Err(e)
}
other => other,
} Prevention
- Upgrade client and server together so protocol revisions stay in lockstep
- Have servers echo a client-requested version from the supported list
- Check the error's 'supported:' list before choosing a server version
- Avoid hard-coding invented version strings like "1.0" in custom servers
When it happens
Trigger: Server's initialize result advertises a protocolVersion string not in the client's supported list — a newer spec revision the client hasn't adopted, or an old/draft revision that was dropped.
Common situations: Server updated to a brand-new MCP spec revision before the client added support (or vice versa: very old server pinned to a retired revision), a custom server hard-coding a made-up version string like "1.0", or a mismatched client/server deployment where one was upgraded without the other.
Related errors
- MCP server ' ' initialize result omitted protocolVersion
- MCP server ' ': unsupported protocol version ' '…
- MCP server ' ': unsupported protocol version ' ' (expected )
- MCP SSE server sent a message before declaring its endpoint
- JSON-RPC line exceeded the
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/366084ce098bd4d7.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/mcp.rs:1899
let response = self.recv(init_id).await?;
let result = response_result(
&response,
"initialize",
self.config.reviewed_plugin.is_some(),
)?;
// Per spec, a server that cannot speak the advertised revision answers
// with one it does support. Accept any dated revision we still
// implement; anything else ends the handshake.
let negotiated = result
.and_then(|result| result.get("protocolVersion"))
.and_then(|version| version.as_str())
.ok_or_else(|| {
anyhow::anyhow!(
"MCP server '{}' initialize result omitted protocolVersion",
self.name
)
})?;
anyhow::ensure!(
MCP_SUPPORTED_PROTOCOL_VERSIONS.contains(&negotiated),
"MCP server '{}' negotiated unsupported protocol version '{negotiated}' (supported: {})",
self.name,
MCP_SUPPORTED_PROTOCOL_VERSIONS.join(", ")
);
self.transport.set_protocol_version(negotiated);
self.server_capabilities = McpServerCapabilities::from_initialize_response(&response);
// Send initialized notification (no id, no response expected)
self.send(serde_json::json!({
"jsonrpc": "2.0",
"method": "notifications/initialized"
}))
.await?;
Ok(())
}
View on GitHub (pinned to 73e0f67d83)