brainwires_mcp_server/
error.rs1use brainwires_mcp::JsonRpcError;
2
3#[derive(Debug, thiserror::Error)]
5pub enum AgentNetworkError {
6 #[error("Parse error: {0}")]
8 ParseError(String),
9 #[error("Method not found: {0}")]
11 MethodNotFound(String),
12 #[error("Invalid params: {0}")]
14 InvalidParams(String),
15 #[error("Internal error: {0}")]
17 Internal(#[from] anyhow::Error),
18 #[error("Transport error: {0}")]
20 Transport(String),
21 #[error("Tool not found: {0}")]
23 ToolNotFound(String),
24 #[error("Rate limited")]
26 RateLimited,
27 #[error("Unauthorized")]
29 Unauthorized,
30}
31
32impl AgentNetworkError {
33 pub fn to_json_rpc_error(&self) -> JsonRpcError {
35 match self {
36 AgentNetworkError::ParseError(msg) => JsonRpcError {
37 code: -32700,
38 message: msg.clone(),
39 data: None,
40 },
41 AgentNetworkError::MethodNotFound(method) => JsonRpcError {
42 code: -32601,
43 message: format!("Method not found: {method}"),
44 data: None,
45 },
46 AgentNetworkError::InvalidParams(msg) => JsonRpcError {
47 code: -32602,
48 message: msg.clone(),
49 data: None,
50 },
51 AgentNetworkError::Internal(err) => JsonRpcError {
52 code: -32603,
53 message: err.to_string(),
54 data: None,
55 },
56 AgentNetworkError::Transport(msg) => JsonRpcError {
57 code: -32000,
58 message: format!("Transport error: {msg}"),
59 data: None,
60 },
61 AgentNetworkError::ToolNotFound(name) => JsonRpcError {
62 code: -32001,
63 message: format!("Tool not found: {name}"),
64 data: None,
65 },
66 AgentNetworkError::RateLimited => JsonRpcError {
67 code: -32002,
68 message: "Rate limited".to_string(),
69 data: None,
70 },
71 AgentNetworkError::Unauthorized => JsonRpcError {
72 code: -32003,
73 message: "Unauthorized".to_string(),
74 data: None,
75 },
76 }
77 }
78}
79
80#[cfg(test)]
81mod tests {
82 use super::*;
83
84 #[test]
85 fn parse_error_code_is_minus_32700() {
86 let err = AgentNetworkError::ParseError("bad JSON".to_string());
87 assert_eq!(err.to_json_rpc_error().code, -32700);
88 }
89
90 #[test]
91 fn method_not_found_code_is_minus_32601() {
92 let err = AgentNetworkError::MethodNotFound("unknownMethod".to_string());
93 let rpc = err.to_json_rpc_error();
94 assert_eq!(rpc.code, -32601);
95 assert!(rpc.message.contains("unknownMethod"));
96 }
97
98 #[test]
99 fn invalid_params_code_is_minus_32602() {
100 let err = AgentNetworkError::InvalidParams("missing field".to_string());
101 assert_eq!(err.to_json_rpc_error().code, -32602);
102 }
103
104 #[test]
105 fn internal_error_code_is_minus_32603() {
106 let err = AgentNetworkError::Internal(anyhow::anyhow!("database down"));
107 let rpc = err.to_json_rpc_error();
108 assert_eq!(rpc.code, -32603);
109 assert!(rpc.message.contains("database down"));
110 }
111
112 #[test]
113 fn transport_error_code_is_minus_32000() {
114 let err = AgentNetworkError::Transport("connection reset".to_string());
115 let rpc = err.to_json_rpc_error();
116 assert_eq!(rpc.code, -32000);
117 assert!(rpc.message.contains("connection reset"));
118 }
119
120 #[test]
121 fn tool_not_found_code_is_minus_32001() {
122 let err = AgentNetworkError::ToolNotFound("my_tool".to_string());
123 let rpc = err.to_json_rpc_error();
124 assert_eq!(rpc.code, -32001);
125 assert!(rpc.message.contains("my_tool"));
126 }
127
128 #[test]
129 fn rate_limited_code_is_minus_32002() {
130 let err = AgentNetworkError::RateLimited;
131 assert_eq!(err.to_json_rpc_error().code, -32002);
132 }
133
134 #[test]
135 fn unauthorized_code_is_minus_32003() {
136 let err = AgentNetworkError::Unauthorized;
137 assert_eq!(err.to_json_rpc_error().code, -32003);
138 }
139
140 #[test]
141 fn display_messages_are_non_empty() {
142 let errors: Vec<AgentNetworkError> = vec![
143 AgentNetworkError::ParseError("x".to_string()),
144 AgentNetworkError::MethodNotFound("m".to_string()),
145 AgentNetworkError::InvalidParams("p".to_string()),
146 AgentNetworkError::Transport("t".to_string()),
147 AgentNetworkError::ToolNotFound("tool".to_string()),
148 AgentNetworkError::RateLimited,
149 AgentNetworkError::Unauthorized,
150 ];
151 for e in errors {
152 assert!(!e.to_string().is_empty());
153 }
154 }
155}