oddsrail

MCP server for Polymarket and Kalshi

The rail AI agents use to trade prediction markets.

Live books, costed fills, settlement audits and non-custodial order routing in one open-source MCP server your agent can call. Free to run. 0 bps on every trade. Keys never leave your machine.

pip install oddsrail

claude mcp add --transport stdio oddsrail -- oddsrail

status
Verified Polymarket builder
surface
39 tools, 4 workflow prompts
cost
0 bps added to trades
default
dry-run, with a paper ledger
license
MIT, self-hosted

What a session looks like

A real exchange, captured on 2026-09-02. Tool results are abridged; the numbers are the venue's.

you   find markets about bitcoin and quote 100 shares on the favourite

agent find_markets("bitcoin")
      {"markets": [{"venue": "polymarket",
        "title": "Will the price of Bitcoin be above $72,000 on September 2?",
        "yes_price": 0.991, "best_bid": 0.988, "best_ask": 0.994,
        "spread": 0.006, "volume_24h": 196435, "market_id": "4430…2778"}, …]}

agent quote_cost("polymarket", "4430…2778", "BUY", 100)
      {"cost": {"fillable": true, "filled_size": 100, "avg_price": 0.994,
        "notional": 99.4, "slippage_vs_best": 0.0,
        "levels_consumed": [{"price": 0.994, "size": 100}]},
       "fees": {"fees_enabled": true, "fee_type": "crypto_fees_v2", "taker_only": true}}

agent 100 YES on "Bitcoin above $72,000 on Sept 2" costs $99.40 at 0.994,
      all at one level, no slippage. It pays $100 if it resolves YES: 0.6%
      gross before the taker fee. place_order is in dry-run; say the word
      and I will read back the intent before anything is signed.

How it compares

Against the raw venue APIs and the three products that actually compete today. Every cell is verified from their own docs and dated in the README.

Capabilityoddsrailraw venue APIspmxtSimmerPolymarket agent-skills
What it isself-hosted MCP serverthe venues themselvesunified API + SDK + MCP, "CCXT for prediction markets"agent trading platform + SDK + MCPmarkdown skill docs for agents
Venues you can tradePolymarket, Kalshione eachPolymarket, Opinion, Limitless (hosted); a dozen more for dataPolymarket, Kalshi, own $SIM sandboxPolymarket only
Custodynon-custodial, keys never leave your machineyourshosted: "PMXT handles custody, signing infrastructure"; self-hosted mode uses your keysself-custody, local signingyours (docs only)
Attribution you controlODDSRAIL_BUILDER_CODE overrides the 0 bps defaultn/anot documentednot documenteddocuments builder headers for your own code
Cost to the trader0 bps, free toolsfreehosted pricing not in the READMEnot documentedfree
Open sourceMIT, full sourcen/aMIT, ~2.1k starsnot stateddocs; license not stated
Operator guardrailsnotional caps, open-order cap, allowed markets; enforced in dry-run toononenot documentedper-trade limits, daily caps, stop-loss/take-profit, kill switchnone
Paper tradingdry-run fills against the live book, P&Lnonenot documentedvirtual $SIM sandboxnone
Book-walked cost, settlement audit, jurisdiction-classified failures, dated quirk notesall fournonot documentednot documentedquirks partly documented
Realtimewatch_book, boundedwebsocket, yours to wirenot documented in the READMEnot documentedwebsocket documented

Verified 2026-09-02 from each project's own README or docs. "Not documented" means exactly that, not "absent". These projects move; re-check before quoting.

The wedge: pmxt is the reference for trading everywhere; Simmer is the reference for an agent economy with a sandbox and a reputation layer; oddsrail is the reference for trading correctly, non-custodially, with attribution you own.

Where the others are honestly ahead: pmxt trades three venues to our two and covers a dozen more for data, with hosted convenience and a community many times ours. Simmer has a virtual-balance sandbox, stop-loss and take-profit rails we do not have, a public reasoning layer, and a strategy-skills marketplace. Polymarket's agent-skills is the venue's own documentation and covers bridging and deposits, which oddsrail does not.

Built from the things the raw API gets wrong

Each of these was found by driving the venues live, then encoded so an agent never has to rediscover it.

  1. The book arrives worst-first

    Polymarket's raw orderbook lists bids ascending and asks descending, so bids[0] is the worst level. Every model's prior says index 0 is best. oddsrail normalises both venues to best-first and walks the book to quote what a size actually costs.

  2. Rejections don't raise

    The exchange models a rejected order as a return value, not an exception. Reported carelessly, a rejection reads to an agent as a resting order. oddsrail branches on it: accepted: false, nothing attributed, and an unrecognised response shape is never reported as posted.

  3. Geoblocks look healthy until the order

    Restricted jurisdictions are enforced at order placement. Public reads answer normally, so everything works right up to the trade. oddsrail classifies every failure shape (jurisdiction, network filter, ISP interstitial, a missing local CA bundle) and gives the agent an actionable hint instead of a retry loop.

  4. "Account trades" returns everyone's

    The SDK call that sounds like your fills returns the market's public tape. oddsrail reads the operator's activity feed by wallet, with transaction hashes.

  5. Kalshi has no yes/no side

    Everything is quoted from the YES book as bid and ask; prices are dollar strings, not cents. Getting the translation backwards silently takes the opposite position. oddsrail lets the agent say outcome=no, action=buy and translates it, tested exhaustively rather than by example.

  6. A price gap is not an edge

    Identical wording on two venues does not mean identical settlement. oddsrail pairs candidates by similarity and close date, then audits resolution sources, UMA status and structure before anyone calls it arbitrage.

What's inside

30 read-only tools that need no keys, 9 trading tools that respect dry-run and the operator's guardrails, and four prompts that encode the order of operations that keeps an agent out of trouble.

Market data

  • search_markets
  • get_market
  • get_orderbook
  • watch_book
  • price_history
  • closing_soon
  • kalshi_*

Cross-venue

  • find_markets
  • compare_venues
  • settlement_audit
  • resolution_criteria

Cost and sizing

  • quote_cost
  • position_size
  • overshoot_signal
  • dispute_risk

Trading

  • place_order
  • cancel_order
  • cancel_all_orders
  • kalshi_place_order
  • split_position
  • merge_positions
  • redeem_positions

Lifecycle

  • order_status
  • open_orders
  • my_fills
  • my_positions
  • redeemable_positions
  • paper_positions
  • server_info

Prompts

  • find_fade_setup
  • check_cross_venue_edge
  • settle_resolved
  • daily_review

Where the builder code goes

Nothing is proxied and nothing is stored. The only thing oddsrail adds to your order is a public attribution tag, signed by your key, on your machine.

  1. 1. your agentAny MCP client
    • Claude Code, Desktop, Cursor and others
    • speaks plain intent: "buy 100 YES at 0.62"
  2. 2. oddsrail, on your machineChecks, then signs
    • guardrails, then the dry-run gate: simulate unless ODDSRAIL_DRY_RUN=0
    • book-walked cost, jurisdiction preflight
    • builder code placed in the order struct, then signed with your key
  3. 3. venuePolymarket CLOB, Kalshi
    • your own credentials
    • rejections branched, never reported as resting
    • 0 bps builder fee added
  4. 4. on-chainCTF Exchange V2
    • every OrderFilled event carries the code
    • attribution is public and auditable
    • weekly pool share paid by Polymarket

How it pays for itself without charging you

custody
None. You run the server; your keys sign your orders on your machine. Nothing is proxied and nothing is stored.
fees
0 bps. Orders carry a builder code registered at 0 bps maker and 0 bps taker. No fee is added to any trade.
attribution
The code is placed in the CLOB V2 order struct before signing, so attribution is on-chain in every OrderFilled event. The project earns only a share of Polymarket's weekly builder pool, which Polymarket pays out of its own program.
override
Set ODDSRAIL_BUILDER_CODE to your own code and the share accrues to you instead. The default is a default, not a lock-in.
status
Verified in Polymarket's builder program, with the attribution pattern for self-hosted, non-custodial tools confirmed by their builder team.
guardrails
ODDSRAIL_MAX_ORDER_NOTIONAL, ODDSRAIL_MAX_SESSION_NOTIONAL, ODDSRAIL_MAX_OPEN_ORDERS, ODDSRAIL_ALLOWED_MARKETS. Set by you, enforced before any request, in dry-run too. The agent cannot change them.
# the whole configuration
export ODDSRAIL_DRY_RUN=1          # default: simulate, papered
export ODDSRAIL_BUILDER_CODE=0x…   # optional: yours
export ODDSRAIL_MAX_ORDER_NOTIONAL=25
export POLYMARKET_PRIVATE_KEY=…    # only to trade
export POLYMARKET_RELAYER_API_KEY=… # only for gasless ops
export KALSHI_KEY_ID=…             # only for Kalshi private

# then, in any MCP client
"find markets about the world cup and
 quote the cost of 100 shares on the favourite"

Both venues restrict trading by jurisdiction; reads work from restricted places. server_info reports this machine's geoblock verdict and venue reachability before your first order. Where this works. Kalshi's REST API has no attribution field, so Kalshi flow is never attributed or monetised.

Live from the builder program

Fetched in your browser from Polymarket's public data API. Nothing here is a screenshot. Reward epochs run Sunday 00:00 to Saturday 23:59 UTC.

Top 10 builders by attributed volume, this week

loading…

View as table
#BuilderVolumeActive usersVerified

oddsrail, this week

loading…

Attributed volume is the sum of matched orders carrying the oddsrail code. Verified builders share a weekly USDC pool pro-rata to volume. There is no top-N cutoff, only a ranking. The attribution ledger shows which wallets that volume comes from, with the maintainer's own bot subtracted.