fantasy-yolo
This server provides read-only queries about your ESPN fantasy football league, plus guarded write operations (preview then execute) for managing your lineup, waivers, and add/drops.
Read your roster: Get your starters, bench, open roster spots, projections, opponents, and injury designations for any week.
Check your lineup: Get a one-line alert for empty slots, byes, injured players, already-locked players, and players projected zero points.
See weekly matchups: View your opponent, both teams' projected scores, and a summary for a given week.
Get league details: Retrieve league rules, key dates, waiver system, and standings.
Check budgets: See FAAB or waiver budgets for all teams.
Search players: Find free agents and rank them by any criterion you name.
Look up individual players: Get a player's details and which team rosters them.
View other teams: Request any team's roster for trade evaluation.
Compare positional depth: See every team's positional counts to spot trade targets.
Browse transactions: List recent league transactions, filterable by type or team.
View pending claims: See waivers and trades awaiting processing.
Write operations (disabled by default, preview/execute pattern): Set your lineup, add/drop players, submit waiver claims, and cancel pending waivers—each requiring a preview-generated confirmation token before execution.
Safety guarantees: Writes are read-only until previewed, re-read the roster before executing, and only affect your own team.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@fantasy-yolowho am I playing this week?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
fantasy-yolo
A fantasy football agent server. An MCP server and a matching CLI that let you — or an agent you run — read and manage your own ESPN Fantasy Football team.
$ fy check-lineup
1 thing(s) to look at across 9 starters
projected_zero: Josh Jacobs (RB/WR/TE) is projected 0.0 points by ESPN
$ fy player "Saquon Barkley"
Saquon Barkley (RB, PHI) is rostered by The white BhatoyasAsk an agent "anything wrong with my lineup this week?" or "who has Saquon, and what are they thin at?" and get an answer from live league data.
The one thing to understand first
The human is the brain. This server has no optimizer, no projections model, and no opinion about which players are good. It answers questions accurately and executes instructions carefully. It will tell you a starter is projected zero points; it will never tell you to bench him.
That is a deliberate constraint, not a missing feature. See Why no optimizer.
Related MCP server: Sleeper MCP Server
Install
Needs Python 3.13 and uv.
git clone https://github.com/gagandaroach/fantasy-yolo
cd fantasy-yolo
uv sync
uv run fy --helpThen follow docs/setup.md — two cookies out of your browser and a small config file naming your league. Five minutes.
As an MCP server
{
"mcpServers": {
"fantasy-yolo": {
"command": "uv",
"args": ["run", "--directory", "/path/to/fantasy-yolo", "fantasy-yolo-mcp"]
}
}
}No credentials in that stanza — deliberately. They live in a chmod 0600 file
the config points at.
Tools
Every tool is available identically over MCP and on the CLI, generated from one definition, so the two cannot drift apart.
Reading — always available
Tool | CLI | What it answers |
|
| Your roster with slots, opponents, projections, injury designations |
|
| One pre-kickoff check: empty slots, byes, players out, already-locked, projected zero |
|
| Who you're playing, projected score both sides, who's yet to play |
|
| Rules, key dates, waiver system, standings |
|
| What every team can still spend, not just you |
|
| Search the pool, ranked on a basis you name |
|
| One player, and which team rosters them |
|
| Another team's roster |
|
| Every team's positional shape, for trade shopping |
|
| The league's transaction log, filterable |
|
| Your claims and trades ESPN hasn't processed yet |
Writing — off by default
Set write_enabled: true in your config to turn these on. While it's false they
are not registered at all, so a model cannot see or offer them.
Preview | Execute | Effect |
|
| Set your starting lineup |
|
| Add a free agent, drop a player, or both |
|
| Submit a waiver claim with a FAAB bid |
|
| Cancel a pending claim |
Trades are designed but not yet built.
How writes are made safe
ESPN's transaction API has no dry run and no idempotency key. A retried write genuinely submits the move a second time. Everything below exists because of those two facts.
Two calls, one code. Every write is split. preview_* shows the change in
player names and returns a short-lived, single-use code bound to that exact
transaction. execute_* refuses to run without it. An approval given for one
add cannot be spent on another, and a retried execute is refused rather than
double-submitted.
Being honest about what that guarantees. It makes a write impossible as a side effect of a question, and forces the preview into the transcript. It does not guarantee a human read it — a model can call preview and execute in the same turn. The real human-in-the-loop guarantee is your MCP client's approval prompt on a tool marked
destructiveHint. We set that annotation; your client decides what to do with it.
Nothing is ever retried. Retries are disabled at the HTTP adapter, because
requests and urllib3 retry by default and this is the one platform where
that silently double-submits a waiver claim. A timeout is reported as
unknown — never as success, never as failure — with your roster re-read so
you can see for yourself.
Your roster is re-read immediately before every write. If anything moved since the preview — you set a lineup on your phone — the write is refused rather than silently clobbering it.
Legality is checked client-side, since ESPN won't tell you in advance: roster space, slot eligibility, whether a player is actually free or actually yours, your bid against your remaining budget and the league minimum, and whether your league even uses FAAB.
It can only ever touch your own team. isLeagueManager and
isActingAsTeamOwner are hard-wired false with no parameter exposing them, and
your team id is pinned in config.
Every write is logged — intent before the request leaves, outcome after — so an interrupted write still leaves something to reconcile against. Credentials are redacted from every line.
What this server does not know
Stated in the server's own instructions, so a model driving it is told up front rather than left to invent:
No projections beyond ESPN's own number. There is no model here.
No injury news, no news feed, no reporter text.
No timestamps on injury designations. ESPN reports a status word and nothing else. It will catch a player ruled out on Wednesday; it will not catch a Sunday-morning inactive.
No ranking of players on merit.
A missing projection is returned as null, never as 0.0 — because ESPN really
does project some players at zero, and conflating the two invites a confident
wrong conclusion.
Why no optimizer
Removing the optimizer doesn't remove decision-making from the product — it moves it to you, where the context is. An automated optimizer on this platform would also be operating with no dry run and no undo, which is a bad combination for irreversible moves.
There's a second reason worth naming: if you drive this with an LLM, the decision-making relocates into a general model with no current fantasy data. That model will fill silence with confident, plausible, wrong detail. Hence the section above — telling it loudly what it doesn't know is the compensating control.
Notes on ESPN's private API
Documented here because it is otherwise scattered across gists and half-wrong repos. All verified against live ESPN.
Fact | Detail |
Read host |
|
Write host |
|
Auth |
|
| Not an auth signal. Reads |
Dry run | Does not exist. |
Idempotency | Does not exist. |
Body parsing | Strict, and happens before auth — so an unauthenticated POST returns |
Wire slot names |
|
Errors | Match |
Three shapes most public implementations get wrong, all confirmed correct here by ESPN's own parser:
A future-week lineup is
FUTURE_ROSTER, notROSTER.A standalone drop is
ROSTER, notFREEAGENT.The trade verbs (
TRADE_ACCEPT,TRADE_DECLINE, …) do exist.
A daily canary checks that ESPN still parses
the exact payloads we'd send. ESPN tightened leagueHistory in Aug 2025 and split
read/write hosts in Apr 2024, both without notice.
Design
docs/user-stories.md — 101 stories, the ground truth
docs/design.md — architecture, the write protocol, open questions
docs/setup.md — getting your cookies
src/fantasy_yolo/
espn/ vendored ESPN client (football), ours to fix
read/ read wrappers + the raw fetches espn-api misses
write/ payload builders, never-retry client, error interpretation
policy/ lineup planner, legality, confirm tokens, audit log
tools/ the 19 tools
cli.py Typer frontend ─┐ both generated from one registry,
mcp/ MCP frontend ─┘ so they cannot driftStatus
Reads are working and verified against a live league.
Writes are proven. A six-item batched lineup change against a live 14-team
league returned 200 EXECUTED on 2026-09-08. The confirmation token survived
across two separate CLI processes, the re-read-before-write guard held, and the
audit log captured intent and outcome with credentials redacted.
Add/drop and waiver writes are built and their payloads validated by ESPN's own parser, but have not yet been fired authenticated. Trades are designed, not built.
Before you use this
Unofficial. Not affiliated with, endorsed by, or sponsored by ESPN or Disney. It drives a private, undocumented API that can change or break without notice.
It runs on your machine, with your credentials, on your own account. It operates no service and redistributes nothing.
"Runs locally" is not "stays local." Everything this server returns is handed to whatever MCP client and model you configure — for most people, a hosted service. There is no telemetry and no network connection other than to ESPN, but that is not the same as your data staying on your machine.
What you're risking. ESPN's terms restrict unofficial automated access. ESPN can suspend or terminate your account and your league, and neither this project nor its author can restore anything they take. Read Disney's Terms of Use and ESPN's Fair Play and Conduct rules and decide for yourself. Note ESPN ships its own "Auto Control" AI that makes roster moves — automation is not itself against the spirit of the game — but that is not permission to drive the private API from outside.
espn_s2 is a full ESPN/Disney session cookie, not a scoped token. Leaking
it is account compromise. Never paste it into an issue, a chat, or a screenshot.
Licence
MIT. Permissive: use it, change it, ship it, sell it. The only thing it asks is that the copyright notice travels with the code.
It covers this project's own code. It grants no rights to ESPN's data, marks, or API, and it is not permission from ESPN.
Vendored code
src/fantasy_yolo/espn/ is a vendored copy of the football half of
espn-api by Christian Wendt, also MIT.
Its licence is preserved verbatim at LICENSE-espn-api, as
MIT requires when redistributing.
It is vendored rather than depended on so defects in the read path can be fixed
directly. The first was a POSITION_MAP that could not convert a lineup slot
label back to its id for bench, IR or flex — which made lineup writes impossible.
Our changes are marked fantasy-yolo: in comments, and its own test suite runs
in our CI.
Available Tools
2 toolsget_matchupCRead-only
Who you are playing this week, and the projected score for both sides.
| Name | Required | Description | Default |
|---|---|---|---|
| week | No | ||
| league | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| summary | Yes | |
| opponent | Yes | |
| provenance | Yes | |
| my_projected | Yes | |
| their_projected | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and destructiveHint=false, so the safety profile is covered. The description adds the nuance that the score is projected and the context is 'this week', but it does not disclose any additional behavioral traits such as defaulting behavior, rate limits, or authentication needs.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, concise sentence with no filler words. It is front-loaded with the most important information and every word contributes meaning.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Despite an output schema being present, the complete lack of parameter documentation in both the schema and description leaves significant gaps. An agent cannot confidently invoke the tool correctly without knowing how 'league' is used or what happens when 'week' is null.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, and the description does not explain the 'week' or 'league' parameters at all. The phrase 'this week' only hints at the week parameter, while 'league' remains completely unexplained, leaving an agent unable to determine how to set these optional parameters.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly identifies the resource ('who you are playing') and the output ('projected score for both sides'), making the tool's purpose immediately understandable. It does not explicitly contrast with the sibling get_roster, but the matchup focus is distinct enough on its own.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides no guidance on when to use this tool versus the sibling get_roster, no mention of alternatives, and no exclusions or prerequisites. An agent is left to infer usage solely from the tool name and purpose.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_rosterBRead-only
Your roster: lineup slots, NFL opponents, projections and injury designations.
Injury designations are exactly what ESPN reports. There is no timestamp and no news text behind them, so do not describe how recent one is (B-02).
| Name | Required | Description | Default |
|---|---|---|---|
| week | No | ||
| league | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| bench | Yes | |
| summary | Yes | |
| starters | Yes | |
| provenance | Yes | |
| open_roster_spots | Yes | |
| counts_by_position | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already provide readOnlyHint and destructiveHint, so the safety profile is covered. The description adds valuable behavioral context by explaining that injury designations are exactly as reported by ESPN and that there is no timestamp or news text, explicitly warning the agent not to describe recency. This goes beyond the structured metadata.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is short and front-loaded, with the first sentence stating what the tool returns. The second sentence adds an important caveat without verbosity. The internal reference '(B-02)' is slightly cryptic but does not materially hurt clarity.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present and read-only annotations, the description does not need to explain return shapes or safety. It competently covers roster contents and the injury-designation limitation. The main gaps are the undocumented week/league parameters and the lack of any comparison to get_matchup, leaving the selection context incomplete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, and the description does not explain the 'week' or 'league' parameters at all. Their names are mildly suggestive, but the description does not clarify whether they control the roster week, which league, or what null defaults mean. With low schema coverage, the description was expected to compensate and did not.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly identifies the resource ('roster') and its contents ('lineup slots, NFL opponents, projections and injury designations'), which is specific and informative. It does not use an explicit verb like 'get' or 'list', but 'Your roster' strongly implies retrieval. It distinguishes from get_matchup by subject matter, though it never names the sibling.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The phrase 'Your roster' gives an implied usage context: use this when the user's lineup, projections, or injury statuses are needed. However, there is no explicit guidance about when not to use it or when to prefer get_matchup instead, so an agent must infer the boundary.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
2 tool updates
v0.1.0- First observed
get_matchup - First observed
get_roster
TDQS
Scored across 2 tools
get_matchup and get_roster target completely different resources: one provides weekly opponent and projected scores, the other provides team roster details. There is no overlap or ambiguity between them.
Both tools follow the exact same get_<noun> snake_case pattern, making the naming predictable and easy to understand.
Two tools is borderline: they cover the core read-only queries for a fantasy matchup and roster, but the server is sparse compared to the typical footprint of a fantasy football tool.
The server is entirely read-only and limited to matchup and roster information. There are no tools for lineup changes, player news, league standings, or transactions, which are significant gaps for fantasy football workflows.
Maintenance
Related MCP Connectors
Manage Superlist tasks and lists in plain language from any MCP-compatible AI agent.
Provide detailed Pokémon data and information through a standardized MCP interface. Enable LLMs an…
- ManiloOAuthapp.manilo
Log, query, and edit expenses, budgets, and accounts in Manilo from any MCP-compatible AI assistant.
Log, query, and edit expenses, budgets, and accounts in Ledgy from any MCP-compatible AI assistant.
Related MCP Servers
- AlicenseNot gradedqualityBmaintenanceConnect 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.21MIT
- FlicenseAqualityCmaintenanceEnables natural language interaction with Sleeper Fantasy Football API data, allowing queries about leagues, players, matchups, draft results, and trade analysis.1321-
- AlicenseNot gradedqualityBmaintenanceEnables 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.70 npmMIT
- FlicenseBqualityCmaintenanceProvides MCP-compatible LLMs with read-only access to normalized ESPN Fantasy Football league snapshots, team rosters, and free-agent data.3-