Skip to main content

mcp_stdio_proxy/
mcp_error.rs

1use axum::{
2    Json,
3    response::{IntoResponse, Response},
4};
5use http::StatusCode;
6use mcp_common::t;
7use serde::{Deserialize, Serialize};
8use thiserror::Error;
9
10/// MCP 应用错误类型
11///
12/// 包含错误码和详细错误信息,便于程序化处理
13#[derive(Error, Debug)]
14pub enum AppError {
15    /// 服务未找到 (0001)
16    #[error("{0}")]
17    ServiceNotFound(String),
18
19    /// 服务在重启冷却期内 (0002)
20    #[error("{0}")]
21    ServiceRestartCooldown(String),
22
23    /// 服务正在启动中 (0003)
24    #[error("{0}")]
25    ServiceStartupInProgress(String),
26
27    /// 服务启动失败 (0004)
28    #[error("{0}")]
29    ServiceStartupFailed(String),
30
31    /// 后端连接错误 (0005)
32    #[error("{0}")]
33    BackendConnection(String),
34
35    /// 配置解析错误 (0006)
36    #[error("{0}")]
37    ConfigParse(String),
38
39    /// MCP 服务器错误 (0007)
40    #[error("{0}")]
41    McpServerError(String),
42
43    /// JSON 序列化错误 (0008)
44    #[error("{0}")]
45    SerdeJsonError(String),
46
47    /// IO 错误 (0009)
48    #[error("{0}")]
49    IoError(String),
50
51    /// 路由未找到 (0010)
52    #[error("{0}")]
53    RouteNotFound(String),
54
55    /// 无效的请求参数 (0011)
56    #[error("{0}")]
57    InvalidParameter(String),
58}
59
60impl AppError {
61    // ===========================================
62    // 工厂方法 - 创建带国际化消息的错误
63    // ===========================================
64
65    /// 创建服务未找到错误
66    pub fn service_not_found(service: impl Into<String>) -> Self {
67        Self::ServiceNotFound(
68            t!(
69                "errors.mcp_proxy.service_not_found",
70                service = service.into()
71            )
72            .to_string(),
73        )
74    }
75
76    /// 创建服务重启冷却期错误
77    pub fn service_restart_cooldown(service: impl Into<String>) -> Self {
78        Self::ServiceRestartCooldown(
79            t!(
80                "errors.mcp_proxy.service_restart_cooldown",
81                service = service.into()
82            )
83            .to_string(),
84        )
85    }
86
87    /// 创建服务启动中错误
88    pub fn service_startup_in_progress(service: impl Into<String>) -> Self {
89        Self::ServiceStartupInProgress(
90            t!(
91                "errors.mcp_proxy.service_startup_in_progress",
92                service = service.into()
93            )
94            .to_string(),
95        )
96    }
97
98    /// 创建服务启动失败错误
99    pub fn service_startup_failed(mcp_id: impl Into<String>, reason: impl Into<String>) -> Self {
100        Self::ServiceStartupFailed(
101            t!(
102                "errors.mcp_proxy.service_startup_failed",
103                mcp_id = mcp_id.into(),
104                reason = reason.into()
105            )
106            .to_string(),
107        )
108    }
109
110    /// 创建后端连接错误
111    pub fn backend_connection(detail: impl Into<String>) -> Self {
112        Self::BackendConnection(
113            t!(
114                "errors.mcp_proxy.backend_connection",
115                detail = detail.into()
116            )
117            .to_string(),
118        )
119    }
120
121    /// 创建配置解析错误
122    pub fn config_parse(detail: impl Into<String>) -> Self {
123        Self::ConfigParse(t!("errors.mcp_proxy.config_parse", detail = detail.into()).to_string())
124    }
125
126    /// 创建 MCP 服务器错误
127    pub fn mcp_server_error(detail: impl Into<String>) -> Self {
128        Self::McpServerError(
129            t!("errors.mcp_proxy.mcp_server_error", detail = detail.into()).to_string(),
130        )
131    }
132
133    /// 创建 JSON 序列化错误
134    pub fn json_serialization(detail: impl Into<String>) -> Self {
135        Self::SerdeJsonError(
136            t!(
137                "errors.mcp_proxy.json_serialization",
138                detail = detail.into()
139            )
140            .to_string(),
141        )
142    }
143
144    /// 创建 IO 错误
145    pub fn io_error(detail: impl Into<String>) -> Self {
146        Self::IoError(t!("errors.mcp_proxy.io_error", detail = detail.into()).to_string())
147    }
148
149    /// 创建路由未找到错误
150    pub fn route_not_found(path: impl Into<String>) -> Self {
151        Self::RouteNotFound(t!("errors.mcp_proxy.route_not_found", path = path.into()).to_string())
152    }
153
154    /// 创建无效参数错误
155    pub fn invalid_parameter(detail: impl Into<String>) -> Self {
156        Self::InvalidParameter(
157            t!("errors.mcp_proxy.invalid_parameter", detail = detail.into()).to_string(),
158        )
159    }
160
161    // ===========================================
162    // 错误码和状态码
163    // ===========================================
164
165    /// 获取错误码
166    pub fn error_code(&self) -> &'static str {
167        match self {
168            Self::ServiceNotFound(_) => "0001",
169            Self::ServiceRestartCooldown(_) => "0002",
170            Self::ServiceStartupInProgress(_) => "0003",
171            Self::ServiceStartupFailed { .. } => "0004",
172            Self::BackendConnection(_) => "0005",
173            Self::ConfigParse(_) => "0006",
174            Self::McpServerError(_) => "0007",
175            Self::SerdeJsonError(_) => "0008",
176            Self::IoError(_) => "0009",
177            Self::RouteNotFound(_) => "0010",
178            Self::InvalidParameter(_) => "0011",
179        }
180    }
181
182    /// 获取 HTTP 状态码
183    pub fn status_code(&self) -> StatusCode {
184        match self {
185            Self::ServiceNotFound(_) => StatusCode::NOT_FOUND,
186            Self::ServiceRestartCooldown(_) => StatusCode::TOO_MANY_REQUESTS,
187            Self::ServiceStartupInProgress(_) => StatusCode::SERVICE_UNAVAILABLE,
188            Self::ServiceStartupFailed { .. } => StatusCode::INTERNAL_SERVER_ERROR,
189            Self::BackendConnection(_) => StatusCode::BAD_GATEWAY,
190            Self::ConfigParse(_) => StatusCode::BAD_REQUEST,
191            Self::McpServerError(_) => StatusCode::INTERNAL_SERVER_ERROR,
192            Self::SerdeJsonError(_) => StatusCode::BAD_REQUEST,
193            Self::IoError(_) => StatusCode::INTERNAL_SERVER_ERROR,
194            Self::RouteNotFound(_) => StatusCode::NOT_FOUND,
195            Self::InvalidParameter(_) => StatusCode::BAD_REQUEST,
196        }
197    }
198}
199
200// ===========================================
201// 从外部错误类型转换
202// ===========================================
203
204impl From<anyhow::Error> for AppError {
205    fn from(err: anyhow::Error) -> Self {
206        Self::mcp_server_error(err.to_string())
207    }
208}
209
210impl From<serde_json::Error> for AppError {
211    fn from(err: serde_json::Error) -> Self {
212        Self::json_serialization(err.to_string())
213    }
214}
215
216impl From<std::io::Error> for AppError {
217    fn from(err: std::io::Error) -> Self {
218        Self::io_error(err.to_string())
219    }
220}
221
222#[derive(Debug, Serialize, Deserialize)]
223pub struct ErrorOutput {
224    pub code: String,
225    pub error: String,
226}
227
228impl ErrorOutput {
229    pub fn with_code(code: &'static str, error: impl Into<String>) -> Self {
230        Self {
231            code: code.to_string(),
232            error: error.into(),
233        }
234    }
235}
236
237impl IntoResponse for AppError {
238    fn into_response(self) -> Response<axum::body::Body> {
239        (
240            self.status_code(),
241            Json(ErrorOutput::with_code(self.error_code(), self.to_string())),
242        )
243            .into_response()
244    }
245}