@parlayx/mcp
Model Context Protocol server for the ParlayX public API, a
single trading interface over aggregated prediction markets. It gives an MCP
client 17 read tools covering identity, the server clock, sports discovery,
orders, fills, positions and balances, and 4 trading tools that stay unregistered
unless you opt in.
Full guides, authentication and the API reference live at
docs.parlayx.com.
Requirements
Node.js 20 or newer, and a ParlayX API key. Requests are signed with Ed25519 via
node:crypto, so the server runs on a machine, not in a browser or an edge
runtime. The private key never leaves your machine and never travels on the
wire, only the signature does.
Configure your client
The server runs over stdio and reads its credentials from the client's env
block. Nothing is passed as a tool argument.
Claude Code:
claude mcp add --env PARLAYX_KEY_ID=your-key-id --env PARLAYX_PRIVATE_KEY_HEX=your-seed \
--transport stdio parlayx -- npx -y @parlayx/mcp
The -- separator is required, and at least one other option has to sit between
the last --env and the server name, or the CLI reads the name as another
env pair.
Claude Desktop, in
~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"parlayx": {
"command": "npx",
"args": ["-y", "@parlayx/mcp"],
"env": {
"PARLAYX_KEY_ID": "your-key-id",
"PARLAYX_PRIVATE_KEY_HEX": "your-seed"
}
}
}
}
Cursor, in .cursor/mcp.json, takes the same shape and additionally resolves
${env:NAME}, so the seed can stay in your shell environment instead of in a
file:
{
"mcpServers": {
"parlayx": {
"command": "npx",
"args": ["-y", "@parlayx/mcp"],
"env": {
"PARLAYX_KEY_ID": "${env:PARLAYX_KEY_ID}",
"PARLAYX_PRIVATE_KEY_HEX": "${env:PARLAYX_PRIVATE_KEY_HEX}"
}
}
}
}
Environment variables
PARLAYX_KEY_ID | yes | The key id issued with your signing keypair. |
PARLAYX_PRIVATE_KEY_HEX | yes | The Ed25519 private key seed, 64 lowercase hex characters. |
PARLAYX_MCP_ALLOW_TRADING | no | Set to 1 to register the trading tools. Off by default. |
Trading is off by default
The trading tools place real orders against real money. They register only
when both halves of the gate are satisfied: PARLAYX_MCP_ALLOW_TRADING=1 is set
in the client's env block, and the key itself carries the trade capability.
Without both, none of the *_submit_order, *_cancel_order or
limitless_replace_order* tools are advertised at all, so no model and no
auto-approval rule can reach them.
Both halves are resolved once at startup, so the tool list a client sees cannot
change under it mid-session. Leave the opt-in off unless you intend an agent to
trade, and keep a human in front of every order when you turn it on.
Tools
Read tools, always registered:
whoami | Identify the calling key, its pod, scope and capabilities |
get_time | Read the server clock in Unix seconds |
list_sports | List the sports on the discovery surface |
list_competitions | List competitions, optionally filtered to one sport |
list_events | List the events in a competition |
list_event_markets | List an event's markets, outcomes and per-venue listings |
lookup_market | Resolve one venue identifier to its canonical markets |
polymarket_list_orders | Page through Polymarket orders |
polymarket_get_order | Read one Polymarket order |
polymarket_get_order_fills | List the fills on one Polymarket order |
polymarket_list_positions | List open Polymarket positions |
polymarket_get_balance | Read the Polymarket balance |
kalshi_list_orders | Page through Kalshi orders |
kalshi_get_order | Read one Kalshi order |
kalshi_get_order_fills | List the fills on one Kalshi order |
kalshi_list_positions | List open Kalshi positions |
kalshi_get_balance | Read the Kalshi balance |
prophetx_list_orders | Page through ProphetX orders |
prophetx_get_order | Read one ProphetX order |
prophetx_get_order_fills | List the fills on one ProphetX order |
prophetx_list_positions | List open ProphetX positions |
prophetx_get_balance | Read the ProphetX balance |
prophetx_get_ladder | List every price ProphetX accepts |
limitless_list_markets | Page through the tradeable Limitless markets |
limitless_list_orders | Page through Limitless orders |
limitless_get_order | Read one Limitless order |
limitless_get_order_fills | List the fills on one Limitless order |
limitless_list_positions | List open Limitless positions |
limitless_get_balance | Read the Limitless balance |
Trading tools, registered only behind the opt-in above:
polymarket_submit_order | Place a Polymarket order |
polymarket_cancel_order | Cancel a Polymarket order |
kalshi_submit_order | Place a Kalshi order |
kalshi_cancel_order | Cancel a Kalshi order |
prophetx_submit_order | Place a ProphetX order |
prophetx_cancel_order | Cancel a ProphetX order |
limitless_submit_order | Place a Limitless order |
limitless_cancel_order | Cancel a Limitless order |
limitless_replace_order | Cancel a Limitless order and replace it |
limitless_replace_orders | Cancel several Limitless orders and replace them |
The order-list tools return one page and hand back a nextPageToken; pass it
back as pageToken to read the next one.
Listings report venue as POLYMARKET, KALSHI or PROPHETX, while the tools
that place orders are named polymarket_*, kalshi_* and prophetx_*. Read the
venue off the listing and pick the matching tool. Limitless markets are not
carried by the discovery surface; read them with limitless_list_markets.
Diagnostics
Everything the server logs goes to stderr, never to stdout, which belongs to the
protocol. Claude Desktop collects it in
~/Library/Logs/Claude/mcp-server-parlayx.log. Startup logs the server and SDK
versions, the key id, the pod and actor, and whether the trading tools
registered. Each call logs its tool name, duration and error code. Arguments,
response bodies and the private key are never logged, and the configured signing
key is replaced with [redacted] before anything is written.
If every call comes back unauthorized, check the host clock first: signed
requests are only valid within 30 seconds of the ParlayX server clock, and the
server tells you which of the two problems it is.
If the server never starts, the log names the reason:
- A missing or malformed credential names the variable it wanted.
- A rejected key, or a host clock too far from the server's, reports which of
the two it is.
startup identity check timed out after 10000ms means the ParlayX API did not
answer at all. Check network egress from the host; the process exits non-zero
rather than waiting for a handshake that will not come.
If the server starts and then goes quiet, a line beginning transport error
reports a failure on the stdio connection itself, which is otherwise invisible
to the client.
License
MIT. See LICENSE.