fix: change mcp_api_keys to string field to avoid JSON parsing
Pydantic was trying to parse List[str] as JSON from env vars. Changed to use a string field (mcp_api_keys_raw) and parse manually in model_validator, then expose as property. This fixes the JSONDecodeError when reading MCP_API_KEYS from .env
This commit is contained in:
@@ -15,6 +15,8 @@ class Settings(BaseSettings):
|
||||
env_file_encoding="utf-8",
|
||||
case_sensitive=False,
|
||||
extra="ignore",
|
||||
# Don't try to parse env vars as JSON for complex types
|
||||
env_parse_none_str="null",
|
||||
)
|
||||
|
||||
# Gitea configuration
|
||||
@@ -72,9 +74,10 @@ class Settings(BaseSettings):
|
||||
default=True,
|
||||
description="Enable API key authentication (disable only for testing)",
|
||||
)
|
||||
mcp_api_keys: List[str] = Field(
|
||||
default_factory=list,
|
||||
description="List of valid API keys for MCP access (comma-separated in env)",
|
||||
mcp_api_keys_raw: str = Field(
|
||||
default="",
|
||||
description="Comma-separated API keys for MCP access",
|
||||
alias="MCP_API_KEYS",
|
||||
)
|
||||
max_auth_failures: int = Field(
|
||||
default=5,
|
||||
@@ -105,34 +108,26 @@ class Settings(BaseSettings):
|
||||
raise ValueError("gitea_token cannot be empty or whitespace")
|
||||
return v.strip()
|
||||
|
||||
@field_validator("mcp_api_keys", mode="before")
|
||||
@classmethod
|
||||
def parse_api_keys(cls, v: object) -> List[str]:
|
||||
"""Parse API keys from comma-separated string or list."""
|
||||
if v is None:
|
||||
return []
|
||||
if isinstance(v, str):
|
||||
# Empty string returns empty list
|
||||
if not v.strip():
|
||||
return []
|
||||
# Split by comma and strip whitespace
|
||||
keys = [key.strip() for key in v.split(",") if key.strip()]
|
||||
return keys
|
||||
elif isinstance(v, list):
|
||||
return v
|
||||
return []
|
||||
|
||||
@model_validator(mode="after")
|
||||
def validate_api_keys_if_auth_enabled(self) -> "Settings":
|
||||
"""Validate API keys if authentication is enabled."""
|
||||
if self.auth_enabled and not self.mcp_api_keys:
|
||||
def validate_and_parse_api_keys(self) -> "Settings":
|
||||
"""Parse and validate API keys if authentication is enabled."""
|
||||
# Parse comma-separated keys into list
|
||||
keys = []
|
||||
if self.mcp_api_keys_raw and self.mcp_api_keys_raw.strip():
|
||||
keys = [key.strip() for key in self.mcp_api_keys_raw.split(",") if key.strip()]
|
||||
|
||||
# Store in a property we'll access
|
||||
object.__setattr__(self, "_mcp_api_keys", keys)
|
||||
|
||||
# Validate if auth is enabled
|
||||
if self.auth_enabled and not keys:
|
||||
raise ValueError(
|
||||
"At least one API key must be configured when auth_enabled=True. "
|
||||
"Set MCP_API_KEYS environment variable or disable auth with AUTH_ENABLED=false"
|
||||
)
|
||||
|
||||
# Validate key format (at least 32 characters for security)
|
||||
for key in self.mcp_api_keys:
|
||||
for key in keys:
|
||||
if len(key) < 32:
|
||||
raise ValueError(
|
||||
f"API keys must be at least 32 characters long. "
|
||||
@@ -140,6 +135,11 @@ class Settings(BaseSettings):
|
||||
)
|
||||
|
||||
return self
|
||||
|
||||
@property
|
||||
def mcp_api_keys(self) -> List[str]:
|
||||
"""Get parsed list of API keys."""
|
||||
return getattr(self, "_mcp_api_keys", [])
|
||||
|
||||
@property
|
||||
def gitea_base_url(self) -> str:
|
||||
|
||||
Reference in New Issue
Block a user