Skip to main content
Glama

Server Configuration

Describes the environment variables required to run the server.

NameRequiredDescriptionDefault
JMRI_URLNoBase URL of the JMRI Web Serverhttp://localhost:12080

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
list_systemsA

List every DCC power system known to JMRI, with its current power state.

Use this to discover what systems exist before calling get_power, or to answer "what systems are there?". No side effects.

Each system's "name" is JMRI's full connection name, often with a parenthetical describing what it's for (e.g. "zou (test)", "raijin (tracks)") — the user set these themselves in JMRI. If asked what a system is used for, this name is the answer; don't say that information isn't available.

get_powerA

Get the current power state (ON/OFF/UNKNOWN/IDLE) of one DCC system.

Args: system: System name, prefix, or fragment (e.g. "ohara", "O"). Case-insensitive. Omit to use JMRI's default system.

No side effects — this only reads state, it never changes power.

The returned "name" is JMRI's full connection name, often with a parenthetical describing what the system is for (e.g. "zou (test)"). If the user asks what a system is used for rather than its power state, answer from this name.

set_powerA

Turn a DCC system's power ON or OFF, and report the state actually observed.

Args: system: System name, prefix, or fragment (e.g. "ohara", "O"). Case-insensitive. Omit to use JMRI's default system. turn_on: True to turn power ON, False to turn it OFF.

This writes to JMRI. The reported state is re-read ~1s after the command (JMRI's immediate POST response is transient/unreliable) — if the observed state doesn't match the request, "confirmed" will be false and the caller should say so honestly rather than assume success.

Safe to call repeatedly with the same turn_on value, including right after another call already set that state: current state is always checked first, and nothing is sent to JMRI if it already matches the request — re-POSTing a state JMRI already reports is a real bug (JMRI/JMRI#15279) that knocks the system into UNKNOWN. JMRI 5.17.1+ self-recovers from that within seconds; older JMRI doesn't, so this result may include "outdated_jmri_version" — tell the user to upgrade JMRI rather than expect this to self-heal.

In exhibition mode, turn_on=True is REFUSED (returns an error, power stays off) — turn_on=False (an emergency power cut) always still works. See enter_exhibition_mode.

power_off_allA

Cut power to EVERY DCC system at once — the real "stop absolutely everything" button.

No arguments. Call for "cut the power", "cut everything", "kill the power", "coupe le courant", "coupe tout", "coupe l'alimentation" — any generic power-cut request with no specific system named. Use this even when the phrase sounds like a stop command — "coupe le courant" means THIS tool, not emergency_stop_all, since the user is naming power, not motion. For a genuine layout-wide emergency, this reaches every locomotive regardless of who's driving it (JMRI panel, PanelPro, another session) — unlike emergency_stop_all, which only e-stops locomotives THIS session has acquired and never touches power.

More drastic than emergency_stop_all: also stops anything with no throttle acquired, but re-powering afterward requires an explicit set_power(system, turn_on=True) per system before any locomotive can move again — don't use this for a routine "stop the train", only a real emergency.

Each system's result is re-read and confirmed like set_power — check "confirmed" per system (see set_power's docstring for the "outdated_jmri_version" upgrade note, also per system here).

power_on_allA

Restore power to EVERY DCC system at once.

No arguments. Call this for phrases like "turn everything on", "power everything on", "allume tout", "remets le courant" — any request to restore/turn on power generically, without a specific system named. The inverse of power_off_all — use this after a layout-wide power cut (power_off_all, or manually turning systems off) to bring every system back to ON in one call, rather than naming each system individually with set_power.

IMPORTANT: restoring power does NOT make locomotives resume their previous speed. Every decoder stays stopped until a new speed command is sent — this only restores track power, it is not an "undo" of power_off_all or emergency_stop_all. Tell the user locomotives will need to be started again after calling this.

Each system's result is re-read and confirmed like set_power — check "confirmed" per system (see set_power's docstring for the "outdated_jmri_version" upgrade note, also per system here).

In exhibition mode this is REFUSED entirely (returns an error, no system is touched) — power_off_all is unaffected. See enter_exhibition_mode.

system_statusA

One-call diagnostic: is JMRI reachable, and what state is it in?

Reports JMRI reachability/version and every power system's state. Call this first when something isn't responding, instead of guessing which tool to retry. No side effects.

list_rosterA

List every locomotive in JMRI's roster: name, DCC address, road, road number, manufacturer, model, owner, last-modified date, roster groups, DCC system, and max speed percent.

Use this to discover what locomotives exist and their DCC addresses before calling acquire_throttle/set_speed/etc. — this is currently the only way to find which address belongs to which named loco (e.g. "start the Autorail" but set_speed needs address=4). Any field can be empty if unfilled in JMRI — normal, not an error. "groups": JMRI Roster Groups (most belong to none). "dcc_system": command station prefix from a "DccSystem" Roster Entry Attribute, null if unset (JMRI's default station drives it instead) — pass as acquire_throttle's prefix when set. "dcc_system_name": full name of the system actually in use, always populated. "max_speed_percent": roster "Throttle Speed Limit" (1-100, default 100) — set_speed/ set_speed_ramped already scale by this, so 100% requested means 100% of THIS number, not the raw decoder ceiling. No side effects.

Does NOT resolve a name to an address for you — use find_locomotive.

find_locomotiveA

Resolve a locomotive's spoken/typed name to its DCC address.

Use this whenever the user names a locomotive ("the Autorail", "141R", "start the Pacific") instead of giving a DCC address directly — call this first to get the address, then pass that address to acquire_throttle/set_speed/set_direction/set_function/ lights_on/lights_off/etc.

Matching is tolerant: case-insensitive, accent-insensitive (useful for French names — "boite a sel" matches "Boite à Sel"), and accepts an exact name or an unambiguous partial match ("autorail" matches "Autorail"). If the name matches more than one roster entry, or matches none, this returns an "error" explaining why (listing the candidates or the full roster) instead of guessing — ask the user to clarify rather than picking one yourself.

Includes the same "dcc_system"/"dcc_system_name"/"max_speed_percent" fields as list_roster — see that tool's docstring for what they mean.

get_locomotive_functionsA

List a locomotive's named decoder functions (e.g. "F2": "Rear lights").

JMRI lets the user label each loco's functions individually in its roster editor — call this BEFORE set_function whenever the user refers to a function by what it does ("turn on the rear lights", "blow the whistle") instead of an F-number, so you can look up the right number instead of guessing or asking. Only labels the user actually set are returned; most locos have few or none (an empty "functions" dict is normal, not an error — it means this loco has no custom labels, so ask the user for an F-number instead).

Args: name: The locomotive's name (fuzzy-resolved the same way as find_locomotive — call this directly, you don't need to call find_locomotive first just to get the exact name).

Returns functions as {"F0": "label", ...}. Function numbers with no label set are omitted entirely (JMRI has 29 possible slots, F0-F28, per loco — only the labeled ones are useful to you).

acquire_throttleA

Acquire control of a locomotive by its DCC address, and report its current state.

Args: address: The locomotive's DCC address. prefix: Optional command station prefix (e.g. "O", "Z", "R") to target when more than one DCC system is connected. Omit to auto-detect from the roster's DccSystem attribute (see list_roster's "dcc_system" field), else JMRI's default station. Pass explicitly only to override auto-detection.

You usually do NOT need to call this explicitly before set_speed/ stop/emergency_stop — those auto-acquire on first use (same DccSystem auto-detection) for a smoother voice UX. Call this directly when you want a loco's current speed/direction before deciding what to do (the reply reports both), or to override the detected station via an explicit prefix.

Safe to call again on an address already acquired this session — JMRI just re-confirms it, no error or loco reset. Release with release_throttle when done, though not required: JMRI releases every throttle this session holds if the MCP server disconnects.

In exhibition mode with an address allowlist configured, an address outside it is refused here (and by every other throttle tool, routed through this same check) — see enter_exhibition_mode.

Returns "system": full name of the command station actually used, only when non-default — mention it to the user when present.

release_throttleA

Release this session's control of a locomotive acquired with acquire_throttle.

Args: address: The locomotive's DCC address.

Good practice once you're done controlling a loco (frees it up for other JMRI clients/throttles to acquire without contention), but not required for correctness — JMRI releases it automatically when the MCP server's connection to JMRI closes, so a missed release_throttle does not leave the loco "stuck" for other clients across restarts.

Turns off any still-active function (e.g. lights) first automatically — releasing with one on leaves the decoder in an unpredictable state (can flip direction). No action needed from you for this.

set_speedA

Set a locomotive's speed as a percentage of its maximum (0-100%).

Args: address: DCC address. Auto-acquires the throttle if needed. speed_percent: 0-100, clamped not rejected. direction: Optional "forward"/"reverse" (case-insensitive) — set together with speed_percent atomically ("avance à 40%") instead of a separate set_direction call. Omit to leave direction untouched. Flips instantly; for a ramped flip use set_speed_ramped instead.

Returns actual speed as % of THIS loco's own configured maximum (roster "Throttle Speed Limit"), matching PanelPro's slider, not the raw decoder ceiling. Includes "direction" only when passed, "system" (command-station name) only when non-default.

Use stop (0%) or emergency_stop (panic) rather than speed_percent=0. For a DURATION use set_speed_ramped(hold_seconds=...) — this tool is immediate only.

No-op (no error, no write) if requested speed already matches current — JMRI sends no confirmation for a redundant command.

Exhibition mode overrides speed_percent/direction with a fixed moderate forward speed — see enter_exhibition_mode.

set_speed_rampedA

Change a locomotive's speed gradually — a smooth ramp up and/or down.

Args: address: DCC address. Auto-acquires the throttle if needed. speed_percent: Target speed, 0-100%. Legacy shorthand: NEGATIVE toggles direction relative to current facing, ramps to |value|%. Prefer explicit direction for new calls — ignored as a sign once direction is given (only its clamped 0-100 magnitude used then). direction: Optional "forward"/"reverse" (case-insensitive), set atomically with speed_percent, e.g. "avance progressivement à 40%" (loco in reverse) -> speed_percent=40, direction="forward", rampup_seconds=3. Wins over the negative-sign shorthand if both given. rampup_seconds: Seconds to climb to the target if higher (or on a direction flip while moving). 0 = instant. rampdown_seconds: Seconds to descend when lower, on a direction-flip stop-first, and for hold_seconds' auto-stop. 0 = instant. hold_seconds: Hold the target this long, then auto-ramp to a stop before returning — "run forward at 30% for 10s" -> hold_seconds=10. Omit to reach the target and keep going.

Use instead of plain set_speed for "en douceur"/"progressivement" or a duration before stopping. Use emergency_stop for a panic stop — never sent here, even at rampdown_seconds=0.

A SHORT total duration blocks and returns final speed/direction. A LONGER one returns immediately with "status": "started" and keeps running server-side — the loco stops itself automatically, no follow-up call needed. "started" is success, not "finished".

A direction flip while moving ramps to 0 first, flips, then ramps back up.

speed_percent is relative to THIS loco's configured maximum (roster "Throttle Speed Limit") like set_speed.

Returns final speed/direction, or for the background path: {"address", "status": "started", "speed_percent", "direction", "seconds_total"}. Either shape includes "system" (full command-station name) only when non-default.

In exhibition mode, speed_percent/direction are IGNORED and replaced with a fixed, moderate, forward-only speed.

stopA

Bring a locomotive to a controlled stop (speed 0%), like releasing the throttle.

Args: address: DCC address. Auto-acquires the throttle if needed.

For a panic/safety stop (derailment risk, collision course, "stop it NOW") use emergency_stop instead — a distinct decoder command (immediate motor power cut), not just "speed 0". Use this stop for a normal, intentional halt (end of run, waiting at a signal).

Safe to call repeatedly, even when already stopped: JMRI silently ignores a redundant request, and a local speed cache (kept fresh by JMRI's own broadcasts from ANY client) still returns the correct current speed_percent without hanging.

emergency_stopA

Emergency-stop a locomotive immediately (JMRI's decoder e-stop command).

Args: address: DCC address. Auto-acquires the throttle if needed.

Use ONLY for safety-critical stops: derailment risk, imminent collision, or any situation needing an immediate halt rather than smooth deceleration. This is JMRI's actual decoder e-stop (speed -1.0 on the wire, distinct from a normal speed command) — cuts power abruptly, rougher on the mechanism, so don't use as a synonym for routine stop.

Returns stopped: true once confirmed. Safe to call repeatedly: a redundant e-stop is a silent no-op on JMRI's side, and a local cache (kept fresh from JMRI's broadcasts from any client) reports correct status instead of hanging.

emergency_stop_allA

Emergency-stop EVERY locomotive currently under this session's control at once.

No arguments — panic button for "stop everything NOW" (derailment, collision risk, no time to name individual locomotives). Call for "stop everything"/"stop all trains"/"arrête tout"/"arrête toutes les locos" — stop MOTION generically, no locomotive named. Sends the same decoder e-stop as emergency_stop(address) to every address this session has acquired.

NOT "cut the power"/"coupe le courant"/"coupe tout" — that means power_off_all (real power cut to every DCC system, reaching locomotives regardless of who's driving them). This only sends a throttle command, never touches track power.

LIMITATION: only reaches locomotives THIS session has acquired. A locomotive driven only from a JMRI panel or another session is NOT stopped, since only the connection holding a throttle can command it. For a guarantee covering everything regardless of driver, use power_off_all instead.

Returns {"stopped": [...addresses e-stopped...], "failed": [...]}. An address with no error is confirmed at emergency-stop speed either way (already-stopped locos are a safe no-op, not skipped silently without being reported).

set_directionA

Set a locomotive's direction of travel: "forward" or "reverse".

Args: address: DCC address. Auto-acquires the throttle if needed. direction: Exactly "forward" or "reverse" (case-insensitive) — the decoder's own front/back, not compass direction. For "turn it around"/"go the other way", flip the current reported direction rather than guessing.

Best practice: stop a moving loco first — a direction change at speed can jolt or be ignored depending on the decoder; this tool doesn't enforce that, just forwards the request.

Returns direction as "forward"/"reverse" (translated from JMRI's true/false) — independent of speed, never changed here.

Safe to call repeatedly with the same direction: JMRI silently no-ops a redundant request, and a local cache (kept fresh by JMRI's own broadcasts from ANY client) avoids hanging on a repeat or externally-set direction.

In exhibition mode, "reverse" is REFUSED outright (returns an error, does not silently force forward — there's no speed change here to narrate as "moving anyway") — "forward" still works normally. See enter_exhibition_mode.

set_functionA

Turn one of a locomotive's decoder functions (F0-F28) on or off.

Args: address: DCC address. Auto-acquires the throttle if needed. function: 0-28 inclusive (validated locally; out-of-range returns an error without contacting JMRI). What each number controls is decoder/roster-specific — F0 is almost always headlight(s) (see lights_on/lights_off), F1-F28 vary loco to loco (bell, horn, sounds, couplers...). If the user names a function by effect ("turn on the bell", "rear lights") rather than a number, call get_locomotive_functions(name) FIRST to check for a user-set label before guessing or asking — only ask for the F-number if no label matches. state: True to turn the function on, False to turn it off.

Safe to call repeatedly with the same state: JMRI silently no-ops a redundant request, and a local per-function cache (kept fresh by JMRI's own broadcasts from ANY client holding this address) avoids hanging on a repeat or externally-toggled function.

lights_onA

Turn on a locomotive's headlight(s): shortcut for set_function(address, 0, True).

F0 is almost universally the headlight function across DCC decoders (this is a very strong convention, not a JMRI/protocol guarantee), so this is the tool to reach for on a plain "turn the lights on" voice request without asking the user for a function number. Same auto-acquire and no-op-safe behavior as set_function.

This is the locomotive's own headlight, NOT layout/scenery lighting (depot, street lamps, signals) — for those, use set_light instead.

lights_offA

Turn off a locomotive's headlight(s): shortcut for set_function(address, 0, False).

See lights_on for why F0. Same auto-acquire and no-op-safe behavior as set_function.

This is the locomotive's own headlight, NOT layout/scenery lighting (depot, street lamps, signals) — for those, use set_light instead.

set_loco_lightsA

Turn ON/OFF EVERY light-related function of ONE locomotive in a single call.

Args: address: DCC address. Auto-acquires the throttle if needed. state: True to turn every light-related function on, False off.

Different from lights_on/lights_off (F0 only). Reads the roster function LABELS (set by the user in JMRI's roster editor — see get_locomotive_functions) and switches every function whose label names a light: "light"/"lamp"/"headlight" (EN) or "lumière"/"feu"/ "lampe"/"phare" (FR), case/accent-insensitive. Example: Autorail has F0="Lumières avant", F1="Lumières cabine", F2="Lumières arrières" — all three light-labeled, so "all lights" must flip all three, not just F0. Use for "all"/"every"/"toutes les lumières" with a named locomotive — never loop set_function yourself.

No light-labeled functions is NOT an error: returns an empty "applied" list with a "note". Only ask for an explicit F-number as a fallback then.

For "all locos" (no locomotive named), use set_all_locos_lights. For layout/scenery lighting (JMRI Light objects), use set_layout_lights instead.

Returns {"address", "applied": [{"function", "label", "state"}...], "failed": [...]} — catch-and-continue per function.

set_all_locos_lightsA

Turn ON/OFF EVERY light-related function of EVERY currently-acquired locomotive at once.

Args: state: True to turn every light-related function on for every locomotive, False to turn them all off.

Call for "turn on/off all the lights of all the locos"/"allume/ éteins toutes les lumières de toutes les locos" — locomotives in bulk, no single one named. Never loop set_loco_lights/set_function yourself — this loops server-side in one call, over every locomotive this session has acquired.

Same scope limitation as emergency_stop_all: only reaches locomotives THIS session has acquired a throttle for. A locomotive driven only from a JMRI panel or another session is untouched. Nothing acquired yet returns {"locomotives": []}, not an error.

For ONE named locomotive use set_loco_lights. For layout/scenery lighting (JMRI Light objects, no locomotive involved), use set_layout_lights instead — never this tool.

Returns {"locomotives": []} — attempted independently, one failure doesn't block the others.

prepare_locomotiveA

Prepare ONE locomotive for a session: acquire, face forward, lights on.

Args: address: The locomotive's DCC address. prefix: Optional command station prefix (e.g. "O", "Z", "R"), passed straight through to acquire_throttle — including its DccSystem roster auto-detection when omitted.

Use for "prépare la loco"/"prepare the 3"/"get the autorail ready" — counterpart to park_locomotive, beginning a session rather than a normal "go" mid-run.

NOT stop/emergency_stop (speed only, active session) and NOT set_power (DCC station power, JMRI-wide). Only touches this locomotive's session state (throttle + lights), never power or speed/motion.

Three steps, one call: (1) acquire the throttle (safe if already held); (2) set direction forward (session-start convention, matching park_locomotive's end-of-session state); (3) turn on every light-related function, same as set_loco_lights(address, True).

Does NOT set a speed. Follow with set_speed/set_speed_ramped if the user also asked it to move.

Never call acquire_throttle, set_direction, and set_loco_lights yourself in sequence for a "prepare" request — use this tool.

Returns {"address", "acquired": bool, "direction": "forward", "lights": }.

park_locomotiveA

Put ONE locomotive to rest for the session: smooth stop, forward, lights off, throttle released.

Args: address: The locomotive's DCC address.

Use for "éteins la loco"/"coupe les moteurs"/"put the 3 to bed"/ "park the autorail"/"shut down the autorail" — end-of-session shutdown for one locomotive, not a mid-run pause (use stop).

NOT stop/emergency_stop (speed only, throttle stays acquired, lights untouched) and NOT set_power (DCC station's own power, JMRI-wide). This tool only touches this one locomotive's session state (speed + lights + release), never system power.

Four steps, one call: (1) ramp down to 0, duration scaled to current speed (up to ~3s at full speed, shorter/none if already slow); (2) flip to forward if in reverse (safe, since speed is 0 by now); (3) turn off every light-related function, same as set_loco_lights(address, False); (4) release the throttle.

If never acquired, steps 1-2 are skipped, but step 3 still auto-acquires (like set_loco_lights always does) so step 4 always has something to release.

Never call set_speed/stop, set_direction, set_loco_lights, and release_throttle yourself in sequence for a shutdown request — use this tool.

Returns {"address", "stopped": bool, "direction": "forward", "lights": , "released": bool}.

park_all_locomotivesA

Put EVERY currently-acquired locomotive to rest at once: smooth stop, forward, lights off, released.

Call for "éteins toutes les locos"/"coupe tous les moteurs"/"shut down every locomotive"/"put everything to bed" — the bulk counterpart to park_locomotive. Never loop park_locomotive yourself — this loops server-side in one call, running the same four-step sequence (proportional rampdown, face forward, lights off, release) independently per locomotive.

NOT emergency_stop_all (motion-only, no lights/release) and NOT system power off (cuts every locomotive on a DCC system regardless of driver — no single "power off everything" tool exists, see set_power per system). Only touches locomotives THIS session has a throttle for — one driven only from a JMRI panel or another session is untouched; nothing acquired yet returns {"locomotives": []}, not an error.

For ONE named locomotive use park_locomotive. For motion-only with no lights/release, use emergency_stop_all.

Returns {"locomotives": []} — each stopped independently, one failure doesn't block the others.

list_lightsA

List every layout light known to JMRI, with its current ON/OFF state.

These are JMRI light objects wired to the layout/scenery itself (depot lighting, street lamps, signal lamps, ...) — NOT a locomotive's headlight (that's F0, via set_function/lights_on on a DCC address). Use this to discover what lights exist before calling get_light/set_light, or to answer "what lights are there?". No side effects.

get_lightA

Get the current ON/OFF state of one layout light.

Args: name: Light name (JMRI system name like "IL1", or its user-friendly label like "Depot Lighting") or an unambiguous fragment of the label. Case-insensitive.

This is a layout light (scenery), not a locomotive headlight — for "is the Autorail's headlight on", use get_locomotive_functions instead. No side effects.

set_lightA

Turn a layout light ON or OFF, and report the state actually observed.

Args: name: Light name (JMRI system name like "IL1", or its user-friendly label like "Depot Lighting") or an unambiguous fragment of the label. Case-insensitive. turn_on: True to turn the light ON, False to turn it OFF.

This is a layout light (scenery: depot, street, signal lamps, ...), distinct from a locomotive's F0 headlight function — if the user names a locomotive rather than a place/scene, use set_function or lights_on/lights_off on its DCC address instead. This writes to JMRI; the reported state is re-read after the command, and "confirmed" is honestly reported false if the observed state doesn't match what was requested (e.g. a feedback-wired light that didn't actually switch).

set_layout_lightsA

Turn EVERY layout light ON or OFF at once (depot, street, signal lamps — JMRI Light objects).

Args: turn_on: True to turn every layout light ON, False to turn every layout light OFF.

These are JMRI light objects wired to the layout/scenery itself — NOT a locomotive's own headlight/cabin/rear-light functions. Call for a lighting request that does NOT name a locomotive ("turn on all the lights", "éteins toutes les lumières" with no loco mentioned). If the request DOES name a locomotive ("all of the Autorail's lights"), use set_loco_lights or set_all_locos_lights instead — never this tool for that case.

Never loop set_light yourself for "every light"/"toutes les lumières" — this loops server-side in one call over every light JMRI reports.

Returns {"succeeded": [...], "failed": [...]}, each entry shaped like set_light's own return value plus "name". One light failing doesn't stop the rest (catch-and-continue).

list_turnoutsA

List every turnout known to JMRI, with its current CLOSED/THROWN state.

Use this to discover what turnouts exist before calling get_turnout/set_turnout, or to answer "what turnouts are there?"/ "which way is turnout X set?". No side effects.

Each entry includes "has_feedback_sensor" (bool). When false, that turnout has no real position sensor wired up, and a state of INCONSISTENT is its normal/expected steady state — not an anomaly. Do not flag it to the user as a problem in that case; only state="INCONSISTENT" on a turnout where has_feedback_sensor is true is worth calling out as possibly unsettled.

get_turnoutA

Get the current CLOSED/THROWN state of one turnout.

Args: name: Turnout name (JMRI system name like "IT100", or its user-friendly label like "Layout Turnout A") or an unambiguous fragment of the label. Case-insensitive.

No side effects — this only reads state, it never changes the turnout.

The result includes "has_feedback_sensor" (bool). When false, that turnout has no real position sensor wired up, and a state of INCONSISTENT is its normal/expected steady state — not an anomaly. Do not flag it to the user as a problem in that case; only state="INCONSISTENT" on a turnout where has_feedback_sensor is true is worth calling out as possibly unsettled.

set_turnoutA

Set a turnout CLOSED or THROWN, and report the state actually observed.

Args: name: Turnout name (JMRI system name like "IT100", or its user-friendly label like "Layout Turnout A") or an unambiguous fragment of the label. Case-insensitive. thrown: True to THROW the turnout, False to CLOSE it. JMRI/ PanelPro's own terminology — not "open"/"closed" track, which would be ambiguous about which direction is which.

This writes to JMRI (and moves a physical turnout motor on real hardware). The reported state is re-read after the command; if the observed state doesn't match the request, "confirmed" will be false and that should be reported honestly rather than assumed as success — some turnouts have feedback sensors that can fail to settle to the commanded position.

set_all_turnoutsA

Set EVERY turnout on the layout to the SAME state (all CLOSED, or all THROWN) in one call.

Args: thrown: True to THROW every turnout, False to CLOSE every turnout. Applies this ONE state to ALL of them — NOT a "restore each turnout to its own previous/default position" operation, there is no such per-turnout memory.

Call for "close/throw all turnouts"/"tous les aiguillages en position fermée/déviée". Never loop set_turnout yourself — this loops server-side in one call over every turnout JMRI reports.

BLAST RADIUS WARNING: moves every turnout motor on the real layout at once if hardware is connected. Only call for a clear layout-wide request, not as a shortcut for one named turnout (use set_turnout for that).

Returns {"succeeded": [...], "failed": [...]}, each entry shaped like set_turnout's own return value plus "name". One turnout failing doesn't stop the rest (catch-and-continue).

list_sensorsA

List every sensor known to JMRI, with its current ACTIVE/INACTIVE state.

Sensors report real-world state detected by JMRI's own hardware inputs — most commonly block occupancy ("is a train on block X?"), but also things like turnout motor feedback or a clock-running flag. Read-only, no side effects. Use this to discover what sensors exist before calling get_sensor, or to answer "what sensors are there?"/"is anything occupied right now?".

get_sensorA

Get the current ACTIVE/INACTIVE state of one sensor.

Args: name: Sensor name (JMRI system name like "RS22", or its user-friendly label like "Montagne B") or an unambiguous fragment of the label. Case-insensitive.

Use this to answer "is block X occupied?" or similar real-world state questions ("is the clock running?" for the ISCLOCKRUNNING sensor JMRI always has). Read-only — there is no set_sensor tool, since a sensor reflects hardware JMRI detects, not a command this project should issue. No side effects.

list_signalsA

List every signal mast known to JMRI, with its current aspect.

Use to discover what signal masts exist before calling get_signal/set_signal, or to answer "what signals are there?"/ "what aspect is signal X showing?". No side effects.

A signal mast is a trackside signal (e.g. German Hauptsignal), distinct from a turnout (switch/points) or a layout light (scenery) — don't confuse with set_turnout/set_light. Only covers signalMast objects, not JMRI's lower-level signalHead objects (rarely used directly once a mast is configured).

"aspect" is a name like "Hp0"/"Hp1"/"Hp2" (German Hauptsignal) or a different vocabulary depending on the mast's configured signal system — aspect names are never hardcoded/translated, just passed through from JMRI.

get_signalA

Get the current aspect of one signal mast.

Args: name: Signal mast name (JMRI system name, or its user-friendly label if one is set) or an unambiguous fragment of the label. Case-insensitive.

No side effects — this only reads state, it never changes the signal.

set_signalA

Set a signal mast's aspect, and report the aspect actually observed.

Args: name: Signal mast name (JMRI system name or user-friendly label) or an unambiguous fragment. Case-insensitive. aspect: The aspect to request, e.g. "Hp0" (stop), "Hp1" (proceed), "Hp2" (proceed reduced speed) for a German DB-HV-1969 mast — valid names depend on this mast's configured signal system and are NOT validated locally (JMRI doesn't expose a valid-aspect list); JMRI validates server-side and this tool reports rejection as an error. If unsure, call get_signal/list_signals first to see the current aspect as a naming-style example, or ask the user rather than guessing.

Writes to JMRI, and on masts driven by external hardware (DCC accessory decoder, microcontroller) changes the real physical signal. An unknown aspect is reported as an "error". A valid aspect is re-read after the command; if the observed aspect still doesn't match, "confirmed" is false — report that honestly, not as success, since unresponsive hardware can cause this even when JMRI itself accepted the change.

list_blocksA

List every layout block known to JMRI, with its current OCCUPIED/UNOCCUPIED state.

A block is a named section of track JMRI uses for occupancy detection and signaling logic — richer than a plain sensor: each block also reports which sensor drives its occupancy, and (on layouts with RFID/reporter-based detection, not just simple occupancy) a "value" identifying what's occupying it. Also includes static layout metadata set in PanelPro's block editor: "length" (track length), "curvature", "speed" (a named speed restriction, e.g. "Normal"/"Fifty" — vocabulary is layout-defined), and "comment" (free text). Read-only, no side effects. Use this to discover what blocks exist before calling get_block, or to answer "what blocks are there?"/"is anything occupied right now?" at the layout-section level (as opposed to a single sensor's raw state).

get_blockA

Get the current OCCUPIED/UNOCCUPIED state of one layout block.

Args: name: Block name (JMRI system name like "IB1", or its user-friendly label) or an unambiguous fragment of the label. Case-insensitive.

Use this to answer "is block X occupied?" when the user names a layout block/section specifically (as opposed to a raw sensor id — if they instead name a sensor directly, use get_sensor). Read-only — there is no set_block tool, since a block reflects hardware JMRI detects via its linked sensor, not a command this project should issue. No side effects.

set_executor_modeA

Turn "executor mode" (concise, no-narration responses) on or off. ON by default.

Args: enabled: False to switch to normal, explanatory responses for the rest of the conversation — call this when the user asks you to explain more / stop being so terse. True to switch back to terse/execution-only responses (already the default at the start of every conversation, so you only need this to undo a previous enabled=False).

Concise responses are the standing default from the very first turn (see the server's own instructions) — you do not need to call this at conversation start. Call it only when the user explicitly asks to change the response style, in either direction — phrases like "explain more", "stop being so terse" -> enabled=False; "be quick", "mode exécutant" again after asking for explanations -> enabled=True.

This does NOT silence errors or safety confirmations — always report a failed command or a "confirmed: false" honestly, briefly, even in executor mode.

get_executor_modeA

Report whether executor mode (concise, no-narration responses) is currently on.

No arguments. Executor mode is ON by default from the start of every conversation. Call this if you're unsure whether it's still active (e.g. at the start of a new turn after a long gap, or after the user asked for more explanation earlier and you want to check it wasn't re-enabled) — it re-delivers the same standing instruction as set_executor_mode for whichever state is current, since there's no system-prompt-level way for this server to keep reminding you otherwise.

enter_exhibition_modeA

Turn ON exhibition mode: a restricted-safety mode for public demos (exhibitions, kids trying voice control).

No arguments, no password needed — always freely callable, so this can be turned on quickly whenever the layout is about to be unsupervised or handed to the general public. Call for "mode exposition"/"exhibition mode"/"passe en mode démo"/"active la protection visiteurs" or similar.

While active: power_on_all/set_power(turn_on=True) are refused (power_off_all and set_power(turn_on=False) still work — cutting power for an emergency always stays available); every locomotive moves FORWARD ONLY at a fixed moderate speed no matter what speed/ direction is requested (the request is silently downgraded, not rejected — report that the loco is moving, not an error); and if an address allowlist was configured at install time, only those DCC addresses can be acquired or driven. Lights and functions (set_function/lights_on/lights_off/set_loco_lights) are NOT restricted — the exhibition can still show off lighting.

Exiting requires exit_exhibition_mode(password) — a password configured at install time (see that tool's docstring), NOT this one. This asymmetry is deliberate: turning the safety ON should never be gated, only turning it back OFF.

exit_exhibition_modeA

Turn OFF exhibition mode, restoring full normal control. Requires the correct password.

Args: password: Must match the password configured at .mcpb install time (EXHIBITION_PASSWORD env var; a playful default is used if the installer left it blank). Compared tolerantly (case/accent/whitespace-insensitive, via the same folding used for locomotive name matching) since this password is normally spoken aloud through voice transcription — this is a casual demo-mode guard against a curious visitor, not a real auth system, so a transcription quirk shouldn't lock the operator out.

Call only when the user explicitly asks to leave exhibition mode AND provides (or is asked for) the password — never guess or supply a password yourself, and never reveal the configured password if asked what it is. A wrong password leaves exhibition mode ON (see the returned instruction) — ask the user to retry rather than trying variations yourself.

On success, restores real speeds, reverse, power on/off, and any DCC address (no more allowlist).

get_exhibition_modeA

Report whether exhibition mode (restricted-safety public-demo mode) is currently on.

No arguments. Call this if you're unsure whether it's still active (e.g. at the start of a new turn after a long gap) — it re-delivers the same standing restriction instruction as enter_exhibition_mode for whichever state is current.

layout_statusA

One-call overview of the whole layout: connectivity, power, active locomotives, blocks, sensors.

Call for "what's happening on the layout?"/"is everything ready?"/"donne-moi l'état du layout" — a broad status question with no single named target. Never chain list_systems + list_roster + list_blocks + list_sensors yourself, this gathers them in one call.

Different from system_status (reachability + DCC power only): this adds every locomotive THIS session holds a throttle for (with speed/direction), block occupancy, and sensor states — fuller, at the cost of more JMRI calls. Use system_status when only reachability/power is in question.

No side effects. Each section is fetched independently with its own "error" key on failure — one section failing doesn't block the rest.

Returns {"reachable", "version", "systems": [...], "locomotives": [], "blocks": [...], "sensors": [...]}, with "*_error" keys for any failed section.

release_all_locomotivesA

Release this session's throttle on EVERY currently-acquired locomotive, without changing their state.

Call for "release all locomotives"/"libère toutes les locos" — ending a session or handing off without stopping anything. Speed and direction stay untouched; only the throttle is released. Exception: any still-active function (e.g. lights) is turned off first automatically — releasing with one on can flip direction.

NOT park_all_locomotives (also stops, faces forward, lights off before releasing) and NOT emergency_stop_all (stops motion but keeps throttles acquired). Use only to let go of control without changing current locomotive state — e.g. handing off mid-run.

Only reaches locomotives THIS session acquired. Nothing acquired yet returns {"released": []}, not an error.

Returns {"released": [{"address", "released": bool}...]} — one entry per locomotive, attempted independently so one failure doesn't block the rest.

secure_layoutA

Put the whole layout into a known safe resting state — the end-of-session "I'm done for today" command.

Args: release_throttles: True (default) to also release every locomotive's throttle at the end. False to stop/light-off every locomotive but keep throttles acquired.

Call for "I'm done for today, secure the layout"/"sécurise le layout"/"on arrête pour aujourd'hui" — a broad end-of-session request naming the layout as a whole, not one locomotive. Never chain stop/set_loco_lights/set_layout_lights/release_throttle yourself, this runs the full sequence server-side in one call.

Runs in order: 1) every acquired locomotive smoothly stopped (ramped, not abrupt), faced forward, lights off — same as park_locomotive, independently per locomotive; 2) every layout light (JMRI Light objects) turned off — same as set_layout_lights(False); 3) if release_throttles is True (default), every throttle released.

NOT power_off_all (cuts DCC track power itself, unconditionally, including locomotives never acquired here — more drastic, never touches power) and NOT emergency_stop_all (motion-only, no lights/release). Only reaches locomotives THIS session has acquired.

Returns {"locomotives": [<per-locomotive stop/lights/release result>...], "layout_lights": }.

night_modeA

Set the layout to night operation mode: turn on every layout light and every locomotive's lights.

Call for "put the layout in night mode"/"mode nuit"/"il fait nuit" — a demonstration-style lighting scene, not a status/power command. Turns ON every layout light (JMRI Light objects — same as set_layout_lights(True)) and every acquired locomotive's light-related functions (same as set_all_locos_lights(True)), in one call.

Does NOT change speed, direction, or throttle acquisition, and does NOT affect track power (set_power) or signal aspects (set_signal) — lighting only. Inverse is day_mode.

Visual/demonstration only — does not read or change JMRI's internal fast clock.

Returns {"locomotives": [...], "layout_lights": }.

day_modeA

Set the layout to daytime operation mode: turn off every layout light and every locomotive's lights.

Call for "put the layout in day mode"/"mode jour"/"il fait jour" — the inverse of night_mode. Turns OFF every layout light (JMRI Light objects — same as set_layout_lights(False)) and every acquired locomotive's light-related functions (same as set_all_locos_lights(False)), in one call.

Does NOT change speed, direction, or throttle acquisition, and does NOT affect track power (set_power) or signal aspects (set_signal) — lighting only.

Returns {"locomotives": [...], "layout_lights": }.

start_sessionA

Begin a driving session: power on every DCC system, then prepare every already-acquired locomotive.

Call for "let's start"/"démarre la session"/"on commence" — the one-call opener. Steps: 1) power_on_all; 2) for every locomotive THIS session already holds a throttle for (usually none at session start — not an error), face forward + lights on, same as prepare_locomotive. Does NOT acquire locomotives untouched this session — follow up with prepare_locomotive/acquire_throttle by name once one is named. Refused in exhibition mode like power_on_all; a power-on failure skips step 2, returns "error".

Returns {"systems": [...], "locomotives": [...]}.

end_sessionA

End a driving session: stop, park and release every acquired locomotive, then cut power to every DCC system.

Call for "let's stop"/"termine la session"/"on arrête" — the one-call closer, inverse of start_session. Strictly ordered so power is never cut mid-motion: 1) every locomotive THIS session holds a throttle for is ramped to stop, faced forward, lights off, released — same as secure_layout(release_throttles=True), one failure doesn't block the rest; 2) power_off_all. Layout lights are NOT touched — use secure_layout/day_mode for those.

NOT secure_layout (also handles layout lights, never touches DCC power) and NOT power_off_all alone (no clean stop/release first). Nothing acquired reduces this to power_off_all alone.

Returns {"locomotives": [...], "systems": [...]}.

Prompts

Interactive templates invoked by user choice

NameDescription

No prompts

Resources

Contextual data attached and managed by the client

NameDescription

No resources

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/HO44-PROJECT/MrJ-JMRI-MCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server