MCP server for Sleeper fantasy football — leagues, rosters, matchups, players, stats and projections, plus optional account tools (lineups, IR, waivers, trades, league chat) over stdio or Streamable...
Overview
A Model Context Protocol server for Sleeper fantasy football, built so an AI assistant can actually answer fantasy questions instead of handing you a wall of player IDs. Ask Claude, Cursor, or any MCP client things like: - "Who should I start this week in my dynasty league?" - "Show me the standings and who's on the waiver wire at RB." - "Was the Bijan-for-Chase trade fair? Who won it?" - "Who did I draft in round 1 the last three years?" - "Am I going to win this week? What are my playoff odds, and how many wins do I need?" - "Would trading for Justin Jefferson actually raise my playoff odds? What about picking up a backup RB?" - "Are any of my lineups broken this week?" (one check across all your leagues: empty slots, byes, players ruled out) - "Move Jacobs to IR, start Corum, and put a claim in for Kaelon Black." (with a Sleeper session, see Account tools) No login, no API key for reads: Sleeper's public API covers everything above the "Account" line.
README
sleeper-mcp
A Model Context Protocol server for Sleeper fantasy football, built so an AI assistant can actually answer fantasy questions instead of handing you a wall of player IDs.
Ask Claude, Cursor, or any MCP client things like:
- “Who should I start this week in my dynasty league?”
- “Show me the standings and who’s on the waiver wire at RB.”
- “Was the Bijan-for-Chase trade fair? Who won it?”
- “Who did I draft in round 1 the last three years?”
- “Am I going to win this week? What are my playoff odds, and how many wins do I need?”
- “Would trading for Justin Jefferson actually raise my playoff odds? What about picking up a backup RB?”
- “Are any of my lineups broken this week?” (one check across all your leagues: empty slots, byes, players ruled out)
- “Move Jacobs to IR, start Corum, and put a claim in for Kaelon Black.” (with a Sleeper session, see Account tools)
No login, no API key for reads: Sleeper’s public API covers everything above the “Account” line. Add your Sleeper session and the same server can also set lineups, manage IR/taxi, submit waiver claims and propose trades.
Why another Sleeper MCP?
There are several community Sleeper MCP servers. This one focuses on the things that make the difference between “it works” and “it’s useful in a conversation”:
| sleeper-mcp (this) | typical alternatives | |
|---|---|---|
| Player IDs resolved to names/positions/teams/injury flags in every response | ✅ everywhere (rosters, matchups, transactions, drafts, brackets) | usually raw IDs, or names only in one or two tools |
| Roster IDs resolved to team + manager names | ✅ | rarely |
| Computed standings (rank, record, PF/PA, streak, FAAB left, divisions) | ✅ | raw roster settings |
| Matchups paired with per-player points and margins | ✅ | raw matchup arrays |
| Trades summarized as “gave / got” per side, picks and FAAB included | ✅ | raw adds/drops maps |
| Free agents for a league (unrostered, ranked, trending-annotated) | ✅ | ❌ |
| Projections & stats scored with the league’s exact scoring settings | ✅ | ❌ (or PPR only) |
| Start/sit: optimal lineup with slot eligibility (FLEX, SUPER_FLEX, IDP) | ✅ | ❌ |
| Live win probability, Monte Carlo playoff odds and trade/waiver what-ifs over the real schedule, under league scoring | ✅ | rare |
| League history across seasons with champions | ✅ | ❌ |
| Select a team by username, user_id, roster_id or team name | ✅ | user_id / roster_id only |
| “Current week/season” defaults from Sleeper’s NFL state | ✅ | manual |
| Transports | stdio and Streamable HTTP (stateless, bearer auth, CORS, health check, Docker) | stdio only |
| Player database (~5 MB) | memory + disk cache, daily refresh, stale-cache fallback | re-downloaded per process |
| Rate limiting / retries | 600 req/min budget, backoff on 429/5xx, in-flight de-dup | none |
| Tests | 100+ unit + integration tests (in-memory and HTTP transports) plus a live smoke test | varies |
Tool annotations, structuredContent, prompts, resources |
✅ | partial |
The 28 read tools need no login. They use Sleeper by default; optional injury context can add ESPN reports. The 11 account tools (2 private reads, 9 writes) are registered only when you configure a Sleeper session, and --read-only keeps the writes off even then.
Quick start
Requires Git, Node.js 20+ and npm. Install from source; this project is not currently distributed on npm. npm is used below to install dependencies and build the local server, not to download a published @joscaz/sleeper-mcp package.
git clone https://github.com/joscaz/sleeper-mcp.git
cd sleeper-mcp
npm ci
npm run build
node dist/index.js --help
Keep the checkout: MCP clients launch its built dist/index.js. Replace /absolute/path/to/sleeper-mcp in the examples with its actual location. Use the full path to node too if your desktop client cannot find it on PATH. On Windows, use a path such as C:/Users/you/sleeper-mcp/dist/index.js.
The examples use --read-only, so they cannot change your account even if session credentials are present. To enable account changes deliberately, see Account tools.
Claude Desktop
claude_desktop_config.json:
{
"mcpServers": {
"sleeper": {
"command": "node",
"args": ["/absolute/path/to/sleeper-mcp/dist/index.js", "--read-only"],
"env": { "SLEEPER_USERNAME": "your_sleeper_username" }
}
}
}
Claude Code
claude mcp add sleeper -e SLEEPER_USERNAME=your_sleeper_username -- node /absolute/path/to/sleeper-mcp/dist/index.js --read-only
Cursor / Windsurf / other stdio clients
Same shape: command node, args ["/absolute/path/to/sleeper-mcp/dist/index.js", "--read-only"], env SLEEPER_USERNAME.
Updating your checkout
From a clean checkout on the branch you want to follow:
git pull --ff-only
npm ci
npm run build
Restart your MCP client afterwards. If you have local changes or a detached release tag, choose how to preserve or update those before pulling.
Make it yours
Sleeper’s API is public and read-only, so there is no login step: every league, roster and matchup is readable by anyone who knows a username or league ID. The only thing the server cannot know by itself is who you are. Set SLEEPER_USERNAME (or pass --user) and every tool that takes a user or team falls back to you, so “what are my leagues?”, “show my roster” and “who should I start?” work without naming yourself. Explicit selectors always win, so questions about other managers still work.
Remote / hosted (Streamable HTTP)
node dist/index.js --http --host 127.0.0.1 --port 3000 --read-only
# MCP endpoint: http://localhost:3000/mcp (POST, JSON-RPC)
# Health check: http://localhost:3000/healthz
This example listens only on your own machine. For remote hosting, configure SLEEPER_MCP_AUTH_TOKEN through your host’s secret manager, use --host 0.0.0.0, and put HTTPS in front of the service. Configure the same bearer credential securely in your MCP client. Not every remote MCP client supports static bearer authentication; check your client’s requirements.
When a Sleeper session is configured with write tools enabled, the bearer token is mandatory unless the server is bound to loopback: anyone who can reach an unauthenticated /mcp could otherwise change your lineups, drop players and send trades. The server refuses to start in that configuration unless the explicit insecure override is set. Bearer authentication is also recommended for remote read-only account access, which can expose private pending transactions. See SECURITY.md.
Build Docker locally from the checkout; no published container image is required. With SLEEPER_MCP_AUTH_TOKEN already set securely in your environment:
docker build -t sleeper-mcp .
docker run --rm -p 127.0.0.1:3000:3000 -e SLEEPER_MCP_AUTH_TOKEN -v sleeper-cache:/data sleeper-mcp node dist/index.js --http --read-only
The port is exposed only to the host by default. Use your hosting platform’s private ingress or HTTPS configuration for remote access. Neither command publishes an image.
Tools
Every tool that takes a team accepts any of username (or display name), user_id, roster_id, team_name (partial, case-insensitive), team (any of those names in one field, when you are not sure which kind you have), or nothing at all when SLEEPER_USERNAME is set. week defaults to the current NFL week and season to the current league season.
Users & leagues
| Tool | What it returns |
|---|---|
get_nfl_state |
Current season, season_type, week, league_season. |
get_user |
Username ↔ user_id, display name, avatar. |
get_user_leagues |
A user’s leagues for a season with league_id, scoring format, roster shape, status. |
get_league |
Summarized settings: scoring (PPR/half/std, TE premium, pass TD, bonuses), roster slots, redraft/keeper/dynasty, waivers/FAAB, playoffs, trade deadline, divisions, commissioners. include_raw for the full objects. |
get_league_standings |
Ranked standings with record, PF/PA, streak, waiver position, FAAB remaining, division. Doubles as the roster_id → manager map. |
get_league_history |
Walks previous_league_id back through seasons: champion, runner-up, regular-season leader, points leader. |
Rosters & matchups
| Tool | What it returns |
|---|---|
get_roster |
One team: current weekly starters during an active season, labeled with slots (QB, RB, FLEX…), plus bench, IR, taxi, record, FAAB. Uses live weekly starters with a session; otherwise public matchup data, which can lag. |
get_league_rosters |
Every roster in the league, including roster-default starters (include_bench=false for a lighter payload). Use get_matchups for weekly scoring lineups. |
get_matchups |
Paired matchups for a week with scores, margin, leader, starters with per-player points (include_bench for bench points). Filter to one team. |
get_playoff_bracket |
Winners/losers bracket with round labels (“Championship”, “Semifinal”, “Toilet bowl final”), teams and results. |
Transactions & picks
| Tool | What it returns |
|---|---|
get_transactions |
Trades, waivers, free-agent moves with players, teams, FAAB bids, traded picks and a per-side trade_summary. Current week or all_weeks. Failed claims hidden unless status="failed"/"all". |
get_traded_picks |
All traded picks grouped by current owner with original/previous owners. |
Drafts
| Tool | What it returns |
|---|---|
get_drafts |
Drafts for a league or for a user + season. |
get_draft |
Draft settings and the resolved draft order (slot → manager → roster). |
get_draft_picks |
Every pick with player, position, overall/round pick, drafter, keeper flag, auction price. Filter by round or team. |
Players
| Tool | What it returns |
|---|---|
search_players |
Name search (handles “ja marr”, “lions”) with position/team filters, injury and depth-chart info. |
get_player |
Full profile plus sourced injury context: report/retrieval timestamps, cache expiry, stale flags, and disagreements. Existing profile fields remain Sleeper-based. |
get_injury_report |
Current injury context for a roster (league_id + team selector) or up to 100 player_ids. Shows each source, timestamps, links, and a needs_check flag; never assumes a missing report means healthy. |
get_trending_players |
Most added/dropped players platform-wide over the last N hours. |
get_free_agents |
Unrostered players in a league ranked by Sleeper’s player rank, annotated with 24h trending adds. In season, flags players who can’t be picked up right now (availability: locked once their game has kicked off, on_waivers after a recent drop); addable_only hides them. |
Projections & stats
| Tool | What it returns |
|---|---|
get_projections |
Weekly or season (week=0) projections. Filter by players/position/league/team. scoring="league" applies the league’s exact scoring_settings. |
get_player_stats |
Actual weekly/season fantasy production with the same filters and scoring options. |
get_lineup_projections |
Start/sit for one team: current vs optimal lineup (respecting FLEX/SUPER_FLEX/IDP eligibility), suggested swaps, bye/injury/empty-slot warnings. Once games kick off, players whose game has started stay locked and count the points they have scored (plus a projection for the rest of a live game), so totals are projected finals and swaps only involve players still to play. |
check_lineups |
Checks every in-season league for zero-point slots and missing projections. A separate needs_check watchlist flags questionable starters, stale injury snapshots, and conflicting reports without injury-driven set_lineup moves. Clear zero-point fixes can still return ready-made arguments. Locked starters, best ball leagues, and empty rosters are skipped. |
Odds & simulations
| Tool | What it returns |
|---|---|
compare_lineups |
Current weekly lineup versus up to five named start/sit scenarios, using one collected input set. Shows projected-point deltas, approximate win-probability deltas in percentage points, slot/lock validation, and injury warnings. Read-only; invalid roster/slot/lock scenarios do not discard valid ones. |
get_matchup_odds |
Win probability for a week’s matchups, live during games: points so far, projected final and win % per side, plus a starter-by-starter view (final / playing / yet to play / bye) for a selected team. Past weeks come back as results, future weeks as projections. |
get_playoff_odds |
Simulates the rest of the regular season (10,000 runs by default) over the real schedule: playoff %, first-round-bye %, #1-seed %, projected record and average seed for every team. For a selected team, also this week’s swing (playoff % if they win vs lose) and playoff % by final win total. |
get_move_impact |
What-if for a trade, waiver claim or add/drop: playoff %, bye %, #1-seed %, projected record and average weekly projection before and after the move for your team and the trade partner, plus who enters and leaves the best lineup and a warning when a roster would be over its limit. |
Comparing lineups (read-only)
compare_lineups uses your current scoring-week lineup as the baseline. Each named scenario starts from that same baseline, not from the preceding scenario. Use either moves (start/bench swaps) or a complete starters list in league slot order.
For example, if Warren is currently starting and Likely is on your bench, call compare_lineups with these arguments after replacing the league and username placeholders:
{
"league_id": "YOUR_LEAGUE_ID",
"username": "your_sleeper_username",
"scenarios": [
{
"name": "Start Likely",
"moves": [{ "start": "Isaiah Likely", "bench": "Tyler Warren" }]
},
{
"name": "Keep Warren",
"moves": [{ "start": "Tyler Warren", "bench": "Tyler Warren" }]
}
]
}
- The response includes
baseline,opponent, andscenarios. Valid scenarios include resolved starters, changes,projected_points_delta,win_pct, andwin_probability_delta_pp. A delta of2.5means 2.5 percentage points, not a 2.5% relative improvement. - It reuses the existing league scoring and matchup-odds model, including points already scored and the projection for the rest of live games. A no-op produces zero deltas.
- Roster membership, position/FLEX eligibility, IR/taxi status, duplicate starters, and kickoff locks are validated. Roster/slot/lock errors return
valid: falsefor that scenario while valid scenarios still run. Malformed tool arguments or duplicate scenario names reject the request. - The first version supports the current regular-season NFL week in an active, synchronized, non-best-ball league. No past/future-week counterfactuals, trades, pickups, or opponent lineup optimization.
- Every scenario uses one collected set of inputs. This is not an atomic upstream snapshot; source caches apply, and public roster/matchup data can lag a recent change. The tool uses public weekly matchups even when a session is configured and never calls account APIs.
- If there is no single head-to-head opponent or the opponent’s lineup is unavailable, point comparisons still work but win probabilities are
nullwith a reason. Commissionercustom_pointsoverrides keep the modeled team total fixed. - Injury evidence and warnings accompany the results, but Questionable/ESPN reports do not rewrite the model. Probabilities assume independent position-based variation and are approximate—not Sleeper’s official odds or a guarantee of improved results.
- This tool never changes your lineup. Any later
set_lineupaction requires a separate decision and fresh validation.
Account tools (optional, session)
Registered only when a Sleeper session is configured (SLEEPER_TOKEN, or SLEEPER_EMAIL + SLEEPER_PASSWORD). They talk to Sleeper’s private GraphQL API (https://sleeper.com/graphql), the same one the web app uses. Every tool that changes the account takes dry_run=true to validate and preview first, resolves player names for you, and re-reads the roster afterwards so you see the result. “My team” is the roster owned by the logged-in user; pass roster_id to act on another one (co-owners/commissioners).
The quick-start client configurations explicitly disable writes. To enable them, configure the session securely and remove --read-only; also ensure SLEEPER_MCP_READ_ONLY is not enabled. These tools can affect your real account: preview with dry_run=true, require confirmation in your MCP client, and verify changes in Sleeper.
| Tool | What it does |
|---|---|
get_auth_status |
Who the session belongs to, how it was configured, token expiry, whether writes are enabled. Call it first to verify a token. |
get_pending_transactions |
Open trade offers (sent/received, who still has to accept) and pending waiver claims for your team, with names resolved. all_teams / include_finished widen it. |
set_lineup |
Start/bench swaps (moves: [{start, bench?}]) or a full starters list. In season, reads and updates the current weekly matchup—not roster defaults—and verifies it independently. Checks slot eligibility, IR/taxi, duplicates, kickoff locks and week rollover. |
update_ir |
Move players onto/off IR. A starter is benched first so the lineup stays valid; slot counts are enforced. |
update_taxi |
Move players onto/off the taxi squad, same guarantees. force for commissioner overrides. Note: most leagues block taxi additions once the regular season starts, and Sleeper enforces that server-side. |
add_drop_player |
Free-agent add and/or drop, refusing players who are already rostered. |
submit_waiver_claim |
Waiver claim with optional drop and FAAB bid (required in FAAB leagues, capped at your budget). Sleeper checks roster room at submission time, so a full roster needs a drop. |
cancel_waiver_claim |
Cancel one of your pending claims. |
propose_trade |
Offer players to another manager (partner = username, display name, team name or roster_id); counter_transaction_id rejects their offer and sends yours in one step. |
respond_to_trade |
Accept or reject an offer you received, or cancel one you sent. |
post_league_message |
Post in the league chat (e.g. pitch a trade). |
Write tools carry readOnlyHint: false so clients can ask for confirmation. Start with --read-only to keep the two private reads and drop every write tool even though a session exists.
Weekly lineup safety: In-season set_lineup returns week and verified: true only after a separate authenticated read confirms the requested starters. Missing/malformed weekly data, a failed live roster read, or unavailable kickoff information stops the write rather than falling back to roster defaults. If a request was sent but cannot be verified, check Sleeper before retrying: a transport or read-back failure does not prove nothing changed. Dry runs never send mutations. Outside an active season, lineup changes still update roster defaults and do not claim weekly verification.
IR/taxi moves that bench an in-season starter use the same weekly update and verification first. These are separate requests, not an atomic transaction: if the subsequent IR/taxi move fails, the error reports that the lineup already changed. Preflight checks catch observed concurrent lineup changes but cannot eliminate every race with another client.
Heads-up: the private API is undocumented and unsupported by Sleeper; field names and behaviour can change without notice. Use a session you are comfortable exposing to the machine running the server, and confirm each change in the Sleeper app the first few times.
Getting a token: log in at sleeper.com, open DevTools → Network, click any graphql request and copy the value of the authorization request header (a long eyJ... JWT). Set it as SLEEPER_TOKEN. Tokens are long-lived but do expire; get_auth_status tells you when. Alternatively set SLEEPER_EMAIL + SLEEPER_PASSWORD and the server logs in on first use (accounts with 2FA/captcha challenges need the token route).
Injury context (optional ESPN)
Sleeper-only mode is the default. To add the keyless, read-only ESPN injury feed to the existing tools:
SLEEPER_MCP_INJURY_SOURCE=espn node dist/index.js --read-only --user your_sleeper_username
For desktop clients, add SLEEPER_MCP_INJURY_SOURCE with value espn to the server’s env configuration. No new account connection, package, or credential is needed. The ESPN endpoint is unofficial and may change or stop working; opt in only if its use is appropriate for your deployment and the provider’s terms.
get_injury_reportaccepts a roster or explicitplayer_ids;get_playerincludes the same context. Current-week lineup projections include aneeds_checklist alongside their existing results.- Each report has
source,reported_at,retrieved_at,cache_expires_at,stale, and a source link. Sleeper does not expose a reliable per-injury update time, so itsreported_atis null—not the player-map load time ornews_updated. stalemeans the cached source snapshot has expired, not that the underlying injury has ended. Read the report timestamp too: a recently fetched feed can contain an older report. Expired snapshots retained after a refresh failure keep their original timestamps and carry a warning.- ESPN defaults to a five-minute shared cache/retry window, configurable with
SLEEPER_MCP_INJURY_TTL_SECONDS(60–3600). This is an operational caching policy, not a prediction-confidence threshold. Concurrent callers share a request; there is no background polling. The daily Sleeper player-map cache is unchanged. - Player matching requires corroborated ESPN identity or a unique exact name/team/position match. Ambiguous mappings are surfaced, not guessed. The feed is fetched once per cache window rather than downloading every NFL team’s roster.
- Conflicting designations are shown together with
source: "conflict"and no chosen designation. An ESPNActivereport does not silently clear a Sleeper injury flag. Absence from the feed is not proof of health. - Questionable means check availability, not automatically bench. Stale/conflicting reports and newly reported ESPN injuries go on the watchlist rather than creating injury-driven lineup moves. Clear existing Sleeper problems still work; questionable replacement candidates still require your judgment.
- This release adds evidence, not a new forecasting model: projection totals, optimized lineups and odds remain Sleeper-based. Review the injury context before acting on those recommendations.
- ESPN outages, malformed responses and timeouts produce warnings while basic Sleeper reads continue. Setting the source back to
sleeperdisables ESPN requests.
Prompts
weekly_briefing(league_id, username, week?)— matchup preview, lineup check, waiver targets, league news.waiver_wire_report(league_id, username)— prioritized claims with drop candidates and FAAB suggestions.trade_analysis(league_id, team_a, team_b, proposal)— needs, lineup impact, depth, dynasty value, verdict.
Resources
sleeper://nfl/statesleeper://league/{league_id}
Configuration
| Variable | Purpose | Default |
|---|---|---|
SLEEPER_USERNAME |
Your Sleeper username (or user_id). Tools that take a user/team default to it, so “my team” questions need no selector. | unset |
SLEEPER_TOKEN |
Sleeper session JWT (see Account tools). Enables the private reads and the lineup/IR/taxi/waiver/trade/chat tools. | unset (reads only) |
SLEEPER_EMAIL, SLEEPER_PASSWORD |
Alternative to SLEEPER_TOKEN: log in with your Sleeper credentials on first use. |
unset |
SLEEPER_MCP_READ_ONLY |
1/true keeps write tools off even when a session is configured (same as --read-only). |
unset |
SLEEPER_MCP_AUTH_TOKEN |
If set, HTTP clients must send Authorization: Bearer . Required in HTTP mode when a Sleeper session has writes enabled and the server is not bound to loopback: it refuses to start otherwise. |
unset (no auth) |
SLEEPER_MCP_INSECURE_NO_AUTH |
Set to 1 to run account write tools on a non-loopback address without a bearer token, for deployments that authenticate in front of the server. |
unset |
SLEEPER_MCP_CACHE_DIR |
Where the player database is cached on disk. Set to an empty string to disable. | ~/.cache/sleeper-mcp |
SLEEPER_MCP_INJURY_SOURCE |
sleeper or espn for optional sourced injury context. No account credentials are sent to ESPN. |
sleeper |
SLEEPER_MCP_INJURY_TTL_SECONDS |
ESPN snapshot cache/retry window; integer 60–3600. | 300 |
PORT, HOST |
HTTP bind defaults (--port/--host override). |
3000, 0.0.0.0 |
CLI flags: --http, --port , --host , --user , --read-only, --no-preload, --help, --version.
How it works
- Player database. Sleeper publishes one ~5 MB JSON of every NFL player. It is downloaded once, indexed for name search, cached in memory and on disk for 24 hours, and preloaded in the background on startup. If a refresh fails, the stale copy is used rather than failing requests.
- Caching & rate limits. Every endpoint is cached with a TTL matched to how fast it changes (20 s for live matchups, 5 min for league lists, 24 h for players). Concurrent identical requests are de-duplicated. Outbound calls are capped at 600/min (Sleeper asks for < 1000) and retried with backoff on 429/5xx.
- Payload design. Responses use short keys where they repeat hundreds of times (
{id, name, pos, team, inj, pts}) and drop empty fields, which keeps token usage down for large leagues. - Projections/stats. These use Sleeper’s
/projections,/statsand/scheduleendpoints, which power the Sleeper app but are not in the public docs. They have been stable for years; if they change, the rest of the server is unaffected. - Odds. A starter’s remaining points are modeled around their league-scored projection for the share of their game still to play: Sleeper’s NFL schedule says which games are final, live or upcoming, and the plays both teams have run so far (rushes, pass attempts and sacks in the live box scores) estimate how far along a live game is, since Sleeper only adds snap counts once a game ends. The spread depends on position, and win % is the normal approximation of the score difference.
get_playoff_oddsplays out every remaining week with each team’s best projected lineup (the week in progress starts from live points), adds a season-long projection error per team, counts median games when the league plays them, and seeds by record, then points for. Runs are seeded, so the same data always gives the same odds.get_move_impactruns that simulation twice with the same random draws, before and after the move (which counts from the next week that has not started), so the difference comes from the move rather than chance: a pickup that would not start changes nothing.
Development
npm ci
npm run dev # stdio server via tsx
npm run dev:http # HTTP on :3000
npm test # vitest (unit + in-memory MCP + HTTP integration)
npm run typecheck
npm run smoke # live checks against the real Sleeper API
SLEEPER_USERNAME=you npm run smoke # also exercises your own leagues
npm run inspect # MCP Inspector against the built server
Layout:
src/
index.ts CLI entry (stdio / --http)
server.ts createServer(): tools, prompts, resources
http.ts Streamable HTTP host (stateless, auth, CORS, /healthz)
context.ts Shared context + resolvers (user, season, week, league, team)
format.ts Scoring summaries, standings math, slot eligibility, lineup helpers
sleeper/ API client, TTL cache, player store, types
tools/ Tool registrations grouped by domain
tests/ Fixtures + fake fetch; no network needed
scripts/smoke.ts Live end-to-end check
Using the client library from a checkout
After building, run this as an ES module from the checkout root (for example in a local .mjs script):
import { SleeperClient } from "./dist/sleeper/client.js";
const sleeper = new SleeperClient();
const state = await sleeper.getNflState();
const leagues = await sleeper.getUserLeagues("", "nfl", state.league_season);
Contributing
Issues and pull requests are welcome. CONTRIBUTING.md covers the dev setup, the project layout and how to add a tool; the short version is npm ci && npm test. Security reports go through SECURITY.md, and everyone is expected to follow the Code of Conduct.
Releasing
Distribution is source-first. npm publication is intentionally disabled with "private": true in package.json; this does not make the GitHub repository private.
After a maintainer explicitly pushes a version tag, the release workflow validates the source and creates a draft GitHub release for review. It does not publish to npm or upload a container image. See Releasing in CONTRIBUTING.md for the version/tag procedure.
Credits & license
Data comes from Sleeper’s public API (docs.sleeper.com). This project is not affiliated with Sleeper. Thanks to the earlier community servers, in particular FloSchl8/sleeper-mcp, for mapping out the space.
MIT © 2026 Jose Zertuche
Install
docker run --rm -p 127.0.0.1:3000:3000 -e SLEEPER_MCP_AUTH_TOKEN -v sleeper-cache:/data sleeper-mcp node dist/index.js --http --read-onlyConfiguration
{
"mcpServers": {
"sleeper": {
"command": "node",
"args": ["/absolute/path/to/sleeper-mcp/dist/index.js", "--read-only"],
"env": { "SLEEPER_USERNAME": "your_sleeper_username" }
}
}
}