Skip to content

Commit 97d6a3d

Browse files
committed
feat!: relax tool result structuredContent type
1 parent 2522036 commit 97d6a3d

6 files changed

Lines changed: 38 additions & 26 deletions

File tree

crates/rmcp/src/model/content.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
//! The various content types can be display to humans but also understood by models
33
//! They include optional annotations used to help inform agent usage
44
use serde::{Deserialize, Serialize};
5-
use serde_json::json;
5+
use serde_json::{Value, json};
66

77
use super::{AnnotateAble, Annotated, resource::ResourceContents};
88

@@ -107,7 +107,7 @@ pub struct ToolResultContent {
107107
pub content: Vec<Content>,
108108
/// Optional structured result
109109
#[serde(skip_serializing_if = "Option::is_none")]
110-
pub structured_content: Option<super::JsonObject>,
110+
pub structured_content: Option<Value>,
111111
/// Whether tool execution failed
112112
#[serde(skip_serializing_if = "Option::is_none")]
113113
pub is_error: Option<bool>,

crates/rmcp/tests/test_message_schema/client_json_rpc_message_schema.json

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2118,12 +2118,7 @@
21182118
]
21192119
},
21202120
"structuredContent": {
2121-
"description": "Optional structured result",
2122-
"type": [
2123-
"object",
2124-
"null"
2125-
],
2126-
"additionalProperties": true
2121+
"description": "Optional structured result"
21272122
},
21282123
"toolUseId": {
21292124
"description": "ID of the corresponding tool use",

crates/rmcp/tests/test_message_schema/client_json_rpc_message_schema_current.json

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2118,12 +2118,7 @@
21182118
]
21192119
},
21202120
"structuredContent": {
2121-
"description": "Optional structured result",
2122-
"type": [
2123-
"object",
2124-
"null"
2125-
],
2126-
"additionalProperties": true
2121+
"description": "Optional structured result"
21272122
},
21282123
"toolUseId": {
21292124
"description": "ID of the corresponding tool use",

crates/rmcp/tests/test_message_schema/server_json_rpc_message_schema.json

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3467,12 +3467,7 @@
34673467
]
34683468
},
34693469
"structuredContent": {
3470-
"description": "Optional structured result",
3471-
"type": [
3472-
"object",
3473-
"null"
3474-
],
3475-
"additionalProperties": true
3470+
"description": "Optional structured result"
34763471
},
34773472
"toolUseId": {
34783473
"description": "ID of the corresponding tool use",

crates/rmcp/tests/test_message_schema/server_json_rpc_message_schema_current.json

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3467,12 +3467,7 @@
34673467
]
34683468
},
34693469
"structuredContent": {
3470-
"description": "Optional structured result",
3471-
"type": [
3472-
"object",
3473-
"null"
3474-
],
3475-
"additionalProperties": true
3470+
"description": "Optional structured result"
34763471
},
34773472
"toolUseId": {
34783473
"description": "ID of the corresponding tool use",

crates/rmcp/tests/test_sampling.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,38 @@ async fn test_tool_result_content_serialization() -> Result<()> {
359359
Ok(())
360360
}
361361

362+
#[tokio::test]
363+
async fn test_tool_result_content_with_array_structured_content() -> Result<()> {
364+
let structured =
365+
serde_json::json!([{ "city": "SF", "temp": 72 }, { "city": "NY", "temp": 65 }]);
366+
let mut tool_result = ToolResultContent::new("call_123", vec![Content::text("forecast")]);
367+
tool_result.structured_content = Some(structured);
368+
369+
let json = serde_json::to_string(&tool_result)?;
370+
let deserialized: ToolResultContent = serde_json::from_str(&json)?;
371+
assert_eq!(tool_result, deserialized);
372+
assert!(deserialized.structured_content.unwrap().is_array());
373+
374+
Ok(())
375+
}
376+
377+
#[tokio::test]
378+
async fn test_tool_result_content_with_primitive_structured_content() -> Result<()> {
379+
let structured = serde_json::json!(42);
380+
let mut tool_result = ToolResultContent::new("call_123", vec![Content::text("count")]);
381+
tool_result.structured_content = Some(structured);
382+
383+
let json = serde_json::to_string(&tool_result)?;
384+
let deserialized: ToolResultContent = serde_json::from_str(&json)?;
385+
assert_eq!(tool_result, deserialized);
386+
assert!(matches!(
387+
deserialized.structured_content,
388+
Some(serde_json::Value::Number(_))
389+
));
390+
391+
Ok(())
392+
}
393+
362394
#[tokio::test]
363395
async fn test_sampling_message_with_tool_use() -> Result<()> {
364396
let message = SamplingMessage::assistant_tool_use(

0 commit comments

Comments
 (0)