rust_mcp_transport/
error.rs

1use crate::schema::{schema_utils::SdkError, RpcError};
2use crate::utils::CancellationError;
3use core::fmt;
4#[cfg(any(feature = "sse", feature = "streamable-http"))]
5use reqwest::Error as ReqwestError;
6#[cfg(any(feature = "sse", feature = "streamable-http"))]
7use reqwest::StatusCode;
8use std::any::Any;
9use std::io::Error as IoError;
10use thiserror::Error;
11use tokio::sync::{broadcast, mpsc};
12/// A wrapper around a broadcast send error. This structure allows for generic error handling
13/// by boxing the underlying error into a type-erased form.
14#[derive(Debug)]
15pub struct GenericSendError {
16    inner: Box<dyn Any + Send>,
17}
18
19#[allow(unused)]
20impl GenericSendError {
21    pub fn new<T: Send + 'static>(error: mpsc::error::SendError<T>) -> Self {
22        Self {
23            inner: Box::new(error),
24        }
25    }
26
27    /// Attempts to downcast the wrapped error to a specific `broadcast::error::SendError` type.
28    ///
29    /// # Returns
30    /// `Some(T)` if the error can be downcasted, `None` otherwise.
31    fn downcast<T: Send + 'static>(self) -> Option<broadcast::error::SendError<T>> {
32        self.inner
33            .downcast::<broadcast::error::SendError<T>>()
34            .ok()
35            .map(|boxed| *boxed)
36    }
37}
38
39impl fmt::Display for GenericSendError {
40    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
41        write!(f, "Broadcast SendError: Failed to send a message.")
42    }
43}
44// Implementing `Error` trait
45impl std::error::Error for GenericSendError {}
46
47/// A wrapper around a broadcast send error. This structure allows for generic error handling
48/// by boxing the underlying error into a type-erased form.
49#[derive(Debug)]
50pub struct GenericWatchSendError {
51    inner: Box<dyn Any + Send>,
52}
53
54#[allow(unused)]
55impl GenericWatchSendError {
56    pub fn new<T: Send + 'static>(error: tokio::sync::watch::error::SendError<T>) -> Self {
57        Self {
58            inner: Box::new(error),
59        }
60    }
61
62    /// Attempts to downcast the wrapped error to a specific `broadcast::error::SendError` type.
63    ///
64    /// # Returns
65    /// `Some(T)` if the error can be downcasted, `None` otherwise.
66    fn downcast<T: Send + 'static>(self) -> Option<tokio::sync::watch::error::SendError<T>> {
67        self.inner
68            .downcast::<tokio::sync::watch::error::SendError<T>>()
69            .ok()
70            .map(|boxed| *boxed)
71    }
72}
73
74impl fmt::Display for GenericWatchSendError {
75    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
76        write!(f, "Watch SendError: Failed to send a message.")
77    }
78}
79// Implementing `Error` trait
80impl std::error::Error for GenericWatchSendError {}
81
82pub type TransportResult<T> = core::result::Result<T, TransportError>;
83
84#[derive(Debug, Error)]
85pub enum TransportError {
86    #[error("Session expired or not found")]
87    SessionExpired,
88
89    #[error("Failed to open SSE stream: {0}")]
90    FailedToOpenSSEStream(String),
91
92    #[error("Unexpected content type: '{0}'")]
93    UnexpectedContentType(String),
94
95    #[error("Failed to send message: {0}")]
96    SendFailure(String),
97
98    #[error("I/O error: {0}")]
99    Io(#[from] IoError),
100
101    #[cfg(any(feature = "sse", feature = "streamable-http"))]
102    #[error("HTTP connection error: {0}")]
103    HttpConnection(#[from] ReqwestError),
104
105    #[cfg(any(feature = "sse", feature = "streamable-http"))]
106    #[error("HTTP error: {0}")]
107    Http(StatusCode),
108
109    #[error("SDK error: {0}")]
110    Sdk(#[from] SdkError),
111
112    #[error("Operation cancelled: {0}")]
113    Cancelled(#[from] CancellationError),
114
115    #[error("Channel closed: {0}")]
116    ChannelClosed(#[from] tokio::sync::oneshot::error::RecvError),
117
118    #[error("Configuration error: {message}")]
119    Configuration { message: String },
120
121    #[error("{0}")]
122    SendError(#[from] GenericSendError),
123
124    #[error("{0}")]
125    JsonrpcError(#[from] RpcError),
126
127    #[error("Process error: {0}")]
128    ProcessError(String),
129
130    #[error("Internal error: {0}")]
131    Internal(String),
132
133    #[error("Shutdown timed out")]
134    ShutdownTimeout,
135}