Skip to main content

mcp_stdio_proxy/
mcp_error.rs

1use axum::{
2    Json,
3    response::{IntoResponse, Response},
4};
5use http::StatusCode;
6use serde::{Deserialize, Serialize};
7use thiserror::Error;
8
9/// MCP 应用错误类型
10///
11/// 包含错误码和详细错误信息,便于程序化处理
12#[derive(Error, Debug)]
13pub enum AppError {
14    /// 服务未找到 (0001)
15    #[error("服务 {0} 未找到")]
16    ServiceNotFound(String),
17
18    /// 服务在重启冷却期内 (0002)
19    #[error("服务 {0} 在重启冷却期内,请稍后再试")]
20    ServiceRestartCooldown(String),
21
22    /// 服务正在启动中 (0003)
23    #[error("服务 {0} 正在启动中,请稍后再试")]
24    ServiceStartupInProgress(String),
25
26    /// 服务启动失败 (0004)
27    #[error("服务启动失败: {mcp_id}: {reason}")]
28    ServiceStartupFailed { mcp_id: String, reason: String },
29
30    /// 后端连接错误 (0005)
31    #[error("后端连接错误: {0}")]
32    BackendConnection(String),
33
34    /// 配置解析错误 (0006)
35    #[error("配置解析错误: {0}")]
36    ConfigParse(String),
37
38    /// MCP 服务器错误 (0007)
39    #[error("MCP 服务器错误: {0}")]
40    McpServerError(#[from] anyhow::Error),
41
42    /// JSON 序列化错误 (0008)
43    #[error("JSON 序列化错误: {0}")]
44    SerdeJsonError(#[from] serde_json::Error),
45
46    /// IO 错误 (0009)
47    #[error("IO 错误: {0}")]
48    IoError(#[from] std::io::Error),
49
50    /// 路由未找到 (0010)
51    #[error("路由未找到: {0}")]
52    RouteNotFound(String),
53
54    /// 无效的请求参数 (0011)
55    #[error("无效的请求参数: {0}")]
56    InvalidParameter(String),
57}
58
59impl AppError {
60    /// 获取错误码
61    pub fn error_code(&self) -> &'static str {
62        match self {
63            Self::ServiceNotFound(_) => "0001",
64            Self::ServiceRestartCooldown(_) => "0002",
65            Self::ServiceStartupInProgress(_) => "0003",
66            Self::ServiceStartupFailed { .. } => "0004",
67            Self::BackendConnection(_) => "0005",
68            Self::ConfigParse(_) => "0006",
69            Self::McpServerError(_) => "0007",
70            Self::SerdeJsonError(_) => "0008",
71            Self::IoError(_) => "0009",
72            Self::RouteNotFound(_) => "0010",
73            Self::InvalidParameter(_) => "0011",
74        }
75    }
76
77    /// 获取 HTTP 状态码
78    pub fn status_code(&self) -> StatusCode {
79        match self {
80            Self::ServiceNotFound(_) => StatusCode::NOT_FOUND,
81            Self::ServiceRestartCooldown(_) => StatusCode::TOO_MANY_REQUESTS,
82            Self::ServiceStartupInProgress(_) => StatusCode::SERVICE_UNAVAILABLE,
83            Self::ServiceStartupFailed { .. } => StatusCode::INTERNAL_SERVER_ERROR,
84            Self::BackendConnection(_) => StatusCode::BAD_GATEWAY,
85            Self::ConfigParse(_) => StatusCode::BAD_REQUEST,
86            Self::McpServerError(_) => StatusCode::INTERNAL_SERVER_ERROR,
87            Self::SerdeJsonError(_) => StatusCode::BAD_REQUEST,
88            Self::IoError(_) => StatusCode::INTERNAL_SERVER_ERROR,
89            Self::RouteNotFound(_) => StatusCode::NOT_FOUND,
90            Self::InvalidParameter(_) => StatusCode::BAD_REQUEST,
91        }
92    }
93}
94
95#[derive(Debug, Serialize, Deserialize)]
96pub struct ErrorOutput {
97    pub code: String,
98    pub error: String,
99}
100
101impl ErrorOutput {
102    pub fn with_code(code: &'static str, error: impl Into<String>) -> Self {
103        Self {
104            code: code.to_string(),
105            error: error.into(),
106        }
107    }
108}
109
110impl IntoResponse for AppError {
111    fn into_response(self) -> Response<axum::body::Body> {
112        (
113            self.status_code(),
114            Json(ErrorOutput::with_code(self.error_code(), self.to_string())),
115        )
116            .into_response()
117    }
118}