//! MCP (Model Context Protocol) support //! //! Implements MCP client and server for tool/resource integration. use async_trait::async_trait; use serde::{Deserialize, Serialize}; use std::collections::HashMap; use zclaw_types::Result; // Re-export McpServerConfig from mcp_transport pub use crate::mcp_transport::McpServerConfig; /// MCP tool definition #[derive(Debug, Clone, Serialize, Deserialize)] pub struct McpTool { pub name: String, pub description: String, pub input_schema: serde_json::Value, } /// MCP resource definition #[derive(Debug, Clone, Serialize, Deserialize)] pub struct McpResource { pub uri: String, pub name: String, pub description: Option, pub mime_type: Option, } /// MCP prompt definition #[derive(Debug, Clone, Serialize, Deserialize)] pub struct McpPrompt { pub name: String, pub description: String, pub arguments: Vec, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct McpPromptArgument { pub name: String, pub description: String, pub required: bool, } /// MCP server info #[derive(Debug, Clone, Serialize, Deserialize)] pub struct McpServerInfo { pub name: String, pub version: String, pub protocol_version: String, } /// MCP client configuration #[derive(Debug, Clone, Serialize, Deserialize)] pub struct McpClientConfig { pub server_url: String, pub server_info: McpServerInfo, pub capabilities: McpCapabilities, } #[derive(Debug, Clone, Serialize, Deserialize, Default)] pub struct McpCapabilities { pub tools: Option, pub resources: Option, pub prompts: Option, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct McpToolCapabilities { pub list_changed: bool, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct McpResourceCapabilities { pub subscribe: bool, pub list_changed: bool, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct McpPromptCapabilities { pub list_changed: bool, } /// MCP tool call request #[derive(Debug, Clone, Serialize, Deserialize)] pub struct McpToolCallRequest { pub name: String, pub arguments: HashMap, } /// MCP tool call response #[derive(Debug, Clone, Serialize, Deserialize)] pub struct McpToolCallResponse { pub content: Vec, pub is_error: bool, } #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(tag = "type", rename_all = "snake_case")] pub enum McpContent { Text { text: String }, Image { data: String, mime_type: String }, Resource { resource: McpResourceContent }, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct McpResourceContent { pub uri: String, pub mime_type: Option, pub text: Option, pub blob: Option, } /// MCP Client trait #[async_trait] pub trait McpClient: Send + Sync { /// List available tools async fn list_tools(&self) -> Result>; /// Call a tool async fn call_tool(&self, request: McpToolCallRequest) -> Result; /// List available resources async fn list_resources(&self) -> Result>; /// Read a resource async fn read_resource(&self, uri: &str) -> Result; /// List available prompts async fn list_prompts(&self) -> Result>; /// Get a prompt async fn get_prompt(&self, name: &str, arguments: HashMap) -> Result; } /// Basic MCP client implementation using stdio transport pub struct BasicMcpClient { transport: crate::mcp_transport::McpTransport, } impl BasicMcpClient { /// Create new MCP client with server configuration pub fn new(config: McpServerConfig) -> Self { Self { transport: crate::mcp_transport::McpTransport::new(config), } } /// Initialize the MCP connection pub async fn initialize(&self) -> Result<()> { self.transport.initialize().await } } #[async_trait] impl McpClient for BasicMcpClient { async fn list_tools(&self) -> Result> { McpClient::list_tools(&self.transport).await } async fn call_tool(&self, request: McpToolCallRequest) -> Result { McpClient::call_tool(&self.transport, request).await } async fn list_resources(&self) -> Result> { McpClient::list_resources(&self.transport).await } async fn read_resource(&self, uri: &str) -> Result { McpClient::read_resource(&self.transport, uri).await } async fn list_prompts(&self) -> Result> { McpClient::list_prompts(&self.transport).await } async fn get_prompt(&self, name: &str, arguments: HashMap) -> Result { McpClient::get_prompt(&self.transport, name, arguments).await } }