Skip to main content

rust_mcp_sdk/mcp_handlers/
mcp_client_handler.rs

1use crate::mcp_client::client_runtime::ClientInternalHandler;
2use crate::mcp_traits::McpClient;
3use crate::schema::schema_utils::{CustomNotification, CustomRequest};
4use crate::schema::{
5    CancelTaskParams, CancelTaskRequest, CancelTaskResult, CancelledNotificationParams,
6    CreateMessageRequest, CreateMessageRequestParams, CreateMessageResult, ElicitCompleteParams,
7    ElicitRequest, ElicitRequestParams, ElicitResult, GenericResult, GetTaskParams,
8    GetTaskPayloadParams, GetTaskPayloadRequest, GetTaskRequest, GetTaskResult, ListRootsRequest,
9    ListRootsResult, ListTasksRequest, ListTasksResult, LoggingMessageNotificationParams,
10    NotificationParams, PaginatedRequestParams, ProgressNotificationParams, RequestParams,
11    ResourceUpdatedNotificationParams, Result, RpcError, TaskStatusNotificationParams,
12};
13use crate::task_store::ClientTaskCreator;
14use crate::{McpClientHandler, ToMcpClientHandler};
15use async_trait::async_trait;
16use rust_mcp_schema::CreateTaskResult;
17
18/// The `ClientHandler` trait defines how a client handles Model Context Protocol (MCP) operations.
19/// It includes default implementations for handling requests , notifications and errors and must be
20/// extended or overridden by developers to customize client behavior.
21#[allow(unused)]
22#[async_trait]
23pub trait ClientHandler: Send + Sync + 'static {
24    //**********************//
25    //** Request Handlers **//
26    //**********************//
27
28    /// Handles a ping, to check that the other party is still alive.
29    /// The receiver must promptly respond, or else may be disconnected.
30    async fn handle_ping_request(
31        &self,
32        params: Option<RequestParams>,
33        runtime: &dyn McpClient,
34    ) -> std::result::Result<Result, RpcError> {
35        Ok(Result::default())
36    }
37
38    /// Handles a request from the server to sample an LLM via the client.
39    /// The client has full discretion over which model to select.
40    /// The client should also inform the user before beginning sampling,
41    /// to allow them to inspect the request (human in the loop) and decide whether to approve it.
42    async fn handle_create_message_request(
43        &self,
44        params: CreateMessageRequestParams,
45        runtime: &dyn McpClient,
46    ) -> std::result::Result<CreateMessageResult, RpcError> {
47        Err(RpcError::method_not_found().with_message(format!(
48            "No handler is implemented for '{}'.",
49            CreateMessageRequest::method_value()
50        )))
51    }
52
53    /// Handles requests to call a task-augmented sampling (sampling/createMessage).
54    /// you need to returns a CreateTaskResult containing task data.
55    /// The actual operation result becomes available later
56    /// through tasks/result after the task completes.
57    async fn handle_task_augmented_create_message(
58        &self,
59        params: CreateMessageRequestParams,
60        runtime: &dyn McpClient,
61    ) -> std::result::Result<CreateTaskResult, RpcError> {
62        if !runtime.capabilities().can_accept_sampling_task() {
63            return Err(RpcError::invalid_request()
64                .with_message("Task-augmented sampling is not supported.".to_string()));
65        }
66
67        Err(RpcError::method_not_found().with_message(format!(
68            "No handler is implemented for task-augmented '{}'.",
69            CreateMessageRequest::method_value()
70        )))
71    }
72
73    /// Handles a request from the server to request a list of root URIs from the client. Roots allow
74    /// servers to ask for specific directories or files to operate on.
75    /// This request is typically used when the server needs to understand the file system
76    /// structure or access specific locations that the client has permission to read from.
77    async fn handle_list_roots_request(
78        &self,
79        params: Option<RequestParams>,
80        runtime: &dyn McpClient,
81    ) -> std::result::Result<ListRootsResult, RpcError> {
82        Err(RpcError::method_not_found().with_message(format!(
83            "No handler is implemented for '{}'.",
84            ListRootsRequest::method_value(),
85        )))
86    }
87
88    ///Handles a request from the server to elicit additional information from the user via the client.
89    async fn handle_elicit_request(
90        &self,
91        params: ElicitRequestParams,
92        runtime: &dyn McpClient,
93    ) -> std::result::Result<ElicitResult, RpcError> {
94        Err(RpcError::method_not_found().with_message(format!(
95            "No handler is implemented for '{}'.",
96            ElicitRequest::method_value()
97        )))
98    }
99
100    /// Handles task-augmented elicitation, to elicit additional information from the user via the client.
101    /// you need to returns a CreateTaskResult containing task data.
102    /// The actual operation result becomes available later
103    /// through tasks/result after the task completes.
104    async fn handle_task_augmented_elicit_request(
105        &self,
106        task_creator: ClientTaskCreator,
107        params: ElicitRequestParams,
108        runtime: &dyn McpClient,
109    ) -> std::result::Result<CreateTaskResult, RpcError> {
110        Err(RpcError::method_not_found().with_message(format!(
111            "No handler is implemented for '{}'.",
112            ElicitRequest::method_value()
113        )))
114    }
115
116    /// Handles a request to retrieve the state of a task.
117    async fn handle_get_task_request(
118        &self,
119        params: GetTaskParams,
120        runtime: &dyn McpClient,
121    ) -> std::result::Result<GetTaskResult, RpcError> {
122        Err(RpcError::method_not_found().with_message(format!(
123            "No handler is implemented for '{}'.",
124            GetTaskRequest::method_value()
125        )))
126    }
127
128    /// Handles a request to retrieve the result of a completed task.
129    async fn handle_get_task_payload_request(
130        &self,
131        params: GetTaskPayloadParams,
132        runtime: &dyn McpClient,
133    ) -> std::result::Result<GenericResult, RpcError> {
134        Err(RpcError::method_not_found().with_message(format!(
135            "No handler is implemented for '{}'.",
136            GetTaskPayloadRequest::method_value()
137        )))
138    }
139
140    /// Handles a request to cancel a task.
141    async fn handle_cancel_task_request(
142        &self,
143        params: CancelTaskParams,
144        runtime: &dyn McpClient,
145    ) -> std::result::Result<CancelTaskResult, RpcError> {
146        Err(RpcError::method_not_found().with_message(format!(
147            "No handler is implemented for '{}'.",
148            CancelTaskRequest::method_value()
149        )))
150    }
151
152    /// Handles a request to retrieve a list of tasks.
153    async fn handle_list_tasks_request(
154        &self,
155        params: Option<PaginatedRequestParams>,
156        runtime: &dyn McpClient,
157    ) -> std::result::Result<ListTasksResult, RpcError> {
158        Err(RpcError::method_not_found().with_message(format!(
159            "No handler is implemented for '{}'.",
160            ListTasksRequest::method_value()
161        )))
162    }
163
164    /// Handle a custom request
165    async fn handle_custom_request(
166        &self,
167        request: CustomRequest,
168        runtime: &dyn McpClient,
169    ) -> std::result::Result<ListRootsResult, RpcError> {
170        Err(RpcError::method_not_found().with_message(format!(
171            "No handler for custom request : \"{}\"",
172            request.method
173        )))
174    }
175
176    //***************************//
177    //** Notification Handlers **//
178    //***************************//
179
180    /// Handles a notification that indicates that it is cancelling a previously-issued request.
181    /// it is always possible that this notification MAY arrive after the request has already finished.
182    /// This notification indicates that the result will be unused, so any associated processing SHOULD cease.
183    async fn handle_cancelled_notification(
184        &self,
185        params: CancelledNotificationParams,
186        runtime: &dyn McpClient,
187    ) -> std::result::Result<(), RpcError> {
188        Ok(())
189    }
190
191    /// Handles an out-of-band notification used to inform the receiver of a progress update for a long-running request.
192    async fn handle_progress_notification(
193        &self,
194        params: ProgressNotificationParams,
195        runtime: &dyn McpClient,
196    ) -> std::result::Result<(), RpcError> {
197        Ok(())
198    }
199
200    /// Handles a notification from the server to the client, informing it that the list of resources it can read from has changed.
201    async fn handle_resource_list_changed_notification(
202        &self,
203        params: Option<NotificationParams>,
204        runtime: &dyn McpClient,
205    ) -> std::result::Result<(), RpcError> {
206        Ok(())
207    }
208
209    /// handles a notification from the server to the client, informing it that a resource has changed and may need to be read again.
210    async fn handle_resource_updated_notification(
211        &self,
212        params: ResourceUpdatedNotificationParams,
213        runtime: &dyn McpClient,
214    ) -> std::result::Result<(), RpcError> {
215        Ok(())
216    }
217
218    ///Handles a notification from the server to the client, informing it that the list of prompts it offers has changed.
219    async fn handle_prompt_list_changed_notification(
220        &self,
221        params: Option<NotificationParams>,
222        runtime: &dyn McpClient,
223    ) -> std::result::Result<(), RpcError> {
224        Ok(())
225    }
226
227    /// Handles a notification from the server to the client, informing it that the list of tools it offers has changed.
228    async fn handle_tool_list_changed_notification(
229        &self,
230        params: Option<NotificationParams>,
231        runtime: &dyn McpClient,
232    ) -> std::result::Result<(), RpcError> {
233        Ok(())
234    }
235
236    /// Handles notification of a log message passed from server to client.
237    /// If no logging/setLevel request has been sent from the client, the server MAY decide which messages to send automatically.
238    async fn handle_logging_message_notification(
239        &self,
240        params: LoggingMessageNotificationParams,
241        runtime: &dyn McpClient,
242    ) -> std::result::Result<(), RpcError> {
243        Ok(())
244    }
245
246    /// Handles a notification from the receiver to the requestor, informing them that a task's status has changed.
247    /// Receivers are not required to send these notifications.
248    async fn handle_task_status_notification(
249        &self,
250        params: TaskStatusNotificationParams,
251        runtime: &dyn McpClient,
252    ) -> std::result::Result<(), RpcError> {
253        Ok(())
254    }
255
256    /// Handles a notification from the server to the client, informing it of a completion of a out-of-band elicitation request.
257    async fn handle_elicitation_complete_notification(
258        &self,
259        params: ElicitCompleteParams,
260        runtime: &dyn McpClient,
261    ) -> std::result::Result<(), RpcError> {
262        Ok(())
263    }
264
265    /// Handles a custom notification message
266    async fn handle_custom_notification(
267        &self,
268        notification: CustomNotification,
269        runtime: &dyn McpClient,
270    ) -> std::result::Result<(), RpcError> {
271        Ok(())
272    }
273
274    //********************//
275    //** Error Handlers **//
276    //********************//
277    async fn handle_error(
278        &self,
279        error: &RpcError,
280        runtime: &dyn McpClient,
281    ) -> std::result::Result<(), RpcError> {
282        Ok(())
283    }
284
285    async fn handle_process_error(
286        &self,
287        error_message: String,
288        runtime: &dyn McpClient,
289    ) -> std::result::Result<(), RpcError> {
290        if !runtime.is_shut_down().await {
291            tracing::error!("Process error: {error_message}");
292        }
293        Ok(())
294    }
295}
296
297impl<T: ClientHandler + 'static> ToMcpClientHandler for T {
298    fn to_mcp_client_handler(self) -> Box<dyn McpClientHandler + 'static> {
299        Box::new(ClientInternalHandler::new(Box::new(self)))
300    }
301}