codeprism_mcp_server/
config.rs

1//! Advanced Configuration System for CodePrism MCP Server
2//!
3//! This module provides a comprehensive configuration system with predefined profiles,
4//! dynamic tool enablement, performance monitoring, and production-ready features.
5//! Ported from legacy codeprism-mcp and adapted for rust-sdk architecture.
6
7use crate::Result;
8use serde::{Deserialize, Serialize};
9use std::collections::HashMap;
10use std::path::{Path, PathBuf};
11use std::time::Duration;
12use tracing::info;
13
14/// Configuration profile for different deployment scenarios
15#[derive(Debug, Clone, Serialize, Deserialize)]
16pub struct CodePrismProfile {
17    /// Profile name
18    pub name: String,
19    /// Profile description
20    pub description: String,
21    /// Base configuration settings
22    pub settings: ServerSettings,
23    /// Tool enablement rules
24    pub tools: ToolsConfig,
25    /// Performance monitoring settings
26    pub monitoring: MonitoringConfig,
27    /// Security and access control
28    pub security: SecurityConfig,
29    /// Caching configuration
30    pub caching: CachingConfig,
31}
32
33/// Main server configuration settings
34#[derive(Debug, Clone, Serialize, Deserialize)]
35pub struct ServerSettings {
36    /// Server name for MCP identification
37    pub name: String,
38    /// Server version
39    pub version: String,
40    /// Memory limit in MB
41    pub memory_limit_mb: usize,
42    /// Batch size for parallel processing
43    pub batch_size: usize,
44    /// Maximum file size to process in MB
45    pub max_file_size_mb: usize,
46    /// Disable memory limit checking
47    pub disable_memory_limit: bool,
48    /// Directories to exclude from analysis
49    pub exclude_dirs: Vec<String>,
50    /// File extensions to include
51    pub include_extensions: Option<Vec<String>>,
52    /// Dependency scanning mode
53    pub dependency_mode: DependencyMode,
54    /// Default timeout for operations
55    pub default_timeout: Duration,
56    /// Maximum concurrent operations
57    pub max_concurrent_operations: usize,
58    /// Enable streaming responses
59    pub enable_streaming: bool,
60    /// Maximum response size in bytes
61    pub max_response_size: usize,
62}
63
64/// Dependency scanning modes
65#[derive(Debug, Clone, Serialize, Deserialize)]
66pub enum DependencyMode {
67    /// Exclude all dependency directories
68    Exclude,
69    /// Smart scanning - include only public APIs
70    Smart,
71    /// Include all dependencies
72    IncludeAll,
73}
74
75/// Tool configuration and enablement
76#[derive(Debug, Clone, Serialize, Deserialize)]
77pub struct ToolsConfig {
78    /// Enabled tool categories
79    pub enabled_categories: Vec<ToolCategory>,
80    /// Disabled specific tools
81    pub disabled_tools: Vec<String>,
82    /// Tool-specific configurations
83    pub tool_configs: HashMap<String, ToolConfig>,
84    /// Conditional enablement rules
85    pub enablement_rules: Vec<EnablementRule>,
86}
87
88/// Tool categories for organization
89#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
90pub enum ToolCategory {
91    /// Core navigation and understanding
92    CoreNavigation,
93    /// Search and discovery
94    SearchDiscovery,
95    /// Code analysis and quality
96    Analysis,
97    /// Workflow orchestration
98    Workflow,
99    /// Experimental features
100    Experimental,
101}
102
103/// Individual tool configuration
104#[derive(Debug, Clone, Serialize, Deserialize)]
105pub struct ToolConfig {
106    /// Tool-specific timeout
107    pub timeout: Option<Duration>,
108    /// Maximum results to return
109    pub max_results: Option<usize>,
110    /// Tool-specific memory limit
111    pub memory_limit_mb: Option<usize>,
112    /// Custom parameters
113    pub custom_params: HashMap<String, serde_json::Value>,
114}
115
116/// Tool enablement rules based on conditions
117#[derive(Debug, Clone, Serialize, Deserialize)]
118pub struct EnablementRule {
119    /// Rule name
120    pub name: String,
121    /// Condition for enablement
122    pub condition: EnablementCondition,
123    /// Tools to enable/disable
124    pub actions: Vec<EnablementAction>,
125}
126
127/// Conditions for tool enablement
128#[derive(Debug, Clone, Serialize, Deserialize)]
129pub enum EnablementCondition {
130    /// Based on repository size
131    RepositorySize { max_size_mb: usize },
132    /// Based on file count
133    FileCount { max_files: usize },
134    /// Based on detected languages
135    HasLanguages { languages: Vec<String> },
136    /// Based on client type
137    ClientType { client_types: Vec<String> },
138    /// Based on repository type
139    RepositoryType { repo_types: Vec<String> },
140    /// Custom condition
141    Custom { expression: String },
142}
143
144/// Actions for tool enablement
145#[derive(Debug, Clone, Serialize, Deserialize)]
146pub enum EnablementAction {
147    /// Enable specific tools
148    Enable { tools: Vec<String> },
149    /// Disable specific tools
150    Disable { tools: Vec<String> },
151    /// Enable tool category
152    EnableCategory { category: ToolCategory },
153    /// Disable tool category
154    DisableCategory { category: ToolCategory },
155    /// Modify tool configuration
156    Configure { tool: String, config: ToolConfig },
157}
158
159/// Performance monitoring configuration
160#[derive(Debug, Clone, Serialize, Deserialize)]
161pub struct MonitoringConfig {
162    /// Enable performance monitoring
163    pub enabled: bool,
164    /// Metrics collection interval
165    pub collection_interval: Duration,
166    /// Memory usage monitoring
167    pub monitor_memory: bool,
168    /// Response time monitoring
169    pub monitor_response_times: bool,
170    /// Error rate monitoring
171    pub monitor_errors: bool,
172    /// Export metrics to file
173    pub export_metrics: bool,
174    /// Metrics export path
175    pub metrics_export_path: Option<PathBuf>,
176    /// Performance alerting thresholds
177    pub alert_thresholds: AlertThresholds,
178}
179
180/// Performance alerting thresholds
181#[derive(Debug, Clone, Serialize, Deserialize)]
182pub struct AlertThresholds {
183    /// Maximum memory usage in MB
184    pub max_memory_mb: usize,
185    /// Maximum response time in milliseconds
186    pub max_response_time_ms: u64,
187    /// Maximum error rate (0.0 to 1.0)
188    pub max_error_rate: f64,
189    /// Minimum success rate (0.0 to 1.0)
190    pub min_success_rate: f64,
191}
192
193/// Security and access control configuration
194#[derive(Debug, Clone, Serialize, Deserialize)]
195pub struct SecurityConfig {
196    /// Enable audit logging
197    pub enable_audit_log: bool,
198    /// Audit log path
199    pub audit_log_path: Option<PathBuf>,
200    /// Allowed repository paths
201    pub allowed_paths: Vec<PathBuf>,
202    /// Denied repository paths
203    pub denied_paths: Vec<PathBuf>,
204    /// Maximum analysis depth
205    pub max_analysis_depth: usize,
206    /// Enable path validation
207    pub validate_paths: bool,
208    /// Rate limiting configuration
209    pub rate_limiting: RateLimitConfig,
210}
211
212/// Rate limiting configuration
213#[derive(Debug, Clone, Serialize, Deserialize)]
214pub struct RateLimitConfig {
215    /// Enable rate limiting
216    pub enabled: bool,
217    /// Maximum requests per minute
218    pub requests_per_minute: usize,
219    /// Maximum concurrent requests
220    pub max_concurrent: usize,
221    /// Burst allowance
222    pub burst_size: usize,
223}
224
225/// Caching configuration
226#[derive(Debug, Clone, Serialize, Deserialize)]
227pub struct CachingConfig {
228    /// Enable caching
229    pub enabled: bool,
230    /// Cache directory
231    pub cache_dir: PathBuf,
232    /// Cache size limit in MB
233    pub max_cache_size_mb: usize,
234    /// Cache TTL for analysis results
235    pub analysis_ttl: Duration,
236    /// Cache TTL for file content
237    pub content_ttl: Duration,
238    /// Cache compression
239    pub enable_compression: bool,
240    /// Cache cleanup interval
241    pub cleanup_interval: Duration,
242}
243
244/// Main configuration structure for the CodePrism MCP Server
245#[derive(Debug, Clone, Serialize, Deserialize)]
246pub struct Config {
247    /// Active configuration profile
248    pub profile: CodePrismProfile,
249    /// Configuration profile manager
250    #[serde(skip)]
251    pub manager: ConfigProfileManager,
252}
253
254/// Configuration profile manager
255#[derive(Debug, Clone)]
256pub struct ConfigProfileManager {
257    profiles: HashMap<String, CodePrismProfile>,
258    active_profile: Option<String>,
259}
260
261impl ConfigProfileManager {
262    /// Create a new configuration profile manager
263    pub fn new() -> Self {
264        let mut manager = Self {
265            profiles: HashMap::new(),
266            active_profile: None,
267        };
268
269        // Register built-in profiles
270        manager.register_builtin_profiles();
271        manager
272    }
273
274    /// Register built-in configuration profiles
275    fn register_builtin_profiles(&mut self) {
276        // Development profile
277        self.profiles.insert(
278            "development".to_string(),
279            CodePrismProfile {
280                name: "development".to_string(),
281                description: "Fast development with minimal resource usage".to_string(),
282                settings: ServerSettings {
283                    name: crate::SERVER_NAME.to_string(),
284                    version: crate::VERSION.to_string(),
285                    memory_limit_mb: 1024,
286                    batch_size: 10,
287                    max_file_size_mb: 5,
288                    disable_memory_limit: false,
289                    exclude_dirs: vec![
290                        "node_modules".to_string(),
291                        "target".to_string(),
292                        ".git".to_string(),
293                    ],
294                    include_extensions: Some(vec![
295                        "py".to_string(),
296                        "js".to_string(),
297                        "ts".to_string(),
298                        "rs".to_string(),
299                    ]),
300                    dependency_mode: DependencyMode::Exclude,
301                    default_timeout: Duration::from_secs(30),
302                    max_concurrent_operations: 4,
303                    enable_streaming: true,
304                    max_response_size: 50_000,
305                },
306                tools: ToolsConfig {
307                    enabled_categories: vec![
308                        ToolCategory::CoreNavigation,
309                        ToolCategory::SearchDiscovery,
310                    ],
311                    disabled_tools: vec!["analyze_transitive_dependencies".to_string()],
312                    tool_configs: HashMap::new(),
313                    enablement_rules: vec![],
314                },
315                monitoring: MonitoringConfig {
316                    enabled: true,
317                    collection_interval: Duration::from_secs(60),
318                    monitor_memory: true,
319                    monitor_response_times: true,
320                    monitor_errors: true,
321                    export_metrics: false,
322                    metrics_export_path: None,
323                    alert_thresholds: AlertThresholds {
324                        max_memory_mb: 2048,
325                        max_response_time_ms: 10000,
326                        max_error_rate: 0.1,
327                        min_success_rate: 0.9,
328                    },
329                },
330                security: SecurityConfig {
331                    enable_audit_log: false,
332                    audit_log_path: None,
333                    allowed_paths: vec![],
334                    denied_paths: vec![],
335                    max_analysis_depth: 100,
336                    validate_paths: true,
337                    rate_limiting: RateLimitConfig {
338                        enabled: false,
339                        requests_per_minute: 100,
340                        max_concurrent: 10,
341                        burst_size: 20,
342                    },
343                },
344                caching: CachingConfig {
345                    enabled: true,
346                    cache_dir: PathBuf::from("./cache/dev"),
347                    max_cache_size_mb: 256,
348                    analysis_ttl: Duration::from_secs(3600),
349                    content_ttl: Duration::from_secs(1800),
350                    enable_compression: false,
351                    cleanup_interval: Duration::from_secs(3600),
352                },
353            },
354        );
355
356        // Production profile
357        self.profiles.insert(
358            "production".to_string(),
359            CodePrismProfile {
360                name: "production".to_string(),
361                description: "Production deployment with high performance and monitoring"
362                    .to_string(),
363                settings: ServerSettings {
364                    name: crate::SERVER_NAME.to_string(),
365                    version: crate::VERSION.to_string(),
366                    memory_limit_mb: 8192,
367                    batch_size: 50,
368                    max_file_size_mb: 25,
369                    disable_memory_limit: false,
370                    exclude_dirs: vec![
371                        "node_modules".to_string(),
372                        "target".to_string(),
373                        ".git".to_string(),
374                        "vendor".to_string(),
375                        "dist".to_string(),
376                        "build".to_string(),
377                    ],
378                    include_extensions: None, // Include all supported extensions
379                    dependency_mode: DependencyMode::Smart,
380                    default_timeout: Duration::from_secs(120),
381                    max_concurrent_operations: 12,
382                    enable_streaming: true,
383                    max_response_size: 150_000,
384                },
385                tools: ToolsConfig {
386                    enabled_categories: vec![
387                        ToolCategory::CoreNavigation,
388                        ToolCategory::SearchDiscovery,
389                        ToolCategory::Analysis,
390                        ToolCategory::Workflow,
391                    ],
392                    disabled_tools: vec![],
393                    tool_configs: HashMap::new(),
394                    enablement_rules: vec![EnablementRule {
395                        name: "large_repository".to_string(),
396                        condition: EnablementCondition::RepositorySize { max_size_mb: 1000 },
397                        actions: vec![EnablementAction::Disable {
398                            tools: vec!["find_duplicates".to_string()],
399                        }],
400                    }],
401                },
402                monitoring: MonitoringConfig {
403                    enabled: true,
404                    collection_interval: Duration::from_secs(30),
405                    monitor_memory: true,
406                    monitor_response_times: true,
407                    monitor_errors: true,
408                    export_metrics: true,
409                    metrics_export_path: Some(PathBuf::from("./metrics")),
410                    alert_thresholds: AlertThresholds {
411                        max_memory_mb: 10240,
412                        max_response_time_ms: 30000,
413                        max_error_rate: 0.05,
414                        min_success_rate: 0.95,
415                    },
416                },
417                security: SecurityConfig {
418                    enable_audit_log: true,
419                    audit_log_path: Some(PathBuf::from("./logs/audit.log")),
420                    allowed_paths: vec![],
421                    denied_paths: vec![
422                        PathBuf::from("/etc"),
423                        PathBuf::from("/var"),
424                        PathBuf::from("/proc"),
425                    ],
426                    max_analysis_depth: 1000,
427                    validate_paths: true,
428                    rate_limiting: RateLimitConfig {
429                        enabled: true,
430                        requests_per_minute: 200,
431                        max_concurrent: 15,
432                        burst_size: 50,
433                    },
434                },
435                caching: CachingConfig {
436                    enabled: true,
437                    cache_dir: PathBuf::from("./cache/prod"),
438                    max_cache_size_mb: 2048,
439                    analysis_ttl: Duration::from_secs(7200),
440                    content_ttl: Duration::from_secs(3600),
441                    enable_compression: true,
442                    cleanup_interval: Duration::from_secs(1800),
443                },
444            },
445        );
446
447        // Enterprise profile
448        self.profiles.insert(
449            "enterprise".to_string(),
450            CodePrismProfile {
451                name: "enterprise".to_string(),
452                description: "Enterprise deployment with maximum performance and security"
453                    .to_string(),
454                settings: ServerSettings {
455                    name: crate::SERVER_NAME.to_string(),
456                    version: crate::VERSION.to_string(),
457                    memory_limit_mb: 16384,
458                    batch_size: 100,
459                    max_file_size_mb: 50,
460                    disable_memory_limit: false,
461                    exclude_dirs: vec![
462                        "node_modules".to_string(),
463                        "target".to_string(),
464                        ".git".to_string(),
465                        "vendor".to_string(),
466                        "dist".to_string(),
467                        "build".to_string(),
468                        "coverage".to_string(),
469                    ],
470                    include_extensions: None,
471                    dependency_mode: DependencyMode::Smart,
472                    default_timeout: Duration::from_secs(300),
473                    max_concurrent_operations: 24,
474                    enable_streaming: true,
475                    max_response_size: 500_000,
476                },
477                tools: ToolsConfig {
478                    enabled_categories: vec![
479                        ToolCategory::CoreNavigation,
480                        ToolCategory::SearchDiscovery,
481                        ToolCategory::Analysis,
482                        ToolCategory::Workflow,
483                    ],
484                    disabled_tools: vec![],
485                    tool_configs: HashMap::new(),
486                    enablement_rules: vec![],
487                },
488                monitoring: MonitoringConfig {
489                    enabled: true,
490                    collection_interval: Duration::from_secs(15),
491                    monitor_memory: true,
492                    monitor_response_times: true,
493                    monitor_errors: true,
494                    export_metrics: true,
495                    metrics_export_path: Some(PathBuf::from("./metrics")),
496                    alert_thresholds: AlertThresholds {
497                        max_memory_mb: 20480,
498                        max_response_time_ms: 60000,
499                        max_error_rate: 0.02,
500                        min_success_rate: 0.98,
501                    },
502                },
503                security: SecurityConfig {
504                    enable_audit_log: true,
505                    audit_log_path: Some(PathBuf::from("./logs/audit.log")),
506                    allowed_paths: vec![],
507                    denied_paths: vec![
508                        PathBuf::from("/etc"),
509                        PathBuf::from("/var"),
510                        PathBuf::from("/proc"),
511                        PathBuf::from("/sys"),
512                    ],
513                    max_analysis_depth: 10000,
514                    validate_paths: true,
515                    rate_limiting: RateLimitConfig {
516                        enabled: true,
517                        requests_per_minute: 500,
518                        max_concurrent: 30,
519                        burst_size: 100,
520                    },
521                },
522                caching: CachingConfig {
523                    enabled: true,
524                    cache_dir: PathBuf::from("./cache/enterprise"),
525                    max_cache_size_mb: 8192,
526                    analysis_ttl: Duration::from_secs(14400),
527                    content_ttl: Duration::from_secs(7200),
528                    enable_compression: true,
529                    cleanup_interval: Duration::from_secs(900),
530                },
531            },
532        );
533
534        info!(
535            "Registered {} built-in configuration profiles",
536            self.profiles.len()
537        );
538    }
539
540    /// Get available profile names
541    pub fn list_profiles(&self) -> Vec<String> {
542        self.profiles.keys().cloned().collect()
543    }
544
545    /// Get a profile by name
546    pub fn get_profile(&self, name: &str) -> Option<&CodePrismProfile> {
547        self.profiles.get(name)
548    }
549
550    /// Set active profile
551    pub fn set_active_profile(&mut self, name: String) -> Result<()> {
552        if self.profiles.contains_key(&name) {
553            self.active_profile = Some(name.clone());
554            info!("Activated configuration profile: {}", name);
555            Ok(())
556        } else {
557            Err(crate::Error::server_init(format!(
558                "Profile '{name}' not found"
559            )))
560        }
561    }
562
563    /// Get active profile
564    pub fn get_active_profile(&self) -> Option<&CodePrismProfile> {
565        self.active_profile
566            .as_ref()
567            .and_then(|name| self.profiles.get(name))
568    }
569
570    /// Register a custom profile
571    pub fn register_profile(&mut self, profile: CodePrismProfile) {
572        let name = profile.name.clone();
573        self.profiles.insert(name.clone(), profile);
574        info!("Registered custom configuration profile: {}", name);
575    }
576
577    /// Validate a configuration profile
578    pub fn validate_profile(&self, profile: &CodePrismProfile) -> Result<Vec<String>> {
579        let mut warnings = Vec::new();
580
581        // Validate memory settings
582        if profile.settings.memory_limit_mb < 512 {
583            warnings.push("Memory limit is very low, may cause performance issues".to_string());
584        }
585
586        if profile.settings.memory_limit_mb > 32768 {
587            warnings
588                .push("Memory limit is very high, ensure system has sufficient RAM".to_string());
589        }
590
591        // Validate batch size
592        if profile.settings.batch_size > 200 {
593            warnings.push("Batch size is very high, may cause memory pressure".to_string());
594        }
595
596        // Validate file size limit
597        if profile.settings.max_file_size_mb > 100 {
598            warnings
599                .push("Max file size is very high, may cause long processing times".to_string());
600        }
601
602        // Validate timeout
603        if profile.settings.default_timeout.as_secs() > 600 {
604            warnings.push("Default timeout is very high, clients may disconnect".to_string());
605        }
606
607        // Validate caching
608        if profile.caching.enabled && profile.caching.max_cache_size_mb > 10240 {
609            warnings.push("Cache size is very large, ensure sufficient disk space".to_string());
610        }
611
612        // Validate security settings
613        if !profile.security.validate_paths {
614            warnings.push("Path validation is disabled, security risk in production".to_string());
615        }
616
617        if profile.security.rate_limiting.enabled
618            && profile.security.rate_limiting.requests_per_minute > 1000
619        {
620            warnings.push("Rate limit is very high, may not prevent abuse effectively".to_string());
621        }
622
623        Ok(warnings)
624    }
625
626    /// Create a profile from environment variables
627    pub fn profile_from_env() -> Result<CodePrismProfile> {
628        let profile_name =
629            std::env::var("CODEPRISM_PROFILE").unwrap_or_else(|_| "development".to_string());
630
631        // Start with base profile if it exists, otherwise use development defaults
632        let base_profile = if profile_name == "development"
633            || profile_name == "production"
634            || profile_name == "enterprise"
635        {
636            let manager = Self::new();
637            manager.get_profile(&profile_name).cloned()
638        } else {
639            None
640        };
641
642        let mut profile = base_profile.unwrap_or_else(|| {
643            let manager = Self::new();
644            manager.get_profile("development").unwrap().clone()
645        });
646
647        // Override with environment variables
648        if let Ok(memory_limit) = std::env::var("CODEPRISM_MEMORY_LIMIT_MB") {
649            if let Ok(limit) = memory_limit.parse::<usize>() {
650                profile.settings.memory_limit_mb = limit;
651            }
652        }
653
654        if let Ok(batch_size) = std::env::var("CODEPRISM_BATCH_SIZE") {
655            if let Ok(size) = batch_size.parse::<usize>() {
656                profile.settings.batch_size = size;
657            }
658        }
659
660        if let Ok(timeout) = std::env::var("CODEPRISM_TIMEOUT_SECS") {
661            if let Ok(secs) = timeout.parse::<u64>() {
662                profile.settings.default_timeout = Duration::from_secs(secs);
663            }
664        }
665
666        if let Ok(enable_cache) = std::env::var("CODEPRISM_ENABLE_CACHE") {
667            profile.caching.enabled = enable_cache.to_lowercase() == "true";
668        }
669
670        if let Ok(cache_dir) = std::env::var("CODEPRISM_CACHE_DIR") {
671            profile.caching.cache_dir = PathBuf::from(cache_dir);
672        }
673
674        profile.name = format!("{profile_name}_env");
675        profile.description = format!("Environment-configured {profile_name} profile");
676
677        Ok(profile)
678    }
679}
680
681impl Config {
682    /// Create configuration from environment variables
683    pub async fn from_env() -> Result<Self> {
684        let profile = ConfigProfileManager::profile_from_env()?;
685        let manager = ConfigProfileManager::new();
686
687        Ok(Self { profile, manager })
688    }
689
690    /// Load configuration from a file
691    pub async fn from_file<P: AsRef<Path>>(path: P) -> Result<Self> {
692        let path_ref = path.as_ref();
693        let extension = path_ref.extension().and_then(|s| s.to_str());
694        let content = tokio::fs::read_to_string(path_ref).await?;
695
696        let profile: CodePrismProfile = match extension {
697            Some("toml") => toml::from_str(&content)?,
698            Some("yaml") | Some("yml") => serde_yaml::from_str(&content)?,
699            Some("json") => serde_json::from_str(&content)?,
700            _ => {
701                // Try to detect format by trying each parser
702                toml::from_str(&content)
703                    .or_else(|_| serde_yaml::from_str(&content))
704                    .or_else(|_| serde_json::from_str(&content))?
705            }
706        };
707
708        let manager = ConfigProfileManager::new();
709        Ok(Self { profile, manager })
710    }
711
712    /// Save configuration to a file
713    pub async fn save_to_file<P: AsRef<Path>>(&self, path: P) -> Result<()> {
714        let content = match path.as_ref().extension().and_then(|s| s.to_str()) {
715            Some("toml") => toml::to_string_pretty(&self.profile)?,
716            Some("yaml") | Some("yml") => serde_yaml::to_string(&self.profile)?,
717            Some("json") => serde_json::to_string_pretty(&self.profile)?,
718            _ => toml::to_string_pretty(&self.profile)?, // Default to TOML
719        };
720        tokio::fs::write(path, content).await?;
721        Ok(())
722    }
723
724    /// Validate the configuration
725    pub fn validate(&self) -> Result<Vec<String>> {
726        if self.profile.settings.name.is_empty() {
727            return Err(crate::Error::server_init("Server name cannot be empty"));
728        }
729
730        if self.profile.settings.max_concurrent_operations == 0 {
731            return Err(crate::Error::server_init(
732                "Max concurrent operations must be greater than 0",
733            ));
734        }
735
736        if self.profile.settings.max_file_size_mb == 0 {
737            return Err(crate::Error::server_init(
738                "Max file size must be greater than 0",
739            ));
740        }
741
742        // Return validation warnings
743        self.manager.validate_profile(&self.profile)
744    }
745
746    /// Check if a tool is enabled based on configuration
747    pub fn is_tool_enabled(&self, tool_name: &str) -> bool {
748        // Check if tool is explicitly disabled
749        if self
750            .profile
751            .tools
752            .disabled_tools
753            .contains(&tool_name.to_string())
754        {
755            return false;
756        }
757
758        // Check if tool category is enabled
759        let tool_category = match tool_name {
760            "trace_path" | "find_dependencies" | "find_references" | "explain_symbol"
761            | "search_symbols" => Some(ToolCategory::CoreNavigation),
762            "search_content" | "find_patterns" | "semantic_search" | "search_by_type"
763            | "advanced_search" => Some(ToolCategory::SearchDiscovery),
764            "analyze_complexity"
765            | "analyze_control_flow"
766            | "analyze_code_quality"
767            | "analyze_performance" => Some(ToolCategory::Analysis),
768            "provide_guidance" | "optimize_code" | "batch_process" | "workflow_automation" => {
769                Some(ToolCategory::Workflow)
770            }
771            _ => None,
772        };
773
774        if let Some(category) = tool_category {
775            self.profile.tools.enabled_categories.contains(&category)
776        } else {
777            true // Enable unknown tools by default
778        }
779    }
780
781    /// Get tool-specific configuration
782    pub fn get_tool_config(&self, tool_name: &str) -> Option<&ToolConfig> {
783        self.profile.tools.tool_configs.get(tool_name)
784    }
785
786    /// Get server configuration for backward compatibility
787    pub fn server(&self) -> ServerConfig {
788        ServerConfig {
789            name: self.profile.settings.name.clone(),
790            version: self.profile.settings.version.clone(),
791            max_concurrent_tools: self.profile.settings.max_concurrent_operations,
792            request_timeout_secs: self.profile.settings.default_timeout.as_secs(),
793        }
794    }
795
796    /// Get tools configuration for backward compatibility
797    pub fn tools(&self) -> ToolsConfigCompat {
798        ToolsConfigCompat {
799            enable_core: self
800                .profile
801                .tools
802                .enabled_categories
803                .contains(&ToolCategory::CoreNavigation),
804            enable_search: self
805                .profile
806                .tools
807                .enabled_categories
808                .contains(&ToolCategory::SearchDiscovery),
809            enable_analysis: self
810                .profile
811                .tools
812                .enabled_categories
813                .contains(&ToolCategory::Analysis),
814            enable_workflow: self
815                .profile
816                .tools
817                .enabled_categories
818                .contains(&ToolCategory::Workflow),
819        }
820    }
821
822    /// Get analysis configuration for backward compatibility
823    pub fn analysis(&self) -> AnalysisConfigCompat {
824        AnalysisConfigCompat {
825            max_file_size_bytes: self.profile.settings.max_file_size_mb * 1024 * 1024,
826            max_files_per_request: self.profile.settings.batch_size,
827            enable_caching: self.profile.caching.enabled,
828            cache_ttl_secs: self.profile.caching.analysis_ttl.as_secs(),
829        }
830    }
831}
832
833/// Backward compatibility structures
834#[derive(Debug, Clone)]
835pub struct ServerConfig {
836    pub name: String,
837    pub version: String,
838    pub max_concurrent_tools: usize,
839    pub request_timeout_secs: u64,
840}
841
842#[derive(Debug, Clone)]
843pub struct ToolsConfigCompat {
844    pub enable_core: bool,
845    pub enable_search: bool,
846    pub enable_analysis: bool,
847    pub enable_workflow: bool,
848}
849
850#[derive(Debug, Clone)]
851pub struct AnalysisConfigCompat {
852    pub max_file_size_bytes: usize,
853    pub max_files_per_request: usize,
854    pub enable_caching: bool,
855    pub cache_ttl_secs: u64,
856}
857
858impl Default for Config {
859    fn default() -> Self {
860        let manager = ConfigProfileManager::new();
861        let profile = manager.get_profile("development").unwrap().clone();
862        Self { profile, manager }
863    }
864}
865
866impl Default for ConfigProfileManager {
867    fn default() -> Self {
868        Self::new()
869    }
870}