1use serde::{Deserialize, Serialize};
6use std::time::Duration;
7
8#[derive(Debug, Clone)]
17pub struct McpConfig {
18 pub connect_timeout: Duration,
20 pub request_timeout: Duration,
22 pub max_response_size: usize,
24 pub require_tls: bool,
26 pub auth_token: Option<String>,
28}
29
30impl Default for McpConfig {
31 fn default() -> Self {
32 Self {
33 connect_timeout: Duration::from_secs(10),
34 request_timeout: Duration::from_secs(30),
35 max_response_size: 10 * 1024 * 1024, require_tls: true,
37 auth_token: None,
38 }
39 }
40}
41
42impl McpConfig {
43 pub fn with_auth(mut self, token: impl Into<String>) -> Self {
45 self.auth_token = Some(token.into());
46 self
47 }
48
49 pub fn allow_insecure(mut self) -> Self {
54 self.require_tls = false;
55 self
56 }
57}
58
59#[derive(Debug, Clone, Serialize, Deserialize)]
61pub struct McpToolInfo {
62 pub name: String,
64 pub description: String,
66 pub input_schema: serde_json::Value,
68}
69
70#[derive(Debug, thiserror::Error)]
72pub enum McpError {
73 #[error("Failed to connect to MCP server: {0}")]
75 ConnectionFailed(String),
76
77 #[error("Authentication failed: {0}")]
79 AuthenticationFailed(String),
80
81 #[error("Tool '{0}' not found on MCP server")]
83 ToolNotFound(String),
84
85 #[error("MCP tool execution failed: {0}")]
87 ExecutionFailed(String),
88
89 #[error("Response exceeded maximum size ({0} bytes)")]
91 ResponseTooLarge(usize),
92
93 #[error("Operation timed out after {0:?}")]
95 Timeout(Duration),
96
97 #[error("TLS required for remote connections")]
99 TlsRequired,
100
101 #[error("MCP protocol error: {0}")]
103 ProtocolError(String),
104
105 #[error("Serialization error: {0}")]
107 Serialization(String),
108}
109
110impl McpError {
111 pub fn is_retryable(&self) -> bool {
113 matches!(self, Self::ConnectionFailed(_) | Self::Timeout(_))
114 }
115}
116
117#[cfg(test)]
118mod tests {
119 use super::*;
120
121 #[test]
122 fn test_config_default() {
123 let config = McpConfig::default();
124 assert_eq!(config.connect_timeout, Duration::from_secs(10));
125 assert!(config.require_tls);
126 assert!(config.auth_token.is_none());
127 }
128
129 #[test]
130 fn test_config_with_auth() {
131 let config = McpConfig::default().with_auth("token123");
132 assert_eq!(config.auth_token, Some("token123".to_string()));
133 }
134
135 #[test]
136 fn test_error_retryable() {
137 assert!(McpError::ConnectionFailed("test".into()).is_retryable());
138 assert!(McpError::Timeout(Duration::from_secs(1)).is_retryable());
139 assert!(!McpError::ToolNotFound("test".into()).is_retryable());
140 }
141}