Skip to main content
Glama
homeassistant-ai

Home Assistant MCP Server

Official

Server Configuration

Describes the environment variables required to run the server.

NameRequiredDescriptionDefault
HOMEASSISTANT_URLYesThe URL of your Home Assistant instance
HOMEASSISTANT_TOKENYesA long-lived access token for Home Assistant

Instructions

Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.

This server publishes no instructions, or was last inspected before Glama recorded them.

Capabilities

Features and capabilities supported by this server

Protocol revision2025-11-25

CapabilityDetails
tools
{
  "listChanged": true
}
logging
{}
prompts
{
  "listChanged": false
}
resources
{
  "subscribe": false,
  "listChanged": false
}

Tools

Functions exposed to the LLM to take actions

NameDescription
ha_get_appA

Get installed or available Home Assistant apps (add-ons), or details for one.

Do not use this tool to change app state or configuration; use ha_manage_app. Use slug for details, source="installed" for an inventory, or source="available" for store discovery.

Requires Home Assistant OS or Supervised.

ha_manage_appA

Manage Home Assistant apps (add-ons) or proxy an app API.

For app inventory, status, and Supervisor metadata, call ha_get_app first; use proxy mode here for documented app-specific read APIs, and do not infer private app API schemas.

Use exactly one mode: lifecycle/store action, configuration fields, path proxy, or path with array_patch.

Requires Home Assistant OS or Supervised. When ha-mcp itself runs as an app it cannot update its own running slug; update ha-mcp from the Home Assistant Apps UI. options merges top-level keys and one nested mapping level; supply complete values for deeper nested mappings because they are replaced. Prefer Ingress: direct-port access requires a shared container network and may require weakening the target app authentication. If a Supervisor lifecycle, configuration, or repository write has an unknown outcome, verify durable state with ha_get_app before retrying. That cannot prove whether restart or rebuild ran; inspect Supervisor jobs and logs and do not automatically replay them. For a proxy or array-patch write, query the target app's own read API before retrying.

If a Claude Desktop user gets a 4-minute timeout with no result on this call, read the target back before repeating it, and tell them to wait a few seconds before clicking the manual-approve button, as clicking it too quickly is known to cause hangs in Claude Desktop. This workaround is specific to Claude Desktop.

manage app apps addon add-on configure settings options port network boot watchdog auto_update supervisor ingress proxy websocket api rest esphome nodered node-red frigate mosquitto mqtt zigbee2mqtt zigbee z-wave zwave appdaemon hacs studio code server file editor terminal ssh samba grafana influxdb deconz motioneye compile validate upload deploy firmware ota flash yaml device logs flows events stats

ha_list_floors_areasA

List floors sorted by level ascending, each with their assigned areas nested, plus areas without a floor.

Use for location-based reasoning where floor-to-area relationships matter, such as "which rooms are on the ground floor" or operations scoped to a level.

Floors with level=None sort alongside level 0 (ground floor). Areas without a floor assignment appear in unassigned_areas; areas whose floor_id points to a non-existent floor appear in orphaned_areas. When the ha_mcp_tools component's registries capability is available, both registries come from a single in-process snapshot, so this classification is always consistent. Without it (legacy path), the two registries are fetched via independent WebSocket calls and a registry change between reads may transiently misclassify an area.

ha_remove_area_or_floorA

Remove a Home Assistant area or floor.

Removing an area unassigns its entities and devices (the entities and devices themselves are not removed). Removing a floor unassigns its areas. May break automations referencing the removed area/floor.

If a Claude Desktop user gets a 4-minute timeout with no result on this call, read the target back before repeating it, and tell them to wait a few seconds before clicking the manual-approve button, as clicking it too quickly is known to cause hangs in Claude Desktop. This workaround is specific to Claude Desktop.

ha_set_area_or_floorA

Create or update a Home Assistant area or floor.

Pass kind='area' (with optional floor_id, picture, labels, temperature_entity_id, humidity_entity_id) or kind='floor' (with optional level). Provide name only to create a new entry; provide id to update an existing one. Cross-kind parameters (e.g., picture or labels under kind='floor') are rejected with VALIDATION_INVALID_PARAMETER.

EXAMPLES: ha_set_area_or_floor(kind="area", name="Kitchen") ha_set_area_or_floor(kind="area", id="kitchen", floor_id="ground_floor") ha_set_area_or_floor(kind="area", id="kitchen", labels=["site_home"]) ha_set_area_or_floor(kind="area", id="kitchen", temperature_entity_id="sensor.kitchen_temp", humidity_entity_id=None) ha_set_area_or_floor(kind="floor", name="Basement", level=-1) ha_set_area_or_floor(kind="floor", id="ground_floor", level=0)

If a Claude Desktop user gets a 4-minute timeout with no result on this call, read the target back before repeating it, and tell them to wait a few seconds before clicking the manual-approve button, as clicking it too quickly is known to cause hangs in Claude Desktop. This workaround is specific to Claude Desktop.

ha_manage_pipelineA

Manage Home Assistant Assist pipelines.

Use action='list' to discover pipeline IDs, action='get' to inspect one pipeline, action='create' or action='update' to write pipeline settings, action='set_preferred' to choose the preferred pipeline, and action='process' to run a sentence through Assist.

action='process' sends the sentence straight to Assist's conversation agent, so a matched intent executes: it turns on the light rather than reporting that it would. Its result carries response_type ('action_done', 'query_answer' or 'error') and, on an error, error_code such as 'no_intent_match' — Assist declining a sentence is an answer, not a tool failure, so inspect those fields rather than expecting a raised error. Use ha_call_service to act on an entity directly; use this to test what Assist itself understands. When the built-in agent answers, a matching conversation trigger runs its automation: that agent checks its sentence triggers before it matches intents, so this is not limited to intents. Even with pipeline_id, the sentence goes to the agent directly. So with an agent other than the built-in one, neither sentence triggers nor prefer_local_intents apply — a full pipeline run is what adds those for other agents.

EXAMPLES:

  • Get the preferred pipeline: ha_manage_pipeline(action="get", pipeline_id="preferred")

  • Create by cloning a pipeline: ha_manage_pipeline(action="create", base_pipeline_id="preferred", name="Local Assist", conversation_engine="conversation.local_llm")

  • Update the agent and clear the TTS voice: ha_manage_pipeline(action="update", pipeline_id="preferred", conversation_engine="conversation.local_llm", tts_voice="")

  • Run a sentence through one pipeline's agent: ha_manage_pipeline(action="process", sentence="turn on the kitchen light", pipeline_id="preferred")

  • Continue a conversation: ha_manage_pipeline(action="process", sentence="and the hallway?", conversation_id="")

Non-nullable fields such as name, language, conversation_language, and conversation_engine must be omitted or non-empty.

If a Claude Desktop user gets a 4-minute timeout with no result on this call, read the target back before repeating it, and tell them to wait a few seconds before clicking the manual-approve button, as clicking it too quickly is known to cause hangs in Claude Desktop. This workaround is specific to Claude Desktop.

ha_manage_blueprintsA

Manage Home Assistant blueprints — list, read, import, save, delete, or render a standalone config.

One interface for the whole blueprint lifecycle in the automation and script domains.

DO NOT use this to create an automation or script FROM a blueprint — that is ha_config_set_automation / ha_config_set_script with a use_blueprint config.

To duplicate a blueprint, get it and save its yaml under a new path; to edit one in place, get it, change the text, and save it back to the same path with overwrite=True.

get also reports used_by: the automations or scripts built on the blueprint, which is the UI's "Show automations using this blueprint". Check it before deleting — Home Assistant refuses to delete a blueprint anything still uses (the error lists the consumers), and it goes on counting a consumer that has since taken control of its own config until that consumer is removed.

CAVEATS: get returns the on-disk YAML only when something can read it — an in-process server, the ha_mcp_tools component, the File & YAML Tools entry, or the blueprint's source_url; yaml_source names which one answered, and source_url text is a fresh download that can differ from the installed file. Core's blueprint API alone exposes metadata only, so a locally authored blueprint on a bare install has no readable text. Both writes are snapshotted first when a copy can be read, so ha_manage_backup(scope="edits") can restore the previous file. substitute only renders — it writes nothing, so pass the returned config to ha_config_set_automation / ha_config_set_script to persist it. To convert an automation or script that ALREADY exists, prefer those tools' take_control_of_blueprint=True: it renders with that item's own current inputs and saves the result over itself in one call.

EXAMPLES:

  • Get one (with its consumers in used_by): ha_manage_blueprints(action="get", path="homeassistant/motion_light.yaml")

  • Import: ha_manage_blueprints(action="import", url="https://example.com/bp.yaml")

  • Edit in place: ha_manage_blueprints(action="save", path="user/motion.yaml", yaml=, overwrite=True)

  • Delete: ha_manage_blueprints(action="delete", path="user/motion.yaml", confirm=True)

  • Render standalone: ha_manage_blueprints(action="substitute", path="user/motion.yaml", input={"motion_sensor": "binary_sensor.hall"})

RELATED TOOLS: ha_config_remove_automation / ha_config_remove_script to clear consumers blocking a delete, ha_search to find them.

If a Claude Desktop user gets a 4-minute timeout with no result on this call, read the target back before repeating it, and tell them to wait a few seconds before clicking the manual-approve button, as clicking it too quickly is known to cause hangs in Claude Desktop. This workaround is specific to Claude Desktop.

blueprint blueprints import delete remove unused substitute take-control list ha_get_blueprint ha_import_blueprint

ha_report_issueA

Get diagnostics and a finished GitHub issue for a bug, agent feedback or a feature request.

Use it before filing any GitHub issue about ha-mcp: a bug report without this report is closed after 24 hours. report_type picks the kind of report; if it is unclear which, ask: "Are you reporting a bug in ha-mcp, giving feedback on how I used the tools, or requesting a feature?"

Pass the report text in the call: the server combines it with the diagnostics it collects into issue_title, issue_body (the full report with logs) and issue_url (a new-issue link with title and body filled in, log sections left out to fit GitHub's URL limit; error messages stay in, with secrets redacted). A call without text still returns diagnostics, with placeholders in the body.

The response is LARGE; fields= narrows it. Read instructions before showing anything to the user: it covers the missing-tool and known-client pre-checks, the duplicate check, the mandatory anonymisation step, and how to file the issue. Check missing_tool_hint FIRST when the report is about a missing tool: a stale client tool list (not a bug) is the usual cause.

ha_config_get_calendar_eventsA

Get calendar events from a calendar entity within a time range.

Returns each event's summary, start, end, description and location, plus the uid, recurrence_id and rrule when the calendar provides them (the edit and remove tools use uid and recurrence_id). To find calendar entities, use ha_search(domain_filter='calendar').

EXAMPLES:

  • Next week (defaults): ha_config_get_calendar_events("calendar.family")

  • Date range: ha_config_get_calendar_events("calendar.work", start="2024-01-01T00:00:00", end="2024-01-31T23:59:59")

ha_config_remove_calendar_eventA

Delete an event from a calendar.

Deletes a calendar event via the WebSocket calendar/event/delete command. HA's calendar component only registers create_event and get_events as REST services — delete and update live on the WebSocket API only. Get the event UID from ha_config_get_calendar_events().

EXAMPLES:

  • Delete a single event: ha_config_remove_calendar_event("calendar.family", uid="event-12345")

  • Delete one occurrence and all later ones: ha_config_remove_calendar_event("calendar.work", uid="recurring-event-67890", recurrence_id="20240115T100000", recurrence_range="THISANDFUTURE")

If a Claude Desktop user gets a 4-minute timeout with no result on this call, read the target back before repeating it, and tell them to wait a few seconds before clicking the manual-approve button, as clicking it too quickly is known to cause hangs in Claude Desktop. This workaround is specific to Claude Desktop.

ha_config_set_calendar_eventA

Create a new event in a calendar, or update an existing one.

Creates a one-off event via the calendar.create_event service, or a recurring series via the WebSocket calendar/event/create command when rrule is provided (the REST service schema does not accept recurrence rules). Passing uid switches to update mode, which uses the WebSocket calendar/event/update command — HA registers no REST service for updating an event.

When NOT to use:

  • To retrieve calendar events, use ha_config_get_calendar_events.

  • To delete an event, use ha_config_remove_calendar_event.

  • To find the uid of an event to update, use ha_config_get_calendar_events; this tool does not search.

Passing date-only values (YYYY-MM-DD) for both start and end creates an all-day event; passing full ISO datetimes creates a timed event. The two forms cannot be mixed — a date-only start with a datetime end (or vice versa) is rejected.

An update replaces the whole event rather than patching it, so summary, start and end stay required in update mode, and a description or location that is not re-supplied is cleared. An rrule is the exception: Home Assistant accepts a new rule but has no way to express "no recurrence", so an existing rule survives an update that omits it. Delete the event and create it again to drop the recurrence.

Not every calendar integration supports event creation; recurring events additionally require the integration to support recurrence (the built-in Local Calendar does). Update support is narrower still: Local Calendar implements it, while the core Google Calendar and CalDAV integrations do not.

EXAMPLES:

  • Create: ha_config_set_calendar_event("calendar.family", summary="Doctor appointment", start="2024-01-15T14:00:00", end="2024-01-15T15:00:00")

  • Recurring (every Monday, 10 occurrences): ha_config_set_calendar_event("calendar.work", summary="Team meeting", start="2024-01-15T10:00:00", end="2024-01-15T11:00:00", rrule="FREQ=WEEKLY;BYDAY=MO;COUNT=10")

  • Update this and all later occurrences: ha_config_set_calendar_event("calendar.work", summary="Team meeting (new time)", start="2024-02-05T11:00:00", end="2024-02-05T12:00:00", uid="recurring-event-67890", recurrence_id="20240205T100000", recurrence_range="THISANDFUTURE")

If a Claude Desktop user gets a 4-minute timeout with no result on this call, read the target back before repeating it, and tell them to wait a few seconds before clicking the manual-approve button, as clicking it too quickly is known to cause hangs in Claude Desktop. This workaround is specific to Claude Desktop.

ha_get_camera_imageA

Get a snapshot image from a Home Assistant camera entity.

Fetches the current camera image and returns it directly for visual analysis (security checks, delivery verification, confirming a garage door actually closed), in the format Home Assistant serves (JPEG, PNG, or GIF), alongside a short text block stating the served snapshot's size and retrieval time in Home Assistant local time.

Do not use it to inspect the camera's state or attributes — use ha_search or ha_get_state for those; it returns an image, not state. Use it when you need to see the current scene, and on high-resolution cameras pass width and height to reduce token usage.

EXAMPLE: ha_get_camera_image(entity_id="camera.backyard", width=640, height=480)

ha_config_get_categoryA

Get category info - list all categories for a scope or get a specific one by ID.

Without a category_id: Lists all Home Assistant categories for the given scope. With a category_id: Returns configuration for that specific category.

Categories are domain-scoped organizational groups for automations, scripts, scenes, and helpers.

EXAMPLES:

  • List helper categories: ha_config_get_category("helpers")

  • Get specific category: ha_config_get_category("automation", category_id="my_category_id")

Use ha_config_set_category() to create or update categories. Use ha_set_entity(categories={"automation": "category_id"}) to assign categories to entities.

ha_config_remove_categoryA

Delete a Home Assistant category.

Removes the category from the category registry for the given scope. This will also remove the category assignment from all entities in that scope.

EXAMPLES:

  • Delete category: ha_config_remove_category("automation", "my_category_id")

Use ha_config_get_category() to find category IDs.

WARNING: Deleting a category will remove it from all assigned entities. This action cannot be undone.

If a Claude Desktop user gets a 4-minute timeout with no result on this call, read the target back before repeating it, and tell them to wait a few seconds before clicking the manual-approve button, as clicking it too quickly is known to cause hangs in Claude Desktop. This workaround is specific to Claude Desktop.

ha_config_set_categoryA

Create or update a Home Assistant category.

Creates a new category if category_id is not provided, or updates an existing category if category_id is provided.

Categories are domain-scoped organizational groups for automations, scripts, scenes, and helpers. Unlike labels (which are cross-domain), categories are specific to a single domain scope.

EXAMPLES:

  • Create automation category: ha_config_set_category("Lighting", scope="automation")

  • Create with icon: ha_config_set_category("Security", scope="automation", icon="mdi:shield")

  • Update category: ha_config_set_category("Updated Name", scope="automation", category_id="my_category_id")

After creating a category, use ha_set_entity(categories={"automation": "category_id"}) to assign it.

If a Claude Desktop user gets a 4-minute timeout with no result on this call, read the target back before repeating it, and tell them to wait a few seconds before clicking the manual-approve button, as clicking it too quickly is known to cause hangs in Claude Desktop. This workaround is specific to Claude Desktop.

ha_config_get_automationA

Get Home Assistant automation configuration.

Returns the complete configuration including triggers, conditions, actions, and mode settings.

The returned config_hash stays the same across consecutive reads of an unchanged config.

The returned automation_id is the resolved entity_id (canonical form, e.g. automation.morning_routine) when the registry lookup succeeds, falling back to the input identifier otherwise.

EXAMPLES:

  • Get automation: ha_config_get_automation("automation.morning_routine")

  • Get by unique_id: ha_config_get_automation("my_unique_automation_id")

For comprehensive automation documentation, use ha_get_skill_guide.

read inspect fetch view existing automation config triggers conditions actions get show detail

ha_config_remove_automationA

Delete a Home Assistant automation permanently.

The returned automation_id is the resolved entity_id (canonical form, e.g. automation.morning_routine) when the registry lookup succeeded before the delete, falling back to the input identifier otherwise.

EXAMPLES:

  • Delete automation: ha_config_remove_automation("automation.old_automation")

  • Delete by unique_id: ha_config_remove_automation("my_unique_id")

If a Claude Desktop user gets a 4-minute timeout with no result on this call, read the target back before repeating it, and tell them to wait a few seconds before clicking the manual-approve button, as clicking it too quickly is known to cause hangs in Claude Desktop. This workaround is specific to Claude Desktop.

ha_config_set_automationA

Create or update a Home Assistant automation.

MUST call ha_get_skill_guide OR refer to your locally installed skills first.

Prefer native triggers/conditions/actions over templates in logic positions; templates belong only in data.*, notification text, event_data and variables. The best-practice checker reports violations under best_practice_warnings — fix them before re-submitting. triggers-and-conditions.md, automation-actions.md and template-guidelines.md ship under skill_content by default. Test any unavoidable template with ha_eval_template first.

Consider a dedicated tool first: a state snapshot with no trigger -> ha_config_set_scene; a value derived from other entities -> ha_config_set_helper(helper_type='template'); a counter / timer / schedule / boolean -> ha_config_set_helper.

MODES (pick one; each can also take enabled, which alone with identifier turns the automation on or off without touching config):

  • python_transform: surgical edits to an existing automation. Requires identifier and config_hash from ha_config_get_automation(). Operates on the fetched config, which uses HA's plural root keys 'triggers'/'actions'/'conditions', e.g. python_transform="config['triggers'].append({'trigger': 'state', 'entity_id': 'binary_sensor.motion', 'to': 'on'})"

  • config: new automations or full restructures. Regular automations need alias, triggers and actions; blueprint automations need alias and use_blueprint {path, input}.

  • take_control_of_blueprint: convert a blueprint-backed automation into a standalone one. Takes no config of its own.

IDENTITY: omit identifier and config['id'] to create with a generated ID; an unused raw ID creates that specific ID. Reusing an identifier targets the same automation even if the alias changes; to rename or replace it, read it first and pass its config_hash — a changed alias without that hash is rejected before writing. The returned automation_id is the resolved entity_id, falling back to the input identifier or the generated unique_id.

EXAMPLES:

  • Create: ha_config_set_automation(config={"alias": "Morning Lights", "triggers": [{"trigger": "time", "at": "07:00:00"}], "actions": [{"action": "light.turn_on", "target": {"area_id": "bedroom"}}]})

  • From a blueprint: ha_config_set_automation(config={"alias": "Motion Light Kitchen", "use_blueprint": {"path": "homeassistant/motion_light.yaml", "input": {"motion_entity": "binary_sensor.kitchen_motion", "light_target": {"entity_id": "light.kitchen"}}}})

  • Update: current = ha_config_get_automation(identifier="automation.x"); ha_config_set_automation(identifier="automation.x", config_hash=current["config_hash"], config={...})

  • Disable: ha_config_set_automation(identifier="automation.x", enabled=False)

  • Run now: ha_config_set_automation(identifier="automation.x", run_actions=True)

  • Take control: ha_config_set_automation(identifier="automation.x", take_control_of_blueprint=True)

TAKE CONTROL is one-way: later blueprint edits stop reaching the automation; to change an input value, update 'use_blueprint.input' instead. It does NOT free the blueprint — Home Assistant keeps counting the converted automation as a user, so deleting that blueprint stays refused until the automation is removed (an automation reload does not clear it). The response names the blueprint in took_control_of_blueprint. To preview the rendering without writing anything, use ha_manage_blueprints(action="substitute", path=..., input=...).

If a Claude Desktop user gets a 4-minute timeout with no result on this call, read the target back before repeating it, and tell them to wait a few seconds before clicking the manual-approve button, as clicking it too quickly is known to cause hangs in Claude Desktop. This workaround is specific to Claude Desktop.

create update modify edit automation triggers conditions actions new automation write save take control blueprint detach unlink standalone convert enable disable turn on off run trigger now

ha_config_delete_dashboardA

Delete a storage-mode dashboard completely.

WARNING: This permanently deletes the dashboard and all its configuration. Cannot be undone. Does not work on YAML-mode dashboards.

HA internal IDs may differ from url_path (e.g. hyphens → underscores); the tool resolves either form to the actual registry ID before deletion.

EXAMPLES:

  • Delete dashboard: ha_config_delete_dashboard("mobile-dashboard")

Note: The default dashboard cannot be deleted via this method.

If a Claude Desktop user gets a 4-minute timeout with no result on this call, read the target back before repeating it, and tell them to wait a few seconds before clicking the manual-approve button, as clicking it too quickly is known to cause hangs in Claude Desktop. This workaround is specific to Claude Desktop.

ha_config_get_dashboardA

Get Lovelace dashboards: list them, read one config, or search their cards.

Not for a render alone: ha_get_dashboard_screenshot (screenshot beta feature) returns images without the config. Not for entity discovery: use ha_search.

The parameters pick the mode:

  • list_only=True: storage and YAML dashboards alike.

  • Any of query / entity_id / card_type / heading searches cards and header cards, AND-ing the criteria, in url_path or, when it is omitted, every storage dashboard. View badges answer entity_id and query, and heading excludes them. Cards nested at any depth count, including custom cards' own keys such as groups[].cards[].card. Each match has a jq_path and a python_path to append to config in ha_config_set_dashboard(python_transform=...), e.g. f'config{m["python_path"]}["icon"] = "mdi:x"'. Each match carries its dashboard's url_path and config_hash; a one-dashboard search also returns the config_hash at the top level.

  • Otherwise the full config of url_path (the default dashboard when omitted) is returned; with view_path only that view, while config_hash still covers the full config.

Caveats: config_hash stays the same across reads of an unchanged config. Searches stop at 200 matches (truncated). A search across dashboards skips YAML dashboards (HA resolves !secret in them) and, without a current ha_mcp_tools component, the default dashboard (with a warning); name either by url_path. Strategy dashboards have no stored cards to search. An unknown view_path errors and lists the available ones.

EXAMPLES:

  • List all dashboards: ha_config_get_dashboard(list_only=True)

  • Get one view only: ha_config_get_dashboard(url_path="lovelace-mobile", view_path="office")

  • Find cards by entity (wildcards allowed): ha_config_get_dashboard(url_path="my-dash", entity_id="sensor.temperature_*")

  • Find heading: ha_config_get_dashboard(url_path="my-dash", heading="Climate", card_type="heading")

  • Which dashboards use an entity: ha_config_get_dashboard(query="light.bedroom")

  • Fields of a card type before writing one (omit card_type to list types): ha_config_get_dashboard(card_type="tile", describe=True)

ha_config_set_dashboardA

Create or update a Home Assistant dashboard.

MUST call ha_get_skill_guide OR refer to your locally installed skills first. dashboard-guide.md ships under skill_content by default. A card's fields: ha_config_get_dashboard(card_type=..., describe=True).

MODES (pick one):

  • patch: edit known paths with literal values using JSON Patch add/remove/replace/test and config_hash, e.g. patch=[{"op": "replace", "path": "/views/0/title", "value": "Home"}]. move/copy are unsupported. Full guide: https://github.com/homeassistant-ai/ha-mcp/blob/master/docs/dashboard-edits.md

  • python_transform: loops or pattern-based changes across cards and views, e.g. 'config["views"][0]["cards"].append({"type": "button", "entity": "light.bedroom"})'. After delete/add operations indices shift, so chain multiple ops in ONE expression where possible; a later call needs a fresh config_hash from ha_config_get_dashboard().

  • config: new dashboards only, or a full restructure. Replaces everything. Omit it to create a dashboard without initial config.

Use ha_config_get_dashboard(entity_id=...) to get the path of any card, and ha_search / ha_get_overview to find entity IDs — never guess them. For visual re-checks after the write, use ha_get_dashboard_screenshot (when available) instead of re-sending config.

title/icon/require_admin/show_in_sidebar can be updated in a metadata-only call or alongside a full config replacement; with python_transform or patch, update metadata in a separate call (combining it with patch is rejected). Strategy dashboards (config {"strategy": {...}}) cannot be converted to custom dashboards here; use "Take Control" in the Home Assistant UI.

EXAMPLE: ha_config_set_dashboard(url_path="home-dashboard", title="Home Overview", config={"views": [{"title": "Home", "type": "sections", "sections": [{"title": "Climate", "cards": [{"type": "tile", "entity": "climate.living_room"}]}]}]})

This tool manages storage-mode dashboards only. YAML-mode dashboards (a .yaml file registered under lovelace: dashboards: in configuration.yaml) and dashboards inlined under lovelace: are edited in their .yaml file; ha_config_set_yaml can update the lovelace: registration but not the dashboard body.

If a Claude Desktop user gets a 4-minute timeout with no result on this call, read the target back before repeating it, and tell them to wait a few seconds before clicking the manual-approve button, as clicking it too quickly is known to cause hangs in Claude Desktop. This workaround is specific to Claude Desktop.

ha_config_list_helpersA

List Home Assistant helpers of a specific type with their configurations.

Returns one page of helpers; total_count and has_more report the full set. Each record carries the configuration for its helper: id (immutable storage key), entity_id (current — address the helper by this, where available), name (current display name), original_name (creation-time name), icon, type-specific settings, and area and label assignments. A flow helper record carries entry_id and options instead of id; a custom helper integration's options are withheld, marked options_withheld.

For a helper renamed in the UI, id/original_name keep the storage values while entity_id/name reflect the current entity registry (entity_id is the identifier ha_config_set_helper resolves against, so prefer it over id for a renamed helper). entity_id/original_name are present only for storage-collection helpers matched in the entity registry — types with no backing entity (e.g. tag), and every record when the registry read degrades, carry only id/name (a warning flags the degraded case).

Storage types list what HA's {type}/list command returns: the storage-backed helpers (created via UI/API), not the YAML-defined ones. person is the exception — HA lists its YAML-configured persons alongside the storage ones, so both appear here.

Listing flow types requires the ha_mcp_tools custom component (>= 1.1.0); without it, such a listing returns a COMPONENT_NOT_INSTALLED error.

With helper_type="all", each record carries its own helper_type. This mode is component-only (there is no single built-in command that lists all types): without the ha_mcp_tools component it returns a COMPONENT_NOT_INSTALLED error rather than a partial or empty list.

describe=True returns each field's name, type, required flag, options, default and (with helper_id) current value, or the menu_options a menu-based helper needs a menu_choice from. Call it before ha_config_set_helper to learn the config keys for a type.

EXAMPLES:

  • List all counters: ha_config_list_helpers("counter")

  • List every helper type at once: ha_config_list_helpers("all")

  • Next page: ha_config_list_helpers("input_boolean", offset=100)

  • Fields for a template sensor: ha_config_list_helpers("template", describe=True, menu_choice="sensor")

For detailed helper documentation, use ha_get_skill_guide.

list all helpers input_boolean input_number input_text counter timer input_datetime input_select

ha_config_set_helperA

Create or update Home Assistant helpers: storage types, every helper flow HA lists, and config subentries.

MUST call ha_get_skill_guide OR refer to your locally installed skills first. helper-selection.md ships under skill_content by default.

SIMPLE types (pass config dict): input_boolean, input_button, input_select, input_number, input_text, input_datetime, counter, timer, schedule, zone, person, tag. Create requires name; update requires helper_id.

FLOW types (pass config dict, Config Entry Flow API): every helper flow Home Assistant lists, read from it at call time — template, group, utility_meter, derivative, min_max, threshold, integration, statistics, trend, ... and custom helper integrations. Create requires name; for updates pass the existing entry_id as helper_id (options flows reject the name key). Do not create otp here although Home Assistant lists it: the user sets it up in the HA UI, since its secret is a credential they enroll in an authenticator app.

CONFIG_SUBENTRY type (Config Subentry Flow API): pass entry_id, subentry_type and config; pass subentry_id to reconfigure an existing subentry, omit it to create one.

Behavior:

  • UPDATE preserves type-specific fields not re-passed (a rename never wipes initial/icon/etc.); flow-helper and config subentry updates behave the same way (see config).

  • Omitted action falls back to the helper_id-presence discriminator (SIMPLE/FLOW) or the subentry_id-presence discriminator (config subentries).

  • For flow-based helpers, config keys not declared by any step's data_schema are silently ignored by HA. Validation errors carry the helper's data_schema (and menu_options for menu-rooted helpers like template/group when no sub-type is chosen yet), so a follow-up call can self-correct without a separate schema-discovery round-trip.

  • Flows that present more than one menu (e.g. an MQTT device subentry reconfigure looping through its summary menu) take next_step_id as a LIST of successive selections, consumed one per menu encounter.

EXAMPLES:

  • input_number: ha_config_set_helper(helper_type="input_number", name="Target", config={"min": 0, "max": 100, "step": 5})

  • template sensor: ha_config_set_helper(helper_type="template", name="Room Temp", config={"next_step_id": "sensor", "state": "{{ states('sensor.x')|float }}", "unit_of_measurement": "°C"})

  • group: ha_config_set_helper(helper_type="group", name="Kitchen Lights", config={"group_type": "light", "entities": ["light.a", "light.b"]})

  • config subentry: ha_config_set_helper(helper_type="config_subentry", entry_id="01HXYZ...", subentry_type="conversation", config={"name": "Local agent", "model": "gemma3:27b"})

If a Claude Desktop user gets a 4-minute timeout with no result on this call, read the target back before repeating it, and tell them to wait a few seconds before clicking the manual-approve button, as clicking it too quickly is known to cause hangs in Claude Desktop. This workaround is specific to Claude Desktop.

create update new add helper input_boolean input_button input_number input_text input_datetime input_select counter timer schedule zone person tag template group utility_meter derivative min_max threshold integration statistics trend random filter tod generic_thermostat switch_as_x generic_hygrostat history_stats mold_indicator

ha_config_get_sceneA

Get a scene's complete configuration, or list and search scenes without scene_id.

Use ha_search for cross-domain discovery and dependency searches. For ordinary scene discovery, use this tool and pass a returned scene_id back to retrieve the complete entities dict and config_hash for editing (pass that hash to ha_config_set_scene for python_transform updates).

Listing returns compact metadata. Integration-managed scenes have no editable storage config or scene_id. Partial content-search results explicitly report unread configs and are not exhaustive.

EXAMPLES:

  • Get scene: ha_config_get_scene("movie_night")

  • Find scenes: ha_config_get_scene(query="movie")

  • Find attribute values: ha_config_get_scene(query="rainbow", search_in_config=True)

For detailed scene configuration help, use ha_get_skill_guide.

ha_config_remove_sceneA

Delete a Home Assistant scene.

EXAMPLE: ha_config_remove_scene("old_scene")

Only scenes created via the Home Assistant UI can be deleted. Scenes defined in YAML configuration files (scenes.yaml or configuration.yaml) cannot be deleted through the API and return a 405 Method Not Allowed error; edit the configuration file directly instead.

WARNING: Deleting a scene that is referenced by automations or scripts (via scene.turn_on) may cause those to fail.

If a Claude Desktop user gets a 4-minute timeout with no result on this call, read the target back before repeating it, and tell them to wait a few seconds before clicking the manual-approve button, as clicking it too quickly is known to cause hangs in Claude Desktop. This workaround is specific to Claude Desktop.

ha_config_set_sceneA

Create or update a Home Assistant scene.

MUST call ha_get_skill_guide OR refer to your locally installed skills first.

Supports two modes: full config replacement (config) or Python transformation of an existing scene (python_transform). See the field descriptions for python_transform examples and the config shape contract. Either mode can also take activate, which can be passed alone with scene_id to activate a scene without touching its config.

WHEN TO USE:

  • python_transform: surgical edits to an existing scene (add/remove/update a single entity entry).

  • config: creating a new scene, or wholesale replacement.

  • activate (with scene_id, no config): activate any scene, e.g. ha_config_set_scene(scene_id="scene.movie_night", activate=True).

WHEN NOT TO USE:

  • To list or look up existing scenes, use ha_config_get_scene.

SCENE SHAPE: Automations use a list of actions; scenes capture a snapshot of states as a dict.

EXAMPLE:

ha_config_set_scene(scene_id="movie_night", config={ "name": "Movie Night", "entities": { "light.living_room": {"state": "on", "brightness": 50}, }, "icon": "mdi:movie", })

The top-level SKILL.md for home-assistant-best-practices ships in this response under skill_content by default — generic best-practice index covering entity-naming and safe-refactoring patterns that intersect with scene authoring. For detailed scene configuration help beyond that, use ha_get_skill_guide.

If a Claude Desktop user gets a 4-minute timeout with no result on this call, read the target back before repeating it, and tell them to wait a few seconds before clicking the manual-approve button, as clicking it too quickly is known to cause hangs in Claude Desktop. This workaround is specific to Claude Desktop.

create update modify edit scene entities snapshot activate apply turn on

ha_config_get_scriptA

Get Home Assistant script configuration.

Returns the complete configuration for a script, including sequence, mode, fields, and other settings.

The returned config_hash stays the same across consecutive reads of an unchanged config.

The returned script_id is the canonical bare storage key resolved by the REST client (matching what ha_config_set_script / ha_config_remove_script expect), falling back to the input identifier on the rare path where the REST envelope omits it. Prefix handling matches ha_config_get_automation in behavior (mechanism differs: automations resolve via state lookup; scripts strip the prefix).

EXAMPLES:

  • Get script (bare form): ha_config_get_script("morning_routine")

  • Get script (entity_id form): ha_config_get_script("script.morning_routine")

For detailed script configuration help, use ha_get_skill_guide.

read inspect fetch view existing script config sequence actions get show detail

ha_config_remove_scriptA

Delete a Home Assistant script.

EXAMPLE: ha_config_remove_script("old_script")

Only scripts created via the Home Assistant UI can be deleted. Scripts defined in YAML configuration files (scripts.yaml or configuration.yaml) cannot be deleted through the API and return a 405 Method Not Allowed error; edit the configuration file directly instead.

WARNING: Deleting a script that is used by automations may cause those automations to fail.

If a Claude Desktop user gets a 4-minute timeout with no result on this call, read the target back before repeating it, and tell them to wait a few seconds before clicking the manual-approve button, as clicking it too quickly is known to cause hangs in Claude Desktop. This workaround is specific to Claude Desktop.

ha_config_set_scriptA

Create or update a Home Assistant script.

MUST call ha_get_skill_guide OR refer to your locally installed skills first.

Prefer native actions (choose / if, wait_for_trigger, repeat, for:) over templates in logic positions; templates belong only in data.*, notification text, event_data and variables. The best-practice checker reports violations under best_practice_warnings. automation-actions.md, triggers-and-conditions.md and template-guidelines.md ship under skill_content by default.

Scripts use 'sequence', NOT 'trigger' or 'action'; for trigger-based execution use ha_config_set_automation.

MODES (pick one):

  • python_transform: surgical edits to an existing script. Requires config_hash from ha_config_get_script(), e.g. python_transform="config['sequence'].append({'delay': {'seconds': 5}})"

  • config: new scripts or full restructures. Needs 'sequence' (regular) or 'use_blueprint' {path, input} (blueprint-based).

  • take_control_of_blueprint: convert a blueprint-backed script into a standalone one. Takes no config of its own.

  • run (alone with script_id): 'start' runs the script (optional variables), 'stop' stops its running executions. Write config changes in a separate call first: Home Assistant signals no completion of the script reload a write triggers.

EXAMPLES:

  • Create: ha_config_set_script(script_id="blink_light", config={"alias": "Light Blink", "sequence": [{"action": "light.turn_on", "target": {"entity_id": "light.living_room"}}, {"delay": {"seconds": 2}}, {"action": "light.turn_off", "target": {"entity_id": "light.living_room"}}]})

  • From a blueprint: ha_config_set_script(script_id="notification_script", config={"alias": "My Notification Script", "use_blueprint": {"path": "notification_script.yaml", "input": {"message": "Hello World"}}})

  • Take control: ha_config_set_script(script_id="notification_script", take_control_of_blueprint=True)

TAKE CONTROL is one-way: later blueprint edits stop reaching the script; to change an input value, update 'use_blueprint.input' instead. It does NOT free the blueprint — Home Assistant keeps counting the converted script as a user, so deleting that blueprint stays refused until the script is removed. To preview the rendering without writing anything, use ha_manage_blueprints(action="substitute", domain="script", path=..., input=...).

If a Claude Desktop user gets a 4-minute timeout with no result on this call, read the target back before repeating it, and tell them to wait a few seconds before clicking the manual-approve button, as clicking it too quickly is known to cause hangs in Claude Desktop. This workaround is specific to Claude Desktop.

create update modify edit script sequence actions new script write save take control blueprint detach unlink standalone convert run start stop execute

ha_manage_energy_prefsA

Manage the Home Assistant Energy Dashboard preferences: grid / solar / battery / gas / water energy sources, device consumption sensors for electricity and water, and cost tariffs.

WHEN NOT TO USE:

  • To create the underlying statistics themselves — they must already exist as HA entities before being referenced here; create them via the relevant integration's config flow first.

WHEN TO USE:

  • mode='get' / 'set': inspect or replace the full Energy Dashboard config. Use 'set' for bulk edits or anything touching multiple top-level keys at once.

  • mode='add_device' / 'remove_device': add or remove a single device-consumption entry. The tool performs a fresh read-modify-write internally.

  • mode='add_source': append a single entry to energy_sources. Same optimistic read-modify-write semantics.

RELATED TOOLS: Use ha_get_history(source="statistics") with the returned statistic IDs for consumption, totals, and trends. Metadata comes directly from the running Core, including stored and display units.

CAVEATS:

  • energy/save_prefs has per-key FULL-REPLACE semantics. Passing {"device_consumption": [<one entry>]} deletes every other device the user had configured — silently, with no error.

  • The per-key config_hash form lets an agent submit only the top-level key it wants to change: config keys must equal the dict keys, and a per-key submission still fully replaces that key's value. A mismatch on any locked key returns RESOURCE_LOCKED with the offending keys in mismatched_keys.

  • dry_run=True skips the hash check entirely for both forms.

  • Writes need an administrator token; Home Assistant rejects the save otherwise.

  • After a successful write, the tool calls energy/validate and returns residual issues (missing stats, unit mismatches) as post_save_validation_errors; the save persists regardless — correct the config and write again if needed.

  • 'add_source' rejects duplicates by (type, stat_energy_from) for solar/battery/gas/water; grid entries are appended without a duplicate check (multiple grid variants are legitimate), so the caller de-duplicates grid sources.

EXAMPLES:

  • ha_manage_energy_prefs(mode="get", include_schema=True)

  • Preview a device: ha_manage_energy_prefs(mode="add_device", stat_consumption="sensor.fridge_energy", dry_run=True)

  • Remove a device: ha_manage_energy_prefs(mode="remove_device", stat_consumption="sensor.fridge_energy")

If a Claude Desktop user gets a 4-minute timeout with no result on this call, read the target back before repeating it, and tell them to wait a few seconds before clicking the manual-approve button, as clicking it too quickly is known to cause hangs in Claude Desktop. This workaround is specific to Claude Desktop.

read get inspect energy dashboard preferences prefs electricity price prices pricing tariff tariffs rate rates cost costs kwh peak off-peak offpeak contract utility bill grid solar battery gas water consumption number_energy_price entity_energy_price stat_energy_from

ha_get_entityA

Get entity registry information for one or more entities.

Returns detailed entity registry metadata: area, custom name/icon, original name, disabled_by/hidden_by (with enabled/hidden shorthands), aliases (a null entry = the entity's own name), labels, categories, device_class override, per-domain options, platform, device_id, config_entry_id and unique_id.

RESOLVER MODE: Pass unique_id (instead of entity_id) to resolve a stable integration unique_id to its entity_id(s). Since the registry's unique key is (domain, platform, unique_id), the same unique_id can match multiple platforms — all matches are returned in entity_entries with a matches count. Narrow with domain/platform. Resolver reads as_partial_dict, so aliases and the device_class override come back as defaults ([]/null).

When config_entry_id is non-null — e.g. for UI-created template / group / utility_meter / derivative helpers — pass it to ha_get_integration(entry_id=..., include_options=True) to read the helper's current config (template body, group members, etc.) without scanning a domain list. Voice-assistant exposure is stored under options but is set via ha_set_entity(expose_to=...).

Resolved-name enrichment (present only when the ha_mcp_tools component advertises it; otherwise these keys are absent): area (assigned area NAME, device-inherited when the entity has none), floor, and label_names. This tool's base labels carries the label ids; ha_search result_fields and ha_get_entity_exposure instead emit the resolved names under labels.

RELATED TOOLS: ha_set_entity() to modify these properties; ha_get_state() for current state/attributes; ha_search() to find entities.

EXAMPLES:

  • Single entity: ha_get_entity("sensor.temperature")

  • Multiple entities: ha_get_entity(["light.living_room", "switch.porch"])

  • Resolve a unique_id: ha_get_entity(unique_id="00:11:22:33", domain="sensor")

get entity state attributes details single specific entity_id

ha_remove_entityA

Remove one or more entities from the Home Assistant entity registry.

Permanently removes the entity registration; the entity will no longer appear in the UI or be available to automations. Use only for orphaned or stale entity entries: if the underlying device or integration is still active, the entity may be re-added automatically on the next HA restart or reload. This cannot be undone without restoring from backup. For most use cases, consider disabling instead: ha_set_entity(entity_id="sensor.old", enabled=False).

BULK MODE: Pass a list of entity IDs to remove up to 100 at once — handy for clearing the restored=true orphans an integration leaves behind after its filters change. Removals run sequentially and return: {removed: [...], skipped: [...], errors: [{entity_id, code, message}]} where skipped = ids already absent (not-found is idempotent, not an error). Bulk mode is NOT auto-backed-up (the snapshot is single-entity); single-id removal still is.

EXAMPLES:

  • Remove orphaned sensor: ha_remove_entity("sensor.old_temperature")

  • Bulk cleanup: ha_remove_entity(["sensor.orphan_1", "sensor.orphan_2"])

Use ha_search / ha_get_entity to verify an entity before removing it.

If a Claude Desktop user gets a 4-minute timeout with no result on this call, read the target back before repeating it, and tell them to wait a few seconds before clicking the manual-approve button, as clicking it too quickly is known to cause hangs in Claude Desktop. This workaround is specific to Claude Desktop.

ha_set_entityA

Update entity properties in the entity registry.

Allows modifying entity metadata such as area assignment, display name, icon, "Show As" device class override, per-domain registry options, enabled/disabled state, visibility, aliases, labels, voice assistant exposure, and entity_id rename in a single call.

BULK OPERATIONS: When entity_id is a list, only labels, expose_to, and categories parameters are supported. Other parameters (area_id, name, use_device_name, icon, device_class, options, enabled, hidden, aliases, use_entity_name_alias, new_entity_id, new_device_name) require single entity.

SHOW AS / DEVICE CLASS: a device_class change applies instantly, no reload needed.

REGISTRY OPTIONS: multi-domain options are sent as separate registry updates because HA's WS schema requires options_domain + options to be paired one domain at a time.

ENTITY ID RENAME: Voice exposure settings are preserved automatically.

WARNING: Renaming an entity_id does NOT update references in automations, scripts, templates, or dashboards. All consumers of the old entity_id must be updated manually — HA does not propagate the rename automatically.

Rename limitations:

  • Entity history is preserved (HA 2022.4+)

  • Entities without unique IDs cannot be renamed

  • Entities disabled by their integration cannot be renamed

DEVICE RENAME: new_device_name can be combined with new_entity_id to rename both in one call. The device is looked up automatically.

Use ha_search() or ha_get_device() to find entity IDs. Use ha_config_get_label() to find available label IDs.

EXAMPLES:

  • Assign to area: ha_set_entity("sensor.temp", area_id="living_room")

  • Set Show As: ha_set_entity("binary_sensor.zone_10", device_class="window")

  • Set sensor precision: ha_set_entity("sensor.power", options={"sensor": {"display_precision": 2}})

  • Rename entity and device: ha_set_entity("light.old", new_entity_id="light.new", new_device_name="New Lamp")

  • Add labels to multiple: ha_set_entity(["light.a", "light.b"], labels=["new"], label_operation="add")

  • Expose to Alexa: ha_set_entity("light.lamp", expose_to={"cloud.alexa": True})

ENABLED/DISABLED WARNING: A disabled entity will NOT appear in state queries, dashboards, or automations until re-enabled AND the integration is reloaded. This is NOT the same as "turning off" an entity.

For automations and scripts, enabled=False is blocked. For automations, use ha_config_set_automation(identifier="automation.xxx", enabled=False) (or enabled=True to re-enable). For scripts, ha_config_set_script(script_id="script.xxx", run="stop") only stops a currently running execution; it does not disable the script. Home Assistant has no script runtime enable/disable service.

If a Claude Desktop user gets a 4-minute timeout with no result on this call, read the target back before repeating it, and tell them to wait a few seconds before clicking the manual-approve button, as clicking it too quickly is known to cause hangs in Claude Desktop. This workaround is specific to Claude Desktop.

ha_config_list_groupsA

List Home Assistant entity groups with their member entities.

Returns one page of old-style groups created via the group.set service or YAML configuration (platform-specific groups such as light or cover groups are separate entities); total_count and has_more report the full set. Each group includes its entity_id, friendly name, state, member entities, icon and all mode.

EXAMPLE: ha_config_list_groups(offset=100)

ha_config_remove_groupA

Remove a service-based Home Assistant entity group via the group.remove service.

When NOT to use: for groups created through ha_config_set_helper(helper_type="group", ...), use ha_remove_helpers_integrations. Those config-entry-backed groups are not reachable via the group.remove service.

When to use: removing groups created with ha_config_set_group or defined in YAML via group: configuration. Config-entry-backed deletion tools cannot find these.

EXAMPLES:

  • Remove group: ha_config_remove_group("living_room_lights")

Use ha_config_list_groups() to find existing groups.

WARNING:

  • Removing a group used in automations may cause those automations to fail.

  • Groups defined in YAML can be removed at runtime but will reappear after restart.

  • This only removes old-style groups, not platform-specific groups.

If a Claude Desktop user gets a 4-minute timeout with no result on this call, read the target back before repeating it, and tell them to wait a few seconds before clicking the manual-approve button, as clicking it too quickly is known to cause hangs in Claude Desktop. This workaround is specific to Claude Desktop.

ha_config_set_groupA

Create or update a service-based Home Assistant entity group via the group.set service.

When NOT to use: for typical "combine these entities into one controllable group" requests, prefer ha_config_set_helper(helper_type="group", ...). Config-entry-backed groups are registered in the entity registry, so ha_set_entity can assign them to areas and they are deletable via ha_remove_helpers_integrations.

When to use: compatibility with existing groups already configured via group.set or YAML, or the rare case where entity-registry membership is explicitly unwanted. Groups created here are only removable via ha_config_remove_group — ha_remove_helpers_integrations will not find them.

For NEW groups: Provide object_id and entities (required). For EXISTING groups: Provide object_id and any fields to update. entities, add_entities, and remove_entities are mutually exclusive.

EXAMPLES:

  • Create: ha_config_set_group("bedroom_lights", entities=["light.lamp", "light.ceiling"], name="Bedroom Lights")

  • Add entities: ha_config_set_group("lights", add_entities=["light.extra"])

If a Claude Desktop user gets a 4-minute timeout with no result on this call, read the target back before repeating it, and tell them to wait a few seconds before clicking the manual-approve button, as clicking it too quickly is known to cause hangs in Claude Desktop. This workaround is specific to Claude Desktop.

ha_get_hacs_infoA

Get HACS (Home Assistant Community Store) data — search the store or fetch repository details.

Use action="search" to search/browse/list store repositories, or action="info" for one repository's full details (README, versions, GitHub stats). This tool is read-only; to install or add repositories use ha_manage_hacs, and for non-HACS entities/config use the domain-specific tools.

DASHBOARD TIP: action="search", installed_only=True, category="lovelace" discovers installed custom cards to wire into ha_config_set_dashboard().

Examples:

  • Search the store: ha_get_hacs_info(action="search", query="mushroom", category="lovelace")

  • List installed: ha_get_hacs_info(action="search", installed_only=True)

  • Repository details: ha_get_hacs_info(action="info", repository_id="441028036")

Caveats: info fetches full repository detail from GitHub, so it can hit GitHub rate limits / needs HACS's configured GitHub token; search reads HACS's locally cached repository index.

ha_manage_hacsA

Manage HACS (Home Assistant Community Store) — install/update, remove, add custom repositories, or refresh repository information.

This tool performs writes; to search the store or read repository details use ha_get_hacs_info. Use action="update_information" to run the HACS UI's "Update information" action — a forced re-fetch of one repository's release data from GitHub, so a pending update becomes visible to HACS and its update entity immediately.

Examples:

  • Install latest: ha_manage_hacs(action="download", repository_id="441028036")

  • Install a version: ha_manage_hacs(action="download", repository_id="piitaya/lovelace-mushroom", version="v4.0.0")

  • Remove: ha_manage_hacs(action="remove", repository_id="owner/repo")

  • Add a custom repo: ha_manage_hacs(action="add_repository", repository="owner/repo", category="lovelace")

  • Refresh release data: ha_manage_hacs(action="update_information", repository_id="owner/repo")

Caveats: Installing an integration usually needs a Home Assistant restart to activate; new Lovelace cards need a browser cache clear. add_repository requires owner/repo format plus a matching category. Removing an integration deletes its files but the loaded module persists until the next Home Assistant restart — delete its config entries first (ha_remove_helpers_integrations). HACS refreshes custom repositories on its own only about every 48 hours, so update_information is the way to surface a just-published release.

If a Claude Desktop user gets a 4-minute timeout with no result on this call, read the target back before repeating it, and tell them to wait a few seconds before clicking the manual-approve button, as clicking it too quickly is known to cause hangs in Claude Desktop. This workaround is specific to Claude Desktop.

ha_get_historyA

Get historical data from Home Assistant's recorder.

WHEN NOT TO USE: For current values, use ha_get_state. To inspect Energy Dashboard preferences and configured statistics, use ha_manage_energy_prefs(mode="get", include_statistics=True).

WHEN TO USE: Use source="history" (default) to troubleshoot why a value changed, check event sequences, or analyze recent patterns. Use source="statistics" for long-term trends and period averages.

CAVEATS: History rows rename Core's compact keys once: s -> state, a -> attributes, lu -> last_updated, lc -> last_changed. History event times are ISO strings in HA's timezone (UTC if unavailable). When Core omits lc, last_changed falls back to last_updated; this may not be the actual state-change time with significant_changes_only (default) or a window-start snapshot. Attributes and unknown fields pass through unchanged. Statistics timestamps use Unix milliseconds. Minimal history may omit attributes. No duplicate compact aliases are added. include_schema=True retains core_contract even when fields selects other data keys.

Output units come from Core recorder metadata and reflect its display-unit conversion; unresolved units include a reason. statistics_metadata preserves Core's native fields.

All data is fetched from HA before slicing; limit/offset are client-side. With multiple entity_ids, offset must be 0 — use a single entity_id for offset > 0. Use has_more and next_offset from the response to paginate. Administrators can optionally enable recorder workload guardrails in Advanced settings. When enabled, oversized entity/time workloads are rejected before the recorder query is issued; narrow the time range or entity list to stay within the budget. Calendar statistics may first read HA's configured timezone so the estimate follows local calendar boundaries.

EXAMPLES:

  • ha_get_history(entity_ids="sensor.bedroom_temperature", start_time="24h")

  • Paginate oldest-first: ha_get_history(entity_ids="sensor.temperature", start_time="7d", limit=100, offset=100, order="asc")

  • ha_get_history(source="statistics", entity_ids="sensor.living_room_temperature", start_time="6m", period="month", statistic_types=["mean", "min", "max"])

ha_get_integrationA

Get integration (config entry) information with pagination.

Without an entry_id: Lists all configured integrations with optional filters. With an entry_id: Returns detailed information including full options/configuration.

EXAMPLES:

  • List / search: ha_get_integration(query="zigbee")

  • Get an entry with its editable fields: ha_get_integration(entry_id="abc123", include_schema=True)

  • Diagnostics dump, paged along a list-valued path: ha_get_integration(entry_id="abc123", include_diagnostics=True, diagnostics_data_path="", diagnostics_data_limit=10, diagnostics_data_offset=20)

  • Inspect a subentry reconfigure schema: ha_get_integration(entry_id="abc123", include_subentry_schema=True, subentry_type="conversation", subentry_id="sub123")

  • List template entries with their options: ha_get_integration(domain="template")

STATES: 'loaded', 'setup_error', 'setup_retry', 'not_loaded', 'failed_unload', 'migration_error'.

OPTIONS: options reflect the entry's persisted values. Values that match a secrets.yaml entry are returned as "**redacted**". Use include_schema=True to see every editable field and its default/type. The shape depends on the read path, which the response does not name: when the ha_mcp_tools custom component serves the read, options are the stored mapping as-is, so a field never set may be absent and a section's fields stay nested under the section key (e.g. a template helper's additional_options). Otherwise they are read from the options flow form, which shows unset fields at their schema default and lists a section's fields at the top level. Check both places for a section field.

Each entry carries log_level: the canonical Python logger level name (DEBUG/INFO/WARNING/ERROR/CRITICAL) when the integration has a log-level override (set one with ha_set_integration(log_level=...)), or "DEFAULT" (uppercase sentinel) when no override is set; and log_level_raw: the original numeric level (e.g. 10 for DEBUG) when HA returned an int, None otherwise. This is distinct from the app side, where ha_get_app returns Supervisor's lowercase "default" literal — do not cross-compare.

ha_remove_helpers_integrationsA

Remove a Home Assistant helper or integration config entry.

Unifies three backend removal mechanisms — simple-helper websocket delete, config-entry delete, and config-subentry delete — behind one entry point; helper_type picks the path, or the entity registry does when an entity_id comes without one.

WHEN NOT TO USE:

  • Removing only an entity (without deleting its underlying helper or config entry) — use ha_remove_entity instead.

  • YAML-configured helpers — they have no storage backend. Edit the YAML file and reload the relevant integration.

ROUTING:

  • SIMPLE helper_type (input_button, input_boolean, input_select, input_number, input_text, input_datetime, counter, timer, schedule, zone, person, tag) + bare helper_id or entity_id → websocket delete.

  • FLOW helper_type (any helper flow Home Assistant lists: template, group, utility_meter, derivative, ...; custom helper integrations too)

    • full entity_id → resolve entity_id to config_entry_id via entity_registry, then delete the config entry. All sub-entities (e.g. utility_meter tariffs) are removed together. An entity registered by another integration is refused with VALIDATION_INVALID_PARAMETER and nothing is deleted.

  • helper_type=None + entity_id → the entity's registry entry names its helper (storage type or helper flow); an entity of any other integration is refused with VALIDATION_INVALID_PARAMETER.

  • helper_type=None + entry_id → direct config entry delete (any integration).

  • helper_type="config_subentry" + parent entry_id + subentry_id → delete one config subentry.

A target that cannot be removed raises a structured error rather than returning silent success: ENTITY_NOT_FOUND when the entity_id is absent from both the state machine and the entity registry (a bare helper_id on a FLOW target also raises it — FLOW resolution needs a full entity_id); RESOURCE_NOT_FOUND when it exists but is not storage- or registry-managed (a YAML-configured helper, or an entity with a state but no registry entry), for a config entry the backend reports as 404, or for a missing config subentry. Calling N times gives the same response. Transient connectivity failures raise their own codes (WEBSOCKET_DISCONNECTED, CONNECTION_FAILED) so retry logic can branch separately.

EXAMPLES:

  • Remove SIMPLE button: ha_remove_helpers_integrations(target="my_button", helper_type="input_button", confirm=True)

  • Remove FLOW utility_meter (any sub-entity works): ha_remove_helpers_integrations(target="sensor.energy_peak", helper_type="utility_meter", confirm=True)

  • Remove whatever helper owns an entity: ha_remove_helpers_integrations(target="sensor.energy_peak", confirm=True)

  • Remove any integration by entry_id: ha_remove_helpers_integrations(target="01HXYZ...", confirm=True)

  • Remove a config subentry: ha_remove_helpers_integrations(target="01HXYZ...", helper_type="config_subentry", subentry_id="subentry-123", confirm=True)

WARNING: Removing a helper or integration that is referenced by automations, scripts, or other integrations may cause those to fail. Use ha_search() / ha_get_integration() to verify before removal. ha_manage_backup(scope="edits", action="restore") recreates removed FLOW helpers whose options could be snapshotted, and config subentries. It cannot recreate custom helper integrations (their options are withheld) or otp (no stored options); re-add those yourself, otp through the user in the HA UI.

If a Claude Desktop user gets a 4-minute timeout with no result on this call, read the target back before repeating it, and tell them to wait a few seconds before clicking the manual-approve button, as clicking it too quickly is known to cause hangs in Claude Desktop. This workaround is specific to Claude Desktop.

ha_set_integrationA

Manage an integration (config entry): enable/disable, add, update options, or reconfigure.

Modes (pick one):

  • Enable/disable: entry_id + enabled.

  • Add integration: domain (+ config) — drives the domain's config flow, including menus and multi-step forms.

  • Update options: entry_id + config — drives the entry's options flow (what the "Configure" button does in the HA UI).

  • Reconfigure: entry_id + reconfigure=True + config — connection settings such as host, port, credentials. Repeat with the token the preflight returns as confirm_token to apply.

  • Log level: log_level + domain (or entry_id) — sets how much the integration logs; read it back with ha_get_integration's log_level.

WHEN NOT TO USE:

  • Helpers (template, group, utility_meter, ...): use ha_config_set_helper. otp is the user's to set up in the HA UI: its secret is a credential enrolled in an authenticator app; do not create it.

  • Config subentries: use ha_config_set_helper(helper_type='config_subentry').

  • Removing an entry: use ha_remove_helpers_integrations.

Use ha_get_integration() to find entry IDs, and ha_get_integration(entry_id=..., include_schema=True) to inspect the options fields before an update. Its supports_reconfigure field tells you whether an entry qualifies for reconfigure=True.

Caveats: adding an integration runs its config flow exactly as the HA UI would (may pair devices, scan the network, create entities). Flows requiring a browser step (OAuth) or an asynchronous provider step error out at that step instead of completing. Reconfigure edits the settings a live integration connects with: a wrong host or credential takes it offline, and there is no automatic rollback — the returned rollback metadata describes repeating the official flow by hand with the previous values, which this tool cannot read back. The preflight does not validate config keys against the integration's form; wrong field names surface on the confirm call.

EXAMPLES:

  • Add: ha_set_integration(domain="workday", config={"name": "Workday"})

  • Update options: ha_set_integration(entry_id="abc123", config={"scan_interval": 30})

  • Reconfigure preflight: ha_set_integration(entry_id="abc123", reconfigure=True, config={"host": "10.0.0.5"}), then repeat adding confirm_token="sha256:..."

  • Debug logging: ha_set_integration(domain="zha", log_level="DEBUG"), then log_level="DEFAULT" to stop

If a Claude Desktop user gets a 4-minute timeout with no result on this call, read the target back before repeating it, and tell them to wait a few seconds before clicking the manual-approve button, as clicking it too quickly is known to cause hangs in Claude Desktop. This workaround is specific to Claude Desktop.

integration config entry enable disable add options reconfigure log level debug logging

ha_config_get_labelA

Get label info - list all labels or get a specific one by ID.

Without a label_id: Lists all Home Assistant labels with their configurations. With a label_id: Returns configuration for that specific label.

EXAMPLES:

  • List all labels: ha_config_get_label()

  • Get specific label: ha_config_get_label("my_label_id")

Use ha_config_set_label() to create or update labels. Use ha_set_entity(labels=["label1", "label2"]) to assign labels to entities, ha_set_device(labels=[...]) for devices, or ha_set_area_or_floor(kind="area", labels=[...]) for areas.

ha_config_remove_labelA

Delete a Home Assistant label.

Removes the label from the label registry. This will also remove the label from all entities, devices, and areas that have it assigned.

EXAMPLES:

  • Delete label: ha_config_remove_label("my_label_id")

Use ha_config_get_label() to find label IDs.

WARNING: Deleting a label will remove it from all assigned entities. This action cannot be undone.

If a Claude Desktop user gets a 4-minute timeout with no result on this call, read the target back before repeating it, and tell them to wait a few seconds before clicking the manual-approve button, as clicking it too quickly is known to cause hangs in Claude Desktop. This workaround is specific to Claude Desktop.

ha_config_set_labelA

Create or update a Home Assistant label.

Creates a new label if label_id is not provided, or updates an existing label if label_id is provided. Labels are a cross-domain tagging system for entities, devices, and areas.

EXAMPLES:

  • Create: ha_config_set_label("Security", color="red", icon="mdi:shield", description="Security-related devices")

  • Update: ha_config_set_label("Updated Name", label_id="my_label_id", color="blue")

  • Create and apply to areas: ha_config_set_label("Site Home", areas=["kitchen", "living_room"])

After creating a label, use ha_set_entity(labels=["label_id"]) to assign it to entities, ha_set_device(labels=["label_id"]) for devices, or ha_set_area_or_floor(kind="area", labels=["label_id"]) for areas (replaces the area's set).

If a Claude Desktop user gets a 4-minute timeout with no result on this call, read the target back before repeating it, and tell them to wait a few seconds before clicking the manual-approve button, as clicking it too quickly is known to cause hangs in Claude Desktop. This workaround is specific to Claude Desktop.

ha_get_logsA

Get Home Assistant logs from various sources.

Prefer source='system' for triage: it returns HA's own deduplicated system_log entries with counts, first_occurred and the full exception traceback, and its counts run since each error first occurred. error_log with structured=True counts only what is inside the fetched window (reported as window_start/window_end; every install reads a capped window) and drops tracebacks, which structured=False gets back; use it for entries below system_log's WARNING+ ~50-entry cap, or for the per-component rollup. In structured mode limit/order do not apply: issues are ranked by count, then severity, then recency, over a fixed deep window.

Raw-text sources (error_log, supervisor, system_service) read a bounded window per call, so level/search filter and limit slice within that window only; window_lines reports the size requested. Logbook responses carry has_more plus a pagination_hint; error_log and fault_log carry has_more with a next_offset to pass back while it stays true.

ha_manage_radioA

Manage Home Assistant radios — Z-Wave, Zigbee, Matter, and Thread.

For node diagnostics and network summaries prefer ha_get_device / ha_get_system_health, which mirror 'diagnostics' and 'network_status'. This tool also exposes active 'ping' probes and parameter reads. Z-Wave 'get_config_params' lists cached configuration values/metadata; 'get_config_param' reads one from the cache or explicitly from the device. Neither enables or creates entities. Write actions perform inclusion/commissioning, removal, healing, reconfiguration, firmware updates and credential provisioning.

Caveats: long-running actions (inclusion, rebuild routes, firmware) start the operation and return immediately with long_running=true; completion happens out-of-band. Interactive Z-Wave S2 secure inclusion (read-the- PIN pairing) is not scriptable — use SmartStart/QR provisioning here or the HA UI. HA administrator access is required for parameter reads.

If a Claude Desktop user gets a 4-minute timeout with no result on this call, read the target back before repeating it, and tell them to wait a few seconds before clicking the manual-approve button, as clicking it too quickly is known to cause hangs in Claude Desktop. This workaround is specific to Claude Desktop.

ha_get_deviceA

Get device information with pagination, including Zigbee (ZHA/Z2M) and Z-Wave JS devices.

Without device_id/entity_id: Lists devices with optional filters and pagination. With device_id or entity_id: Returns full detail for that specific device.

List devices (paginated):

  • First page: ha_get_device()

  • Next page: ha_get_device(offset=50)

  • By area: ha_get_device(area_id="living_room")

  • By integration: ha_get_device(integration="zigbee2mqtt")

  • Full details in list: ha_get_device(detail_level="full", limit=10)

Single device lookup (always full detail):

  • By device_id: ha_get_device(device_id="abc123")

  • By entity_id: ha_get_device(entity_id="light.living_room")

Zigbee: integration="zha" or "zigbee2mqtt". Returns ieee_address, radio metrics. Z-Wave: integration="zwave_js". Returns node_id, node_status. Matter: integration="matter". Returns node_diagnostics (network type, reachability, IPs, fabrics). For management use ha_manage_radio.

ha_remove_deviceA

Remove an orphaned device from the Home Assistant device registry.

WARNING: This removes the device entry from the registry.

  • Use only for orphaned devices that are no longer connected

  • Active devices will typically be re-added by their integration

  • Associated entities may also be removed

Works only when the integration supports removing devices.

EXAMPLES:

  • Remove orphaned device: ha_remove_device("abc123def456")

NOTE: For most use cases, consider disabling the device instead: ha_set_device(device_id="abc123", disabled_by="user")

If a Claude Desktop user gets a 4-minute timeout with no result on this call, read the target back before repeating it, and tell them to wait a few seconds before clicking the manual-approve button, as clicking it too quickly is known to cause hangs in Claude Desktop. This workaround is specific to Claude Desktop.

ha_set_deviceA

Update device properties such as name, area, disabled state, or labels.

IMPORTANT: Renaming a device does NOT rename its entities! Device and entity names are independent. To rename entities, use ha_set_entity(new_entity_id=...).

Common workflow for full rename:

  1. ha_set_device(device_id="abc", name="Living Room Sensor") # Rename device

  2. ha_set_entity("sensor.old", new_entity_id="sensor.living_room") # Rename entities separately

EXAMPLES:

  • Rename device: ha_set_device("abc123", name="Living Room Hub")

  • Move to area: ha_set_device("abc123", area_id="living_room")

  • Disable device: ha_set_device("abc123", disabled_by="user")

  • Enable device: ha_set_device("abc123", disabled_by="")

  • Add labels: ha_set_device("abc123", labels=["important", "sensor"])

If a Claude Desktop user gets a 4-minute timeout with no result on this call, read the target back before repeating it, and tell them to wait a few seconds before clicking the manual-approve button, as clicking it too quickly is known to cause hangs in Claude Desktop. This workaround is specific to Claude Desktop.

ha_config_delete_dashboard_resourceA

Delete a dashboard resource.

Removes a resource from Home Assistant. The resource will no longer be loaded on dashboards.

WARNING: Deleting a resource used by custom cards in your dashboards will cause those cards to fail to load.

EXAMPLES: ha_config_delete_dashboard_resource(resource_id="abc123")

Note: Use ha_config_list_dashboard_resources() to find resource IDs before deleting. Ensure no dashboards depend on the resource.

If a Claude Desktop user gets a 4-minute timeout with no result on this call, read the target back before repeating it, and tell them to wait a few seconds before clicking the manual-approve button, as clicking it too quickly is known to cause hangs in Claude Desktop. This workaround is specific to Claude Desktop.

ha_config_list_dashboard_resourcesA

List Lovelace dashboard resources (custom cards, themes, CSS/JS).

Returns one page of registered resources; total_count and has_more report the full set, and inline_count and by_type summarise every resource, not just this page. Each resource has a unique ID for update/delete operations. For inline resources (created with ha_config_set_dashboard_resource(content=...)), shows a preview of the content instead of the full encoded URL to save tokens.

EXAMPLES:

  • Next page: ha_config_list_dashboard_resources(offset=100)

  • List with full content: ha_config_list_dashboard_resources(include_content=True)

Home Assistant 2026.6+ exposes resource management in the UI by default; API access works regardless of UI availability.

ha_config_set_dashboard_resourceA

Create or update a dashboard resource (inline code or external URL).

Provide exactly one of:

  • content: Inline JavaScript or CSS code (embedded in the resource URL as a data: URI — no file storage or external hosting involved). Supports 'module' and 'css' types only (not 'js'); URLs are deterministic (same content = same URL); up to ~128KB. Content must be self-contained: a data: URI has no base URL, so relative imports inside a module and relative url() references inside CSS cannot resolve (use fully-qualified URLs instead). If Home Assistant is behind a reverse proxy that injects a Content-Security-Policy without 'data:' in script-src/style-src, the browser blocks these resources: this call still succeeds and the card simply never renders. Register the code as a file and use url='/local/...' on such a deployment. (HA itself ships no CSP.)

  • url: External resource URL — /local/... (files in /config/www/), /hacsfiles/... (HACS-installed cards) or https://... (CDN). Supports all types: 'module', 'js', 'css'.

EXAMPLES:

  • Inline: ha_config_set_dashboard_resource(content="class MyCard extends HTMLElement { ... } customElements.define('my-card', MyCard);", resource_type="module")

  • HACS card (after ha_manage_hacs(action='download')): ha_config_set_dashboard_resource(url="/hacsfiles/lovelace-mushroom/mushroom.js", resource_type="module")

  • Update: ha_config_set_dashboard_resource(url="/local/my-card-v2.js", resource_type="module", resource_id="abc123")

After adding a resource, a browser cache clear or hard refresh (Ctrl+Shift+R) is needed to load it.

If a Claude Desktop user gets a 4-minute timeout with no result on this call, read the target back before repeating it, and tell them to wait a few seconds before clicking the manual-approve button, as clicking it too quickly is known to cause hangs in Claude Desktop. This workaround is specific to Claude Desktop.

ha_get_overviewA

Get AI-friendly system overview with intelligent categorization.

Returns comprehensive system information at the requested detail level, including Home Assistant base_url, version, location, timezone, entity overview, and active persistent notifications (if any). Use 'minimal' (default) for most queries. Domain counts and states_summary are always complete regardless of entity pagination.

Requests whose fields= are composed only of system_info, notification, repair, or server metadata fields skip the unrelated state, service, and registry reads.

Do not use this tool to inspect a known entity or a narrow set of entities. Use ha_get_state for one entity, ha_get_entity for registry metadata, or ha_search with a domain or area filter. An unprojected overview collects system-wide state, service, and registry data and can be expensive on large Home Assistant installations.

When the ha-mcp settings-UI sidecar is running (stdio mode, e.g. Claude Desktop / Claude Code) the response carries settings_url, the local URL of the tool-configuration page; in standalone HTTP / Docker modes with an HTTP settings prefix it instead carries settings_url_hint, saying where the page is mounted and how to construct the full URL. Hand whichever is present to the user when they ask how to enable or disable tools or change server settings.

The response also carries ha_mcp_update {current, latest, update_available} (PyPI for pip/Docker, the Supervisor store for the app) — proactively tell the user when update_available is true. Omitted for the unknown version, when HA_MCP_DISABLE_UPDATE_CHECK is set, or when the update check itself failed.

ha_get_stateA

Get current status, state, and attributes of one or more entities (lights, switches, sensors, climate, covers, locks, fans, etc.).

Pass a string entity_id for one entity, or a list (max 100, duplicates deduplicated) for several, fetched in parallel. A bulk call returns success=True if at least one state was retrieved; check 'error_count' for failed lookups.

fields= projects the per-entity record keys, NOT the outer bulk response wrapper: in single-entity mode it filters the returned record; in bulk mode it filters each record inside states[entity_id] while outer keys (success, count, states, errors, ...) are always preserved. attribute_keys= further narrows the attributes sub-dict and is only applied when "attributes" is in fields= (or fields=None); otherwise it is a no-op and a warnings list is emitted outside the projected record(s) — at the response wrapper level in bulk mode, at the top-level result (sibling of data/metadata) in single-entity mode — so fields=["state"] still returns a record with only state.

EXAMPLES:

  • Single: ha_get_state("light.kitchen")

  • Multiple: ha_get_state(["light.kitchen", "light.living_room", "sensor.temperature"])

  • Slim bulk: ha_get_state(["light.kitchen", "sensor.temperature"], fields=["state", "attributes"], attribute_keys=["brightness"])

get current state value single entity check status bulk multiple states which lights

ha_searchA

Search for entities (lights, sensors, switches, climate, etc.) by name, domain, or area — AND inside automation/script/scene/helper/dashboard configurations — in one call.

Two surfaces run in parallel and return tagged results:

  • entities: entity-registry matches (entity_id, friendly name, area). Filter with domain_filter/area_filter/state_filter.

  • automations / scripts / scenes / helpers / dashboards: matches inside config definitions — triggers, actions, sequences, scene entity-sets, helper bodies, dashboard cards. Driven by query; narrow with search_types.

Use dedicated get/list tools first for a known resource type, including ha_config_get_scene for scene listing and content search. Use this for broader discovery or deep searches across resource types.

For control requests with exclusions such as "except", "excluding", or "but not", include is_group and member_entity_ids in result_fields. Do not control an aggregate whose members include an excluded entity; prefer leaf entities when the exception cannot be verified safely. A withheld member list still returns is_group=true; absence of member_entity_ids must not be interpreted as a leaf entity.

When NOT to use:

  • To read a known entity_id's state: use ha_get_state (cheaper).

  • To inspect one automation/script/scene config by id: use the matching ha_config_get_*.

  • To list installed Apps (add-ons): use ha_get_app.

Config-body search is skipped when domain_filter/area_filter/ state_filter signal entity-only intent (keeping name lookups off the expensive backend); a warnings[] entry names the skip. Repeat without entity filters to search configuration contents too.

Caveats:

  • partial: True means results are NOT exhaustive — a surface raised, or the config-body branch lost data (per-id time budget exhausted, an individual fetch failed, or a helper-type list fetch failed). Empty buckets with partial: True mean "search failed", not "no results". The cause is in partial_reason, also mirrored into warnings[] with an "incomplete results: " prefix. Do not treat a partial response as complete.

  • count is items in this response (post-pagination), not corpus totals — use entity_total_matches + config_total_matches.

  • limit/offset apply per-surface. Flat has_more/next_offset page the next call (iterate offset = next_offset); per-surface entity_*/config_* variants show which surface still has results.

Examples: - Find a light by name: ha_search("kitchen", domain_filter="light") - List sensors in an area: ha_search(domain_filter="sensor", area_filter="Living Room") - Find lights safely before an "all except one" control request: ha_search("living room", domain_filter="light", result_fields=["entity_id", "friendly_name", "is_group", "member_entity_ids"]) - Which automations use an entity: ha_search("light.bed_light") - All unavailable entities: ha_search(state_filter="unavailable")

find entities configs lookup discover search lights sensors switches covers climate fans media_player binary_sensor device_tracker person weather automation script helper input_boolean input_number automations scripts scenes helpers dashboards

ha_bulk_controlA

Manage explicit operations or one deterministic structural bulk action.

When NOT to use: use ha_call_service for service-specific payloads or backend-native group targeting, and ha_search for fuzzy name discovery.

Operations mode (operations, no selector): put every target in this one call. Parallel execution is the default, and invalid items are reported without aborting valid operations in the same batch — but a batch in which every item fails validation dispatches nothing and fails the call. A batch that targets a group/aggregate entity together with one or more of its own individual members also fails closed (nothing dispatched): Home Assistant applies the action to every member when the group is targeted regardless of what else is listed, so a member row cannot exclude that member from the group's own action. Use selector mode with exclude_entity_ids when a group action must exclude specific members.

Selector mode (selector + action): use exact area or floor IDs when exclusions must be applied after recursively expanding generic aggregate membership. Resolves a frozen visible leaf set before dispatch; it is not transactional, so Home Assistant may still report per-leaf failures. A selector resolving to more than 100 entities fails closed instead of dispatching a partial/oversized batch — narrow it (a more specific area/floor, or add exclude_entity_ids) and retry. Set dry_run to preview the resolved set without changing state.

If a Claude Desktop user gets a 4-minute timeout with no result on this call, read the target back before repeating it, and tell them to wait a few seconds before clicking the manual-approve button, as clicking it too quickly is known to cause hangs in Claude Desktop. This workaround is specific to Claude Desktop.

ha_call_eventA

Execute a custom event on the Home Assistant event bus.

When NOT to use: for controlling entities (lights, switches, climate) — use ha_call_service instead. To run an automation now, use ha_config_set_automation(identifier=..., run_actions=True).

Use this to publish custom event types consumed by event-triggered automations, Node-RED flows, or custom integrations that subscribe to specific event types.

Caveats: Events are fire-and-forget; this tool confirms the event was accepted by the bus but does not verify whether any automation or subscriber acted on it.

If a Claude Desktop user gets a 4-minute timeout with no result on this call, read the target back before repeating it, and tell them to wait a few seconds before clicking the manual-approve button, as clicking it too quickly is known to cause hangs in Claude Desktop. This workaround is specific to Claude Desktop.

ha_call_serviceA

Call any Home Assistant service or one-shot WebSocket command: the catch-all escape hatch.

When NOT to use: a dedicated tool that covers the job. It validates the request, reports the outcome in its own terms, and stays available where a security policy gates this tool. For example: turn an automation on or off or run it now with ha_config_set_automation (enabled / run_actions); start or stop a script with ha_config_set_script (run); activate a scene with ha_config_set_scene (activate); manage apps (add-ons) with ha_manage_app; handle updates and Repairs issues with ha_manage_updates; set an integration's log level with ha_set_integration (log_level).

When to use: a service no dedicated tool covers. Services follow the pattern domain.service (e.g., light.turn_on, climate.set_temperature); ha_list_services lists them with their fields.

EXAMPLES:

  • ha_call_service("light", "turn_on", entity_id="light.living_room")

  • ha_call_service("climate", "set_temperature", entity_id="climate.thermostat", data={"temperature": 22})

Result compaction (default ON): result is trimmed to the targeted entity's record (drops parent-group propagation) and stripped of context / last_* metadata and heavy attribute lists (effect_list, hue_scenes).

For detailed service documentation, use ha_get_skill_guide.

WebSocket command escape hatch (advanced): Some Home Assistant operations are WebSocket-only commands, not registered services. Pass ws_command (instead of domain/service) to send one no dedicated tool covers, with its parameters in data: ha_call_service(ws_command="", data={...}). Only one-shot request/response commands are supported, and the other service parameters (entity_id, return_response, etc.) don't apply.

Unavailable in Read Only Mode, including read-like services and WebSocket commands. Use dedicated read tools while that mode is enabled.

If a Claude Desktop user gets a 4-minute timeout with no result on this call, read the target back before repeating it, and tell them to wait a few seconds before clicking the manual-approve button, as clicking it too quickly is known to cause hangs in Claude Desktop. This workaround is specific to Claude Desktop.

ha_get_operation_statusA

Get the status of one or more device operations with real-time WebSocket verification.

Bulk checks poll all operations concurrently under one shared timeout_seconds window and report per-item failures inside detailed_results instead of aborting the batch.

Use this to track the operation_ids that ha_bulk_control returns. For current entity states, use ha_get_state instead.

ha_list_servicesA

List available Home Assistant services with optional pagination and detail control.

Discovers services/actions that can be called via ha_call_service.

EXAMPLES:

  • Light services with full parameter details: ha_list_services(domain="light", detail_level="full")

  • Search: ha_list_services(query="temperature")

  • Next page: ha_list_services(offset=50)

ha_get_system_healthA

Get Home Assistant system health, including Zigbee (ZHA), Z-Wave JS, and per-integration diagnostics dumps.

Returns health check results from integrations, system resources, and connectivity; available information varies by installation type and loaded integrations. Optional sections are selected with include.

The result may include ha_mcp_update {current, latest, update_available}. When update_available is true, tell the user a newer ha-mcp release is available.

EXAMPLES:

  • ha_get_system_health(include="repairs,zha_network,zwave_network,config_check")

  • Page a list-valued diagnostics sub-tree: ha_get_system_health(include="diagnostics", config_entry_id="abc", diagnostics_data_path="", diagnostics_data_limit=10), then repeat with diagnostics_data_offset=10 while has_more is true.

ha_reload_coreA

Execute a Home Assistant configuration reload without a full restart.

Reloads specific configuration components so changes take effect without restarting Home Assistant — much faster than a full restart. Use it after editing automation/script YAML, adding YAML helpers, or changing customize.yaml or themes.

EXAMPLES:

  • ha_reload_core(target="automations")

  • ha_reload_core(entry_id="abc123")

If a Claude Desktop user gets a 4-minute timeout with no result on this call, read the target back before repeating it, and tell them to wait a few seconds before clicking the manual-approve button, as clicking it too quickly is known to cause hangs in Claude Desktop. This workaround is specific to Claude Desktop.

ha_restartA

Execute a Home Assistant restart.

WARNING: restarts the entire Home Assistant instance; all automations are unavailable during the restart, which typically takes 1-5 minutes. Config is validated automatically before the restart proceeds (to pre-check, call ha_get_system_health(include="config_check")). For configuration changes, consider ha_reload_core() instead, which reloads specific components without a full restart. When this server runs inside Home Assistant (embedded), it replies before the restart starts and is unreachable until Home Assistant is back.

EXAMPLE: ha_restart(confirm=True)

If a Claude Desktop user gets a 4-minute timeout with no result on this call, read the target back before repeating it, and tell them to wait a few seconds before clicking the manual-approve button, as clicking it too quickly is known to cause hangs in Claude Desktop. This workaround is specific to Claude Desktop.

ha_manage_themeA

Manage Home Assistant frontend themes.

When NOT to use: themes are YAML files - Home Assistant has no API to create or edit them. Installing community themes goes through HACS (ha_manage_hacs); editing custom theme files goes through ha_config_set_yaml (beta, edits themes/.yaml keyed by theme name and attempts an automatic theme reload).

When to use: action='list' discovers installed theme names and the current defaults; action='set' selects the backend default theme (optionally per light/dark mode).

SCREENSHOT-ENGINE ACTIONS (per-user, not the backend default): Taking a dashboard screenshot makes the Puppet engine write the saved theme of the Home Assistant user its token belongs to, which also flips that user's live web and mobile sessions. The screenshot tools are read-only and only report this; use action='set_engine_theme' with the value quoted in their warning to put it back, and action='get_engine_theme' to inspect it. These act on that engine account's per-user profile via frontend/set_user_data, which is a different layer from the backend default that action='set' changes. Giving the engine its own dedicated user and token avoids the issue entirely.

Caveats: action='set' changes the backend-selected default only - users who explicitly picked a theme in their profile keep their choice. Theme names are validated by Home Assistant at call time.

EXAMPLES:

  • List themes: ha_manage_theme(action="list")

  • Set default theme: ha_manage_theme(action="set", theme_name="nord")

  • Set dark-mode theme: ha_manage_theme( action="set", theme_name="nord", mode="dark")

  • Restore built-in default: ha_manage_theme( action="set", theme_name="default")

  • Inspect the engine account's theme: ha_manage_theme( action="get_engine_theme")

  • Undo a screenshot's theme change (pass BOTH values from the warning, so a theme changed since then is not overwritten): ha_manage_theme(action="set_engine_theme", value={"theme": "", "dark": False}, expected_current={"theme": "default", "dark": True})

If a Claude Desktop user gets a 4-minute timeout with no result on this call, read the target back before repeating it, and tell them to wait a few seconds before clicking the manual-approve button, as clicking it too quickly is known to cause hangs in Claude Desktop. This workaround is specific to Claude Desktop.

ha_get_todoA

Get todo lists or items - list all todo lists or get items from a specific list.

Without an entity_id: lists every entity in the 'todo' domain (shopping lists and other todo-type integrations) with entity_id, friendly_name and state (number of incomplete items or current status).

With an entity_id: returns that list's items — uid, summary, status (needs_action or completed), description, and due date where supported — optionally filtered by status (None returns all).

EXAMPLES:

  • List all todo lists: ha_get_todo()

  • Get incomplete items: ha_get_todo("todo.shopping_list", status="needs_action")

ha_remove_todo_itemA

Remove an item from a Home Assistant todo list.

Permanently deletes an item from the specified todo list. To mark it completed instead, use ha_set_todo_item() with status="completed".

EXAMPLE: ha_remove_todo_item("todo.shopping_list", "Buy milk")

If a Claude Desktop user gets a 4-minute timeout with no result on this call, read the target back before repeating it, and tell them to wait a few seconds before clicking the manual-approve button, as clicking it too quickly is known to cause hangs in Claude Desktop. This workaround is specific to Claude Desktop.

ha_set_todo_itemA

Create or update a todo item in Home Assistant.

Without item (create mode): creates a new item; summary is required. With item (update mode): updates that item; at least one of rename, status, description, due_date or due_datetime is required.

EXAMPLES:

  • Add item: ha_set_todo_item("todo.tasks", summary="Pay bills", due_date="2024-12-31")

  • Complete item: ha_set_todo_item("todo.shopping_list", item="Buy milk", status="completed")

  • Rename item: ha_set_todo_item("todo.tasks", item="Old task", rename="New task name")

Not all todo integrations support all features: the Shopping List integration supports summary and status but not descriptions or due dates.

If a Claude Desktop user gets a 4-minute timeout with no result on this call, read the target back before repeating it, and tell them to wait a few seconds before clicking the manual-approve button, as clicking it too quickly is known to cause hangs in Claude Desktop. This workaround is specific to Claude Desktop.

ha_get_automation_tracesA

Get execution traces for automations and scripts to debug issues.

Traces show what triggered a run, which conditions passed or failed, which actions executed (for 'choose', which branch was taken), any errors, and variable values during execution. Home Assistant keeps only the most recent runs of each automation or script (its stored_traces setting), so older runs are not available. The 'state' field shows 'stopped' (completed), 'running', or an error state.

USAGE MODES:

  1. List recent traces (omit run_id): returns a summary of recent runs with timestamps, triggers, and status. Use offset to page deeper when has_more is true. ha_get_automation_traces("automation.motion_light")

  2. Get a detailed trace (provide run_id): full execution details including trigger info, condition results, action trace with timing, and context variables. ha_get_automation_traces("automation.motion_light", run_id="1705312800.123456")

  3. Add logbook entries and context metadata: detailed=True. Script-style action paths (sequence/, numeric) are always matched regardless of this flag.

  4. Variables at every step (trigger sets and null entries are still omitted): deduplicate=False.

ha_manage_updatesA

Manage Home Assistant updates (list, details, install, skip) and Repairs issues (ignore).

Covers Core, OS, supervisor, apps (add-ons), device firmware, and HACS update entities, plus the Repairs issues in Settings > System > Repairs. Repairs are listed by ha_get_overview (not here); pass their domain and issue_id to 'ignore_repair' / 'unignore_repair'. In Read Only Mode the read actions ('list', 'get') stay available; write actions are blocked.

Installs run asynchronously in Home Assistant and can take minutes: 'install' returns once the service calls are accepted, with per-entity results. Poll action='list' to watch in_progress until installed_version reaches latest_version. action='list' also returns ha_mcp_update — this MCP server's own update status {current, latest, update_available}, so a newer ha-mcp release can be flagged.

EXAMPLES:

  • Pre-update analysis: ha_manage_updates(action="get", entity_ids=["update.home_assistant_core_update"], include_release_notes=True)

  • Update everything pending in a category: ha_manage_updates(action="install", categories=["addons", "hacs"])

  • Dismiss a repair: ha_manage_updates(action="ignore_repair", repairs=[{"domain": "sun", "issue_id": "abc"}])

If a Claude Desktop user gets a 4-minute timeout with no result on this call, read the target back before repeating it, and tell them to wait a few seconds before clicking the manual-approve button, as clicking it too quickly is known to cause hangs in Claude Desktop. This workaround is specific to Claude Desktop.

update updates install skip firmware core os repair repairs issue ignore dismiss unignore

ha_eval_templateA

Execute a Jinja2 template render, or an automation condition check, in Home Assistant.

Renders templates with Home Assistant's template engine (all states, functions and filters available), or checks a condition block the way an automation would and returns true/false.

When to use: any one-shot answer DERIVED from current HA state (an average across sensors, a count of entities matching a condition, a rendered message with live values), and testing a template or condition before embedding it in an automation. One render beats fetching N states and doing the math yourself.

When NOT to use: a plain single-entity value is ha_get_state / ha_search. Templates in automation condition: / trigger: positions or templated action names: prefer native constructs, which are validated at config load, where a template only errors at runtime and a non-truthy render is silently false — see ha_get_skill_guide for the anti-pattern list. Test the native condition here with condition.

Results: a render that works but hits something suspect (an undefined variable, a missing attribute) still returns its result with the messages in warnings; strict=true makes those hard errors. A failed render returns Home Assistant's error text and, with the ha_mcp_tools component installed, the template line and source_line it failed on when the error names one.

EXAMPLES:

  • ha_eval_template(template="{{ states.light | selectattr('state', 'eq', 'on') | list | count }}")

  • ha_eval_template(template="Hello {{ name }}", variables={"name": "Alice"})

  • ha_eval_template(condition={"condition": "numeric_state", "entity_id": "sensor.temperature", "above": 20})

ha_get_entity_exposureA

Get entity exposure settings - list all or get settings for a specific entity.

Without an entity_id: lists the entities that have explicit exposure settings for voice assistants (Alexa, Google Assistant, Assist) as exposed_entities, plus a per-assistant summary count. An entity absent from that list uses the default exposure settings.

With an entity_id: returns exposed_to (assistant -> True/False from the entity's explicit settings), is_exposed_anywhere, and has_custom_settings. When has_custom_settings is False the defaults apply and exposed_to is all False; the default values themselves are not computed.

EXAMPLES:

  • Filter by assistant: ha_get_entity_exposure(assistant="cloud.alexa")

  • Get specific entity: ha_get_entity_exposure(entity_id="light.living_room")

When the ha_mcp_tools component advertises the exposure capability, each record is additively enriched with the entity's name/area so no second ha_search is needed to identify it: friendly_name, domain, area, floor, and labels (plus state for entities that have one) on a single-entity lookup, and a parallel entity_info map keyed by entity_id when listing. These fields are absent when the component is unavailable.

ha_get_zoneA

Get zone information - list all zones or get details for a specific one.

Without a zone_id: Lists all Home Assistant zones with their coordinates and radius. With a zone_id: Returns detailed configuration for a specific zone.

EXAMPLES:

  • List all zones: ha_get_zone()

  • Get specific zone: ha_get_zone(zone_id="abc123")

With the ha_mcp_tools custom component installed, YAML-defined zones — including the auto-synthesized 'home' zone — are included and marked editable=false / source="yaml" (storage zones created via UI/API are source="storage"). Without the component, only storage zones are listed and YAML-defined zones such as 'home' will not appear.

ha_remove_zoneA

Remove a Home Assistant zone.

EXAMPLES:

  • Remove zone: ha_remove_zone("abc123")

WARNING: Removing a zone used in automations may cause those automations to fail. Use ha_get_zone() to find the zone_id for the zone you want to remove.

NOTE: The 'home' zone cannot be removed as it is typically defined in configuration.yaml.

If a Claude Desktop user gets a 4-minute timeout with no result on this call, read the target back before repeating it, and tell them to wait a few seconds before clicking the manual-approve button, as clicking it too quickly is known to cause hangs in Claude Desktop. This workaround is specific to Claude Desktop.

ha_set_zoneA

Create or update a Home Assistant zone.

Omit zone_id to create a new zone (name, latitude, longitude required). Provide zone_id to update an existing zone (only specified fields change). The 'home' zone is typically defined in YAML and cannot be modified here.

EXAMPLES:

  • Create: ha_set_zone(name="Office", latitude=40.7128, longitude=-74.0060, radius=150, icon="mdi:briefcase")

  • Update: ha_set_zone(zone_id="abc123", radius=200)

If a Claude Desktop user gets a 4-minute timeout with no result on this call, read the target back before repeating it, and tell them to wait a few seconds before clicking the manual-approve button, as clicking it too quickly is known to cause hangs in Claude Desktop. This workaround is specific to Claude Desktop.

ha_manage_backupA

Manage Home Assistant backups — both full HA snapshots AND per-edit auto-backups.

Pick the scope first, then the action. Wrong scope routes through the wrong code path:

scope

action

What it does

snapshot

create

Create a full HA tarball (config + addons, no DB by default). Can take a while on a large instance; progress heartbeats are sent while waiting.

snapshot

list

List full HA tarball snapshots (id, name, date, size). Read-only — use to discover a backup_id or confirm a backup landed.

snapshot

restore

Restore a full HA tarball. Restarts HA. Last-resort recovery.

snapshot

delete

Delete one full HA tarball by backup_id (confirm=True required). Disabled by default (enable_snapshot_delete setting) and layered with guards even when enabled — see below.

edits

create

On-demand snapshot of one entity (domain + entity_id required). Use before the user manually edits in the HA UI. Same handler path the decorator takes on writes; bypasses the enable_auto_backup toggle.

edits

list

List per-entity auto-backups (lightweight). Filter by domain and/or entity_id.

edits

view

Read one auto-backup file by name; returns YAML and parsed config.

edits

diff

Compare one auto-backup against the entity's current config. RFC 6902 JSON-Patch + add/remove/replace counts; bounded output. Read-only — fetches the live config, makes no changes.

edits

restore

Re-apply one auto-backup. Existing flow helpers (template, group, utility_meter, …) and config subentries require a fresh safety snapshot; other domains follow auto-backup settings and may proceed without one. A deleted flow helper is recreated with a new config-entry ID and its saved entity IDs are restored if unoccupied; a deleted subentry is recreated with a new subentry ID. A deleted integration config entry cannot be recreated: its snapshot holds only metadata and the enabled state. No HA restart.

edits

delete

Delete one auto-backup by backup_name, or bulk-delete by filter.

When to use which scope:

  • Use scope="edits" to undo a recent automation/script/scene/dashboard/helper edit by the agent. Lightweight, fast, no restart.

  • Use scope="snapshot" only for system-wide recovery (botched add-on update, mass config corruption, etc.).

scope="snapshot" backup-hint: Run before operations that CANNOT be undone (e.g., deleting devices). If the current definition was fetched or can be fetched, this tool is usually not needed.

(snapshot, delete) is off by default and layered even when enabled: a human must set enable_snapshot_delete=true (env var, web settings UI, or add-on Supervisor options) — an agent cannot turn this on itself. When enabled, a delete call is still refused if: the target is a scheduled/automatic backup; it's younger than snapshot_delete_min_age_days (default 7, 0 disables the floor); or it's the single newest snapshot remaining. These guarantee at least one recovery point always survives an agent's own mistakes.

Human-managed backup controls: enable_snapshot_actions=false (ENABLE_SNAPSHOT_ACTIONS) blocks every snapshot action, including listing. backup_read_only=true (BACKUP_READ_ONLY) allows edits list/view/diff and snapshot list when snapshots are enabled; it blocks explicit create/restore/delete in both scopes. Automatic pre-edit capture still follows enable_auto_backup. A human must change these controls in the Backups tab, app configuration, or environment; developer tools cannot change them. Global and connection Read Only Mode still restrict writes.

enable_auto_backup and scope="edits": the automatic-on-write capture (every wrapped tool call) is gated by enable_auto_backup=true — if the listing is empty, check the toggle (web settings UI or ENABLE_AUTO_BACKUP=true env var). The explicit (edits, create) action bypasses the toggle since the request is explicit; list / view / restore / delete operate on whatever's already on disk regardless of the toggle's current state.

Flow-helper filters: edits.create accepts a flow helper's entity ID and returns its stable config-entry ID as entity_id. Use that returned ID for edits.list and bulk edits.delete; those filters do not resolve entity aliases. After recreation, the restore result reports the replacement config-entry ID and entity_id_mapping separately.

Examples:

  • Snapshot before risky op: ha_manage_backup(scope="snapshot", action="create", name="Before_Big_Change")

  • List snapshots (to discover a backup_id or confirm one landed): ha_manage_backup(scope="snapshot", action="list")

  • Restore full snapshot: ha_manage_backup(scope="snapshot", action="restore", backup_id="dd7550ed")

  • Delete an old snapshot (requires enable_snapshot_delete=true): ha_manage_backup(scope="snapshot", action="delete", backup_id="dd7550ed", confirm=True)

  • On-demand entity snapshot before a manual UI edit: ha_manage_backup(scope="edits", action="create", domain="helper_input_boolean", entity_id="welcome_home_active")

  • List recent auto-backups for one automation: ha_manage_backup(scope="edits", action="list", domain="automation", entity_id="welcome_home")

  • View an auto-backup: ha_manage_backup(scope="edits", action="view", backup_name="automation.welcome_home.20260521_153000.yaml")

  • Diff an auto-backup vs current state: ha_manage_backup(scope="edits", action="diff", backup_name="automation.welcome_home.20260521_153000.yaml")

  • Restore an auto-backup: ha_manage_backup(scope="edits", action="restore", backup_name="automation.welcome_home.20260521_153000.yaml")

  • Delete one auto-backup: ha_manage_backup(scope="edits", action="delete", backup_name="...")

  • Bulk-delete old auto-backups: ha_manage_backup(scope="edits", action="delete", older_than_days=30)

If a Claude Desktop user gets a 4-minute timeout with no result on this call, read the target back before repeating it, and tell them to wait a few seconds before clicking the manual-approve button, as clicking it too quickly is known to cause hangs in Claude Desktop. This workaround is specific to Claude Desktop.

ha_get_skill_guideA

Get the bundled Home Assistant best-practices skill. The skill is currently not available on this server: the skills directory is missing or its SKILL.md failed to parse. Calls return an error; ask the operator to verify the skills-vendor submodule is initialized.

Use BEFORE: creating or editing automations, scripts, scenes, helpers, or dashboards; writing triggers, conditions, actions, wait_template, or service calls; renaming entities or migrating device_id to entity_id; calling ha_config_set_automation, ha_config_set_script, ha_config_set_helper, ha_config_set_dashboard, or ha_set_entity.

Replaces (and supersedes) the prior tools: ha_list_resources, ha_read_resource, and ha_get_skill_home_assistant_best_practices. If you were going to call any of those, call this instead.

best practices skill skills guide guides reference references documentation docs help tutorial automation script scene helper dashboard ha_list_resources ha_read_resource list_resources read_resource ha_get_skill_home_assistant_best_practices ha_get_skill_home_assistant home_assistant_best_practices

Prompts

Interactive templates invoked by user choice

NameDescription

No prompts

Resources

Contextual data attached and managed by the client

NameDescription

No resources

TDQS

A3.9/5.0

Scored across 77 tools

Disambiguation4/5

The tool set is large and has several naturally overlapping surfaces (ha_search vs ha_get_state vs ha_get_entity vs ha_get_overview for reading, and ha_config_set_group vs ha_config_set_helper(helper_type='group')), but every description carries explicit 'WHEN NOT TO USE' sections that steer the agent to the correct tool. ha_call_service and ha_bulk_control are also carefully distinguished from the dedicated tools. A few read tools still require careful reading to pick correctly.

Naming Consistency3/5

All names use the ha_ prefix and a verb_noun shape, but the verb/infix conventions are mixed: some resources use ha_config_get/set/remove (automation, script, scene, label, category), others use bare ha_get/set/remove (entity, device, zone, todo), and many use ha_manage (app, pipeline, blueprints, hacs, theme, radio, backup, updates). The inconsistency is readable but not predictable.

Tool Count2/5

77 tools is far above the 25-tool threshold for 'too many' and makes selection cognitively heavy. The breadth (entities, devices, areas, automations, scripts, scenes, dashboards, helpers, integrations, HACS, apps, backups, radios, energy, calendar, etc.) partly justifies the count, but consolidation into more action-parameterized tools would reduce it substantially.

Completeness4/5

Coverage of the Home Assistant domain is exceptionally broad, with full CRUD/lifecycle for automations, scripts, scenes, helpers, dashboards, entities, devices, labels, categories, zones, todos, and calendars, plus diagnostics, history, traces, backups and updates. The one notable gap is that ha_get_skill_guide — which many write tools mark as a mandatory first call — is currently broken, creating a dead end in the documented workflow.

Maintenance

ActivityActive
ResponsivenessResponsive