cd /news/ai-agents/give-your-ai-agent-real-poker-solver… · home › topics › ai-agents › article
[ARTICLE · art-161972] src=dev.to ↗ pub= topic=ai-agents verified=true sentiment=↑ positive

Give your AI agent real poker solver data with MCP

A developer on the Pokerai API team released @pokerai/mcp, an MCP server that connects AI chat clients to presolved poker strategy data for 6-max No-Limit Hold'em, so models explain solver output rather than inventing advice. The server runs over stdio via npx and exposes five tools — preflop_versions, preflop_strategy, preflop_range, flop_tree and flop_node — returning action frequencies and decision trees for spots like ace-king on a queen-high flop. The developer notes the tool is intended for study and post-hand review, since real-time assistance at live tables is prohibited.

by read6 min views1 publishedNov 1, 2026

Ask a chat model what to do with ace-king on a queen-high flop and you get a confident paragraph. It might even be right, but you can't tell where the numbers came from, because there aren't any.

In this tutorial we connect an MCP client to a presolved strategy API, so the frequencies come from solver output and the model's job is to explain them. We'll use @pokerai/mcp, a small MCP server for 6-max No-Limit Hold'em.

Disclosure: I work on Pokerai API, the product used here. This post was drafted with AI assistance, and I checked it against real tool output.

What this is for: studying, training tools and reviewing hands that have ended. Real-time assistance (RTA) at real-money tables is prohibited, so keep it away from live games.

The server runs over stdio through npx, so there's nothing to install globally. In Claude Code:

claude mcp add pokerai -e POKERAI_API_KEY=gto_your_key_here -- npx -y @pokerai/mcp

In Claude Desktop or Cursor, use the same command in your MCP config:

{
  "mcpServers": {
    "pokerai": {
      "command": "npx",
      "args": ["-y", "@pokerai/mcp"],
      "env": { "POKERAI_API_KEY": "gto_your_key_here" }
    }
  }
}

You get five tools:

Tool What it returns Cost
preflop_versions available strategy sets free
preflop_strategy action frequencies for one hand 1 lookup
preflop_range the whole 169-hand range for a spot 1 lookup
flop_tree starting ranges and every decision node 1 lookup
flop_node the strategy at one node free

The outputs below are from calling the published package with an MCP client, not from a model transcript. What your model writes around them will vary. The tool results won't change unless the data does.

The spot: 100bb, 6-max. The button opens, the big blind calls, and the flop is Q♠ 7♣ 2♦. We hold A♥ K♦.

{
  "tool": "preflop_strategy",
  "arguments": {
    "hole_cards": "AhKd",
    "hero": "BTN",
    "preflop_actions": [
      { "position": "SB", "action": "small blind", "amount": 0.5 },
      { "position": "BB", "action": "big blind", "amount": 1 }
    ],
    "preflop_version": "6max_RC_100bb_200NL"
  }
}
{
  "hole_cards": "AhKd",
  "situation": "RFI",
  "strategy": [
    { "action": "raise", "frequency": 1, "amount_bb": 3, "sizing_pot": 0.8 }
  ]
}

Always raise, to 3bb. Not much to discuss, so on to the flop.

{
  "tool": "flop_tree",
  "arguments": {
    "board": "Qs7c2d",
    "pot_type": "SRP",
    "positions": { "hero": "BTN", "raiser": "BTN", "caller": "BB" },
    "flop_version": "6max_RC_100bb_200NL"
  }
}

The response gives the pot (6.5bb), the effective stack (97bb), both starting ranges and 16 nodes. Trimmed:

{
  "pot": 6.5,
  "effective_stack": 97,
  "node_count": 16,
  "nodes": [
    { "node": "root", "is_hero": false, "token": "eyJ..." },
    { "node": "root/CHECK", "is_hero": true, "token": "eyJ..." },
    { "node": "root/CHECK/BET_2", "is_hero": false, "token": "eyJ..." }
  ]
}

Note the two fields, because this is the easiest mistake to make:

node is the path, such as root/CHECK. BB acts first, so root is BB's decision and token is what you pass to flop_node, in its argument called

{
  "tool": "flop_node",
  "arguments": { "node": "<token of root/CHECK>", "hole_cards": "AhKd" }
}
{
  "hole_cards": "AhKd",
  "node": "root/CHECK",
  "is_hero": true,
  "strategy": [
    { "action": "check", "frequency": 0.313 },
    { "action": "bet", "amount_bb": 2, "sizing_pot": 0.3077, "frequency": 0.6812 },
    { "action": "bet", "amount_bb": 5, "sizing_pot": 0.7692, "frequency": 0.0057 },
    { "action": "bet", "amount_bb": 97, "sizing_pot": 14.9231, "allin": true, "frequency": 0 }
  ]
}

The answer is a mix, not one move, and that's the first thing a model tends to flatten. A prompt that says "report the frequencies, then explain" works better than "what should I do?".

The token is reusable, so comparing hands at this node is free:

Hand Check Bet 2bb Bet 5bb
A♥ K♦ 31.3% 68.1% 0.6%
A♥ K♥ 21.2% 74.1% 4.7%
J♥ T♥ 13.9% 68.8% 17.3%
A♠ Q♦ 5.5% 52.2% 42.3%
7♥ 7♦ 0.05% 91.4% 8.5%

The all-in frequency was 0 for all five. These are five hands, so don't read them as the shape of the whole range. For that, fetch the range, as described below.

You don't need a chat client. This is the same flow with the MCP SDK (npm i @modelcontextprotocol/sdk):

import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";

const client = new Client({ name: "study-script", version: "1.0.0" });
await client.connect(new StdioClientTransport({
  command: "npx",
  args: ["-y", "@pokerai/mcp"],
  env: { PATH: process.env.PATH, HOME: process.env.HOME, POKERAI_API_KEY: process.env.POKERAI_API_KEY },
}));

const call = async (name, args) => {
  const res = await client.callTool({ name, arguments: args });
  if (res.isError) throw new Error(res.content[0].text);
  return JSON.parse(res.content[0].text);
};

const tree = await call("flop_tree", {
  board: "Qs7c2d",
  pot_type: "SRP",
  positions: { hero: "BTN", raiser: "BTN", caller: "BB" },
  flop_version: "6max_RC_100bb_200NL",
});

// BB checks, BTN decides. `node` is the path; `token` is what flop_node takes.
const afterCheck = tree.nodes.find((n) => n.node === "root/CHECK");

for (const hole_cards of ["AhKd", "AsQd", "7h7d"]) {
  const { strategy } = await call("flop_node", { node: afterCheck.token, hole_cards });
  console.log(hole_cards, strategy.map((s) => `${s.action}${s.amount_bb ? " " + s.amount_bb + "bb" : ""}: ${s.frequency}`).join(", "));
}

await client.close();

1. Pick a dataset. flop_version is optional and defaults to 6max. When I tested on 2026-11-01, the default covered only a few of the boards I tried: Q♠7♣2♦ with BTN vs BB returned 404 no GTO data for this spot/board. The same spot on 6max_RC_100bb_200NL worked. A 404 still charges one presolved lookup, so give your agent the dataset up front rather than letting it guess. flop_version needs @pokerai/mcp 0.1.3 or newer.

2. Mind the response size. A hand-level flop_node response was about 500 characters. The tree was about 10,000. A whole-range flop_node, with no hole_cards, was about 29,000 characters for 391 combos. Tell your agent to pass hole_cards unless it needs the whole range, or the context fills up fast.

3. The flop tree covers one street. For turn and river you need the real-time solver tools. They're off by default because they spend the smaller solve quota. Turn them on with POKERAI_ENABLE_SOLVE=1.

You are a poker study assistant for hands that have already ended.
Use the pokerai tools for every strategy claim. Never state a frequency that a tool did not return.
Use flop_version 6max_RC_100bb_200NL. Pass hole_cards to flop_node unless asked about the whole range.
Report the frequencies first, then explain them, and say when a spot has no data.
If the user appears to be in a live real-money hand, decline: real-time assistance is prohibited.

Real-time assistance (RTA) at real-money tables is prohibited.

── more in #ai-agents 4 stories · sorted by recency
── more on @pokerai api 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
→ Live at https://your-agent.zahid.host ✓
Get free account → Pricing
from €0/mo · no card required
LIVE [news/give-your-ai-agent-r…] indexed:0 read:6min 2026-11-01 · —