1use thiserror::Error;
2
3#[derive(Error, Debug)]
4pub enum MCPError {
5 #[error("Parse error: {0}")]
6 ParseError(String),
7
8 #[error("Method not found: {0}")]
9 MethodNotFound(String),
10
11 #[error("Invalid params: {0}")]
12 InvalidParams(String),
13
14 #[error("Database error: {0}")]
15 DatabaseError(#[from] tokio_postgres::Error),
16
17 #[error("Connection pool error: {0}")]
18 PoolError(String),
19
20 #[error("IO error: {0}")]
21 IoError(#[from] std::io::Error),
22
23 #[error("JSON error: {0}")]
24 JsonError(#[from] serde_json::Error),
25}
26
27impl MCPError {
28 pub fn error_code(&self) -> i64 {
29 match self {
30 MCPError::ParseError(_) => -32700,
31 MCPError::MethodNotFound(_) => -32601,
32 MCPError::InvalidParams(_) => -32602,
33 MCPError::DatabaseError(_) => -32000,
34 MCPError::PoolError(_) => -32001,
35 MCPError::IoError(_) => -32003,
36 MCPError::JsonError(_) => -32700,
37 }
38 }
39}
40
41pub type Result<T> = std::result::Result<T, MCPError>;
42
43#[cfg(test)]
44mod tests {
45 use super::*;
46
47 #[test]
48 fn test_parse_error_code() {
49 let err = MCPError::ParseError("bad json".into());
50 assert_eq!(err.error_code(), -32700);
51 }
52
53 #[test]
54 fn test_method_not_found_code() {
55 let err = MCPError::MethodNotFound("unknown".into());
56 assert_eq!(err.error_code(), -32601);
57 }
58
59 #[test]
60 fn test_invalid_params_code() {
61 let err = MCPError::InvalidParams("missing field".into());
62 assert_eq!(err.error_code(), -32602);
63 }
64
65 #[test]
66 fn test_database_error_code() {
67 assert_eq!(-32000i64, -32000);
70 }
71
72 #[test]
73 fn test_pool_error_code() {
74 let err = MCPError::PoolError("timeout".into());
75 assert_eq!(err.error_code(), -32001);
76 }
77
78 #[test]
79 fn test_io_error_code() {
80 let io_err = std::io::Error::new(std::io::ErrorKind::ConnectionRefused, "refused");
81 let err = MCPError::from(io_err);
82 assert_eq!(err.error_code(), -32003);
83 }
84
85 #[test]
86 fn test_json_error_code() {
87 let json_err = serde_json::from_str::<()>("invalid").unwrap_err();
88 let err = MCPError::from(json_err);
89 assert_eq!(err.error_code(), -32700);
90 }
91
92 #[test]
93 fn test_parse_error_display() {
94 let err = MCPError::ParseError("bad token".into());
95 assert_eq!(err.to_string(), "Parse error: bad token");
96 }
97
98 #[test]
99 fn test_method_not_found_display() {
100 let err = MCPError::MethodNotFound("foo".into());
101 assert_eq!(err.to_string(), "Method not found: foo");
102 }
103
104 #[test]
105 fn test_invalid_params_display() {
106 let err = MCPError::InvalidParams("missing x".into());
107 assert_eq!(err.to_string(), "Invalid params: missing x");
108 }
109
110 #[test]
111 fn test_pool_error_display() {
112 let err = MCPError::PoolError("exhausted".into());
113 assert_eq!(err.to_string(), "Connection pool error: exhausted");
114 }
115
116 #[test]
117 fn test_debug_format() {
118 let err = MCPError::InvalidParams("bad".into());
119 let debug = format!("{:?}", err);
120 assert!(debug.contains("InvalidParams"));
121 assert!(debug.contains("bad"));
122 }
123
124 #[test]
125 fn test_result_type() {
126 let ok: Result<i32> = Ok(42);
127 assert!(ok.is_ok());
128 let err: Result<i32> = Err(MCPError::PoolError("fail".into()));
129 assert!(err.is_err());
130 }
131
132 #[test]
133 fn test_error_clone_via_debug() {
134 let err = MCPError::MethodNotFound("test".into());
135 let json_err = serde_json::to_value(&format!("{:?}", err)).unwrap();
136 assert!(json_err.as_str().unwrap().contains("MethodNotFound"));
137 }
138}