Skip to main content

dome_core/
error.rs

1use thiserror::Error;
2
3/// Unified error taxonomy for MCPDome.
4///
5/// Every error maps to a JSON-RPC error code so we can send
6/// meaningful responses back to the MCP client.
7#[derive(Debug, Error)]
8pub enum DomeError {
9    #[error("authentication failed: {reason}")]
10    AuthFailed { reason: String },
11
12    #[error("denied by policy: rule={rule_id}, tool={tool}")]
13    PolicyDenied { rule_id: String, tool: String },
14
15    #[error("rate limit exceeded: {limit} req/{window}")]
16    RateLimited { limit: u64, window: String },
17
18    #[error("budget exhausted: {spent}/{cap} {unit}")]
19    BudgetExhausted { spent: f64, cap: f64, unit: String },
20
21    #[error("injection detected: {pattern} in {field}")]
22    InjectionDetected { pattern: String, field: String },
23
24    #[error("schema drift: tool={tool}, field={field}")]
25    SchemaDrift { tool: String, field: String },
26
27    #[error("transport error: {0}")]
28    Transport(#[from] std::io::Error),
29
30    #[error("json parse error: {0}")]
31    Json(#[from] serde_json::Error),
32
33    #[error("upstream error: {0}")]
34    Upstream(String),
35
36    #[error("internal error: {0}")]
37    Internal(String),
38}
39
40impl DomeError {
41    /// Map this error to a JSON-RPC error code.
42    pub fn rpc_code(&self) -> i64 {
43        match self {
44            Self::AuthFailed { .. } => -32001,
45            Self::PolicyDenied { .. } => -32002,
46            Self::RateLimited { .. } => -32003,
47            Self::BudgetExhausted { .. } => -32004,
48            Self::InjectionDetected { .. } => -32005,
49            Self::SchemaDrift { .. } => -32006,
50            Self::Transport(_) => -32000,
51            Self::Json(_) => -32700, // Parse error (JSON-RPC standard)
52            Self::Upstream(_) => -32000,
53            Self::Internal(_) => -32603, // Internal error (JSON-RPC standard)
54        }
55    }
56}