Files
ds_mcp_template/build/lib/mcp_template/config/config_manager.py
T

134 lines
4.6 KiB
Python
Raw Normal View History

2025-09-11 23:13:58 +01:00
"""
Centralized Configuration Manager
"""
import os
import json
from typing import Dict, Any, Optional
from pathlib import Path
try:
from dotenv import load_dotenv
DOTENV_AVAILABLE = True
except ImportError:
DOTENV_AVAILABLE = False
class ConfigManager:
"""Centralized configuration manager for MCP components"""
def __init__(self, config_file: Optional[str] = None, env_file: Optional[str] = None):
self._config_file = config_file or "config.json"
self._env_file = env_file or ".env"
self._config: Dict[str, Any] = {}
self._loaded = False
async def load_config(self) -> Dict[str, Any]:
"""Load configuration from all sources"""
if self._loaded:
return self._config
# Load environment variables
await self._load_env_vars()
# Load JSON configuration file
await self._load_json_config()
# Merge configurations
self._config = await self._merge_configs()
self._loaded = True
return self._config
async def _load_env_vars(self) -> None:
"""Load environment variables"""
if DOTENV_AVAILABLE and Path(self._env_file).exists():
load_dotenv(self._env_file)
async def _load_json_config(self) -> Dict[str, Any]:
"""Load JSON configuration file"""
config_path = Path(self._config_file)
if config_path.exists():
with open(config_path, 'r') as f:
return json.load(f)
return {}
async def _merge_configs(self) -> Dict[str, Any]:
"""Merge all configuration sources"""
merged = {}
# Start with JSON config as base
json_config = await self._load_json_config()
merged.update(json_config)
# Override with environment variables
env_config = await self._get_env_config()
self._deep_update(merged, env_config)
return merged
async def _get_env_config(self) -> Dict[str, Any]:
"""Get configuration from environment variables"""
env_config = {}
# Server configuration
if os.getenv("MCP_SERVER_NAME"):
env_config.setdefault("server", {})["name"] = os.getenv("MCP_SERVER_NAME")
if os.getenv("MCP_SERVER_HOST"):
env_config.setdefault("server", {})["host"] = os.getenv("MCP_SERVER_HOST")
if os.getenv("MCP_SERVER_PORT"):
env_config.setdefault("server", {})["port"] = int(os.getenv("MCP_SERVER_PORT"))
if os.getenv("MCP_TRANSPORT"):
env_config.setdefault("server", {})["transport"] = os.getenv("MCP_TRANSPORT")
# Client configuration
if os.getenv("MCP_AI_PROVIDER"):
env_config.setdefault("client", {})["provider"] = os.getenv("MCP_AI_PROVIDER")
if os.getenv("MCP_AI_MODEL"):
env_config.setdefault("client", {})["model"] = os.getenv("MCP_AI_MODEL")
# API keys
for provider in ["OPENAI", "CLAUDE", "GROK"]:
api_key = os.getenv(f"{provider}_API_KEY")
if api_key:
env_config.setdefault("api_keys", {})[provider.lower()] = api_key
return env_config
def _deep_update(self, base_dict: Dict[str, Any], update_dict: Dict[str, Any]) -> None:
"""Deep update dictionary"""
for key, value in update_dict.items():
if isinstance(value, dict) and key in base_dict and isinstance(base_dict[key], dict):
self._deep_update(base_dict[key], value)
else:
base_dict[key] = value
async def get_server_config(self) -> Dict[str, Any]:
"""Get server-specific configuration"""
config = await self.load_config()
return config.get("server", {})
async def get_client_config(self) -> Dict[str, Any]:
"""Get client-specific configuration"""
config = await self.load_config()
return config.get("client", {})
async def get_api_key(self, provider: str) -> Optional[str]:
"""Get API key for a specific provider"""
config = await self.load_config()
api_keys = config.get("api_keys", {})
return api_keys.get(provider.lower())
async def save_config(self, config: Dict[str, Any]) -> None:
"""Save configuration to file"""
with open(self._config_file, 'w') as f:
json.dump(config, f, indent=2)
async def update_config(self, updates: Dict[str, Any]) -> None:
"""Update configuration and save"""
config = await self.load_config()
self._deep_update(config, updates)
await self.save_config(config)
self._loaded = False # Force reload on next access