BallStreet MCP Server
Exposes the BallStreet API to MCP clients (Claude Code, Claude Desktop, or anything else that speaks MCP), so a model can explain the game, read your league, manage a portfolio, and place orders.
Two distinct uses, and most people want the first:
- Ask questions about your league. A read-only key lets an assistant answer "why did my player drop overnight", "who is locked this week", "how many shares are left" using your actual numbers, and read the official rules from the server rather than guessing from how stock markets usually work.
- Run a trading bot. A key with
tradecan place and manage orders.
The same server, with a debug key, is what we use to diagnose a live league
from a terminal — see Debugging with it.
Setup
-
Create a key at https://ballstreetleague.com/dashboard/api-keys/. Pick the narrowest scopes that do the job, and scope it to one league if the bot only plays in one.
-
Install it:
pip install ballstreet-mcp
Dependencies are just
mcpandhttpx. The package does not import Django and does not need a running BallStreet server or database — it is an HTTP client, so it runs anywhere. Python 3.10 or newer. -
Register it:
claude mcp add ballstreet \ --env BALLSTREET_API_KEY=bsl_xxxxxxxx_... \ -- ballstreet-mcp
For Claude Desktop, in
claude_desktop_config.json:{ "mcpServers": { "ballstreet": { "command": "ballstreet-mcp", "env": { "BALLSTREET_API_KEY": "bsl_xxxxxxxx_..." } } } }
Configuration
| Variable | Default | Purpose |
|---|---|---|
BALLSTREET_API_KEY |
— | Required. |
BALLSTREET_BASE_URL |
https://ballstreetleague.com |
Point at a local server for development. |
BALLSTREET_READ_ONLY |
unset | 1 withholds the trading tools even if the key allows them. |
BALLSTREET_MAX_SHARES_PER_ORDER |
unset | Client-side per-order share cap. |
BALLSTREET_READ_ONLY and the share cap exist so you can bound a strategy you
are still experimenting with, without revoking and reissuing the key. They are
convenience rails on the client; the server's scopes are the real boundary.
Tools
Tools are registered from what the key actually allows, discovered at startup.
A read-only key does not merely get refused when it calls place_order — the
tool is never offered, so the model does not plan around a capability it does
not have.
Always available: whoami, market_primer, get_rules, search_rules
read: get_league_rules, list_leagues, get_market_state, list_players, get_player,
get_price_history, get_player_news, get_holdings_news,
get_player_holders, get_matchups, get_portfolio, get_portfolio_history,
get_leaderboard, get_live_stats, list_orders, get_pending_orders
trade: place_order, cancel_order, reorder_pending_orders
debug (tester accounts only): debug_league, debug_player
Answering questions about the game
get_rules returns the official rules, glossary, and FAQ from the server,
with every constant filled in from the live engine settings — so it cannot
quote a number that has since been retuned. search_rules ranks them against a
specific question ("why can't I buy him", "what is a short").
get_league_rules is the one that matters most for support answers. The
universal rules have to hedge — demand pricing is optional, round counts are
configurable — and this resolves them against what the league is actually set
to. Answering "why did his price go up" without it risks describing a demand
premium in a league that has demand switched off.
The rules endpoint is public, so an assistant can explain the game to someone who does not have an account yet.
What a bot should know about this market
market_primer is fetched from the server at startup. The short version,
because it is genuinely different from the order-book markets most trading code
assumes:
- Trading does not move prices. No order book, no per-trade impact. Prices move at settlement and on projection updates.
- Speed is not an edge. Buys queue and fill in a batch run ordered by a per-member priority that rotates each cycle. An order placed three seconds after an injury report fills at the same price as one placed three hours after it. Polling every second buys you nothing but a rate limit.
- Float is finite.
league_size x 100shares per player. When it is gone, buys are refused. This is the real scarcity — and the one place ordering matters, via your ownfill_prioritywithin your queue. - Halted players cannot be bought. IR/OUT/inactive. You can always sell or cover.
- Performance is measured against projections, not raw points.
Disclosure
Placing an order through an API key marks your league membership
bot_operated, which your leaguemates can see. Bots are a supported way to
play; undisclosed ones are not.
Debugging with it
A key with the debug scope (tester accounts only) adds two read-only tools
that expose what no screen shows:
debug_league— market state, both week counters, and the fill queue ordered bysettlement_priority. This is what answers "why did my order not fill" and "why is it showing the wrong week".debug_player— every component of a price: base, each multiplier, the share basis the posted price was built from, your own buy and sell prices, and recent price rows with their components.
debug_player also evaluates the two invariants server-side, so a diagnosis
never depends on a client reassembling the arithmetic:
sell_never_above_buy— a hard invariant. False means a real bug.posted_matches_recomputed— informational only. The posted price deliberately lags its own share basis between settlements, so a mismatch mid-week is expected on any player carrying demand.
There is no write path in the debug surface, by design. Diagnosing a pricing question needs reads, and a credential that can mutate a live league while investigating it is a category of accident worth designing out.
Releasing
./release-mcp.sh patch from the repo root. See RELEASING.md.
Rate limits
120 read requests/minute and 30 writes/minute per key, metered per key rather
than per user so one bot cannot starve another integration. A 429 comes back
with Retry-After.
Release files for ballstreet-mcp 1.0.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| ballstreet_mcp-1.0.1.tar.gz | 14.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| ballstreet_mcp-1.0.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 31.1 kB
Release files / ballstreet_mcp-1.0.1.tar.gz
| Download URL | ballstreet_mcp-1.0.1.tar.gz |
|---|---|
| Size | 14.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
3327ca01581609760f456603cb0c5cd05f2fb2c784dadaeabe2f802e6602ec3c
|
|
BLAKE2b-256 checksum How to use checksums |
51ef1e73dbbca16ddc73361fb2ee03b396bce3081119c1c251d5d8f82a166d11
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 24, 2026.
Transparency logRelease files / ballstreet_mcp-1.0.1-py3-none-any.whl
| Download URL | ballstreet_mcp-1.0.1-py3-none-any.whl |
|---|---|
| Size | 16.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
4f996f13ac44a089a02674231f0e193d50be981a8dd636f48898fb416e9624a9
|
|
BLAKE2b-256 checksum How to use checksums |
32fd83d888c41754777a82be8cf40799cfa821beea31821e3e255e5ea42d6cc7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 24, 2026.
Transparency log