croissant-mcp

croissant-mcp

MCP server that gives Claude programmatic access to a local En Croissant chess opening trainer, enabling conversational opening prep by reading its SQLite database, PGN files, and Lichess API. It supports repertoire review, due cards, and opponent statistics directly from chat.

Category
访问服务器

README

croissant-mcp

An MCP server that gives Claude programmatic access to a local En Croissant installation, so opening prep can be driven from a conversation instead of by hand in the GUI.

Quickstart

Requires Python 3.13+, uv, and a local En Croissant install (developed against 0.15.0).

git clone https://github.com/cheungbrenden/croissant-mcp
cd croissant-mcp
uv sync

Register the server once, user-level, so it's available in any session:

claude mcp add --scope user croissant-mcp -- uv run --directory /path/to/croissant-mcp croissant-mcp

Then ask for prep in a conversation:

What am I due to review today, and what do opponents actually play there?

Nothing else to configure — the Lichess handle is derived from the <handle>_lichess.db3 filename and paths from the standard macOS locations. USAGE.md has the full tool list, with honest status marks for what is built and what isn't.

Why this exists

En Croissant is a Tauri desktop app. Its 64 backend commands are registered via tauri_specta::collect_commands!() and reachable only over Tauri's IPC bridge — there is no CLI, HTTP API, or headless mode. (tauri_plugin_cli is registered, but its config declares a single positional file arg: that's file-association handling, not a scripting interface.)

It doesn't need one. Everything the app persists is in open formats:

~/Library/Application Support/org.encroissant.app/
  db/<name>.db3      SQLite — Games, Players, Events, Sites, Info
  db/<name>.pgn      the PGN the database was imported from
  db/<name>.ecsi     proprietary position index (magic bytes "ECSI", v4)
  engines/stockfish/ the UCI engine binary
~/Documents/EnCroissant/*.pgn   repertoire files
~/Library/WebKit/org.encroissant.app/.../LocalStorage/localstorage.sqlite3
                   FSRS training state, keyed deck-<repertoire path>-<n>,
                   values UTF-16. Not in the PGN.

So this project reads En Croissant's files, never its code. It is not a fork and has no upstream relationship.

Start with USAGE.md — what you can ask for and what's built yet. Design records (build order, test seams, domain vocabulary) live in docs/.

Developed against En Croissant 0.15.0. The app registers tauri_plugin_updater and updates itself, and every format above is internal and undocumented. Startup asserts the shapes we depend on so a format change fails loudly instead of being misread.

The sidecar is not a live export. It's the file the database was imported from, so the two can drift: the Lichess pair matches exactly (190/190), the chess.com pair does not (3525 PGN events against a GameCount of 3521). Treat equivalence as an invariant to check, never a property to rely on. Because of this — and because a game played ten minutes ago isn't in it at all — recent games come from the Lichess API and the sidecar is the bulk/offline fallback.

How repertoires and decks work

Read from En Croissant's own source rather than inferred by experiment.

Start header — [Start "[0,0,0]"] is a JSON array of child indices from the tree root, written as JSON.stringify(game.start) and read as JSON.parse(Start ?? "[]"). It marks where training begins, not where the file begins: buildFromTree skips any node whose path is a prefix of start. The Vienna file starts at [0,0,0], which is why its deck drills from move 3 (f4, e5, Nf3) and never asks for 1.e4 or 2.Nc3.

Deck key suffix — deck-${file}-${game}, where game is the index of the game within the PGN file. -0 is the first game; a multi-game repertoire gets one deck per game.

Cards are built eagerly, and adding lines is safe. On open, if the deck is empty En Croissant builds cards for the whole tree. If the deck is non-empty it calls syncDeck, which reconciles against the tree, reports added/removed counts, and preserves existing cards and the review log. So writing new lines into a repertoire and reopening it schedules the new positions without disturbing existing scheduling. Logs are only wiped by the explicit Reset button.

A position's drilled answer is always its first child. buildFromTree uses item.node.children[0].san and ignores the rest. Whatever move we write first at a node is the move you'll be drilled on — variation order is semantic, not cosmetic.

Cards are only created for positions where it's your turn (halfmove parity against Orientation), leaf nodes are skipped, and positions are deduplicated by full FEN with the first occurrence winning — so transpositions collapse to one card.

Scope

Lichess only; chess.com is historical and opt-in. Blitz only by default, since that's the bulk of most players' game history.

Your own win rate is not a ranking signal anywhere. A typical two-year window holds only a few dozen blitz games per colour, which makes any per-position percentage noise. Ranking is on coverage instead: deterministic, and it needs no sample size.

What it deliberately does not do

Two things on disk are closed formats:

  • The move BLOB. length(Moves) equals PlyCount exactly — one byte per ply, an index into the generated legal moves for each position. Decoding it means reproducing En Croissant's move generator ordering byte-for-byte. Avoided entirely by reading the .pgn sidecar instead.
  • The .ecsi index. Powers fast position search over large databases. No substitute here; brute-force PGN scanning covers the personal databases (130 KB and 7.6 MB) and the Lichess explorer API covers reference statistics.

Indexed search over a multi-gigabyte master database is the one capability this project cannot reach. If that ever becomes a real need, it's a separate project (extract the Rust search core from En Croissant as a [[bin]] target) — not a requirement here.

What it does to your data

  • Read-only against .db3. The PawnHome column and the .ecsi index are derived; hand-written rows would desync them. To add games, write PGN and import through the GUI.
  • Repertoire files under ~/Documents/EnCroissant/ are the one place this project writes at all.

Development

uv sync
uv run pytest

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选