diff --git a/crates/rmcp/src/transport/async_rw.rs b/crates/rmcp/src/transport/async_rw.rs index 3d561fe71..acd1b4f65 100644 --- a/crates/rmcp/src/transport/async_rw.rs +++ b/crates/rmcp/src/transport/async_rw.rs @@ -179,8 +179,31 @@ fn without_carriage_return(s: &[u8]) -> &[u8] { } } -/// Check if a notification method is a standard MCP notification -/// should update this when MCP spec is updated about new notifications +/// Check if a method is a standard MCP method (request, response, or notification). +/// This includes both requests and notifications defined in the MCP specification. +/// +/// Based on MCP specification 2025-06-18: https://modelcontextprotocol.io/specification/2025-06-18 +fn is_standard_method(method: &str) -> bool { + matches!( + method, + "initialize" + | "ping" + | "prompts/get" + | "prompts/list" + | "resources/list" + | "resources/read" + | "resources/subscribe" + | "resources/unsubscribe" + | "resources/templates/list" + | "tools/call" + | "tools/list" + | "completion/complete" + | "logging/setLevel" + | "roots/list" + | "sampling/createMessage" + ) || is_standard_notification(method) +} + fn is_standard_notification(method: &str) -> bool { matches!( method, @@ -196,6 +219,29 @@ fn is_standard_notification(method: &str) -> bool { ) } +/// Determines if a notification should be ignored for compatibility. +fn should_ignore_notification(json_value: &serde_json::Value, method: &str) -> bool { + let is_notification = json_value.get("id").is_none(); + + // Ignore non-MCP notifications (like LSP messages) for compatibility + if is_notification && !is_standard_method(method) { + tracing::trace!( + "Ignoring non-MCP notification '{}' for compatibility", + method + ); + return true; + } + + // Ignore non-standard MCP notifications + matches!( + ( + method.starts_with("notifications/"), + is_standard_notification(method) + ), + (true, false) + ) +} + /// Try to parse a message with compatibility handling for non-standard notifications fn try_parse_with_compatibility( line: &[u8], @@ -205,22 +251,13 @@ fn try_parse_with_compatibility( match serde_json::from_slice(line) { Ok(item) => Ok(Some(item)), Err(e) => { - // Check if this is a non-standard notification that should be ignored - if line_str.contains("\"method\":\"notifications/") { - // Extract the method name to check if it's standard - if let Ok(json_value) = serde_json::from_str::(line_str) { - if let Some(method) = json_value.get("method").and_then(|m| m.as_str()) { - if method.starts_with("notifications/") - && !is_standard_notification(method) - { - tracing::debug!( - "Ignoring non-standard notification {} {}: {}", - method, - context, - line_str - ); - return Ok(None); // Skip this message - } + // Check if this is a notification that should be ignored for compatibility + if let Ok(json_value) = serde_json::from_str::(line_str) { + if let Some(method) = + json_value.get("method").and_then(serde_json::Value::as_str) + { + if should_ignore_notification(&json_value, method) { + return Ok(None); } } }