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>;