wordle-solver
# Wordle Solver MCP Server
An [MCP (Model Context Protocol)](https://modelcontextprotocol.io/) server that gives AI assistants governed access to a **production analytics microservice**: the entropy-based Wordle solver that powers the [interactive demo on courtneyperigo.com](https://courtneyperigo.com/wordle).
This repo is the companion demo for the article *"Your Analytics Microservices Have a New Customer"* — a sequel to [*Get More Out of Your Data with Analytics Microservices*](https://medium.com/data-science/get-more-out-of-your-data-with-analytics-microservices-9a5a34a3ad2f) (Towards Data Science, 2022). The 2022 argument: put your analytics behind independently deployable, domain-bound services. The 2026 payoff: the highest-volume consumer of a well-built analytics service is now an AI agent — and MCP is the standardized communication layer that article said was the pattern's biggest cost.
```
2022 2026
┌──────────┐ ┌──────────────────┐ ┌───────────┐ ┌──────────────────┐
│ Web UI │───▶│ Solver API │ │ AI agent │───▶│ MCP server │
│ (Vue) │ │ (FastAPI on │ │ (Claude, │ │ (this repo) │
└──────────┘ │ App Engine) │ │ etc.) │ └────────┬─────────┘
└──────────────────┘ └───────────┘ │
▼
┌──────────────────┐
│ Same solver API │
│ — unchanged │
└──────────────────┘
```
The microservice didn't change. It gained a new kind of customer.
## What the solver does
The upstream service ranks every legal Wordle guess by **expected information gain** (measured in bits) against the words still consistent with the game's feedback. It knows the official NYT allowed-guess and answer lists, and reports game state as uncertainty in bits. It's a FastAPI app on Google App Engine with Cloud Build CI/CD — a small but real production analytics service, built originally for a website UI, long before agents.
## Tools
| Tool | When the agent should call it |
|---|---|
| `get_game_stats` | At the start of a game — dictionary size, answer count, starting uncertainty, and suggested opening words |
| `recommend_guesses` | After each guess — pass the full guess history with color feedback (`g`/`y`/`x` per letter); returns ranked recommendations, best eligible answers, and updated game state |
## Resources
| Resource | Contents |
|---|---|
| `wordle://methodology` | How the ranking works (lower bits = better), what the two ranked lists mean, how to read uncertainty — so the assistant explains recommendations correctly instead of guessing |
## Design notes (the part that generalizes beyond Wordle)
1. **Tools accept the agent's representation, not the API's.** The upstream API wants position-wise constraint lists (`green_letters`, per-position yellow exclusions, duplicate caps). Agents think in guesses: *"I played CRANE and got gray-yellow-gray-green-gray."* The translation — including the subtle duplicate-letter rules — lives in [`constraints.py`](constraints.py), tested in [`test_constraints.py`](test_constraints.py). Don't make the model do bookkeeping code can do.
2. **Tool descriptions say *when* to call, not just what.** The descriptions steer the agent away from a known-expensive call path (scoring the full dictionary with no constraints) and toward the cheap one.
3. **Responses are shaped for context economy.** The API returns 100 recommendations; the tool returns 10 plus the answer-eligible shortlist. An agent's context window is a cost center.
4. **Documentation is served, not linked.** The methodology resource travels with the tools, so the assistant's explanations are grounded in how the solver actually works.
## Install & run
Requires Python 3.10+ and [uv](https://docs.astral.sh/uv/) (or plain pip).
```bash
git clone https://github.com/agentdanger/wordle-mcp-server.git
cd wordle-mcp-server
uv sync # or: pip install -e .
uv run server.py # starts the server on stdio
```
### Claude Code
```bash
claude mcp add wordle-solver -- uv --directory /path/to/wordle-mcp-server run server.py
```
### Claude Desktop
Add to `claude_desktop_config.json`:
```json
{
"mcpServers": {
"wordle-solver": {
"command": "uv",
"args": ["--directory", "/path/to/wordle-mcp-server", "run", "server.py"]
}
}
}
```
Point at a different deployment of the solver with `WORDLE_API_BASE`.
### Try it
Ask your assistant:
> I'm playing Wordle. I opened with CRANE and got: C gray, R yellow, A gray, N green, E gray. What should I play next?
The assistant calls `recommend_guesses(words=["crane"], feedback=["xyxgx"])` and reasons over ranked, real solver output instead of guessing.
## Tests
```bash
uv run pytest
```
## License
MIT
TDQS
Scored across 2 tools
The two tools have clearly distinct purposes: get_game_stats initializes a game, while recommend_guesses drives in-progress gameplay. Each description explicitly states when to call the tool and what it must not be called with, leaving no ambiguity about which to invoke at any stage.
Both tools follow a verb_noun pattern (get_game_stats, recommend_guesses). The verbs differ (get vs recommend) but this reflects distinct actions rather than inconsistency; this is a minor stylistic variation within an otherwise consistent scheme.
Two tools is on the thin side for a solver server. The set covers game initialization and guidance, but a solver could reasonably also expose a dedicated 'get opening word' tool or a 'filter results' capability. That said, two focused tools for a tightly scoped purpose is defensible.
The surface covers the start-state and the recommendation loop, which are the core needs. However, get_game_stats doesn't itself return a first guess (it explicitly instructs against calling recommend_guesses with empty history), leaving the opening move unexplained. A tool to provide the standard high-information first word would close the gap between game start and first guess.