Skip to main content

rmcp_soddygo/
service.rs

1use std::sync::OnceLock;
2
3use futures::FutureExt;
4#[cfg(not(feature = "local"))]
5use futures::future::BoxFuture;
6#[cfg(feature = "local")]
7use futures::future::LocalBoxFuture;
8use thiserror::Error;
9
10// ---------------------------------------------------------------------------
11// Conditional Send helpers
12//
13// `MaybeSend`       – supertrait alias: `Send + Sync` without `local`, empty with `local`
14// `MaybeSendFuture` – future bound alias: `Send` without `local`, empty with `local`
15// `MaybeBoxFuture`  – boxed future type: `BoxFuture` without `local`, `LocalBoxFuture` with `local`
16// ---------------------------------------------------------------------------
17
18#[cfg(not(feature = "local"))]
19#[doc(hidden)]
20pub trait MaybeSend: Send + Sync {}
21#[cfg(not(feature = "local"))]
22impl<T: Send + Sync> MaybeSend for T {}
23
24#[cfg(feature = "local")]
25#[doc(hidden)]
26pub trait MaybeSend {}
27#[cfg(feature = "local")]
28impl<T> MaybeSend for T {}
29
30#[cfg(not(feature = "local"))]
31#[doc(hidden)]
32pub trait MaybeSendFuture: Send {}
33#[cfg(not(feature = "local"))]
34impl<T: Send> MaybeSendFuture for T {}
35
36#[cfg(feature = "local")]
37#[doc(hidden)]
38pub trait MaybeSendFuture {}
39#[cfg(feature = "local")]
40impl<T> MaybeSendFuture for T {}
41
42#[cfg(not(feature = "local"))]
43pub(crate) type MaybeBoxFuture<'a, T> = BoxFuture<'a, T>;
44#[cfg(feature = "local")]
45pub(crate) type MaybeBoxFuture<'a, T> = LocalBoxFuture<'a, T>;
46
47#[cfg(feature = "server")]
48use crate::model::ClientNotification;
49#[cfg(feature = "server")]
50use crate::model::ServerJsonRpcMessage;
51#[cfg(feature = "client")]
52use crate::model::ServerNotification;
53use crate::{
54    error::ErrorData as McpError,
55    model::{
56        CancelledNotification, CancelledNotificationParam, ClientCapabilities, Extensions,
57        GetExtensions, GetMeta, Implementation, JsonRpcError, JsonRpcMessage, JsonRpcNotification,
58        JsonRpcRequest, JsonRpcResponse, NotificationMetaObject, NumberOrString, ProgressToken,
59        ProtocolVersion, RequestId, RequestMetaObject,
60    },
61    transport::{DynamicTransportError, IntoTransport, Transport},
62};
63#[cfg(feature = "client")]
64mod client;
65#[cfg(feature = "client")]
66pub use client::*;
67#[cfg(feature = "server")]
68mod server;
69#[cfg(feature = "server")]
70pub use server::*;
71#[cfg(feature = "tower")]
72mod tower;
73use tokio_util::sync::{CancellationToken, DropGuard};
74#[cfg(feature = "tower")]
75pub use tower::*;
76use tracing::{Instrument as _, instrument};
77#[derive(Error, Debug)]
78#[non_exhaustive]
79pub enum ServiceError {
80    #[error("Mcp error: {0}")]
81    McpError(McpError),
82    #[error("Transport send error: {0}")]
83    TransportSend(DynamicTransportError),
84    #[error("Transport closed")]
85    TransportClosed,
86    #[error("Unexpected response type")]
87    UnexpectedResponse,
88    #[error("task cancelled for reason {}", reason.as_deref().unwrap_or("<unknown>"))]
89    Cancelled { reason: Option<String> },
90    #[error("request timeout after {}", chrono::Duration::from_std(*timeout).unwrap_or_default())]
91    Timeout { timeout: Duration },
92    /// The peer kept returning `input_required` beyond the configured round cap.
93    #[error("input_required did not complete within {max_rounds} MRTR rounds")]
94    InputRequiredRoundsExceeded { max_rounds: usize },
95}
96
97trait TransferObject:
98    std::fmt::Debug + Clone + serde::Serialize + serde::de::DeserializeOwned + Send + Sync + 'static
99{
100}
101
102impl<T> TransferObject for T where
103    T: std::fmt::Debug
104        + serde::Serialize
105        + serde::de::DeserializeOwned
106        + Send
107        + Sync
108        + 'static
109        + Clone
110{
111}
112
113#[allow(private_bounds, reason = "there's no the third implementation")]
114pub trait ServiceRole: std::fmt::Debug + Send + Sync + 'static + Copy + Clone {
115    type Req: TransferObject + GetMeta<Metadata = RequestMetaObject> + GetExtensions;
116    type Resp: TransferObject;
117    type Not: TryInto<CancelledNotification, Error = Self::Not>
118        + From<CancelledNotification>
119        + TransferObject;
120    type PeerReq: TransferObject + GetMeta<Metadata = RequestMetaObject> + GetExtensions;
121    type PeerResp: TransferObject;
122    type PeerNot: TryInto<CancelledNotification, Error = Self::PeerNot>
123        + From<CancelledNotification>
124        + TransferObject
125        + GetMeta<Metadata = NotificationMetaObject>
126        + GetExtensions;
127    type InitializeError;
128    const IS_CLIENT: bool;
129    type Info: TransferObject;
130    type PeerInfo: TransferObject;
131}
132
133pub type TxJsonRpcMessage<R> =
134    JsonRpcMessage<<R as ServiceRole>::Req, <R as ServiceRole>::Resp, <R as ServiceRole>::Not>;
135pub type RxJsonRpcMessage<R> = JsonRpcMessage<
136    <R as ServiceRole>::PeerReq,
137    <R as ServiceRole>::PeerResp,
138    <R as ServiceRole>::PeerNot,
139>;
140
141#[cfg(not(feature = "local"))]
142pub trait Service<R: ServiceRole>: Send + Sync + 'static {
143    fn handle_request(
144        &self,
145        request: R::PeerReq,
146        context: RequestContext<R>,
147    ) -> impl Future<Output = Result<R::Resp, McpError>> + MaybeSendFuture + '_;
148    fn handle_notification(
149        &self,
150        notification: R::PeerNot,
151        context: NotificationContext<R>,
152    ) -> impl Future<Output = Result<(), McpError>> + MaybeSendFuture + '_;
153    fn get_info(&self) -> R::Info;
154}
155
156#[cfg(feature = "local")]
157pub trait Service<R: ServiceRole>: 'static {
158    fn handle_request(
159        &self,
160        request: R::PeerReq,
161        context: RequestContext<R>,
162    ) -> impl Future<Output = Result<R::Resp, McpError>> + MaybeSendFuture + '_;
163    fn handle_notification(
164        &self,
165        notification: R::PeerNot,
166        context: NotificationContext<R>,
167    ) -> impl Future<Output = Result<(), McpError>> + MaybeSendFuture + '_;
168    fn get_info(&self) -> R::Info;
169}
170
171pub trait ServiceExt<R: ServiceRole>: Service<R> + Sized {
172    /// Convert this service to a dynamic boxed service
173    ///
174    /// This could be very helpful when you want to store the services in a collection
175    fn into_dyn(self) -> Box<dyn DynService<R>> {
176        Box::new(self)
177    }
178    fn serve<T, E, A>(
179        self,
180        transport: T,
181    ) -> impl Future<Output = Result<RunningService<R, Self>, R::InitializeError>> + MaybeSendFuture
182    where
183        T: IntoTransport<R, E, A>,
184        E: std::error::Error + Send + Sync + 'static,
185        Self: Sized,
186    {
187        Self::serve_with_ct(self, transport, Default::default())
188    }
189    fn serve_with_ct<T, E, A>(
190        self,
191        transport: T,
192        ct: CancellationToken,
193    ) -> impl Future<Output = Result<RunningService<R, Self>, R::InitializeError>> + MaybeSendFuture
194    where
195        T: IntoTransport<R, E, A>,
196        E: std::error::Error + Send + Sync + 'static,
197        Self: Sized;
198}
199
200impl<R: ServiceRole> Service<R> for Box<dyn DynService<R>> {
201    fn handle_request(
202        &self,
203        request: R::PeerReq,
204        context: RequestContext<R>,
205    ) -> impl Future<Output = Result<R::Resp, McpError>> + MaybeSendFuture + '_ {
206        DynService::handle_request(self.as_ref(), request, context)
207    }
208
209    fn handle_notification(
210        &self,
211        notification: R::PeerNot,
212        context: NotificationContext<R>,
213    ) -> impl Future<Output = Result<(), McpError>> + MaybeSendFuture + '_ {
214        DynService::handle_notification(self.as_ref(), notification, context)
215    }
216
217    fn get_info(&self) -> R::Info {
218        DynService::get_info(self.as_ref())
219    }
220}
221
222#[cfg(not(feature = "local"))]
223pub trait DynService<R: ServiceRole>: Send + Sync {
224    fn handle_request(
225        &self,
226        request: R::PeerReq,
227        context: RequestContext<R>,
228    ) -> MaybeBoxFuture<'_, Result<R::Resp, McpError>>;
229    fn handle_notification(
230        &self,
231        notification: R::PeerNot,
232        context: NotificationContext<R>,
233    ) -> MaybeBoxFuture<'_, Result<(), McpError>>;
234    fn get_info(&self) -> R::Info;
235}
236
237#[cfg(feature = "local")]
238pub trait DynService<R: ServiceRole> {
239    fn handle_request(
240        &self,
241        request: R::PeerReq,
242        context: RequestContext<R>,
243    ) -> MaybeBoxFuture<'_, Result<R::Resp, McpError>>;
244    fn handle_notification(
245        &self,
246        notification: R::PeerNot,
247        context: NotificationContext<R>,
248    ) -> MaybeBoxFuture<'_, Result<(), McpError>>;
249    fn get_info(&self) -> R::Info;
250}
251
252impl<R: ServiceRole, S: Service<R>> DynService<R> for S {
253    fn handle_request(
254        &self,
255        request: R::PeerReq,
256        context: RequestContext<R>,
257    ) -> MaybeBoxFuture<'_, Result<R::Resp, McpError>> {
258        Box::pin(self.handle_request(request, context))
259    }
260    fn handle_notification(
261        &self,
262        notification: R::PeerNot,
263        context: NotificationContext<R>,
264    ) -> MaybeBoxFuture<'_, Result<(), McpError>> {
265        Box::pin(self.handle_notification(notification, context))
266    }
267    fn get_info(&self) -> R::Info {
268        self.get_info()
269    }
270}
271
272use std::{
273    collections::{HashMap, VecDeque},
274    ops::Deref,
275    sync::{Arc, atomic::AtomicU64},
276    time::Duration,
277};
278
279use tokio::sync::mpsc;
280
281pub trait RequestIdProvider: Send + Sync + 'static {
282    fn next_request_id(&self) -> RequestId;
283}
284
285pub trait ProgressTokenProvider: Send + Sync + 'static {
286    fn next_progress_token(&self) -> ProgressToken;
287}
288
289pub type AtomicU32RequestIdProvider = AtomicU32Provider;
290pub type AtomicU32ProgressTokenProvider = AtomicU32Provider;
291
292#[derive(Debug, Default)]
293pub struct AtomicU32Provider {
294    id: AtomicU64,
295}
296
297impl RequestIdProvider for AtomicU32Provider {
298    fn next_request_id(&self) -> RequestId {
299        let id = self.id.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
300        // Safe conversion: we start at 0 and increment by 1, so we won't overflow i64::MAX in practice
301        RequestId::Number(id as i64)
302    }
303}
304
305impl ProgressTokenProvider for AtomicU32Provider {
306    fn next_progress_token(&self) -> ProgressToken {
307        let id = self.id.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
308        ProgressToken(NumberOrString::Number(id as i64))
309    }
310}
311
312#[doc(hidden)]
313pub trait ProgressNotificationToken {
314    fn progress_token(&self) -> Option<&ProgressToken>;
315}
316
317#[cfg(feature = "server")]
318impl ProgressNotificationToken for ClientNotification {
319    fn progress_token(&self) -> Option<&ProgressToken> {
320        match self {
321            ClientNotification::ProgressNotification(notification) => {
322                Some(&notification.params.progress_token)
323            }
324            _ => None,
325        }
326    }
327}
328
329#[cfg(feature = "client")]
330impl ProgressNotificationToken for ServerNotification {
331    fn progress_token(&self) -> Option<&ProgressToken> {
332        match self {
333            ServerNotification::ProgressNotification(notification) => {
334                Some(&notification.params.progress_token)
335            }
336            _ => None,
337        }
338    }
339}
340
341type Responder<T> = tokio::sync::oneshot::Sender<T>;
342type ProgressTimeoutWatchers = Arc<tokio::sync::RwLock<HashMap<ProgressToken, mpsc::Sender<()>>>>;
343
344/// A handle to a remote request
345///
346/// You can cancel it by call [`RequestHandle::cancel`] with a reason,
347///
348/// or wait for response by call [`RequestHandle::await_response`]
349#[derive(Debug)]
350#[non_exhaustive]
351pub struct RequestHandle<R: ServiceRole> {
352    pub rx: tokio::sync::oneshot::Receiver<Result<R::PeerResp, ServiceError>>,
353    pub options: PeerRequestOptions,
354    pub peer: Peer<R>,
355    pub id: RequestId,
356    pub progress_token: ProgressToken,
357    progress_reset_rx: Option<mpsc::Receiver<()>>,
358}
359
360impl<R: ServiceRole> RequestHandle<R> {
361    pub const REQUEST_TIMEOUT_REASON: &str = "request timeout";
362    pub const REQUEST_MAX_TOTAL_TIMEOUT_REASON: &str = "maximum total timeout exceeded";
363
364    pub async fn await_response(mut self) -> Result<R::PeerResp, ServiceError> {
365        let timeout = self.options.timeout;
366        let max_total_timeout = self.options.max_total_timeout;
367        let reset_timeout_on_progress = self.options.reset_timeout_on_progress;
368
369        let has_progress_reset_rx = self.progress_reset_rx.is_some();
370        let progress_token = self.progress_token.clone();
371
372        let result = match (timeout, max_total_timeout, reset_timeout_on_progress) {
373            (Some(timeout), None, false) => match tokio::time::timeout(timeout, &mut self.rx).await
374            {
375                Ok(response) => response.map_err(|_e| ServiceError::TransportClosed)?,
376                Err(_) => {
377                    let error = Err(ServiceError::Timeout { timeout });
378                    // cancel this request
379                    self.send_timeout_cancel_notification(Self::REQUEST_TIMEOUT_REASON)
380                        .await;
381                    error
382                }
383            },
384            (None, None, _) => (&mut self.rx)
385                .await
386                .map_err(|_e| ServiceError::TransportClosed)?,
387            _ => {
388                self.await_response_with_progress_timeout(
389                    timeout,
390                    max_total_timeout,
391                    reset_timeout_on_progress,
392                )
393                .await
394            }
395        };
396
397        Self::cleanup_progress_timeout_watcher(
398            &self.peer.progress_timeout_watchers,
399            &progress_token,
400            has_progress_reset_rx,
401        )
402        .await;
403        result
404    }
405
406    async fn send_timeout_cancel_notification(&self, reason: &str) {
407        let notification = CancelledNotification {
408            params: CancelledNotificationParam {
409                request_id: Some(self.id.clone()),
410                reason: Some(reason.to_owned()),
411                meta: None,
412            },
413            method: crate::model::CancelledNotificationMethod,
414            extensions: Default::default(),
415        };
416        let _ = self.peer.send_notification(notification.into()).await;
417    }
418
419    async fn await_response_with_progress_timeout(
420        &mut self,
421        timeout: Option<Duration>,
422        max_total_timeout: Option<Duration>,
423        reset_timeout_on_progress: bool,
424    ) -> Result<R::PeerResp, ServiceError> {
425        let mut idle_sleep =
426            timeout.map(|timeout| (timeout, Box::pin(tokio::time::sleep(timeout))));
427        let mut max_total_sleep =
428            max_total_timeout.map(|timeout| (timeout, Box::pin(tokio::time::sleep(timeout))));
429
430        loop {
431            tokio::select! {
432                biased;
433
434                response = &mut self.rx => {
435                    return response.map_err(|_e| ServiceError::TransportClosed)?;
436                }
437                _ = async {
438                    if let Some((_, sleep)) = idle_sleep.as_mut() {
439                        sleep.as_mut().await;
440                    }
441                }, if idle_sleep.is_some() => {
442                    if let Some((timeout, _)) = idle_sleep.as_ref() {
443                        self.send_timeout_cancel_notification(Self::REQUEST_TIMEOUT_REASON).await;
444                        return Err(ServiceError::Timeout { timeout: *timeout });
445                    }
446                }
447                _ = async {
448                    if let Some((_, sleep)) = max_total_sleep.as_mut() {
449                        sleep.as_mut().await;
450                    }
451                }, if max_total_sleep.is_some() => {
452                    if let Some((timeout, _)) = max_total_sleep.as_ref() {
453                        self.send_timeout_cancel_notification(Self::REQUEST_MAX_TOTAL_TIMEOUT_REASON).await;
454                        return Err(ServiceError::Timeout { timeout: *timeout });
455                    }
456                }
457                progress = async {
458                    match self.progress_reset_rx.as_mut() {
459                        Some(rx) => rx.recv().await,
460                        None => None,
461                    }
462                }, if reset_timeout_on_progress && idle_sleep.is_some() && self.progress_reset_rx.is_some() => {
463                    if progress.is_some() {
464                        if let Some((timeout, sleep)) = idle_sleep.as_mut() {
465                            sleep.as_mut().reset(tokio::time::Instant::now() + *timeout);
466                        }
467                    }
468                }
469            }
470        }
471    }
472
473    /// Cancel this request
474    pub async fn cancel(self, reason: Option<String>) -> Result<(), ServiceError> {
475        Self::cleanup_progress_timeout_watcher(
476            &self.peer.progress_timeout_watchers,
477            &self.progress_token,
478            self.progress_reset_rx.is_some(),
479        )
480        .await;
481        let notification = CancelledNotification {
482            params: CancelledNotificationParam {
483                request_id: Some(self.id),
484                reason,
485                meta: None,
486            },
487            method: crate::model::CancelledNotificationMethod,
488            extensions: Default::default(),
489        };
490        self.peer.send_notification(notification.into()).await?;
491        Ok(())
492    }
493
494    async fn cleanup_progress_timeout_watcher(
495        progress_timeout_watchers: &ProgressTimeoutWatchers,
496        progress_token: &ProgressToken,
497        has_progress_reset_rx: bool,
498    ) {
499        if has_progress_reset_rx {
500            progress_timeout_watchers
501                .write()
502                .await
503                .remove(progress_token);
504        }
505    }
506}
507
508#[derive(Debug)]
509pub(crate) enum PeerSinkMessage<R: ServiceRole> {
510    Request {
511        request: R::Req,
512        id: RequestId,
513        responder: Responder<Result<R::PeerResp, ServiceError>>,
514    },
515    Notification {
516        notification: R::Not,
517        responder: Responder<Result<(), ServiceError>>,
518    },
519}
520
521#[derive(Debug, Clone)]
522pub(crate) struct ClientRequestMetadata {
523    pub protocol_version: ProtocolVersion,
524    pub client_info: Implementation,
525    pub client_capabilities: ClientCapabilities,
526}
527
528/// An interface to fetch the remote client or server
529///
530/// For general purpose, call [`Peer::send_request`] or [`Peer::send_notification`] to send message to remote peer.
531///
532/// To create a cancellable request, call [`Peer::send_request_with_option`].
533#[derive(Clone)]
534pub struct Peer<R: ServiceRole> {
535    tx: mpsc::Sender<PeerSinkMessage<R>>,
536    request_id_provider: Arc<dyn RequestIdProvider>,
537    progress_token_provider: Arc<dyn ProgressTokenProvider>,
538    progress_timeout_watchers: ProgressTimeoutWatchers,
539    info: Arc<std::sync::RwLock<Option<Arc<R::PeerInfo>>>>,
540    client_request_metadata: Arc<OnceLock<ClientRequestMetadata>>,
541    request_metadata_required: Arc<std::sync::atomic::AtomicBool>,
542}
543
544impl<R: ServiceRole> std::fmt::Debug for Peer<R> {
545    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
546        f.debug_struct("PeerSink")
547            .field("tx", &self.tx)
548            .field("is_client", &R::IS_CLIENT)
549            .finish()
550    }
551}
552
553type ProxyOutbound<R> = mpsc::Receiver<PeerSinkMessage<R>>;
554
555#[derive(Debug, Default)]
556#[non_exhaustive]
557pub struct PeerRequestOptions {
558    pub timeout: Option<Duration>,
559    pub meta: Option<RequestMetaObject>,
560    /// Reset the request timeout when a matching progress notification is received.
561    pub reset_timeout_on_progress: bool,
562    /// Maximum total time to wait for the request, regardless of progress notifications.
563    pub max_total_timeout: Option<Duration>,
564}
565
566impl PeerRequestOptions {
567    pub fn no_options() -> Self {
568        Self::default()
569    }
570
571    pub fn with_timeout(timeout: Duration) -> Self {
572        Self {
573            timeout: Some(timeout),
574            ..Self::default()
575        }
576    }
577
578    /// Adds request metadata while preserving any other configured options.
579    ///
580    /// Explicit values take precedence over discover-lifecycle metadata defaults.
581    pub fn with_meta(mut self, meta: RequestMetaObject) -> Self {
582        self.meta = Some(meta);
583        self
584    }
585
586    pub fn reset_timeout_on_progress(mut self) -> Self {
587        self.reset_timeout_on_progress = true;
588        self
589    }
590
591    pub fn with_max_total_timeout(mut self, timeout: Duration) -> Self {
592        self.max_total_timeout = Some(timeout);
593        self
594    }
595}
596
597impl<R: ServiceRole> Peer<R> {
598    const CLIENT_CHANNEL_BUFFER_SIZE: usize = 1024;
599    pub(crate) fn new(
600        request_id_provider: Arc<dyn RequestIdProvider>,
601        peer_info: Option<R::PeerInfo>,
602    ) -> (Peer<R>, ProxyOutbound<R>) {
603        let (tx, rx) = mpsc::channel(Self::CLIENT_CHANNEL_BUFFER_SIZE);
604        (
605            Self {
606                tx,
607                request_id_provider,
608                progress_token_provider: Arc::new(AtomicU32ProgressTokenProvider::default()),
609                progress_timeout_watchers: Default::default(),
610                info: Arc::new(std::sync::RwLock::new(peer_info.map(Arc::new))),
611                client_request_metadata: Default::default(),
612                request_metadata_required: Default::default(),
613            },
614            rx,
615        )
616    }
617    pub async fn send_notification(&self, notification: R::Not) -> Result<(), ServiceError> {
618        let (responder, receiver) = tokio::sync::oneshot::channel();
619        self.tx
620            .send(PeerSinkMessage::Notification {
621                notification,
622                responder,
623            })
624            .await
625            .map_err(|_m| ServiceError::TransportClosed)?;
626        receiver.await.map_err(|_e| ServiceError::TransportClosed)?
627    }
628    pub async fn send_request(&self, request: R::Req) -> Result<R::PeerResp, ServiceError> {
629        self.send_request_with_option(request, PeerRequestOptions::no_options())
630            .await?
631            .await_response()
632            .await
633    }
634
635    pub async fn send_cancellable_request(
636        &self,
637        request: R::Req,
638        options: PeerRequestOptions,
639    ) -> Result<RequestHandle<R>, ServiceError> {
640        self.send_request_with_option(request, options).await
641    }
642
643    pub async fn send_request_with_option(
644        &self,
645        mut request: R::Req,
646        options: PeerRequestOptions,
647    ) -> Result<RequestHandle<R>, ServiceError> {
648        let id = self.request_id_provider.next_request_id();
649        let progress_token = self.progress_token_provider.next_progress_token();
650        if let Some(metadata) = self.client_request_metadata.get() {
651            let meta = request.get_meta_mut();
652            meta.set_protocol_version(metadata.protocol_version.clone());
653            meta.set_client_info(metadata.client_info.clone());
654            meta.set_client_capabilities(metadata.client_capabilities.clone());
655        }
656        if let Some(meta) = options.meta.clone() {
657            request.get_meta_mut().extend(meta);
658        }
659        request
660            .get_meta_mut()
661            .set_progress_token(progress_token.clone());
662        let (responder, receiver) = tokio::sync::oneshot::channel();
663        let progress_reset_rx = if options.reset_timeout_on_progress && options.timeout.is_some() {
664            let (sender, receiver) = mpsc::channel(1);
665            self.progress_timeout_watchers
666                .write()
667                .await
668                .insert(progress_token.clone(), sender);
669            Some(receiver)
670        } else {
671            None
672        };
673        if self
674            .tx
675            .send(PeerSinkMessage::Request {
676                request,
677                id: id.clone(),
678                responder,
679            })
680            .await
681            .is_err()
682        {
683            if progress_reset_rx.is_some() {
684                self.progress_timeout_watchers
685                    .write()
686                    .await
687                    .remove(&progress_token);
688            }
689            return Err(ServiceError::TransportClosed);
690        }
691        Ok(RequestHandle {
692            id,
693            rx: receiver,
694            progress_token,
695            options,
696            peer: self.clone(),
697            progress_reset_rx,
698        })
699    }
700
701    async fn notify_progress_timeout_watcher(&self, progress_token: &ProgressToken) {
702        let sender = self
703            .progress_timeout_watchers
704            .read()
705            .await
706            .get(progress_token)
707            .cloned();
708        if let Some(sender) = sender {
709            match sender.try_send(()) {
710                Ok(()) => {}
711                Err(mpsc::error::TrySendError::Full(_)) => {
712                    tracing::trace!(?progress_token, "progress timeout watcher channel is full");
713                }
714                Err(mpsc::error::TrySendError::Closed(_)) => {
715                    self.progress_timeout_watchers
716                        .write()
717                        .await
718                        .remove(progress_token);
719                }
720            }
721        }
722    }
723
724    /// Snapshot of the peer's handshake info.
725    pub fn peer_info(&self) -> Option<Arc<R::PeerInfo>> {
726        self.info.read().expect("peer info lock poisoned").clone()
727    }
728
729    /// Stores the peer's handshake info, overwriting any previous value.
730    pub fn set_peer_info(&self, info: R::PeerInfo) {
731        *self.info.write().expect("peer info lock poisoned") = Some(Arc::new(info));
732    }
733
734    pub(crate) fn set_client_request_metadata(&self, metadata: ClientRequestMetadata) {
735        let result = self.client_request_metadata.set(metadata);
736        debug_assert!(result.is_ok(), "client request metadata set more than once");
737    }
738
739    pub(crate) fn require_request_metadata(&self) {
740        self.request_metadata_required
741            .store(true, std::sync::atomic::Ordering::Release);
742    }
743
744    pub(crate) fn request_metadata_required(&self) -> bool {
745        self.request_metadata_required
746            .load(std::sync::atomic::Ordering::Acquire)
747    }
748
749    pub fn is_transport_closed(&self) -> bool {
750        self.tx.is_closed()
751    }
752}
753
754#[derive(Debug)]
755pub struct RunningService<R: ServiceRole, S: Service<R>> {
756    service: Arc<S>,
757    peer: Peer<R>,
758    handle: Option<tokio::task::JoinHandle<QuitReason>>,
759    cancellation_token: CancellationToken,
760    dg: DropGuard,
761}
762impl<R: ServiceRole, S: Service<R>> Deref for RunningService<R, S> {
763    type Target = Peer<R>;
764
765    fn deref(&self) -> &Self::Target {
766        &self.peer
767    }
768}
769
770impl<R: ServiceRole, S: Service<R>> RunningService<R, S> {
771    #[inline]
772    pub fn peer(&self) -> &Peer<R> {
773        &self.peer
774    }
775    #[inline]
776    pub fn service(&self) -> &S {
777        self.service.as_ref()
778    }
779    #[inline]
780    pub fn cancellation_token(&self) -> RunningServiceCancellationToken {
781        RunningServiceCancellationToken(self.cancellation_token.clone())
782    }
783
784    /// Returns true if the service has been closed or cancelled.
785    #[inline]
786    pub fn is_closed(&self) -> bool {
787        self.handle.is_none() || self.cancellation_token.is_cancelled()
788    }
789
790    /// Wait for the service to complete.
791    ///
792    /// This will block until the service loop terminates (either due to
793    /// cancellation, transport closure, or an error).
794    #[inline]
795    pub async fn waiting(mut self) -> Result<QuitReason, tokio::task::JoinError> {
796        match self.handle.take() {
797            Some(handle) => handle.await,
798            None => Ok(QuitReason::Closed),
799        }
800    }
801
802    /// Gracefully close the connection and wait for cleanup to complete.
803    ///
804    /// This method cancels the service, waits for the background task to finish
805    /// (which includes calling `transport.close()`), and ensures all cleanup
806    /// operations complete before returning.
807    ///
808    /// Unlike [`cancel`](Self::cancel), this method takes `&mut self` and can be
809    /// called without consuming the `RunningService`. After calling this method,
810    /// the service is considered closed and subsequent operations will fail.
811    ///
812    /// # Example
813    ///
814    /// ```rust,ignore
815    /// let mut client = ().serve(transport).await?;
816    /// // ... use the client ...
817    /// client.close().await?;
818    /// ```
819    pub async fn close(&mut self) -> Result<QuitReason, tokio::task::JoinError> {
820        if let Some(handle) = self.handle.take() {
821            // Disarm the drop guard so it doesn't try to cancel again
822            // We need to cancel manually and wait for completion
823            self.cancellation_token.cancel();
824            handle.await
825        } else {
826            // Already closed
827            Ok(QuitReason::Closed)
828        }
829    }
830
831    /// Gracefully close the connection with a timeout.
832    ///
833    /// Similar to [`close`](Self::close), but returns after the specified timeout
834    /// if the cleanup doesn't complete in time. This is useful for ensuring
835    /// a bounded shutdown time.
836    ///
837    /// Returns `Ok(Some(reason))` if shutdown completed within the timeout,
838    /// `Ok(None)` if the timeout was reached, or `Err` if there was a join error.
839    pub async fn close_with_timeout(
840        &mut self,
841        timeout: Duration,
842    ) -> Result<Option<QuitReason>, tokio::task::JoinError> {
843        if let Some(handle) = self.handle.take() {
844            self.cancellation_token.cancel();
845            match tokio::time::timeout(timeout, handle).await {
846                Ok(result) => result.map(Some),
847                Err(_elapsed) => {
848                    tracing::warn!(
849                        "close_with_timeout: cleanup did not complete within {:?}",
850                        timeout
851                    );
852                    Ok(None)
853                }
854            }
855        } else {
856            Ok(Some(QuitReason::Closed))
857        }
858    }
859
860    /// Cancel the service and wait for cleanup to complete.
861    ///
862    /// This consumes the `RunningService` and ensures the connection is properly
863    /// closed. For a non-consuming alternative, see [`close`](Self::close).
864    pub async fn cancel(mut self) -> Result<QuitReason, tokio::task::JoinError> {
865        // Disarm the drop guard since we're handling cancellation explicitly
866        let _ = std::mem::replace(&mut self.dg, self.cancellation_token.clone().drop_guard());
867        self.close().await
868    }
869}
870
871impl<R: ServiceRole, S: Service<R>> Drop for RunningService<R, S> {
872    fn drop(&mut self) {
873        if self.handle.is_some() && !self.cancellation_token.is_cancelled() {
874            tracing::debug!(
875                "RunningService dropped without explicit close(). \
876                 The connection will be closed asynchronously. \
877                 For guaranteed cleanup, call close() or cancel() before dropping."
878            );
879        }
880        // The DropGuard will handle cancellation
881    }
882}
883
884// use a wrapper type so we can tweak the implementation if needed
885pub struct RunningServiceCancellationToken(CancellationToken);
886
887impl RunningServiceCancellationToken {
888    pub fn cancel(self) {
889        self.0.cancel();
890    }
891}
892
893#[derive(Debug)]
894#[non_exhaustive]
895pub enum QuitReason {
896    Cancelled,
897    Closed,
898    JoinError(tokio::task::JoinError),
899}
900
901/// Request execution context
902#[derive(Debug, Clone)]
903#[non_exhaustive]
904pub struct RequestContext<R: ServiceRole> {
905    /// this token will be cancelled when the [`CancelledNotification`] is received.
906    pub ct: CancellationToken,
907    pub id: RequestId,
908    pub meta: RequestMetaObject,
909    pub extensions: Extensions,
910    /// An interface to fetch the remote client or server
911    pub peer: Peer<R>,
912}
913
914impl<R: ServiceRole> RequestContext<R> {
915    /// Create a new RequestContext.
916    pub fn new(id: RequestId, peer: Peer<R>) -> Self {
917        Self {
918            ct: CancellationToken::new(),
919            id,
920            meta: RequestMetaObject::default(),
921            extensions: Extensions::default(),
922            peer,
923        }
924    }
925}
926
927#[cfg(feature = "server")]
928impl RequestContext<RoleServer> {
929    /// The current request's protocol version, falling back to legacy handshake state.
930    pub fn protocol_version(&self) -> Option<crate::model::ProtocolVersion> {
931        self.meta.protocol_version().or_else(|| {
932            self.peer
933                .peer_info()
934                .map(|info| info.protocol_version.clone())
935        })
936    }
937
938    /// The current request's client implementation, falling back only for legacy sessions.
939    pub fn client_info(&self) -> Option<Implementation> {
940        if self.peer.request_metadata_required() {
941            self.meta.client_info()
942        } else {
943            self.meta
944                .client_info()
945                .or_else(|| self.peer.peer_info().map(|info| info.client_info.clone()))
946        }
947    }
948
949    /// The current request's client capabilities, falling back only for legacy sessions.
950    pub fn client_capabilities(&self) -> Option<ClientCapabilities> {
951        if self.peer.request_metadata_required() {
952            self.meta.client_capabilities()
953        } else {
954            self.meta
955                .client_capabilities()
956                .or_else(|| self.peer.peer_info().map(|info| info.capabilities.clone()))
957        }
958    }
959}
960
961/// Request execution context
962#[derive(Debug, Clone)]
963#[non_exhaustive]
964pub struct NotificationContext<R: ServiceRole> {
965    pub meta: NotificationMetaObject,
966    pub extensions: Extensions,
967    /// An interface to fetch the remote client or server
968    pub peer: Peer<R>,
969}
970
971/// Use this function to skip initialization process
972pub fn serve_directly<R, S, T, E, A>(
973    service: S,
974    transport: T,
975    peer_info: Option<R::PeerInfo>,
976) -> RunningService<R, S>
977where
978    R: ServiceRole,
979    R::PeerNot: ProgressNotificationToken,
980    S: Service<R>,
981    T: IntoTransport<R, E, A>,
982    E: std::error::Error + Send + Sync + 'static,
983{
984    serve_directly_with_ct(service, transport, peer_info, Default::default())
985}
986
987/// Use this function to skip initialization process
988pub fn serve_directly_with_ct<R, S, T, E, A>(
989    service: S,
990    transport: T,
991    peer_info: Option<R::PeerInfo>,
992    ct: CancellationToken,
993) -> RunningService<R, S>
994where
995    R: ServiceRole,
996    R::PeerNot: ProgressNotificationToken,
997    S: Service<R>,
998    T: IntoTransport<R, E, A>,
999    E: std::error::Error + Send + Sync + 'static,
1000{
1001    let (peer, peer_rx) = Peer::new(Arc::new(AtomicU32RequestIdProvider::default()), peer_info);
1002    serve_inner(service, transport.into_transport(), peer, peer_rx, ct)
1003}
1004
1005/// Spawn a task that may hold `!Send` state when the `local` feature is active.
1006///
1007/// Without the `local` feature this is `tokio::spawn` (requires `Future: Send + 'static`).
1008/// With `local` it uses `tokio::task::spawn_local` (requires only `Future: 'static`).
1009#[cfg(not(feature = "local"))]
1010fn spawn_service_task<F>(future: F) -> tokio::task::JoinHandle<F::Output>
1011where
1012    F: Future + Send + 'static,
1013    F::Output: Send + 'static,
1014{
1015    tokio::spawn(future)
1016}
1017
1018#[cfg(feature = "local")]
1019fn spawn_service_task<F>(future: F) -> tokio::task::JoinHandle<F::Output>
1020where
1021    F: Future + 'static,
1022    F::Output: 'static,
1023{
1024    tokio::task::spawn_local(future)
1025}
1026
1027#[instrument(skip_all)]
1028fn serve_inner<R, S, T>(
1029    service: S,
1030    transport: T,
1031    peer: Peer<R>,
1032    mut peer_rx: tokio::sync::mpsc::Receiver<PeerSinkMessage<R>>,
1033    ct: CancellationToken,
1034) -> RunningService<R, S>
1035where
1036    R: ServiceRole,
1037    R::PeerNot: ProgressNotificationToken,
1038    S: Service<R>,
1039    T: Transport<R> + 'static,
1040{
1041    const SINK_PROXY_BUFFER_SIZE: usize = 64;
1042    let (sink_proxy_tx, mut sink_proxy_rx) =
1043        tokio::sync::mpsc::channel::<TxJsonRpcMessage<R>>(SINK_PROXY_BUFFER_SIZE);
1044    let peer_info = peer.peer_info();
1045    if R::IS_CLIENT {
1046        tracing::info!(?peer_info, "Service initialized as client");
1047    } else {
1048        tracing::info!(?peer_info, "Service initialized as server");
1049    }
1050
1051    let mut local_responder_pool =
1052        HashMap::<RequestId, Responder<Result<R::PeerResp, ServiceError>>>::new();
1053    let mut local_ct_pool = HashMap::<RequestId, CancellationToken>::new();
1054    let shared_service = Arc::new(service);
1055    // for return
1056    let service = shared_service.clone();
1057
1058    // let message_sink = tokio::sync::
1059    // let mut stream = std::pin::pin!(stream);
1060    let serve_loop_ct = ct.child_token();
1061    let peer_return: Peer<R> = peer.clone();
1062    let current_span = tracing::Span::current();
1063    let handle = spawn_service_task(async move {
1064        let mut transport = transport.into_transport();
1065        let mut batch_messages = VecDeque::<RxJsonRpcMessage<R>>::new();
1066        let mut send_task_set = tokio::task::JoinSet::<SendTaskResult>::new();
1067        let mut response_send_tasks = tokio::task::JoinSet::<()>::new();
1068        #[derive(Debug)]
1069        enum SendTaskResult {
1070            Request {
1071                id: RequestId,
1072                result: Result<(), DynamicTransportError>,
1073            },
1074            Notification {
1075                responder: Responder<Result<(), ServiceError>>,
1076                cancellation_param: Option<CancelledNotificationParam>,
1077                result: Result<(), DynamicTransportError>,
1078            },
1079        }
1080        #[derive(Debug)]
1081        enum Event<R: ServiceRole> {
1082            ProxyMessage(PeerSinkMessage<R>),
1083            PeerMessage(RxJsonRpcMessage<R>),
1084            ToSink(TxJsonRpcMessage<R>),
1085            SendTaskResult(SendTaskResult),
1086        }
1087
1088        let quit_reason = loop {
1089            let evt = if let Some(m) = batch_messages.pop_front() {
1090                Event::PeerMessage(m)
1091            } else {
1092                tokio::select! {
1093                    m = sink_proxy_rx.recv(), if !sink_proxy_rx.is_closed() => {
1094                        if let Some(m) = m {
1095                            Event::ToSink(m)
1096                        } else {
1097                            continue
1098                        }
1099                    }
1100                    m = transport.receive() => {
1101                        if let Some(m) = m {
1102                            Event::PeerMessage(m)
1103                        } else {
1104                            // input stream closed
1105                            tracing::info!("input stream terminated");
1106                            break QuitReason::Closed
1107                        }
1108                    }
1109                    m = peer_rx.recv(), if !peer_rx.is_closed() => {
1110                        if let Some(m) = m {
1111                            Event::ProxyMessage(m)
1112                        } else {
1113                            continue
1114                        }
1115                    }
1116                    m = send_task_set.join_next(), if !send_task_set.is_empty() => {
1117                        let Some(result) = m else {
1118                            continue
1119                        };
1120                        match result {
1121                            Err(e) => {
1122                                // join error, which is serious, we should quit.
1123                                tracing::error!(%e, "send request task encounter a tokio join error");
1124                                break QuitReason::JoinError(e)
1125                            }
1126                            Ok(result) => {
1127                                Event::SendTaskResult(result)
1128                            }
1129                        }
1130                    }
1131                    _ = serve_loop_ct.cancelled() => {
1132                        tracing::info!("task cancelled");
1133                        break QuitReason::Cancelled
1134                    }
1135                }
1136            };
1137
1138            tracing::trace!(?evt, "new event");
1139            match evt {
1140                Event::SendTaskResult(SendTaskResult::Request { id, result }) => {
1141                    if let Err(e) = result {
1142                        if let Some(responder) = local_responder_pool.remove(&id) {
1143                            let _ = responder.send(Err(ServiceError::TransportSend(e)));
1144                        }
1145                    }
1146                }
1147                Event::SendTaskResult(SendTaskResult::Notification {
1148                    responder,
1149                    result,
1150                    cancellation_param,
1151                }) => {
1152                    let response = if let Err(e) = result {
1153                        Err(ServiceError::TransportSend(e))
1154                    } else {
1155                        Ok(())
1156                    };
1157                    let _ = responder.send(response);
1158                    if let Some(param) = cancellation_param {
1159                        if let Some(request_id) = &param.request_id {
1160                            if let Some(responder) = local_responder_pool.remove(request_id) {
1161                                tracing::info!(id = %request_id, reason = param.reason, "cancelled");
1162                                let _response_result = responder.send(Err(ServiceError::Cancelled {
1163                                    reason: param.reason.clone(),
1164                                }));
1165                            }
1166                        }
1167                    }
1168                }
1169                // response and error
1170                Event::ToSink(m) => {
1171                    if let Some(id) = match &m {
1172                        JsonRpcMessage::Response(response) => Some(&response.id),
1173                        JsonRpcMessage::Error(error) => error.id.as_ref(),
1174                        _ => None,
1175                    } {
1176                        let Some(ct) = local_ct_pool.remove(id) else {
1177                            tracing::debug!(%id, "dropping response for cancelled request");
1178                            continue;
1179                        };
1180                        ct.cancel();
1181                        let send = transport.send(m);
1182                        let current_span = tracing::Span::current();
1183                        response_send_tasks.spawn(async move {
1184                            let send_result = send.await;
1185                            if let Err(error) = send_result {
1186                                tracing::error!(%error, "fail to response message");
1187                            }
1188                        }.instrument(current_span));
1189                    }
1190                }
1191                Event::ProxyMessage(PeerSinkMessage::Request {
1192                    request,
1193                    id,
1194                    responder,
1195                }) => {
1196                    local_responder_pool.insert(id.clone(), responder);
1197                    let send = transport.send(JsonRpcMessage::request(request, id.clone()));
1198                    {
1199                        let id = id.clone();
1200                        let current_span = tracing::Span::current();
1201                        send_task_set.spawn(send.map(move |r| SendTaskResult::Request {
1202                            id,
1203                            result: r.map_err(DynamicTransportError::new::<T, R>),
1204                        }).instrument(current_span));
1205                    }
1206                }
1207                Event::ProxyMessage(PeerSinkMessage::Notification {
1208                    notification,
1209                    responder,
1210                }) => {
1211                    // catch cancellation notification
1212                    let mut cancellation_param = None;
1213                    let notification = match notification.try_into() {
1214                        Ok::<CancelledNotification, _>(cancelled) => {
1215                            cancellation_param.replace(cancelled.params.clone());
1216                            cancelled.into()
1217                        }
1218                        Err(notification) => notification,
1219                    };
1220                    let send = transport.send(JsonRpcMessage::notification(notification));
1221                    let current_span = tracing::Span::current();
1222                    send_task_set.spawn(send.map(move |result| SendTaskResult::Notification {
1223                        responder,
1224                        cancellation_param,
1225                        result: result.map_err(DynamicTransportError::new::<T, R>),
1226                    }).instrument(current_span));
1227                }
1228                Event::PeerMessage(JsonRpcMessage::Request(JsonRpcRequest {
1229                    id,
1230                    mut request,
1231                    ..
1232                })) => {
1233                    tracing::debug!(%id, ?request, "received request");
1234                    {
1235                        let service = shared_service.clone();
1236                        let sink = sink_proxy_tx.clone();
1237                        let request_ct = serve_loop_ct.child_token();
1238                        let context_ct = request_ct.child_token();
1239                        local_ct_pool.insert(id.clone(), request_ct);
1240                        let mut extensions = Extensions::new();
1241                        let mut meta = RequestMetaObject::new();
1242                        // avoid clone
1243                        // swap meta firstly, otherwise progress token will be lost
1244                        std::mem::swap(&mut meta, request.get_meta_mut());
1245                        std::mem::swap(&mut extensions, request.extensions_mut());
1246                        let context = RequestContext {
1247                            ct: context_ct,
1248                            id: id.clone(),
1249                            peer: peer.clone(),
1250                            meta,
1251                            extensions,
1252                        };
1253                        let current_span = tracing::Span::current();
1254                        spawn_service_task(async move {
1255                            let result = service
1256                                .handle_request(request, context)
1257                                .await;
1258                            let response = match result {
1259                                Ok(result) => {
1260                                    tracing::debug!(%id, ?result, "response message");
1261                                    JsonRpcMessage::response(result, id)
1262                                }
1263                                Err(error) => {
1264                                    tracing::warn!(%id, ?error, "response error");
1265                                    JsonRpcMessage::error(error, Some(id))
1266                                }
1267                            };
1268                            let _send_result = sink.send(response).await;
1269                        }.instrument(current_span));
1270                    }
1271                }
1272                Event::PeerMessage(JsonRpcMessage::Notification(JsonRpcNotification {
1273                    notification,
1274                    ..
1275                })) => {
1276                    tracing::info!(?notification, "received notification");
1277                    // catch cancelled notification
1278                    let mut notification = match notification.try_into() {
1279                        Ok::<CancelledNotification, _>(cancelled) => {
1280                            if let Some(request_id) = &cancelled.params.request_id {
1281                                if let Some(ct) = local_ct_pool.remove(request_id) {
1282                                    tracing::info!(id = %request_id, reason = cancelled.params.reason, "cancelled");
1283                                    ct.cancel();
1284                                }
1285                            }
1286                            cancelled.into()
1287                        }
1288                        Err(notification) => notification,
1289                    };
1290                    if let Some(progress_token) = notification.progress_token() {
1291                        peer.notify_progress_timeout_watcher(progress_token).await;
1292                    }
1293                    {
1294                        let service = shared_service.clone();
1295                        let mut extensions = Extensions::new();
1296                        let mut meta = NotificationMetaObject::new();
1297                        // avoid clone
1298                        std::mem::swap(&mut extensions, notification.extensions_mut());
1299                        std::mem::swap(&mut meta, notification.get_meta_mut());
1300                        let context = NotificationContext {
1301                            peer: peer.clone(),
1302                            meta,
1303                            extensions,
1304                        };
1305                        let current_span = tracing::Span::current();
1306                        spawn_service_task(async move {
1307                            let result = service.handle_notification(notification, context).await;
1308                            if let Err(error) = result {
1309                                tracing::warn!(%error, "Error sending notification");
1310                            }
1311                        }.instrument(current_span));
1312                    }
1313                }
1314                Event::PeerMessage(JsonRpcMessage::Response(JsonRpcResponse {
1315                    result,
1316                    id,
1317                    ..
1318                })) => {
1319                    if let Some(responder) = local_responder_pool.remove(&id) {
1320                        let response_result = responder.send(Ok(result));
1321                        if let Err(_error) = response_result {
1322                            tracing::warn!(%id, "Error sending response");
1323                        }
1324                    }
1325                }
1326                Event::PeerMessage(JsonRpcMessage::Error(JsonRpcError { error, id, .. })) => {
1327                    let Some(id) = id else {
1328                        // MCP error responses without an id (e.g. Parse error / Invalid Request)
1329                        // can't be routed back to a pending request — log and drop.
1330                        tracing::debug!(?error, "received id-less peer error");
1331                        continue;
1332                    };
1333                    if let Some(responder) = local_responder_pool.remove(&id) {
1334                        let _response_result = responder.send(Err(ServiceError::McpError(error)));
1335                        if let Err(_error) = _response_result {
1336                            tracing::warn!(%id, "Error sending response");
1337                        }
1338                    }
1339                }
1340            }
1341        };
1342
1343        // Drain in-flight handler responses before closing the transport.
1344        // When stdin EOF or cancellation arrives, spawned handler tasks may still
1345        // be finishing. We need to:
1346        // 1. Wait for response sends that were already spawned in the main loop
1347        // 2. Drain any remaining handler responses from the channel
1348        let drain_timeout = match &quit_reason {
1349            QuitReason::Closed => Some(Duration::from_secs(5)),
1350            QuitReason::Cancelled => Some(Duration::from_secs(2)),
1351            _ => None,
1352        };
1353        if let Some(timeout_duration) = drain_timeout {
1354            // Drop our sender so the channel closes once all handler task
1355            // clones finish sending their responses (or are dropped).
1356            drop(sink_proxy_tx);
1357            let drain_result = tokio::time::timeout(timeout_duration, async {
1358                // First, wait for any response sends already dispatched by the
1359                // main loop (these hold transport write futures).
1360                while let Some(result) = response_send_tasks.join_next().await {
1361                    if let Err(error) = result {
1362                        tracing::error!(%error, "response send task failed during drain");
1363                    }
1364                }
1365                // Then drain any handler responses still in the channel
1366                // (handlers that finished after the loop broke).
1367                while let Some(m) = sink_proxy_rx.recv().await {
1368                    if let Err(error) = transport.send(m).await {
1369                        tracing::error!(%error, "failed to send pending response during drain");
1370                        break;
1371                    }
1372                }
1373            })
1374            .await;
1375            if drain_result.is_err() {
1376                tracing::warn!("timed out draining in-flight responses");
1377            }
1378        }
1379
1380        let sink_close_result = transport.close().await;
1381        if let Err(e) = sink_close_result {
1382            tracing::error!(%e, "fail to close sink");
1383        }
1384        tracing::info!(?quit_reason, "serve finished");
1385        quit_reason
1386    }.instrument(current_span));
1387    RunningService {
1388        service,
1389        peer: peer_return,
1390        handle: Some(handle),
1391        cancellation_token: ct.clone(),
1392        dg: ct.drop_guard(),
1393    }
1394}