Skip to content

Commit e615300

Browse files
authored
feat: unified error type (#308)
* feat: unified error type * fix: use type id to compare transport type
1 parent c74b26b commit e615300

File tree

23 files changed

+286
-161
lines changed

23 files changed

+286
-161
lines changed

crates/rmcp-macros/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ impl ServerHandler for MyToolHandler {
134134
&self,
135135
request: CallToolRequestParam,
136136
context: RequestContext<RoleServer>,
137-
) -> Result<CallToolResult, rmcp::Error> {
137+
) -> Result<CallToolResult, rmcp::ErrorData> {
138138
let tcc = ToolCallContext::new(self, request, context);
139139
self.tool_router.call(tcc).await
140140
}
@@ -143,7 +143,7 @@ impl ServerHandler for MyToolHandler {
143143
&self,
144144
_request: Option<PaginatedRequestParam>,
145145
_context: RequestContext<RoleServer>,
146-
) -> Result<ListToolsResult, rmcp::Error> {
146+
) -> Result<ListToolsResult, rmcp::ErrorData> {
147147
let items = self.tool_router.list_all();
148148
Ok(ListToolsResult::with_all_items(items))
149149
}

crates/rmcp-macros/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ pub fn tool_router(attr: TokenStream, input: TokenStream) -> TokenStream {
139139
/// &self,
140140
/// request: CallToolRequestParam,
141141
/// context: RequestContext<RoleServer>,
142-
/// ) -> Result<CallToolResult, rmcp::Error> {
142+
/// ) -> Result<CallToolResult, rmcp::ErrorData> {
143143
/// let tcc = ToolCallContext::new(self, request, context);
144144
/// self.tool_router.call(tcc).await
145145
/// }
@@ -148,7 +148,7 @@ pub fn tool_router(attr: TokenStream, input: TokenStream) -> TokenStream {
148148
/// &self,
149149
/// _request: Option<PaginatedRequestParam>,
150150
/// _context: RequestContext<RoleServer>,
151-
/// ) -> Result<ListToolsResult, rmcp::Error> {
151+
/// ) -> Result<ListToolsResult, rmcp::ErrorData> {
152152
/// let items = self.tool_router.list_all();
153153
/// Ok(ListToolsResult::with_all_items(items))
154154
/// }

crates/rmcp-macros/src/tool_handler.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ pub fn tool_handler(attr: TokenStream, input: TokenStream) -> syn::Result<TokenS
2929
&self,
3030
request: rmcp::model::CallToolRequestParam,
3131
context: rmcp::service::RequestContext<rmcp::RoleServer>,
32-
) -> Result<rmcp::model::CallToolResult, rmcp::Error> {
32+
) -> Result<rmcp::model::CallToolResult, rmcp::ErrorData> {
3333
let tcc = rmcp::handler::server::tool::ToolCallContext::new(self, request, context);
3434
#router.call(tcc).await
3535
}
@@ -39,7 +39,7 @@ pub fn tool_handler(attr: TokenStream, input: TokenStream) -> syn::Result<TokenS
3939
&self,
4040
_request: Option<rmcp::model::PaginatedRequestParam>,
4141
_context: rmcp::service::RequestContext<rmcp::RoleServer>,
42-
) -> Result<rmcp::model::ListToolsResult, rmcp::Error> {
42+
) -> Result<rmcp::model::ListToolsResult, rmcp::ErrorData> {
4343
Ok(rmcp::model::ListToolsResult::with_all_items(#router.list_all()))
4444
}
4545
};

crates/rmcp/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ wait for the first release.
1515
Creating a server with tools is simple using the `#[tool]` macro:
1616

1717
```rust, ignore
18-
use rmcp::{Error as McpError, ServiceExt, model::*, tool, tool_handler, tool_router, transport::stdio, handler::server::router::tool::ToolRouter};
18+
use rmcp::{ErrorData as McpError, ServiceExt, model::*, tool, tool_router, transport::stdio, handler::server::tool::ToolCallContext, handler::server::router::tool::ToolRouter};
1919
use std::sync::Arc;
2020
use tokio::sync::Mutex;
2121

crates/rmcp/src/error.rs

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1-
use std::fmt::Display;
2-
3-
use crate::model::ErrorData;
1+
use std::{borrow::Cow, fmt::Display};
42

3+
use crate::ServiceError;
4+
pub use crate::model::ErrorData;
5+
#[deprecated(
6+
note = "Use `rmcp::ErrorData` instead, `rmcp::ErrorData` could become `RmcpError` in the future."
7+
)]
58
pub type Error = ErrorData;
6-
79
impl Display for ErrorData {
810
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
911
write!(f, "{}: {}", self.code.0, self.message)?;
@@ -15,3 +17,40 @@ impl Display for ErrorData {
1517
}
1618

1719
impl std::error::Error for ErrorData {}
20+
21+
/// This is an unified error type for the errors could be returned by the service.
22+
#[derive(Debug, thiserror::Error)]
23+
pub enum RmcpError {
24+
#[error("Service error: {0}")]
25+
Service(#[from] ServiceError),
26+
#[cfg(feature = "client")]
27+
#[error("Client initialization error: {0}")]
28+
ClientInitialize(#[from] crate::service::ClientInitializeError),
29+
#[cfg(feature = "server")]
30+
#[error("Server initialization error: {0}")]
31+
ServerInitialize(#[from] crate::service::ServerInitializeError),
32+
#[error("Runtime error: {0}")]
33+
Runtime(#[from] tokio::task::JoinError),
34+
#[error("Transport creation error: {error}")]
35+
// TODO: Maybe we can introduce something like `TryIntoTransport` to auto wrap transport type,
36+
// but it could be an breaking change, so we could do it in the future.
37+
TransportCreation {
38+
into_transport_type_name: Cow<'static, str>,
39+
into_transport_type_id: std::any::TypeId,
40+
#[source]
41+
error: Box<dyn std::error::Error + Send + Sync>,
42+
},
43+
// and cancellation shouldn't be an error?
44+
}
45+
46+
impl RmcpError {
47+
pub fn transport_creation<T: 'static>(
48+
error: impl Into<Box<dyn std::error::Error + Send + Sync>>,
49+
) -> Self {
50+
RmcpError::TransportCreation {
51+
into_transport_type_id: std::any::TypeId::of::<T>(),
52+
into_transport_type_name: std::any::type_name::<T>().into(),
53+
error: error.into(),
54+
}
55+
}
56+
}

crates/rmcp/src/handler/client.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
pub mod progress;
22
use crate::{
3-
error::Error as McpError,
3+
error::ErrorData as McpError,
44
model::*,
55
service::{NotificationContext, RequestContext, RoleClient, Service, ServiceRole},
66
};

crates/rmcp/src/handler/server.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::{
2-
error::Error as McpError,
2+
error::ErrorData as McpError,
33
model::*,
44
service::{NotificationContext, RequestContext, RoleServer, Service, ServiceRole},
55
};

crates/rmcp/src/handler/server/router.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ where
5151
&self,
5252
notification: <RoleServer as crate::service::ServiceRole>::PeerNot,
5353
context: NotificationContext<RoleServer>,
54-
) -> Result<(), crate::Error> {
54+
) -> Result<(), crate::ErrorData> {
5555
self.service
5656
.handle_notification(notification, context)
5757
.await
@@ -60,7 +60,7 @@ where
6060
&self,
6161
request: <RoleServer as crate::service::ServiceRole>::PeerReq,
6262
context: crate::service::RequestContext<RoleServer>,
63-
) -> Result<<RoleServer as crate::service::ServiceRole>::Resp, crate::Error> {
63+
) -> Result<<RoleServer as crate::service::ServiceRole>::Resp, crate::ErrorData> {
6464
match request {
6565
ClientRequest::CallToolRequest(request) => {
6666
if self.tool_router.has_route(request.params.name.as_ref())

crates/rmcp/src/handler/server/router/tool.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ impl<S: Send + Sync + 'static> ToolRoute<S> {
5252
where
5353
C: for<'a> Fn(
5454
ToolCallContext<'a, S>,
55-
) -> BoxFuture<'a, Result<CallToolResult, crate::Error>>
55+
) -> BoxFuture<'a, Result<CallToolResult, crate::ErrorData>>
5656
+ Send
5757
+ Sync
5858
+ 'static,
@@ -237,11 +237,11 @@ where
237237
pub async fn call(
238238
&self,
239239
context: ToolCallContext<'_, S>,
240-
) -> Result<CallToolResult, crate::Error> {
240+
) -> Result<CallToolResult, crate::ErrorData> {
241241
let item = self
242242
.map
243243
.get(context.name())
244-
.ok_or_else(|| crate::Error::invalid_params("tool not found", None))?;
244+
.ok_or_else(|| crate::ErrorData::invalid_params("tool not found", None))?;
245245
(item.call)(context).await
246246
}
247247

0 commit comments

Comments
 (0)