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.

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.

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.

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, model.

Use this to discover what locomotives exist and their DCC addresses before calling acquire_throttle/set_speed/etc. — those tools take a DCC address, not a name, and this is currently the only way to find out which address belongs to which named loco (e.g. the user says "start the Autorail" but set_speed needs address=4). road/model can be empty strings if the user never filled them in in JMRI — that's normal, not an error. No side effects.

This does NOT resolve a name to an address for you automatically — use find_locomotive for that.

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.

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 use JMRI's default command station.

You usually do NOT need to call this explicitly before set_speed/ stop/emergency_stop — those acquire the throttle automatically on first use for a smoother voice UX ("speed up the 3" just works). Call acquire_throttle directly when you specifically want to know a loco's current speed/direction before deciding what to do (the acquire reply reports both), or to target a non-default command station via prefix.

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

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.

set_speedA

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

Args: address: The locomotive's DCC address. speed_percent: 0-100. Values outside this range are clamped, not rejected. Acquires the throttle automatically if this session doesn't already hold it — no need to call acquire_throttle first for a simple "speed up the 3" style voice command.

Returns the actual speed JMRI reports back, as a percentage — this may differ slightly from what was requested (DCC uses a small number of discrete speed steps, so exact percentages get rounded).

Use stop for a controlled halt (speed 0%) or emergency_stop for a panic stop — don't call set_speed(speed_percent=0) for an emergency, it's a different command to JMRI, not just "speed 0".

A locomotive's speed can be changed by something other than this tool at any time — another JMRI panel, PanelPro, another MCP/voice session controlling the same loco. If the requested speed already matches the current one (whoever set it), JMRI does not send a confirmation and this call returns immediately without writing anything new to the layout — this is expected, not a failure; the reported speed_percent in the response is still accurate because it's read from a cache kept continuously up to date by JMRI's own state broadcasts, not from what this tool last sent.

stopA

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

Args: address: The locomotive's DCC address. Acquires the throttle automatically if this session doesn't already hold it.

For a panic/safety stop (derailment risk, collision course, or any "stop it NOW") use emergency_stop instead — JMRI treats it as a distinct decoder command (an immediate power cut to the motor), not just "speed 0". Use this stop tool for a normal, intentional halt (end of a run, waiting at a signal, user just says "stop the 3").

Safe to call repeatedly, including when the loco is already stopped: JMRI silently ignores a redundant "already at this speed" request instead of replying, and this tool's client keeps a local speed cache continuously refreshed by JMRI's own state broadcasts (which fire for ANY client's changes, not just this tool's), so a repeat call still returns the correct current speed_percent (very likely 0) without hanging or erroring.

emergency_stopA

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

Args: address: The locomotive's DCC address. Acquires the throttle automatically if this session doesn't already hold it.

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

Returns stopped: true once JMRI confirms the e-stop speed. Safe to call repeatedly: like stop, a redundant emergency_stop on an already-e-stopped loco is a silent no-op on JMRI's side, and this tool's local throttle-state cache (kept fresh from JMRI's broadcasts, including e-stops triggered by any OTHER client) reports the correct current status instead of hanging.

set_directionA

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

Args: address: The locomotive's DCC address. Acquires the throttle automatically if this session doesn't already hold it. direction: Must be exactly "forward" or "reverse" (case- insensitive). "forward"/"reverse" here mean the loco's own notion of front/back as wired in its decoder — not compass direction or "toward/away from the operator" — so if a user says "turn it around" or "go the other way", flip whatever the current reported direction is rather than guessing.

Best practice: for a moving loco, bring it to a stop first — DCC decoders generally accept a direction change at speed, but it can cause a rough jolt or be ignored/delayed by the decoder depending on its configuration; this tool does not enforce that, it just forwards the request.

Returns the direction JMRI actually reports back as "forward" or "reverse" (translated from JMRI's own true/false), not "stopped" — direction and speed are independent fields on the same throttle, so set_direction never changes speed and doesn't report one.

Like set_speed/stop/emergency_stop, this is safe to call repeatedly with the same direction: JMRI silently no-ops a redundant "already going this way" request instead of replying, and this tool checks a local direction cache — kept fresh by JMRI's own broadcasts of state changes from ANY client, not just this one — before deciding whether to send anything, so a repeat call (or a direction that was actually last changed by a JMRI panel/PanelPro, not this session) still reports the correct current direction instead of hanging.

set_functionA

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

Args: address: The locomotive's DCC address. Acquires the throttle automatically if this session doesn't already hold it. function: Function number, 0-28 inclusive (validated; anything outside that range returns an error rather than being sent to JMRI). What each number actually controls is decoder/ roster-specific — F0 is almost universally the headlight(s) (see lights_on/lights_off below for that common case), but F1-F28 vary loco to loco (bell, horn, sound effects, couplers, etc.). If a 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 fall back to asking the user for the F-number if that loco has no label matching what they described. state: True to turn the function on, False to turn it off.

Safe to call repeatedly with the same state: like set_speed/ set_direction, JMRI silently no-ops a redundant "already in this state" request instead of replying, and this tool checks a local per-function cache — kept fresh by JMRI's own broadcasts from ANY client holding this address, not just this one — before deciding whether to send anything, so a repeat call (or a function last toggled by a JMRI panel/PanelPro) still reports the correct current state instead of hanging.

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.

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.

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