Source code for config

"""Configuration models for MCP Downloader.

This module defines the configuration models used throughout the MCP downloader
system, including templates, server configurations, and installation methods.

Example:
    Creating a server template:

        .. code-block:: python
        template = ServerTemplate(
            name="npm_official",
            installation_method=InstallationMethod.NPM,
            command_pattern="@modelcontextprotocol/server-{service}",
            capabilities=["tools"],
            category="official"
        )

    Creating a server configuration:

        .. code-block:: python

            config = ServerConfig(
            name="filesystem",
            template="npm_official",
            source="npm",
            variables={"service": "filesystem"},
            tags={"official", "file-operations"}
        )

Classes:
    InstallationMethod: Enum of supported installation methods
    ServerTemplate: Template for server installation patterns
    ServerConfig: Configuration for a specific server
    DownloaderConfig: Overall downloader configuration
"""

from enum import Enum
from pathlib import Path
from typing import Any

import yaml
from pydantic import BaseModel, ConfigDict, Field


[docs] class InstallationMethod(str, Enum): """Supported installation methods for MCP servers. Attributes: NPM: Node Package Manager installation PIP: Python Package Index installation GIT: Git repository cloning DOCKER: Docker image pull BINARY: Binary executable download CURL: Direct HTTP download MANUAL: Manual installation process SCRIPT: Custom script execution """ NPM = "npm" PIP = "pip" GIT = "git" DOCKER = "docker" BINARY = "binary" CURL = "curl" MANUAL = "manual" SCRIPT = "script"
[docs] class ServerTemplate(BaseModel): """Template for MCP server installation patterns. Templates define reusable installation patterns that can be applied to multiple servers with similar installation requirements. Attributes: name: Unique template identifier installation_method: Method to use for installation command_pattern: Pattern for the command to run the server args_pattern: Default arguments for the command env_vars: Environment variables to set capabilities: List of server capabilities category: Server category for organization health_check: Command to verify server health prerequisites: Required system dependencies post_install: Commands to run after installation timeout: Installation timeout in seconds Example: NPM template: .. code-block:: python template = ServerTemplate( name="npm_official", installation_method=InstallationMethod.NPM, command_pattern="@modelcontextprotocol/server-{service}", capabilities=["tools"], category="official", prerequisites=["node", "npm"] ) """ model_config = ConfigDict(use_enum_values=True) name: str = Field(..., description="Unique template identifier") installation_method: InstallationMethod = Field( ..., description="Installation method" ) command_pattern: str = Field(..., description="Command pattern with variables") args_pattern: list[str] = Field( default_factory=list, description="Default arguments" ) env_vars: dict[str, str] = Field( default_factory=dict, description="Environment variables" ) capabilities: list[str] = Field( default_factory=list, description="Server capabilities" ) category: str = Field(default="general", description="Server category") health_check: str | None = Field(None, description="Health check command") prerequisites: list[str] = Field( default_factory=list, description="System prerequisites" ) post_install: list[str] = Field( default_factory=list, description="Post-install commands" ) timeout: int = Field(default=300, description="Installation timeout in seconds")
[docs] class ServerConfig(BaseModel): """Configuration for a specific MCP server. Server configurations define individual servers to be installed, referencing a template and providing server-specific variables. Attributes: name: Server name identifier template: Template name to use source: Source location (npm, git URL, etc.) variables: Variables to substitute in template patterns enabled: Whether the server is enabled for installation priority: Installation priority (lower = higher priority) tags: Set of tags for categorization env_vars: Additional environment variables version: Specific version to install Example: Filesystem server config: .. code-block:: python config = ServerConfig( name="filesystem", template="npm_official", source="npm", variables={"service": "filesystem"}, tags={"official", "file-operations"}, priority=1 ) """ model_config = ConfigDict(use_enum_values=True) name: str = Field(..., description="Server name identifier") template: str = Field(..., description="Template name to use") source: str = Field(..., description="Source location") variables: dict[str, Any] = Field( default_factory=dict, description="Template variables" ) enabled: bool = Field(default=True, description="Enable server for installation") priority: int = Field(default=0, description="Installation priority") tags: set[str] = Field(default_factory=set, description="Server tags") env_vars: dict[str, str] = Field( default_factory=dict, description="Additional env vars" ) version: str | None = Field(None, description="Specific version constraint")
[docs] class DiscoveryConfig(BaseModel): """Configuration for server discovery. Attributes: sources: List of discovery source URLs patterns: Package naming patterns by registry auto_discover: Enable automatic discovery discovery_interval: Hours between discovery runs max_servers: Maximum servers to discover per source """ sources: list[str] = Field( default_factory=list, description="Discovery source URLs" ) patterns: dict[str, list[str]] = Field( default_factory=dict, description="Naming patterns" ) auto_discover: bool = Field(default=False, description="Enable auto-discovery") discovery_interval: int = Field(default=24, description="Hours between discovery") max_servers: int = Field(default=100, description="Max servers per source")
[docs] class DownloaderConfig(BaseModel): """Overall configuration for the MCP downloader. Attributes: install_dir: Directory for server installations config_dir: Directory for configuration files log_dir: Directory for log files max_concurrent: Maximum concurrent downloads retry_attempts: Number of retry attempts retry_delay: Delay between retries in seconds health_check_enabled: Enable health checks after install health_check_timeout: Health check timeout in seconds backup_enabled: Enable configuration backups backup_dir: Directory for backups templates: List of server templates servers: List of server configurations discovery: Discovery configuration Example: Full configuration: .. code-block:: python config = DownloaderConfig( install_dir="/home/user/.mcp/servers", max_concurrent=5, retry_attempts=3, templates=[template1, template2], servers=[server1, server2] ) """ install_dir: Path = Field( default_factory=lambda: Path.home() / ".mcp" / "servers", description="Installation directory", ) config_dir: Path = Field( default_factory=lambda: Path.home() / ".mcp" / "configs", description="Configuration directory", ) log_dir: Path = Field( default_factory=lambda: Path.home() / ".mcp" / "logs", description="Log directory", ) max_concurrent: int = Field(default=5, gt=0, description="Max concurrent downloads") retry_attempts: int = Field(default=3, ge=0, description="Retry attempts") retry_delay: int = Field(default=5, gt=0, description="Retry delay in seconds") health_check_enabled: bool = Field(default=True, description="Enable health checks") health_check_timeout: int = Field( default=30, gt=0, description="Health check timeout" ) backup_enabled: bool = Field(default=True, description="Enable backups") backup_dir: Path = Field( default_factory=lambda: Path.home() / ".mcp" / "backups", description="Backup directory", ) templates: list[ServerTemplate] = Field( default_factory=list, description="Server templates" ) servers: list[ServerConfig] = Field( default_factory=list, description="Server configs" ) discovery: DiscoveryConfig = Field( default_factory=DiscoveryConfig, description="Discovery config" )
[docs] def load_config(config_file: Path) -> DownloaderConfig: """Load configuration from YAML file. Args: config_file: Path to YAML configuration file Returns: DownloaderConfig: Loaded configuration Raises: FileNotFoundError: If config file doesn't exist ValueError: If config file is invalid Example: Loading config: .. code-block:: python config = load_config(Path("mcp_config.yaml")) print(f"Loaded {len(config.templates)} templates") """ if not config_file.exists(): raise FileNotFoundError(f"Config file not found: {config_file}") try: with open(config_file) as f: data = yaml.safe_load(f) # Convert template data templates = [] for template_data in data.get("templates", []): templates.append(ServerTemplate(**template_data)) # Convert server data servers = [] for server_data in data.get("servers", []): servers.append(ServerConfig(**server_data)) # Create config config_data = data.copy() config_data["templates"] = templates config_data["servers"] = servers return DownloaderConfig(**config_data) except Exception as e: raise ValueError(f"Invalid config file: {e}")
[docs] def save_config(config: DownloaderConfig, config_file: Path) -> None: """Save configuration to YAML file. Args: config: Configuration to save config_file: Path to save file Example: Saving config: .. code-block:: python config = DownloaderConfig(max_concurrent=10) save_config(config, Path("my_config.yaml")) """ # Convert to dict for YAML serialization data = config.model_dump(mode="json") # Ensure directories exist config_file.parent.mkdir(parents=True, exist_ok=True) with open(config_file, "w") as f: yaml.dump(data, f, default_flow_style=False, sort_keys=False)