"""Startup configuration for the Firefox RDP MCP server."""
from __future__ import annotations
from dataclasses import dataclass
import ipaddress
import os
import socket
from .errors import ConfigurationError
def _readInt(name: str, default: int, minimum: int = 1) -> int:
value = os.environ.get(name, str(default))
try:
result = int(value)
except ValueError as error:
raise ConfigurationError(
f"{name} must be an integer."
) from error
if result < minimum:
raise ConfigurationError(
f"{name} must be at least {minimum}."
)
return result
def _requireLoopback(host: str) -> None:
try:
addresses = socket.getaddrinfo(
host,
None,
type=socket.SOCK_STREAM,
)
except socket.gaierror as error:
raise ConfigurationError(
f"FIREFOX_RDP_HOST cannot be resolved: {host}"
) from error
if not addresses:
raise ConfigurationError(
f"FIREFOX_RDP_HOST cannot be resolved: {host}"
)
for address in addresses:
value = address[4][0].split("%", 1)[0]
if not ipaddress.ip_address(value).is_loopback:
raise ConfigurationError(
"FIREFOX_RDP_HOST must resolve only to loopback addresses."
)
@dataclass(frozen=True)
class Config:
"""Hold validated immutable process configuration."""
host: str
port: int
max_file_bytes: int
max_upload_bytes: int
upload_chunk_bytes: int
max_elements: int
max_text_chars: int
request_timeout_ms: int
log_level: str
@classmethod
def fromEnvironment(cls) -> "Config":
"""Read and validate all supported environment variables."""
host = os.environ.get("FIREFOX_RDP_HOST", "127.0.0.1")
_requireLoopback(host)
log_level = os.environ.get(
"FIREFOX_MCP_LOG_LEVEL",
"info",
).lower()
if log_level not in {"debug", "info", "warning", "error"}:
raise ConfigurationError(
"FIREFOX_MCP_LOG_LEVEL must be debug, info, warning, "
"or error."
)
return cls(
host=host,
port=_readInt("FIREFOX_RDP_PORT", 6000),
max_file_bytes=_readInt(
"FIREFOX_MCP_MAX_FILE_BYTES",
26_214_400,
),
max_upload_bytes=_readInt(
"FIREFOX_MCP_MAX_UPLOAD_BYTES",
52_428_800,
),
upload_chunk_bytes=_readInt(
"FIREFOX_MCP_UPLOAD_CHUNK_BYTES",
262_144,
),
max_elements=_readInt("FIREFOX_MCP_MAX_ELEMENTS", 500),
max_text_chars=_readInt(
"FIREFOX_MCP_MAX_TEXT_CHARS",
50_000,
),
request_timeout_ms=_readInt(
"FIREFOX_MCP_REQUEST_TIMEOUT_MS",
30_000,
),
log_level=log_level,
)