SatisfactoryMCP
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| SATISFACTORY_DOCS | No | Path to the game's CommunityResources/Docs/en-US.json file, overriding install auto-detection. | |
| SATISFACTORY_SAVES | No | Override the save directory (default: %LOCALAPPDATA%\FactoryGame\Saved\SaveGames). |
Capabilities
Features and capabilities supported by this server
| Capability | Details |
|---|---|
| tools | {
"listChanged": false
} |
| prompts | {
"listChanged": false
} |
| resources | {
"subscribe": false,
"listChanged": false
} |
| experimental | {} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| factory_mapA | Proposed factories, from power islands and belt topology, plus what is named. Three independent signals are reported rather than one answer, because none is
right alone: power islands separate outposts but leave a grown-together base as one
476-machine blob; belt components shatter that blob into fragments; foundation slabs
are the sharpest of the three but say nothing about the ground-built parts of a
factory. Where they disagree, carve the difference with |
| factory_queryA | Ask one thing about one factory: what it makes, needs, draws, or touches.
Rates are NAMEPLATE at each machine's saved clock, not measured throughput. A starved factory still reports its full rate. |
| factory_healthA | Measured uptime per machine, and WHY each stopped one is stopped. The only measured numbers in this MCP. Every manufacturing building keeps a fixed 300-second productivity window; uptime is seconds-producing over that window. States, worst first: Blocked is not automatically a fault. A base whose output nobody consumes fills its buffers and stops, which is what a mature factory at rest looks like. Starved, stalled and no-recipe are the actionable ones. |
| propose_factoriesA | One coherence score over every signal, agglomerated into proposed factories. Combines foundation slabs, proximity, belt connectivity, shared products and supply links. Validated leave-one-factory-out against the player's twelve hand-named factories: precision 1.000, recall 0.945, and precision was 1.000 on every fold -- it never merges two factories, it only ever splits one. Use |
| select_machinesA | Preview which machines a selector picks, before naming them. Worth running first on anything product-based: 17 machines make Concrete on the reference save, but 15 of them are a construction feed inside the steel site and only one is the player's "concrete setup". |
| name_factoryA | Name a set of machines and persist it for this world. The label stores the machine instance ids, which are stable across saves, so it survives moving machines, adding to the factory, and autosave rotation. Calling this again with the same name re-anchors it to the current selection. |
| list_factoriesB | Named factories for this world, with how much of each is still standing. |
| forget_factoryB | Delete a factory label. The machines themselves are untouched. |
| trace_upstreamA | What feeds a machine, or what it feeds -- walked on the save's own connections.
Direction is READ, not guessed. Every material edge carries its connector role, and 92.5% of the connectors landing on a machine name their direction outright; the rest are all on extractors or generators, whose own nature settles them. Where even that fails the edge is walked BOTH ways -- over-reporting a feeder is recoverable, missing one is not. Belts and pipes are walked THROUGH and left out of the table: a trace from the generators touches 331 nodes at depth 72, nearly all of it conveyor. |
| search_itemsC | Find items by name. Returns form, energy and sink points. |
| recipe_detailA | Exact numbers for one recipe: rates, machine, power, unlock source. Takes a class id OR a display name. Refusing the name cost a caller two round trips
to fetch an id this function could resolve itself, which is a poor trade for strictness
that buys nothing -- |
| alternates_for_itemC | Every automatable recipe that makes an item, alternates first. When a save is readable, each row is marked HAVE or LOCKED. |
| search_recipesA | Search recipes by name, or by what they consume/produce. Marks HAVE/LOCKED.
|
| list_buildingsB | Buildings by kind: production, extractor, generator, logistics. Rows are marked HAVE or LOCKED against the save when one can be read. That matters
most for |
| list_pending_hard_drive_choicesC | The pending hard-drive choices stored in the save, with rerolls left. |
| advise_hard_drive_pickB | Rank one pending drive's options by marginal value, via counterfactual LP. Each option is solved for and against across several objectives, because a recipe can be worthless for power yet excellent for parts. Deltas are reported per objective and never collapsed into one score.
|
| list_plansC | Plans saved for this world, and whether the world has moved under them. |
| forget_planA | Delete a saved plan. Nothing in the world is touched. |
| plan_factoryA | Optimise a factory with an LP over this world's unlocked recipes.
Omit it and the whole map is in scope. Use search_resource_nodes to discover ids. Machine counts are whole buildings at a derived clock: a 52.8 machine-equivalent result is reported as 53 machines at 99.6%. That is exact, always a clean ratio, and provably the power-optimal way to run that throughput, so ordinary ratio underclocking is automatic and needs no parameter.
objective: max_mw | max_item | min_raw | min_machines | min_power. Every item is balanced as an EQUALITY, so a byproduct with no consumer makes the plan infeasible rather than silently vanishing.
Two things worth reading twice. The power token is MW (
|
| plan_layoutA | Turn a plan into a buildable schematic: blocks, buses and floors. Same arguments as plan_factory, plus This is a SCHEMATIC, not a blueprint. It gives modules, connections, floor assignment and a space budget. It deliberately does NOT give world coordinates or belt routing -- there is no terrain data here, so those would be invented. Blocks are split by throughput: 46 Refineries needing 1380 m3/min of crude cannot share one manifold when a Mk2 pipe carries 600, so that is 3 blocks. Floors follow chain depth, with a logistics deck between each pair of production floors. |
| diff_vs_saveA | What to change to get from the factory you have to the one plan_factory plans. Takes exactly plan_factory's arguments and re-solves, because the server keeps no state. Both tools print a plan id hashed over the arguments AND the save-derived solve inputs, so two responses carrying the same id are provably the same plan. Machines are matched by IDENTITY, never by position: a manufacturer on (building, recipe), a generator on its building alone since its fuel is piped in rather than set on the machine, an extractor on the node it occupies. A Refinery running some other recipe is busy, not spare, so it never counts toward the plan. Actions are ordered free-first -- UNPAUSE, then SETRECIPE on machines that produce nothing today, then BUILD. Stages follow the plan's own chain depth and the power arithmetic is INCREMENTAL, charging only the machines you have yet to place. Where a machine cannot be identified at all (Water Extractors have no recipe and no resolvable node) the answer is a RANGE, never a number. Recall a stored plan with Built and energised are DIFFERENT states and the save separates them in one direction only: a machine that produced in the last 300s window certainly had power, while one that did not may be unpowered, starved, blocked or idle. Grid membership is not persisted at all, so a stage is never reported as "unpowered" -- only as built with nothing proven running, which is exactly what a finished but not-yet-energised block looks like. Saves are read-only: this never proposes writing one, and there is no dismantle action. Machines standing among the plan but not in it are listed for you to judge. |
| explain_byproductsA | Explain which byproducts stall a plan, and what can legally consume them. Every item balance is an equality, so a byproduct with no consumer makes a plan INFEASIBLE rather than silently vanishing. This says WHICH item is stuck, whether it can be sunk (solids only -- a fluid must be consumed exactly or packaged first), and which recipes would absorb it, split into ones this world has unlocked and ones it does not. Pass |
| compare_recipe_optionsA | Rank whole ROUTES to make an item by what each actually costs. Not a recipe list -- alternates_for_item already does that. Each route is solved end to end with the LP, so the comparison is Crude -> Alt HOR -> Diluted Fuel against Crude -> Fuel, priced in raw resource per unit, whole buildings, net power, and byproducts needing an outlet. |
| bomB | Flattened bill of materials: total raw and intermediate rates for qty/min of an item.
|
| commission_planA | In what order to switch a built plant on, without blowing the fuse. This is a STARTUP order, not a build order, and the difference removes most of the problem. Building costs materials, not power -- a machine draws only when it runs -- so the whole plant can be constructed at leisure, drawing nothing, and then energised block by block. Nothing here tells you what to build first. The constraint is one line, and it is hard: at every step, energised consumer draw must stay under the headroom plus generation from generators already burning fuel. Exceeding it in Satisfactory does not degrade gracefully -- the fuse blows and the whole grid stops until it is reset by hand, including the plant that was feeding it. Generators are free to energise (0 MW draw, read from the dump), so a wave costs its consumers and refunds its generators, and that refund pays for the next wave. Takes plan_factory's arguments, or recall a saved plan with |
| rank_unlocksA | What every locked alternate recipe would be worth to THIS plan. One counterfactual per candidate: solve the plan, solve it again with the recipe added, report the difference. It answers "which unlock should I chase" with a number in the plan's own units instead of a tier list, because a recipe's worth depends entirely on what you already have. A zero is an answer. Most candidates change nothing, and "you are not missing anything here" is a decision -- it is otherwise reached by walking the recipe tree by hand. Deltas are an UPPER bound: a candidate needing a machine you have not built is judged as if you had it, and the machine is named. Alternates currently offered by a pending hard drive are flagged, which is the difference between "worth having" and "claimable now". |
| phase_requirementsC | What the Space Elevator still wants, live record and deprecated record apart. The per-phase item table in the save is DEPRECATED and frozen, so it is shown labelled rather than believed. Read the header line first. |
| power_shardsB | Power Shards held, committed and free, plus what an overclock plan would cost.
|
| mam_researchA | MAM research: what is left, what it costs, and what you can afford right now. The MAM is where CAPABILITIES live, as opposed to recipes -- the Dimensional Depot, the Power Augmenter, and Production Amplifier, which is the one that lets a Somersloop go into a machine at all. That last one has no flag in the save. |
| somersloopsC | Somersloops held, slotted and owned -- the sibling of power_shards.
Free and committed are both exact. Slotted ones live in |
| collected_from_worldA | Map collectibles: how many exist, how many you took, what is left and what is closest. Slugs, somersloops, Mercer spheres and their shrines, mushrooms, drop pods and the loot caches around them. Two sources, and neither is asked the other's question:
Modes: A placement in a cell no save has ever loaded is counted as remaining and reported as
|
| list_regionsA | Named map regions, optionally only those containing a given resource. Region names are ADVISORY: the boundaries are the game's own map areas, downsampled to a 256 m grid to publish and a 64 m one to look up in, so a name near a boundary can be one cell out. Use them to talk about places, not to compute with -- every node row also carries an exact grid cell. |
| describe_locationA | Name the region at a coordinate, with confidence, and sample its elevation. Returns 'off-map or ocean' rather than guessing the nearest land region. There is no heightmap in any data this reads, so elevation is a SAMPLE and is reported with its count and spread rather than as one invented number. Resource nodes rest on terrain and are quoted as ground; foundations and buildings are quoted separately as built elevation, because a platform is wherever the player put it. Where the two disagree, the difference is the fill already stacked there. |
| search_resource_nodesA | Resource nodes, in one of three modes.
|
| show_on_mapA | A satisfactory-calculator.com map link centred on something, with layers on.
Only the Crude Oil layer tokens are confirmed; the rest follow the same pattern and are flagged. A wrong token still opens the map in the right place, just without that overlay. |
| rank_build_sitesA | Rank candidate fields for a new extraction site, best first. Scores untapped REACHABLE capacity against spread, distance to your existing buildings, and purity mix. Every raw component is shown so you can re-weight: the single score is a starting point, not a verdict.
|
| whereamiA | Where the player is standing, and what is around them. Position comes from the Char_Player_C pawn in the save, so it is wherever you
were when it was written -- an autosave can be several minutes stale. Use
|
| list_worldsA | List save games grouped by world, newest first. Unsupported files are reported separately rather than failing the scan -- pre-1.0 saves cannot be parsed at all. |
| world_summaryC | Progress, power and problems for one world. |
| unlocked_recipesC | Which recipes this world has. Defaults to alternates, never all 872. |
| power_reportA | Generation capacity vs machine draw, nameplate AND measured. Nameplate is what everything built would draw running at once. Measured weights each machine by the 300 s productivity monitor the save already carries, which on a factory with idle blocks is a very different number -- and it is the one that says what is free right now. Both are shown because they answer different questions. |
| factory_sitesC | Built production buildings clustered into sites, largest first. |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
| design_factory | Plan a factory for a target item, respecting what this world has unlocked. |
| plan_power_plant | Plan a power plant from a given resource and area. |
| pick_hard_drive | Advise which alternate recipe to take from a pending hard drive. |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
| docs_summary | One-line census of the normalized game data, plus its content hash. |
| current_save | Which world and file the server would read right now, and its headline state. |
| factory_labels | Factory labels for the current world, as the JSON another tool can consume. Labels are the one thing in this server a player authored by hand, so they are the one thing worth publishing as a stable interface rather than a private cache. The file is per world, keyed by the save header's ``saveIdentifier``, and carries a ``schema`` integer so a reader can refuse a shape it does not know. ``anchors`` are machine instance names, which were verified stable across saves -- 365 of 365 kept id and position between two files. That is what makes a label portable: a consumer can join it against its own read of the same save without needing anything from this server. |
| map_regions | Region names available as source selectors, with their accuracy caveat. |
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/lukszi/SatisfactoryMCP'
If you have feedback or need assistance with the MCP directory API, please join our Discord server