NBA MCP Server
# NBA MCP Server
[](https://github.com/SergioCastro02/nba-mcp-server/actions/workflows/ci.yml)
[](pyproject.toml)
[](LICENSE)
A [Model Context Protocol](https://modelcontextprotocol.io) server that gives any
MCP-compatible LLM client (Claude Desktop, Cursor, VS Code, a custom LangGraph
agent) live access to NBA stats, standings, rosters, scores and box scores.
```
"Compare LeBron James and Kevin Durant's playoff scoring."
"Who led the league in assists in 2023-24?"
"What was the final score and top scorers of game 0042300405?"
```
The LLM answers these by calling tools on this server — no hard-coded data, no
scraping in the prompt.
---
## Why this project exists
Most "LLM + API" demos wire one API to one chatbot with glue code. MCP replaces the
glue with a protocol: write the server once, and every compatible client can use it.
This repo is a small, production-shaped example of that — caching, error handling,
a clean data/protocol split, tests, and two transports (stdio + HTTP).
## Tools
| Tool | What it does |
|------|--------------|
| `find_player(name)` | Resolve a player name → `player_id` |
| `find_team(name)` | Resolve a team name / city / abbreviation → `team_id` |
| `list_teams()` | All 30 teams with ids |
| `player_career_stats(player_id)` | Career + playoff averages + season-by-season |
| `league_standings(season)` | Standings by conference for a season |
| `team_roster(team_id, season)` | Roster with position, age, experience |
| `stat_leaders(season, stat, limit)` | Per-game leaders (points/rebounds/assists/…) |
| `scoreboard(game_date)` | Games and scores for a date (defaults to today) |
| `game_boxscore(game_id)` | Final score + top 5 scorers per side |
Every tool returns `{"ok": true, "data": ...}` or `{"ok": false, "error": "..."}` so
the model can recover from a bad name instead of hallucinating.
### Resources
| URI | Contents |
|-----|----------|
| `nba://teams` | The 30 teams with ids (JSON) |
| `nba://glossary` | What each stat field means (Markdown) |
### Prompts
| Prompt | Arguments |
|--------|-----------|
| `scouting_report` | `player_name`, `focus` (overall/offense/defense/playoffs) |
| `compare_players` | `player_a`, `player_b` |
Both walk the model through calling the tools and grounding every claim in the
returned numbers.
## Architecture
```
MCP client (Claude Desktop / Cursor / LangGraph agent)
│ JSON-RPC over stdio or streamable HTTP
▼
server.py ── tool schemas (docstrings + type hints), thin error wrapping
▼
nba_client.py ── normalizes nba_api's 80-column rows into small LLM-friendly dicts
▼
cache.py ── TTL disk cache (scores 5 min, season stats 6 h, rosters 30 d)
▼
nba_api ──► stats.nba.com
```
`nba_client.py` has no MCP dependency on purpose — the same layer will feed the RAG
pipeline and agents in the companion project.
## Install
```bash
git clone https://github.com/SergioCastro02/nba-mcp-server
cd nba-mcp-server
python -m venv .venv && . .venv/Scripts/activate # or source .venv/bin/activate
pip install -e ".[dev]"
```
## Run
```bash
nba-mcp-server # stdio (for Claude Desktop / Cursor)
nba-mcp-server --http # streamable HTTP on http://localhost:8000/mcp
nba-mcp-server --http --host 0.0.0.0 # bind all interfaces (containers)
```
`GET /healthz` returns `{"status": "ok"}` for load balancers and container probes.
### Claude Desktop
Add to `claude_desktop_config.json`:
```json
{
"mcpServers": {
"nba": {
"command": "nba-mcp-server"
}
}
}
```
(Use the absolute path to the `.venv` binary if it isn't on your PATH.)
### MCP Inspector
```bash
npx @modelcontextprotocol/inspector nba-mcp-server
```
### End-to-end demo
Launches the server as a subprocess and drives it over stdio, exactly like a real
client would — resolves names to ids, compares two players' playoff stats, pulls
season leaders and a box score:
```bash
python examples/mcp_client_demo.py
```
## Deploy to AWS
Terraform stack for ECS Fargate + ALB + CloudWatch in [`infra/`](infra/README.md).
## Development
```bash
ruff check .
pytest
```
## Roadmap
- [x] `resources` for static reference data (`nba://teams`, `nba://glossary`)
- [x] `prompts` (`scouting_report`, `compare_players`)
- [x] IaC to deploy the HTTP transport to AWS ECS Fargate — see [`infra/`](infra/)
- [ ] Wire continuous deployment (OIDC + push job) and stand up a public demo URL
- [ ] Publish to PyPI
This server is the tool layer for a larger project: a multi-agent NBA analysis
platform (LangGraph orchestration + RAG over news/recaps + AWS Bedrock).
## Data source & limits
Data comes from `stats.nba.com` via [`nba_api`](https://github.com/swar/nba_api).
It is unofficial and rate-limited; the disk cache absorbs most repeat calls.
Not affiliated with the NBA.
## License
MIT
TDQS
Scored across 9 tools
Each tool targets a distinct NBA entity or query type: player lookup, team lookup, team enumeration, player stats, standings, roster, stat leaders, scoreboard, and box score. Even the closest pair, find_team and list_teams, are clearly differentiated as search versus full list.
Tool names mix imperative verb-led forms like find_player, find_team, and list_teams with noun/resource forms like player_career_stats, league_standings, and game_boxscore. The names are readable and consistently snake_case, but the verb/noun pattern is not applied uniformly.
Nine tools is a well-scoped size for an NBA data server, covering the major stat and score queries without redundancy. Each tool earns its place in the set.
The tool set covers the core read-only NBA workflow: player and team lookup, player stats, rosters, standings, stat leaders, scoreboard, and box score summaries. Gaps such as full box score details, player game logs, or a season schedule are minor and can be worked around.