1use protocol_transport_core::{ProtocolError, TransportError};
9use thiserror::Error;
10
11#[derive(Error, Debug)]
13pub enum McpError {
14 #[error("JSON-RPC error: {0}")]
15 JsonRpc(String),
16
17 #[error("Authentication failed: {0}")]
18 Authentication(String),
19
20 #[error("Authorization failed: {0}")]
21 Authorization(String),
22
23 #[error("Tool not found: {0}")]
24 ToolNotFound(String),
25
26 #[error("Tool execution failed: {0}")]
27 ToolExecutionFailed(String),
28
29 #[error("Memory operation failed: {0}")]
30 MemoryOperationFailed(String),
31
32 #[error("Invalid tool parameters: {0}")]
33 InvalidToolParameters(String),
34
35 #[error("Protocol version mismatch: expected {expected}, got {actual}")]
36 ProtocolVersionMismatch { expected: String, actual: String },
37
38 #[error("Server capability not supported: {0}")]
39 UnsupportedCapability(String),
40
41 #[error("Request timeout: {0}")]
42 Timeout(String),
43
44 #[error("External MCP server error: {0}")]
45 ExternalServerError(String),
46
47 #[error("Transport error: {0}")]
48 Transport(#[from] TransportError),
49
50 #[error("Protocol error: {0}")]
51 Protocol(#[from] ProtocolError),
52
53 #[error("Serialization error: {0}")]
54 Serialization(#[from] serde_json::Error),
55}
56
57impl McpError {
58 pub fn is_retryable(&self) -> bool {
60 match self {
61 McpError::Timeout(_) => true,
62 McpError::ExternalServerError(_) => true,
63 McpError::Transport(te) => te.is_retryable(),
64 McpError::Protocol(pe) => pe.is_retryable(),
65 _ => false,
66 }
67 }
68
69 pub fn is_auth_error(&self) -> bool {
71 matches!(
72 self,
73 McpError::Authentication(_) | McpError::Authorization(_)
74 )
75 }
76
77 pub fn to_jsonrpc_code(&self) -> i32 {
79 match self {
80 McpError::JsonRpc(_) => -32603,
81 McpError::Authentication(_) => -32001,
82 McpError::Authorization(_) => -32002,
83 McpError::ToolNotFound(_) => -32601,
84 McpError::ToolExecutionFailed(_) => -32603,
85 McpError::MemoryOperationFailed(_) => -32603,
86 McpError::InvalidToolParameters(_) => -32602,
87 McpError::ProtocolVersionMismatch { .. } => -32600,
88 McpError::UnsupportedCapability(_) => -32601,
89 McpError::Timeout(_) => -32003,
90 McpError::ExternalServerError(_) => -32004,
91 McpError::Transport(_) => -32603,
92 McpError::Protocol(_) => -32603,
93 McpError::Serialization(_) => -32700,
94 }
95 }
96}
97
98pub type McpResult<T> = Result<T, McpError>;
100
101impl From<McpError> for ProtocolError {
103 fn from(err: McpError) -> Self {
104 match err {
105 McpError::Transport(te) => ProtocolError::Transport(te),
106 McpError::Protocol(pe) => pe,
107 McpError::Serialization(se) => ProtocolError::Serialization(se),
108 other => ProtocolError::Internal(other.to_string()),
109 }
110 }
111}