Skip to main content
Glama
eponerine

ESPN Fantasy Football MCP Server

by eponerine

ESPN Fantasy Football MCP Server

A Model Context Protocol server that puts an ESPN fantasy football league in front of an LLM. It is a thin, read-only client for espn-fantasy-football-api-node and exposes every route in that API's OpenAPI spec as an MCP tool, plus fantasy-football domain knowledge and ready-made prompts for the questions managers actually ask.

  • Runtime: Node.js 22 LTS+

  • SDK: @modelcontextprotocol/server v2 (stdio transport)

  • Schemas: Zod v4

  • No build step — plain ESM JavaScript

Architecture

MCP host (VS Code / Claude / Cursor)
        |  stdio (JSON-RPC)
        v
espn-fantasy-football-mcp-node   <-- this repo
        |  HTTP (fetch)
        v
espn-fantasy-football-api-node   <-- your Express API
        |
        v
    ESPN fantasy endpoints

This server holds no ESPN logic of its own. It adds schemas, descriptions, caching, credential hygiene and fantasy-football context on top of your HTTP API.

Related MCP server: sleeper-caffeine MCP

Setup

npm install
Copy-Item .env.example .env

Start your fantasy API first (it must be reachable at FF_API_BASE_URL):

cd ..\espn-fantasy-football-api-node
npm start

Then run the MCP server:

npm start

It waits on stdin — that is correct for stdio servers. To poke at it interactively:

npm run inspect

Configuration

Variable

Default

Purpose

FF_API_BASE_URL

http://localhost:3000

Base URL of the fantasy HTTP API. Must be http/https.

LEAGUE_ID

Default league. Tools may override it per call.

SEASON_YEAR

Default season year.

ESPN_S2

Private-league cookie. Prefer setting this on the API server instead.

SWID

Private-league cookie. Prefer setting this on the API server instead.

FF_API_TIMEOUT_MS

20000

Per-request timeout.

FF_CACHE_TTL_MS

60000

TTL for the in-memory response cache.

Environment variables are read from the process environment. Set them in your MCP client config (see .vscode/mcp.json) or export them in the shell — this server does not read .env itself, so use node --env-file=.env src/index.js if you want that.

Tools

Every route in the upstream OpenAPI spec is covered.

Tool

Route

What it is for

get_health

/health

Is the API up? Diagnose failures before blaming league config.

get_league

/league

League name, team count, current week. Call this first.

get_settings

/settings

Scoring format, lineup slots, playoff rules, waiver/FAAB rules.

get_teams

/teams

Team ids, names, records, PF/PA, divisions. Name → id lookup.

get_standings

/standings

Ranked records and points for.

get_power_rankings

/power-rankings

Quality estimate that ignores schedule luck.

get_draft

/draft

Every pick, bid amount and keeper status.

get_roster

/roster

One team's roster for one week, with slots and injury status.

get_scoreboard

/scoreboard

Head-to-head scores for a week.

get_matchups

/matchups

Schedule plus matchup type (regular / playoff / consolation).

get_box_scores

/box-scores

Per-player actual vs projected points. The analysis workhorse.

get_transactions

/transactions

Waiver claims, adds, drops, trades, FAAB bids.

get_activity

/activity

Chronological league activity feed.

get_free_agents

/free-agents

Waiver wire and free agents, filterable by position.

get_player_info

/player-info

Player card by name or ESPN player id.

get_league_profile

composite

Start here. Raw ESPN settings translated into plain English.

check_lineup

composite

Lineup legality and optimization audit against the league's real slots.

explain_fantasy_football

Fantasy primer: formats, scoring, slots, waivers, jargon.

how_to_answer

Which tools to combine for common question types.

leagueId and year are optional on every tool and fall back to LEAGUE_ID / SEASON_YEAR.

The interpreter tools

ESPN speaks in integers: scoring is statId → points, lineups are slotId → count. Neither is usable by a model without translation, and the failure mode is silent — a league with two FLEX spots and an IR slot looks identical to a standard league until you decode slot IDs 23 and 21.

get_league_profile does that decoding in one call:

  • Scoring — PPR value (standard / half / full / custom), passing-TD value, interception penalty, active yardage bonuses, and every scoring rule grouped by category. Any rule ESPN reports that cannot be labeled is listed explicitly rather than silently dropped.

  • Roster — the exact starting lineup with eligible positions per slot, FLEX count, superflex detection, bench and IR counts, and total roster size.

  • Rules — FAAB vs rolling waivers with budget and process day/hour, acquisition limits, trade deadline, veto rules, playoff team count and first playoff week, median scoring, keepers.

  • Strategic implications — what those specific rules mean for how the league should be played.

check_lineup cross-references a roster against those slots and player availability, returning severity-ranked issues:

Severity

Detects

error

Unfilled starting slots, starters on bye, OUT/DOUBTFUL starters, a player illegally occupying IR

warning

Questionable starters, bench players outscoring a starter they may legally replace

info

Injured bench players eligible for an open IR slot

Slot eligibility is checked against ESPN's own eligible_slots for each player, not against position labels, so unusual flex configurations are handled correctly.

Prompts

Slash-command style entry points for the questions people actually ask:

start-sit, waiver-wire-targets, trade-evaluation, matchup-preview, weekly-recap, power-rankings-writeup, playoff-outlook, roster-checkup, draft-review, league-briefing, explain-my-league, lineup-legality-check, ir-and-bench-optimization, scoring-quirks, format-adjusted-rankings.

Each one is preloaded with the answering rules — start from the league profile, never assume a standard league, never request box scores for a future week, know whether a projection is seasonal or weekly, separate skill from schedule luck, and do not invent NFL news.

Resources

URI

Contents

fantasy://knowledge/glossary

How fantasy football works, end to end.

fantasy://knowledge/playbook

Question → tool-sequence playbook.

fantasy://knowledge/espn-codes

Decoder for slot IDs, stat IDs, injury statuses, transaction types.

fantasy://league/rules-digest

The interpreted league profile.

fantasy://api/openapi.json

The live upstream OpenAPI document.

fantasy://league/current

Snapshot of the configured league.

Known data traps

These are encoded in the server instructions and the ESPN code reference, but are worth knowing:

  • A roster player's projected_points and total_points are season figures (scoring period 0). Use avg_points / projected_avg_points per game, or get_box_scores with includeLineup: true for true weekly projections.

  • active_status initializes to 'bye' and only resolves once real stats exist, so every player reads as on-bye before kickoff. Use on_bye_week and injury_status for availability.

  • on_bye_week is derived from the absence of a scheduled game, so missing schedule data makes an entire roster look like it is on bye. check_lineup detects this case and reports it rather than emitting a dozen bogus bye warnings.

  • percent_owned of -1 means "no data reported", not 0% ownership.

Security notes

  • ESPN cookies are never tool inputs. The upstream API accepts espnS2/swid as query parameters, but exposing them as tool arguments would put credentials into model context. They are read from the environment only, and are masked in every error message and log line.

  • Because the upstream API takes those cookies on the query string, the safest setup is to configure ESPN_S2/SWID on the API server and leave them unset here.

  • FF_API_BASE_URL is validated to http/https and has any embedded user:password stripped.

  • All tools are read-only and annotated as such; nothing in this server can modify a league.

  • Responses are cached in memory only, for FF_CACHE_TTL_MS, and never written to disk.

Development

npm test

Tests cover URL construction, credential redaction, configuration validation, league-profile interpretation (half-PPR vs superflex detection, multi-FLEX and IR slot counts, unmapped scoring IDs) and every lineup-audit rule.

Upstream API requirements

get_league_profile and check_lineup need settings.lineup_slots from the API, which keys lineup counts by ESPN slot ID. Against an older API build that does not expose it, both tools degrade with an explicit warning rather than reporting wrong slot counts.

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    A
    maintenance
    Connect ESPN & Yahoo fantasy leagues to AI assistants via MCP. Read-only tools for rosters, standings, matchups, free agents, and league info across football and baseball.
    19
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Provides read-only access to Sleeper fantasy football leagues, enabling team snapshots, available players, matchups, trade context, and league history through standardized MCP tools.
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables Claude to interact with Sleeper fantasy football leagues via MCP tools for roster, waiver, matchup, and transaction queries, plus a dashboard for daily reports, live scoring, and game-day alerts.
    72 npm
    MIT
  • F
    license
    Not graded
    quality
    C
    maintenance
    Provides read-only access to Yahoo Fantasy Football league data through MCP, letting ChatGPT retrieve rosters, standings, scoreboards, draft results, transactions, and player stats without making any roster changes.
    1
    -