Search all 160 tools by name, task, or required capability. Phoenix includes Home Assistant's 23 native MCP tools plus 137 scoped tools for configuration, diagnostics, and control.
Read one automation's full configuration before editing it. edit_automation replaces the entire configuration, so omitting a trigger, condition, or action removes it.
The response includes a content_hash for the edit's expected_hash. This prevents overwriting a newer change. YAML tags appear as display strings, such as !secret my_key; secret values are never resolved. The read requires Automation write but never needs approval.
params
automation_id (required), from list_automations or the entity's id attribute
Create, edit, or delete automations in the YAML file selected by configuration.yaml. Phoenix follows !include and !include_dir_* layouts to the correct file. It rewrites only the target entry, preserving unrelated comments, formatting, and !secret references.
New automations are appended to a plain include or written as separate files for directory includes. Phoenix refuses ambiguous layouts, including duplicate IDs, package or inline entries, and multiple possible create targets. Edit replaces the entire automation; read it first and resend every field you want to keep.
create
config (required), an object holding alias, trigger, action, plus optional condition, mode
edit / delete
automation_id (the slug); edit replaces the entire config and accepts an optional expected_hash from get_automation, which refuses the write if the automation changed since that read
get_scriptScript write
Read one script's full current configuration, the read half of a safe edit for the same reason as get_automation: edit_script replaces the whole config. Returns a content_hash for the edit's expected_hash, and renders YAML tags as display strings without resolving secrets.
params
script_id (required), the part after script. in the entity id
create_scriptedit_scriptdelete_scriptScript write
Create, edit, or delete scripts in the YAML file your configuration.yaml routes scripts to. Split configurations (!include and !include_dir_named/merge_named layouts) are followed to the correct leaf file, preserving untouched content byte-for-byte, the same include-graph handling as the automation tools. Edit replaces the entire configuration, so read it with get_script first.
create
script_id and config (both required), where config holds alias, sequence, mode, variables, fields
edit / delete
script_id (the slug); edit replaces the entire config and accepts an optional expected_hash from get_script
Configuration & templates
get_configConfig read
Read a curated subset of Home Assistant's configuration: version, time zone, unit system, location name, and the list of loaded integrations. Precise home coordinates, internal/external URLs, and host filesystem paths are withheld.
get_energy_configConfig read
Read the Energy dashboard configuration, including grid, solar, battery, gas, water, and individual-device statistics. referenced_entities combines every referenced entity into one list. Check this list before deleting an entity or removing its integration.
issues reports missing entities, absent long-term statistics, and incompatible device class, state class, or unit settings. A null value means the check could not run; an empty list means it found no issue. configured: false means the Energy dashboard has not been set up.
Entities outside the token's scope are redacted and omitted from referenced_entities. This tool is read-only.
get_solar_forecastConfig read
Read solar production forecasts for the config entries your Energy dashboard's solar source names. Returns an empty result when no solar source names a forecast integration, which is the normal state without one installed.
edit_energy_configManage Energy dashboard
Change one addressed part of the Energy dashboard. The tool never accepts the whole configuration because Home Assistant replaces complete lists and would delete entries you omitted.
Phoenix re-reads the current preferences, applies one change, verifies its scope, and sends only the affected list. Every call is recorded in Changes and can be rolled back.
params
operation (required): replace_statistic, add_device, remove_device, rename_device, set_source, or remove_source.
target (required): set target.kind to statistic, device_name, or source, then supply the matching target.id, target.name, or target.source_type.
changes (required): supply changes.new_statistic for replace_statistic, or changes.name for add_device and rename_device. Use an empty object for a removal.
Source operations: set target.source_type to grid, solar, battery, gas, or water. Accepted change fields are stat_energy_from, stat_energy_to, number_energy_price, number_energy_price_export, entity_energy_price, entity_energy_price_export, stat_cost, and stat_compensation.
Use device_name to address a device whose statistic appears as <redacted> in get_energy_config. This can happen after the source entity has been removed. A new statistic must reference an entity the token can use; an existing statistic used only as an address does not.
set_source updates an existing source or creates one. Grid export and battery charge use stat_energy_to; solar, gas, and water do not accept it. Export-price fields apply only to grid sources.
Set a price with either a fixed number or a price entity, not both. Use stat_cost for an external cost statistic, and pass null to clear an optional field. A grid source must retain at least one meter. remove_source refuses to choose between multiple sources of the same type.
list_blueprintsConfig read
List installed automation and script blueprints with their inputs. To instantiate one, create an automation or script with a use_blueprint config (the existing authoring tools accept it); there is no separate create-from-blueprint tool.
params
domain (optional, automation or script)
get_blueprintConfig read
Read a blueprint's YAML before using it. list_blueprints reports accepted inputs; this tool returns the complete body, including !input placeholders. It accepts only paths enumerated by the blueprint registry, so files outside blueprints/ are unreachable.
params
domain (required; automation or script), path (required; exactly as returned by list_blueprints)
Create, edit, or delete blueprints from supplied YAML. Writes are Confirm-eligible and require cap_blueprint_write plus the matching automation or script authoring capability. This prevents blueprint writes from bypassing a denied authoring capability.
Paths stay inside the domain's blueprint folder. Phoenix validates YAML with Home Assistant's blueprint schema before creating an approval.
An edit affects every consumer. Home Assistant reloads all automations or scripts built from the blueprint, although their own configurations and version histories do not change. Approval and results list the affected entities. Home Assistant refuses deletion while a consumer still uses the blueprint.
Import from URL is not supported. A request made inside Home Assistant could reach the LAN or Supervisor API without operator review. The agent must fetch the source and pass the YAML, which makes the complete blueprint visible during approval.
params
domain (required; automation or script), path (required; relative .yaml path, jailed to blueprints/<domain>/), content (required for create/edit; the full blueprint YAML)
get_logsLog read
Read Home Assistant's bounded, deduplicated system_log ring, newest first. Phoenix MCP's own entries are excluded. Each bucket includes its first and latest occurrence, occurrence count, every message variant Home Assistant retained, a scrubbed exception, and safe relative source and root-cause locations. Absolute or unrecognized paths are replaced.
The response reports whether the source is available or degraded, its configured capacity, retained and skipped bucket counts, earliest and latest retained times, the read timestamp, and the effective filters. matched_buckets, has_more, and an opaque next_cursor support stateless continuation. Pagination is best-effort over a live ring because an updated deduplication bucket can move between calls.
Home Assistant retains only WARNING and above in this source. Phoenix does not read or parse the raw home-assistant.log file. Search is case-insensitive and literal, and runs only after token and credential scrubbing. The scrubber cannot recognize every arbitrary third-party secret or piece of personal data, so Log read remains an elevated-trust grant.
Read only Phoenix MCP's own retained WARNING-and-above buckets. This separate tool requires both cap_diagnostics and cap_log_read. It uses the same source-coverage, time, search, and cursor contract as get_logs, with an optional Phoenix logger-prefix filter.
A stronger scrub removes credentials, network topology, URLs, filesystem paths, UUIDs, ULIDs, long opaque identifiers, and inaccessible or unknown entity IDs before search. Accessible entity IDs remain useful for diagnosis.
Read the human-readable event narrative (state changes, triggered automations and scripts) in chronological order. Narrow one query with a target object. Use target.kind: "resources" with up to 100 unique accessible target.entity_ids and target.device_ids together, or use target.kind: "context" with one causal target.id. Every requested resource must be accessible; a missing and an inaccessible resource answer identically.
Home-wide reads cover up to 7 days. Entity, device, and context queries cover up to 31 days. Search performs a bounded, case-insensitive literal match on safe name, message, and state fields after filtering and redaction.
The result includes total before limiting, plus count, truncated, and effective filters. Narrow the time window when truncated. Home Assistant does not provide a cursor for this query.
This is the narrative event history, distinct from get_logs (error log) and get_history (Recorder states).
Inspect effective per-logger levels and the current Home Assistant integration-aware override for integration domains visible through this token's accessible config entries or registry entities. Phoenix MCP and inaccessible domains stay hidden. Stored overrides identify none, once, or permanent persistence, and the response reports unavailable or degraded upstream state instead of guessing after Home Assistant changes shape.
The write targets an integration domain, not an arbitrary Python logger. NOTSET clears the override. A runtime-only level can last 5 to 120 minutes.
Approval fingerprints visibility, declared loggers, and the previous override. A timed restore runs only while the applied setting and logger set remain current, so a newer operator change is preserved. INFO and DEBUG can consume disk and expose sensitive third-party output.
params
integration, level (NOTSET/DEBUG/INFO/WARNING/ERROR/CRITICAL), persistence (none/once/permanent), optional duration_minutes (5 to 120)
render_templateTemplate render
Render a Jinja2 template in a permission-scoped environment; templates can only reach entities the token can read.
params
template (string, required)
Discovery & diagnostics
Read-only, scoped to accessible entities. Per-object lookups return an identical "not found" for a missing object and one the token cannot see, so they cannot probe for existence.
check_ha_config validates the Home Assistant configuration files. validate_automation_or_script validates an automation or script configuration without saving it and reports, for each referenced entity, whether the token can access it. Entities outside the token's scope are reported as inaccessible without being revealed.
params
check_ha_config takes none. validate_automation_or_script: type (required; automation or script) and config (required; the configuration to validate).
compare_entitiesSearch & discovery
Compare two accessible entities before substituting one for the other. The result shows both states, missing attributes, and attributes with different values.
Option lists such as preset_modes, hvac_modes, and source_list are compared item by item. Long differences are clipped with their full totals. Oversized values, such as weather forecasts, are summarized by type and size.
If either entity is unavailable, or Home Assistant restored its state because the integration supplied none, the response carries a warnings entry naming it. An offline entity publishes few or none of its attributes, so the differences describe the outage rather than the entity.
Use this before repointing automations, scripts, or cards. Differences such as a narrower min_temp, a missing target_temp_step, or a renamed preset can break an otherwise valid replacement.
The comparison is a snapshot. For values that vary, such as an enum sensor's state, compare both entities with get_history over the same period.
params
entity_id (required; the entity you have), compare_to (required; the entity to compare it against)
compare_statesSearch & discovery
Compare up to 100 accessible entities' states between two ordered times, backed by two point-in-time Recorder reads rather than an interval scan (the tool fails when the Recorder integration is disabled).
params
entity_ids (required; one to 100 IDs), t1 (required; ISO or relative like 24h), t2 (later than t1; default now)
describe_areaSearch & discovery
One area, its floor, and accessible entities grouped by domain.
params
area (required; an area name, alias, or area_id)
describe_entitySearch & discovery
Summarize one entity, including a disabled or registry-only entry when access is inherited from its device or domain. The result includes current state when available, safe registry metadata, area, domain services, references, and the active MESA control_mode.
Registry metadata covers disabled and hidden state, labels, categories, platform, and current or original overrides. It excludes the integration's unique ID, config-entry identity, private options, and capabilities. The entity_category field identifies configuration and diagnostic entities.
params
entity_id (required)
find_available_actionsSearch & discovery
The services in an entity's domain and whether the token can invoke each one now, accounting for write access, physical and dual gates, and the entity's MESA control_mode.
params
entity_id (required)
get_automation_tracesAutomation traces
Execution traces for an accessible automation. Optional run_id and summary (highlights the error and last step).
params
automation_id (required), run_id, summary
get_overviewSearch & discovery
Return a compact home summary with accessible entity totals, counts by domain and area, unavailable count, and deployment mesa_mode. When MESA is active and the token has Config Read, the result also lists operator-defined prohibited and read-only entities.
get_relationshipsSearch & discovery
Find configurations that reference an entity before you rename, replace, or remove it. The required scope selects one entity or all accessible entities attached to a device, integration, area, or label. This lets one integration-level query replace many entity-by-entity searches.
Results are grouped by consumer, such as an automation, script, scene, dashboard, group, person, or config entry. Each result identifies the referenced entities and their roles. Dashboard results also include a card path accepted by patch_dashboard.
Phoenix combines Home Assistant's loaded reference graph with direct configuration scans. The graph adds loaded package and blueprint configurations, people, and integration-managed consumers. The direct scan preserves detailed trigger, condition, action, sequence, and member roles and can find literal references that Home Assistant's extractor does not report.
The response states what it searched. searched lists completed sources; not_searched lists unavailable, unreadable, unmodeled, or capability-skipped sources with reasons. Automation, script, scene, and legacy YAML group searches follow inline, !include, and compatible !include_dir_* layouts. Dashboard searches require Dashboard write, and config-entry searches require Integration management. Config entries matter because entity-based helpers can keep an integration in use without another recorded dependency.
dangling_references lists entity IDs that appear in a consumer but no longer exist in state or the entity registry. Each result identifies the consumer and, for dashboards, the card path. Paths are capped; path_count reports the full number when the returned list is clipped.
Phoenix filters likely false positives. It omits targets computed by templates because their runtime values are unknown. Dashboard and config-entry values must resemble an entity ID from a domain present in Home Assistant, and service-name fields are ignored except for script calls. A scope with no accessible matches returns the same not-found response as a scope with no matches.
params
scope (required): {kind, id}, where kind is entity, device, integration, area, or label. With an entity scope, the response also carries references: what that automation or script itself uses.
get_system_healthDiagnostics
Home Assistant version and per-integration system health. Secret-keyed values and URL-embedded credentials in the integration data are scrubbed before they are returned, as are network-topology details (LAN IP addresses, hostnames inside URLs, and filesystem paths) that Phoenix MCP withholds elsewhere. This is an elevated read; treat cap_diagnostics accordingly.
get_repairsDiagnostics
Active Home Assistant Repairs issues, ordered by severity and recency. Ignored issues are omitted unless requested. Each result has a token-specific reference, safe status fields, and scrubbed translation placeholders; raw issue IDs, repair data, links, credentials, private network details, filesystem paths, and out-of-scope entity IDs are not returned. Open Home Assistant Repairs to read the localized explanation or start a repair flow.
params
optional domain, severity (critical, error, or warning), include_ignored, limit (1-50)
get_esphome_overviewDiagnostics
Show the ESPHome devices in scope, including firmware version, build time, online state, Bluetooth proxy capacity, and user-defined API actions. When the ESPHome Device Builder add-on is available, the result also includes each configuration filename and update status.
A device appears only when the token can access one of its entities. Phoenix never returns MAC addresses, API encryption keys, or network addresses. Out-of-scope Device Builder configurations are reported only as a count.
Inspect auto-detected Zigbee2MQTT or ZHA networks. get_radio_network reports channel, PAN ID, coordinator, and pairing-window status. get_radio_device reports signal quality, availability, power source, and interview state. ZHA results can include scoped mesh neighbors.
For Zigbee2MQTT, device results also include bounded converter options, endpoint clusters, bindings, reporting configuration, and conflict-detection hashes. Binding targets are mapped to Home Assistant device IDs only when accessible. Direct fallback properties appear only when MQTT discovery shows that no Home Assistant entity owns them.
get_zigbee_groups returns groups anchored by accessible entities, visible members, hidden-member counts, and scoped groupable endpoints. Network keys, bridge configuration, IEEE addresses, raw group IDs, MQTT topics, and inaccessible target addresses are never returned.
params
get_radio_network and get_zigbee_groups: none; get_radio_device: device_id, optional property
List permission-scoped registry data. Areas and floors require an accessible entity. Devices are visible through an explicit device grant or an accessible attached entity.
list_devices defaults to enabled entries and accepts registry_state as enabled, disabled, or all. Rows contain safe identity, placement, state, ownership, and model details. get_device adds versions, accessible entities, visible relationships, and allowlisted owner summaries. Sensitive identifiers and config-entry data are omitted.
params
list_devices: optional registry_state. get_device: device_id (required). The area, floor, and zone list tools take no parameters.
Enumerate accessible automations, scripts, scenes, and helpers. The automation and script listings carry the id each one's read and edit tools take (get_automation / get_script), alongside the entity id, alias, and current state.
params
list_helpers accepts optional helper_type to limit results to one helper type. The other three tools take no parameters.
recent_activitySearch & discovery
Accessible entities that changed in the last N minutes, newest first.
Filter accessible entities by text, domain, area, device class, state, or staleness. registry_state defaults to enabled. Choose disabled for disabled registry entries or all to include both states and registry entries whose integration currently publishes no state. Access to a registry-only result must be inherited from its device or domain.
Multi-word searches require every word and rank the best matches first. If no exact result exists, Phoenix retries entity IDs and friendly names with typo tolerance and sets fuzzy_fallback: true. Results include non-default MESA control_mode values and an entity_category for configuration or diagnostic entities.
Diagnose how Home Assistant's default conversation agent recognizes one sentence without running the intent or changing state. A complete match returns the intent, parsed slots, and resolved entities intersected with both this token's read scope and Assist exposure. An incomplete recognition returns the closest candidate in near_misses.
Custom sentence templates and source file paths are omitted. The caller cannot select an agent, device, or satellite context.
params
sentence (required; 1-512 characters), optional language
whatifSearch & discovery
Predict which automations would fire if an accessible entity changed to a hypothetical state, without changing anything. State and numeric_state triggers are evaluated best-effort.
Read and edit ESPHome device files inside the isolated esphome/ directory. This uses a separate capability from general filesystem access because device YAML can contain C++ lambdas and inline credentials. Call get_esphome_yaml without file to list accessible files, or supply file to read one.
Credentials are masked with __PHOENIX_REDACTED__<path>__ placeholders. This includes API keys, Wi-Fi, OTA, and MQTT passwords, credential-shaped fields, and values also found in ESPHome's secrets.yaml.
Leave each placeholder in place. Phoenix restores the real value during the write without placing it in the agent request, approval record, or diff. Comments and formatting outside redacted spans remain byte-for-byte unchanged.
A credential cannot be changed to a new literal value. You may replace it with a !secret reference when that key appears in defined_secrets. No tool can read or write ESPHome's secrets.yaml.
This restriction also protects connectivity. An API encryption key must match the value stored by Home Assistant, and the OTA password controls the next upload. Changing either blindly can make the device unreachable without a wired reflash.
Writing never flashes anything. The file lands on disk and the device keeps running its current firmware until a build is installed, which is a separate tool behind a separate capability. content_hash is taken over the real file, so expected_hash still guards against a change during an approval window, and every write is versioned for rollback in the Changes tab.
Generating a new credential. Use !phoenix_generate for a missing API encryption key or OTA password. Phoenix replaces the tag with a cryptographically random value during the write. The generated value exists only on disk and remains masked in later reads, approvals, and diffs.
Read the generated value from the ESPHome dashboard when Home Assistant requests it. Phoenix refuses the tag for an existing credential because an uncoordinated rotation can disconnect the device. It also refuses the tag for Wi-Fi SSIDs and passwords.
params
get_esphome_yaml: file (omit to list); set_esphome_yaml: file, content, expected_hash
These four read-only tools use the ESPHome Device Builder add-on. They are hidden when the add-on is not installed. If it is installed but stopped, calls return an unavailable error. Phoenix sends only an allowlisted set of commands to the add-on.
validate_esphome_yaml checks one file already stored on disk without compiling or flashing it. It does not accept arbitrary YAML because ESPHome validation can fetch and execute external_components. Validation output may quote source lines, so Phoenix scrubs known credentials before returning it.
get_esphome_board searches boards or returns hardware details, pin availability, current pin use, and warnings. get_esphome_component searches components, lists categories, or returns configuration schemas. get_esphome_automations lists triggers, actions, and conditions for the components loaded by one device.
File-bound lookups use the same jail and entity scope as get_esphome_yaml. Missing and inaccessible files return the same response. Automation results keep every catalog entry but omit verbose prose, editor flags, and duplicate display labels to limit response size.
Compile an ESPHome configuration or install it on the device. Validation catches schema and pin errors; a real build also catches C++ and lambda compilation errors.
Building and flashing use separate capabilities. Compiling uses ESPHome device YAML because it creates a binary without touching the device. Installing uses ESPHome firmware flashing. That capability is denied in every default persona except ESPHome devices, where it requires confirmation.
Compile and install calls enqueue Device Builder jobs and immediately return a job_id. Use get_esphome_job to poll them. Job state belongs to the add-on and survives an add-on restart.
An install runs a compile followed by an upload. get_esphome_job reports flashed: true only after the upload completes. If an offline device is configured to update on its next wake, the result reports that pending state instead of success. Phoenix installs over the air and ignores caller-supplied ports.
wait_for_esphome_job waits up to five minutes and returns when the job finishes. It follows both compile and upload stages for an install and emits progress such as Compiling living-room: 70%. Agent Chat shows these updates live. External clients receive them only when they request and render MCP progress notifications.
Phoenix refuses a second build for a file that is already building and returns the active job instead. Job IDs remain scoped to accessible files; missing and inaccessible jobs return the same response. Build logs are bounded and scrubbed of known credentials.
params
compile_esphome_firmware, install_esphome_firmware: file (required). get_esphome_job: lookup (required; {kind: job|file, id}) for a job ID or a file's newest job. cancel_esphome_job: job_id (required). wait_for_esphome_job: job_id (required), timeout.
Remove an unused configuration, clear broken build artifacts, or rename a device without opening the ESPHome panel.
Deleting a configuration.delete_esphome_yaml records the file in version history before removing it, so the Changes tab can restore it. Deleting the file does not alter the device, remove its Home Assistant entities, or unadopt it. The device continues running its current firmware.
Cleaning build files.clean_esphome_build removes cached build artifacts without changing YAML or contacting the device, so it needs no approval. It also clears the shared PlatformIO cache, which slows the next build for every device. It refuses while a build is running and points to cancel_esphome_job. Fleet-wide cleanup is not exposed.
Renaming a device. A rename compiles and flashes firmware, so it requires ESPHome firmware flashing. Entities, entity IDs, areas, history, and MESA profiles keep working because Home Assistant identifies the hardware by MAC address.
User-defined action names do change. For example, esphome.old_name_action becomes esphome.new_name_action; the approval lists affected actions. The device must be reachable. If compilation or flashing fails, Phoenix removes the new copy and leaves the original configuration in place.
get_esphome_device_logs captures the device's live console for 15 seconds by default or up to 60 seconds. The console contains more detail than Home Assistant receives. Because the stream does not end by itself, the requested window defines the capture. An empty result means the device produced no log entries.
decode_esphome_backtrace turns the hex panic dump an ESP32 prints when it crashes into a real stack trace with function names and source lines, resolved against that device's last build. It reports stale_build when the firmware has moved on since, so a trace is never silently read against the wrong binary. Both are reads needing only read access to the device, and both are scrubbed.
Read or replace configuration.yaml and the YAML files it loads. Writes are Confirm-eligible. get_yaml_config reads the main file by default; optional file selects another .yaml or .yml file in the configuration directory.
Phoenix refuses secrets.yaml, esphome/, hidden directories such as .storage, and symlinks that resolve into them. Use get_esphome_yaml for device files. Optional key returns one dotted mapping key and preserves YAML tags.
Reads return file content verbatim. Inline secrets therefore enter the agent's context. Grant Raw YAML edit only to trusted clients, and prefer !secret references over inline values.
Writing included files.set_yaml_config uses the same file parameter, so files such as templates.yaml and sensors.yaml can be edited directly. The file must be loaded by configuration.yaml at an ordinary integration key.
Phoenix refuses packages and files loaded under protected homeassistant:, http:, frontend:, or lovelace: keys. An included file inherits the rules of the key that loads it. Unreferenced files are also refused. If the main configuration cannot be read, no included file can be written.
Concurrency guard. The read returns a whole-file content_hash, and set_yaml_config accepts optional expected_hash. If the file changes before execution, Phoenix refuses the write and asks you to read and reapply it. Omitting the hash skips this check.
Protected keys cannot be changed. Phoenix blocks changes to homeassistant: auth_providers, auth_mfa_modules, and packages; http: trusted_proxies, use_x_forwarded_for, cors_allowed_origins, ip_ban_enabled, and login_attempts_threshold; frontend: extra_module_url; and lovelace: resources. Sending these keys back unchanged is allowed.
New content must parse as YAML, but parsing is not full Home Assistant validation. Run check_ha_config before restarting to catch valid YAML that contains invalid configuration.
Declare removals. When replacing a mapping, list removed top-level keys in remove_keys. When replacing a top-level list, set remove_entries to the number of entries removed. Use patch_yaml_config when replacing one list entry with another, because a whole-list comparison can detect only the net count.
This guard prevents accidental omissions such as dropping automation: !include automations.yaml. Missing or currently invalid files remain repairable without a removal declaration, and restores from the Changes tab are exempt. Protected-key checks still apply. The approval summary reports the keys actually removed.
patch_yaml_configRaw YAML edit
Change one key or list entry without resending the file. The tool is Confirm-eligible and follows the same file restrictions as set_yaml_config. Required address selects either a dotted mapping key, such as recorder.include, or a mixed key/index path.
Required change.kind is set, append, or remove. Set and append carry YAML in content. Phoenix adjusts indentation to the address depth.
Only the addressed section is rewritten. Unrelated comments, blank lines, key order, and quoting remain unchanged. Approval shows the addressed section's before and after values. Removing a key also removes a comment directly above it, but not one separated by a blank line.
Address the narrowest useful key. Content returned for a key uses standard YAML formatting and omits comments inside that value. For example, rewriting recorder can reformat the block, while patching recorder.include changes only that subsection.
Addressing lists. Use {kind: "path", value: [...]} with 0-based indexes. For example, [0, "binary_sensor", 0, "state"] reaches one template state. Use append on a list or set on an existing index. set also accepts the first index after the list; larger and negative indexes are refused.
Parent mappings and lists must already exist. Phoenix cannot patch inside a one-line {...} mapping or address a key whose name contains a dot; edit the parent instead. Before writing, Phoenix parses the result and verifies that it matches the requested change.
The trust-boundary keys set_yaml_config refuses cannot be changed here either, and the deletion rule applies with change.kind: remove and the address standing as the declaration. Version history records the whole file on both sides, so a patch restores from the Changes tab exactly like a whole-file write.
params
address (required; the YAML key or path), change (required; a typed set, append, or remove object), and optional file and expected_hash from a prior get_yaml_config. The result returns the file's new content_hash, so several patches can be chained without re-reading. Run check_ha_config and restart Home Assistant afterwards to apply.
list_backupscreate_backupBackup
List and create backups. Restore is intentionally never exposed. Confirm-eligible. list_backups reports total, returned and a truncated flag, so a clipped page is distinguishable from the whole list.
params
list_backups: optional limit (1-200, default 20). create_backup: optional name and agent_ids; choose agent IDs from list_backups' available_agents.
list_filesread_filewrite_fileFilesystem access
Read and write files under www/, themes/, and custom_templates/. Writes are Confirm-eligible. read_file returns a content_hash, and write_file accepts optional expected_hash.
A hash mismatch refuses the write. A missing file uses an empty-string fingerprint, so read-then-create is protected too.
params
path (required for read/write; relative to the allowed directories), content (required for write), expected_hash (write, optional)
list_integrations returns config entries visible through an accessible owned entity or device. Pass-through tokens may also see entries with no resources. Each result includes safe metadata, normalized state, accessible entity and device counts, preferences, and probed support for reload, unload, options, and reconfiguration. An inconclusive support probe is null.
The result never includes private config-entry data, options, credentials, URLs, network identity, or unique and discovery identifiers. Setup failures are scrubbed. Phoenix MCP's own entry is always excluded.
The write tools require cap_integration_write, WRITE on every owned entity, and an explicit WRITE grant on every owned device. Scoped entries with no resources fail closed. set_integration changes the title or safe preferences. Only a polling-preference change reloads a loaded entry.
set_integration_enabled changes user-controlled enabled state and verifies registry-only access before disabling. reload_integration refuses disabled, non-recoverable, and unsupported entries. Results distinguish a successful reload from a change that requires a Home Assistant restart.
No-op metadata and enabled-state requests create no approval or version. A reload also creates no version.
Rename, reload, enable, disable, and removal use every owned entity's inherited MESA profile. Entity, device, area, integration, and domain restrictions all apply. One denial blocks the whole entry; enforced confirmation joins the capability approval.
Before execution, Phoenix rechecks entry state, entity and device membership, permissions, and resolved MESA results. Metadata and enabled-state versions can be restored from Changes.
remove_integration calls only Home Assistant's integration-aware config-entry removal, then reports observed entity/device cleanup, shared owners, anomalies, and restart need. Its approval preview includes consumers, permission references, global hints, MESA profiles, and pending Phoenix identities. Removal versions contain safe metadata only and cannot be restored; Phoenix never manually deletes registry rows or profiles.
params
set_integration: entry_id plus at least one of title, pref_disable_new_entities, or pref_disable_polling; set_integration_enabled: entry_id and boolean enabled; reload_integration and remove_integration: entry_id
Submit new settings to an existing integration through Home Assistant's official reconfigure flow. Use list_integrations to find the exact entry_id, then provide a flat config object and, when needed, ordered menu_choices. Phoenix supports bounded form and menu steps, repeated fields, integration-provided defaults, and confirmation-only forms. It does not use generic setup, options, or reauthentication flows.
Review-only is not Home Assistant's form
Phoenix shows the agent-provided values for approval; the operator cannot edit them there, and the integration has not validated them yet. Credential-shaped values are redacted, while non-secret hosts and URLs stay visible for endpoint review. Browser, OAuth, and asynchronous progress steps are unsupported. Phoenix cannot automatically roll the change back.
What approval protects. Reconfiguration has its own cap_integration_reconfigure capability because it may replace credentials or endpoints. It requires WRITE on every owned entity and device. Phoenix also evaluates config_entry.reconfigure through inherited MESA.
Approval pins private entry identity, modification time, registry membership, device identity, ownership, and MESA results. Phoenix blocks same-domain shared ownership and warns about cross-domain co-owners. No Home Assistant flow starts before approval or an Allow grant.
Validation and outcomes. After approval, Phoenix matches each form against the supplied fields. It reports missing values, validation errors, bad menu choices, unsupported steps, and exhausted step limits. A value-free schema is included when available.
Ordinary success requires Home Assistant to return ABORT with reason reconfigure_successful. Phoenix attributes reload transitions to the accepted change's modified_at boundary, then checks terminal state and private identity.
The result status is flow_aborted_before_apply, apply_failed, or one of four applied_* states: applied_and_verified, applied_but_unverified, applied_but_incomplete, and applied_identity_mismatch. Do not automatically retry an applied_* result because the first attempt may have changed credentials or an endpoint. Inspect the integration in Home Assistant and use its native UI for recovery.
Start in the Home Assistant frontend when you must discover fields, edit values during review, complete OAuth, or wait for progress. Use it also for setup, options, and reauthentication flows.
Successful or possibly applied changes create a redacted, non-restorable Changes record. It lists submitted field names and masks credential-shaped values, but stores no raw current or previous config-entry data. The record is evidence, not a rollback snapshot.
params
entry_id (required), config (required object; may be empty for a confirmation-only flow), and optional menu_choices (up to 10 strings, consumed in encounter order)
set_entitydelete_entityRegistry write
Edit an entity's user-controlled registry metadata or delete a stale or duplicate entry. Editable fields include friendly name, icon, area, device class, enabled and hidden state, labels, categories, aliases, and a same-domain entity ID. A live entity requires direct write access. A registry-only entity requires inherited write access from its device or domain.
These writes require cap_registry_write, are Confirm-eligible, and create versions. Disabling is refused if it would remove the caller's only write grant. Phoenix does not overwrite integration-controlled or system-controlled state. A deleted entry cannot be recreated through Phoenix MCP.
Rename and delete are additionally governed by the entity's fully inherited MESA profile, including device and domain profiles. read_only always refuses; prohibited refuses when MESA is enforced and warns in advisory mode; enforced confirm joins the ordinary registry approval instead of creating a second approval. The approval is valid only for the MESA profile that was reviewed, and permissions and MESA are checked again immediately before execution.
An entity-ID rename does not rewrite consumers. Its approval preview scans known automations, scripts, scenes, legacy groups, dashboards, config entries, and Phoenix configuration. Rename is refused while the old ID is used by an active token or preset permission, a global hint, an entity-level MESA profile, or another pending Phoenix action. Device and domain MESA profiles are inherited safety rules, not rename blockers.
Pass null for name, icon, area_id, or device_class to clear that user override. Labels use add/remove operations. categories is a patch keyed by category scope: provide an existing category ID to assign it or null to remove that scope.
Aliases are spoken names that Assist uses to match an entity. For example, add "lounge lamp" when the entity is named "Kitchen Light" but that is the phrase you use.
Use add_aliases and remove_aliases; do not send a replacement list. These operations preserve Home Assistant's marker for the entity's current name, even after a rename. They also prevent an empty alias list from removing the entity from voice control.
Alias matching is case-insensitive. Adding an existing alias or removing a missing one succeeds with no change. The result and describe_entity both show the names the entity currently answers to.
params
set_entity: entity_id and a non-empty changes object containing at least one of name / icon / area_id / device_class / enabled / hidden / add_aliases / remove_aliases / add_labels / remove_labels / categories / new_entity_id; delete_entity: entity_id
set_deviceRegistry write
Edit a device's reversible user metadata: display-name override, area, enabled state, and labels. This requires cap_registry_write plus an explicit device WRITE grant; child-entity or domain inheritance cannot authorize a whole-device write. Pass null to clear name or area. Only user-disabled devices can be toggled, and an owner-disabled config entry prevents enablement.
Name, area, and enabled-state changes require every attached registry entity to remain writable; a more-specific entity RED/YELLOW restriction blocks the whole operation. Label-only edits do not change child authorization. Disabling previews every affected entity and its known consumers, while enabling reports whether an integration reload or restart may be needed. Changes are versioned and restorable.
Name changes and enable/disable evaluate device_registry.rename, device_registry.enable, or device_registry.disable across every attached entity's fully inherited MESA profile. Any denial blocks the whole device; enforced confirmation merges into the ordinary registry approval, whose fingerprint pins both entity membership and every resolved profile. Area and labels have no MESA gate. Entity-less devices fail closed for those MESA actions while MESA is active.
params
device_id (required) and changes (required; non-empty object containing one or more of name, area_id, enabled, add_labels, or remove_labels)
remove_deviceIntegration write
Ask one owning integration to remove a device through Home Assistant's integration-aware removal hook. This requires cap_integration_write plus an explicit device WRITE grant. Phoenix never deletes the raw device-registry row. The owner is inferred only when exactly one exists; pass config_entry_id for a multi-owner device. Unsupported integrations and Phoenix MCP's own entry are refused before approval, and an integration may reject the request without changing the registry.
The approval preview identifies the selected owner's affected entities and their known consumers, child devices that could lose their parent if the device disappears, remaining owners, device permission references, and device-level MESA configuration. device_registry.remove is evaluated across exactly those affected entities using normal MESA inheritance. Capability, permission, ownership, membership, support, and MESA are recomputed immediately before execution.
After the hook accepts, Phoenix removes only the selected config-entry ownership if the integration did not already do so. The result says whether the entire device disappeared and lists any remaining owners. Removal is captured as a non-restorable delete version.
params
device_id (required), optional config_entry_id when exactly one owner cannot be inferred
Manage a ZHA or Zigbee2MQTT network. Open or close pairing, re-interview a device, or remove one. set_zigbee_binding binds or unbinds two scoped devices on the same network. It requires Physical control and inherited MESA approval.
ZHA selects compatible bindings internally. Zigbee2MQTT requires explicit endpoints, compatible clusters, and current configuration hashes. Unbinding preserves existing reporting configuration.
The group tools create a non-empty group, change exact membership, or remove a fully scoped group. They use Home Assistant registry IDs and require the latest group hash when changing an existing group. Physical control and inherited MESA approval apply to every affected member.
For Zigbee2MQTT, configure_zigbee_reporting changes one input-cluster attribute rule with the latest configuration hash. set_zigbee_device_options accepts only converter-declared options and checks each value. It reports a required restart without performing one.
set_zigbee_device_property changes one direct-fallback property with exact state confirmation. It requires Physical control and inherited MESA approval. Device writes require access to at least one entity on that device. The coordinator cannot be targeted.
params
permit_zigbee_join: duration (0-254, default 60), optional device_id (router) and backend; set_zigbee_binding: operation, source_device_id, target_device_id, plus Zigbee2MQTT source_endpoint, target_endpoint, clusters, expected_source_hash, and expected_target_hash; configure_zigbee_reporting: device_id, endpoint, cluster, attribute, minimum_report_interval, maximum_report_interval, optional reportable_change, and expected_hash; set_zigbee_device_options: device_id, partial options, and expected_hash; set_zigbee_device_property: device_id, property, value, and expected_hash from the latest property read; create_zigbee_group: name and non-empty members (device_id, endpoint); set_zigbee_group_members: group_entity_id, add/remove operation, members, and expected_hash; remove_zigbee_group: group_entity_id and expected_hash; reconfigure/remove device: device_id
scan_zigbee_topologyDiagnostics + Radio management
Actively query one ZHA or Zigbee2MQTT mesh and return its registry-scoped neighbor map. Nodes are accessible Home Assistant device IDs plus one opaque coordinator; links include direction, LQI, and an allowlisted relationship. IEEE and network addresses, friendly names, raw group IDs, routes, inaccessible nodes, and hidden-node counts never appear. partial reports only that some topology was omitted, without revealing how much.
The scan may make the mesh less responsive for roughly 10 seconds to 2 minutes, so it requires both Diagnostics and Radio management and is Confirm-eligible. ZHA queries only visible routers. Zigbee2MQTT's backend request necessarily scans the whole mesh, but Phoenix scopes the response before returning it and explicitly disables route-table output.
params
optional backend (z2m or zha); required when both are present
restart_haHA restart / stop
Restart Home Assistant. Pass-through-exempt: even pass-through tokens must have this flag enabled.
MESA profiles
Token-scoped reads of the per-entity safety profiles, plus the advisory lease pair. All require Config read, only ever see entities the token can read, and return an identical "not found" for a missing or out-of-scope entity, so they cannot probe for existence. See MESA.
mesa_explain_profileConfig read
Field-by-field explanation of why an accessible entity resolved the way it did, including any conflicts between levels.
params
entity_id (required), show_conflicts
mesa_get_caller_contextConfig read
The MESA context for the current caller.
mesa_get_profileConfig read
Return the stored and effective profile for one accessible entity. With include_semantic_moments: true, the result also lists its purpose-specific triggers and conditions on Home Assistant 2026.7 or newer. This live data is informational and is omitted on older versions.
Phoenix checks declared invalidation conditions against the current deployment. A changed dependency, integration version, or Home Assistant version produces staleness_status: stale and a warning that names the change.
List the profiles in scope, with array filters for domains, tags, areas, devices, integrations, and intents. tags_match selects any-tag or all-tags matching. Tag and intent filters use the effective resolved profile. Counts and cursors are relative to the token's scope.
params
domains, tags, tags_match (any or all, default any), areas, devices, integrations, intents, min_origin_authority (inferred_ai, hybrid, user, or developer), include_inferred (default false), include_fields, limit (1-200, default 50), cursor
mesa_request_leaseConfig read
Announce a short operation on specific entities (up to 30 seconds) so MESA-aware components can coordinate. A lease is advice, not a lock, and grants no authority: every action stays gated by scope, capabilities, and MESA. Covers only entities the token could already control; entities under protected or critical automation control are denied. Lease endings fire an phoenix_mcp_mesa_lease_expired event.
params
entities (required; list of entity ids), duration_seconds (required; max 30), intent, priority_level (deferential, cooperative, assertive), caller_priority, preemption_handling (rollback_abort or continue_ignore)
mesa_release_leaseConfig read
Release a lease early when the work finishes ahead of its expiry. A token can only release its own leases.
params
lease_id (required)
Native control tools
These match the native Home Assistant MCP tools, including the domain-prefixed names introduced in Home Assistant 2026.9, parameters, and action_done responses. Phoenix advertises only the canonical prefixed names. Older unprefixed names remain callable for compatibility but are not listed. Targets resolve to explicit entities and are then filtered to WRITE access. area, floor, and name are strings; domain and device_class are string arrays. Every target-based action schema explains its expected shape and requires at least one caller-supplied target. No match returns "No accessible entities matched your request." without revealing why.
assist_satellite__HassBroadcastBroadcast
Send an announcement through Assist satellite devices. Satellites are subject to MESA like any other entity, so one marked read-only or prohibited is skipped.
params
message (string, required)
intent__HassCancelAllTimerstree-scoped
Cancel all running timers in an area (or everywhere if area is omitted). Always returns speech_slots: { "canceled": N }, even when N is 0. N counts the timers actually cancelled: a timer MESA holds back is not included, so the number always matches what happened.
climate__HassClimateSetTemperaturetree-scoped
Set a climate device's target temperature.
params
temperature (required), plus at least one of area, floor, or name
fan__HassFanSetSpeedtree-scoped
Set fan speed by percentage.
params
percentage (0-100, required), plus at least one of area, floor, name, or domain (fixed to ["fan"])
light__HassLightSettree-scoped
Set brightness, color, or color temperature of accessible lights.
params
At least one target from area, floor, name, or domain (string array), plus at least one change from brightness (0-100), color, or temperature (kelvin)
Set or adjust media player volume. media_player__HassSetVolume takes volume_level (0-100); media_player__HassSetVolumeRelative takes volume_step ("up", "down", or a signed percentage).
params
The volume value is required. media_player__HassSetVolume requires at least one of area, floor, name, domain (fixed to ["media_player"]), or device_class. media_player__HassSetVolumeRelative requires at least one of area, floor, or name.
Start a vacuum, or send it back to its dock. Targeted by name, area, or floor; only vacuums that report supporting the operation are targeted, so a vacuum that cannot dock is left out rather than asked and failing.
params
At least one of name, area, floor, or domain (fixed to ["vacuum"])
vacuum__HassVacuumCleanAreatree-scoped
Send a vacuum to clean a named area. area is required and names the cleaning target; it does not select the vacuum. Optional name selects one vacuum. Without it, Phoenix uses every accessible vacuum that supports named-area cleaning. An unknown area returns the same response as no accessible match.
intent__HassStopMovingPhysical control
Stop a moving cover or similar device.
params
At least one of name, area, floor, domain, or device_class
intent__HassTurnOnintent__HassTurnOfftree-scoped
Turn entities on or off by area, name, floor, or domain.
params
At least one of area, floor, name (strings), domain, or device_class (string arrays)
Query & entity access
get_historytree-scoped
Bounded chronological Recorder history for one entity. state_changes is the default and supports arbitrary ranges using Home Assistant's database-limited transition query without attributes. significant_states returns scrubbed full state records that Home Assistant considers significant, not every sample, and refuses ranges over 7 days because its upstream query has no database limit. The default range is 24 hours.
params
entity_id (required), start_time (default 24 hours before the end), end_time (default now), mode (state_changes or significant_states), limit (default 100, max 1000), cursor (the previous next_cursor)
returns
requested, covered, and data ranges; count and effective limit; retention and warnings; and has_more/next_cursor pagination with no estimated total
get_statetree-scoped
Current state of a single entity. The required projection object selects compact key attributes, the full state, or exact fields. Requires READ or WRITE on the entity. Sensitive attributes are always scrubbed.
with compact, entity_id, state, and key attributes; full returns the full state.
get_statestree-scoped
All entity states the token can read. The required projection object uses the same compact, full, or exact fields form as get_state. Pass-through tokens receive every non-Phoenix entity.
Retrieve a still image from one accessible camera.* entity named by entity_id, which is required. Requires the dedicated camera-image capability and READ or WRITE permission for the entity. Returns standard MCP image content for multimodal clients and never exposes a stream URL.
params
entity_id (required), optional width and height (1-2048 pixels)
get_statisticstree-scoped
Bounded Recorder statistics for numeric entities, aligned to Home Assistant's local calendar. 5minute uses short-term retention; hour, day, week, month, and year use long-term statistics. Only entities that produce Recorder statistics have data; a merely numeric state is not enough. The default range is 30 days. The year period requires Home Assistant 2026.3 or newer.
params
entity_id (required), start_time (default 30 days before the end), end_time (default now), period (5minute, hour the default, day, week, month, year), statistic_types (subset of mean, min, max, sum, state, change, last_reset), limit (default 100, max 1000), cursor (the previous next_cursor)
returns
the common range, retention, warning, and cursor envelope plus a statistics page; safe period caps are reported as effective_limit
get_calendar_eventstree-scoped
Events from an accessible calendar.* entity within a time window (defaults to the next 7 days). Requires READ access to the calendar entity.
Current date, time, and timezone. Always available, no permission required.
homeassistant__GetLiveContexttree-scoped
YAML snapshot of accessible entity states, optimized for LLM context. Filtered by the token's permissions; pass-through tokens get the same output as the native server.
Realtime subscriptions
watch_entityConfig read
Bounded blocking subscription (max 30 seconds) that waits for an accessible entity to change state, then returns it.
params
entity_id (required), timeout (seconds, max 30)
Scenes, helpers & dashboards
create_helperedit_helperdelete_helperHelper write
Create, edit, or delete storage-backed helpers, including input_*, input_button, counters, timers, schedules, zones, tags, and people. Writes are Confirm-eligible. Phoenix evaluates inherited MESA before approval and again before execution. A newly created helper is rolled back if its materialized entity inherits stricter rules than the approved proposal.
Creating a zone, tag, or person requires write access to the entire entity domain. Later edits and deletes require write access to the specific entity. Core zones, YAML-backed zones, and YAML-defined people cannot be changed with these tools.
A person accepts name and device_trackers. Every current and proposed tracker must be writable. Phoenix reports whether the person is linked to a Home Assistant user, but never returns or accepts the user ID or picture. Name-only edits preserve existing links. Restoring an existing person preserves private bindings; recreating a deleted person restores only its name and tracker links.
Tag creation requires tag_id and accepts optional name and description. Edits cannot change scanner metadata or the last-scanned time. Deleting a tag removes its metadata and entity, but scanning the same NFC or QR identifier can cause Home Assistant to discover it again. Schedules accept non-overlapping from/to ranges for each weekday, with optional custom data.
Home Assistant saves new helpers after a short storage debounce. A graceful restart flushes the pending write; a crash or abrupt restart within a few seconds may lose it. The Changes tab can restore a lost helper because Phoenix records the version immediately.
create_helper also supports config-flow helper integrations such as mold_indicator and history_stats. Send flow_steps: [] to read the first form, then resend the accumulated {step_id, data} steps. Unfinished flows create nothing. The final step is approval-gated, and every referenced entity must be writable. OTP helpers are excluded because they require a live confirmation code.
params
helper_type (required); config for storage create/edit; flow_steps for config-flow create; helper_id for storage edit/delete
Read and change helpers built on other entities, such as threshold, derivative, switch_as_x, min_max, utility meter, and attribute sensor. Home Assistant stores these helpers as config entries, not in the storage collection used by the helper CRUD tools. Writes are Confirm-eligible.
Before a write, Phoenix resolves inherited MESA for every entity owned by the helper. Approval records that result, and execution rechecks both membership and profiles. Phoenix supports the helper's options or reconfigure flow; mechanism identifies which one is used.
Use these tools to finish a migration. A helper can remain after its source entity is removed, but it stops producing values. get_relationships lists the helper as a config_entry consumer. Use this pair to point it to a replacement entity.
The read returns the current options, a content_hash, and the schema: which fields the helper accepts, their types and defaults, and for an entity field the domains it allows. That is the same description Home Assistant's own UI works from.
Send editable_settings, not settings. Stored settings and editable form fields can differ. For example, an attribute sensor may store its source entity and original name even when its options flow exposes neither.
Phoenix merges your input over stored values. Omitting a non-editable setting preserves it, while sending one is refused. Omitting an optional editable field clears it. A field present in schema but absent from editable_settings has no current value.
If Phoenix cannot describe the form, it reports that limitation instead of returning an empty list. This distinction prevents an empty write from clearing every optional setting.
Only helper config entries are accepted. Every referenced entity must be writable because a helper may expose or control it. Other integrations can contain credentials or network endpoints that entity scope cannot protect, so they are refused. Missing and non-helper entries return the same response.
Helpers with multi-step options flows must be changed in the Home Assistant UI. Phoenix returns that reason instead of starting the flow.
params
entry_id (required for both), settings (required for the write), and optional expected_hash from the read. Every change is recorded in Changes and can be rolled back, which re-runs the helper's own options flow with the snapshot. The helper reloads with the new settings; no restart.
Read, create, edit, or delete scenes. Writes are Confirm-eligible; reads are not. Phoenix follows !include and !include_dir_* references to the correct leaf file.
get_scene returns the name, entity map, and a content_hash for optional expected_hash checking. An edit replaces the entire scene, so read it first and resend every member. A missing scene and one containing an unwritable entity return the same response.
params
scene_id (required except for create), config (required for create/edit), expected_hash (edit, optional)
List and manage Lovelace dashboards, or read and replace a stored view and card layout. get_dashboard_config masks out-of-scope entities with <redacted>. set_dashboard_config is Confirm-eligible, writes storage-mode dashboards, and creates a version.
Phoenix refuses a full layout containing a redaction placeholder because writing it would destroy the hidden reference. Use patch_dashboard for one value, or a card tool when its payload contains no placeholders.
The read returns a content_hash; the write accepts optional expected_hash. Phoenix checks the hash again after approval. Auto-generated dashboards have no stored layout, so any expected hash conflicts.
set_dashboard_config warns about uninstalled custom: cards but does not block them. A saved layout is display configuration, not automatic execution. Card actions run under the viewing user's session, so layouts may reference entities outside the token's scope. See indirect control risk.
params
create_dashboard/edit_dashboard: config (required; title etc.) plus dashboard_id (required for edit); delete_dashboard: dashboard_id (required); the config read/write pair: url_path (omit for the default dashboard), config (required for set), expected_hash (optional)
list_dashboard_cardsDashboard write
List custom cards installed through HACS or integrations. Each entry includes the card's name, short description, and published documentation URL. Request details to include an example from the card's getStubConfig. The tool is read-only and never approval-gated.
Custom cards do not publish a standard configuration schema, and an uninstalled type is saved but renders as an error. Use the returned example as the starting point for a card configuration.
The Phoenix MCP panel builds this catalog in a browser from window.customCards. It cannot reliably discover those runtime names from files. Until a browser opens the panel, the catalog reports un-harvested: installed cards are unknown, not absent.
params
type (optional; one card type, with or without the custom: prefix, returned in full with its example config), detailed (optional; include every card's example config, verbose on an instance with many plugins)
Add, replace, or remove one card by index without resending the dashboard. Sections views also require a section index. These writes are Confirm-eligible and versioned.
The dashboard must already have a stored layout. Create one with set_dashboard_config first. Strategy views, strategy dashboards, and auto-generated dashboards are refused.
Phoenix validates the operation before approval and again before applying it. A layout change during approval therefore fails instead of editing the wrong index. An unknown or unloaded custom: card adds an advisory warnings entry but does not block the write.
Use these tools for single-card changes. They avoid resending a large layout and reduce the chance of exceeding a model's output limit.
params
url_path (omit for the default dashboard), view_index, section_index (required when the target view uses sections, rejected otherwise), card (the card object, for add/edit), position (add; omit to append) or card_index (edit/delete), and optional expected_hash from a prior read, strongly recommended since card indexes shift when the layout changes. Unlike the whole-layout writers, each result returns the layout's new content_hash, so several card operations can be chained without re-reading.
patch_dashboardDashboard write
Change one dashboard value by path without resending the layout. Required target contains url_path and a key/index path. For example, ["views", 0, "badges", 4, "entity"] selects one badge entity.
Required change.kind is set, append, or remove. Set and append include a value. Parent structures must exist, and indexes cannot be negative. The write is Confirm-eligible, versioned, and validated before approval and execution.
Phoenix refuses any value containing <redacted>. That placeholder represents an entity ID the token cannot resolve, including IDs that no longer exist. Writing it would permanently replace the stored reference. Use a narrow patch when a full dashboard cannot safely round-trip.
params
target (required; {url_path?, path}) and change (required; {kind: set|append|remove, value?}), plus optional expected_hash from a prior read. The result returns the layout's new content_hash, so several patches can be chained without re-reading.
Service execution
call_servicetree-scoped
Call any Home Assistant service. Put its domain, name, and optional data in the required service object. Put resource selectors in optional targets.
Phoenix expands device and area targets to explicit entities, then silently drops denied entities. If all resolved entities are denied, it returns the generic Forbidden result without calling Home Assistant. Bulk expansion also skips configuration, diagnostic, and hidden entities. Direct entity targets are not filtered by those categories.
Phoenix strips primary target keys from service.data and refuses service-specific secondary selectors such as media_player_entity_id or group_members, because only the resolved target list is permission-checked and MESA-evaluated. Response data is scanned and inaccessible entity IDs are replaced with <redacted>. Physical-control and restart services need their capabilities. The core config-reload family is gated on cap_yaml_edit and is Confirm-eligible.
params
service (required): service.domain and service.name are required strings; service.data is optional. targets is an optional array of {kind, ids} objects. kind is entity, device, area, or all; ids is required and non-empty except for all.
dry_run_serviceSearch & discovery
Preview a service call without running it. Resolves and flattens targets, reports the MESA verdict per entity, and returns a single predicted_outcome of allowed, pending_approval, or denied, folding the capability gate and MESA together. It uses the same structured service and targets parameters as call_service.
params
service (required): required service.domain and service.name, plus optional service.data. Optional targets entries use kindentity, device, area, or all, with non-empty ids except for all.
Token introspection
Each token can always inspect its own state. No capability required, and you only ever see your own data.
get_approval_statusno capability
Check a Confirm-gated action you submitted. With an approval_id, returns its status and result; without one, lists all of this token's pending approvals, useful after a reconnect.
wait_for_approvalno capability
Block until your pending approvals resolve, instead of polling. Returns immediately if already resolved, otherwise waits server-side (up to a capped timeout) for a human to approve or reject, then returns the status and result; on timeout it returns still-pending so you can call again.
Pass several approval_ids after queuing a group of Confirm-gated writes. The operator can resolve them in any order, while the agent waits once for the entire set.
The result lists every status and any IDs still pending. In a batch, each result is reduced to an error flag and clipped text so the response stays bounded. Use get_approval_status with one approval_id to retrieve its full result.
params
approval_ids (required; a non-empty array), timeout (seconds)
get_audit_summaryno capability
This token's own recent audit entries (request_id, time, method, resource, outcome), newest first, with an optional outcome filter.
params
outcome (optional), limit (1-200, default 50)
get_capability_summaryno capability
This token's persona, effective capabilities, Confirm-gated capabilities, write scope, rate limits, and a tool-level gate map (tools.usable / tools.needs_approval / tools.unavailable). A capability set to Confirm does not put every tool that uses it into needs_approval: the reads on that capability, such as get_automation or get_dashboard_config, run directly and are listed as usable. Only the tools that actually write queue for approval.
Runtime and reconnect rules
Vetted commands: helper, dashboard, and backup tools dispatch a fixed, validated set of Home Assistant commands in-process. They hold no long-lived token, open no socket, and never expose backup restore.
Reconnect after the visible tool set changes: reconnect after changing a capability between deny and allow/confirm, write scope, or announce_all_tools. Changing only allow to confirm, or back, takes effect on the next call.
Enforcement is immediate: Phoenix always uses current settings and sends a one-time stale-tool-list notice after a capability, permission, or preset change.