@chessceo/mcp 0.49.8 → 0.49.10

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.
@@ -179,3 +179,17 @@ export function storedEvalToCompact(ev, analysis) {
179
179
  }
180
180
  return compact;
181
181
  }
182
+ // Fan-out merge: each rental returns the engines it runs. Keep the first
183
+ // rental's block per engine field, so one object carries e.g. Stockfish from
184
+ // one rental and Lc0 from another. Top-level fields come from the first result.
185
+ export function mergeRentalAnalyses(results) {
186
+ const merged = { ...(results[0] ?? {}) };
187
+ for (const key of ["stockfish", "lc0"]) {
188
+ delete merged[key];
189
+ for (const r of results) {
190
+ if (r[key] !== undefined && merged[key] === undefined)
191
+ merged[key] = r[key];
192
+ }
193
+ }
194
+ return merged;
195
+ }
package/dist/index.js CHANGED
@@ -22,7 +22,7 @@ import { TOOLS } from "./tools.js";
22
22
  import { PROMPTS } from "./prompts.js";
23
23
  import { commentAntiPatterns, longLineWarning, noDescribeWarning, noStatsCheckWarning, positionalNagOnIntermediateWarning, positionsDescribed, positionsStatsChecked, } from "./warnings.js";
24
24
  import { authContext, authedRequest, deleteGame, fetchGame, get, makeFileId, restoreGame, } from "./http.js";
25
- import { analysisToStoredEval, capPvsInResponse, convertCloudSnapshotResponse, fetchCompactEval, } from "./analysis/response.js";
25
+ import { analysisToStoredEval, capPvsInResponse, convertCloudSnapshotResponse, fetchCompactEval, mergeRentalAnalyses, } from "./analysis/response.js";
26
26
  import { autoEvaluate, autoEvaluateCancel, autoEvaluateStatus, } from "./analysis/auto.js";
27
27
  import { deepAnalyseCancel, deepAnalyseStart, deepAnalyseStatus, } from "./analysis/deep.js";
28
28
  import { analyseRouting, getNodeByPath, resolveFromNodeOrFen, storeEvalOnNode, } from "./analysis/file_handle.js";
@@ -122,8 +122,9 @@ const EXAMPLE_REPERTOIRE_PGN = loadBundledDoc("examples/najdorf-6-f4-white.pgn",
122
122
  // putting it there would surface this to any caller who can list tools,
123
123
  // not just ones who actually hold a token.
124
124
  const ENGINE_GUIDE = {
125
- stockfish: "Objective calculation — the ground truth for whether a line is actually winning/drawn/losing with best play, whether a tactic is real, whether a defense holds. Gives 0.00 to a large share of normal positions even when one side is much harder to play for a human — that means 'drawn with best play,' not 'trivial' or 'nothing to look for.'",
126
- lc0: "Neural-net engine trained on human-style play, roughly 3500-strength. Its evaluation approximates how a strong human judges the position (practical chances, initiative, structure) rather than pure objective truth — good for finding ideas and gauging which side is easier to play over the board. Has real weaknesses in unconventional/irregular positions outside its training distribution: evals there can be unstable or it can miss a deep concrete tactic. When it disagrees sharply with Stockfish, look for the tactical justification before trusting its read.",
125
+ stockfish: "Objective calculation, the default cloud engine at about 100 million nodes per second. A few seconds gives a very strong view of the position. Use it on every position, including when steering by lc0 or human. Its score is the objective value with best defense: 0.00 means objectively a draw with best play, not that nothing is happening or that neither side has chances. Many positions that are very hard to play for a human score 0.00. Scores drift toward 0.00 as the search deepens, especially in drawn positions. Use it to check whether a tactic is real, whether a defense holds, and whether a move loses material or the game.",
126
+ lc0: "Neural-net engine trained on self-play games, not human games. It is better than Stockfish at long-term ideas and at judging which side is practically on top. Never gives 0.00: it always says which side prefers the position, at least a little. Use it when Stockfish gives 0.00 to see who still has the practical edge, and to find where the long-term ideas are. Contempt changes how it values a draw and which side it plays for: contempt at -20 makes Black play for a win, which is useful for finding ideas, including in openings. It is much weaker tactically than Stockfish, so confirm any concrete line with Stockfish.",
127
+ human: "Neural net trained only on human games, about 11 million rated games. Its moves and evaluations are practical, not objective: the moves it suggests are the ones a human would find and play. It punishes dubious moves less than Stockfish, because human games contain many imperfect moves that still work in practice, so a move with a sound idea behind it can score well here. Use it to predict how a person will respond to an idea, to find ideas (it may like a move that only fails to a refutation no human would find; Stockfish shows whether that refutation exists), and to see how a human would evaluate a position, especially positional or unclear ones. Like lc0 it is weaker in very unusual positions, and its evaluations there can be trusted much less. Stockfish remains the check on tactics and on whether a practical idea is objectively sound.",
127
128
  combo: "Runs Stockfish and Lc0 together — use when you want both the objective read and the practical/human-feel read on the same position.",
128
129
  };
129
130
  // Modern engines give equality very often, so small numbers are not "equal".
@@ -413,7 +414,16 @@ async function callToolInner(name, args) {
413
414
  if (typeof args.contempt === "number")
414
415
  body.contempt = args.contempt;
415
416
  Object.assign(body, analyseRouting(args));
416
- const raw = await authedRequest("POST", "/api/agent/cloud-engines/analyse", body);
417
+ // Fan-out: several rentals analyse the same FEN in parallel, each
418
+ // returning the engines it runs; the results are merged into one
419
+ // object (first rental wins per engine field). One call, one
420
+ // position, any mix of rentals.
421
+ const fanOutIds = Array.isArray(args.contract_ids)
422
+ ? args.contract_ids.filter((id) => typeof id === "string" && id.trim() !== "").map((id) => id.trim())
423
+ : [];
424
+ const raw = fanOutIds.length > 1
425
+ ? mergeRentalAnalyses(await Promise.all(fanOutIds.map((id) => authedRequest("POST", "/api/agent/cloud-engines/analyse", { ...body, contract_id: id }))))
426
+ : await authedRequest("POST", "/api/agent/cloud-engines/analyse", body);
417
427
  const converted = convertCloudSnapshotResponse(raw, fen);
418
428
  // PV cap: engine PVs beyond ~6 plies are speculative (the tail is
419
429
  // where the search's confidence collapses — SF at depth 24 has
package/dist/tools.js CHANGED
@@ -305,7 +305,7 @@ export const TOOLS = [
305
305
  name: "cloud_analyse",
306
306
  description: "Runs a synchronous ~2s analysis on one of the user's running engine instances and returns the requested engines' 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\n" +
307
307
  "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" +
308
- "Runs on any of the caller's running rentals — combo, stockfish-only, or lc0-only. Pass `contract_id` to choose one; without it the only rental that can serve the requested engines is used, and the error lists the candidates if there are several.\n\n" +
308
+ "Runs on any of the caller's running rentals. Pass `contract_id` to choose one; without it the only rental that can serve the requested engines is used, and the error lists the candidates if there are several. Pass `contract_ids` (several rentals) to analyse the same FEN on all of them in parallel: the result merges the engines, e.g. Stockfish from one rental and Lc0 from another.\n\n" +
309
309
  "How to read the response:\n" +
310
310
  "• 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" +
311
311
  "• 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" +
@@ -351,6 +351,7 @@ export const TOOLS = [
351
351
  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.",
352
352
  },
353
353
  contract_id: { type: "string", description: "Which of your running rentals to use, from list_cloud_engines. Any engine shape works (combo, stockfish-only, lc0-only). Omit it when only one rental can serve the request; if several can, the error lists their contract ids." },
354
+ contract_ids: { type: "array", items: { type: "string" }, description: "Several running rentals to analyse the same FEN in parallel, from list_cloud_engines. Results merge by engine. Use it to get Stockfish and Lc0 on one position from separate rentals in one call." },
354
355
  engines: {
355
356
  type: "array",
356
357
  items: { type: "string", enum: ["stockfish", "lc0"] },
@@ -34,7 +34,7 @@ Concrete failure this rule blocks: the LLM says *"9...Bb7: both engines 0.00"* a
34
34
 
35
35
  ### Stockfish — objective source of truth
36
36
 
37
- Stockfish is calculation. Its evaluation is objective: *"is this position a draw, a win, or a loss with best play from both sides?"*
37
+ Stockfish is the default cloud engine, searching about 100 million nodes per second. A few seconds gives a very strong view of the position. Use it on every position, including when steering by Lc0 or the human engine. Its score is objective: *"is this position a draw, a win, or a loss with best play from both sides?"* 0.00 means objectively a draw with best play, not that nothing is happening.
38
38
 
39
39
  Trust Stockfish for questions like:
40
40
  - Does this defensive line actually hold?
@@ -44,11 +44,11 @@ Trust Stockfish for questions like:
44
44
 
45
45
  **Watch out for:** Stockfish gives 0.00 to a *lot* of positions in the opening and early middlegame. 0.00 does not mean "trivial draw" — it means "objectively drawn with best play." Practically, one side can still be much harder to defend for a human. Every top-level classical game past move 8 typically shows 0.00 in Stockfish's eyes, yet real players win and lose those games all the time.
46
46
 
47
- ### Lc0 — practical eval, human-like feel
47
+ ### Lc0 — practical eval, long-term ideas
48
48
 
49
- Lc0 is a neural net trained on self-play games. Its evaluation is closer to how a strong human sees the position — it weighs long-term positional factors, piece activity, space, and initiative in a way Stockfish's fixed search often can't reach.
49
+ Lc0 is a neural net trained on self-play games, not human games. It is better than Stockfish at long-term ideas and at judging which side is practically on top. It never gives 0.00: it always says which side prefers the position, at least a little.
50
50
 
51
- Where Stockfish says 0.00, Lc0 might say +0.15 — meaning *"White still has a small but real practical edge over the board."* That's exactly the signal you want for opening prep, where 95% of positions are within the objective drawing margin and the real question is *"which side is easier to play?"*
51
+ Use it when Stockfish gives 0.00 to see who still has the practical edge, and to find where the long-term ideas are. Contempt changes how it values a draw and which side it plays for: contempt at -20 makes Black play for a win, which is useful for finding ideas, including in openings.
52
52
 
53
53
  Trust Lc0 for:
54
54
  - Which side has practical chances in an opening structure
@@ -56,7 +56,20 @@ Trust Lc0 for:
56
56
  - Whether a slow positional idea has long-term venom
57
57
  - Ranking candidate moves when Stockfish sees several as equal
58
58
 
59
- **Watch out for:** Lc0 can miss very deep tactical shots — its search is guided by intuition, not depth. If Lc0 loves a line but Stockfish doesn't, look for a concrete tactical justification (or a refutation).
59
+ **Watch out for:** Lc0 is much weaker tactically than Stockfish. If Lc0 loves a line but Stockfish doesn't, look for a concrete tactical justification (or a refutation). Confirm any concrete line with Stockfish.
60
+
61
+ ### Human engine — the practical read
62
+
63
+ The human engine is a neural net trained only on human games, about 11 million rated games. Its moves and evaluations are practical, not objective: the moves it suggests are the ones a human would find and play.
64
+
65
+ It punishes dubious moves less than Stockfish. Human games contain many imperfect moves that still work in practice, so a move with a sound idea behind it can score well here.
66
+
67
+ Use it to:
68
+ - Predict how a person will respond to an idea.
69
+ - Find ideas. It may like a move that only fails to a refutation no human would find. Stockfish shows whether that refutation exists.
70
+ - See how a human would evaluate a position, especially positional or unclear ones.
71
+
72
+ **Watch out for:** like Lc0, it is weaker in very unusual positions, and its evaluations there can be trusted much less. Stockfish remains the check on tactics and on whether a practical idea is objectively sound.
60
73
 
61
74
  ### Rule of thumb
62
75
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chessceo/mcp",
3
- "version": "0.49.8",
3
+ "version": "0.49.10",
4
4
  "description": "Model Context Protocol server for chess.ceo — 11.7M+ games, ~1.5M FIDE player profiles, opening preparation, live broadcasts.",
5
5
  "type": "module",
6
6
  "bin": {