From f8941d8920441cdee1b050c7aa115f0b97d8224d Mon Sep 17 00:00:00 2001 From: James Peter Date: Tue, 28 Oct 2025 15:44:46 +1000 Subject: [PATCH] fix: improve MCP version mismatch detection and error messages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Addresses #292 by enhancing error reporting and validation in the MCP handshake process: - Add MCP_SCHEMA_VERSION to handshake error messages to help users identify version compatibility issues - Implement explicit protocol version comparison after successful handshake conversion to detect version mismatches - Add clear, actionable error message when server and client versions don't match - Include test to verify MCP_SCHEMA_VERSION constant is accessible This helps prevent confusion when MCP servers and clients are running incompatible protocol versions. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- code-rs/rmcp-client/src/rmcp_client.rs | 34 +++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/code-rs/rmcp-client/src/rmcp_client.rs b/code-rs/rmcp-client/src/rmcp_client.rs index b8896ae5859f..34fdf751328f 100644 --- a/code-rs/rmcp-client/src/rmcp_client.rs +++ b/code-rs/rmcp-client/src/rmcp_client.rs @@ -14,6 +14,7 @@ use mcp_types::InitializeRequestParams; use mcp_types::InitializeResult; use mcp_types::ListToolsRequestParams; use mcp_types::ListToolsResult; +use mcp_types::MCP_SCHEMA_VERSION; use rmcp::model::CallToolRequestParam; use rmcp::model::InitializeRequestParam; use rmcp::model::PaginatedRequestParam; @@ -151,18 +152,28 @@ impl RmcpClient { let service = match timeout { Some(duration) => time::timeout(duration, service_future) .await - .map_err(|_| anyhow!("timed out handshaking with MCP server after {duration:?}"))? - .map_err(|err| anyhow!("handshaking with MCP server failed: {err}"))?, + .map_err(|_| anyhow!("timed out handshaking with MCP server after {duration:?}. Expected MCP protocol version: {MCP_SCHEMA_VERSION}"))? + .map_err(|err| anyhow!("handshaking with MCP server failed: {err}. Expected MCP protocol version: {MCP_SCHEMA_VERSION}"))?, None => service_future .await - .map_err(|err| anyhow!("handshaking with MCP server failed: {err}"))?, + .map_err(|err| anyhow!("handshaking with MCP server failed: {err}. Expected MCP protocol version: {MCP_SCHEMA_VERSION}"))?, }; let initialize_result_rmcp = service .peer() .peer_info() .ok_or_else(|| anyhow!("handshake succeeded but server info was missing"))?; - let initialize_result = convert_to_mcp(initialize_result_rmcp)?; + let initialize_result: InitializeResult = convert_to_mcp(initialize_result_rmcp)?; + + // Check if the protocol version matches the expected version + if initialize_result.protocol_version != MCP_SCHEMA_VERSION { + return Err(anyhow!( + "MCP protocol version mismatch: server returned '{}', but client expects '{}'. \ + Please ensure both the MCP server and client are using compatible versions.", + initialize_result.protocol_version, + MCP_SCHEMA_VERSION + )); + } { let mut guard = self.state.lock().await; @@ -217,3 +228,18 @@ impl RmcpClient { } } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_mcp_schema_version_is_available() { + // This test verifies that MCP_SCHEMA_VERSION is accessible and has a valid format + assert!(!MCP_SCHEMA_VERSION.is_empty()); + assert!(MCP_SCHEMA_VERSION.contains('-')); + // Expected format: YYYY-MM-DD (e.g., "2025-06-18") + let parts: Vec<&str> = MCP_SCHEMA_VERSION.split('-').collect(); + assert_eq!(parts.len(), 3, "MCP_SCHEMA_VERSION should be in YYYY-MM-DD format"); + } +}