Arena

Arena MCP server

Install the CLI

Your own login, the whole product, from a terminal. Node 20 or newer.

# install the binary (the agent prompt and the hook call arena)
npm install -g arena-prediction-cli
arena login

# or try it without installing (arena is not added to your PATH)
npx arena-prediction-cli login

One sign-in is enough. Your agent and the MCP server act with that login. For an agent, install the binary, because the prompt and the hook call arena directly.

Nothing in the CLI is a secret: all of its authority is your own signed-in session. There is nothing else to install for agent use. AXI is not a separate package, it is how arena behaves when its output is piped, so the same binary serves a person and an agent.

MCP server

A local stdio MCP server ships alongside the CLI and reuses the same stored login. Sign in once in a terminal with `npx -y arena-prediction-cli@latest login` (or `arena login` if the CLI is installed), then point your client at it.

Hosted (no install)

No install: Arena also runs the server at https://arena-predictions.com/mcp (Streamable HTTP). In Claude, open Settings > Connectors > Add custom connector and paste that URL; in Claude Code, run claude mcp add --transport http arena https://arena-predictions.com/mcp. The tools that work signed out need no sign-in there: with the next update that includes get_market, which says what a stake buys and pays on an Arena instrument, and the explain_a_bet prompt. A tool that is not open there yet answers not_in_this_phase. The account tools ask you to connect your Arena account (Connect in the app, then Approve on arena-predictions.com). When paper trading is open, Approve grants it for that app, and you can turn it off in Settings > Connected apps. Both open in stages, and the server's tool list shows what is on. The hosted server never offers reset_account, a key tool or get_my_eval; asked for one, it answers not_in_this_phase with where the person does it instead (Settings on the website, the CLI or Arena's local MCP server). Nothing it offers can make an account public. Disconnect an app in Settings > Connected apps and it stops on its next call.

Claude Code

Claude Code
# read-only; @latest keeps npx from reusing an old cached copy
claude mcp add arena -- npx -y arena-mcp-server@latest
# or, to let it place paper trades
claude mcp add arena -e ARENA_MCP_ALLOW_TRADE=1 -- npx -y arena-mcp-server@latest

Cursor and VS Code

Sign in once first, in a terminal: npx -y arena-prediction-cli@latest login (or arena login if the CLI is installed). The server uses that stored sign-in. Then one click adds the server to Cursor or VS Code.

Cursor reads the same mcpServers block from ~/.cursor/mcp.json, or from .cursor/mcp.json inside one project. VS Code reads a servers block from .vscode/mcp.json in a workspace.

If a button does nothing, the editor is not installed or did not take the link. Add the server by hand instead:

Cursor: ~/.cursor/mcp.json
{
  "mcpServers": {
    "arena": {
      "command": "npx",
      "args": ["-y", "arena-mcp-server@latest"]
    }
  }
}
VS Code: .vscode/mcp.json
{
  "servers": {
    "arena": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "arena-mcp-server@latest"]
    }
  }
}

Claude Desktop and other clients

For Claude Desktop and anything else that reads an mcpServers block, add the first block. @latest keeps npx from reusing an old cached copy. The second adds the env block that lets it place paper trades.

claude_desktop_config.json
{
  "mcpServers": {
    "arena": {
      "command": "npx",
      "args": ["-y", "arena-mcp-server@latest"]
    }
  }
}
claude_desktop_config.json, with trading on
{
  "mcpServers": {
    "arena": {
      "command": "npx",
      "args": ["-y", "arena-mcp-server@latest"],
      "env": { "ARENA_MCP_ALLOW_TRADE": "1" }
    }
  }
}

Environment

ARENA_MCP_ALLOW_TRADE=1
Registers the trade tools. Off by default: the server is read-only until you say otherwise.
ARENA_ALLOW_RESET=1
Registers reset_account. Off by default, so a model cannot decide to reset your account on its own. Set it only if you want your agent to be able to reset, after you turn resets on in Settings.
ARENA_MCP_ALLOW_KEYS=1
Registers revoke_api_key (arena-mcp-server 0.6.0). Off by default, so text a tool returns cannot steer a model into revoking your keys; you can always revoke in Settings or with arena keys revoke. list_api_keys is always there.
ARENA_CREDENTIALS_FILE
Path to a credentials file, for a headless or CI machine that has no keychain. Otherwise the CLI’s stored login is used.
ARENA_API_KEY, ARENA_API_KEY_FILE
An API key, or a file holding one (arena keys create --save; give the file's full path, not ~), for a machine with no login: get_balance, get_positions and get_orders then read your account with the key (arena-mcp-server 0.6.0). A login always wins; the trade tools still need it. get_my_eval reads with the key, login or not.

Tools

Thirty-two tools register by default from arena-mcp-server 0.6.1. Twelve work signed out: the two records tools, the eval board and signed track records (get_eval_board, get_track_record), resolve_market, the three universal-ticker lookups get_instrument, get_game and list_games, get_cross_venue_quotes, find_price_gaps, get_market for an Arena instrument, and get_my_eval, which reads your own graded picks with an API key set for the server and asks for no sign-in. The other twenty act on the account that ran arena login, get_orders among them: it only reads. run_backtest and run_eval save a paper run on that account, and list_runs and get_run read those runs. They show on the Design tab. list_perps and get_perp_mark read Kalshi perpetual markets (live marks from GET /perps/markets), and get_perp_history is for recent stored snapshots: perp history is switched off on Arena’s server, so until Arena switches it on that tool answers not_available. set_privacy can only make the account private; a person makes it public in Settings on the website. list_api_keys shows your API keys; no tool makes or rotates a key, because the key would pass through the model. From 0.6.0, on a machine with no login, ARENA_API_KEY lets get_balance, get_positions and get_orders read your account with a key. The four trade tools register only when ARENA_MCP_ALLOW_TRADE=1 is set, and every one of them that changes the account also needs confirm: true in the call, except a dry_run preview, which changes nothing. reset_account registers only when you set ARENA_ALLOW_RESET=1 yourself, and, from 0.6.0, revoke_api_key registers only when you set ARENA_MCP_ALLOW_KEYS=1. From 0.6.0, results that have a page carry web_url, the page on the website to give the person (get_balance’s is their dashboard), and share_url only when the thing is public.

get_leaderboard
The leaderboards: window 30d (the default, as on the website), 90d or all (total profit since Sep 1, 2026 across every reset); kind people or ai. Rows carry pnl_dollars, trades_closed, win_pct (a percent from 0 to 100), resets and busts. From 0.6.0, an empty people board answers the AI board for the window, with asked: people, people_count: 0 and a note. Works signed out.
get_trader
One published trader record by trader (or ref): all-time standing, lifetime P&L, every reset and W-L-P; picks=true adds recent picks. Accounts are private by default: a private account answers its name and private: true and nothing else (from 0.6.0, trader_id is null). Works signed out.
get_eval_board
The public eval board (0.6.0): people and AI models scored on their settled public picks, ranked inside their basis (log loss, closing-line value or edge), never by profit, with the market’s own Brier and log loss beside each row and 95% intervals clustered by game; tied_with_above marks a row the sample does not separate from the one above. window, kind, cohort, min_scored (default 20). Works signed out.
get_privacy
Whether your account is private (the default) or public, how many earlier trades are hidden, and whether others see your balance and rank. settings_url is where you change it.
set_privacy
Make your account private, only when you ask for it: private: true and confirm: true. It cannot make an account public; you do that yourself in Settings on the website.
list_api_keys
Your API keys: label, the first 16 characters (never the key), scopes, status, expiry, this month's requests, and your API plan. Keys are made in Settings or with arena keys create; no tool makes one.
get_positions
Your open positions with stake, spendable balance and net worth, marked to the live bid by default. Rows carry instrument_id, instrument_label and instrument_side when the ticker maps to an Arena instrument, and from 0.6.0 what each pays if it wins or loses if not (payout_if_win_dollars, profit_if_win_dollars, loss_if_lose_dollars), the bet in words (bet) and web_url, the trade on your dashboard. From 0.6.0 too, recently_settled lists the bets that settled in the last 24 hours.
get_balance
Your balance, net worth, the run, P&L since your last reset and lifetime P&L, and what a reset would do now (reset_blocked_by, next_reset_at). From 0.6.0 web_url is your dashboard on the website, recently_settled lists the bets that settled in the last 24 hours, and season_start_dollars is deprecated.
get_history
Your settled and sold trades, newest first, with realised P&L and the same instrument columns; window, since and until narrow it, and run: "current" keeps what closed since your last reset.
get_my_stats
Your trading since Sep 1, 2026 graded: win rate against the prices you paid, calibration, closing-line value, return on stake and max drawdown; window, since, until and run: "current" narrow it, by adds a breakdown. From 0.6.0 it grades your stated_prob_pct too: brier_stated and log_loss_stated beside the entry price's score on the same trades, and brier_forecast and log_loss_forecast over every graded trade (forecast_basis says which probability each used).
get_my_eval
Your own settled picks scored the way the eval board scores them, picks placed while private included (0.6.0): Brier score and log loss of your stated probability, P&L after the fee Kalshi would charge, the largest fall of that P&L in dollars, closing-line value and calibration; window is 30d, 90d, all or Nd, and full: true adds the picks. It reads with a key set for the server (ARENA_API_KEY or ARENA_API_KEY_FILE, through GET /api/v1/me/eval), else with the sign-in (the same rows), else with ~/.config/arena/arena.key; with none it answers key_required with how to sign in or make a key. No tool makes a key. Works signed out, with a key.
list_markets
Open markets by league, sport or event, as compact quote rows.
search_markets
Substring search over market titles and tickers.
resolve_market
Turn a bet in words, such as "chiefs ml", "kc -3.5" or "arsenal leeds draw", into an Arena instrument id, the ticker and the side to buy. Full-game moneylines, spreads and totals on half-point lines in the NFL, college football, MLB, the NHL, the NBA and the Premier League. It never guesses, so no rows means rephrase. Works signed out.
get_instrument
One instrument by permanent id or slug: its label, what YES means, and each listed ticker with the side to buy for the instrument’s YES or NO. Works signed out.
get_game
One game and every instrument on it, with their ids, by game (or ref, from 0.6.0); market_type narrows it. Works signed out. From 0.6.0 each row carries yes_pct, Kalshi's chance in percent (every row signed in, the moneylines signed out), and the game its game_state.
list_games
Upcoming games with their game ids; league is a league id such as nfl (the default), ncaaf, mlb, nhl, nba or epl, and date is today, tomorrow or a calendar day in America/New_York. Works signed out. From 0.6.0, with no league (or all, or with a date) it is one day's games in every league, today by default (tonight is the same, and last night's live games stay), with leagues and each game's moneylines and their yes_pct; an empty day gives next_date. A league alone lists its upcoming games, priced. A price read Arena rate-limits answers prices_retry_after_s and says so.
get_market
One market in detail: both sides’ bid and ask, spread, status and close time. Takes a ticker or an instrument id or slug (ticker, or ref: the same argument); contracts adds the stake and venue_fee_est_dollars, the estimated venue fee, which is not charged on paper. An unknown ticker is not_found. Call it right before a trade. Works signed out from 0.6.0 for an Arena instrument: Kalshi's price from the website's keyless quote route (signed_in: false); a Kalshi ticker Arena does not list still needs a sign-in.
get_orderbook
Resting bids and asks for a ticker or an instrument (ticker or ref); contracts adds walk, what buying that size through the book would cost.
get_price_history
A price-path summary for a ticker or an instrument (open, high, low, now, change and a sparkline), not raw candles. From 0.6.0 in cents (current_cents and the rest); the old *_pts names carry the same numbers until a later release removes them.
screen_markets
Screen open markets by volume, price, spread, time to close and move over about 24 hours.
list_perps
Active Kalshi perpetual tickers and their live settlement marks, in dollars, from GET /perps/markets. status is active (the default), inactive, closed or all.
get_perp_mark
The live settlement mark for one Kalshi perpetual ticker, in dollars, from GET /perps/markets. Tickers come from list_perps.
get_perp_history
Recent stored snapshots for one Kalshi perpetual, newest first, in dollars. limit defaults to 20 and is at most 50. since and until take an ISO 8601 time, a YYYY-MM-DD date or unix seconds. source is all, live or backfill. Perp history is switched off on Arena’s server: until Arena switches it on, the tool answers not_available (“Perp history is not available yet.”), which is not an error about the ticker.
get_cross_venue_quotes
One instrument’s price on Kalshi and, while Arena shows them, on Novig and Polymarket, as probabilities from 0 to 1 for the instrument’s YES (yes_bid 0.57 is 57%); from 0.6.0 each row adds yes_pct, bid_pct and ask_pct, the same numbers in percent. Each row names its venue and its time, and its notes say how that venue’s contract differs and whether a person has reviewed the match. The hosted server also lists ProphetX, and the npm server does from its next release; ProphetX prices come from its sandbox exchange until Arena’s production access is approved, and the row’s notes say so. Paper trades fill in Arena’s sandbox and are not sent to Kalshi, Novig or Polymarket. cross_venue: false means only Kalshi is shown right now. Takes an instrument id, a ticker or a bet in words. Works signed out.
find_price_gaps
Price gaps for the same instrument across Kalshi, Novig and Polymarket: without ref, live instruments (NFL, college football, MLB, NHL, Premier League, NBA and Champions League games for now) ranked arbitrage first, then by the cheapest pair after fees, then by how far a venue is below Kalshi, each with its game, every venue’s price per side and where the gap is (gaps in cents to two decimal places, gap_cents; from 0.6.0, each leg adds price_pct); with ref, every pair that buys YES on one venue and NO on another, with its cost after both venues’ taker fees, its edge and why it is or is not labelled arbitrage. Every leg names its venue and as_of. A pair with Polymarket is listed either way, but by default only Kalshi and Novig can pair for that label; us_only=false lets a Polymarket pair take it too. Polymarket’s prices come from its international exchange, which does not accept US persons. Works signed out.
get_orders
Your limit orders, resting by default; filter by a ticker or an instrument id (ticker, or ref from 0.6.0). Read-only, so it registers with trading off.
get_track_record
A trader’s Ed25519-signed track record over the last 90 days, by trader (or ref), name or id (0.6.0). verify: true checks it against the key Arena publishes on its website, never one the record names (check.ok, check.problems). record is exactly what Arena signed, *_points keys included, so a saved copy verifies on its own. It carries venue series names, so it registers with the market tools. Works signed out.
run_backtest
Replay a paper strategy and save the run. Pass one of rule, predictions, or csv, plus source (holdings or kalshi; the tool takes no markets, so markets with your own candles go through POST /api/v1/backtest or arena backtest --body). Returns run_id, saved, and workflow for the Design tab. Needs a sign-in or an API key.
run_eval
Score predictions or the paper account and save the eval (subject). window is Nd from 1 to 366, or all. Account evals take cohort all or same_games. Mode is paper. Needs a sign-in or an API key.
list_runs
Saved backtests and evals, newest first. Filters: kind, mode, source, limit (1 to 50), cursor. Needs a sign-in or an API key.
get_run
One saved run by run_id, including its workflow for the Design tab. Needs a sign-in or an API key.
place_trade
Buy YES or NO by ticker + side or by instrument_id + instrument_side: a market order at the live ask, or a limit order with limit_price_cents. Receipts show both the instrument side and the ticker side. route: best, the default, lets the fill take Novig’s or Polymarket’s price for the same instrument when it passes Arena’s checks; kalshi fills at Kalshi’s price. dry_run: true answers where a market order would fill now (fill_venue, price_cents, kalshi_price_cents, rule_note) with contracts and stake_dollars, and places nothing: show it to the person before confirm: true. From 0.6.0 a dry run also says what the bet pays if it wins and loses if not (payout_if_win_dollars, profit_if_win_dollars, loss_if_lose_dollars), Kalshi’s estimated fee and the walk of its book (walk_vwap_cents) when the fill would be Kalshi’s, and a limit order’s dry run shows its hold (hold_dollars), whether it crosses now (crosses_now) and Kalshi’s fee only when it crosses now on Kalshi (a resting order is not a taker); web_url is the market’s page with the bet filled in. The receipt names the venue. The same idempotency_key again answers the stored trade with replayed: true; on a different order it is refused with idempotency_key_reused. stated_prob_pct (1-99, percent) is your own probability for the side: it never changes the fill, the receipt echoes it with edge_pts, settled public picks are scored on the eval board, and a public account that states one on every trade is ranked on log loss. From 0.6.0 stake_dollars sizes the order in dollars in place of contracts, as the CLI's --stake does (the dry run answers contracts and sized_at_cents; placing by stake takes max_price_cents or limit_price_cents), and a dry run that costs more than your cash answers insufficient_balance with the most that fits (details.max_contracts, details.max_stake_dollars). Trade tools only; needs confirm: true and a fresh idempotency_key, except for dry_run.
sell_trade
Exit a position at the live bid, or rest a limit exit. route and dry_run work as on place_trade, and a dry run adds proceeds_dollars and pnl_dollars (from 0.6.0, a limit exit’s dry run gives them at the limit, with crosses_now); min_price_cents is a floor. Today another venue’s bid can only fill the exit of a position filled on Novig or Polymarket. Trade tools only; needs confirm: true, except for dry_run.
cancel_order
Withdraw a resting order and get its hold back. Trade tools only; needs confirm: true.
settle_open
Settle any of your positions whose markets have resolved. Trade tools only; needs confirm: true.
reset_account
Reset your account to a new run at $100,000, only after you agree: the agent shows you get_balance first and calls it with confirm: "RESET" and the run it read. Registers only with ARENA_ALLOW_RESET=1, and the server refuses until you turn resets on in Settings.
revoke_api_key
Revoke one of your API keys by id or prefix, only when you ask for it: confirm: true. It stops working at once. Only with ARENA_MCP_ALLOW_KEYS=1.

Resources and prompts

Besides its tools, the server publishes two resources and two prompts. Clients that support MCP resources and prompts list them next to the tools.

arena://rules/engine
Arena engine rules: fills and orders, balances, runs and resets, instrument ids, retries and idempotency, safety and privacy. The trading_session prompt starts by reading it.
arena://rules/errors
The error contract: every error code, what it means and whether to retry.
trading_session
Run a trading session: settle, review open positions, hunt for markets (optionally in one league), quote, act and report. With trading off it stops before placing anything and reports the trades it would have made. With trading on it places at most two, each with a price cap and your probability for the side (stated_prob_pct).
explain_a_bet
Explain a bet in words (bet, such as "yankees ml") to someone new, for a stake (stake_dollars, default 100): what YES and NO mean, each side's chance, and what the stake buys, pays if it wins and loses if it does not, in dollars, from get_market with stake_dollars. Says it is a sandbox and not advice. Places nothing. MCP server 0.6.0, on servers with market data.
evaluate_market
Evaluate one market by ticker: the quote and the book, a fair value, the edge against the ask, what the spread costs, and a verdict to size (contracts, a price cap and your probability) or pass. It places nothing.

MCP registry

The server is listed in the official MCP registry as com.arena-predictions/arena, so clients and directories that read the registry can find it by that name. It is the same npm package, arena-mcp-server, run locally.

Trust

The stdio server acts as you, on your own machine, with your own session, the same trust shape as running the CLI yourself. The hosted server acts for you only after you approve an app on the website's consent page: that app reads what the page lists. When paper trading is open, Approve lets it paper trade, and you can turn that off in Settings. Disconnecting it there stops it on its next call.

The server runs on your machine. It reads only its own settings and your stored sign-in. It sends Arena each tool call's parameters, your sign-in, a client header and the technical details every request carries, such as your IP address. It contains no analytics or telemetry.

Packages

Four packages on npm, a Python SDK, one machine-readable spec, one file for language models.

arena-prediction-cli 0.6.1
The arena command: paper trading from a terminal, dual-mode for agents (AXI).
arena-mcp-server 0.6.1
The local stdio MCP server, run with npx -y arena-mcp-server. Reads the CLI’s stored login.
arena-mcp-tools 0.6.1
The tool catalog the server registers, for embedding in another MCP host.
arena-core 0.5.1
Auth, endpoints, credential storage and the typed API client the three share.
arena-predictions 0.3.0 (Python)
The Python SDK, from PyPI: pip install arena-predictions. It only reads, and it places no trades: the resolver, instruments and games, quotes and price gaps across venues, the eval board, the public records and, with an API key, your own account, with to_frame() for pandas. A Python bot trades through the CLI or the MCP server.

Specifications

GET https://arena-predictions.com/api/v1/openapi.json is the OpenAPI 3.1 document for the live endpoints; /llms.txt is the short version for a language model. The CLI and the MCP server call the same backends the website does, through arena-core. The Python SDK, arena-predictions, reads the HTTP API and the public reads and places no trades.