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