settings.py•6.86 kB
"""
Configuration settings using Pydantic for validation and type safety.
"""
from enum import Enum
from pathlib import Path
from typing import Any, Dict, List, Optional
from pydantic import Field, field_validator
from pydantic_settings import BaseSettings, SettingsConfigDict
class LogLevel(str, Enum):
"""Logging level enumeration."""
DEBUG = "DEBUG"
INFO = "INFO"
WARNING = "WARNING"
ERROR = "ERROR"
CRITICAL = "CRITICAL"
class LogFormat(str, Enum):
"""Log format enumeration."""
JSON = "json"
TEXT = "text"
class TransportType(str, Enum):
"""Transport type enumeration."""
STDIO = "stdio"
SSE = "sse"
WEBSOCKET = "websocket"
class AuthType(str, Enum):
"""Authentication type enumeration."""
API_KEY = "api_key"
BEARER = "bearer"
OAUTH2 = "oauth2"
class Environment(str, Enum):
"""Environment enumeration."""
DEVELOPMENT = "development"
STAGING = "staging"
PRODUCTION = "production"
class TransportSettings(BaseSettings):
"""Transport configuration settings."""
type: TransportType = Field(default=TransportType.STDIO, description="Transport type")
class ServerSettings(BaseSettings):
"""Server configuration settings."""
name: str = Field(default="mcp-template-server", description="Server name")
version: str = Field(default="0.1.0", description="Server version")
description: str = Field(
default="Production-ready MCP server template", description="Server description"
)
debug: bool = Field(default=False, description="Enable debug mode")
transport: TransportSettings = Field(default_factory=TransportSettings)
class LoggingSettings(BaseSettings):
"""Logging configuration settings."""
level: LogLevel = Field(default=LogLevel.INFO, description="Logging level")
format: LogFormat = Field(default=LogFormat.JSON, description="Log format")
file: Optional[Path] = Field(default=None, description="Log file path")
processors: List[str] = Field(
default_factory=lambda: ["timestamp", "level", "logger", "stack_info"]
)
class AuthSettings(BaseSettings):
"""Authentication configuration settings."""
type: AuthType = Field(default=AuthType.API_KEY, description="Authentication type")
api_key: Optional[str] = Field(default=None, description="API key for authentication")
class RetrySettings(BaseSettings):
"""Retry configuration settings."""
max_attempts: int = Field(default=3, ge=1, description="Maximum retry attempts")
initial_delay: float = Field(default=1.0, ge=0, description="Initial delay in seconds")
max_delay: float = Field(default=60.0, ge=0, description="Maximum delay in seconds")
exponential_base: float = Field(default=2.0, ge=1, description="Exponential backoff base")
class ConnectionSettings(BaseSettings):
"""Connection configuration settings."""
timeout: int = Field(default=30, ge=1, description="Connection timeout in seconds")
retry: RetrySettings = Field(default_factory=RetrySettings)
class HeartbeatSettings(BaseSettings):
"""Heartbeat configuration settings."""
enabled: bool = Field(default=True, description="Enable heartbeat")
interval: int = Field(default=60, ge=1, description="Heartbeat interval in seconds")
class RegistryMetadata(BaseSettings):
"""Registry metadata settings."""
tags: List[str] = Field(default_factory=lambda: ["template", "python"])
capabilities: List[str] = Field(
default_factory=lambda: ["tools", "resources", "prompts"]
)
environment: Environment = Field(default=Environment.DEVELOPMENT)
class RegistrySettings(BaseSettings):
"""Registry configuration settings."""
enabled: bool = Field(default=True, description="Enable registry integration")
url: str = Field(
default="https://registry.example.com/api/v1", description="Registry endpoint URL"
)
auth: AuthSettings = Field(default_factory=AuthSettings)
connection: ConnectionSettings = Field(default_factory=ConnectionSettings)
heartbeat: HeartbeatSettings = Field(default_factory=HeartbeatSettings)
metadata: RegistryMetadata = Field(default_factory=RegistryMetadata)
@field_validator("url")
@classmethod
def validate_url(cls, v: str) -> str:
"""Validate that URL is not empty and has proper format."""
if not v or not v.strip():
raise ValueError("Registry URL cannot be empty")
if not v.startswith(("http://", "https://")):
raise ValueError("Registry URL must start with http:// or https://")
return v.strip()
class ToolsSettings(BaseSettings):
"""Tools configuration settings."""
enabled: List[str] = Field(
default_factory=lambda: ["example_calculator", "example_search"]
)
calculator: Dict[str, Any] = Field(default_factory=lambda: {"max_precision": 10})
search: Dict[str, Any] = Field(
default_factory=lambda: {"default_limit": 10, "max_limit": 100}
)
class ResourcesSettings(BaseSettings):
"""Resources configuration settings."""
enabled: List[str] = Field(default_factory=lambda: ["example_config", "example_status"])
cache: Dict[str, Any] = Field(default_factory=lambda: {"enabled": True, "ttl": 300})
class PromptsSettings(BaseSettings):
"""Prompts configuration settings."""
enabled: List[str] = Field(default_factory=lambda: ["example_prompt"])
templates: Dict[str, Any] = Field(default_factory=lambda: {"path": "./prompts"})
class HealthSettings(BaseSettings):
"""Health check configuration settings."""
enabled: bool = Field(default=True, description="Enable health checks")
checks: List[str] = Field(
default_factory=lambda: ["registry", "tools", "resources"]
)
class Settings(BaseSettings):
"""Main application settings."""
model_config = SettingsConfigDict(
env_file=".env",
env_file_encoding="utf-8",
env_nested_delimiter="__",
case_sensitive=False,
extra="ignore",
)
server: ServerSettings = Field(default_factory=ServerSettings)
logging: LoggingSettings = Field(default_factory=LoggingSettings)
registry: RegistrySettings = Field(default_factory=RegistrySettings)
tools: ToolsSettings = Field(default_factory=ToolsSettings)
resources: ResourcesSettings = Field(default_factory=ResourcesSettings)
prompts: PromptsSettings = Field(default_factory=PromptsSettings)
health: HealthSettings = Field(default_factory=HealthSettings)
def is_production(self) -> bool:
"""Check if running in production environment."""
return self.registry.metadata.environment == Environment.PRODUCTION
def is_debug(self) -> bool:
"""Check if debug mode is enabled."""
return self.server.debug or self.logging.level == LogLevel.DEBUG