AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
MCP verified MIT Self-run

Kalshi Mcp Server

mcp-cejor6-kalshi-mcp-server · by cejor6

Self-hosted MCP server for Kalshi prediction markets. Native RSA-PSS auth, token-bucket rate limiting, demo/prod safety controls. Designed to be forked and deployed.

No reviews yet
0 installs
40 views
0.0% view→install

Install

$ agentstack add mcp-cejor6-kalshi-mcp-server

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access Used
  • Filesystem access No
  • Shell / process execution Used
  • Environment & secrets Used
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/mcp-cejor6-kalshi-mcp-server)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
2mo ago

Declared compatibility

Claude CodeClaude DesktopCursorWindsurf

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Kalshi Mcp Server? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

kalshi-mcp-server

[](https://pypi.org/project/kalshi-mcp-server/) [](https://github.com/cejor6/kalshi-mcp-server/actions/workflows/ci.yml) [](LICENSE) [](pyproject.toml) [](https://github.com/astral-sh/ruff)

📦 PyPI  ·  🗂️ MCP Registry  ·  🐳 Container image  ·  🚀 [Deploy guide](DEPLOY.md)

A Model Context Protocol server for Kalshi prediction markets. Native RSA-PSS auth, async token-bucket rate limiting, two-step prepare/confirm order flow with safety caps, optional bundled OAuth proxy for remote-MCP deployments, 26 tools + 4 resources across REST and WebSocket. MIT, designed to be forked.

Works with any MCP client — locally via stdio (Claude Desktop, Claude Code, Cursor, Zed, Continue, Cline, Goose, etc.) or remotely as a self-hosted HTTP server (claude.ai custom connectors today, any OAuth-capable MCP client in the future).

> ⚠️ This software lets an LLM place trades. Read [DISCLAIMER.md](DISCLAIMER.md) > before deploying. Trading prediction markets involves substantial > risk of loss. AI agents make mistakes — sometimes confidently. The > authors are not liable for any losses. Test in demo (KALSHI_ENV=demo, > KALSHI_TRADING_ENABLED=0) until you understand the failure modes.

> Status — alpha. Auth (REST + WS), rate limiting, safety controls, > 26 tools across REST + live channels, and 4 resources are in place. > A long-lived multiplexed WebSocket session and kalshi://markets/{ticker}/orderbook > live resource are planned for v0.2.


Quickstart (30 seconds)

Read-only against Kalshi's demo environment — no real money, no trading flag. This is the safe way to try it.

pipx install kalshi-mcp-server        # or: pip install kalshi-mcp-server

Point any MCP client at it (this is the Claude Desktop / Claude Code shape — see the [full client matrix](#where-to-put-this-config) for others):

{
  "mcpServers": {
    "kalshi": {
      "command": "kalshi-mcp",
      "args": ["--env-file", "/Users/you/.kalshi/.env"]
    }
  }
}

Minimal ~/.kalshi/.env (get a demo key at demo.kalshi.co — it's shown once):

KALSHI_API_KEY_ID=
KALSHI_PRIVATE_KEY_PATH=/absolute/path/to/demo_private_key.pem
KALSHI_ENV=demo

Restart the client and ask it to run a Kalshi tool. Enabling prod and trading is a deliberate opt-in — a few more flags (KALSHI_ALLOW_PROD=1, KALSHI_TRADING_ENABLED=1) — see [Configure](#configure) and the [safety model](#safety-model).

What a call looks like

Ask the agent for tradeable markets and kalshi_find_liquid_markets returns a volume-ranked, combo-excluded shortlist (trimmed, illustrative):

{
  "scanned": 300,
  "markets": [
    {
      "ticker": "KXNBAGAME-25JUL12BOSLAL-BOS",
      "title": "Will the Celtics beat the Lakers?",
      "yes_bid_dollars": 0.58, "yes_ask_dollars": 0.60,
      "volume_24h_fp": 41230, "open_interest_fp": 88400,
      "status": "active", "close_time": "2026-07-12T23:30:00Z"
    },
    {
      "ticker": "KXHIGHNY-26JUL12-B90.5",
      "title": "Will NYC's high temp exceed 90.5°F today?",
      "yes_bid_dollars": 0.31, "yes_ask_dollars": 0.34,
      "volume_24h_fp": 12760, "open_interest_fp": 23110,
      "status": "active", "close_time": "2026-07-13T04:00:00Z"
    }
  ]
}

Placing a trade is a deliberate two step — kalshi_prepare_order runs the local safety checks and hands back a confirmation_id; nothing reaches Kalshi until you call kalshi_confirm_order with that token. An LLM can't place an order in a single call.


Why this server

Most existing Kalshi MCPs are thin wrappers around a handful of REST endpoints. This one aims to be:

  • Native Kalshi. Real RSA-PSS signer that handles the gotchas

(path-without-query-string, ms timestamps, separate demo/prod keys).

  • Rate-limit aware. Client-side token bucket mirrors Kalshi's 2026

read/write budget model, so the server can't spam the API into a 429.

  • Safe by default. Refuses to start against prod without an explicit

opt-in flag. Refuses to write without a separate trading-enabled flag. Order-time controls (size cap, daily cap, cash reserve) are all operator-configurable.

  • Hosted-deploy friendly. Accepts the private key as either a file

path OR an env var with inline PEM, so it works on platforms without filesystem mounts.

  • Fork-able. MIT, no personal data, CI/CD set up so PR contributions

flow through main without ever triggering a production deploy — only tagged releases (v*) do. Your fork's deployment stays decoupled from this repo's, and your fork's contributors can't affect what you run.

Install

From PyPI (recommended)

Published as kalshi-mcp-server. pipx installs the kalshi-mcp entrypoint into its own isolated environment:

pipx install kalshi-mcp-server        # or: pip install kalshi-mcp-server

From source

git clone https://github.com/cejor6/kalshi-mcp-server.git
cd kalshi-mcp-server
uv sync

Docker

Multi-arch (amd64 + arm64) images are published to GHCR on every tagged release, tagged :latest and :vX.Y.Z:

docker pull ghcr.io/cejor6/kalshi-mcp-server:latest

See [DEPLOY.md](DEPLOY.md) for hosted deployment.

Configure

  1. Generate a Kalshi API key at https://kalshi.com/account/profile (or

the demo equivalent at https://demo.kalshi.co/account/profile). Save the private key — it is shown ONCE.

  1. Put your secrets in one .env file. A good location for the

MCP-client use case is ~/.kalshi/.env (outside any repo). For local dev, the repo's own .env (gitignored) works too.

cp .env.example ~/.kalshi/.env
# edit ~/.kalshi/.env
  1. At minimum, set:
KALSHI_API_KEY_ID=
KALSHI_PRIVATE_KEY_PATH=/absolute/path/to/your_kalshi_private_key.pem
KALSHI_ENV=demo

For prod, also set:

KALSHI_ENV=prod
KALSHI_ALLOW_PROD=1
KALSHI_TRADING_ENABLED=1   # only if you want writes

How env vars are resolved

On startup, the server resolves config in this order (highest wins):

  1. Values already in the process environment — set in the MCP client

config's env: block, or exported in your shell.

  1. .env file — loaded from --env-file PATH if you pass that flag,

otherwise from ./.env in the current working directory if it exists. Variables already in the environment from step 1 are not overridden.

So you can put secrets either inline in the MCP config (env:) or in a file the config points at (--env-file). You don't need to do both.

Use with an MCP client (stdio)

Every MCP stdio client uses the same shape: a command to launch the server, optional args, optional env. The differences are just the file/UI where you put the config.

Three install patterns work — pick whichever fits your environment.

Pattern A — pipx install (cleanest, recommended)

Installs kalshi-mcp to a globally-available, isolated environment. pipx is the modern Python tool for this:

pipx install kalshi-mcp-server

MCP client config then collapses to:

{
  "mcpServers": {
    "kalshi": {
      "command": "kalshi-mcp",
      "args": ["--env-file", "/Users/you/.kalshi/.env"]
    }
  }
}

Update with pipx upgrade kalshi-mcp-server when you want the latest.

Pattern B — uv run against a local clone

Best if you've cloned the repo and have uv installed. Point the MCP client at uv with --directory:

{
  "mcpServers": {
    "kalshi": {
      "command": "uv",
      "args": [
        "run",
        "--directory", "/absolute/path/to/kalshi-mcp-server",
        "kalshi-mcp",
        "--env-file", "/Users/you/.kalshi/.env"
      ]
    }
  }
}

uv run activates the project's venv automatically. Update with git pull + restart the MCP client. Useful for development / hacking on the server itself.

Pattern C — Docker against the public image

Best for users without Python installed, or who prefer container isolation:

{
  "mcpServers": {
    "kalshi": {
      "command": "docker",
      "args": [
        "run", "--rm", "-i",
        "-v", "/Users/you/.kalshi/demo.pem:/secrets/demo.pem:ro",
        "-e", "KALSHI_API_KEY_ID=",
        "-e", "KALSHI_PRIVATE_KEY_PATH=/secrets/demo.pem",
        "-e", "KALSHI_ENV=demo",
        "ghcr.io/cejor6/kalshi-mcp-server:latest"
      ]
    }
  }
}

The -v mount bind-mounts your PEM file read-only into the container; KALSHI_PRIVATE_KEY_PATH points at that path. Secrets live in the JSON config — fine for a single-user machine.

Where to put this config:

| Client | Config location | |---|---| | Claude Desktop | claude_desktop_config.json (Settings → Developer) | | Claude Code | project .mcp.json or ~/.claude/mcp.json | | Cursor | Settings → MCP → Add new MCP Server (UI fills the same JSON) | | Zed | ~/.config/zed/settings.json under context_servers | | Continue | ~/.continue/config.json under experimental.modelContextProtocolServers | | Cline | Cline settings → MCP Servers → Edit JSON | | Goose | ~/.config/goose/config.yaml under extensions |

If you'd rather inline secrets in the MCP config (acceptable for local dev where the config file is on your own machine):

{
  "mcpServers": {
    "kalshi": {
      "command": "kalshi-mcp",
      "env": {
        "KALSHI_API_KEY_ID": "your-key-id",
        "KALSHI_PRIVATE_KEY_PATH": "/path/to/your/private_key.pem",
        "KALSHI_ENV": "demo"
      }
    }
  }
}

> Why not just .env in the project dir? MCP clients spawn the > server as a subprocess from their own working directory (typically > your home dir on macOS/Linux, the client's install dir on Windows), > so a .env sitting in this repo wouldn't get found. Hence > --env-file to point at it explicitly. Running the server directly > from the project dir (no client) still works without flags — the > CLI auto-loads ./.env when launched there.

Use as a remote MCP service

For clients that don't speak local stdio — currently the main one being claude.ai's custom connector form, which only supports OAuth-protected HTTP — host the server somewhere reachable and point the client at it. The OAuth proxy is bundled with the server; you just need to configure it.

See [DEPLOY.md](DEPLOY.md) for an end-to-end walkthrough using Render + GitHub OAuth + Upstash Redis. Other image-deploy hosts (Fly.io, Cloud Run, ECS, Railway) work the same way — Render is just the worked example.

Tools

| Group | Tools | |---|---| | Exchange / account | kalshi_get_exchange_status, kalshi_get_exchange_schedule, kalshi_get_api_limits, kalshi_get_environment, kalshi_set_safety_limits | | Discovery | kalshi_get_markets, kalshi_find_liquid_markets, kalshi_get_market, kalshi_get_event, kalshi_get_events, kalshi_get_series, kalshi_get_trades | | Market data | kalshi_get_orderbook, kalshi_get_market_candlesticks, kalshi_get_event_candlesticks, kalshi_get_market_trades | | Portfolio | kalshi_get_balance, kalshi_get_positions, kalshi_get_orders, kalshi_get_fills, kalshi_get_settlements | | Orders (write) | kalshi_prepare_order, kalshi_confirm_order, kalshi_cancel_order, kalshi_decrease_order, kalshi_get_order | | Live (WebSocket) | kalshi_get_live_orderbook, kalshi_sample_trades | | External data (read-only) | kalshi_fetch_external_data — host-allowlisted, GET-only, https-only fetch of public data feeds (Polymarket gamma/clob, NWS api.weather.gov, Open-Meteo incl. ensemble, Tennis Abstract, Deribit public). No credentials attached (trust_env=False), redirects not followed, body size- and wall-clock-capped and returned wrapped in UNTRUSTED-EXTERNAL-DATA delimiters. Exists so clients whose own egress is restricted (e.g. claude.ai cloud routines) can reach the public feeds their read-only research needs; the allowlist is enforced at runtime, additions are a code change, and the boundary rationale lives in AGENTS.md. |

Write tools require KALSHI_TRADING_ENABLED=1. kalshi_prepare_order runs local safety checks and returns a confirmation_id; nothing is sent to Kalshi until you call kalshi_confirm_order with that token. Cancel and decrease bypass the trading-enabled flag — they only reduce exposure.

Listing markets for an LLM: kalshi_get_markets / kalshi_get_market accept minimal=true to project each market down to a small whitelist of triage fields (ticker, prices, sizes, volume, status, close time). Prefer this over compact=true for scanning — compact is a blacklist and barely shrinks multivariate (KXMVE…) combo markets, whose bulk lives in custom_strike / mve_selected_legs / long sub-titles. Pass a custom fields="ticker,yes_bid_dollars,…" to override the default whitelist. View precedence is fields > minimal > compact > full. kalshi_get_event / kalshi_get_events accept the same minimal / fields for their nested markets (the event objects themselves only have the compact view).

Don't gate on liquidity_dollars: Kalshi currently returns it as 0.0000 on every market, even deep books — measure liquidity from the orderbook (best bid/ask + resting size) plus volume_24h_fp / open_interest_fp. It is stripped from compact and minimal views.

Finding tradeable markets: the default open listing is dominated by multivariate (KXMVE…) combo markets with empty/one-sided books. Pass mve_filter="exclude" to kalshi_get_markets to drop them server-side, or use kalshi_find_liquid_markets — it excludes combos, ranks by 24h volume, and returns a short minimal-projection shortlist. (Kalshi has no server-side sort, so the helper's ranking is over a bounded scan window, reported as scanned in the result.)

Event ticker vs market ticker: a market ticker carries an outcome suffix (…PITHOU-HOU); an event ticker (…PITHOU) does not. Passing an event ticker to kalshi_get_market / kalshi_get_orderbook / kalshi_get_markets used to fail silently (404, or an empty book/list read as "no liquidity"). These tools now detect that case and raise an actionable hint naming the real market tickers instead.

Resources

| URI | Description | |---|---| | kalshi://environment | Current env, safety limits in force + their env ceilings, rate-limit headroom (no API call) | | kalshi://balance | Cash + buying power | | kalshi://positions | Open positions (unsettled) | | kalshi://orders | Resting orders (open / partially filled) |

A WebSocket-backed live-orderbook resource (kalshi://markets/{ticker}/orderbook) is planned — for now, use the kalshi_get_live_orderbook tool which opens a transient WS, samples the book, and returns the current snapshot + delta arrival rate.

Safety model

This server is deliberately conservative for the same reason your bank's ATM is — small mistakes shouldn't cost large amounts.

  • KALSHI_ENV=prod requires KALSHI_ALLOW_PROD=1. The server

refuses to start without both.

  • All write tools require KALSHI_TRADING_ENABLED=1. The default is

read-only.

  • Per-order caps (MCP_MAX_ORDER_SIZE_USD, MCP_DAILY_LIMIT_USD,

MCP_MAX_CONTRACTS_PER_ORDER, MCP_CASH_RESERVE_USD) are checked before the request reaches Kalshi.

  • Tighten limits at runtime, no redeploy. Those env vars are the hard

ceiling. The `kalshisetsa

Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.