Overview
An open-source MCP server. It reads any Sleeper league by id, NFL stats, open projections, and the closing line for every game since 1999.
What this is
Three families of verbs. Your league reads any Sleeper league by id with no account; on a box you own it also moves the league you host. The game is the NFL with no league attached. The lab is every closing line since 1999.
| Surface | Reach | Entry point |
|---|---|---|
| MCP server | 88 of 99 verbs; 23 with no account | /api/mcp · scripts/mcp.mjs |
| The public box | Default mode: public MCP plus the open-data files; no accounts, no leagues | OPENLEAGUES_MODE unset · league for the whole product |
| The lab | Real NFL lines since 1999, cohorts, grading, staking | /api/lines/:season.json · two skills |
| Open data | Three JSON files, anonymous, CORS on | /api/players.json · /api/wire · /api/lines |
| Receipts | A worked example: any Sleeper league, anonymous | /r/:leagueId |
| Browser app | Every verb, in the browser | createServerFn |
| Ledger CLI | Three reads, one gated write | scripts/ledger.mjs |
The CLI dispatches a slice of the catalog; see CLI.
Install
Docker gives a durable box: PGLite on a volume, the league clock in-process, no managed Postgres.
docker · durable box, in-process clock
git clone https://github.com/ryanwaits/open-leagues.git cd open-leagues docker compose up -d # http://localhost:8080
The shape of a league
One league row, ten rosters by default, a schedule, a wire, and a book. Three invariants hold on every surface:
- FAAB is one purse. Waiver bids and wager stakes draw from the same
faab_remaining. A spend is checked againstspendable(remaining minus unsettled stakes), never againstremaining. - You cannot fade your own roster. You may back it. The engine throws: “You can back yourself, but you cannot bet against yourself.”
- Stakes are whole dollars. A stake is floored to an integer with a $1 minimum before any other check runs.
exportLeague returns a JSON snapshot. Nothing reads one back in, and nothing syncs to Sleeper or ESPN.