use serde::{Deserialize, Serialize};
use std::time::Duration;
#[derive(Debug, Clone)]
pub struct McpConfig {
pub connect_timeout: Duration,
pub request_timeout: Duration,
pub max_response_size: usize,
pub require_tls: bool,
pub auth_token: Option<String>,
}
impl Default for McpConfig {
fn default() -> Self {
Self {
connect_timeout: Duration::from_secs(10),
request_timeout: Duration::from_secs(30),
max_response_size: 10 * 1024 * 1024, require_tls: true,
auth_token: None,
}
}
}
impl McpConfig {
pub fn with_auth(mut self, token: impl Into<String>) -> Self {
self.auth_token = Some(token.into());
self
}
pub fn allow_insecure(mut self) -> Self {
self.require_tls = false;
self
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct McpToolInfo {
pub name: String,
pub description: String,
pub input_schema: serde_json::Value,
}
#[derive(Debug, thiserror::Error)]
pub enum McpError {
#[error("Failed to connect to MCP server: {0}")]
ConnectionFailed(String),
#[error("Authentication failed: {0}")]
AuthenticationFailed(String),
#[error("Tool '{0}' not found on MCP server")]
ToolNotFound(String),
#[error("MCP tool execution failed: {0}")]
ExecutionFailed(String),
#[error("Response exceeded maximum size ({0} bytes)")]
ResponseTooLarge(usize),
#[error("Operation timed out after {0:?}")]
Timeout(Duration),
#[error("TLS required for remote connections")]
TlsRequired,
#[error("MCP protocol error: {0}")]
ProtocolError(String),
#[error("Serialization error: {0}")]
Serialization(String),
}
impl McpError {
pub fn is_retryable(&self) -> bool {
matches!(self, Self::ConnectionFailed(_) | Self::Timeout(_))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_config_default() {
let config = McpConfig::default();
assert_eq!(config.connect_timeout, Duration::from_secs(10));
assert!(config.require_tls);
assert!(config.auth_token.is_none());
}
#[test]
fn test_config_with_auth() {
let config = McpConfig::default().with_auth("token123");
assert_eq!(config.auth_token, Some("token123".to_string()));
}
#[test]
fn test_error_retryable() {
assert!(McpError::ConnectionFailed("test".into()).is_retryable());
assert!(McpError::Timeout(Duration::from_secs(1)).is_retryable());
assert!(!McpError::ToolNotFound("test".into()).is_retryable());
}
}