""" MCP Server Configuration Loads configuration from environment variables and provides settings for the MCP server, integrations, and security. """ import os from pathlib import Path from typing import Optional from dotenv import load_dotenv from cryptography.fernet import Fernet # Load environment variables load_dotenv() # Base paths PROJECT_ROOT = Path(__file__).parent.parent.parent TOOLS_DIR = PROJECT_ROOT / "tools" STORAGE_DIR = PROJECT_ROOT / "tools" / "storage" CACHE_DIR = PROJECT_ROOT / os.getenv("DSS_CACHE_DIR", ".dss/cache") class MCPConfig: """MCP Server Configuration""" # Server Settings HOST: str = os.getenv("DSS_MCP_HOST", "127.0.0.1") PORT: int = int(os.getenv("DSS_MCP_PORT", "3457")) # Database DATABASE_PATH: str = os.getenv( "DATABASE_PATH", str(STORAGE_DIR / "dss.db") ) # Context Caching CONTEXT_CACHE_TTL: int = int(os.getenv("DSS_CONTEXT_CACHE_TTL", "300")) # 5 minutes # Encryption ENCRYPTION_KEY: Optional[str] = os.getenv("DSS_ENCRYPTION_KEY") @classmethod def get_cipher(cls) -> Optional[Fernet]: """Get Fernet cipher for encryption/decryption""" if not cls.ENCRYPTION_KEY: return None return Fernet(cls.ENCRYPTION_KEY.encode()) @classmethod def generate_encryption_key(cls) -> str: """Generate a new encryption key""" return Fernet.generate_key().decode() # Redis/Celery for worker pool REDIS_URL: str = os.getenv("REDIS_URL", "redis://localhost:6379/0") CELERY_BROKER_URL: str = os.getenv("CELERY_BROKER_URL", "redis://localhost:6379/0") CELERY_RESULT_BACKEND: str = os.getenv("CELERY_RESULT_BACKEND", "redis://localhost:6379/0") # Circuit Breaker CIRCUIT_BREAKER_FAILURE_THRESHOLD: int = int( os.getenv("CIRCUIT_BREAKER_FAILURE_THRESHOLD", "5") ) CIRCUIT_BREAKER_TIMEOUT_SECONDS: int = int( os.getenv("CIRCUIT_BREAKER_TIMEOUT_SECONDS", "60") ) # Logging LOG_LEVEL: str = os.getenv("LOG_LEVEL", "INFO").upper() class IntegrationConfig: """External Integration Configuration""" # Figma FIGMA_TOKEN: Optional[str] = os.getenv("FIGMA_TOKEN") FIGMA_CACHE_TTL: int = int(os.getenv("FIGMA_CACHE_TTL", "300")) # Anthropic (for Sequential Thinking) ANTHROPIC_API_KEY: Optional[str] = os.getenv("ANTHROPIC_API_KEY") # Jira (defaults, can be overridden per-user) JIRA_URL: Optional[str] = os.getenv("JIRA_URL") JIRA_USERNAME: Optional[str] = os.getenv("JIRA_USERNAME") JIRA_API_TOKEN: Optional[str] = os.getenv("JIRA_API_TOKEN") # Confluence (defaults, can be overridden per-user) CONFLUENCE_URL: Optional[str] = os.getenv("CONFLUENCE_URL") CONFLUENCE_USERNAME: Optional[str] = os.getenv("CONFLUENCE_USERNAME") CONFLUENCE_API_TOKEN: Optional[str] = os.getenv("CONFLUENCE_API_TOKEN") # Singleton instances mcp_config = MCPConfig() integration_config = IntegrationConfig() def validate_config() -> list[str]: """ Validate configuration and return list of warnings. Returns: List of warning messages for missing optional config """ warnings = [] if not mcp_config.ENCRYPTION_KEY: warnings.append( "DSS_ENCRYPTION_KEY not set. Integration credentials will not be encrypted. " f"Generate one with: python -c \"from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())\"" ) if not integration_config.ANTHROPIC_API_KEY: warnings.append("ANTHROPIC_API_KEY not set. Sequential Thinking tools will not be available.") if not integration_config.FIGMA_TOKEN: warnings.append("FIGMA_TOKEN not set. Figma tools will not be available.") return warnings if __name__ == "__main__": print("=== DSS MCP Configuration ===\n") print(f"MCP Server: {mcp_config.HOST}:{mcp_config.PORT}") print(f"Database: {mcp_config.DATABASE_PATH}") print(f"Context Cache TTL: {mcp_config.CONTEXT_CACHE_TTL}s") print(f"Encryption Key: {'✓ Set' if mcp_config.ENCRYPTION_KEY else '✗ Not Set'}") print(f"Redis URL: {mcp_config.REDIS_URL}") print(f"\nCircuit Breaker:") print(f" Failure Threshold: {mcp_config.CIRCUIT_BREAKER_FAILURE_THRESHOLD}") print(f" Timeout: {mcp_config.CIRCUIT_BREAKER_TIMEOUT_SECONDS}s") print(f"\n=== Integration Configuration ===\n") print(f"Figma Token: {'✓ Set' if integration_config.FIGMA_TOKEN else '✗ Not Set'}") print(f"Anthropic API Key: {'✓ Set' if integration_config.ANTHROPIC_API_KEY else '✗ Not Set'}") print(f"Jira URL: {integration_config.JIRA_URL or '✗ Not Set'}") print(f"Confluence URL: {integration_config.CONFLUENCE_URL or '✗ Not Set'}") warnings = validate_config() if warnings: print(f"\n⚠️ Warnings:") for warning in warnings: print(f" - {warning}") else: print(f"\n✓ Configuration is valid")