Inspiration
There's no shortage of chess apps. What's actually new here is WebMCP: a proposed API that lets a web page expose its own client-side functions as tools an AI agent can discover and call directly in the browser, no scraping the DOM, no separate backend integration for the agent. Chess was a good test case because it needs multi-step, stateful interaction: read the board, act, wait your turn, repeat. That's a real workflow, not a single API call dressed up as a demo.
What it does
Play chess in the browser on your own, or hand control to an AI agent mid-game. You share one board and one move history, and both of you go through the same validated chess logic.
(Note: the demo video predates the engine work and shows the five original tools. The three Stockfish tools below are live in the deployed app and in the repository.)
Eight WebMCP tools are registered on the page:
Playing
chess-get-board-statereads the current position, whose turn it is, legal moves, captured pieces and the material balance.chess-make-moveplays a legal move.chess-wait-for-human-movepauses for your turn, then picks back up automatically.chess-new-gameresets.
Thinking
chess-analyze-positionreturns ranked lines with real evaluations. Each one breaks out from, to and promotion, so a recommendation feeds straight intochess-make-movewithout the model having to parse its own advice.chess-evaluate-movereviews a move you just played: how much it cost in centipawns, what class of error it was, and the line that refutes it.chess-set-engine-strengthweakens the agent's own play so it can be a beatable opponent. It never weakens the advice you are given.
Coaching
chess-suggest-moveranks candidate moves, draws them as arrows on the board, and explains the reasoning.
The board also shows captured pieces and the material advantage for each side, so you can see who is up without replaying the move list in your head.
How I built it
Next.js, React and TypeScript. chess.js for the rules, react-chessboard for the board. Tools are registered with document.modelContext.registerTool(), each with a JSON schema and a callback that shares state with the UI, so an agent's move and a human's move land in exactly the same place.
Stockfish 18 runs in the page, compiled to WebAssembly in a Web Worker. There is no backend. Searching happens off the main thread, so the board stays responsive while the engine thinks, and it reaches depth 16 to 18 in about a second. The 7 MB binary downloads on first analysis rather than on page load, and a small UCI client on the page serialises searches and handles aborts, so moving on to a new position cancels the search before it.
Challenges I ran into
WebMCP has no way to push application state to an agent. The spec has no notification for "the human moved, your turn". The workaround is chess-wait-for-human-move, a long-running call that resolves when the position changes, guarded by a FEN check and a two-minute timeout so it cannot hang. It works, but it is a workaround for a real protocol gap, not a claim that WebMCP does push notifications.
A legal move is not a good move. Early on ChatGPT would cheerfully propose legal but tactically losing moves, because the only thing the page told it was which moves were legal. Legality answers whether a move follows the rules, not whether the opponent can immediately punish it. Stockfish now answers the second question, and the model is left to do the part it is actually good at.
What I learned
Long-running tool calls can bridge WebMCP's current gaps, but they are not push notifications and it is worth being honest about the difference.
The pattern that actually emerged is a split of labour: the model explains, deterministic domain tools verify. Stockfish is the strongest version of that in this project. The engine calculates and returns ranked lines with real numbers; the model turns a principal variation into a sentence you can learn something from. Neither is asked to do the other's job, and the failure mode of each is caught by the other.
What's next
The interesting unfinished work is in the protocol, not the chess. Waiting for a human turn should not need a two-minute long poll, and the open WebMCP design discussions on application-driven observations, human-in-the-loop elicitation and long-running tool progress are all pointing at the same gap from different directions. This project is a small, concrete test case for whatever lands there.
Built With
- chess.js
- next.js
- react
- react-chessboard
- stockfish
- tailwind
- typescript
- webmcp
Log in or sign up for Devpost to join the conversation.