e034b46
use subtle::ConstantTimeEq;
use thiserror::Error;
#[inline]
pub fn ct_eq(a: &[u8], b: &[u8]) -> bool {
a.ct_eq(b).into()
}
#[derive(Debug, Error)]
pub enum McpError {
#[error("mcp disabled by configuration")]
Disabled,
#[error("invalid mcp config: {0}")]
InvalidConfig(String),
#[error("mcp db error: {0}")]
Db(#[from] db::conn::DbError),
#[error("mcp auth: {0}")]
Auth(AuthError),
#[error("mcp tool `{tool}` failed: {message}")]
Tool { tool: String, message: String },
#[error("internal MCP track not configured (mcp.internal_secret_key unset)")]
InternalNotConfigured,
#[error("mcp authentication context missing from request")]
AuthContextMissing,
}
pub const JSONRPC_PARSE_ERROR: i64 = -32700;
pub const JSONRPC_INVALID_REQUEST: i64 = -32600;
pub const JSONRPC_METHOD_NOT_FOUND: i64 = -32601;
pub const JSONRPC_INVALID_PARAMS: i64 = -32602;
pub const JSONRPC_INTERNAL_ERROR: i64 = -32603;
pub const MCP_TOOL_ERROR: i64 = -32000;
pub const MCP_UNAUTHORIZED: i64 = -32001;
pub const MCP_IP_NOT_ALLOWED: i64 = -32002;
#[derive(Debug, Error)]
pub enum AuthError {
#[error("invalid credentials")]
InvalidCredentials,
#[error("insufficient access key scope: {0:?}")]
InsufficientScope(db::user::user_access_keys::AccessKeyScope),
#[error("internal MCP track not configured")]
InternalNotConfigured,
#[error("peer IP is not in the platform whitelist")]
IpNotAllowed,
}
/// can pattern-match the variant. The `#[from] AuthError` on
impl From<AuthError> for McpError {
fn from(e: AuthError) -> Self {
match e {
AuthError::InternalNotConfigured => McpError::InternalNotConfigured,
other => McpError::Auth(other),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn ct_eq_basic() {
assert!(ct_eq(b"hello", b"hello"));
assert!(!ct_eq(b"hello", b"world"));
assert!(!ct_eq(b"hello", b"hell"));
assert!(!ct_eq(b"hell", b"hello"));
assert!(ct_eq(b"", b""));
}
#[test]
fn auth_error_maps_to_mcp_error() {
let a = AuthError::InternalNotConfigured;
let m: McpError = a.into();
assert!(matches!(m, McpError::InternalNotConfigured));
let a = AuthError::InvalidCredentials;
let m: McpError = a.into();
assert!(matches!(m, McpError::Auth(AuthError::InvalidCredentials)));
}
}