Skip to main content
Glama
sdotj
by sdotj

SleepBot

CI

An MCP server that connects Claude to fantasy football leagues. Phase 1: read-only tools over Sleeper's public API (no auth required). Built to extend to write actions, ESPN, and multiple leagues without changing the tool interface.

Architecture

The core is platform-agnostic. Every tool talks to a LeagueAdapter interface, never to a platform SDK directly:

tools ──▶ LeagueAdapter (interface) ◀── SleeperAdapter ──▶ api.sleeper.app
  │                                       (EspnAdapter later)
  └──▶ config (leagues[] registry)

Adding a league or a platform is a config change, not a code change. The architecture is mapped with Cairn in cairn.blueprint; run cairn scan to reconcile the map against the code.

Related MCP server: sleeper-mcp

Setup

npm install
cp config/leagues.example.json config/leagues.json   # then edit with your league
npm run build

Find your Sleeper league id in the app URL or via https://api.sleeper.app/v1/user/<username>/leagues/nfl/<season>.

config/leagues.json

{
  "leagues": [
    {
      "id": "my-main-league",        // your own label, passed to every tool
      "platform": "sleeper",         // "sleeper" | "espn"
      "sleeper": { "leagueId": "123456789012345678", "username": "yourusername" }
    }
  ]
}

Secrets are never stored inline — a value like "env:ESPN_S2" is resolved from the environment at runtime (see .env.example). Phase 1 needs no secrets.

Run

npm start          # serves over stdio (built)
npm run dev        # serves over stdio (tsx, no build)

Register with Claude Code

// .mcp.json / claude mcp add
{
  "mcpServers": {
    "sleepbot": { "command": "node", "args": ["dist/index.js"] }
  }
}

Tools (Phase 1 — all read-only)

Tool

Purpose

list_leagues

Configured leagues (from config, no API call)

get_league_info

Settings, scoring, season, roster positions

get_rosters

Every roster: starters, bench, IR (player names resolved), record

get_my_roster

Your own roster, identified from the configured username

get_matchups

Weekly matchups + scores (defaults to current week)

get_standings

Ranked by wins, then points-for

get_transactions

Trades, waivers, add/drops (defaults to current week)

search_players

Players by name, filter by position/team

get_trending_players

Sleeper's most-added / most-dropped

Every tool takes your leagueId label, so multi-league support is just "pass a different id." Set sleeper.username in config and rosters/standings/matchups are flagged with isYou, so SleepBot knows which team is yours without asking.

Tools (Phase 2 — write actions, confirm-by-default)

Tool

Purpose

propose_trade

Draft a trade (runs rules); returns a draft, never sends

propose_waiver_claim

Draft a waiver claim (add/drop + FAAB); draft only

propose_add_drop

Draft a free-agent add/drop; draft only

execute_action

Send a previously-proposed action, by actionId — MCP only (a human-in-the-loop client). The chat panel and HTTP API cannot send from a proposal; approval is a separate, explicit step

list_pending_actions

Drafts awaiting confirmation

get_auth_status

Whether writes are authorized (ok / needs-reauth) + token expiry

Nothing changes your league silently: a propose_* tool ALWAYS returns a draft and never dispatches. Sending is a separate, explicit step — the web app's Pending approvals list (Activity page), a Telegram tap, or the MCP execute_action tool. Guardrails live in config/rules.json (copy config/rules.example.json):

{
  "mode": "manual",                 // DEPRECATED / no-op: proposals are always drafts.
                                    // Automation is per-league via `agent.autonomy`.
  "protect": [                      // hard blocks
    { "playerName": "Ja'Marr Chase", "actions": ["trade", "drop"] }
  ],
  "warn": [                         // non-blocking flags
    { "type": "trade_value_diff", "thresholdPct": 20 }
  ]
}

trade_value_diff uses KeepTradeCut (KTC) player values, bridged to Sleeper ids by name+position (~99% match). A snapshot ships in config/ktc-values.example.json; drop a fresher one at config/ktc-values.json to update, and set SLEEPBOT_KTC_MODE=oqb for 1-QB leagues (default superflex). Values from KeepTradeCut via cameron-eth/sleeper-sdk.

Enabling writes (unofficial Sleeper API)

Sleeper has no official write API. Writes go through its private GraphQL endpoint (https://sleeper.com/graphql), authenticated with a session JWT — there is no password automation. To enable them:

  1. Log in at sleeper.com in a desktop browser.

  2. DevTools → Network → filter graphql → click any request → copy the full authorization header value (a long eyJ... JWT).

  3. Put it in .env as SLEEPER_TOKEN=eyJ... (never commit it; .env is ignored).

The token is a JWT, so SleepBot reads its expiry and reports needs-reauth before attempting a doomed write. Check status any time with the get_auth_status tool. When the token expires or is rejected, writes pause, reads keep working, and you're notified to re-capture — no refresh endpoint exists, so recovery is a manual re-capture by design. Some networks/regions may need a VPN to reach the endpoint.

Protocol reverse-engineered by the community (cameron-eth/sleeper-sdk); it is unofficial and may change without notice.

Run the tests with npm test.

GUI (Phase 3)

A local React (Vite) app over a thin HTTP API that reuses the same core operations as the MCP server. Screens: My Team, Standings, Matchups, Draft, the Audit log, and a Chat panel (server-side Claude with the same tools).

npm run build && npm run api          # HTTP API on :8787 (reuses the core)
cd web && npm install && npm run dev  # GUI on :5173 (proxies /api -> :8787)

Then open http://localhost:5173. Secrets (SLEEPER_TOKEN, ANTHROPIC_API_KEY) live on the server only; the browser never sees them. The Chat panel needs ANTHROPIC_API_KEY — without it, chat returns a clear message and everything else keeps working.

Cloud deploy: one container serves the API + GUI, with Postgres for state (set DATABASE_URL) and the leagues config as an env secret (SLEEPBOT_CONFIG_JSON). See docs/deploy.md — there's a Dockerfile and a Fly.io walkthrough.

Roadmap

  • Phase 2 (built) — write actions (confirm-by-default) wired to Sleeper's private GraphQL API, rules engine, audit log, JWT session handling with fail-safe re-auth. Add SLEEPER_TOKEN to enable real sends.

  • Phase 3 (built) — local GUI (Vite/React) + HTTP API + in-app Claude chat, all over the shared core. Surfaces the audit log ("what SleepBot did while I was away").

  • Drafts (built) — read-only draft assistant for mock and real drafts: live board (status, on-the-clock, your next pick), and best-available recommendations by KTC value + roster need. Tools get_drafts / get_draft_board / get_draft_recommendations, a GUI Draft tab (auto-refresh while live), and chat with real draft context. Picks are made by you in Sleeper (their pick-submit is an undocumented real-time websocket).

  • Autonomous (built) — an opt-in per-league manager: a scheduled sweep reasons with Claude (+ web search for news) and proposes waiver/add-drop/trade moves through the same rules → pipeline → audit. Real-time Telegram alerts with Approve / Deny, and Override for rule-blocked moves. auto mode auto-executes clean actions; warned/blocked always wait. Opt in with an agent block in the league config + TELEGRAM_BOT_TOKEN/TELEGRAM_CHAT_ID.

  • Phase 4EspnAdapter against ESPN's cookie-based API, same interface

License & disclaimer

MIT — see LICENSE. You're free to use, modify, and distribute it.

Not affiliated with Sleeper, ESPN, or KeepTradeCut. SleepBot talks to Sleeper's unofficial, undocumented private API for writes; that can break at any time and may be against their terms — use it at your own risk, with your own account. The write protocol is derived from the community project cameron-eth/sleeper-sdk, and player values come from KeepTradeCut data. The software is provided "as is", without warranty (see the LICENSE).

Related MCP Connectors

Related MCP Servers

  • F
    license
    B
    quality
    C
    maintenance
    Enables comprehensive Sleeper Fantasy Football integration with Claude, providing real-time player projections, historical performance analytics, league management, and waiver wire analysis. Supports advanced NFL metrics, lineup optimization, and matchup analysis for fantasy football decision-making.
    6
    12
    1
    -
  • 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
    Enables Claude to query Sleeper's public fantasy football API over Streamable HTTP, covering leagues, rosters, drafts, matchups, player stats, trends, and player search. Roster data keeps IR (reserve) and taxi players distinct and enriched with player names, positions, teams, and statuses.
    -