Skip to main content
Glama

Redmine MCP Server

by snowild
config.py3.99 kB
""" 配置管理模組 負責載入和驗證環境變數配置 """ import os from typing import Optional from dotenv import load_dotenv class RedmineConfig: """Redmine MCP 服務器配置管理""" def __init__(self): # 載入環境變數 load_dotenv() # 必要配置 self.redmine_domain = self._get_required_env("REDMINE_DOMAIN") self.redmine_api_key = self._get_required_env("REDMINE_API_KEY") # 可選配置 - 使用專屬前綴避免與其他專案環境變數衝突 self.redmine_timeout = int(os.getenv("REDMINE_MCP_TIMEOUT") or os.getenv("REDMINE_TIMEOUT") or "30") # 日誌級別管理策略: # 1. 優先使用 REDMINE_MCP_LOG_LEVEL(專屬變數) # 2. 其次使用 LOG_LEVEL(向後相容) # 3. 都沒設定時預設為 INFO # 4. FASTMCP_LOG_LEVEL 始終跟隨最終的日誌級別值 redmine_log_level = os.getenv("REDMINE_MCP_LOG_LEVEL") if redmine_log_level: self.log_level = redmine_log_level.upper() else: # 向後相容:如果沒有專屬變數,檢查舊的 LOG_LEVEL legacy_log_level = os.getenv("LOG_LEVEL") if legacy_log_level: self.log_level = legacy_log_level.upper() else: self.log_level = "INFO" # FastMCP 日誌級別控制 - 始終設定為與最終日誌級別相同的值 # 無論使用者是否有設定 FASTMCP_LOG_LEVEL,都會被覆蓋 os.environ["FASTMCP_LOG_LEVEL"] = self.log_level self.fastmcp_log_level = self.log_level self.effective_log_level = self.log_level self.debug_mode = self.effective_log_level == "DEBUG" self._validate_config() def _get_required_env(self, key: str) -> str: """取得必要的環境變數,如果不存在則拋出錯誤""" value = os.getenv(key) if not value: raise ValueError(f"必要的環境變數 {key} 未設定") return value def _validate_config(self) -> None: """驗證配置的有效性""" # 驗證 domain 格式 if not self.redmine_domain.startswith(('http://', 'https://')): raise ValueError("REDMINE_DOMAIN 必須以 http:// 或 https:// 開頭") # 移除末尾的斜線 self.redmine_domain = self.redmine_domain.rstrip('/') # 驗證 API key 不為空 if not self.redmine_api_key.strip(): raise ValueError("REDMINE_API_KEY 不能為空") # 驗證 timeout 值 if self.redmine_timeout <= 0: raise ValueError("REDMINE_TIMEOUT 必須大於 0") # 驗證 log_level 值 valid_levels = ['DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL'] if self.log_level not in valid_levels: raise ValueError(f"日誌級別必須是以下值之一: {', '.join(valid_levels)}(當前: {self.log_level})") @property def api_headers(self) -> dict[str, str]: """回傳 API 請求所需的標頭""" return { 'X-Redmine-API-Key': self.redmine_api_key, 'Content-Type': 'application/json' } def __repr__(self) -> str: """除錯用的字串表示,隱藏敏感資訊""" return f"RedmineConfig(domain='{self.redmine_domain}', timeout={self.redmine_timeout}, log_level='{self.log_level}', fastmcp_log_level='{self.fastmcp_log_level}', debug={self.debug_mode})" # 全域配置實例 _config: Optional[RedmineConfig] = None def get_config() -> RedmineConfig: """取得全域配置實例(單例模式)""" global _config if _config is None: _config = RedmineConfig() return _config def reload_config() -> RedmineConfig: """重新載入配置(主要用於測試)""" global _config _config = None return get_config()

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/snowild/redmine-mcp'

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