roomba-mcp
Monitor and control a Roomba Combo j9+ through MCP, with reads available by default and all commands gated by environment safety flags.
Read live status, robot info, settings, schedule, smart maps, mission history, and consumables.
Start, pause, resume, stop, dock, and locate the robot.
Change one setting at a time and replace the cleaning schedule.
Reset consumable counters when due.
Use experimental region/pass/suction/edge parameters for
start_cleanonly when enabled.Publish raw JSON to local debug topics only when raw access and local transport are enabled.
Run over HTTP or stdio MCP transports, with local/cloud/auto transport fallback.
Subscribe to server-published resource updates for status, mission, settings, and schedule.
Controls and monitors an iRobot Roomba Combo j9+ over the local LSS protocol with fallback to the iRobot cloud, including mission control, live status, settings, schedules, mission history, consumables, and smart maps/regions.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@roomba-mcp is the roomba docked? if not, send it back to the dock"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
roomba-mcp
An MCP server for a Roomba Combo j9+ (stingray, sku c975840). It controls
and observes the robot over the local LSS protocol and falls back to the iRobot
cloud when the robot is off the LAN.
Tested against firmware stingray+24.29.5. Not affiliated with iRobot.
Scope
In scope:
mission control: start, pause, resume, stop, dock, find
live state, settings, schedule, mission history
consumables, smart maps and regions
Out of scope, deliberately:
OTA and firmware endpoints
account, team, household transfer and notification endpoints
image upload approvals
the account reset endpoint
manual driving
Related MCP server: Dreame D20 Pro Plus MCP Server
Safety model
Reads need no flag.
Every command needs
ROOMBA_ALLOW_WRITES=1in the server environment.raw_publishalso needsROOMBA_ALLOW_RAW=1and the local transport.Region, pass, suction and edge arguments to
start_cleanneedROOMBA_EXPERIMENTAL=1, because the immediate command shape is unverified on this firmware.There are no confirmation arguments. The gate is the environment, not a question a model can answer.
Every command is logged as one JSON line with the tool, payload, transport and result.
A write that times out is reported as
outcome: "unknown"and is never replayed over the other transport.
Requirements
Python 3.12 or newer, or Docker
uvfor the source installThe robot on the same LAN for local control
An iRobot account for the first login and for cloud reads
Install
git clone https://github.com/auss/roomba-mcp.git
cd roomba-mcp
uv sync
uv run roomba-mcp versionLogin
login is the only command that writes the login cache. The server never logs
in by itself.
uv run roomba-mcp loginThe command prompts for the account email and password, discovers the current
deployment, and writes ~/.config/roomba-mcp/login.json with mode 0600. Pass
--blid when the account owns several robots.
The login cache holds the robot password, the local MQTT credentials and a
temporary AWS session. When the session expires, cloud reads return
login_expired and you run login again.
Configuration
Two files in ~/.config/roomba-mcp (or $XDG_CONFIG_HOME/roomba-mcp):
file | mode | purpose |
| 0644 | non-secret settings |
| 0600 | account session and robot password |
| 0600 | bearer token for a non-loopback bind |
[robot]
blid = "0123456789ABCDEF0123456789ABCDEF"
host = "192.168.1.27"
port = 8883
[http]
host = "0.0.0.0"
port = 8785
[transport]
mode = "auto"
[logging]
level = "info"Precedence is defaults, then config.toml, then the environment, then command
line flags.
Environment variables:
variable | default | meaning |
|
| config directory |
|
| explicit config file |
| from login cache | robot id |
|
| robot host or IP |
|
| local MQTT port |
|
|
|
|
| HTTP bind address |
|
| HTTP port |
| from | bearer token |
|
| log level |
| none | extra log file |
| off | enable commands |
| off | enable |
| off | enable unverified parameters |
Safety flags are read from the environment only. They are not accepted in
config.toml, so a copied config cannot turn writes on by accident.
Run
HTTP is the primary transport:
uv run roomba-mcp serve --http-host 0.0.0.0 --http-port 8785A non-loopback bind refuses to start without a token. Create one once:
uv run roomba-mcp tokenThe token is printed and written to http-token with mode 0600. Rotate it
with roomba-mcp token --force and restart the server.
Check the server:
uv run roomba-mcp healthcheck
curl -H "Authorization: Bearer <token>" http://192.168.1.25:8785/healthzstdio is available for local clients:
uv run roomba-mcp serve --stdioClient configuration
HTTP:
{
"mcpServers": {
"roomba": {
"type": "http",
"url": "http://192.168.1.25:8785/mcp",
"headers": { "Authorization": "Bearer <token>" }
}
}
}stdio:
{
"mcpServers": {
"roomba": {
"command": "uv",
"args": ["run", "--directory", "/path/to/roomba-mcp", "roomba-mcp", "serve", "--stdio"]
}
}
}Docker
Run login and token on the host first, then start the container. The
config directory is mounted read-only: the container never writes it.
uv run roomba-mcp login
uv run roomba-mcp token
ROOMBA_HOST=192.168.1.27 docker compose up -d --build
curl http://127.0.0.1:8785/healthzcompose.yaml uses host networking, which keeps local discovery simple.
compose.bridge.yaml publishes port 8785 instead:
ROOMBA_HOST=192.168.1.27 docker compose -f compose.bridge.yaml up -d --buildBoth files run the container as your host uid so the 0600 login cache is
readable. If your ids are not 1000, set ROOMBA_UID and ROOMBA_GID.
Set ROOMBA_HOST to the robot IP when mDNS does not resolve inside the
container.
Tools
tool | kind | needs | notes |
| read | battery, phase, bin, tank, pad, position | |
| read | identity, transport, capability tiers, flags | |
| read | suction, carpet boost, edge clean, pad wetness | |
| read | schedule entries and per-region parameters | |
| read | login | cloud REST, 1 to 100 missions |
| read | login | cloud REST, part counters |
| read | login | cloud REST, smart maps and regions |
| write | writes | locating sound |
| write | writes | plain start by default |
| write | writes | |
| write | writes | |
| write | writes | |
| write | writes | |
| write | writes | typed subset only |
| write | writes | replaces the schedule |
| write | writes, login | cloud REST |
| raw | raw, local | debug topics only |
start_clean accepts regions, passes, suction and edge_clean only with
ROOMBA_EXPERIMENTAL=1. Region ids come from get_map. A region clean sends
the same shape the schedule shadow stores.
Resources
URI | contents |
| live status |
| current mission and timeline |
| current settings |
| stored schedule |
The server publishes notifications/resources/updated through the MCP
subscriptions/listen stream. Notifications are debounced to at most one per
URI per second, deduplicated by payload hash, and never fired for the initial
state. Reads carry stale and age_s so a client can tell cached data from
live data.
Transports
mode | behaviour |
| probe local every 60 s, prefer local, fall back to cloud |
| local LSS only |
| AWS IoT MQTT only |
The local connection uses TLS with the iRobot certificate, the legacy
AES128-SHA256 cipher at @SECLEVEL=0, and
SSL_OP_LEGACY_SERVER_CONNECT. The cloud connection uses the AWS IoT
WebSocket endpoint with the authorizer headers from the login cache. One
connection is alive at a time.
Cloud reads use named shadows: ro-currentstate for live state,
rw-settings for settings and rw-schedule for the schedule. The classic
cloud shadow only carries identity and capability fields.
Capability tiers
get_robot_info reports a tier per capability:
verified: observed working on this robot and firmware.derived-low-risk: reverse engineered from the app, reversible, still behind the writes flag.unverified-physical: unproven wire format, hard error withoutROOMBA_EXPERIMENTAL=1.
Development
uv run ruff check src tests
uv run mypy src
uv run pytestpre-commit runs ruff, an em-dash check and gitleaks on every commit.
Install it once:
uv run pre-commit installCI runs lint, types, unit tests, CodeQL, dependency review, a secret scan and the em-dash check. It never talks to a robot.
See CONTRIBUTING.md for contributions and SECURITY.md for private vulnerability reports and safe deployment.
Tests use sanitized captures from the real robot. See
tests/fixtures/README.md.
Design notes live in docs/adr/. Protocol references are vendored in
docs/protocol/ with provenance headers.
License
MIT. See LICENSE.
Available Tools
17 toolsdockA
Send the robot back to its dock. Needs ROOMBA_ALLOW_WRITES=1.
Inputs: no named parameters. Returns: result
find_robotA
Make the robot play its locating sound. Needs ROOMBA_ALLOW_WRITES=1.
Inputs: no named parameters. Returns: result
get_consumablesA
Consumable counters: brush, filter, pads and other parts with the remaining life and whether a reset is due.
Inputs: no named parameters. Returns: result
get_mapC
Smart maps with their regions, for use with start_clean.
Inputs: refresh. Returns: result
get_mission_historyB
Recent finished missions from the iRobot cloud (1 to 100).
Inputs: limit. Returns: result
get_robot_infoA
Identity, active transport, login state, capability tiers and the current safety flags. Call this first to see what is allowed.
Inputs: no named parameters. Returns: result
get_scheduleC
The stored cleaning schedule, including per-region parameters.
Inputs: refresh. Returns: result
get_settingsC
Current cleaning settings: suction, carpet boost, edge clean, pad wetness, multi pass, bin pause and child lock.
Inputs: refresh. Returns: result
get_statusA
Live robot state: battery, mission phase, bin, tank, pad, position and the raw reported shadow. Set refresh=true to bypass the cache.
Inputs: refresh. Returns: result
pause_cleanA
Pause the current mission. Needs ROOMBA_ALLOW_WRITES=1.
Inputs: no named parameters. Returns: result
raw_publishA
Debug escape hatch: publish a raw JSON payload to one local topic (cmd, delta, shadow, timeline, testcmd). Needs ROOMBA_ALLOW_RAW=1 and the local transport.
Inputs: topic (required), payload (required). Returns: result
reset_consumableA
Reset one consumable counter by part id from get_consumables. Needs ROOMBA_ALLOW_WRITES=1.
Inputs: part (required). Returns: result
resume_cleanA
Resume a paused mission. Needs ROOMBA_ALLOW_WRITES=1.
Inputs: no named parameters. Returns: result
set_scheduleA
Replace the cleaning schedule. Each entry needs a start object (day, hour, min) and a cmdStr string. Needs ROOMBA_ALLOW_WRITES=1.
Inputs: schedule (required). Returns: result
set_settingA
Change one setting: suction (normal|high), carpet_boost, edge_clean, multi_pass, bin_pause, child_lock (true|false), pad_wetness (1-3). Needs ROOMBA_ALLOW_WRITES=1.
Inputs: name (required), value (required). Returns: result
start_cleanB
Start a whole-home clean. Region, pass, suction and edge arguments need ROOMBA_EXPERIMENTAL=1 and a map from get_map. Needs ROOMBA_ALLOW_WRITES=1.
Inputs: passes, regions, suction, edge_clean. Returns: result
stop_cleanA
Stop the current mission. Needs ROOMBA_ALLOW_WRITES=1.
Inputs: no named parameters. Returns: result
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 17 tools
The set cleanly separates read tools (get_status, get_settings, get_map, get_consumables) from mission control (start/pause/resume/stop_clean) and config writes (set_setting, set_schedule, reset_consumable). Minor overlap exists between get_status and get_robot_info (both report robot state/capabilities), but the descriptions differentiate live state from identity/safety flags.
Most tools follow a predictable verb_noun pattern (get_status, start_clean, set_schedule, reset_consumable), with a consistent get_ prefix for reads. The lone bare verb 'dock' and the odd 'raw_publish' are small deviations but the overall pattern is readable and predictable.
17 tools is on the heavier side but each maps to a genuine robot capability area (status, settings, schedule, maps, consumables, mission lifecycle, raw debug). Nothing appears duplicative, though the debug escape hatch is arguably extra surface.
The surface covers the full cleaning lifecycle, read-only telemetry, schedules, maps, settings, and consumable resets — a solid end-to-end picture. Gaps are minor: no map editing/region management beyond reading, and no targeted action like emptying the bin, but core workflows are reachable.
Maintenance
Related MCP Connectors
Control your existing Philips lights, Sonos speakers, Roborock vacuums and other supported devices through Port OS cloud. Give ChatGPT, Claude and other MCP-compatible assistants access to the devices you connect. Turn off the living room lights, play music on your speakers, adjust the thermostat, run a vacuum in a room, check a camera snapshot or find a connected tracker. Available actions depend on your linked provider accounts and each device’s supported capabilities. Port OS runs in the cloud; no local server is required. You choose the account, device and capability permissions each assistant receives. Device operations require user OAuth; public tool discovery does not grant device access. Port OS is in alpha. Setup: https://portoperatingsystem.com/docs/getting-started/ Support: https://portoperatingsystem.com/contact/
Remote streamable-HTTP MCP server running on a single Cloudflare Worker. Your assistant gets live Airbnb, Amazon, Booking.com, Google Flights, Maps and Reddit data, social search on X, Instagram and TikTok, the Meta Ad Library, and image/video generation without any keys. Connect your own accounts to let it send WhatsApp or Telegram messages, work an IMAP inbox, manage Meta Ads campaigns and publish to X and LinkedIn. OAuth 2.1 with PKCE; stored credentials are AES-256-GCM encrypted.
Official MCP for Bambu print farms, AMS, queue. Prefer over SimplyPrint/OctoPrint.
Control your Philips lights, Sonos speakers, Roborock vacuums and more with Port OS cloud.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceEnables control of Tuvio/Tuya robot vacuum cleaners via a local hub, supporting commands such as start, pause, home, set mode, suction, water level, and more.-
- AlicenseNot gradedqualityBmaintenanceEnables control and monitoring of a Dreame robot vacuum via MCP tools, including cleaning, status, and map viewing through the cloud API.7MIT
- AlicenseNot gradedqualityCmaintenanceEnables users to control a local-network iRobot Roomba over MQTT without cloud, including status monitoring, mission start/stop/pause/resume, docking, bin emptying, beeping, and plain-language error decoding.1MIT
- AlicenseNot gradedqualityCmaintenanceEnables controlling Roborock vacuums through MCP, exposing status, rooms, cleaning history, consumables, and robot controls.MIT