# Nike — Football Data Platform MCP server and web dashboard for football (soccer) data, with full MLS support. Queries live data from [TheSportsDB](https://www.thesportsdb.com/) and exposes it via MCP tools for conversational analysis, with a SvelteKit dashboard for status and interactive testing. A PostgreSQL cache stores permanent data (teams, players, leagues, events) to minimise API calls. Project #205 --- ## Architecture ``` ┌─────────────────────────────────────────────────────────┐ │ nike/server.py — single process on 0.0.0.0:{PORT} │ │ │ │ GET / → SvelteKit dashboard (dashboard/build)│ │ GET /api/* → Dashboard JSON API │ │ /mcp/ → FastMCP HTTP (streamable) │ └──────────┬──────────────────────────────────────────────┘ │ nike/sportsdb.py ←→ nike/db.py (PostgreSQL cache) (TheSportsDB client) │ TheSportsDB API ``` ### Module responsibilities | Module | Role | |--------|------| | `nike/config.py` | Centralised settings from `.env` (API key, DB, server) | | `nike/sportsdb.py` | TheSportsDB client with in-memory TTL cache (live backend) | | `nike/db.py` | PostgreSQL connection pool + active cache layer for permanent data | | `nike/server.py` | FastAPI app: MCP tools, dashboard routes, mounts MCP ASGI | | `schema.sql` | Cache database DDL | ### MCP Tools | Tool | Description | |------|-------------| | `get_team_info(team_name)` | Team profile: stadium, capacity, location, founded year, colors | | `get_roster(team_name)` | Current squad grouped by position | | `get_player_info(player_name)` | Player profile: position, nationality, DOB, team, status | | `get_fixtures(team_name, status)` | Recent results and upcoming matches (`status`: all/upcoming/past) | | `get_standings(league, season)` | Full league table with points, goal difference, and form | | `get_match_result(team_name, match_date)` | Match result for a team on a specific date | | `get_match_detail(event_id)` ★ | Deep match stats, lineup, and timeline | | `get_livescores()` ★ | Current live soccer scores worldwide | ★ Requires a premium TheSportsDB key. The dashboard derives its tool list from these registrations via `GET /api/tools`, so it stays in sync automatically. --- ## Dashboard The web dashboard is a SvelteKit 2 / Svelte 5 / Tailwind CSS 4 + DaisyUI 5 app in `dashboard/`. | Route | Description | |-------|-------------| | `/` | System status: cache, API, and MCP health cards; followed teams; tools list; request log | | `/tools` | Interactive tool runner — pick a tool, fill in parameters, inspect raw output | ### Build (required before serving via FastAPI) ```bash cd dashboard npm install npm run build # outputs to dashboard/build/ ``` Once built, `python run.py` serves the SvelteKit app at `http://:{PORT}/`. ### Development (live reload) Run the FastAPI backend and the SvelteKit dev server in separate terminals: ```bash # Terminal 1 — backend python run.py # Terminal 2 — frontend (proxies /api and /mcp to localhost:8000) cd dashboard && npm run dev ``` The dev dashboard is at `http://localhost:5173`. --- ## Setup ### Prerequisites - Python >= 3.11 - PostgreSQL (for the cache; see `schema.sql`) - A TheSportsDB key (`3` is the free test key; premium tools require a paid key) ### Install ```bash python3 -m venv ~/env/nike source ~/env/nike/bin/activate pip install -e . ``` ### Configure Copy `.env.example` to `.env` and fill in your values (TheSportsDB key, database connection, server host/port). See `.env.example` for the full list of `NIKE_*` variables. ### Provision the cache database ```bash python scripts/apply_schema.py ``` This applies `schema.sql` to the PostgreSQL database configured in `.env`. --- ## Running ### Development ```bash python run.py ``` The server starts on `http://0.0.0.0:{PORT}`: - **Dashboard** → `http://:{PORT}/` - **MCP endpoint** → `http://:{PORT}/mcp` ### Production (systemd) ```bash sudo cp nike.service /etc/systemd/system/ sudo systemctl daemon-reload sudo systemctl enable --now nike ``` --- ## MCP Client Configuration Nike exposes a Streamable HTTP MCP endpoint at `/mcp/`. To connect an MCP client (e.g. Claude Desktop, Cline, or any MCP-compatible tool), add the following to your client's MCP server configuration: ```json { "mcpServers": { "nike": { "type": "streamable-http", "url": "http://:{PORT}/mcp/" } } } ``` Once connected, you can ask questions like: - *"What matches are live right now?"* - *"Show the MLS standings"* - *"Who plays for Toronto FC?"* - *"Tell me about Federico Bernardeschi"* --- ## Scripts | Script | Purpose | |--------|---------| | `scripts/apply_schema.py` | Apply `schema.sql` to provision the cache database | | `scripts/discover_sportsdb.py` | Explore TheSportsDB API responses | --- ## Project Structure ``` nike/ ├── .env # Secrets (not committed) ├── pyproject.toml # Package metadata & dependencies ├── run.py # Entrypoint: python run.py ├── schema.sql # Cache database DDL ├── nike.service # systemd unit file ├── nike/ │ ├── __init__.py │ ├── config.py # Settings from .env │ ├── sportsdb.py # TheSportsDB client (live backend) │ ├── db.py # PostgreSQL pool + active cache │ ├── logging_config.py # Structured logging setup │ └── server.py # FastAPI + MCP server ├── dashboard/ # SvelteKit + DaisyUI dashboard └── scripts/ ├── apply_schema.py # Provision the cache database └── discover_sportsdb.py # API exploration ``` --- ## Caching Nike caches in two layers to minimise TheSportsDB calls: a short-lived in-memory TTL cache in `nike/sportsdb.py`, and a PostgreSQL cache (`nike/db.py`) for permanent data such as teams, players, leagues, and events. The dashboard's **Clear Cache** button (and `POST /api/cache/invalidate`) flushes both. ## File Management Philosophy Following red panda-approved practices: - **Under 500 lines:** ✅ Perfect! Red pandas are happy - **500-1000 lines:** ⚠️ Acceptable, but watch carefully - **Over 1000 lines:** 🚨 Time to refactor! Split into multiple files Large files burn through LLM context and produce poor results. Keep files focused and modular. ## Monitoring & Health Check Endpoints Follow standard Kubernetes health check endpoints for container orchestration: ### /ready/ - Readiness probe checks if the application is ready to serve traffic Validates database connectivity Validates cache connectivity Returns 200 if ready, 503 if dependencies are unavailable Used by load balancers to determine if pod should receive traffic ### /live/ - Liveness probe checks if the application process is alive Simple health check with minimal logic Returns 200 if Django is responding to requests Used by Kubernetes to determine if pod should be restarted ### /metrics Detailed metrics, use Prometheus and Alloy integration for logs rather than custom health endpoints. ## Documentation Place documentation in the docs directory of the repository /docs/ HTML documents must follow docs/documentation_style_guide.html ### Diagrams When creating or updating diagrams in HTML files, use MERMAID --- *Remember: Red pandas are tough critics, but they reward quality with their approval. Strive for MCP servers that would make a red panda proud!* 🐾