Fix CI/CD issues and add comprehensive tests for multi-user features #6

Merged
NyxiumYuuki merged 3 commits from claude/add-mcp-authentication-01V5tbppGEtXc3tvjRGoTcfh into master 2025-11-30 01:01:37 +01:00
3 changed files with 58 additions and 133 deletions
Showing only changes of commit c04ba73c8a - Show all commits

View file

@ -1,12 +1,12 @@
services: services:
geoguessr-mcp: geoguessr-mcp:
# Option 1: Build locally (for development) # Option 1: Build locally (for development)
# build: build:
# context: . context: .
# dockerfile: Dockerfile dockerfile: Dockerfile
# Option 2: Use pre-built image from Docker Hub (recommended) # Option 2: Use pre-built image from Docker Hub (recommended)
image: nyxiumyuuki/geoguessr-mcp:latest # image: nyxiumyuuki/geoguessr-mcp:latest
container_name: geoguessr-mcp-server container_name: geoguessr-mcp-server
restart: unless-stopped restart: unless-stopped

View file

@ -7,15 +7,12 @@ with automatic API monitoring and dynamic schema adaptation.
import logging import logging
import sys import sys
from typing import Any
from mcp.server.fastmcp import FastMCP from mcp.server.fastmcp import FastMCP
from starlette.applications import Starlette from starlette.middleware.cors import CORSMiddleware
from starlette.middleware import Middleware
from .config import settings from .config import settings
from .middleware import AuthenticationMiddleware from .middleware import AuthenticationMiddleware
from .monitoring import endpoint_monitor
from .tools import register_all_tools from .tools import register_all_tools
# Configure logging # Configure logging
@ -28,6 +25,9 @@ logging.basicConfig(
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
def main():
"""Main entry point for the server."""
# Create the MCP server instance # Create the MCP server instance
mcp = FastMCP( mcp = FastMCP(
"GeoGuessr Analyzer", "GeoGuessr Analyzer",
@ -60,100 +60,25 @@ mcp = FastMCP(
) )
# Register all tools # Register all tools
services = register_all_tools(mcp) register_all_tools(mcp)
# Setup authentication middleware if enabled # Setup authentication middleware if enabled
if settings.MCP_AUTH_ENABLED: if settings.MCP_AUTH_ENABLED:
logger.info("Setting up authentication middleware") logger.info("Setting up authentication middleware")
# Create a function to add middleware to the app # Récupérez l'application ASGI via streamable_http_app
def add_middleware_to_app(app): mcp_app = mcp.streamable_http_app()
"""Add authentication middleware to a Starlette app."""
if app is not None:
try:
app.add_middleware(AuthenticationMiddleware)
logger.info("Authentication middleware successfully added")
return True
except Exception as e:
logger.error(f"Failed to add middleware: {e}")
return False
# Try to add middleware immediately to any existing app # Ajoutez les middlewares
middleware_added = False mcp_app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"]
)
mcp_app.add_middleware(AuthenticationMiddleware)
# Try different possible locations where FastMCP might store the app
for attr_path in [
"mcp._transport.app",
"mcp.sse.app",
"mcp.http_server.app",
"mcp._http_server.app",
"mcp._app",
"mcp._asgi_app",
]:
try:
parts = attr_path.split(".")
obj = mcp
for part in parts[1:]: # Skip 'mcp' itself
obj = getattr(obj, part, None)
if obj is None:
break
if obj is not None and add_middleware_to_app(obj):
middleware_added = True
break
except (AttributeError, TypeError):
continue
if not middleware_added:
# If we couldn't add it immediately, wrap the run method
logger.info("Deferring middleware addition until server starts")
_original_run = mcp.run
def run_with_middleware_wrapper(*args, **kwargs):
"""Wrapper to try adding middleware when run() is called."""
# Try again when run is called
for attr_path in [
"mcp._transport.app",
"mcp.sse.app",
"mcp.http_server.app",
"mcp._http_server.app",
"mcp._app",
"mcp._asgi_app",
]:
try:
parts = attr_path.split(".")
obj = mcp
for part in parts[1:]:
obj = getattr(obj, part, None)
if obj is None:
break
if obj is not None and add_middleware_to_app(obj):
break
except (AttributeError, TypeError):
continue
return _original_run(*args, **kwargs)
mcp.run = run_with_middleware_wrapper
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( logger.info(
f"Starting GeoGuessr MCP Server on {settings.HOST}:{settings.PORT} " f"Starting GeoGuessr MCP Server on {settings.HOST}:{settings.PORT} "
f"with {settings.TRANSPORT} transport" f"with {settings.TRANSPORT} transport"

View file

@ -61,7 +61,7 @@ class TestMultiUserSessionManager:
assert session is None assert session is None
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_login_user_creates_manager_if_not_exists(self, manager, mock_http_client): async def test_login_user_creates_manager_if_not_exists(self, manager):
"""Test that login_user creates a manager if it doesn't exist.""" """Test that login_user creates a manager if it doesn't exist."""
# This test requires mocking the HTTP client for GeoGuessr API # This test requires mocking the HTTP client for GeoGuessr API
# We'll mark it as a placeholder for now # We'll mark it as a placeholder for now