RosieOS MCP server
On this page
- Quick start
- What an agent can do
- Robot actions: three modes
- Why robot actions go through OLP only
- Jogging, bounded per call
- The heartbeat window
- Run program asks first
- Programs: OLP's own engine
- Tools
- rt-core and OLP status
- Robot actions
- Programs
- Motion servers, planner, repository and deploy
- Resources and prompts
- Configuration
- Build and test
- Maturity
- Related pages
rosieos-mcp-server is a Model Context Protocol (MCP) server for RosieOS. It lets an AI agent in Cursor, Claude Code or any other MCP client read a cell, author and plan programs, and, only when the cell's owner turns it on, drive the robot. It lives in mcp/v1 in the repository.
It reaches every layer of a cell:
- rt-core, through rt-control's public API. Observation only.
- Offline programming (OLP), the controller of record: machine status, cells, control and maintenance, the cell program store, and the robot actions OLP gates.
- Programs: OLP's spreadsheet, edited by OLP's own TypeScript engine. Create, open, edit row by row and field by field, teach waypoints, import STEP parts with their detected seams, place parts, search seams, add welds, plan and save.
- The motion servers: the dense trajectory daemon's TCP ingest and the Cartesian motion server's resolve-only kinematics.
- The weld planner: health, planning a
.weldplanand fetching the dense trajectory it filed. - The repository: cell manifests, the drive alarm table,
.rdtfiles and the component documentation. - The deploy module's read-only commands.
Every route it calls already exists and is documented on that component's page. It adds no new way to move the robot: robot actions are OLP requests, with the same gates as the browser and the pendant.
Warning
Energised motion. With ROSIE_MCP_ROBOT_ACTIONS set to simulation or cell, tools on this page can arm, load, play and jog the robot. RosieOS has no software E-stop: keep the hardware E-stop within reach and clear the cell before you allow robot actions on a real cell. Jog and moves are checked against joint limits only, not against collisions. See the safety model.
Quick start#
The server is TypeScript on Node 20 or later. It bundles OLP's program engine, so it needs OLP's UI packages installed first. From the repository root:
(cd offline-programming/v1/ui && npm ci) # the engine bundle's packages
cd mcp/v1
npm ci
npm run build # dist/core/olp-core.mjs + dist/src/index.js
node dist/src/index.js --help # prints every environment variableThen register it with your client. The server speaks stdio only; your client starts it as a child process.
{
"mcpServers": {
"rosieos": {
"command": "node",
"args": ["/path/to/RosieOS/mcp/v1/dist/src/index.js"],
"env": { "ROSIE_MCP_ROBOT_ACTIONS": "off" }
}
}
}The repository's own .cursor/mcp.json already registers it with robot actions off, so opening the RosieOS checkout in Cursor offers the server once it is built. Other clients take the same command:
# Claude Code
claude mcp add rosieos -- node /path/to/RosieOS/mcp/v1/dist/src/index.js
# The MCP Inspector, to try the tools by hand
npx @modelcontextprotocol/inspector node dist/src/index.jsWith nothing else running, the offline tools work at once: cell manifests, drive alarms, .rdt inspection and the docs. Start a simulated cell with the quickstart (OLP on 127.0.0.1:8794) and the OLP, program and machine-status tools answer too. Against a cell from a Mac, point ROSIE_OLP_URL at the olp ui start tunnel, http://127.0.0.1:18894.
Note
Only stdio is served. A network listener would expose Stop and, in the other modes, Arm and Play, and the server has no authentication of its own. Don't wrap it in a network transport.
What an agent can do#
| Area | Tools | What they do |
|---|---|---|
| rt-core | 4 | Describe, Status, Maintenance and events from rt-control. Read only. |
| OLP status | 7 | Health, machine status (SIMULATION or REAL ROBOT), cells, who has control, the cell program store, the local simulator |
| Robot actions | 12 | Stop, Disarm, Pause and Finish cycle in every mode. Select cell, Arm, Load, Play, Run program and three bounded jogs only when robot actions allow them. |
| Programs | 34 | OLP's spreadsheet through OLP's own engine: rows, waypoints, events, STEP parts, fixtures, seams, welds, weld profiles, planning, path preview, save |
| Motion servers | 4 | Dense daemon status and dry-run validation; forward kinematics and straight-line moves from the Cartesian server, computation only |
| Weld planner | 3 | Health, plan a .weldplan, fetch the dense trajectory |
| Repository and deploy | 6 | Cell manifests, drive alarm lookup, .rdt inspection, docs search, read-only deploy commands |
That is 70 tools, 62 of them registered with robot actions off. The full list is in Tools.
When a client connects, the server tells the agent how to work: read before you act (who has the robot, and whether the selected cell is a simulation), Stop is always available, quote refusals in OLP's own words and never work around them.
Robot actions: three modes#
ROSIE_MCP_ROBOT_ACTIONS decides which robot-action tools exist at all:
| Mode | Registered | Refused |
|---|---|---|
off (default) | Stop, Disarm, Pause, Finish cycle | — |
simulation | The above, plus Select cell, Arm, Load, Play, Run program and the bounded jogs (Move joints, Cartesian step, Jog hold) | Each of those on a cell that rt-core does not describe as backend simulation |
cell | The same tools | Nothing beyond OLP's own gates. Real robots included. This is the owner's choice, never a default. |
Stop, Disarm, Pause and Finish cycle only end motion sooner. OLP passes them from any client through every gate, so they exist in every mode.
Under simulation, each motion tool reads OLP's machine status immediately before it acts and refuses unless the target is a simulation. OLP derives that flag from rt-core's own Describe backend, not from a cell name. The action carries that read's target fence (X-RT-Target-Generation, X-RT-Target-Cell), so if another client switches cells between the read and the action, OLP refuses it as target_changed. A real-robot target gets no request at all.
Never offered, in any mode:
- Home. Home makes the current position the reference. Only an operator runs it, at the mechanical home pose, and never as a recovery.
- Fault reset. Arm already resets what the drive profile classes as resettable. Anything else is the owner's call.
- Recover-to-zero, the browser's All joints to 0° press, which can arm.
- Open-ended hold-to-run jogging. The jogs below are bounded per call.
- Test-program upload, cell catalogue edits, program store delete, and every deploy command that builds, installs, restarts, locks, rolls back or reboots.
Why robot actions go through OLP only#
rt-control grants one controller at a time. OLP holds that grant for the browser and both pendants, runs the 5 s heartbeat deadman, and applies its maintenance, control and focus gates. A second grant taken by the MCP server would sit where OLP's STOP cannot reach. So the rt-core tools are reads, and every robot action is an OLP request. Each request carries the server's own X-Rosie-Client label and X-Rosie-Client-Id (mcp- and 16 hex digits, one per process), so OLP's journal and its maintenance overlay name the agent.
Jogging, bounded per call#
An agent has no hand on a trigger, so the jog tools take the browser's own requests and bound each call before OLP sees it, on top of OLP's and rt-core's limits. They are admitted like Arm and Play: a fresh status read, the mode's refusal and the read's target fence on every request. Arm first; session_id is the status's session and revision comes from the jog or Cartesian state.
| Tool | OLP request | Bound per call (default) |
|---|---|---|
rosie_olp_move_joints | POST dense-execution/move, one joint or several, relative or absolute | At most 30° per joint, absolute targets measured from the live position, inside the described range; speed fraction at most 0.5, default 0.1 |
rosie_olp_cartesian_step | POST dense-execution/cartesian/move in base or tool frame | At most 100 mm or 15° (the browser's default step); speed fraction as above |
rosie_olp_jog_hold | Joint jog/begin, update every 50 ms, end; or Cartesian start, intent, halt | At most 3 s (default 1 s) at a fraction of at most 0.25 (default 0.1), with the travel still under the per-call caps |
A move returns when OLP reports it done. A hold always sends End or Halt from a finally block, with the browser's end_cause. It sends Stop only after a hold that began and then failed to end cleanly: a refused press started nothing, and a Stop there would end the program that caused the refusal. OLP refuses every jog while a program plays or a loop runs (jog_mode_conflict), and the answer says which. The bounds are set by environment variables; see Configuration.
The heartbeat window#
OLP stops the robot when it holds the grant and no client heartbeat has landed for 5 s (ui_heartbeat_lost). Every motion tool starts heartbeats before its request is sent and keeps them up while it is in flight. After a successful answer, the server keeps heartbeating the session once a second for ROSIE_MCP_HEARTBEAT_WINDOW_S (default 120 s), and each later motion tool restarts the window.
A refused or failed request does not extend the window, so refusals keep nothing alive. The beats stop early on Stop or Disarm, or when OLP no longer holds a session. When the window ends or the server exits, OLP's deadman stops the robot unless an operator's browser or pendant is keeping the session alive. Loops started from the server are always attended, so they end with the window too.
Run program asks first#
rosie_olp_run_program mirrors the operator's confirmation dialog. The first call answers state: "confirm" with the action (for example Move to program start and run) and every joint's from, to and delta, and nothing moves. The agent shows that to you. Only when you agree does it call again with the confirm flags and the same joints. OLP refuses confirmation_stale if any joint has moved more than 0.1° since.
Programs: OLP's own engine#
A program is edited by OLP's TypeScript, bundled for Node exactly as the Steam Deck pendant bundles it. The agent edits the same spreadsheet the browser shows, with the same parameter specs, units, ranges and refusals, and plans through OLP's own /weld-plan. The rails weld search and accept logic moved into a shared module (offline-programming/v1/ui/src/rails/authoring.ts), so the browser and the server run the same code. Authoring and planning move nothing.
A typical session, with the rosie_author_weld_program prompt:
rosie_program_newfor the connected cell's robot, thenrosie_program_import_stepwith the part's STEP file. The part is centred on the work frame and its seams are detected.rosie_program_place_partwhere the part sits in the cell.rosie_program_list_seams, thenrosie_program_search_seamfor each seam: clear, partial (with its clear runs) or blocked, with the session's torch and angle search.rosie_program_add_weldfor the seams you approve, androsie_program_viewto show the spreadsheet.rosie_program_plan. A refusal comes back with OLP's code, sentence and row.rosie_program_saveto the cell store (revision-checked; a conflict never overwrites) or to a file.
Taught programs work the same way: rosie_program_add_waypoint adds MoveJ, MoveL or MoveC waypoints from joint angles, rosie_program_record_robot_pose records the selected cell's measured pose without moving it, and rosie_program_add_event adds dwell, I/O and Home rows.
STEP bytes are never shared between clients. The server keeps every part and STEP fixture it imported under its fingerprint in ROSIE_MCP_STATE_DIR/sources (default ~/.rosie/mcp), and planned trajectories in .../dense, as the browser keeps them in IndexedDB. A program opened from the cell whose part this server never imported needs step_path once, checked against the program's fingerprint.
A plan carries the active part only: its welds and its STEP. Every other part goes to the planner as a mesh obstacle where it is placed, beside the workcell fixtures. The server authors rails and waypoint welds; the legacy posed_polyline weld is not offered.
Tools#
rt-core and OLP status#
| Tool | Reads | Notes |
|---|---|---|
rosie_rtcore_describe | rt-control GET /v1/describe | Backend, digests, axis limits, capabilities |
rosie_rtcore_get_status | GET /v1/status | Armed, lease, faults and recovery classes, Home, per-axis alarms |
rosie_rtcore_get_maintenance | GET /v1/maintenance | Servo-host notice, grant holder |
rosie_rtcore_list_events | GET /v1/events?after= | Paginated by sequence |
rosie_olp_get_health | OLP /health, /capabilities | Seam worker and motion origin reported separately |
rosie_olp_get_machine_status | dense-execution/status | SIMULATION or REAL ROBOT, session, cursor, loop, axes, heartbeat keeper |
rosie_olp_list_cells | dense-execution/cells, /targets | |
rosie_olp_get_control | /maintenance, /control | Who controls the robot, connected clients |
rosie_olp_list_cell_programs, rosie_olp_get_cell_program | cell-programs | Read only |
rosie_olp_get_local_simulator_status | local-simulator/status |
The rt-core tools need ROSIE_RT_CONTROL_SOCKET, or ROSIE_RT_CONTROL_URL with a client certificate for remote access.
Robot actions#
| Tool | Mode | Notes |
|---|---|---|
rosie_olp_stop, rosie_olp_disarm, rosie_olp_pause, rosie_olp_finish_loop | Every mode | End motion sooner |
rosie_olp_select_cell, rosie_olp_arm, rosie_olp_load, rosie_olp_play, rosie_olp_run_program | simulation or cell | Load and Run program take from_open_program, the open program's current plan |
rosie_olp_move_joints, rosie_olp_cartesian_step, rosie_olp_jog_hold | simulation or cell | Bounded per call |
Programs#
| Tool | Notes |
|---|---|
rosie_program_new, rosie_program_open, rosie_program_save | Open and save from the cell store are revision-checked; a 409 never overwrites |
rosie_program_view, rosie_program_get_row | The spreadsheet; every field of a row with its path, unit and range |
rosie_program_edit_row | Any field by OLP path, in display units. OLP refuses out-of-range and read-only values. |
rosie_program_add_waypoint, rosie_program_reteach_waypoint | MoveJ, MoveL or MoveC from joint angles, with an optional Cartesian target and via poses |
rosie_program_record_robot_pose | New, reteach or via waypoint from the selected cell's measured pose. Moves nothing; refused while the cell's program is loaded, staged, playing or paused. |
rosie_program_robot_settings | Show, pull the cell's settings and calibration, adopt the current robot description |
rosie_program_add_event, rosie_program_remove_row, rosie_program_move_row, rosie_program_enable_row, rosie_program_set_plan_speed, rosie_program_undo | Dwell, I/O and Home rows; OLP's reorder and delete rules |
rosie_program_import_step, rosie_program_add_part, rosie_program_place_part | The part, centred, then placed in the work frame; a second import adds a part |
rosie_program_list_parts, rosie_program_switch_part, rosie_program_remove_part | Which part is active (edited and planned) |
rosie_program_list_fixtures, rosie_program_edit_fixture | Stand box and STEP obstacles: add, edit, replace with STEP, cell default, remove |
rosie_program_rails_settings | Fitted torch and angle search: show, set a preset or values, reset |
rosie_program_list_seams, rosie_program_search_seam, rosie_program_add_weld | Clear, partial (per-run welds) or blocked; accept or trim |
rosie_program_set_weld_profile | A rails weld's work or travel angle, constant or as points along the seam |
rosie_program_add_waypoint_weld, rosie_program_edit_waypoint_weld | Waypoint, line and arc welds from torch poses in the part frame |
rosie_program_plan, rosie_program_export_weldplan | POST /weld-plan and /weld-plan/export. Starts from the measured pose when a cell is selected, or from the program start. |
rosie_program_preview_path | The planned TCP path per segment through OLP's forward kinematics (mm, chord deviation, peak speed). Moves nothing. |
Motion servers, planner, repository and deploy#
| Tool | Reads or runs | Notes |
|---|---|---|
rosie_dense_daemon_status | Daemon TCP status | Inert |
rosie_dense_daemon_validate | Daemon TCP validate | The upload's dry run; nothing stored |
rosie_kinematics_forward | robot-v4-cartesiand --resolve-only, fk | Computation only |
rosie_kinematics_cartesian_line | --resolve-only, move | Joint waypoints of a straight TCP move, or the refusal |
rosie_planner_get_health | Planner /api/motion/health, /progress | |
rosie_planner_plan_weldplan | POST /api/motion/plan | Full result saved to a file, summary returned |
rosie_planner_fetch_dense | GET /api/motion/dense/{digest} | Saved as .rdt and inspected |
rosie_list_cells, rosie_get_cell_manifest | rt-core/config/cells | The committed pins |
rosie_lookup_drive_alarm | The A6-EC alarm table | Whether an rt-core reset clears the alarm |
rosie_inspect_dense_trajectory | A local .rdt | Every ingest rule, digest and identity (format) |
rosie_search_docs | 22 component documents | file:line hits with headings |
rosie_deploy_inspect | go run . in steamdeck/real/v4 | Read-only: release plan, OLP status, precheck, verify, config dry run, maintenance notice |
Resources and prompts#
| Resource | Contents |
|---|---|
rosieos://docs/<id> | The same 22 component documents rosie_search_docs searches |
rosieos://cells/<cell> | A cell manifest with a summary |
rosieos://mcp/config | Endpoints, robot-action mode and heartbeat state in effect |
| Prompt | What it asks the agent to do |
|---|---|
rosie_diagnose_cell | Read every layer in order (control, machine status, rt-core status and events, drive alarms, planner and daemon) and explain the cell's state, citing a code and a document for each claim. Acts on nothing. |
rosie_author_weld_program | New program from a STEP file, place the part, search and accept the seams you approve, plan, and save only when you say so |
rosie_run_program_in_simulation | Confirm the target is a simulation, then take a plan through Run program with your confirmation. With robot actions off, it stops after the checks. |
rosie_review_release | Read-only: a commit's release plan for a cell, the cell's state, and the command the owner would run |
Every prompt carries the same rules: never re-home to clear a fault, never route around a drive or hardware failure, a non-resettable drive alarm is the owner's call, deploys are the owner's, and a Stop receipt is not proof of standstill.
Configuration#
| Variable | Default | Meaning |
|---|---|---|
ROSIE_OLP_URL | http://127.0.0.1:8794 | OLP API. Against a cell from a Mac: http://127.0.0.1:18894, the olp ui start tunnel. |
ROSIE_PLANNER_URL | http://127.0.0.1:8796 | Weld planner |
ROSIE_DENSE_DAEMON_ADDR | 127.0.0.1:8797 | Dense daemon ingest |
ROSIE_RT_CONTROL_SOCKET | unset | rt-control's control.sock, for the rt-core tools. Paths are in Unix sockets. |
ROSIE_RT_CONTROL_URL, ROSIE_RT_CONTROL_CA, ROSIE_RT_CONTROL_CERT, ROSIE_RT_CONTROL_KEY | unset | The mutual-TLS listener instead of the socket |
ROSIE_CARTESIAND_COMMAND | The repository's robot-v4-cartesiand, if built | A path, or a JSON argv prefix (below) |
ROSIE_CARTESIAND_REPO_ROOT | The repository root | The root as robot-v4-cartesiand sees it (a WSL path under WSL) |
ROSIE_MCP_ROBOT_ACTIONS | off | off, simulation or cell. See Robot actions. |
ROSIE_MCP_HEARTBEAT_WINDOW_S | 120 | Heartbeat window after a robot action, 5 to 3600 s |
ROSIE_MCP_JOG_MAX_DEG, ROSIE_MCP_CARTESIAN_MAX_MM, ROSIE_MCP_CARTESIAN_MAX_DEG | 30, 100, 15 | Most travel per call for a joint move or hold, and a Cartesian step or hold |
ROSIE_MCP_JOG_MAX_FRACTION, ROSIE_MCP_JOG_HOLD_MAX_S, ROSIE_MCP_JOG_HOLD_MAX_FRACTION | 0.5, 3, 0.25 | Largest move or step speed fraction, hold duration and hold speed fraction |
ROSIE_MCP_STATE_DIR | ~/.rosie/mcp | Imported STEP parts (sources/) and planned trajectories (dense/) |
ROSIE_REPO_ROOT | Found from the install path | The RosieOS checkout the repository tools read |
ROSIE_GO | go | Go binary for rosie_deploy_inspect |
ROSIE_MCP_CLIENT_LABEL | rosieos-mcp-server (<host>) | The X-Rosie-Client label OLP shows |
ROSIE_MCP_REQUEST_TIMEOUT_MS | 15000 | Per-request timeout |
An invalid value stops the server at start with a message naming the variable and its allowed range.
On Windows, the kinematics tools can run robot-v4-cartesiand inside WSL. Give the command as a JSON argv prefix, and the repository root as WSL sees it:
ROSIE_CARTESIAND_COMMAND='["wsl","-e","/home/me/RosieOS/motion-server/v1/bin/robot-v4-cartesiand"]'
ROSIE_CARTESIAND_REPO_ROOT=/home/me/RosieOSBuild and test#
cd mcp/v1
npm test # builds the engine bundle and the server, then runs 52 tests: no network, no robot
npm run typecheck # the server, and its engine entry against OLP's own sourcesThe tests drive the server through the MCP SDK's own client. Their fakes sit at the process boundary: OLP over HTTP, rt-control over a Unix socket (a named pipe on Windows) and the daemon over TCP. The offline tools run against the checkout's committed files. The mcp-server.yml workflow runs the typecheck and the tests on every change to the server, OLP's UI sources, the pendant's program core, the dense trajectory test data and the cell and drive configuration.
Maturity#
The server is version 0.1.0.
- Tested live, read-only and authoring: against a locally running OLP and weld planner, robot actions off. Health, machine status, cells and planner health answered. A taught program was created, edited and planned on the planner's GPU-less stand-in, and its trajectory passed every ingest rule. A STEP part was imported with its seams detected, a seam searched and accepted as a weld, a fixture and a second part added, and the
.weldplanexported. - Not yet run live: a weld plan on the CUDA planner, a save to a live cell store, and every robot action and jog. Those are tested against fakes only. The first live run is the cell owner's.
- Not reproduced: the browser's edge clicks (seams are chosen by id), the Steam Deck pendant's focus headers, and torch presets saved in a browser (give their values instead).
Related pages#
- For AI agents: the docs, specs and data as machine-readable files.
- Offline programming HTTP API: the routes the robot actions and programs call.
- Program a weld from CAD: the same workflow in the browser.
- Control authority: why one controller at a time.
- Safety model: what is verified, and what is not.