- Pass the /ask question to claude on stdin so it can't be parsed as a CLI option. - Block run_lua in multiplayer unless an admin enables the new "Allow Lua queries in multiplayer" map setting. - Ignore UDP packets that don't come from the game's port, in both the MCP server and the ask helper. - Build the screenshot path from our own name instead of the game's reply, and restrict screenshot names in the mod. - Validate ask packets, cap question length and limit concurrent claude runs. - Replace hard-coded home paths in the README and systemd unit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude Co-Engineer
Ask Claude questions about your live Factorio game — "what should I do next?", "why is my science slow?", "where's the nearest iron?" — from Claude Desktop or Claude Code, using your subscription instead of API tokens. Works in singleplayer; no RCON needed.
It's read-only by design: Claude looks, explains and suggests; you play.
Claude Desktop / Claude Code ──stdio(MCP)──▶ server/ (Python) ──UDP localhost──▶ mod/ (in-game Lua)
The mod uses Factorio 2.x's Lua UDP API (helpers.recv_udp / send_udp), which is enabled
per game instance with --enable-lua-udp <port>.
Setup
1. Install the mod (symlinked, so edits apply on the next save load):
ln -s "$PWD/mod/claude-co-engineer" ~/.factorio/mods/claude-co-engineer
Then enable "Claude Co-Engineer" in the in-game Mods menu.
2. Launch Factorio with UDP enabled. In Steam: Factorio → Properties → Launch Options, add:
--enable-lua-udp 34200
The game only listens on 127.0.0.1.
3. Register the MCP server. Requires uv.
Claude Code (run from this repo's root):
claude mcp add factorio --scope user -e FACTORIO_UDP_PORT=34200 -- uv run --directory "$PWD/server" claude-co-engineer-mcp
Claude Desktop — add to claude_desktop_config.json (Settings → Developer → Edit Config), with
/path/to/claude-co-engineer replaced by where you cloned this repo, then restart it:
{
"mcpServers": {
"factorio": {
"command": "uv",
"args": ["run", "--directory", "/path/to/claude-co-engineer/server", "claude-co-engineer-mcp"],
"env": { "FACTORIO_UDP_PORT": "34200" }
}
}
}
Local (stdio) MCP servers only work in the desktop app and Claude Code, not claude.ai in a browser or the mobile apps.
Tools
| Tool | Answers |
|---|---|
get_overview |
Where am I, what am I hovering, what's researching, what's broken — start here |
get_player |
Inventory, cursor, hand-crafting queue, hovered/opened entity |
inspect_entity |
Everything about the hovered entity (or one at x,y): status, recipe, contents, fuel, power |
find_problems |
Machines not working, grouped by status (no_ingredients, full_output, low_power, …) with nearest examples |
find_entities |
What's around a point; ore patches with total amounts |
get_production |
Produced/consumed/net per minute per item and fluid |
get_power |
kW consumption and production per electric network |
trace_belt |
Follows a belt (the hovered one by default) through undergrounds, side-loads and splitters: fill and motion per section (backed up vs full and flowing), what inserters and drills put on or take off, and where it ends |
get_trends |
How production, consumption and power changed over the last 10 min / hour / 10 hours; finds the biggest movers by itself |
get_research |
Current/queued research, what's researchable now, the path to any technology |
get_recipe |
How to make something, in which machines, whether it's unlocked, what uses it |
calculate_ratios |
Machines, drills, belts and power for a target rate (or machine count), using your unlocked recipes and machines, research productivity, and what you've already built |
screenshot |
An image of part of the map (Alt mode on, always daylight) for layout questions |
highlight / clear_highlights |
Outline places in your game, with labels, guide lines from you, and clickable map links in chat |
run_lua |
Read-only Lua query for anything else |
"This" usually works: hover over a machine and ask "why isn't this working?".
When Claude points you at something, it outlines it in your world and posts a [gps] link in chat
(click it to open the map there). Highlights are visible only to you, expire after a minute by
default, and are purely visual.
run_lua is instructed to only read, but Lua can't be sandboxed read-only. To guarantee nothing in
your world changes, turn off Allow Lua queries in Settings → Mod settings → Map. Every query is
logged to factorio-current.log.
In multiplayer, run_lua is off unless an admin also turns on Allow Lua queries in multiplayer:
the Lua runs for everyone, and text other players put in the world (station names, labels) ends up
in what Claude reads, so it could be talked into changing things.
Asking from inside the game
Type /ask <question> in the game chat (e.g. /ask why is my green science slow?). The answer
appears in chat a few seconds to a minute later, with clickable map links and item icons, and
the places it mentions get highlighted. Follow-up questions continue the same conversation;
/ask-new starts a fresh one.
/ask ──UDP──▶ claude-co-engineer-ask ──▶ claude -p (+ this MCP server) ──▶ answer ──UDP──▶ chat
This needs:
-
the
claudeCLI logged in with your subscription (claude auth login, once); -
the helper running. Either start it by hand from this repo's root:
uv run --directory server claude-co-engineer-askor install it as a systemd user service that starts at login (from this repo's root; this fills in its path):
uv sync --directory server && mkdir -p ~/.config/systemd/user && sed "s|/path/to/claude-co-engineer|$PWD|" server/claude-co-engineer-ask.service > ~/.config/systemd/user/claude-co-engineer-ask.service && systemctl --user daemon-reload && systemctl --user enable --now claude-co-engineer-askIts log shows each question and answer:
journalctl --user -u claude-co-engineer-ask -f.
Pick the model under Settings → Mod settings → Per player → /ask model: Haiku, Sonnet (default), Opus or Fable. Bigger models give more thorough answers but are slower and use more of your plan's usage. It's per player, so in multiplayer everyone picks their own.
The dropdown entries are aliases, which the claude CLI resolves to the newest model of that name,
so a new Sonnet or Opus is used automatically. To force any other model, uncomment
FACTORIO_ASK_MODEL_OVERRIDE in ~/.config/systemd/user/claude-co-engineer-ask.service (an alias or a full model ID)
and run systemctl --user daemon-reload && systemctl --user restart claude-co-engineer-ask. It wins
over the in-game setting for everyone.
Claude only gets the Factorio tools in these sessions: no shell, files or web. If the helper isn't
running, the game tells you after 3 seconds. The helper's port is a map setting (Ask helper port, default 34201).
Helper environment variables: FACTORIO_ASK_PORT, FACTORIO_ASK_MODEL (model when the game doesn't
send one, default sonnet), FACTORIO_ASK_MODEL_OVERRIDE (always use this model),
FACTORIO_ASK_TIMEOUT (300 s), FACTORIO_ASK_MAX_CONCURRENT (Claude runs at once across all players,
default 2), FACTORIO_ASK_CLAUDE (path to the CLI). The helper only accepts packets from the game's UDP port.
Ratio calculator
Ask things like "how many assemblers for 1 green science per second?" or "what does 10 red
science assemblers need?". calculate_ratios works from your game, not a generic table:
- Recipe: the unlocked one for each item (never recycling). Mineable items count as mined, so Space Age asteroid ore doesn't sneak in.
- Machine: the type you already use for that recipe, otherwise the fastest one you've unlocked.
- Productivity: research and machine bonuses are included. Modules and beacons aren't (yet).
- Output: per step, how many machines you need, how many you've already built on that recipe, and how much you currently make. Ore becomes mining drill and belt counts.
Tell it what you already supply ("plates come from my main bus") to stop the breakdown there, or override the recipe or machine for any item. Byproducts are listed but not subtracted from demand.
Configuration
Environment variables for the server: FACTORIO_UDP_PORT (default 34200), FACTORIO_UDP_HOST
(127.0.0.1), FACTORIO_TIMEOUT seconds (5), FACTORIO_SCRIPT_OUTPUT (~/.factorio/script-output).
Screenshots are rendered off-screen with game.take_screenshot (your camera doesn't move), written
to script-output/claude-co-engineer/, and deleted once sent to Claude.
Troubleshooting
- "No reply from Factorio": the game must be running a save, launched with
--enable-lua-udpon the same port, with the mod enabled — and not paused. Singleplayer pauses while the Esc menu is open. - Headless servers pause with no players connected unless
auto_pauseis false in server settings. With nobody connected, queries use theplayerforce and the first surface. - Screenshots need a game client that renders; a headless server can't take them.
- Changes to
control.luatake effect after reloading the save; changes tosettings.luaneed a full game restart.