diff --git a/src/geoguessr_mcp/__init__.py b/src/geoguessr_mcp/__init__.py index e69de29..eac7498 100644 --- a/src/geoguessr_mcp/__init__.py +++ b/src/geoguessr_mcp/__init__.py @@ -0,0 +1,13 @@ +""" +GeoGuessr MCP Server Package. + +A Model Context Protocol server for analyzing GeoGuessr game statistics +with automatic API monitoring and dynamic schema adaptation. +""" + +__version__ = "0.2.0" +__author__ = "Yûki VACHOT" + +from .main import mcp, main + +__all__ = ["mcp", "main", "__version__"] \ No newline at end of file diff --git a/src/geoguessr_mcp/config.py b/src/geoguessr_mcp/config.py index 373bdaf..6c0cc6d 100644 --- a/src/geoguessr_mcp/config.py +++ b/src/geoguessr_mcp/config.py @@ -1,17 +1,53 @@ -"""Configuration management.""" +"""Configuration management for GeoGuessr MCP Server.""" import os -from dataclasses import dataclass +from dataclasses import dataclass, field +from typing import Optional @dataclass class Settings: - HOST: str = os.getenv("MCP_HOST", "0.0.0.0") - PORT: int = int(os.getenv("MCP_PORT", "8000")) - TRANSPORT: str = os.getenv("MCP_TRANSPORT", "streamable-http") - GEOGUESSR_BASE_URL: str = "https://www.geoguessr.com/api" + """Application settings loaded from environment variables.""" + + # MCP Server Configuration + HOST: str = field(default_factory=lambda: os.getenv("MCP_HOST", "0.0.0.0")) + PORT: int = field(default_factory=lambda: int(os.getenv("MCP_PORT", "8000"))) + TRANSPORT: str = field(default_factory=lambda: os.getenv("MCP_TRANSPORT", "streamable-http")) + + # GeoGuessr API Configuration + GEOGUESSR_DOMAIN_NAME: str = "geoguessr.com" + GEOGUESSR_API_URL: str = "https://www.geoguessr.com/api" GAME_SERVER_URL: str = "https://game-server.geoguessr.com/api" - DEFAULT_NCFA_COOKIE: str | None = os.getenv("GEOGUESSR_NCFA_COOKIE") + DEFAULT_NCFA_COOKIE: Optional[str] = field( + default_factory=lambda: os.getenv("GEOGUESSR_NCFA_COOKIE") + ) + + # API Monitoring Configuration + MONITORING_ENABLED: bool = field( + default_factory=lambda: os.getenv("MONITORING_ENABLED", "true").lower() == "true" + ) + MONITORING_INTERVAL_HOURS: int = field( + default_factory=lambda: int(os.getenv("MONITORING_INTERVAL_HOURS", "24")) + ) + SCHEMA_CACHE_DIR: str = field( + default_factory=lambda: os.getenv("SCHEMA_CACHE_DIR", "/app/data/schemas") + ) + + # Logging Configuration + LOG_LEVEL: str = field(default_factory=lambda: os.getenv("LOG_LEVEL", "INFO")) + + # Request Configuration + REQUEST_TIMEOUT: float = field( + default_factory=lambda: float(os.getenv("REQUEST_TIMEOUT", "30.0")) + ) + MAX_RETRIES: int = field(default_factory=lambda: int(os.getenv("MAX_RETRIES", "3"))) + + def __post_init__(self): + """Validate configuration after initialization.""" + if self.PORT < 1 or self.PORT > 65535: + raise ValueError(f"Invalid port number: {self.PORT}") + if self.MONITORING_INTERVAL_HOURS < 1: + raise ValueError("Monitoring interval must be at least 1 hour") settings = Settings() diff --git a/src/geoguessr_mcp/main.py b/src/geoguessr_mcp/main.py index 10d7a28..8a935a3 100644 --- a/src/geoguessr_mcp/main.py +++ b/src/geoguessr_mcp/main.py @@ -1,19 +1,96 @@ -"""Main entry point for the Geoguessr MCP Server.""" +""" +GeoGuessr MCP Server - Main Entry Point. + +This server provides tools for analyzing GeoGuessr game statistics, +with automatic API monitoring and dynamic schema adaptation. +""" + +import asyncio +import logging +import sys from mcp.server.fastmcp import FastMCP from .config import settings +from .monitoring import endpoint_monitor from .tools import register_all_tools +# Configure logging +logging.basicConfig( + level=getattr(logging, settings.LOG_LEVEL), + format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", + handlers=[logging.StreamHandler(sys.stdout)], +) + +logger = logging.getLogger(__name__) + + +# Create the MCP server instance mcp = FastMCP( - "Geoguessr Analyzer", - instructions="MCP server for analyzing Geoguessr game statistics", + "GeoGuessr Analyzer", + instructions=""" + MCP server for analyzing GeoGuessr game statistics and optimizing gameplay strategy. + + This server provides: + - Profile and statistics retrieval + - Game history and analysis + - Performance tracking and recommendations + - API monitoring with automatic schema adaptation + + The server automatically tracks API endpoint changes and adapts to response format + modifications. Use the monitoring tools to check API status and discover available data. + + Authentication: + - Use 'login(email, password)' to authenticate with your GeoGuessr account + - Or use 'set_ncfa_cookie(cookie)' with a cookie from your browser + - Or set GEOGUESSR_NCFA_COOKIE environment variable for automatic auth + + Key tools: + - get_performance_summary() - Comprehensive overview of your account + - analyze_recent_games(count) - Analyze your recent gameplay + - get_strategy_recommendations() - Get personalized improvement tips + - check_api_status() - Monitor API endpoint availability + - explore_endpoint(path) - Discover new API endpoints + """, host=settings.HOST, port=settings.PORT, ) # Register all tools -register_all_tools(mcp) +services = register_all_tools(mcp) + + +async def start_background_tasks(): + """Start background monitoring tasks.""" + if settings.MONITORING_ENABLED: + logger.info("Starting API monitoring background task...") + await endpoint_monitor.start_periodic_monitoring() + + +async def stop_background_tasks(): + """Stop background monitoring tasks.""" + if endpoint_monitor._running: + await endpoint_monitor.stop_monitoring() + + +def main(): + """Main entry point for the server.""" + logger.info( + f"Starting GeoGuessr MCP Server on {settings.HOST}:{settings.PORT} " + f"with {settings.TRANSPORT} transport" + ) + + if settings.DEFAULT_NCFA_COOKIE: + logger.info("Default authentication cookie configured from environment") + else: + logger.warning( + "No default authentication cookie set. " + "Users will need to login or provide a cookie." + ) + + # Run the server + mcp.run(transport=settings.TRANSPORT) + if __name__ == "__main__": - mcp.run(transport=settings.TRANSPORT) + main()