Myro:Home Helper MCP server
Lets an AI assistant (Claude Desktop, Claude Code, ChatGPT desktop, anything that speaks MCP) read and control an HAI / Leviton Omni controller, a NESS / ELK M1 panel, a Savant system (preview), or a Control4 system through Control4 Link (preview, Helper 5.50), through Myro:Home Helper, using the Helper's HTTP API. The assistant sees typed tools with descriptions instead of guessing URL shapes.
What you need
- Myro:Home Helper (Mac App Store)
4.06 or later on a Mac on your network (4.07 or later for
the read tools:
list_objects,get_object,helper_log). - An API key for your controller: Helper → API tab → Generate.
uvon the machine running the assistant (brew install uvor the one-line installer).uvxfetches and runs this server on demand and keeps it updated.
NESS / ELK
Helper 5.0 adds NESS / ELK M1 panels alongside HAI / Leviton Omni. The tools and
their parameters are the same for both; controller_status reports
controllerFamily ("HAI / Leviton" or "NESS / ELK", derived from the
controller's protocol), and the live scripting_reference is scoped to that
family, so the assistant should read it before writing scripts. On ELK, user
codes may be 4 or 6 digits (security-code set accepts either), there is no
energy-cost level, and audio is a legacy M1XEP integration.
Savant (preview) and Control4 Link (preview, Helper 5.50)
Savant and Control4 are room and activity systems, not alarm panels. They have
no zones, units, arming or panel messages, so the panel tools (set_unit,
arm, set_thermostat and the rest) do not apply to them.
controller_statusreportscontrollerFamily"Savant"or"Control4", plusbackend,rooms,roomStates,inventory,homeKit,objectCountsandcapabilities. Unknown room fields are omitted rather than guessed.- Automate them through scripts. Read
scripting_referencefirst (it is scoped to the selected controller and lists the real rooms, activities and services), thenvalidate_scriptandsave_script(saved disabled). Savant scripts useMyroSavant; Control4 scripts useMyroControl4. Saving and enabling need an API key with remote script management. - Sign-in credentials for either system live only in Helper's Connection pane, never in MCP or a conversation.
Compatibility
| Adapter | Needs Helper |
|---|---|
0.8.1 suggestions described as Suggestions, Helper's name for the list since 5.51 |
5.50 or later |
0.8.0 timeline, timeline_note, timeline_moment |
5.50 or later |
0.7.0 list_favorites, list_doorbells, web_capabilities, suggestions |
5.50 or later (other tools keep their own minimums above) |
| 0.6.0 Pro 2.51 message, beeper, scene and lock tools | 5.01 or later |
0.5.0 typed /control tools |
4.07 or later (relative controls: 4.50) |
| 0.4.0 history and panel events | 4.50 or later |
A tool that needs a newer Helper than the one running answers with
requiredHelper instead of failing silently.
Configure
Claude Desktop (claude_desktop_config.json) or any client that takes the
standard MCP config:
{
"mcpServers": {
"myrohome-helper": {
"command": "uvx",
"args": ["myrohome-helper-mcp"],
"env": {
"MHH_URL": "http://192.168.1.76:9393",
"MHH_API_KEY": "your-api-key"
}
}
}
}
Claude Code:
claude mcp add myrohome-helper -e MHH_URL=http://192.168.1.76:9393 -e MHH_API_KEY=your-api-key -- uvx myrohome-helper-mcp
The controller ID is fetched from the Helper automatically. Set
MHH_CONTROLLER_ID only if you want to pin it.
Tools
Read:
| Tool | What it returns |
|---|---|
helper_info |
Helper version and identity, and which controller the key is for |
controller_status |
Name, model, firmware, connection, power, battery, phone line, energy cost, troubles, controllerFamily |
controller_property(name) |
One controller property |
list_objects(type?) |
Every object with decoded state; filter by Zone, Unit, Flag, Output, Thermostat, Auxiliary Sensor, … |
get_object(type, number) |
One object; for a door lock, its locked state and the reader's last access |
helper_log(lines) |
The Helper's recent log lines |
ethernet_quality(since?) |
The controller connection's health record |
list_favorites(resolve?) |
Helper 5.50+: the objects starred in Helper's web control (shared by every signed-in browser), matched to their names and current state |
list_doorbells |
Helper 5.50+: the zones, flags and outputs marked "Treat as doorbell" in the web control, with their current state |
web_capabilities |
Helper 5.50+: which web-control and Apple TV features (favorites, doorbells, history, Timeline, Apple TV pairing, UniFi Protect cameras and camera events, Savant activities) Helper offers for this controller, and the Helper version |
suggestions(kind?, home?, at?, limit?, compose?) |
Helper 5.50+: the household's Suggestions list, the shared favorites first and then the things people in this home usually do at about this time on a day like today, ranked from the taps Myro:Home Pro and the Apple TV share with Helper, with object, name, room, suggested action, score, favorite, state, reasons, why and last use; limit 1 to 24, compose: false for the plain ranking (up to 12). Read-only; a confirm: true entry is a security action and only a suggestion |
timeline(hours?, kind?) |
Helper 5.50+: the home Timeline for the last 1 to 24 hours (default 8) as the browser control, Myro:Home Pro and the Apple TV show it: headline, moments (arrivals, departures, doorbell rings, alarms, scenes, music, busy rooms, named moments), events with their source (and approximate: true on a light the panel changed quietly), flags, gaps and the current security, lights and open doors; kind keeps only events of those kinds. Never pictures; the per-room drawing data is left out. Read-only |
connection_status |
Helper 4.07+: live connected/reconnecting state and the panel messages showing now |
list_logged_sensors |
Which sensors record history, with the type and number |
sensor_history(type, number, points) |
Logged readings for one sensor or thermostat |
history_window(type, number, start, end, points, remove_outliers, runtime_bucket, time_zone) |
Helper 4.50+: bounded live/archived samples, statistics before display reduction, and hourly/daily/weekly reported HVAC intervals with unknown coverage and archive warnings |
panel_events(...) |
Helper 4.50+: cached panel history with zone/area/type/month/day filters and user attribution |
refresh_panel_events(scope) |
Helper 4.50+: recent history by default; explicit all reads up to 2000 available panel records. Poll panel_events while refreshing is true; check panelEndReached and refreshError before claiming completeness |
Door access (HAI / Leviton)
An access-control reader and the lock it releases share one number.
list_objects("Access Control Lock") and get_object("Access Control Lock", n)
return locked and, once the reader has reported, the last access:
| Field | Meaning |
|---|---|
lastAccessGranted |
true granted, false denied |
lastAccessUser |
Omni user number: 0 none, 251 Duress, 252 Keyswitch, 253 Quick Arm, 254 PC Access, 255 Programming |
lastAccessBy |
Added by this server: that number in words ("user 7", "Duress", "none") |
lastAccessAt |
When Helper received the reader status (ISO 8601) |
Access Control Reader objects carry the same result as granted, lastUser
and lastAccessAt. The panel does not timestamp accesses, so lastAccessAt is
"last reported", not necessarily the moment of the swipe. Helper 5.01 and later
read reader status at startup and on every status refresh; older Helpers report
it only after the next badge or keypad code. User codes are never exposed.
Reading door access is a read: it adds no write tool, and unlocking stays
behind the owner opt-in below.
The new history/activity tools require adapter 0.4.0 and Helper 4.50. Panel event
dates contain no year; receivedAt is download time, not event time. History
indexing is incremental: retry when indexing is true. HVAC intervals are
estimates from reported action, and unknownSeconds must not be interpreted as
equipment being off. These additions do not change the existing security tools.
Recent event refreshes are limited to once every 30 seconds per controller;
full downloads to once every 10 minutes. A 429 means wait and use the cached
panel_events result, not repeat the download immediately.
Write (each changes the physical home; tool descriptions tell the assistant to confirm first):
| Tool | Effect |
|---|---|
set_unit(number, value, timer?) |
0 off, 1 or 100 on, 2–99 dimmer level; optional timer 1–99 s for on/off |
set_blind(number, value, timer?) |
Blind/shade 0–100 |
set_flag(number, value, timer?) |
Flag to 0–255; optional timer 1–99 s for 0/1 |
increment_flag(number) / decrement_flag(number) |
Updated Helper 4.50+: one native counter step, without cached read/modify/write |
dim_unit(number, steps?) / brighten_unit(number, steps?) |
Updated Helper 4.50+: 1-9 native lighting steps (default 1), not percentage points |
set_output(number, on, timer?) |
Output relay on or off; optional timer 1–99 s |
set_thermostat(number, mode?, heat_setpoint?, cool_setpoint?, humidify_setpoint?, dehumidify_setpoint?, fan?, hold?) |
Mode off/heat/cool/auto/emergency, setpoints, fan auto/on, hold |
set_area_lights(on, area) |
All lights in an area on or off (area 0 = all) |
run_button(number) |
Run a controller button (macro) |
set_upb_link(number, state) |
UPB link on / off / store |
blink_upb_unit(number, stop?) |
Helper 5.01+: blink a UPB light for 30 s at 1 s to find it, or stop it (UPB units only, HAI / Leviton) |
say_panel_message(number) / log_panel_message(number) |
Helper 5.01+: speak a programmed message, or write it to the event log (HAI / Leviton) |
set_keypad_beepers(operation) |
Helper 5.01+: keypad beepers on / off, or stop (silence now) |
press_radiora2_phantom(number) |
Helper 5.01+: press a RadioRA 2 phantom button by number |
set_leviton_scene(number, state) |
Helper 5.01+: Leviton scene on / off / set |
lock_all_doors() |
Helper 5.01+: lock every door (there is no unlock-all tool) |
show_panel_message(number, presentation) |
Show a programmed message on the keypads: beep_led / led / silent |
clear_panel_message(number) |
Clear one message, or 0 for all |
lock_door(number) |
Lock an access-control lock (unlocking is opt-in, below) |
set_user_setting(number, value) |
User setting 1–255 to a raw value 0–65535 |
set_energy_cost(level) |
low / medium / high / critical (HAI / Leviton only) |
send_notification(message) |
Push to the Myro:Home apps |
send_test_notification |
The Helper's test push, to check delivery |
speak(message) |
Speak on the Mac |
log_message(message) |
Write to the Helper log |
log_to_file(filename, message) |
Append to a file in the Helper's Logs folder |
sync_now |
Re-sync from the controller |
Adapter 0.5.0 adds typed /control tools for blinds, thermostats, area lights,
buttons, UPB links, messages, locks, user settings and audio transport, plus
timers on units, flags and outputs (Helper 4.07 or later). Existing untimed
unit/flag/output, audio, energy, notification, speech, log and sync tools retain
their existing routes. Timed dim levels, intermediate blind positions and flag
counters are rejected because the panel ignores their timer. Thermostat
setpoints use the controller's temperature format; Helper enforces that format's
range. A controller ACK means acceptance, not physical completion. After an
error or timeout, read the state before considering another write; commands are
never automatically retried.
Timeline notes (Helper 5.50+; a note is a line in the home Timeline, not a physical action: it never notifies, never takes a picture and never sends a command):
| Tool | Effect |
|---|---|
timeline_note(title, kind?, object?, room?, at?, importance?, detail?) |
One note in the Timeline with source: "api": a title of up to 80 characters, filed under an event kind (note by default), optionally about one object (an id such as Unit:12 or a name that matches one object), in a room, at an ISO 8601 time within the last 72 hours, with importance 0, 1 or 2 and up to 200 characters of detail |
timeline_moment(title, symbol?, tone?, objects?, start?, end?, detail?) |
A named moment card with exactly this title, an SF Symbol (sparkles by default), a tone (info, good, warn, alert), the objects it covers and an optional start and end (default now and open) |
Helper allows 120 notes and moments an hour per API key (429 past that) and refuses a
bad value with one sentence (400). The tool descriptions tell the assistant to say what
it wrote. Notes cannot be changed or deleted through MCP, and the scripting rules that
quiet or rename automatic Timeline events (MyroTimeline.mute, rename, mode) have
no MCP form; a script saved with save_script can set them.
Scripts (save, enable and reload need a key with remote script management enabled; listing, reading and validating do not):
| Tool | What it does |
|---|---|
list_scripts |
Every script: name, id, enabled, schedule |
get_script(identifier) |
One script's full source |
scripting_reference(compact) |
The live scripting API, with your real device names |
validate_script(code) |
Syntax and warnings, without running it |
save_script(name, code, script_id, enabled) |
Create or replace; disabled by default |
set_script_enabled(identifier, enabled) |
Enabling runs the script immediately |
reload_scripts |
Re-runs every enabled script |
Helper 4.50 relative controls
Adapter 0.5.0 adds the four relative tools above, requiring an updated Helper 4.50 build with these actions. Earlier 4.50 builds may not support them. Discover the exact Flag or Unit number first. They validate input locally and use the authenticated typed control endpoint; the Helper also checks that the object has the right type. Each counter call requests one step. Lighting steps are not percentage points; device support and resulting levels depend on the panel and lighting technology. The panel defines behavior at counter endpoints 0/255. Flags can trigger panel programs, so confirm intent before changing them.
No automatic retries: an ACK timeout may mean the command already applied.
accepted means the panel acknowledged it, not that a particular final value was
observed. Check reported state after uncertainty. These additions do not expand
security permissions. Older Helpers return explicit failure with an updated
4.50 build requirement; the adapter never substitutes a cached-value write.
Helper 4.50 scripting features
The live scripting_reference exposes MyroLibraries, MyroControllers, and
MyroSystem.speakQueued / cancelSpeech / cancelAllSpeech. MCP can generate,
validate and save scripts using these APIs through the existing script tools;
it does not need a separate tool for every JavaScript method.
Library files must be installed locally in Helper's Scripts/Libraries folder.
Cross-controller access requires local Send To and Accept From grants
at the respective controllers. MCP cannot upload library files, change grants,
or silently switch its controller API key. A grant extends the origin scripts'
authority, including remotely managed scripts, so enable it only deliberately.
Validation checks the script body without loading dependencies or proving
permissions, device state or speech playback. Save disabled and review before
enabling. Script-owned speech cancellation does not cancel the separate HTTP
speech queue used by MCP's speak tool.
Browser login, themes, live page navigation, Apple TV pairing, doorbell
marking, the home history, the Timeline (and its kept doorbell and camera
pictures) and UniFi Protect camera setup and events are UI and browser-session
features, not MCP tools: they are served under /helper/web/* for a signed-in
browser, or under /helper/timeline for a paired app's session token, and the
MCP API key cannot use them. MCP reads only the results an API key can reach:
list_favorites, the doorbell field that list_objects and get_object
carry on marked zones, flags and outputs (list_doorbells filters to them),
web_capabilities, which reads the public controller list the web control
and Myro:Home Pro for Apple TV use (no sign-in; only this controller's entry is
returned), suggestions, the household's usage-ranked Suggestions list
(GET /helper/{controllerID}/suggestions; the usage events themselves, their
upload and their deletion stay with the paired apps and the browser's Clear
usage history), and since 0.8.0 the Timeline itself through its keyed routes:
timeline reads GET /helper/{controllerID}/timeline (moments and events,
never the pictures) and timeline_note and timeline_moment write through
POST /helper/{controllerID}/timeline/notes. UniFi Protect sign-ins never pass
through MCP.
History queries include archived data automatically; archive deletion policy
remains local configuration, not an MCP write capability.
Audio, Lutron and displays:
| Tool | What it does |
|---|---|
list_audio_sources |
Sources and their cached metadata |
audio_source_metadata(source, refresh) |
What one source is playing |
set_audio_zone(zone, power, volume, mute, source) |
Control a zone |
audio_zone_key(zone, transport or key) |
Russound transport (play, pause, next, …) or a raw audio key 1–40 |
list_lutron |
Bridges, devices and Picos |
set_lutron_level(bridge_id, level, ...) |
Set a Lutron device 0-100 |
activate_lutron_scene(bridge_id, scene_href) |
Activate a scene |
press_lutron_button(bridge_id, integration_id, component) |
Press a keypad or Pico button |
list_displays |
Vestaboards and LaMetric clocks |
| `send_to_vestaboard(text | lines |
send_to_lametric(text, ...) |
Show a notification on a LaMetric |
sync_clock |
Set the controller's clock from this Mac |
Helper Mac:
| Tool | What it does |
|---|---|
beep |
System beep on the Helper Mac |
show_mac_alert(message) |
Alert dialog on the Helper Mac |
set_speech_delays(start_delay_ms, between_delay_ms) |
Tune the speech queue |
play_sound(filename, queue_with_speech) |
Play a sound from the Helper's Scripts folder |
stop_sound(filename) |
Stop it |
Security (all three need an API key with arm/disarm enabled; arm also needs a panel code stored locally):
| Tool | Effect |
|---|---|
arm(mode, area) |
day, night, away, vacation, day_instant, night_delayed |
bypass_zone(zone, bypassed, area) |
Bypass or restore one zone |
restore_all_zones(area) |
Restore every bypassed zone |
arm stays disabled until the owner stores a panel code on the machine
running this server. bypass_zone and restore_all_zones work without one on
Helper 4.13 or later, running as the panel's Programmed user; with a stored code
they run as that user instead. To store or remove the code:
uvx myrohome-helper-mcp security-code set # prompts; nothing is echoed
uvx myrohome-helper-mcp security-code delete
The code goes into the operating system credential store (macOS Keychain, Windows Credential Locker, Linux Secret Service) under the controller's identity. It is never placed in the MCP config, an environment variable, or a conversation, and it is read only when a security tool is actually called. Helper validates it against the panel itself.
Disarming and unlocking (off by default)
An assistant cannot turn the alarm off or unlock a door unless you allow it, on the computer running this server:
uvx myrohome-helper-mcp allow disarm # adds the disarm tool
uvx myrohome-helper-mcp allow unlock # adds the unlock_door tool
uvx myrohome-helper-mcp disallow disarm # takes it away again
Each asks you to type the word to confirm, and applies only to the controller that API key belongs to. Restart your MCP client afterwards. Until you allow them, the tools are not registered at all, so an instruction hidden in an email, web page or document the assistant reads has nothing to call. Disarm still also needs an API key with arm/disarm enabled and a stored panel code. Revoking takes effect on the next call, without a restart.
AI assistants can be misled by text they read. Allow these only if you understand that, and prefer the Myro:Home app for disarming.
Security
This server runs on your LAN like every other Myro:Home client and holds one controller's API key. Anyone who can run the assistant with this config can do what the key allows. Keep it on trusted machines. The Helper's HTTP API is plain HTTP on the local network; do not expose port 9393 to the internet.
Developing
uv sync
MHH_URL=http://192.168.1.76:9393 MHH_API_KEY=... uv run myrohome-helper-mcp # stdio server
uv run mcp dev src/myrohome_helper_mcp/server.py # MCP inspector
Releasing
Bump version in pyproject.toml and __init__.py, commit, then tag and
push: git tag v0.1.0 && git push origin v0.1.0. The GitLab CI job builds
and publishes to PyPI through trusted publishing (one-time setup: PyPI
project -> Publishing -> add GitLab publisher MyroControl/myrohome-helper-mcp,
environment pypi).
MIT licensed. Myro Control, LLC.
Metadata
Release files for myrohome-helper-mcp 0.8.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| myrohome_helper_mcp-0.8.1.tar.gz | 111.9 kB | Without provenance | Details for myrohome_helper_mcp-0.8.1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| myrohome_helper_mcp-0.8.1-py3-none-any.whl | Python 3 | none | any | Details for myrohome_helper_mcp-0.8.1-py3-none-any.whl |
Total release size: 150.6 kB
Release files / myrohome_helper_mcp-0.8.1.tar.gz
| Download URL | myrohome_helper_mcp-0.8.1.tar.gz |
|---|---|
| Size | 111.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
7087bcb8082400d69cbb484c4a2b12ba58d1f2d6fef7d82bf43ca9d96636a265
|
|
BLAKE2b-256 checksum How to use checksums |
9f381f7ca7fcb89eb653ebc779e615295b28bb586c843234fb1c5524694d9068
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.9.30 {"installer":{"name":"uv","version":"0.9.30","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"12","id":"bookworm","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / myrohome_helper_mcp-0.8.1-py3-none-any.whl
| Download URL | myrohome_helper_mcp-0.8.1-py3-none-any.whl |
|---|---|
| Size | 38.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
850171156ab22f7d106b6e7db17dcc6102c0141198076dc0863cf82399d945ff
|
|
BLAKE2b-256 checksum How to use checksums |
f9b26851fa1b87f8508d18ce231252207d6dc792a151ac3fd42787840764c65d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.9.30 {"installer":{"name":"uv","version":"0.9.30","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"12","id":"bookworm","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Security for myrohome-helper-mcp 0.8.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.