CivMCP
# CivMCP
MCP server that lets an AI read your Civilization VI game and coach you. See `PLAN.md` for the architecture and phase history.
## Description
CivMCP is an [MCP](https://modelcontextprotocol.io/) server for Sid Meier's Civilization VI (Aspyr Mac 1.4.6). It feeds an AI client — Claude Code, Grok, or any other MCP host — three kinds of truth about the game:
1. **Rules** from the cached gameplay database (`DebugGameplay.sqlite`): techs, civics, units, districts, adjacency, eurekas.
2. **History** from engine CSVs (`Player_Stats`, combat, diplomacy, boosts), archived so they survive the game wiping `Logs/` on launch.
3. **Live state** over the FireTuner socket (`127.0.0.1:4318`): cities, units, diplomacy, threats, tiles around a city.
A coaching layer on top of that records per-turn snapshots, compares you to speed- and difficulty-scaled pace targets, and turns the gap into advice.
You play by default. The model explains, prioritizes, and points at mistakes. If you ask it to take control, `play_*` tools can move units, set production/research/civics/policies, found cities, and end the turn — still through the game's own APIs, not cheats. Read Lua is adapted from [civ6-mcp](https://github.com/lmwilki/civ6-mcp) (MIT); writes use the same operation types.
## Goals
- **Teach, don't autopilot.** After a session you should know *why* a Campus wants mountains, why a second city is late, or why 4 science/turn has been flat — not just which button to press.
- **Cite the real game.** Advice must come from this save's yields, queues, and logs, not from the model's memory of Civ VI.
- **Stay honest about pace.** Marathon turn 30 is not standard turn 30. Benchmarks scale by game speed and difficulty so the coach does not invent a crisis.
- **Work on this Mac.** Aspyr Apple Silicon has no `Lua.log` and no `io` in the sandbox. Live data goes through FireTuner; history goes through archived CSVs.
- **Coach first, control on request.** Do not autopilot a turn unless asked. `game_lua` still rejects mutations unless `mutate=True`; use `play_*` for normal actions.
- **Get better from real games.** Keep findings that changed a decision; drop the rest. Snapshot history exists so later advice can say “science unchanged for 15 turns.”
Success looks like: you ask “what should I build in my capital and why?” and the answer names the actual queue, yields, and available districts; or “how has my science compared to the AI?” and you get a table from the logs.
## Start the server
You need [uv](https://docs.astral.sh/uv/) (Python 3.12 is installed per-project) and a Civ VI install that has been launched at least once so `Logs/` and `Cache/` exist.
```bash
cd ~/Projects/CivMCP
uv sync
```
### One-shot checks (no MCP client)
```bash
uv run civmcp-smoke # FireTuner: needs Civ VI running, a game loaded, EnableTuner 1
uv run python -m unittest discover -s tests -v
uv run mcp dev src/civmcp/__init__.py # MCP inspector UI
```
`uv run civmcp` is the stdio MCP server. Do not run it by hand in a normal terminal and type at it — an MCP client must spawn it.
### Register with Claude Code (this machine)
Already done once as:
```bash
claude mcp add civmcp -- uv run --directory ~/Projects/CivMCP civmcp
```
After you pull new tools/prompts, **restart the MCP server** (quit/reload Claude Code, or `/mcp`) so the client picks up the new list.
### Other MCP clients
Point the client at stdio:
```json
{
"mcpServers": {
"civmcp": {
"command": "uv",
"args": ["run", "--directory", "/Users/jonesdevlin/Projects/CivMCP", "civmcp"]
}
}
}
```
### Live reads (optional but needed for “what should I build?”)
1. Quit Civ VI.
2. In `~/Library/Application Support/Sid Meier's Civilization VI/Firaxis Games/Sid Meier's Civilization VI/AppOptions.txt`, under `[Debug]`, set `EnableTuner 1`.
3. Launch the game, load a save. The Tuner listens on `127.0.0.1:4318` (achievements are disabled while this is on).
4. Confirm: `uv run civmcp-smoke`.
Rules, logs, saves, and log-based coaching work **without** the Tuner. Live city/unit/map tools do not.
## Usage
Typical loop:
1. Play a few turns (or load a save).
2. In the MCP client, ask in plain English (examples below). The model should call `coach_snapshot` / `coach_review_turn` or the `game_*` tools — you do not invoke Lua yourself.
3. Take the advice in-game, or say “take control” / “do it” and the model will call `play_*`. Repeat next turn.
Pace is scaled by game speed: **Marathon turn N ≈ standard N/3**. A one-city Marathon T28 game is still the ancient settler phase.
## Example commands (what to type to the AI)
Coaching:
- Review my turn. What should I do next?
- Diagnose my science.
- Diagnose expansion.
- Explain Campus adjacency.
- Explain why a Monument is the first building.
- How does a science victory work from here?
- What mistakes did I already make?
State (Tuner + loaded game):
- What should I build in my capital and why?
- What techs can I research right now?
- List city-states and my envoys.
- Preview combat: warrior at (x,y) vs the spear on the camp.
- List my units and who is idle.
- Any barbarians or camps near my cities?
- What are the tiles around Constantinople? Where should I settle?
- Who have I met and are we at war?
History / logs (game does not need to be open):
- How has my science compared to the AI over the last 30 turns?
- Show recent combats and eurekas.
- List my saves.
Rules (always available after one Civ VI launch):
- What does a Campus get from mountains and geothermal fissures?
- Compare Swordsman and Man-At-Arms.
- What techs do I need for Crossbowmen?
- Look up Dromon.
If the model has MCP prompts available, these map directly:
| You say | Prompt / tool |
|---|---|
| “Review my turn” | `game_turn` or `coach_snapshot` / prompt `coach_review_turn` |
| “Diagnose my economy / science / military / expansion” | prompt `coach_diagnose` |
| “Explain X” | prompt `coach_explain` or tool `rules_lookup` |
## Tools
| Tool | Source | What |
|---|---|---|
| `civ_status` | filesystem | Where CivMCP looks for game data and what it finds. Archives engine CSVs on each call. |
| `civ_tuner_status` | Tuner socket | Is the game reachable; current turn if a game is loaded. |
| `rules_lookup(name, kind?)` | rules DB | Tech / civic / unit / building / district / improvement / policy / government: cost, prereqs, yields, unlocks, eureka, adjacency, description. |
| `rules_adjacency(district)` | rules DB | Full adjacency bonus table for a district. |
| `rules_compare(kind, a, b)` | rules DB | Side-by-side stats. |
| `rules_path_to(target)` | rules DB | Transitive tech/civic prerequisites with costs. |
| `rules_schema(table?)` | rules DB | Tables / columns. |
| `rules_query(sql)` | rules DB | Read-only SELECT; localization attached as `loc`. |
| `game_history(metric, player?, last_n?)` | engine CSVs | Per-turn science/culture/gold/faith/cities/score/… for you vs other majors. Survives launch truncation via `data/logs/` archives. |
| `game_recent_events(last_n?)` | engine CSVs | Combat, meetings, envoys, eurekas, disasters, production-queue changes. |
| `saves_list(limit?)` | `.Civ6Save` headers | Turn, leader, civ, difficulty, speed, map size, timestamp. |
| `game_overview()` | Tuner Lua | Live turn, era, yields, government, policies, research/civic + turns left, era score. |
| `game_cities()` | Tuner Lua | Cities: pop, yields, housing, amenities, queue, districts, buildings, loyalty. |
| `game_units()` | Tuner Lua | Units: type, position, HP, moves, charges, promotions, idle. |
| `game_diplomacy()` | Tuner Lua | Relationship, war, grievances, alliances, agendas. |
| `game_threats()` | Tuner Lua | Visible enemy/barbarian units **and barb camps** (occupant if any). |
| `game_turn(city?)` | Tuner Lua | One connection: overview, cities, units, alerts, camps, CS, tech/civic options, governors, trades, map. Prefer this for reviews. |
| `game_city_states()` | Tuner Lua | Met CS: type, envoys, war, suzerain, tokens to send. |
| `game_tech_options()` / `game_civic_options()` | Tuner Lua | Legal next nodes with cost, turns, eureka/inspiration already popped. |
| `game_build_options(city?)` | Tuner Lua | What the city can produce, turns, gold buy cost. |
| `game_combat_preview(x,y,dest_x,dest_y)` | Tuner Lua | Approximate melee % damage; warns if a CS is on a camp. |
| `game_governors()` | Tuner Lua | Appointed governors and leftover titles. |
| `game_trade_routes()` | Tuner Lua | Outgoing routes vs capacity. |
| `game_map_near(city?, radius?)` | Tuner Lua | Tiles, unimproved resources, district hints, **ASCII hex**, **settle scores**. |
| `game_lua(code, mutate?)` | Tuner Lua | Escape hatch; mutations rejected unless `mutate=True`. |
| `game_plot(x, y)` | Tuner Lua | One tile: terrain, resource, improvement, units. |
| `play_move_unit` / `play_unit_action` | Tuner write | Move, fortify, heal, skip, explore, found city, build improvement. |
| `play_set_production` | Tuner write | Replace a city's queue (Builder, Settler, Monument, …). |
| `play_set_research` / `play_set_civic` | Tuner write | Set the current tech or civic. |
| `play_set_policies` | Tuner write | Swap military/economic/diplomatic/wildcard cards. |
| `play_appoint_governor` | Tuner write | Appoint and assign Liang / Pingala / … |
| `play_end_turn` | Tuner write | Request end of turn. |
| `coach_snapshot()` | logs + Tuner + sqlite | Record this turn; return pace targets, trends, findings. |
| `coach_findings(area?)` | same | Findings only (`economy` / `science` / `military` / `expansion`). |
### Prompts
| Prompt | What |
|---|---|
| `coach_review_turn` | Snapshot + history → at most 5 actions for this turn. |
| `coach_diagnose(area)` | Economy / science / military / expansion (or all). |
| `coach_explain(thing)` | How a tech/unit/district works, tied to the current game. |
### Resources
| URI | What |
|---|---|
| `civ://coach/benchmarks` | Pace table (standard-speed turns) + speed/difficulty multipliers. |
| `civ://coach/mistakes` | Common-mistakes checklist. |
| `civ://coach/victory/{path}` | Science / culture / domination / religion / diplomacy checklist. |
| `civ://coach/snapshots` | Stored per-turn snapshots (`data/snapshots.sqlite`). |
Live Tuner tools need Civ VI running with a game loaded and `EnableTuner 1`. Engine logs, saves, and coaching-from-logs work without the game open. **Marathon turn N is treated as ≈ standard N/3** so the coach does not demand four cities at turn 30.
## Tests
uv run python -m unittest discover -s tests -v
## Civ VI on this Mac (Aspyr build 1.4.6)
Root: `~/Library/Application Support/Sid Meier's Civilization VI/`
| Path (under root) | What |
|---|---|
| `Firaxis Games/Sid Meier's Civilization VI/AppOptions.txt` | Engine options. `[Debug] EnableTuner 1` enables the FireTuner listener (set by us; backup at `AppOptions.txt.civmcp-backup`). Verified 2026-09-06: opens `127.0.0.1:4318` (126 Lua states) and a decoy `:4319` with none. The game rewrites this file on launch/quit, so edit it only while the game is closed. Enabling the Tuner disables Steam achievements. |
| `Firaxis Games/Sid Meier's Civilization VI/Logs/` | Engine logs. ~40 per-turn CSVs (`Player_Stats.csv`, `Game_PlayerScores.csv`, `City_BuildQueue.csv`, `CombatLog.csv`, `DiplomacySummary.csv`, `Game_Boosts.csv`, `AI_*.csv`). **Truncated on every launch** — archive them. **No `Lua.log` on the Mac build** (the string does not exist in the binary), so Lua `print()` is not a data channel here. |
| `Firaxis Games/Sid Meier's Civilization VI/Cache/DebugGameplay.sqlite` | Full gameplay rules DB (318 tables). Rebuilt on launch. |
| `Firaxis Games/Sid Meier's Civilization VI/Cache/DebugLocalization.sqlite` | Base-game text only (`LocalizedText`, `BaseGameText`). Expansion/DLC text comes from the install's `Assets/DLC/*/Text/*.xml`, indexed by `textindex.py` into `data/dlc_text_en_US.json`. |
| `Sid Meier's Civilization VI/Saves/Single/` | Manual saves; autosaves in `auto/AutoSave_NNNN.Civ6Save`. Magic `CIV6`, ~2 MB, mixed plaintext header + zlib chunks. |
| `Sid Meier's Civilization VI/Mods/` | User mods folder (where the snapshot mod goes). |
Game install (read-only reference for Lua API examples):
`~/Library/Application Support/Steam/steamapps/common/Sid Meier's Civilization VI/Civ6.app/Contents/Assets/Base/Assets/UI/`
TDQS
Scored across 8 tools
Each tool has a clear, distinct purpose: generic SQL query, game entity lookup, adjacency bonus rules, comparison, tech/civic path, schema introspection, and server status. No apparent overlap or ambiguity.
The majority use a consistent 'rules_' prefix, but two tools (civ_status, civ_tuner_status) deviate with a 'civ_' prefix. This is a minor inconsistency but still understandable.
With 8 tools, the set is well-scoped—neither too sparse nor overwhelming. Each serves a distinct function relevant to querying and exploring Civilization VI game data.
The tool set covers core CRUD-like operations (query, lookup, adjacency, compare, path) and system introspection (schema, status). It lacks obvious write/update operations, but given the read-only nature of the domain, it is reasonably complete.