PokerData
Server Details
GTO poker solver data: NLHE and PLO preflop ranges, postflop strategy and EV. 6-max NL is free.
- Status
- Healthy
- Last Tested
- Transport
- Streamable HTTP · MCP 2025-11-25
- URL
TDQS
Scored across 29 tools
Tools cover distinct resources such as preflop ranges, postflop nodes, hand uploads, opponent stats, and tournament results. Some overlap exists between get_node/get_range and get_postflop_node/get_postflop_range, but descriptions clearly distinguish granularity and return types.
All 29 tools follow a consistent snake_case verb_noun convention (e.g., get_range, list_games, upload_hand_history). Minor variations like list_my_opponents still fit the pattern and remain predictable.
29 tools is heavy for an MCP server, though the poker domain is inherently broad. Several discovery/metadata tools (list_datasets, list_games, list_spots, get_range_metadata, get_tree_docs) and queue tools (enqueue_solve, get_queued_solve, list_queued_solves) could potentially be consolidated.
Core workflows are well covered: preflop/postflop range queries, hand upload and analysis, opponent tracking, and tournament results. Minor gaps like deleting uploaded hands or managing opponent lists are acceptable for a primarily read-only analytics server.
Available Tools
29 toolscompare_strategiesCompare two strategiesARead-onlyIdempotentInspect
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.
| Name | Required | Description | Default |
|---|---|---|---|
| anteBb | No | Requested ante in bb. nlmtt8 models a 1bb BB-ante; other positive antes return unsupported coverage. | |
| domain | Yes | Preflop contexts use game/stack/history/hand. Postflop contexts use pack/board/path/combo. | |
| format | No | 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. | |
| baseline | Yes | 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. | |
| objective | No | Requested optimization objective. chip_ev is supported for nlmtt8 preflop. ICM, PKO, and satellite return unsupported coverage. | |
| comboLimit | No | Maximum largest-changing combos for aggregate postflop comparisons (default 12, maximum 50) | |
| comparison | Yes | 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. |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | No | Both snapshots, the per-action frequency and EV deltas, and the largest combo changes for postflop comparisons. Null when the request is unsupported. |
| context | No | Canonical context the answer belongs to (variant, format, stacks, positions, board, path). Null when the request is unsupported. |
| coverage | No | Whether the request was answered exactly, aggregated, or refused as out of coverage. |
| warnings | No | Caveats that must survive into any answer built on this result. |
| schemaVersion | No | Envelope version, currently "1.0". |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, so the bar is lower. The description still adds genuinely useful behavior: the server performs both fetches internally and returns deltas plus largest combo changes, sidestepping two large node payloads. It does not mention limits or failure modes, keeping it short of a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, no filler, and the core value proposition (preferred tool, what it returns, why it is cheaper) is front-loaded. Every clause earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With annotations covering the safety profile and a full output schema, the description does not need to enumerate return fields, yet it usefully summarizes them. Combined with 100% schema coverage and nested contexts documented in the schema, an agent has what it needs; only the internal limits (e.g. comboLimit capping) are left to the schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema carries baseline semantics, including nested baseline/comparison contexts, comboLimit defaults, and enum constraints. The description adds no parameter-level detail beyond the schema, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: computing differences between two preflop or postflop contexts, with a concrete return (action-frequency/EV deltas plus largest postflop combo changes). This clearly separates it from single-node siblings like get_node and get_postflop_node without needing to open their schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly labels itself the 'Preferred tool for differences between two ... contexts' and implies the alternative (fetching both nodes separately) by noting it avoids 'two large node payloads.' No hard exclusions or prerequisites are stated, but the usage context is clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
enqueue_solveRecord a solve requestAInspect
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.
| Name | Required | Description | Default |
|---|---|---|---|
| pot | Yes | Starting pot in big blinds. | |
| tags | No | Free-form tags stored with the job. | |
| board | Yes | Board to solve, e.g. "3h 3d 2s". | |
| title | Yes | Label for the job, 1 to 120 characters. | |
| ip_range | No | In-position range in the same weights format. | |
| add_allin | No | Add an all-in branch alongside the bet sizes. | |
| bet_sizes | No | Bet sizes as fractions of the pot, e.g. [0.33, 0.75]. | |
| oop_range | No | Out-of-position range as hand-class weights, e.g. "AA:1,AKs:0.42". Defaults are left to the solver config. | |
| iterations | No | Requested solver iterations, 50 to 5000. | |
| effective_stack | Yes | Effective stack behind, in big blinds. | |
| max_aggressions | No | Raises allowed per street, 1 to 4. |
Output Schema
| Name | Required | Description |
|---|---|---|
| pot | No | Pot in big blinds. |
| board | No | Board for the requested solve. |
| title | No | Title given when the job was recorded. |
| reason | No | Why the job does not start a solve. |
| status | No | "pending", "running", "done", or "failed". |
| dispatch | No | Always "not_configured". |
| queue_id | No | Id for get_queued_solve. |
| createdAt | No | ISO timestamp the job was recorded. |
| solution_id | No | Always null while dispatch is disabled. |
| effective_stack | No | Effective stack in big blinds. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations state the write/side-effect profile (readOnly=false, destructive=false, idempotent=false), and the description adds genuinely non-obvious context: the recorded job stays pending and no solver dispatch or billing occurs. This is exactly the kind of operational caveat annotations cannot express; it stops short of describing retry/idempotency implications.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences, front-loaded with purpose, then required inputs, then the key 'does not start a solve' caveat. Efficient, though the 'Required: ...' list marginally duplicates the schema's required array.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present and annotations covering the safety profile, the description need not explain returns. It covers purpose, required inputs, and the critical pending/no-dispatch behavior, so an agent has what it needs; only the interaction with retries/idempotency is left implicit.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% with units ('in big blinds') and constraints already documented per-property, so the schema carries the burden. The description's enumeration of the four required fields and '(bb)' units largely repeats what the schema provides, adding little beyond confirming the required set.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (Record) and resource (heads-up postflop solve request/enqueue solve), and the scope qualifier 'heads-up postflop' distinguishes it from the many read-side siblings like get_queued_solve, list_queued_solves, get_postflop_node.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explains what happens after the call (job stays pending, no solve started), which informs usage, but it never names an alternative or states when to record a request versus inspecting existing ones. Usage is implied rather than explicitly routed.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
explain_comboExplain a postflop comboARead-onlyIdempotentInspect
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.
| Name | Required | Description | Default |
|---|---|---|---|
| pack | Yes | 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 | No | Exact childSegment path from get_postflop_node, e.g. ["Check", "Bet 5.5"]. Empty for the root. | |
| board | Yes | Board in spaced form, e.g. "6s 4h 2s" | |
| combo | Yes | Required exact two-card combo, e.g. As5s | |
| anteBb | No | Requested ante in bb. nlmtt8 models a 1bb BB-ante; other positive antes return unsupported coverage. | |
| format | No | 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 | No | Requested optimization objective. chip_ev is supported for nlmtt8 preflop. ICM, PKO, and satellite return unsupported coverage. | |
| comparisonLimit | No | Maximum same-rank-class suit comparisons (default 6, maximum 12) |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | No | 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. |
| context | No | Canonical context the answer belongs to (variant, format, stacks, positions, board, path). Null when the request is unsupported. |
| coverage | No | Whether the request was answered exactly, aggregated, or refused as out of coverage. |
| warnings | No | Caveats that must survive into any answer built on this result. |
| schemaVersion | No | Envelope version, currently "1.0". |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The annotations already declare a safe, idempotent, read-only, closed-world read. Beyond that, the description adds real behavioral guidance: EV/loss is only returned 'when available,' and the explicit instruction that the server computes evidence while the agent should phrase causality as interpretation is a meaningful guardrail not captured by structured fields.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tight sentences, front-loaded with the primary use case, followed by the return payload and a behavioral caveat. No filler, though the enumerated return list is somewhat dense.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, the description needn't restate return values, and the parameter-level guidance lives in a fully described schema. The added note on framing causality as interpretation rounds out an otherwise complete definition for this domain-specific analysis tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so all eight parameters — including the pack/path/board/combo mechanics and the anteBb/format/objective coverage caveats — are already documented in the schema. The description adds no additional parameter-level detail, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource ('explain' a 'postflop combo') and lists exactly what the tool returns (action mix, EV/loss, hand and draw classification, blocker facts, suit comparisons). It is clearly a per-combo solver explanation, but it never names a sibling (e.g. get_hand_results, get_postflop_node, compare_strategies) to differentiate itself.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It positions itself as the 'preferred tool for exact NLHE postflop hand questions,' which implies the usage context, and the schema notes tie parameters back to list_postflop_packs and get_postflop_node. However, there is no explicit when-not and no named alternative for adjacent tasks such as comparing strategies or fetching a whole node.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
find_handsFind my handsARead-onlyIdempotentInspect
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.
| Name | Required | Description | Default |
|---|---|---|---|
| sort | Yes | Row order: newest first, largest win first, or largest loss first (the default). | biggest_loss |
| limit | Yes | Hands to return, 1 to 50. | |
| filter | No | Hand-level filters, all optional. | |
| game_type | No | Only hands of this game type. Matches hole-card count. | |
| session_id | No | Only hands from this upload session (see list_my_sessions). | |
| table_size | No | Only hands dealt at tables of this many seats. | |
| gto_vs_3bet_bucket | No | 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. | |
| gto_plo5_rfi_bucket | No | Solver grade bucket for PLO5 raise-first-in. Grades are not computed, so any value matches nothing. |
Output Schema
| Name | Required | Description |
|---|---|---|
| gto | No | Always "not graded": solver grades are not attached. |
| hint | No | Where to upload hands when the account has none. |
| hands | No | Matching hands, sorted as requested. |
| total | No | Matching hands before the limit. |
| gtoNote | No | Why a solver-grade filter matches nothing. |
| returned | No | Hands in this response. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnlyHint, idempotentHint, non-destructive), so the bar is lower. The description still adds real behavioral value: solver grade buckets are not filled, and the explicit fallback when the account has no hands. It omits pagination/truncation behavior and the fact that sort defaults to biggest_loss.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences, front-loaded with the core purpose before details, with no filler. The enumeration of return fields is long but useful; the grade-bucket sentence is partly redundant with the schema descriptions.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, return values need not be explained, yet the key behavioral edge cases (empty account, unfilled grade buckets affecting the gto_* filters) are covered. An agent has enough to call it correctly and handle the zero-result path.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents sort, limit, filter fields, and both gto bucket params. The description's note that grade buckets 'are not filled' restates the schema's own caveat rather than adding new meaning. Baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource and scopes it precisely ('hands the account has uploaded'), then enumerates the returned fields (hand_id, session_id, handAt, position, cards, game, board, potType, street lines, netBb). It does not explicitly contrast with the nearest sibling (list_my_sessions, get_hand_results), but the scope is unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives a concrete routing rule for the empty-result case: offer get_upload_link's hosted upload page rather than asking the user to paste histories into chat. That names an alternative tool and the condition that selects it, though it offers no guidance on when to prefer this over sibling retrieval tools in the normal case.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_board_reportReport on board texturesARead-onlyIdempotentInspect
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.
| Name | Required | Description | Default |
|---|---|---|---|
| pack | Yes | 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 | No | Exact childSegment path from get_postflop_node, e.g. ["Check", "Bet 5.5"]. Empty for the root. | |
| anteBb | No | Requested ante in bb. nlmtt8 models a 1bb BB-ante; other positive antes return unsupported coverage. | |
| format | No | 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. | |
| filters | No | Texture filters applied to the pack's solved boards. All optional; omit for every board. | |
| objective | No | Requested optimization objective. chip_ev is supported for nlmtt8 preflop. ICM, PKO, and satellite return unsupported coverage. | |
| boardLimit | No | Maximum matching boards to analyze (default and maximum 50) | |
| representativeLimit | No | Maximum representative boards returned (default 12, maximum 20) |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | No | Action frequencies and range composition aggregated across solved boards, with equal weight per board, plus representative boards. Null when the request is unsupported. |
| context | No | Canonical context the answer belongs to (variant, format, stacks, positions, board, path). Null when the request is unsupported. |
| coverage | No | Whether the request was answered exactly, aggregated, or refused as out of coverage. |
| warnings | No | Caveats that must survive into any answer built on this result. |
| schemaVersion | No | Envelope version, currently "1.0". |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare read-only, idempotent, non-destructive behavior, so the bar is low. The description adds genuinely non-obvious methodology: results report sample breadth and weight each board equally, which matters for interpreting the aggregate. It does not mention rate limits or cost.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, front-loaded with the usage claim followed by the mechanism and the statistical caveat. Every sentence carries information an agent would not get from the schema or annotations.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return-shape explanation is not needed, and annotations carry the safety profile. With 100% schema coverage the remaining burden is light, and the description covers purpose, usage fit, and weighting methodology. It stops short of clarifying how it relates to the node-level siblings for related questions.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents all 8 parameters including the nested filters object and the pack/path relationship. The description adds only the scoping phrase "one postflop pack" and no format or syntax detail beyond the schema. Baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific action (aggregates action frequencies and range/action composition) on a specific resource (solved boards in one postflop pack), which distinguishes it from node-level siblings like get_postflop_node. It positions itself as the texture-heuristic tool but never names the sibling it displaces, so an agent still has to infer the boundary.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
"Preferred tool for board-texture heuristics" gives a clear use context: reach for this when aggregating across many boards rather than inspecting one node. The pack parameter also routes the agent to list_postflop_packs. There is no explicit when-not statement or named alternative.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_configGet table configurationARead-onlyIdempotentInspect
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 }).
| Name | Required | Description | Default |
|---|---|---|---|
| game | Yes | "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. | |
| stack | Yes | Stack depth in big blinds, e.g. 40 |
Output Schema
| Name | Required | Description |
|---|---|---|
| ante | No | Ante in big blinds. |
| game | No | Game id. |
| seats | No | Seats in action order. |
| stack | No | Stack depth in big blinds. |
| units | No | Unit labels for stack, stacks, blinds, ante, openSizes, and evs. |
| blinds | No | Blinds in big blinds. |
| evUnit | No | EV unit, "sb". |
| stacks | No | Starting stacks per seat. Null where the depth is solved against a different stack (10bb all-in/fold versus 50bb). |
| openSizes | No | First-in raise-to sizes, by seat, with label and sizeBb. |
| evBaseline | No | What EV is measured against, "fold". |
| antePostedBy | No | Seat that posts the ante. |
| schemaVersion | No | Payload version, 1. |
| stackIncludesAnte | No | True when the named depth already contains the ante. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly, idempotent, closed-world, non-destructive), and the description adds real behavioral context beyond them: convergence is not published, stackIncludesAnte semantics for the 1bb BB ante, stacks is null at 10bb (all-in/fold vs 50bb), and that node EVs are small blinds relative to fold. These are non-obvious edge cases an agent would otherwise get wrong, though formatting behavior and error cases are unaddressed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Information density is high and most sentences carry non-obvious domain facts, but there is no front-loaded topic sentence and the text is a run-on stream mixing return fields, ante accounting, open-size encoding, null semantics and units. Detail such as 'node decodes code 40034 to 2.19bb' is marginal and hurts readability without adding routing value.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be explained, yet the description supplies the interpretive context an agent needs (units, ante treatment, null stacks at 10bb) for a two-parameter lookup tool. What remains missing is when to prefer this over listing games or fetching tree docs, which is a usage gap rather than a completeness one.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the schema itself documents each game enum value exhaustively, so the description's enum discussion (nlmtt8, nlh8-hydra ante scheme) is largely redundant with structured data. It does add field-level semantics not in the schema (evUnit, evBaseline, openSizes as first-in raise-to), but not parameter-level meaning, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening clause identifies the returned resource precisely ('Table for one preflop game and stack, in big blinds: seats, stacks, blinds, ante, antePostedBy, stackIncludesAnte, openSizes, evUnit, evBaseline'), so an agent can tell it returns table/spot configuration rather than strategy or results. It is not a clean verb+resource sentence and makes no attempt to distinguish itself from siblings like list_games or get_tree_docs, which keeps it out of 5 territory.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is only implied: the trailing example get_config({ game: "nlmtt8", stack: 40 }) shows how to call it, and the field list implies you use it to understand a table before deeper queries. There is no explicit when-to-use, no when-not, and no named alternative among the ~28 siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_exploitabilityGet preflop exploitabilityARead-onlyIdempotentInspect
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.
| Name | Required | Description | Default |
|---|---|---|---|
| game | Yes | Preflop game id to report on, e.g. "nl" or "nlmtt8". Any known game answers "not available". |
Output Schema
| Name | Required | Description |
|---|---|---|
| game | No | Game id, echoed. |
| reason | No | Why no number is returned. |
| status | No | Always "not available". |
| dataset | No | Dataset the game maps to, or null when unknown. |
| available | No | Always false. |
| iterations | No | Always null. |
| convergence | No | Always null. |
| exploitability | No | Always null: no figure is published or estimated. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly, idempotent, non-destructive), so the description's job is to add behavior beyond that. It does: it explains why the answer is unavailable (no preflop dataset publishes exploitability, convergence, or iteration counts) and guarantees the tool will never fabricate a number. The only gap is not stating whether the response is an empty result or an explicit "not available" payload.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, front-loaded with the resource and immediately followed by the critical caveat. Every sentence earns its place; nothing is repeated from the schema or annotations.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, the description need not explain return values, and it covers the essential oddity of the tool thoroughly. It is only incomplete in not pointing the agent toward an alternative path for computing exploitability.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and there is a single parameter, whose description already explains that any known game yields "not available". The description adds nothing further about the game id format or valid values. Baseline 3 is appropriate when the schema carries the parameter semantics.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names the resource (preflop exploitability for a given game) and, unusually, its defining behavior: it reports that no dataset publishes this metric rather than a value. An agent can immediately tell this apart from siblings like get_hand_results or compare_strategies. It is slightly weakened by being a noun phrase rather than stating a retrieval action, but the intent is unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It implicitly tells the agent not to call this expecting a number ("The answer is not available; this tool never fills in a number"), which is meaningful usage guidance for a dead-end lookup. However, it names no alternative for actually obtaining exploitability (e.g., enqueue_solve), and gives no explicit when-to-use / when-not-to-use framing. Guidance is implied rather than stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_hand_resultsGet my results curveARead-onlyIdempotentInspect
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.
| Name | Required | Description | Default |
|---|---|---|---|
| max_points | Yes | Points on the curve after downsampling, 2 to 200. | |
| session_id | No | Only this upload session's hands. Omit for the whole account. |
Output Schema
| Name | Required | Description |
|---|---|---|
| hint | No | Where to upload hands when the account has none. |
| netBb | No | Final cumulative result in big blinds. |
| points | No | Downsampled curve, oldest to newest. |
| totalHands | No | Hands behind the curve. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare the safe read-only/idempotent profile, so the bar is lower. The description still adds real value beyond them: the curve is downsampled, ordered oldest to newest, and formats points as [{ hand, bb }], plus empty-state guidance to route to the upload page.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the purpose, then output shape, then the one parameter, then the empty-state fallback. Dense but every sentence carries information; slightly compressed with the inline backtick notation.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, the description doesn't need to explain returns, yet it usefully summarizes the curve format. Empty-account behavior is covered, so an agent has enough to call and recover from the zero-hands case.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so both parameters are already documented. The description restates session_id scoping ('Pass session_id for one session') but adds no syntax or behavior beyond the schema; the points format described is output, not a parameter. Baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific verb+resource: a per-hand cumulative results curve of winnings. It is distinguishable from siblings like get_session_summary or get_tournament_results by the per-hand granularity, though it doesn't explicitly contrast itself with those tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives clear context: pass session_id to scope to one session, and instructs the agent to fall back to the upload page from get_upload_link when the account has no hands. It stops short of explicitly naming alternative tools for aggregated stats.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_nodeGet preflop decision nodeARead-onlyIdempotentInspect
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.
| Name | Required | Description | Default |
|---|---|---|---|
| full | No | 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 | Yes | "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. | |
| hand | No | Optional hand/class | |
| stack | Yes | Stack depth in big blinds | |
| detail | No | Response detail. "compact" is the default and removes bulk maps; use "full" only when exact complete data is required. | |
| history | Yes | Action path ending in a position | |
| minFreq | No | Trim per-action ranges |
Output Schema
| Name | Required | Description |
|---|---|---|
| game | No | Preflop game id, e.g. "nl" or "nlmtt8". |
| hand | No | The requested hand, when one was asked for. |
| hint | No | How to narrow, page, or widen the same query. |
| spot | No | Action path ending in an action, echoed from the request. |
| actor | No | Position to act at this node. |
| stack | No | Stack depth in big blinds. |
| units | No | Unit labels: stack and sizeBb in bb, evs in sb. |
| evUnit | No | EV unit, "sb". |
| actions | No | Actions at the node. |
| history | No | Action path ending in the acting position. |
| version | No | Dataset version where the bundle publishes one. |
| evBaseline | No | What EV is measured against, "fold". |
| schemaVersion | No | Payload version, 1. |
| continuingHands | No | Hand classes that continue past this node. |
| continuingCombos | No | Combos that continue past this node. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, so safety is covered. The description adds real behavioral context: EV values are small blinds relative to fold, compact mode returns action totals, and full=true yields all 169 hands with explicit 0 and no invented EVs — meaningful disclosures about what is and isn't synthesized.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose is front-loaded in the first clause, then it moves through parameter and mode semantics economically. The 'full=true is full=1' fragment is cryptic and some sentences are dense, but there is little waste.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, return values need not be described, yet the description still clarifies mode differences and EV units for a complex 7-parameter solver tool. Together with full schema coverage, an agent has enough to call it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% (baseline 3), and the description goes further by explaining the `history` string format with a concrete example ('UTG_60%_HJ'), sizeBb as raise-to in big blinds with a worked number, and the rationale behind full=true's 0-weight hands.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource — 'Actions available at a decision node' — which clearly separates it from the sibling get_postflop_node via the 'preflop' scope in the title. It never names the alternative sibling explicitly, so an agent must infer preflop-vs-postflop routing rather than being told.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
'add `hand` for its exact mixed strategy' and the detail schema's 'use "full" only when exact complete data is required' give implied usage conditions. However, there is no explicit when-to-use / when-not-to-use guidance or routing to siblings like get_postflop_node or get_range.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_opponent_limp_rangeGet an opponent's limp rangeARead-onlyIdempotentInspect
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.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | Yes | Hole-card classes to return, most frequent first, 1 to 169. | |
| position | No | Only limps from these seats. | |
| game_type | No | Only hands of this game type. | |
| session_id | No | Only hands from this upload session. | |
| table_size | No | Only hands dealt at tables of this many seats. | |
| opponent_id | No | Only this opponent's limps (see list_my_opponents). Omit for every tracked villain. |
Output Schema
| Name | Required | Description |
|---|---|---|
| note | No | That the sample is showdown-only and the counts are observations. |
| sample | No | Shown limped hands behind the counts. |
| classes | No | Observed classes, most frequent first. Counts, not solver frequencies. |
| classesByPosition | No | Seat label to that seat's observed classes. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly, idempotent, non-destructive), so the bar is lower; the description nonetheless adds substantive caveats beyond them — the sample is showdown-only and shown-hand only, and it is not a solver-derived range. It does not discuss sample-size thresholds or filtering behavior, but the added context is meaningful.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tight clauses, front-loaded with what the tool returns, then the invocation hint, then the two caveats. Telegraphic but every clause carries information; no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present the description need not explain return values, and it supplies the key interpretive caveats (showdown-only, not a solver range). For a 6-parameter filterable analytics tool whose schema is fully documented, this is close to complete, though a note on sparsity/sample confidence would help.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so every one of the 6 parameters is already documented in the schema. The description only adds 'Pass position for one seat', which sits slightly awkwardly against the schema's array-of-seats semantics and provides marginal extra meaning. Baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a precise verb+resource (observed limp range) plus the exact output form (169-class hole-card counts) and the population (hole cards villains showed after an open limp). The closing 'This is not a solver range' explicitly separates it from solver-range siblings such as get_range and get_postflop_range.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied rather than stated: the solver-range disclaimer and 'Sample is showdown-only' hint at when the data is appropriate, and 'Pass position for one seat' is a light invocation hint. However, no explicit when-to-use/when-not conditions or named alternative tools are given beyond the negation.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_opponent_notesGet opponent notesARead-onlyIdempotentInspect
Leak notes computed from uploaded hands for one opponent, with the sample size on each line.
| Name | Required | Description | Default |
|---|---|---|---|
| opponent_id | Yes | Opponent id from list_my_opponents. |
Output Schema
| Name | Required | Description |
|---|---|---|
| error | No | Present instead of a payload when the request named something that does not exist. No figure is estimated in its place. |
| notes | No | Notes, or a single line saying the sample is too small. |
| opponent_id | No | Opponent id, echoed. |
| display_name | No | Screen name as written in the history. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly, idempotent, non-destructive, closed-world), so the bar is lower. The description still adds real context beyond them: notes are derived from uploaded hands, and every line carries its own sample size, which tells the agent how to interpret the output.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single front-loaded sentence with no filler; the scope ('one opponent') and the output characteristic ('sample size on each line') both land immediately.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present and annotations carrying the safety profile, the description only needs to frame the tool's purpose, which it does. The implicit dependency on prior hand uploads is hinted at but not spelled out, leaving a small gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and there is only one parameter, whose schema description already routes to list_my_opponents. The description adds no further parameter detail, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific resource (leak notes) with its scope ('for one opponent') and origin ('computed from uploaded hands'), which is clear and distinct from the range/report siblings. It does not explicitly contrast itself with any sibling tool, so it stops short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied rather than stated: the phrase 'computed from uploaded hands' hints that hand histories must exist first, and the schema points to list_my_opponents for the id. There is no explicit when-to-use/when-not guidance or named alternative.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_postflop_nodeGet postflop solver nodeARead-onlyIdempotentInspect
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.
| Name | Required | Description | Default |
|---|---|---|---|
| pack | Yes | 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 | No | Segments from the root, e.g. ["Check", "Bet 5.5"]. Empty for the root node. | |
| board | Yes | Board in spaced form, e.g. "3h 3d 2s" | |
| combo | No | Optional exact combo, e.g. AsKh (PLO5: five cards, as listed in the node's hands) | |
| limit | No | Maximum representative compact combos (default 40, maximum 200) | |
| detail | No | Response detail. "compact" is the default and removes bulk maps; use "full" only when exact complete data is required. |
Output Schema
| Name | Required | Description |
|---|---|---|
| hint | No | How to narrow, page, or widen the same query. |
| node | No | Full detail: the stored node. Null at a chance point, where runouts hang directly under the path. |
| path | No | Segments walked from the root to this node. |
| board | No | Board at this node. |
| combo | No | The requested combo, when one was asked for. |
| hands | No | Compact rows in `columns` order, or the full per-combo strategy objects in full detail. |
| potBb | No | Pot at this node in big blinds. |
| reach | No | Full detail: the acting player's per-combo reach. |
| actions | No | Actions at the node with their reach-weighted frequency. |
| columns | No | Column order for `hands`: combo, reach, frequencies, evBb, evLossBb, actionEvBb. |
| summary | No | What the compact range left out, so nothing looks complete when it is sampled. |
| actionFreqs | No | Full detail: aggregate frequency per action. |
| actingPlayer | No | 0 for out of position, 1 for in position. |
| childSegments | No | Append one of these to `path` to walk deeper. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly, idempotent, non-destructive, closed-world, so the safety profile is covered. The description adds real behavioral context beyond that: the node is reachable/expandable via path+childSegment, and the default compact detail 'removes bulk maps' while 'full' is reserved for exact complete data — useful trade-off disclosure.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two dense sentences with no filler, front-loading what the node returns before the traversal instruction. It is efficient, though poker-domain jargon ('childSegment', 'reach-weighted action split') keeps it slightly heavy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, the description needn't explain return values, and annotations plus 100% schema coverage carry most of the structured load. It covers content, traversal and detail trade-offs; the only real gap is not routing the agent away from the superficially similar get_node sibling.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so all six parameters including pack, path, board, combo, limit and the detail enum are already documented in the schema. The description reinforces how path works (appending a childSegment) but adds little per-parameter meaning beyond what the schema provides; baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource (get a postflop solver node) and enumerates exactly what one node contains: per-hand-class strategy, legal next segments, board, reach and reach-weighted action split. The 'postflop' qualifier separates it from generic siblings, but it never distinguishes itself from the sibling get_node, which is the one an agent could easily confuse it with.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The second sentence explains the traversal pattern — append a returned childSegment to `path` to go deeper — which is genuinely useful usage guidance. However, it gives no explicit when-to-use/when-not guidance against alternatives like get_node, get_postflop_range, or get_hand_results, leaving the agent to infer the boundary.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_postflop_rangeGet postflop action rangeARead-onlyIdempotentInspect
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.
| Name | Required | Description | Default |
|---|---|---|---|
| hand | No | Optional exact combo (AsKh) or hand class (AKs) for one frequency instead of reading the whole range. | |
| pack | Yes | Pack id from list_postflop_packs | |
| path | Yes | Flop actions ending in the action whose range you want | |
| tree | Yes | 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. | |
| board | Yes | Flop, e.g. "3h 3d 2s" | |
| minFreq | No | Drop classes at or below this weight. Default 0. |
Output Schema
| Name | Required | Description |
|---|---|---|
| hand | No | The requested hand, when one was asked for. |
| pack | No | Pack id the range was read from, after tree resolution. |
| path | No | Flop actions, ending in the action asked for. |
| tree | No | Bet-size tree, "33" or "75". |
| board | No | Canonical board as stored in the pack. |
| error | No | Present instead of a payload when the request named something that does not exist. No figure is estimated in its place. |
| range | No | Hand-class weights as "AA:1,AKs:0.42,…", the preflop range format. |
| action | No | The action whose range this is. |
| summary | No | What the compact range left out, so nothing looks complete when it is sampled. |
| weights | No | Hand class to frequency. An omitted class has weight 0. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, so safety is covered. The description adds useful behavioral context – the hand-class weight return format and how the path accumulates prior actions – but says nothing about pagination, cost, or failure modes for an invalid path.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
It is reasonably front-loaded, but the tree explanation ('33' = 33% pot on the flop...) restates the schema's tree description almost verbatim, duplicating structured data rather than adding new information. A sentence could be trimmed without loss.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present the return shape needn't be described, and annotations carry the safety profile. Between the path example and tree semantics, the agent has enough to call a 6-param tool correctly; only explicit sibling routing is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% so the baseline is 3, but the description adds real value with a concrete path example (['Check','Bet 1.8','Call 1.8']) and distinguishes the tree enum behavior ('33' vs '75'), which helps the agent construct valid values beyond reading the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('the range a player takes one flop action with, from a solved pack') and clarifies it returns the action range itself rather than the compact/full-detail ranges of the other range tools. It differentiates from siblings only loosely ('the other range tools'), so it falls just short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The path-accumulation semantics ('after every earlier flop action on the path') and the worked example imply when to use it, but the description never names a concrete alternative tool or states an explicit when-not-to-use condition versus get_range or get_postflop_node. Usage is inferable rather than stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_queued_solveGet a queued solveARead-onlyIdempotentInspect
Look up one queued solve for this account. status is pending, running, done, or failed. solution_id is null until a worker exists.
| Name | Required | Description | Default |
|---|---|---|---|
| queue_id | Yes | Queue id returned by enqueue_solve. |
Output Schema
| Name | Required | Description |
|---|---|---|
| pot | No | Pot in big blinds. |
| board | No | Board for the requested solve. |
| title | No | Title given when the job was recorded. |
| reason | No | Why the job does not start a solve. |
| status | No | "pending", "running", "done", or "failed". |
| dispatch | No | Always "not_configured". |
| queue_id | No | Id for get_queued_solve. |
| createdAt | No | ISO timestamp the job was recorded. |
| solution_id | No | Always null while dispatch is disabled. |
| effective_stack | No | Effective stack in big blinds. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly, idempotent, non-destructive), and the description adds genuine context beyond them: the valid status values and the fact that solution_id stays null until a worker exists. It does not state whether polling is expected or at what cadence.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, front-loaded with the action and then the state/model semantics. Every sentence carries new information with no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, the return shape needn't be re-explained, and annotations cover safety. The only gap is routing guidance relative to list_queued_solves, which the description leaves to inference.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so queue_id is fully documented in the schema as 'Queue id returned by enqueue_solve'. The description's added detail (status, solution_id) concerns returned fields, not the parameter, so the baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Look up one queued solve') and the 'one' implicitly distinguishes it from the list_queued_solves sibling. It does not explicitly name that sibling, so an agent still has to infer the single-vs-list split.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Scoping is implied by 'for this account' and 'one queued solve', but there is no explicit when-to-use guidance or named alternative (e.g. list_queued_solves) to route the agent. Usage must be inferred from the singular framing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_rangeGet preflop rangeARead-onlyIdempotentInspect
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).
| Name | Required | Description | Default |
|---|---|---|---|
| game | Yes | "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. | |
| hand | No | Optional hand/class, e.g. AKs or (KA)(KA) | |
| spot | Yes | Action path ending in an action | |
| limit | No | Maximum compact rows to return (default 120, maximum 500). | |
| stack | Yes | Stack depth in big blinds, e.g. 100 | |
| detail | No | Response detail. "compact" is the default and removes bulk maps; use "full" only when exact complete data is required. | |
| minFreq | No | Drop hands at or below this weight (PLO ranges are large) |
Output Schema
| Name | Required | Description |
|---|---|---|
| ev | No | Full detail: EV of the requested hand in small blinds. |
| evs | No | Hand class to EV, only where the solved bundle scored the hand. |
| evSb | No | EV of the requested hand in small blinds. |
| freq | No | Full detail: frequency of the requested hand. |
| game | No | Preflop game id, e.g. "nl" or "nlmtt8". |
| hand | No | The requested hand, when one was asked for. |
| hint | No | How to narrow, page, or widen the same query. |
| kind | No | plo5: the action family. |
| spot | No | Action path ending in an action, echoed from the request. |
| actor | No | Position to act at this node. |
| hands | No | Hand classes in the range. |
| range | No | Compact rows in `columns` order. |
| stack | No | Stack depth in big blinds. |
| action | No | plo5: the action the range belongs to. |
| combos | No | Combos in the range. |
| columns | No | Column order for `range`: hand, frequency, evSb. |
| history | No | Action path ending in the acting position. |
| summary | No | What the compact range left out, so nothing looks complete when it is sampled. |
| version | No | Dataset version where the bundle publishes one. |
| weights | No | Hand class to frequency. An omitted class has weight 0. |
| frequency | No | Frequency of the requested hand, 0 to 1. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare this a safe, idempotent read, so the bar is lower; the description still adds meaningful behavior: compact is the default response shape, PLO collapses to representative pure/mixed hands, and plo5 truncates to the top hands by EV with stated limits. It does not mention rate limits or pagination beyond the limit note, but the modality differences across game families are genuinely useful disclosure.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with purpose in the first sentence, then examples and mode notes; nearly every clause carries information. It is dense and slightly run-on in the example-heavy middle, but no sentence is filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be described; the description instead covers the inputs that matter (spot token grammar, game family quirks, detail modes, hand drill-down). The main residual gap is the absence of routing guidance to sibling range tools, which is a usage rather than a completeness issue.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3, but the description compensates for the schema's thin "Action path ending in an action" by giving concrete spot strings per game family ("UTG_60%_HJ_Call", "UTG_Open", "UTG_Open_HJ_3B") and explaining what `hand` yields. That is real added meaning for the least self-evident parameter.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ("The GTO range for one spot") and enumerates the supported game formats, so the agent knows exactly what comes back. It never names a sibling such as get_postflop_range or get_range_metadata to sharpen the boundary, but the title/description pairing makes the preflop scope unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives real usage signals: add `hand` when you want a single frequency and EV, only use `detail: full` "when exact complete data is required," and PLO returns representative hands unless a hand is named. It stops short of comparing itself to alternatives (get_postflop_range, get_node, compare_strategies), so the agent must infer which tool to pick.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_range_metadataGet range index metadataARead-onlyIdempotentInspect
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.
| Name | Required | Description | Default |
|---|---|---|---|
| game | Yes | Preflop game id, e.g. "nl", "nl9", "nlmtt8", "nlh8-hydra", "plo", "plo9", "plo5", "plo6hu". | |
| path | Yes | Action path, e.g. UTG_Open or LJ_Fold. Use (root) or empty for the plo5 root. | |
| stack | Yes | Stack depth in big blinds, e.g. 100. |
Output Schema
| Name | Required | Description |
|---|---|---|
| game | No | Game id, echoed. |
| note | No | What the match means, or that nothing was estimated. |
| path | No | Action path, echoed. |
| rows | No | Matching index rows. |
| actor | No | Acting position read off the path. |
| error | No | Present instead of a payload when the request named something that does not exist. No figure is estimated in its place. |
| match | No | "bundle", "node", or "none". |
| stack | No | Stack depth in big blinds, echoed. |
| dataset | No | Dataset the game maps to. |
| preflopExploitability | No | Always "not available". |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly, idempotent, non-destructive, closed-world behavior, so the safety profile is covered. The description adds genuine extra context: the return payload branches by game type (bundle stats for hold'em/PLO vs. a node row for plo5/plo6hu) and it explicitly disclaims two things it does not do.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight sentences with the payload behavior front-loaded and the exclusions second; every clause carries information. Slightly dense with domain jargon ('bundle stats', 'plo6hu') but no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
A read-only, single-shot lookup with full schema descriptions, rich annotations, and an output schema, so return-format explanation is not needed. The description covers the one non-obvious element (game-dependent payload) and the boundary conditions; only an explicit sibling pointer is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% with per-parameter examples ('nl', 'plo5', 'UTG_Open', '100'), so the schema already carries the meaning. The description restates the three required inputs without adding format or validity detail beyond them, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a concrete verb and resource ('Index metadata for one preflop game, stack, and path') and further specifies the output shape per game family (bundle stats vs. node row). It also fences itself off from the more obvious sibling by declaring it 'does not return a strategy', which is what get_range presumably does, though it never names that alternative.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives clear when-not guidance by excluding strategy and exploitability outputs, which tells the agent when to prefer get_range or get_exploitability instead. However, no alternative tool is named and there is no positive statement of the use case that selects this tool over list_games/get_node.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_session_summarySummarize a sessionBRead-onlyIdempotentInspect
Headline numbers and HUD rates for one uploaded session.
| Name | Required | Description | Default |
|---|---|---|---|
| session_id | Yes | Session id from list_my_sessions. |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | No | Session id. |
| hud | No | HUD rates over this session, as percentages. |
| hero | No | Hero name in the history. |
| error | No | Present instead of a payload when the request named something that does not exist. No figure is estimated in its place. |
| hands | No | Hands in the session. |
| netBb | No | Session result in big blinds. |
| endedAt | No | Last hand timestamp. |
| game_type | No | Game type: "NLHE", "PLO", "PLO5", or "PLO6". |
| startedAt | No | First hand timestamp. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, non-destructive, and closed-world, so the safety profile is fully covered. The description adds only the scope constraint that it operates on a single already-uploaded session; it discloses nothing about aggregation method or cost.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single eight-word sentence with no filler and the resource front-loaded. It is efficient, though terse to the point of omitting any actionable usage context.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, return values need no explanation, and the one parameter is fully described in the schema while annotations carry the safety profile. The definition is adequate for correct invocation, with the main gap being the absence of usage guidance.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the single session_id parameter is fully documented in the schema (UUID format, sourced from list_my_sessions). The description adds no syntax or format meaning beyond that, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific resource (one uploaded session) and specifies the content returned (headline numbers and HUD rates), which distinguishes it from generic session listings. It does not explicitly contrast with siblings like list_my_sessions or get_board_report, but the scope is unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no when-to-use guidance: no mention of prerequisites (session must be uploaded first), no statement of when this is preferable to get_board_report or other per-session tools, and no exclusions. The only usage hint lives in the schema's session_id description, not the tool description.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_tournament_resultsGet my tournament resultsARead-onlyIdempotentInspect
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.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | Yes | Tournament summaries to include, 1 to 500. |
Output Schema
| Name | Required | Description |
|---|---|---|
| roi | No | Return on investment as a ratio, or null. |
| note | No | Present when no tournament summaries have been uploaded. |
| itmPct | No | Share of tournaments that cashed, 0 to 1, or null. |
| recent | No | Tournaments, newest first. |
| buyInCents | No | Total buy-ins, or null when one buy-in is unknown. |
| tournaments | No | Tournament summaries counted. |
| receivedCents | No | Total prize money received. |
| netProfitCents | No | Received minus buy-ins, or null when a buy-in is unknown. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly, idempotent, non-destructive, closed-world), so the description correctly spends its words on added context: money is denominated in cents and hand histories are not a source of buy-ins or prizes. This is meaningful data-shape information beyond the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four short sentences, front-loaded with what the data is, then units and caveats, then the fallback workflow. No filler, though the upload-link sentence is long enough that it could be tightened.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return-value explanation is unnecessary, and the description covers provenance, currency units, and a fallback path. It does not state what happens when there are zero tournaments (as opposed to zero hands), a minor gap for a single-parameter read tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% for the single `limit` parameter (1–500, default 200), so the schema fully documents it. The description adds nothing about the limit or result windowing, which is the expected baseline-3 outcome when the schema does the heavy lifting.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description identifies the resource and its provenance ("MTT results imported from tournament summary files"), which tells an agent this returns tournament-level results rather than hand results. It is clear but does not explicitly contrast with siblings like get_hand_results or get_session_summary.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives a concrete conditional workflow: when the account has no hands, offer the hosted upload page from get_upload_link instead of asking for pasted histories. That is real usage guidance, though there is no explicit when-to-use framing versus other results tools.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_tree_docsGet tree documentationARead-onlyIdempotentInspect
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.
| Name | Required | Description | Default |
|---|---|---|---|
| dataset | Yes | Dataset id from list_datasets, e.g. "nl/v2", "nl9", "nlmtt8", "plo", "plo9", "plo5", "plo6hu". |
Output Schema
| Name | Required | Description |
|---|---|---|
| error | No | Present instead of a payload when the request named something that does not exist. No figure is estimated in its place. |
| source | No | File the coverage note came from. |
| stacks | No | Per-stack counts. |
| dataset | No | Dataset id, echoed. |
| coverage | No | Coverage row from the shipped README. |
| preflopExploitability | No | Always "not available". |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint/idempotentHint/destructiveHint=false and closed-world, so the safety profile is covered. The description adds real scope detail beyond that: it clarifies the payload comes only from the shipped README and shipped index, and explicitly that range bytes are neither read nor modified. That scoping is meaningful added context, though no auth, staleness or paging behavior is mentioned.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two compact sentences, front-loaded with what the tool returns, followed by a scope-limiting exclusion. Every clause carries information and nothing is redundant.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter, read-only tool with full annotations and an output schema, the description needn't explain return values, and it adequately covers content and scope. It is essentially complete, with only the absence of any when-to-use guidance keeping it from a 5.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
There is a single parameter (dataset) at 100% schema description coverage, with the schema supplying concrete id examples. The description contributes only "for one dataset", adding no format or constraint beyond what the schema already documents, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb+resource (documentation for one dataset's tree) and enumerates exactly what the payload contains: a coverage note from the shipped README and per-stack bundle/node counts from the shipped index. This is far more specific than a tautology. However, it never names a sibling it should be preferred over (e.g. get_range or get_range_metadata), so sibling differentiation is left implicit.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The clause "Does not read or modify range bytes" gives a negative boundary that implicitly routes an agent wanting actual range data to a sibling like get_range. But there is no positive statement of when to reach for this tool and no alternative is named, so guidance is merely implied.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_upload_linkGet the hand-upload linkARead-onlyIdempotentInspect
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.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| url | No | URL to hand to the user, signed when signing is configured. |
| primary | No | Always true: this is the primary upload path. |
| resource | No | MCP resource URI that returns the same payload. |
| expiresAt | No | When the signed token expires, or null when unsigned. |
| tokenAttached | No | Whether the URL carries a signed token for this account. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint and destructiveHint=false, so the safety profile is covered. The description contributes real extra context beyond that: the token is short-lived, signed, tied to the caller's account, and only present 'when signing is configured.' It does not explain what happens when signing is absent.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four short sentences, front-loaded with the essential fact (this is the primary upload path) followed by return details and the action to take. No filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return-value documentation is not required, and the annotations carry the safety profile. The description covers purpose, returned URL, token behavior, and the fallback action. Missing only the edge case where signing is not configured.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so the baseline is 4 and there is no parameter meaning to add. The description correctly focuses on output rather than inventing inputs.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific outcome: returns the https://pokerdata.io/upload URL with a signed token for the caller's account. It is clear this is the link-acquisition tool and not the actual upload. It does not name the closest sibling (upload_hand_history) or explain the relationship, so it falls short of full sibling differentiation.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives a clear directive: 'Hand the URL to the user,' and frames pasting histories into chat as 'the fallback,' which implies this link is the preferred path. No explicit when-not conditions or named alternatives among the sibling tools, but the usage context is unambiguous.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_datasetsList solved datasetsARead-onlyIdempotentInspect
List preflop datasets in the shipped tree documentation (stacks, positions, whether each bundle was analyzed). Preflop exploitability is not available.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| readme | No | How to read one dataset's write-up. |
| source | No | Where the documentation came from, "data/tree-docs". |
| datasets | No | Documented datasets. |
| generated | No | Date the documentation was generated. |
| preflopExploitability | No | Always "not available": no preflop dataset publishes it. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare this a safe, read-only, idempotent, closed-world read, so the safety profile is covered. The description adds value beyond them by describing the content each entry carries and by flagging the key limitation (no preflop exploitability), which prevents the agent from misusing the results.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences with the resource and scope front-loaded and the limitation trailing. Every clause carries information (what is listed, where it lives, what fields appear, what is unavailable) with no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists so return values need not be spelled out, and annotations cover the safety profile; the description supplies the remaining needed context (scope, per-entry content, one absence). Only the differentiation from sibling listing tools is left implicit.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so there is nothing for the description to disambiguate; the baseline for a no-parameter tool applies. No parameter semantics are missing or contradicted.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (List) and resource (preflop datasets) and adds scope: they live in the shipped tree documentation, and it enumerates what each entry conveys (stacks, positions, analyzed status). It does not name or distinguish itself from similar siblings such as list_postflop_packs or get_tree_docs, so an agent must infer the boundary.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no explicit when-to-use guidance and no alternatives named among a large family of list_* siblings. The closing caveat 'Preflop exploitability is not available' hints at what the tool cannot do, but it is not framed as routing guidance, leaving usage to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_gamesList covered gamesARead-onlyIdempotentInspect
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.
| Name | Required | Description | Default |
|---|---|---|---|
| detail | No | Response detail. "compact" is the default and removes bulk maps; use "full" only when exact complete data is required. |
Output Schema
| Name | Required | Description |
|---|---|---|
| _coverage | No | Formats and objectives this server does and does not answer. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly, idempotent, non-destructive, closed-world), so the bar is lower. The description still adds real behavioral context beyond them: which solves are out of scope ('Cash trees are not tournament, ICM, PKO, or satellite solves') and what each code actually returns (169-grid hands, per-hand EV in small blinds, chip-EV vs. classic-ante variants).
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The purpose and the preflop-query directive are front-loaded before the reference block. The long code enumeration is dense but each entry carries distinct information an agent cannot get elsewhere; the only blemish is the stray escaped newline ("\n" = ...) that breaks the 'nl' entry's formatting.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return-value explanation is not required, and the description fully documents the game-code domain plus scope caveats a caller needs. It is essentially complete for a zero-required-parameter discovery tool, missing only a note on how the detail flag changes the payload (already handled by the schema).
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the single 'detail' parameter has its enum values documented in the schema, so the schema carries the parameter burden. The description says nothing about the 'detail' option, so baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource ('Discover covered stack depths and positions') and then enumerates the exact game identifiers it returns, so an agent knows precisely what this produces. It does not explicitly differentiate itself from near-siblings like list_datasets or list_spots, but the enumerated domain makes the distinction inferable.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives an explicit usage directive: 'Call this before low-level preflop queries,' which tells the agent when to reach for it and its ordering relative to other tools. It stops short of naming the alternative tools to use once the code is known, so it is clear context rather than full when/when-not routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_library_solutionsList my saved solutionsARead-onlyIdempotentInspect
Finished postflop solutions saved for this account. None are marked done while dispatch is disabled.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | Yes | Solutions to return, 1 to 50. |
Output Schema
| Name | Required | Description |
|---|---|---|
| note | No | Why no solution is marked done. |
| solutions | No | Empty while solver dispatch is disabled. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, destructiveHint=false and openWorldHint=false, so safety and determinism are covered without the description. The description adds one genuine behavioral caveat – 'None are marked done while dispatch is disabled' – which tells the agent results may lack a completed status depending on system state, though the phrasing is cryptic and the return format/pagination is left to the output schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences with no filler, and the resource scope is front-loaded ahead of the state caveat. The second sentence is terse to the point of ambiguity but does convey information rather than padding.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a read-only list tool with full annotations, complete parameter schema and an output schema, the description supplies the essential scope plus a state caveat. Nothing critical is missing, though the dispatch caveat is underexplained.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the single 'limit' parameter is fully documented with range and default in the schema. The description adds no additional meaning about the limit, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific resource with a qualifier: 'Finished postflop solutions saved for this account.' The word 'finished' implicitly distinguishes it from list_queued_solves and get_queued_solve, so an agent can separate the completed-solution listing from the pending one. It is clear but does not explicitly name the sibling it excludes.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied by the phrase 'finished postflop solutions' – an agent can infer this is the tool for browsing already-computed results rather than queued work. However, there is no explicit when-to-use statement and no named alternative (e.g., list_queued_solves) to route to for unfinished solves.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_my_opponentsList my opponentsARead-onlyIdempotentInspect
Tracked opponents from uploaded hands. Each row has handCount, handsVsHero, and heroBb100Vs. Pass name to find one villain.
| Name | Required | Description | Default |
|---|---|---|---|
| hero | No | Only hands where this hero name was seated. | |
| name | No | Case-insensitive substring of the opponent's screen name. | |
| sort | Yes | Row order: most hands, most recent, or by hero's bb/100 against them (toughest = worst for hero). | hands |
| limit | Yes | Opponents to return, 1 to 500. | |
| game_type | No | Only hands of this game type, e.g. "NLHE" or "PLO". | |
| min_hands | Yes | Drop opponents seen in fewer hands than this. |
Output Schema
| Name | Required | Description |
|---|---|---|
| opponents | No | Opponents, sorted as requested. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, non-destructive and closed-world, so the safety profile is fully covered. The description adds the shape of each returned row (handCount, handsVsHero, heroBb100Vs), which is useful behavioral context, but says nothing about defaults, caps, or empty-result behavior.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, front-loaded with the data source before the row shape and the filter hint; nothing is wasted. Slight deduction because the row field names are dropped without context, leaving the reader to interpret heroBb100Vs on their own.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present the description need not explain returns, and the schema fully covers all six parameters plus required/minimum constraints. For a read-only list tool this is close to complete; the missing piece is any hint about the typical workflow connecting this to the per-opponent siblings.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and every parameter is documented in-schema, including the sort enum semantics and the 1-500 limit range, so the baseline is 3. The description only echoes the name filter ('find one villain') and does not add meaning beyond the schema, e.g. how it interacts with hero or min_hands.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific resource and scope: tracked opponents derived from uploaded hands, which an agent can distinguish from session/hand-level siblings. It does not explicitly name a sibling, so it stops short of a 5, but the verb+resource pairing is clear.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The only guidance is 'Pass name to find one villain,' which implies a lookup use case but gives no when-to-use versus when-not-to-use, and no routing to alternatives like get_opponent_notes for notes on a specific villain. Usage is implied rather than stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_my_sessionsList my sessionsARead-onlyIdempotentInspect
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.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | Yes | Sessions to return, 1 to 50. | |
| game_type | No | Only sessions containing this game type. |
Output Schema
| Name | Required | Description |
|---|---|---|
| hint | No | Where to upload hands when the account has none. |
| sessions | No | Sessions, newest first. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already establish read-only, idempotent, non-destructive behavior, so the description is free to add other context — and it does: newest-first ordering and the empty-state fallback flow. It does not mention pagination or result-size behavior, a minor gap for a listing tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, front-loaded with the core purpose and return fields, then the fallback instruction. Efficient and free of filler, though the second sentence packs two distinct ideas into one line.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so field-level return explanation is optional, yet the description still names key fields and the sort order. Combined with the empty-account fallback, an agent has enough to call this correctly, with only pagination behavior unaddressed.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds real meaning beyond the schema by explaining that 'game_type matches hole-card count', which clarifies the NLHE/PLO/PLO5/PLO6 enum semantics. The limit parameter is left entirely to the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Specific verb+resource ('Recent uploaded sessions') with a clear scope signal ('newest first') and an enumeration of returned fields, which separates it from detail-oriented siblings like get_session_summary. It stops short of explicitly naming the sibling it differs from, so it is clear but not fully self-differentiating.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit conditional routing for the empty-account case: fall back to get_upload_link rather than asking the user to paste histories. That is a concrete when-to-use rule, but there is no guidance on when to prefer this list view over get_session_summary or find_hands for detail.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_postflop_packsList postflop packsARead-onlyIdempotentInspect
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.
| Name | Required | Description | Default |
|---|---|---|---|
| pack | No | One pack id (75% id or the -flop33 id): per-board detail and that tree's exploitability | |
| detail | No | Response detail. "compact" is the default and removes bulk maps; use "full" only when exact complete data is required. | |
| variant | No | Only packs of this game: nlhe (hold'em) or plo5 (five-card Omaha) |
Output Schema
| Name | Required | Description |
|---|---|---|
| hint | No | How to narrow, page, or widen the same query. |
| packs | No | Packs matching `variant` and `pack`. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, and the description adds substantial domain behavior on top: pack-id conventions for the 75% vs '-flop33' trees, the PLO5 single-tree restriction, and the policy that missing exploitability is omitted rather than estimated. It also discloses that 'compact' removes bulk maps, which materially affects what an agent receives.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The opening sentence is well front-loaded with the full content of a pack, and nearly every clause carries information. However, the remainder is a dense run-on that mixes parameter semantics and output-mode behavior into one block, which would benefit from structure.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be explained; the description nonetheless clarifies the compact/full distinction and exploitability omission. For a filtered-list tool with 100% schema coverage and clear annotations, nothing an agent needs to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3. The description goes beyond the schema by explaining what the `pack` ids actually mean (75% id vs `<pack>-flop33`), that every postflop tool accepts either tree's packId, and what detail levels retain or drop, adding real domain semantics the schema cannot express.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Every solved postflop pack') and enumerates exactly what each entry contains (preflop line, positions, stack, pot, sizing trees, solved boards). It is clearly distinguishable from sibling list/get tools and explicitly positions itself relative to get_postflop_node.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives strong usage direction: 'Call this before get_postflop_node' establishes the workflow, and it explains how to use `variant` and `pack` to narrow the listing. It does not state when this tool should be skipped in favor of a sibling list tool (e.g., list_datasets), so it stops short of explicit when-not guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_queued_solvesList my queued solvesARead-onlyIdempotentInspect
List this account's solver-queue jobs, newest first. Jobs are not dispatched.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | Yes | Jobs to return, 1 to 50. |
Output Schema
| Name | Required | Description |
|---|---|---|
| solves | No | Queued jobs. None are dispatched. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly, idempotent, non-destructive, and closed-world, so safety is covered. The description adds two things annotations cannot convey: result ordering (newest first) and that queued jobs are not dispatched, which tells the agent this is passive inspection rather than a trigger.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences with no waste. The resource and scope lead, and the non-dispatch caveat follows immediately where it is most useful.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return shape need not be described, and annotations cover the safety profile. The description supplies scope and ordering; the only minor gap is no mention of how the queue relates to enqueue_solve or of pagination beyond the limit parameter.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the single 'limit' parameter is fully documented in the schema (range 1-50, default 20). The description adds no syntax or default information beyond that, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Specific verb+resource ('List this account's solver-queue jobs') plus ordering ('newest first'). It does not name the adjacent siblings get_queued_solve (singular fetch) or enqueue_solve, so an agent must infer the boundary itself, but the scope is unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is only implied by the verb and the scoping phrase 'this account's'; there is no explicit when-to-use statement and no pointer to get_queued_solve for single-job retrieval or enqueue_solve for adding jobs. The closest thing to guidance is the behavioral note that jobs are not dispatched.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_spotsSearch preflop spotsARead-onlyIdempotentInspect
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".
| Name | Required | Description | Default |
|---|---|---|---|
| game | Yes | "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. | |
| depth | No | Optional decision depth filter | |
| limit | No | Maximum compact rows to return (default 120, maximum 500). | |
| stack | Yes | Stack depth in big blinds | |
| detail | No | Response detail. "compact" is the default and removes bulk maps; use "full" only when exact complete data is required. | |
| offset | No | Compact pagination offset | |
| contains | No | Optional case-insensitive history substring filter |
Output Schema
| Name | Required | Description |
|---|---|---|
| game | No | Game id. |
| hint | No | How to narrow, page, or widen the same query. |
| spots | No | This page of decision nodes. |
| stack | No | Stack depth in big blinds. |
| total | No | Spots in the dataset for this stack. |
| offset | No | Offset this page started at. |
| matched | No | Spots left after the depth and contains filters. |
| returned | No | Spots in this page. |
| nextOffset | No | Offset for the next page, or null at the end. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive and the closed world, so safety is covered. The description adds real behavioral context: compact mode is paginated, results can be narrowed to avoid huge payloads, and plo9 lacks a spot index entirely — a genuine capability limitation not visible in the schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose is front-loaded and every sentence carries information; nothing is redundant with the schema. It is slightly clipped in places (the trailing plo9 sentence lacks a period), but the terse style suits an agent-facing definition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, return values need no explanation, and the game enum is fully documented in the schema. The description covers pagination, depth codes, and the plo9 exception, leaving only minor gaps such as default-vs-full detail behavior, which the schema already states.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3. The description goes beyond it by decoding the depth values (1 = RFI, 2 = vs open, 3 = 3-bet pots), which the schema only labels as an opaque "decision depth filter," and ties contains/offset to the compact pagination workflow.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ("Search valid decision nodes") scoped to a stack depth, and differentiates itself from the sibling get_node by contrast. An agent can tell this is the preflop spot index rather than a postflop node or range tool.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives concrete usage guidance (use depth, contains, and offset to narrow results without loading thousands of paths) and an explicit when-not case: plo9 has no spot index, so use get_node instead. The alternative and the condition that selects it are both named.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
upload_hand_historyUpload a hand historyAInspect
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.
| Name | Required | Description | Default |
|---|---|---|---|
| text | Yes | Raw hand history or tournament summary text. | |
| filename | No | Name to record for the paste. Defaults to "paste.txt". |
Output Schema
| Name | Required | Description |
|---|---|---|
| errors | No | Parse errors, if any. |
| filename | No | Filename recorded for the paste. |
| persisted | No | Always false: nothing is written to durable storage. |
| sessionId | No | Session id for the stored hands, or null when nothing parsed. |
| handsParsed | No | Hands parsed. |
| persistence | No | Where the hands live, "process_memory". |
| tournamentsParsed | No | Tournament summaries parsed. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare the mutation profile (readOnlyHint=false, destructiveHint=false, idempotentHint=false), so the bar is lower. The description adds real context beyond them: it shares the same ingestion pipeline as the hosted path and reports hands parsed, tournaments parsed, and errors. It omits that repeated uploads are non-idempotent, which is the one meaningful behavioral gap.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four short sentences with no filler, and the identity plus the routing advice are front-loaded. The trailing scope exclusion earns its place, though the returns sentence partly duplicates the output schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be explained, and the description still covers purpose, routing, and scope limits. The remaining gap is the non-idempotent nature of re-uploading the same paste, which the description never warns about.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so both parameters (text, filename) are already fully documented. The description only implies a size expectation via 'small paste' and adds no format or content detail beyond the schema, so the baseline 3 is correct.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource (upload a hand history paste) and immediately positions itself as a secondary path versus the primary sibling get_upload_link. An agent can tell it apart from the other upload route without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly names the preferred alternative (get_upload_link and the hosted /upload page) and the condition that selects this tool instead (a small paste). It also states a scope exclusion — it does not grade solver frequencies — leaving nothing to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
29 tool updates
- Changed
compare_strategies15 fields changed- added
Input schema / properties / baseline / descriptionAdded value: +"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." - added
Input schema / properties / baseline / properties / board / descriptionAdded value: +"Postflop only. Board in spaced form, e.g. \"3h 3d 2s\"." - added
Input schema / properties / baseline / properties / combo / descriptionAdded value: +"Postflop only. Exact two-card combo, e.g. As5s. Provide it in both contexts or neither." - added
Input schema / properties / baseline / properties / game / descriptionAdded value: +"Preflop only. Both sides must name the same game." - added
Input schema / properties / baseline / properties / hand / descriptionAdded value: +"Preflop only. One hand or class, e.g. AKs. Provide it in both contexts or neither; PLO comparisons require it." - added
Input schema / properties / baseline / properties / history / descriptionAdded value: +"Preflop only. Action path ending in the position about to act, e.g. \"UTG_60%_HJ\"." - added
Input schema / properties / baseline / properties / stack / descriptionAdded value: +"Preflop only. Stack depth in big blinds." - added
Input schema / properties / comparison / descriptionAdded value: +"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." - added
Input schema / properties / comparison / properties / board / descriptionAdded value: +"Postflop only. Board in spaced form, e.g. \"3h 3d 2s\"." - added
Input schema / properties / comparison / properties / combo / descriptionAdded value: +"Postflop only. Exact two-card combo, e.g. As5s. Provide it in both contexts or neither." - added
Input schema / properties / comparison / properties / game / descriptionAdded value: +"Preflop only. Both sides must name the same game." - added
Input schema / properties / comparison / properties / hand / descriptionAdded value: +"Preflop only. One hand or class, e.g. AKs. Provide it in both contexts or neither; PLO comparisons require it." - added
Input schema / properties / comparison / properties / history / descriptionAdded value: +"Preflop only. Action path ending in the position about to act, e.g. \"UTG_60%_HJ\"." - added
Input schema / properties / comparison / properties / stack / descriptionAdded value: +"Preflop only. Stack depth in big blinds." - changed
Output schema / (root)Previous value: -nullNew value: +{ + "description": "Coverage-first envelope: coverage and context describe the answer, result carries it.", + "properties": { + "context": { + "description": "Canonical context the answer belongs to (variant, format, stacks, positions, board, path). Null when the request is unsupported.", + "type": [ + "object", + "null" + ] + }, + "coverage": { + "description": "Whether the request was answered exactly, aggregated, or refused as out of coverage.", + "properties": { + "analyzedBoards": { + "description": "Boards actually read at the requested path.", + "type": "integer" + }, + "available": { + "description": "What is published instead.", + "type": "string" + }, + "dataClass": { + "description": "\"solver\", \"solver_aggregate\", or \"solver_comparison\".", + "type": "string" + }, + "generatedAt": { + "description": "When the pack was generated.", + "type": "string" + }, + "hasEv": { + "description": "Whether the pack ships per-combo EV.", + "type": "boolean" + }, + "matchingBoards": { + "description": "Boards matching the texture filters.", + "type": "integer" + }, + "objective": { + "description": "\"solver_ev\", \"cash_game_ev\", or \"chip_ev\".", + "type": "string" + }, + "omittedByLimit": { + "description": "Matching boards dropped by boardLimit.", + "type": "integer" + }, + "reason": { + "description": "Why the request is out of coverage.", + "type": "string" + }, + "requested": { + "description": "The format, objective, ante, or pack that was asked for.", + "type": "object" + }, + "solveQuality": { + "description": "Published exploitability and iteration counts. Omitted, never estimated, when the pack does not publish them.", + "type": "object" + }, + "source": { + "description": "Pack, board, path, generation time, and solve quality.", + "type": "object" + }, + "status": { + "description": "\"exact\", \"aggregated_report\", or \"unsupported\". Treat \"unsupported\" as a hard stop.", + "type": "string" + }, + "unavailableAtPath": { + "description": "Selected boards with no node at the path.", + "type": "integer" + } + }, + "type": "object" + }, + "result": { + "description": "Both snapshots, the per-action frequency and EV deltas, and the largest combo changes for postflop comparisons. Null when the request is unsupported.", + "type": [ + "object", + "null" + ] + }, + "schemaVersion": { + "description": "Envelope version, currently \"1.0\".", + "type": "string" + }, + "warnings": { + "description": "Caveats that must survive into any answer built on this result.", + "items": { + "description": "One caveat about how the result may be used.", + "type": "string" + }, + "type": "array" + } + }, + "type": "object" +}
- Changed
enqueue_solve12 fields changed- added
Input schema / properties / add_allin / descriptionAdded value: +"Add an all-in branch alongside the bet sizes." - added
Input schema / properties / bet_sizes / descriptionAdded value: +"Bet sizes as fractions of the pot, e.g. [0.33, 0.75]." - added
Input schema / properties / board / descriptionAdded value: +"Board to solve, e.g. \"3h 3d 2s\"." - added
Input schema / properties / effective_stack / descriptionAdded value: +"Effective stack behind, in big blinds." - added
Input schema / properties / ip_range / descriptionAdded value: +"In-position range in the same weights format." - added
Input schema / properties / iterations / descriptionAdded value: +"Requested solver iterations, 50 to 5000." - added
Input schema / properties / max_aggressions / descriptionAdded value: +"Raises allowed per street, 1 to 4." - added
Input schema / properties / oop_range / descriptionAdded value: +"Out-of-position range as hand-class weights, e.g. \"AA:1,AKs:0.42\". Defaults are left to the solver config." - added
Input schema / properties / pot / descriptionAdded value: +"Starting pot in big blinds." - added
Input schema / properties / tags / descriptionAdded value: +"Free-form tags stored with the job." - added
Input schema / properties / title / descriptionAdded value: +"Label for the job, 1 to 120 characters." - changed
Output schema / (root)Previous value: -nullNew value: +{ + "description": "One recorded solve request. Dispatch is not configured, so a job stays pending and never gets a solution id.", + "properties": { + "board": { + "description": "Board for the requested solve.", + "type": "string" + }, + "createdAt": { + "description": "ISO timestamp the job was recorded.", + "type": "string" + }, + "dispatch": { + "description": "Always \"not_configured\".", + "type": "string" + }, + "effective_stack": { + "description": "Effective stack in big blinds.", + "type": "number" + }, + "pot": { + "description": "Pot in big blinds.", + "type": "number" + }, + "queue_id": { + "description": "Id for get_queued_solve.", + "type": "integer" + }, + "reason": { + "description": "Why the job does not start a solve.", + "type": "string" + }, + "solution_id": { + "description": "Always null while dispatch is disabled.", + "type": [ + "string", + "null" + ] + }, + "status": { + "description": "\"pending\", \"running\", \"done\", or \"failed\".", + "type": "string" + }, + "title": { + "description": "Title given when the job was recorded.", + "type": "string" + } + }, + "type": "object" +}
- Changed
explain_combo1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "description": "Coverage-first envelope: coverage and context describe the answer, result carries it.", + "properties": { + "context": { + "description": "Canonical context the answer belongs to (variant, format, stacks, positions, board, path). Null when the request is unsupported.", + "type": [ + "object", + "null" + ] + }, + "coverage": { + "description": "Whether the request was answered exactly, aggregated, or refused as out of coverage.", + "properties": { + "analyzedBoards": { + "description": "Boards actually read at the requested path.", + "type": "integer" + }, + "available": { + "description": "What is published instead.", + "type": "string" + }, + "dataClass": { + "description": "\"solver\", \"solver_aggregate\", or \"solver_comparison\".", + "type": "string" + }, + "generatedAt": { + "description": "When the pack was generated.", + "type": "string" + }, + "hasEv": { + "description": "Whether the pack ships per-combo EV.", + "type": "boolean" + }, + "matchingBoards": { + "description": "Boards matching the texture filters.", + "type": "integer" + }, + "objective": { + "description": "\"solver_ev\", \"cash_game_ev\", or \"chip_ev\".", + "type": "string" + }, + "omittedByLimit": { + "description": "Matching boards dropped by boardLimit.", + "type": "integer" + }, + "reason": { + "description": "Why the request is out of coverage.", + "type": "string" + }, + "requested": { + "description": "The format, objective, ante, or pack that was asked for.", + "type": "object" + }, + "solveQuality": { + "description": "Published exploitability and iteration counts. Omitted, never estimated, when the pack does not publish them.", + "type": "object" + }, + "source": { + "description": "Pack, board, path, generation time, and solve quality.", + "type": "object" + }, + "status": { + "description": "\"exact\", \"aggregated_report\", or \"unsupported\". Treat \"unsupported\" as a hard stop.", + "type": "string" + }, + "unavailableAtPath": { + "description": "Selected boards with no node at the path.", + "type": "integer" + } + }, + "type": "object" + }, + "result": { + "description": "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.", + "type": [ + "object", + "null" + ] + }, + "schemaVersion": { + "description": "Envelope version, currently \"1.0\".", + "type": "string" + }, + "warnings": { + "description": "Caveats that must survive into any answer built on this result.", + "items": { + "description": "One caveat about how the result may be used.", + "type": "string" + }, + "type": "array" + } + }, + "type": "object" +}
- Changed
find_hands10 fields changed- changed
Input schema / properties / filter / anyOfPrevious value: -[ - { - "additionalProperties": false, - "properties": { - "facedLimp": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ] - }, - "facedThreeBet": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ] - }, - "flopBetPctPot": { - "anyOf": [ - { - "additionalProperties": false, - "properties": { - "max": { - "anyOf": [ - { - "description": "Exclusive upper bound, % of pot.", - "minimum": 0, - "type": "number" - }, - { - "type": "null" - } - ] - }, - "min": { - "anyOf": [ - { - "description": "Inclusive lower bound, % of pot.", - "minimum": 0, - "type": "number" - }, - { - "type": "null" - } - ] - } - }, - "type": "object" - }, - { - "type": "null" - } - ] - }, - "flopFacedBetPctPot": { - "anyOf": [ - { - "additionalProperties": false, - "properties": { - "max": { - "anyOf": [ - { - "description": "Exclusive upper bound, % of pot.", - "minimum": 0, - "type": "number" - }, - { - "type": "null" - } - ] - }, - "min": { - "anyOf": [ - { - "description": "Inclusive lower bound, % of pot.", - "minimum": 0, - "type": "number" - }, - { - "type": "null" - } - ] - } - }, - "type": "object" - }, - { - "type": "null" - } - ] - }, - "flopFirstAction": { - "anyOf": [ - { - "items": { - "enum": [ - "check", - "bet", - "call", - "fold", - "raise" - ], - "type": "string" - }, - "type": "array" - }, - { - "type": "null" - } - ] - }, - "flopFirstResponseToBet": { - "anyOf": [ - { - "items": { - "enum": [ - "check", - "bet", - "call", - "fold", - "raise" - ], - "type": "string" - }, - "type": "array" - }, - { - "type": "null" - } - ] - }, - "foldedToThreeBet": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ] - }, - "isIpVsPfr": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ] - }, - "isPfr": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ] - }, - "limped": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ] - }, - "pfr": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ] - }, - "position": { - "anyOf": [ - { - "items": { - "enum": [ - "UTG", - "UTG1", - "UTG2", - "MP", - "LJ", - "HJ", - "CO", - "BTN", - "SB", - "BB" - ], - "type": "string" - }, - "type": "array" - }, - { - "type": "null" - } - ] - }, - "rfi": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ] - }, - "rfiOpp": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ] - }, - "riverBetPctPot": { - "anyOf": [ - { - "additionalProperties": false, - "properties": { - "max": { - "anyOf": [ - { - "description": "Exclusive upper bound, % of pot.", - "minimum": 0, - "type": "number" - }, - { - "type": "null" - } - ] - }, - "min": { - "anyOf": [ - { - "description": "Inclusive lower bound, % of pot.", - "minimum": 0, - "type": "number" - }, - { - "type": "null" - } - ] - } - }, - "type": "object" - }, - { - "type": "null" - } - ] - }, - "riverFacedBetPctPot": { - "anyOf": [ - { - "additionalProperties": false, - "properties": { - "max": { - "anyOf": [ - { - "description": "Exclusive upper bound, % of pot.", - "minimum": 0, - "type": "number" - }, - { - "type": "null" - } - ] - }, - "min": { - "anyOf": [ - { - "description": "Inclusive lower bound, % of pot.", - "minimum": 0, - "type": "number" - }, - { - "type": "null" - } - ] - } - }, - "type": "object" - }, - { - "type": "null" - } - ] - }, - "riverFirstAction": { - "anyOf": [ - { - "items": { - "enum": [ - "check", - "bet", - "call", - "fold", - "raise" - ], - "type": "string" - }, - "type": "array" - }, - { - "type": "null" - } - ] - }, - "riverFirstResponseToBet": { - "anyOf": [ - { - "items": { - "enum": [ - "check", - "bet", - "call", - "fold", - "raise" - ], - "type": "string" - }, - "type": "array" - }, - { - "type": "null" - } - ] - }, - "sawFlop": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ] - }, - "sawShowdown": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ] - }, - "threeBet": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ] - }, - "turnBetPctPot": { - "anyOf": [ - { - "additionalProperties": false, - "properties": { - "max": { - "anyOf": [ - { - "description": "Exclusive upper bound, % of pot.", - "minimum": 0, - "type": "number" - }, - { - "type": "null" - } - ] - }, - "min": { - "anyOf": [ - { - "description": "Inclusive lower bound, % of pot.", - "minimum": 0, - "type": "number" - }, - { - "type": "null" - } - ] - } - }, - "type": "object" - }, - { - "type": "null" - } - ] - }, - "turnFacedBetPctPot": { - "anyOf": [ - { - "additionalProperties": false, - "properties": { - "max": { - "anyOf": [ - { - "description": "Exclusive upper bound, % of pot.", - "minimum": 0, - "type": "number" - }, - { - "type": "null" - } - ] - }, - "min": { - "anyOf": [ - { - "description": "Inclusive lower bound, % of pot.", - "minimum": 0, - "type": "number" - }, - { - "type": "null" - } - ] - } - }, - "type": "object" - }, - { - "type": "null" - } - ] - }, - "turnFirstAction": { - "anyOf": [ - { - "items": { - "enum": [ - "check", - "bet", - "call", - "fold", - "raise" - ], - "type": "string" - }, - "type": "array" - }, - { - "type": "null" - } - ] - }, - "turnFirstResponseToBet": { - "anyOf": [ - { - "items": { - "enum": [ - "check", - "bet", - "call", - "fold", - "raise" - ], - "type": "string" - }, - "type": "array" - }, - { - "type": "null" - } - ] - }, - "vpip": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ] - }, - "vsThreeBetAction": { - "anyOf": [ - { - "description": "Opener's action vs a 3-bet: fold, call, or raise (4-bet).", - "items": { - "enum": [ - "fold", - "call", - "raise" - ], - "type": "string" - }, - "type": "array" - }, - { - "type": "null" - } - ] - }, - "wasSrp": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ] - }, - "wasThreeBetPot": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ] - }, - "wonAtShowdown": { - "anyOf": [ - { - "type": "boolean" - }, - { - "type": "null" - } - ] - } - }, - "type": "object" - }, - { - "type": "null" - } -]New value: +[ + { + "additionalProperties": false, + "description": "Hand-level filters. Every field is optional; null means the filter is not applied.", + "properties": { + "facedLimp": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "description": "Hero acted after an opponent's open limp." + }, + "facedThreeBet": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "description": "Hero's open was 3-bet." + }, + "flopBetPctPot": { + "anyOf": [ + { + "additionalProperties": false, + "properties": { + "max": { + "anyOf": [ + { + "minimum": 0, + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Exclusive upper bound, % of pot." + }, + "min": { + "anyOf": [ + { + "minimum": 0, + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Inclusive lower bound, % of pot." + } + }, + "type": "object" + }, + { + "type": "null" + } + ], + "description": "Size of hero's flop bet, as % of pot." + }, + "flopFacedBetPctPot": { + "anyOf": [ + { + "additionalProperties": false, + "properties": { + "max": { + "anyOf": [ + { + "minimum": 0, + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Exclusive upper bound, % of pot." + }, + "min": { + "anyOf": [ + { + "minimum": 0, + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Inclusive lower bound, % of pot." + } + }, + "type": "object" + }, + { + "type": "null" + } + ], + "description": "Size of the flop bet hero faced, as % of pot." + }, + "flopFirstAction": { + "anyOf": [ + { + "items": { + "enum": [ + "check", + "bet", + "call", + "fold", + "raise" + ], + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "description": "Hero's first action on the flop." + }, + "flopFirstResponseToBet": { + "anyOf": [ + { + "items": { + "enum": [ + "check", + "bet", + "call", + "fold", + "raise" + ], + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "description": "Hero's first action facing a flop bet." + }, + "foldedToThreeBet": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "description": "Hero folded to a 3-bet." + }, + "isIpVsPfr": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "description": "Hero was in position against the preflop raiser." + }, + "isPfr": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "description": "Hero was the preflop raiser." + }, + "limped": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "description": "Hero open-limped." + }, + "pfr": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "description": "Hero raised preflop." + }, + "position": { + "anyOf": [ + { + "items": { + "enum": [ + "UTG", + "UTG1", + "UTG2", + "MP", + "LJ", + "HJ", + "CO", + "BTN", + "SB", + "BB" + ], + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "description": "Keep hands where hero sat in one of these seats." + }, + "rfi": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "description": "Hero raised first in." + }, + "rfiOpp": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "description": "Hero had a raise-first-in opportunity (folded to hero)." + }, + "riverBetPctPot": { + "anyOf": [ + { + "additionalProperties": false, + "properties": { + "max": { + "anyOf": [ + { + "minimum": 0, + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Exclusive upper bound, % of pot." + }, + "min": { + "anyOf": [ + { + "minimum": 0, + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Inclusive lower bound, % of pot." + } + }, + "type": "object" + }, + { + "type": "null" + } + ], + "description": "Size of hero's river bet, as % of pot." + }, + "riverFacedBetPctPot": { + "anyOf": [ + { + "additionalProperties": false, + "properties": { + "max": { + "anyOf": [ + { + "minimum": 0, + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Exclusive upper bound, % of pot." + }, + "min": { + "anyOf": [ + { + "minimum": 0, + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Inclusive lower bound, % of pot." + } + }, + "type": "object" + }, + { + "type": "null" + } + ], + "description": "Size of the river bet hero faced, as % of pot." + }, + "riverFirstAction": { + "anyOf": [ + { + "items": { + "enum": [ + "check", + "bet", + "call", + "fold", + "raise" + ], + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "description": "Hero's first action on the river." + }, + "riverFirstResponseToBet": { + "anyOf": [ + { + "items": { + "enum": [ + "check", + "bet", + "call", + "fold", + "raise" + ], + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "description": "Hero's first action facing a river bet." + }, + "sawFlop": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "description": "Hero saw a flop." + }, + "sawShowdown": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "description": "Hand reached showdown." + }, + "threeBet": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "description": "Hero 3-bet." + }, + "turnBetPctPot": { + "anyOf": [ + { + "additionalProperties": false, + "properties": { + "max": { + "anyOf": [ + { + "minimum": 0, + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Exclusive upper bound, % of pot." + }, + "min": { + "anyOf": [ + { + "minimum": 0, + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Inclusive lower bound, % of pot." + } + }, + "type": "object" + }, + { + "type": "null" + } + ], + "description": "Size of hero's turn bet, as % of pot." + }, + "turnFacedBetPctPot": { + "anyOf": [ + { + "additionalProperties": false, + "properties": { + "max": { + "anyOf": [ + { + "minimum": 0, + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Exclusive upper bound, % of pot." + }, + "min": { + "anyOf": [ + { + "minimum": 0, + "type": "number" + }, + { + "type": "null" + } + ], + "description": "Inclusive lower bound, % of pot." + } + }, + "type": "object" + }, + { + "type": "null" + } + ], + "description": "Size of the turn bet hero faced, as % of pot." + }, + "turnFirstAction": { + "anyOf": [ + { + "items": { + "enum": [ + "check", + "bet", + "call", + "fold", + "raise" + ], + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "description": "Hero's first action on the turn." + }, + "turnFirstResponseToBet": { + "anyOf": [ + { + "items": { + "enum": [ + "check", + "bet", + "call", + "fold", + "raise" + ], + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "description": "Hero's first action facing a turn bet." + }, + "vpip": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "description": "Hero put money in voluntarily." + }, + "vsThreeBetAction": { + "anyOf": [ + { + "items": { + "enum": [ + "fold", + "call", + "raise" + ], + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "description": "Opener's action vs a 3-bet: fold, call, or raise (4-bet)." + }, + "wasSrp": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "description": "Hand was a single-raised pot." + }, + "wasThreeBetPot": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "description": "Hand was a 3-bet pot." + }, + "wonAtShowdown": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "description": "Hero won at showdown." + } + }, + "type": "object" + }, + { + "type": "null" + } +] - added
Input schema / properties / filter / descriptionAdded value: +"Hand-level filters, all optional." - added
Input schema / properties / game_type / descriptionAdded value: +"Only hands of this game type. Matches hole-card count." - added
Input schema / properties / gto_plo5_rfi_bucket / descriptionAdded value: +"Solver grade bucket for PLO5 raise-first-in. Grades are not computed, so any value matches nothing." - added
Input schema / properties / gto_vs_3bet_bucket / descriptionAdded value: +"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." - added
Input schema / properties / limit / descriptionAdded value: +"Hands to return, 1 to 50." - added
Input schema / properties / session_id / descriptionAdded value: +"Only hands from this upload session (see list_my_sessions)." - added
Input schema / properties / sort / descriptionAdded value: +"Row order: newest first, largest win first, or largest loss first (the default)." - added
Input schema / properties / table_size / descriptionAdded value: +"Only hands dealt at tables of this many seats." - changed
Output schema / (root)Previous value: -nullNew value: +{ + "description": "Hands this account has uploaded.", + "properties": { + "gto": { + "description": "Always \"not graded\": solver grades are not attached.", + "type": "string" + }, + "gtoNote": { + "description": "Why a solver-grade filter matches nothing.", + "type": "string" + }, + "hands": { + "description": "Matching hands, sorted as requested.", + "items": { + "description": "One uploaded hand.", + "properties": { + "board": { + "description": "Board as dealt.", + "type": [ + "string", + "null" + ] + }, + "cards": { + "description": "Hero's hole cards.", + "type": [ + "string", + "null" + ] + }, + "flop": { + "description": "Flop action lines.", + "items": { + "description": "One flop action line.", + "type": "string" + }, + "type": "array" + }, + "game": { + "description": "Game type: \"NLHE\", \"PLO\", \"PLO5\", or \"PLO6\".", + "type": "string" + }, + "gto_plo5_rfi_bucket": { + "description": "Solver grade bucket. Not filled: grades are not computed.", + "type": [ + "string", + "null" + ] + }, + "gto_status": { + "description": "Always \"not_graded\": no solver frequency is attached to uploaded hands.", + "type": "string" + }, + "gto_vs_3bet_bucket": { + "description": "Solver grade bucket. Not filled: grades are not computed.", + "type": [ + "string", + "null" + ] + }, + "handAt": { + "description": "Hand timestamp as written in the history.", + "type": [ + "string", + "null" + ] + }, + "hand_id": { + "description": "Stable id for this hand.", + "type": "string" + }, + "netBb": { + "description": "Hero's result in big blinds.", + "type": "number" + }, + "position": { + "description": "Hero's seat, e.g. BTN.", + "type": [ + "string", + "null" + ] + }, + "potType": { + "description": "Preflop pot type, e.g. \"srp\" or \"3bet\".", + "type": [ + "string", + "null" + ] + }, + "preflop": { + "description": "Preflop action lines.", + "items": { + "description": "One preflop action line.", + "type": "string" + }, + "type": "array" + }, + "river": { + "description": "River action lines.", + "items": { + "description": "One river action line.", + "type": "string" + }, + "type": "array" + }, + "session_id": { + "description": "Upload session the hand came from.", + "type": "string" + }, + "source_hand_id": { + "description": "Hand id printed by the original site.", + "type": [ + "string", + "null" + ] + }, + "table_size": { + "description": "Seats at the table.", + "type": [ + "number", + "null" + ] + }, + "timezone": { + "description": "Timezone label from the history.", + "type": [ + "string", + "null" + ] + }, + "turn": { + "description": "Turn action lines.", + "items": { + "description": "One turn action line.", + "type": "string" + }, + "type": "array" + }, + "vsThreeBetAction": { + "description": "Hero's action facing a 3-bet: \"fold\", \"call\", or \"raise\".", + "type": [ + "string", + "null" + ] + } + }, + "type": "object" + }, + "type": "array" + }, + "hint": { + "description": "Where to upload hands when the account has none.", + "type": "string" + }, + "returned": { + "description": "Hands in this response.", + "type": "integer" + }, + "total": { + "description": "Matching hands before the limit.", + "type": "integer" + } + }, + "type": "object" +}
- Changed
get_board_report7 fields changed- added
Input schema / properties / filters / descriptionAdded value: +"Texture filters applied to the pack's solved boards. All optional; omit for every board." - added
Input schema / properties / filters / properties / connectivity / descriptionAdded value: +"How many board cards sit inside one five-rank straight window." - added
Input schema / properties / filters / properties / highCard / descriptionAdded value: +"Exact highest board rank." - added
Input schema / properties / filters / properties / highCardClass / descriptionAdded value: +"Highest board rank bucketed: ace, ten through king, seven through nine, or lower." - added
Input schema / properties / filters / properties / pairedness / descriptionAdded value: +"Rank repetition on the board." - added
Input schema / properties / filters / properties / suitTexture / descriptionAdded value: +"Most cards of one suit on the board. A three-card monotone flop is monotone." - changed
Output schema / (root)Previous value: -nullNew value: +{ + "description": "Coverage-first envelope: coverage and context describe the answer, result carries it.", + "properties": { + "context": { + "description": "Canonical context the answer belongs to (variant, format, stacks, positions, board, path). Null when the request is unsupported.", + "type": [ + "object", + "null" + ] + }, + "coverage": { + "description": "Whether the request was answered exactly, aggregated, or refused as out of coverage.", + "properties": { + "analyzedBoards": { + "description": "Boards actually read at the requested path.", + "type": "integer" + }, + "available": { + "description": "What is published instead.", + "type": "string" + }, + "dataClass": { + "description": "\"solver\", \"solver_aggregate\", or \"solver_comparison\".", + "type": "string" + }, + "generatedAt": { + "description": "When the pack was generated.", + "type": "string" + }, + "hasEv": { + "description": "Whether the pack ships per-combo EV.", + "type": "boolean" + }, + "matchingBoards": { + "description": "Boards matching the texture filters.", + "type": "integer" + }, + "objective": { + "description": "\"solver_ev\", \"cash_game_ev\", or \"chip_ev\".", + "type": "string" + }, + "omittedByLimit": { + "description": "Matching boards dropped by boardLimit.", + "type": "integer" + }, + "reason": { + "description": "Why the request is out of coverage.", + "type": "string" + }, + "requested": { + "description": "The format, objective, ante, or pack that was asked for.", + "type": "object" + }, + "solveQuality": { + "description": "Published exploitability and iteration counts. Omitted, never estimated, when the pack does not publish them.", + "type": "object" + }, + "source": { + "description": "Pack, board, path, generation time, and solve quality.", + "type": "object" + }, + "status": { + "description": "\"exact\", \"aggregated_report\", or \"unsupported\". Treat \"unsupported\" as a hard stop.", + "type": "string" + }, + "unavailableAtPath": { + "description": "Selected boards with no node at the path.", + "type": "integer" + } + }, + "type": "object" + }, + "result": { + "description": "Action frequencies and range composition aggregated across solved boards, with equal weight per board, plus representative boards. Null when the request is unsupported.", + "type": [ + "object", + "null" + ] + }, + "schemaVersion": { + "description": "Envelope version, currently \"1.0\".", + "type": "string" + }, + "warnings": { + "description": "Caveats that must survive into any answer built on this result.", + "items": { + "description": "One caveat about how the result may be used.", + "type": "string" + }, + "type": "array" + } + }, + "type": "object" +}
- Changed
get_config1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "description": "Table setup for one preflop game and stack, in big blinds. Convergence is not published.", + "properties": { + "ante": { + "description": "Ante in big blinds.", + "type": "number" + }, + "antePostedBy": { + "description": "Seat that posts the ante.", + "type": [ + "string", + "null" + ] + }, + "blinds": { + "description": "Blinds in big blinds.", + "properties": { + "bb": { + "description": "Big blind, 1.", + "type": "number" + }, + "sb": { + "description": "Small blind, 0.5.", + "type": "number" + } + }, + "type": "object" + }, + "evBaseline": { + "description": "What EV is measured against, \"fold\".", + "type": "string" + }, + "evUnit": { + "description": "EV unit, \"sb\".", + "type": "string" + }, + "game": { + "description": "Game id.", + "type": "string" + }, + "openSizes": { + "description": "First-in raise-to sizes, by seat, with label and sizeBb.", + "type": "object" + }, + "schemaVersion": { + "description": "Payload version, 1.", + "type": "number" + }, + "seats": { + "description": "Seats in action order.", + "items": { + "description": "Seat label.", + "type": "string" + }, + "type": "array" + }, + "stack": { + "description": "Stack depth in big blinds.", + "type": "number" + }, + "stackIncludesAnte": { + "description": "True when the named depth already contains the ante.", + "type": "boolean" + }, + "stacks": { + "description": "Starting stacks per seat. Null where the depth is solved against a different stack (10bb all-in/fold versus 50bb).", + "items": { + "description": "Starting stack in big blinds.", + "type": "number" + }, + "type": [ + "array", + "null" + ] + }, + "units": { + "description": "Unit labels for stack, stacks, blinds, ante, openSizes, and evs.", + "type": "object" + } + }, + "type": "object" +}
- Changed
get_exploitability2 fields changed- added
Input schema / properties / game / descriptionAdded value: +"Preflop game id to report on, e.g. \"nl\" or \"nlmtt8\". Any known game answers \"not available\"." - changed
Output schema / (root)Previous value: -nullNew value: +{ + "description": "Preflop exploitability for one game. No preflop dataset publishes one, so the answer is always unavailable and never a number.", + "properties": { + "available": { + "description": "Always false.", + "type": "boolean" + }, + "convergence": { + "description": "Always null.", + "type": [ + "number", + "null" + ] + }, + "dataset": { + "description": "Dataset the game maps to, or null when unknown.", + "type": [ + "string", + "null" + ] + }, + "exploitability": { + "description": "Always null: no figure is published or estimated.", + "type": [ + "number", + "null" + ] + }, + "game": { + "description": "Game id, echoed.", + "type": "string" + }, + "iterations": { + "description": "Always null.", + "type": [ + "number", + "null" + ] + }, + "reason": { + "description": "Why no number is returned.", + "type": "string" + }, + "status": { + "description": "Always \"not available\".", + "type": "string" + } + }, + "type": "object" +}
- Changed
get_hand_results3 fields changed- added
Input schema / properties / max_points / descriptionAdded value: +"Points on the curve after downsampling, 2 to 200." - added
Input schema / properties / session_id / descriptionAdded value: +"Only this upload session's hands. Omit for the whole account." - changed
Output schema / (root)Previous value: -nullNew value: +{ + "description": "Cumulative result per hand, for a winnings curve.", + "properties": { + "hint": { + "description": "Where to upload hands when the account has none.", + "type": "string" + }, + "netBb": { + "description": "Final cumulative result in big blinds.", + "type": "number" + }, + "points": { + "description": "Downsampled curve, oldest to newest.", + "items": { + "description": "One point on the curve.", + "properties": { + "bb": { + "description": "Cumulative result in big blinds.", + "type": "number" + }, + "hand": { + "description": "Hand number, oldest first.", + "type": "integer" + } + }, + "type": "object" + }, + "type": "array" + }, + "totalHands": { + "description": "Hands behind the curve.", + "type": "integer" + } + }, + "type": "object" +}
- Changed
get_node1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "description": "Every action at one preflop decision node.", + "properties": { + "actions": { + "description": "Actions at the node.", + "items": { + "description": "One action available at a preflop node.", + "properties": { + "action": { + "description": "Action token, e.g. \"Fold\", \"Open\", \"3B\".", + "type": "string" + }, + "combos": { + "description": "Combos that take this action.", + "type": "number" + }, + "evSb": { + "description": "EV in small blinds for the requested hand, if scored.", + "type": [ + "number", + "null" + ] + }, + "evs": { + "additionalProperties": { + "description": "EV in small blinds relative to folding.", + "type": "number" + }, + "description": "Hand class to EV, only where the solved bundle scored the hand.", + "type": "object" + }, + "frequency": { + "description": "Frequency for the requested hand, or the action total.", + "type": "number" + }, + "kind": { + "description": "Action family, e.g. \"fold\", \"call\", \"raise\".", + "type": [ + "string", + "null" + ] + }, + "sizeBb": { + "description": "Raise-to size in big blinds, for raising actions.", + "type": "number" + }, + "sizePctPot": { + "description": "Raise size as a percent of the pot after calling.", + "type": "number" + }, + "weights": { + "additionalProperties": { + "description": "Action frequency from 0 to 1.", + "type": "number" + }, + "description": "Hand class to frequency. An omitted class has weight 0.", + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "actor": { + "description": "Position to act at this node.", + "type": "string" + }, + "continuingCombos": { + "description": "Combos that continue past this node.", + "type": "number" + }, + "continuingHands": { + "description": "Hand classes that continue past this node.", + "type": "number" + }, + "evBaseline": { + "description": "What EV is measured against, \"fold\".", + "type": "string" + }, + "evUnit": { + "description": "EV unit, \"sb\".", + "type": "string" + }, + "game": { + "description": "Preflop game id, e.g. \"nl\" or \"nlmtt8\".", + "type": "string" + }, + "hand": { + "description": "The requested hand, when one was asked for.", + "type": "string" + }, + "hint": { + "description": "How to narrow, page, or widen the same query.", + "type": "string" + }, + "history": { + "description": "Action path ending in the acting position.", + "type": "string" + }, + "schemaVersion": { + "description": "Payload version, 1.", + "type": "number" + }, + "spot": { + "description": "Action path ending in an action, echoed from the request.", + "type": "string" + }, + "stack": { + "description": "Stack depth in big blinds.", + "type": "number" + }, + "units": { + "description": "Unit labels: stack and sizeBb in bb, evs in sb.", + "type": "object" + }, + "version": { + "description": "Dataset version where the bundle publishes one.", + "type": "number" + } + }, + "type": "object" +}
- Changed
get_opponent_limp_range7 fields changed- added
Input schema / properties / game_type / descriptionAdded value: +"Only hands of this game type." - added
Input schema / properties / limit / descriptionAdded value: +"Hole-card classes to return, most frequent first, 1 to 169." - added
Input schema / properties / opponent_id / descriptionAdded value: +"Only this opponent's limps (see list_my_opponents). Omit for every tracked villain." - added
Input schema / properties / position / descriptionAdded value: +"Only limps from these seats." - added
Input schema / properties / session_id / descriptionAdded value: +"Only hands from this upload session." - added
Input schema / properties / table_size / descriptionAdded value: +"Only hands dealt at tables of this many seats." - changed
Output schema / (root)Previous value: -nullNew value: +{ + "description": "Shown-hand first-in limp range from uploaded hands. Observed counts, not a solver range.", + "properties": { + "classes": { + "description": "Observed classes, most frequent first. Counts, not solver frequencies.", + "items": { + "description": "One observed hole-card class.", + "properties": { + "count": { + "description": "Times the class was shown.", + "type": "integer" + }, + "hand": { + "description": "169-grid class, e.g. AKs.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "classesByPosition": { + "additionalProperties": { + "description": "Observed classes, most frequent first. Counts, not solver frequencies.", + "items": { + "description": "One observed hole-card class.", + "properties": { + "count": { + "description": "Times the class was shown.", + "type": "integer" + }, + "hand": { + "description": "169-grid class, e.g. AKs.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "description": "Seat label to that seat's observed classes.", + "type": "object" + }, + "note": { + "description": "That the sample is showdown-only and the counts are observations.", + "type": "string" + }, + "sample": { + "description": "Shown limped hands behind the counts.", + "type": "integer" + } + }, + "type": "object" +}
- Changed
get_opponent_notes2 fields changed- added
Input schema / properties / opponent_id / descriptionAdded value: +"Opponent id from list_my_opponents." - changed
Output schema / (root)Previous value: -nullNew value: +{ + "description": "Leak notes computed from uploaded hands for one opponent.", + "properties": { + "display_name": { + "description": "Screen name as written in the history.", + "type": "string" + }, + "error": { + "description": "Present instead of a payload when the request named something that does not exist. No figure is estimated in its place.", + "type": "string" + }, + "notes": { + "description": "Notes, or a single line saying the sample is too small.", + "items": { + "description": "One note, with the sample size it rests on.", + "type": "string" + }, + "type": "array" + }, + "opponent_id": { + "description": "Opponent id, echoed.", + "type": "string" + } + }, + "type": "object" +}
- Changed
get_postflop_node1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "description": "One postflop solver node: the acting player's strategy and the legal next segments.", + "properties": { + "actingPlayer": { + "description": "0 for out of position, 1 for in position.", + "type": [ + "integer", + "null" + ] + }, + "actionFreqs": { + "description": "Full detail: aggregate frequency per action.", + "items": { + "description": "Reach-weighted frequency for the action at this index.", + "type": "number" + }, + "type": "array" + }, + "actions": { + "description": "Actions at the node with their reach-weighted frequency.", + "items": { + "description": "One action available at a postflop node.", + "properties": { + "action": { + "description": "Action segment including its size, e.g. \"Bet 5.5\".", + "type": "string" + }, + "actionType": { + "description": "Action label without the size.", + "type": "string" + }, + "addBb": { + "description": "Chips this action adds, in big blinds.", + "type": "number" + }, + "comparisonKey": { + "description": "Size-normalised action key used to line two nodes up, e.g. \"Bet 75% pot\".", + "type": "string" + }, + "evBb": { + "description": "Action EV in big blinds where the pack publishes it.", + "type": [ + "number", + "null" + ] + }, + "evLossBb": { + "description": "EV given up against the best action, in big blinds.", + "type": [ + "number", + "null" + ] + }, + "frequency": { + "description": "Reach-weighted frequency from 0 to 1.", + "type": "number" + }, + "label": { + "description": "Action label, e.g. \"Check\", \"Bet\", \"Call\".", + "type": "string" + }, + "sizePotPct": { + "description": "Bet size as a percent of the pot, bets only.", + "type": [ + "number", + "null" + ] + } + }, + "type": "object" + }, + "type": "array" + }, + "board": { + "anyOf": [ + { + "description": "Board in spaced form.", + "type": "string" + }, + { + "description": "Cards visible at this node.", + "items": { + "description": "One card.", + "type": "string" + }, + "type": "array" + } + ], + "description": "Board at this node." + }, + "childSegments": { + "description": "Append one of these to `path` to walk deeper.", + "items": { + "description": "An action like \"Bet 5.5\" or a runout like \"deal:7c\".", + "type": "string" + }, + "type": "array" + }, + "columns": { + "description": "Column order for `hands`: combo, reach, frequencies, evBb, evLossBb, actionEvBb.", + "items": { + "description": "Column name.", + "type": "string" + }, + "type": "array" + }, + "combo": { + "description": "The requested combo, when one was asked for.", + "type": "string" + }, + "hands": { + "description": "Compact rows in `columns` order, or the full per-combo strategy objects in full detail.", + "items": { + "anyOf": [ + { + "description": "One compact row.", + "type": "array" + }, + { + "description": "One combo's stored strategy.", + "type": "object" + } + ] + }, + "type": "array" + }, + "hint": { + "description": "How to narrow, page, or widen the same query.", + "type": "string" + }, + "node": { + "description": "Full detail: the stored node. Null at a chance point, where runouts hang directly under the path.", + "type": [ + "object", + "null" + ] + }, + "path": { + "description": "Segments walked from the root to this node.", + "items": { + "description": "One segment from the root.", + "type": "string" + }, + "type": [ + "array", + "null" + ] + }, + "potBb": { + "description": "Pot at this node in big blinds.", + "type": [ + "number", + "null" + ] + }, + "reach": { + "description": "Full detail: the acting player's per-combo reach.", + "items": { + "description": "A combo and its reach weight.", + "type": "array" + }, + "type": "array" + }, + "summary": { + "description": "What the compact range left out, so nothing looks complete when it is sampled.", + "properties": { + "classes": { + "description": "Postflop: hand classes with reach at the node.", + "type": "integer" + }, + "matchingHands": { + "description": "plo5: classes that take the action before the cut.", + "type": "integer" + }, + "minFreq": { + "description": "plo5: the frequency floor applied.", + "type": "number" + }, + "mixedHands": { + "description": "Classes strictly between 0.005 and 0.995.", + "type": "integer" + }, + "mixedInReturned": { + "description": "plo5: mixed classes among the returned rows.", + "type": "integer" + }, + "nonzeroHands": { + "description": "Hand classes with a frequency above 0.", + "type": "integer" + }, + "omitted": { + "description": "Rows dropped by the compact cut.", + "type": "integer" + }, + "pureHands": { + "description": "Classes at frequency 0.995 or higher.", + "type": "integer" + }, + "pureInReturned": { + "description": "plo5: pure classes among the returned rows.", + "type": "integer" + }, + "returned": { + "description": "Rows in this response.", + "type": "integer" + } + }, + "type": "object" + } + }, + "type": "object" +}
- Changed
get_postflop_range4 fields changed- added
Input schema / properties / hand / descriptionAdded value: +"Optional exact combo (AsKh) or hand class (AKs) for one frequency instead of reading the whole range." - added
Input schema / properties / minFreq / descriptionAdded value: +"Drop classes at or below this weight. Default 0." - added
Input schema / properties / tree / descriptionAdded value: +"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." - changed
Output schema / (root)Previous value: -nullNew value: +{ + "description": "The range a player takes one flop action with, as hand-class weights.", + "properties": { + "action": { + "description": "The action whose range this is.", + "type": "string" + }, + "board": { + "description": "Canonical board as stored in the pack.", + "type": "string" + }, + "error": { + "description": "Present instead of a payload when the request named something that does not exist. No figure is estimated in its place.", + "type": "string" + }, + "hand": { + "description": "The requested hand, when one was asked for.", + "properties": { + "frequency": { + "description": "Reach-weighted frequency from 0 to 1.", + "type": "number" + }, + "hand": { + "description": "Hand or class the frequency belongs to.", + "type": "string" + } + }, + "type": "object" + }, + "pack": { + "description": "Pack id the range was read from, after tree resolution.", + "type": "string" + }, + "path": { + "description": "Flop actions, ending in the action asked for.", + "items": { + "description": "One flop action.", + "type": "string" + }, + "type": "array" + }, + "range": { + "description": "Hand-class weights as \"AA:1,AKs:0.42,…\", the preflop range format.", + "type": "string" + }, + "summary": { + "description": "What the compact range left out, so nothing looks complete when it is sampled.", + "properties": { + "classes": { + "description": "Postflop: hand classes with reach at the node.", + "type": "integer" + }, + "matchingHands": { + "description": "plo5: classes that take the action before the cut.", + "type": "integer" + }, + "minFreq": { + "description": "plo5: the frequency floor applied.", + "type": "number" + }, + "mixedHands": { + "description": "Classes strictly between 0.005 and 0.995.", + "type": "integer" + }, + "mixedInReturned": { + "description": "plo5: mixed classes among the returned rows.", + "type": "integer" + }, + "nonzeroHands": { + "description": "Hand classes with a frequency above 0.", + "type": "integer" + }, + "omitted": { + "description": "Rows dropped by the compact cut.", + "type": "integer" + }, + "pureHands": { + "description": "Classes at frequency 0.995 or higher.", + "type": "integer" + }, + "pureInReturned": { + "description": "plo5: pure classes among the returned rows.", + "type": "integer" + }, + "returned": { + "description": "Rows in this response.", + "type": "integer" + } + }, + "type": "object" + }, + "tree": { + "description": "Bet-size tree, \"33\" or \"75\".", + "type": "string" + }, + "weights": { + "additionalProperties": { + "description": "Action frequency from 0 to 1.", + "type": "number" + }, + "description": "Hand class to frequency. An omitted class has weight 0.", + "type": "object" + } + }, + "type": "object" +}
- Changed
get_queued_solve2 fields changed- added
Input schema / properties / queue_id / descriptionAdded value: +"Queue id returned by enqueue_solve." - changed
Output schema / (root)Previous value: -nullNew value: +{ + "description": "One recorded solve request. Dispatch is not configured, so a job stays pending and never gets a solution id.", + "properties": { + "board": { + "description": "Board for the requested solve.", + "type": "string" + }, + "createdAt": { + "description": "ISO timestamp the job was recorded.", + "type": "string" + }, + "dispatch": { + "description": "Always \"not_configured\".", + "type": "string" + }, + "effective_stack": { + "description": "Effective stack in big blinds.", + "type": "number" + }, + "pot": { + "description": "Pot in big blinds.", + "type": "number" + }, + "queue_id": { + "description": "Id for get_queued_solve.", + "type": "integer" + }, + "reason": { + "description": "Why the job does not start a solve.", + "type": "string" + }, + "solution_id": { + "description": "Always null while dispatch is disabled.", + "type": [ + "string", + "null" + ] + }, + "status": { + "description": "\"pending\", \"running\", \"done\", or \"failed\".", + "type": "string" + }, + "title": { + "description": "Title given when the job was recorded.", + "type": "string" + } + }, + "type": "object" +}
- Changed
get_range1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "description": "One action's range: hand-class frequencies, and EV where the bundle scored it.", + "properties": { + "action": { + "description": "plo5: the action the range belongs to.", + "type": "string" + }, + "actor": { + "description": "Position to act at this node.", + "type": "string" + }, + "columns": { + "description": "Column order for `range`: hand, frequency, evSb.", + "items": { + "description": "Column name.", + "type": "string" + }, + "type": "array" + }, + "combos": { + "description": "Combos in the range.", + "type": "number" + }, + "ev": { + "description": "Full detail: EV of the requested hand in small blinds.", + "type": [ + "number", + "null" + ] + }, + "evSb": { + "description": "EV of the requested hand in small blinds.", + "type": [ + "number", + "null" + ] + }, + "evs": { + "additionalProperties": { + "description": "EV in small blinds relative to folding.", + "type": "number" + }, + "description": "Hand class to EV, only where the solved bundle scored the hand.", + "type": "object" + }, + "freq": { + "description": "Full detail: frequency of the requested hand.", + "type": "number" + }, + "frequency": { + "description": "Frequency of the requested hand, 0 to 1.", + "type": "number" + }, + "game": { + "description": "Preflop game id, e.g. \"nl\" or \"nlmtt8\".", + "type": "string" + }, + "hand": { + "description": "The requested hand, when one was asked for.", + "type": "string" + }, + "hands": { + "description": "Hand classes in the range.", + "type": "number" + }, + "hint": { + "description": "How to narrow, page, or widen the same query.", + "type": "string" + }, + "history": { + "description": "Action path ending in the acting position.", + "type": "string" + }, + "kind": { + "description": "plo5: the action family.", + "type": "string" + }, + "range": { + "description": "Compact rows in `columns` order.", + "items": { + "description": "One row: hand, frequency, EV in small blinds or null.", + "type": "array" + }, + "type": "array" + }, + "spot": { + "description": "Action path ending in an action, echoed from the request.", + "type": "string" + }, + "stack": { + "description": "Stack depth in big blinds.", + "type": "number" + }, + "summary": { + "description": "What the compact range left out, so nothing looks complete when it is sampled.", + "properties": { + "classes": { + "description": "Postflop: hand classes with reach at the node.", + "type": "integer" + }, + "matchingHands": { + "description": "plo5: classes that take the action before the cut.", + "type": "integer" + }, + "minFreq": { + "description": "plo5: the frequency floor applied.", + "type": "number" + }, + "mixedHands": { + "description": "Classes strictly between 0.005 and 0.995.", + "type": "integer" + }, + "mixedInReturned": { + "description": "plo5: mixed classes among the returned rows.", + "type": "integer" + }, + "nonzeroHands": { + "description": "Hand classes with a frequency above 0.", + "type": "integer" + }, + "omitted": { + "description": "Rows dropped by the compact cut.", + "type": "integer" + }, + "pureHands": { + "description": "Classes at frequency 0.995 or higher.", + "type": "integer" + }, + "pureInReturned": { + "description": "plo5: pure classes among the returned rows.", + "type": "integer" + }, + "returned": { + "description": "Rows in this response.", + "type": "integer" + } + }, + "type": "object" + }, + "version": { + "description": "Dataset version where the bundle publishes one.", + "type": "number" + }, + "weights": { + "additionalProperties": { + "description": "Action frequency from 0 to 1.", + "type": "number" + }, + "description": "Hand class to frequency. An omitted class has weight 0.", + "type": "object" + } + }, + "type": "object" +}
- Changed
get_range_metadata3 fields changed- added
Input schema / properties / game / descriptionAdded value: +"Preflop game id, e.g. \"nl\", \"nl9\", \"nlmtt8\", \"nlh8-hydra\", \"plo\", \"plo9\", \"plo5\", \"plo6hu\"." - added
Input schema / properties / stack / descriptionAdded value: +"Stack depth in big blinds, e.g. 100." - changed
Output schema / (root)Previous value: -nullNew value: +{ + "description": "Index metadata for one preflop game, stack, and path. Never a strategy, and never an invented exploitability.", + "properties": { + "actor": { + "description": "Acting position read off the path.", + "type": [ + "string", + "null" + ] + }, + "dataset": { + "description": "Dataset the game maps to.", + "type": "string" + }, + "error": { + "description": "Present instead of a payload when the request named something that does not exist. No figure is estimated in its place.", + "type": "string" + }, + "game": { + "description": "Game id, echoed.", + "type": "string" + }, + "match": { + "description": "\"bundle\", \"node\", or \"none\".", + "type": "string" + }, + "note": { + "description": "What the match means, or that nothing was estimated.", + "type": "string" + }, + "path": { + "description": "Action path, echoed.", + "type": "string" + }, + "preflopExploitability": { + "description": "Always \"not available\".", + "type": "string" + }, + "rows": { + "description": "Matching index rows.", + "items": { + "description": "One index row.", + "properties": { + "analyzed": { + "description": "Whether the row was analyzed.", + "type": "boolean" + }, + "decisionNodes": { + "description": "Decision nodes.", + "type": [ + "number", + "null" + ] + }, + "edges": { + "description": "Edges.", + "type": [ + "number", + "null" + ] + }, + "format": { + "description": "Format label.", + "type": "string" + }, + "freqSumChecks": { + "description": "Frequency-sum checks run.", + "type": [ + "number", + "null" + ] + }, + "freqSumOff": { + "description": "Checks that came out off.", + "type": [ + "number", + "null" + ] + }, + "gzBytes": { + "description": "Compressed size in bytes.", + "type": [ + "number", + "null" + ] + }, + "hasRaiseMeta": { + "description": "Whether raise metadata is stored.", + "type": "boolean" + }, + "key": { + "description": "Row key.", + "type": "string" + }, + "manifestEdgeCount": { + "description": "Edge count from the manifest.", + "type": [ + "number", + "null" + ] + }, + "maxActions": { + "description": "Most actions on any node.", + "type": [ + "number", + "null" + ] + }, + "position": { + "description": "Acting position.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "stack": { + "description": "Stack depth in big blinds, echoed.", + "type": "number" + } + }, + "type": "object" +}
- Changed
get_session_summary2 fields changed- added
Input schema / properties / session_id / descriptionAdded value: +"Session id from list_my_sessions." - changed
Output schema / (root)Previous value: -nullNew value: +{ + "description": "Headline numbers and HUD rates for one uploaded session.", + "properties": { + "endedAt": { + "description": "Last hand timestamp.", + "type": [ + "string", + "null" + ] + }, + "error": { + "description": "Present instead of a payload when the request named something that does not exist. No figure is estimated in its place.", + "type": "string" + }, + "game_type": { + "description": "Game type: \"NLHE\", \"PLO\", \"PLO5\", or \"PLO6\".", + "type": "string" + }, + "hands": { + "description": "Hands in the session.", + "type": "integer" + }, + "hero": { + "description": "Hero name in the history.", + "type": "string" + }, + "hud": { + "description": "HUD rates over this session, as percentages.", + "properties": { + "limp": { + "description": "Open limp, percent.", + "type": "number" + }, + "pfr": { + "description": "Preflop raise, percent.", + "type": "number" + }, + "sample": { + "description": "Hands the rates are computed over.", + "type": "integer" + }, + "threeBet": { + "description": "3-bet, percent.", + "type": "number" + }, + "vpip": { + "description": "Voluntarily put money in pot, percent.", + "type": "number" + } + }, + "type": "object" + }, + "id": { + "description": "Session id.", + "type": "string" + }, + "netBb": { + "description": "Session result in big blinds.", + "type": "number" + }, + "startedAt": { + "description": "First hand timestamp.", + "type": [ + "string", + "null" + ] + } + }, + "type": "object" +}
- Changed
get_tournament_results2 fields changed- added
Input schema / properties / limit / descriptionAdded value: +"Tournament summaries to include, 1 to 500." - changed
Output schema / (root)Previous value: -nullNew value: +{ + "description": "MTT results from uploaded tournament summaries. Money is in cents.", + "properties": { + "buyInCents": { + "description": "Total buy-ins, or null when one buy-in is unknown.", + "type": [ + "number", + "null" + ] + }, + "itmPct": { + "description": "Share of tournaments that cashed, 0 to 1, or null.", + "type": [ + "number", + "null" + ] + }, + "netProfitCents": { + "description": "Received minus buy-ins, or null when a buy-in is unknown.", + "type": [ + "number", + "null" + ] + }, + "note": { + "description": "Present when no tournament summaries have been uploaded.", + "type": "string" + }, + "receivedCents": { + "description": "Total prize money received.", + "type": "number" + }, + "recent": { + "description": "Tournaments, newest first.", + "items": { + "description": "One tournament.", + "properties": { + "buyInCents": { + "description": "Buy-in in cents.", + "type": [ + "number", + "null" + ] + }, + "fieldSize": { + "description": "Entrants.", + "type": [ + "number", + "null" + ] + }, + "finish": { + "description": "Finishing place.", + "type": [ + "number", + "null" + ] + }, + "game": { + "description": "Game label from the summary.", + "type": [ + "string", + "null" + ] + }, + "id": { + "description": "Row id.", + "type": "string" + }, + "receivedCents": { + "description": "Prize received in cents.", + "type": [ + "number", + "null" + ] + }, + "sourceId": { + "description": "Tournament id from the summary file.", + "type": [ + "string", + "null" + ] + } + }, + "type": "object" + }, + "type": "array" + }, + "roi": { + "description": "Return on investment as a ratio, or null.", + "type": [ + "number", + "null" + ] + }, + "tournaments": { + "description": "Tournament summaries counted.", + "type": "integer" + } + }, + "type": "object" +}
- Changed
get_tree_docs1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "description": "Tree documentation and per-stack counts for one dataset.", + "properties": { + "coverage": { + "description": "Coverage row from the shipped README.", + "type": "string" + }, + "dataset": { + "description": "Dataset id, echoed.", + "type": "string" + }, + "error": { + "description": "Present instead of a payload when the request named something that does not exist. No figure is estimated in its place.", + "type": "string" + }, + "preflopExploitability": { + "description": "Always \"not available\".", + "type": "string" + }, + "source": { + "description": "File the coverage note came from.", + "type": "string" + }, + "stacks": { + "description": "Per-stack counts.", + "items": { + "description": "One stack depth of the dataset.", + "properties": { + "analyzed": { + "description": "Analyzed rows at this depth.", + "type": "integer" + }, + "bundles": { + "description": "Bundles at this depth, for per-bundle datasets.", + "items": { + "description": "One bundle.", + "properties": { + "analyzed": { + "description": "Whether the bundle was analyzed.", + "type": "boolean" + }, + "decisionNodes": { + "description": "Decision nodes in the bundle.", + "type": [ + "number", + "null" + ] + }, + "edges": { + "description": "Edges in the bundle.", + "type": [ + "number", + "null" + ] + }, + "gzBytes": { + "description": "Compressed size in bytes.", + "type": [ + "number", + "null" + ] + }, + "key": { + "description": "Bundle key.", + "type": "string" + }, + "position": { + "description": "Acting position the bundle covers.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "decisionNodes": { + "description": "Decision nodes across the bundles.", + "type": [ + "number", + "null" + ] + }, + "edges": { + "description": "Edges across the bundles.", + "type": [ + "number", + "null" + ] + }, + "formats": { + "description": "Formats at this depth.", + "items": { + "description": "Format label.", + "type": "string" + }, + "type": "array" + }, + "hasRaiseMeta": { + "description": "Whether raise metadata is stored.", + "type": "boolean" + }, + "note": { + "description": "How to read the rows at this depth.", + "type": "string" + }, + "positions": { + "description": "Positions at this depth.", + "items": { + "description": "Seat label.", + "type": "string" + }, + "type": "array" + }, + "rows": { + "description": "Index rows at this depth.", + "type": "integer" + }, + "sampleKeys": { + "description": "Sample keys, for per-node datasets.", + "items": { + "description": "A node key.", + "type": "string" + }, + "type": "array" + }, + "stackBb": { + "description": "Stack depth in big blinds.", + "type": [ + "number", + "null" + ] + } + }, + "type": "object" + }, + "type": "array" + } + }, + "type": "object" +}
- Changed
get_upload_link1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "description": "Hosted upload page for hand histories.", + "properties": { + "expiresAt": { + "description": "When the signed token expires, or null when unsigned.", + "type": [ + "string", + "null" + ] + }, + "primary": { + "description": "Always true: this is the primary upload path.", + "type": "boolean" + }, + "resource": { + "description": "MCP resource URI that returns the same payload.", + "type": "string" + }, + "tokenAttached": { + "description": "Whether the URL carries a signed token for this account.", + "type": "boolean" + }, + "url": { + "description": "URL to hand to the user, signed when signing is configured.", + "type": "string" + } + }, + "type": "object" +}
- Changed
list_datasets1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "description": "Preflop datasets in the shipped tree documentation.", + "properties": { + "datasets": { + "description": "Documented datasets.", + "items": { + "description": "One dataset.", + "properties": { + "analyzed": { + "description": "Rows whose bundle was analyzed.", + "type": "integer" + }, + "formats": { + "description": "Formats in the index.", + "items": { + "description": "Format label.", + "type": "string" + }, + "type": "array" + }, + "id": { + "description": "Dataset id to pass to get_tree_docs, e.g. \"nl/v2\".", + "type": "string" + }, + "perNode": { + "description": "True when index rows are per node rather than per bundle.", + "type": "boolean" + }, + "positions": { + "description": "Positions with index rows.", + "items": { + "description": "Seat label.", + "type": "string" + }, + "type": "array" + }, + "rows": { + "description": "Index rows for the dataset.", + "type": "integer" + }, + "stacks": { + "description": "Covered stack depths.", + "items": { + "description": "Stack depth in big blinds.", + "type": "number" + }, + "type": "array" + } + }, + "type": "object" + }, + "type": "array" + }, + "generated": { + "description": "Date the documentation was generated.", + "type": "string" + }, + "preflopExploitability": { + "description": "Always \"not available\": no preflop dataset publishes it.", + "type": "string" + }, + "readme": { + "description": "How to read one dataset's write-up.", + "type": "string" + }, + "source": { + "description": "Where the documentation came from, \"data/tree-docs\".", + "type": "string" + } + }, + "type": "object" +}
- Changed
list_games1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "additionalProperties": { + "description": "One game id to its covered stacks and positions. Full detail adds the bundle manifest fields.", + "properties": { + "bundleCount": { + "description": "Bundles in the dataset.", + "type": "integer" + }, + "error": { + "description": "Upstream status code when a game did not answer.", + "type": "number" + }, + "game": { + "description": "Game id.", + "type": "string" + }, + "generatedAt": { + "description": "When the dataset was generated.", + "type": "string" + }, + "positions": { + "description": "Covered positions.", + "items": { + "description": "Seat label.", + "type": "string" + }, + "type": "array" + }, + "stacks": { + "description": "Covered stack depths.", + "items": { + "description": "Stack depth in big blinds.", + "type": "number" + }, + "type": "array" + }, + "version": { + "description": "Dataset version.", + "type": "number" + } + }, + "type": "object" + }, + "description": "Coverage for every preflop game, plus what this server does not solve.", + "properties": { + "_coverage": { + "description": "Formats and objectives this server does and does not answer.", + "properties": { + "format": { + "description": "Supported formats: cash and mtt_chip_ev.", + "items": { + "description": "A supported format.", + "type": "string" + }, + "type": "array" + }, + "supportedObjectives": { + "description": "Objectives that return data.", + "items": { + "description": "A supported objective.", + "type": "string" + }, + "type": "array" + }, + "supportedTournament": { + "description": "The one certified tournament tree.", + "properties": { + "anteBb": { + "description": "BB ante in big blinds, 1.", + "type": "number" + }, + "format": { + "description": "Always \"mtt\".", + "type": "string" + }, + "game": { + "description": "Game id, \"nlmtt8\".", + "type": "string" + }, + "objective": { + "description": "Always \"chip_ev\".", + "type": "string" + }, + "tableSize": { + "description": "Seats, 8.", + "type": "integer" + } + }, + "type": "object" + }, + "unsupported": { + "description": "ICM, PKO, satellites, 9-max MTT, tournament and multiway postflop.", + "items": { + "description": "A request type with no published data.", + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + } + }, + "type": "object" +}
- Changed
list_library_solutions2 fields changed- added
Input schema / properties / limit / descriptionAdded value: +"Solutions to return, 1 to 50." - changed
Output schema / (root)Previous value: -nullNew value: +{ + "description": "Finished postflop solutions saved for this account.", + "properties": { + "note": { + "description": "Why no solution is marked done.", + "type": "string" + }, + "solutions": { + "description": "Empty while solver dispatch is disabled.", + "items": { + "description": "One finished solution.", + "type": "object" + }, + "type": "array" + } + }, + "type": "object" +}
- Changed
list_my_opponents7 fields changed- added
Input schema / properties / game_type / descriptionAdded value: +"Only hands of this game type, e.g. \"NLHE\" or \"PLO\"." - added
Input schema / properties / hero / descriptionAdded value: +"Only hands where this hero name was seated." - added
Input schema / properties / limit / descriptionAdded value: +"Opponents to return, 1 to 500." - added
Input schema / properties / min_hands / descriptionAdded value: +"Drop opponents seen in fewer hands than this." - added
Input schema / properties / name / descriptionAdded value: +"Case-insensitive substring of the opponent's screen name." - added
Input schema / properties / sort / descriptionAdded value: +"Row order: most hands, most recent, or by hero's bb/100 against them (toughest = worst for hero)." - changed
Output schema / (root)Previous value: -nullNew value: +{ + "description": "Opponents tracked across this account's uploaded hands.", + "properties": { + "opponents": { + "description": "Opponents, sorted as requested.", + "items": { + "description": "One opponent.", + "properties": { + "cbetFaced": { + "description": "Flop c-bets the opponent faced.", + "type": "integer" + }, + "cbetFold": { + "description": "Those c-bets the opponent folded to.", + "type": "integer" + }, + "displayName": { + "description": "Screen name as written in the history.", + "type": "string" + }, + "gameTypes": { + "description": "Game types seen.", + "items": { + "description": "Game type.", + "type": "string" + }, + "type": "array" + }, + "handCount": { + "description": "Hands the opponent appears in.", + "type": "integer" + }, + "handsVsHero": { + "description": "Hands played against hero.", + "type": "integer" + }, + "heroBb100Vs": { + "description": "Hero's bb/100 in hands against this opponent.", + "type": [ + "number", + "null" + ] + }, + "heroes": { + "description": "Hero accounts that faced this opponent.", + "items": { + "description": "Hero name.", + "type": "string" + }, + "type": "array" + }, + "id": { + "description": "Opponent id for get_opponent_notes.", + "type": "string" + }, + "lastSeen": { + "description": "Most recent hand timestamp.", + "type": [ + "string", + "null" + ] + }, + "net": { + "description": "Hero's net big blinds in those hands.", + "type": "number" + }, + "notes": { + "description": "Leak notes.", + "items": { + "description": "One leak note with its sample size.", + "type": "string" + }, + "type": "array" + }, + "notesCount": { + "description": "Leak notes available.", + "type": "integer" + } + }, + "type": "object" + }, + "type": "array" + } + }, + "type": "object" +}
- Changed
list_my_sessions3 fields changed- added
Input schema / properties / game_type / descriptionAdded value: +"Only sessions containing this game type." - added
Input schema / properties / limit / descriptionAdded value: +"Sessions to return, 1 to 50." - changed
Output schema / (root)Previous value: -nullNew value: +{ + "description": "Recent uploaded sessions, newest first.", + "properties": { + "hint": { + "description": "Where to upload hands when the account has none.", + "type": "string" + }, + "sessions": { + "description": "Sessions, newest first.", + "items": { + "description": "One upload session.", + "properties": { + "endedAt": { + "description": "Last hand timestamp.", + "type": [ + "string", + "null" + ] + }, + "filename": { + "description": "Uploaded filename.", + "type": "string" + }, + "game_type": { + "description": "Dominant game type in the session.", + "type": "string" + }, + "game_types": { + "description": "Every game type in the session.", + "items": { + "description": "Game type.", + "type": "string" + }, + "type": "array" + }, + "hands": { + "description": "Hands in the session.", + "type": "integer" + }, + "hero": { + "description": "Hero name in the history.", + "type": "string" + }, + "id": { + "description": "Session id.", + "type": "string" + }, + "netBb": { + "description": "Session result in big blinds.", + "type": "number" + }, + "startedAt": { + "description": "First hand timestamp.", + "type": [ + "string", + "null" + ] + } + }, + "type": "object" + }, + "type": "array" + } + }, + "type": "object" +}
- Changed
list_postflop_packs1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "description": "Solved postflop packs and their boards.", + "properties": { + "hint": { + "description": "How to narrow, page, or widen the same query.", + "type": "string" + }, + "packs": { + "description": "Packs matching `variant` and `pack`.", + "items": { + "description": "One solved pack.", + "properties": { + "actionEvCoverage": { + "description": "How action EV is reconstructed, and for how many boards.", + "type": "object" + }, + "boardCount": { + "description": "Solved boards in the pack.", + "type": "integer" + }, + "boards": { + "description": "Board names in the pack list, or per-board detail when one `pack` was requested.", + "items": { + "anyOf": [ + { + "description": "Board in spaced form, e.g. \"3h 3d 2s\".", + "type": "string" + }, + { + "description": "One solved board.", + "properties": { + "actionEv": { + "description": "Whether per-action EV can be reconstructed here.", + "type": "object" + }, + "board": { + "description": "Board in spaced form.", + "type": "string" + }, + "exploitabilityPct": { + "description": "Published exploitability as a percent of the pot. Omitted when the index has no number.", + "type": "number" + }, + "exploitabilityTree": { + "description": "Which tree the exploitability belongs to.", + "type": "string" + }, + "iterations": { + "description": "Published solver iterations.", + "type": "integer" + }, + "queryable": { + "description": "Whether nodes can be walked.", + "type": "boolean" + }, + "river": { + "description": "Whether the river is solved.", + "type": "boolean" + }, + "trees": { + "description": "Trees this board is solved under.", + "items": { + "description": "\"75\" or \"33\".", + "type": "string" + }, + "type": "array" + } + }, + "type": "object" + } + ] + }, + "type": "array" + }, + "effStackBb": { + "description": "Effective stack behind, in big blinds.", + "type": "number" + }, + "exploitability": { + "description": "\"published\" or \"not available\" for this tree. Never estimated.", + "type": "string" + }, + "generatedAt": { + "description": "When the pack was generated.", + "type": "string" + }, + "hasEv": { + "description": "Whether combos carry EV.", + "type": "boolean" + }, + "id": { + "description": "Pack id to pass as `pack`.", + "type": "string" + }, + "ipPos": { + "description": "In-position seat.", + "type": "string" + }, + "oopPos": { + "description": "Out-of-position seat.", + "type": "string" + }, + "potBb": { + "description": "Starting pot in big blinds.", + "type": "number" + }, + "preflopLine": { + "description": "Preflop line the pack starts from.", + "type": "string" + }, + "queryableBoards": { + "description": "Boards whose nodes can be walked.", + "type": "integer" + }, + "sizingTrees": { + "description": "Bet-size trees; either packId is accepted by every postflop tool.", + "items": { + "description": "One bet-size tree of this pack.", + "properties": { + "betSizing": { + "description": "What the tree bets on each street.", + "type": "string" + }, + "boards": { + "description": "Boards solved under the tree.", + "type": "integer" + }, + "missing": { + "description": "Boards the tree does not cover.", + "items": { + "description": "A board absent from this tree.", + "type": "string" + }, + "type": "array" + }, + "packId": { + "description": "Pack id that addresses this tree.", + "type": "string" + }, + "tree": { + "description": "\"75\" or \"33\".", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "stackBb": { + "description": "Starting stack in big blinds.", + "type": "number" + }, + "title": { + "description": "Human title.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + } + }, + "type": "object" +}
- Changed
list_queued_solves2 fields changed- added
Input schema / properties / limit / descriptionAdded value: +"Jobs to return, 1 to 50." - changed
Output schema / (root)Previous value: -nullNew value: +{ + "description": "This account's solver-queue jobs, newest first.", + "properties": { + "solves": { + "description": "Queued jobs. None are dispatched.", + "items": { + "description": "One recorded solve request. Dispatch is not configured, so a job stays pending and never gets a solution id.", + "properties": { + "board": { + "description": "Board for the requested solve.", + "type": "string" + }, + "createdAt": { + "description": "ISO timestamp the job was recorded.", + "type": "string" + }, + "dispatch": { + "description": "Always \"not_configured\".", + "type": "string" + }, + "effective_stack": { + "description": "Effective stack in big blinds.", + "type": "number" + }, + "pot": { + "description": "Pot in big blinds.", + "type": "number" + }, + "queue_id": { + "description": "Id for get_queued_solve.", + "type": "integer" + }, + "reason": { + "description": "Why the job does not start a solve.", + "type": "string" + }, + "solution_id": { + "description": "Always null while dispatch is disabled.", + "type": [ + "string", + "null" + ] + }, + "status": { + "description": "\"pending\", \"running\", \"done\", or \"failed\".", + "type": "string" + }, + "title": { + "description": "Title given when the job was recorded.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + } + }, + "type": "object" +}
- Changed
list_spots1 field changed- changed
Output schema / (root)Previous value: -nullNew value: +{ + "description": "Valid decision nodes for one game and stack, paginated.", + "properties": { + "game": { + "description": "Game id.", + "type": "string" + }, + "hint": { + "description": "How to narrow, page, or widen the same query.", + "type": "string" + }, + "matched": { + "description": "Spots left after the depth and contains filters.", + "type": "integer" + }, + "nextOffset": { + "description": "Offset for the next page, or null at the end.", + "type": [ + "integer", + "null" + ] + }, + "offset": { + "description": "Offset this page started at.", + "type": "integer" + }, + "returned": { + "description": "Spots in this page.", + "type": "integer" + }, + "spots": { + "description": "This page of decision nodes.", + "items": { + "description": "One decision node.", + "properties": { + "actor": { + "description": "Position to act.", + "type": "string" + }, + "depth": { + "description": "Decision depth: 1 = RFI, 2 = vs open, 3 = 3-bet pots.", + "type": "integer" + }, + "history": { + "description": "Action path ending in the acting position.", + "type": "string" + } + }, + "type": "object" + }, + "type": "array" + }, + "stack": { + "description": "Stack depth in big blinds.", + "type": "number" + }, + "total": { + "description": "Spots in the dataset for this stack.", + "type": "integer" + } + }, + "type": "object" +}
- Changed
upload_hand_history2 fields changed- added
Input schema / properties / filename / descriptionAdded value: +"Name to record for the paste. Defaults to \"paste.txt\"." - changed
Output schema / (root)Previous value: -nullNew value: +{ + "description": "Result of ingesting one pasted hand history.", + "properties": { + "errors": { + "description": "Parse errors, if any.", + "items": { + "description": "One parse error.", + "type": "string" + }, + "type": "array" + }, + "filename": { + "description": "Filename recorded for the paste.", + "type": "string" + }, + "handsParsed": { + "description": "Hands parsed.", + "type": "integer" + }, + "persisted": { + "description": "Always false: nothing is written to durable storage.", + "type": "boolean" + }, + "persistence": { + "description": "Where the hands live, \"process_memory\".", + "type": "string" + }, + "sessionId": { + "description": "Session id for the stored hands, or null when nothing parsed.", + "type": [ + "string", + "null" + ] + }, + "tournamentsParsed": { + "description": "Tournament summaries parsed.", + "type": "integer" + } + }, + "type": "object" +}
29 tool updates
- First observed
compare_strategies - First observed
enqueue_solve - First observed
explain_combo - First observed
find_hands - First observed
get_board_report - First observed
get_config - First observed
get_exploitability - First observed
get_hand_results - First observed
get_node - First observed
get_opponent_limp_range - First observed
get_opponent_notes - First observed
get_postflop_node - First observed
get_postflop_range - First observed
get_queued_solve - First observed
get_range - First observed
get_range_metadata - First observed
get_session_summary - First observed
get_tournament_results - First observed
get_tree_docs - First observed
get_upload_link - First observed
list_datasets - First observed
list_games - First observed
list_library_solutions - First observed
list_my_opponents - First observed
list_my_sessions - First observed
list_postflop_packs - First observed
list_queued_solves - First observed
list_spots - First observed
upload_hand_history
Related MCP Connectors
All-in outcome rankings with live depth, fees, verified rules, EV checks, and track records.
Exact Texas Hold'em equity and hand analysis, every runout enumerated. Free, no API key.
Real-time crypto market data, funding rates, arbitrage and trading tools from 60+ exchanges.
Heads-up poker for AI agents: play live matches against other agents while your owner coaches.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceEnables interaction with the TexasSolver poker solver to run game theory optimal (GTO) poker calculations, load preflop ranges, and build game trees with structured parameters for analyzing poker hands and strategies.-
- AlicenseAqualityDmaintenanceEnables simulated multi-table No-Limit Texas Hold'em study and decision-support, allowing users to practice against bots and get equity/pot-odds/preflop-chart advice.12MIT
- AlicenseAqualityCmaintenanceMCP server for the Pokerai API providing solver-grade GTO strategy for 6-max No-Limit Hold'em, exposed as tools for LLM agents like Claude and Cursor.524 npmMIT
- AlicenseNot gradedqualityCmaintenanceEnables heads-up Texas Hold'em river analysis by exposing exact showdown equity/call EV and restricted-tree CFR+ solve frequencies/action EVs through MCP tools. It is intended for post-session review, not live or unconstrained GTO decisions.MIT
Glama MCP Gateway
Add one secure layer between your agents and this server.