turbomcp_client/client/operations/handlers.rs
1//! Handler registration operations for MCP client
2//!
3//! This module provides methods for registering and managing various event handlers
4//! that process server-initiated operations and notifications.
5
6use crate::handlers::{
7 CancellationHandler, ElicitationHandler, LogHandler, ProgressHandler, PromptListChangedHandler,
8 ResourceListChangedHandler, ResourceUpdateHandler, RootsHandler, ToolListChangedHandler,
9};
10use std::sync::Arc;
11
12impl<T: turbomcp_transport::Transport + 'static> super::super::core::Client<T> {
13 /// Register a roots handler for responding to server filesystem root requests
14 ///
15 /// Roots handlers respond to `roots/list` requests from servers (SERVER->CLIENT).
16 /// Per MCP 2025-06-18 specification, servers ask clients what filesystem roots
17 /// they have access to. This is commonly used when servers need to understand
18 /// their operating boundaries, such as which repositories or project directories
19 /// they can access.
20 ///
21 /// # Arguments
22 ///
23 /// * `handler` - The roots handler implementation
24 ///
25 /// # Examples
26 ///
27 /// ```rust,no_run
28 /// use turbomcp_client::Client;
29 /// use turbomcp_client::handlers::{RootsHandler, HandlerResult};
30 /// use turbomcp_protocol::types::Root;
31 /// use turbomcp_transport::stdio::StdioTransport;
32 /// use async_trait::async_trait;
33 /// use std::sync::Arc;
34 ///
35 /// #[derive(Debug)]
36 /// struct MyRootsHandler {
37 /// project_dir: String,
38 /// }
39 ///
40 /// #[async_trait]
41 /// impl RootsHandler for MyRootsHandler {
42 /// async fn handle_roots_request(&self) -> HandlerResult<Vec<Root>> {
43 /// Ok(vec![Root {
44 /// uri: format!("file://{}", self.project_dir).into(),
45 /// name: Some("My Project".to_string()),
46 /// }])
47 /// }
48 /// }
49 ///
50 /// let mut client = Client::new(StdioTransport::new());
51 /// client.set_roots_handler(Arc::new(MyRootsHandler {
52 /// project_dir: "/home/user/projects/myproject".to_string(),
53 /// }));
54 /// ```
55 pub fn set_roots_handler(&self, handler: Arc<dyn RootsHandler>) {
56 self.inner
57 .handlers
58 .lock()
59 .expect("handlers mutex poisoned")
60 .set_roots_handler(handler);
61 }
62
63 /// Register an elicitation handler for processing user input requests
64 ///
65 /// Elicitation handlers are called when the server needs user input during
66 /// operations. The handler should present the request to the user and
67 /// collect their response according to the provided schema.
68 ///
69 /// # Arguments
70 ///
71 /// * `handler` - The elicitation handler implementation
72 ///
73 /// # Examples
74 ///
75 /// ```rust,no_run
76 /// use turbomcp_client::Client;
77 /// use turbomcp_client::handlers::{ElicitationHandler, ElicitationRequest, ElicitationResponse, ElicitationAction, HandlerResult};
78 /// use turbomcp_transport::stdio::StdioTransport;
79 /// use async_trait::async_trait;
80 /// use std::sync::Arc;
81 /// use serde_json::json;
82 ///
83 /// #[derive(Debug)]
84 /// struct MyElicitationHandler;
85 ///
86 /// #[async_trait]
87 /// impl ElicitationHandler for MyElicitationHandler {
88 /// async fn handle_elicitation(
89 /// &self,
90 /// request: ElicitationRequest,
91 /// ) -> HandlerResult<ElicitationResponse> {
92 /// let mut content = std::collections::HashMap::new();
93 /// content.insert("user_input".to_string(), json!("example"));
94 /// Ok(ElicitationResponse::accept(content))
95 /// }
96 /// }
97 ///
98 /// let mut client = Client::new(StdioTransport::new());
99 /// client.set_elicitation_handler(Arc::new(MyElicitationHandler));
100 /// ```
101 pub fn set_elicitation_handler(&self, handler: Arc<dyn ElicitationHandler>) {
102 self.inner
103 .handlers
104 .lock()
105 .expect("handlers mutex poisoned")
106 .set_elicitation_handler(handler);
107 }
108
109 /// Register a progress handler for processing operation progress updates
110 ///
111 /// Progress handlers receive notifications about long-running server operations.
112 /// Display progress bars, status updates, or other
113 /// feedback to users.
114 ///
115 /// # Arguments
116 ///
117 /// * `handler` - The progress handler implementation
118 ///
119 /// # Examples
120 ///
121 /// ```rust,no_run
122 /// use turbomcp_client::Client;
123 /// use turbomcp_client::handlers::{ProgressHandler, ProgressNotification, HandlerResult};
124 /// use turbomcp_transport::stdio::StdioTransport;
125 /// use async_trait::async_trait;
126 /// use std::sync::Arc;
127 ///
128 /// #[derive(Debug)]
129 /// struct MyProgressHandler;
130 ///
131 /// #[async_trait]
132 /// impl ProgressHandler for MyProgressHandler {
133 /// async fn handle_progress(&self, notification: ProgressNotification) -> HandlerResult<()> {
134 /// println!("Progress: {:?}", notification);
135 /// Ok(())
136 /// }
137 /// }
138 ///
139 /// let mut client = Client::new(StdioTransport::new());
140 /// client.set_progress_handler(Arc::new(MyProgressHandler));
141 /// ```
142 pub fn set_progress_handler(&self, handler: Arc<dyn ProgressHandler>) {
143 self.inner
144 .handlers
145 .lock()
146 .expect("handlers mutex poisoned")
147 .set_progress_handler(handler);
148 }
149
150 /// Register a log handler for processing server log messages
151 ///
152 /// Log handlers receive log messages from the server and can route them
153 /// to the client's logging system. This is useful for debugging and
154 /// maintaining a unified log across client and server.
155 ///
156 /// # Arguments
157 ///
158 /// * `handler` - The log handler implementation
159 ///
160 /// # Examples
161 ///
162 /// ```rust,no_run
163 /// use turbomcp_client::Client;
164 /// use turbomcp_client::handlers::{LogHandler, LoggingNotification, HandlerResult};
165 /// use turbomcp_transport::stdio::StdioTransport;
166 /// use async_trait::async_trait;
167 /// use std::sync::Arc;
168 ///
169 /// #[derive(Debug)]
170 /// struct MyLogHandler;
171 ///
172 /// #[async_trait]
173 /// impl LogHandler for MyLogHandler {
174 /// async fn handle_log(&self, log: LoggingNotification) -> HandlerResult<()> {
175 /// println!("Server log: {}", log.data);
176 /// Ok(())
177 /// }
178 /// }
179 ///
180 /// let mut client = Client::new(StdioTransport::new());
181 /// client.set_log_handler(Arc::new(MyLogHandler));
182 /// ```
183 pub fn set_log_handler(&self, handler: Arc<dyn LogHandler>) {
184 self.inner
185 .handlers
186 .lock()
187 .expect("handlers mutex poisoned")
188 .set_log_handler(handler);
189 }
190
191 /// Register a resource update handler for processing resource change notifications
192 ///
193 /// Resource update handlers receive notifications when subscribed resources
194 /// change on the server. Supports reactive updates to cached data or
195 /// UI refreshes when server-side resources change.
196 ///
197 /// # Arguments
198 ///
199 /// * `handler` - The resource update handler implementation
200 ///
201 /// # Examples
202 ///
203 /// ```rust,no_run
204 /// use turbomcp_client::Client;
205 /// use turbomcp_client::handlers::{ResourceUpdateHandler, ResourceUpdatedNotification, HandlerResult};
206 /// use turbomcp_transport::stdio::StdioTransport;
207 /// use async_trait::async_trait;
208 /// use std::sync::Arc;
209 ///
210 /// #[derive(Debug)]
211 /// struct MyResourceUpdateHandler;
212 ///
213 /// #[async_trait]
214 /// impl ResourceUpdateHandler for MyResourceUpdateHandler {
215 /// async fn handle_resource_update(
216 /// &self,
217 /// notification: ResourceUpdatedNotification,
218 /// ) -> HandlerResult<()> {
219 /// println!("Resource updated: {}", notification.uri);
220 /// Ok(())
221 /// }
222 /// }
223 ///
224 /// let mut client = Client::new(StdioTransport::new());
225 /// client.set_resource_update_handler(Arc::new(MyResourceUpdateHandler));
226 /// ```
227 pub fn set_resource_update_handler(&self, handler: Arc<dyn ResourceUpdateHandler>) {
228 self.inner
229 .handlers
230 .lock()
231 .expect("handlers mutex poisoned")
232 .set_resource_update_handler(handler);
233 }
234
235 /// Register a cancellation handler for processing cancellation notifications
236 ///
237 /// Per MCP 2025-06-18 specification, cancellation notifications can be sent
238 /// by the server to indicate that a previously-issued request is being cancelled.
239 ///
240 /// # Arguments
241 ///
242 /// * `handler` - The cancellation handler implementation
243 pub fn set_cancellation_handler(&self, handler: Arc<dyn CancellationHandler>) {
244 self.inner
245 .handlers
246 .lock()
247 .expect("handlers mutex poisoned")
248 .set_cancellation_handler(handler);
249 }
250
251 /// Register a resource list changed handler
252 ///
253 /// This handler is called when the server's available resource list changes.
254 ///
255 /// # Arguments
256 ///
257 /// * `handler` - The resource list changed handler implementation
258 pub fn set_resource_list_changed_handler(&self, handler: Arc<dyn ResourceListChangedHandler>) {
259 self.inner
260 .handlers
261 .lock()
262 .expect("handlers mutex poisoned")
263 .set_resource_list_changed_handler(handler);
264 }
265
266 /// Register a prompt list changed handler
267 ///
268 /// This handler is called when the server's available prompt list changes.
269 ///
270 /// # Arguments
271 ///
272 /// * `handler` - The prompt list changed handler implementation
273 pub fn set_prompt_list_changed_handler(&self, handler: Arc<dyn PromptListChangedHandler>) {
274 self.inner
275 .handlers
276 .lock()
277 .expect("handlers mutex poisoned")
278 .set_prompt_list_changed_handler(handler);
279 }
280
281 /// Register a tool list changed handler
282 ///
283 /// This handler is called when the server's available tool list changes.
284 ///
285 /// # Arguments
286 ///
287 /// * `handler` - The tool list changed handler implementation
288 pub fn set_tool_list_changed_handler(&self, handler: Arc<dyn ToolListChangedHandler>) {
289 self.inner
290 .handlers
291 .lock()
292 .expect("handlers mutex poisoned")
293 .set_tool_list_changed_handler(handler);
294 }
295
296 /// Check if a roots handler is registered
297 pub fn has_roots_handler(&self) -> bool {
298 self.inner
299 .handlers
300 .lock()
301 .expect("handlers mutex poisoned")
302 .has_roots_handler()
303 }
304
305 /// Check if an elicitation handler is registered
306 pub fn has_elicitation_handler(&self) -> bool {
307 self.inner
308 .handlers
309 .lock()
310 .expect("handlers mutex poisoned")
311 .has_elicitation_handler()
312 }
313
314 /// Check if a progress handler is registered
315 pub fn has_progress_handler(&self) -> bool {
316 self.inner
317 .handlers
318 .lock()
319 .expect("handlers mutex poisoned")
320 .has_progress_handler()
321 }
322
323 /// Check if a log handler is registered
324 pub fn has_log_handler(&self) -> bool {
325 self.inner
326 .handlers
327 .lock()
328 .expect("handlers mutex poisoned")
329 .has_log_handler()
330 }
331
332 /// Check if a resource update handler is registered
333 pub fn has_resource_update_handler(&self) -> bool {
334 self.inner
335 .handlers
336 .lock()
337 .expect("handlers mutex poisoned")
338 .has_resource_update_handler()
339 }
340}