httpmcp_rust/
error.rs

1use crate::jsonrpc::{error_codes, JsonRpcError};
2use actix_web::{http::StatusCode, HttpResponse, ResponseError};
3use thiserror::Error;
4
5#[derive(Debug, Error)]
6pub enum McpError {
7    #[error("Parse error: {0}")]
8    ParseError(String),
9
10    #[error("Invalid request: {0}")]
11    InvalidRequest(String),
12
13    #[error("Method not found: {0}")]
14    MethodNotFound(String),
15
16    #[error("Invalid params: {0}")]
17    InvalidParams(String),
18
19    #[error("Internal error: {0}")]
20    InternalError(String),
21
22    #[error("Resource not found: {0}")]
23    ResourceNotFound(String),
24
25    #[error("Tool not found: {0}")]
26    ToolNotFound(String),
27
28    #[error("Prompt not found: {0}")]
29    PromptNotFound(String),
30
31    #[error("Authentication required")]
32    AuthenticationRequired,
33
34    #[error("Authorization failed: {0}")]
35    AuthorizationFailed(String),
36
37    #[error("Serialization error: {0}")]
38    SerializationError(#[from] serde_json::Error),
39
40    #[error("IO error: {0}")]
41    IoError(#[from] std::io::Error),
42
43    #[error("JSON-RPC error: {0}")]
44    JsonRpcError(String),
45}
46
47impl From<JsonRpcError> for McpError {
48    fn from(err: JsonRpcError) -> Self {
49        McpError::JsonRpcError(err.message)
50    }
51}
52
53impl McpError {
54    pub fn to_jsonrpc_error(&self) -> JsonRpcError {
55        match self {
56            McpError::ParseError(msg) => JsonRpcError {
57                code: error_codes::PARSE_ERROR,
58                message: msg.clone(),
59                data: None,
60            },
61            McpError::InvalidRequest(msg) => JsonRpcError {
62                code: error_codes::INVALID_REQUEST,
63                message: msg.clone(),
64                data: None,
65            },
66            McpError::MethodNotFound(msg) => JsonRpcError {
67                code: error_codes::METHOD_NOT_FOUND,
68                message: msg.clone(),
69                data: None,
70            },
71            McpError::InvalidParams(msg) => JsonRpcError {
72                code: error_codes::INVALID_PARAMS,
73                message: msg.clone(),
74                data: None,
75            },
76            McpError::InternalError(msg) => JsonRpcError {
77                code: error_codes::INTERNAL_ERROR,
78                message: msg.clone(),
79                data: None,
80            },
81            McpError::ResourceNotFound(uri) => JsonRpcError {
82                code: error_codes::RESOURCE_NOT_FOUND,
83                message: format!("Resource not found: {}", uri),
84                data: Some(serde_json::json!({ "uri": uri })),
85            },
86            McpError::ToolNotFound(name) => JsonRpcError {
87                code: error_codes::METHOD_NOT_FOUND,
88                message: format!("Tool not found: {}", name),
89                data: Some(serde_json::json!({ "tool": name })),
90            },
91            McpError::PromptNotFound(name) => JsonRpcError {
92                code: error_codes::METHOD_NOT_FOUND,
93                message: format!("Prompt not found: {}", name),
94                data: Some(serde_json::json!({ "prompt": name })),
95            },
96            McpError::AuthenticationRequired => JsonRpcError {
97                code: error_codes::INVALID_REQUEST,
98                message: "Authentication required".to_string(),
99                data: None,
100            },
101            McpError::AuthorizationFailed(msg) => JsonRpcError {
102                code: error_codes::INVALID_REQUEST,
103                message: format!("Authorization failed: {}", msg),
104                data: None,
105            },
106            McpError::SerializationError(e) => JsonRpcError {
107                code: error_codes::INTERNAL_ERROR,
108                message: format!("Serialization error: {}", e),
109                data: None,
110            },
111            McpError::IoError(e) => JsonRpcError {
112                code: error_codes::INTERNAL_ERROR,
113                message: format!("IO error: {}", e),
114                data: None,
115            },
116            McpError::JsonRpcError(msg) => JsonRpcError {
117                code: error_codes::INTERNAL_ERROR,
118                message: msg.clone(),
119                data: None,
120            },
121        }
122    }
123}
124
125impl ResponseError for McpError {
126    fn status_code(&self) -> StatusCode {
127        match self {
128            McpError::ParseError(_) => StatusCode::BAD_REQUEST,
129            McpError::InvalidRequest(_) => StatusCode::BAD_REQUEST,
130            McpError::MethodNotFound(_) => StatusCode::NOT_FOUND,
131            McpError::InvalidParams(_) => StatusCode::BAD_REQUEST,
132            McpError::ResourceNotFound(_) => StatusCode::NOT_FOUND,
133            McpError::ToolNotFound(_) => StatusCode::NOT_FOUND,
134            McpError::PromptNotFound(_) => StatusCode::NOT_FOUND,
135            McpError::AuthenticationRequired => StatusCode::UNAUTHORIZED,
136            McpError::AuthorizationFailed(_) => StatusCode::FORBIDDEN,
137            _ => StatusCode::INTERNAL_SERVER_ERROR,
138        }
139    }
140
141    fn error_response(&self) -> HttpResponse {
142        let jsonrpc_error = self.to_jsonrpc_error();
143        HttpResponse::build(self.status_code()).json(serde_json::json!({
144            "jsonrpc": "2.0",
145            "error": jsonrpc_error,
146            "id": null
147        }))
148    }
149}
150
151pub type Result<T> = std::result::Result<T, McpError>;