@chessceo/mcp
Model Context Protocol server for chess.ceo — 11.7M+ games, ~1.5M FIDE player profiles, opening preparation, live broadcasts.
npm · fingerprint 0a69051c96a1f26ec312bfb2 · repository · RSS
What changed
Changed 2026-10-07 13:30 UTC
2 descriptions rewritten, 1 schema or annotation change with the description left byte-identical, 2 tools added, 1 tool removed.
+ tool added: file_versions
--- pinned/get_prep_position +++ observed/get_prep_position { - "description": "A player's moves at one position: move statistics (frequency + win rate + last-played date per move) plus the actual games from that position, in one call.\n\nTwo ways in: `fide_id` + `color` reads one FIDE player's games directly, no session (the usual case). `session_token` reads a session from `prepare_opponent` (Chess.com / Lichess accounts, combined sources, or date / time-control filters).\n\nPosition input: prefer `file_id`+`node_id` when inside a prep file (server derives FEN from the tree). Otherwise pass `fen`.\n\nAUTO-EVAL: if a cloud engine instance is running, the response includes `.eval` (whichever engines that rental provides — Stockfish, Lc0, or both) so you don't need a separate cloud_analyse.\n\nReading the response — CRITICAL:\n• Win % is one weight, not a verdict. Sample size matters (3 games at 66% is noise; 300 at 55% is signal).\n• Prep is symmetric information — both sides see the same history. Assume the opponent knows the weakness you spotted.\n• Recency > career. The last 12-24 months dominate — filter your session with `start_month` if the player's repertoire shifted.\n• Opponent will deviate early. Prep is a tree — cover the 2 most likely replies at each real branching point, not one 20-move line.\n\nFor the full guide call `read_opening_prep_guide`.", + "description": "A player's moves at one position: move statistics (frequency + win rate + last-played date per move) plus the actual games from that position, in one call.\n\nTwo ways in: `fide_id` + `color` reads one FIDE player's games directly, no session (the usual case). `session_token` reads a session from `prepare_opponent` (Chess.com / Lichess accounts, combined sources, or date / time-control filters).\n\nCOMPARE: `compare` reads up to 4 sources at the same position in one call, e.g. the opponent and the user (FIDE id from their memory), two candidate opponents, or one player's FIDE games next to a session of their Chess.com games or a classical-only session. Each entry is `fide_id` + `color` or `session_token`, plus a `label`; the response has one result per source (5 games each by default) under `sources`.\n\nPosition input: prefer `file_id`+`node_id` when inside a prep file (server derives FEN from the tree). Otherwise pass `fen`.\n\nAUTO-EVAL: if a cloud engine instance is running, the response includes `.eval` (whichever engines that rental provides — Stockfish, Lc0, or both) so you don't need a separate cloud_analyse.\n\nReading the response — CRITICAL:\n• Win % is one weight, not a verdict. Sample size matters (3 games at 66% is noise; 300 at 55% is signal).\n• Prep is symmetric information — both sides see the same history. Assume the opponent knows the weakness you spotted.\n• Recency > career. The last 12-24 months dominate — filter your session with `start_month` if the player's repertoire shifted.\n• Opponent will deviate early. Prep is a tree — cover the 2 most likely replies at each real branching point, not one 20-move line.\n\nFor the full guide call `read_opening_prep_guide`.", "inputSchema": { "properties": { "color": { + "compare": { + "description": "Several sources at the same position, instead of `fide_id` / `session_token`.", + "items": { + "properties": { + "color": { + "enum": [ + "white", + "black" + ], + "type": "string" + }, + "fide_id": { + "type": "integer" + }, + "label": { + "description": "Name for this source in the response, e.g. 'opponent', 'me', 'chess.com blitz'.", + "type": "string" + }, + "session_token": { + "type": "string" + } + }, + "type": "object" + }, + "maxItems": 4, + "type": "array" + }, "fen": { "description": "Position as FEN. Only used if `node_id` is not set.", "type": "string" - "description": "Games to return (default 10; at most 10 with `fide_id`).", + "description": "Games to return per source (default 10, or 5 per source with `compare`; at most 10 with `fide_id`).", "maximum": 50, "minimum": 1, "type": "integer"
--- pinned/memory +++ observed/memory { "description": "What the user told you about themselves, saved on their chess.ceo account and shown to you at the start of every chat (all clients). Call with no arguments to read; pass fields to change them.\n\nSAVE WHEN the user states something about themselves ('this is my FIDE id', 'my chess.com is X', 'I like concrete engine lines', 'I struggle in IQP positions', 'I play the Najdorf') or asks you to remember it. Your own inference (e.g. a weakness you noticed in their games) only after the user agrees. Never save other people's data. Tell the user in one line what you saved.\n\nKinds: preference (how they like analysis), weakness, strength, repertoire, goal, other. One fact per note, max 500 characters, max 50 notes; update or merge an existing note (ids are shown as [n]) instead of adding a near-duplicate. To forget something, delete the note or set the account field to null.", "inputSchema": { + "rating": { + "description": "The level to explain at, Elo-like (null clears). The user's choice: it may differ from their FIDE rating or exist without one ('I'm about 1200 online').", + "maximum": 3500, + "minimum": 100, + "type": [ + "integer", + "null" + ] + }, "update": { "items": { "properties": {
+ tool added: natural_moves
--- pinned/read_prep_file +++ observed/read_prep_file { - "description": "Read one prep file. Response always includes `id`, `version`, `tags`. The tree/PGN part is controlled by `view` and `node_id`/`max_depth` — large files (500+ nodes) can otherwise blow the LLM's token limit.\n\n**Views** (pick the smallest one that answers your question):\n • `compact` (default) — per-node: `id`, `san`, `ply`, `nags`, `comment`, `ceoEval`, `children`. Drops `fen` and `annotations`. Typical size: ~120 chars/node vs ~330 in `full`.\n • `full` — everything (`fen`, `annotations` too). Use when you actually need the FEN inline or want to inspect arrows/highlights. On a 500+-node file this can exceed token limits.\n • `spine` — mainline only (children[0] recursively). Great for a 'what does this repertoire cover' summary.\n • `pgn` — subtree as raw PGN text (comments, NAGs, [%cal] arrows all preserved). Useful for sanity-checking formatting against reference material.\n\n**Node addressing.** Every node has a stable `id` — root is `'r'`, every other node is an 8-hex-char content hash of parent-id + SAN. Sibling insertions, deletions, variation promotions never shift ids. Pass as `node_id` (or `parent_id` for add_move / add_line) to every mutation and engine/DB tool.\n\n**Scoping.** `node_id` starts the tree from a subtree root (default `'r'`). `max_depth` caps the tree at that many plies below the anchor (default unlimited). Use both to drill into a specific branch without dumping the whole file — the LLM never needs to see the full 800-node tree at once.\n\nFor querying the tree without reading it (\"which nodes have no ceoEval?\", \"give me the mainline spine\") call `list_nodes` — cheaper than parsing a full read.\n\n**Every engine/DB tool accepts `file_id`+`node_id`** (get_position_stats, cloud_analyse, describe_position, predict_human_move, prep_snapshot, get_prep_position, quote_engine_eval). Use it whenever a file is open — the server derives the FEN from the tree, so you can't 'analyse the wrong position' by mis-typing a FEN.", + "description": "Read one prep file. Response always includes `id`, `version`, `tags`. The tree/PGN part is controlled by `view` and `node_id`/`max_depth` — large files (500+ nodes) can otherwise blow the LLM's token limit.\n\n**Views** (pick the smallest one that answers your question):\n • `compact` (default) — per-node: `id`, `san`, `ply`, `nags`, `comment`, `ceoEval`, `children`. Drops `fen` and `annotations`. Typical size: ~120 chars/node vs ~330 in `full`.\n • `full` — everything (`fen`, `annotations` too). Use when you actually need the FEN inline or want to inspect arrows/highlights. On a 500+-node file this can exceed token limits.\n • `spine` — mainline only (children[0] recursively). Great for a 'what does this repertoire cover' summary.\n • `pgn` — subtree as raw PGN text (comments, NAGs, [%cal] arrows all preserved). Useful for sanity-checking formatting against reference material.\n\n**Node addressing.** Every node has a stable `id` — root is `'r'`, every other node is an 8-hex-char content hash of parent-id + SAN. Sibling insertions, deletions, variation promotions never shift ids. Pass as `node_id` (or `parent_id` for add_move / add_line) to every mutation and engine/DB tool.\n\n**Scoping.** `node_id` starts the tree from a subtree root (default `'r'`). `max_depth` caps the tree at that many plies below the anchor (default unlimited). Use both to drill into a specific branch without dumping the whole file — the LLM never needs to see the full 800-node tree at once.\n\nFor querying the tree without reading it (\"which nodes have no ceoEval?\", \"give me the mainline spine\") call `list_nodes` — cheaper than parsing a full read.\n\n**Every engine/DB tool accepts `file_id`+`node_id`** (get_position_stats, cloud_analyse, describe_position, natural_moves, prep_snapshot, get_prep_position, quote_engine_eval). Use it whenever a file is open — the server derives the FEN from the tree, so you can't 'analyse the wrong position' by mis-typing a FEN.", "inputSchema": { "properties": { "id": { + "version": { + "description": "Read an earlier saved version of the file (numbers from file_versions). Omit for the current file. Read-only: edits always go to the current file.", + "minimum": 1, + "type": "integer" + }, "view": { "description": "Response shape. Default `compact` — drops fen + annotations to keep token count sane. See tool description for when to use each.", "enum": [
tool removed: predict_human_move
Changed 2026-10-06 15:01 UTC
3 descriptions rewritten.
--- pinned/auto_evaluate +++ observed/auto_evaluate { - "description": "Analyse a whole prep file, or the subtree under `node_id`, on the engines you choose and store the evals on every node. Example: \"analyse the whole tree with Stockfish and the human engine and save the evals\" → `{id, engines: [\"stockfish\", \"human\"]}`.\n\nEach node gets only the requested engines it is missing (`only_missing`, default true), so adding an engine later runs just that engine. Transpositions are analysed once and stamped on every node that reaches the position. Stored evals merge per engine; other engines' stored reads are kept. Results are saved after every batch of up to 10 positions.\n\n**Async job, returns immediately:** `{ job_id, target_count, already_complete, estimated_seconds }`. Poll auto_evaluate_status(job_id); cancel with auto_evaluate_cancel. Do other work between polls.\n\nNeeds running rentals for every engine you ask for (ensure_engines). Wall time ≈ target_count × movetime (engines run in parallel per position). Does not set visible NAGs: the eval symbol is your call.", + "description": "Analyse a whole prep file, or the subtree under `node_id`, on the engines you choose and store the evals on every node. Example: \"analyse the whole tree with Stockfish and the human engine and save the evals\" → `{id, engines: [\"stockfish\", \"human\"]}`.\n\nEach node gets only the requested engines it is missing (`only_missing`, default true), so adding an engine later runs just that engine. Transpositions are analysed once and stamped on every node that reaches the position. Stored evals merge per engine; other engines' stored reads are kept. Results are saved after every batch of up to 10 positions. Positions you analysed in the last 24 h (cloud_analyse, deep_analyse) are filled in first and not run again (`filled_from_recent_analysis`). Only sweep when the user asks for it; usually it is enough to analyse positions as you work.\n\n**Async job, returns immediately:** `{ job_id, target_count, already_complete, estimated_seconds }`. Poll auto_evaluate_status(job_id); cancel with auto_evaluate_cancel. Do other work between polls.\n\nNeeds running rentals for every engine you ask for (ensure_engines). Wall time ≈ target_count × movetime (engines run in parallel per position). Does not set visible NAGs: the eval symbol is your call.", "inputSchema": { "properties": { "contempt": {
--- pinned/get_prep_position +++ observed/get_prep_position { - "description": "Query one position within a prep session created by `prepare_opponent`. Returns move statistics (frequency + win rate + last-played date per move) plus the actual games played from that position, in one call.\n\nPosition input: prefer `file_id`+`node_id` when inside a prep file (server derives FEN from the tree). Otherwise pass `fen`.\n\nAUTO-EVAL: if a cloud engine instance is running, the response includes `.eval` (whichever engines that rental provides — Stockfish, Lc0, or both) so you don't need a separate cloud_analyse.\n\nReading the response — CRITICAL:\n• Win % is one weight, not a verdict. Sample size matters (3 games at 66% is noise; 300 at 55% is signal).\n• Prep is symmetric information — both sides see the same history. Assume the opponent knows the weakness you spotted.\n• Recency > career. The last 12-24 months dominate — filter your session with `start_month` if the player's repertoire shifted.\n• Opponent will deviate early. Prep is a tree — cover the 2 most likely replies at each real branching point, not one 20-move line.\n\nFor the full guide call `read_opening_prep_guide`.", + "description": "A player's moves at one position: move statistics (frequency + win rate + last-played date per move) plus the actual games from that position, in one call.\n\nTwo ways in: `fide_id` + `color` reads one FIDE player's games directly, no session (the usual case). `session_token` reads a session from `prepare_opponent` (Chess.com / Lichess accounts, combined sources, or date / time-control filters).\n\nPosition input: prefer `file_id`+`node_id` when inside a prep file (server derives FEN from the tree). Otherwise pass `fen`.\n\nAUTO-EVAL: if a cloud engine instance is running, the response includes `.eval` (whichever engines that rental provides — Stockfish, Lc0, or both) so you don't need a separate cloud_analyse.\n\nReading the response — CRITICAL:\n• Win % is one weight, not a verdict. Sample size matters (3 games at 66% is noise; 300 at 55% is signal).\n• Prep is symmetric information — both sides see the same history. Assume the opponent knows the weakness you spotted.\n• Recency > career. The last 12-24 months dominate — filter your session with `start_month` if the player's repertoire shifted.\n• Opponent will deviate early. Prep is a tree — cover the 2 most likely replies at each real branching point, not one 20-move line.\n\nFor the full guide call `read_opening_prep_guide`.", "inputSchema": { "properties": { + "color": { + "description": "The colour the player had (with `fide_id`).", + "enum": [ + "white", + "black" + ], + "type": "string" + }, "fen": { "description": "Position as FEN. Only used if `node_id` is not set.", "type": "string" + "fide_id": { + "description": "FIDE player to read directly (no session). Needs `color`.", + "type": "integer" + }, "file_id": { "description": "Prep file id — combine with `node_id` for tree-addressed position lookup.", "type": "string" - "description": "Games to return (default 10).", + "description": "Games to return (default 10; at most 10 with `fide_id`).", "maximum": 50, "minimum": 1, "type": "integer" + "moves": { + "description": "SAN moves from the start, e.g. 'e4 c5 Nf3'. Alternative to `fen`.", + "type": "string" + }, "node_id": { "description": "Node id inside `file_id`. Root is 'r'. When set, overrides `fen`.", "type": "string" - "description": "Session token from `prepare_opponent`.", + "description": "Session token from `prepare_opponent` (instead of `fide_id`).", "type": "string" } }, - "required": [ - "session_token" - ], "type": "object" }, "name": "get_prep_position"
--- pinned/prepare_opponent +++ observed/prepare_opponent { - "description": "Create a prep SESSION combining games from one or more sources — FIDE database, Chess.com account, Lichess account — with optional filters (colour, date range, time control). Returns a session `token` you pass to `get_prep_position` to query stats at any position within that filtered corpus.\n\nThis is the main opponent-prep tool. Use it whenever a user asks 'prep me against X' — call once with the right sources+filters, then walk the tree with `get_prep_position(session_token, ...)`. Sessions are cached on the server (list existing ones with `list_prep_sessions` to avoid rebuilding).\n\nSOURCES (1-10 per call, combined into one gameset):\n- `fide` — needs `fideId`. Optional filters: `color`, `startMonth`/`endMonth`, `timeControl` (`classical`|`rapid`|`blitz`), `excludeOnline`.\n- `chesscom` — needs `username`. Filters: `color`, `startMonth`/`endMonth` (**required** for chesscom/lichess), `timeControl`.\n- `lichess` — needs `username`. Same filters as chesscom; `timeControl` also accepts `bullet` on Lichess.\n\nMulti-source example: one player with both a FIDE ID and a Lichess account → two sources in one call, all their games combined into one session.\n\nGROUNDING: every claim about the opponent's repertoire must trace back to a `get_prep_position` call on this session. Don't assert 'they play sharply' or 'they hate isolated queen pawn' without pointing at actual game counts / win rates in the response. Prep is a two-player game — see `read_opening_prep_guide` before recommending an opening plan.", + "description": "Create a prep SESSION combining games from one or more sources — FIDE database, Chess.com account, Lichess account — with optional filters (colour, date range, time control). Returns a session `token` you pass to `get_prep_position` to query stats at any position within that filtered corpus.\n\nWHEN YOU NEED IT: a Chess.com or Lichess account, several sources combined, or a FIDE player with filters (date range, time control, exclude online). For ONE FIDE player and a colour with no filters, skip this: call `get_prep_position` with `fide_id` + `color` directly (no session). Sessions are owned by the user's account and cached on the server; check `list_prep_sessions` first to reuse one instead of rebuilding.\n\nSOURCES (1-10 per call, combined into one gameset):\n- `fide` — needs `fideId`. Optional filters: `color`, `startMonth`/`endMonth`, `timeControl` (`classical`|`rapid`|`blitz`), `excludeOnline`.\n- `chesscom` — needs `username`. Filters: `color`, `startMonth`/`endMonth` (**required** for chesscom/lichess), `timeControl`.\n- `lichess` — needs `username`. Same filters as chesscom; `timeControl` also accepts `bullet` on Lichess.\n\nMulti-source example: one player with both a FIDE ID and a Lichess account → two sources in one call, all their games combined into one session.\n\nGROUNDING: every claim about the opponent's repertoire must trace back to a `get_prep_position` call on this session. Don't assert 'they play sharply' or 'they hate isolated queen pawn' without pointing at actual game counts / win rates in the response. Prep is a two-player game — see `read_opening_prep_guide` before recommending an opening plan.", "inputSchema": { "properties": { "sources": {
Changed 2026-10-06 13:32 UTC
6 tools added.
+ tool added: get_games
+ tool added: memory
+ tool added: puzzle
+ tool added: puzzle_move
+ tool added: search_games
+ tool added: share
Changed 2026-10-05 14:40 UTC
15 descriptions rewritten, 4 tools added.
--- pinned/auto_evaluate +++ observed/auto_evaluate { - "description": "Walk the tree from `node_id` (default `'r'` = whole file) and populate the persistent `ceoEval` on every descendant via cloud_analyse. Requires a running cloud combo instance.\n\n**Async job — returns immediately.** Response: `{ job_id, target_count, status: 'running', estimated_seconds }`. Then poll `auto_evaluate_status(job_id)` until `done: true`. Cancel a run with `auto_evaluate_cancel(job_id)` — partial progress is preserved. Do useful other work between polls (write more of the tree, walk the opponent's repertoire) — the engine runs in the background.\n\nProgress is checkpointed to the prep file every 8 successfully-evaluated nodes, so a cancel / crash / MCP restart mid-run leaves the tree partially populated rather than losing everything. On MCP restart the job record disappears; re-run auto_evaluate and `only_missing=true` naturally skips what was already saved.\n\n**Does NOT set visible NAGs.** NAG placement is your call, not the engine's — an opening tree full of 0.00 positions doesn't need a `$10` (=) glyph on every move. Use quote_engine_eval on individual nodes before writing prose that references engine numbers.\n\nCosts real money — one cloud_analyse per node. A 200-node walk at default movetime is ~5 min of engine time (calls serialise on the per-combo semaphore in the backend).", + "description": "Analyse a whole prep file, or the subtree under `node_id`, on the engines you choose and store the evals on every node. Example: \"analyse the whole tree with Stockfish and the human engine and save the evals\" → `{id, engines: [\"stockfish\", \"human\"]}`.\n\nEach node gets only the requested engines it is missing (`only_missing`, default true), so adding an engine later runs just that engine. Transpositions are analysed once and stamped on every node that reaches the position. Stored evals merge per engine; other engines' stored reads are kept. Results are saved after every batch of up to 10 positions.\n\n**Async job, returns immediately:** `{ job_id, target_count, already_complete, estimated_seconds }`. Poll auto_evaluate_status(job_id); cancel with auto_evaluate_cancel. Do other work between polls.\n\nNeeds running rentals for every engine you ask for (ensure_engines). Wall time ≈ target_count × movetime (engines run in parallel per position). Does not set visible NAGs: the eval symbol is your call.", "inputSchema": { "properties": { + "contempt": { + "description": "lc0 only. Stored evals then carry the bias; use for idea finding, not for the stored record.", + "maximum": 100, + "minimum": -100, + "type": "integer" + }, + "engines": { + "description": "Engines to run. Default [\"stockfish\"].", + "items": { + "enum": [ + "stockfish", + "lc0", + "human" + ], + "type": "string" + }, + "type": "array" + }, "id": { + "description": "Prep file id.", "type": "string" }, "movetime_ms": { - "description": "Per-node cloud_analyse think time (default 1500).", - "maximum": 5000, + "description": "Think time per position in ms (default 2000).", + "maximum": 15000, "minimum": 500, "type": "integer" }, - "description": "Skip nodes that already carry a stored ceoEval (default true).", + "description": "Run only the engines a node has no stored eval for (default true). false re-analyses everything.", "type": "boolean" + }, + "rentals": { + "description": "Only when two running rentals provide the same engine: engine → contract_id.", + "properties": { + "human": { + "type": "string" + }, + "lc0": { + "type": "string" + }, + "stockfish": { + "type": "string" + } + }, + "type": "object" } }, "required": [
--- pinned/auto_evaluate_cancel +++ observed/auto_evaluate_cancel { - "description": "Ask a running auto_evaluate job to stop as soon as its current node finishes. Whatever progress was completed before cancellation is durably saved (checkpoint on cancel). Idempotent — cancelling an already-finished job is a no-op with a clear note in the response.", + "description": "Ask a running auto_evaluate job to stop after the batch in flight. Every batch already analysed is saved in the file. Idempotent — cancelling an already-finished job is a no-op with a clear note in the response.", "inputSchema": { "properties": { "job_id": {
--- pinned/auto_evaluate_status +++ observed/auto_evaluate_status { - "description": "Poll the status of an auto_evaluate job. Response: `{ status: 'running' | 'done' | 'cancelled' | 'error' | 'not_found', target_count, evaluated, errored, remaining, done, error?, version? }`. When `status: 'not_found'` the job either expired (kept ~15 min after completion), never existed, or the MCP restarted since it was created — re-run auto_evaluate.\n\nTypical poll cadence: every 3-5 s for small walks, every 10-30 s for large ones. Don't hammer — status is a pure in-memory read but polling doesn't speed the engine up.", + "description": "Poll the status of an auto_evaluate job. Response: `{ status: 'running' | 'done' | 'cancelled' | 'error' | 'not_found', engines, target_count, processed, remaining, evaluated: {engine: n}, failed: {engine: n}, failed_node_ids: {engine: [ids]}, last_error?, aborted_reason?, done }`. Retry failures with cloud_analyse({file_id, node_ids}) or a new auto_evaluate. When `status: 'not_found'` the job either expired (kept ~15 min after completion), never existed, or the MCP restarted since it was created — re-run auto_evaluate.\n\nTypical poll cadence: every 3-5 s for small walks, every 10-30 s for large ones. Don't hammer — status is a pure in-memory read but polling doesn't speed the engine up.", "inputSchema": { "properties": { "job_id": {
--- pinned/cloud_analyse +++ observed/cloud_analyse { - "description": "Runs a synchronous ~2s analysis on the user's running combo instance and returns both Stockfish and Lc0's final read for the FEN — depth, top-N candidate moves with scores (**scoreCp is White-POV centipawns**: +20 = White is +0.20 pawns better regardless of whose turn it is; matches the sign convention used everywhere else in this MCP, including the stored ceoEval). Mate is White-POV plies-to-mate (+5 = White mates in 5). Also returns each engine's principal variation.\n\nGROUNDING: every claim you make about a position must trace back to actual engine output from a call in THIS session. Don't invent evaluations, don't name 'best moves' you haven't seen the engine list, don't fabricate variations that 'look plausible.' Compute is cheap — call this 5-10 times while walking a tree rather than pattern-matching from your training data. When you don't have data for the position, either run the tool or say so; don't fill the gap with chess prose the user can't distinguish from measured output.\n\nAuto-picks the caller's only running combo instance; errors clearly if there are zero (start one first with start_cloud_engine) or more than one (destroy the extras first).\n\nHow to read the response:\n• Stockfish is objective truth — trust it for 'does this line hold?' 'is there a tactic?' 'is this endgame drawn?' A Stockfish 0.00 means 'objectively equal', NOT 'trivial draw' — one side can still be much harder to play in practice.\n• Lc0 is practical eval — trust it for 'which side is easier?' 'which candidate is best when Stockfish shows several as equal?' Lc0 sees long-term positional factors Stockfish's fixed search can miss.\n• When they agree → high confidence. When they disagree → look at both scores and reason WHY (Stockfish sharply higher = tactic Lc0 missed; Lc0 higher = long-term positional edge past Stockfish's horizon). Never dismiss either — the disagreement is the signal.\n\nContempt (`contempt`) skews Lc0 (only Lc0 — Stockfish always stays objective) toward White (positive) or Black (negative). Signed 0-100 strength — same scale as the web UI's ContemptStrength slider (the server multiplies by 8 to produce Lc0's internal cp bias). Typical values: ±15 for a light nudge, ±30-60 for real fighting play, ±80-100 for maximum steer. Use it to find non-objective 'practical' ideas or when the user needs to lean toward fighting/solid lines with a specific colour. Do NOT quote a contempt-biased eval as objective — cross-check with Stockfish.\n\nAlso useful: pass `moves` on top of `fen` to explore a variation without computing FENs yourself (e.g. fen='<tabiya>', moves='b4 a5 c3'). And the flip-side-to-move threat check documented in the guide is a great free trick.\n\n**PVs are capped at 6 plies by default (3 full moves), and lines that got truncated are marked with `pv_truncated: true`.** This is deliberate: the tail of a PV is where the engine's confidence collapses, AND pasting a long PV into `add_line` as if it were prepared repertoire is the #1 documented anti-pattern of this MCP — a 15-move PV is one line of engine output through positions where both sides had real choices, not a repertoire. To see further, don't raise `pv_max_plies`; instead, walk the tree one branch at a time with a fresh `cloud_analyse` at each position where the opponent has real alternatives — that's what makes it prep instead of pasted output. Only raise the cap when you're verifying a forcing sequence (a mate, a forced tactical resolution), not to build lines.\n\nFor the full guide including worked examples, call the `read_engine_usage_guide` tool.\n\nNot for casual questions — this costs real money per second. Use `get_position_stats` for anything that doesn't require deep prep.\n\n**When called with `file_id`+`node_id` (preferred inside a prep file), the resulting eval is auto-stored on that node's `ceoEval` — you can then quote it with quote_engine_eval on any later call.** This is what makes engine attribution trustworthy: prose that says 'engines say X on node Y' can only be true if a call was actually made against node_id=Y.", + "description": "Analyse up to 10 positions on the engines you choose (`stockfish`, `lc0`, `human`), each engine on whichever running rental provides it. Engines run in parallel per position. Returns, per position, each engine's depth, candidate lines and best move.\n\nPositions: `fens` (list), `lines` (list of SAN move sequences from `fen` or the start), `file_id` + `node_ids` (list), or a single `fen` / `moves` / `file_id`+`node_id`. Examples: analyse three FENs with Stockfish → `{fens: [a, b, c], engines: [\"stockfish\"]}`; with the human engine and Stockfish → `engines: [\"stockfish\", \"human\"]`. For a whole file or subtree use auto_evaluate instead.\n\nScores: `scoreCp` and `mate` are White's point of view (+20 = White +0.20; mate +5 = White mates in 5). lc0 and human lines carry `wdl`: win/draw/loss percent, White's point of view. Read the response's `eval_scale` before calling a position equal.\n\nGROUNDING: every claim about a position must trace back to engine output from this session. Don't invent evaluations, best moves or variations. When you have no data for a position, run it or say so.\n\nStoring: with `file_id`, each result is merged into the `ceoEval` of every node that reaches that position (`stored_on` in the response), keeping other engines' stored reads. quote_engine_eval cites them later. Without `file_id` nothing is lost either: results are remembered for 24 h and filled into any node reaching that position the next time you write to a file (`evals_filled` in add_move / add_line / apply_mutations responses).\n\nContempt (`contempt`, lc0 only): signed -100..100, positive favours White. Use it to find ideas (e.g. -20 makes Black play for a win). Never quote a contempt eval as objective.\n\nPVs are capped at 6 plies (`pv_truncated: true` when cut). To see further, analyse the position at the end of the line; raise `pv_max_plies` only to verify a forcing line. Don't paste PVs into add_line as prep.\n\nNeeds running rentals for the engines you ask for (see ensure_engines). Costs money while rentals run; use get_position_stats for casual questions.", "inputSchema": { "properties": { "contempt": { - "description": "Lc0 contempt bias. Signed 0-100 strength (same scale as the web UI's ContemptStrength slider — server multiplies by 8 to get the internal cp bias). 0 = objective (default). Positive favours White, negative favours Black. Typical: ±15 light nudge, ±30-60 real fighting play, ±80-100 maximum steer. Not applied to Stockfish. See engine_usage_primer for when to use.", + "description": "lc0 only. Positive favours White, negative Black. 0 = objective (default).", "maximum": 100, "minimum": -100, "type": "integer" - "description": "Which engines to run. Default = both. Use `[\"lc0\"]` to skip Stockfish (e.g. while a deep_analyse job is holding the SF slot on the same combo). Use `[\"stockfish\"]` when only the objective read matters. The skipped engine's field is omitted from the response.", + "description": "Engines to run. Default [\"stockfish\"]. Each needs a running rental that provides it.", "items": { "enum": [ "stockfish", - "lc0" + "lc0", + "human" ], "type": "string" }, - "description": "Starting position as FEN. Only used if `node_id` is not set.", + "description": "One position, or the start position for `moves` / `lines`.", "type": "string" }, + "fens": { + "description": "Positions as FENs (up to 10 in total with the other inputs).", + "items": { + "type": "string" + }, + "type": "array" + }, "file_id": { - "description": "Prep file id. **Prefer file_id+node_id over fen** when inside a prep file — the FEN comes from the tree AND the result is stored on the node.", + "description": "Prep file id. With node_ids/node_id the FEN comes from the tree; with any input, results are stored on matching nodes.", "type": "string" }, - "lc0_multipv": { - "description": "Lc0 candidate lines (default 8). Kept wide because multipv doesn't degrade Lc0's strength the way it does Stockfish's — Lc0 is the 'find inspiration / explore practical tries' leg, use a high multipv to get a full slate of ideas.", - "maximum": 10, - "minimum": 1, - "type": "integer" + "lines": { + "description": "SAN move sequences, each applied from `fen` (or the start position), e.g. [\"e4 c5 Nf3\", \"e4 e5 Nf3\"].", + "items": { + "type": "string" + }, + "type": "array" }, "moves": { - "description": "Optional SAN moves to apply on top of `fen` (or startpos). Only used if `node_id` is not set.", + "description": "SAN moves applied on top of `fen` (or the start position) for a single position.", "type": "string" }, "movetime_ms": { - "description": "Think time in milliseconds (default 2000).", - "maximum": 10000, + "description": "Think time per position in ms (default 2000).", + "maximum": 15000, "minimum": 100, "type": "integer" }, + "multipv": { + "description": "Candidate lines per engine. Defaults: stockfish 2 (extra lines cost it strength), lc0 and human 8 (wide slate of ideas, no strength cost).", + "properties": { + "human": { + "maximum": 10, + "minimum": 1, + "type": "integer" + }, + "lc0": { + "maximum": 10, + "minimum": 1, + "type": "integer" + }, + "stockfish": { + "maximum": 10, + "minimum": 1, + "type": "integer" + } + }, + "type": "object" + }, "node_id": { - "description": "Node id inside `file_id`. Root is 'r'. When set, overrides `fen`/`moves`.", + "description": "One node id inside `file_id`. Root is 'r'.", "type": "string" }, + "node_ids": { + "description": "Node ids inside `file_id`.", + "items": { + "type": "string" + }, + "type": "array" + }, "pv_max_plies": { - "description": "Cap each returned PV to this many plies (default 6 = 3 full moves). PVs beyond ~6 plies are speculative and are the anti-pattern behind pasted-engine-line 'prep' — don't raise unless you're specifically checking a forcing tactic or verifying a mate. When a line was truncated, the response marks it with `pv_truncated: true`.", + "description": "Cap each PV (default 6 plies). Raise only to verify a forcing line.", "maximum": 40, "minimum": 1, "type": "integer" - "stockfish_multipv": { - "description": "Stockfish candidate lines (default 2). Kept tight because each extra PV steals search bandwidth from the top choice — SF is the 'what's objectively best' leg, use a low multipv to keep it strong. Raise only when you specifically need SF's take on a wide range of candidates.", - "maximum": 10, - "minimum": 1, - "type": "integer" + "rentals": { + "description": "Only when two running rentals provide the same engine: engine → contract_id from list_cloud_engines.", + "properties": { + "human": { + "type": "string" + }, + "lc0": { + "type": "string" + }, + "stockfish": { + "type": "string" + } + }, + "type": "object" } }, "type": "object"
+ tool added: create_collection
--- pinned/deep_analyse +++ observed/deep_analyse { - "description": "Start a long Stockfish think on a single position (up to 5 min movetime). Returns a `job_id` immediately; poll `deep_analyse_status(job_id)` for the result, cancel with `deep_analyse_cancel(job_id)`. Runs SF only — Lc0 doesn't benefit from long thinks past a handful of seconds — and **holds only the SF engine slot on the combo, so `cloud_analyse(..., engines: [\"lc0\"])` stays available for other work in parallel**.\n\nUse this when a specific critical position deserves depth — a novelty candidate, a hairy tactical shot, a difficult endgame — and you want Stockfish at depth 35+ rather than the ~depth 22 you get from a 2s cloud_analyse. Movetime is in ms; typical: 30_000-60_000 for 'careful check', 120_000-300_000 for 'find the truth'.\n\nResult shape when done matches cloud_analyse's Stockfish leg (depth, top-N candidates with scoreCp/mate, best move, PV). Auto-stores the eval on `file_id`+`node_id` when both are supplied, same as cloud_analyse.", + "description": "Start one long think (up to 5 min) on one position, on one engine (`engine`, default stockfish). Returns a `job_id` immediately; poll deep_analyse_status, cancel with deep_analyse_cancel. It holds only that engine, so cloud_analyse on the other engines keeps working meanwhile.\n\nUse it when a critical position deserves depth: a novelty candidate, a sharp tactic, a hard endgame. Typical movetime: 30_000-60_000 for a careful check, 120_000-300_000 to find the truth.\n\nWith `file_id`+`node_id`, the result is merged into that node's ceoEval (other engines' stored reads are kept) and stamped on its transpositions.", "inputSchema": { "properties": { + "contempt": { + "description": "lc0 only.", + "maximum": 100, + "minimum": -100, + "type": "integer" + }, + "engine": { + "description": "Default stockfish.", + "enum": [ + "stockfish", + "lc0", + "human" + ], + "type": "string" + }, "fen": { "description": "Position as FEN. Only used if `node_id` is not set.", "type": "string" - "description": "Prep file id. Combine with `node_id` to derive FEN from the tree AND persist the result on the node's ceoEval.", + "description": "Prep file id. With `node_id`, the FEN comes from the tree and the result is stored on the node.", "type": "string" }, "moves": { - "description": "Number of candidate lines (default 2). Stockfish gets weaker as multipv grows — each extra PV steals search bandwidth from the top choice — so keep this low unless you specifically want to see several candidates ranked deep.", + "description": "Candidate lines. Default 2 for stockfish (extra lines cost it strength), 8 for lc0/human.", "maximum": 10, "minimum": 1, "type": "integer" + }, + "rental": { + "description": "Only when two running rentals provide this engine: the contract_id to use.", + "type": "string" } }, "type": "object"
--- pinned/deep_analyse_status +++ observed/deep_analyse_status { - "description": "Poll a deep_analyse job. Response: `{ status: 'running' | 'done' | 'cancelled' | 'error' | 'not_found', elapsed_ms, movetime_ms, result?, error? }`. `result` shape when done: `{ engine, depth, timeMs, bestMove, lines: [{rank, depth, scoreCp?, mate?, pv, nodes?}] }` — the SF leg of a cloud_analyse response.\n\nPoll cadence: every ~15-30s for long thinks; there's no penalty for polling more often but the engine progresses at its own pace.", + "description": "Poll a deep_analyse job. Response: `{ status: 'running' | 'done' | 'cancelled' | 'error' | 'not_found', elapsed_ms, movetime_ms, result?, error? }`. `result` when done: that engine's block from a cloud_analyse response (`{ depth, bestMove, lines: [{rank, depth, scoreCp?, mate?, wdl?, pv}] }`, PVs in SAN, wdl in percent); `stored_on` lists the nodes it was saved to.\n\nPoll cadence: every ~15-30s for long thinks; there's no penalty for polling more often but the engine progresses at its own pace.", "inputSchema": { "properties": { "job_id": {
+ tool added: ensure_engines
--- pinned/get_position_stats +++ observed/get_position_stats { - "description": "Move statistics + example games at a position. Answers 'how often is 4.O-O vs 4.d3 played here and which scores better'.\n\nSOURCE (default: `gm-classical`) selects a pre-aggregated database shard:\n- `gm-classical` — GM classical games (both players ≥2500, real thinking-time). BEST for opening prep — every move is signal, avgElo ~2600 across all listed moves.\n- `main` — the whole 11.7M-game DB. Widest coverage but noisiest (includes 1000-Elo blunder-fests in the move stats). Use as fallback when gm-classical's totalCount is too small to be informative.\n\nGame movetext is trimmed to the moves AFTER the queried position (using each game's plyNumber). Saves ~70% of the bytes vs full movetext.\n\nAUTO-EVAL: if a cloud combo instance is running, the response includes `.eval` with a compact Stockfish + Lc0 read and the corresponding NAG. Do NOT fire cloud_analyse separately for the same FEN. When called with `file_id`+`node_id`, the eval is also auto-stored on that node's `ceoEval` — later readable via quote_engine_eval.", + "description": "Move statistics + example games at a position. Answers 'how often is 4.O-O vs 4.d3 played here and which scores better'.\n\nSOURCE (default: `gm-classical`) selects a pre-aggregated database shard:\n- `gm-classical` — GM classical games (both players ≥2500, real thinking-time). BEST for opening prep — every move is signal, avgElo ~2600 across all listed moves.\n- `main` — the whole 11.7M-game DB. Widest coverage but noisiest (includes 1000-Elo blunder-fests in the move stats). Use as fallback when gm-classical's totalCount is too small to be informative.\n\nGame movetext is trimmed to the moves AFTER the queried position (using each game's plyNumber). Saves ~70% of the bytes vs full movetext.\n\nAUTO-EVAL: if a Stockfish rental is running, the response includes `.eval` with a short Stockfish read (cp/mate White's point of view, best move, PV). Not stored on any node; for a stored eval or other engines use cloud_analyse.", "inputSchema": { "properties": { "fen": {
--- pinned/get_prep_position +++ observed/get_prep_position { - "description": "Query one position within a prep session created by `prepare_opponent`. Returns move statistics (frequency + win rate + last-played date per move) plus the actual games played from that position, in one call.\n\nPosition input: prefer `file_id`+`node_id` when inside a prep file (server derives FEN from the tree). Otherwise pass `fen`.\n\nAUTO-EVAL: if a cloud combo instance is running, the response includes `.eval` (Stockfish + Lc0 read at the position) so you don't need a separate cloud_analyse.\n\nReading the response — CRITICAL:\n• Win % is one weight, not a verdict. Sample size matters (3 games at 66% is noise; 300 at 55% is signal).\n• Prep is symmetric information — both sides see the same history. Assume the opponent knows the weakness you spotted.\n• Recency > career. The last 12-24 months dominate — filter your session with `start_month` if the player's repertoire shifted.\n• Opponent will deviate early. Prep is a tree — cover the 2 most likely replies at each real branching point, not one 20-move line.\n\nFor the full guide call `read_opening_prep_guide`.", + "description": "Query one position within a prep session created by `prepare_opponent`. Returns move statistics (frequency + win rate + last-played date per move) plus the actual games played from that position, in one call.\n\nPosition input: prefer `file_id`+`node_id` when inside a prep file (server derives FEN from the tree). Otherwise pass `fen`.\n\nAUTO-EVAL: if a cloud engine instance is running, the response includes `.eval` (whichever engines that rental provides — Stockfish, Lc0, or both) so you don't need a separate cloud_analyse.\n\nReading the response — CRITICAL:\n• Win % is one weight, not a verdict. Sample size matters (3 games at 66% is noise; 300 at 55% is signal).\n• Prep is symmetric information — both sides see the same history. Assume the opponent knows the weakness you spotted.\n• Recency > career. The last 12-24 months dominate — filter your session with `start_month` if the player's repertoire shifted.\n• Opponent will deviate early. Prep is a tree — cover the 2 most likely replies at each real branching point, not one 20-move line.\n\nFor the full guide call `read_opening_prep_guide`.", "inputSchema": { "properties": { "fen": {
--- pinned/list_cloud_engines +++ observed/list_cloud_engines { - "description": "List the user's currently running cloud engines. Use before starting a new one, or to find the contract_id for stop_cloud_engine. `cloud_analyse` auto-picks the only running combo, so listing is only necessary when the user might have zero or several.", + "description": "List the user's running cloud engines, each with its `contractId` and `engines` (what it provides). A row with empty `engines` is still starting. Use the contractId for stop_cloud_engine, or in `rentals` when two running rentals provide the same engine.", "inputSchema": { "properties": {}, "type": "object"
--- pinned/list_cloud_machine_options +++ observed/list_cloud_machine_options { - "description": "Returns the catalog of combo cloud-engine machine types the user can start (SKU, human display name, cost per hour, availability). ALWAYS call this before start_cloud_engine — SKU strings like 'rtx-5090-64' do not match the display names ('Stockfish 32 CPUs + Lc0 1× RTX 5090') and are NOT guessable. Present the user the display names + prices; pass the SKU to start_cloud_engine.", + "description": "Returns the catalog of cloud-engine SKUs the user can start, same visibility as the chess.ceo app: SKU (`machineType`), the one engine it runs (`engine`: stockfish, lc0 or human), display name, cost per hour, availability. Also returns `engine_guide`, `eval_scale`, `eval_symbols` and `workflow`. ensure_engines already picks the cheapest SKU per engine; use this when the user wants to choose hardware. SKU strings are NOT guessable from display names; pass them verbatim to start_cloud_engine.", "inputSchema": { "properties": {}, "type": "object"
--- pinned/list_transpositions +++ observed/list_transpositions { - "description": "Group every position in a prep file that appears more than once — the same piece placement + side-to-move + castling rights reached by different move orders. Chess move orders diverge and re-converge constantly (1.d4 Nf6 2.c4 e6 3.Nc3 vs 1.c4 e6 2.Nc3 Nf6 3.d4 land on the same position); if you analyse both branches independently or write the same commentary twice, you're wasting engine time and inviting inconsistency.\n\nCall this BEFORE `auto_evaluate` on a big subtree to see how much work will actually be new, and BEFORE writing prose to know which nodes can share a comment or should point at each other with 'transposes to line X'.\n\nNote: engine evals auto-propagate — when `cloud_analyse({file_id, node_id})` stores `ceoEval` on a node, it also stamps every transposition of that position in the same file (see the response's `also_stored_on`). And `auto_evaluate({only_missing: true})` naturally skips the twin because it now has an eval. So detection is cheap AND propagation is automatic; this tool is for prose planning and one-shot audits, not for gating engine work.\n\nResponse: `{ file_id, group_count, node_count, groups: [{ position_key, size, node_ids, sans }] }`. `position_key` is the 3-field FEN prefix used as the match key; `size` is how many nodes share it; `sans` are the moves that led to each occurrence (parallel with `node_ids`, DFS order — first entry is the earliest/mainline-preferred occurrence). Only groups with size ≥ 2 are returned; sorted by size descending.", + "description": "Group every position in a prep file that appears more than once — the same piece placement + side-to-move + castling rights reached by different move orders. Chess move orders diverge and re-converge constantly (1.d4 Nf6 2.c4 e6 3.Nc3 vs 1.c4 e6 2.Nc3 Nf6 3.d4 land on the same position); if you analyse both branches independently or write the same commentary twice, you're wasting engine time and inviting inconsistency.\n\nCall this BEFORE `auto_evaluate` on a big subtree to see how much work will actually be new, and BEFORE writing prose to know which nodes can share a comment or should point at each other with 'transposes to line X'.\n\nNote: engine evals auto-propagate — when `cloud_analyse({file_id, node_id})` stores `ceoEval` on a node, it also stamps every transposition of that position in the same file (see the response's `stored_on`). And `auto_evaluate` analyses each position once and skips nodes that already hold every requested engine. So detection is cheap AND propagation is automatic; this tool is for prose planning and one-shot audits, not for gating engine work.\n\nResponse: `{ file_id, group_count, node_count, groups: [{ position_key, size, node_ids, sans }] }`. `position_key` is the 3-field FEN prefix used as the match key; `size` is how many nodes share it; `sans` are the moves that led to each occurrence (parallel with `node_ids`, DFS order — first entry is the earliest/mainline-preferred occurrence). Only groups with size ≥ 2 are returned; sorted by size descending.", "inputSchema": { "properties": { "id": {
--- pinned/prep_snapshot +++ observed/prep_snapshot { - "description": "One call, three parallel fetches at the same position: opponent's stats on their side, your stats on your side, and the 11.7M-game general database at that position. Use this while walking the opening tree — one round trip instead of three separate calls, and you can compare the three views directly (e.g. opponent has 2 games here but the general DB has 8k → prep candidate).\n\nAUTO-EVAL: if a cloud combo instance is running, the response includes a top-level `.eval` (Stockfish + Lc0 read at the shared position) so you get four signals in one call. Do NOT fire cloud_analyse separately for the same FEN.", + "description": "One call, three parallel fetches at the same position: opponent's stats on their side, your stats on your side, and the 11.7M-game general database at that position. Use this while walking the opening tree — one round trip instead of three separate calls, and you can compare the three views directly (e.g. opponent has 2 games here but the general DB has 8k → prep candidate).\n\nAUTO-EVAL: if a cloud engine instance is running, the response includes a top-level `.eval` (the engines that rental provides, read at the shared position) so you get four signals in one call. Do NOT fire cloud_analyse separately for the same FEN.", "inputSchema": { "properties": { "fen": {
--- pinned/quote_engine_eval +++ observed/quote_engine_eval { - "description": "Return the stored engine eval for a node, or null if that node was never analysed. **Call this before writing prose or NAGs that quote engine numbers** — if it returns null, you have no measurement to cite. Do NOT infer an eval for the node from siblings or children; either analyse it (cloud_analyse with node_id) or omit the number from your prose.\n\nResponse: `{ ceoEval: { sf: {cp, depth}, lc0: {cp, depth}, nag } | null }`. `cp` is White-POV centipawns as an integer (+20 = +0.20). `nag` is the threshold-derived glyph as a SUGGESTION — promote to a visible NAG via set_nags only when a glyph on that move carries editorial signal.", + "description": "Return the stored engine eval for a node, or null if that node was never analysed. **Call this before writing prose or NAGs that quote engine numbers** — if it returns null, you have no measurement to cite. Do NOT infer an eval for the node from siblings or children; either analyse it (cloud_analyse with node_id) or omit the number from your prose.\n\nResponse: `{ ceoEval: { sf?: {cp | mate, depth}, lc0?: {w, d, l, depth}, human?: {w, d, l, depth} } | null }`. `cp` is White-POV centipawns (+20 = +0.20); `mate` White-POV moves to mate; `w/d/l` win/draw/loss percent from White's point of view. An engine missing from the object was never run on this position. Files analysed before 0.50 may hold an lc0 `cp` instead of w/d/l.", "inputSchema": { "properties": { "id": {
+ tool added: rename_collection
+ tool added: set_collection_folder
--- pinned/start_cloud_engine +++ observed/start_cloud_engine { - "description": "Rent a combo GPU instance (Stockfish + Lc0 in the same container) on the user's chess.ceo account. Real money — billed per second while running.\n\nCRITICAL: `machine_type` must be an exact SKU from `list_cloud_machine_options` (e.g. 'rtx-5090-64', NOT 'rtx-5090'). Guessing SKUs will fail. Call list_cloud_machine_options first, show the user the display names + prices, get their confirmation, then pass the SKU here.\n\nUse list_cloud_engines first to check if the user already has one running; don't start a second combo unless the user asked for it. Requires an MCP token with agent access.", + "description": "Rent one cloud engine on the user's chess.ceo account. Each SKU runs exactly one engine (stockfish, lc0 or human), taken from the SKU. Real money: billed per minute from start until stop_cloud_engine.\n\n`machine_type` must be an exact SKU from ensure_engines or list_cloud_machine_options. Show the user the price and get their confirmation first. For several engines, start one rental per engine; cloud_analyse uses them together. Don't start an engine that is already running (ensure_engines / list_cloud_engines show what is).", "inputSchema": { "properties": { "machine_type": { - "description": "SKU from list_cloud_machine_options (e.g. 'rtx-5090-64', 'rtx-5090-dual-64'). MUST be the exact SKU, not the display name and not a guess.", + "description": "Exact SKU from ensure_engines or list_cloud_machine_options. Not a display name, not a guess.", "type": "string" } },
--- pinned/stop_cloud_engine +++ observed/stop_cloud_engine { - "description": "Destroy a running cloud engine. Billing stops immediately. Use the contract_id from `list_cloud_engines` — don't guess.", + "description": "Destroy a running cloud engine. Billing stops immediately. Use the contract_id from `list_cloud_engines`, don't guess. Stop rentals when the analysis is done unless the user wants them kept.", "inputSchema": { "properties": { "contract_id": {
Current tools
Show all 59 tool fingerprints
Watch this server yourself
If you run this server, put the proxy in front of it. It pins these exact fingerprints on first connect and stops the session if they move.
npx -y mcp-pin@0.2.3 -- <your @chessceo/mcp command>
Or subscribe to this page's RSS feed to be told when it changes.
Badge
The badge states one fact about time and nothing else. It never claims a server is safe.
[](https://mcp-pin.gautamkhosla.com/servers/061c40aa09ba3434.html)