mcp-tools 0.1.0

Rust MCP tools library
Documentation
//! Configuration management for MCP Tools

use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::path::Path;

/// Global MCP Tools configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct McpToolsConfig {
    /// Default server configurations
    pub servers: HashMap<String, crate::common::ServerConfig>,

    /// Default client configurations  
    pub clients: HashMap<String, crate::common::ClientConfig>,

    /// Global settings
    pub global: GlobalConfig,
}

/// Global configuration settings
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GlobalConfig {
    /// Default log level
    pub log_level: String,

    /// Enable metrics collection
    pub enable_metrics: bool,

    /// Metrics collection interval in seconds
    pub metrics_interval_secs: u64,

    /// Default session timeout in seconds
    pub session_timeout_secs: u64,
}

impl Default for McpToolsConfig {
    fn default() -> Self {
        Self {
            servers: HashMap::new(),
            clients: HashMap::new(),
            global: GlobalConfig::default(),
        }
    }
}

impl Default for GlobalConfig {
    fn default() -> Self {
        Self {
            log_level: "info".to_string(),
            enable_metrics: true,
            metrics_interval_secs: 60,
            session_timeout_secs: 3600, // 1 hour
        }
    }
}

/// Load configuration from file
pub async fn load_config<P: AsRef<Path>>(path: P) -> Result<McpToolsConfig, Box<dyn std::error::Error + Send + Sync>> {
    let content = tokio::fs::read_to_string(path).await?;

    // Try TOML first, then JSON
    if let Ok(config) = toml::from_str::<McpToolsConfig>(&content) {
        Ok(config)
    } else {
        serde_json::from_str::<McpToolsConfig>(&content)
            .map_err(|e| Box::new(e) as Box<dyn std::error::Error + Send + Sync>)
    }
}

/// Save configuration to file
pub async fn save_config<P: AsRef<Path>>(config: &McpToolsConfig, path: P) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
    let content = toml::to_string_pretty(config)
        .map_err(|e| Box::new(e) as Box<dyn std::error::Error + Send + Sync>)?;

    tokio::fs::write(path, content).await?;
    Ok(())
}

#[cfg(test)]
mod tests {
    use super::*;
    use tempfile::NamedTempFile;

    #[test]
    fn test_default_config() {
        let config = McpToolsConfig::default();
        assert_eq!(config.global.log_level, "info");
        assert!(config.global.enable_metrics);
    }

    #[tokio::test]
    async fn test_config_serialization() {
        let config = McpToolsConfig::default();

        let toml_str = toml::to_string(&config).unwrap();
        let parsed: McpToolsConfig = toml::from_str(&toml_str).unwrap();

        assert_eq!(config.global.log_level, parsed.global.log_level);
    }
}