// Sampling/Roots/Logging are SEP-2577-deprecated; internal references are expected. #![expect(deprecated)] pub mod progress; use std::sync::Arc; use crate::{ error::ErrorData as McpError, model::*, service::{ MaybeSendFuture, NotificationContext, RequestContext, RoleClient, Service, ServiceRole, }, }; impl Service for H { async fn handle_request( &self, request: ::PeerReq, context: RequestContext, ) -> Result<::Resp, McpError> { match request { ServerRequest::PingRequest(_) => self.ping(context).await.map(ClientResult::empty), ServerRequest::CreateMessageRequest(request) => self .create_message(request.params, context) .await .map(Box::new) .map(ClientResult::CreateMessageResult), ServerRequest::ListRootsRequest(_) => self .list_roots(context) .await .map(ClientResult::ListRootsResult), ServerRequest::ElicitRequest(request) => self .create_elicitation(request.params, context) .await .map(ClientResult::ElicitResult), ServerRequest::CustomRequest(request) => self .on_custom_request(request, context) .await .map(ClientResult::CustomResult), } } async fn handle_notification( &self, notification: ::PeerNot, context: NotificationContext, ) -> Result<(), McpError> { match notification { ServerNotification::CancelledNotification(notification) => { self.on_cancelled(notification.params, context).await } ServerNotification::ProgressNotification(notification) => { self.on_progress(notification.params, context).await } ServerNotification::LoggingMessageNotification(notification) => { self.on_logging_message(notification.params, context).await } ServerNotification::ResourceUpdatedNotification(notification) => { self.on_resource_updated(notification.params, context).await } ServerNotification::ResourceListChangedNotification(_notification_no_param) => { self.on_resource_list_changed(context).await } ServerNotification::ToolListChangedNotification(_notification_no_param) => { self.on_tool_list_changed(context).await } ServerNotification::PromptListChangedNotification(_notification_no_param) => { self.on_prompt_list_changed(context).await } ServerNotification::SubscriptionsAcknowledgedNotification(notification) => { self.on_subscriptions_acknowledged(notification.params, context) .await } ServerNotification::TaskStatusNotification(notification) => { self.on_task_status(notification.params, context).await } ServerNotification::CustomNotification(notification) => { self.on_custom_notification(notification, context).await } }; Ok(()) } fn get_info(&self) -> ::Info { self.get_info() } } macro_rules! client_handler_methods { () => { fn ping( &self, context: RequestContext, ) -> impl Future> + MaybeSendFuture + '_ { std::future::ready(Ok(())) } fn create_message( &self, params: CreateMessageRequestParams, context: RequestContext, ) -> impl Future> + MaybeSendFuture + '_ { std::future::ready(Err( McpError::method_not_found::(), )) } fn list_roots( &self, context: RequestContext, ) -> impl Future> + MaybeSendFuture + '_ { std::future::ready(Ok(ListRootsResult::default())) } /// Handle an elicitation request from a server asking for user input. /// /// This method is called when a server needs interactive input from the user /// during tool execution. Implementations should present the message to the user, /// collect their input according to the requested schema, and return the result. /// /// # Arguments /// * `request` - The elicitation request with message and schema /// * `context` - The request context /// /// # Returns /// The user's response including action (accept/decline/cancel) and optional data /// /// # Default Behavior /// The default implementation automatically declines all elicitation requests. /// Real clients should override this to provide user interaction. /// /// # Example /// ```rust,no_run /// use rmcp::{ /// ClientHandler, /// model::{ /// ElicitRequestParams, ElicitResult, ElicitationAction, ElicitationSchema, /// ErrorData as McpError, /// }, /// service::{RequestContext, RoleClient}, /// }; /// /// # struct MyClient; /// # /// # async fn get_user_input( /// # _message: String, /// # _schema: ElicitationSchema, /// # ) -> Result { /// # std::future::pending().await /// # } /// # /// # async fn open_url_in_browser(_url: String) -> Result<(), McpError> { /// # Ok(()) /// # } /// # /// impl ClientHandler for MyClient { /// async fn create_elicitation( /// &self, /// request: ElicitRequestParams, /// _context: RequestContext, /// ) -> Result { /// match request { /// ElicitRequestParams::FormElicitationParams { /// message, /// requested_schema, /// .. /// } => { /// let input = get_user_input(message, requested_schema).await?; /// Ok(ElicitResult::new(ElicitationAction::Accept).with_content(input)) /// } /// ElicitRequestParams::UrlElicitationParams { url, .. } => { /// open_url_in_browser(url).await?; /// Ok(ElicitResult::new(ElicitationAction::Accept)) /// } /// _ => Ok(ElicitResult::new(ElicitationAction::Decline)), /// } /// } /// } /// ``` fn create_elicitation( &self, request: ElicitRequestParams, context: RequestContext, ) -> impl Future> + MaybeSendFuture + '_ { // Default implementation declines all requests - real clients should override this let _ = (request, context); std::future::ready(Ok(ElicitResult { action: ElicitationAction::Decline, content: None, meta: None, })) } fn on_custom_request( &self, request: CustomRequest, context: RequestContext, ) -> impl Future> + MaybeSendFuture + '_ { let CustomRequest { method, .. } = request; let _ = context; std::future::ready(Err(McpError::new( ErrorCode::METHOD_NOT_FOUND, method, None, ))) } fn on_cancelled( &self, params: CancelledNotificationParam, context: NotificationContext, ) -> impl Future + MaybeSendFuture + '_ { std::future::ready(()) } fn on_progress( &self, params: ProgressNotificationParam, context: NotificationContext, ) -> impl Future + MaybeSendFuture + '_ { std::future::ready(()) } fn on_logging_message( &self, params: LoggingMessageNotificationParam, context: NotificationContext, ) -> impl Future + MaybeSendFuture + '_ { std::future::ready(()) } fn on_resource_updated( &self, params: ResourceUpdatedNotificationParam, context: NotificationContext, ) -> impl Future + MaybeSendFuture + '_ { std::future::ready(()) } fn on_resource_list_changed( &self, context: NotificationContext, ) -> impl Future + MaybeSendFuture + '_ { std::future::ready(()) } fn on_tool_list_changed( &self, context: NotificationContext, ) -> impl Future + MaybeSendFuture + '_ { std::future::ready(()) } fn on_prompt_list_changed( &self, context: NotificationContext, ) -> impl Future + MaybeSendFuture + '_ { std::future::ready(()) } fn on_subscriptions_acknowledged( &self, params: SubscriptionsAcknowledgedNotificationParams, context: NotificationContext, ) -> impl Future + MaybeSendFuture + '_ { std::future::ready(()) } fn on_task_status( &self, params: TaskStatusNotificationParams, context: NotificationContext, ) -> impl Future + MaybeSendFuture + '_ { std::future::ready(()) } fn on_custom_notification( &self, notification: CustomNotification, context: NotificationContext, ) -> impl Future + MaybeSendFuture + '_ { let _ = (notification, context); std::future::ready(()) } fn get_info(&self) -> ClientInfo { InitializeRequestParams::default() } }; } #[allow(unused_variables)] #[cfg(not(feature = "local"))] pub trait ClientHandler: Sized + Send + Sync + 'static { client_handler_methods!(); } #[allow(unused_variables)] #[cfg(feature = "local")] pub trait ClientHandler: Sized + 'static { client_handler_methods!(); } /// Do nothing, with default client info. impl ClientHandler for () {} /// Do nothing, with a specific client info. impl ClientHandler for ClientInfo { fn get_info(&self) -> ClientInfo { self.clone() } } macro_rules! impl_client_handler_for_wrapper { ($wrapper:ident) => { impl ClientHandler for $wrapper { fn ping( &self, context: RequestContext, ) -> impl Future> + MaybeSendFuture + '_ { (**self).ping(context) } fn create_message( &self, params: CreateMessageRequestParams, context: RequestContext, ) -> impl Future> + MaybeSendFuture + '_ { (**self).create_message(params, context) } fn list_roots( &self, context: RequestContext, ) -> impl Future> + MaybeSendFuture + '_ { (**self).list_roots(context) } fn create_elicitation( &self, request: ElicitRequestParams, context: RequestContext, ) -> impl Future> + MaybeSendFuture + '_ { (**self).create_elicitation(request, context) } fn on_custom_request( &self, request: CustomRequest, context: RequestContext, ) -> impl Future> + MaybeSendFuture + '_ { (**self).on_custom_request(request, context) } fn on_cancelled( &self, params: CancelledNotificationParam, context: NotificationContext, ) -> impl Future + MaybeSendFuture + '_ { (**self).on_cancelled(params, context) } fn on_progress( &self, params: ProgressNotificationParam, context: NotificationContext, ) -> impl Future + MaybeSendFuture + '_ { (**self).on_progress(params, context) } fn on_logging_message( &self, params: LoggingMessageNotificationParam, context: NotificationContext, ) -> impl Future + MaybeSendFuture + '_ { (**self).on_logging_message(params, context) } fn on_resource_updated( &self, params: ResourceUpdatedNotificationParam, context: NotificationContext, ) -> impl Future + MaybeSendFuture + '_ { (**self).on_resource_updated(params, context) } fn on_resource_list_changed( &self, context: NotificationContext, ) -> impl Future + MaybeSendFuture + '_ { (**self).on_resource_list_changed(context) } fn on_tool_list_changed( &self, context: NotificationContext, ) -> impl Future + MaybeSendFuture + '_ { (**self).on_tool_list_changed(context) } fn on_prompt_list_changed( &self, context: NotificationContext, ) -> impl Future + MaybeSendFuture + '_ { (**self).on_prompt_list_changed(context) } fn on_subscriptions_acknowledged( &self, params: SubscriptionsAcknowledgedNotificationParams, context: NotificationContext, ) -> impl Future + MaybeSendFuture + '_ { (**self).on_subscriptions_acknowledged(params, context) } fn on_task_status( &self, params: TaskStatusNotificationParams, context: NotificationContext, ) -> impl Future + MaybeSendFuture + '_ { (**self).on_task_status(params, context) } fn on_custom_notification( &self, notification: CustomNotification, context: NotificationContext, ) -> impl Future + MaybeSendFuture + '_ { (**self).on_custom_notification(notification, context) } fn get_info(&self) -> ClientInfo { (**self).get_info() } } }; } impl_client_handler_for_wrapper!(Box); impl_client_handler_for_wrapper!(Arc);