use arc_swap::ArcSwapOption; pub use mcp_common::ToolFilter; /** * Create a local SSE server that proxies requests to a stdio MCP server. */ use rmcp::{ ErrorData, RoleClient, RoleServer, ServerHandler, model::{ CallToolRequestParams, CallToolResult, ClientInfo, Content, Implementation, ListToolsResult, PaginatedRequestParams, ServerInfo, }, service::{NotificationContext, Peer, RequestContext, RunningService}, }; use std::sync::Arc; use std::sync::atomic::{AtomicU64, Ordering}; use std::time::Instant; use tracing::{debug, error, info, warn}; /// 全局请求计数器,用于生成唯一的请求 ID static REQUEST_COUNTER: AtomicU64 = AtomicU64::new(1); /// 包装后端连接和运行服务 /// 用于 ArcSwap 热替换 #[derive(Debug)] struct PeerInner { /// Peer 用于发送请求 peer: Peer, /// 保持 RunningService 的所有权,确保服务生命周期 #[allow(dead_code)] _running: Arc>, } /// A proxy handler that forwards requests to a client based on the server's capabilities /// 使用 ArcSwap 实现后端热替换,支持断开时立即返回错误 /// /// **增强功能**: /// - 后端版本控制:每次 swap_backend 都会递增版本号 /// - 支持 Session 版本跟踪:配合 ProxyAwareSessionManager 使用 #[derive(Clone, Debug)] pub struct ProxyHandler { /// 后端连接(ArcSwap 支持无锁原子替换) /// None 表示后端断开/重连中 peer: Arc>, /// 缓存的服务器信息(保持不变,重连后应一致) cached_info: ServerInfo, /// MCP ID 用于日志记录 mcp_id: String, /// 工具过滤配置 tool_filter: ToolFilter, /// 后端版本号(每次 swap_backend 递增) /// 用于跟踪后端连接变化,使旧 session 失效 backend_version: Arc, } impl ServerHandler for ProxyHandler { fn get_info(&self) -> ServerInfo { self.cached_info.clone() } #[tracing::instrument(skip(self, request, context), fields( mcp_id = %self.mcp_id, request = ?request, ))] async fn list_tools( &self, request: Option, context: RequestContext, ) -> Result { // 原子加载后端连接 let inner_guard = self.peer.load(); let inner = inner_guard.as_ref().ok_or_else(|| { error!("Backend connection is not available (reconnecting)"); ErrorData::internal_error( "Backend connection is not available, reconnecting...".to_string(), None, ) })?; // 检查后端连接是否已关闭 if inner.peer.is_transport_closed() { error!("Backend transport is closed"); return Err(ErrorData::internal_error( "Backend connection closed, please retry".to_string(), None, )); } // Check if the server has tools capability and forward the request match self.capabilities().tools { Some(_) => { // 使用 tokio::select! 同时等待取消和结果 tokio::select! { result = inner.peer.list_tools(request) => { match result { Ok(result) => { // 根据过滤配置过滤工具列表 let filtered_tools: Vec<_> = if self.tool_filter.is_enabled() { result .tools .into_iter() .filter(|tool| self.tool_filter.is_allowed(&tool.name)) .collect() } else { result.tools }; // 记录工具列表结果,这些结果会通过 SSE 推送给客户端 info!( "[list_tools] Tool list results - MCP ID: {}, number of tools: {}{}", self.mcp_id, filtered_tools.len(), if self.tool_filter.is_enabled() { " (filtered)" } else { "" } ); debug!( "Proxying list_tools response with {} tools", filtered_tools.len() ); Ok(ListToolsResult { tools: filtered_tools, next_cursor: result.next_cursor, meta: result.meta, // rmcp 0.12 新增字段 }) } Err(err) => { error!("Error listing tools: {:?}", err); Err(ErrorData::internal_error( format!("Error listing tools: {err}"), None, )) } } } _ = context.ct.cancelled() => { info!("[list_tools] Request canceled - MCP ID: {}", self.mcp_id); Err(ErrorData::internal_error( "Request cancelled".to_string(), None, )) } } } None => { // Server doesn't support tools, return empty list warn!("Server doesn't support tools capability"); Ok(ListToolsResult::default()) } } } #[tracing::instrument(skip(self, request, context), fields( mcp_id = %self.mcp_id, tool_name = %request.name, tool_arguments = ?request.arguments, ))] async fn call_tool( &self, request: CallToolRequestParams, context: RequestContext, ) -> Result { // 生成唯一请求 ID 用于追踪 let request_id = REQUEST_COUNTER.fetch_add(1, Ordering::Relaxed); let start = Instant::now(); info!( "[call_tool:{}] Start - Tool: {}, MCP ID: {}", request_id, request.name, self.mcp_id ); // 首先检查工具是否被过滤 if !self.tool_filter.is_allowed(&request.name) { info!( "[call_tool:{}] Tool is filtered - MCP ID: {}, Tool: {}", request_id, self.mcp_id, request.name ); return Ok(CallToolResult::error(vec![Content::text(format!( "Tool '{}' is not allowed by filter configuration", request.name ))])); } // 原子加载后端连接 let inner_guard = self.peer.load(); let inner = match inner_guard.as_ref() { Some(inner) => { let transport_closed = inner.peer.is_transport_closed(); info!( "[call_tool:{}] Backend connection exists - transport_closed: {}", request_id, transport_closed ); inner } None => { error!( "[call_tool:{}] Backend connection unavailable (reconnecting) - MCP ID: {}", request_id, self.mcp_id ); return Ok(CallToolResult::error(vec![Content::text( "Backend connection is not available, reconnecting...", )])); } }; // 检查后端连接是否已关闭 if inner.peer.is_transport_closed() { error!( "[call_tool:{}] Backend transport is closed - MCP ID: {}", request_id, self.mcp_id ); return Ok(CallToolResult::error(vec![Content::text( "Backend connection closed, please retry", )])); } // Check if the server has tools capability and forward the request let result = match self.capabilities().tools { Some(_) => { // 记录发送请求到后端的时间点 info!( "[call_tool:{}] Send request to backend... - Tool: {}, Elapsed time: {}ms", request_id, request.name, start.elapsed().as_millis() ); // 创建后端调用的 Future,使用 pin 固定 let call_future = inner.peer.call_tool(request.clone()); tokio::pin!(call_future); // 等待心跳间隔(30秒) const HEARTBEAT_INTERVAL: std::time::Duration = std::time::Duration::from_secs(30); let mut heartbeat_interval = tokio::time::interval(HEARTBEAT_INTERVAL); // 跳过第一次立即触发 heartbeat_interval.tick().await; // 使用循环 + select! 实现等待心跳 let call_result = loop { tokio::select! { // biased 确保按顺序优先检查,避免心跳检查抢占实际结果 biased; result = &mut call_future => { break result; } _ = context.ct.cancelled() => { let elapsed = start.elapsed(); warn!( "[call_tool:{}] Request canceled - Tool: {}, Time taken: {}ms, MCP ID: {}", request_id, request.name, elapsed.as_millis(), self.mcp_id ); return Ok(CallToolResult::error(vec![Content::text( "Request cancelled" )])); } _ = heartbeat_interval.tick() => { // 定期打印等待日志,证明 mcp-proxy 在等待后端响应 let elapsed = start.elapsed(); let transport_closed = inner.peer.is_transport_closed(); info!( "[call_tool:{}] Waiting for backend response... - Tool: {}, Waiting: {}ms, \\ transport_closed: {}, MCP ID: {}", request_id, request.name, elapsed.as_millis(), transport_closed, self.mcp_id ); } } }; let elapsed = start.elapsed(); match &call_result { Ok(call_result) => { // 记录工具调用结果 let is_error = call_result.is_error.unwrap_or(false); info!( "[call_tool:{}] Response received - tool: {}, time taken: {}ms, is_error: {}, MCP ID: {}", request_id, request.name, elapsed.as_millis(), is_error, self.mcp_id ); if is_error { debug!( "[call_tool:{}] Error response content: {:?}", request_id, call_result.content ); } Ok(call_result.clone()) } Err(err) => { error!( "[call_tool:{}] Backend returns error - Tool: {}, Time: {}ms, Error: {:?}, MCP ID: {}", request_id, request.name, elapsed.as_millis(), err, self.mcp_id ); // Return an error result instead of propagating the error Ok(CallToolResult::error(vec![Content::text(format!( "Error: {err}" ))])) } } } None => { error!( "[call_tool:{}] The server does not support tools capability - MCP ID: {}", request_id, self.mcp_id ); Ok(CallToolResult::error(vec![Content::text( "Server doesn't support tools capability", )])) } }; let total_elapsed = start.elapsed(); info!( "[call_tool:{}] Completed - Tool: {}, total time taken: {}ms", request_id, request.name, total_elapsed.as_millis() ); result } async fn list_resources( &self, request: Option, context: RequestContext, ) -> Result { // 原子加载后端连接 let inner_guard = self.peer.load(); let inner = inner_guard.as_ref().ok_or_else(|| { error!("Backend connection is not available (reconnecting)"); ErrorData::internal_error( "Backend connection is not available, reconnecting...".to_string(), None, ) })?; // 检查后端连接是否已关闭 if inner.peer.is_transport_closed() { error!("Backend transport is closed"); return Err(ErrorData::internal_error( "Backend connection closed, please retry".to_string(), None, )); } // Check if the server has resources capability and forward the request match self.capabilities().resources { Some(_) => { tokio::select! { result = inner.peer.list_resources(request) => { match result { Ok(result) => { // 记录资源列表结果,这些结果会通过 SSE 推送给客户端 info!( "[list_resources] Resource list results - MCP ID: {}, resource quantity: {}", self.mcp_id, result.resources.len() ); debug!("Proxying list_resources response"); Ok(result) } Err(err) => { error!("Error listing resources: {:?}", err); Err(ErrorData::internal_error( format!("Error listing resources: {err}"), None, )) } } } _ = context.ct.cancelled() => { info!("[list_resources] Request canceled - MCP ID: {}", self.mcp_id); Err(ErrorData::internal_error( "Request cancelled".to_string(), None, )) } } } None => { // Server doesn't support resources, return empty list warn!("Server doesn't support resources capability"); Ok(rmcp::model::ListResourcesResult::default()) } } } async fn read_resource( &self, request: rmcp::model::ReadResourceRequestParams, context: RequestContext, ) -> Result { // 原子加载后端连接 let inner_guard = self.peer.load(); let inner = inner_guard.as_ref().ok_or_else(|| { error!("Backend connection is not available (reconnecting)"); ErrorData::internal_error( "Backend connection is not available, reconnecting...".to_string(), None, ) })?; // 检查后端连接是否已关闭 if inner.peer.is_transport_closed() { error!("Backend transport is closed"); return Err(ErrorData::internal_error( "Backend connection closed, please retry".to_string(), None, )); } // Check if the server has resources capability and forward the request match self.capabilities().resources { Some(_) => { tokio::select! { result = inner.peer.read_resource(rmcp::model::ReadResourceRequestParams::new(request.uri.clone())) => { match result { Ok(result) => { // 记录资源读取结果,这些结果会通过 SSE 推送给客户端 info!( "[read_resource] Resource read result - MCP ID: {}, URI: {}", self.mcp_id, request.uri ); debug!("Proxying read_resource response for {}", request.uri); Ok(result) } Err(err) => { error!("Error reading resource: {:?}", err); Err(ErrorData::internal_error( format!("Error reading resource: {err}"), None, )) } } } _ = context.ct.cancelled() => { info!("[read_resource] Request canceled - MCP ID: {}, URI: {}", self.mcp_id, request.uri); Err(ErrorData::internal_error( "Request cancelled".to_string(), None, )) } } } None => { // Server doesn't support resources, return error error!("Server doesn't support resources capability"); Ok(rmcp::model::ReadResourceResult::new(vec![])) } } } async fn list_resource_templates( &self, request: Option, context: RequestContext, ) -> Result { // 原子加载后端连接 let inner_guard = self.peer.load(); let inner = inner_guard.as_ref().ok_or_else(|| { error!("Backend connection is not available (reconnecting)"); ErrorData::internal_error( "Backend connection is not available, reconnecting...".to_string(), None, ) })?; // 检查后端连接是否已关闭 if inner.peer.is_transport_closed() { error!("Backend transport is closed"); return Err(ErrorData::internal_error( "Backend connection closed, please retry".to_string(), None, )); } // Check if the server has resources capability and forward the request match self.capabilities().resources { Some(_) => { tokio::select! { result = inner.peer.list_resource_templates(request) => { match result { Ok(result) => { debug!("Proxying list_resource_templates response"); Ok(result) } Err(err) => { error!("Error listing resource templates: {:?}", err); Err(ErrorData::internal_error( format!("Error listing resource templates: {err}"), None, )) } } } _ = context.ct.cancelled() => { info!("[list_resource_templates] request canceled - MCP ID: {}", self.mcp_id); Err(ErrorData::internal_error( "Request cancelled".to_string(), None, )) } } } None => { // Server doesn't support resources, return empty list warn!("Server doesn't support resources capability"); Ok(rmcp::model::ListResourceTemplatesResult::default()) } } } async fn list_prompts( &self, request: Option, context: RequestContext, ) -> Result { // 原子加载后端连接 let inner_guard = self.peer.load(); let inner = inner_guard.as_ref().ok_or_else(|| { error!("Backend connection is not available (reconnecting)"); ErrorData::internal_error( "Backend connection is not available, reconnecting...".to_string(), None, ) })?; // 检查后端连接是否已关闭 if inner.peer.is_transport_closed() { error!("Backend transport is closed"); return Err(ErrorData::internal_error( "Backend connection closed, please retry".to_string(), None, )); } // Check if the server has prompts capability and forward the request match self.capabilities().prompts { Some(_) => { tokio::select! { result = inner.peer.list_prompts(request) => { match result { Ok(result) => { debug!("Proxying list_prompts response"); Ok(result) } Err(err) => { error!("Error listing prompts: {:?}", err); Err(ErrorData::internal_error( format!("Error listing prompts: {err}"), None, )) } } } _ = context.ct.cancelled() => { info!("[list_prompts] Request canceled - MCP ID: {}", self.mcp_id); Err(ErrorData::internal_error( "Request cancelled".to_string(), None, )) } } } None => { // Server doesn't support prompts, return empty list warn!("Server doesn't support prompts capability"); Ok(rmcp::model::ListPromptsResult::default()) } } } async fn get_prompt( &self, request: rmcp::model::GetPromptRequestParams, context: RequestContext, ) -> Result { // 原子加载后端连接 let inner_guard = self.peer.load(); let inner = inner_guard.as_ref().ok_or_else(|| { error!("Backend connection is not available (reconnecting)"); ErrorData::internal_error( "Backend connection is not available, reconnecting...".to_string(), None, ) })?; // 检查后端连接是否已关闭 if inner.peer.is_transport_closed() { error!("Backend transport is closed"); return Err(ErrorData::internal_error( "Backend connection closed, please retry".to_string(), None, )); } // Check if the server has prompts capability and forward the request match self.capabilities().prompts { Some(_) => { tokio::select! { result = inner.peer.get_prompt(request.clone()) => { match result { Ok(result) => { debug!("Proxying get_prompt response"); Ok(result) } Err(err) => { error!("Error getting prompt: {:?}", err); Err(ErrorData::internal_error( format!("Error getting prompt: {err}"), None, )) } } } _ = context.ct.cancelled() => { info!("[get_prompt] Request canceled - MCP ID: {}, prompt: {:?}", self.mcp_id, request.name); Err(ErrorData::internal_error( "Request cancelled".to_string(), None, )) } } } None => { // Server doesn't support prompts, return empty messages warn!("Server doesn't support prompts capability"); let messages = Vec::new(); Ok(rmcp::model::GetPromptResult::new(messages)) } } } async fn complete( &self, request: rmcp::model::CompleteRequestParams, context: RequestContext, ) -> Result { // 原子加载后端连接 let inner_guard = self.peer.load(); let inner = inner_guard.as_ref().ok_or_else(|| { error!("Backend connection is not available (reconnecting)"); ErrorData::internal_error( "Backend connection is not available, reconnecting...".to_string(), None, ) })?; // 检查后端连接是否已关闭 if inner.peer.is_transport_closed() { error!("Backend transport is closed"); return Err(ErrorData::internal_error( "Backend connection closed, please retry".to_string(), None, )); } tokio::select! { result = inner.peer.complete(request) => { match result { Ok(result) => { debug!("Proxying complete response"); Ok(result) } Err(err) => { error!("Error completing: {:?}", err); Err(ErrorData::internal_error( format!("Error completing: {err}"), None, )) } } } _ = context.ct.cancelled() => { info!("[complete] Request canceled - MCP ID: {}", self.mcp_id); Err(ErrorData::internal_error( "Request cancelled".to_string(), None, )) } } } async fn on_progress( &self, notification: rmcp::model::ProgressNotificationParam, _context: NotificationContext, ) { // 原子加载后端连接 let inner_guard = self.peer.load(); let inner = match inner_guard.as_ref() { Some(inner) => inner, None => { error!("Backend connection is not available, cannot forward progress notification"); return; } }; // 检查后端连接是否已关闭 if inner.peer.is_transport_closed() { error!("Backend transport is closed, cannot forward progress notification"); return; } match inner.peer.notify_progress(notification).await { Ok(_) => { debug!("Proxying progress notification"); } Err(err) => { error!("Error notifying progress: {:?}", err); } } } async fn on_cancelled( &self, notification: rmcp::model::CancelledNotificationParam, _context: NotificationContext, ) { // 原子加载后端连接 let inner_guard = self.peer.load(); let inner = match inner_guard.as_ref() { Some(inner) => inner, None => { error!( "Backend connection is not available, cannot forward cancelled notification" ); return; } }; // 检查后端连接是否已关闭 if inner.peer.is_transport_closed() { error!("Backend transport is closed, cannot forward cancelled notification"); return; } match inner.peer.notify_cancelled(notification).await { Ok(_) => { debug!("Proxying cancelled notification"); } Err(err) => { error!("Error notifying cancelled: {:?}", err); } } } } impl ProxyHandler { /// 获取 capabilities 的引用,避免 clone #[inline] fn capabilities(&self) -> &rmcp::model::ServerCapabilities { &self.cached_info.capabilities } /// 创建一个默认的 ServerInfo(用于断开状态) fn default_server_info(mcp_id: &str) -> ServerInfo { warn!( "[ProxyHandler] Create default ServerInfo - MCP ID: {}", mcp_id ); ServerInfo::new(rmcp::model::ServerCapabilities::default()) .with_server_info(Implementation::new("MCP Proxy", "0.1.0")) } /// 从 RunningService 提取 ServerInfo fn extract_server_info( client: &RunningService, mcp_id: &str, ) -> ServerInfo { client .peer_info() .map(|peer_info| { ServerInfo::new(peer_info.capabilities.clone()) .with_protocol_version(peer_info.protocol_version.clone()) .with_server_info(Implementation::new( peer_info.server_info.name.clone(), peer_info.server_info.version.clone(), )) .with_instructions(peer_info.instructions.clone().unwrap_or_default()) }) .unwrap_or_else(|| Self::default_server_info(mcp_id)) } /// 创建断开状态的 handler(用于初始化) /// 后续通过 swap_backend() 注入实际的后端连接 pub fn new_disconnected( mcp_id: String, tool_filter: ToolFilter, default_info: ServerInfo, ) -> Self { info!( "[ProxyHandler] Create a disconnected handler - MCP ID: {}", mcp_id ); // 记录过滤器配置 if tool_filter.is_enabled() { if let Some(ref allow_list) = tool_filter.allow_tools { info!( "[ProxyHandler] Tool whitelist enabled - MCP ID: {}, allowed tools: {:?}", mcp_id, allow_list ); } if let Some(ref deny_list) = tool_filter.deny_tools { info!( "[ProxyHandler] Tool blacklist enabled - MCP ID: {}, excluded tools: {:?}", mcp_id, deny_list ); } } Self { peer: Arc::new(ArcSwapOption::empty()), cached_info: default_info, mcp_id, tool_filter, backend_version: Arc::new(AtomicU64::new(0)), // 断开状态版本为 0 } } pub fn new(client: RunningService) -> Self { Self::with_mcp_id(client, "unknown".to_string()) } pub fn with_mcp_id(client: RunningService, mcp_id: String) -> Self { Self::with_tool_filter(client, mcp_id, ToolFilter::default()) } /// 创建带工具过滤器的 ProxyHandler(带初始后端连接) pub fn with_tool_filter( client: RunningService, mcp_id: String, tool_filter: ToolFilter, ) -> Self { use std::ops::Deref; // 提取 ServerInfo let cached_info = Self::extract_server_info(&client, &mcp_id); // 克隆 Peer 用于并发请求(无需锁) let peer = client.deref().clone(); // 记录过滤器配置 if tool_filter.is_enabled() { if let Some(ref allow_list) = tool_filter.allow_tools { info!( "[ProxyHandler] Tool whitelist enabled - MCP ID: {}, allowed tools: {:?}", mcp_id, allow_list ); } if let Some(ref deny_list) = tool_filter.deny_tools { info!( "[ProxyHandler] Tool blacklist enabled - MCP ID: {}, excluded tools: {:?}", mcp_id, deny_list ); } } // 创建 PeerInner let inner = PeerInner { peer, _running: Arc::new(client), }; Self { peer: Arc::new(ArcSwapOption::from(Some(Arc::new(inner)))), cached_info, mcp_id, tool_filter, backend_version: Arc::new(AtomicU64::new(1)), // 初始版本为 1 } } /// 原子性替换后端连接 /// - Some(client): 设置新的后端连接 /// - None: 标记后端断开 /// /// **版本控制**:每次调用都会递增 backend_version,使旧 session 失效 pub fn swap_backend(&self, new_client: Option>) { use std::ops::Deref; match new_client { Some(client) => { let peer = client.deref().clone(); let inner = PeerInner { peer, _running: Arc::new(client), }; self.peer.store(Some(Arc::new(inner))); info!( "[ProxyHandler] Backend connection updated - MCP ID: {}", self.mcp_id ); } None => { self.peer.store(None); info!( "[ProxyHandler] Backend connection disconnected - MCP ID: {}", self.mcp_id ); } } // 关键:递增版本号,使所有旧 session 失效 let new_version = self.backend_version.fetch_add(1, Ordering::SeqCst) + 1; info!( "[ProxyHandler] Backend version update: {} - MCP ID: {}", new_version, self.mcp_id ); } /// 检查后端是否可用(快速检查,不发送请求) pub fn is_backend_available(&self) -> bool { let inner_guard = self.peer.load(); match inner_guard.as_ref() { Some(inner) => !inner.peer.is_transport_closed(), None => false, } } /// 检查 mcp 服务是否正常(异步版本,会发送验证请求) pub async fn is_mcp_server_ready(&self) -> bool { !self.is_terminated_async().await } /// 检查后端连接是否已关闭(同步版本,仅检查 transport 状态) pub fn is_terminated(&self) -> bool { !self.is_backend_available() } /// 异步检查后端连接是否已断开(会发送验证请求) pub async fn is_terminated_async(&self) -> bool { // 原子加载后端连接 let inner_guard = self.peer.load(); let inner = match inner_guard.as_ref() { Some(inner) => inner, None => return true, }; // 快速检查 transport 状态 if inner.peer.is_transport_closed() { return true; } // 通过发送轻量级请求来验证连接 match inner.peer.list_tools(None).await { Ok(_) => { debug!("Backend connection status check: OK"); false } Err(e) => { info!("Backend connection status check: Disconnected, reason: {e}"); true } } } /// 获取 MCP ID pub fn mcp_id(&self) -> &str { &self.mcp_id } /// 获取后端 ServerInfo 的 JSON 表示 /// /// 用于跨 rmcp 版本桥接:将 rmcp 1.4.0 的 ServerInfo 序列化为 JSON, /// 供 rmcp 0.10 侧反序列化使用。 pub fn get_server_info_json(&self) -> serde_json::Value { serde_json::to_value(&self.cached_info).unwrap_or_default() } /// 获取当前后端版本号 /// /// 版本号用于跟踪后端连接变化: /// - 0: 断开状态 /// - 1+: 已连接,每次 swap_backend 递增 /// /// **用途**:配合 ProxyAwareSessionManager 实现 session 版本控制 pub fn get_backend_version(&self) -> u64 { self.backend_version.load(Ordering::SeqCst) } /// 直接调用后端 peer 的方法(用于 BackendSession trait 实现) /// /// 这是一个低级接口,直接操作 peer 而不经过 ServerHandler 的封装 pub async fn call_peer_method( &self, method: &str, params: serde_json::Value, ) -> Result { use rmcp::model::PaginatedRequestParams; let inner_guard = self.peer.load(); let inner = inner_guard.as_ref().ok_or_else(|| { "Backend connection is not available (reconnecting)".to_string() })?; if inner.peer.is_transport_closed() { return Err("Backend transport is closed".to_string()); } match method { "tools/list" => { let request: Option = serde_json::from_value(params).ok(); let result = inner.peer.list_tools(request).await .map_err(|e| format!("list_tools error: {:?}", e))?; serde_json::to_value(result) .map_err(|e| format!("serialize error: {}", e)) } "tools/call" => { let request: rmcp::model::CallToolRequestParams = serde_json::from_value(params) .map_err(|e| format!("Invalid params for tools/call: {}", e))?; let result = inner.peer.call_tool(request).await .map_err(|e| format!("call_tool error: {:?}", e))?; serde_json::to_value(result) .map_err(|e| format!("serialize error: {}", e)) } "resources/list" => { let request: Option = serde_json::from_value(params).ok(); let result = inner.peer.list_resources(request).await .map_err(|e| format!("list_resources error: {:?}", e))?; serde_json::to_value(result) .map_err(|e| format!("serialize error: {}", e)) } "resources/read" => { let request: rmcp::model::ReadResourceRequestParams = serde_json::from_value(params) .map_err(|e| format!("Invalid params for resources/read: {}", e))?; let result = inner.peer.read_resource(request).await .map_err(|e| format!("read_resource error: {:?}", e))?; serde_json::to_value(result) .map_err(|e| format!("serialize error: {}", e)) } "prompts/list" => { let request: Option = serde_json::from_value(params).ok(); let result = inner.peer.list_prompts(request).await .map_err(|e| format!("list_prompts error: {:?}", e))?; serde_json::to_value(result) .map_err(|e| format!("serialize error: {}", e)) } "prompts/get" => { let request: rmcp::model::GetPromptRequestParams = serde_json::from_value(params) .map_err(|e| format!("Invalid params for prompts/get: {}", e))?; let result = inner.peer.get_prompt(request).await .map_err(|e| format!("get_prompt error: {:?}", e))?; serde_json::to_value(result) .map_err(|e| format!("serialize error: {}", e)) } "resources/templates/list" => { let request: Option = serde_json::from_value(params).ok(); let result = inner.peer.list_resource_templates(request).await .map_err(|e| format!("list_resource_templates error: {:?}", e))?; serde_json::to_value(result) .map_err(|e| format!("serialize error: {}", e)) } "completion/complete" => { let request: rmcp::model::CompleteRequestParams = serde_json::from_value(params) .map_err(|e| format!("Invalid params for completion/complete: {}", e))?; let result = inner.peer.complete(request).await .map_err(|e| format!("complete error: {:?}", e))?; serde_json::to_value(result) .map_err(|e| format!("serialize error: {}", e)) } _ => Err(format!("Unsupported method: {}", method)), } } /// Update backend from a StreamClientConnection /// /// This method allows updating the backend connection using the high-level /// `StreamClientConnection` type, which is more convenient than the raw /// `RunningService` type. /// /// # Arguments /// * `conn` - Some(connection) to set new backend, None to mark disconnected pub fn swap_backend_from_connection( &self, conn: Option, ) { match conn { Some(c) => { let running = c.into_running_service(); self.swap_backend(Some(running)); } None => { self.swap_backend(None); } } } } impl mcp_common::BackendBridge for ProxyHandler { fn mcp_id(&self) -> &str { self.mcp_id() } fn get_server_info_json(&self) -> serde_json::Value { self.get_server_info_json() } fn is_backend_available(&self) -> bool { self.is_backend_available() } fn is_mcp_server_ready( &self, ) -> std::pin::Pin + Send + '_>> { Box::pin(self.is_mcp_server_ready()) } fn is_terminated_async( &self, ) -> std::pin::Pin + Send + '_>> { Box::pin(self.is_terminated_async()) } fn call_peer_method( &self, method: &str, params: serde_json::Value, ) -> std::pin::Pin< Box> + Send + '_>, > { let method = method.to_string(); Box::pin(async move { ProxyHandler::call_peer_method(self, &method, params).await }) } }