ultrafast_mcp_core/
error.rs1use thiserror::Error;
4
5pub type MCPResult<T> = Result<T, MCPError>;
7
8#[derive(Debug, Error)]
10pub enum MCPError {
11 #[error("Protocol error: {0}")]
12 Protocol(#[from] ProtocolError),
13
14 #[error("Transport error: {0}")]
15 Transport(#[from] TransportError),
16
17 #[error("Tool execution error: {0}")]
18 ToolExecution(#[from] ToolError),
19
20 #[error("Resource error: {0}")]
21 Resource(#[from] ResourceError),
22
23 #[error("Authentication error: {0}")]
24 Authentication(#[from] AuthenticationError),
25
26 #[error("Validation error: {0}")]
27 Validation(#[from] ValidationError),
28
29 #[error("Rate limiting error: {0}")]
30 RateLimit(#[from] RateLimitError),
31
32 #[error("Serialization error: {0}")]
33 Serialization(#[from] serde_json::Error),
34
35 #[error("IO error: {0}")]
36 Io(#[from] std::io::Error),
37
38 #[error("Other error: {0}")]
39 Other(#[from] anyhow::Error),
40}
41
42impl MCPError {
43 pub fn invalid_params(msg: String) -> Self {
44 MCPError::Protocol(ProtocolError::InvalidParams(msg))
45 }
46
47 pub fn method_not_found(msg: String) -> Self {
48 MCPError::Protocol(ProtocolError::MethodNotFound(msg))
49 }
50
51 pub fn not_found(msg: String) -> Self {
52 MCPError::Protocol(ProtocolError::NotFound(msg))
53 }
54
55 pub fn invalid_request(msg: String) -> Self {
56 MCPError::Protocol(ProtocolError::InvalidRequest(msg))
57 }
58
59 pub fn invalid_response(msg: String) -> Self {
60 MCPError::Protocol(ProtocolError::InvalidResponse(msg))
61 }
62
63 pub fn serialization_error(msg: String) -> Self {
64 MCPError::Protocol(ProtocolError::SerializationError(msg))
65 }
66
67 pub fn transport_error(msg: String) -> Self {
68 MCPError::Transport(TransportError::ConnectionFailed(msg))
69 }
70
71 pub fn request_timeout() -> Self {
72 MCPError::Protocol(ProtocolError::RequestTimeout)
73 }
74
75 pub fn internal_error(msg: String) -> Self {
76 MCPError::Protocol(ProtocolError::InternalError(msg))
77 }
78}
79
80#[derive(Debug, Error)]
82pub enum ProtocolError {
83 #[error("Invalid JSON-RPC version: {0}")]
84 InvalidVersion(String),
85
86 #[error("Invalid request ID: {0}")]
87 InvalidRequestId(String),
88
89 #[error("Method not found: {0}")]
90 MethodNotFound(String),
91
92 #[error("Invalid parameters: {0}")]
93 InvalidParams(String),
94
95 #[error("Invalid request: {0}")]
96 InvalidRequest(String),
97
98 #[error("Invalid response: {0}")]
99 InvalidResponse(String),
100
101 #[error("Request timeout")]
102 RequestTimeout,
103
104 #[error("Internal error: {0}")]
105 InternalError(String),
106
107 #[error("Initialization failed: {0}")]
108 InitializationFailed(String),
109
110 #[error("Capability not supported: {0}")]
111 CapabilityNotSupported(String),
112
113 #[error("Not found: {0}")]
114 NotFound(String),
115
116 #[error("Connection closed")]
117 ConnectionClosed,
118
119 #[error("Transport error: {0}")]
120 TransportError(String),
121
122 #[error("Serialization error: {0}")]
123 SerializationError(String),
124
125 #[error("Authentication error: {0}")]
126 AuthenticationError(String),
127}
128
129#[derive(Debug, Error)]
131pub enum TransportError {
132 #[error("Connection failed: {0}")]
133 ConnectionFailed(String),
134
135 #[error("Connection closed")]
136 ConnectionClosed,
137
138 #[error("Send failed: {0}")]
139 SendFailed(String),
140
141 #[error("Receive failed: {0}")]
142 ReceiveFailed(String),
143}
144
145#[derive(Debug, Error)]
147pub enum ToolError {
148 #[error("Tool not found: {0}")]
149 NotFound(String),
150
151 #[error("Tool execution failed: {0}")]
152 ExecutionFailed(String),
153
154 #[error("Invalid input: {0}")]
155 InvalidInput(String),
156
157 #[error("Schema validation failed: {0}")]
158 SchemaValidation(String),
159}
160
161#[derive(Debug, Error)]
163pub enum ResourceError {
164 #[error("Resource not found: {0}")]
165 NotFound(String),
166
167 #[error("Access denied: {0}")]
168 AccessDenied(String),
169
170 #[error("Invalid URI: {0}")]
171 InvalidUri(String),
172
173 #[error("Content type mismatch: expected {expected}, got {actual}")]
174 ContentTypeMismatch { expected: String, actual: String },
175}
176
177#[derive(Debug, Error)]
179pub enum AuthenticationError {
180 #[error("Invalid credentials")]
181 InvalidCredentials,
182
183 #[error("Token expired")]
184 TokenExpired,
185
186 #[error("Insufficient permissions for resource: {resource}")]
187 InsufficientPermissions { resource: String },
188
189 #[error("OAuth error: {error} - {description}")]
190 OAuthError { error: String, description: String },
191}
192
193#[derive(Debug, Error)]
195pub enum ValidationError {
196 #[error("Schema validation failed for field '{field}': {details}")]
197 SchemaValidation { field: String, details: String },
198
199 #[error("Required field '{field}' is missing")]
200 RequiredField { field: String },
201
202 #[error("Invalid format for field '{field}': expected {expected}")]
203 InvalidFormat { field: String, expected: String },
204
205 #[error("Value for field '{field}' is out of range: {actual} (expected {min}..{max})")]
206 ValueOutOfRange {
207 field: String,
208 min: String,
209 max: String,
210 actual: String,
211 },
212}
213
214#[derive(Debug, Error)]
216pub enum RateLimitError {
217 #[error("Too many requests. Retry after {retry_after}ms. Limit: {limit}")]
218 TooManyRequests { retry_after: u64, limit: u32 },
219
220 #[error("Quota exceeded: {quota} requests per {period}")]
221 QuotaExceeded { quota: u32, period: String },
222}
223
224pub mod error_codes {
226 pub const PARSE_ERROR: i32 = -32700;
227 pub const INVALID_REQUEST: i32 = -32600;
228 pub const METHOD_NOT_FOUND: i32 = -32601;
229 pub const INVALID_PARAMS: i32 = -32602;
230 pub const INTERNAL_ERROR: i32 = -32603;
231
232 pub const INITIALIZATION_FAILED: i32 = -32000;
234 pub const CAPABILITY_NOT_SUPPORTED: i32 = -32001;
235 pub const RESOURCE_NOT_FOUND: i32 = -32002;
236 pub const TOOL_EXECUTION_ERROR: i32 = -32003;
237 pub const INVALID_URI: i32 = -32004;
238 pub const ACCESS_DENIED: i32 = -32005;
239 pub const AUTHENTICATION_ERROR: i32 = -32006;
240 pub const VALIDATION_ERROR: i32 = -32007;
241 pub const RATE_LIMIT_ERROR: i32 = -32008;
242}
243
244impl From<crate::protocol::jsonrpc::JsonRpcError> for MCPError {
245 fn from(err: crate::protocol::jsonrpc::JsonRpcError) -> Self {
246 match err.code {
247 error_codes::PARSE_ERROR => {
248 MCPError::Protocol(ProtocolError::SerializationError(err.message))
249 }
250 error_codes::INVALID_REQUEST => {
251 MCPError::Protocol(ProtocolError::InvalidRequest(err.message))
252 }
253 error_codes::METHOD_NOT_FOUND => {
254 MCPError::Protocol(ProtocolError::MethodNotFound(err.message))
255 }
256 error_codes::INVALID_PARAMS => {
257 MCPError::Protocol(ProtocolError::InvalidParams(err.message))
258 }
259 error_codes::INTERNAL_ERROR => {
260 MCPError::Protocol(ProtocolError::InternalError(err.message))
261 }
262 error_codes::INITIALIZATION_FAILED => {
263 MCPError::Protocol(ProtocolError::InitializationFailed(err.message))
264 }
265 error_codes::CAPABILITY_NOT_SUPPORTED => {
266 MCPError::Protocol(ProtocolError::CapabilityNotSupported(err.message))
267 }
268 error_codes::RESOURCE_NOT_FOUND => {
269 MCPError::Resource(ResourceError::NotFound(err.message))
270 }
271 error_codes::TOOL_EXECUTION_ERROR => {
272 MCPError::ToolExecution(ToolError::ExecutionFailed(err.message))
273 }
274 error_codes::INVALID_URI => MCPError::Resource(ResourceError::InvalidUri(err.message)),
275 error_codes::ACCESS_DENIED => {
276 MCPError::Resource(ResourceError::AccessDenied(err.message))
277 }
278 error_codes::AUTHENTICATION_ERROR => {
279 MCPError::Authentication(AuthenticationError::InvalidCredentials)
280 }
281 error_codes::VALIDATION_ERROR => {
282 MCPError::Validation(ValidationError::SchemaValidation {
283 field: "unknown".to_string(),
284 details: err.message,
285 })
286 }
287 error_codes::RATE_LIMIT_ERROR => MCPError::RateLimit(RateLimitError::TooManyRequests {
288 retry_after: 0,
289 limit: 0,
290 }),
291 _ => MCPError::Protocol(ProtocolError::InternalError(err.message)),
292 }
293 }
294}
295
296#[cfg(test)]
297mod tests {
298 use super::*;
299
300 #[test]
301 fn test_error_variant_conversion() {
302 let error = MCPError::invalid_params("test".to_string());
303 assert!(matches!(
304 error,
305 MCPError::Protocol(ProtocolError::InvalidParams(_))
306 ));
307
308 let error = MCPError::method_not_found("test".to_string());
309 assert!(matches!(
310 error,
311 MCPError::Protocol(ProtocolError::MethodNotFound(_))
312 ));
313 }
314
315 #[test]
316 fn test_error_creation() {
317 let error = MCPError::internal_error("test error".to_string());
318 assert!(matches!(
319 error,
320 MCPError::Protocol(ProtocolError::InternalError(_))
321 ));
322 }
323}