ultrafast_mcp_core/
config.rs

1//! Configuration management for UltraFast MCP
2//!
3//! This module provides configuration structures and utilities for managing
4//! timeouts, connections, and other operational parameters.
5
6// Include the base config module from the config subdirectory
7#[path = "config/base.rs"]
8pub mod base;
9
10use serde::{Deserialize, Serialize};
11use std::time::Duration;
12
13// Re-export common config types
14pub use base::{
15    BaseConfig, ConfigBuilder, ConfigDefaults, NetworkConfig as BaseNetworkConfig,
16    RetryConfig as BaseRetryConfig, SecurityConfig as BaseSecurityConfig,
17    TimeoutConfig as BaseTimeoutConfig,
18};
19
20/// Timeout configuration for MCP operations
21///
22/// This is the original timeout config, now with base config support
23#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
24pub struct TimeoutConfig {
25    /// Default timeout for all operations
26    pub default_timeout: Duration,
27
28    /// Timeout for connection establishment
29    pub connect_timeout: Duration,
30
31    /// Timeout for individual requests
32    pub request_timeout: Duration,
33
34    /// Timeout for receiving responses
35    pub response_timeout: Duration,
36
37    /// Timeout for tool execution
38    pub tool_execution_timeout: Duration,
39
40    /// Timeout for resource reading
41    pub resource_read_timeout: Duration,
42
43    /// Timeout for prompt generation
44    pub prompt_generation_timeout: Duration,
45
46    /// Timeout for sampling operations
47    pub sampling_timeout: Duration,
48
49    /// Timeout for completion operations
50    pub completion_timeout: Duration,
51
52    /// Timeout for shutdown operations
53    pub shutdown_timeout: Duration,
54
55    /// Heartbeat interval for connection health
56    pub heartbeat_interval: Duration,
57}
58
59impl Default for TimeoutConfig {
60    fn default() -> Self {
61        Self {
62            default_timeout: Duration::from_secs(30),
63            connect_timeout: Duration::from_secs(10),
64            request_timeout: Duration::from_secs(30),
65            response_timeout: Duration::from_secs(30),
66            tool_execution_timeout: Duration::from_secs(300), // 5 minutes
67            resource_read_timeout: Duration::from_secs(60),
68            prompt_generation_timeout: Duration::from_secs(30),
69            sampling_timeout: Duration::from_secs(120), // 2 minutes for LLM calls
70            completion_timeout: Duration::from_secs(30),
71            shutdown_timeout: Duration::from_secs(5),
72            heartbeat_interval: Duration::from_secs(30),
73        }
74    }
75}
76
77impl base::ConfigDefaults for TimeoutConfig {}
78
79impl base::BaseConfig for TimeoutConfig {
80    fn validate(&self) -> crate::MCPResult<()> {
81        use crate::validation::timeout::validate_timeout;
82
83        validate_timeout(self.default_timeout)?;
84        validate_timeout(self.connect_timeout)?;
85        validate_timeout(self.request_timeout)?;
86        validate_timeout(self.response_timeout)?;
87        validate_timeout(self.tool_execution_timeout)?;
88        validate_timeout(self.resource_read_timeout)?;
89        validate_timeout(self.prompt_generation_timeout)?;
90        validate_timeout(self.sampling_timeout)?;
91        validate_timeout(self.completion_timeout)?;
92        validate_timeout(self.shutdown_timeout)?;
93        validate_timeout(self.heartbeat_interval)?;
94
95        Ok(())
96    }
97
98    fn config_name(&self) -> &'static str {
99        "MCPTimeoutConfig"
100    }
101}
102
103impl TimeoutConfig {
104    /// Create a high-performance configuration with shorter timeouts
105    pub fn high_performance() -> Self {
106        Self {
107            default_timeout: Duration::from_secs(10),
108            connect_timeout: Duration::from_secs(3),
109            request_timeout: Duration::from_secs(10),
110            response_timeout: Duration::from_secs(10),
111            tool_execution_timeout: Duration::from_secs(60),
112            resource_read_timeout: Duration::from_secs(30),
113            prompt_generation_timeout: Duration::from_secs(15),
114            sampling_timeout: Duration::from_secs(60),
115            completion_timeout: Duration::from_secs(15),
116            shutdown_timeout: Duration::from_secs(3),
117            heartbeat_interval: Duration::from_secs(15),
118        }
119    }
120
121    /// Create a long-running configuration with extended timeouts
122    pub fn long_running() -> Self {
123        Self {
124            default_timeout: Duration::from_secs(300), // 5 minutes
125            connect_timeout: Duration::from_secs(30),
126            request_timeout: Duration::from_secs(300),
127            response_timeout: Duration::from_secs(300),
128            tool_execution_timeout: Duration::from_secs(1800), // 30 minutes
129            resource_read_timeout: Duration::from_secs(600),   // 10 minutes
130            prompt_generation_timeout: Duration::from_secs(120),
131            sampling_timeout: Duration::from_secs(600), // 10 minutes for complex LLM calls
132            completion_timeout: Duration::from_secs(120),
133            shutdown_timeout: Duration::from_secs(30),
134            heartbeat_interval: Duration::from_secs(60),
135        }
136    }
137
138    /// Get timeout for a specific operation type
139    pub fn get_timeout_for_operation(&self, operation: &str) -> Duration {
140        match operation {
141            "connect" => self.connect_timeout,
142            "request" => self.request_timeout,
143            "response" => self.response_timeout,
144            "tool_execution" | "tools/call" => self.tool_execution_timeout,
145            "resource_read" | "resources/read" => self.resource_read_timeout,
146            "prompt_generation" | "prompts/get" => self.prompt_generation_timeout,
147            "sampling" | "sampling/createMessage" => self.sampling_timeout,
148            "completion" | "completion/complete" => self.completion_timeout,
149            "shutdown" => self.shutdown_timeout,
150            "heartbeat" | "ping" => self.heartbeat_interval,
151            _ => self.default_timeout,
152        }
153    }
154
155    /// Check if a timeout value is valid
156    pub fn validate_timeout(&self, timeout: Duration) -> bool {
157        timeout >= Duration::from_millis(100) && timeout <= Duration::from_secs(3600)
158    }
159}
160
161#[cfg(test)]
162mod tests {
163    use super::*;
164
165    #[test]
166    fn test_default_timeout_config() {
167        let config = TimeoutConfig::default();
168        assert_eq!(config.default_timeout, Duration::from_secs(30));
169        assert_eq!(config.connect_timeout, Duration::from_secs(10));
170        assert_eq!(config.request_timeout, Duration::from_secs(30));
171    }
172
173    #[test]
174    fn test_high_performance_timeout_config() {
175        let config = TimeoutConfig::high_performance();
176        assert_eq!(config.default_timeout, Duration::from_secs(10));
177        assert_eq!(config.connect_timeout, Duration::from_secs(3));
178        assert!(config.connect_timeout < TimeoutConfig::default().connect_timeout);
179    }
180
181    #[test]
182    fn test_long_running_timeout_config() {
183        let config = TimeoutConfig::long_running();
184        assert_eq!(config.default_timeout, Duration::from_secs(300));
185        assert_eq!(config.tool_execution_timeout, Duration::from_secs(1800));
186        assert!(config.tool_execution_timeout > TimeoutConfig::default().tool_execution_timeout);
187    }
188
189    #[test]
190    fn test_get_timeout_for_operation() {
191        let config = TimeoutConfig::default();
192        assert_eq!(
193            config.get_timeout_for_operation("connect"),
194            config.connect_timeout
195        );
196        assert_eq!(
197            config.get_timeout_for_operation("tools/call"),
198            config.tool_execution_timeout
199        );
200        assert_eq!(
201            config.get_timeout_for_operation("unknown"),
202            config.default_timeout
203        );
204    }
205
206    #[test]
207    fn test_timeout_validation() {
208        let config = TimeoutConfig::default();
209        assert!(config.validate_timeout(Duration::from_secs(30)));
210        assert!(!config.validate_timeout(Duration::from_millis(50))); // Too short
211        assert!(!config.validate_timeout(Duration::from_secs(3700))); // Too long
212    }
213
214    #[test]
215    fn test_config_validation() {
216        let config = TimeoutConfig::default();
217        assert!(config.validate().is_ok());
218    }
219
220    #[test]
221    fn test_base_configs() {
222        let timeout_config = BaseTimeoutConfig::default();
223        assert!(timeout_config.validate().is_ok());
224        assert_eq!(timeout_config.config_name(), "TimeoutConfig");
225
226        let retry_config = BaseRetryConfig::default();
227        assert!(retry_config.validate().is_ok());
228        assert_eq!(retry_config.config_name(), "RetryConfig");
229
230        let network_config = BaseNetworkConfig::default();
231        assert!(network_config.validate().is_ok());
232        assert_eq!(network_config.config_name(), "NetworkConfig");
233
234        let security_config = BaseSecurityConfig::default();
235        assert!(security_config.validate().is_ok());
236        assert_eq!(security_config.config_name(), "SecurityConfig");
237    }
238}