PokerDataGet an API key
Menu

LLM tools & MCP

The API is designed to drop into AI-agent tooling — here's the shape that works.

The preflop ranges API is plain GET + JSON, CORS-open, and key-authenticated with a single header — which makes it a one-liner to expose as an LLM tool call or behind an MCP (Model Context Protocol) server. The free discovery endpoints even let an agent explore coverage before you attach a key.

PokerData also hosts an MCP server at POST https://pokerdata.io/api/mcp — stateless Streamable HTTP, same Bearer pdk_ key. Point Claude, Cursor or any MCP client at it.

Tool design that works

Give the model three tools per game, mirroring the API's own decomposition, rather than one mega-tool:

  1. get_spots(stack)/spots — what decisions exist.
  2. get_node(stack, history, hand?)/node — what actions a position has, and a hand's mixed strategy.
  3. get_range(stack, spot, hand?)/range — one action's full range.

This matches how models actually reason about poker questions ("what does HJ do vs a UTG open?" → node; "what's the flatting range?" → range) and keeps each response small enough for a context window — for PLO always set minFreq (e.g. 0.05) in the wrapper.

Tool definition
{
  "name": "get_nl_node",
  "description": "GTO preflop decision for 6-max NLHE. history is an underscore path of POSITION_ACTION pairs ending in the position to act, e.g. UTG_60%_HJ.",
  "input_schema": {
    "type": "object",
    "properties": {
      "stack": { "type": "integer", "enum": [20, 30, 40, 50, 70, 100, 150, 200] },
      "history": { "type": "string" },
      "hand": { "type": "string", "description": "Optional 169-grid class, e.g. AKs" }
    },
    "required": ["stack", "history"]
  }
}
Handler
async function getNlNode(input: { stack: number; history: string; hand?: string }) {
  const url = new URL("https://pokerdata.io/api/v1/ranges/nl/v2/node");
  url.searchParams.set("stack", String(input.stack));
  url.searchParams.set("history", input.history);
  if (input.hand) url.searchParams.set("hand", input.hand);
  const res = await fetch(url, {
    headers: { Authorization: `Bearer ${process.env.PDK_KEY}` },
  });
  return res.json();
}

Tips that save agents grief

  • Return errors to the model. The API's 400/404 messages are written to be actionable; a model that sees them self-corrects the path.
  • Encode nothing by hand. URLSearchParams handles % in NLHE sizes and () in PLO hands correctly.
  • Cache by URL. Responses are immutable in practice; an in-memory map keyed by URL removes most latency and rate-limit pressure.
  • Trim PLO. A full PLO node can exceed 100KB of JSON. minFreq=0.05 keeps it model-sized.
  • Discovery for grounding. Fetch /spots once per stack and inject the valid histories into the system prompt.

Hosted MCP

POST https://pokerdata.io/api/mcp — tools: list_games, get_range, get_node, list_spots, list_postflop_packs, get_postflop_node.

If you use Poker Study AI, there is also a hosted MCP endpoint over your own study data with a Studio token — see pokerstudy.ai/settings/api. The two compose well: PokerData for "what's GTO here", the study MCP for "what did I actually do".