A Factorio 2.x mod plus MCP server that lets Claude answer questions about a running game over Lua UDP, without RCON, so it works in singleplayer. - Read-only tools: overview, problems, entities, production, power, trends, research, recipes, ratio calculator, belt tracer, screenshots, Lua queries - In-game highlights with clickable [gps] links - /ask chat command answered by a local helper running claude -p, with a per-player model setting and a systemd user service Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
8.0 KiB
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:
claude mcp add factorio --scope user -e FACTORIO_UDP_PORT=34200 -- uv run --directory /home/faab/Documents/Code/Factorio/claude-co-engineer/server claude-co-engineer-mcp
Claude Desktop — add to claude_desktop_config.json (Settings → Developer → Edit Config), then restart it:
{
"mcpServers": {
"factorio": {
"command": "uv",
"args": ["run", "--directory", "/home/faab/Documents/Code/Factorio/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.
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:
~/Documents/Code/Factorio/claude-co-engineer/server/.venv/bin/claude-co-engineer-askor install it as a systemd user service that starts at login:
cp server/claude-co-engineer-ask.service ~/.config/systemd/user/ && 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 server/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_CLAUDE (path to the CLI).
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.