"""
Centralized Configuration Management
Provides environment-aware configuration using Pydantic for validation
and type safety. Supports both environment variables and default values.
"""
import os
from typing import Literal, Optional
from pydantic import BaseModel, Field
class Settings(BaseModel):
"""Main configuration class with environment variable support"""
# Server Configuration
server_name: str = Field(
default="MCP Server Template",
description="Name of the MCP server"
)
host: str = Field(
default="0.0.0.0",
description="Host to bind the server to"
)
port: int = Field(
default=8080,
description="Port to bind the server to"
)
transport: Literal["streamable-http", "sse"] = Field(
default="streamable-http",
description="Transport protocol to use"
)
# Logging Configuration
log_level: str = Field(
default="INFO",
description="Logging level"
)
log_format: str = Field(
default="[%(levelname)s]: %(message)s",
description="Logging format string"
)
# Environment Configuration
environment: Literal["development", "production", "testing"] = Field(
default="development",
description="Runtime environment"
)
# Version Information
version: str = Field(
default="2.0.1",
description="Server version"
)
# Weather Service Configuration
weather_api_key: Optional[str] = Field(
default=None,
description="OpenWeatherMap API key"
)
use_mock_weather_data: bool = Field(
default=True,
description="Use mock weather data instead of real API calls"
)
model_config = {
# Enable environment variable loading with MCP_ prefix
"env_prefix": "MCP_",
"case_sensitive": False,
"env_file": ".env",
"env_file_encoding": "utf-8"
}
@classmethod
def from_env(cls) -> "Settings":
"""Create settings instance from environment variables"""
# Manual environment variable handling for compatibility
env_vars = {}
# Map environment variables to settings
env_mappings = {
"MCP_SERVER_NAME": "server_name",
"MCP_HOST": "host",
"MCP_PORT": "port",
"MCP_TRANSPORT": "transport",
"MCP_LOG_LEVEL": "log_level",
"MCP_LOG_FORMAT": "log_format",
"MCP_ENVIRONMENT": "environment",
"MCP_VERSION": "version",
"MCP_WEATHER_API_KEY": "weather_api_key",
"MCP_USE_MOCK_WEATHER_DATA": "use_mock_weather_data",
"WEATHER_API_KEY": "weather_api_key", # Alternative naming
"USE_MOCK_WEATHER_DATA": "use_mock_weather_data", # Alternative naming
"PORT": "port" # Cloud Run compatibility
}
for env_key, setting_key in env_mappings.items():
if env_key in os.environ:
value = os.environ[env_key]
# Convert port to int
if setting_key == "port":
try:
value = int(value)
except ValueError:
continue
# Convert boolean values
elif setting_key == "use_mock_weather_data":
value = value.lower() in ("true", "1", "yes", "on")
env_vars[setting_key] = value
return cls(**env_vars)
# Singleton pattern for settings
_settings: Settings | None = None
def get_settings() -> Settings:
"""Get singleton settings instance"""
global _settings
if _settings is None:
_settings = Settings.from_env()
return _settings
def reset_settings():
"""Reset settings singleton (useful for testing)"""
global _settings
_settings = None