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:
2026-01-29 20:30:28 +01:00
parent 0945f560ff
commit a0605eaa27

View File

@@ -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: