Advanced Token Management (ATM)
ATM gives your AI agents scoped, least-privilege access to Home Assistant. Each client gets its own token, limited to exactly the entities you allow, with its own capabilities, rate limit, and optional expiry. Every request is audited, any token can be revoked instantly, and the per-entity semantic safety layer (MESA) can make a device confirm-only or off-limits by its nature, no matter what permissions a token is granted.
ATM runs entirely inside Home Assistant, with no extra process, no cloud dependency, and no setup beyond the ATM panel. It works with the MCP clients you already use (Claude Code, Cursor, ChatGPT/Codex, Gemini, and others), or you can skip installing a client altogether and chat from inside Home Assistant itself. Either way, a guided setup takes you from a new token to a working agent in minutes, backed by a catalog of 101 tools for reading, controlling, and authoring your configuration.
Documentation
The full documentation, including the tool reference, permissions, capabilities, MESA, and the admin API, lives at sfox38.github.io/ATM.
New here? Start with the Quick start: it creates your first token, grants it one device, then lets you choose whether to chat from inside Home Assistant or connect an external agent, in a few minutes either way.
How ATM compares
We road-tested ATM against the built-in and community MCP servers, one agent model, one synthetic home, the same tasks. ATM was the cheapest per completed task, the only server that left every off-limits device untouched, and the most capable. See the latest road test report, or run the tests yourself from the roadtest repository.
Requirements
- Home Assistant 2024.5.0 or later.
- One ATM instance per Home Assistant. No Python dependencies beyond what HA ships.
Install via HACS
- In HACS, open Integrations, then the top-right menu, and choose Custom repositories.
- Enter
https://github.com/sfox38/ATMand select Integration as the category, then click Add. - Find ATM in the HACS integration list, install it, and restart Home Assistant.
Prefer to install by hand? Copy the custom_components/atm folder into your Home Assistant config directory under custom_components/atm, then restart.
Set up
Go to Settings > Devices & services > Add integration and search for Advanced Token Management. Click through the single-step config flow, then open the ATM panel in your sidebar. The Quick start takes it from there.
Changelog
The complete release history is on the GitHub releases page. Recent changes:
2.3.0
- New: Bundled mesa-core updated to 1.2.1
- New: Agent Chat can show the time on each message. Turn on "Show timestamps" in the gear menu (off by default); each user and assistant bubble gets a small clock label, in your locale's time format.
- New: Agent Chat shows the conversation's token usage live in a small footer under the message box, for example "Session 48.2k tokens · context 12.1k". Session is the conversation's total consumption (every model call's input plus output, which is why it grows faster than the visible text); context is the size of the most recent call, the number the Chat memory setting bounds. The counts are the provider's own exact numbers, harvested from the same streams Agent Chat already reads, never estimated. Toggle it with "Show token usage" in the gear menu (on by default). A provider that does not report usage says so in the footer instead of showing a forever-zero counter.
- New: a one-click "Reject with error message" button on the approval card whenever the preview detected a card configuration error. It rejects with that error as the rejection reason, which the agent receives directly.
- New: Agent Chat's approval cards now show why an action was rejected (your typed rejection reason) or what failed after an approval, instead of just the word "rejected".
- New: entity search and the entity detail tool now label a configuration or diagnostic entity as such, so an agent can tell a device's setup and health entities apart from its primary controls. These entities stay fully visible and usable for reads (checking battery levels, connectivity, or firmware updates is a common, legitimate task); only bulk device/area actions skip them.
- New: safer concurrent editing of raw configuration. The tools that replace a whole file or dashboard layout (raw
configuration.yaml, dashboard layouts, and files underwww//themes//custom_templates/) can now be made conditional: the read tool returns a content fingerprint, and the write tool accepts it and refuses if the file changed since it was read, instead of silently overwriting an edit you (or another agent) made in the meantime, which matters most because a change awaiting approval can sit for minutes. It is optional, so agents that do not read-first are unaffected, and an admin restore from the version history is never blocked by it. - New: card-level dashboard editing. Three new tools (
add_dashboard_card,edit_dashboard_card,delete_dashboard_card) let an agent add, change, or remove a single card by its view (and section) position, instead of resending the entire dashboard layout throughset_dashboard_config. This matters beyond convenience: rewriting a whole dashboard inside one tool call can exceed a model's output limit, and the card tools make that failure structurally impossible for single-card changes. Same capability gate and approval flow as the full-layout tool, with a focused one-card approval diff; each result returns the layout's new content fingerprint so several card changes can be chained safely without re-reading. - New: live dashboard preview when reviewing a dashboard change. When an agent proposes a dashboard layout, the approval card and the Changes tab can now render the actual cards (using Home Assistant's own card renderer, with live entity states) next to the usual red/green diff, via a Diff | Preview toggle. The preview is display-only: clicking a card cannot actuate anything. A whole-layout approval (
set_dashboard_config) previews the proposed layout; a single-card approval (add_dashboard_card/edit_dashboard_card/delete_dashboard_card) previews just that card, with a Before/After switch when both exist; the Changes tab can flip between the Before and After of any recorded dashboard version, always showing the resource's full layout (a card-level change is still stored as a complete before/after configuration, so its own preview is not isolated to just that card, unlike the approval review). Reviewing before you approve is the way to see the isolated single-card preview: from Agent Chat's inline approval prompt, use "Review..." rather than approving directly, since the compact in-chat prompt does not itself show a diff or preview. The Diff | Preview switch sits in the diff's toolbar next to the layout toggle, and both choices are remembered: pick Preview (or the stacked diff layout) once and every later change opens that way, on both the approval card and the Changes tab. If your browser session has not loaded a dashboard yet (or the layout is strategy-generated), the toggle simply does not appear and the diff works exactly as before. - Improved: the Changes tab now says what each change actually did. Dashboard rows carry the card operation ("added custom:apexcharts-card (view 0, section 6)") or the card-count movement, raw config and file writes show the size movement, and entity edits list which fields changed, instead of every row showing only the resource name.
- Improved: automations that reference entities indirectly (device triggers, or area/floor/label target blocks) are no longer invisible to the analysis tools.
get_relationshipsanddescribe_entitynow list such automations under "referenced by",whatifsurfaces them as candidates (marked "unknown", since a device trigger cannot be simulated),validate_configexpands them into its referenced-entities report, and MESA's trigger-staleness check catches atriggers_automations: nonedeclaration hidden behind a device trigger. - Hardened: an approval is final for the approved change, and a rejection reason steers the next attempt. Once you approve, the agent treats the result exactly as applied as accepted and will not file corrective follow-ups, even if it landed differently than the agent intended. When you reject with a reason, the agent is told the reason is your direction for its next proposal, so building a card through many reject-with-reason rounds works naturally. Rejecting without a reason tells it to ask rather than try again.
- Hardened: a corrupt or hand-edited
.storage/atm.jsoncan no longer break ATM. A damaged token record is skipped with a warning instead of aborting startup, out-of-range rate limits fall back to their defaults instead of rejecting every request from that token, a damaged permission tree loads as "grants nothing" rather than crashing, and a wrong-typed storage root, collection, or pending-approval entry is reset (and the cleaned file re-saved) instead of aborting setup. - Hardened: the flags that widen a token's access (pass-through and its acknowledgment, plus the pass-through-only assist-exposure flag) now require real true/false values. A malformed request sending the string "false" (which is technically "truthy") is rejected instead of silently enabling pass-through, and a corrupted stored value loads as off rather than on.
- Fixed: when a model's reply was cut off by its output-token limit in the middle of a tool call, Agent Chat reported the misleading "The model produced an invalid tool call." It now says the model hit its output length limit and suggests a smaller change. DeepSeek requests also now carry an explicit generous output cap, since DeepSeek's default is low enough to truncate large tool calls.
- Fixed: approving an action whose execution then failed (for example a dashboard write refused because the layout changed since the agent read it) was reported back to the agent as a bare rejection. Agents could interpret the approval as a refusal and loop, re-proposing the same action while you kept approving it. The agent is now told the action was approved but failed to execute, with the actual error, so it can fix the cause instead of retrying blind. This applies to Agent Chat and to external clients using the inline confirm wait.
- Fixed: pressing Cancel in Agent Chat erased the visible conversation. A long agentic exchange counts as one turn, and Cancel discarded the in-progress turn, which in a single long session was everything on screen. Cancel now keeps everything already streamed in the transcript, marks the cut point with a "Cancelled." notice, flips any still-unanswered approval prompt to cancelled, and still puts your question back in the input box for editing.
- Fixed: the "needs approval" capability mode now works on the plain REST API too. A capability set to Confirm answered REST service calls with a flat 403 (behaving like Deny), while the same call through MCP queued an approval. The three gated call families (restart/stop, physical control of locks/alarms/covers/valves, and the config-reload services) now return "pending approval" with the approval id on REST as well, and an admin approval runs the identical call through the same executor as MCP.
- Fixed: creating a token through the admin API with a timezone-less expiry (for example
2026-08-01T00:00:00) poisoned the stored record and could stop ATM from loading at the next restart, taking the panel down with it. Expiry timestamps are now normalized to UTC when the token is created (a bare local time is accepted and converted), and an already-poisoned record heals itself on load. The audit query'ssincefilter had the same timezone bug and is fixed the same way. - Fixed: the version-restore admin endpoint now rejects malformed request bodies instead of quietly restoring the default side, and enforces the same request-size limit as every other endpoint.
- Changed: bulk actions that target a device or area now skip that device's configuration and diagnostic entities (and any hidden entities), matching how Home Assistant's own service calls behave. For example, "turn off every switch in the bedroom" no longer also flips a child-lock switch, an LED-indicator toggle, or a do-not-disturb switch that happens to be a switch. This applies to both the standard service calls and the native voice/intent tools. If you actually want to control one of these entities, name it directly (its entity id), which is never filtered; only device/area sweeps and area/domain voice commands are.
- Changed: the default (compact) output of
get_state/get_statesnow includes the key attributes for many more entity types (updates, valves, timers, sun, automations, scripts, calendars, input helpers, counters, remotes, and more), and fills in gaps for existing ones (a light's color mode, a media player's mute/position/duration, a cover's device class, and others). Agents get the state details they need without asking for the full attribute dump, while the compact-by-default token savings are preserved. Ask fordetailedoutput or specificfieldsto get everything, exactly as before.
2.2.0
- New: Bundled mesa-core updated to 1.2.0
- New: Agent Chat, our recommended way to use ATM. Instead of using an external client, you can now talk to Home Assistant from a floating chat window. ATM runs the agent itself, on a token you choose, so every capability gate, per-entity MESA rule, approval, and audit entry applies exactly as it would for any external MCP client.
- New: use ATM with Home Assistant's own Assist and voice. You can now bind an ATM token to Home Assistant's native assistant so a voice or chat conversation runs through that token's scope, MESA safety, approvals, and audit. A least-privilege token (for example the Voice Assistant persona) is recommended. A Confirm-gated action becomes queued for approval in the ATM panel, since voice has no inline Approve button.
- New: ATM as a Home Assistant conversation agent (self-contained voice). The option above hands ATM's tools to a model supplied by a separate integration (OpenAI, Anthropic, Ollama, and so on). ATM can register itself directly as a conversation agent so "ATM" appears in Settings > Voice assistants and runs its own model, an existing Agent Chat provider account, on a token's scope, with no separate integration. ATM can then set up the assistant for you in one click (it creates an Assist assistant pointed at ATM). Confirm-gated actions are queued for approval in the ATM panel (voice has no inline Approve button).
- New: ATM as a Home Assistant AI Task entity. Home Assistant's AI Task lets automations, scripts, and dashboards generate text or structured data with an AI model (the
ai_task.generate_dataaction). ATM can now provide that entity itself, and it runs ATM's own model on the token's scope, with the same per-token permissions, MESA safety, approvals, and audit as the rest of ATM. - New:
mesa_get_profilecan include an entity's "semantic moments", the purpose-specific triggers and conditions Home Assistant 2026.7 introduced (e.g. a lock's "locked" trigger), so an agent reading a MESA profile also sees what automation moments the entity offers. Passinclude_semantic_moments: true; the list is read live from Home Assistant, is informational only, and is simply omitted on older Home Assistant versions. For moments whose config shape is non-obvious (such as a numeric-threshold crossing), each moment also includes a ready-to-adapt example config, so an agent can copy the exact automation trigger or condition rather than reverse-engineering it. The connection primer tells agents that can author automations to call it on the trigger or condition entity before building the automation. - New: MESA advisory leases. Two new tools,
mesa_request_leaseandmesa_release_lease, let an agent announce "I am operating these entities for the next few seconds" (30-second cap) so MESA-aware components can coordinate. A lease grants no authority (every action stays gated by scope, capabilities, and MESA), covers only entities the token could already control, is denied for entities under protected or critical automation control, and lease endings fire anatm_mesa_lease_expiredevent you can automate on. - New: MESA profile export and import. Two icon buttons next to the MESA tab's refresh control download your entire MESA profile set as one JSON file (the standard MESA archive format, so it doubles as a backup and transfers to any other MESA-aware server) and import one back. Both confirm first; importing validates every profile, reports anything invalid without writing it, and by default never touches an existing profile. A "Replace existing profiles" checkbox switches to overwrite mode behind a clearly destructive confirm.
- New: the on-boarding wizard now offers Agent Chat as its primary client - external clients are no longer required. After granting access to one device, a new "Choose how to connect" step lets you pick chatting inside Home Assistant or connecting an external app. Choosing Agent Chat walks you through adding a model provider account right there in the wizard, then a highlighted "Try now" opens the Agent Chat window with your new token and provider already selected and a test prompt typed in for you.
- New: Include-graph-aware YAML authoring. The automation, script, and scene tools now follow
configuration.yaml's!include/!include_dir_*layout to the correct leaf file and edit only the target entry's lines, preserving comments, formatting, and!secretreferences everywhere else, instead of refusing whenever an include appeared. Creates route by include flavor (append for plain!include, a new file per entry for directory includes); every write is re-parse-verified before it lands, and anything ambiguous (duplicate ids, packages/inline config, multiple create targets) refuses rather than guesses. Even HA's own UI editor still cannot edit split configurations at all. - New: per-token MCP server names. The connect instructions now derive the client-side server name from the token's name (
atm-<token-name>) instead of one shared name, so you can keep one client entry per token and switch tokens by toggling which entry is enabled in your MCP client, no more clearing auth and retyping. Enable only one atm-* entry at a time. - New: token settings presets (experimental, off by default). A token can save named snapshots of its full configuration (capabilities, permissions, rate limits, pass-through) and switch between them from its detail view. Turning the setting on saves every token's current settings as its first preset; switching first saves your unsaved changes into the outgoing preset (the dialog shows exactly what), and applying the active preset reverts to its saved state, so nothing is ever lost silently. Switching is admin-only by design.
- New: inline "wait for approval" per-token setting. When a Confirm-gated action is queued, ATM now holds the response open for a short window so that if you approve within it, the agent gets the result in the same call with no second round-trip; if you do not decide in time it falls back to the immediate "pending approval" reply and the agent carries on. On by default at 60 seconds, adjustable per token from 30 to 180 seconds in the token's detail view. Agents that run unattended (no human watching) can be switched to the return-immediately behavior via the admin API.
- New: Zigbee management. Agents can now see radio-network health and, when granted, manage the Zigbee network. Two read tools under the diagnostics capability (
get_radio_networkfor channel, coordinator, and join-window state;get_radio_devicefor one device's signal quality, availability, and mesh neighbors) and three write tools under a new "Radio management" capability (permit_zigbee_jointo open or close the pairing window,reconfigure_zigbee_deviceto re-interview a misbehaving device,remove_zigbee_deviceto drop one from the network), all Confirm-eligible. Works with Zigbee2MQTT and ZHA. Network keys and other credentials never appear in any response; device writes require write access to the device's entities; the coordinator itself can never be targeted. Persona defaults: deny everywhere except confirm for power_user, home_admin, and maintenance. - New: agents are told when their tool list goes stale. ATM's stateless MCP transport cannot push a tools-changed notification, so after you change a token's capabilities, permissions, or preset mid-session, the next tool response carries a one-time notice telling the agent to check get_capability_summary and ask you to reconnect. The audit log marks the request that carried the notice and records the token's active preset per request.
- New: MESA profile suggestions. The MESA tab now scans for under-protected entities and suggests profiles you can apply in one click, review in the editor, or dismiss: automations, scripts, and scenes whose actions reach risky devices (an agent allowed to trigger them controls those devices indirectly, bypassing the devices' own profiles), and risky devices (locks, alarms, garage doors, valves, sirens, water heaters, firmware updates) with no MESA coverage at any level. Locks and alarms suggest prohibited (matching the built-in baseline); everything else suggests confirm. Suggestions are never applied automatically, and the scan is honest about being a lower bound: templated automation targets are invisible to it.
- New: typo-tolerant entity search.
search_entitiesmatched only exact words, so a misspelled query ("themostat", "kitchne") returned nothing. It now falls back to an approximate, similarity-based match when, and only when, the exact search finds nothing, returning the closest entities and flagging the result as approximate. Queries that already match exactly behave exactly as before. - New: MESA profiles can now use solar-angle time conditions ("only after sunset", twilight boundaries, with minute offsets). They are evaluated against Home Assistant's own sun position calculations; previously these conditions were always treated as unevaluable and failed closed, and they still fail closed if the sun position cannot be computed.
- New: when an agent calls a service by the wrong name on a common device domain (for example
valve.openinstead ofvalve.open_valve, orcover.openinstead ofcover.open_cover), ATM now tells it the valid service names for that domain instead of a bare "Forbidden.", so it can retry correctly rather than assuming it lacks permission. This reveals nothing sensitive: it only ever fires for a device the token already controls, and the suggested names are a fixed list of standard Home Assistant services, never a lookup of what is actually installed. Every other case still returns the generic error, so ATM never discloses whether an arbitrary service exists. - New: agents can now call Home Assistant's config-reload services (
automation.reload,script.reload,scene.reload,homeassistant.reload_all, and the other core reloads for helpers, groups, zones, people, and schedules) throughcall_service. These take no entity target. The reload is Confirm-eligible like any other write. This is a curated list of stable core reloads; integration-specific reloads are intentionally not included. - Panel: a rejected approval now shows a readable reason instead of a raw code. An approval that failed re-execution shows the underlying tool error (e.g. "Execution failed: Forbidden.") rather than the bare
execution_failedslug, and the other internal reason codes render as plain English; a free-text reason an admin typed still shows verbatim. - Panel: the Approvals list now updates instantly when a request is queued or resolved (it subscribes to the Home Assistant event bus, matching the badge) instead of lagging behind on its own poll.
- Panel: the approval before/after diff is now a red/green line diff (removed lines tinted red, added green) in a wider dialog with an icon toggle between side-by-side and stacked layout, matching the Changes tab, so it is easy to see exactly what an approval would change. Raw args, results, and audit payloads render in Home Assistant's code editor (which now also upgrades to the editor if HA registers it after the panel loads, instead of staying on the plain-text fallback for the session).
- Panel: the Changes (version history) tab now shows structured configs (automations, scripts, scenes, helpers, dashboards) as a red/green line diff, the same as raw file snapshots, instead of two plain side-by-side panes.
- Panel: delete approvals now show the configuration being removed as an all-red pane, so you can see exactly what a delete would remove before approving.
- Panel: Audit, Approvals, and Changes now paginate the same way: a page at a time with a "Load more" button.
- Panel: an approval or audit entry for a MESA-gated action (one blocked by a device's own safety setting rather than a token capability) now shows "MESA-gated action" instead of the internal
call_service_mesa_approvedlabel, which read like a real tool name but was not one you could actually call. - Panel: accessibility and responsiveness. The light theme's amber accent and muted-grey text were darkened one shade to meet WCAG AA contrast; form fields and the Agent Chat window gained proper labels and polite screen-reader announcements; keyboard focus is now visible on the capability mode selectors; dialogs keep focus contained and move it to the new step on wizard and modal transitions. Responsive frontend now works on any mobile device.
- Changed: valve mutation (open / close / stop / set position) now requires the physical-control capability, the same as covers, locks, and alarms. A valve controls the flow of water or gas and is just as consequential as a cover, so gating it consistently closes a gap where a valve could be opened without that capability. If you have a token that operates valves, make sure it has physical control enabled (allow or confirm), not denied.
- Changed: per-token sensors (request count, last access) now publish to Home Assistant at most once every 5 seconds per token instead of on every single request. A busy agent previously generated one recorder row per call in pure telemetry; panel statistics are unaffected (they read the live counters directly) and automations watching an ATM sensor see at most 5 seconds of extra latency.
- Changed: changing the audit flush interval in Settings now takes effect immediately instead of after the previously scheduled flush wakes up, and the "Never" setting no longer keeps an idle timer running.
- Changed: the Settings > Data Management wipe is now scoped by three independent switches: all ATM data (tokens, archived records, permissions, settings, and the audit log), your Agent Chat provider accounts and their stored API keys, and your MESA safety profiles. The first two default on and MESA defaults off, so a reset keeps hand-authored safety policy unless you ask otherwise. The wipe also tears down any queued pending approvals and dismisses their notifications, the same cleanup revoking a token performs.
- Behavior change: on a configuration.yaml that does not route automations/scripts/scenes to an editable YAML file, create now refuses with a clear message; previously it silently wrote a hardcoded file Home Assistant never loaded.
- Hardened: the MCP endpoint now rejects malformed JSON-RPC requests cleanly instead of returning a server error, validates the
Originheader against your Home Assistant URLs as a DNS-rebinding defense, and can no longer have its audit log poisoned by a malformed request. - Hardened: the Home Assistant compatibility probe now also catches a class of constructor drift it previously missed (required keyword-only parameters); a new startup check warns when the system_log internals get_logs depends on have changed shape; a broken template-sandbox environment is now a loud startup warning; settings writes are clamped and type-coerced at the storage layer on every path, not just the admin API; the pass-through entity-filter logic that was hand-written in four places is now a single shared path; and a batch of dead code and unused constants was removed.
- Security: The physical-control capability now gates on the actuator domain rather than an exact service-name list, so
cover.toggle, cover/valve tilt services,valve.toggle,alarm_control_panel.alarm_arm_custom_bypass, andhomeassistant.toggleon a cover or valve are all covered (previously these could actuate a lock/cover/valve/alarm on a token that had write access butcap_physical_controldenied). Non-finite JSON numbers (NaN/Infinity) in tool arguments are now rejected instead of silently passing range checks. Audit-log fields are now length-bounded and type-coerced so a malformed value can't bloat or poison a stored entry. Thesearch_entitiesfree-text query is now length-capped. - Fixed: a native intent tool (
HassTurnOn,HassTurnOff, and the otherHass*tools) called with no recognized target (no name, area, floor, domain, or device class) no longer falls back to every entity the token can write. This could be triggered by a model passing an unrecognized argument such asentity_id(these tools takename, notentity_id), which left every recognized selector empty; the call now matches nothing (fail closed) instead of fanning the action out to the token's whole writable scope. A call with any real selector (including a domain-only "all the lights") is unaffected. - Fixed: calling a service the token is genuinely permitted to use, but with a value Home Assistant itself rejects (for example a thermostat setpoint outside the entity's allowed range), is now reported to the agent as an invalid request with the actual reason, instead of the generic "Forbidden." that made a bad value look like a permission denial. This only applies to Home Assistant's own input-validation errors on an entity the token already controls; a missing/unknown service still returns the generic error so service existence is never revealed.
- Fixed: an agent targeting entities by name with an unexpected argument shape (for example asking to lock two named locks and sending a list of names instead of one) could previously hang for minutes instead of getting an error back. The underlying issue is fixed (a list is now treated the same as if the name had not been given, so the request still resolves via any other target you specified), and every tool call now has a safety net that turns any unexpected internal error into a normal, fast response instead of leaving the connection hanging.
- Fixed: the native
HassTurnOn/HassTurnOfftools now route vacuum and valve entities to their real domain services (vacuum.start/stop,valve.open_valve/close_valve), the same routing locks and covers already had. Home Assistant's generichomeassistant.turn_on/turn_offsilently ignores these domains (it logs "does not support entities vacuum.X" and does nothing), so before this fix the tool reported success while the device never moved. - Fixed:
HassSetPositionnow positions valves as well as covers, dispatching each target to its own domain service (cover.set_cover_position/valve.set_valve_position). The tool was previously hardcoded to covers, so a valve could never be resolved or positioned through it even though the documentation always promised valve support. - Fixed: the per-token sensor write debounce (
flush_sensor_writes) could be dispatched to Home Assistant's executor thread pool instead of the event loop. The function is now correctly marked@callbackso it always runs on the event loop, matching every other scheduled callback in the integration. - Fixed: a larger request body (such as importing a well-profiled deployment's MESA archive, or a big automation/dashboard/file argument on any MCP tool call) could occasionally fail with "Invalid JSON body." even though it was sent correctly; every request reader in ATM (admin API, REST proxy, and the MCP endpoint) now keeps reading until the whole body has arrived instead of trusting a single read to return everything at once.
- Fixed: revoking a token (or a token expiring) now also cancels its queued pending approvals, dismisses their notifications, and fires the resolved event for each, so a dead token's requests no longer sit in the Approvals queue looking approvable until they time out. An approval that is mid-execution at that moment is left alone. The audit outcome filter in the panel also gains Invalid Request and Pending Approval options, and a pending-approval audit entry is now documented as always recorded (logging toggles cannot suppress the approval trail).
- Fixed: the get_relationships tool no longer reads YAML files on Home Assistant's event loop (it now uses a worker thread, like describe_entity always did), avoiding the blocking-call warnings recent Home Assistant versions log for this.
- Fixed: an entry containing
!secretno longer breaks the authoring tools (the file previously failed to load at all). Edits replace an entry wholesale, so a dropped!secretreference is visible in the version history and approval diff; restoring a version whose snapshot contains YAML tags is refused to avoid writing a broken config. - Fixed: the
set_dashboard_configapproval showed an empty "Before" pane (the diff builder was synchronous and could not read the current layout). It now reads the dashboard's current layout for the "Before" side, with out-of-scope entity ids redacted the same wayget_dashboard_configdoes, so an edit shows a real before/after. - Fixed: a malformed or corrupted tool call (for example from a struggling local model) could write an unreadably long string into the audit log's Method/Resource columns. It is now capped to a sane length; no real tool call is affected.
- Fixed:
search_entities's "only show stale entities" filter (stale_hours) failed every time it was used, with a generic internal error. It now correctly compares each entity's last-changed time. - Fixed: creating or editing an automation, script, scene, helper, dashboard layout,
configuration.yaml, or a scoped file with an invalid config used to still show "queued for approval" if the capability was set to Confirm. These tools now check the same way they would eventually fail before queuing the approval at all, so an invalid request is rejected immediately and never shows as pending. - Fixed: calling a service whose own Home Assistant schema does not support an entity target at all, such as a notification service, is a different problem than lacking permission for one, and previously failed with a generic internal error instead of a clear explanation. The agent now gets the actual reason back and can adjust its request instead of retrying blindly.
- Fixed:
search_entitiessilently returned zero results wheneverdomain,device_class, orstatewas passed as an empty string rather than omitted, instead of treating it the same as not filtering on that field at all. Some MCP clients fill in every declared optional parameter on every call rather than omitting unset ones, which made an otherwise-correct search return nothing for no visible reason. - Fixed: an action gated by both a Confirm-mode capability and a MESA confirm-mode entity erroneously required two sequential admin approvals: approving the first quietly queued a second "MESA confirmation" approval for the same action. Entities whose MESA nature is prohibited or read-only are still refused regardless of approvals. So that MESA's involvement stays on the record with no second approval, such an approval is now marked "(includes MESA confirmation)" in its summary (visible in the Approvals list and History) and its review card names the entities that confirmation covers.
2.1.0
- New: Raw
configuration.yamland file writes (set_yaml_config,write_file) are now captured in the configuration version history with admin rollback, the same before/after snapshots and Restore the structured authoring tools already had. - New: Orphaned MESA profiles can be cleared in bulk: a Clear all orphaned profiles button on the MESA tab removes every profile whose entity, area, or integration no longer exists in one step
- New: The agent skill guide now includes modular domain-authoring recipes (automations, scripts and scenes, dashboards and cards, conditional/visibility, and climate), so connected agents produce better Home Assistant configuration.
- New:
get_logbook(the human-readable event history) - New:
get_calendar_events(events from an accessible calendar entity within a time window) - New:
list_blueprintstool lists installed automation and script blueprints with their inputs - New: entity-registry tools
set_entity(friendly name / icon / area) anddelete_entity(remove a stale or duplicate registry entry; renaming anentity_idis intentionally not exposed. - Security fix:
get_system_healthnow scrubs secret-keyed values and URL-embedded credentials from the per-integration health data before returning it, and also network-topology details (LAN/loopback/link-local IP addresses, hostnames inside URLs, and filesystem paths), consistent with whatget_configalready withholds. The topology scrub is conservative (private IP ranges only, so a public-IP-shaped version string is untouched). - Security fix:
validate_configno longer reveals whether an out-of-scope entity exists. - Fix: The MCP batch endpoint now runs its items sequentially instead of concurrently, so a single batch can never execute many write tools at once and interleave them.
- Fix:
get_confignow returns a curated subset of Home Assistant's configuration (version, time zone, units, location name, loaded components) instead of the full config object. - Updated: The Changes tab now renders raw
configuration.yamland file-write history as a line-highlighted text diff, instead of YAML-quoting the file contents. - Updated: Better MCP tool descriptions so agents can pick the right tool on the first try.
- Updated:
get_stateandget_statesnow return a compact, domain-aware view by default (key attributes only) to cut token cost. - Updated:
search_entitiesnow ranks results by relevance and supports multi-word queries. - Tests: Hardening
- Docs: Documented
get_yaml_configreturnsconfiguration.yamlverbatim (inline secrets included; prefer!secretreferences), and that a saved dashboard
No comments yet
Be the first to share your take.