Skip to main content
Glama
kjpou1

ForexFactory MCP Server

by kjpou1
settings.py4.42 kB
""" settings.py Centralized application configuration for ForexFactory MCP. This module uses Pydantic's BaseSettings to define strongly-typed configuration values with sensible defaults. Environment variables (and .env files) override these defaults automatically. We also expose a `get_settings()` function (cached with @lru_cache) to ensure the Settings object is created only once per process. This avoids the pitfalls of manual globals or singletons while keeping access simple and consistent. Usage: from forexfactory_mcp.settings import get_settings settings = get_settings() print(settings.BASE_URL) timeout = settings.SCRAPER_TIMEOUT_MS headers = settings.EXTRA_HTTP_HEADERS """ from functools import lru_cache from typing import List, Optional from zoneinfo import ZoneInfo from pydantic import field_validator from pydantic_settings import BaseSettings, SettingsConfigDict from tzlocal import get_localzone class Settings(BaseSettings): """ Application configuration class. Values are: - Pulled from environment variables if available. - Otherwise, fallback defaults defined here are used. - Optionally loaded from a `.env` file in the project root. Example: export SCRAPER_TIMEOUT_MS=10000 → overrides default timeout (5s → 10s). """ # === Core configuration values === BASE_URL: str = "https://www.forexfactory.com" SCRAPER_TIMEOUT_MS: int = 5000 # Default 5s (Playwright expects ms) # === MCP namespace === NAMESPACE: str = "ffcal" # === MCP server transport === MCP_TRANSPORT: str = "stdio" # stdio | http | sse MCP_HOST: str = "127.0.0.1" # only relevant for http/sse MCP_PORT: int = 8000 # only relevant for http/sse # === Default HTTP headers for Playwright === USER_AGENT: str = ( "Mozilla/5.0 (Windows NT 10.0; Win64; x64) " "AppleWebKit/537.36 (KHTML, like Gecko) " "Chrome/127.0.0.0 Safari/537.36" ) ACCEPT: str = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" ACCEPT_LANGUAGE: str = "en-US,en;q=0.9" # === Event field filtering === INCLUDE_FIELDS: Optional[List[str]] = None EXCLUDE_FIELDS: Optional[List[str]] = None LOCAL_TIMEZONE: str = "UTC" # Tell Pydantic to look for environment variables in `.env` model_config = SettingsConfigDict(env_file=".env", env_file_encoding="utf-8") @field_validator("INCLUDE_FIELDS", "EXCLUDE_FIELDS", mode="before") @classmethod def split_comma_or_blank(cls, v): """ Normalize values: - blank string → None - comma separated → list - JSON array → list """ if v is None: return None if isinstance(v, str): v = v.strip() if not v: # blank string return None return [x.strip() for x in v.split(",") if x.strip()] return v @property def default_fields(self) -> list[str]: """Default lean set of fields if INCLUDE_FIELDS not set.""" return [ "id", "title", "currency", "impact", "datetime", "forecast", "previous", "actual", ] @property def extra_http_headers(self) -> dict[str, str]: """ Build the HTTP headers dict for Playwright requests. Returns values that can be directly passed to `page.set_extra_http_headers()`. """ return { "User-Agent": self.USER_AGENT, "Accept": self.ACCEPT, "Accept-Language": self.ACCEPT_LANGUAGE, } @property def local_tz(self) -> ZoneInfo: try: return ZoneInfo(self.LOCAL_TIMEZONE) except Exception: # fallback to system local timezone try: return get_localzone() except Exception: return ZoneInfo("UTC") @lru_cache def get_settings() -> Settings: """ Cached accessor for the global Settings instance. Using @lru_cache ensures: - Settings are instantiated only once per process. - No accidental recreation of config objects on every import. - Easy reset in tests (`get_settings.cache_clear()`). Returns: Settings: The singleton configuration instance. """ return Settings()

Implementation Reference

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/kjpou1/forexfactory-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server