Replace mcp_core::content types with rmcp::model types (#3500)

This commit is contained in:
Jack Amadeo
2025-07-18 17:23:25 -04:00
committed by GitHub
parent a2309d9436
commit d5291461ca
66 changed files with 867 additions and 856 deletions
+2 -3
View File
@@ -47,9 +47,8 @@ use crate::agents::tool_router_index_manager::ToolRouterIndexManager;
use crate::agents::tool_vectordb::generate_table_id;
use crate::agents::types::SessionConfig;
use crate::agents::types::{FrontendTool, ToolResultReceiver};
use mcp_core::{
prompt::Prompt, protocol::GetPromptResult, tool::Tool, Content, ToolError, ToolResult,
};
use mcp_core::{prompt::Prompt, protocol::GetPromptResult, tool::Tool, ToolError, ToolResult};
use rmcp::model::Content;
use super::final_output_tool::FinalOutputTool;
use super::platform_tools;
+2 -1
View File
@@ -19,7 +19,8 @@ use crate::config::{Config, ExtensionConfigManager};
use crate::prompt_template;
use mcp_client::client::{ClientCapabilities, ClientInfo, McpClient, McpClientTrait};
use mcp_client::transport::{SseTransport, StdioTransport, StreamableHttpTransport, Transport};
use mcp_core::{prompt::Prompt, Content, Tool, ToolCall, ToolError};
use mcp_core::{prompt::Prompt, Tool, ToolCall, ToolError};
use rmcp::model::Content;
use serde_json::Value;
// By default, we set it to Jan 1, 2020 if the resource does not have a timestamp
+2 -1
View File
@@ -3,8 +3,9 @@ use crate::recipe::Response;
use indoc::formatdoc;
use mcp_core::{
tool::{Tool, ToolAnnotations},
Content, ToolCall, ToolError,
ToolCall, ToolError,
};
use rmcp::model::Content;
use serde_json::Value;
pub const FINAL_OUTPUT_TOOL_NAME: &str = "recipe__final_output";
@@ -1,5 +1,6 @@
use chrono::Utc;
use mcp_core::{Content, ToolError};
use mcp_core::ToolError;
use rmcp::model::Content;
use std::fs::File;
use std::io::Write;
@@ -14,8 +15,8 @@ pub fn process_tool_response(
let mut processed_contents = Vec::new();
for content in contents {
match content {
Content::Text(text_content) => {
match content.as_text() {
Some(text_content) => {
// Check if text exceeds threshold
if text_content.text.chars().count() > LARGE_TEXT_THRESHOLD {
// Write to temp file
@@ -41,11 +42,13 @@ pub fn process_tool_response(
}
} else {
// Keep original content for smaller texts
processed_contents.push(Content::Text(text_content));
processed_contents.push(content);
}
}
// Pass through other content types unchanged
_ => processed_contents.push(content),
None => {
// Pass through other content types unchanged
processed_contents.push(content);
}
}
}
@@ -76,7 +79,8 @@ fn write_large_text_to_file(content: &str) -> Result<String, std::io::Error> {
#[cfg(test)]
mod tests {
use super::*;
use mcp_core::{Content, ImageContent, TextContent, ToolError};
use mcp_core::ToolError;
use rmcp::model::Content;
use std::fs;
use std::path::Path;
@@ -84,10 +88,7 @@ mod tests {
fn test_small_text_response_passes_through() {
// Create a small text response
let small_text = "This is a small text response";
let content = Content::Text(TextContent {
text: small_text.to_string(),
annotations: None,
});
let content = Content::text(small_text.to_string());
let response = Ok(vec![content]);
@@ -96,7 +97,7 @@ mod tests {
// Verify the response is unchanged
assert_eq!(processed.len(), 1);
if let Content::Text(text_content) = &processed[0] {
if let Some(text_content) = processed[0].as_text() {
assert_eq!(text_content.text, small_text);
} else {
panic!("Expected text content");
@@ -107,10 +108,7 @@ mod tests {
fn test_large_text_response_redirected_to_file() {
// Create a text larger than the threshold
let large_text = "a".repeat(LARGE_TEXT_THRESHOLD + 1000);
let content = Content::Text(TextContent {
text: large_text.clone(),
annotations: None,
});
let content = Content::text(large_text.clone());
let response = Ok(vec![content]);
@@ -119,7 +117,7 @@ mod tests {
// Verify the response contains a message about the file
assert_eq!(processed.len(), 1);
if let Content::Text(text_content) = &processed[0] {
if let Some(text_content) = processed[0].as_text() {
assert!(text_content
.text
.contains("The response returned from the tool call was larger"));
@@ -147,11 +145,7 @@ mod tests {
#[test]
fn test_image_content_passes_through() {
// Create an image content
let image_content = Content::Image(ImageContent {
data: "base64data".to_string(),
mime_type: "image/png".to_string(),
annotations: None,
});
let image_content = Content::image("base64data".to_string(), "image/png".to_string());
let response = Ok(vec![image_content]);
@@ -160,12 +154,11 @@ mod tests {
// Verify the response is unchanged
assert_eq!(processed.len(), 1);
match &processed[0] {
Content::Image(img) => {
assert_eq!(img.data, "base64data");
assert_eq!(img.mime_type, "image/png");
}
_ => panic!("Expected image content"),
if let Some(img) = processed[0].as_image() {
assert_eq!(img.data, "base64data");
assert_eq!(img.mime_type, "image/png");
} else {
panic!("Expected image content");
}
}
@@ -173,15 +166,8 @@ mod tests {
fn test_mixed_content_handled_correctly() {
// Create a response with mixed content types
let small_text = Content::text("Small text");
let large_text = Content::Text(TextContent {
text: "a".repeat(LARGE_TEXT_THRESHOLD + 1000),
annotations: None,
});
let image = Content::Image(ImageContent {
data: "image_data".to_string(),
mime_type: "image/jpeg".to_string(),
annotations: None,
});
let large_text = Content::text("a".repeat(LARGE_TEXT_THRESHOLD + 1000));
let image = Content::image("image_data".to_string(), "image/jpeg".to_string());
let response = Ok(vec![small_text, large_text, image]);
@@ -192,14 +178,14 @@ mod tests {
assert_eq!(processed.len(), 3);
// First item should be unchanged small text
if let Content::Text(text_content) = &processed[0] {
if let Some(text_content) = processed[0].as_text() {
assert_eq!(text_content.text, "Small text");
} else {
panic!("Expected text content");
}
// Second item should be a message about the file
if let Content::Text(text_content) = &processed[1] {
if let Some(text_content) = processed[1].as_text() {
assert!(text_content
.text
.contains("The response returned from the tool call was larger"));
@@ -216,12 +202,11 @@ mod tests {
}
// Third item should be unchanged image
match &processed[2] {
Content::Image(img) => {
assert_eq!(img.data, "image_data");
assert_eq!(img.mime_type, "image/jpeg");
}
_ => panic!("Expected image content"),
if let Some(img) = processed[2].as_image() {
assert_eq!(img.data, "image_data");
assert_eq!(img.mime_type, "image/jpeg");
} else {
panic!("Expected image content");
}
}
@@ -5,7 +5,8 @@
use crate::agents::subagent_execution_tool::tasks_manager::TasksManager;
use crate::agents::subagent_execution_tool::{lib::ExecutionMode, task_types::Task};
use crate::agents::tool_execution::ToolCallResult;
use mcp_core::{tool::ToolAnnotations, Content, Tool, ToolError};
use mcp_core::{tool::ToolAnnotations, Tool, ToolError};
use rmcp::model::Content;
use serde_json::{json, Value};
pub const DYNAMIC_TASK_TOOL_NAME_PREFIX: &str = "dynamic_task__create_task";
@@ -1,6 +1,6 @@
use mcp_core::content::TextContent;
use mcp_core::tool::Tool;
use mcp_core::{Content, ToolError};
use mcp_core::ToolError;
use rmcp::model::Content;
use anyhow::{Context, Result};
use async_trait::async_trait;
@@ -115,10 +115,7 @@ impl RouterToolSelector for VectorToolSelector {
"Tool: {}\nDescription: {}\nSchema: {}",
tool.tool_name, tool.description, tool.schema
);
Content::Text(TextContent {
text,
annotations: None,
})
Content::text(text)
})
.collect();
@@ -292,12 +289,7 @@ impl RouterToolSelector for LLMToolSelector {
let tool_entries: Vec<Content> = text
.split("\n\n")
.filter(|entry| entry.trim().starts_with("Tool:"))
.map(|entry| {
Content::Text(TextContent {
text: entry.trim().to_string(),
annotations: None,
})
})
.map(|entry| Content::text(entry.trim().to_string()))
.collect();
Ok(tool_entries)
+2 -1
View File
@@ -6,7 +6,8 @@
use std::sync::Arc;
use chrono::Utc;
use mcp_core::{Content, ToolError, ToolResult};
use mcp_core::{ToolError, ToolResult};
use rmcp::model::Content;
use crate::recipe::Recipe;
use crate::scheduler_trait::SchedulerTrait;
@@ -1,4 +1,5 @@
use mcp_core::{Content, Tool, ToolError};
use mcp_core::{Tool, ToolError};
use rmcp::model::Content;
use serde_json::Value;
use std::collections::HashMap;
@@ -1,4 +1,5 @@
use mcp_core::{tool::ToolAnnotations, Content, Tool, ToolError};
use mcp_core::{tool::ToolAnnotations, Tool, ToolError};
use rmcp::model::Content;
use serde_json::Value;
use crate::agents::subagent_task_config::TaskConfig;
@@ -1,4 +1,5 @@
use serde_json::Value;
use std::ops::Deref;
use std::process::Stdio;
use std::sync::Arc;
use tokio::io::{AsyncBufReadExt, BufReader};
@@ -80,8 +81,10 @@ async fn handle_text_instruction_task(
// Extract the text content from the result
let result_text = contents
.into_iter()
.filter_map(|content| match content {
mcp_core::Content::Text(text) => Some(text.text),
.filter_map(|content| match content.deref() {
rmcp::model::RawContent::Text(raw_text_content) => {
Some(raw_text_content.text.clone())
}
_ => None,
})
.collect::<Vec<_>>()
+2 -1
View File
@@ -1,7 +1,8 @@
use crate::agents::subagent::SubAgent;
use crate::agents::subagent_task_config::TaskConfig;
use anyhow::Result;
use mcp_core::{Content, ToolError};
use mcp_core::ToolError;
use rmcp::model::Content;
use serde_json::Value;
/// Standalone function to run a complete subagent task
+2 -1
View File
@@ -11,7 +11,8 @@ use crate::config::permission::PermissionLevel;
use crate::config::PermissionManager;
use crate::message::{Message, ToolRequest};
use crate::permission::Permission;
use mcp_core::{Content, ToolResult};
use mcp_core::ToolResult;
use rmcp::model::Content;
// ToolCallResult combines the result of a tool call with an optional notification stream that
// can be used to receive notifications from the tool.
+2 -1
View File
@@ -1,5 +1,6 @@
use crate::session;
use mcp_core::{Content, Tool, ToolResult};
use mcp_core::{Tool, ToolResult};
use rmcp::model::Content;
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
use std::sync::Arc;