chess-esca-mcp
OfficialClick on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@chess-esca-mcpIs e4 legal from the start position and what's its ECO name?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
esca
Esca is the anglerfish's lure — the light that shows what is really on the board.
Rust/Python MIT chess library: rules, facts, explanations, PGN, opening books and names, UCI client, and an MCP server over it; one API, Chess960 throughout.
Position is placement and state and nothing else. Rules live in Variant implementations —
Classic and Chess960 — so a position answers a rules question by taking the variant that
defines it, and a new variant is a new implementation and nothing else. A Game pairs a variant
with the moves played, which is what repetition and claimable draws need. Facts answers what is
true about one position — 221 named facts in 14 groups — and annotated_moves() answers what each
of its legal moves does, with 27 more. Every fact is typed, named after what a player would call
it, and told about White and Black by name.
Rust
[dependencies]
esca = "0.4"use esca::{Colour, Game, classic};
let mut game = Game::new(classic()); // Chess960 rules: `esca::chess960()`
game.play_san("e4").unwrap();
game.play_uci("e7e5").unwrap();
println!("{}", game.position().fen());
let facts = game.facts();
println!("{}", facts.tactics.legal_move_count.white);
println!("{:?}", facts.pawns.passed.of(Colour::Black).files());
println!("{}", facts.summary());Cargo features, none on by default: lichess (streaming reader for the Lichess evaluation
dump), pgn (reading and writing games as PGN), polyglot (opening books), openings (the
bundled ECO catalogue), serde (the one JSON form of the facts, and the JSON Schema for it),
tensors (a run of positions as one typed array per fact) and python (the PyO3 module the
wheel is built from). Position::polyglot_key needs no feature.
Related MCP server: json-sanity
Python
pip install escaimport esca
game = esca.Game() # Chess960 rules: esca.Game(variant=esca.CHESS960)
game.play_san("e4")
game.play("e7e5")
print(game.position.fen)
facts = game.facts()
print(facts.tactics.legal_move_count.white)
print(list(facts.pawns.passed.black.files))
print(facts.to_dict()["material"]) # every group in the one JSON formWheels are abi3 for Python 3.12 and up. pip install esca[tensors] adds NumPy and
esca.tensors, which turns a run of positions into one typed array per fact.
Examples
Three short programs a side, reading the same examples/games.pgn, in
examples/ and
python/examples/:
pgn_report/read_games.py— per game of a PGN file: opening, final position, ending, passers.why_illegal/legal_moves.py— every legal move and what it does, then why one other is not.engine_game/engine_game.py— a UCI engine against itself, its ending as English, JSON and arrays. Takes the engine's path; without one it says so and stops.
What it covers
Classic chess and Chess960, behind one
Varianttrait.FEN and EPD, reading
KQkqand theAHahof X-FEN and Shredder-FEN alike, and writingKQkqwhenever the rook files allow it.Legal move generation into a
MoveListthat never allocates.UCI move text in either castling spelling, and SAN with the disambiguation it needs.
Checkmate, stalemate, insufficient material, the fifty- and seventy-five-move rules, and threefold and fivefold repetition.
Facts: fourteen groups of cheap facts about one position — the board itself, game state, history, material, pawns, pieces, king, mobility, attacks, exchanges, threats, one-ply tactics, endgame and the attack maps side by side — andMoveFactsfor every legal move, fromannotated_moves(). Every value that differs between the two sides is aByColour, read as.white,.blackor.of(colour).A catalogue of those facts as data — name, type, dtype, shape and meaning — which
docs/features.md,docs/facts.schema.json, the Python type stubs and the tensor layout are all generated from, and which the MCP server serves.One JSON form for the facts, written by Rust's
serde::Serializeand by Python'sto_dict(), byte for byte the same and described bydocs/facts.schema.json.A typed tensor export: one array per fact, batch first, each keeping the width and sign it was declared with — nothing scaled, normalised or cast to a float — expanded or bit-packed, and written as safetensors.
Polyglot opening books: the format's own key on every
Position, books read, drawn from and built, and an ECO code and name for some 3,800 named positions.Named endings with theory verdicts and technique names, and a one-line English
describe()beside every value the explanations layer answers with.
MCP server
mcp/ is a second distribution from this repository: chess-esca-mcp, an MCP server that hands
esca's answers to an LLM as JSON — the whole state of a position, whether a move is legal and
every reason it is not, the named facts, the ECO name, opening-book moves, and PGN read and
written. It carries no engine and does no search. It runs as uvx chess-esca-mcp, is versioned
with the library and pins the matching esca, and is documented in
mcp/README.md.
Documentation
docs/esca-api.md— the API in both languages; §11 is the whole Python surface.docs/features.md— every fact, its type and its meaning, group by group.docs/esca-vocabulary.md— the terms the API and the facts are named after.
Related projects
AnglerfishChess/anglerfish — the chess engine that plays from a learned evaluation, and the Python trainer that produces it. Both are built on esca; the trainer turns its facts into the rows a net eats.
AnglerfishChess/uci-test-suite — a conformance suite that checks a program is a valid UCI engine, whatever its strength. It talks to the engine under test through esca's UCI client.
AnglerfishChess/chess-uci-mcp — an MCP server that drives UCI engines from an LLM, so an esca position can be handed to Stockfish for a number and a line to go with the facts esca reads off it.
AnglerfishChess/plugins — the agent-plugin marketplace, where
chess-esca-mcpships with a skill that teaches an agent which of its tools answers which question.
License
MIT — see LICENSE.
Acknowledgements
cozy-chess (MIT) — the move generator esca stands on.
Lichess — the evaluation dump the
lichessreader streams, the game database, and lichess-org/chess-openings, whose opening names theopeningsfeature bundles (CC0 1.0 Universal Public Domain Dedication).The Polyglot opening-book format and its key scheme, by Fabien Letouzey; the key constants are those published in polyglot-book-rs (MIT OR Apache-2.0).
Stockfish and Leela Chess Zero, the engines the UCI client is tested against.
This server cannot be deployed
Maintenance
Related MCP Connectors
Deterministic JSON repair, validate, example-gen, schema-coerce for agents. Zero LLM, sub-10ms.
AI Reasoning Cache & Consensus Layer with 11 MCP tools via Streamable HTTP.
Trademark clearance (USPTO+TMview) and self-graded stock signals for AI agents. JSON verdicts.
Verified extraction: source-backed JSON from PDFs/URLs; honest null + signed receipt.
Related MCP Servers
- AlicenseAqualityAmaintenanceMCP server exposing a deterministic, local knowledge graph over stdio. Zero LLM calls in the bridge; answers are classified as Fact, Inference, or Unknown and persisted in redb (ACID, BLAKE3-hashed).1014Apache 2.0
- AlicenseNot gradedqualityDmaintenanceDeterministic JSON validation and repair for AI agents. Validates, repairs, schema-checks, and diffs JSON so long-running agents don't corrupt their session state with malformed writes.MIT
- AlicenseNot gradedqualityBmaintenanceAn LLM-managed knowledge base following the Open Knowledge Format (OKF) v0.1 spec. Provides MCP tools: kb_query, kb_add, kb_update, kb_status over stdio or streamable HTTP.201 npm317Apache 2.0
- AlicenseAqualityAmaintenanceDeterministic rails for game-running agents — verifies rule legality under SRD 5.2.1 via stateless, offline, sub-millisecond verdicts with citations.242MIT