Skip to main content

systemprompt_models/validators/
mcp.rs

1//! MCP configuration validator.
2
3use super::ValidationConfigProvider;
4use crate::ServicesConfig;
5use std::collections::HashMap;
6use systemprompt_traits::validation_report::{ValidationError, ValidationReport};
7use systemprompt_traits::{ConfigProvider, DomainConfig, DomainConfigError};
8
9#[derive(Debug, Default)]
10pub struct McpConfigValidator {
11    services_config: Option<ServicesConfig>,
12}
13
14impl McpConfigValidator {
15    pub fn new() -> Self {
16        Self::default()
17    }
18}
19
20impl DomainConfig for McpConfigValidator {
21    fn domain_id(&self) -> &'static str {
22        "mcp"
23    }
24
25    fn priority(&self) -> u32 {
26        40
27    }
28
29    fn dependencies(&self) -> &[&'static str] {
30        &["agents"]
31    }
32
33    fn load(&mut self, config: &dyn ConfigProvider) -> Result<(), DomainConfigError> {
34        let provider = config
35            .as_any()
36            .downcast_ref::<ValidationConfigProvider>()
37            .ok_or_else(|| {
38                DomainConfigError::LoadError(
39                    "Expected ValidationConfigProvider with pre-loaded configs".into(),
40                )
41            })?;
42
43        self.services_config = Some(provider.services_config().clone());
44        Ok(())
45    }
46
47    fn validate(&self) -> Result<ValidationReport, DomainConfigError> {
48        let mut report = ValidationReport::new("mcp");
49
50        let Some(config) = self.services_config.as_ref() else {
51            return Ok(report);
52        };
53
54        let mut used_ports: HashMap<u16, String> = HashMap::new();
55
56        for (name, deployment) in &config.mcp_servers {
57            let port = deployment.port;
58
59            if let Some(existing) = used_ports.get(&port) {
60                report.add_error(
61                    ValidationError::new(
62                        format!("mcp_servers.{}.port", name),
63                        format!("Port {} already used by server '{}'", port, existing),
64                    )
65                    .with_suggestion("Assign unique ports to each MCP server"),
66                );
67            } else {
68                used_ports.insert(port, name.clone());
69            }
70        }
71
72        Ok(report)
73    }
74}