Lichess Coach MCP
Provides tools for interacting with the Lichess chess platform: fetch player profiles and recent games, retrieve analysed games with per-move evaluations and mistake/blunder labels, find a player's worst moves, get cloud engine evaluations for a position, look up exact endgame results from the Syzygy tablebase, fetch puzzles (with solutions optionally hidden), and query opening explorer statistics.
Click 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., "@Lichess Coach MCPReview my last blitz game as thibault and show my worst moves"
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.
lichess-mcp
An MCP server for Lichess, the free, open-source chess site. MCP (Model Context Protocol) is the open standard that lets AI apps like Claude and Cursor call outside tools. This server gives them a player's profile and recent games, the mistakes Lichess's engine flagged in those games, cloud engine evaluations, exact endgame results from the tablebase, puzzles, and opening statistics.
It is built around one rule: the model never does the chess. Every evaluation, every "this was a mistake", every best move comes from Lichess: its server analysis of a game, its cloud evaluation cache, or its endgame tablebase. When Lichess has no answer, the tool says "not available" and tells the model not to estimate one.
No API key needed. Runs locally over stdio or as a remote server with a web playground.

Why the model never does the chess
Language models are fluent about chess and often wrong about it. They suggest illegal moves, hang pieces, miss short tactics, and state evaluations no engine would agree with, all in the same confident tone as when they are right. For a coaching tool that is the worst kind of error, because the player has no easy way to tell.
So the work is split:
Lichess does the chess. Per-move evals and inaccuracy / mistake / blunder labels come from Lichess's server analysis (Stockfish). Position evals come from the Lichess cloud cache. Positions with 7 pieces or fewer come from the Syzygy tablebase, which is perfect play.
The code does bookkeeping. chess.js validates FENs (the standard text format for a chess position), replays games to recover each position, and converts engine notation (
e7e5) to normal notation (e5). It never judges a position.The model explains. It reads the structured results and talks to the player.
Missing data stays missing. An unanalysed game, a position the cloud cache doesn't have, or a hidden puzzle solution comes back as an explicit "not available" with the next step (request analysis on Lichess, use the tablebase, open the analysis board). The server instructions and tool messages tell the model not to fill the gap itself.
Related MCP server: Lichess MCP
What you can ask
Review my last blitz game as thibault. What were my worst moves?
What does the engine say about this position?
r1bqkbnr/pppp1ppp/2n5/4p3/4P3/5N2/PPPP1PPP/RNBQKB1R w KQkq - 2 3
Is this king and pawn endgame a win?
4k3/8/4K3/4P3/8/8/8/8 w - - 0 1
Give me today's puzzle but don't tell me the answer yet.
What do 1600-1800 blitz players play against the Sicilian after 2. Nf3? (needs a token, see below)
Install
Requires Node.js 20 or newer. The package name is lichess-coach-mcp (the name lichess-mcp on npm belongs to an unrelated project).
The package is not on npm yet. The commands below install it straight from GitHub with npx -y github:frogr/lichess-mcp: npm clones the repo, installs dependencies and builds it (a prepare script runs npm run build). The first start takes about 20 seconds while that happens, so run it once in a terminal before adding it to a client. If you'd rather not run a build through npx, use From source.
After the package is published to npm, npx -y lichess-coach-mcp will do the same thing. Until then, don't run that name: nothing has been published under it by this project.
Claude Desktop
Add this to claude_desktop_config.json (macOS: ~/Library/Application Support/Claude/, Windows: %APPDATA%\Claude\), then restart Claude Desktop:
{
"mcpServers": {
"lichess": {
"command": "npx",
"args": ["-y", "github:frogr/lichess-mcp"]
}
}
}To enable opening_stats, add "env": { "LICHESS_TOKEN": "lip_..." } with your own token.
Claude Code
claude mcp add --transport stdio lichess -- npx -y github:frogr/lichess-mcp
# with a token, available in every project:
claude mcp add --env LICHESS_TOKEN=lip_... --transport stdio --scope user lichess -- npx -y github:frogr/lichess-mcp
# or a hosted copy of the remote server:
claude mcp add --transport http lichess https://your-host.example/mcpCursor
Add to ~/.cursor/mcp.json (all projects) or .cursor/mcp.json (this project):
{
"mcpServers": {
"lichess": {
"command": "npx",
"args": ["-y", "github:frogr/lichess-mcp"]
}
}
}For a hosted copy, use { "url": "https://your-host.example/mcp" } instead.
From source
git clone https://github.com/frogr/lichess-mcp && cd lichess-mcp
npm ci # also builds dist/ through the prepare script
# then use "command": "node", "args": ["/absolute/path/to/lichess-mcp/dist/index.js"]Configuration
Env var | Default | Purpose |
| none | Personal API token from lichess.org/account/oauth/token, no scopes needed. Only |
|
| Per-request timeout. |
The HTTP server has more settings (rate limits, CORS, body size); they are listed in .env.example.
Tools
Tool | What it does | Key inputs | Source of the chess |
| Profile: title, rating per speed with game counts and provisional flags, W/L/D totals, puzzle high scores |
| n/a |
| Up to 20 recent finished games, read from Lichess's NDJSON export: opponent, result, opening, accuracy, and whether the game has analysis |
| Lichess server analysis (accuracy) |
| One game: players, result, opening, every move in SAN with clock time, per-move eval and judgment when analysed, clean PGN |
| Lichess server analysis |
| One player's flagged moves: move played, Lichess's best move and line, eval and winning chances before and after, the FEN before the move |
| Lichess server analysis |
| Cloud eval for a FEN: score, best move and line in SAN, up to 3 lines |
| Lichess cloud eval |
| Exact win/draw/loss for 7 pieces or fewer, distance to mate or zeroing, every move ranked |
| Lichess tablebase (Syzygy) |
| Today's puzzle: position, side to move, rating, themes, source game. Solution hidden unless |
| Lichess puzzles |
| Same, by puzzle id |
| Lichess puzzles |
| Opening explorer: opening name, each next move's popularity and results, from the Lichess or Masters database |
| Lichess opening explorer (needs token) |
Every tool is marked readOnlyHint: true and declares an outputSchema. Results come back as JSON text, which works in any client, and as structuredContent for clients that use it.
Design notes
Not available is a normal answer. Three things are often missing, and each has its own reply:
A game nobody asked Lichess to analyse.
find_mistakesreturnsanalysis_available: false, no mistakes, and the steps to request a free analysis on Lichess. In the live check on 2026-10-07 (see PROOF.md), 8 of thibault's 20 most recent games had no analysis.A position not in the cloud cache.
evaluate_positionreturnsavailable: false. If the position has 7 pieces or fewer it points totablebase; otherwise it gives the Lichess analysis-board URL. This is common for real middlegame positions: in the same live check, 13 of 15 mistake positions were not in the cache.The opening explorer without a token. Lichess now requires sign-in for it, so
opening_statssays that up front instead of failing with a bare 401.
Puzzles are for solving. The solution stays out of the response (not just out of the text) until reveal_solution: true. While hidden, there is a one-line hint naming the piece that moves first, taken from Lichess's solution, so the model can nudge without working anything out. The puzzle position is rebuilt by replaying the source game, which keeps real move numbers; the solution is then numbered from there (14... e4 15. Nxf6+ Qxf6).
Bookkeeping that can't invent notation. UCI-to-SAN conversion plays each move on a real board and stops at the first illegal move, so a malformed engine line comes back shorter, never made up. Lichess engines write castling as king-takes-rook (e1h1); that is translated before replay. Win chances use Lichess's own formula on Lichess's eval.
Being polite to Lichess. The client follows the Lichess API tips: one request at a time per host, a descriptive User-Agent, and after any 429 it stops calling that host for a full minute and says so instead of retrying. It also has timeouts, retries on 5xx with backoff, and a 60-second cache so an agent asking the same thing twice costs one request. The game export is NDJSON (one JSON object per line); it is read as a stream and the download is cancelled once enough games have arrived.
Inputs. Usernames, game ids, puzzle ids and enum values are checked by zod schemas before any request. A game id can also be a lichess.org URL. FENs are validated with chess.js (including Lichess's underscore URL form and missing move counters) before anything is sent. Move lists for the explorer accept SAN or UCI and name the first illegal move.
Errors. Upstream failures become tool errors (isError: true) with a hint the model can act on:
No Lichess game with id 'zzzzzzzz'. (HTTP 404)
Hint: Game ids are the 8 characters after lichess.org/ in the game URL. Use recent_games to list a player's games.Remote server and playground
npm start serves:
Route | |
| MCP over Streamable HTTP (official SDK), stateless, JSON responses |
| Web playground: enter a username to review recent games and their flagged mistakes on a board, try the puzzle of the day, and copy client configs |
| Status, version, limits and whether a token is set. Never calls Lichess. |
/mcp is protected for public hosting: per-IP rate limit (default 30/min, token bucket), a global daily cap (default 5,000), a 64 KB body limit checked before parsing, a 30-second wall-clock limit per request, CORS with an optional allow list, and generic messages instead of stack traces. The playground page is served with a strict Content-Security-Policy and builds every element with DOM methods, so text from Lichess is never parsed as HTML.
Deploy
Render (free): push the repo to GitHub, then in Render choose New > Blueprint and pick the repo. render.yaml sets up a free web service with npm ci && npm run build, npm start, health check on /health, and TRUST_PROXY=1. Optionally add LICHESS_TOKEN in the dashboard to enable opening_stats. Free instances sleep when idle, so the first request after a while takes a few extra seconds.
Docker:
docker build -t lichess-mcp . && docker run -p 3000:3000 lichess-mcpAny Node host: npm ci && npm run build && npm start. Set TRUST_PROXY to the number of proxies in front of the app so rate limiting sees the real client IP.
Env vars: LICHESS_TOKEN (optional), LICHESS_TIMEOUT_MS, PORT, HOST, RATE_LIMIT_PER_MINUTE, DAILY_REQUEST_LIMIT, MAX_BODY_BYTES, REQUEST_TIMEOUT_MS, CORS_ORIGINS, TRUST_PROXY. Defaults are in .env.example.
Development
npm install
npm test # vitest, recorded fixtures only, no network
npm run typecheck
npm run build
npm run smoke # stdio: initialize + tools/list
npm run smoke:http # HTTP: /health, CORS, initialize, tools/list, playground
node scripts/smoke.mjs --live # also real tool calls to Lichess
node scripts/live-check.mjs thibault # consistency check against live Lichess (see PROOF.md)
npm run screenshots # Playwright + Chromium, live dataTests run against responses recorded from the real Lichess API in test/fixtures/ (one opening-explorer response is synthetic and labeled as such, since the explorer needs a token). A mocked fetch fails on any URL it doesn't know. test/server.test.ts drives the full MCP protocol in memory, including output-schema validation; test/http.test.ts runs the SDK client against a real socket.
src/
index.ts stdio entrypoint (the package bin)
http.ts Node HTTP adapter for the remote server
app.ts routes, CORS, rate limits, size and time limits
server.ts tool registration and server instructions
lichess.ts HTTP client: per-host queue, 429 cooldown, retries, cache
ndjson.ts streaming NDJSON parser
chess.ts chess.js helpers: FEN checks, UCI to SAN, replay
tools/ one file per tool group: zod schemas + handler
public/ playground page and piece SVGs
test/ vitest suites + fixtures/
scripts/ smoke tests, live check, screenshotsCredits
Data from the Lichess API. Not affiliated with Lichess. Piece images are the cburnett set by Colin M.L. Burnett, the set Lichess uses by default, licensed GPLv2+ (as listed in Lichess's COPYING.md). They are not under this repo's MIT license: public/pieces/LICENSE has the attribution and the full GPLv2 text, and it applies if you copy those files.
License
MIT © Austin French, for the code. The piece SVGs in public/pieces/ are GPLv2+, not MIT; see public/pieces/LICENSE.
Need an MCP server for your own API? austn.net
This server cannot be deployed
Maintenance
Related MCP Connectors
Lichess MCP — public read-only API for users, games, explorer, tablebase.
Chess MCP for Claude: engine analysis, attack maps, game review. One URL, no install.
Chess opening guides and names, FEN and PGN checks, the daily chess puzzle and Elo estimates.
Pedagogical chess intelligence for AI agents: explain positions and games for a target Elo.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables natural language interaction with Lichess chess platform to play games, analyze positions, manage challenges and tournaments, and interact with other players through Claude Desktop.37 npmMIT
- AlicenseAqualityDmaintenanceConnects Claude to Lichess for playing chess games, analyzing positions with Stockfish cloud evaluation, and solving puzzles. Supports real-time gameplay including moves, challenges, draw offers, and accessing user profiles and game history.2837 npmMIT
- AlicenseNot gradedqualityDmaintenanceEnables AI assistants to explore player profiles, ratings, game archives, leaderboards, clubs, and puzzles via the Chess.com API.1MIT
- AlicenseNot gradedqualityCmaintenanceEnables AI assistants to perform professional-grade chess analysis using Stockfish and optionally Leela Chess Zero, including position analysis, full game review, opening lookup, and puzzle generation.15 npm2MIT