From 0a98f431c638857fcef9a9afc27289f11cfb5620 Mon Sep 17 00:00:00 2001 From: Jack Amadeo Date: Mon, 21 Jul 2025 21:33:33 -0400 Subject: [PATCH] Replace mcp_core::prompt with rmcp::model types (#3561) --- crates/goose-cli/src/session/completion.rs | 3 +- crates/goose-cli/src/session/mod.rs | 29 +--- crates/goose-cli/src/session/output.rs | 2 +- .../goose-mcp/src/computercontroller/mod.rs | 3 +- crates/goose-mcp/src/developer/mod.rs | 7 +- crates/goose-mcp/src/google_drive/mod.rs | 3 +- crates/goose-mcp/src/memory/mod.rs | 3 +- crates/goose-mcp/src/tutorial/mod.rs | 4 +- crates/goose-server/src/routes/reply.rs | 4 +- crates/goose/src/agents/agent.rs | 4 +- crates/goose/src/agents/extension_manager.rs | 4 +- crates/goose/src/providers/claude_code.rs | 6 +- crates/mcp-core/src/lib.rs | 3 - crates/mcp-core/src/prompt.rs | 164 ------------------ crates/mcp-core/src/protocol.rs | 9 +- crates/mcp-core/src/role.rs | 3 - crates/mcp-server/src/main.rs | 3 +- crates/mcp-server/src/router.rs | 3 +- 18 files changed, 23 insertions(+), 234 deletions(-) delete mode 100644 crates/mcp-core/src/prompt.rs delete mode 100644 crates/mcp-core/src/role.rs diff --git a/crates/goose-cli/src/session/completion.rs b/crates/goose-cli/src/session/completion.rs index 8468e944..9c7bd246 100644 --- a/crates/goose-cli/src/session/completion.rs +++ b/crates/goose-cli/src/session/completion.rs @@ -397,9 +397,10 @@ impl Validator for GooseCompleter { #[cfg(test)] mod tests { + use rmcp::model::PromptArgument; + use super::*; use crate::session::output; - use mcp_core::prompt::PromptArgument; use std::sync::{Arc, RwLock}; // Helper function to create a test completion cache diff --git a/crates/goose-cli/src/session/mod.rs b/crates/goose-cli/src/session/mod.rs index 8be19589..1635a65d 100644 --- a/crates/goose-cli/src/session/mod.rs +++ b/crates/goose-cli/src/session/mod.rs @@ -362,34 +362,7 @@ impl Session { } pub async fn get_prompt(&mut self, name: &str, arguments: Value) -> Result> { - let result = self.agent.get_prompt(name, arguments).await?; - // Convert mcp_core::prompt::PromptMessage to rmcp::model::PromptMessage - let converted_messages = result - .messages - .into_iter() - .map(|msg| rmcp::model::PromptMessage { - role: match msg.role { - mcp_core::prompt::PromptMessageRole::User => { - rmcp::model::PromptMessageRole::User - } - mcp_core::prompt::PromptMessageRole::Assistant => { - rmcp::model::PromptMessageRole::Assistant - } - }, - content: match msg.content { - mcp_core::prompt::PromptMessageContent::Text { text } => { - rmcp::model::PromptMessageContent::Text { text } - } - mcp_core::prompt::PromptMessageContent::Image { image } => { - rmcp::model::PromptMessageContent::Image { image } - } - mcp_core::prompt::PromptMessageContent::Resource { resource } => { - rmcp::model::PromptMessageContent::Resource { resource } - } - }, - }) - .collect(); - Ok(converted_messages) + Ok(self.agent.get_prompt(name, arguments).await?.messages) } /// Process a single message and get the response diff --git a/crates/goose-cli/src/session/output.rs b/crates/goose-cli/src/session/output.rs index 673cb8c5..9ce71800 100644 --- a/crates/goose-cli/src/session/output.rs +++ b/crates/goose-cli/src/session/output.rs @@ -4,9 +4,9 @@ use goose::config::Config; use goose::message::{Message, MessageContent, ToolRequest, ToolResponse}; use goose::providers::pricing::get_model_pricing; use indicatif::{MultiProgress, ProgressBar, ProgressStyle}; -use mcp_core::prompt::PromptArgument; use mcp_core::tool::ToolCall; use regex::Regex; +use rmcp::model::PromptArgument; use serde_json::Value; use std::cell::RefCell; use std::collections::HashMap; diff --git a/crates/goose-mcp/src/computercontroller/mod.rs b/crates/goose-mcp/src/computercontroller/mod.rs index ac0be9ac..c87c5f19 100644 --- a/crates/goose-mcp/src/computercontroller/mod.rs +++ b/crates/goose-mcp/src/computercontroller/mod.rs @@ -13,14 +13,13 @@ use std::os::unix::fs::PermissionsExt; use mcp_core::{ handler::{PromptError, ResourceError, ToolError}, - prompt::Prompt, protocol::{JsonRpcMessage, ServerCapabilities}, resource::Resource, tool::{Tool, ToolAnnotations}, }; use mcp_server::router::CapabilitiesBuilder; use mcp_server::Router; -use rmcp::model::Content; +use rmcp::model::{Content, Prompt}; mod docx_tool; mod pdf_tool; diff --git a/crates/goose-mcp/src/developer/mod.rs b/crates/goose-mcp/src/developer/mod.rs index eeb7006b..d47bc2c2 100644 --- a/crates/goose-mcp/src/developer/mod.rs +++ b/crates/goose-mcp/src/developer/mod.rs @@ -22,19 +22,16 @@ use tokio::{ use url::Url; use include_dir::{include_dir, Dir}; +use mcp_core::tool::ToolAnnotations; use mcp_core::{ handler::{PromptError, ResourceError, ToolError}, protocol::{JsonRpcMessage, JsonRpcNotification, ServerCapabilities}, resource::Resource, tool::Tool, }; -use mcp_core::{ - prompt::{Prompt, PromptArgument, PromptTemplate}, - tool::ToolAnnotations, -}; use mcp_server::router::CapabilitiesBuilder; use mcp_server::Router; -use rmcp::model::Content; +use rmcp::model::{Content, Prompt, PromptArgument, PromptTemplate}; use rmcp::model::Role; diff --git a/crates/goose-mcp/src/google_drive/mod.rs b/crates/goose-mcp/src/google_drive/mod.rs index 5e85ecc1..e7f275f7 100644 --- a/crates/goose-mcp/src/google_drive/mod.rs +++ b/crates/goose-mcp/src/google_drive/mod.rs @@ -11,7 +11,7 @@ use mcp_core::protocol::JsonRpcMessage; use mcp_core::tool::ToolAnnotations; use oauth_pkce::PkceOAuth2Client; use regex::Regex; -use rmcp::model::Content; +use rmcp::model::{Content, Prompt}; use serde_json::{json, Value}; use std::io::Cursor; use std::{env, fs, future::Future, path::Path, pin::Pin, sync::Arc}; @@ -20,7 +20,6 @@ use tokio::sync::mpsc; use mcp_core::{ handler::{PromptError, ResourceError, ToolError}, - prompt::Prompt, protocol::ServerCapabilities, resource::Resource, tool::Tool, diff --git a/crates/goose-mcp/src/memory/mod.rs b/crates/goose-mcp/src/memory/mod.rs index d1fee83c..e5a2be88 100644 --- a/crates/goose-mcp/src/memory/mod.rs +++ b/crates/goose-mcp/src/memory/mod.rs @@ -14,14 +14,13 @@ use tokio::sync::mpsc; use mcp_core::{ handler::{PromptError, ResourceError, ToolError}, - prompt::Prompt, protocol::{JsonRpcMessage, ServerCapabilities}, resource::Resource, tool::{Tool, ToolAnnotations, ToolCall}, }; use mcp_server::router::CapabilitiesBuilder; use mcp_server::Router; -use rmcp::model::Content; +use rmcp::model::{Content, Prompt}; // MemoryRouter implementation #[derive(Clone)] diff --git a/crates/goose-mcp/src/tutorial/mod.rs b/crates/goose-mcp/src/tutorial/mod.rs index 966ab8fd..83f1a380 100644 --- a/crates/goose-mcp/src/tutorial/mod.rs +++ b/crates/goose-mcp/src/tutorial/mod.rs @@ -1,17 +1,15 @@ use anyhow::Result; use include_dir::{include_dir, Dir}; use indoc::formatdoc; -use rmcp::model::Content; +use rmcp::model::{Content, Prompt, Role}; use serde_json::{json, Value}; use std::{future::Future, pin::Pin}; use tokio::sync::mpsc; use mcp_core::{ handler::{PromptError, ResourceError, ToolError}, - prompt::Prompt, protocol::{JsonRpcMessage, ServerCapabilities}, resource::Resource, - role::Role, tool::{Tool, ToolAnnotations}, }; use mcp_server::router::CapabilitiesBuilder; diff --git a/crates/goose-server/src/routes/reply.rs b/crates/goose-server/src/routes/reply.rs index b5e55487..e5804171 100644 --- a/crates/goose-server/src/routes/reply.rs +++ b/crates/goose-server/src/routes/reply.rs @@ -18,8 +18,8 @@ use goose::{ permission::{Permission, PermissionConfirmation}, session, }; -use mcp_core::{protocol::JsonRpcMessage, role::Role, ToolResult}; -use rmcp::model::Content; +use mcp_core::{protocol::JsonRpcMessage, ToolResult}; +use rmcp::model::{Content, Role}; use serde::{Deserialize, Serialize}; use serde_json::json; use serde_json::Value; diff --git a/crates/goose/src/agents/agent.rs b/crates/goose/src/agents/agent.rs index 5478ab51..1fbc70e8 100644 --- a/crates/goose/src/agents/agent.rs +++ b/crates/goose/src/agents/agent.rs @@ -48,8 +48,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, ToolError, ToolResult}; -use rmcp::model::Content; +use mcp_core::{protocol::GetPromptResult, tool::Tool, ToolError, ToolResult}; +use rmcp::model::{Content, Prompt}; use super::final_output_tool::FinalOutputTool; use super::platform_tools; diff --git a/crates/goose/src/agents/extension_manager.rs b/crates/goose/src/agents/extension_manager.rs index d03c3bff..4667a100 100644 --- a/crates/goose/src/agents/extension_manager.rs +++ b/crates/goose/src/agents/extension_manager.rs @@ -19,8 +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, Tool, ToolCall, ToolError}; -use rmcp::model::Content; +use mcp_core::{Tool, ToolCall, ToolError}; +use rmcp::model::{Content, Prompt}; use serde_json::Value; // By default, we set it to Jan 1, 2020 if the resource does not have a timestamp diff --git a/crates/goose/src/providers/claude_code.rs b/crates/goose/src/providers/claude_code.rs index 907b8535..38097945 100644 --- a/crates/goose/src/providers/claude_code.rs +++ b/crates/goose/src/providers/claude_code.rs @@ -1,5 +1,6 @@ use anyhow::Result; use async_trait::async_trait; +use rmcp::model::Role; use serde_json::{json, Value}; use std::path::PathBuf; use std::process::Stdio; @@ -13,7 +14,6 @@ use crate::config::Config; use crate::message::{Message, MessageContent}; use crate::model::ModelConfig; use mcp_core::tool::Tool; -use mcp_core::Role; pub const CLAUDE_CODE_DEFAULT_MODEL: &str = "claude-3-5-sonnet-latest"; pub const CLAUDE_CODE_KNOWN_MODELS: &[&str] = &["sonnet", "opus", "claude-3-5-sonnet-latest"]; @@ -412,7 +412,7 @@ impl ClaudeCodeProvider { // Extract the first user message text let description = messages .iter() - .find(|m| m.role == mcp_core::Role::User) + .find(|m| m.role == Role::User) .and_then(|m| { m.content.iter().find_map(|c| match c { MessageContent::Text(text_content) => Some(&text_content.text), @@ -437,7 +437,7 @@ impl ClaudeCodeProvider { let message = Message { id: None, - role: mcp_core::Role::Assistant, + role: Role::Assistant, created: chrono::Utc::now().timestamp(), content: vec![MessageContent::text(description.clone())], }; diff --git a/crates/mcp-core/src/lib.rs b/crates/mcp-core/src/lib.rs index 4bd7d1ad..a5da268f 100644 --- a/crates/mcp-core/src/lib.rs +++ b/crates/mcp-core/src/lib.rs @@ -1,10 +1,7 @@ pub mod handler; -pub mod role; -pub use role::Role; pub mod tool; pub use tool::{Tool, ToolCall}; pub mod resource; pub use resource::{Resource, ResourceContents}; pub mod protocol; pub use handler::{ToolError, ToolResult}; -pub mod prompt; diff --git a/crates/mcp-core/src/prompt.rs b/crates/mcp-core/src/prompt.rs deleted file mode 100644 index 9b50396f..00000000 --- a/crates/mcp-core/src/prompt.rs +++ /dev/null @@ -1,164 +0,0 @@ -use crate::handler::PromptError; -use base64::engine::{general_purpose::STANDARD as BASE64_STANDARD, Engine}; -use rmcp::model::{Annotations, EmbeddedResource, ImageContent}; -use serde::{Deserialize, Serialize}; - -/// A prompt that can be used to generate text from a model -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct Prompt { - /// The name of the prompt - pub name: String, - /// Optional description of what the prompt does - #[serde(skip_serializing_if = "Option::is_none")] - pub description: Option, - /// Optional arguments that can be passed to customize the prompt - #[serde(skip_serializing_if = "Option::is_none")] - pub arguments: Option>, -} - -impl Prompt { - /// Create a new prompt with the given name, description and arguments - pub fn new( - name: N, - description: Option, - arguments: Option>, - ) -> Self - where - N: Into, - D: Into, - { - Prompt { - name: name.into(), - description: description.map(Into::into), - arguments, - } - } -} - -/// Represents a prompt argument that can be passed to customize the prompt -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct PromptArgument { - /// The name of the argument - pub name: String, - /// A description of what the argument is used for - #[serde(skip_serializing_if = "Option::is_none")] - pub description: Option, - /// Whether this argument is required - #[serde(skip_serializing_if = "Option::is_none")] - pub required: Option, -} - -/// Represents the role of a message sender in a prompt conversation -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -#[serde(rename_all = "lowercase")] -pub enum PromptMessageRole { - User, - Assistant, -} - -/// Content types that can be included in prompt messages -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -#[serde(tag = "type", rename_all = "lowercase")] -pub enum PromptMessageContent { - /// Plain text content - Text { text: String }, - /// Image content with base64-encoded data - Image { image: ImageContent }, - /// Embedded server-side resource - Resource { resource: EmbeddedResource }, -} - -/// A message in a prompt conversation -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct PromptMessage { - /// The role of the message sender - pub role: PromptMessageRole, - /// The content of the message - pub content: PromptMessageContent, -} - -impl PromptMessage { - /// Create a new text message with the given role and text content - pub fn new_text>(role: PromptMessageRole, text: S) -> Self { - Self { - role, - content: PromptMessageContent::Text { text: text.into() }, - } - } - - pub fn new_image>( - role: PromptMessageRole, - data: S, - mime_type: S, - annotations: Option, - ) -> Result { - let data = data.into(); - let mime_type = mime_type.into(); - - // Validate base64 data - BASE64_STANDARD.decode(&data).map_err(|_| { - PromptError::InvalidParameters("Image data must be valid base64".to_string()) - })?; - - // Validate mime type - if !mime_type.starts_with("image/") { - return Err(PromptError::InvalidParameters( - "MIME type must be a valid image type (e.g. image/jpeg)".to_string(), - )); - } - - Ok(Self { - role, - content: PromptMessageContent::Image { - image: ImageContent { - raw: rmcp::model::RawImageContent { data, mime_type }, - annotations, - }, - }, - }) - } - - /// Create a new resource message - pub fn new_resource( - role: PromptMessageRole, - uri: String, - mime_type: String, - text: Option, - annotations: Option, - ) -> Self { - let resource_contents = rmcp::model::ResourceContents::TextResourceContents { - uri, - mime_type: Some(mime_type), - text: text.unwrap_or_default(), - }; - - Self { - role, - content: PromptMessageContent::Resource { - resource: EmbeddedResource { - raw: rmcp::model::RawEmbeddedResource { - resource: resource_contents, - }, - annotations, - }, - }, - } - } -} - -/// A template for a prompt -#[derive(Debug, Serialize, Deserialize)] -pub struct PromptTemplate { - pub id: String, - pub template: String, - pub arguments: Vec, -} - -/// A template for a prompt argument, this should be identical to PromptArgument -#[derive(Debug, Serialize, Deserialize)] -pub struct PromptArgumentTemplate { - pub name: String, - pub description: Option, - pub required: Option, -} diff --git a/crates/mcp-core/src/protocol.rs b/crates/mcp-core/src/protocol.rs index e7d1c12f..8a1788b2 100644 --- a/crates/mcp-core/src/protocol.rs +++ b/crates/mcp-core/src/protocol.rs @@ -1,11 +1,6 @@ /// The protocol messages exchanged between client and server -use crate::{ - prompt::{Prompt, PromptMessage}, - resource::Resource, - resource::ResourceContents, - tool::Tool, -}; -use rmcp::model::Content; +use crate::{resource::Resource, resource::ResourceContents, tool::Tool}; +use rmcp::model::{Content, Prompt, PromptMessage}; use serde::{Deserialize, Serialize}; use serde_json::Value; diff --git a/crates/mcp-core/src/role.rs b/crates/mcp-core/src/role.rs deleted file mode 100644 index 2d753e90..00000000 --- a/crates/mcp-core/src/role.rs +++ /dev/null @@ -1,3 +0,0 @@ -// passthrough, which will be deleted with the rest of the mcp-core crate after it is no longer used -// needed because it has internal references in this crate which leak out to usages used in goose etc crates -pub use rmcp::model::Role; diff --git a/crates/mcp-server/src/main.rs b/crates/mcp-server/src/main.rs index 2d7edfe0..7cf12d03 100644 --- a/crates/mcp-server/src/main.rs +++ b/crates/mcp-server/src/main.rs @@ -1,12 +1,11 @@ use anyhow::Result; use mcp_core::handler::{PromptError, ResourceError}; -use mcp_core::prompt::{Prompt, PromptArgument}; use mcp_core::protocol::JsonRpcMessage; use mcp_core::tool::ToolAnnotations; use mcp_core::{handler::ToolError, protocol::ServerCapabilities, resource::Resource, tool::Tool}; use mcp_server::router::{CapabilitiesBuilder, RouterService}; use mcp_server::{ByteTransport, Router, Server}; -use rmcp::model::Content; +use rmcp::model::{Content, Prompt, PromptArgument}; use serde_json::Value; use std::{future::Future, pin::Pin, sync::Arc}; use tokio::sync::mpsc; diff --git a/crates/mcp-server/src/router.rs b/crates/mcp-server/src/router.rs index 06c294a6..f0925bee 100644 --- a/crates/mcp-server/src/router.rs +++ b/crates/mcp-server/src/router.rs @@ -8,7 +8,6 @@ type PromptFuture = Pin> + S use mcp_core::{ handler::{PromptError, ResourceError, ToolError}, - prompt::{Prompt, PromptMessage, PromptMessageRole}, protocol::{ CallToolResult, GetPromptResult, Implementation, InitializeResult, JsonRpcMessage, JsonRpcRequest, JsonRpcResponse, ListPromptsResult, ListResourcesResult, ListToolsResult, @@ -17,7 +16,7 @@ use mcp_core::{ }, ResourceContents, }; -use rmcp::model::Content; +use rmcp::model::{Content, Prompt, PromptMessage, PromptMessageRole}; use serde_json::Value; use tokio::sync::mpsc; use tower_service::Service;