use std::sync::Arc; use rmcp::ClientHandler; use rmcp::RoleClient; use rmcp::model::CancelledNotificationParam; use rmcp::model::ClientInfo; use rmcp::model::CreateElicitationRequestParam; use rmcp::model::CreateElicitationResult; use rmcp::model::LoggingLevel; use rmcp::model::LoggingMessageNotificationParam; use rmcp::model::ProgressNotificationParam; use rmcp::model::RequestId; use rmcp::model::ResourceUpdatedNotificationParam; use rmcp::service::NotificationContext; use rmcp::service::RequestContext; use tracing::debug; use tracing::error; use tracing::info; use tracing::warn; use crate::rmcp_client::SendElicitation; #[derive(Clone)] pub(crate) struct LoggingClientHandler { client_info: ClientInfo, send_elicitation: Arc, } impl LoggingClientHandler { pub(crate) fn new(client_info: ClientInfo, send_elicitation: SendElicitation) -> Self { Self { client_info, send_elicitation: Arc::new(send_elicitation), } } } impl ClientHandler for LoggingClientHandler { async fn create_elicitation( &self, request: CreateElicitationRequestParam, context: RequestContext, ) -> Result { let id = match context.id { RequestId::String(id) => mcp_types::RequestId::String(id.to_string()), RequestId::Number(id) => mcp_types::RequestId::Integer(id), }; (self.send_elicitation)(id, request) .await .map_err(|err| rmcp::ErrorData::internal_error(err.to_string(), None)) } async fn on_cancelled( &self, params: CancelledNotificationParam, _context: NotificationContext, ) { info!( "MCP server cancelled request (request_id: {}, reason: {:?})", params.request_id, params.reason ); } async fn on_progress( &self, params: ProgressNotificationParam, _context: NotificationContext, ) { info!( "MCP server progress notification (token: {:?}, progress: {}, total: {:?}, message: {:?})", params.progress_token, params.progress, params.total, params.message ); } async fn on_resource_updated( &self, params: ResourceUpdatedNotificationParam, _context: NotificationContext, ) { info!("MCP server resource updated (uri: {})", params.uri); } async fn on_resource_list_changed(&self, _context: NotificationContext) { info!("MCP server resource list changed"); } async fn on_tool_list_changed(&self, _context: NotificationContext) { info!("MCP server tool list changed"); } async fn on_prompt_list_changed(&self, _context: NotificationContext) { info!("MCP server prompt list changed"); } fn get_info(&self) -> ClientInfo { self.client_info.clone() } async fn on_logging_message( &self, params: LoggingMessageNotificationParam, _context: NotificationContext, ) { let LoggingMessageNotificationParam { level, logger, data, } = params; let logger = logger.as_deref(); match level { LoggingLevel::Emergency | LoggingLevel::Alert | LoggingLevel::Critical | LoggingLevel::Error => { error!( "MCP server log message (level: {:?}, logger: {:?}, data: {})", level, logger, data ); } LoggingLevel::Warning => { warn!( "MCP server log message (level: {:?}, logger: {:?}, data: {})", level, logger, data ); } LoggingLevel::Notice | LoggingLevel::Info => { info!( "MCP server log message (level: {:?}, logger: {:?}, data: {})", level, logger, data ); } LoggingLevel::Debug => { debug!( "MCP server log message (level: {:?}, logger: {:?}, data: {})", level, logger, data ); } } } }