feat: allow configurable user agent

Support overriding the default UA via configuration for stricter gateways.
This commit is contained in:
2026-02-04 19:34:25 +03:00
parent 0dbbb09317
commit 5bb8405340
2 changed files with 13 additions and 2 deletions

View File

@@ -7,6 +7,9 @@ from urllib.parse import urlparse
from dotenv import load_dotenv from dotenv import load_dotenv
DEFAULT_USER_AGENT = "ctfd-mcp/0.1 (+https://github.com/)"
class ConfigError(Exception): class ConfigError(Exception):
"""Raised when configuration is missing or invalid.""" """Raised when configuration is missing or invalid."""
@@ -22,6 +25,7 @@ class Config:
read_timeout: float | None = None read_timeout: float | None = None
username: str | None = None username: str | None = None
password: str | None = None password: str | None = None
user_agent: str | None = None
@property @property
def auth_header(self) -> dict[str, str]: def auth_header(self) -> dict[str, str]:
@@ -51,6 +55,7 @@ def load_config() -> Config:
total_timeout = _parse_timeout("CTFD_TIMEOUT") total_timeout = _parse_timeout("CTFD_TIMEOUT")
connect_timeout = _parse_timeout("CTFD_CONNECT_TIMEOUT") connect_timeout = _parse_timeout("CTFD_CONNECT_TIMEOUT")
read_timeout = _parse_timeout("CTFD_READ_TIMEOUT") read_timeout = _parse_timeout("CTFD_READ_TIMEOUT")
user_agent = os.getenv("CTFD_USER_AGENT")
if not base_url: if not base_url:
raise ConfigError( raise ConfigError(
@@ -75,6 +80,10 @@ def load_config() -> Config:
"Set CTFD_TOKEN, CTFD_SESSION or both CTFD_USERNAME/CTFD_PASSWORD." "Set CTFD_TOKEN, CTFD_SESSION or both CTFD_USERNAME/CTFD_PASSWORD."
) )
user_agent = user_agent.strip() if user_agent else ""
if not user_agent:
user_agent = DEFAULT_USER_AGENT
return Config( return Config(
base_url.rstrip("/"), base_url.rstrip("/"),
token.strip() if token else None, token.strip() if token else None,
@@ -85,4 +94,5 @@ def load_config() -> Config:
read_timeout=read_timeout, read_timeout=read_timeout,
username=username.strip() if username else None, username=username.strip() if username else None,
password=password.strip() if password else None, password=password.strip() if password else None,
user_agent=user_agent,
) )

View File

@@ -7,7 +7,7 @@ from typing import Any
import httpx import httpx
from .config import Config from .config import DEFAULT_USER_AGENT, Config
class CTFdClientError(Exception): class CTFdClientError(Exception):
@@ -45,9 +45,10 @@ class CTFdClient:
read=config.read_timeout if config.read_timeout is not None else 15.0, read=config.read_timeout if config.read_timeout is not None else 15.0,
) )
# Force h1 and send explicit Accept/UA to reduce chances of HTML/redirect responses. # Force h1 and send explicit Accept/UA to reduce chances of HTML/redirect responses.
user_agent = (config.user_agent or "").strip() or DEFAULT_USER_AGENT
headers = { headers = {
"Accept": "application/json", "Accept": "application/json",
"User-Agent": "ctfd-mcp/0.1 (+https://github.com/)", "User-Agent": user_agent,
"X-Requested-With": "XMLHttpRequest", "X-Requested-With": "XMLHttpRequest",
**config.auth_header, **config.auth_header,
} }