mcpkit_warp/
error.rs

1//! Error types for Warp MCP integration.
2
3use thiserror::Error;
4use warp::http::StatusCode;
5use warp::reject::Reject;
6
7/// Errors that can occur during MCP request handling.
8#[derive(Debug, Error)]
9pub enum WarpError {
10    /// Invalid JSON-RPC message format.
11    #[error("Invalid message: {0}")]
12    InvalidMessage(String),
13
14    /// Unsupported protocol version.
15    #[error("Unsupported protocol version: {0}")]
16    UnsupportedVersion(String),
17
18    /// Session not found.
19    #[error("Session not found: {0}")]
20    SessionNotFound(String),
21
22    /// JSON serialization error.
23    #[error("Serialization error: {0}")]
24    Serialization(#[from] serde_json::Error),
25
26    /// Internal server error.
27    #[error("Internal error: {0}")]
28    Internal(String),
29}
30
31impl Reject for WarpError {}
32
33/// Convert a `WarpError` to an HTTP status code.
34impl WarpError {
35    /// Get the appropriate HTTP status code for this error.
36    #[must_use]
37    pub const fn status_code(&self) -> StatusCode {
38        match self {
39            WarpError::InvalidMessage(_) | WarpError::UnsupportedVersion(_) => {
40                StatusCode::BAD_REQUEST
41            }
42            WarpError::SessionNotFound(_) => StatusCode::NOT_FOUND,
43            WarpError::Serialization(_) | WarpError::Internal(_) => {
44                StatusCode::INTERNAL_SERVER_ERROR
45            }
46        }
47    }
48}
49
50#[cfg(test)]
51mod tests {
52    use super::*;
53
54    #[test]
55    fn test_invalid_message_error() {
56        let error = WarpError::InvalidMessage("bad json".to_string());
57        assert_eq!(error.to_string(), "Invalid message: bad json");
58        assert_eq!(error.status_code(), StatusCode::BAD_REQUEST);
59    }
60
61    #[test]
62    fn test_unsupported_version_error() {
63        let error = WarpError::UnsupportedVersion("1.0.0".to_string());
64        assert_eq!(error.to_string(), "Unsupported protocol version: 1.0.0");
65        assert_eq!(error.status_code(), StatusCode::BAD_REQUEST);
66    }
67
68    #[test]
69    fn test_session_not_found_error() {
70        let error = WarpError::SessionNotFound("abc-123".to_string());
71        assert_eq!(error.to_string(), "Session not found: abc-123");
72        assert_eq!(error.status_code(), StatusCode::NOT_FOUND);
73    }
74
75    #[test]
76    fn test_serialization_error() {
77        let json_err = serde_json::from_str::<serde_json::Value>("invalid").unwrap_err();
78        let error = WarpError::Serialization(json_err);
79        assert!(error.to_string().starts_with("Serialization error:"));
80        assert_eq!(error.status_code(), StatusCode::INTERNAL_SERVER_ERROR);
81    }
82
83    #[test]
84    fn test_internal_error() {
85        let error = WarpError::Internal("something went wrong".to_string());
86        assert_eq!(error.to_string(), "Internal error: something went wrong");
87        assert_eq!(error.status_code(), StatusCode::INTERNAL_SERVER_ERROR);
88    }
89
90    #[test]
91    fn test_from_serde_json_error() {
92        let json_err = serde_json::from_str::<serde_json::Value>("invalid").unwrap_err();
93        let error: WarpError = json_err.into();
94        assert!(matches!(error, WarpError::Serialization(_)));
95    }
96
97    #[test]
98    fn test_error_is_send_sync() {
99        fn assert_send_sync<T: Send + Sync>() {}
100        assert_send_sync::<WarpError>();
101    }
102
103    #[test]
104    fn test_error_debug_format() {
105        let error = WarpError::InvalidMessage("test".to_string());
106        let debug = format!("{error:?}");
107        assert!(debug.contains("InvalidMessage"));
108        assert!(debug.contains("test"));
109    }
110
111    #[test]
112    fn test_error_implements_reject() {
113        fn assert_reject<T: Reject>() {}
114        assert_reject::<WarpError>();
115    }
116}