From e1c4db15c2028a147bbbacb0645a9d8aaae479cf Mon Sep 17 00:00:00 2001 From: Michael Neale Date: Thu, 7 Aug 2025 10:29:02 +1000 Subject: [PATCH] fix(rmcp): allow both content and structured content Co-authored-by: Alex Hancock --- crates/rmcp/src/model.rs | 5 +---- .../server_json_rpc_message_schema.json | 2 +- .../server_json_rpc_message_schema_current.json | 6 +++--- crates/rmcp/tests/test_structured_output.rs | 12 ++++++------ 4 files changed, 11 insertions(+), 14 deletions(-) diff --git a/crates/rmcp/src/model.rs b/crates/rmcp/src/model.rs index f0c92c0a..7156ccae 100644 --- a/crates/rmcp/src/model.rs +++ b/crates/rmcp/src/model.rs @@ -1181,8 +1181,6 @@ pub type RootsListChangedNotification = NotificationNoParam Result<(), &'static str> { match (&self.content, &self.structured_content) { - (Some(_), Some(_)) => Err("content and structured_content are mutually exclusive"), (None, None) => Err("either content or structured_content must be provided"), _ => Ok(()), } diff --git a/crates/rmcp/tests/test_message_schema/server_json_rpc_message_schema.json b/crates/rmcp/tests/test_message_schema/server_json_rpc_message_schema.json index 81b1221d..09eca257 100644 --- a/crates/rmcp/tests/test_message_schema/server_json_rpc_message_schema.json +++ b/crates/rmcp/tests/test_message_schema/server_json_rpc_message_schema.json @@ -299,7 +299,7 @@ } }, "CallToolResult": { - "description": "The result of a tool call operation.\n\nContains the content returned by the tool execution and an optional\nflag indicating whether the operation resulted in an error.\n\nNote: `content` and `structured_content` are mutually exclusive - exactly one must be provided.", + "description": "The result of a tool call operation.\n\nContains the content returned by the tool execution and an optional\nflag indicating whether the operation resulted in an error.", "type": "object", "properties": { "content": { diff --git a/crates/rmcp/tests/test_message_schema/server_json_rpc_message_schema_current.json b/crates/rmcp/tests/test_message_schema/server_json_rpc_message_schema_current.json index aaa5562e..09eca257 100644 --- a/crates/rmcp/tests/test_message_schema/server_json_rpc_message_schema_current.json +++ b/crates/rmcp/tests/test_message_schema/server_json_rpc_message_schema_current.json @@ -299,7 +299,7 @@ } }, "CallToolResult": { - "description": "The result of a tool call operation.\n\nContains the content returned by the tool execution and an optional\nflag indicating whether the operation resulted in an error.\n\nNote: `content` and `structured_content` are mutually exclusive - exactly one must be provided.", + "description": "The result of a tool call operation.\n\nContains the content returned by the tool execution and an optional\nflag indicating whether the operation resulted in an error.", "type": "object", "properties": { "content": { @@ -1336,7 +1336,7 @@ { "type": "object", "properties": { - "mime_type": { + "mimeType": { "type": [ "string", "null" @@ -1360,7 +1360,7 @@ "blob": { "type": "string" }, - "mime_type": { + "mimeType": { "type": [ "string", "null" diff --git a/crates/rmcp/tests/test_structured_output.rs b/crates/rmcp/tests/test_structured_output.rs index 7e85d0e7..8d77cf80 100644 --- a/crates/rmcp/tests/test_structured_output.rs +++ b/crates/rmcp/tests/test_structured_output.rs @@ -146,7 +146,7 @@ async fn test_structured_error_in_call_result() { #[tokio::test] async fn test_mutual_exclusivity_validation() { - // Test that content and structured_content are mutually exclusive + // Test that content and structured_content can both be passed separately let content_result = CallToolResult::success(vec![Content::text("Hello")]); let structured_result = CallToolResult::structured(json!({"message": "Hello"})); @@ -154,15 +154,15 @@ async fn test_mutual_exclusivity_validation() { assert!(content_result.validate().is_ok()); assert!(structured_result.validate().is_ok()); - // Try to create an invalid result with both fields - let invalid_json = json!({ + // Try to create a result with both fields + let json_with_both = json!({ "content": [{"type": "text", "text": "Hello"}], "structuredContent": {"message": "Hello"} }); - // The deserialization itself should fail due to validation - let deserialized: Result = serde_json::from_value(invalid_json); - assert!(deserialized.is_err()); + // The deserialization itself should not fail + let deserialized: Result = serde_json::from_value(json_with_both); + assert!(deserialized.is_ok()); } #[tokio::test]