@chessceo/mcp 0.8.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +32 -5
- package/docs/engine-usage.md +16 -0
- package/docs/prep-strategy.md +17 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -166,13 +166,14 @@ const TOOLS = [
|
|
|
166
166
|
{
|
|
167
167
|
name: "get_player_preparation",
|
|
168
168
|
description: "For a given player, colour and starting position, return both the moves the player actually chose (frequency + win rate) and the underlying games. Position is specified either as a move sequence in SAN (`line`) or a raw FEN. Use `line` iteratively to walk the opening tree: call once with empty `line`, pick a move, call again with `line` extended by that move, etc.\n\n" +
|
|
169
|
+
"GROUNDING: every claim about the opponent's repertoire must trace back to this tool's output. Don't assert 'they play sharply' or 'they hate isolated queen pawn' without pointing at the actual game counts / win rates in the response. Don't invent 'the opponent typically plays X' — check first. Compute is cheap: run this on more branches instead of pattern-matching from a chess book.\n\n" +
|
|
169
170
|
"Reading the response — CRITICAL:\n" +
|
|
170
171
|
"• Win % is one weight, not a verdict. Recommend 1.b3 over 1.d4 because 60% > 50% is wrong. Sample size matters (3 games at 66% is noise; 300 at 55% is signal); avgWhite / avgBlack per move show the rating context (a big score often means a rating gap, not repertoire truth).\n" +
|
|
171
172
|
"• Prep is symmetric information — both sides see the same history. Assume the opponent knows the weakness you spotted; a weak opponent won't patch it, a strong or improving one already has (but structural weaknesses like 'bad in Catalan structures' hold anyway).\n" +
|
|
172
173
|
"• Recency > career. The last 12-24 months dominate. This endpoint's compact/LLM view deliberately omits per-move `hotness` — at the individual level it's trailing noise. The general DB endpoint keeps it (there it's fashion signal).\n" +
|
|
173
174
|
"• Opponent will deviate early. Prep is a tree, not a line — cover the 2 most likely replies at each real branching point, not one 20-move line.\n" +
|
|
174
175
|
"• Surprise is a scalpel. Don't tell a lifelong 1.e4 player to switch to 1.d4 — meta-signal screams prep. Rare secondary lines within the user's existing repertoire (e.g. 6.Bc4 instead of usual 6.Bg5 vs the Najdorf) are where surprise is real.\n\n" +
|
|
175
|
-
"For the full guide
|
|
176
|
+
"For the full guide call the `read_prep_strategy_guide` tool.",
|
|
176
177
|
inputSchema: {
|
|
177
178
|
type: "object",
|
|
178
179
|
properties: {
|
|
@@ -223,7 +224,9 @@ const TOOLS = [
|
|
|
223
224
|
},
|
|
224
225
|
{
|
|
225
226
|
name: "analyse",
|
|
226
|
-
description: "Short Stockfish evaluation at a position. Returns the top-N candidate moves with score (centipawns from side-to-move POV, positive = advantage; or mate distance) and the principal variation for each. Defaults: 2s think time, top-3 lines. PV moves come back in UCI notation (e2e4, not e4).
|
|
227
|
+
description: "Short Stockfish evaluation at a position. Returns the top-N candidate moves with score (centipawns from side-to-move POV, positive = advantage; or mate distance) and the principal variation for each. Defaults: 2s think time, top-3 lines. PV moves come back in UCI notation (e2e4, not e4). Free (no cloud instance needed) — use liberally.\n\n" +
|
|
228
|
+
"GROUNDING: cite this tool's actual output when you claim things about positions. Don't invent evaluations from general principles or training data — if you don't have engine output for a FEN, call this. Compute is cheap.\n\n" +
|
|
229
|
+
"Use this to sanity-check candidate lines from get_position_stats or get_player_preparation — human game frequency tells you what people play, engine evaluation tells you what's actually good.",
|
|
227
230
|
inputSchema: {
|
|
228
231
|
type: "object",
|
|
229
232
|
properties: {
|
|
@@ -285,15 +288,22 @@ const TOOLS = [
|
|
|
285
288
|
required: ["fide_id"],
|
|
286
289
|
},
|
|
287
290
|
},
|
|
291
|
+
{
|
|
292
|
+
name: "list_cloud_machine_options",
|
|
293
|
+
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.",
|
|
294
|
+
inputSchema: { type: "object", properties: {} },
|
|
295
|
+
},
|
|
288
296
|
{
|
|
289
297
|
name: "start_cloud_engine",
|
|
290
|
-
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
|
|
298
|
+
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\n" +
|
|
299
|
+
"CRITICAL: `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\n" +
|
|
300
|
+
"Use 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.",
|
|
291
301
|
inputSchema: {
|
|
292
302
|
type: "object",
|
|
293
303
|
properties: {
|
|
294
304
|
machine_type: {
|
|
295
305
|
type: "string",
|
|
296
|
-
description: "SKU
|
|
306
|
+
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.",
|
|
297
307
|
},
|
|
298
308
|
},
|
|
299
309
|
required: ["machine_type"],
|
|
@@ -321,13 +331,14 @@ const TOOLS = [
|
|
|
321
331
|
{
|
|
322
332
|
name: "cloud_analyse",
|
|
323
333
|
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 (centipawns from side-to-move POV, or mate distance), and each engine's principal variation.\n\n" +
|
|
334
|
+
"GROUNDING: 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\n" +
|
|
324
335
|
"Auto-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\n" +
|
|
325
336
|
"How to read the response:\n" +
|
|
326
337
|
"• 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" +
|
|
327
338
|
"• 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" +
|
|
328
339
|
"• 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\n" +
|
|
329
340
|
"Contempt (`contempt`) skews Lc0 (only Lc0 — Stockfish always stays objective) toward White (positive) or Black (negative). Practical range -20..+20. Use it to find non-objective 'practical' ideas or when the user needs to steer toward fighting/solid lines with a specific colour. Do NOT quote a contempt-biased eval as objective — cross-check with Stockfish.\n\n" +
|
|
330
|
-
"For the full guide including worked examples,
|
|
341
|
+
"For the full guide including worked examples, call the `read_engine_usage_guide` tool.\n\n" +
|
|
331
342
|
"Not for casual questions — this costs real money per second. Use the free `analyse` tool (single Stockfish, 2s) or `get_position_stats` for anything that doesn't require deep prep.",
|
|
332
343
|
inputSchema: {
|
|
333
344
|
type: "object",
|
|
@@ -355,6 +366,16 @@ const TOOLS = [
|
|
|
355
366
|
required: ["fen"],
|
|
356
367
|
},
|
|
357
368
|
},
|
|
369
|
+
{
|
|
370
|
+
name: "read_engine_usage_guide",
|
|
371
|
+
description: "Returns the full chess.ceo engine-usage guide: when to trust Stockfish (objective truth) vs Lc0 (practical eval), how to read disagreements between them, and how to use Lc0 contempt to find non-objective 'practical' ideas. Call this ONCE per session before running expensive `cloud_analyse` calls or when the user asks WHY the engines gave certain scores. Same content is also available as the `engine_usage_primer` prompt (for clients that surface prompts as slash commands), but many clients do not expose prompts to the model — this tool works everywhere.",
|
|
372
|
+
inputSchema: { type: "object", properties: {} },
|
|
373
|
+
},
|
|
374
|
+
{
|
|
375
|
+
name: "read_prep_strategy_guide",
|
|
376
|
+
description: "Returns the full chess.ceo prep-strategy guide: why win% is one weight not a verdict, why prep is a two-player game with symmetric information (opponent sees your history too), how sample size and recency change the reading, when 'revealed weaknesses' are actionable vs already patched, how to use move-order tricks with the `trs` field, and how to calibrate surprise (rare secondary lines inside the existing repertoire, not big first-move switches). Call this ONCE per session before recommending an opening plan, especially when the user is preparing for a specific real opponent.",
|
|
377
|
+
inputSchema: { type: "object", properties: {} },
|
|
378
|
+
},
|
|
358
379
|
{
|
|
359
380
|
name: "prep_snapshot",
|
|
360
381
|
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).",
|
|
@@ -427,6 +448,8 @@ async function callTool(name, args) {
|
|
|
427
448
|
case "list_player_live_tournaments":
|
|
428
449
|
// Note: snake_case fide_id, unlike the prep endpoints. Documented quirk.
|
|
429
450
|
return get("/api/chess/live/player", { fide_id: Number(args.fide_id) });
|
|
451
|
+
case "list_cloud_machine_options":
|
|
452
|
+
return authedRequest("GET", "/api/agent/cloud-engines/options");
|
|
430
453
|
case "start_cloud_engine":
|
|
431
454
|
return authedRequest("POST", "/api/agent/cloud-engines", {
|
|
432
455
|
machineType: String(args.machine_type),
|
|
@@ -445,6 +468,10 @@ async function callTool(name, args) {
|
|
|
445
468
|
body.contempt = args.contempt;
|
|
446
469
|
return authedRequest("POST", "/api/agent/cloud-engines/analyse", body);
|
|
447
470
|
}
|
|
471
|
+
case "read_engine_usage_guide":
|
|
472
|
+
return { guide: ENGINE_USAGE_DOC };
|
|
473
|
+
case "read_prep_strategy_guide":
|
|
474
|
+
return { guide: PREP_STRATEGY_DOC };
|
|
448
475
|
case "prep_snapshot": {
|
|
449
476
|
const me = Number(args.fide_id_me);
|
|
450
477
|
const opp = Number(args.fide_id_opponent);
|
package/docs/engine-usage.md
CHANGED
|
@@ -2,6 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
When you call `cloud_analyse`, chess.ceo runs Stockfish and Lc0 in parallel on the user's rented combo instance and returns both engines' final read. This doc explains what each engine is good for and how to interpret the numbers you get back — the difference between "this line is a draw" and "this line is easy to draw" is central to real prep and both engines are needed.
|
|
4
4
|
|
|
5
|
+
## Grounding: don't invent, run the engine
|
|
6
|
+
|
|
7
|
+
**Every claim you make about a position must trace back to actual engine output from this session.** Not from a book you were trained on, not from generic chess principles, not from a plausible-sounding pattern. If you don't have a Stockfish or Lc0 line for the exact FEN you're discussing, run one. Compute is cheap — `cloud_analyse` at ~2s each is fine to call 5-10 times while walking a tree; you can burn 20-30 seconds of billable time and it's still cents.
|
|
8
|
+
|
|
9
|
+
**Concrete failure modes to avoid:**
|
|
10
|
+
|
|
11
|
+
- Inventing an evaluation. If you say "this is +0.4 for White", that number must come from an engine call. Not a guess, not a vibe.
|
|
12
|
+
- Naming a "best move" you never saw in engine output. If Stockfish's response listed `[Nf3, Nc3, d4]` and the user asks about `e4`, don't claim `e4` is anywhere in the ranking without checking.
|
|
13
|
+
- Fabricating a variation. "1.e4 e5 2.Nf3 Nc6 3.Bb5 gives White a big edge" is not a valid claim unless you actually ran the engine on that position. Walking the tree with generic pattern-matching is hallucination, however well-formed the moves look.
|
|
14
|
+
- Falling back to trained-in book judgments ("the Ruy Lopez is objectively best") when the user is asking about a specific position with specific stats.
|
|
15
|
+
- Dressing measured data up in generic chess prose that reads like analysis. If you cite that Lc0 shows +0.15, don't extend that into three sentences of positional narration you didn't verify.
|
|
16
|
+
|
|
17
|
+
**When the engine disagrees with your intuition**, trust the engine first and *then* try to explain the disagreement — look at the PV, look at both engines' scores, don't wave off the tool because a general principle "should" apply.
|
|
18
|
+
|
|
19
|
+
**When you don't have data**, don't fill the gap with prose. Either run the tool or say "I don't have engine data for that position — should I check?" The user cannot tell which parts of your output came from a tool call and which parts came from pattern-matching; the whole point of running an engine is that its judgment beats yours here, so cite it.
|
|
20
|
+
|
|
5
21
|
## Two engines, two truths
|
|
6
22
|
|
|
7
23
|
### Stockfish — objective source of truth
|
package/docs/prep-strategy.md
CHANGED
|
@@ -2,6 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
Opening prep is not a monologue with the position-stats and player-prep endpoints as sources of truth. It's a two-player adversarial game with **symmetric information** — both sides can see the same history, both know what the other has played, both have their own weaknesses and their own idea of the other's weaknesses. Everything below flows from that.
|
|
4
4
|
|
|
5
|
+
## Grounding: cite tools, don't fill gaps with chess prose
|
|
6
|
+
|
|
7
|
+
Every recommendation you make must trace back to an actual tool call in this session — engine output from `cloud_analyse` / `analyse` for evaluations and lines, `get_player_preparation` / `get_position_stats` for statistics, `get_player_profile` / `get_head_to_head` for style and history. **Compute is cheap.** When you don't have the data to justify a claim, run the tool — do not paper over the gap with generic chess wisdom you didn't verify.
|
|
8
|
+
|
|
9
|
+
**Concrete failure modes to catch yourself doing:**
|
|
10
|
+
|
|
11
|
+
- "This is a good line because Black gets the two bishops." → Did Lc0 or Stockfish score it that way? If not, drop the claim.
|
|
12
|
+
- "Your opponent hates isolated queen pawn positions." → Did you actually look at their IQP games in `get_player_preparation`? Or is this a training-data pattern?
|
|
13
|
+
- "The Petroff is a solid choice here." → Did you check the opponent's score as White vs the Petroff, or against Black openings in general? If not, drop it.
|
|
14
|
+
- "Aim for a Catalan setup, they historically struggle there." → Point at concrete games where they lost in Catalan structures. If you can't, don't say it.
|
|
15
|
+
- Inventing move sequences that "look like typical prep" without walking the actual tree via `get_player_preparation` / `prep_snapshot`.
|
|
16
|
+
- Asserting an opponent's style ("sharp tactician", "endgame grinder") without pointing at their profile data or specific games.
|
|
17
|
+
|
|
18
|
+
The failure mode is *authoritative-sounding recipe = 30% real tool output + 70% chess-book filler*. The user cannot tell which is which; from their side it all looks like analysis. That's worse than saying "I don't have data on this yet — should I run X?"
|
|
19
|
+
|
|
20
|
+
**Do this instead:** cite the specific numbers ("opponent scores 32% as White vs the Sveshnikov over 47 games, 2023-2025"), the tool that produced them ("via `get_player_preparation`"), and reason from there. If the reasoning wants to extend beyond what the data supports, either run more tools or flag it as your read, not the data's.
|
|
21
|
+
|
|
5
22
|
## Numbers are inputs, not verdicts
|
|
6
23
|
|
|
7
24
|
The move statistics endpoints return win %, game counts, and (in the big DB) hotness. Treat every one of these as a *weight*, not a *rule*.
|
package/package.json
CHANGED