1use crate::builder::{NotRegistered, Registered, Server};
36use crate::context::{CancellationToken, Context, Peer};
37use crate::handler::{PromptHandler, ResourceHandler, ServerHandler, ToolHandler};
38use mcpkit_core::capability::{ClientCapabilities, ServerCapabilities};
39use mcpkit_core::error::McpError;
40use mcpkit_core::protocol::{Message, Notification, ProgressToken, Request, Response};
41use mcpkit_core::protocol_version::ProtocolVersion;
42use mcpkit_core::types::CallToolResult;
43use mcpkit_transport::Transport;
44use std::collections::HashMap;
45use std::sync::Arc;
46use std::sync::RwLock;
47use std::sync::atomic::{AtomicBool, Ordering};
48
49pub struct ServerState {
51 pub client_caps: RwLock<ClientCapabilities>,
53 pub server_caps: ServerCapabilities,
55 pub initialized: AtomicBool,
57 pub cancellations: RwLock<HashMap<String, CancellationToken>>,
59 pub negotiated_version: RwLock<Option<ProtocolVersion>>,
64}
65
66impl ServerState {
67 #[must_use]
69 pub fn new(server_caps: ServerCapabilities) -> Self {
70 Self {
71 client_caps: RwLock::new(ClientCapabilities::default()),
72 server_caps,
73 initialized: AtomicBool::new(false),
74 cancellations: RwLock::new(HashMap::new()),
75 negotiated_version: RwLock::new(None),
76 }
77 }
78
79 pub fn protocol_version(&self) -> Option<ProtocolVersion> {
93 self.negotiated_version.read().ok().and_then(|guard| *guard)
94 }
95
96 pub fn set_protocol_version(&self, version: ProtocolVersion) {
100 if let Ok(mut guard) = self.negotiated_version.write() {
101 *guard = Some(version);
102 }
103 }
104
105 pub fn client_caps(&self) -> ClientCapabilities {
109 self.client_caps
110 .read()
111 .map(|guard| guard.clone())
112 .unwrap_or_default()
113 }
114
115 pub fn set_client_caps(&self, caps: ClientCapabilities) {
119 if let Ok(mut guard) = self.client_caps.write() {
120 *guard = caps;
121 }
122 }
123
124 pub fn is_initialized(&self) -> bool {
126 self.initialized.load(Ordering::Acquire)
127 }
128
129 pub fn set_initialized(&self) {
131 self.initialized.store(true, Ordering::Release);
132 }
133
134 pub fn register_cancellation(&self, request_id: &str, token: CancellationToken) {
136 if let Ok(mut cancellations) = self.cancellations.write() {
137 cancellations.insert(request_id.to_string(), token);
138 }
139 }
140
141 pub fn cancel_request(&self, request_id: &str) {
143 if let Ok(cancellations) = self.cancellations.read() {
144 if let Some(token) = cancellations.get(request_id) {
145 token.cancel();
146 }
147 }
148 }
149
150 pub fn remove_cancellation(&self, request_id: &str) {
152 if let Ok(mut cancellations) = self.cancellations.write() {
153 cancellations.remove(request_id);
154 }
155 }
156}
157
158pub struct TransportPeer<T: Transport> {
160 transport: Arc<T>,
161}
162
163impl<T: Transport> TransportPeer<T> {
164 pub const fn new(transport: Arc<T>) -> Self {
166 Self { transport }
167 }
168}
169
170impl<T: Transport + 'static> Peer for TransportPeer<T>
171where
172 T::Error: Into<McpError>,
173{
174 fn notify(
175 &self,
176 notification: Notification,
177 ) -> std::pin::Pin<Box<dyn std::future::Future<Output = Result<(), McpError>> + Send + '_>>
178 {
179 let transport = self.transport.clone();
180 Box::pin(async move {
181 transport
182 .send(Message::Notification(notification))
183 .await
184 .map_err(std::convert::Into::into)
185 })
186 }
187}
188
189#[derive(Debug, Clone)]
191pub struct RuntimeConfig {
192 pub auto_initialized: bool,
194 pub max_concurrent_requests: usize,
196}
197
198impl Default for RuntimeConfig {
199 fn default() -> Self {
200 Self {
201 auto_initialized: true,
202 max_concurrent_requests: 100,
203 }
204 }
205}
206
207pub struct ServerRuntime<S, Tr>
212where
213 Tr: Transport,
214{
215 server: S,
216 transport: Arc<Tr>,
217 state: Arc<ServerState>,
218 config: RuntimeConfig,
220}
221
222impl<S, Tr> ServerRuntime<S, Tr>
223where
224 S: RequestRouter + Send + Sync,
225 Tr: Transport + 'static,
226 Tr::Error: Into<McpError>,
227{
228 pub const fn state(&self) -> &Arc<ServerState> {
230 &self.state
231 }
232
233 pub async fn run(&self) -> Result<(), McpError> {
244 use futures::future::{Either, select};
245 use futures::stream::{FuturesUnordered, StreamExt};
246
247 let max = self.config.max_concurrent_requests.max(1);
248 let mut in_flight = FuturesUnordered::new();
249
250 let outcome = loop {
251 let message = if in_flight.is_empty() {
255 match self.transport.recv().await {
256 Ok(opt) => opt,
257 Err(e) => break Err(e.into()),
258 }
259 } else if in_flight.len() < max {
260 let recv = std::pin::pin!(self.transport.recv());
262 match select(recv, in_flight.next()).await {
263 Either::Left((Ok(opt), _)) => opt,
264 Either::Left((Err(e), _)) => break Err(e.into()),
265 Either::Right((_, _)) => continue,
268 }
269 } else {
270 in_flight.next().await;
273 continue;
274 };
275
276 match message {
277 Some(Message::Request(request)) => {
278 in_flight.push(self.handle_request_isolated(request));
279 }
280 Some(Message::Notification(notification)) => {
281 if let Err(e) = self.handle_notification(notification).await {
282 tracing::error!(error = %e, "Error handling notification");
283 }
284 }
285 Some(Message::Response(_)) => {
286 tracing::warn!("Received unexpected response message");
287 }
288 None => {
289 tracing::info!("Connection closed");
290 break Ok(());
291 }
292 }
293 };
294
295 while in_flight.next().await.is_some() {}
298
299 if let Err(ref err) = outcome {
300 tracing::error!(error = %err, "Transport error");
301 }
302 outcome
303 }
304
305 async fn compute_response(&self, request: &Request) -> Result<serde_json::Value, McpError> {
307 match request.method.as_ref() {
308 "initialize" => self.handle_initialize(request).await,
309 _ if !self.state.is_initialized() => {
310 Err(McpError::invalid_request("Server not initialized"))
311 }
312 _ => self.route_request(request).await,
313 }
314 }
315
316 async fn handle_request_isolated(&self, request: Request) {
322 use futures::FutureExt;
323 use std::panic::AssertUnwindSafe;
324
325 let id = request.id.clone();
326 tracing::debug!(method = %request.method, id = %id, "Handling request");
327
328 let computed = AssertUnwindSafe(self.compute_response(&request))
329 .catch_unwind()
330 .await;
331
332 let response_msg = match computed {
333 Ok(Ok(result)) => Response::success(id, result),
334 Ok(Err(e)) => Response::error(id, e.into()),
335 Err(panic) => {
336 let detail = panic_message(&*panic);
337 tracing::error!(method = %request.method, panic = %detail, "Handler panicked");
338 Response::error(
339 id,
340 McpError::internal(format!("handler panicked: {detail}")).into(),
341 )
342 }
343 };
344
345 if let Err(e) = self.transport.send(Message::Response(response_msg)).await {
346 let err: McpError = e.into();
347 tracing::error!(error = %err, "Failed to send response");
348 }
349 }
350
351 async fn handle_initialize(&self, request: &Request) -> Result<serde_json::Value, McpError> {
358 if self.state.is_initialized() {
359 return Err(McpError::invalid_request("Already initialized"));
360 }
361
362 let params = request
364 .params
365 .as_ref()
366 .ok_or_else(|| McpError::invalid_params("initialize", "missing params"))?;
367
368 let requested_version_str = params
370 .get("protocolVersion")
371 .and_then(|v| v.as_str())
372 .unwrap_or("");
373
374 let negotiated_version =
376 ProtocolVersion::negotiate(requested_version_str, ProtocolVersion::ALL)
377 .unwrap_or(ProtocolVersion::LATEST);
378
379 if requested_version_str == negotiated_version.as_str() {
381 tracing::debug!(
382 version = %negotiated_version,
383 "Protocol version negotiated successfully"
384 );
385 } else {
386 tracing::info!(
387 requested = %requested_version_str,
388 negotiated = %negotiated_version,
389 supported = ?ProtocolVersion::ALL.iter().map(ProtocolVersion::as_str).collect::<Vec<_>>(),
390 "Protocol version negotiation: client requested different version"
391 );
392 }
393
394 self.state.set_protocol_version(negotiated_version);
396
397 if let Some(caps) = params.get("capabilities") {
399 if let Ok(client_caps) = serde_json::from_value::<ClientCapabilities>(caps.clone()) {
400 self.state.set_client_caps(client_caps);
401 }
402 }
403
404 let result = serde_json::json!({
406 "protocolVersion": negotiated_version.as_str(),
407 "serverInfo": self.server.server_info(),
408 "capabilities": self.state.server_caps
409 });
410
411 self.state.set_initialized();
412
413 Ok(result)
414 }
415
416 async fn route_request(&self, request: &Request) -> Result<serde_json::Value, McpError> {
418 let method = request.method.as_ref();
419 let params = request.params.as_ref();
420
421 let progress_token = extract_progress_token(params);
423
424 let peer = TransportPeer::new(self.transport.clone());
426 let client_caps = self.state.client_caps();
427 let protocol_version = self
428 .state
429 .protocol_version()
430 .unwrap_or(ProtocolVersion::LATEST);
431 let ctx = Context::new(
432 &request.id,
433 progress_token.as_ref(),
434 &client_caps,
435 &self.state.server_caps,
436 protocol_version,
437 &peer,
438 );
439
440 self.server.route(method, params, &ctx).await
442 }
443
444 async fn handle_notification(&self, notification: Notification) -> Result<(), McpError> {
446 let method = notification.method.as_ref();
447
448 tracing::debug!(method = %method, "Handling notification");
449
450 match method {
451 "notifications/initialized" => {
452 tracing::info!("Client sent initialized notification");
453 Ok(())
454 }
455 "notifications/cancelled" => {
456 if let Some(params) = ¬ification.params {
457 if let Some(request_id) = params.get("requestId").and_then(|v| v.as_str()) {
458 self.state.cancel_request(request_id);
459 }
460 }
461 Ok(())
462 }
463 _ => {
464 tracing::debug!(method = %method, "Ignoring unknown notification");
465 Ok(())
466 }
467 }
468 }
469}
470
471impl<H, T, R, P, K, Tr> ServerRuntime<Server<H, T, R, P, K>, Tr>
473where
474 H: ServerHandler + Send + Sync,
475 T: Send + Sync,
476 R: Send + Sync,
477 P: Send + Sync,
478 K: Send + Sync,
479 Tr: Transport + 'static,
480 Tr::Error: Into<McpError>,
481{
482 pub fn new(server: Server<H, T, R, P, K>, transport: Tr) -> Self {
484 let caps = server.capabilities().clone();
485 Self {
486 server,
487 transport: Arc::new(transport),
488 state: Arc::new(ServerState::new(caps)),
489 config: RuntimeConfig::default(),
490 }
491 }
492
493 pub fn with_config(
495 server: Server<H, T, R, P, K>,
496 transport: Tr,
497 config: RuntimeConfig,
498 ) -> Self {
499 let caps = server.capabilities().clone();
500 Self {
501 server,
502 transport: Arc::new(transport),
503 state: Arc::new(ServerState::new(caps)),
504 config,
505 }
506 }
507}
508
509#[allow(async_fn_in_trait)]
514pub trait RequestRouter: Send + Sync {
515 fn server_info(&self) -> mcpkit_core::capability::ServerInfo;
517
518 async fn route(
520 &self,
521 method: &str,
522 params: Option<&serde_json::Value>,
523 ctx: &Context<'_>,
524 ) -> Result<serde_json::Value, McpError>;
525}
526
527impl<H, T, R, P, K> Server<H, T, R, P, K>
529where
530 H: ServerHandler + Send + Sync + 'static,
531 T: Send + Sync + 'static,
532 R: Send + Sync + 'static,
533 P: Send + Sync + 'static,
534 K: Send + Sync + 'static,
535 Self: RequestRouter,
536{
537 pub async fn serve<Tr>(self, transport: Tr) -> Result<(), McpError>
539 where
540 Tr: Transport + 'static,
541 Tr::Error: Into<McpError>,
542 {
543 let runtime = ServerRuntime::new(self, transport);
544 runtime.run().await
545 }
546}
547
548async fn route_tools<TH: ToolHandler + Send + Sync>(
556 handler: &TH,
557 method: &str,
558 params: Option<&serde_json::Value>,
559 ctx: &Context<'_>,
560) -> Option<Result<serde_json::Value, McpError>> {
561 match method {
562 "tools/list" => {
563 tracing::debug!("Listing available tools");
564 let result = handler.list_tools(ctx).await;
565 match &result {
566 Ok(tools) => tracing::debug!(count = tools.len(), "Listed tools"),
567 Err(e) => tracing::warn!(error = %e, "Failed to list tools"),
568 }
569 Some(result.map(|tools| serde_json::json!({ "tools": tools })))
570 }
571 "tools/call" => {
572 let result = async {
573 let params = params.ok_or_else(|| {
574 McpError::invalid_params("tools/call", "missing params")
575 })?;
576 let name = params.get("name")
577 .and_then(|v| v.as_str())
578 .ok_or_else(|| McpError::invalid_params("tools/call", "missing tool name"))?;
579 let args = params.get("arguments")
580 .cloned()
581 .unwrap_or_else(|| serde_json::json!({}));
582
583 tracing::info!(tool = %name, "Calling tool");
584 let start = std::time::Instant::now();
585 let output = handler.call_tool(name, args, ctx).await;
586 let duration = start.elapsed();
587
588 match &output {
589 Ok(_) => tracing::info!(tool = %name, duration_ms = duration.as_millis(), "Tool call completed"),
590 Err(e) => tracing::warn!(tool = %name, duration_ms = duration.as_millis(), error = %e, "Tool call failed"),
591 }
592
593 let output = output?;
594 let result: CallToolResult = output.into();
595 Ok(serde_json::to_value(result).unwrap_or_else(|_| serde_json::json!({})))
596 }.await;
597 Some(result)
598 }
599 _ => None,
600 }
601}
602
603async fn route_resources<RH: ResourceHandler + Send + Sync>(
604 handler: &RH,
605 method: &str,
606 params: Option<&serde_json::Value>,
607 ctx: &Context<'_>,
608) -> Option<Result<serde_json::Value, McpError>> {
609 match method {
610 "resources/list" => {
611 tracing::debug!("Listing available resources");
612 let result = handler.list_resources(ctx).await;
613 match &result {
614 Ok(resources) => tracing::debug!(count = resources.len(), "Listed resources"),
615 Err(e) => tracing::warn!(error = %e, "Failed to list resources"),
616 }
617 Some(result.map(|resources| serde_json::json!({ "resources": resources })))
618 }
619 "resources/templates/list" => {
620 tracing::debug!("Listing available resource templates");
621 let result = handler.list_resource_templates(ctx).await;
622 match &result {
623 Ok(templates) => {
624 tracing::debug!(count = templates.len(), "Listed resource templates");
625 }
626 Err(e) => tracing::warn!(error = %e, "Failed to list resource templates"),
627 }
628 Some(result.map(|templates| serde_json::json!({ "resourceTemplates": templates })))
629 }
630 "resources/read" => {
631 let result = async {
632 let params = params.ok_or_else(|| {
633 McpError::invalid_params("resources/read", "missing params")
634 })?;
635 let uri = params.get("uri")
636 .and_then(|v| v.as_str())
637 .ok_or_else(|| McpError::invalid_params("resources/read", "missing uri"))?;
638
639 tracing::info!(uri = %uri, "Reading resource");
640 let start = std::time::Instant::now();
641 let contents = handler.read_resource(uri, ctx).await;
642 let duration = start.elapsed();
643
644 match &contents {
645 Ok(_) => tracing::info!(uri = %uri, duration_ms = duration.as_millis(), "Resource read completed"),
646 Err(e) => tracing::warn!(uri = %uri, duration_ms = duration.as_millis(), error = %e, "Resource read failed"),
647 }
648
649 let contents = contents?;
650 Ok(serde_json::json!({ "contents": contents }))
651 }.await;
652 Some(result)
653 }
654 _ => None,
655 }
656}
657
658async fn route_prompts<PH: PromptHandler + Send + Sync>(
659 handler: &PH,
660 method: &str,
661 params: Option<&serde_json::Value>,
662 ctx: &Context<'_>,
663) -> Option<Result<serde_json::Value, McpError>> {
664 match method {
665 "prompts/list" => {
666 tracing::debug!("Listing available prompts");
667 let result = handler.list_prompts(ctx).await;
668 match &result {
669 Ok(prompts) => tracing::debug!(count = prompts.len(), "Listed prompts"),
670 Err(e) => tracing::warn!(error = %e, "Failed to list prompts"),
671 }
672 Some(result.map(|prompts| serde_json::json!({ "prompts": prompts })))
673 }
674 "prompts/get" => {
675 let result = async {
676 let params = params.ok_or_else(|| {
677 McpError::invalid_params("prompts/get", "missing params")
678 })?;
679 let name = params.get("name")
680 .and_then(|v| v.as_str())
681 .ok_or_else(|| McpError::invalid_params("prompts/get", "missing prompt name"))?;
682 let args = params.get("arguments")
683 .and_then(|v| v.as_object())
684 .cloned();
685
686 tracing::info!(prompt = %name, "Getting prompt");
687 let start = std::time::Instant::now();
688 let prompt_result = handler.get_prompt(name, args, ctx).await;
689 let duration = start.elapsed();
690
691 match &prompt_result {
692 Ok(_) => tracing::info!(prompt = %name, duration_ms = duration.as_millis(), "Prompt retrieval completed"),
693 Err(e) => tracing::warn!(prompt = %name, duration_ms = duration.as_millis(), error = %e, "Prompt retrieval failed"),
694 }
695
696 let result = prompt_result?;
697 Ok(serde_json::to_value(result).unwrap_or_else(|_| serde_json::json!({})))
698 }.await;
699 Some(result)
700 }
701 _ => None,
702 }
703}
704
705macro_rules! impl_request_router {
710 (base; $($bounds:tt)*) => {
712 impl<H $($bounds)*> RequestRouter for Server<H, NotRegistered, NotRegistered, NotRegistered, NotRegistered>
713 where
714 H: ServerHandler + Send + Sync,
715 {
716 fn server_info(&self) -> mcpkit_core::capability::ServerInfo {
717 self.handler().server_info()
718 }
719
720 async fn route(
721 &self,
722 method: &str,
723 _params: Option<&serde_json::Value>,
724 _ctx: &Context<'_>,
725 ) -> Result<serde_json::Value, McpError> {
726 match method {
727 "ping" => Ok(serde_json::json!({})),
728 _ => Err(McpError::method_not_found(method)),
729 }
730 }
731 }
732 };
733
734 (tools; $($bounds:tt)*) => {
736 impl<H, TH $($bounds)*> RequestRouter for Server<H, Registered<TH>, NotRegistered, NotRegistered, NotRegistered>
737 where
738 H: ServerHandler + Send + Sync,
739 TH: ToolHandler + Send + Sync,
740 {
741 fn server_info(&self) -> mcpkit_core::capability::ServerInfo {
742 self.handler().server_info()
743 }
744
745 async fn route(
746 &self,
747 method: &str,
748 params: Option<&serde_json::Value>,
749 ctx: &Context<'_>,
750 ) -> Result<serde_json::Value, McpError> {
751 if method == "ping" {
752 return Ok(serde_json::json!({}));
753 }
754 if let Some(result) = route_tools(self.tool_handler(), method, params, ctx).await {
755 return result;
756 }
757 Err(McpError::method_not_found(method))
758 }
759 }
760 };
761
762 (resources; $($bounds:tt)*) => {
764 impl<H, RH $($bounds)*> RequestRouter for Server<H, NotRegistered, Registered<RH>, NotRegistered, NotRegistered>
765 where
766 H: ServerHandler + Send + Sync,
767 RH: ResourceHandler + Send + Sync,
768 {
769 fn server_info(&self) -> mcpkit_core::capability::ServerInfo {
770 self.handler().server_info()
771 }
772
773 async fn route(
774 &self,
775 method: &str,
776 params: Option<&serde_json::Value>,
777 ctx: &Context<'_>,
778 ) -> Result<serde_json::Value, McpError> {
779 if method == "ping" {
780 return Ok(serde_json::json!({}));
781 }
782 if let Some(result) = route_resources(self.resource_handler(), method, params, ctx).await {
783 return result;
784 }
785 Err(McpError::method_not_found(method))
786 }
787 }
788 };
789
790 (prompts; $($bounds:tt)*) => {
792 impl<H, PH $($bounds)*> RequestRouter for Server<H, NotRegistered, NotRegistered, Registered<PH>, NotRegistered>
793 where
794 H: ServerHandler + Send + Sync,
795 PH: PromptHandler + Send + Sync,
796 {
797 fn server_info(&self) -> mcpkit_core::capability::ServerInfo {
798 self.handler().server_info()
799 }
800
801 async fn route(
802 &self,
803 method: &str,
804 params: Option<&serde_json::Value>,
805 ctx: &Context<'_>,
806 ) -> Result<serde_json::Value, McpError> {
807 if method == "ping" {
808 return Ok(serde_json::json!({}));
809 }
810 if let Some(result) = route_prompts(self.prompt_handler(), method, params, ctx).await {
811 return result;
812 }
813 Err(McpError::method_not_found(method))
814 }
815 }
816 };
817
818 (tools_resources; $($bounds:tt)*) => {
820 impl<H, TH, RH $($bounds)*> RequestRouter for Server<H, Registered<TH>, Registered<RH>, NotRegistered, NotRegistered>
821 where
822 H: ServerHandler + Send + Sync,
823 TH: ToolHandler + Send + Sync,
824 RH: ResourceHandler + Send + Sync,
825 {
826 fn server_info(&self) -> mcpkit_core::capability::ServerInfo {
827 self.handler().server_info()
828 }
829
830 async fn route(
831 &self,
832 method: &str,
833 params: Option<&serde_json::Value>,
834 ctx: &Context<'_>,
835 ) -> Result<serde_json::Value, McpError> {
836 if method == "ping" {
837 return Ok(serde_json::json!({}));
838 }
839 if let Some(result) = route_tools(self.tool_handler(), method, params, ctx).await {
840 return result;
841 }
842 if let Some(result) = route_resources(self.resource_handler(), method, params, ctx).await {
843 return result;
844 }
845 Err(McpError::method_not_found(method))
846 }
847 }
848 };
849
850 (tools_prompts; $($bounds:tt)*) => {
852 impl<H, TH, PH $($bounds)*> RequestRouter for Server<H, Registered<TH>, NotRegistered, Registered<PH>, NotRegistered>
853 where
854 H: ServerHandler + Send + Sync,
855 TH: ToolHandler + Send + Sync,
856 PH: PromptHandler + Send + Sync,
857 {
858 fn server_info(&self) -> mcpkit_core::capability::ServerInfo {
859 self.handler().server_info()
860 }
861
862 async fn route(
863 &self,
864 method: &str,
865 params: Option<&serde_json::Value>,
866 ctx: &Context<'_>,
867 ) -> Result<serde_json::Value, McpError> {
868 if method == "ping" {
869 return Ok(serde_json::json!({}));
870 }
871 if let Some(result) = route_tools(self.tool_handler(), method, params, ctx).await {
872 return result;
873 }
874 if let Some(result) = route_prompts(self.prompt_handler(), method, params, ctx).await {
875 return result;
876 }
877 Err(McpError::method_not_found(method))
878 }
879 }
880 };
881
882 (resources_prompts; $($bounds:tt)*) => {
884 impl<H, RH, PH $($bounds)*> RequestRouter for Server<H, NotRegistered, Registered<RH>, Registered<PH>, NotRegistered>
885 where
886 H: ServerHandler + Send + Sync,
887 RH: ResourceHandler + Send + Sync,
888 PH: PromptHandler + Send + Sync,
889 {
890 fn server_info(&self) -> mcpkit_core::capability::ServerInfo {
891 self.handler().server_info()
892 }
893
894 async fn route(
895 &self,
896 method: &str,
897 params: Option<&serde_json::Value>,
898 ctx: &Context<'_>,
899 ) -> Result<serde_json::Value, McpError> {
900 if method == "ping" {
901 return Ok(serde_json::json!({}));
902 }
903 if let Some(result) = route_resources(self.resource_handler(), method, params, ctx).await {
904 return result;
905 }
906 if let Some(result) = route_prompts(self.prompt_handler(), method, params, ctx).await {
907 return result;
908 }
909 Err(McpError::method_not_found(method))
910 }
911 }
912 };
913
914 (tools_resources_prompts; $($bounds:tt)*) => {
916 impl<H, TH, RH, PH $($bounds)*> RequestRouter for Server<H, Registered<TH>, Registered<RH>, Registered<PH>, NotRegistered>
917 where
918 H: ServerHandler + Send + Sync,
919 TH: ToolHandler + Send + Sync,
920 RH: ResourceHandler + Send + Sync,
921 PH: PromptHandler + Send + Sync,
922 {
923 fn server_info(&self) -> mcpkit_core::capability::ServerInfo {
924 self.handler().server_info()
925 }
926
927 async fn route(
928 &self,
929 method: &str,
930 params: Option<&serde_json::Value>,
931 ctx: &Context<'_>,
932 ) -> Result<serde_json::Value, McpError> {
933 if method == "ping" {
934 return Ok(serde_json::json!({}));
935 }
936 if let Some(result) = route_tools(self.tool_handler(), method, params, ctx).await {
937 return result;
938 }
939 if let Some(result) = route_resources(self.resource_handler(), method, params, ctx).await {
940 return result;
941 }
942 if let Some(result) = route_prompts(self.prompt_handler(), method, params, ctx).await {
943 return result;
944 }
945 Err(McpError::method_not_found(method))
946 }
947 }
948 };
949}
950
951impl_request_router!(base;);
953impl_request_router!(tools;);
954impl_request_router!(resources;);
955impl_request_router!(prompts;);
956impl_request_router!(tools_resources;);
957impl_request_router!(tools_prompts;);
958impl_request_router!(resources_prompts;);
959impl_request_router!(tools_resources_prompts;);
960
961fn panic_message(panic: &(dyn std::any::Any + Send)) -> String {
983 if let Some(s) = panic.downcast_ref::<&str>() {
984 (*s).to_string()
985 } else if let Some(s) = panic.downcast_ref::<String>() {
986 s.clone()
987 } else {
988 "unknown panic".to_string()
989 }
990}
991
992fn extract_progress_token(params: Option<&serde_json::Value>) -> Option<ProgressToken> {
993 params?
994 .get("_meta")?
995 .get("progressToken")
996 .and_then(|v| serde_json::from_value(v.clone()).ok())
997}
998
999#[cfg(test)]
1000mod tests {
1001 use super::*;
1002
1003 use mcpkit_core::capability::ServerInfo;
1004 use mcpkit_core::protocol::RequestId;
1005 use mcpkit_transport::MemoryTransport;
1006 use std::time::Duration;
1007 use tokio::sync::Notify;
1008 use tokio::time::timeout;
1009
1010 struct PanicRouter;
1012
1013 impl RequestRouter for PanicRouter {
1014 fn server_info(&self) -> ServerInfo {
1015 ServerInfo::new("panic-test", "0.0.0")
1016 }
1017 async fn route(
1018 &self,
1019 method: &str,
1020 _params: Option<&serde_json::Value>,
1021 _ctx: &Context<'_>,
1022 ) -> Result<serde_json::Value, McpError> {
1023 match method {
1024 "panic" => panic!("boom in handler"),
1025 "ok" => Ok(serde_json::json!("ok")),
1026 other => Err(McpError::method_not_found(other)),
1027 }
1028 }
1029 }
1030
1031 struct CoordRouter {
1034 started: Arc<Notify>,
1035 release: Arc<Notify>,
1036 }
1037
1038 impl RequestRouter for CoordRouter {
1039 fn server_info(&self) -> ServerInfo {
1040 ServerInfo::new("coord-test", "0.0.0")
1041 }
1042 async fn route(
1043 &self,
1044 method: &str,
1045 _params: Option<&serde_json::Value>,
1046 _ctx: &Context<'_>,
1047 ) -> Result<serde_json::Value, McpError> {
1048 match method {
1049 "blocker" => {
1050 self.started.notify_one();
1051 self.release.notified().await;
1052 Ok(serde_json::json!("blocked-done"))
1053 }
1054 "fast" => Ok(serde_json::json!("fast-done")),
1055 other => Err(McpError::method_not_found(other)),
1056 }
1057 }
1058 }
1059
1060 fn req(method: &'static str, id: u64) -> Message {
1061 Message::Request(Request::new(method, id))
1062 }
1063
1064 async fn next_response(transport: &MemoryTransport) -> Response {
1065 let msg = timeout(Duration::from_secs(2), transport.recv())
1066 .await
1067 .expect("no response (connection died?)")
1068 .expect("recv ok")
1069 .expect("some message");
1070 match msg {
1071 Message::Response(r) => r,
1072 other => panic!("expected response, got {other:?}"),
1073 }
1074 }
1075
1076 #[tokio::test]
1077 async fn panic_in_handler_returns_internal_error_and_keeps_connection() {
1078 let (client, server) = MemoryTransport::pair();
1079 let state = Arc::new(ServerState::new(ServerCapabilities::default()));
1080 state.set_initialized();
1081 let runtime = ServerRuntime {
1082 server: PanicRouter,
1083 transport: Arc::new(server),
1084 state,
1085 config: RuntimeConfig::default(),
1086 };
1087 let handle = tokio::spawn(async move { runtime.run().await });
1088
1089 client.send(req("panic", 1)).await.expect("send");
1091 let resp = next_response(&client).await;
1092 assert_eq!(resp.id, RequestId::Number(1));
1093 let err = resp.error.expect("expected error response");
1094 assert!(
1095 err.message.contains("panicked"),
1096 "unexpected error message: {}",
1097 err.message
1098 );
1099
1100 client.send(req("ok", 2)).await.expect("send");
1102 let resp = next_response(&client).await;
1103 assert_eq!(resp.id, RequestId::Number(2));
1104 assert!(
1105 resp.result.is_some(),
1106 "expected success after a prior panic"
1107 );
1108
1109 drop(client);
1110 let _ = timeout(Duration::from_secs(2), handle).await;
1111 }
1112
1113 #[tokio::test]
1114 async fn requests_are_processed_concurrently() {
1115 let (client, server) = MemoryTransport::pair();
1116 let started = Arc::new(Notify::new());
1117 let release = Arc::new(Notify::new());
1118 let state = Arc::new(ServerState::new(ServerCapabilities::default()));
1119 state.set_initialized();
1120 let runtime = ServerRuntime {
1121 server: CoordRouter {
1122 started: started.clone(),
1123 release: release.clone(),
1124 },
1125 transport: Arc::new(server),
1126 state,
1127 config: RuntimeConfig::default(),
1128 };
1129 let handle = tokio::spawn(async move { runtime.run().await });
1130
1131 client.send(req("blocker", 1)).await.expect("send");
1132 client.send(req("fast", 2)).await.expect("send");
1133
1134 timeout(Duration::from_secs(2), started.notified())
1136 .await
1137 .expect("blocker never started");
1138
1139 let resp = next_response(&client).await;
1143 assert_eq!(
1144 resp.id,
1145 RequestId::Number(2),
1146 "fast request should finish first"
1147 );
1148
1149 release.notify_one();
1151 let resp = next_response(&client).await;
1152 assert_eq!(resp.id, RequestId::Number(1));
1153
1154 drop(client);
1155 let _ = timeout(Duration::from_secs(2), handle).await;
1156 }
1157
1158 #[tokio::test]
1159 async fn max_concurrent_requests_limits_in_flight() {
1160 let (client, server) = MemoryTransport::pair();
1163 let started = Arc::new(Notify::new());
1164 let release = Arc::new(Notify::new());
1165 let state = Arc::new(ServerState::new(ServerCapabilities::default()));
1166 state.set_initialized();
1167 let runtime = ServerRuntime {
1168 server: CoordRouter {
1169 started: started.clone(),
1170 release: release.clone(),
1171 },
1172 transport: Arc::new(server),
1173 state,
1174 config: RuntimeConfig {
1175 auto_initialized: true,
1176 max_concurrent_requests: 1,
1177 },
1178 };
1179 let handle = tokio::spawn(async move { runtime.run().await });
1180
1181 client.send(req("blocker", 1)).await.expect("send");
1182 client.send(req("fast", 2)).await.expect("send");
1183
1184 timeout(Duration::from_secs(2), started.notified())
1185 .await
1186 .expect("blocker never started");
1187
1188 let early = timeout(Duration::from_millis(200), client.recv()).await;
1191 assert!(
1192 early.is_err(),
1193 "fast request was processed despite max_concurrent_requests = 1"
1194 );
1195
1196 release.notify_one();
1198 assert_eq!(next_response(&client).await.id, RequestId::Number(1));
1199 assert_eq!(next_response(&client).await.id, RequestId::Number(2));
1200
1201 drop(client);
1202 let _ = timeout(Duration::from_secs(2), handle).await;
1203 }
1204
1205 #[test]
1206 fn test_server_state_initialization() {
1207 let state = ServerState::new(ServerCapabilities::default());
1208 assert!(!state.is_initialized());
1209
1210 state.set_initialized();
1211 assert!(state.is_initialized());
1212 }
1213
1214 #[test]
1215 fn test_cancellation_management() {
1216 let state = ServerState::new(ServerCapabilities::default());
1217 let token = CancellationToken::new();
1218
1219 state.register_cancellation("req-1", token.clone());
1220 assert!(!token.is_cancelled());
1221
1222 state.cancel_request("req-1");
1223 assert!(token.is_cancelled());
1224
1225 state.remove_cancellation("req-1");
1226 }
1227
1228 #[test]
1229 fn test_runtime_config_default() {
1230 let config = RuntimeConfig::default();
1231 assert!(config.auto_initialized);
1232 assert_eq!(config.max_concurrent_requests, 100);
1233 }
1234
1235 #[test]
1236 fn test_extract_progress_token_string() -> Result<(), Box<dyn std::error::Error>> {
1237 let params = serde_json::json!({
1238 "_meta": {
1239 "progressToken": "my-token-123"
1240 },
1241 "name": "test-tool"
1242 });
1243 let token = extract_progress_token(Some(¶ms));
1244 assert!(token.is_some());
1245 assert_eq!(
1246 token.ok_or("Token not found")?,
1247 ProgressToken::String("my-token-123".to_string())
1248 );
1249
1250 Ok(())
1251 }
1252
1253 #[test]
1254 fn test_extract_progress_token_number() -> Result<(), Box<dyn std::error::Error>> {
1255 let params = serde_json::json!({
1256 "_meta": {
1257 "progressToken": 42
1258 },
1259 "arguments": {}
1260 });
1261 let token = extract_progress_token(Some(¶ms));
1262 assert!(token.is_some());
1263 assert_eq!(token.ok_or("Token not found")?, ProgressToken::Number(42));
1264
1265 Ok(())
1266 }
1267
1268 #[test]
1269 fn test_extract_progress_token_missing_meta() {
1270 let params = serde_json::json!({
1271 "name": "test-tool",
1272 "arguments": {}
1273 });
1274 let token = extract_progress_token(Some(¶ms));
1275 assert!(token.is_none());
1276 }
1277
1278 #[test]
1279 fn test_extract_progress_token_missing_token() {
1280 let params = serde_json::json!({
1281 "_meta": {},
1282 "name": "test-tool"
1283 });
1284 let token = extract_progress_token(Some(¶ms));
1285 assert!(token.is_none());
1286 }
1287
1288 #[test]
1289 fn test_extract_progress_token_none_params() {
1290 let token = extract_progress_token(None);
1291 assert!(token.is_none());
1292 }
1293}