fix(rmcp): return serialized json with structured content (#368)

This commit is contained in:
Allan 2025-08-12 20:06:12 +12:00 • committed by GitHub
commit 3d8e950a52
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 46 additions and 8 deletions

View file

@ -1229,7 +1229,7 @@ impl CallToolResult {
/// ```
pub fn structured(value: Value) -> Self {
CallToolResult {
content: None,
content: Some(vec![Content::text(value.to_string())]),
structured_content: Some(value),
is_error: Some(false),
}
@ -1254,7 +1254,7 @@ impl CallToolResult {
/// ```
pub fn structured_error(value: Value) -> Self {
CallToolResult {
content: None,
content: Some(vec![Content::text(value.to_string())]),
structured_content: Some(value),
is_error: Some(true),
}

View file

@ -7,7 +7,7 @@ use rmcp::{
};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use serde_json::json;
use serde_json::{Value, json};
#[derive(Serialize, Deserialize, JsonSchema)]
pub struct CalculationRequest {
@ -122,8 +122,20 @@ async fn test_structured_content_in_call_result() {
let result = CallToolResult::structured(structured_data.clone());
assert!(result.content.is_none());
assert!(result.content.is_some());
assert!(result.structured_content.is_some());
let contents = result.content.unwrap();
assert_eq!(contents.len(), 1);
let content_text = contents.first().unwrap().as_text();
assert!(content_text.is_some());
let content_value: Value = serde_json::from_str(&content_text.unwrap().text).unwrap();
assert_eq!(content_value, structured_data);
assert_eq!(result.structured_content.unwrap(), structured_data);
assert_eq!(result.is_error, Some(false));
}
@ -138,8 +150,20 @@ async fn test_structured_error_in_call_result() {
let result = CallToolResult::structured_error(error_data.clone());
assert!(result.content.is_none());
assert!(result.content.is_some());
assert!(result.structured_content.is_some());
let contents = result.content.unwrap();
assert_eq!(contents.len(), 1);
let content_text = contents.first().unwrap().as_text();
assert!(content_text.is_some());
let content_value: Value = serde_json::from_str(&content_text.unwrap().text).unwrap();
assert_eq!(content_value, error_data);
assert_eq!(result.structured_content.unwrap(), error_data);
assert_eq!(result.is_error, Some(true));
}
@ -180,10 +204,24 @@ async fn test_structured_return_conversion() {
assert!(result.is_ok());
let call_result = result.unwrap();
assert!(call_result.content.is_none());
// Tools which return structured content should also return a serialized version as
// Content::text for backwards compatibility.
assert!(call_result.content.is_some());
assert!(call_result.structured_content.is_some());
let contents = call_result.content.unwrap();
assert_eq!(contents.len(), 1);
let content_text = contents.first().unwrap().as_text();
assert!(content_text.is_some());
let content_value: Value = serde_json::from_str(&content_text.unwrap().text).unwrap();
let structured_value = call_result.structured_content.unwrap();
assert_eq!(content_value, structured_value);
assert_eq!(structured_value["sum"], 7);
assert_eq!(structured_value["product"], 12);
}
@ -227,7 +265,7 @@ async fn test_output_schema_requires_structured_content() {
assert!(call_result.is_ok());
let call_result = call_result.unwrap();
// Verify it has structured_content and no content
// Verify it has structured_content and content
assert!(call_result.structured_content.is_some());
assert!(call_result.content.is_none());
assert!(call_result.content.is_some());
}