Skip to main content
Glama
golfamigo

Odoo MCP Unified Server

by golfamigo
config.py4.35 kB
""" Unified Configuration Management for Odoo MCP Server Type-safe configuration with validation """ import os from typing import Optional from dataclasses import dataclass from pathlib import Path import json @dataclass class OdooConfig: """Odoo connection configuration""" url: str database: str username: str password: str timeout: int = 60 verify_ssl: bool = False def __post_init__(self): """Validate configuration""" if not self.url: raise ValueError("ODOO_URL is required") if not self.database: raise ValueError("ODOO_DB is required") if not self.username: raise ValueError("ODOO_USERNAME is required") if not self.password: raise ValueError("ODOO_PASSWORD is required") # Ensure URL doesn't end with slash self.url = self.url.rstrip('/') @classmethod def from_env(cls) -> "OdooConfig": """Load configuration from environment variables""" return cls( url=os.getenv("ODOO_URL", ""), database=os.getenv("ODOO_DB", ""), username=os.getenv("ODOO_USERNAME", ""), password=os.getenv("ODOO_PASSWORD", ""), timeout=int(os.getenv("ODOO_TIMEOUT", "60")), verify_ssl=os.getenv("ODOO_VERIFY_SSL", "false").lower() == "true" ) @classmethod def from_json(cls, file_path: str) -> "OdooConfig": """Load configuration from JSON file""" with open(file_path, 'r') as f: data = json.load(f) return cls(**data) def to_dict(self) -> dict: """Convert to dictionary (without password)""" return { "url": self.url, "database": self.database, "username": self.username, "timeout": self.timeout, "verify_ssl": self.verify_ssl } @dataclass class MCPConfig: """MCP Server configuration""" transport: str = "stdio" # stdio or sse host: str = "0.0.0.0" port: int = 8000 log_level: str = "INFO" @classmethod def from_env(cls) -> "MCPConfig": """Load configuration from environment variables""" return cls( transport=os.getenv("MCP_TRANSPORT", "stdio"), host=os.getenv("HOST", "0.0.0.0"), port=int(os.getenv("PORT", "8000")), log_level=os.getenv("LOG_LEVEL", "INFO") ) @dataclass class UnifiedConfig: """Unified configuration for the entire MCP server""" odoo: OdooConfig mcp: MCPConfig @classmethod def from_env(cls) -> "UnifiedConfig": """Load all configuration from environment variables""" return cls( odoo=OdooConfig.from_env(), mcp=MCPConfig.from_env() ) @classmethod def from_json(cls, file_path: str) -> "UnifiedConfig": """Load all configuration from JSON file""" with open(file_path, 'r') as f: data = json.load(f) return cls( odoo=OdooConfig(**data.get("odoo", {})), mcp=MCPConfig(**data.get("mcp", {})) ) def validate(self) -> bool: """Validate entire configuration""" try: # OdooConfig validation happens in __post_init__ if self.mcp.transport not in ["stdio", "sse"]: raise ValueError(f"Invalid transport: {self.mcp.transport}") if self.mcp.port < 1 or self.mcp.port > 65535: raise ValueError(f"Invalid port: {self.mcp.port}") return True except Exception as e: raise ValueError(f"Configuration validation failed: {e}") # Global configuration instance _config: Optional[UnifiedConfig] = None def get_config() -> UnifiedConfig: """Get global configuration instance (singleton)""" global _config if _config is None: # Try to load from JSON file first, fall back to environment config_file = os.getenv("MCP_CONFIG_FILE") if config_file and Path(config_file).exists(): _config = UnifiedConfig.from_json(config_file) else: _config = UnifiedConfig.from_env() # Validate _config.validate() return _config def reset_config(): """Reset global configuration (useful for testing)""" global _config _config = None

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/golfamigo/odooMcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server