API + MCP live · talk to us

// AI AGENTS THAT TRADE

Trading Kalshi and Polymarket with Claude via MCP (tutorial)

2026-07-16 · Mithril

This is a hands-on tutorial: by the end, Claude will be able to search prediction markets on Kalshi and Polymarket, place and cancel orders, and read your portfolio — all from a chat window, with hard risk limits enforced server-side so a confused model can't hurt you. Fair warning that this post is Mithril-specific: it documents our hosted MCP server at https://mcp.trymithril.com/mcp. For the vendor-neutral background on why this architecture looks the way it does, start with the hub article.

What you need

  1. A Mithril account — app.trymithril.com, free during beta.
  2. Venue credentials you add in the Mithril dashboard: a Kalshi API key and/or a Polymarket signing key. These are encrypted at rest (X25519 envelope encryption) and are only ever decrypted in memory to sign an order — Claude never sees them. Details in agent custody.
  3. Any MCP-capable Claude surface: claude.ai (custom connectors), Claude Desktop, or Claude Code.

Step 1: set your limits before connecting anything

This ordering is the whole point. Before the model can place a single order, configure in the dashboard:

  • Max notional per order — e.g. $50.
  • Max daily notional — e.g. $200.
  • Per-market position cap — e.g. 200 contracts.
  • Slippage bound — reject any fill worse than, say, 2¢ from the quoted price.
  • Kill switch — one toggle that halts all order placement instantly.

These are enforced on Mithril's servers on every order, regardless of what Claude asks for. A prompt-injected or hallucinating model cannot raise them, because no tool exposes them for writing. Why prompt-level limits don't count as limits: risk limits for AI trading agents.

Start with numbers that would merely annoy you if the agent spent all of them on nonsense. You can raise them after a week of sane behavior.

Step 2: connect Claude to the MCP server

claude.ai / Claude Desktop: Settings → Connectors → Add custom connector, URL https://mcp.trymithril.com/mcp. You'll go through an OAuth-style authorization tying the connection to your Mithril account and its limits.

Claude Code:

bash
claude mcp add --transport http mithril https://mcp.trymithril.com/mcp

Then authenticate when prompted. Either way, Claude now sees four tools:

ToolWhat it does
search_marketsFind markets across Kalshi and Polymarket by keyword; returns unified mkt_ IDs, prices, and which venues list the event
place_orderSubmit an order against a mkt_ ID — routed to the better venue net of fees, checked against your limits first
cancel_orderCancel a resting order by ID
get_portfolioPositions, resting orders, and remaining limit headroom — ground truth from the venues, not the model's memory

Note what's not there: no tool to change limits, no tool to export credentials, no raw venue passthrough. The tool surface is the security boundary.

Step 3: a real session

Here's the shape of a first session, condensed:

You: What markets are there on the September Fed decision?

Claude: (calls search_markets with "Fed September rate") I found the event on both venues. On Kalshi, "Fed decision in September" trades around 38¢ for a cut; the matching Polymarket market is at 0.40. Unified ID: mkt_fed_sep26_cut.

You: Buy $30 of yes if you can get it at 39 or better.

Claude: (calls place_order: mkt_fed_sep26_cut, side yes, limit 0.39, notional $30) Order placed and filled on Kalshi — 76 contracts at 39¢, taker fee $1.27, total cost $30.91. The receipt shows Polymarket's effective price at the same moment was 0.402, so routing to Kalshi saved about 1.2¢ per contract net of fees.

You: What am I holding now?

Claude: (calls get_portfolio) One position: 76 yes contracts in mkt_fed_sep26_cut, average price 39¢. You've used $30.91 of your $200 daily notional limit.

Three things to notice. The price comparison happened at execution time, on the server — Claude didn't have to get the fee math right. The fill came back with an execution receipt, so the numbers above are the venue's, not the model's. And the portfolio answer came from get_portfolio, not from Claude remembering the earlier trade.

Step 4: make the model verify, not narrate

Two habits that make agent trading dramatically safer in practice:

  • After every place_order, have Claude call get_portfolio and report the delta. If the model ever narrates a fill that the portfolio doesn't show, you've caught a hallucination instead of trading on one.
  • Ask for the receipt. Every fill has one — venue, price, fees, timestamp, and the counterfactual price on the other venue. It's your audit trail and your answer to "is the routing actually saving me money?" (More on why receipts matter: execution receipts and best execution.)

A useful system-prompt line if you're scripting this with Claude Code or the API: "Never state a fill, position, or balance without calling get_portfolio first. Never exceed the user's stated size even if limits would allow it." — belt and suspenders on top of the server-side braces.

What happens when Claude misbehaves

The failure cases you should actually test on day one:

  • Ask Claude to place an order 10× your per-order cap. The server rejects it with a limit error; Claude relays the rejection. Nothing fills.
  • Flip the kill switch mid-session. Every subsequent place_order fails instantly; search_markets and get_portfolio keep working, so the agent can still observe while disarmed.
  • Ask Claude for your API keys. There is no tool that returns them, so the worst possible outcome is a refusal — not a leak.

If any of these tests didn't fail safely on a system you're evaluating, that system is not safe to hand to a model.

Where to go next

Interfaces and venue details change. Everything above reflects documentation as of July 2026 — confirm against current docs before trading real money.

One API + MCP for Kalshi and Polymarket

Fee-aware routing, unified market IDs, and hard server-side risk limits — live today, free during beta.