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, 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 std::sync::Arc;
33 /// use std::future::Future;
34 /// use std::pin::Pin;
35 ///
36 /// #[derive(Debug)]
37 /// struct MyRootsHandler {
38 /// project_dir: String,
39 /// }
40 ///
41 /// impl RootsHandler for MyRootsHandler {
42 /// fn handle_roots_request(&self) -> Pin<Box<dyn Future<Output = HandlerResult<Vec<Root>>> + Send + '_>> {
43 /// Box::pin(async move {
44 /// Ok(vec![Root {
45 /// uri: format!("file://{}", self.project_dir).into(),
46 /// name: Some("My Project".to_string()),
47 /// }])
48 /// })
49 /// }
50 /// }
51 ///
52 /// let mut client = Client::new(StdioTransport::new());
53 /// client.set_roots_handler(Arc::new(MyRootsHandler {
54 /// project_dir: "/home/user/projects/myproject".to_string(),
55 /// }));
56 /// ```
57 pub fn set_roots_handler(&self, handler: Arc<dyn RootsHandler>) {
58 self.inner.handlers.lock().set_roots_handler(handler);
59 }
60
61 /// Register an elicitation handler for processing user input requests
62 ///
63 /// Elicitation handlers are called when the server needs user input during
64 /// operations. The handler should present the request to the user and
65 /// collect their response according to the provided schema.
66 ///
67 /// # Arguments
68 ///
69 /// * `handler` - The elicitation handler implementation
70 ///
71 /// # Examples
72 ///
73 /// ```rust,no_run
74 /// use turbomcp_client::Client;
75 /// use turbomcp_client::handlers::{ElicitationHandler, ElicitationRequest, ElicitationResponse, ElicitationAction, HandlerResult};
76 /// use turbomcp_transport::stdio::StdioTransport;
77 /// use std::sync::Arc;
78 /// use serde_json::json;
79 /// use std::future::Future;
80 /// use std::pin::Pin;
81 ///
82 /// #[derive(Debug)]
83 /// struct MyElicitationHandler;
84 ///
85 /// impl ElicitationHandler for MyElicitationHandler {
86 /// fn handle_elicitation(
87 /// &self,
88 /// request: ElicitationRequest,
89 /// ) -> Pin<Box<dyn Future<Output = HandlerResult<ElicitationResponse>> + Send + '_>> {
90 /// Box::pin(async move {
91 /// let mut content = std::collections::HashMap::new();
92 /// content.insert("user_input".to_string(), json!("example"));
93 /// Ok(ElicitationResponse::accept(content))
94 /// })
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.handlers.lock().set_elicitation_handler(handler);
103 }
104
105 /// Register a log handler for processing server log messages
106 ///
107 /// Log handlers receive log messages from the server and can route them
108 /// to the client's logging system. This is useful for debugging and
109 /// maintaining a unified log across client and server.
110 ///
111 /// # Arguments
112 ///
113 /// * `handler` - The log handler implementation
114 ///
115 /// # Examples
116 ///
117 /// ```rust,no_run
118 /// use turbomcp_client::Client;
119 /// use turbomcp_client::handlers::{LogHandler, LoggingNotification, HandlerResult};
120 /// use turbomcp_transport::stdio::StdioTransport;
121 /// use std::sync::Arc;
122 /// use std::future::Future;
123 /// use std::pin::Pin;
124 ///
125 /// #[derive(Debug)]
126 /// struct MyLogHandler;
127 ///
128 /// impl LogHandler for MyLogHandler {
129 /// fn handle_log(&self, log: LoggingNotification) -> Pin<Box<dyn Future<Output = HandlerResult<()>> + Send + '_>> {
130 /// Box::pin(async move {
131 /// println!("Server log: {}", log.data);
132 /// Ok(())
133 /// })
134 /// }
135 /// }
136 ///
137 /// let mut client = Client::new(StdioTransport::new());
138 /// client.set_log_handler(Arc::new(MyLogHandler));
139 /// ```
140 pub fn set_log_handler(&self, handler: Arc<dyn LogHandler>) {
141 self.inner.handlers.lock().set_log_handler(handler);
142 }
143
144 /// Register a resource update handler for processing resource change notifications
145 ///
146 /// Resource update handlers receive notifications when subscribed resources
147 /// change on the server. Supports reactive updates to cached data or
148 /// UI refreshes when server-side resources change.
149 ///
150 /// # Arguments
151 ///
152 /// * `handler` - The resource update handler implementation
153 ///
154 /// # Examples
155 ///
156 /// ```rust,no_run
157 /// use turbomcp_client::Client;
158 /// use turbomcp_client::handlers::{ResourceUpdateHandler, ResourceUpdatedNotification, HandlerResult};
159 /// use turbomcp_transport::stdio::StdioTransport;
160 /// use std::sync::Arc;
161 /// use std::future::Future;
162 /// use std::pin::Pin;
163 ///
164 /// #[derive(Debug)]
165 /// struct MyResourceUpdateHandler;
166 ///
167 /// impl ResourceUpdateHandler for MyResourceUpdateHandler {
168 /// fn handle_resource_update(
169 /// &self,
170 /// notification: ResourceUpdatedNotification,
171 /// ) -> Pin<Box<dyn Future<Output = HandlerResult<()>> + Send + '_>> {
172 /// Box::pin(async move {
173 /// println!("Resource updated: {}", notification.uri);
174 /// Ok(())
175 /// })
176 /// }
177 /// }
178 ///
179 /// let mut client = Client::new(StdioTransport::new());
180 /// client.set_resource_update_handler(Arc::new(MyResourceUpdateHandler));
181 /// ```
182 pub fn set_resource_update_handler(&self, handler: Arc<dyn ResourceUpdateHandler>) {
183 self.inner
184 .handlers
185 .lock()
186 .set_resource_update_handler(handler);
187 }
188
189 /// Register a cancellation handler for processing cancellation notifications
190 ///
191 /// Per MCP 2025-06-18 specification, cancellation notifications can be sent
192 /// by the server to indicate that a previously-issued request is being cancelled.
193 ///
194 /// # Arguments
195 ///
196 /// * `handler` - The cancellation handler implementation
197 pub fn set_cancellation_handler(&self, handler: Arc<dyn CancellationHandler>) {
198 self.inner.handlers.lock().set_cancellation_handler(handler);
199 }
200
201 /// Register a resource list changed handler
202 ///
203 /// This handler is called when the server's available resource list changes.
204 ///
205 /// # Arguments
206 ///
207 /// * `handler` - The resource list changed handler implementation
208 pub fn set_resource_list_changed_handler(&self, handler: Arc<dyn ResourceListChangedHandler>) {
209 self.inner
210 .handlers
211 .lock()
212 .set_resource_list_changed_handler(handler);
213 }
214
215 /// Register a prompt list changed handler
216 ///
217 /// This handler is called when the server's available prompt list changes.
218 ///
219 /// # Arguments
220 ///
221 /// * `handler` - The prompt list changed handler implementation
222 pub fn set_prompt_list_changed_handler(&self, handler: Arc<dyn PromptListChangedHandler>) {
223 self.inner
224 .handlers
225 .lock()
226 .set_prompt_list_changed_handler(handler);
227 }
228
229 /// Register a tool list changed handler
230 ///
231 /// This handler is called when the server's available tool list changes.
232 ///
233 /// # Arguments
234 ///
235 /// * `handler` - The tool list changed handler implementation
236 pub fn set_tool_list_changed_handler(&self, handler: Arc<dyn ToolListChangedHandler>) {
237 self.inner
238 .handlers
239 .lock()
240 .set_tool_list_changed_handler(handler);
241 }
242
243 /// Check if a roots handler is registered
244 #[must_use]
245 pub fn has_roots_handler(&self) -> bool {
246 self.inner.handlers.lock().has_roots_handler()
247 }
248
249 /// Check if an elicitation handler is registered
250 #[must_use]
251 pub fn has_elicitation_handler(&self) -> bool {
252 self.inner.handlers.lock().has_elicitation_handler()
253 }
254
255 /// Check if a log handler is registered
256 #[must_use]
257 pub fn has_log_handler(&self) -> bool {
258 self.inner.handlers.lock().has_log_handler()
259 }
260
261 /// Check if a resource update handler is registered
262 #[must_use]
263 pub fn has_resource_update_handler(&self) -> bool {
264 self.inner.handlers.lock().has_resource_update_handler()
265 }
266}