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.
- ✓Open-source license (MIT)
- ✓Actively maintained (<30d)
- ✓Clear description
- ✓Topics declared
- ✓Mature repo (>1y old)
- ✓Documented (README)
claude mcp add esca -- uvx chess-esca-mcp{
"mcpServers": {
"esca": {
"command": "uvx",
"args": ["chess-esca-mcp"]
}
}
}MCP Servers overview
# esca
[](https://crates.io/crates/esca)
[](https://docs.rs/esca)
[](https://pypi.org/project/esca/)
[](https://pypi.org/project/esca/)
[](https://github.com/AnglerfishChess/esca/actions/workflows/ci.yml)
[](https://github.com/AnglerfishChess/esca/blob/main/LICENSE)
*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
```toml
[dependencies]
esca = "0.4"
```
```rust
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.
## Python
```sh
pip install esca
```
```python
import 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 form
```
Wheels 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/`](https://github.com/AnglerfishChess/esca/tree/main/examples) and
[`python/examples/`](https://github.com/AnglerfishChess/esca/tree/main/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 `Variant` trait.
- FEN and EPD, reading `KQkq` and the `AHah` of X-FEN and Shredder-FEN alike, and writing `KQkq`
whenever the rook files allow it.
- Legal move generation into a `MoveList` that 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 — and `MoveFacts` for every legal move, from
`annotated_moves()`. Every value that differs between the two sides is a `ByColour`, read as
`.white`, `.black` or `.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::Serialize` and by Python's `to_dict()`,
byte for byte the same and described by `docs/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`](https://github.com/AnglerfishChess/esca/blob/main/mcp/README.md).
## Documentation
- [`docs/esca-api.md`](https://github.com/AnglerfishChess/esca/blob/main/docs/esca-api.md) —
the API in both languages; §11 is the whole Python surface.
- [`docs/features.md`](https://github.com/AnglerfishChess/esca/blob/main/docs/features.md) —
every fact, its type and its meaning, group by group.
- [`docs/esca-vocabulary.md`](https://github.com/AnglerfishChess/esca/blob/main/docs/esca-vocabulary.md) —
the terms the API and the facts are named after.
## Related projects
- [AnglerfishChess/anglerfish](https://github.com/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](https://github.com/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](https://github.com/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](https://github.com/AnglerfishChess/plugins) — the agent-plugin
marketplace, where `chess-esca-mcp` ships with a skill that teaches an agent which of its tools
answers which question.
## License
MIT — see [LICENSE](https://github.com/AnglerfishChess/esca/blob/main/LICENSE).
## Acknowledgements
- [cozy-chess](https://github.com/analog-hors/cozy-chess) (MIT) — the move generator esca
stands on.
- [Lichess](https://lichess.org) — the evaluation dump the `lichess` reader streams, the game
database, and [lichess-org/chess-openings](https://github.com/lichess-org/chess-openings),
whose opening names the `openings` feature 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](https://crates.io/crates/polyglot-book-rs)
(MIT OR Apache-2.0).
- [Stockfish](https://stockfishchess.org) and [Leela Chess Zero](https://lczero.org), the
engines the UCI client is tested against.
What people ask about esca
What is AnglerfishChess/esca?
+
AnglerfishChess/esca is mcp servers for the Claude AI ecosystem. 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. It has 0 GitHub stars and its last recorded update is dated 2026-09-11.
How do I install esca?
+
You can install esca by cloning the repository (https://github.com/AnglerfishChess/esca) or following the README instructions on GitHub. ClaudeWave also provides quick install blocks on this page.
Is AnglerfishChess/esca safe to use?
+
Our security agent has analyzed AnglerfishChess/esca and assigned a Trust Score of 100/100 (tier: Verified). See the full breakdown of passed checks and flags on this page.
Who maintains AnglerfishChess/esca?
+
AnglerfishChess/esca is maintained by AnglerfishChess. The last recorded GitHub activity is dated 2026-09-11, with 0 open issues.
Are there alternatives to esca?
+
Yes. On ClaudeWave you can browse similar mcp servers at /categories/mcp, sorted by popularity or recent activity.
Deploy esca to your cloud
Ship this repo to production in minutes. Each platform spins up its own environment with editable env vars.
Maintain this repo? Add a badge to your README
Drop the badge into your GitHub README to show it's tracked on ClaudeWave. Each badge links back to this page and reflects the live Trust Score.
[](https://claudewave.com/repo/anglerfishchess-esca)<a href="https://claudewave.com/repo/anglerfishchess-esca"><img src="https://claudewave.com/api/badge/anglerfishchess-esca" alt="Featured on ClaudeWave: AnglerfishChess/esca" width="320" height="64" /></a>More MCP Servers
Fair-code workflow automation platform with native AI capabilities. Combine visual building with custom code, self-host or cloud, 400+ integrations.
User-friendly AI Interface (Supports Ollama, OpenAI API, ...)
An open-source AI agent that brings the power of Gemini directly into your terminal.
Real-time global intelligence dashboard. AI-powered news aggregation, geopolitical monitoring, and infrastructure tracking in a unified situational awareness interface
The fastest path to AI-powered full stack observability, even for lean teams.
🕷️ An adaptive Web Scraping framework that handles everything from a single request to a full-scale crawl!