CORS preflight requests (OPTIONS) don't include Authorization headers
by browser design. The middleware was blocking these requests with 401.
Solution:
- Skip authentication check for OPTIONS requests
- OPTIONS requests are handled by CORS middleware only
- Actual requests (GET, POST) still require authentication
This fixes the "401 Unauthorized" error on OPTIONS /mcp when using
MCP Inspector or other browser-based clients with authentication enabled.
The previous fix added CORS middleware to the app, but mcp.run()
creates a new app instance that doesn't include our middleware.
Solution:
- Import uvicorn
- For streamable-http transport, run uvicorn directly with the
middleware-enhanced app (mcp_app)
- This ensures CORS middleware is actually applied
- For other transports (SSE), fall back to mcp.run() with a warning
This fixes the "OPTIONS /mcp HTTP/1.1 405 Method Not Allowed" error
by ensuring CORS middleware handles preflight requests properly.
This commit addresses two critical issues in the MCP server:
1. CORS Middleware Fix:
- Move CORS middleware outside the auth check so it's always enabled
- CORS is required for browser-based MCP clients, regardless of auth
- Fixes "OPTIONS /mcp HTTP/1.1 405 Method Not Allowed" error
2. Schema Cache Improvements:
- Add specific handling for corrupted JSON cache files
- Automatically remove corrupted cache files and log the action
- Prevents startup failures due to malformed JSON
- Better error messages to help diagnose cache issues
3. Configuration Updates:
- Change default SCHEMA_CACHE_DIR from /app/data/schemas to ./data/schemas
- Better default for local development (Docker still uses /app/data/schemas)
- Update .env.example with clearer documentation
These fixes improve robustness and make local development easier.
Implements comprehensive multi-user support allowing multiple users to
access the same MCP server instance with their own independent GeoGuessr
accounts. Each API key now has its own session storage and context.
## Multi-User Architecture
### New Components
**User Context System** (src/geoguessr_mcp/auth/user_context.py):
- UserContext dataclass tracks API key and associated GeoGuessr session
- Properties for user_id, username, ncfa_cookie, is_authenticated
- Automatically attached to each request
**Multi-User Session Manager** (src/geoguessr_mcp/auth/multi_user_session.py):
- MultiUserSessionManager manages separate SessionManager per API key
- Maps API keys to their own GeoGuessr sessions
- Methods: get_user_context, login_user, logout_user, set_user_cookie
- Global instance: multi_user_session_manager
**Request Context** (src/geoguessr_mcp/auth/request_context.py):
- ContextVar for accessing current user context in tools
- Functions: get_current_user_context, require_user_context, set_current_user_context
- Enables tools to access user-specific sessions automatically
### Updated Components
**Authentication Middleware** (src/geoguessr_mcp/middleware/auth.py):
- Now creates user context for each authenticated request
- Attaches context to both request.state and ContextVar
- Supports both authenticated and unauthenticated modes
- Default user context created when auth is disabled
**Authentication Tools** (src/geoguessr_mcp/tools/auth_tools.py):
- Completely rewritten for multi-user support
- login(): Creates session tied to caller's API key
- logout(): Logs out only the calling user's session
- set_ncfa_cookie(): Sets cookie for calling user only
- get_auth_status(): Returns calling user's auth status
- All tools use get_current_user_context() automatically
**GeoGuessr Client** (src/geoguessr_mcp/api/geoguessr_client.py):
- _get_authenticated_client() checks user context first
- Falls back to session_manager for backward compatibility
- Automatically uses caller's session when available
- No changes needed in services (profile, game, analysis)
## How It Works
1. User connects with API key in Authorization header
2. Middleware validates API key and creates/retrieves UserContext
3. UserContext attached to request.state and ContextVar
4. Tools call get_current_user_context() to access caller's session
5. Client automatically uses correct session for API calls
6. Each user's session is completely isolated
## Usage Example
```bash
# Configure multiple API keys
MCP_AUTH_ENABLED=true
MCP_API_KEYS=alice_key,bob_key,charlie_key
# Alice connects with: Authorization: Bearer alice_key
# Bob connects with: Authorization: Bearer bob_key
# Each can login to their own GeoGuessr account
# Sessions are completely independent
```
## Key Features
- **Zero Interference**: Users don't affect each other's sessions
- **Automatic Routing**: Requests automatically use correct user's session
- **Hot Reload**: Add new API keys and restart in ~2-3 seconds
- **Backward Compatible**: Still works with single-user mode
- **Fallback Support**: GEOGUESSR_NCFA_COOKIE still works as default
## Documentation Updates
- README.md: Added Multi-User Mode section with examples
- README.md: Updated authentication section with multi-user details
- README.md: Added "Adding New Users" workflow
- Key Features section now highlights multi-user support
## Technical Details
- Uses Python ContextVar for request-scoped user context
- Each API key gets its own SessionManager instance
- Session storage is in-memory (persists across requests, not restarts)
- Default cookie (GEOGUESSR_NCFA_COOKIE) used as fallback for all users
- Fully async/await compatible throughout
This commit implements several key improvements to the GeoGuessr MCP server:
## MCP Server Authentication
- Add Bearer token authentication for MCP server access control
- New middleware in src/geoguessr_mcp/middleware/auth.py
- Configuration via MCP_AUTH_ENABLED and MCP_API_KEYS environment variables
- Support for multiple API keys (comma-separated)
- Optional authentication - can be disabled for trusted deployments
- Clients connect using Authorization: Bearer YOUR_API_KEY header
## Docker Configuration Updates
- Update to use official pre-built image: nyxiumyuuki/geoguessr-mcp:latest
- Remove DOCKER_USERNAME and IMAGE_TAG from environment variables
- Simplify docker-compose.yml and docker-compose.prod.yml
- Remove healthcheck configuration (not necessary for the deployment)
## Deployment Improvements
- Move deploy.sh to scripts/deploy.sh for better organization
- Update deploy.sh to use official Docker image
- Add authentication validation in deployment script
- Improve deployment logging and error messages
## Documentation Updates
- Update README.md with authentication configuration examples
- Add MCP server authentication section with setup instructions
- Update environment variables table
- Simplify deployment instructions
- Update CLAUDE.md with new authentication architecture
- Add .env.example configuration for MCP authentication
## Technical Details
- Authentication middleware integrates with FastMCP's Starlette ASGI app
- Middleware validates Bearer tokens on all requests except /health
- Logs authentication attempts and failures
- Returns proper 401/403 HTTP status codes
- Validates configuration on startup to prevent misconfiguration
Resolves TODO items:
- [x] Fix Docker username in compose files and env vars
- [x] Add authentication to MCP server to allow access only to specific users
This commit adds comprehensive support for deploying the GeoGuessr MCP Server
to a VPS alongside existing nginx-proxy-manager setup (e.g., Firefly III).
Changes:
- Updated docker-compose.prod.yml to use existing firefly_network
- Removed standalone nginx service (uses nginx-proxy-manager instead)
- Changed from ports to expose for internal-only access
- Switched default to pre-built Docker Hub images
New files:
- DEPLOYMENT.md: Comprehensive deployment guide with SSL setup
- .env.production: Production-ready environment configuration template
- deploy.sh: Automated deployment script with health checks
Updated files:
- README.md: Added quick reference to VPS deployment with nginx-proxy-manager
- docker-compose.prod.yml: Simplified for proxy manager integration
Deployment features:
- Automatic SSL certificate management via nginx-proxy-manager
- Let's Encrypt integration for HTTPS
- Shared Docker network with existing services
- Persistent schema storage
- Health checks and logging
- Easy updates via deploy script
This setup allows users to deploy the MCP server on the same VPS as other
Docker services while using a single nginx-proxy-manager for SSL/HTTPS.
- Update Dockerfile to use pyproject.toml instead of requirements.txt
- Add support for Docker Hub image pulling in compose files
- Add comprehensive deployment documentation with multiple methods
- Create CLAUDE.md with development and architecture guide
- Add .dockerignore for optimized build context
- Update .env.example with Docker configuration variables
- Configure 24-hour monitoring interval by default
Changes:
- Dockerfile: Install from pyproject.toml, use main.py entry point
- docker-compose.yml: Add image option for registry deployment
- docker-compose.prod.yml: Add image option for VPS deployment
- README.md: Add Docker Hub push/pull workflows and examples
- CLAUDE.md: Comprehensive guide for AI assistants and developers
- .dockerignore: Exclude unnecessary files from Docker builds
- .env.example: Add DOCKER_USERNAME and IMAGE_TAG variables