
Pulls live scores, schedules, standings, and player/team data from ESPN, MLB StatsAPI, and TheSportsDB without requiring API keys. Seven tools handle the full workflow: fuzzy-match team or player names, fetch today's games, pull upcoming fixtures, check league tables, and retrieve full roster or bio details. Routes each sport to its best source internally (MLB goes to StatsAPI, everything else to ESPN), then normalizes the output so you get consistent game, team, and player objects regardless of upstream API. Returns empty arrays with reason strings when there's no data instead of throwing errors, which keeps agents from breaking on off-season queries. Built on the author's mcp-ts-core framework with support for both stdio and streamable HTTP transports.
Sponsors
THESPORTSDB_API_KEYdefault: 3TheSportsDB API key. Defaults to '3' (free public test key). Replace with a paid key for higher rate limits.
MCP_LOG_LEVELdefault: infoSets the minimum log level for output (e.g., 'debug', 'info', 'warn').
MCP_HTTP_HOSTdefault: 127.0.0.1The hostname for the HTTP server.
MCP_HTTP_PORTdefault: 3010The port to run the HTTP server on.
MCP_HTTP_ENDPOINT_PATHdefault: /mcpThe endpoint path for the MCP server.
MCP_AUTH_MODEdefault: noneAuthentication mode to use: 'none', 'jwt', or 'oauth'.
Get live scores, schedules, standings, team and player data for NFL, NBA, MLB, NHL, soccer, and more via MCP. STDIO or Streamable HTTP.
Live and historical sports data from ESPN, MLB StatsAPI, and TheSportsDB. Check scores, schedules, and standings, and look up teams and players across the NFL, NBA, MLB, NHL, major soccer leagues, and college football and basketball.
| Tool | Description |
|---|---|
sports_find_team | Resolve a team name or partial name to canonical records and source IDs across providers. |
sports_find_player | Resolve a player name to canonical TheSportsDB records with ID, team, position, and bio fields. |
sports_get_scores | Live and final scores for a league on a given date, optionally filtered by team. |
sports_get_game | Game metadata, period scores, team totals, provider top performers, and paged scoring plays. |
sports_get_schedule | Upcoming and past fixtures for a team or league over a date range. |
sports_get_standings | Current standings or league table for a league and season. |
sports_get_team | Team detail combining metadata, roster, recent results, and upcoming fixtures. |
sports_get_player | Player details from TheSportsDB — biography, team, position, and physical stats. |
The sports-guide covers complete fixture ranges, game recaps, standings comparisons, and player identity checks. It ships with plugin installs, npm, Docker, and the desktop bundle, and is available to MCP clients as a skill resource.
sports_find_team toolquery (max 200 characters) with an optional league filterespnId/mlbId/tsdbId cross-references merged across providers; totalFound counts returned recordsunavailableSources; no results returns no_match, or sources_unavailable if a source failed. The free TheSportsDB key can return incomplete resultssports_find_player toolquery (max 200 characters); optional sport is advisory and does not filterno_match when none is found123 limits searches to one recordsports_get_scores toolleague required; date (YYYY-MM-DD) defaults to today in US Eastern time; optional team_name filters gamesreason, emptyReason (no_games or no_team_matches), and noticelimit defaults to 100 (max 200) and offset to 0; responses include availableGames, totalReturned, effectiveLimit, offset, truncated, and nextOffsetsports_get_schedule toolleague required; optional team_name, date_from/date_to, limit (default 100, max 200), and offset (default 0). A single date bound requests that day; reversed dates failteam_name must identify one team: ambiguous_team lists candidates, team_not_found means no matchrequestedDateFrom/requestedDateTo, servedDateFrom/servedDateTo, availableGames, effectiveLimit, offset, and truncated; follow nextOffset, then nextDateFrom as date_fromsports_get_game toolleague and source-prefixed numeric game_id from scores, schedules, or team detail; mlb: IDs require league: "mlb"periodScores, teamStats, leaders, and scoringPlays; missing values are null. Scheduled games return metadata only; game_not_found for a missing or wrong-league game. Athlete IDs belong to ESPN or MLB, not TheSportsDBlimit defaults to 20 (max 50) and offset to 0; responses include totalCount, returnedCount, servedFrom/servedTo, effectiveLimit, and nextOffsetsports_get_standings toolleague required; optional season (4-digit year), current season if omittedseason_not_found when the season has no datalimit defaults to 100 (max 200) and offset to 0; responses include availableStandings, totalReturned, effectiveLimit, offset, truncated, and nextOffset. If the MLB team lookup fails, unavailableSources lists standings_team_metadatasports_get_team toolleague and team_name required; exact names or abbreviations win, otherwise a partial name must identify one team (ambiguous_team lists candidates, team_not_found means no match)sports_get_player toolplayer_id accepts a tsdb:-prefixed ID (from sports_find_player) or a raw numeric TheSportsDB IDplayer_not_found when the ID doesn't resolveespnId is filled when TheSportsDB supplies one, otherwise nullBuilt on @cyanheads/mcp-ts-core: stdio and Streamable HTTP transports, pluggable auth (none / jwt / oauth), swappable storage (in-memory, filesystem, Supabase, Cloudflare KV/R2/D1), structured logging with optional OpenTelemetry tracing.
Sports-specific:
123)NormalizedGame, NormalizedTeam, NormalizedPlayer, NormalizedStandingsports_find_teamgames: [] with a reason (scoreboards) instead of an errorAgent-friendly output:
source: 'espn' | 'mlbstats' | 'thesportsdb'no_match, sources_unavailable, team_not_found, ambiguous_team, player_not_found, season_not_found, game_not_found, incompatible_game_source), each with a recovery hintAdd it to Claude Code:
claude mcp add sports-mcp-server -- npx -y @cyanheads/sports-mcp-server
For other clients, add this to the MCP config file:
{
"mcpServers": {
"sports-mcp-server": {
"command": "npx",
"args": ["-y", "@cyanheads/sports-mcp-server"]
}
}
}
No API keys are required. THESPORTSDB_API_KEY optionally enables a premium key for broader player and team searches; the default free key returns at most one record. For Docker or a source build, see Running the server.
| Variable | Description | Default |
|---|---|---|
THESPORTSDB_API_KEY | TheSportsDB API key. The free key limits searches to one record. | 123 |
MCP_TRANSPORT_TYPE | Transport: stdio or http. | stdio |
MCP_HTTP_PORT | Port for HTTP server. | 3010 |
MCP_SESSION_MODE | HTTP session mode: stateful, stateless, or auto. | stateless |
MCP_AUTH_MODE | Auth mode: none, jwt, or oauth. | none |
MCP_LOG_LEVEL | Log level (RFC 5424). | info |
LOGS_DIR | Directory for log files (Node.js only). | <project-root>/logs |
LOG_TOOL_FAILURE_PAYLOADS | Log failed tool arguments and results, redacted by key name and capped by LOG_TOOL_FAILURE_PAYLOAD_MAX_BYTES (default 16384). Free-form values are not redacted. | false |
OTEL_ENABLED | Enable OpenTelemetry instrumentation. | false |
OTEL_EXPORTER_OTLP_ENDPOINT | Base OTLP/HTTP URL for traces and metrics. | Unset |
OTEL_EXPORTER_OTLP_LOGS_ENDPOINT | OTLP log endpoint. | Unset |
See .env.example for the full list of optional overrides.
Requires Bun v1.4.0 or higher and Node.js v24+.
git clone https://github.com/cyanheads/sports-mcp-server.git
cd sports-mcp-server && bun install
cp .env.example .env
# All overrides are optional.
Serving commands execute Node, including when launched with bun run. Bun handles dependency resolution and build tooling; ESPN requests run under Node.
Build and run:
# One-time build
bun run rebuild
# Run the built server
bun run start:stdio
# or
bun run start:http
Run checks and tests:
bun run devcheck # Lint, format, typecheck, security
bun run test # Vitest test suite
bun run lint:mcp # Validate MCP definitions against spec
docker run --rm -p 3010:3010 ghcr.io/cyanheads/sports-mcp-server:latest
The image builds with Bun, runs the production server under Node, defaults to HTTP transport and stateless session mode, and logs to /var/log/sports-mcp-server. For stdio, use docker run -i --rm -e MCP_TRANSPORT_TYPE=stdio ghcr.io/cyanheads/sports-mcp-server:latest. To build locally, use docker build -t sports-mcp-server .; OpenTelemetry peer dependencies are installed by default — build with --build-arg OTEL_ENABLED=false to omit them.
| Directory | Purpose |
|---|---|
src/index.ts | createApp() entry point — registers tools and inits services. |
src/config | Server-specific environment variable parsing (THESPORTSDB_API_KEY). |
src/services/types.ts | Normalized cross-source types and league routing table. |
src/services/espn | ESPN site API service — scores, schedules, standings, teams. |
src/services/mlb | MLB StatsAPI service — scores, schedules, standings, rosters. |
src/services/thesportsdb | TheSportsDB service — player and team search/metadata. |
src/mcp-server/tools | Tool definitions (*.tool.ts). |
tests/ | Unit and integration tests mirroring src/. |
docs/ | Design doc and directory tree. |
See CLAUDE.md/AGENTS.md for development guidelines and architectural rules. The short version:
try/catch in tool logicctx.log for request-scoped logging, ctx.state for tenant-scoped storagesrc/mcp-server/tools/definitions/index.tsIssues are welcome. Run checks and tests before submitting:
bun run devcheck
bun run test
Apache-2.0 — see LICENSE for details.
@cyanheads/sports-mcp-server