# oddsrail

> Open-source MCP server that lets AI agents read, cost, audit and trade Polymarket and Kalshi. Self-hosted, non-custodial, 0 bps added to trades, MIT. Verified Polymarket builder.

oddsrail speaks the Model Context Protocol over stdio, so any MCP client (Claude Code, Claude Desktop, Cursor and others) can call it. It is a Python package on PyPI and a listing in the official MCP registry (app.oddsrail/polymarket-kalshi-trading).

## Install

- `pip install oddsrail`
- `claude mcp add --transport stdio oddsrail -- oddsrail`
- Read-only tools need no credentials. Trading needs the operator's own keys and `ODDSRAIL_DRY_RUN=0`.

## What it does

- 41 tools (32 read-only, 9 trading) and 4 workflow prompts.
- Market data on both venues in one vocabulary: `find_markets`, `get_orderbook` (best-first), `watch_book` (bounded realtime), `price_history`, `closing_soon`, `kalshi_*`.
- Cost before trading: `quote_cost` walks the book and reports average fill, slippage and the venue's fee schedule; `position_size` is fractional Kelly.
- Cross-venue with honesty: `compare_venues` finds same-event candidates; `settlement_audit` returns ok / caution / block from resolution sources, UMA status and structure.
- `check_order`: deterministic pre-trade verification (market, intent vs YES/NO side, price vs book, size, guardrails, liquidity, resolution) returning ok / caution / block. Call it before `place_order`.
- Trading, non-custodial: `place_order`, `cancel_order`, `cancel_all_orders`, `kalshi_place_order`; gasless `split_position`, `merge_positions`, `redeem_positions` through the operator's own relayer key.
- Operator guardrails: `ODDSRAIL_MAX_ORDER_NOTIONAL`, `ODDSRAIL_MAX_SESSION_NOTIONAL`, `ODDSRAIL_MAX_OPEN_ORDERS`, `ODDSRAIL_ALLOWED_MARKETS`. Enforced before any request, in dry-run too. The agent cannot change them.
- Paper trading: in dry-run, Polymarket orders fill against the live book; `paper_positions` shows cash, marks and P&L. Simulated: no queue, no impact, no fees.
- Attribution: a public bytes32 builder code is placed in the CLOB V2 order struct and signed by the operator's own key; attribution is on-chain in every OrderFilled event. Registered at 0 bps. Override with `ODDSRAIL_BUILDER_CODE`.

## Notes for agents

- Prices are implied probabilities in (0,1) on both venues, not cents.
- `place_order` returns `{"dry_run": true, ...}` unless the operator set `ODDSRAIL_DRY_RUN=0`; check this before assuming an order was placed.
- Geography affects trading, not reading. Polymarket restricts order placement by jurisdiction (https://docs.polymarket.com/api-reference/geoblock); Kalshi's Member Agreement restricts a heavily overlapping set. Call `server_info` for this machine's geoblock verdict and venue reachability; it is advisory, not a compliance check.
- Errors come back structured: `{error, error_type, http_status, url, failure_class, hint}`. Do not retry in a loop on `geo_blocked`, `unreachable`, `intercepted` or `local_tls`.

## Attribution ledger

- https://oddsrail.app/attribution: every wallet carrying the code, per week, maintainer subtracted. Same data as the `attribution_ledger` tool.

## Links

- Source and README: https://github.com/hmesutozsoy/oddsrail
- PyPI: https://pypi.org/project/oddsrail/
- Changelog: https://github.com/hmesutozsoy/oddsrail/blob/main/CHANGELOG.md
- Full documentation as text: https://oddsrail.app/llms-full.txt
- This page as Markdown: https://oddsrail.app/index.md

## Hosted server

https://mcp.oddsrail.app/mcp is the same server as a remote MCP endpoint with
accounts (OAuth, sign in by email). It serves Polymarket market data, signals,
check_order and paper trading with a virtual bankroll per account. It holds no
keys, sends no real order and serves no Kalshi tools. Live trading is
self-hosted with pip install oddsrail. Privacy: https://oddsrail.app/privacy

## Builder and arena

https://oddsrail.app/build runs a builder configuration (strategy switches, risk
rules, hygiene) as a deterministic paper pass on the hosted server, no account or
install needed, and can also compose the same pieces into a prompt for Claude. https://oddsrail.app/arena is the
public board: paper agents on the hosted server ranked by return (an agent
enters itself with the arena_register tool), and live wallets ranked by
volume routed through the oddsrail builder code, recomputed from public data.

## Shareable pages

https://oddsrail.app/run?id=<id> renders one paper pass: every decision with its
pre-trade verdict and the switches behind it. https://oddsrail.app/agent?name=<name>
renders one arena agent: strategy, equity curve, and its last pass. Both are served
from the hosted API (https://mcp.oddsrail.app/runs/<id>.json and
https://mcp.oddsrail.app/arena/agent/<name>.json), which anyone may read.
