Clausewitz-MCP
Allows an AI agent to play Hearts of Iron IV, a Paradox Interactive game, by reading live game state from process memory and sending commands through the game's own command queue. Provides tools for military planning, combat analysis, encirclements, focus trees, research, production, diplomacy, and save analysis, among others.
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., "@Clausewitz-MCPWhat's my current situation as Germany, and which focus should I pick next?"
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.
Paradox never shipped a way to reach live game state. There's no IPC, no scripting hook that sees the running simulation, no symbols. Just a stripped 68 MB binary.
So this reads the process memory directly, and pushes actions back through
CCommandQueue, which is the path your mouse clicks take. That detail matters more than
it sounds. Because the orders go through the real channel, the game still runs
CanExecute on every one of them. Hand an army group to a general who isn't in the
current government and you get refused, with the same reason a player would get.
$ python3 clausewitz.py status
1936.01.01.11 -- German Reich (GER)
factories : 35 civilian 28 military 10 dockyards
political power: 2 stability: 75% war support: 30%
multiplayer: False (1 players)
at war: False active land combats: 0Why not just parse the save file?
Because saves are a snapshot written on autosave, and almost nothing you need for a decision survives to disk. Organisation this hour. The damage rate inside a battle that's happening right now. Which province a division is walking toward, and how far along it is. You can only get that from the heap.
Quick start
git clone https://github.com/smerss/Clausewitz-MCP
cd Clausewitz-MCP
pip install -r requirements.txt # numpy, that's the whole list
python3 clausewitz.py doctordoctor looks for your install in the usual Steam places, in extra Steam library
drives, and in WSL mounts. If it comes up empty, point it yourself:
export HOI4_PATH="$HOME/.steam/steam/steamapps/common/Hearts of Iron IV"Reading another process needs permission. Run as root, or do this once per boot:
sudo sysctl -w kernel.yama.ptrace_scope=0Then add it to your MCP client:
claude mcp add hoi4 -- python3 /path/to/Clausewitz-MCP/clausewitz.py serve{
"mcpServers": {
"hoi4": {
"command": "python3",
"args": ["/path/to/Clausewitz-MCP/clausewitz.py", "serve"],
"env": { "HOI4_PATH": "/path/to/Hearts of Iron IV" }
}
}
}More examples in mcp/config/.
Related MCP server: local-game-mcp
What it does
107 tools covering focus tree, research, production, construction, politics, decisions, diplomacy, armies, fleets, templates and save analysis. Most of that is plumbing. The interesting parts are below.
Attacks it won't make, and why
Every coefficient here is read out of the shipped game files, common/terrain/00_terrain.txt
and common/defines/00_defines.lua. Not from a wiki, and not from memory.
attack -> 11529 | 4 divisions from 3 directions (limit 11, width 108/120)
skip -> 11444 | ratio 0.47 < 1.15 needed
(forest -15%, river crossing(small) -30%, entrenchment 9.0 +18%)
skip -> 9517 | ratio 1.62 < 2.00 needed (urban -30%, entrenchment 3.0 +6%)That river penalty comes from rivers.bmp. Crossings aren't stored anywhere convenient,
so they get recovered from the pixel borders between provinces: 4,385 of them, cached on
first run.
Piling on divisions makes an attack worse
COMBAT_STACKING_START = 5 COMBAT_STACKING_EXTRA = 3
COMBAT_STACKING_PENALTY = -0.02 (per division over the line, applied to everything)Ten divisions attacking from one direction is a 10% penalty on the whole attack. The fix is another direction, not another division, since each direction raises both the stacking allowance and the combat width. The planner works that out before committing.
Encirclements
One province almost never cuts a front of any width, so the search runs over sets of one, two and three provinces, looking for the cheapest cut that disconnects enemy divisions from their capital. It holds the plan across ticks and attacks whichever piece it can currently reach.
encircle -> 334 | POCKET: 2 enemy divisions cut off
6 divisions from 3 directions (limit 11, width 108/120)Pockets don't get attacked immediately. Units carry 72 hours of supply, so it waits on
the game's out_of_supply_days counter instead of assuming that a graph cut means
starvation. That distinction came from a pocket that was sitting at 108% supply the whole
time, quietly fed by a port.
Combat is read, never simulated
Reimplementing HOI4's combat maths would drift out of sync with the next patch. The game already computes, every tick, how much damage each side is taking. The engine reads that, smooths it, and divides it into each side's organisation pool. Terrain, doctrine, air support, entrenchment and supply are already inside those numbers because the game put them there.
It can sleep
hoi4_wait_for(max_days=30, signals=["focus", "research", "war"])
→ woke_because: ["focus finished/changed: industrial_effort -> None"]Checking every second burns tokens. Never checking misses things. This watches the game
and returns when something needs a decision, and it always returns by max_days, because
nothing here is allowed to wait forever.
Speed
The micro engine runs once per in-game day. A tick is about 46 ms. It used to be a full second, almost all of it spent reading 26,826 province objects one at a time to work out who owned what. Province-to-state membership never changes during a game, so that half now comes from static files and only ownership is read live. 646 ms down to 35 ms, checked against the old path across all 10,272 provinces with no disagreements.
How it works
┌──────────────────────────────────────────┐
MCP client ──────▶ mcp/server.py JSON-RPC over stdio │
└───────────────┬──────────────────────────┘
│
┌───────────────▼──────────────────────────┐
│ calling/ the memory layer │
│ │
reads ──────────┼─▶ process_vm_readv never stops the game│
actions ─────────┼─▶ CCommandQueue::Post the player's path │
└───────────────┬──────────────────────────┘
│
┌───────────────▼──────────────────────────┐
│ Hearts of Iron IV (stripped, 68 MB) │
└──────────────────────────────────────────┘directory | what's in it |
| the server and client configs. Thin. |
| memory access, the game model, generated tables. This is the part worth reusing if you're building something else. |
| plain text reference: verified call addresses, struct offsets, 358 player commands, handle types, terrain constants |
| scanners, dumps, and |
None of it started from a symbol name. Classes came out of Itanium C++ RTTI, 22,479
typeinfo records worth. Function boundaries came from .eh_frame_hdr, 128,144 of them.
The struct layouts came from the game's serializer, which writes field names next to
offsets when it saves, so CArmy+0x428 is called organisation here because that's what
Paradox calls it.
After a patch, regenerate:
python3 clausewitz.py tablesSafety
Reads never stop the game. Calls do, because on Linux they ptrace-stop all 28 threads and hijack the main one, so anything running in a loop is read-only and only drops that guard to post a batch of orders inside a single attach.
Three rules live in the code. Each one cost something:
rule | what it cost |
Only call addresses whose signature was recovered by disassembly | two guessed virtuals segfaulted the game |
Check handle types before posting | passing |
No injected calls inside a loop | a status call inside a tick loop froze a live multiplayer session, audio and all |
The write-ups are in FINDINGS.md. The reasoning is more useful
than the rule.
Roadmap
Live state reads, 107 MCP tools
Player command channel with the game's own legality checks
Combat read from the game's damage output
Terrain, rivers, forts, stacking and combat width in the planner
Encirclement search over the province graph
Turn loop with wake-on-event
Windows port. At 50 ⭐ I'll build it. The framework doesn't care about the OS. What's missing is a PE backend (
ReadProcessMemory,CreateRemoteThread) and, the slower half, regenerating every offset table againsthoi4.exe, since all of them came out of the Linux ELF.Air and navy micro. The commands are extracted; none have been fired in anger.
Peace conference automation
Linux only today. That's a fact about the offset tables, not about the design.
Contributing
The Windows port is the most useful thing anyone could pick up, and it's self-contained.
research/README.md spells out both halves.
After that, the unwrapped command areas. Division templates (25 commands), air missions
(35), navy (42), intelligence (20). All of them are extracted with their parameter
layouts and none have been tested in-game. calling/tables/commands.txt is the map.
Found an offset that moved in a newer patch? Open an issue with the version and what broke.
This server cannot be deployed
Maintenance
Related MCP Connectors
Live competitive-game predictions, meta data and decision tools for AI agents.
Savecraft serves real save game data and expert game knowledge to AI assistants.
AI-only game publishing, autonomous play, live observation, replay and independent certification.
Create, test and play AI-native games through server-authoritative contracts.
Related MCP Servers
- AlicenseNot gradedqualityAmaintenanceEnables AI agents to read and control Command: Modern Operations scenarios locally via MCP tools, supporting real-time battle assessment, task planning, and scenario editing.7MIT
- FlicenseNot gradedqualityBmaintenanceEnables AI agents to play local Windows games through low-level keyboard/mouse input, screen capture, OCR, and per-game profiles for semantic actions.-
- AlicenseNot gradedqualityCmaintenanceEnables AI agents to control Cheat Engine for memory reading/writing, scanning, debugging, and .NET/Mono game reverse engineering through 43 Chinese-language MCP tools, with thread-safe named-pipe communication.MIT
- AlicenseAqualityBmaintenanceEnables AI assistants to interact with running games in real time — introspecting game state, simulating keyboard and mouse input to actually play, capturing screenshots, executing Lua code, hot-reloading files, and receiving push notifications when state changes.8MIT