Configuration
All options live in the add-on Configuration tab. Restart the add-on after changing them.
Options
| Option | Default | Description |
|---|---|---|
log_level | info | Log verbosity: trace, debug, info, notice, warning, error, fatal. See Logging. |
api_token | empty | Primary token (full access) expected from MCP clients in the Authorization: Bearer ... header. Leave empty to have one generated on first start (it is saved back into this option). |
allow_write | false | Exposes the ha_call_service tool. Without it the add-on is strictly read only: no write tool is even visible to the client. |
allow_camera | false | Exposes ha_get_camera_snapshot (still images from cameras). Independent from allow_write; seeing your home is not acting on it, but it gets its own switch. filter_reads and entity_denylist still apply. |
allow_config_write | false | Exposes the eight config write tools: creation, modification and deletion of automations and scripts, blueprint instantiation, dashboard cards (HA-validated where possible, mandatory two-step confirmation). Independent from allow_write, and since 0.31.0 it also covers the runtime controls of what it manages (run, trigger, enable/disable): whoever can rewrite an automation can make it do anything anyway, so the access levels stopped pretending otherwise (#165). See the security model. |
enable_sessions | false | Long-lived MCP sessions: SSE streams, ha://entity/{id} subscriptions with change notifications, and in-protocol confirmations (elicitation). Stateless clients keep working unchanged. 16 sessions max, 30 min idle timeout. |
filter_reads | false | Also applies entity_denylist to reads: denied entities disappear from listings, details, history and logbook. |
entity_allowlist | [] | Glob patterns of entities allowed for writes. When non-empty, writes are deny-by-default. |
entity_denylist | [] | Glob patterns of entities always refused for writes. Wins over the allowlist. |
service_denylist | see below | Services refused in any context. |
confirm_domains | [lock, alarm_control_panel] | Writes on these domains require a two-step confirmation: the assistant first gets a preview and a single-use token, and must call again with it to execute. |
Named tokens
The single api_token grants full access (it is the bootstrap and recovery token). Every other token is created on the ingress page and stored hashed in a local database. The YAML api_tokens option was removed in 1.3.0: tokens it used to hold were imported into the store by earlier versions (0.32 to 1.2) and keep working; a leftover key in the stored options is ignored by the Supervisor and cleaned up automatically at boot. Creating tokens happens on the ingress page (sidebar entry), Tokens tab: pick a level (none / read / write / manage) per tool category, optionally an expiry and per-token entity lists (applied on writes, on top of the global ones). The secret is shown once at creation; grants are capped by the allow_* options on every request, so closing a gate instantly degrades every token. Revocation is one click.
Backups
Home Assistant backups (full, or partial with the add-on ticked) include the add-on's /data, so the token store travels with them:
- Nothing sensitive leaks: the database only holds sha256 hashes, names and grants. A stolen backup yields no usable token (unlike the deprecated clear-text
api_tokensoption of the pre-1.0 era). - Consistency is guaranteed by a snapshot: the Supervisor archives
/datawhile the add-on runs, so the livetokens.dbinside a backup could be torn. After every mutation the add-on writestokens.snapshot.dbthrough SQLite'sVACUUM INTOplus an atomic rename: the backup always carries at least one coherent copy, and the add-on restores from it automatically if the main database ever turns out unreadable (the broken file is kept alongside as evidence). - Restoring a backup brings back the tokens as they were at backup time: clients holding secrets created after it get a 401 and need a fresh token.
Glob patterns
Lists accept simple globs where * matches anything and every other character is literal:
light.*: every lightlock.front_door: one exact entity*.kitchen_*: any domain, entities whose name starts withkitchen_
Matching is case insensitive.
Write rules
A service call must pass all of these checks, in order:
allow_writeis enabled (otherwise the tool is not registered at all).- The service is not in
service_denylist. - Every targeted
entity_idpasses the allow/deny lists: allowed when the allowlist is empty or matches, and the denylist does not match. The denylist always wins. - When any entity restriction is configured, targeting by
area_idordevice_idis refused (it would bypass the lists): target explicitentity_idvalues instead. - On a domain listed in
confirm_domains, the call must carry a validconfirm_tokenobtained from a first call (single use, expires after 5 minutes, bound to the exact same call).
These rules apply identically to all four write tools (ha_call_service, ha_run_script, ha_trigger_automation, ha_set_automation): they share a single guarded write path. Every attempt, allowed or refused, produces a JSON audit line in the add-on log.
Default service denylist
service_denylist:
- homeassistant.stop
- homeassistant.restart
- hassio.*
- shell_command.*
- python_script.*
- recorder.purge*
- backup.*These block stopping or restarting Home Assistant, arbitrary shell commands, recorder purges and backup manipulation. You can edit the list, but think twice before removing entries.
Example: cautious write setup
Allow the assistant to control lights and media players, nothing else, and hide cameras from reads:
allow_write: true
entity_allowlist:
- light.*
- media_player.*
entity_denylist:
- light.baby_room
filter_reads: true
# entity_denylist also hides these from reads thanks to filter_reads