# PokerData (remote · pokerdata.io)

GTO poker solver data: NLHE/PLO preflop ranges, postflop strategy, EV. 6-max NL preflop free.

- Trust score: 81/100 (high trust)
- Registry status: active
- Liveness: live
- Owner verified: no
- Last scored: 2026-10-18

## Components

- remote · `pokerdata.io`: 81/100 (this document), [markdown](https://verifymcp.io/servers/hft-studio-pokerdata/api-mcp.md), [page](https://verifymcp.io/servers/hft-studio-pokerdata/api-mcp)
- npm · `pokerdata-mcp`: 39/100, [markdown](https://verifymcp.io/servers/hft-studio-pokerdata/pokerdata-mcp.md), [page](https://verifymcp.io/servers/hft-studio-pokerdata/pokerdata-mcp)

## Channel facts

- Endpoint: `https://pokerdata.io/api/mcp`
- Transports: `streamable-http`
- Auth: `required`
- Version: `1.0.4`

## Trust breakdown

How this component scores in each security and reliability category. Every signal is checked automatically against the live server, and we only credit what we can confirm. Scores are 0–100 per category. Scoring method: https://verifymcp.io/docs/scoring (what has changed: https://verifymcp.io/docs/scoring/changelog)

Scored 2026-10-18.

- **Endpoint Security**: 97/100
  - The endpoint's TLS certificate is valid, in date, and uses a strong key.
  - Authorisation is enforced on tool calls, advertised via RFC 9728 protected-resource metadata. Discovery is public, which costs nothing: no tool can be invoked without a token.
  - HTTPS is enforced; there's no plaintext access path.
  - The HSTS (Strict-Transport-Security) header is present.
  - DNSSEC check failed: this domain isn't protected by DNSSEC.
  - The authorisation server supports Client ID Metadata Documents, the current MCP client-registration mechanism.
- **Transport & Reachability**: 100/100
  - Verified streamable-http transport via a live MCP handshake.
- **Schema Quality & AI Usability**: 75/100
  - 100% of prompts and resources have a non-trivial description (not blank, and not just the item's name).
  - AI-judged instruction clarity (good).
  - Context-footprint check failed: tool/resource definitions use about 6309 tokens (~210/item across 30 items; 29 tools + 1 resources), over budget; trim descriptions and params.
  - Usage-examples check failed: none of the tools include examples.
- **Stability & Change Management**: 7/100
  - Stability observed for 2 of 30 days with no destabilising changes; credit accrues until the full window elapses.
- **Tool Coverage**: 100/100
  - 100% of tools have a non-trivial description (not blank, and not just the tool's name).
  - 100% of tool parameters carry a description.
  - Structured output schemas are declared (100% of tools); any adoption earns full credit.
- **Tool Safety**: 100/100
  - No prompt-injection markers were found in the server instructions, tool names or descriptions we captured.
  - We read all 29 captured tool definition(s), and no name or description among them implies an irreversible operation.
  - An AI judge read all 31 captured unit(s) of tool text and found none that tries to manipulate the model reading it.
- **Capabilities**: 100/100
  - Implements a supported MCP spec version (2025-11-25); the latest is 2026-07-28.

## Install

### How do I install the PokerData MCP server?

PokerData is a hosted endpoint at https://pokerdata.io/api/mcp, so there is nothing to install locally. Ready-made configuration for Claude, Cursor, VS Code, Codex and 5 more is on this page, copied from each client's own documentation.

### Claude

```bash
claude mcp add --transport http hft-studio-pokerdata 'https://pokerdata.io/api/mcp'
```

### Cursor

```json
{
  "mcpServers": {
    "hft-studio-pokerdata": {
      "url": "https://pokerdata.io/api/mcp"
    }
  }
}
```

### VS Code

```json
{
  "servers": {
    "hft-studio-pokerdata": {
      "type": "http",
      "url": "https://pokerdata.io/api/mcp"
    }
  }
}
```

### Codex

```toml
[mcp_servers.hft-studio-pokerdata]
url = "https://pokerdata.io/api/mcp"
```

### opencode

```json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "hft-studio-pokerdata": {
      "type": "remote",
      "url": "https://pokerdata.io/api/mcp",
      "enabled": true
    }
  }
}
```

### OpenClaw

```bash
openclaw mcp add hft-studio-pokerdata --url 'https://pokerdata.io/api/mcp' --transport streamable-http
```

### Hermes

```yaml
mcp_servers:
  hft-studio-pokerdata:
    url: "https://pokerdata.io/api/mcp"
```

### Netclaw

```json
{
  "McpServers": {
    "hft-studio-pokerdata": {
      "Transport": "http",
      "Url": "https://pokerdata.io/api/mcp"
    }
  }
}
```

### Vellum

```bash
assistant mcp add hft-studio-pokerdata -t streamable-http -u 'https://pokerdata.io/api/mcp'
```

### Other

```json
{
  "mcpServers": {
    "hft-studio-pokerdata": {
      "type": "http",
      "url": "https://pokerdata.io/api/mcp"
    }
  }
}
```

The mcpServers block is a cross-client convention. Remote transports vary, so check your client's docs.

## Changelog

Every change recorded for this component, newest first. Days that predate change tracking, or that we cannot explain, say so: "we were watching and nothing happened" and "we were not watching" are different claims.

### 2026-10-18 (score 81, +7)

- [security improvement] Authorization: partial → pass
- [security] First check of Authorization: pass
- [security] The server rewrote its instructions, which are the text every model session reads
- [security] Tool “upload_hand_history” is now declared destructive
- [security] Tool “enqueue_solve” is now declared destructive

### 2026-10-17 (score 74, +9)

- [security improvement] Authorization: unverified → partial
- [security] Tool “get_session_summary” rewrote its description, which is the text the model reads
- [functional regression] Schema quality: 180 → 210
- [functional improvement] Tool coverage: 54% → 100%
- [functional improvement] Stability: unverified → 0.03
- [functional improvement] Tool “explain_combo” now declares an output schema
- [functional improvement] Tool “find_hands” now declares an output schema
- [functional improvement] Tool “get_board_report” now declares an output schema
- [functional improvement] Tool “get_config” now declares an output schema
- [functional improvement] Tool “get_exploitability” now declares an output schema
- [functional improvement] Tool “get_hand_results” now declares an output schema
- [functional improvement] Tool “get_node” now declares an output schema
- [functional improvement] Tool “get_opponent_limp_range” now declares an output schema
- [functional improvement] Tool “get_opponent_notes” now declares an output schema
- [functional improvement] Tool “get_postflop_node” now declares an output schema
- [functional improvement] Tool “get_postflop_range” now declares an output schema
- [functional improvement] Tool “get_queued_solve” now declares an output schema
- [functional improvement] Tool “get_range” now declares an output schema
- [functional improvement] Tool “get_range_metadata” now declares an output schema
- [functional improvement] Tool “get_session_summary” now declares an output schema
- [functional improvement] Tool “get_tournament_results” now declares an output schema
- [functional improvement] Tool “get_tree_docs” now declares an output schema
- [functional improvement] Tool “get_upload_link” now declares an output schema
- [functional improvement] Tool “list_datasets” now declares an output schema
- [functional improvement] Tool “list_games” now declares an output schema
- [functional improvement] Tool “list_library_solutions” now declares an output schema
- [functional improvement] Tool “list_my_opponents” now declares an output schema
- [functional improvement] Tool “list_my_sessions” now declares an output schema
- [functional improvement] Tool “list_postflop_packs” now declares an output schema
- [functional improvement] Tool “list_queued_solves” now declares an output schema
- [functional improvement] Tool “list_spots” now declares an output schema
- [functional improvement] Tool “upload_hand_history” now declares an output schema
- [functional improvement] Tool “compare_strategies” now declares an output schema
- [functional improvement] Tool “enqueue_solve” now declares an output schema
- [functional] First check of Tool coverage: 100
- [cosmetic] “enqueue_solve” reworded the description of “pot”
- [cosmetic] “enqueue_solve” reworded the description of “tags”
- [cosmetic] “enqueue_solve” reworded the description of “title”
- [cosmetic] “find_hands” reworded the description of “filter”
- [cosmetic] “find_hands” reworded the description of “game_type”
- [cosmetic] “find_hands” reworded the description of “gto_plo5_rfi_bucket”
- [cosmetic] “find_hands” reworded the description of “gto_vs_3bet_bucket”
- [cosmetic] “find_hands” reworded the description of “limit”
- [cosmetic] “find_hands” reworded the description of “session_id”
- [cosmetic] “find_hands” reworded the description of “sort”
- [cosmetic] “find_hands” reworded the description of “table_size”
- [cosmetic] “get_board_report” reworded the description of “filters”
- [cosmetic] “get_exploitability” reworded the description of “game”
- [cosmetic] “get_hand_results” reworded the description of “max_points”
- [cosmetic] “get_hand_results” reworded the description of “session_id”
- [cosmetic] “get_opponent_limp_range” reworded the description of “game_type”
- [cosmetic] “get_opponent_limp_range” reworded the description of “limit”
- [cosmetic] “get_opponent_limp_range” reworded the description of “opponent_id”
- [cosmetic] “get_opponent_limp_range” reworded the description of “position”
- [cosmetic] “get_opponent_limp_range” reworded the description of “session_id”
- [cosmetic] “get_opponent_limp_range” reworded the description of “table_size”
- [cosmetic] “get_opponent_notes” reworded the description of “opponent_id”
- [cosmetic] “get_postflop_range” reworded the description of “hand”
- [cosmetic] “get_postflop_range” reworded the description of “minFreq”
- [cosmetic] “get_postflop_range” reworded the description of “tree”
- [cosmetic] “get_queued_solve” reworded the description of “queue_id”
- [cosmetic] “get_range_metadata” reworded the description of “game”
- [cosmetic] “get_range_metadata” reworded the description of “stack”
- [cosmetic] “get_session_summary” reworded the description of “session_id”
- [cosmetic] “get_tournament_results” reworded the description of “limit”
- [cosmetic] “list_library_solutions” reworded the description of “limit”
- [cosmetic] “list_my_opponents” reworded the description of “game_type”
- [cosmetic] “list_my_opponents” reworded the description of “hero”
- [cosmetic] “list_my_opponents” reworded the description of “min_hands”
- [cosmetic] “list_my_opponents” reworded the description of “name”
- [cosmetic] “list_my_opponents” reworded the description of “sort”
- [cosmetic] “list_my_sessions” reworded the description of “game_type”
- [cosmetic] “list_my_sessions” reworded the description of “limit”
- [cosmetic] “list_queued_solves” reworded the description of “limit”
- [cosmetic] “upload_hand_history” reworded the description of “filename”
- [cosmetic] “list_my_opponents” reworded the description of “limit”
- [cosmetic] “compare_strategies” reworded the description of “baseline”
- [cosmetic] “compare_strategies” reworded the description of “comparison”
- [cosmetic] “enqueue_solve” reworded the description of “add_allin”
- [cosmetic] “enqueue_solve” reworded the description of “bet_sizes”
- [cosmetic] “enqueue_solve” reworded the description of “board”
- [cosmetic] “enqueue_solve” reworded the description of “effective_stack”
- [cosmetic] “enqueue_solve” reworded the description of “ip_range”
- [cosmetic] “enqueue_solve” reworded the description of “iterations”
- [cosmetic] “enqueue_solve” reworded the description of “max_aggressions”
- [cosmetic] “enqueue_solve” reworded the description of “oop_range”
- [cosmetic] Tool “explain_combo” changed its title: Explain a postflop combo
- [cosmetic] Tool “find_hands” changed its title: Find my hands
- [cosmetic] Tool “get_board_report” changed its title: Report on board textures
- [cosmetic] Tool “get_config” changed its title: Get table configuration
- [cosmetic] Tool “get_exploitability” changed its title: Get preflop exploitability
- [cosmetic] Tool “get_hand_results” changed its title: Get my results curve
- [cosmetic] Tool “get_node” changed its title: Get preflop decision node
- [cosmetic] Tool “get_opponent_limp_range” changed its title: Get an opponent's limp range
- [cosmetic] Tool “get_opponent_notes” changed its title: Get opponent notes
- [cosmetic] Tool “get_postflop_node” changed its title: Get postflop solver node
- [cosmetic] Tool “get_postflop_range” changed its title: Get postflop action range
- [cosmetic] Tool “get_queued_solve” changed its title: Get a queued solve
- [cosmetic] Tool “get_range” changed its title: Get preflop range
- [cosmetic] Tool “get_range_metadata” changed its title: Get range index metadata
- [cosmetic] Tool “get_session_summary” changed its title: Summarize a session
- [cosmetic] Tool “get_tournament_results” changed its title: Get my tournament results
- [cosmetic] Tool “get_tree_docs” changed its title: Get tree documentation
- [cosmetic] Tool “get_upload_link” changed its title: Get the hand-upload link
- [cosmetic] Tool “list_datasets” changed its title: List solved datasets
- [cosmetic] Tool “list_games” changed its title: List covered games
- [cosmetic] Tool “list_library_solutions” changed its title: List my saved solutions
- [cosmetic] Tool “list_my_opponents” changed its title: List my opponents
- [cosmetic] Tool “list_my_sessions” changed its title: List my sessions
- [cosmetic] Tool “list_postflop_packs” changed its title: List postflop packs
- [cosmetic] Tool “list_queued_solves” changed its title: List my queued solves
- [cosmetic] Tool “list_spots” changed its title: Search preflop spots
- [cosmetic] Tool “upload_hand_history” changed its title: Upload a hand history
- [cosmetic] Tool “compare_strategies” changed its title: Compare two strategies
- [cosmetic] Tool “enqueue_solve” changed its title: Record a solve request

### 2026-10-16 (score 65)

First indexed and scored.

## MCP tools (29)

### `list_games` (~294 tokens)

List covered games

Discover covered stack depths and positions. Call this before low-level preflop queries. "nl" = no-limit hold'em 6-max cash (169-grid hands, per-hand EV in small blinds), "nl9" = no-limit hold'em 9-max cash, "nlmtt8" = no-limit hold'em 8-max MTT chip-EV (10–300bb, 1bb BB-ante; Fold/Call/Limp/AI/Open/3B tokens), "nlh8-hydra" = no-limit hold'em 8-max MTT chip-EV with a classic 0.1bb ante from every seat (10, 20, 30, 60bb; same tokens as nlmtt8), "plo" = pot-limit Omaha 6-max cash (4-card), "plo5" = pot-limit Omaha 5-card 6-max (100bb, 1.2bb ante), "plo9" = pot-limit Omaha 9-max cash, "plo6hu" = 6-card Omaha heads-up (BTN vs BB, 100bb). Cash trees are not tournament, ICM, PKO, or satellite solves. nlmtt8 is chip-EV only.

Input parameters:

- `detail` (string): Response detail. "compact" is the default and removes bulk maps; use "full" only when exact complete data is required.

Output parameters:

- `_coverage` (object): Formats and objectives this server does and does not answer.

### `get_range` (~497 tokens)

Get preflop range

The GTO range for one spot. `spot` is an action path of POSITION_ACTION pairs ending in the action whose range you want, e.g. NLHE cash "UTG_60%_HJ_Call", nlmtt8 "UTG_Open", or PLO "UTG_Open_HJ_3B". Add `hand` for one exact frequency and EV. Compact mode is default; PLO returns representative pure/mixed hands unless a hand is specified; plo5 returns the top hands by EV that take the action (limit up to 500 compact, 2000 full).

Input parameters:

- `detail` (string): Response detail. "compact" is the default and removes bulk maps; use "full" only when exact complete data is required.
- `game` (string, required): "nl" = no-limit hold'em 6-max cash (169-grid hands, per-hand EV in small blinds), "nl9" = no-limit hold'em 9-max cash, "nlmtt8" = no-limit hold'em 8-max MTT chip-EV (10–300bb, 1bb BB-ante; Fold/Call/…
- `hand` (string): Optional hand/class, e.g. AKs or (KA)(KA)
- `limit` (number): Maximum compact rows to return (default 120, maximum 500).
- `minFreq` (number): Drop hands at or below this weight (PLO ranges are large)
- `spot` (string, required): Action path ending in an action
- `stack` (number, required): Stack depth in big blinds, e.g. 100

Output parameters:

- `action` (string): plo5: the action the range belongs to.
- `actor` (string): Position to act at this node.
- `columns` (array): Column order for `range`: hand, frequency, evSb.
- `combos` (number): Combos in the range.
- `ev` (number|null): Full detail: EV of the requested hand in small blinds.
- `evSb` (number|null): EV of the requested hand in small blinds.
- `evs` (object): Hand class to EV, only where the solved bundle scored the hand.
- `freq` (number): Full detail: frequency of the requested hand.
- `frequency` (number): Frequency of the requested hand, 0 to 1.
- `game` (string): Preflop game id, e.g. "nl" or "nlmtt8".
- `hand` (string): The requested hand, when one was asked for.
- `hands` (number): Hand classes in the range.
- `hint` (string): How to narrow, page, or widen the same query.
- `history` (string): Action path ending in the acting position.
- `kind` (string): plo5: the action family.
- `range` (array): Compact rows in `columns` order.
- `spot` (string): Action path ending in an action, echoed from the request.
- `stack` (number): Stack depth in big blinds.
- `summary` (object): What the compact range left out, so nothing looks complete when it is sampled.
- `version` (number): Dataset version where the bundle publishes one.
- `weights` (object): Hand class to frequency. An omitted class has weight 0.

### `get_node` (~504 tokens)

Get preflop decision node

Actions available at a decision node. `history` is an action path ending in the position about to act, e.g. "UTG_60%_HJ". sizeBb is the raise-to in big blinds and sizePctPot is the percent of the pot after calling (nlmtt8 40bb Open 40034 is 2.19bb; the pack label is 2.2x). evs are small blinds relative to fold. Compact mode returns action totals; add `hand` for its exact mixed strategy. full=true is full=1: all 169 hold'em hands with explicit 0, and no invented EVs.

Input parameters:

- `detail` (string): Response detail. "compact" is the default and removes bulk maps; use "full" only when exact complete data is required.
- `full` (boolean): Hold'em only. When true, each action includes all 169 hands with weight 0 where the bundle omitted the hand. EVs stay only where the bundle scored them.
- `game` (string, required): "nl" = no-limit hold'em 6-max cash (169-grid hands, per-hand EV in small blinds), "nl9" = no-limit hold'em 9-max cash, "nlmtt8" = no-limit hold'em 8-max MTT chip-EV (10–300bb, 1bb BB-ante; Fold/Call/…
- `hand` (string): Optional hand/class
- `history` (string, required): Action path ending in a position
- `minFreq` (number): Trim per-action ranges
- `stack` (number, required): Stack depth in big blinds

Output parameters:

- `actions` (array): Actions at the node.
- `actor` (string): Position to act at this node.
- `continuingCombos` (number): Combos that continue past this node.
- `continuingHands` (number): Hand classes that continue past this node.
- `evBaseline` (string): What EV is measured against, "fold".
- `evUnit` (string): EV unit, "sb".
- `game` (string): Preflop game id, e.g. "nl" or "nlmtt8".
- `hand` (string): The requested hand, when one was asked for.
- `hint` (string): How to narrow, page, or widen the same query.
- `history` (string): Action path ending in the acting position.
- `schemaVersion` (number): Payload version, 1.
- `spot` (string): Action path ending in an action, echoed from the request.
- `stack` (number): Stack depth in big blinds.
- `units` (object): Unit labels: stack and sizeBb in bb, evs in sb.
- `version` (number): Dataset version where the bundle publishes one.

### `get_config` (~452 tokens)

Get table configuration

Table for one preflop game and stack, in big blinds: seats, stacks, blinds (sb 0.5, bb 1), ante, antePostedBy, stackIncludesAnte, openSizes (first-in raise-to), evUnit, evBaseline. Convergence is not published. stackIncludesAnte is true: the named depth is the starting stack and the 1bb BB ante is posted from it. openSizes at 40bb is open 2.2x (listing 2.2bb; node decodes code 40034 to 2.19bb) and SB 2.8x (2.8bb). 10bb is all-in/fold versus 50bb stacks, so stacks is null there. evs on nodes are small blinds relative to fold. Example: get_config({ game: "nlmtt8", stack: 40 }).

Input parameters:

- `game` (string, required): "nl" = no-limit hold'em 6-max cash (169-grid hands, per-hand EV in small blinds), "nl9" = no-limit hold'em 9-max cash, "nlmtt8" = no-limit hold'em 8-max MTT chip-EV (10–300bb, 1bb BB-ante; Fold/Call/…
- `stack` (number, required): Stack depth in big blinds, e.g. 40

Output parameters:

- `ante` (number): Ante in big blinds.
- `antePostedBy` (string|null): Seat that posts the ante.
- `blinds` (object): Blinds in big blinds.
- `evBaseline` (string): What EV is measured against, "fold".
- `evUnit` (string): EV unit, "sb".
- `game` (string): Game id.
- `openSizes` (object): First-in raise-to sizes, by seat, with label and sizeBb.
- `schemaVersion` (number): Payload version, 1.
- `seats` (array): Seats in action order.
- `stack` (number): Stack depth in big blinds.
- `stackIncludesAnte` (boolean): True when the named depth already contains the ante.
- `stacks` (array|null): Starting stacks per seat. Null where the depth is solved against a different stack (10bb all-in/fold versus 50bb).
- `units` (object): Unit labels for stack, stacks, blinds, ante, openSizes, and evs.

### `list_spots` (~426 tokens)

Search preflop spots

Search valid decision nodes for a stack depth, tagged by depth (1 = RFI, 2 = vs open, 3 = 3-bet pots, …). Compact mode is paginated; use depth, contains, and offset to narrow results without loading thousands of paths. plo9 has no spot index: walk it with get_node from history "UTG".

Input parameters:

- `contains` (string): Optional case-insensitive history substring filter
- `depth` (number): Optional decision depth filter
- `detail` (string): Response detail. "compact" is the default and removes bulk maps; use "full" only when exact complete data is required.
- `game` (string, required): "nl" = no-limit hold'em 6-max cash (169-grid hands, per-hand EV in small blinds), "nl9" = no-limit hold'em 9-max cash, "nlmtt8" = no-limit hold'em 8-max MTT chip-EV (10–300bb, 1bb BB-ante; Fold/Call/…
- `limit` (number): Maximum compact rows to return (default 120, maximum 500).
- `offset` (number): Compact pagination offset
- `stack` (number, required): Stack depth in big blinds

Output parameters:

- `game` (string): Game id.
- `hint` (string): How to narrow, page, or widen the same query.
- `matched` (integer): Spots left after the depth and contains filters.
- `nextOffset` (integer|null): Offset for the next page, or null at the end.
- `offset` (integer): Offset this page started at.
- `returned` (integer): Spots in this page.
- `spots` (array): This page of decision nodes.
- `stack` (number): Stack depth in big blinds.
- `total` (integer): Spots in the dataset for this stack.

### `list_postflop_packs` (~317 tokens)

List postflop packs

Every solved postflop pack: preflop line, positions (OOP vs IP), stack, pot, the bet-size trees it is solved under, and the solved boards. Boards use the spaced form ("3h 3d 2s"). NLHE packs list `sizingTrees`: "75" (75% pot every street, the pack id itself) and "33" (33% pot on the flop, then 75%, under the `<pack>-flop33` id); every postflop tool accepts either tree's packId. PLO5 packs (ids starting plo5-) solve one 33% flop tree, flop decisions only. Compact output lists board names per pack. Pass `pack` (the 75% id or the -flop33 id) for that tree's per-board detail and per-flop exploitability where the index publishes a number. Missing exploitability is omitted, never estimated. Pass `variant` to list only NLHE or PLO5 packs. Call this before get_postflop_node.

Input parameters:

- `detail` (string): Response detail. "compact" is the default and removes bulk maps; use "full" only when exact complete data is required.
- `pack` (string): One pack id (75% id or the -flop33 id): per-board detail and that tree's exploitability
- `variant` (string): Only packs of this game: nlhe (hold'em) or plo5 (five-card Omaha)

Output parameters:

- `hint` (string): How to narrow, page, or widen the same query.
- `packs` (array): Packs matching `variant` and `pack`.

### `get_postflop_node` (~266 tokens)

Get postflop solver node

One postflop solver node: the acting player's strategy for every hand class, the legal next segments, board, reach and the reach-weighted action split. Walk deeper by appending a returned childSegment (an action like "Bet 5.5" or a runout like "deal:7c") to `path`.

Input parameters:

- `board` (string, required): Board in spaced form, e.g. "3h 3d 2s"
- `combo` (string): Optional exact combo, e.g. AsKh (PLO5: five cards, as listed in the node's hands)
- `detail` (string): Response detail. "compact" is the default and removes bulk maps; use "full" only when exact complete data is required.
- `limit` (number): Maximum representative compact combos (default 40, maximum 200)
- `pack` (string, required): Pack id from list_postflop_packs. Use a sizingTrees packId to pick the tree: the pack id for 75% pot on the flop, or "<pack>-flop33" for 33%.
- `path` (array): Segments from the root, e.g. ["Check", "Bet 5.5"]. Empty for the root node.

Output parameters:

- `actingPlayer` (integer|null): 0 for out of position, 1 for in position.
- `actionFreqs` (array): Full detail: aggregate frequency per action.
- `actions` (array): Actions at the node with their reach-weighted frequency.
- `board`: Board at this node.
- `childSegments` (array): Append one of these to `path` to walk deeper.
- `columns` (array): Column order for `hands`: combo, reach, frequencies, evBb, evLossBb, actionEvBb.
- `combo` (string): The requested combo, when one was asked for.
- `hands` (array): Compact rows in `columns` order, or the full per-combo strategy objects in full detail.
- `hint` (string): How to narrow, page, or widen the same query.
- `node` (object|null): Full detail: the stored node. Null at a chance point, where runouts hang directly under the path.
- `path` (array|null): Segments walked from the root to this node.
- `potBb` (number|null): Pot at this node in big blinds.
- `reach` (array): Full detail: the acting player's per-combo reach.
- `summary` (object): What the compact range left out, so nothing looks complete when it is sampled.

### `explain_combo` (~336 tokens)

Explain a postflop combo

Preferred tool for exact NLHE postflop hand questions. Returns a canonical context, exact action mix, action EV/loss when available, made-hand and draw classification, blocker facts, and same-rank-class suit comparisons. The server computes evidence; the agent should phrase causality as interpretation.

Input parameters:

- `anteBb` (number): Requested ante in bb. nlmtt8 models a 1bb BB-ante; other positive antes return unsupported coverage.
- `board` (string, required): Board in spaced form, e.g. "6s 4h 2s"
- `combo` (string, required): Required exact two-card combo, e.g. As5s
- `comparisonLimit` (number): Maximum same-rank-class suit comparisons (default 6, maximum 12)
- `format` (string): Requested poker format. "cash" uses the cash trees. "mtt" is supported only for preflop chip-EV against game nlmtt8; ICM, PKO, and satellite remain unsupported.
- `objective` (string): Requested optimization objective. chip_ev is supported for nlmtt8 preflop. ICM, PKO, and satellite return unsupported coverage.
- `pack` (string, required): Pack id from list_postflop_packs. Use a sizingTrees packId to pick the tree: the pack id for 75% pot on the flop, or "<pack>-flop33" for 33%.
- `path` (array): Exact childSegment path from get_postflop_node, e.g. ["Check", "Bet 5.5"]. Empty for the root.

Output parameters:

- `context` (object|null): Canonical context the answer belongs to (variant, format, stacks, positions, board, path). Null when the request is unsupported.
- `coverage` (object): Whether the request was answered exactly, aggregated, or refused as out of coverage.
- `result` (object|null): Recommendation, made-hand and draw classification, blockers, the exact action mix with EV, and same-rank-class suit comparisons. Null when the request is unsupported.
- `schemaVersion` (string): Envelope version, currently "1.0".
- `warnings` (array): Caveats that must survive into any answer built on this result.

### `get_board_report` (~314 tokens)

Report on board textures

Preferred tool for board-texture heuristics. Aggregates action frequencies and range/action composition across solved boards in one postflop pack. Results explicitly report sample breadth and use equal weight per board.

Input parameters:

- `anteBb` (number): Requested ante in bb. nlmtt8 models a 1bb BB-ante; other positive antes return unsupported coverage.
- `boardLimit` (number): Maximum matching boards to analyze (default and maximum 50)
- `filters` (object): Texture filters applied to the pack's solved boards. All optional; omit for every board.
- `format` (string): Requested poker format. "cash" uses the cash trees. "mtt" is supported only for preflop chip-EV against game nlmtt8; ICM, PKO, and satellite remain unsupported.
- `objective` (string): Requested optimization objective. chip_ev is supported for nlmtt8 preflop. ICM, PKO, and satellite return unsupported coverage.
- `pack` (string, required): Pack id from list_postflop_packs. Use a sizingTrees packId to pick the tree: the pack id for 75% pot on the flop, or "<pack>-flop33" for 33%.
- `path` (array): Exact childSegment path from get_postflop_node, e.g. ["Check", "Bet 5.5"]. Empty for the root.
- `representativeLimit` (number): Maximum representative boards returned (default 12, maximum 20)

Output parameters:

- `context` (object|null): Canonical context the answer belongs to (variant, format, stacks, positions, board, path). Null when the request is unsupported.
- `coverage` (object): Whether the request was answered exactly, aggregated, or refused as out of coverage.
- `result` (object|null): Action frequencies and range composition aggregated across solved boards, with equal weight per board, plus representative boards. Null when the request is unsupported.
- `schemaVersion` (string): Envelope version, currently "1.0".
- `warnings` (array): Caveats that must survive into any answer built on this result.

### `compare_strategies` (~324 tokens)

Compare two strategies

Preferred tool for differences between two preflop or postflop contexts. The server fetches both strategies and returns action-frequency/EV deltas plus the largest postflop combo changes, avoiding two large node payloads.

Input parameters:

- `anteBb` (number): Requested ante in bb. nlmtt8 models a 1bb BB-ante; other positive antes return unsupported coverage.
- `baseline` (object, required): The context deltas are measured from. One side of the comparison. Preflop contexts use game, stack, history and optional hand; postflop contexts use pack, board, path and optional combo.
- `comboLimit` (number): Maximum largest-changing combos for aggregate postflop comparisons (default 12, maximum 50)
- `comparison` (object, required): The context deltas are measured to. One side of the comparison. Preflop contexts use game, stack, history and optional hand; postflop contexts use pack, board, path and optional combo.
- `domain` (string, required): Preflop contexts use game/stack/history/hand. Postflop contexts use pack/board/path/combo.
- `format` (string): Requested poker format. "cash" uses the cash trees. "mtt" is supported only for preflop chip-EV against game nlmtt8; ICM, PKO, and satellite remain unsupported.
- `objective` (string): Requested optimization objective. chip_ev is supported for nlmtt8 preflop. ICM, PKO, and satellite return unsupported coverage.

Output parameters:

- `context` (object|null): Canonical context the answer belongs to (variant, format, stacks, positions, board, path). Null when the request is unsupported.
- `coverage` (object): Whether the request was answered exactly, aggregated, or refused as out of coverage.
- `result` (object|null): Both snapshots, the per-action frequency and EV deltas, and the largest combo changes for postflop comparisons. Null when the request is unsupported.
- `schemaVersion` (string): Envelope version, currently "1.0".
- `warnings` (array): Caveats that must survive into any answer built on this result.

### `list_datasets` (~40 tokens)

List solved datasets

List preflop datasets in the shipped tree documentation (stacks, positions, whether each bundle was analyzed). Preflop exploitability is not available.

Output parameters:

- `datasets` (array): Documented datasets.
- `generated` (string): Date the documentation was generated.
- `preflopExploitability` (string): Always "not available": no preflop dataset publishes it.
- `readme` (string): How to read one dataset's write-up.
- `source` (string): Where the documentation came from, "data/tree-docs".

### `get_tree_docs` (~88 tokens)

Get tree documentation

Tree documentation for one dataset: coverage note from the shipped README and per-stack bundle or node counts from the shipped index. Does not read or modify range bytes.

Input parameters:

- `dataset` (string, required): Dataset id from list_datasets, e.g. "nl/v2", "nl9", "nlmtt8", "plo", "plo9", "plo5", "plo6hu".

Output parameters:

- `coverage` (string): Coverage row from the shipped README.
- `dataset` (string): Dataset id, echoed.
- `error` (string): Present instead of a payload when the request named something that does not exist. No figure is estimated in its place.
- `preflopExploitability` (string): Always "not available".
- `source` (string): File the coverage note came from.
- `stacks` (array): Per-stack counts.

### `get_range_metadata` (~159 tokens)

Get range index metadata

Index metadata for one preflop game, stack, and path: bundle stats for hold'em/PLO bundles, or the matching node row for plo5 and plo6hu. Does not return a strategy and does not invent exploitability.

Input parameters:

- `game` (string, required): Preflop game id, e.g. "nl", "nl9", "nlmtt8", "nlh8-hydra", "plo", "plo9", "plo5", "plo6hu".
- `path` (string, required): Action path, e.g. UTG_Open or LJ_Fold. Use (root) or empty for the plo5 root.
- `stack` (number, required): Stack depth in big blinds, e.g. 100.

Output parameters:

- `actor` (string|null): Acting position read off the path.
- `dataset` (string): Dataset the game maps to.
- `error` (string): Present instead of a payload when the request named something that does not exist. No figure is estimated in its place.
- `game` (string): Game id, echoed.
- `match` (string): "bundle", "node", or "none".
- `note` (string): What the match means, or that nothing was estimated.
- `path` (string): Action path, echoed.
- `preflopExploitability` (string): Always "not available".
- `rows` (array): Matching index rows.
- `stack` (number): Stack depth in big blinds, echoed.

### `get_exploitability` (~84 tokens)

Get preflop exploitability

Preflop exploitability for a game. No preflop dataset publishes exploitability, convergence, or iteration counts. The answer is not available; this tool never fills in a number.

Input parameters:

- `game` (string, required): Preflop game id to report on, e.g. "nl" or "nlmtt8". Any known game answers "not available".

Output parameters:

- `available` (boolean): Always false.
- `convergence` (number|null): Always null.
- `dataset` (string|null): Dataset the game maps to, or null when unknown.
- `exploitability` (number|null): Always null: no figure is published or estimated.
- `game` (string): Game id, echoed.
- `iterations` (number|null): Always null.
- `reason` (string): Why no number is returned.
- `status` (string): Always "not available".

### `get_postflop_range` (~333 tokens)

Get postflop action range

The range a player takes one flop action with, from a solved pack: hand-class weights ("AA:1,AKs:0.42,...", same format as the preflop ranges) after every earlier flop action on the path. `path` ends in the action whose range you want, e.g. ["Check", "Bet 1.8", "Call 1.8"] for the check-call range. Bet-size tree. "33" = 33% pot on the flop, then 75% pot on the turn and river, plus all-in. "75" = 75% pot on every street, plus all-in. Compact and full detail apply to the other range tools; this returns the action range itself.

Input parameters:

- `board` (string, required): Flop, e.g. "3h 3d 2s"
- `hand` (string): Optional exact combo (AsKh) or hand class (AKs) for one frequency instead of reading the whole range.
- `minFreq` (number): Drop classes at or below this weight. Default 0.
- `pack` (string, required): Pack id from list_postflop_packs
- `path` (array, required): Flop actions ending in the action whose range you want
- `tree` (string, required): Bet-size tree. "33" = 33% pot on the flop, then 75% pot on the turn and river, plus all-in. "75" = 75% pot on every street, plus all-in. PLO5 packs are solved on "33" only.

Output parameters:

- `action` (string): The action whose range this is.
- `board` (string): Canonical board as stored in the pack.
- `error` (string): Present instead of a payload when the request named something that does not exist. No figure is estimated in its place.
- `hand` (object): The requested hand, when one was asked for.
- `pack` (string): Pack id the range was read from, after tree resolution.
- `path` (array): Flop actions, ending in the action asked for.
- `range` (string): Hand-class weights as "AA:1,AKs:0.42,…", the preflop range format.
- `summary` (object): What the compact range left out, so nothing looks complete when it is sampled.
- `tree` (string): Bet-size tree, "33" or "75".
- `weights` (object): Hand class to frequency. An omitted class has weight 0.

### `find_hands` (~261 tokens)

Find my hands

Find hands the account has uploaded. Returns hand_id, session_id, handAt, position, cards, game, board, potType, street lines, and netBb. Solver grade buckets are not filled. If this account has no hands, offer the hosted upload page from get_upload_link (https://pokerdata.io/upload) instead of asking the user to paste histories into chat.

Input parameters:

- `filter`: Hand-level filters, all optional.
- `game_type`: Only hands of this game type. Matches hole-card count.
- `gto_plo5_rfi_bucket`: Solver grade bucket for PLO5 raise-first-in. Grades are not computed, so any value matches nothing.
- `gto_vs_3bet_bucket`: Solver grade bucket for hero's action vs a 3-bet. Grades are not computed, so any value matches nothing rather than inventing a frequency.
- `limit` (integer, required): Hands to return, 1 to 50.
- `session_id`: Only hands from this upload session (see list_my_sessions).
- `sort` (string, required): Row order: newest first, largest win first, or largest loss first (the default).
- `table_size`: Only hands dealt at tables of this many seats.

Output parameters:

- `gto` (string): Always "not graded": solver grades are not attached.
- `gtoNote` (string): Why a solver-grade filter matches nothing.
- `hands` (array): Matching hands, sorted as requested.
- `hint` (string): Where to upload hands when the account has none.
- `returned` (integer): Hands in this response.
- `total` (integer): Matching hands before the limit.

### `get_hand_results` (~119 tokens)

Get my results curve

Per-hand cumulative results for a winnings curve. `points` is [{ hand, bb }], oldest to newest, downsampled. Pass session_id for one session. If this account has no hands, offer the hosted upload page from get_upload_link (https://pokerdata.io/upload) instead of asking the user to paste histories into chat.

Input parameters:

- `max_points` (integer, required): Points on the curve after downsampling, 2 to 200.
- `session_id`: Only this upload session's hands. Omit for the whole account.

Output parameters:

- `hint` (string): Where to upload hands when the account has none.
- `netBb` (number): Final cumulative result in big blinds.
- `points` (array): Downsampled curve, oldest to newest.
- `totalHands` (integer): Hands behind the curve.

### `get_session_summary` (~164 tokens)

Summarize a session

One uploaded session's headline numbers: hero, game type, start and end times, hands played, net result in big blinds, and HUD rates (VPIP, PFR, 3-bet, open limp) as percentages with the sample size. Use it after list_my_sessions to report how a session went; use get_hand_results for its winnings curve and find_hands for individual hands. Returns an error for an unknown session id. Any key works, free trial included, and it never counts against the allowance. If this account has no hands, offer the hosted upload page from get_upload_link (https://pokerdata.io/upload) instead of asking the user to paste histories into chat.

Input parameters:

- `session_id` (string, required): Session id from list_my_sessions.

Output parameters:

- `endedAt` (string|null): Last hand timestamp.
- `error` (string): Present instead of a payload when the request named something that does not exist. No figure is estimated in its place.
- `game_type` (string): Game type: "NLHE", "PLO", "PLO5", or "PLO6".
- `hands` (integer): Hands in the session.
- `hero` (string): Hero name in the history.
- `hud` (object): HUD rates over this session, as percentages.
- `id` (string): Session id.
- `netBb` (number): Session result in big blinds.
- `startedAt` (string|null): First hand timestamp.

### `list_my_sessions` (~102 tokens)

List my sessions

Recent uploaded sessions, newest first: id, hero, game type, dates, hands, and net result. game_type matches hole-card count. If this account has no hands, offer the hosted upload page from get_upload_link (https://pokerdata.io/upload) instead of asking the user to paste histories into chat.

Input parameters:

- `game_type`: Only sessions containing this game type.
- `limit` (integer, required): Sessions to return, 1 to 50.

Output parameters:

- `hint` (string): Where to upload hands when the account has none.
- `sessions` (array): Sessions, newest first.

### `get_tournament_results` (~89 tokens)

Get my tournament results

MTT results imported from tournament summary files. Money is in cents. Hand histories are not a source of buy-ins or prizes. If this account has no hands, offer the hosted upload page from get_upload_link (https://pokerdata.io/upload) instead of asking the user to paste histories into chat.

Input parameters:

- `limit` (integer, required): Tournament summaries to include, 1 to 500.

Output parameters:

- `buyInCents` (number|null): Total buy-ins, or null when one buy-in is unknown.
- `itmPct` (number|null): Share of tournaments that cashed, 0 to 1, or null.
- `netProfitCents` (number|null): Received minus buy-ins, or null when a buy-in is unknown.
- `note` (string): Present when no tournament summaries have been uploaded.
- `receivedCents` (number): Total prize money received.
- `recent` (array): Tournaments, newest first.
- `roi` (number|null): Return on investment as a ratio, or null.
- `tournaments` (integer): Tournament summaries counted.

### `list_my_opponents` (~160 tokens)

List my opponents

Tracked opponents from uploaded hands. Each row has handCount, handsVsHero, and heroBb100Vs. Pass name to find one villain.

Input parameters:

- `game_type`: Only hands of this game type, e.g. "NLHE" or "PLO".
- `hero`: Only hands where this hero name was seated.
- `limit` (integer, required): Opponents to return, 1 to 500.
- `min_hands` (integer, required): Drop opponents seen in fewer hands than this.
- `name`: Case-insensitive substring of the opponent's screen name.
- `sort` (string, required): Row order: most hands, most recent, or by hero's bb/100 against them (toughest = worst for hero).

Output parameters:

- `opponents` (array): Opponents, sorted as requested.

### `get_opponent_notes` (~44 tokens)

Get opponent notes

Leak notes computed from uploaded hands for one opponent, with the sample size on each line.

Input parameters:

- `opponent_id` (string, required): Opponent id from list_my_opponents.

Output parameters:

- `display_name` (string): Screen name as written in the history.
- `error` (string): Present instead of a payload when the request named something that does not exist. No figure is estimated in its place.
- `notes` (array): Notes, or a single line saying the sample is too small.
- `opponent_id` (string): Opponent id, echoed.

### `get_opponent_limp_range` (~149 tokens)

Get an opponent's limp range

Shown-hand first-in limp range: 169-class counts of hole cards villains showed after an open limp. Pass position for one seat. Sample is showdown-only. This is not a solver range.

Input parameters:

- `game_type`: Only hands of this game type.
- `limit` (integer, required): Hole-card classes to return, most frequent first, 1 to 169.
- `opponent_id`: Only this opponent's limps (see list_my_opponents). Omit for every tracked villain.
- `position`: Only limps from these seats.
- `session_id`: Only hands from this upload session.
- `table_size`: Only hands dealt at tables of this many seats.

Output parameters:

- `classes` (array): Observed classes, most frequent first. Counts, not solver frequencies.
- `classesByPosition` (object): Seat label to that seat's observed classes.
- `note` (string): That the sample is showdown-only and the counts are observations.
- `sample` (integer): Shown limped hands behind the counts.

### `enqueue_solve` (~275 tokens)

Record a solve request

Record a heads-up postflop solve request. Required: title, board, pot (bb), effective_stack (bb). The job stays pending: solver dispatch and billing are not configured, so this does not start a solve.

Input parameters:

- `add_allin` (boolean): Add an all-in branch alongside the bet sizes.
- `bet_sizes` (array): Bet sizes as fractions of the pot, e.g. [0.33, 0.75].
- `board` (string, required): Board to solve, e.g. "3h 3d 2s".
- `effective_stack` (number, required): Effective stack behind, in big blinds.
- `ip_range` (string): In-position range in the same weights format.
- `iterations` (integer): Requested solver iterations, 50 to 5000.
- `max_aggressions` (integer): Raises allowed per street, 1 to 4.
- `oop_range` (string): Out-of-position range as hand-class weights, e.g. "AA:1,AKs:0.42". Defaults are left to the solver config.
- `pot` (number, required): Starting pot in big blinds.
- `tags` (array): Free-form tags stored with the job.
- `title` (string, required): Label for the job, 1 to 120 characters.

Output parameters:

- `board` (string): Board for the requested solve.
- `createdAt` (string): ISO timestamp the job was recorded.
- `dispatch` (string): Always "not_configured".
- `effective_stack` (number): Effective stack in big blinds.
- `pot` (number): Pot in big blinds.
- `queue_id` (integer): Id for get_queued_solve.
- `reason` (string): Why the job does not start a solve.
- `solution_id` (string|null): Always null while dispatch is disabled.
- `status` (string): "pending", "running", "done", or "failed".
- `title` (string): Title given when the job was recorded.

### `get_queued_solve` (~55 tokens)

Get a queued solve

Look up one queued solve for this account. status is pending, running, done, or failed. solution_id is null until a worker exists.

Input parameters:

- `queue_id` (integer, required): Queue id returned by enqueue_solve.

Output parameters:

- `board` (string): Board for the requested solve.
- `createdAt` (string): ISO timestamp the job was recorded.
- `dispatch` (string): Always "not_configured".
- `effective_stack` (number): Effective stack in big blinds.
- `pot` (number): Pot in big blinds.
- `queue_id` (integer): Id for get_queued_solve.
- `reason` (string): Why the job does not start a solve.
- `solution_id` (string|null): Always null while dispatch is disabled.
- `status` (string): "pending", "running", "done", or "failed".
- `title` (string): Title given when the job was recorded.

### `list_queued_solves` (~44 tokens)

List my queued solves

List this account's solver-queue jobs, newest first. Jobs are not dispatched.

Input parameters:

- `limit` (integer, required): Jobs to return, 1 to 50.

Output parameters:

- `solves` (array): Queued jobs. None are dispatched.

### `list_library_solutions` (~45 tokens)

List my saved solutions

Finished postflop solutions saved for this account. None are marked done while dispatch is disabled.

Input parameters:

- `limit` (integer, required): Solutions to return, 1 to 50.

Output parameters:

- `note` (string): Why no solution is marked done.
- `solutions` (array): Empty while solver dispatch is disabled.

### `get_upload_link` (~58 tokens)

Get the hand-upload link

Primary hand-upload path. Returns https://pokerdata.io/upload on this origin, with a short-lived signed token for the caller's account when signing is configured. Hand the URL to the user. Pasting histories into chat is the fallback.

Output parameters:

- `expiresAt` (string|null): When the signed token expires, or null when unsigned.
- `primary` (boolean): Always true: this is the primary upload path.
- `resource` (string): MCP resource URI that returns the same payload.
- `tokenAttached` (boolean): Whether the URL carries a signed token for this account.
- `url` (string): URL to hand to the user, signed when signing is configured.

### `upload_hand_history` (~83 tokens)

Upload a hand history

Secondary upload path for a small paste. Prefer get_upload_link and the hosted /upload page. Runs the same ingestion pipeline and returns hands parsed, tournaments parsed, and errors. Does not grade solver frequencies.

Input parameters:

- `filename` (string): Name to record for the paste. Defaults to "paste.txt".
- `text` (string, required): Raw hand history or tournament summary text.

Output parameters:

- `errors` (array): Parse errors, if any.
- `filename` (string): Filename recorded for the paste.
- `handsParsed` (integer): Hands parsed.
- `persisted` (boolean): Always false: nothing is written to durable storage.
- `persistence` (string): Where the hands live, "process_memory".
- `sessionId` (string|null): Session id for the stored hands, or null when nothing parsed.
- `tournamentsParsed` (integer): Tournament summaries parsed.

## Diagnostics

Captured diagnostic sections: TLS, DNSSEC, Authorisation, Transports. The full working is on the page: https://verifymcp.io/servers/hft-studio-pokerdata/api-mcp#diagnostics

## Score history

- 2026-10-18: 81
- 2026-10-17: 74
- 2026-10-16: 65

## Common questions

### What is the PokerData MCP server?

PokerData is an MCP server listed in the public MCP registry as io.github.hft-studio/pokerdata. GTO poker solver data: NLHE/PLO preflop ranges, postflop strategy, EV. 6-max NL preflop free. This page covers its hosted endpoint (https://pokerdata.io/api/mcp).

### Is the PokerData MCP server safe to use?

PokerData scores 81 out of 100 on VerifyMCP. That is a record of what we were able to check automatically, not an endorsement. The category breakdown on this page shows every signal behind the number, including the ones we could not confirm.

### What tools does the PokerData MCP server expose?

PokerData exposes 29 tools: list_games, get_range, get_node, get_config, list_spots, and 24 more. Their descriptions and schemas cost roughly 6,082 tokens of context every time the server is loaded.

### Does the PokerData MCP server require authentication?

Yes. PokerData asked us for credentials when we connected, so you will need to authorise it in your MCP client before it can do anything.

### Is the PokerData MCP server still maintained?

PokerData is still listed as active in the MCP registry. We last reached this channel on 18 October 2026. Those dates come from our own scans of the registry and the channel itself, not from anything the publisher announced.

## Links

- Remote endpoint: https://pokerdata.io/api/mcp
- Repository: https://github.com/hft-studio/pokerdata-mcp
- Website: https://pokerdata.io/api
- Changelog RSS feed: https://verifymcp.io/servers/hft-studio-pokerdata/api-mcp.xml
- Changelog JSON feed: https://verifymcp.io/servers/hft-studio-pokerdata/api-mcp.json
- HTML version of this page: https://verifymcp.io/servers/hft-studio-pokerdata/api-mcp
