use thiserror::Error;
#[derive(Error, Debug)]
pub enum Error {
#[error("HTTP request failed: {method} {url} - status {status}: {message}")]
HttpRequest {
method: String,
url: String,
status: u16,
message: String,
},
#[error("Cache operation '{operation}' failed for key '{key}': {message}")]
Cache {
operation: String,
key: String,
message: String,
},
#[error("MCP protocol error in '{context}': {message}")]
Mcp {
context: String,
message: String,
},
#[error("Initialization failed for '{component}': {message}")]
Initialization {
component: String,
message: String,
},
#[error("Configuration error for '{field}': {message}")]
Config {
field: String,
message: String,
},
#[error("Parse failed for '{input}'{position}: {message}")]
Parse {
input: String,
position: String,
message: String,
},
#[error("Authentication failed for '{provider}': {message}")]
Auth {
provider: String,
message: String,
},
#[error("IO error: {0}")]
Io(#[from] std::io::Error),
#[error("JSON error: {0}")]
Json(#[from] serde_json::Error),
#[error("URL parse error: {0}")]
Url(#[from] url::ParseError),
#[error("HTTP client error: {0}")]
Reqwest(#[from] reqwest::Error),
#[error("Unknown error: {0}")]
Other(String),
}
pub type Result<T> = std::result::Result<T, Error>;
impl Error {
#[must_use]
pub fn http_request(
method: impl Into<String>,
url: impl Into<String>,
status: u16,
message: impl Into<String>,
) -> Self {
Self::HttpRequest {
method: method.into(),
url: url.into(),
status,
message: message.into(),
}
}
#[must_use]
pub fn cache(
operation: impl Into<String>,
key: Option<String>,
message: impl Into<String>,
) -> Self {
Self::Cache {
operation: operation.into(),
key: key.unwrap_or_else(|| "N/A".to_string()),
message: message.into(),
}
}
#[must_use]
pub fn mcp(context: impl Into<String>, message: impl Into<String>) -> Self {
Self::Mcp {
context: context.into(),
message: message.into(),
}
}
#[must_use]
pub fn initialization(component: impl Into<String>, message: impl Into<String>) -> Self {
Self::Initialization {
component: component.into(),
message: message.into(),
}
}
#[must_use]
pub fn config(field: impl Into<String>, message: impl Into<String>) -> Self {
Self::Config {
field: field.into(),
message: message.into(),
}
}
#[must_use]
pub fn parse(
input: impl Into<String>,
position: Option<usize>,
message: impl Into<String>,
) -> Self {
Self::Parse {
input: input.into(),
position: position.map_or_else(String::new, |p| format!(" at position {p}")),
message: message.into(),
}
}
#[must_use]
pub fn auth(provider: impl Into<String>, message: impl Into<String>) -> Self {
Self::Auth {
provider: provider.into(),
message: message.into(),
}
}
}
impl From<Box<dyn std::error::Error + Send + Sync>> for Error {
fn from(err: Box<dyn std::error::Error + Send + Sync>) -> Self {
Error::Other(err.to_string())
}
}
impl From<anyhow::Error> for Error {
fn from(err: anyhow::Error) -> Self {
Error::Other(err.to_string())
}
}