Enterprise-grade Model Context Protocol (MCP) server for live and historical sports analytics, consensus betting odds, and predictions via ESPN.
Equips AI agents with real-time sports intelligence, live win probabilities, in-depth boxscore statistics, roster hierarchies, and matchup analytics.
Important
Community Project Disclaimer
mcp-server-espn is an independent open-source community project. It is not affiliated with, sponsored by, endorsed by, or supported by ESPN Inc. or The Walt Disney Company. "ESPN" is a trademark of ESPN Inc. All data provided via ESPN's public REST endpoints is intended for educational, research, and personal non-commercial use.
Autonomous sports analysis requires high-velocity, structured, and resilient data feeds:
- Live Game State & Win Probability: Real-time game events (turnovers, scoring plays, pitching changes) shift momentum and expected outcomes dynamically.
- Key Player Injuries & Depth Chart Swaps: An in-game injury or substitution fundamentally alters team efficiency and tactical matchups.
- Consensus Odds & Predictive Models: Aggregating consensus sportsbook lines (DraftKings, Caesars, ESPN BET) alongside predictive metrics (FPI, BPI) powers deep statistical game evaluations.
mcp-server-espn provides a unified, hardened Model Context Protocol interface directly to ESPN's public sports data endpoints.
graph TD
Client["AI Agent / MCP Client<br>(Antigravity, Claude, Codex, Cortex)"]
Gateway["Root FastMCP Gateway (espn-mcp)<br>(stdio / Streamable HTTP)"]
ParentMW["Parent Middleware Pipeline<br>(ParentAuditMiddleware & ReadOnlyGateMiddleware)"]
GamesSub["Sub-Server: espn-games<br>(games_* | GamesDomainGuard)"]
TeamsSub["Sub-Server: espn-teams<br>(teams_* | TeamsDomainGuard)"]
NewsSub["Sub-Server: espn-news<br>(news_* | Resources)"]
ClientHandler["Hardened ESPN AsyncClient<br>(Connection Pool & 429 Jitter Backoff)"]
ESPN["ESPN Public REST CDN<br>(https://site.web.api.espn.com)"]
Client <-->|"JSON-RPC (tools/list, tools/call)"| Gateway
Gateway --> ParentMW
ParentMW --> GamesSub
ParentMW --> TeamsSub
ParentMW --> NewsSub
GamesSub & TeamsSub & NewsSub <-->|"API Methods"| ClientHandler
ClientHandler <-->|"HTTPS REST Mirror"| ESPN
mcp-server-espn implements canonical FastMCP 4 Server Composition via root.mount(..., namespace="..."):
- Domain Sub-Servers: Partitioned into
espn-games(games_*),espn-teams(teams_*), andespn-news(news_*). - Hierarchical Middleware:
- Parent:
ParentAuditMiddleware(timing logs, audit trails, and secret scrubbing) andReadOnlyGateMiddleware(fail-closed read-only enforcement). - Child:
GamesDomainGuardMiddleware(query limit validation <= 100) andTeamsDomainGuardMiddleware(team and athlete identifier validation).
- Parent:
- Focused Profiles: Run lightweight surfaces via
--profile full|games|teams|news|readonly(ESPN_MCP_PROFILE):full(default): All 33 domain tools and resources mounted.games: Scores, summaries, schedules, standings, rankings, transactions, league leaders, draft, live play-by-play, situations, odds, probabilities, predictor, calendar, futures, power index (20 tools).teams: Rosters, depth charts, player stats, athlete profiles, bio, stats, gamelog, splits, search, list teams, team detail, team statistics (12 tools).news: League news and reference resources (1 tool).readonly: Read-only enforcement across all routes.
- Opt-In Tool Search: Preserves standard flat
tools/listby default for seamless client compatibility, while enabling search transforms via--enable-tool-search(ESPN_MCP_ENABLE_TOOL_SEARCH): BM25 ranking for natural-language queries by default (search_toolstakes aquery), or regex patterns with--tool-search-backend regex(ESPN_MCP_TOOL_SEARCH_BACKEND=regex;search_toolstakes apattern).
- Poll Active Games: Agent calls
games_get_scoreboard(sport="football", league="nfl")to identify close games in the 2nd half. - Fetch In-Game Situation & Win Probability: Call
games_get_game_situation(sport="football", league="nfl", event_id="401872947")andgames_get_win_probabilities(sport="football", league="nfl", event_id="401872947")to inspect down/distance, red zone state, and live win expectancy curve. - Inspect Play-by-Play: Call
games_get_play_by_play(sport="football", league="nfl", event_id="401872947")for drive-by-drive sequencing and scoring event logs.
- Bio & Career Context: Call
teams_get_athlete_bio(sport="football", league="nfl", athlete_id="12483")to retrieve draft capital, college pedigree, and physical metrics. - Recent Gamelog & Splits: Pull
teams_get_athlete_gamelogandteams_get_athlete_splitsto analyze performance trends against specific defensive schemes and venue conditions. - League-Wide Leaderboard Standing: Call
games_get_leaders_by_athlete(sport="football", league="nfl", category="passing", sort="yards")to evaluate percentile rankings.
The server supports canonical sport/league slug pairs and auto-normalizes popular shortcuts:
| Sport Slug | League Slug | Recognized Shortcuts / Aliases | Common Display Name |
|---|---|---|---|
football |
nfl |
nfl |
National Football League |
football |
college-football |
cfb, ncaa-football, fbs |
NCAA College Football |
basketball |
nba |
nba |
National Basketball Association |
basketball |
mens-college-basketball |
cbb, ncaa-basketball |
NCAA Men's College Basketball |
basketball |
womens-college-basketball |
wbb, ncaa-womens-basketball |
NCAA Women's Basketball |
basketball |
wnba |
wnba |
Women's National Basketball Association |
baseball |
mlb |
mlb |
Major League Baseball |
hockey |
nhl |
nhl |
National Hockey League |
soccer |
eng.1 |
epl, premier-league |
English Premier League |
soccer |
usa.1 |
mls |
Major League Soccer |
soccer |
uefa.champions |
ucl, champions-league |
UEFA Champions League |
soccer |
esp.1 |
la-liga |
Spanish La Liga |
soccer |
ita.1 |
serie-a |
Italian Serie A |
soccer |
ger.1 |
bundesliga |
German Bundesliga |
soccer |
fra.1 |
ligue-1 |
French Ligue 1 |
All tools implement explicit MCP 2.0 annotations (readOnlyHint=True, idempotentHint=True):
| Domain | Tool | Parameters | Description |
|---|---|---|---|
| Games | games_get_scoreboard |
sport, league, date, week, season_type, group, limit |
Final scores and results for any date (date=YYYYMMDD) or inclusive date range (date=YYYYMMDD-YYYYMMDD; ranges of up to 31 days are fetched one day at a time, because ESPN rejects the range form on team-sport scoreboards, so limit applies to each day (up to 31 ร limit events) and one failed day fails the whole call; golf ranges are sent to ESPN as is), plus live scores, state (pre/in/post), period/clock, TV broadcasts, starting probables. Returns event IDs for other game tools. |
| Games | games_get_game_summary |
sport, league, event_id |
Consensus betting lines, matchup predictor win %, ATS, scoring plays, drives, leaders, momentum. |
| Games | games_get_team_schedule |
sport, league, team_id, season, season_type |
Season schedule with historical game results and scores: the regular season by default, postseason games with season_type=3. |
| Games | games_get_standings |
sport, league, season |
Division, conference, and overall league standings, win-loss records, games back, and win percentages. season is the year the season ends (2016 = the 2015-16 NBA season), or the year it starts for soccer (2026 = the 2026-27 Premier League season); the response echoes requested_season, season, and season_display. |
| Games | games_get_rankings |
sport, league |
Top 25 national polls and rankings (AP Top 25, Coaches Poll, College Football Playoff). |
| Games | games_get_transactions |
sport, league, limit |
League-wide transactions, roster trades, waivers, signings, and releases. |
| Games | games_get_leaders_by_athlete |
sport, league, limit, category, sort |
Statistical leaderboards across players in a league. |
| Games | games_get_leaders_by_team |
sport, league, limit, category, sort |
Team statistical rankings and leaderboards. |
| Games | games_get_league_groups |
sport, league |
League conference, division, and structural group hierarchies. |
| Games | games_get_league_events |
sport, league, dates |
The league's current scheduled events. ESPN's events route ignores dates, so date filtering is not supported: a dates value returns isError: true with no request, pointing to games_get_scoreboard with the same value as date. |
| Games | games_get_league_draft |
sport, league, season |
League draft rounds, team selections, and pick results. |
| Games | games_get_scoreboard_header |
sport, league |
Live ticker scoreboard header data across games for a sport and league. |
| Games | games_get_event_odds |
sport, league, event_id, competition_id |
Sportsbook consensus and provider odds (spreads, totals, moneylines). |
| Games | games_get_play_by_play |
sport, league, event_id, limit, page |
Play-by-play sequence, clock, scoring, and drive events. |
| Games | games_get_game_situation |
sport, league, event_id |
Real-time in-game situation (down, distance, yardline, possession, red zone). |
| Games | games_get_win_probabilities |
sport, league, event_id |
Live and historical win probability curves across game progression. |
| Games | games_get_game_predictor |
sport, league, event_id |
Pre-game and in-game matchup predictor and projection metrics. |
| Games | games_get_calendar |
sport, league, dates |
League schedule calendar and active event dates across a season. |
| Games | games_get_futures |
sport, league, season |
Season futures betting markets (championship odds, win totals). |
| Games | games_get_power_index |
sport, league, season |
Team power index (FPI / BPI) ratings and efficiency metrics. |
| Teams | teams_search |
query, type, limit |
Global search for athletes and teams by name/keyword (type="player" or "team"). |
| Teams | teams_list_teams |
sport, league |
Directory of all franchises/teams in a specified league with IDs, names, and logos. |
| Teams | teams_get_team |
sport, league, team_id |
Team detail overview, venue, record, standings summary, and upcoming scheduled event. |
| Teams | teams_get_team_statistics |
sport, league, team_id |
Comprehensive team and opponent statistical category splits (passing, rushing, etc.). |
| Teams | teams_get_team_roster |
sport, league, team_id |
Full active roster grouped by position, coach info, jersey numbers, and injury status. |
| Teams | teams_get_team_depth_chart |
sport, league, team_id |
Positional starter/backup hierarchy (QB1, QB2, etc.) to model injury substitution impacts. |
| Teams | teams_get_player_stats |
sport, league, event_id |
Boxscore statistics for individual athletes across game categories. |
| Teams | teams_get_athlete_overview |
sport, league, athlete_id |
Athlete biographical info, season/career stats, game logs, next game, and rotowire notes. |
| Teams | teams_get_athlete_bio |
sport, league, athlete_id |
Detailed athlete background, draft history, birth details, college pedigree. |
| Teams | teams_get_athlete_stats |
sport, league, athlete_id, season |
Full seasonal and career category statistics for an athlete. |
| Teams | teams_get_athlete_gamelog |
sport, league, athlete_id, season |
Game-by-game performance log for an athlete across a season. |
| Teams | teams_get_athlete_splits |
sport, league, athlete_id, season |
Situational statistical splits (home/away, turf/grass, monthly, vs opponents). |
| News | news_get_news |
sport, league, limit |
Recent news headlines, injury designations, and breaking roster analysis. |
Console scripts in [project.scripts] both call espn_mcp.server:main: espn-mcp (used below) and mcp-server-espn. Install examples stay unpinned. To freeze a release, pin the version from Releases.
uvx --from mcp-server-espn espn-mcpAfter an upgrade, reload the MCP host so the live process start time is after the new binary mtime (stale process โ new package).
# Using pip
pip install mcp-server-espn
# Using uv
uv add mcp-server-espndocker run --rm -i ghcr.io/christianclaudio/mcp-server-espn:latest| Variable | CLI Flag | Default | Description |
|---|---|---|---|
ESPN_BASE_URL |
โ | https://site.web.api.espn.com |
Target ESPN REST CDN base URL (bypasses Akamai TLS filter) |
ESPN_TIMEOUT_SECONDS |
โ | 30.0 |
HTTP request timeout in seconds |
ESPN_MCP_AUTH_TOKEN |
โ | unset | Shared bearer token required on HTTP transports (stdio ignores it) |
ESPN_MCP_ALLOW_UNAUTHENTICATED_BIND |
โ | unset | 1 accepts a tokenless HTTP bind to a non-localhost host |
ESPN_MAX_RETRIES |
โ | 3 |
Maximum retry attempts on 429 / 5xx with jittered exponential backoff, waiting longer when Retry-After asks (capped at ESPN_TIMEOUT_SECONDS) |
ESPN_MCP_READONLY |
โ | 0 |
Restrict server strictly to read-only inspection tools |
ESPN_MCP_PROFILE |
--profile |
full |
Domain sub-server profile: full, games, teams, news, readonly |
ESPN_MCP_ENABLE_TOOL_SEARCH |
--enable-tool-search |
0 |
Replace flat tool catalog with dynamic search transform (search_tools + call_tool) |
ESPN_MCP_TOOL_SEARCH_BACKEND |
--tool-search-backend |
bm25 |
Tool Search backend: bm25 (BM25SearchTransform, natural-language ranking; search_tools takes query) or regex (RegexSearchTransform, regex patterns; search_tools takes pattern) |
๐งก Claude Desktop
Add to ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):
{
"mcpServers": {
"espn": {
"command": "uvx",
"args": ["--from", "mcp-server-espn", "espn-mcp"],
"env": {
"ESPN_TIMEOUT_SECONDS": "20.0"
}
}
}
}For Claude Code CLI:
claude mcp add espn -- uvx --from mcp-server-espn espn-mcpโ Google Antigravity & Gemini CLI
Add to .agents/mcp_config.json or ~/.gemini/config/mcp_config.json:
{
"mcpServers": {
"espn": {
"command": "uvx",
"args": ["--from", "mcp-server-espn", "espn-mcp"],
"env": {
"ESPN_TIMEOUT_SECONDS": "20.0"
},
"lazy": true
}
}
}โ๏ธ Snowflake Cortex
Add to ~/.snowflake/cortex/mcp.json:
{
"mcpServers": {
"espn": {
"command": "uvx",
"args": ["--from", "mcp-server-espn", "espn-mcp"],
"env": {
"ESPN_TIMEOUT_SECONDS": "20.0"
},
"lazy": true
}
}
}โก Cursor IDE
Add to .cursor/mcp.json:
{
"mcpServers": {
"espn": {
"command": "uvx",
"args": ["--from", "mcp-server-espn", "espn-mcp"]
}
}
}๐ป VS Code (Cline / Roo Code / Copilot Agent Mode)
Add to cline_mcp_settings.json or .vscode/settings.json:
{
"mcpServers": {
"espn": {
"command": "uvx",
"args": ["--from", "mcp-server-espn", "espn-mcp"]
}
}
}๐ Local HTTP / Network Transport Mode
Launch the FastMCP server over modern Streamable HTTP:
uvx --from mcp-server-espn espn-mcp --transport streamable-http --host 127.0.0.1 --port 8000Connect Streamable HTTP clients to http://127.0.0.1:8000/mcp (FastMCP's default Streamable HTTP path).
In the default (stateful) HTTP mode, a session idle for 30 minutes expires: its next request gets HTTP 404 and the client must start a new session. Change this with FastMCP's session_idle_timeout (on http_app()) or FASTMCP_HTTP_SESSION_IDLE_TIMEOUT (seconds, or none to never expire); see the FastMCP 4.1.0 release and #5229.
HTTP authentication. Set ESPN_MCP_AUTH_TOKEN to require Authorization: Bearer <token> on every HTTP request; a missing or wrong token gets 401. The token is stripped, and a blank value counts as unset. It is attached when the server is built, so espn-mcp, fastmcp run and an ASGI host mounting mcp.http_app() all enforce it. stdio never uses it.
With no token, espn-mcp refuses an HTTP bind to any host other than 127.0.0.1, ::1 or localhost and exits with code 2. Set the token, bind to localhost, or set ESPN_MCP_ALLOW_UNAUTHENTICATED_BIND=1 to accept an unauthenticated public bind. Other entry points get the token but not the localhost check: fastmcp run and http_app() do not go through espn-mcp's main(), so a bind to 0.0.0.0 with no token there is not refused and serves without authentication. The host or its process manager owns the bind address, so set ESPN_MCP_AUTH_TOKEN there.
To serve the image over HTTP, pass the token from your shell or an env file (never a fixed value) and name the public host clients use:
PUBLIC_HOST=mcp.example.com # the host name clients use
export ESPN_MCP_AUTH_TOKEN="$(openssl rand -hex 32)" # or keep it in an env file
docker run --rm -p 8000:8000 -e ESPN_MCP_AUTH_TOKEN \
ghcr.io/christianclaudio/mcp-server-espn:latest \
--transport streamable-http --host 0.0.0.0 --allowed-host "$PUBLIC_HOST"
# with an env file instead: docker run --rm -p 8000:8000 --env-file espn.env ...When developing, hardening, or extending MCP servers, consult the official framework and protocol references:
- FastMCP 4 Framework Reference:
https://gofastmcp.com/llms.txtโ Server composition (mount), hierarchical middleware, transforms (ToolTransform,ToolSearch), lifespans, and in-memory test clients. - Model Context Protocol Specification:
https://modelcontextprotocol.io/llms.txtโ Official Spec (2026-07-28), wire-level JSON-RPC schemas, annotations, and transport framing.
Connect your AI coding agent directly to live documentation servers:
- FastMCP Documentation Server:
https://gofastmcp.com/mcp(Tools:search_fast_mcp,query_docs_filesystem_fast_mcp,submit_feedback) - Anthropic MCP Documentation Server:
https://modelcontextprotocol.io/mcp(Tools:search_model_context_protocol,query_docs_filesystem_model_context_protocol,submit_feedback)
{
"mcpServers": {
"fastmcp-docs": { "type": "sse", "url": "https://gofastmcp.com/mcp" },
"mcp-official-docs": { "type": "sse", "url": "https://modelcontextprotocol.io/mcp" }
}
}# Run unit test suite (100% statement coverage enforced)
pytest
# Static type safety & formatting
mypy --strict src/
ruff check --fix .
ruff format .
# Tool contract, drift & protocol conformance audits
python scripts/check_tool_contract.py
python scripts/check_openapi_drift.py
./scripts/check_conformance.shDistributed under the Apache-2.0 License.