MLB Stats MCP
# MLB Stats MCP
An [MCP](https://modelcontextprotocol.io) server that gives Claude (or any MCP client) live and
historical Major League Baseball data: players, season and career stats, schedules, live box
scores, standings and league leaders.
It uses the public MLB Stats API (`statsapi.mlb.com`), so there are no API keys or sign-up.
<!-- mcp-name: io.github.prnv-13/mlb-stats-mcp -->
Ask things like:
- "How did Aaron Judge's 2026 compare to his career averages?"
- "Who's pitching for the Dodgers tonight, and what are their ERAs?"
- "Show me the AL standings and who's leading the wild card."
- "Top 10 home run hitters in the NL this season."
## Tools
| Tool | What it does |
|---|---|
| `search_players` | Name → `player_id`, position, current team |
| `get_player_info` | Bio: age, height, bats/throws, debut, birthplace |
| `get_player_stats` | Hitting / pitching / fielding, by season, career or year-by-year |
| `get_player_game_log` | Game-by-game stats, most recent first, for recent form and streaks |
| `get_league_leaders` | Leaders for any stat category, AL / NL / MLB |
| `get_standings` | Division standings with games back, streak, run differential |
| `list_teams` | All 30 teams with ids, league, division, ballpark |
| `get_team_roster` | Active, 40-man or full-season roster |
| `get_schedule` | Games for a date or range, with scores and probable pitchers |
| `get_game` | Line score by inning plus batting and pitching box score |
Team arguments accept `"Yankees"`, `"NYY"`, `"New York Yankees"` or `"147"`.
### Caching and retries
Responses are cached in memory, and each kind of data keeps its own lifetime, so repeated
questions don't hit MLB again. A cached call takes about 1 ms, compared with about 1.2 s for a
fresh one.
| Data | Cached for |
|---|---|
| Live games | 15 s |
| Today's schedule | 1 min |
| Standings, leaders, current-season stats | 5 min |
| Rosters, player bios | 1 h |
| Teams, finished games, past seasons | 24 h |
The cache keeps at most 1,000 entries and evicts the least recently used. Errors are never cached.
Timeouts, connection errors and HTTP 429 or 5xx responses are retried up to 3 times with
exponential backoff and jitter, and a `Retry-After` header is honored. Other 4xx errors fail right
away.
## Install
You need [uv](https://docs.astral.sh/uv/getting-started/installation/). It fetches Python for you.
### Claude Code
```bash
claude mcp add mlb-stats -- uvx mlb-stats-mcp
```
### Claude Desktop, Cursor, Windsurf, VS Code and others
Add this to the client's MCP config. For Claude Desktop, that's Settings → Developer → Edit Config:
```json
{
"mcpServers": {
"mlb-stats": {
"command": "uvx",
"args": ["mlb-stats-mcp"]
}
}
}
```
### Remote (no install)
If someone hosts the server (see below), clients can connect to the URL directly:
```bash
claude mcp add --transport http mlb-stats https://YOUR-HOST/mcp
```
In Claude.ai, go to Settings → Connectors → Add custom connector and paste the same URL.
## Development
```bash
git clone https://github.com/prnv-13/mlb-stats-mcp
cd mlb-stats-mcp
uv sync
uv run pytest # offline unit tests (MLB API is faked)
uv run scripts/smoke_test.py # calls every tool over stdio against the live API
uv run mlb-stats-mcp --transport http # serves http://127.0.0.1:8000/mcp
npx @modelcontextprotocol/inspector # GUI for poking at tools
claude mcp add mlb-dev -- uv run --directory "$PWD" mlb-stats-mcp # use your local copy in Claude Code
```
Layout:
```
src/mlb_stats_mcp/
config.py every constant: URLs, timeouts, cache TTLs, retry policy, limits
cli.py entry point: stdio (default) or --transport http
server.py build_server(): server identity, instructions, tool registration
mlb/ data layer, the only code that talks to MLB
client.py MLBClient: caching + retries around HTTP
cache.py TTLCache: generic TTL + LRU cache
endpoints.py API paths
errors.py MLBApiError
tools/ the MCP tools, one module per area
teams.py players.py leaders.py games.py standings.py
common.py shared types, annotations, date and season helpers
tests/ offline pytest suite, mirrors src/ (mlb/, tools/)
scripts/smoke_test.py end-to-end test, works on stdio or an HTTP URL
Dockerfile for hosting the HTTP version
```
Requests flow one way: `cli` → `server` → `tools/*` → `mlb.MLBClient` → statsapi.mlb.com.
To add a tool, write an async function in the right `tools/` module (type hints and the
docstring become its schema), then add it to `ALL_TOOLS` in `tools/__init__.py`.
## Publishing guide
There are two ways people can use your MCP. You can do both.
### 1. Publish a package so anyone can run `uvx mlb-stats-mcp`
1. Create accounts on [pypi.org](https://pypi.org) and [test.pypi.org](https://test.pypi.org), then
create an API token on each (Account settings → API tokens).
2. Build:
```bash
uv build # creates dist/*.whl and dist/*.tar.gz
```
3. Do a test run on TestPyPI:
```bash
uv publish --publish-url https://test.pypi.org/legacy/ --token pypi-XXXX
uvx --index-url https://test.pypi.org/simple/ --index-strategy unsafe-best-match mlb-stats-mcp --help
```
4. Publish for real:
```bash
uv publish --token pypi-XXXX
```
5. For each new release, bump `version` in `pyproject.toml`, run `uv build`, then `uv publish`.
To skip handling tokens, set up [Trusted Publishing](https://docs.pypi.org/trusted-publishers/)
on PyPI and publish from a GitHub Action instead.
### 2. Host it so people only need a URL
The server runs as a stateless Streamable HTTP server, so any container host works. Examples are
Render, Railway, Fly.io and Google Cloud Run (many have free tiers). The Dockerfile reads `PORT`
from the platform.
```bash
docker build -t mlb-stats-mcp .
docker run -p 8000:8000 mlb-stats-mcp
# → http://localhost:8000/mcp
```
On Render or Railway, connect the GitHub repo and pick "Docker". Users then add
`https://your-app.onrender.com/mcp`.
The server needs no auth because it only reads public data. If you open it to the internet,
consider putting rate limiting in front of it, and keep in mind that heavy traffic hits MLB's
API from your server's IP address.
### 3. Get listed so people can find it
- **Official MCP Registry** ([registry.modelcontextprotocol.io](https://registry.modelcontextprotocol.io)):
```bash
brew install mcp-publisher
mcp-publisher init # generates server.json from this repo
mcp-publisher login github
mcp-publisher publish
```
The registry checks that you own the PyPI package by looking for the `mcp-name:` comment near
the top of this README.
- **Community lists:** open a PR to
[awesome-mcp-servers](https://github.com/punkpeye/awesome-mcp-servers), and submit to
directories such as Smithery, Glama and mcp.so.
## Data and terms
The data comes from MLB Advanced Media's Stats API. It's © MLB and is offered for individual,
non-commercial, non-bulk use. This project isn't affiliated with MLB. Don't use it to build a paid
product or to bulk-scrape the API.
## License
MIT
TDQS
Scored across 10 tools
Each tool maps to a distinct resource and action: team listing vs. roster, player lookup vs. bio vs. stats vs. game log, league leaders, schedule, single game, and standings. The descriptions explicitly explain boundaries (e.g., search_players yields the player_id consumed by the player tools; get_schedule vs. get_game is list vs. single game). No two tools appear to do the same thing.
All tools follow a snake_case verb_noun pattern (get_player_stats, get_team_roster, get_league_leaders), with 'list_teams' appropriately using list for the only enumeration endpoint and 'search_players' for the lookup. No camelCase or vague-verb deviations.
Ten tools is right-sized for an MLB stats server: one per core entity/operation (teams, roster, player lookup, bio, stats, game log, leaders, schedule, game, standings) with no redundant entries.
The surface covers the core fan/analyst workflow end to end: discover teams and players, then pull bios, season/career stats, game logs, leaders, schedules, box scores, and standings. Gaps are minor: no transactions, injuries, or team-level aggregate stats, and schedule lookups are discouraged for long ranges.