llm-chess-mcp 0.4.1 → 0.4.3
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/README.md +4 -1
- package/dist/chess.js +17 -0
- package/dist/tool-meta.js +2 -2
- package/dist/tool-schemas.js +6 -1
- package/dist/tools/analysis.js +7 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -279,7 +279,7 @@ codex mcp add llm-chess-mcp --command npx --args -y llm-chess-mcp --env LICHESS_
|
|
|
279
279
|
| `game_legal_moves` | All legal moves with metadata |
|
|
280
280
|
| `game_pgn` | Export the game as PGN |
|
|
281
281
|
| `game_import_pgn` | Import a PGN into a new game |
|
|
282
|
-
| `position_analyze` | Stockfish multipv lines (cp/mate/WDL + PV), `analysis_level` preset |
|
|
282
|
+
| `position_analyze` | Stockfish multipv lines (cp/mate/WDL + UCI/SAN PV), `analysis_level` preset |
|
|
283
283
|
| `human_move_distribution` | Maia3 human-move probabilities at a target Elo |
|
|
284
284
|
| `move_evaluate` | Score one or more moves + cpLoss + classification |
|
|
285
285
|
| `move_candidates` | **Primary tool**: unified candidates (objective + human + opening) |
|
|
@@ -307,6 +307,9 @@ human-readable summary and must not be parsed as data.
|
|
|
307
307
|
`best / excellent / good / inaccuracy / mistake / blunder`.
|
|
308
308
|
- `maia3Prob` is a **human-likelihood**, not move quality. A high-probability move
|
|
309
309
|
can still be objectively bad.
|
|
310
|
+
- Analysis continuations return `pv` in UCI and the same legal prefix in
|
|
311
|
+
`pvSan` as SAN. If an engine line contains an invalid move, `pvSan` stops
|
|
312
|
+
before it while the original `pv` remains unchanged.
|
|
310
313
|
|
|
311
314
|
## Candidate structure
|
|
312
315
|
|
package/dist/chess.js
CHANGED
|
@@ -81,3 +81,20 @@ export function parseMove(chess, move) {
|
|
|
81
81
|
export function playParsedMove(chess, move) {
|
|
82
82
|
return chess.move(moveDescriptor(move));
|
|
83
83
|
}
|
|
84
|
+
export function pvToSan(chess, pv) {
|
|
85
|
+
const copy = new Chess(chess.fen());
|
|
86
|
+
const san = [];
|
|
87
|
+
for (const uci of pv) {
|
|
88
|
+
try {
|
|
89
|
+
const move = parseMove(copy, uci);
|
|
90
|
+
san.push(move.san);
|
|
91
|
+
playParsedMove(copy, move);
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
if (!(error instanceof ChessError))
|
|
95
|
+
throw error;
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return san;
|
|
100
|
+
}
|
package/dist/tool-meta.js
CHANGED
|
@@ -46,7 +46,7 @@ export const TOOL_META = {
|
|
|
46
46
|
},
|
|
47
47
|
position_analyze: {
|
|
48
48
|
title: "Analyze Chess Position",
|
|
49
|
-
description: "Run Stockfish on the current position and return the top engine lines (multipv). Scores are from the side-to-move perspective: positive cp = side to move is better; mate N = side to move mates in N. wdl is [win, draw, loss] in permille for the side to move. Use analysis_level (fast/normal/deep) or explicit depth/multipv. Does NOT mutate the game.",
|
|
49
|
+
description: "Run Stockfish on the current position and return the top engine lines (multipv) as UCI pv and SAN pvSan. Scores are from the side-to-move perspective: positive cp = side to move is better; mate N = side to move mates in N. wdl is [win, draw, loss] in permille for the side to move. Use analysis_level (fast/normal/deep) or explicit depth/multipv. Does NOT mutate the game.",
|
|
50
50
|
annotations: readOnly(),
|
|
51
51
|
},
|
|
52
52
|
human_move_distribution: {
|
|
@@ -56,7 +56,7 @@ export const TOOL_META = {
|
|
|
56
56
|
},
|
|
57
57
|
move_evaluate: {
|
|
58
58
|
title: "Evaluate Chess Moves",
|
|
59
|
-
description: "Evaluate one or more moves with Stockfish without mutating the game. Pass a single move string or an array of moves to compare. Returns, for each move, the score after the move (from the mover's perspective), cpLoss vs the best move,
|
|
59
|
+
description: "Evaluate one or more moves with Stockfish without mutating the game. Pass a single move string or an array of moves to compare. Returns, for each move, the score after the move (from the mover's perspective), cpLoss vs the best move, a classification (best/excellent/good/inaccuracy/mistake/blunder), and the continuation as UCI pv and SAN pvSan.",
|
|
60
60
|
annotations: readOnly(),
|
|
61
61
|
},
|
|
62
62
|
move_candidates: {
|
package/dist/tool-schemas.js
CHANGED
|
@@ -45,6 +45,10 @@ export const SfLineSchema = z.strictObject({
|
|
|
45
45
|
wdl: wdl.nullable(),
|
|
46
46
|
pv: z.array(z.string()),
|
|
47
47
|
});
|
|
48
|
+
export const AnalysisLineSchema = z.strictObject({
|
|
49
|
+
...SfLineSchema.shape,
|
|
50
|
+
pvSan: z.array(z.string()),
|
|
51
|
+
});
|
|
48
52
|
export const OpeningStatsSchema = z.strictObject({
|
|
49
53
|
status: z.enum(["available", "no_data", "unavailable", "disabled"]),
|
|
50
54
|
reason: z.enum(EXPLORER_ERROR_KINDS).optional(),
|
|
@@ -121,7 +125,7 @@ export const PositionAnalyzeOutputSchema = z.strictObject({
|
|
|
121
125
|
turn: color,
|
|
122
126
|
revision,
|
|
123
127
|
analysis_level: z.enum(["fast", "normal", "deep"]),
|
|
124
|
-
lines: z.array(
|
|
128
|
+
lines: z.array(AnalysisLineSchema),
|
|
125
129
|
});
|
|
126
130
|
export const Maia3MoveSchema = z.strictObject({
|
|
127
131
|
uci: z.string(),
|
|
@@ -155,6 +159,7 @@ const moveEvaluation = z.strictObject({
|
|
|
155
159
|
.enum(["best", "excellent", "good", "inaccuracy", "mistake", "blunder"])
|
|
156
160
|
.nullable(),
|
|
157
161
|
pv: z.array(z.string()),
|
|
162
|
+
pvSan: z.array(z.string()),
|
|
158
163
|
});
|
|
159
164
|
export const MoveEvaluateOutputSchema = z.strictObject({
|
|
160
165
|
game_id: z.string(),
|
package/dist/tools/analysis.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { drawResult, parseMove, playParsedMove, snapshotChess, } from "../chess.js";
|
|
1
|
+
import { drawResult, parseMove, playParsedMove, pvToSan, snapshotChess, } from "../chess.js";
|
|
2
2
|
import { ANALYSIS_PRESETS, classifyCpLoss, evalToCp, negateEval, toEval, } from "../eval.js";
|
|
3
3
|
import { TOOL_INPUT_SCHEMAS } from "../tool-inputs.js";
|
|
4
4
|
import { TOOL_META } from "../tool-meta.js";
|
|
@@ -28,6 +28,7 @@ export function registerAnalysisTools(server, services) {
|
|
|
28
28
|
scoreMate: line.scoreMate,
|
|
29
29
|
wdl: line.wdl,
|
|
30
30
|
pv: line.pv,
|
|
31
|
+
pvSan: pvToSan(chess, line.pv),
|
|
31
32
|
})),
|
|
32
33
|
};
|
|
33
34
|
return toolResult(payload, `Analyzed game ${game_id} at revision ${revision}; ${payload.lines.length} lines`);
|
|
@@ -80,6 +81,7 @@ export function registerAnalysisTools(server, services) {
|
|
|
80
81
|
cpLoss: null,
|
|
81
82
|
classification: "best",
|
|
82
83
|
pv: [],
|
|
84
|
+
pvSan: [],
|
|
83
85
|
});
|
|
84
86
|
continue;
|
|
85
87
|
}
|
|
@@ -98,6 +100,7 @@ export function registerAnalysisTools(server, services) {
|
|
|
98
100
|
? classifyCpLoss(cpLoss)
|
|
99
101
|
: null,
|
|
100
102
|
pv: [],
|
|
103
|
+
pvSan: [],
|
|
101
104
|
});
|
|
102
105
|
continue;
|
|
103
106
|
}
|
|
@@ -108,6 +111,7 @@ export function registerAnalysisTools(server, services) {
|
|
|
108
111
|
const moverEval = afterEval ? negateEval(afterEval) : null;
|
|
109
112
|
const afterCp = moverEval ? evalToCp(moverEval) : null;
|
|
110
113
|
const cpLoss = afterCp !== null && beforeCp !== null ? beforeCp - afterCp : null;
|
|
114
|
+
const pv = after?.pv ?? [];
|
|
111
115
|
results.push({
|
|
112
116
|
move: parsed.san,
|
|
113
117
|
uci: parsed.lan,
|
|
@@ -119,7 +123,8 @@ export function registerAnalysisTools(server, services) {
|
|
|
119
123
|
classification: cpLoss !== null
|
|
120
124
|
? classifyCpLoss(cpLoss)
|
|
121
125
|
: null,
|
|
122
|
-
pv
|
|
126
|
+
pv,
|
|
127
|
+
pvSan: pvToSan(copy, pv),
|
|
123
128
|
});
|
|
124
129
|
}
|
|
125
130
|
return toolResult({ game_id, revision, results }, `Evaluated ${results.length} move${results.length === 1 ? "" : "s"} in game ${game_id}`);
|