1use std::time::Duration;
2use thiserror::Error;
3
4#[derive(Error, Debug, Clone)]
5pub enum MCPError {
6 #[error("IO error: {message}")]
7 Io { message: String },
8
9 #[error("JSON serialization error: {message}")]
10 Json { message: String },
11
12 #[error("Transport error: {0}")]
13 Transport(String),
14
15 #[error("Transport connection failed: {message}")]
16 TransportConnectionFailed { message: String },
17
18 #[error("Transport disconnected unexpectedly")]
19 TransportDisconnected,
20
21 #[error("Protocol error: {0}")]
22 Protocol(String),
23
24 #[error("Invalid request: {0}")]
25 InvalidRequest(String),
26
27 #[error("Method not found: {0}")]
28 MethodNotFound(String),
29
30 #[error("Invalid parameters for method '{method}': {message}")]
31 InvalidParams { method: String, message: String },
32
33 #[error("Internal error: {0}")]
34 InternalError(String),
35
36 #[error("Connection closed")]
37 ConnectionClosed,
38
39 #[error("Request timeout after {duration:?} for request id: {request_id}")]
40 Timeout {
41 duration: Duration,
42 request_id: String,
43 },
44
45 #[error("Request with id {0} not found")]
46 RequestNotFound(String),
47
48 #[error("Handler error for {handler_type}: {message}")]
49 HandlerError {
50 handler_type: String,
51 message: String,
52 },
53
54 #[error("Resource not found: {uri}")]
55 ResourceNotFound { uri: String },
56
57 #[error("Tool execution failed for '{tool}': {message}")]
58 ToolExecutionFailed { tool: String, message: String },
59
60 #[error("Message too large: {size} bytes exceeds maximum of {max_size} bytes")]
61 MessageTooLarge { size: usize, max_size: usize },
62
63 #[error("Invalid message format: {message}")]
64 InvalidMessageFormat { message: String },
65
66 #[error("Codec error: {message}")]
67 CodecError { message: String },
68}
69
70impl MCPError {
71 pub fn invalid_params(method: impl Into<String>, message: impl Into<String>) -> Self {
73 Self::InvalidParams {
74 method: method.into(),
75 message: message.into(),
76 }
77 }
78
79 pub fn timeout(duration: Duration, request_id: impl Into<String>) -> Self {
81 Self::Timeout {
82 duration,
83 request_id: request_id.into(),
84 }
85 }
86
87 pub fn handler_error(handler_type: impl Into<String>, message: impl Into<String>) -> Self {
89 Self::HandlerError {
90 handler_type: handler_type.into(),
91 message: message.into(),
92 }
93 }
94
95 pub fn tool_execution_failed(tool: impl Into<String>, message: impl Into<String>) -> Self {
97 Self::ToolExecutionFailed {
98 tool: tool.into(),
99 message: message.into(),
100 }
101 }
102
103 pub fn is_retryable(&self) -> bool {
105 matches!(
106 self,
107 Self::Io { .. }
108 | Self::TransportConnectionFailed { .. }
109 | Self::TransportDisconnected
110 | Self::ConnectionClosed
111 | Self::Timeout { .. }
112 )
113 }
114}
115
116impl From<std::io::Error> for MCPError {
117 fn from(err: std::io::Error) -> Self {
118 Self::Io {
119 message: err.to_string(),
120 }
121 }
122}
123
124impl From<serde_json::Error> for MCPError {
125 fn from(err: serde_json::Error) -> Self {
126 Self::Json {
127 message: err.to_string(),
128 }
129 }
130}
131
132pub type Result<T> = std::result::Result<T, MCPError>;