Skip to content

Commit 3d8e950

Browse files
authored
fix(rmcp): return serialized json with structured content (#368)
1 parent 209dbac commit 3d8e950

File tree

2 files changed

+46
-8
lines changed

2 files changed

+46
-8
lines changed

crates/rmcp/src/model.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1229,7 +1229,7 @@ impl CallToolResult {
12291229
/// ```
12301230
pub fn structured(value: Value) -> Self {
12311231
CallToolResult {
1232-
content: None,
1232+
content: Some(vec![Content::text(value.to_string())]),
12331233
structured_content: Some(value),
12341234
is_error: Some(false),
12351235
}
@@ -1254,7 +1254,7 @@ impl CallToolResult {
12541254
/// ```
12551255
pub fn structured_error(value: Value) -> Self {
12561256
CallToolResult {
1257-
content: None,
1257+
content: Some(vec![Content::text(value.to_string())]),
12581258
structured_content: Some(value),
12591259
is_error: Some(true),
12601260
}

crates/rmcp/tests/test_structured_output.rs

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use rmcp::{
77
};
88
use schemars::JsonSchema;
99
use serde::{Deserialize, Serialize};
10-
use serde_json::json;
10+
use serde_json::{Value, json};
1111

1212
#[derive(Serialize, Deserialize, JsonSchema)]
1313
pub struct CalculationRequest {
@@ -122,8 +122,20 @@ async fn test_structured_content_in_call_result() {
122122

123123
let result = CallToolResult::structured(structured_data.clone());
124124

125-
assert!(result.content.is_none());
125+
assert!(result.content.is_some());
126126
assert!(result.structured_content.is_some());
127+
128+
let contents = result.content.unwrap();
129+
130+
assert_eq!(contents.len(), 1);
131+
132+
let content_text = contents.first().unwrap().as_text();
133+
134+
assert!(content_text.is_some());
135+
136+
let content_value: Value = serde_json::from_str(&content_text.unwrap().text).unwrap();
137+
138+
assert_eq!(content_value, structured_data);
127139
assert_eq!(result.structured_content.unwrap(), structured_data);
128140
assert_eq!(result.is_error, Some(false));
129141
}
@@ -138,8 +150,20 @@ async fn test_structured_error_in_call_result() {
138150

139151
let result = CallToolResult::structured_error(error_data.clone());
140152

141-
assert!(result.content.is_none());
153+
assert!(result.content.is_some());
142154
assert!(result.structured_content.is_some());
155+
156+
let contents = result.content.unwrap();
157+
158+
assert_eq!(contents.len(), 1);
159+
160+
let content_text = contents.first().unwrap().as_text();
161+
162+
assert!(content_text.is_some());
163+
164+
let content_value: Value = serde_json::from_str(&content_text.unwrap().text).unwrap();
165+
166+
assert_eq!(content_value, error_data);
143167
assert_eq!(result.structured_content.unwrap(), error_data);
144168
assert_eq!(result.is_error, Some(true));
145169
}
@@ -180,10 +204,24 @@ async fn test_structured_return_conversion() {
180204
assert!(result.is_ok());
181205
let call_result = result.unwrap();
182206

183-
assert!(call_result.content.is_none());
207+
// Tools which return structured content should also return a serialized version as
208+
// Content::text for backwards compatibility.
209+
assert!(call_result.content.is_some());
184210
assert!(call_result.structured_content.is_some());
185211

212+
let contents = call_result.content.unwrap();
213+
214+
assert_eq!(contents.len(), 1);
215+
216+
let content_text = contents.first().unwrap().as_text();
217+
218+
assert!(content_text.is_some());
219+
220+
let content_value: Value = serde_json::from_str(&content_text.unwrap().text).unwrap();
186221
let structured_value = call_result.structured_content.unwrap();
222+
223+
assert_eq!(content_value, structured_value);
224+
187225
assert_eq!(structured_value["sum"], 7);
188226
assert_eq!(structured_value["product"], 12);
189227
}
@@ -227,7 +265,7 @@ async fn test_output_schema_requires_structured_content() {
227265
assert!(call_result.is_ok());
228266
let call_result = call_result.unwrap();
229267

230-
// Verify it has structured_content and no content
268+
// Verify it has structured_content and content
231269
assert!(call_result.structured_content.is_some());
232-
assert!(call_result.content.is_none());
270+
assert!(call_result.content.is_some());
233271
}

0 commit comments

Comments
 (0)