Skip to main content
Glama
Polymarket US MCP server

Polymarket US MCP server

by chand1012

Polymarket US MCP server

An MCP server for the Polymarket US retail REST API, supporting streamable HTTP and stdio. It exposes 58 tools for market and event discovery, prices and order books, sports, tags, account and portfolio, orders, combos, RFQs, and incentives. Tool input schemas are derived from the published Polymarket OpenAPI schemas; use your MCP client's tool listing to see available fields, required inputs, and pagination options.

Trading tools operate on your real account. The MCP endpoint has no authentication: anyone able to connect can read account information and submit or cancel trades. It binds to localhost by default. Only change HOST if the endpoint is protected by a trusted network boundary or an authenticated proxy.

Setup

Install Python 3.14 and uv. Create a Polymarket US account and API key as described in Polymarket's authentication guide. Identity verification and account funding may be required for trading.

uv sync --locked
cp .env.example .env
# Edit .env and add your Polymarket US key ID and secret key.
uv run python main.py

Connect an MCP client using streamable HTTP at http://127.0.0.1:8000/mcp. Configure that URL in the client's remote MCP server settings. HOST and PORT select the server's bind address and port; both keys are required on startup. The server reads .env from the project directory; existing environment variables take precedence over values in the file. Protect the secret as you would any trading credential; do not commit it to source control.

Stdio transport

For local MCP clients that launch a server process, use:

uv run --directory /absolute/path/to/polymarket-us-mcp python main.py --transport stdio

For example, a client using an mcpServers configuration can launch it with:

{
  "mcpServers": {
    "polymarket-us": {
      "command": "uv",
      "args": ["run", "--directory", "/absolute/path/to/polymarket-us-mcp", "python", "main.py", "--transport", "stdio"]
    }
  }
}

Replace the example path with your project directory and make sure uv is available to the client. The server reads the same project .env and environment variables in stdio mode. HOST and PORT apply only to HTTP. Stdio runs as a child of the MCP client and does not open a listening port. Both transports expose the same live trading tools.

Related MCP server: Polymarket MCP Server

Using the tools

Start with search, get_events, get_markets, get_market_by_slug, get_market_book, or get_market_bbo. List tools accept a query object containing the exact documented query parameters, including pagination; for example, get_events with {"query": {"limit": 10, "offset": 0}}. Responses come directly from Polymarket.

Use get_account_balances, get_user_positions, and get_open_orders to inspect the account. For a limit order, the following example buys two YES contracts at $0.55 each, subject to the market's rules. Replace the slug and values with the intended trade. Prices are USD strings, and quantity is in contracts.

Call preview_order first:

{
  "body": {
    "request": {
      "marketSlug": "your-market-slug",
      "intent": "ORDER_INTENT_BUY_LONG",
      "type": "ORDER_TYPE_LIMIT",
      "price": {"value": "0.55", "currency": "USD"},
      "quantity": 2,
      "tif": "TIME_IN_FORCE_GOOD_TILL_CANCEL"
    }
  }
}

After reviewing the preview, create_order takes the same order directly under body, without the request wrapper. A call to create_order submits a live order. The full orders documentation describes intents, order types, time in force, and other options. The server also provides order lookup, modification, cancellation, closing positions, and batch operations. A returned batch cancellation or modification ID does not itself confirm the exchange applied the operation.

Trading and other mutations are never automatically retried. If a mutation times out, loses its connection, or receives an ambiguous server error, the result is outcome_unknown: inspect orders, positions, or the relevant RFQ before retrying. API errors include a status and request ID when available; raw error bodies are not returned to avoid reflecting sensitive data.

The server uses the official Python SDK for supported operations and signed SDK requests for documented endpoints that do not have resource methods. The catalog is a snapshot of the public Polymarket US retail OpenAPI schemas and the documented retail combos endpoint; update it when the upstream API changes. WebSocket streaming and institutional APIs are outside this server's scope.

Tests

uv run python -m unittest discover -s tests -v

Tests use a mocked Polymarket transport, including an actual local HTTP MCP connection; they do not place trades. For optional live read-only verification, start the server with your keys and call get_markets or get_account_balances from an MCP client. Do not use a live trading tool to verify setup unless you intend to submit a real trade.

Container

The GitHub Actions workflow builds the image for Linux amd64 and arm64 and publishes it as ghcr.io/chand1012/polymarket-us-mcp. Pushes to main or master publish latest; version tags beginning with v publish a matching image tag, and published builds also receive a commit SHA tag. Pull requests build and test without publishing.

Build and run locally, supplying credentials at runtime:

docker build -t polymarket-us-mcp .
docker run --rm --env-file .env -e HOST=0.0.0.0 -e PORT=8000 \
  -p 127.0.0.1:8000:8000 polymarket-us-mcp

Replace the image name with ghcr.io/chand1012/polymarket-us-mcp:latest to run a published image. The server listens on all interfaces inside the container so Docker can forward requests; the example publishes the port only on the host's loopback interface. To restrict access to a tailnet, replace 127.0.0.1 in the -p mapping with the host's Tailscale IPv4 address and apply your Tailscale access rules. Do not set HOST inside the container to the host's Tailscale IP, which normally does not exist in the container network namespace. Anyone who can connect to the published port can use the account's trading tools.

To run the stdio transport instead, pass --transport stdio after the image name and keep standard input open with -i; no port mapping is needed. Do not allocate a TTY for MCP communication.

Available Tools

58 tools
accept_quoteAccept QuoteC
Destructive

LIVE ACCOUNT ACTION: Accepts one side of a quote. This operation may affect real funds or account state.

Inputs: body (required), rfqId (required), quoteId (required).

cancel_all_open_ordersCancel All Open OrdersB
Destructive

LIVE ACCOUNT ACTION: Cancel all open orders, optionally filtered by market slugs This operation may affect real funds or account state.

Inputs: body (required).

cancel_multiple_ordersCancel Multiple OrdersA
Destructive

LIVE ACCOUNT ACTION: Cancel up to 20 orders in a single request. If any entry fails request-shape validation, the whole batch is rejected by the gateway before reaching the exchange. The exchange may silently ignore unknown orderIds. canceledOrderIds is an echo of the request, not a confirmation; observe actual outcomes on the order stream. This operation may affect real funds or account state. Returned IDs may not confirm exchange execution; verify the outcome.

Inputs: body (required).

cancel_orderCancel OrderB
Destructive

LIVE ACCOUNT ACTION: Cancel a specific order by its exchange-assigned ID This operation may affect real funds or account state.

Inputs: body (required), orderId (required).

close_position_orderClose Position OrderA
Destructive

LIVE ACCOUNT ACTION: Create an order to close an existing position in a market. This will sell all contracts held in the specified market. This operation may affect real funds or account state.

Inputs: body (required).

confirm_quoteConfirm QuoteC
Destructive

LIVE ACCOUNT ACTION: Confirms an accepted quote during last look. This operation may affect real funds or account state.

Inputs: body (required), rfqId (required), quoteId (required).

create_comboCreate ComboB
Destructive

LIVE ACCOUNT ACTION: Creates or returns the combo instrument for the supplied legs. Each authenticated exchange participant may create up to 1,000 new combo instruments per week across all of its accounts. The quota resets Monday at 00:00 UTC. Returning an existing canonical combo does not consume the quota. This operation may affect real funds or account state.

Inputs: body (required).

create_multiple_ordersCreate Multiple OrdersA
Destructive

LIVE ACCOUNT ACTION: Create up to 20 orders in a single request. If any entry fails request-shape validation, the whole batch is rejected by the gateway before reaching the exchange. Per-entry exchange outcomes (accept, fill, reject) are delivered on the order stream, not in this response. createdOrderIds are returned in request order. This operation may affect real funds or account state.

Inputs: body (required).

create_orderCreate OrderB
Destructive

LIVE ACCOUNT ACTION: Create a new order to enter into a market This operation may affect real funds or account state.

Inputs: body (required).

create_quoteCreate QuoteA
Destructive

LIVE ACCOUNT ACTION: Creates a quote using the authenticated Retail account. Every successful call returns a new quoteId, including replacements. See quote replacement. This operation may affect real funds or account state.

Inputs: body (required).

create_rfqCreate RfqB
Destructive

LIVE ACCOUNT ACTION: Creates a combo RFQ using the authenticated Retail account. This operation may affect real funds or account state.

Inputs: body (required).

delete_quoteDelete QuoteB
Destructive

LIVE ACCOUNT ACTION: Deletes a quote so it can no longer be accepted. This operation may affect real funds or account state.

Inputs: rfqId (required), quoteId (required).

delete_rfqDelete RfqC
Destructive

LIVE ACCOUNT ACTION: Closes an open RFQ. This operation may affect real funds or account state.

Inputs: rfqId (required).

get_a_bucketed_ohlc_price_series_for_one_or_more_assetsGet A Bucketed Ohlc Price Series For One Or More AssetsA
Read-onlyIdempotent

Returns a dense, ascending OHLC candle series per requested asset between from and to, one candle per bucket. Buckets with no ticks are gap-filled: close is carried forward, open/high/low equal that close, and tick_count is 0. The server clamps rather than rejects: a to of 0 or in the future becomes now, and from is raised so the series holds at most 3600 candles. That count is the only size limit, so the widest window scales with the bucket: an hour at 1S, 60 hours at 1M, 150 days at 1H. The effective bounds are echoed on each series. Duplicate assets are deduped; the response holds one series per distinct asset. Match a series to a requested asset by its asset field, never by position: the order is not guaranteed, and the REST surface returns the series sorted by symbol because a repeated query parameter does not keep its order. An unknown symbol, or an asset whose markets are not available yet, fails the whole request with 404 (asset price history is not available). An available asset with no prices yet returns an empty series; an unknown class is rejected.

Inputs: query.

get_account_balancesGet Account BalancesA
Read-onlyIdempotent

Get user's current account balances including buying power, asset values, and pending transactions

Inputs: no named parameters.

get_activitiesGet ActivitiesB
Read-onlyIdempotent

Get activities for a user including trades, position resolutions, and account balance changes

Inputs: query.

get_all_leaguesGet All LeaguesB
Read-onlyIdempotent

Retrieve leagues with pagination (max 50 per page)

Inputs: query.

get_all_sportsGet All SportsC
Read-onlyIdempotent

Retrieve all sports

Inputs: no named parameters.

get_combosGet CombosA
Read-onlyIdempotent

Returns the combo matching the exact symbol.

Inputs: query (required).

get_event_by_idGet Event By IdC
Read-onlyIdempotent

Retrieve a specific event by its ID

Inputs: id (required), query.

get_event_by_partner_external_idGet Event By Partner External IdA
Read-onlyIdempotent

Resolve a partner external event ID (e.g. OpticOdds fixture ID) to the internal event and its mapped market sides

Inputs: externalId (required), partnerKey (required).

get_event_by_slugGet Event By SlugC
Read-onlyIdempotent

Retrieve an event by its slug

Inputs: slug (required), query.

get_eventsGet EventsC
Read-onlyIdempotent

Retrieve all events

Inputs: query.

get_events_by_league_slugGet Events By League SlugA
Read-onlyIdempotent

Retrieve events for a league by its slug (e.g., 'nfl', 'nba'). Resolves the league to its active series and returns events.

Inputs: slug (required), query.

get_events_by_sport_slugGet Events By Sport SlugA
Read-onlyIdempotent

Retrieve events for a sport by its slug (e.g., 'football', 'basketball'). Fetches all leagues for the sport, collects their active series, and returns combined events.

Inputs: slug (required), query.

get_events_for_a_tagGet Events For A TagA
Read-onlyIdempotent

Get events filtered by tag slug, sorted by volume descending by default

Inputs: slug (required), query.

get_incentive_programsGet Incentive ProgramsB
Read-onlyIdempotent

Returns active and historical incentive programs grouped by market.

Inputs: query.

get_league_by_slugGet League By SlugA
Read-onlyIdempotent

Retrieve a league by its slug

Inputs: slug (required).

get_market_bboGet Market BboB
Read-onlyIdempotent

Retrieve current market data (best bid/offer, stats) for a specific market by its slug in a lightweight format

Inputs: slug (required).

get_market_bookGet Market BookB
Read-onlyIdempotent

Retrieve current market data (order book, stats) for a specific market by its slug

Inputs: slug (required).

get_market_by_idGet Market By IdC
Read-onlyIdempotent

Retrieve a specific market by its ID

Inputs: id (required).

get_market_by_slugGet Market By SlugC
Read-onlyIdempotent

Retrieve a specific market by its slug

Inputs: slug (required).

get_marketsGet MarketsC
Read-onlyIdempotent

Retrieve all markets

Inputs: query.

get_market_settlementGet Market SettlementC
Read-onlyIdempotent

Retrieve the settlement price for a specific market by its slug

Inputs: slug (required).

get_open_ordersGet Open OrdersB
Read-onlyIdempotent

Get all open orders for the authenticated user

Inputs: query.

get_orderGet OrderA
Read-onlyIdempotent

Get details for a specific order by its exchange-assigned ID

Inputs: orderId (required).

get_price_historyGet Price HistoryA
Read-onlyIdempotent

Returns book-derived Yes and No display prices for one market. Use the market slug as symbol.

Supported fixed profiles:

  • INTERVAL_1H with fidelity=1: approximately one-minute points for the last hour

  • INTERVAL_6H with fidelity=1: approximately one-minute points for the last six hours

  • INTERVAL_1D with fidelity=5: five-minute points for the last day

  • INTERVAL_1W with fidelity=180: three-hour points for the last week

  • INTERVAL_1M with fidelity=180: three-hour points for the last 30 days

  • INTERVAL_ALL with fidelity=180: three-hour points for newer markets and daily points for longer histories

  • INTERVAL_LIVE with fidelity=1: from 15 minutes before the event starts through now

For a custom range, provide both Unix timestamps and use fidelity=1. Custom ranges are intended for short windows of up to 24 hours and return stored observations, which may be irregular or more frequent than once per minute.

longPrice is the Yes display price, normally derived from the best ask. shortPrice is the No display price, normally derived from one minus the best bid. They can sum to more than 1 because they preserve the bid-ask spread; these are not individual trades.

The endpoint supports one market per request. Cache identical responses for at least 30 seconds, stagger refreshes across markets, and observe the 20 requests/second/IP public limit. For live updates after loading history, use the Markets WebSocket.

Inputs: query (required).

get_quotesGet QuotesC
Read-onlyIdempotent

Returns quotes matching the query filters.

Inputs: query.

get_rfqsGet RfqsC
Read-onlyIdempotent

Returns RFQs matching the query filters.

Inputs: query.

get_rfq_tradesGet Rfq TradesA
Read-onlyIdempotent

Returns anonymous original fills where either order originated from an RFQ, newest first. Includes single instruments, combos, and later fills on resting orders. Repeat the same filters and limit with each cursor; an empty cursor ends the traversal. History is eventually visible. Requery overlapping time windows to find late arrivals and deduplicate by tradeId. Later corrections and busts do not amend these prints.

Inputs: query.

get_rfq_user_idGet Rfq User IdB
Read-onlyIdempotent

Returns the public RFQ user ID for the authenticated participant.

Inputs: no named parameters.

get_seriesGet SeriesC
Read-onlyIdempotent

Retrieve all series

Inputs: query.

get_series_by_idGet Series By IdC
Read-onlyIdempotent

Retrieve a specific series by its ID

Inputs: id (required).

get_sport_by_slugGet Sport By SlugB
Read-onlyIdempotent

Retrieve a sport by its slug, with all leagues attached

Inputs: slug (required).

get_sportsGet SportsC
Read-onlyIdempotent

Fetch sports data

Inputs: no named parameters.

get_sports_eventsGet Sports EventsC
Read-onlyIdempotent

Retrieve events sections for a sport series (optional trending, optional live, and sport section). Same structure as home page.

Inputs: seriesId (required), query.

get_sports_playersGet Sports PlayersB
Read-onlyIdempotent

Fetch sports players, filterable by abbreviation, name, id, team, or provider reference

Inputs: query.

get_sports_teamsGet Sports TeamsC
Read-onlyIdempotent

Fetch sports teams data for enriching sports events

Inputs: query.

get_sports_teams_for_providerGet Sports Teams For ProviderC
Read-onlyIdempotent

Fetch sports teams data for a specific provider

Inputs: query.

get_tag_by_idGet Tag By IdC
Read-onlyIdempotent

Get a tag by its ID

Inputs: id (required).

get_tag_by_slugGet Tag By SlugC
Read-onlyIdempotent

Get a tag by its slug

Inputs: slug (required).

get_tagsGet TagsC
Read-onlyIdempotent

Get ranked tags with optional filtering

Inputs: query.

get_user_positionsGet User PositionsB
Read-onlyIdempotent

Get user's trading positions across all markets or filtered by specific market

Inputs: query.

get_your_incentive_earningsGet Your Incentive EarningsA
Read-onlyIdempotent

Returns rewards earned by the authenticated caller. Each entry sums all payouts for a single (market, date) pair, where date is in Eastern Time.

Inputs: query.

modify_multiple_ordersModify Multiple OrdersA
Destructive

LIVE ACCOUNT ACTION: Modify up to 20 existing orders in a single request. Each entry is forwarded to the exchange as a cancel-replace. If any entry fails request-shape validation, the whole batch is rejected by the gateway before reaching the exchange. The exchange may silently ignore unknown orderIds. modifiedOrderIds is an echo of the request, not a confirmation; observe actual outcomes on the order stream. This operation may affect real funds or account state. Returned IDs may not confirm exchange execution; verify the outcome.

Inputs: body (required).

modify_orderModify OrderB
Destructive

LIVE ACCOUNT ACTION: Modify an existing order in the marketplace. Allows changing price, quantity, time in force, and other parameters. This operation may affect real funds or account state.

Inputs: body (required), orderId (required).

preview_orderPreview OrderA
Read-onlyIdempotent

Preview an order before submission to validate parameters and see expected fills

Inputs: body (required).

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    C2.8/5.0

    Scored across 58 tools

    Disambiguation2/5

    The set contains many overlapping read tools: get_sports vs get_all_sports, get_events vs get_events_by_sport_slug/get_events_by_league_slug/get_events_for_a_tag, and get_price_history vs the bucketed OHLC tool. Descriptions add parameters, but an agent still faces multiple near-duplicate retrieval paths and must infer which variant to use.

    Naming Consistency4/5

    Most names use snake_case with a clear verb (get_, create_, cancel_, modify_, delete_), which is predictable. There are minor deviations such as the extremely long get_a_bucketed_ohlc... name and inconsistent 'all' qualifiers (get_sports vs get_all_sports), but not mixed casing/styles.

    Tool Count1/5

    58 tools is an extreme overload for an MCP surface; the calibration explicitly treats 50+ tools as a mismatch. Many retrieval variants and batch/lifecycle operations could be consolidated or exposed via parameters.

    Completeness4/5

    The surface covers the domain broadly: events/markets/series/sports/tags, price history/OHLC, order lifecycle (create/preview/modify/cancel/batch), RFQs/quotes/combos, and account/positions/activities/balances/incentives. Minor gaps remain around some alternate lookup keys and post-trade/order-history specifics, but core workflows are represented.

    Maintenance

    ActivityMaintained
    ResponsivenessOutdated data

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      D
      maintenance
      Enables users to search, analyze, and trade on Kalshi prediction markets directly through MCP-compatible clients. It supports portfolio management, market data retrieval, and limit order execution with production-grade authentication and rate limiting.
      22 PyPI
      1
      MIT
    • F
      license
      Not graded
      quality
      C
      maintenance
      Enables interaction with Polymarket prediction markets through read-only access to market data, events, orderbooks, and user positions, plus authenticated trading capabilities for creating and managing orders.
      1
      -
    • A
      license
      A
      quality
      C
      maintenance
      A read-only MCP server exposing Polymarket's public prediction-market data. Search markets, read live odds and order books, pull historical probability time-series, and inspect public wallet positions.
      14
      35 PyPI
      MIT