Skip to main content
Glama

Server Configuration

Describes the environment variables required to run the server.

NameRequiredDescriptionDefault
SATISFACTORY_DOCSNoPath to the game's CommunityResources/Docs/en-US.json file, overriding install auto-detection.
SATISFACTORY_SAVESNoOverride the save directory (default: %LOCALAPPDATA%\FactoryGame\Saved\SaveGames).

Capabilities

Features and capabilities supported by this server

CapabilityDetails
tools
{
  "listChanged": false
}
prompts
{
  "listChanged": false
}
resources
{
  "subscribe": false,
  "listChanged": false
}
experimental
{}

Tools

Functions exposed to the LLM to take actions

NameDescription
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 name_factory and a product:, near: or slab: selector.

factory_queryA

Ask one thing about one factory: what it makes, needs, draws, or touches.

of accepts several at once, e.g. "balance,power,links".

  • summary size, position, top recipes, net power

  • balance per-item produced vs consumed vs net -- the sign is the point

  • outputs net surplus: it leaves the factory, or it backs up

  • inputs net deficit: it has to be fed in from outside

  • machines every machine with its building, recipe and clock

  • recipes / buildings counts

  • power draw vs generation at saved clocks

  • nodes resource nodes its extractors sit on

  • links which other factories it exchanges material with

  • issues paused, recipe-less, or unresolved machines

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: paused, dead node (extractor bound to no resource -- a game update removed it), no recipe, blocked (output stack full), starved (input empty), stalled (has input, output has room, still not running -- usually power), intermittent, saturated, unmonitored.

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 name_factory on what it proposes. unnamed_only=True answers "what have I built and not named".

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.

factory_query answers this between LABELLED sets. This answers it for one machine or one building type, which is the question a cutover actually asks: thirteen Oil Extractors sit on the Spire nodes and twenty Fuel Generators are burning, and repiping the wrong extractor first drops several GW.

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 -- match_recipes already does exactly this resolution for exclude_recipes.

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.

consumes="Rubber" is the reverse lookup: every recipe that eats an item. kind is "part" (default), "building" (build-gun costs), "manual" or "all" -- and the header counts EVERY kind over the whole recipe table whatever kind is set to, so a part-only view still says how many buildings eat the item.

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 logistics: a planner assuming a belt or pipe tier it has not unlocked gets every line count wrong by a factor and nothing says so, which is the worst failure mode a planner has.

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.

sources is plan_factory's selector list and means the same thing here, so the baseline printed is the same quantity plan_factory reports for the same nodes.

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.

sources says which resource nodes may feed the plan, as a list of selectors -- named regions, radii, grid cells, compass directions, or specific node ids::

["north"]                        everything in the northern half
["region:Northern Forest"]       one named region
["near:0,-2000,900"]             within 900 m of (0, -2000) metres
["node:BP_ResourceNode30_103"]   one exact node (repeatable)
["grid:X3Y4", "grid:X3Y5"]       specific grid cells
["north", "resource:Crude Oil"]  narrow a location to one resource

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.

extractor_clocks overclocks the SOURCE NODES only, e.g. [1.0, 1.5, 2.0, 2.5]. That is the usual play: a node set is fixed, so speed is the only way to get more out of it, whereas overclocking production machines mostly burns power. Each machine above 100% needs Power Shards, which nothing here counts.

clocks is only for asking a different question: passing [0.5, 1.0] lets the solver SPREAD throughput over more machines to save power, which is real but not free, so each machine is priced at machine_cost_mw (default 5 MW, just above the 2.58 MW/machine that trade was measured to be worth). Overclock modes are not offered by default because they consume Power Shards, which nothing here counts.

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.

exports is the whitelist of what may leave, and the single most load-bearing argument here; default is power only, which is often infeasible for crude oil::

exports=["MW"]                        power out, plant must be self-powered
exports=["Plastic", "Rubber"]         items out, NO power export
exports=["MW", "Plastic", "Rubber"]   both -- MW must be listed explicitly

Two things worth reading twice. The power token is MW (mw, power and Power all work too), not the item name of anything. And exports replaces the default rather than extending it: naming an item drops MW, which is deliberate, because exporting MW also forbids drawing from the existing grid. A token matching no item is refused by name rather than solved around.

sloops is a BUDGET, not a switch: it is how many Somersloops you will actually commit, and the solver spends up to that many wherever they buy the most. Default 0 spends none, because only a fixed number exist on the whole map and a plan that quietly assumed them would be unbuildable. Each one costs 4x power for 2x output on its machine, so they are placed one at a time across many machines rather than filling one -- output is linear in sloops and power is quadratic, so spreading wins.

logistics_items pins named items into the belt/pipe table however small their flow, as rows ADDED to the limit biggest by volume. Without it, a two-item question can fall off the bottom of a big plan's flow table.

plan_layoutA

Turn a plan into a buildable schematic: blocks, buses and floors.

Same arguments as plan_factory, plus detail: "floors" (default, the stack), "blocks" (every module with its size and rates), "buses" (item flows), "trunks" (which resource nodes share each pipe or belt run into the site), "materials" (what the whole thing costs to build, machines plus deck), or "sites" (cut the plan into named modules and report what crosses between them).

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 plan= and the diff is also grouped by STARTUP STAGE -- the same partition commission_plan emits -- so it answers "which stage am I in". stage=<n> narrows to one stage's delta; stage=0 asks for the overview without a stored plan, at the cost that the numbering moves when the arguments do.

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 item to focus on one byproduct instead of the whole plan.

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.

qty is a RATE, per minute. Solved by the LP, never by expanding the recipe tree: Recycled Plastic and Recycled Rubber form a real 2-cycle, so an expansion has no correct depth limit. Every row names the recipe chosen for that item, because alternates change the totals materially.

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 plan=.

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.

plan_machines machines at plan_clock costs shards per machine; the answer says whether the free pool covers it.

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. BP_UnlockSubsystem_C records overclocking as mIsBuildingOverclockUnlocked, but nothing anywhere in the file records production amplification, so it is derived from the purchased-schematic set instead. Capability rows are marked LOCKS so it is obvious which research gates a tool argument rather than just adding a recipe.

somersloopsC

Somersloops held, slotted and owned -- the sibling of power_shards.

sloop_budget has existed since sloops became spendable and nothing exposed it, so the only way to learn how many you had was to guess a sloops= budget and read the shortfall warning: you had to guess the budget to discover the budget.

Free and committed are both exact. Slotted ones live in InventoryPotential, the same component as Power Shards, so this counts slot contents rather than inverting a boost multiplier.

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:

  • the map says what exists and where, read from the installed game's own cooked packages, so placed is exact and every coordinate is exact;

  • the save says what is gone. The world is not saved -- a save never mentions a slug still lying there -- so its destroyed-actor list is the collected list, and it is exact too. remaining is the subtraction of the two.

Modes: census (default) counts every category; collected and remaining list individual placements with coordinates; nearest lists the remaining ones by distance from near, defaulting to the player.

A placement in a cell no save has ever loaded is counted as remaining and reported as never_streamed. It is never called present -- the map says where it is and nothing on disk says whether it is still there.

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.

  • fields (default) clusters nodes within 200 m and ranks by yield -- "where is there a lot of iron".

  • nodes lists one row per node, ranked by yield, with ids reusable as selectors.

  • nearest lists one row per node ranked by DISTANCE from near, with the distance shown -- "what is closest". Requires near.

sources is a list of selectors; locations union, filters intersect::

["north"]                          northern half of the map
["region:Northern Forest"]         one named region
["near:0,-2000,800"]               within 800 m of (0, -2000) metres
["grid:X3Y4"]                      one 1.024 km grid cell
["node:BP_ResourceNode26_99"]      one specific node
["north", "resource:Crude Oil"]    crude oil in the north
["bbox:-500,-2500,600,-1800"]      a rectangle, metres

near accepts a coordinate in metres, me for the player, or the name of a labelled factory -- "the nearest free coal to the coal powerplant" needs no coordinates. Giving near in any mode adds a distance column.

show_on_mapA

A satisfactory-calculator.com map link centred on something, with layers on.

target accepts a coordinate in metres, me, one of your named factories, a node id from search_resource_nodes, or a resource name — the last centres on that resource's nodes and switches its overlays 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.

sources narrows the search area using the same selectors as search_resource_nodes; omit it to search the whole map.

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 near:me,<radius> as a source selector in the planning tools to scope work to here.

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

NameDescription
design_factoryPlan a factory for a target item, respecting what this world has unlocked.
plan_power_plantPlan a power plant from a given resource and area.
pick_hard_driveAdvise which alternate recipe to take from a pending hard drive.

Resources

Contextual data attached and managed by the client

NameDescription
docs_summaryOne-line census of the normalized game data, plus its content hash.
current_saveWhich world and file the server would read right now, and its headline state.
factory_labelsFactory 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_regionsRegion names available as source selectors, with their accuracy caveat.

Latest Blog Posts

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