1use super::*;
2
3impl ServerHandler for ProxyHandler {
4 fn get_info(&self) -> ServerInfo {
5 self.discovery.info()
6 }
7
8 async fn initialize(
10 &self,
11 request: InitializeRequestParams,
12 context: RequestContext<RoleServer>,
13 ) -> Result<InitializeResult, ErrorData> {
14 context.peer.set_peer_info(request.clone());
15
16 if let Some(session) = &self.per_session {
17 session.notify_slot.set(context.peer.clone());
19 self.ensure_connected().await?;
20 info!(
21 "[initialize] Per-session backend ready - MCP ID: {}",
22 self.mcp_id
23 );
24 }
25
26 let mut info = self.get_info();
27 info.protocol_version =
28 negotiate_protocol_version(&request.protocol_version, info.protocol_version);
29 Ok(info)
30 }
31
32 #[tracing::instrument(skip(self, request, context), fields(
33 mcp_id = %self.mcp_id,
34 request = ?request,
35 ))]
36 async fn list_tools(
37 &self,
38 request: Option<PaginatedRequestParams>,
39 context: RequestContext<RoleServer>,
40 ) -> Result<ListToolsResult, ErrorData> {
41 if context.ct.is_cancelled() {
42 return Err(ErrorData::internal_error(
43 "Request cancelled".to_string(),
44 None,
45 ));
46 }
47 let is_first_page = request
48 .as_ref()
49 .and_then(|params| params.cursor.as_ref())
50 .is_none();
51
52 match self.capabilities().tools {
53 Some(_) => {
54 let result = match self
55 .forward_backend(
56 &context,
57 |peer| async move { peer.list_tools(request).await },
58 )
59 .await
60 {
61 Ok(result) => result,
62 Err(error) if context.ct.is_cancelled() => return Err(error),
63 Err(error) => {
64 if let Some(cached) = self.discovery.tools() {
65 warn!(%error, "real tools/list failed; returning cached tools snapshot");
66 return Ok(self.filter_tools(cached));
67 }
68 return Err(error);
69 }
70 };
71 if is_first_page && result.next_cursor.is_none() {
72 self.update_cached_tools(result.clone());
73 }
74 let result = self.filter_tools(result);
75
76 info!(
77 "[list_tools] Tool list results - MCP ID: {}, number of tools: {}{}",
78 self.mcp_id,
79 result.tools.len(),
80 if self.tool_filter.is_enabled() {
81 " (filtered)"
82 } else {
83 ""
84 }
85 );
86
87 debug!(
88 "Proxying list_tools response with {} tools",
89 result.tools.len()
90 );
91 Ok(result)
92 }
93 None => {
94 warn!("Server doesn't support tools capability");
95 Ok(ListToolsResult::default())
96 }
97 }
98 }
99
100 #[tracing::instrument(skip(self, request, context), fields(
101 mcp_id = %self.mcp_id,
102 tool_name = %request.name,
103 tool_arguments = ?request.arguments,
104 ))]
105 async fn call_tool(
106 &self,
107 mut request: CallToolRequestParams,
108 context: RequestContext<RoleServer>,
109 ) -> Result<CallToolResponse, ErrorData> {
110 let request_id = REQUEST_COUNTER.fetch_add(1, Ordering::Relaxed);
111 let start = Instant::now();
112 let tool_name = request.name.clone();
113
114 info!(
115 "[call_tool:{}] Start - Tool: {}, MCP ID: {}",
116 request_id, tool_name, self.mcp_id
117 );
118
119 if !self.tool_filter.is_allowed(&tool_name) {
120 info!(
121 "[call_tool:{}] Tool is filtered - MCP ID: {}, Tool: {}",
122 request_id, self.mcp_id, tool_name
123 );
124 return Ok(CallToolResult::error(vec![ContentBlock::text(format!(
125 "Tool '{tool_name}' is not allowed by filter configuration"
126 ))])
127 .into());
128 }
129
130 if self.capabilities().tools.is_none() {
131 error!(
132 "[call_tool:{}] The server does not support tools capability - MCP ID: {}",
133 request_id, self.mcp_id
134 );
135 return Ok(CallToolResult::error(vec![ContentBlock::text(
136 "Server doesn't support tools capability",
137 )])
138 .into());
139 }
140
141 merge_context_meta_into_params(&mut request, &context.meta);
142 let _progress_guard = self.maybe_progress_guard(&context);
143
144 info!(
145 "[call_tool:{}] Send request to backend... - Tool: {}, Elapsed time: {}ms",
146 request_id,
147 tool_name,
148 start.elapsed().as_millis()
149 );
150
151 let call_result = self
152 .forward_backend_with_heartbeat(
153 &context,
154 request_id,
155 tool_name.as_ref(),
156 |peer| async move { peer.call_tool_once(request).await },
157 )
158 .await;
159
160 let result =
161 self.finish_call_tool(request_id, tool_name.as_ref(), start.elapsed(), call_result);
162
163 if let CallToolResponse::Task(ref task_result) = result
168 && self.isolation == BackendIsolation::Shared
169 {
170 self.upstream_peers
171 .register_task(task_result.task.task_id.clone(), context.peer.clone());
172 }
173
174 info!(
175 "[call_tool:{}] Completed - Tool: {}, total time taken: {}ms",
176 request_id,
177 tool_name,
178 start.elapsed().as_millis()
179 );
180 Ok(result)
181 }
182
183 async fn list_resources(
184 &self,
185 request: Option<PaginatedRequestParams>,
186 context: RequestContext<RoleServer>,
187 ) -> Result<rmcp::model::ListResourcesResult, ErrorData> {
188 match self.capabilities().resources {
189 Some(_) => {
190 let result = self
191 .forward_backend(&context, |peer| async move {
192 peer.list_resources(request).await
193 })
194 .await?;
195 info!(
196 "[list_resources] Resource list results - MCP ID: {}, resource quantity: {}",
197 self.mcp_id,
198 result.resources.len()
199 );
200 debug!("Proxying list_resources response");
201 Ok(result)
202 }
203 None => {
204 warn!("Server doesn't support resources capability");
205 Ok(rmcp::model::ListResourcesResult::default())
206 }
207 }
208 }
209
210 async fn read_resource(
211 &self,
212 mut request: rmcp::model::ReadResourceRequestParams,
213 context: RequestContext<RoleServer>,
214 ) -> Result<ReadResourceResponse, ErrorData> {
215 match self.capabilities().resources {
216 Some(_) => {
217 merge_context_meta_into_params(&mut request, &context.meta);
218 let _progress_guard = self.maybe_progress_guard(&context);
219 let uri = request.uri.clone();
220 let result = self
221 .forward_backend(&context, |peer| async move {
222 peer.read_resource_once(request).await
223 })
224 .await?;
225 info!(
226 "[read_resource] Resource read result - MCP ID: {}, URI: {}",
227 self.mcp_id, uri
228 );
229 debug!("Proxying read_resource response for {}", uri);
230 Ok(result)
231 }
232 None => {
233 error!("Server doesn't support resources capability");
234 Ok(rmcp::model::ReadResourceResult::new(vec![]).into())
235 }
236 }
237 }
238
239 async fn list_resource_templates(
240 &self,
241 request: Option<PaginatedRequestParams>,
242 context: RequestContext<RoleServer>,
243 ) -> Result<rmcp::model::ListResourceTemplatesResult, ErrorData> {
244 match self.capabilities().resources {
245 Some(_) => {
246 let result = self
247 .forward_backend(&context, |peer| async move {
248 peer.list_resource_templates(request).await
249 })
250 .await?;
251 debug!("Proxying list_resource_templates response");
252 Ok(result)
253 }
254 None => {
255 warn!("Server doesn't support resources capability");
256 Ok(rmcp::model::ListResourceTemplatesResult::default())
257 }
258 }
259 }
260
261 async fn list_prompts(
262 &self,
263 request: Option<PaginatedRequestParams>,
264 context: RequestContext<RoleServer>,
265 ) -> Result<rmcp::model::ListPromptsResult, ErrorData> {
266 match self.capabilities().prompts {
267 Some(_) => {
268 let result =
269 self.forward_backend(&context, |peer| async move {
270 peer.list_prompts(request).await
271 })
272 .await?;
273 debug!("Proxying list_prompts response");
274 Ok(result)
275 }
276 None => {
277 warn!("Server doesn't support prompts capability");
278 Ok(rmcp::model::ListPromptsResult::default())
279 }
280 }
281 }
282
283 async fn get_prompt(
284 &self,
285 mut request: rmcp::model::GetPromptRequestParams,
286 context: RequestContext<RoleServer>,
287 ) -> Result<GetPromptResponse, ErrorData> {
288 match self.capabilities().prompts {
289 Some(_) => {
290 merge_context_meta_into_params(&mut request, &context.meta);
291 let _progress_guard = self.maybe_progress_guard(&context);
292 let result = self
293 .forward_backend(&context, |peer| async move {
294 peer.get_prompt_once(request).await
295 })
296 .await?;
297 debug!("Proxying get_prompt response");
298 Ok(result)
299 }
300 None => {
301 warn!("Server doesn't support prompts capability");
302 let messages = Vec::new();
303 Ok(rmcp::model::GetPromptResult::new(messages).into())
304 }
305 }
306 }
307
308 async fn complete(
309 &self,
310 request: rmcp::model::CompleteRequestParams,
311 context: RequestContext<RoleServer>,
312 ) -> Result<rmcp::model::CompleteResult, ErrorData> {
313 let result = self
314 .forward_backend(&context, |peer| async move { peer.complete(request).await })
315 .await?;
316 debug!("Proxying complete response");
317 Ok(result)
318 }
319
320 #[allow(deprecated)]
321 async fn subscribe(
322 &self,
323 request: SubscribeRequestParams,
324 context: RequestContext<RoleServer>,
325 ) -> Result<(), ErrorData> {
326 match self
327 .capabilities()
328 .resources
329 .as_ref()
330 .and_then(|r| r.subscribe)
331 {
332 Some(true) => {
333 self.forward_backend(
334 &context,
335 |peer| async move { peer.subscribe(request).await },
336 )
337 .await
338 }
339 _ => Err(ErrorData::method_not_found::<SubscribeRequestMethod>()),
340 }
341 }
342
343 #[allow(deprecated)]
344 async fn unsubscribe(
345 &self,
346 request: UnsubscribeRequestParams,
347 context: RequestContext<RoleServer>,
348 ) -> Result<(), ErrorData> {
349 match self
350 .capabilities()
351 .resources
352 .as_ref()
353 .and_then(|r| r.subscribe)
354 {
355 Some(true) => {
356 self.forward_backend(
357 &context,
358 |peer| async move { peer.unsubscribe(request).await },
359 )
360 .await
361 }
362 _ => Err(ErrorData::method_not_found::<UnsubscribeRequestMethod>()),
363 }
364 }
365
366 #[allow(deprecated)]
367 async fn set_level(
368 &self,
369 request: rmcp::model::SetLevelRequestParams,
370 context: RequestContext<RoleServer>,
371 ) -> Result<(), ErrorData> {
372 if self.capabilities().logging.is_none() {
373 return Err(ErrorData::method_not_found::<SetLevelRequestMethod>());
374 }
375 self.forward_backend(
376 &context,
377 |peer| async move { peer.set_level(request).await },
378 )
379 .await
380 }
381
382 async fn get_task(
383 &self,
384 request: GetTaskParams,
385 context: RequestContext<RoleServer>,
386 ) -> Result<GetTaskResult, ErrorData> {
387 if !self.capabilities().supports_tasks() {
388 return Err(ErrorData::method_not_found::<rmcp::model::GetTaskMethod>());
389 }
390 self.forward_backend(&context, |peer| async move {
391 let result = peer
392 .send_request(ClientRequest::GetTaskRequest(GetTaskRequest::new(request)))
393 .await?;
394 match result {
395 ServerResult::GetTaskResult(r) => Ok(r),
396 _ => Err(ServiceError::UnexpectedResponse),
397 }
398 })
399 .await
400 }
401
402 async fn update_task(
403 &self,
404 request: rmcp::model::UpdateTaskParams,
405 context: RequestContext<RoleServer>,
406 ) -> Result<(), ErrorData> {
407 if !self.capabilities().supports_tasks() {
408 return Err(ErrorData::method_not_found::<rmcp::model::UpdateTaskMethod>());
409 }
410 self.forward_backend(&context, |peer| async move { peer.update_task(request).await })
411 .await
412 }
413
414 async fn cancel_task(
415 &self,
416 request: CancelTaskParams,
417 context: RequestContext<RoleServer>,
418 ) -> Result<(), ErrorData> {
419 if !self.capabilities().supports_tasks() {
420 return Err(ErrorData::method_not_found::<rmcp::model::CancelTaskMethod>());
421 }
422 let task_id = request.task_id.clone();
423 self.forward_backend(&context, |peer| async move { peer.cancel_task(request).await })
424 .await?;
425 self.upstream_peers.unregister_task(&task_id);
426 Ok(())
427 }
428
429 async fn on_initialized(&self, context: NotificationContext<RoleServer>) {
430 if let Some(session) = &self.per_session {
431 session.notify_slot.set(context.peer.clone());
433 if let Err(err) = self.ensure_connected().await {
434 error!(
435 "[on_initialized] Per-session backend ensure failed - MCP ID: {}, err: {:?}",
436 self.mcp_id, err
437 );
438 }
439 return;
440 }
441
442 let id = self.upstream_peers.register(context.peer.clone());
443 info!(
444 "[on_initialized] Registered upstream peer {} - MCP ID: {}, peers: {}",
445 id,
446 self.mcp_id,
447 self.upstream_peers.len()
448 );
449 }
450
451 async fn on_progress(
452 &self,
453 notification: rmcp::model::ProgressNotificationParam,
454 _context: NotificationContext<RoleServer>,
455 ) {
456 let peer = {
457 let inner_guard = self.peer.load();
458 let inner = match inner_guard.as_ref() {
459 Some(inner) => inner,
460 None => {
461 error!(
462 "Backend connection is not available, cannot forward progress notification"
463 );
464 return;
465 }
466 };
467 if inner.peer.is_transport_closed() {
468 error!("Backend transport is closed, cannot forward progress notification");
469 return;
470 }
471 inner.peer.clone()
472 };
473
474 match peer.notify_progress(notification).await {
475 Ok(_) => {
476 debug!("Proxying progress notification");
477 }
478 Err(err) => {
479 error!("Error notifying progress: {:?}", err);
480 }
481 }
482 }
483
484 async fn on_cancelled(
485 &self,
486 notification: rmcp::model::CancelledNotificationParam,
487 _context: NotificationContext<RoleServer>,
488 ) {
489 let peer = {
490 let inner_guard = self.peer.load();
491 let inner = match inner_guard.as_ref() {
492 Some(inner) => inner,
493 None => {
494 error!(
495 "Backend connection is not available, cannot forward cancelled notification"
496 );
497 return;
498 }
499 };
500 if inner.peer.is_transport_closed() {
501 error!("Backend transport is closed, cannot forward cancelled notification");
502 return;
503 }
504 inner.peer.clone()
505 };
506
507 match peer.notify_cancelled(notification).await {
508 Ok(_) => {
509 debug!("Proxying cancelled notification");
510 }
511 Err(err) => {
512 error!("Error notifying cancelled: {:?}", err);
513 }
514 }
515 }
516
517 async fn on_custom_request(
527 &self,
528 request: rmcp::model::CustomRequest,
529 _context: RequestContext<RoleServer>,
530 ) -> Result<rmcp::model::CustomResult, ErrorData> {
531 let method = request.method.clone();
532 let params = request.params.unwrap_or_default();
533 let value = self
534 .forward_to_backend(&method, params)
535 .await
536 .map_err(|error| {
537 ErrorData::internal_error(format!("{method} backend error: {error}"), None)
538 })?;
539 Ok(rmcp::model::CustomResult::new(value))
540 }
541}