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",
|
env_file_encoding="utf-8",
|
||||||
case_sensitive=False,
|
case_sensitive=False,
|
||||||
extra="ignore",
|
extra="ignore",
|
||||||
|
# Don't try to parse env vars as JSON for complex types
|
||||||
|
env_parse_none_str="null",
|
||||||
)
|
)
|
||||||
|
|
||||||
# Gitea configuration
|
# Gitea configuration
|
||||||
@@ -72,9 +74,10 @@ class Settings(BaseSettings):
|
|||||||
default=True,
|
default=True,
|
||||||
description="Enable API key authentication (disable only for testing)",
|
description="Enable API key authentication (disable only for testing)",
|
||||||
)
|
)
|
||||||
mcp_api_keys: List[str] = Field(
|
mcp_api_keys_raw: str = Field(
|
||||||
default_factory=list,
|
default="",
|
||||||
description="List of valid API keys for MCP access (comma-separated in env)",
|
description="Comma-separated API keys for MCP access",
|
||||||
|
alias="MCP_API_KEYS",
|
||||||
)
|
)
|
||||||
max_auth_failures: int = Field(
|
max_auth_failures: int = Field(
|
||||||
default=5,
|
default=5,
|
||||||
@@ -105,34 +108,26 @@ class Settings(BaseSettings):
|
|||||||
raise ValueError("gitea_token cannot be empty or whitespace")
|
raise ValueError("gitea_token cannot be empty or whitespace")
|
||||||
return v.strip()
|
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")
|
@model_validator(mode="after")
|
||||||
def validate_api_keys_if_auth_enabled(self) -> "Settings":
|
def validate_and_parse_api_keys(self) -> "Settings":
|
||||||
"""Validate API keys if authentication is enabled."""
|
"""Parse and validate API keys if authentication is enabled."""
|
||||||
if self.auth_enabled and not self.mcp_api_keys:
|
# 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(
|
raise ValueError(
|
||||||
"At least one API key must be configured when auth_enabled=True. "
|
"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"
|
"Set MCP_API_KEYS environment variable or disable auth with AUTH_ENABLED=false"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Validate key format (at least 32 characters for security)
|
# Validate key format (at least 32 characters for security)
|
||||||
for key in self.mcp_api_keys:
|
for key in keys:
|
||||||
if len(key) < 32:
|
if len(key) < 32:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
f"API keys must be at least 32 characters long. "
|
f"API keys must be at least 32 characters long. "
|
||||||
@@ -140,6 +135,11 @@ class Settings(BaseSettings):
|
|||||||
)
|
)
|
||||||
|
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
@property
|
||||||
|
def mcp_api_keys(self) -> List[str]:
|
||||||
|
"""Get parsed list of API keys."""
|
||||||
|
return getattr(self, "_mcp_api_keys", [])
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def gitea_base_url(self) -> str:
|
def gitea_base_url(self) -> str:
|
||||||
|
|||||||
Reference in New Issue
Block a user