clausewitz-mcp
# clausewitz-mcp
An MCP server for **Paradox Clausewitz/Jomini modding** — EU5, EU4, Victoria 3, HOI4, CK3, Stellaris.
It gives an AI assistant the two things it needs to write Paradox script that actually loads: the game's own generated documentation for the exact patch you're modding, and a parsed index of the vanilla script tree to copy working patterns from.
No running game required. No DLL injection, no mod to install, nothing to attach to. It reads files, so it works on any OS regardless of what the game itself supports.
## Why
Ask a model to write a Paradox event and you get script that looks right and silently does nothing. `has_country_flagg` instead of `has_country_flag`. An effect used in a trigger block. A localisation key that renders as raw text in game. A mod file that shadows a vanilla file nobody noticed. None of it errors — Paradox games fail quietly, which is the worst possible failure mode for a generated-then-forgotten mod.
The fix isn't a better prompt, it's grounding. Paradox games dump their entire scripting surface — every trigger, effect, scope, event target and modifier, with supported scopes — straight out of the binary via the `script_docs` console command. That output is exact and it's correct for *your* patch. This server parses it and puts it behind tool calls, so the model looks up `add_prestige` instead of remembering it.
[CWTools](https://github.com/cwtools/cwtools-vscode) already does excellent rules-based validation for Paradox script, and if you're hand-writing mods in VS Code you should use it. But it's a language server — an agent can't call it. This is the agent-facing equivalent, grounded in the game's dumps rather than hand-maintained rules, which is also why it works on a game as new as EU5 that has no rule definitions yet.
## Install
```bash
uv sync
```
Register it with Claude Code:
```bash
claude mcp add clausewitz -- uv --directory /path/to/clausewitz-mcp run clausewitz-mcp
```
## Setup
Point it at a vanilla game tree and your mod:
```
set_workspace(
game_root = "/path/to/Europa Universalis IV",
mod_roots = ["/path/to/mod/my_mod"],
docs_dir = "/path/to/Documents/Paradox Interactive/<game>/docs"
)
```
`game_root` and `mod_roots` are enough to start. `docs_dir` is what unlocks the good part.
### Generating the docs dump
This is the step worth doing. In Steam, add `-debug_mode` to the game's launch options. Start the game, press `` ` `` to open the console, then run:
```
script_docs
dump_data_types
```
Output lands in `Documents/Paradox Interactive/<game>/docs` and `.../logs/data_types`. Point `docs_dir` at it.
Everything is copied from there, so you only need access to a machine that can *run* the game once — the server itself never launches it. If you mod EU5 from a Mac, generate the dump on a Windows box and copy the folder across.
## Tools
**Grounding**
- `lookup_script(name, kind)` — a trigger/effect/scope/modifier from the game's own docs, verbatim, with supported scopes. Returns `did_you_mean` on a miss.
- `search_script_docs(query, kind)` — find the real name when you only know roughly what you want.
- `docs_report()` — what was ingested, so you can sanity-check the parse.
**The script tree**
- `find_definition(name, category)` — where a religion/building/event/scripted effect is defined, across vanilla and mods.
- `search_definitions(query, category)` — substring search over every defined name.
- `find_usages(name)` — real working examples of a pattern before you write your own.
- `read_block(file, key_path)` — one block out of a file instead of ten thousand lines.
- `list_categories()` — map of what lives where.
- `lookup_localisation(key)` — resolve a loc key to its text, file and line.
**Authoring**
- `parse_script(text)` — syntax-check a snippet before writing it, with exact line/column.
- `validate_mod(checks)` — run the checks below over your mod.
## Validation
Every check is chosen to be low-noise — a reported problem should be a real one.
| Check | Finds |
|---|---|
| `syntax` | Unclosed braces, dangling operators, malformed blocks, with line/column |
| `unknown_script` | Triggers/effects the game doesn't define, with `did_you_mean` |
| `localisation` | Referenced loc keys that resolve nowhere and will render raw in game |
| `encoding` | Localisation files missing the UTF-8 BOM the game silently requires |
| `duplicates` | The same object defined twice inside your own mod |
| `shadowing` | Mod files overriding vanilla files — usually intended, occasionally the bug |
`unknown_script` requires a loaded `script_docs` dump. Without one it is **skipped, not guessed at** — inferring trigger validity without the game's signature list produces exactly the confident-but-wrong output this server exists to prevent.
## Supported games
Auto-detected from the game root: EU5, EU4, Victoria 3, HOI4, CK3, Stellaris. The `game/` subdirectory layout used by the newer Jomini titles is handled, as are both the `localization` and `localisation` spellings.
Anything else falls back to a generic adapter and still indexes `common/` and `events/`, so an unrecognised or brand-new title works out of the box. Pass `game=` to override detection.
## Status
v0.1. The parser, indexer and validation passes are tested against a fixture tree (`tests/fixtures`). The `script_docs` ingester is deliberately tolerant: entries keep their raw text verbatim and that is what tool calls return, with structured fields layered on best-effort, because the dump format drifts between games and versions. Run `docs_report()` after loading a real dump — if a large file reports one entry, the split heuristics missed and it's worth an issue with a sample.
## License
MIT
TDQS
Scored across 13 tools
Tools are mostly distinct, targeting separate concerns: reading blocks, listing categories, localisation lookup, parsing, validation, definition lookup, substring search on definitions or docs, usage search, and workspace management. The pairings find/search and lookup/search are distinguished by exact vs. substring and game objects vs. script_docs, though they could still be confused by an agent without careful reading.
Names predominantly follow a verb_noun pattern with snake_case (read_block, find_definition, set_workspace). The exceptions are docs_report and workspace_status, which are noun-first compounds, creating a minor inconsistency but not enough to cause confusion.
13 tools is well within the sweet spot for a domain-specific server. Each tool addresses a distinct need—setup, indexing, search, reading, validation, and documentation—without redundancy or bloat.
The surface covers the core workflow of a Clausewitz modding assistant: workspace setup, indexing, searching definitions/usages, reading script blocks, looking up docs, validating syntax and mods, and checking docs ingestion. Minor gaps include the absence of a whole-file read or a file-write tool, but those fall outside the server's read/validate role.