use std::{ future::Future, pin::Pin, task::{Context, Poll}, }; type PromptFuture = Pin> + Send + 'static>>; use mcp_core::{ content::Content, handler::{PromptError, ResourceError, ToolError}, prompt::{Prompt, PromptMessage, PromptMessageRole}, protocol::{ CallToolResult, GetPromptResult, Implementation, InitializeResult, JsonRpcRequest, JsonRpcResponse, ListPromptsResult, ListResourcesResult, ListToolsResult, PromptsCapability, ReadResourceResult, ResourcesCapability, ServerCapabilities, ToolsCapability, }, ResourceContents, }; use serde_json::Value; use tower_service::Service; use crate::{BoxError, RouterError}; /// Builder for configuring and constructing capabilities pub struct CapabilitiesBuilder { tools: Option, prompts: Option, resources: Option, } impl Default for CapabilitiesBuilder { fn default() -> Self { Self::new() } } impl CapabilitiesBuilder { pub fn new() -> Self { Self { tools: None, prompts: None, resources: None, } } /// Add multiple tools to the router pub fn with_tools(mut self, list_changed: bool) -> Self { self.tools = Some(ToolsCapability { list_changed: Some(list_changed), }); self } /// Enable prompts capability pub fn with_prompts(mut self, list_changed: bool) -> Self { self.prompts = Some(PromptsCapability { list_changed: Some(list_changed), }); self } /// Enable resources capability pub fn with_resources(mut self, subscribe: bool, list_changed: bool) -> Self { self.resources = Some(ResourcesCapability { subscribe: Some(subscribe), list_changed: Some(list_changed), }); self } /// Build the router with automatic capability inference pub fn build(self) -> ServerCapabilities { // Create capabilities based on what's configured ServerCapabilities { tools: self.tools, prompts: self.prompts, resources: self.resources, } } } pub trait Router: Send + Sync + 'static { fn name(&self) -> String; // in the protocol, instructions are optional but we make it required fn instructions(&self) -> String; fn capabilities(&self) -> ServerCapabilities; fn list_tools(&self) -> Vec; fn call_tool( &self, tool_name: &str, arguments: Value, ) -> Pin, ToolError>> + Send + 'static>>; fn list_resources(&self) -> Vec; fn read_resource( &self, uri: &str, ) -> Pin> + Send + 'static>>; fn list_prompts(&self) -> Vec; fn get_prompt(&self, prompt_name: &str) -> PromptFuture; // Helper method to create base response fn create_response(&self, id: Option) -> JsonRpcResponse { JsonRpcResponse { jsonrpc: "2.0".to_string(), id, result: None, error: None, } } fn handle_initialize( &self, req: JsonRpcRequest, ) -> impl Future> + Send { async move { let result = InitializeResult { protocol_version: "2024-11-05".to_string(), capabilities: self.capabilities().clone(), server_info: Implementation { name: self.name(), version: env!("CARGO_PKG_VERSION").to_string(), }, instructions: Some(self.instructions()), }; let mut response = self.create_response(req.id); response.result = Some(serde_json::to_value(result).map_err(|e| { RouterError::Internal(format!("JSON serialization error: {}", e)) })?); Ok(response) } } fn handle_tools_list( &self, req: JsonRpcRequest, ) -> impl Future> + Send { async move { let tools = self.list_tools(); let result = ListToolsResult { tools, next_cursor: None, }; let mut response = self.create_response(req.id); response.result = Some(serde_json::to_value(result).map_err(|e| { RouterError::Internal(format!("JSON serialization error: {}", e)) })?); Ok(response) } } fn handle_tools_call( &self, req: JsonRpcRequest, ) -> impl Future> + Send { async move { let params = req .params .ok_or_else(|| RouterError::InvalidParams("Missing parameters".into()))?; let name = params .get("name") .and_then(Value::as_str) .ok_or_else(|| RouterError::InvalidParams("Missing tool name".into()))?; let arguments = params.get("arguments").cloned().unwrap_or(Value::Null); let result = match self.call_tool(name, arguments).await { Ok(result) => CallToolResult { content: result, is_error: None, }, Err(err) => CallToolResult { content: vec![Content::text(err.to_string())], is_error: Some(true), }, }; let mut response = self.create_response(req.id); response.result = Some(serde_json::to_value(result).map_err(|e| { RouterError::Internal(format!("JSON serialization error: {}", e)) })?); Ok(response) } } fn handle_resources_list( &self, req: JsonRpcRequest, ) -> impl Future> + Send { async move { let resources = self.list_resources(); let result = ListResourcesResult { resources, next_cursor: None, }; let mut response = self.create_response(req.id); response.result = Some(serde_json::to_value(result).map_err(|e| { RouterError::Internal(format!("JSON serialization error: {}", e)) })?); Ok(response) } } fn handle_resources_read( &self, req: JsonRpcRequest, ) -> impl Future> + Send { async move { let params = req .params .ok_or_else(|| RouterError::InvalidParams("Missing parameters".into()))?; let uri = params .get("uri") .and_then(Value::as_str) .ok_or_else(|| RouterError::InvalidParams("Missing resource URI".into()))?; let contents = self.read_resource(uri).await.map_err(RouterError::from)?; let result = ReadResourceResult { contents: vec![ResourceContents::TextResourceContents { uri: uri.to_string(), mime_type: Some("text/plain".to_string()), text: contents, }], }; let mut response = self.create_response(req.id); response.result = Some(serde_json::to_value(result).map_err(|e| { RouterError::Internal(format!("JSON serialization error: {}", e)) })?); Ok(response) } } fn handle_prompts_list( &self, req: JsonRpcRequest, ) -> impl Future> + Send { async move { let prompts = self.list_prompts(); let result = ListPromptsResult { prompts }; let mut response = self.create_response(req.id); response.result = Some(serde_json::to_value(result).map_err(|e| { RouterError::Internal(format!("JSON serialization error: {}", e)) })?); Ok(response) } } fn handle_prompts_get( &self, req: JsonRpcRequest, ) -> impl Future> + Send { async move { // Validate and extract parameters let params = req .params .ok_or_else(|| RouterError::InvalidParams("Missing parameters".into()))?; // Extract "name" field let prompt_name = params .get("name") .and_then(Value::as_str) .ok_or_else(|| RouterError::InvalidParams("Missing prompt name".into()))?; // Extract "arguments" field let arguments = params .get("arguments") .and_then(Value::as_object) .ok_or_else(|| RouterError::InvalidParams("Missing arguments object".into()))?; // Fetch the prompt definition first let prompt = self .list_prompts() .into_iter() .find(|p| p.name == prompt_name) .ok_or_else(|| { RouterError::PromptNotFound(format!("Prompt '{}' not found", prompt_name)) })?; // Validate required arguments if let Some(args) = &prompt.arguments { for arg in args { if arg.required.is_some() && arg.required.unwrap() && (!arguments.contains_key(&arg.name) || arguments .get(&arg.name) .and_then(Value::as_str) .is_none_or(str::is_empty)) { return Err(RouterError::InvalidParams(format!( "Missing required argument: '{}'", arg.name ))); } } } // Now get the prompt content let description = self .get_prompt(prompt_name) .await .map_err(|e| RouterError::Internal(e.to_string()))?; // Validate prompt arguments for potential security issues from user text input // Checks: // - Prompt must be less than 10000 total characters // - Argument keys must be less than 1000 characters // - Argument values must be less than 1000 characters // - Dangerous patterns, eg "../", "//", "\\\\", "