Metadata-Version: 2.4
Name: nfl-mcp
Version: 0.3.1
Summary: MCP server for NFL play-by-play data (nflverse, 2013-2025)
Project-URL: Homepage, https://github.com/ebhattad/nfl-mcp
Project-URL: Issues, https://github.com/ebhattad/nfl-mcp/issues
License: MIT
License-File: LICENSE
Keywords: analytics,football,llm,mcp,nfl,sports
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering :: Information Analysis
Requires-Python: >=3.10
Requires-Dist: click>=8.0
Requires-Dist: duckdb>=1.0
Requires-Dist: mcp>=1.0
Requires-Dist: nflreadpy>=0.1
Requires-Dist: polars>=0.20
Requires-Dist: pyarrow>=14.0
Requires-Dist: sse-starlette>=1.6
Requires-Dist: starlette>=0.27
Requires-Dist: tqdm>=4.0
Requires-Dist: uvicorn>=0.20
Provides-Extra: dev
Requires-Dist: mypy; extra == 'dev'
Requires-Dist: openai; extra == 'dev'
Requires-Dist: pytest; extra == 'dev'
Requires-Dist: pytest-cov; extra == 'dev'
Requires-Dist: python-dotenv; extra == 'dev'
Requires-Dist: ruff; extra == 'dev'
Description-Content-Type: text/markdown

# nfl-mcp

MCP server for NFL data (2013–2025), powered by [nflreadpy](https://github.com/nflverse/nflreadpy) and DuckDB.
Query play-by-play, rosters, injuries, stats, and more using natural language in Claude Code, VS Code, or Claude Desktop.

Ask Claude questions like:
- *"Who had the best EPA per play in 2024?"*
- *"Show me Patrick Mahomes' completion % over expected by season"*
- *"Compare 4th quarter red zone efficiency for KC vs PHI in 2023"*
- *"Which defenses had the highest sack rate in 3rd & long situations?"*
- *"Who was on IR for the Eagles in Week 10, 2023?"*
- *"Show me snap count trends for the Chiefs receiving corps in 2024"*

## Quickstart

```bash
pip install nfl-mcp        # or: uvx nfl-mcp
nfl-mcp init               # configure, load data, and start the server
```

`init` walks you through setup and offers to start the server immediately when done. No database server to install. No credentials to manage. Data is stored locally in DuckDB.

## Deploy to Azure

Run the server in the cloud as an [Azure Container App](https://learn.microsoft.com/azure/container-apps/) with one click:

[![Deploy to Azure](https://aka.ms/deploytoazurebutton)](https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2Febhattad%2Fnfl-mcp%2Fmain%2Finfra%2Fazuredeploy.json)

The button opens the Azure portal's **Custom deployment** blade prefilled from [`infra/azuredeploy.json`](infra/azuredeploy.json). Pick a resource group, then **Create**. It provisions a Container Apps Environment, a Log Analytics workspace, and the Container App (public HTTPS ingress on port 8000). When the deployment finishes, the `mcpUrl` output is your endpoint — point any MCP client at `https://<app>.<region>.azurecontainerapps.io/mcp`.

> **The data is baked into the image.** The full DuckDB database is built into the container image at build time, so the app serves read-only with **no runtime ingest** — it starts instantly, never re-downloads data, needs no external storage, and runs comfortably on `0.5` vCPU / `1Gi`. To refresh the data, rebuild the image (re-run the publish workflow); the [`Publish container image`](.github/workflows/docker.yml) workflow also rebuilds weekly. The replica is pinned to a single instance (`minReplicas = maxReplicas = 1`).

**One-time setup before the button works:**
1. The [`Publish container image`](.github/workflows/docker.yml) workflow must have pushed an image to `ghcr.io/ebhattad/nfl-mcp` (it runs weekly, on each GitHub release, or manually via *Actions → Run workflow*). The build ingests all default datasets, so it takes longer than a normal image build.
2. Make that GHCR package **public**: repo → *Packages* → `nfl-mcp` → *Package settings* → *Change visibility → Public*. The ARM template pulls the image without credentials, so it must be public.

## Prerequisites

- Python 3.10+
- [uv](https://docs.astral.sh/uv/) (recommended) or pip

## Setup

### 1. Initialize

```bash
nfl-mcp init
```

The wizard will:
1. Configure the local DuckDB database path
2. Download the default NFL datasets (play-by-play, rosters, stats, injuries, and more)
3. Auto-configure your IDE (Claude Desktop and/or VS Code)
4. Offer to start the server immediately

Options:

```
--skip-ingest       Configure without loading data
```

### 2. Start the server

`init` offers to start the server for you. If you need to start it manually later:

```bash
nfl-mcp serve
nfl-mcp serve --port 9000
nfl-mcp serve --host 0.0.0.0
```

The server uses the [MCP Streamable HTTP](https://modelcontextprotocol.io/docs/concepts/transports) transport. Point any MCP client at `http://<host>:<port>/mcp`.

> **Note:** The server must be running for your IDE to connect. Run `nfl-mcp serve` in a terminal and keep it open.

### 3. Verify

```bash
nfl-mcp doctor
```

Checks database connectivity, loaded data, and IDE configuration.

### 4. Manual client configuration (optional)

If you skipped IDE setup during init, or need to reconfigure:

```bash
nfl-mcp setup-client                    # auto-detect clients
nfl-mcp setup-client --client vscode    # VS Code only
nfl-mcp setup-client --client claude-desktop
```

Or configure manually. Add to `.vscode/mcp.json` (VS Code):

```json
{
  "servers": {
    "nfl": {
      "url": "http://localhost:8000/mcp"
    }
  }
}
```

Add to `~/Library/Application Support/Claude/claude_desktop_config.json` (Claude Desktop):

```json
{
  "mcpServers": {
    "nfl": {
      "url": "http://localhost:8000/mcp"
    }
  }
}
```

## CLI Reference

```
nfl-mcp init               Interactive setup wizard
nfl-mcp serve              Start the MCP server (Streamable HTTP, default port 8000)
nfl-mcp ingest             Load NFL data into the database
nfl-mcp setup-client       Configure IDE MCP clients
nfl-mcp doctor             Health check
```

### Serve options

```bash
nfl-mcp serve
nfl-mcp serve --port 9000
nfl-mcp serve --host 0.0.0.0
```

### Ingestion options

```bash
nfl-mcp ingest                          # default datasets, all available seasons
nfl-mcp ingest --dataset all            # every dataset
nfl-mcp ingest --dataset schedules      # one specific dataset
nfl-mcp ingest --dataset pbp --dataset injuries   # multiple datasets
nfl-mcp ingest --start 2020 --end 2024  # limit to a season range
nfl-mcp ingest --fresh                  # re-ingest even if already loaded
nfl-mcp ingest --list                   # show all available dataset names
```

Ingest is **idempotent** — re-running skips datasets and seasons already in the database.

## Datasets

All data is sourced from [nflverse](https://github.com/nflverse/nflverse-data) via nflreadpy and stored locally in DuckDB. **Every dataset below is ingested by default** — `nfl-mcp ingest` loads the full nflverse family so any data a client might need is already there.

> **Season coverage: 2013 onward.** Season-based tables are ingested from **2013** — the window where every nflverse source is complete and consistent — through the current season. Datasets that begin later (e.g. Next Gen Stats 2016, FTN charting 2022) start at their first available season. Non-seasonal reference tables (draft picks, combine, contracts, players) carry their full historical record.

| Table | Loaded range |
|---|---|
| `plays` | 2013–present |
| `schedules` | 2013–present |
| `rosters` | 2013–present |
| `player_stats` | 2013–present |
| `team_stats_raw` | 2013–present |
| `injuries` | 2013–present |
| `snap_counts` | 2013–present |
| `depth_charts` | 2013–present |
| `rosters_weekly` | 2013–present |
| `ff_opportunity` | 2013–present |
| `officials` | 2015–present |
| `nextgen_stats_*` | 2016–present |
| `participation` | 2016–2024 |
| `pfr_advstats_*` | 2018–present |
| `ftn_charting` | 2022–present |
| `teams` | current |
| `players` | all-time |
| `contracts` | historical |
| `trades` | historical |
| `draft_picks` | 1980–present |
| `combine` | all-time |
| `ff_playerids` | current |
| `ff_rankings_draft` | current |
| `ff_rankings_week` | current |

```bash
nfl-mcp ingest                 # load the full nflverse family (default)
nfl-mcp ingest --list          # see all dataset names
nfl-mcp ingest --dataset pbp   # load just one dataset
```

## MCP Tools

| Tool | Description |
|------|-------------|
| `nfl_schema` | Database schema reference — compact summary by default, pass `category` for detail |
| `nfl_status` | Database health: total plays, loaded seasons, available tables |
| `nfl_query` | Raw SQL SELECT for custom queries (500 row cap, 10s timeout) |
| `nfl_search_plays` | Find plays by player, team, season, season type, situation, touchdowns, etc. |
| `nfl_team_stats` | Pre-aggregated team offense, defense, and situational stats |
| `nfl_player_stats` | Player stats by season and season type — passing, rushing, or receiving |
| `nfl_compare` | Side-by-side comparison of two teams or two players |
| `nfl_schedule` | Game schedule and results — scores, spread, weather, coaches |
| `nfl_roster` | Team roster by season and position |
| `nfl_injuries` | Player injury report status by team, week, and designation |
| `nfl_snap_counts` | Offensive, defensive, and special teams snap counts per player |
| `nfl_fantasy_opportunity` | Target share, air yards share, carry share, and expected fantasy points per player per week (2013–present) |
| `nfl_fantasy_rankings` | Expert consensus rankings (ECR) — draft/dynasty/best-ball (`scope=draft`) or current-week start/sit (`scope=week`) |
| `nfl_ftn_charting` | Aggregated FTN charting tendencies (2022–present) over scrimmage plays — play-action, RPO, screen, no-huddle, motion, trick-play rates, plus box/pass-rush/blitz counts |
| `nfl_td_luck` | Actual vs expected touchdowns per player-season — surfaces TD-regression candidates (most "unlucky" first) |
| `nfl_role_trend` | Rolling 3-week snap / target / carry / air-yards share with current-week delta — usage trending up or down |
| `nfl_separation_opportunity` | Next Gen Stats separation/YAC joined to fantasy opportunity (2016+) — flags receivers getting open but under-producing |
| `nfl_drop_rate` | Catchable-target drop rate per receiver-season from FTN charting (2022+), plus contested targets and created receptions |
| `nfl_contract_value` | Fantasy points per $M of average per year (APY) — best value-for-money players |
| `nfl_injury_return` | Post-return snap-share recovery (% of pre-injury baseline) at +1..+8 weeks, by normalized injury type and position |
| `nfl_catalog` | List all loaded tables with row counts and last refresh time |

## Key columns in `plays`

- `epa` — expected points added (the best single-play quality metric)
- `wpa` — win probability added
- `posteam` / `defteam` — offensive/defensive team abbreviations
- `passer_player_name` / `rusher_player_name` / `receiver_player_name`
- `play_type` — `'pass'` | `'run'` | `'field_goal'` | `'punt'` | `'kickoff'` | ...
- `desc` — raw play description (use `ILIKE` for text search)

## Local Development

```bash
git clone https://github.com/ebhattad/nfl-mcp
cd nfl-mcp
pip install -e ".[dev]"

nfl-mcp ingest --dataset all --start 2024 --end 2024
nfl-mcp serve   # server available at http://localhost:8000/mcp
pytest
pytest -m unit     # unit tests
pytest -m integration  # integration tests (requires loaded DB)
```

## Troubleshooting

- `nfl-mcp doctor` is the fastest way to verify config, database, and client setup.
- If tools return database errors, run `nfl-mcp ingest` to ensure data is loaded.
- You can override the DB location with `NFL_MCP_DB_PATH=/path/to/nflread.duckdb`.
- Re-running `nfl-mcp ingest` is safe — it skips anything already loaded.

## License

MIT
