1pub mod progress;
2use std::sync::Arc;
3
4use crate::{
5 error::ErrorData as McpError,
6 model::*,
7 service::{NotificationContext, RequestContext, RoleClient, Service, ServiceRole},
8};
9
10impl<H: ClientHandler> Service<RoleClient> for H {
11 async fn handle_request(
12 &self,
13 request: <RoleClient as ServiceRole>::PeerReq,
14 context: RequestContext<RoleClient>,
15 ) -> Result<<RoleClient as ServiceRole>::Resp, McpError> {
16 match request {
17 ServerRequest::PingRequest(_) => self.ping(context).await.map(ClientResult::empty),
18 ServerRequest::CreateMessageRequest(request) => self
19 .create_message(request.params, context)
20 .await
21 .map(Box::new)
22 .map(ClientResult::CreateMessageResult),
23 ServerRequest::ListRootsRequest(_) => self
24 .list_roots(context)
25 .await
26 .map(ClientResult::ListRootsResult),
27 ServerRequest::CreateElicitationRequest(request) => self
28 .create_elicitation(request.params, context)
29 .await
30 .map(ClientResult::CreateElicitationResult),
31 ServerRequest::CustomRequest(request) => self
32 .on_custom_request(request, context)
33 .await
34 .map(ClientResult::CustomResult),
35 }
36 }
37
38 async fn handle_notification(
39 &self,
40 notification: <RoleClient as ServiceRole>::PeerNot,
41 context: NotificationContext<RoleClient>,
42 ) -> Result<(), McpError> {
43 match notification {
44 ServerNotification::CancelledNotification(notification) => {
45 self.on_cancelled(notification.params, context).await
46 }
47 ServerNotification::ProgressNotification(notification) => {
48 self.on_progress(notification.params, context).await
49 }
50 ServerNotification::LoggingMessageNotification(notification) => {
51 self.on_logging_message(notification.params, context).await
52 }
53 ServerNotification::ResourceUpdatedNotification(notification) => {
54 self.on_resource_updated(notification.params, context).await
55 }
56 ServerNotification::ResourceListChangedNotification(_notification_no_param) => {
57 self.on_resource_list_changed(context).await
58 }
59 ServerNotification::ToolListChangedNotification(_notification_no_param) => {
60 self.on_tool_list_changed(context).await
61 }
62 ServerNotification::PromptListChangedNotification(_notification_no_param) => {
63 self.on_prompt_list_changed(context).await
64 }
65 ServerNotification::ElicitationCompletionNotification(notification) => {
66 self.on_url_elicitation_notification_complete(notification.params, context)
67 .await
68 }
69 ServerNotification::CustomNotification(notification) => {
70 self.on_custom_notification(notification, context).await
71 }
72 };
73 Ok(())
74 }
75
76 fn get_info(&self) -> <RoleClient as ServiceRole>::Info {
77 self.get_info()
78 }
79}
80
81#[allow(unused_variables)]
82pub trait ClientHandler: Sized + Send + Sync + 'static {
83 fn ping(
84 &self,
85 context: RequestContext<RoleClient>,
86 ) -> impl Future<Output = Result<(), McpError>> + Send + '_ {
87 std::future::ready(Ok(()))
88 }
89
90 fn create_message(
91 &self,
92 params: CreateMessageRequestParams,
93 context: RequestContext<RoleClient>,
94 ) -> impl Future<Output = Result<CreateMessageResult, McpError>> + Send + '_ {
95 std::future::ready(Err(
96 McpError::method_not_found::<CreateMessageRequestMethod>(),
97 ))
98 }
99
100 fn list_roots(
101 &self,
102 context: RequestContext<RoleClient>,
103 ) -> impl Future<Output = Result<ListRootsResult, McpError>> + Send + '_ {
104 std::future::ready(Ok(ListRootsResult::default()))
105 }
106
107 fn create_elicitation(
162 &self,
163 request: CreateElicitationRequestParams,
164 context: RequestContext<RoleClient>,
165 ) -> impl Future<Output = Result<CreateElicitationResult, McpError>> + Send + '_ {
166 let _ = (request, context);
168 std::future::ready(Ok(CreateElicitationResult {
169 action: ElicitationAction::Decline,
170 content: None,
171 }))
172 }
173
174 fn on_custom_request(
175 &self,
176 request: CustomRequest,
177 context: RequestContext<RoleClient>,
178 ) -> impl Future<Output = Result<CustomResult, McpError>> + Send + '_ {
179 let CustomRequest { method, .. } = request;
180 let _ = context;
181 std::future::ready(Err(McpError::new(
182 ErrorCode::METHOD_NOT_FOUND,
183 method,
184 None,
185 )))
186 }
187
188 fn on_cancelled(
189 &self,
190 params: CancelledNotificationParam,
191 context: NotificationContext<RoleClient>,
192 ) -> impl Future<Output = ()> + Send + '_ {
193 std::future::ready(())
194 }
195 fn on_progress(
196 &self,
197 params: ProgressNotificationParam,
198 context: NotificationContext<RoleClient>,
199 ) -> impl Future<Output = ()> + Send + '_ {
200 std::future::ready(())
201 }
202 fn on_logging_message(
203 &self,
204 params: LoggingMessageNotificationParam,
205 context: NotificationContext<RoleClient>,
206 ) -> impl Future<Output = ()> + Send + '_ {
207 std::future::ready(())
208 }
209 fn on_resource_updated(
210 &self,
211 params: ResourceUpdatedNotificationParam,
212 context: NotificationContext<RoleClient>,
213 ) -> impl Future<Output = ()> + Send + '_ {
214 std::future::ready(())
215 }
216 fn on_resource_list_changed(
217 &self,
218 context: NotificationContext<RoleClient>,
219 ) -> impl Future<Output = ()> + Send + '_ {
220 std::future::ready(())
221 }
222 fn on_tool_list_changed(
223 &self,
224 context: NotificationContext<RoleClient>,
225 ) -> impl Future<Output = ()> + Send + '_ {
226 std::future::ready(())
227 }
228 fn on_prompt_list_changed(
229 &self,
230 context: NotificationContext<RoleClient>,
231 ) -> impl Future<Output = ()> + Send + '_ {
232 std::future::ready(())
233 }
234
235 fn on_url_elicitation_notification_complete(
236 &self,
237 params: ElicitationResponseNotificationParam,
238 context: NotificationContext<RoleClient>,
239 ) -> impl Future<Output = ()> + Send + '_ {
240 std::future::ready(())
241 }
242 fn on_custom_notification(
243 &self,
244 notification: CustomNotification,
245 context: NotificationContext<RoleClient>,
246 ) -> impl Future<Output = ()> + Send + '_ {
247 let _ = (notification, context);
248 std::future::ready(())
249 }
250
251 fn get_info(&self) -> ClientInfo {
252 ClientInfo::default()
253 }
254}
255
256impl ClientHandler for () {}
258
259impl ClientHandler for ClientInfo {
261 fn get_info(&self) -> ClientInfo {
262 self.clone()
263 }
264}
265
266macro_rules! impl_client_handler_for_wrapper {
267 ($wrapper:ident) => {
268 impl<T: ClientHandler> ClientHandler for $wrapper<T> {
269 fn ping(
270 &self,
271 context: RequestContext<RoleClient>,
272 ) -> impl Future<Output = Result<(), McpError>> + Send + '_ {
273 (**self).ping(context)
274 }
275
276 fn create_message(
277 &self,
278 params: CreateMessageRequestParams,
279 context: RequestContext<RoleClient>,
280 ) -> impl Future<Output = Result<CreateMessageResult, McpError>> + Send + '_ {
281 (**self).create_message(params, context)
282 }
283
284 fn list_roots(
285 &self,
286 context: RequestContext<RoleClient>,
287 ) -> impl Future<Output = Result<ListRootsResult, McpError>> + Send + '_ {
288 (**self).list_roots(context)
289 }
290
291 fn create_elicitation(
292 &self,
293 request: CreateElicitationRequestParams,
294 context: RequestContext<RoleClient>,
295 ) -> impl Future<Output = Result<CreateElicitationResult, McpError>> + Send + '_ {
296 (**self).create_elicitation(request, context)
297 }
298
299 fn on_custom_request(
300 &self,
301 request: CustomRequest,
302 context: RequestContext<RoleClient>,
303 ) -> impl Future<Output = Result<CustomResult, McpError>> + Send + '_ {
304 (**self).on_custom_request(request, context)
305 }
306
307 fn on_cancelled(
308 &self,
309 params: CancelledNotificationParam,
310 context: NotificationContext<RoleClient>,
311 ) -> impl Future<Output = ()> + Send + '_ {
312 (**self).on_cancelled(params, context)
313 }
314
315 fn on_progress(
316 &self,
317 params: ProgressNotificationParam,
318 context: NotificationContext<RoleClient>,
319 ) -> impl Future<Output = ()> + Send + '_ {
320 (**self).on_progress(params, context)
321 }
322
323 fn on_logging_message(
324 &self,
325 params: LoggingMessageNotificationParam,
326 context: NotificationContext<RoleClient>,
327 ) -> impl Future<Output = ()> + Send + '_ {
328 (**self).on_logging_message(params, context)
329 }
330
331 fn on_resource_updated(
332 &self,
333 params: ResourceUpdatedNotificationParam,
334 context: NotificationContext<RoleClient>,
335 ) -> impl Future<Output = ()> + Send + '_ {
336 (**self).on_resource_updated(params, context)
337 }
338
339 fn on_resource_list_changed(
340 &self,
341 context: NotificationContext<RoleClient>,
342 ) -> impl Future<Output = ()> + Send + '_ {
343 (**self).on_resource_list_changed(context)
344 }
345
346 fn on_tool_list_changed(
347 &self,
348 context: NotificationContext<RoleClient>,
349 ) -> impl Future<Output = ()> + Send + '_ {
350 (**self).on_tool_list_changed(context)
351 }
352
353 fn on_prompt_list_changed(
354 &self,
355 context: NotificationContext<RoleClient>,
356 ) -> impl Future<Output = ()> + Send + '_ {
357 (**self).on_prompt_list_changed(context)
358 }
359
360 fn on_custom_notification(
361 &self,
362 notification: CustomNotification,
363 context: NotificationContext<RoleClient>,
364 ) -> impl Future<Output = ()> + Send + '_ {
365 (**self).on_custom_notification(notification, context)
366 }
367
368 fn get_info(&self) -> ClientInfo {
369 (**self).get_info()
370 }
371 }
372 };
373}
374
375impl_client_handler_for_wrapper!(Box);
376impl_client_handler_for_wrapper!(Arc);