Home Assistant MCP Server
OfficialA comprehensive MCP server that lets AI assistants control, configure, build, monitor, and debug a Home Assistant smart home via natural language.
Control devices and services: Call any Home Assistant service (
ha_call_service), bulk-control entities (ha_bulk_control), fire custom events, and check operation status.Query states and history: Get current entity states/attributes, search entities and config bodies, retrieve history, statistics, logs, and automation traces.
Manage automations, scripts, scenes, and blueprints: Create, read, update, delete, take control of blueprints, and debug with traces.
Build and edit dashboards: Create/update/delete Lovelace dashboards, manage cards and resources, and capture screenshots.
Manage helpers and integrations: Create/update/remove 30+ helper types, config entries, subentries, and config flows.
Organize the home: Manage areas, floors, zones, labels, categories, groups, device/entity registries, and voice-assistant exposure.
Monitor media and environment: Capture camera snapshots, read calendar events, manage todo lists, and inspect energy dashboard preferences.
Administer the system: Manage apps/add-ons, HACS repositories, backups (snapshots and per-edit), updates, themes, reloads, and restarts.
Advanced tooling: Evaluate Jinja2 templates, manage radios (Z-Wave/Zigbee/Matter/Thread), report issues, and access best-practice skill guides.
Flexible safety and deployment: Read-only mode, per-tool enable/disable, security policies, and opt-in file/YAML editing via the HA-MCP custom component.
Enables AI assistants to interact with Home Assistant, allowing natural language control of smart home devices, state queries, service execution, and automation management.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Home Assistant MCP Serverturn off the kitchen lights"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Breaking change (v7.3.0):
ha_config_set_yamlhas been moved to beta.
The Unofficial and Awesome Home Assistant MCP Server

๐ Get Started
The recommended way to run ha-mcp is the HA-MCP Custom Component. It installs into Home Assistant through HACS, runs the full server in-process, and works on every Home Assistant installation type โ Home Assistant OS, Supervised, Container, and Core โ with full feature parity. It is the easiest setup in every case, with no access token to manage.
Add it to Home Assistant via HACS (the preferred install):
Quick start:
Install the HA-MCP Custom Component from HACS โ click the badge above, or in HACS open Integrations โ โฎ โ Custom repositories, add
https://github.com/homeassistant-ai/ha-mcp-integration(category: Integration), then Download.Restart Home Assistant.
Go to Settings โ Devices & Services โ Add Integration, search for HA-MCP Custom Component, choose HA-MCP Server, and click Submit. Creating the entry starts the server.
Copy the connect URL from the entry's Configure screen (Settings โ Devices & Services โ HA-MCP Custom Component โ HA-MCP Server โ Configure) โ it is also printed in the Home Assistant log. A notification confirms the server started and points you there.
Paste that URL into your AI client โ done.
Connect URL. The Configure screen gives you a Home Assistant webhook URL for remote clients โ https://<your-ha-domain>/api/webhook/<webhook-id> through Nabu Casa or any reverse proxy already pointed at Home Assistant (locally, http://<ha-host>:8123/api/webhook/<webhook-id>). For clients on the same network, the server is also reachable directly at http://<ha-ip>:9584/private_<random>.
Replaces other install methods: the in-process server is a complete, standalone ha-mcp install โ it takes the place of the app (add-on), Docker, and uvx/PyPI (stdio) methods. Run only one; do not run the in-process server alongside another install.
Local only? Turn off Remote access via webhook in the entry options โ no webhook is registered at all, while the direct port and sidebar panel keep working.
Settings panel: while the server runs, an admin-only HA-MCP panel appears in the Home Assistant sidebar for managing tools, feature flags, backups, and themes.
Optional authentication: set Webhook authentication to
ha_authto require a Home Assistant account sign-in instead of using the secret URL as the credential.Manual install (no HACS): copy
custom_components/ha_mcp_tools/from this repository into your Home Assistantconfig/custom_components/directory, then restart and add the integration as above.
The component's second entry type, the File & YAML services entry (HA-MCP File & YAML Tools), is only needed if you enable ha-mcp's opt-in file and YAML editing tools (feature flags, off by default) โ skip it otherwise; you can add it later at any time. It works with any server type (in-process, app, Docker, or stdio).
Full in-process server documentation โ ยท Setup Wizard for client-specific config โ
๐ Home Assistant app (add-on)
Prefer to run ha-mcp as a Home Assistant app (add-on)? On Home Assistant OS and Supervised installs it is a close second โ no access token to manage, and it works with Claude Desktop, Claude.ai, ChatGPT, and any other MCP client on your local network or configured for remote access.
Add the repository to your Home Assistant instance:
If that opens the App store without an add-repository dialog (a known Home Assistant issue), add it manually: Settings โ Apps โ Install app โ โฎ โ Repositories, then paste
https://github.com/homeassistant-ai/ha-mcp.Install "Home Assistant MCP Server" from Settings โ Apps โ Install app and click Start. (Home Assistant 2026.2 renamed "Add-ons" to "Apps"; on older versions this is the Add-on store.)
Open the Logs tab to find your unique MCP URL.
Connect your AI client to that URL โ no token or credential setup needed.
โ ๏ธ Configure exactly one install method per client. The custom component, the app, Docker/PyPI, and local stdio are independent ways to run the same server โ pick one and point your AI client at that single URL. Keeping two entries for the same server in one client (for example a local
uvx ha-mcp@latestentry withHOMEASSISTANT_URL/HOMEASSISTANT_TOKENalongside an app or component URL) is a known cause of connection hangs.
Other install methods
These run the server outside Home Assistant โ useful for Container / Core installs (which can't run apps) or a separate host. The Setup Wizard generates the exact client-specific config for each.
Docker (HTTP server): run
ghcr.io/homeassistant-ai/ha-mcpin HTTP mode, pointed at your Home Assistant URL and a long-lived token, and connect your client to its secret URL. See the Setup Wizard for the full command and per-client config.PyPI / uvx (HTTP server): run the published
ha-mcppackage withuvx ha-mcp@latest(or pip) as a streamable-HTTP server the same way. Details in the Setup Wizard.Local stdio (not recommended): runs ha-mcp on your own machine over stdio. The one-command installers in the Demo server section below use this path; the Setup Wizard covers connecting it to your own Home Assistant.
OIDC authentication: gate remote access behind an external identity provider (Authentik, Keycloak, Auth0, etc.) instead of a secret URL โ all authenticated users share the server's Home Assistant credentials. See OIDC Mode.
โ ๏ธ stdio has known transport issues. The stdio transport has connection problems that streamable HTTP does not (#1713). It is recommended only for demo/testing tinkering โ for a real setup, use the custom component or an HTTP method above.
Using the HA-MCP custom component? You do not need the Webhook Proxy โ the component has its own built-in webhook for remote access (see the Get Started quick start at the top). The proxy is for the app (it can also front another external server via its
mcp_server_urloption). The OpenAI Tunnel below is different: it applies to any install method when Home Assistant isn't publicly reachable at all (no Nabu Casa or reverse proxy).
Already have Nabu Casa or another reverse proxy pointing at your Home Assistant? The Webhook Proxy app routes MCP traffic through your existing setup โ no separate tunnel or port forwarding needed.
Install the MCP Server app (see above) and the Webhook Proxy app from the same store
Start the webhook proxy and restart Home Assistant when prompted
Copy the webhook URL from the app logs:
MCP Server URL (remote): https://xxxxx.ui.nabu.casa/api/webhook/mcp_xxxxxxxxConfigure your AI client with that URL
For other remote access methods (Cloudflare Tunnel, custom reverse proxy), see the Setup Wizard.
ChatGPT / Codex behind a firewall (OpenAI Tunnel). ChatGPT connectors normally require a publicly reachable URL. If you can't (or don't want to) expose one, the community OpenAI Tunnel for HA-MCP integration by @norpol runs OpenAI's tunnel-client inside Home Assistant and connects your local MCP server URL to an OpenAI-hosted tunnel over an outbound-only connection โ no port forwarding, reverse proxy, or public URL. Point it at your ha-mcp URL, then attach the ChatGPT connector to the same tunnel ID. See the FAQ entry and #1811.
Webhook proxy documentation โ
๐งช Demo server (Windows / macOS / Linux)
Want to try ha-mcp before connecting your own Home Assistant? No paid subscription required. These one-command scripts set up a local stdio connection to a hosted demo environment so you can see it working in a few minutes. Each script's Connect your own Home Assistant link then shows how to point it at your instance.
Go to claude.ai and sign in (or create a free account)
Open Terminal and run:
curl -LsSf https://raw.githubusercontent.com/homeassistant-ai/ha-mcp/master/scripts/install-macos.sh | shDownload Claude Desktop (or restart: Claude menu โ Quit)
Ask Claude: "Can you see my Home Assistant?"
You're now connected to the demo environment! Connect your own Home Assistant โ
Anthropic doesn't ship Claude Desktop for Linux, so pick one path:
Claude Desktop โ free, via the community build:
Install the community Claude Desktop for Linux build and sign in with a free claude.ai account
Open Terminal and run:
curl -LsSf https://raw.githubusercontent.com/homeassistant-ai/ha-mcp/master/scripts/install-linux.sh | shRestart Claude Desktop, then ask: "Can you see my Home Assistant?"
Claude Code โ official CLI, requires a paid Claude plan:
Install Claude Code:
curl -fsSL https://claude.ai/install.sh | bashConfigure ha-mcp, then run
claude:curl -LsSf https://raw.githubusercontent.com/homeassistant-ai/ha-mcp/master/scripts/install.sh | sh -s -- --claude-codeStart
claude, run/mcpto confirm, then ask: "Can you see my Home Assistant?"
Go to claude.ai and sign in (or create a free account)
Open Windows PowerShell (from Start menu) and run:
irm https://raw.githubusercontent.com/homeassistant-ai/ha-mcp/master/scripts/install-windows.ps1 | iexDownload Claude Desktop (or restart: File โ Exit)
Ask Claude: "Can you see my Home Assistant?"
You're now connected to the demo environment! Connect your own Home Assistant โ
๐ง Setup Wizard for 15+ clients
Claude Code, Gemini CLI, ChatGPT, Open WebUI, VSCode, Cursor, and more.
Having issues? Check the FAQ & Troubleshooting
Related MCP server: hass-mcp-server
๐ฌ What Can You Do With It?
Just talk to Claude naturally. Here are some real examples:
You Say | What Happens |
"Create an automation that turns on the porch light at sunset" | Creates the automation with proper triggers and actions |
"Add a weather card to my dashboard" | Updates your Lovelace dashboard with the new card |
"The motion sensor automation isn't working, debug it" | Analyzes execution traces, identifies the issue, suggests fixes |
"Make my morning routine automation also turn on the coffee maker" | Reads the existing automation, adds the new action, updates it |
"Create a script that sets movie mode: dim lights, close blinds, turn on TV" | Creates a reusable script with the sequence of actions |
Spend less time configuring, more time enjoying your smart home.
โจ Features
Category | Capabilities |
๐ Search | Fuzzy entity search, deep config search, system overview |
๐ Control | Any service, bulk device control, real-time states |
๐ง Manage | Automations, scripts, helpers, dashboards, areas, zones, groups, calendars, blueprints |
๐ Monitor | History, statistics, camera snapshots, automation traces, ZHA devices |
๐พ System | Backup/restore, updates, apps, device registry |
๐ Safety | Read Only Mode toggle, per-tool enable/disable, tool security policies (user approval), automatic edit backups |
Template helper edit backups capture persisted options through the HA-MCP custom component, using either its Server entry or File & YAML Tools entry. Helper edits, generic integration options edits, and deletion capture the stable config-entry identity and entity ID/name mapping. Capture refuses degraded secret scrubbing. Restoring an existing helper requires a fresh safety backup, removes optional settings absent from the snapshot, and verifies persisted options.
For Template backup listing and bulk deletion, filter by the config-entry ID returned as entity_id by capture. Capture accepts an entity alias; the history filters use the stable config-entry ID. Recreation reports its replacement config-entry ID and saved entity mapping separately.
If the original entry has been deleted, restore recreates the helper and reports its new config-entry ID. The saved entity ID and custom name are restored when available; an occupied entity ID is refused before creation. Older snapshots without entity metadata cannot preserve renamed entity IDs. If a collision or verification failure occurs after creation, the new helper and source backup are retained and the result reports the new entry for inspection. Other entity/device registry settings are not restored. Helper and integration edits through the same server wait until restore finishes; other Home Assistant clients are outside this coordination. Failed or uncertain restores report their outcome and safe refusal reasons; inspect the current helper before retrying.
Category | Tools |
Apps (add-ons) |
|
Areas & Floors |
|
Assist |
|
Automations |
|
Blueprints |
|
Calendar |
|
Camera |
|
Dashboard |
|
Dashboards |
|
Developer |
|
Device Registry |
|
Energy |
|
Entity Registry |
|
Files |
|
Groups |
|
HACS |
|
Helper Entities |
|
History & Statistics |
|
Integrations |
|
Labels & Categories |
|
Matter |
|
Scenes |
|
Scripts |
|
Search & Discovery |
|
Service & Device Control |
|
System |
|
Todo Lists |
|
Utilities |
|
Zones |
|
๐ ha-mcp vs. Home Assistant's built-in MCP Server
Home Assistant ships its own MCP Server integration. It is built on the Assist pipeline, so a connected MCP client can read and control the entities you have exposed to Assist and run the intents Assist understands โ handy for voice-style control of already-exposed devices.
ha-mcp is a standalone server built for configuring, building, and debugging your smart home, not just controlling it. On top of device control, it adds capabilities the built-in integration does not have:
Capability | Built-in MCP Server | ha-mcp |
Control exposed devices, query states | Yes | Yes |
Entity scope | Only entities exposed to Assist | Everything in Home Assistant |
Create / edit automations, scripts, scenes | No | Yes |
Build & edit dashboards | No | Yes |
Debug automations from traces, read history & logs | No | Yes |
Manage helpers, areas, zones, labels, groups | No | Yes |
Backups, apps, HACS, device & entity registry | No | Yes |
Rule of thumb: Use the built-in integration for voice-style control of devices you have already exposed; use ha-mcp when you want an AI assistant that can also build and maintain your Home Assistant setup.
๐ Custom Component (ha_mcp_tools) โ File & YAML Services
The HA-MCP Custom Component also powers a set of privileged tools that standard Home Assistant APIs can't provide: file system access and YAML config editing. (The same component runs the full server in-process โ that's the recommended install in the Get Started section at the top.) Its File & YAML services entry (HA-MCP File & YAML Tools) enables the tools below.
Tools that require the component:
Tool | Description |
| Safely add, replace, or remove top-level YAML keys in |
| List files in allowed directories |
| Read files from allowed paths (config YAML, logs, and allowed directories) |
| Write files to allowed directories |
| Delete files from allowed directories |
Template helper edit backups and restores also require the component, using either its Server entry or File & YAML Tools entry. These five tools return an error with installation instructions if the component is missing.
These tools also require beta feature flags. See Beta Features for how to enable them โ including the ENABLE_BETA_FEATURES master flag, which must be on before the filesystem/YAML sub-flags take effect.
Install
Install the HA-MCP File & YAML Tools entry from the same HA-MCP Custom Component:
To add manually: open HACS > Integrations > three-dot menu > Custom repositories > add https://github.com/homeassistant-ai/ha-mcp-integration (category: Integration) > Download. Or copy custom_components/ha_mcp_tools/ from this repository into your HA config/custom_components/ directory.
After installing, restart Home Assistant, then open Settings > Devices & Services > Add Integration, search for HA-MCP Custom Component, and add the HA-MCP File & YAML Tools entry.
To run the full ha-mcp server in-process through this same component, see the Get Started section at the top and the full in-process server documentation โ.
๐ง Better Results with Agent Skills
This server gives your AI agent tools to control Home Assistant. For better configurations, pair it with Home Assistant Agent Skills โ domain knowledge that teaches the agent Home Assistant best practices.
An MCP server can create automations, helpers, and dashboards, but it has no opinion on how to structure them. Without domain knowledge, agents tend to over-rely on templates, pick the wrong helper type, or produce automations that are hard to maintain. The skills fill that gap: native constructs over Jinja2 workarounds, correct helper selection, safe refactoring workflows, and proper use of automation modes.
Bundled Skills (built-in)
Skills from homeassistant-ai/skills are bundled and served as MCP resources via skill:// URIs. Any MCP client that supports resources can discover them automatically โ no manual installation needed. For tool-only clients (claude.ai, etc.), the same skills are reachable through the polymorphic ha_get_skill_guide tool โ call it with no args to list bundled skills, with a skill arg to list its files, or with skill + file to read content. Resources are not auto-injected into context โ clients must explicitly request them, so idle context cost is just the metadata listing.
ha_get_skill_guide is a mandatory tool: the catalog always exposes it (it can't be disabled) so tool-only clients never see a silently missing skill surface.
Skills can still be installed manually for clients that prefer local skill files โ see the skills repo for instructions.
๐ Tool Discovery for AI Agents
By default, the full tool catalog (~87 tools) is listed to the client through the standard MCP tools/list response. Clients with deferred / on-demand tool loading (claude.ai, Claude Desktop, Claude Code) handle that fine โ tools are pulled into context only when needed, so idle context cost is near-zero.
For setups without deferred tool support โ models like Claude Haiku, Gemini, OpenAI-compatible local models and smaller open-weights models, or clients that inline all tool schemas regardless of model (e.g. GitHub Copilot CLI) โ listing the full tool catalog up front adds a lot of idle context and can overwhelm smaller models. To address that, the server ships with a search-based discovery mode built on top of FastMCP's BM25 search transform.
Smaller or local LLMs (Ollama, etc.)
If your model can't see the tools or your Home Assistant, it may be getting handed the whole tool catalog at once and struggling with it. It's recommended to try the following to see if it helps:
Enable tool search (
ENABLE_TOOL_SEARCH=true, or the app option below). Instead of listing every tool up front, the server defers the catalog behind a search interface so the model pulls in only the tools it needs, when it needs them.Raise the model's context window above the default. Local runtimes ship with small defaults (Ollama's
num_ctxis one example) that can't hold a large tool set plus the conversation โ increase it well beyond the default.
Enable search-based discovery
Set ENABLE_TOOL_SEARCH=true (or toggle the option in the HA app). The full catalog is replaced in the tool list with four entry points plus a small set of always-visible "pinned" tools (ha_search, ha_get_overview, ha_report_issue, etc.). All tools remain callable directly by name once discovered:
Tool | Purpose |
| BM25 keyword search across all tools. Returns name, description, parameters, and annotations ( |
| Execute a |
| Execute a write tool that creates or updates data. |
| Execute a tool that removes / deletes data. |
The proxy split lets MCP clients apply different permission policies per category (e.g. auto-approve reads, prompt for writes, confirm deletes) without parsing tool docstrings.
A ha_manage_* tool combines several operations, so it is reachable from more than one proxy: ha_call_write_tool and ha_call_delete_tool run the whole tool, while ha_call_read_tool runs only the read actions Read Only Mode approves (the same per-call verdict), so a manage tool with no approved read actions is not reachable there. Search results list each proxy the tool can be reached through. In Read Only Mode only ha_call_read_tool is listed; the other two still answer a client that holds them in a cached tool list, and any write they carry gets the Read Only Mode error rather than Unknown tool.
Setting | Default | Description |
|
| Replace full tool catalog with search-based discovery (tools deferred behind on-demand search). |
|
| Max results returned by |
| empty | Comma-separated tool names to keep always visible. The web settings UI is the primary way to manage this. |
When to enable
Claude Haiku, OpenAI-compatible local models, Gemini, or any model without native deferred tool support โ large idle-context savings. The same applies to clients that inline all tool schemas regardless of model (e.g. GitHub Copilot CLI, even when running Claude Sonnet/Opus).
MCP clients that cap total tool count (some cap at 100) โ surfaces a minimal set (~10 tools) instead of 87.
Cost-sensitive deployments โ fewer idle tokens per turn.
Leave it off in clients with deferred tool loading (claude.ai, Claude Desktop, Claude Code); the full catalog has no idle cost there, direct calls skip the search step, and the client's built-in tool search is the better choice โ there is no benefit to running ha-mcp's on top of it. Whether tools are deferred depends on the client and model combination: the same model can behave differently per client โ GitHub Copilot CLI running Claude Sonnet/Opus inlines the full catalog and still benefits from tool search here. Some Codex models and ChatGPT include deferred tools too โ check your client/model directly to confirm its features so you don't leave this enabled unnecessarily.
๐ Refresh your client's tool list after changing this (or any) setting. Toggling
ENABLE_TOOL_SEARCH(or changing pinned/disabled tools, Read Only Mode, etc.) changes the tools the server exposes, but your AI client keeps serving its cached tool list until it re-fetches. Restarting the app or Home Assistant does not refresh the client โ reconnect or refresh the MCP server in your client (e.g. re-add/refresh the connector in ChatGPT, or close and reopen Claude Desktop). If you skip this, newly enabled tools won't appear in the client at all, and tools the server no longer exposes still show as available but fail when called (Unknown tool, or the Read Only Mode error for a write tool that mode hides). ChatGPT sometimes keeps serving the stale list even after the connector is removed and re-added under the same name โ if tools are still missing after re-adding, delete the connector and create a new one with a different name.
For the HA app, the same option is documented in homeassistant-addon/DOCS.md along with the in-app settings UI for fine-grained tool enable/disable/pin.
Read-only HTTP connections
Append /readonly to the server's HTTP MCP endpoint to restrict that connection
to the existing Read Only Mode while other clients keep normal access:
Normal: https://example.com/private_your_secret
Read-only: https://example.com/private_your_secret/readonlyOAuth and OIDC connections use the same login/provider: for example,
https://example.com/mcp/readonly. No additional secret or server is required.
Read-only connections hide write tools and block write calls, including calls
through cached tools or search proxies. The global Read Only Mode setting still
restricts both endpoints when enabled. Reconnect the client after changing its URL
so it refreshes its tool list.
This is a connection mode for automated agents, not a separate permission on the
credential: the same credentials still work at the normal endpoint. Home Assistant
webhook URLs also accept the suffix:
https://your-ha.example/api/webhook/<webhook-id>/readonly. This requires the
updated embedded integration or Webhook Proxy dev app (add-on), together with
the updated MCP server.
๐งช Dev Channel
Want early access to new features and fixes? Dev releases (.devN) are published on every push to master.
Dev Channel Documentation โ Instructions for pip/uvx, Docker, and Home Assistant app.
๐ค Contributing
For development setup, testing instructions, and contribution guidelines, see CONTRIBUTING.md.
For comprehensive testing documentation, see tests/README.md.
๐ Privacy
Ha-mcp runs locally on your machine. Your smart home data stays on your network.
No telemetry today โ anonymous usage stats are a planned future feature (as of June 2026); when it lands it will follow your Home Assistant analytics/telemetry setting (which you can override), announced prominently in the release notes and the web Settings UI at least one month beforehand
No personal data collection โ we never collect entity names, configs, or device data
User-controlled bug reports โ only sent with your explicit approval
For full details, see our Privacy Policy.
๐ License
This project is licensed under the MIT License - see the LICENSE file for details.
๐ Acknowledgments
Home Assistant: Amazing smart home platform (!)
FastMCP: Excellent MCP server framework
Model Context Protocol: Standardized AI-application communication
Claude Code: AI-powered coding assistant
PolicyLayer: Argument-path predicate DSL shape (
args.domain in [...]witheq/in/regex/contains/exists/...) inspired the per-tool approval rule schema (#966).
๐ฅ Contributors
Maintainers
@julienld โ Project creator.
@sergeykad โ Core maintainer.
@kingpanther13 โ Core maintainer.
@Patch76 โ Core maintainer.
Contributors
@bigeric08 โ Explicit
mcpdependency for protocol version 2025-11-25 support.@airlabno โ Support for
datafield in schedule time blocks.@ryphez โ Codex Desktop UI MCP quick setup guide.
@Danm72 โ Entity registry tools (
ha_set_entity,ha_get_entity) for managing entity properties.@Raygooo โ SOCKS proxy support.
@cj-elevate โ Integration & entity management tools (enable/disable/delete); person/zone/tag config store routing.
@maxperron โ Beta testing.
@kingbear2 โ Windows UV setup guide.
@konradwalsh โ Financial support via GitHub Sponsors. Thank you! โ
@knowald โ Area resolution via device registry in
ha_get_system_overviewfor entities assigned through their parent device. Financial support via GitHub Sponsors. Thank you! โ@zorrobyte โ Per-client WebSocket credentials in OAuth mode, fixing WebSocket tool failures.
@deanbenson โ Fixed
ha_deep_searchtimeout on large Home Assistant instances with many automations.@saphid โ Config entry options flow tools (initial design, #590).
@adraguidev โ Fix menu-based config entry flows for group helpers (#647).
@transportrefer โ Integration options inspection (
ha_get_integrationschema support, #689).@teh-hippo โ Fix blueprint import missing save step.
@smenzer โ Documentation fix.
@The-Greg-O โ REST API for config entry deletion.
@restriction โ Responsible disclosure: python_transform sandbox missing call target validation.
@lcrostarosa โ Diagnostic and health monitoring tools concept (#675), inspiring system/error logs, repairs, and ZHA radio metrics integration.
@roysha1 โ Copilot CLI support in the installation wizard; replaced placeholder logo SVGs with real brand icons on the documentation site.
@teancom โ Fix add-on stats endpoint (
/addons/{slug}/stats).@TomasDJo โ Category support for automations, scripts, and scenes.
@bzelch โ
python_transformsupport for automations and scripts.@gcormier โ Windows installer improvements: removed unused variable and fixed terminal closing after install.
@ekobres โ Feature flags for
HAMCP_ENABLE_FILESYSTEM_TOOLSand the (since removed)HAMCP_ENABLE_CUSTOM_COMPONENT_INTEGRATIONin the app config, with beta tagging in source and docs.@w3z315 โ Financial support via GitHub Sponsors. Thank you! โ
@griffinmartin โ Added OpenCode (by Anomaly) as a selectable AI client in the setup wizard, with both stdio and streamable HTTP support.
@hhopke โ Fixed app (add-on) API calls to route through HA Core ingress proxy instead of direct container connections, fixing
ha_manage_addon(nowha_manage_app) proxy mode on app installs.@tomwilkie โ JMESPath middleware exploration (#1147) whose review-time token-measurement data informed the design of #1199 and #1225.
@SealKan โ
fields=/attribute_keys=projection on six read-heavy tools (#1225),ha_call_eventtool (#1239), dashboards-list helper refactor (#1207),for:-field duration-math detector in the best-practice checker (#1264), persistent DCR OAuth client registrations across restarts (#1265), and issue-triage prompt token-budgeting (#1522).@KarelTestSpecial โ Cached YAML instance to prevent CPU spikes during bulk edits (#1371).
@corgan2222 โ HA brand assets for custom integration (#1317).
@drseanwing โ Progress emission via FastMCP
Contextin long-running tools (#1124); tool-discovery / categorized-search docs (#1123).@fnordpig โ Config subentry support (#1393) and Assist pipeline management tool (#1392).
@paul43210 โ
array_patchmode inha_manage_appfor atomic GET-modify-POST (#1063).@L1AD โ Filed #966 proposing tool security policies; pointed to PolicyLayer's MCP-security work as prior art that inspired the predicate DSL shape.
@nightcityblade โ Updated stale Home Assistant Advanced Mode references after HA 2026.6 made formerly advanced options available by default (#1533).
@emmelutzer โ Financial support via GitHub Sponsors. Thank you! โ
@pkkr โ
ha_knx_get_projecttool exposing KNX group addresses from an uploaded ETS project file.@cbowns โ Fixed inconsistent hyphen in setup.astro Codex CLI docs.
@Shaan-alpha โ Extended
ha_restartknown-good error patterns to cover 502/503 responses from reverse proxies.@rebelancap โ Fixed UTC-to-local timezone conversion in
add_timezone_metadata.@saevras โ Fixed blueprint import E2E test to use local URL instead of host-to-container networking.
@jasonjhofmann โ Recurring calendar events via
rrulesupport inha_config_set_calendar_event.@vpciii โ Coerce JSON-encoded strings on dict/list tool params.
@pburtchaell โ Financial support via GitHub Sponsors. Thank you! โ
@norpol โ Built the OpenAI Tunnel for HA-MCP companion integration, connecting ChatGPT to a firewalled Home Assistant MCP server (#1811).
๐ฌ Community
GitHub Discussions โ Ask questions, share ideas
Issue Tracker โ Report bugs, request features, or suggest tool behavior improvements
Star History
Available Tools
77 toolsha_bulk_controlBulk ControlADestructive
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
(MAX_SELECTOR_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.
| Name | Required | Description | Default |
|---|---|---|---|
| action | No | One device action applied to every resolved leaf. | |
| dry_run | No | ||
| parallel | No | ||
| selector | No | Optional exact structural scope using domain plus area_ids and/or floor_ids, with optional exclude_entity_ids. | |
| operations | No | Explicit entity operations. Use this or selector, never both. Each item requires exact entity_id and action. Use action='off', not service='turn_off'. | |
| parameters | No | Optional action parameters for selector mode. | |
| validate_first | No | ||
| timeout_seconds | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only carry destructiveHint=true and openWorldHint=false, so the description bears the burden of behavioral disclosure โ and it delivers richly: parallel-by-default execution, invalid items not aborting valid ones, all-fail batches dispatching nothing, group+member batch failing closed, non-transactional selector dispatch, the 100-entity MAX_SELECTOR_ENTITIES fail-closed cap, and dry_run semantics. This far exceeds what the annotations alone communicate.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but front-loaded: purpose first, then when-not-to-use, then mode-specific behavior in labeled sections. Every paragraph carries non-obvious failure semantics that an agent needs before calling. The density is justified by the tool's complexity (two modes, 8 params, multiple failure modes), though it is heavier than the leanest possible version.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a high-complexity tool with 8 parameters, two mutually exclusive modes, and destructive behavior, the description covers all decision-relevant context: mode selection, failure behavior, group/member edge cases, entity-count limits, retry guidance, and dry_run. An output schema exists, so return-value documentation is not required. The only minor omission is top-level validate_first/timeout_seconds semantics, which are addressed in the nested schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With only 50% schema description coverage (dry_run, parallel, validate_first, and timeout_seconds lack top-level schema descriptions), the description compensates by explaining mode-level semantics: which params combine (operations without selector; selector + action), what exclude_entity_ids does after recursive expansion, what dry_run previews, and the shared timeout behavior. It does not explicitly walk through every top-level parameter, but the gaps are mostly covered by the nested operations schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a clear purpose โ managing explicit operations or one deterministic structural bulk action โ and immediately distinguishes itself from siblings by naming ha_call_service and ha_search in the 'When NOT to use' section. The two-mode structure (operations vs. selector) gives an agent a precise mental model of what the tool does and what it is not.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit when-not-to-use guidance names the exact alternative tools and the conditions that select them: ha_call_service for service-specific payloads/backend-native group targeting, ha_search for fuzzy discovery. It also gives conditional routing within the tool itself, e.g., 'Use selector mode with exclude_entity_ids when a group action must exclude specific members' and 'narrow it ... and retry' for oversized selectors.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_call_eventCall EventADestructive
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. For triggering automations by name, use ha_call_service("automation", "trigger").
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.
| Name | Required | Description | Default |
|---|---|---|---|
| data | No | ||
| event_type | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond annotations (destructiveHint=true), the description reveals fire-and-forget behavior and that tool confirms bus acceptance but not subscriber action. This adds value and does not contradict annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured with a clear first sentence, usage guidelines section, and caveats. It is concise with no wasted words.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple tool with two parameters and output schema, the description covers purpose, usage, exclusions, and behavioral caveats. It is fully adequate for an agent to correctly invoke the tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With 0% schema description coverage, the description conveys the meaning of event_type (custom event type) and data (optional payload) through context, though it does not explicitly name or detail each parameter.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states it executes a custom event on the Home Assistant event bus, providing a specific verb and resource. It also explicitly distinguishes itself from sibling tools like ha_call_service by stating when not to use.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit when-to-use and when-not-to-use guidance, including specific alternatives (ha_call_service for entity control and automation triggering). It also describes the intended use case for event-triggered automations.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_call_serviceCall ServiceADestructive
Execute Home Assistant services to control entities and trigger automations.
This is the universal tool for controlling all Home Assistant entities. Services follow the pattern domain.service (e.g., light.turn_on, climate.set_temperature).
Basic Usage:
# Turn on a light
ha_call_service("light", "turn_on", entity_id="light.living_room")
# Set temperature with parameters
ha_call_service("climate", "set_temperature",
entity_id="climate.thermostat", data={"temperature": 22})
# Trigger automation
ha_call_service("automation", "trigger", entity_id="automation.morning_routine")
# Universal controls work with any entity
ha_call_service("homeassistant", "toggle", entity_id="switch.porch_light")Key behavior:
Result compaction (default ON):
resultis trimmed to the targeted entity's record (drops parent-group propagation) and stripped ofcontext/last_*metadata and heavy attribute lists (effect_list,hue_scenes). Escape hatches:verbose=Truefor the raw changed-state records, orresult_fields/result_attribute_keysfor explicit per-record projection (mirrorsha_get_state).
For detailed service documentation, use ha_get_skill_guide.
Common patterns: Use ha_get_state() to check current values before making changes. Use ha_search() to find correct entity IDs.
WebSocket command escape hatch (advanced):
A few Home Assistant operations are WebSocket-only commands, not
registered services โ most notably dismissing a Repairs issue. Pass
ws_command (instead of domain/service) to send one, with its
parameters in data:
# Dismiss a repair (get domain/issue_id from ha_get_overview repairs
# or ha_get_system_health include="repairs")
ha_call_service(ws_command="repairs/ignore_issue",
data={"domain": "sun", "issue_id": "abc", "ignore": True})Only one-shot request/response commands are supported; streaming/two-phase and service-invoking commands are rejected, 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.
| Name | Required | Description | Default |
|---|---|---|---|
| data | No | Extra service-call parameters beyond entity_id (e.g. {'temperature': 22} for climate.set_temperature). Also carries the raw command payload when ws_command is set. If entity_id is also present in data, the entity_id parameter wins. | |
| wait | No | If True (default), wait for the entity state to change before returning. Applies only to state-changing services called with a single entity_id. A comma-separated multi-target does not get confirmed by this: it falls through to a legacy path that polls for the literal composite entity_id and times out after 10s. Set wait=False for multi-target calls. | |
| domain | No | Service domain (e.g. 'light', 'climate', 'automation'). Required for a service call; must be omitted when ws_command is set. | |
| service | No | Service name within domain (e.g. 'turn_on', 'set_temperature', 'trigger'). Required for a service call; must be omitted when ws_command is set. | |
| verbose | No | Return HA's raw changed-state records unchanged (default: False). Use as an escape hatch when you need the full propagation chain or raw attribute payload (debug / inspection). With return_response=True the response data still surfaces once as the top-level service_response key, never nested in result. WARNING: brings back token-bloat for nested-group targets โ prefer result_fields / result_attribute_keys for targeted control. | |
| entity_id | No | Entity ID(s) the service call targets โ one ID ('light.living_room') or several comma-separated ('light.a,light.b'). Optional for services that don't target a specific entity. Must be omitted when ws_command is set. | |
| ws_command | No | Advanced escape hatch: send a raw one-shot Home Assistant WebSocket command that is NOT a registered service (e.g. 'repairs/ignore_issue' to dismiss a Repairs issue). When set, omit domain/service and the other service params; put the command's parameters in data. Streaming/two-phase and service-invoking commands (call_service, execute_script) are rejected. | |
| result_fields | No | Project each record in 'result' to only these top-level keys (e.g. ['entity_id', 'state']). Mirrors ha_get_state's fields=. Setting this DISABLES default compaction โ no entity-id filter, no metadata strip โ and applies the explicit projection instead. | |
| return_response | No | If True, the service's response data is returned once, as the top-level 'service_response' key โ never nested inside 'result' (default: False). Must stay False when ws_command is set. | |
| result_attribute_keys | No | Project each record's 'attributes' dict to only these keys (e.g. ['brightness', 'rgb_color']). Mirrors ha_get_state's attribute_keys=. Setting this DISABLES default compaction. Requires 'attributes' to be present in result_fields (or result_fields=None). |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Despite annotations already carrying destructiveHint=true and readOnlyHint=false, the description adds substantial behavioral context: default result compaction that 'trims to the targeted entity's record' and strips context/last_* metadata, the ws_command escape hatch with explicit rejections of 'streaming/two-phase and service-invoking commands', and the Read Only Mode unavailability. The wait parameter's legacy-path fallback with '10s timeout' for multi-target calls is also disclosed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Long but every section earns its place: purpose statement, code examples, key behavior (compaction), advanced escape hatch, and mode restriction. The structure is front-loaded with the core purpose and examples before advanced topics, uses clear section headers and formatted code blocks. The density is proportionate to a universal 10-parameter tool.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Complete for a complex universal tool: covers invocation pattern, examples, result shaping behavior, escape hatches, rejected command types, and mode restrictions. With an output schema present, return values need not be re-explained. The only possible gap, detailed per-service parameters, is explicitly routed elsewhere: 'For detailed service documentation, use ha_get_skill_guide.'
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% with already-detailed per-parameter descriptions, so baseline is 3. The description adds genuine value beyond the schema: concrete usage examples mapping data to service parameters (e.g., {'temperature': 22}), the entity_id-wins-over-data precedence, the interplay between result_fields/verbose and the default compaction behavior, and the wait=False recommendation for multi-target calls.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb+resource: 'Execute Home Assistant services to control entities and trigger automations.' It then explicitly frames itself as 'the universal tool for controlling all Home Assistant entities' and explains the domain.service pattern with concrete examples. This clearly distinguishes it from siblings like ha_get_state (read), ha_call_event (events), and the config-mutation tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit when/when-not guidance: 'For detailed service documentation, use ha_get_skill_guide', 'Use ha_get_state() to check current values before making changes', 'Use ha_search() to find correct entity IDs', and 'Unavailable in Read Only Mode... Use dedicated read tools while that mode is enabled.' The ws_command section also clarifies when the advanced path applies versus registered services.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_config_delete_dashboardDelete DashboardADestructive
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.
Accepts either the URL path or the internal dashboard ID. 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.
| Name | Required | Description | Default |
|---|---|---|---|
| url_path | Yes | Dashboard URL path or internal ID to delete (e.g., 'my-dashboard' or 'my_dashboard'). Both forms are accepted. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already indicate destructiveHint=true, but the description adds critical details: permanent deletion, irreversibility, ID resolution behavior, and the restriction on default dashboard. No contradiction with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise and well-structured with a clear warning, bullet-point-like explanation, an example, and a note. Every sentence contributes meaning without redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's simplicity (single parameter, destructive operation) and the presence of output schema (not shown but indicated), the description covers all necessary aspects: purpose, limitations, parameter details, and an example. No missing information for an AI agent to use it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The single parameter url_path is fully covered by schema (100%), but the description adds important context: it accepts both URL path and internal ID, explains hyphens vs underscores, and notes the tool resolves to actual registry ID. This adds value beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool deletes a storage-mode dashboard permanently, using a specific verb and resource. It distinguishes from siblings by specifying it works only on storage-mode dashboards, not YAML-mode, and mentions the default dashboard cannot be deleted.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly states when to use (delete storage-mode dashboards) and when not to (YAML-mode, default dashboard). It does not name alternative tools explicitly, but the context implies alternatives like editing config files for YAML-mode.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_config_delete_dashboard_resourceDelete Dashboard ResourceADestructive
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.
| Name | Required | Description | Default |
|---|---|---|---|
| resource_id | Yes | Resource ID to delete. Get from ha_config_list_dashboard_resources() |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations include destructiveHint: true. The description adds important behavioral context: warns that deleting used resources will cause custom cards to fail to load, which goes beyond the annotation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Concise: action stated first, warning, example, and note. No superfluous words.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Complete for a single-parameter delete tool. Covers what happens, prerequisite, example, and warnings. Output schema exists for return values.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema covers resource_id with description. Description reinforces with example and advice to get ID from list function. Adds value beyond schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states 'Delete a dashboard resource' and explains it removes a resource from Home Assistant. It distinguishes from siblings like ha_config_set_dashboard_resource and ha_config_list_dashboard_resources.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides context for when to use (to delete a resource), a warning about consequences, and an example. Mentions using ha_config_list_dashboard_resources() to find IDs, but doesn't explicitly state when not to use or mention alternatives beyond listing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_config_get_automationGet Automation ConfigARead-onlyIdempotent
Retrieve Home Assistant automation configuration.
Returns the complete configuration including triggers, conditions, actions, and mode settings.
The returned config_hash is stable across consecutive reads of an unchanged config โ compute_config_hash documents the underlying contract.
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
| Name | Required | Description | Default |
|---|---|---|---|
| identifier | Yes | Automation entity_id (e.g., 'automation.morning_routine') or unique_id |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Adds value beyond annotations by explaining config_hash stability across reads, automation_id resolution with fallback, and that it returns the complete config. No contradictions with readOnlyHint and idempotentHint.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Well-structured with sections for examples and details. Slightly verbose but not excessive; every sentence adds value. Front-loaded with purpose.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the output schema existence and annotations, the description fully explains return fields (config_hash, automation_id) and behavior. No gaps for a get config tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, and description adds meaning by describing identifier as 'Automation entity_id (e.g., 'automation.morning_routine') or unique_id' with examples. Well-explained.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states 'Retrieve Home Assistant automation configuration' and details what is returned (triggers, conditions, actions, mode). It distinguishes from sibling tools like ha_config_set_automation (write) and ha_config_remove_automation (delete) by being a read operation.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides examples for calling with entity_id or unique_id, and directs to ha_get_skill_guide for comprehensive docs. While not explicitly stating when not to use, the read-only nature is clear, and examples cover typical usage.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_config_get_calendar_eventsGet Calendar EventsARead-onlyIdempotent
Retrieve calendar events from a calendar entity.
Retrieves calendar events within a specified time range.
Parameters:
entity_id: Calendar entity ID (e.g., 'calendar.family')
start: Start datetime in ISO format (default: now)
end: End datetime in ISO format (default: 7 days from start)
max_results: Maximum number of events to return (default: 20)
Example Usage:
# Get events for the next week
events = ha_config_get_calendar_events("calendar.family")
# Get events for a specific date range
events = ha_config_get_calendar_events(
"calendar.work",
start="2024-01-01T00:00:00",
end="2024-01-31T23:59:59"
)Note: To find calendar entities, use ha_search(query='calendar', domain_filter='calendar')
Returns:
List of calendar events with summary, start, end, description, location
| Name | Required | Description | Default |
|---|---|---|---|
| end | No | End datetime in ISO format (default: 7 days from start) | |
| start | No | Start datetime in ISO format (default: now) | |
| entity_id | Yes | Calendar entity ID (e.g., 'calendar.family') | |
| max_results | No | Maximum number of events to return |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond annotations (readOnlyHint, idempotentHint), the description details defaults for start/end, max_results, and the return format (list with fields). This adds operational context not captured by annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured with clear sections: purpose, parameters, example, note, and returns. It is concise and front-loaded, every sentence adds value.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the low complexity, full schema coverage, and presence of output schema, the description is complete. It explains purpose, parameters, defaults, example usage, and suggests how to find entity IDs.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3. The description repeats schema descriptions but adds practical context through example usage and a note on finding entities, which provides extra meaning for an AI agent.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the verb 'Retrieve' and the resource 'calendar events' from a calendar entity. It is distinct from sibling tools 'ha_config_remove_calendar_event' and 'ha_config_set_calendar_event', making the purpose unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides a note on finding calendar entities via 'ha_search' and shows example usage. While it does not explicitly state when not to use, the context of read-only operation is clear from annotations and sibling names.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_config_get_categoryGet CategoryARead-onlyIdempotent
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.
CATEGORY PROPERTIES:
ID (category_id), Name
Icon (optional)
EXAMPLES:
List automation categories: ha_config_get_category("automation")
List script categories: ha_config_get_category("script")
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.
| Name | Required | Description | Default |
|---|---|---|---|
| scope | Yes | Domain scope for categories (e.g., 'automation', 'script', 'scene', 'helpers'). | |
| category_id | No | ID of the category to retrieve. If omitted, lists all categories for the scope. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and idempotentHint=true, indicating a safe, idempotent read. The description confirms read-only behavior (lists, returns configuration). Discloses domain-scoped nature. Does not contradict annotations. Adds details about optional icon, but could mention that the output schema exists (though not shown).
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Well-organized with sections (overview, properties, examples, related tools). About 10 sentences, but each sentence adds value. Could be slightly more concise by merging the examples into a list, but overall efficient and front-loaded with purpose.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's simplicity (2 params) and the presence of an output schema (not shown but context indicates coverage), the description covers all behavioral aspects: parameter behavior, returned properties, usage examples, and even mentions external methods for creation and assignment. It is contextually complete for an agent to invoke correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% with both parameters documented. The description adds significant value beyond the schema: clarifies behavior based on category_id presence, lists the returned properties (ID, Name, Icon) not in schema, and provides concrete examples showing parameter usage and expected outputs.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description explicitly states the tool lists categories for a scope or gets a specific one by ID. It distinguishes itself from sibling tools like ha_config_set_category (create/update) and ha_set_entity (assign to entities). The verb+resource is clear and specific.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides clear when-to-use guidance: without category_id lists all categories for a scope, with category_id returns specific. Includes multiple examples. References ha_config_set_category for creating/updating and ha_set_entity for assigning, giving alternatives and related operations.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_config_get_dashboardGet DashboardARead-onlyIdempotent
Get dashboard info - list all dashboards, get config, or search for cards.
MODE 1 โ List: list_only=True Lists every dashboard's metadata (url_path, title, icon), storage and YAML alike (metadata only โ bodies are never included here).
MODE 2 โ Search: any of entity_id / card_type / heading provided
Finds cards, badges, and header cards matching the criteria, including
cards nested inside stacks, grids, conditional cards, button-card
custom_fields, and state-switch states. Each match carries a
python_path and a jq_path that locate the card for nested as well as
top-level cards. The python_path is a Python subscript chain to be
appended after config โ e.g.
python_transform=f'config{m["python_path"]}["icon"] = "mdi:x"' (it is
NOT valid on its own without the config prefix). jq_path is the same
location in jq dot-notation.
Multiple criteria are AND-ed. Always fetches fresh config, bypassing the cache.
Search covers cards/card/custom_fields/states containers up to a depth
bound; if the dashboard carries a non-traversed child-bearing shape
(e.g. picture-elements elements), the result carries a warnings
entry naming where, so its hidden content is not mistaken for absent.
Strategy dashboards are not searchable (no explicit cards).
MODE 3 โ Get: Active when list_only=False and no search parameters are provided.
Returns the full Lovelace dashboard config, defaulting to the
main dashboard if url_path is omitted.
Pass view_path=<views[].path> to return ONLY that view: the response
then carries view + view_index instead of config, keeping the
payload small on multi-view dashboards. config_hash still covers
the FULL config, so a follow-up
ha_config_set_dashboard(python_transform=...) addressing
config['views'][view_index] validates unchanged. An unknown
view_path errors and lists the available view paths.
include_screenshot=True also returns rendered image(s) of the
dashboard (beta feature); when you only need the render and not
the config, use the dedicated ha_get_dashboard_screenshot tool
instead.
MODE 4 โ Search all: mode="search" with query=
Answers "which dashboards contain this entity/card" by walking every
storage-mode dashboard's views/cards/sections for the query substring.
Each match names the url_path, view, card_path, card_type, and the
matched field/value. Takes precedence over the other modes (list_only /
entity_id / card_type / heading are ignored when mode="search").
YAML-mode dashboards are never searched on either path โ the component
walk skips them in-process and the component-less legacy walk skips any
row tagged mode="yaml" โ because HA resolves !secret when loading a
YAML Lovelace config, so searching one could surface resolved secrets.
On installs without the ha_mcp_tools component, the default (unnamed)
dashboard is also not searched โ only dashboards with a url_path are.
Return a stable config_hash (Get and Search modes only; not present in list_only mode) across consecutive reads of an unchanged config โ compute_config_hash documents the underlying contract.
EXAMPLES:
List all dashboards: ha_config_get_dashboard(list_only=True)
Get default dashboard: ha_config_get_dashboard(url_path="default")
Get custom dashboard: ha_config_get_dashboard(url_path="lovelace-mobile")
Get one view only: ha_config_get_dashboard(url_path="lovelace-mobile", view_path="office")
Force reload: ha_config_get_dashboard(url_path="lovelace-home", force_reload=True)
Find cards by entity: ha_config_get_dashboard(url_path="my-dash", entity_id="light.living_room")
Find by wildcard: ha_config_get_dashboard(url_path="my-dash", entity_id="sensor.temperature_*")
Find by type: ha_config_get_dashboard(url_path="my-dash", card_type="tile")
Find heading: ha_config_get_dashboard(url_path="my-dash", heading="Climate", card_type="heading")
SEARCH WORKFLOW EXAMPLE:
find = ha_config_get_dashboard(url_path="my-dash", entity_id="light.bedroom")
ha_config_set_dashboard( url_path="my-dash", config_hash=find["config_hash"], python_transform=f'config{find["matches"][0]["python_path"]}["icon"] = "mdi:lamp"' )
Note: YAML-mode dashboards (defined in configuration.yaml) are not included in list.
| Name | Required | Description | Default |
|---|---|---|---|
| mode | No | Set to 'search' for a CROSS-dashboard search: which dashboards contain a given entity_id or text (requires query). Leave unset for the default list/get/single-dashboard-search behavior selected by list_only / entity_id / card_type / heading. | |
| query | No | With mode='search': the entity_id or substring to find across all storage-mode dashboards. Ignored otherwise. | |
| heading | No | Find cards by heading/title text (case-insensitive partial match). When provided, activates search mode. | |
| url_path | No | Dashboard URL path (e.g., 'lovelace-home'). Use 'default' for default dashboard. If omitted with list_only=True, lists all dashboards. | |
| card_type | No | Find cards by type, e.g. 'tile', 'button', 'heading'. When provided, activates search mode. | |
| entity_id | No | Find cards by entity ID. Supports wildcards, e.g. 'sensor.temperature_*'. Matches cards with this entity in 'entity' or 'entities' field, view-level badges, and header cards. When provided, activates search mode (returns matches, not full config). | |
| list_only | No | If True, list all dashboards instead of getting config. When True, url_path is ignored. | |
| view_path | No | Get mode: return ONLY the view whose Lovelace views[].path matches (response carries 'view' + 'view_index' instead of the full 'config') โ use this to keep multi-view dashboards from blowing up the response when you only need one view. Does not require any beta feature. With include_screenshot, also selects the view to render. Ignored in list/search mode. Omit for the full config. | |
| force_reload | No | Force reload from storage (bypass cache). Not applicable in search mode, which always reads fresh config. | |
| include_config | No | In search mode: include each matched card's own configuration object in results (increases output size). Note that a matched container card's config contains its descendants, which are themselves separate matches with their own config, so deeply-nested stacks multiply the payload โ keep the default (False) unless you need the bodies. Does not affect whether the full dashboard config is returned โ search mode always returns matches only, not the full dashboard. Config bodies are surfaced only for dashboards provably in storage mode; for a YAML or unconfirmed dashboard the bodies are withheld (they may carry resolved !secret values) and the response says so, with match locations still reported. Ignored outside search mode. | |
| include_screenshot | No | Get mode only: also return rendered image(s) of the dashboard for visual verification. Requires the 'dashboard screenshot' beta feature + engine add-on/sidecar. If the feature is disabled the config is returned with a warning; if the engine is configured but the render fails, the call errors (the screenshot is the requested payload). Ignored in list/search mode. When you already have the config and only need the render, use the dedicated ha_get_dashboard_screenshot tool (registered when the same beta feature is on) โ it returns images without echoing the config. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare readOnlyHint=true, openWorldHint=false, idempotentHint=true, so the safety profile is already covered. The description adds substantial behavioral context beyond that: cache-bypassing behavior in search mode, config_hash stability contract, warnings for non-traversed child-bearing shapes, secret-leak avoidance for YAML dashboards, and the view_path response shape change (view + view_index instead of config). It also discloses failure modes (unknown view_path errors and lists available paths; screenshot render failure errors).
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but well-structured with clear MODE headers, examples, and a workflow example. Every section earns its place given the tool's four-mode complexity. It is front-loaded with the core purpose and mode summary. Slight redundancy exists (e.g., YAML-mode exclusion appears twice, include_screenshot details appear in both the mode section and the parameter description), but the structure makes the length navigable.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For an 11-parameter, 4-mode tool with no output schema, the description is remarkably complete. It covers activation conditions for every mode, return-shape differences, error behavior, cache semantics, security considerations (secrets), and the follow-up write workflow. The examples cover all major modes. Nothing an agent needs to select and invoke the correct mode is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3. The description adds meaningful semantics beyond the schema: it explains mode interactions (mode='search' takes precedence and ignores list_only/entity_id/card_type/heading), the python_path/jq_path contract with the required `config` prefix, wildcard support, and the include_config payload-multiplication caveat. It doesn't add much per-parameter syntax beyond the schema, but the cross-parameter mode logic is genuinely valuable.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a clear verb+resource ('Get dashboard info') and then enumerates four distinct modes (List, Search, Get, Search all) with explicit activation conditions. It distinguishes itself from siblings like ha_config_set_dashboard and ha_get_dashboard_screenshot by naming them and stating when to use them instead.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly states when each mode activates (e.g., 'MODE 1 โ List: list_only=True', 'MODE 3 โ Get: Active when list_only=False and no search parameters are provided'), and names alternatives: 'use the dedicated ha_get_dashboard_screenshot tool instead' and 'ha_config_set_dashboard(python_transform=...)' for follow-up writes. It also gives exclusions: YAML-mode dashboards are not included, strategy dashboards are not searchable.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_config_get_labelGet LabelARead-onlyIdempotent
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.
LABEL PROPERTIES:
ID (label_id), Name
Color (optional), Icon (optional), Description (optional)
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.
| Name | Required | Description | Default |
|---|---|---|---|
| label_id | No | ID of the label to retrieve. If omitted, lists all labels. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already provide readOnlyHint and idempotentHint, but description adds value by listing label properties and explaining dual behavior (list vs fetch). No contradiction.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Well-structured with sections, examples. Every sentence adds essential information without fluff.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given low complexity, full schema coverage, and presence of output schema, description is complete with usage, alternatives, and examples.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, but description adds meaning: omitting label_id lists all, providing it fetches specific. Also lists returned properties.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Description clearly states it gets label info, lists all labels or a specific one by ID. Differentiates from sibling tools like ha_config_set_label and ha_set_entity.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly states when to use with or without label_id, provides examples, and mentions alternative tools for create/update and assigning labels.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_config_get_sceneGet Scene ConfigARead-onlyIdempotent
Retrieve Home Assistant scene configuration.
Returns the complete configuration for a scene, including the entities
dict and other settings (name, icon, id).
EXAMPLES:
Get scene: ha_config_get_scene("movie_night")
Get scene: ha_config_get_scene("bedroom_dim")
RELATED TOOLS:
ha_config_set_scene โ pass the returned
config_hashforpython_transformupdates.
For detailed scene configuration help, use ha_get_skill_guide.
| Name | Required | Description | Default |
|---|---|---|---|
| scene_id | Yes | Scene identifier (e.g., 'movie_night') |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already indicate readOnlyHint and idempotentHint. Description adds that it returns complete config including entities dict and other settings. No contradictions. Sufficiently transparent beyond annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two concise sentences for main description, plus examples and related tools in a well-structured format. Every sentence adds value, no fluff.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given output schema exists and annotations are rich, description is complete for a read-only retrieval tool: purpose, return fields, examples, and related modifications covered.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema has 100% coverage with clear description for scene_id. Examples reinforce usage but description adds little beyond schema. Baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Explicitly states 'Retrieve Home Assistant scene configuration' with clear verb and resource. Distinguishes from sibling ha_config_set_scene. Specifies return fields (entities, name, icon, id).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides examples and related tools section pointing to ha_config_set_scene and mentions passing config_hash for updates. Though no explicit 'when not to use', the context and examples give sufficient guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_config_get_scriptGet Script ConfigARead-onlyIdempotent
Retrieve Home Assistant script configuration.
Returns the complete configuration for a script, including sequence, mode, fields, and other settings.
The returned config_hash is stable across consecutive reads of an unchanged config โ compute_config_hash documents the underlying contract.
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. A leading script. prefix on the input is stripped before lookup โ behavioral parity with ha_config_get_automation (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
| Name | Required | Description | Default |
|---|---|---|---|
| script_id | Yes | Script identifier โ bare storage key ('morning_routine') or entity_id form ('script.morning_routine'); a leading 'script.' prefix is stripped before lookup. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Adds rich behavioral details beyond annotations: config_hash stability contract, script_id resolution fallback, prefix stripping mechanism. The annotations already mark idempotent and read-only, which the description complements without contradiction.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Well-structured with clear sections and examples. The trailing keyword list ('read inspect fetch...') is slightly extraneous but does not detract from clarity. Overall concise and front-loaded with the core purpose.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the existence of an output schema (not shown but assumed comprehensive), the description provides sufficient context on return values (config_hash, script_id) and behavior. Mentions skill guide for further help, completing the user's informational needs.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema covers script_id with 100% documentation, but the description adds significant value by explaining the returned script_id resolution, prefix stripping, and behavioral parity with ha_config_get_automation, enhancing the parameter meaning beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Explicitly states 'Retrieve Home Assistant script configuration' and details the returned content (sequence, mode, fields). Distinguishes from sibling tools like ha_config_set_script and ha_config_remove_script by referencing them in the script_id resolution behavior.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides clear usage context with input examples and notes about prefix stripping. Mentions ha_get_skill_guide for detailed help. Does not explicitly state when not to use this tool, but the read-only nature and sibling relationships are implied.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_config_list_dashboard_resourcesList Dashboard ResourcesARead-onlyIdempotent
List Lovelace dashboard resources (custom cards, themes, CSS/JS).
Returns one page of registered resources; total_count and has_more
report the full set. 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.
inline_count and by_type summarise every resource, not just this page.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Max resources to return per page (default: 100) | |
| offset | No | Number of resources to skip for pagination (default: 0) | |
| include_content | No | Include full decoded content for inline resources. Default False to save tokens (shows 150-char preview instead). |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations indicate readOnlyHint, openWorldHint, and idempotentHint. The description adds valuable behavioral details: pagination via 'one page' and 'total_count'/'has_more', preview for inline resources to save tokens, and summary fields. No contradiction with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise (three sentences) with the main purpose in the first sentence. Every sentence provides essential information without redundancy. It is well-structured and front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the presence of an output schema, the description covers key return fields (total_count, has_more, inline_count, by_type) and explains inline resource behavior. It is sufficient for an agent to use the tool correctly, though it does not detail every field in the output.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3. The description enhances parameter understanding by explaining the practical effect of 'include_content' (preview vs. full content to save tokens), adding context not in the schema. This adds meaningful value beyond the schema alone.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool lists Lovelace dashboard resources and specifies types (custom cards, themes, CSS/JS). It is distinct from sibling list tools like ha_config_list_helpers, but lacks explicit differentiation. However, the purpose is unambiguous and well-communicated.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies usage (listing registered resources) but does not provide explicit when-to-use or when-not-to-use guidance. It does not mention alternatives like ha_config_set_dashboard_resource or ha_config_delete_dashboard_resource, leaving the agent to infer appropriate contexts.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_config_list_groupsList GroupsARead-onlyIdempotent
List Home Assistant entity groups with their member entities.
Returns one page of groups created via group.set service or YAML
configuration; total_count and has_more report the full set. Each
group includes:
Entity ID (group.xxx)
Friendly name
State (on/off based on member states)
Member entities
Icon (if set)
All mode (if all entities must be on)
EXAMPLES:
First page of groups: ha_config_list_groups()
Next page: ha_config_list_groups(offset=100)
NOTE: This returns old-style groups (created via group.set or YAML). Platform-specific groups (light groups, cover groups) are separate entities.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Max groups to return per page (default: 100) | |
| offset | No | Number of groups to skip for pagination (default: 0) |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, and openWorldHint. The description adds significant behavioral context: pagination (one page, limit/offset, total_count and has_more reporting), and the specific fields returned. No contradictions with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise and well-structured: a clear opening sentence, a bullet list of returned fields, two examples, and a clarifying note. Every sentence is necessary and earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the presence of an output schema, comprehensive annotations, and the description covering purpose, pagination, scope, and field list, the description is complete. No gaps are evident for this tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% with descriptions for limit and offset. The description adds value by explaining pagination behavior ('one page' and examples showing usage), which goes beyond the schema's parameter descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states 'List Home Assistant entity groups with their member entities,' specifying the verb and resource. It differentiates from sibling tools by noting that this returns old-style groups created via group.set or YAML, while platform-specific groups are separate entities.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implicitly provides usage context: it is for listing old-style groups, and platform-specific groups are not included. However, it lacks explicit 'when to use' vs alternatives or 'when not to use' guidance, though the note offers some differentiation.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_config_list_helpersList HelpersARead-onlyIdempotent
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 complete configuration for its helper,
including:
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 (min/max for input_number, options for input_select, etc.)
Area and label assignments
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).
SUPPORTED HELPER TYPES:
input_button: Virtual buttons for triggering automations
input_boolean: Toggle switches/checkboxes
input_select: Dropdown selection lists
input_number: Numeric sliders/input boxes
input_text: Text input fields
input_datetime: Date/time pickers
counter: Counters with increment/decrement/reset
timer: Countdown timers with start/pause/cancel
schedule: Weekly schedules with time ranges (on/off per day)
zone: Geographical zones for presence detection
person: Person entities linked to device trackers
tag: NFC/QR tags for automation triggers
EXAMPLES:
List all number helpers: ha_config_list_helpers("input_number")
List all counters: ha_config_list_helpers("counter")
List all zones: ha_config_list_helpers("zone")
List all persons: ha_config_list_helpers("person")
List all tags: ha_config_list_helpers("tag")
List every helper type at once: ha_config_list_helpers("all")
Next page: ha_config_list_helpers("input_boolean", offset=100)
NOTE: 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.
Flow-based types (template / group / utility_meter / derivative / etc.) require the ha_mcp_tools custom component (>= 1.1.0) and are served only through it; storage types are listed on all installs. Requesting a flow type without the component returns a COMPONENT_NOT_INSTALLED error.
Pass helper_type="all" to enumerate every helper type in a single call.
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.
For detailed helper documentation, use ha_get_skill_guide.
list all helpers input_boolean input_number input_text counter timer input_datetime input_select
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Max helpers to return per page (default: 100) | |
| offset | No | Number of helpers to skip for pagination (default: 0) | |
| helper_type | Yes | Helper type to list. Storage types are listed on all installs; flow-based types require the ha_mcp_tools custom component. Pass 'all' to list every helper type in one call (also requires the ha_mcp_tools component). |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description discloses crucial behavioral details: the distinction between storage-based and flow-based types, the handling of renamed helpers (entity_id vs id), the fallback behavior when the registry read degrades, and the fact that each record includes its own helper_type. It also notes that 'all' mode requires the component. These transparency points exceed the bare annotation hints (readOnlyHint, idempotentHint) and provide valuable expectations for callers.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is excessively verbose and repetitive. It lists the same set of helper types in at least two separate blocks (SUPPORTED HELPER TYPES and EXAMPLES) and again within the note about storage vs flow. It includes redundant examples and a seemingly accidental trailing line 'list all helpers input_boolean input_number input_text counter timer input_datetime input_select'. The overall structure could be streamlined significantly without losing information, making it harder to parse quickly.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description is comprehensive: it covers error cases (COMPONENT_NOT_INSTALLED), explains the distinction between storage and flow types, details pagination, clarifies the 'all' mode, and mentions integration with the skill guide. Given the tool's complexity (multiple helper types, conditional behavior, pagination), it provides all necessary context for correct usage.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema fully documents all three parameters (helper_type, limit, offset) with descriptions and ranges. The description goes beyond the schema by explaining the significance of helper_type values, the storage vs flow split, and the behavior of 'all'. It also clarifies pagination semantics. Schema coverage is 100%, and the description adds substantial context, so this dimension is well covered.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's purpose: to list Home Assistant helpers of a specific type. It distinguishes from sibling tools like ha_config_get_helper (retrieves a single helper) and ha_config_set_helper (modifies helpers). The mention of 'list all helpers' and the enumeration of supported types makes the intent unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit guidance on when to use this tool, including pagination via limit and offset, the special 'all' mode, and the requirement for the ha_mcp_tools component for flow-based types. It also explains error conditions (COMPONENT_NOT_INSTALLED) and how to enumerate all types. This is thorough and actionable.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_config_remove_automationRemove AutomationADestructiveIdempotent
Delete a Home Assistant automation.
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")
WARNING: Deleting an automation removes it permanently from your Home Assistant configuration.
| Name | Required | Description | Default |
|---|---|---|---|
| wait | No | Wait for automation to be fully removed before returning. Default: True. | |
| identifier | Yes | Automation entity_id (e.g., 'automation.old_automation') or unique_id to delete |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already indicate destructiveness, and the description adds the return value behavior and a warning about permanent deletion. No contradictions.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise with a clear front-loaded purpose, followed by return value explanation, examples, and warning. No unnecessary content.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a deletion tool with annotations and output schema, the description covers purpose, return behavior, examples, and warning. Could mention error handling or prerequisites but is fairly complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Input schema covers both parameters fully, so baseline is 3. The description adds explanation of the return value depending on identifier but does not elaborate on the 'wait' parameter.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states it deletes a Home Assistant automation, with specific verb and resource. It distinguishes from sibling tools by targeting automations specifically.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies usage for deleting automations and provides examples, but does not explicitly state when to use this vs other removal tools, nor any prerequisites or when-not-to-use.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_config_remove_calendar_eventRemove Calendar EventADestructiveIdempotent
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.
Parameters:
entity_id: Calendar entity ID (e.g., 'calendar.family')
uid: Unique identifier of the event to delete
recurrence_id: Optional recurrence ID for recurring events
recurrence_range: Optional recurrence range ('THIS_AND_FUTURE' to delete this and future occurrences)
Example Usage:
# Delete a single event
result = ha_config_remove_calendar_event(
"calendar.family",
uid="event-12345"
)
# Delete a recurring event instance and future occurrences
result = ha_config_remove_calendar_event(
"calendar.work",
uid="recurring-event-67890",
recurrence_id="20240115T100000",
recurrence_range="THIS_AND_FUTURE"
)Note: To get the event UID, first use ha_config_get_calendar_events() to list events. The UID is returned in each event's data.
Returns:
Success status and deletion confirmation
| Name | Required | Description | Default |
|---|---|---|---|
| uid | Yes | Unique identifier of the event to delete | |
| entity_id | Yes | Calendar entity ID (e.g., 'calendar.family') | |
| recurrence_id | No | Optional recurrence ID for recurring events | |
| recurrence_range | No | Optional recurrence range ('THIS_AND_FUTURE' to delete this and future occurrences) |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true and idempotentHint=true, covering safety and idempotency. The description adds useful context: it uses the WebSocket 'calendar/event/delete' command, returns success status and confirmation, and clarifies that delete is only available via WebSocket. This supplements the annotations without contradiction.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured with a clear title, short purpose statement, detailed parameter list, example usage, a note on prerequisite, and return value. Every sentence serves a purpose, and the format is easy to scan. It is appropriately sized for a tool with 4 parameters and an output schema.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's moderate complexity (4 parameters, 2 required, output schema exists), the description covers the essential workflow: obtaining the UID, using required and optional parameters, and understanding the return. It could benefit from mentioning error handling or permission requirements, but overall it is sufficiently complete for an agent to use correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema has 100% description coverage, so baseline is 3. The description repeats parameter descriptions exactly as in the schema and includes examples demonstrating usage. While examples are helpful, they do not add new semantic information beyond what the schema already provides (e.g., recurrence_range values are already documented).
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states 'Delete an event from a calendar', using a specific verb and resource. It distinguishes itself from sibling tools like ha_config_get_calendar_events (get events) and ha_config_set_calendar_event (set/create event) by explicitly focusing on deletion. The mention of the WebSocket command further clarifies the action.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides a prerequisite note: use ha_config_get_calendar_events to obtain the event UID before deletion. It also explains that delete operations only exist on WebSocket, contrasting with REST services for create/get. However, it does not explicitly exclude usage for modifications or specify when not to use this tool, leaving a minor gap.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_config_remove_categoryRemove CategoryADestructiveIdempotent
Delete a Home Assistant category.
Removes the category from the category registry for the given scope (e.g., 'automation', 'script', 'scene', 'helpers'). 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.
| Name | Required | Description | Default |
|---|---|---|---|
| scope | Yes | Domain scope for the category (e.g., 'automation', 'script', 'scene', 'helpers'). | |
| category_id | Yes | ID of the category to delete |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true and idempotentHint=true. The description adds crucial context: 'This will also remove the category assignment from all entities in that scope' and 'This action cannot be undone.' This goes beyond annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise: a clear opening sentence, followed by effect, example, reference to get_category, and warning. Every sentence adds value and the structure is front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the presence of an output schema (not shown), the description adequately covers the delete operation's effect and irreversibility. It does not mention error conditions, but this is acceptable for a simple destructive tool with good annotations.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% with descriptions for both parameters. The description adds example usage with parameter names but no additional semantic details beyond what the schema already provides.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states 'Delete a Home Assistant category' with specific verb+resource. Among sibling tools, it is distinct from other removal tools like ha_remove_zone or ha_remove_entity.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explains the scope of use (category registry, given scope) and provides an example. It advises using ha_config_get_category() to find IDs. It could be more explicit about when not to use this tool versus alternatives, but gives sufficient context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_config_remove_groupRemove GroupADestructiveIdempotent
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.
| Name | Required | Description | Default |
|---|---|---|---|
| wait | No | Wait for group to be fully removed before returning. Default: True. | |
| object_id | Yes | Group identifier without 'group.' prefix (e.g., 'living_room_lights') |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Adds important behavioral warnings beyond annotations: automations may fail, YAML groups reappear after restart, only removes old-style groups. Annotations already indicate destructiveHint, but description provides specifics.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Well-structured with clear sections, warnings, and an example. Front-loaded with main purpose, then conditional guidance. No wasted words.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers purpose, usage, behavioral traits, and mentions runtime behavior. Missing details on permissions or side effects beyond automations, but overall comprehensive given output schema exists.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so parameters are well-documented. Description adds minimal value beyond schema (only an example usage of object_id). Baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Clearly states the action (remove), resource (service-based Home Assistant entity group), and method (via group.remove service). Differentiates from sibling tools by specifying which groups are covered.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit 'When NOT to use' with reference to sibling tool ha_remove_helpers_integrations, and 'When to use' with examples. Also suggests listing groups first with ha_config_list_groups().
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_config_remove_labelRemove LabelADestructiveIdempotent
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.
| Name | Required | Description | Default |
|---|---|---|---|
| label_id | Yes | ID of the label to delete |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description explains that deleting a label removes it from all entities, devices, and areas, and that the action cannot be undone. This adds significant behavioral context beyond the annotations (destructiveHint true, idempotentHint true).
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured: clear purpose, then details, then example, then warning. Each sentence is informative and necessary.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the single required parameter, annotations, and presence of an output schema, the description fully covers what the tool does and its effects.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema describes label_id as 'ID of the label to delete' (100% coverage). The description adds value by mentioning where to find label IDs (ha_config_get_label()).
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states 'Delete a Home Assistant label' and explains the action (remove from registry and assigned entities). It distinguishes itself from sibling tools like ha_config_set_label and ha_config_get_label by its delete operation.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides an example command and suggests using ha_config_get_label() to find label IDs. It warns about irreversible removal, but does not explicitly state when to use this tool over alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_config_remove_sceneRemove SceneADestructiveIdempotent
Delete a Home Assistant scene.
EXAMPLES:
Delete scene: ha_config_remove_scene("old_scene")
Delete scene: ha_config_remove_scene("temporary_scene")
IMPORTANT LIMITATION: This tool can only delete scenes created via the Home Assistant UI. Scenes defined in YAML configuration files (scenes.yaml or configuration.yaml) cannot be deleted through the API and will return a 405 Method Not Allowed error.
To remove YAML-defined scenes, you must edit the configuration file directly.
WARNING: Deleting a scene that is referenced by automations or scripts
(via scene.turn_on) may cause those to fail.
| Name | Required | Description | Default |
|---|---|---|---|
| wait | No | Wait for scene to be fully removed before returning. Default: True. | |
| scene_id | Yes | Scene identifier to delete (e.g., 'old_scene') |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already indicate destructive and idempotent behavior. Description adds critical context: the tool fails with 405 for YAML scenes and may cause automation failures if referenced. No contradiction with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Well-structured with examples, an important limitation section, and a warning. Each element adds value, though the description could be slightly tighter without losing clarity.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the output schema exists, the description adequately covers purpose, limitations, and caveats. It addresses the key behavioral aspects and constraints, making it sufficiently complete for an agent.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents both parameters. The description does not add new meaning beyond what the schema provides, meeting the baseline expectation.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Description states 'Delete a Home Assistant scene.' This is a clear verb+resource pair. It distinguishes the tool's scope (scenes) from sibling tools that remove other entities, though it doesn't explicitly differentiate.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit guidance: only UI-created scenes can be deleted; YAML-defined scenes require editing configuration. Also warns about references in automations/scripts causing failures. This clearly tells the agent when to use and when not to use.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_config_remove_scriptRemove ScriptADestructiveIdempotent
Delete a Home Assistant script.
EXAMPLES:
Delete script: ha_config_remove_script("old_script")
Delete script: ha_config_remove_script("temporary_script")
IMPORTANT LIMITATION: This tool can only delete scripts created via the Home Assistant UI. Scripts defined in YAML configuration files (scripts.yaml or configuration.yaml) cannot be deleted through the API and will return a 405 Method Not Allowed error.
To remove YAML-defined scripts, you must edit the configuration file directly.
WARNING: Deleting a script that is used by automations may cause those automations to fail.
| Name | Required | Description | Default |
|---|---|---|---|
| wait | No | Wait for script to be fully removed before returning. Default: True. | |
| script_id | Yes | Script identifier to delete โ bare storage key ('old_script') or entity_id form ('script.old_script'); a leading 'script.' prefix is stripped before lookup. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already provide destructiveHint=true, but the description adds critical behavioral details: the tool only works on UI-created scripts and may break automations. It does not discuss idempotency, but overall adds value beyond annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Description is well-structured with sections (examples, limitation, warning). Each part adds value, though slightly verbose. Could be more concise but remains clear and organized.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers purpose, usage, limitations, side effects, and examples. Given the tool's simplicity (2 params, destructive) and presence of output schema, the description is thorough and leaves no important gaps.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, baseline 3. Description adds meaning: explains script_id can be bare key or entity_id with prefix stripping, and clarifies wait default. This extra context merits a 4.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states 'Delete a Home Assistant script' and distinguishes it from sibling tools like automation or scene removal by specifying scripts. The limitation about UI vs YAML-created scripts adds further specificity.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit guidance on when to use (deleting UI-created scripts) and when not to (YAML-defined scripts, instructing to edit configuration directly). Warns about potential automation failures, giving clear context for tool selection.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_config_set_automationCreate or Update AutomationADestructive
Create or update a Home Assistant automation.
MUST call ha_get_skill_guide OR refer to your locally installed skills first.
PREFER NATIVE SOLUTIONS OVER TEMPLATES (read this before writing any {{ ... }}):
Native triggers/conditions/actions are validated at config load, fail loudly, and
do not bypass HA's schema. Templates fail silently at runtime and obscure intent.
condition: numeric_stateinstead of{{ states('x') | float > N }}condition: state(withstate:list) instead of{{ is_state(...) }}/{{ states(x) in [...] }}condition: timeinstead of{{ now().hour ... }}or{{ now().weekday() ... }}condition: suninstead of{{ is_state('sun.sun', ...) }}Native
for:field onstate/numeric_statetriggers andstateconditions over{{ now() - X.last_changed > timedelta(...) }}duration math.wait_for_triggerinstead ofwait_templatechooseaction instead of template-based service namesFor one-shot date firing, use a
timetrigger plusautomation.turn_offon a hardcoded entity_id โ not{{ now().date() ... }}.Hardcode
target.entity_idliterals โ never{{ this.entity_id }}. Templates are appropriate ONLY indata.*fields, notification message/title,event_data, andvariables. The reactive best-practice checker on this tool will surface anything in a logic position that should be native; consult thebest_practice_warningsfield on the response and fix before re-submitting. The relevant skill section is auto-embedded underskill_contenton warnings, and the fullautomation-patterns.md+template-guidelines.mdreferences ship underskill_contentproactively by default. For comprehensive guidance beyond that, callha_get_skill_guide.
The returned automation_id is the resolved entity_id (canonical
form, e.g. automation.morning_routine) when entity registration
succeeds, falling back to the input identifier (update path) or
the generated unique_id from the upsert response (fresh create
when no identifier was passed).
Before reaching for ha_config_set_automation, consider whether a
dedicated tool fits the use case better:
State snapshot of one or more entities (capture-then-replay, no trigger needed) -> ha_config_set_scene
State-derived value that recomputes when its inputs change (template sensor / binary sensor / number / select) -> ha_config_set_helper(helper_type='template')
Stateful counter / timer / schedule / boolean / etc. -> ha_config_set_helper(helper_type='counter' | 'timer' | ...)
Supports three modes: full config replacement, Python transformation, or take_control_of_blueprint (see below).
WHEN TO USE WHICH MODE:
python_transform: RECOMMENDED for edits to existing automations. Surgical updates.
config: Use for creating new automations or full restructures.
take_control_of_blueprint: converts a blueprint-backed automation into a standalone one. Takes no config of its own.
IMPORTANT: python_transform requires 'identifier' and 'config_hash' from ha_config_get_automation().
PYTHON TRANSFORM EXAMPLES (operate on the fetched config, which uses HA's canonical plural root keys 'triggers'/'actions'/'conditions'):
Update action: python_transform="config['actions'][0]['data']['brightness'] = 255"
Add trigger: python_transform="config['triggers'].append({'trigger': 'state', 'entity_id': 'binary_sensor.motion', 'to': 'on'})"
Remove last action: python_transform="config['actions'].pop()"
Omit identifier and config['id'] to create a new automation with a generated ID. A previously unused raw ID can also create an automation with that specific ID. Reusing an identifier targets the same automation, even if the alias changes. To intentionally rename or replace it, first read it with ha_config_get_automation and pass its config_hash. A changed alias without that hash is rejected before writing.
AUTOMATION TYPES:
Regular Automations - Define triggers and actions directly
Blueprint Automations - Use pre-built templates with customizable inputs
REQUIRED FIELDS (Regular Automations):
alias: Human-readable automation name
triggers: List of triggers (time, state, event, etc.)
actions: List of actions to execute
REQUIRED FIELDS (Blueprint Automations):
alias: Human-readable automation name
use_blueprint: Blueprint configuration
path: Blueprint file path (e.g., "motion_light.yaml")
input: Dictionary of input values for the blueprint
OPTIONAL CONFIG FIELDS (Regular Automations):
description: Detailed description of the user's intent (RECOMMENDED: helps safely modify implementation later)
category: Category ID for organization (use ha_config_get_category to list, ha_config_set_category to create)
conditions: Additional conditions that must be met
mode: 'single' (default), 'restart', 'queued', 'parallel'
max: Maximum concurrent executions (for queued/parallel modes)
initial_state: Whether automation starts enabled (true/false)
variables: Variables for use in automation
BASIC EXAMPLES:
Simple time-based automation: ha_config_set_automation(config={ "alias": "Morning Lights", "description": "Turn on bedroom lights at 7 AM to help wake up", "triggers": [{"trigger": "time", "at": "07:00:00"}], "actions": [{"action": "light.turn_on", "target": {"area_id": "bedroom"}}] })
Motion-activated lighting โ for: on the off-transition replaces action-delay:
ha_config_set_automation(config={
"alias": "Motion Light",
"triggers": [
{"trigger": "state", "entity_id": "binary_sensor.motion", "to": "on", "id": "motion_on"},
{"trigger": "state", "entity_id": "binary_sensor.motion", "to": "off",
"for": {"minutes": 5}, "id": "motion_off"}
],
"actions": [
{"choose": [
{"conditions": [
{"condition": "trigger", "id": "motion_on"},
{"condition": "sun", "after": "sunset"}
],
"sequence": [{"action": "light.turn_on", "target": {"entity_id": "light.hallway"}}]},
{"conditions": [{"condition": "trigger", "id": "motion_off"}],
"sequence": [{"action": "light.turn_off", "target": {"entity_id": "light.hallway"}}]}
]}
]
})
Update existing automation: current = ha_config_get_automation(identifier="automation.morning_routine") ha_config_set_automation( identifier="automation.morning_routine", config_hash=current["config_hash"], config={ "alias": "Updated Morning Routine", "triggers": [{"trigger": "time", "at": "06:30:00"}], "actions": [ {"action": "light.turn_on", "target": {"area_id": "bedroom"}}, {"action": "climate.set_temperature", "target": {"entity_id": "climate.bedroom"}, "data": {"temperature": 22}} ] } )
BLUEPRINT AUTOMATION EXAMPLES:
Create automation from 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"}, "no_motion_wait": 120 } } })
Update blueprint automation inputs: ha_config_set_automation( identifier="automation.motion_light_kitchen", 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"}, "no_motion_wait": 300 } } } )
TAKE CONTROL OF A BLUEPRINT AUTOMATION:
take_control_of_blueprint=True converts a blueprint-backed automation into a standalone one โ the UI's "Take control". The blueprint is rendered with the automation's CURRENT inputs and the result is saved over the same automation, which keeps its entity_id, alias and description but gains its own triggers/conditions/actions and loses 'use_blueprint'.
ha_config_set_automation( identifier="automation.motion_light_kitchen", take_control_of_blueprint=True, )
This is one-way: the automation is no longer linked to the blueprint, so later blueprint edits stop reaching it. To change an input value, update 'use_blueprint.input' instead (see the example above) โ that keeps the link.
Taking control does NOT free the blueprint. Home Assistant goes on counting a converted automation as a user of it, so deleting that blueprint stays refused until the automation itself is removed (verified against Home Assistant 2026.9; an automation reload does not clear it either).
The response names the blueprint in took_control_of_blueprint. To see what the rendering looks like WITHOUT writing
anything, call ha_manage_blueprints(action="substitute", path=...,
input=...), which returns the config and leaves the automation alone.
ha_manage_blueprints also lists, imports, saves and deletes blueprints,
and action="get" reports which automations use one.
TRIGGER TYPES: time, time_pattern, sun, state, numeric_state, event, device, zone, template, and more CONDITION TYPES: state, numeric_state, time, sun, template, device, zone, and more ACTION TYPES: action calls, delays, wait_for_trigger, wait_template, if/then/else, choose, repeat, parallel
For comprehensive automation documentation with all trigger/condition/action types and advanced examples:
Use: ha_get_skill_guide
TROUBLESHOOTING:
Use ha_get_state() to verify entity_ids exist
Use ha_search() to find correct entity_ids
IF you must use Jinja2 and have no native alternative, test it first with ha_eval_template() before embedding it in the automation config โ catches syntax errors and unresolved entity_ids before they fail silently at runtime
Use ha_search(domain_filter='automation') to find existing automations
create update modify edit automation triggers conditions actions new automation write save take control blueprint detach unlink standalone convert
| Name | Required | Description | Default |
|---|---|---|---|
| wait | No | Wait for automation to be queryable before returning. Default: True. Set to False for bulk operations. | |
| config | No | Complete automation configuration with required fields: 'alias', 'triggers', 'actions'. Optional: 'description', 'conditions', 'mode', 'max', 'initial_state', 'variables'. Purpose-specific triggers/conditions (HA 2026.7+ default: 'trigger': '<domain>.<name>' with 'target'/'options') are valid config. Mutually exclusive with python_transform. | |
| category | No | Category ID to assign to this automation. Use ha_config_get_category(scope='automation') to list available categories, or ha_config_set_category() to create one. | |
| identifier | No | Target automation entity_id or HA config 'id' (unique_id). Omit for creation with a generated ID. Values such as 'new' are literal IDs, not placeholders. Required for python_transform. | |
| config_hash | No | Config hash from ha_config_get_automation for optimistic locking. REQUIRED for python_transform (validates automation unchanged). Required when a config update changes an existing automation's alias. Otherwise optional for config updates (validates before full replacement if provided). | |
| MandatoryBPS | No | ||
| BestPracticeKey | No | Read-receipt for the home-assistant-best-practices skill; required when strict best-practices mode is enabled. Not a secret or credential: the current value is an attestation phrase published openly at the top of the skill content served by ha_get_skill_guide. Read that content, then pass the value back verbatim โ this round-trip is the server's designed protocol confirming the practices were read before writing. | |
| python_transform | No | Python expression to transform existing automation config. Mutually exclusive with config. Requires identifier and config_hash for validation. WARNING: Expressions with infinite loops will hang the server. Examples: Simple: python_transform="config['actions'][0]['data']['brightness'] = 255" Pattern: python_transform="for a in config['actions']: if a.get('alias') == 'My Step': a['data']['value'] = 100" PYTHON TRANSFORM SECURITY: โ ALLOWED: - Dictionary/list access: config['views'][0]['cards'][1] - Slicing: config['views'][0]['cards'][1:3] - Assignment: config['key'] = 'value' - Deletion: del config['key'] or config.pop('key') - List methods: append, insert, pop, remove, clear, extend - Dict methods: update, get, setdefault, keys, values, items - Loops: for, if/else, pass, break, continue - Comprehensions: [x for x in ...], {k: v for ...}, (x for x in ...) - Ternary: x if condition else y - Iterable unpacking (* in calls/literals): f(*xs), [*xs, y] - Dict unpacking (**) in calls and dict literals: {**d, 'k': v} - Keyword arguments: func(key=value) - Lambdas (e.g. for `key=`): sorted(items, key=lambda x: x['score']) - String methods: startswith, endswith, lower, upper, strip, split, join, replace - Safe builtins: isinstance, len, range, enumerate, zip, sorted, reversed, min, max, sum, abs, any, all, round, str, int, float, bool, list, dict, tuple, set โ FORBIDDEN: - Imports: import, from, __import__ - File operations: open, read, write - Dunder access: __class__, __bases__, __subclasses__ - Dangerous builtins: eval, exec, compile, getattr, setattr, delattr, hasattr - Function definitions: def, class - Exception handling: try/except (validate with isinstance/in/.get() instead) - While loops: use bounded for loops or comprehensions instead ๐ฏ PATTERNS: - Filter cards: cards = [c for c in cards if keep(c)] - Skip in a loop: prefer `continue` over an empty `pass` branch (clearer) - Conditionally include: build a new list and `.append(x)` only the cards you want, instead of iterating the original and using if/pass branches to drop entries - Modify in place when possible (single pass, fewer surprises) over reconstructing the entire list | |
| take_control_of_blueprint | No | Convert a blueprint-backed automation into an editable standalone one -- the UI's "Take control". Renders the blueprint with its current inputs and saves the result over the same automation, which then has its own triggers/conditions/actions and no 'use_blueprint'. Requires identifier; mutually exclusive with config and python_transform. Irreversible: the link to the blueprint is gone afterwards, so edit inputs instead if you only want to change a value. 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. To preview the rendering without writing anything, use ha_manage_blueprints(action="substitute"). |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the destructiveHint annotation, the description discloses key behavioral traits: take_control_of_blueprint is irreversible, the blueprint remains counted as in use, alias changes without config_hash are rejected before writing, and infinite python_transform loops can hang the server. It also explains return-value semantics for automation_id and the best-practice checker behavior. No contradiction with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but well-structured with clear headings, examples, and front-loaded critical guidance (MUST call skill, prefer native solutions). Some redundancy exists around repeated skill references and the bottom documentation link, but the length is largely justified by the tool's complexity.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with 9 parameters, three operating modes, blueprint edge cases, and an output schema, the description is remarkably complete. It covers creation, update, python_transform, blueprint take-control, troubleshooting, return behavior, and alternative tools, leaving little ambiguity for an agent.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Although schema coverage is 89%, the description adds substantial meaning beyond the schema: full config examples, python_transform patterns with allowed/forbidden operations, mode selection rules, mutual exclusivity constraints, identifier/config_hash requirements, and blueprint input examples. This significantly helps an agent construct correct parameter values.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a clear verb and resource: 'Create or update a Home Assistant automation.' It goes further by naming sibling tools for alternatives (ha_config_set_scene, ha_config_set_helper) and explicitly distinguishing modes, so an agent can tell this tool apart from nearby automation-related tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives explicit when-to-use guidance: use ha_config_set_scene for state snapshots, ha_config_set_helper for computed values, and this tool for automations. It also details which mode to use (python_transform for edits, config for new automations, take_control_of_blueprint for blueprint conversion) and requires calling ha_get_skill_guide first.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_config_set_calendar_eventCreate or Update Calendar EventADestructive
Create a new event in a calendar.
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).
When NOT to use:
To retrieve calendar events, use
ha_config_get_calendar_events.To delete an event, use
ha_config_remove_calendar_event.
Example Usage:
# Create a simple event
result = ha_config_set_calendar_event(
"calendar.family",
summary="Doctor appointment",
start="2024-01-15T14:00:00",
end="2024-01-15T15:00:00"
)
# Create a recurring event (every Monday, 10 occurrences)
result = 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"
)
# Create an all-day event (date-only, no time component). The end
# date is EXCLUSIVE, so this spans 2026-07-04 through 2026-07-10.
result = ha_config_set_calendar_event(
"calendar.family",
summary="Vacation",
start="2026-07-04",
end="2026-07-11"
)Note:
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. Because the
all-day end date is exclusive, a single-day all-day event must
set end to start + 1 day.
Not every calendar integration supports event creation; recurring events additionally require the integration to support recurrence (the built-in Local Calendar does).
Returns:
Success status and event details
| Name | Required | Description | Default |
|---|---|---|---|
| end | Yes | Event end date or datetime in ISO format. For all-day events (date-only) the end date is exclusive; a single-day all-day event needs end = start + 1 day. | |
| rrule | No | Optional RFC 5545 recurrence rule, without 'RRULE:' prefix (e.g., 'FREQ=WEEKLY;BYDAY=MO' or 'FREQ=MONTHLY;BYDAY=3SA'). Creates a recurring event series. | |
| start | Yes | Event start date or datetime in ISO format | |
| summary | Yes | Event title/summary | |
| location | No | Optional event location | |
| entity_id | Yes | Calendar entity ID (e.g., 'calendar.family') | |
| description | No | Optional event description |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already mark destructiveHint=true, but the description adds crucial context: exclusive end date for all-day events, requirement for recurrence support, and failure modes for mixed date formats. No contradiction with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-organized into clear sections (purpose, when not to, examples, notes, returns). Every sentence adds value without unnecessary fluff.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given 7 parameters, 4 required, and an output schema, the description covers all critical aspects: differences between event types, integration limitations, return values, and common pitfalls (date mixing, exclusive end). A complete guide for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3, but the description adds meaning through examples (all-day vs timed events, rrule format) and notes on exclusive end dates, which clarifies parameter interaction beyond the schema descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool creates calendar events, distinguishes between one-off and recurring, and explicitly contrasts with sibling tools for retrieval (ha_config_get_calendar_events) and deletion (ha_config_remove_calendar_event).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides a dedicated 'When NOT to use' section naming specific alternatives, along with multiple examples and detailed notes on date format mixing and integration support. This is explicit guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_config_set_categoryCreate or Update CategoryADestructive
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.
| Name | Required | Description | Default |
|---|---|---|---|
| icon | No | Material Design Icon (e.g., 'mdi:tag', 'mdi:label') | |
| name | Yes | Display name for the category | |
| scope | Yes | Domain scope for the category (e.g., 'automation', 'script', 'scene', 'helpers'). | |
| category_id | No | Category ID for updates. If not provided, creates a new category. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description reveals the tool can create or update, implying mutation. This aligns with the destructiveHint=true annotation. It adds context about domain scoping and update behavior (providing category_id updates). No contradiction with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured with clear sections: summary, explanation, and examples. It is front-loaded with the core purpose and is not overly verbose. The examples add length but are helpful.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the presence of an output schema, the description does not need to explain return values. It covers creation vs update, scoping, and provides examples for typical use cases. It also references a related tool (ha_set_entity) for assigning categories, making it complete for the user.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the schema handles basic meaning. The description adds value through examples that clarify usage of icon and category_id, and emphasizes the create/update distinction. While schema already describes each parameter, the examples provide practical context.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool creates or updates a Home Assistant category, specifying the resource (category) and action (create/update). It distinguishes from labels by noting categories are domain-scoped, but does not explicitly differentiate from sibling tools like ha_config_get_category or ha_config_remove_category.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides clear guidance on when to use the tool: create new (no category_id) or update existing (with category_id). It includes examples for each case and references ha_set_entity for assigning categories. However, it does not explicitly state when not to use it or mention alternatives beyond the label comparison.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_config_set_dashboardCreate or Update DashboardADestructive
Create or update a Home Assistant dashboard.
MUST call ha_get_skill_guide OR refer to your locally installed skills first.
Creates a new dashboard or updates an existing one with the provided configuration. Supports full config replacement, Python transformation, or structured patch edits.
Use 'default' or 'lovelace' to target the built-in default dashboard. New dashboards require a hyphenated url_path (e.g., 'my-dashboard').
WHEN TO USE WHICH MODE:
patch: Edit known paths with literal values using add/remove/replace/test and config_hash. Example: patch=[{"op": "replace", "path": "/views/0/title", "value": "Home"}]. Append with /views/0/cards/-; escape ~ as ~0 and / as ~1 in path keys. move/copy are unsupported. See the full patch guide: https://github.com/homeassistant-ai/ha-mcp/blob/master/docs/dashboard-edits.md
python_transform: Use loops or pattern-based changes across cards and views.
config: New dashboards only, or full restructure. Replaces everything.
IMPORTANT: After delete/add operations, indices shift! Subsequent python_transform calls must use fresh config_hash from ha_config_get_dashboard() to get updated structure. Chain multiple ops in ONE expression when possible.
TIP: Use ha_config_get_dashboard(entity_id=...) to get the path for any card.
TIP: return_screenshot=True bundles rendered image(s) with the write result (beta feature); for visual re-checks after the write, use the dedicated ha_get_dashboard_screenshot tool instead of re-sending config.
PYTHON TRANSFORM EXAMPLES:
Update card icon: 'config["views"][0]["cards"][0]["icon"] = "mdi:thermometer"'
Add card: 'config["views"][0]["cards"].append({"type": "button", "entity": "light.bedroom"})'
Delete card: 'del config["views"][0]["cards"][2]'
Pattern-based update: 'for card in config["views"][0]["cards"]: if "light" in card.get("entity", ""): card["icon"] = "mdi:lightbulb"'
Multi-operation: 'config["views"][0]["cards"][0]["icon"] = "mdi:a"; config["views"][0]["cards"][1]["icon"] = "mdi:b"'
MODERN DASHBOARD BEST PRACTICES:
Use "sections" view type (default) with grid-based layouts
Use "tile" cards as primary card type (replaces legacy entity/light/climate cards)
Use "grid" cards for multi-column layouts within sections
Create multiple views with navigation paths (avoid single-view endless scrolling)
Use "area" cards with navigation for hierarchical organization
DISCOVERING ENTITY IDs FOR DASHBOARDS: Do NOT guess entity IDs - use these tools to find exact entity IDs:
ha_get_overview(include_entity_id=True) - Get all entities organized by domain/area
ha_search(query, domain_filter, area_filter, search_types) - Find entities and config-body references in one call
If unsure about entity IDs, ALWAYS use one of these tools first.
DASHBOARD DOCUMENTATION:
dashboard-guide.md and dashboard-cards.md ship in this response under
skill_contentby default โ layout patterns, card-type taxonomy, and worked examples.ha_get_skill_guide โ deeper card-type and configuration guidance.
EXAMPLES:
Create empty dashboard: ha_config_set_dashboard( url_path="mobile-dashboard", title="Mobile View", icon="mdi:cellphone" )
Create dashboard with modern sections view: 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", "features": [{"type": "target-temperature"}] }] }] }] } )
Create strategy-based dashboard (auto-generated): ha_config_set_dashboard( url_path="my-home", title="My Home", config={ "strategy": { "type": "home", "favorite_entities": ["light.bedroom"] } } )
Note: Strategy dashboards cannot be converted to custom dashboards via this tool. Use the "Take Control" feature in the Home Assistant interface to convert them.
Update existing dashboard config: ha_config_set_dashboard( url_path="existing-dashboard", config={ "views": [{ "title": "Updated View", "type": "sections", "sections": [{ "cards": [{"type": "markdown", "content": "Updated!"}] }] }] } )
Note: title/icon/require_admin/show_in_sidebar can be updated in metadata-only calls or alongside a full config replacement. For python_transform or patch, update metadata in a separate call; combining it with patch is rejected.
STORAGE-MODE vs YAML-MODE DASHBOARDS: This tool only manages storage-mode dashboards (created via UI/API and stored in Home Assistant's storage backend). It does NOT touch YAML-defined dashboards. Two distinct YAML cases exist and this tool covers neither:
"YAML-mode" dashboards: written in their own .yaml file referenced from configuration.yaml under
lovelace: dashboards:. The dashboard itself lives in a separate YAML file but its registration is in configuration.yaml.Dashboards inlined directly in
configuration.yamlunder thelovelace:key (legacy single-dashboard mode). For either YAML case, edit the dashboard's .yaml file directly.ha_config_set_yamlcan update thelovelace:registration entry in configuration.yaml but does NOT touch the dashboard body in the referenced .yaml file.
| Name | Required | Description | Default |
|---|---|---|---|
| icon | No | MDI icon name (e.g., 'mdi:home', 'mdi:cellphone'). Defaults to 'mdi:view-dashboard' | |
| patch | No | Structured dashboard edits: up to 100 JSON Patch add, remove, replace or test operations using RFC 6901 paths. Use /- to append to an array; escape ~ as ~0 and / as ~1 in keys. Requires config_hash. Mutually exclusive with config and python_transform. Update title/icon/require_admin/show_in_sidebar in a separate call. Strings in value are preserved literally. | |
| title | No | Dashboard display name shown in sidebar | |
| config | No | Dashboard configuration with views and cards. Omit or set to None to create dashboard without initial config. Mutually exclusive with python_transform and patch. | |
| url_path | Yes | Dashboard URL path (e.g., 'my-dashboard'). Use 'default' or 'lovelace' for the default dashboard. New dashboards must use a hyphenated path. | |
| view_path | No | With return_screenshot: stable Lovelace views[].path to render. | |
| config_hash | No | Config hash from ha_config_get_dashboard for optimistic locking. REQUIRED for python_transform and patch (validates dashboard unchanged). Optional for config (validates before full replacement if provided). | |
| MandatoryBPS | No | ||
| require_admin | No | Restrict dashboard to admin users only. For existing dashboards, only updated when explicitly provided. | |
| BestPracticeKey | No | Read-receipt for the home-assistant-best-practices skill; required when strict best-practices mode is enabled. Not a secret or credential: the current value is an attestation phrase published openly at the top of the skill content served by ha_get_skill_guide. Read that content, then pass the value back verbatim โ this round-trip is the server's designed protocol confirming the practices were read before writing. | |
| show_in_sidebar | No | Show dashboard in sidebar navigation. For existing dashboards, only updated when explicitly provided. | |
| python_transform | No | Python expression to transform existing dashboard config. Mutually exclusive with config and patch. Requires config_hash for validation. See PYTHON TRANSFORM SECURITY below for allowed operations. Examples: Simple: python_transform="config['views'][0]['cards'][0]['icon'] = 'mdi:lamp'" Pattern: python_transform="for card in config['views'][0]['cards']: if 'light' in card.get('entity', ''): card['icon'] = 'mdi:lightbulb'" Multi-op: python_transform="config['views'][0]['cards'][0]['icon'] = 'mdi:lamp'; del config['views'][0]['cards'][2]" PYTHON TRANSFORM SECURITY: โ ALLOWED: - Dictionary/list access: config['views'][0]['cards'][1] - Slicing: config['views'][0]['cards'][1:3] - Assignment: config['key'] = 'value' - Deletion: del config['key'] or config.pop('key') - List methods: append, insert, pop, remove, clear, extend - Dict methods: update, get, setdefault, keys, values, items - Loops: for, if/else, pass, break, continue - Comprehensions: [x for x in ...], {k: v for ...}, (x for x in ...) - Ternary: x if condition else y - Iterable unpacking (* in calls/literals): f(*xs), [*xs, y] - Dict unpacking (**) in calls and dict literals: {**d, 'k': v} - Keyword arguments: func(key=value) - Lambdas (e.g. for `key=`): sorted(items, key=lambda x: x['score']) - String methods: startswith, endswith, lower, upper, strip, split, join, replace - Safe builtins: isinstance, len, range, enumerate, zip, sorted, reversed, min, max, sum, abs, any, all, round, str, int, float, bool, list, dict, tuple, set โ FORBIDDEN: - Imports: import, from, __import__ - File operations: open, read, write - Dunder access: __class__, __bases__, __subclasses__ - Dangerous builtins: eval, exec, compile, getattr, setattr, delattr, hasattr - Function definitions: def, class - Exception handling: try/except (validate with isinstance/in/.get() instead) - While loops: use bounded for loops or comprehensions instead ๐ฏ PATTERNS: - Filter cards: cards = [c for c in cards if keep(c)] - Skip in a loop: prefer `continue` over an empty `pass` branch (clearer) - Conditionally include: build a new list and `.append(x)` only the cards you want, instead of iterating the original and using if/pass branches to drop entries - Modify in place when possible (single pass, fewer surprises) over reconstructing the entire list | |
| return_screenshot | No | After writing, also return rendered image(s) of the dashboard so you can see what it looks like in a single call (the dashboard creation/iteration loop). Requires the 'dashboard screenshot' beta feature + engine add-on/sidecar; if unavailable, the write result is returned with a warning. For visual re-checks after the write (no config round-trip), use the dedicated ha_get_dashboard_screenshot tool instead. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only provide destructiveHint=true, so the description carries the burden of behavioral disclosure. It warns about index shifts after delete/add, requires fresh config_hash, explains that move/copy are unsupported in patch, states metadata updates cannot be combined with patch/python_transform, notes strategy dashboards cannot be converted, and details the storage-mode vs YAML-mode limitation. This far exceeds what annotations convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but well-organized with clear headers, code examples, and front-loaded critical requirements ('MUST call ha_get_skill_guide...'). Some content, such as the extensive Python security whitelist and modern dashboard best practices, could be trimmed or moved to the referenced skill guide, but the structure makes key information easy to locate.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a complex write tool with no output schema, this description is remarkably complete: it covers prerequisites, mode selection, patch syntax, python_transform security, metadata handling, entity ID discovery, screenshot behavior, and YAML-mode exclusions. An agent has all the context needed to invoke the tool correctly and avoid common pitfalls.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Despite 92% schema coverage, the description adds substantial parameter-level meaning: it gives worked examples for python_transform expressions, explains patch path syntax and escape rules, clarifies config_hash requirements per mode, documents metadata-only calls, and elaborates on the BestPracticeKey read-receipt protocol. This goes well beyond the baseline for high schema coverage.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Description opens with a clear, specific verb+resource statement: 'Create or update a Home Assistant dashboard.' It further distinguishes itself from related siblings by referencing ha_config_get_dashboard for reading config and ha_get_dashboard_screenshot for visual checks, and the detailed mode breakdown (patch/python_transform/config) makes the tool's scope unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly states when to use each mode under 'WHEN TO USE WHICH MODE' and gives alternative-tool guidance: use ha_config_get_dashboard to get fresh config_hash after index-shifting operations, use ha_get_dashboard_screenshot for visual re-checks instead of return_screenshot, and use ha_get_overview/ha_search for entity discovery. It also clearly excludes YAML-mode dashboards and routes to ha_config_set_yaml for registration edits.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_config_set_dashboard_resourceSet Dashboard ResourceADestructive
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)
url: External resource URL (/local/, /hacsfiles/, or https://...)
INLINE MODE (content=):
Custom card code written inline
CSS styling for dashboards
Self-contained files up to ~128KB
URLs are deterministic (same content = same URL)
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.)
Supports 'module' and 'css' types only (not 'js')
URL MODE (url=):
Files in /config/www/ directory (/local/...)
HACS-installed cards (/hacsfiles/...)
External CDN resources (https://...)
Supports all types: 'module', 'js', 'css'
RESOURCE TYPES:
module: ES6 JavaScript modules (recommended for custom cards)
js: Legacy JavaScript files (older custom cards, url mode only)
css: CSS stylesheets (themes, global styles)
EXAMPLES:
Inline custom card:
ha_config_set_dashboard_resource(
content="""
class MyCard extends HTMLElement {
setConfig(config) { this.config = config; }
set hass(hass) {
this.innerHTML = <ha-card>Hello ${hass.states[this.config.entity]?.state}</ha-card>;
}
}
customElements.define('my-card', MyCard);
""",
resource_type="module"
)
Add custom card from www/ directory: ha_config_set_dashboard_resource( url="/local/my-custom-card.js", resource_type="module" )
Add HACS card (after installing via ha_manage_hacs(action='download')): ha_config_set_dashboard_resource( url="/hacsfiles/lovelace-mushroom/mushroom.js", resource_type="module" )
Update existing resource: ha_config_set_dashboard_resource( url="/local/my-card-v2.js", resource_type="module", resource_id="abc123" )
Note: After adding a resource, clear browser cache or hard refresh (Ctrl+Shift+R) to load changes.
| Name | Required | Description | Default |
|---|---|---|---|
| url | No | URL of the resource. Can be: /local/file.js (www/ directory), /hacsfiles/component/file.js (HACS), https://cdn.example.com/card.js (external). Mutually exclusive with content. | |
| content | No | JavaScript or CSS code to host inline (max ~128KB). The code is embedded directly in the resource URL as a data: URI - no file storage or external hosting involved. Mutually exclusive with url. Supports 'module' and 'css' types only. | |
| resource_id | No | Resource ID to update. If omitted, creates a new resource. Get IDs from ha_config_list_dashboard_resources() | |
| resource_type | No | Resource type: 'module' for ES6 modules (modern cards, default), 'js' for legacy JavaScript (url mode only), 'css' for stylesheets | module |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description extensively discloses behaviors beyond destructiveHint: true, such as inline content being stored as data: URI, deterministic URLs, ~128KB limit, CSP blocking issues, and supported types per mode. No contradictions with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is verbose but well-structured with sections, bullet points, and examples. It front-loads the core purpose. Some redundancy exists (e.g., examples could be condensed), but every sentence adds meaningful information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity (4 parameters, output schema present), the description covers all aspects: purpose, modes, parameters, limitations, examples, and update mechanism. It is fully complete for an AI agent to use correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Although schema coverage is 100%, the description adds significant value by explaining mutual exclusivity of url and content, inline mode limitations (supports only 'module' and 'css'), and the source of resource_id (from list). Examples demonstrate parameter combinations.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states 'Create or update a dashboard resource (inline code or external URL).' It distinguishes two modes (inline vs URL) and specifies resource types, making the purpose specific and distinct from sibling tools like deletion or listing.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides clear when-to-use guidance by detailing inline vs URL modes, including prerequisites for URL mode (e.g., files in /config/www/ for /local/) and alternatives for CSP-blocked environments. It lacks explicit 'when not to use' but sufficiently implies context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_config_set_groupCreate or Update GroupADestructive
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.
EXAMPLES:
Create group: ha_config_set_group("bedroom_lights", entities=["light.lamp", "light.ceiling"])
Create with name: ha_config_set_group("sensors", entities=["sensor.temp"], name="All Sensors")
Update name: ha_config_set_group("lights", name="Living Room Lights")
Add entities: ha_config_set_group("lights", add_entities=["light.extra"])
Remove entities: ha_config_set_group("lights", remove_entities=["light.old"])
Replace all entities: ha_config_set_group("lights", entities=["light.new1", "light.new2"])
NOTE: entities, add_entities, and remove_entities are mutually exclusive.
| Name | Required | Description | Default |
|---|---|---|---|
| icon | No | Material Design Icon (e.g., 'mdi:lightbulb-group') | |
| name | No | Friendly display name for the group | |
| wait | No | Wait for group to be queryable before returning. Default: True. Set to False for bulk operations. | |
| all_on | No | If True, all entities must be on for group to be on (default: False) | |
| entities | No | List of entity IDs for the group. Required when creating new group. When updating, replaces all entities (mutually exclusive with add_entities/remove_entities). | |
| object_id | Yes | Group identifier without 'group.' prefix (e.g., 'living_room_lights') | |
| add_entities | No | Add these entities to an existing group (mutually exclusive with entities) | |
| remove_entities | No | Remove these entities from an existing group (mutually exclusive with entities) |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
While annotations provide destructiveHint: true, the description adds critical context: groups are only removable via ha_config_remove_group (not ha_remove_helpers_integrations) and notes mutex condition among entities, add_entities, remove_entities. No contradiction with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured with clear sections (When NOT to use, When to use, For NEW groups, For EXISTING groups, EXAMPLES, NOTE). It is front-loaded with essential information, no unnecessary words, and each sentence serves a purpose.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With 8 parameters and 1 required, the description covers all key use cases (create, update, add/remove entities) and addresses lifecycle considerations. It also notes the existence of an output schema (though not shown). The description is fully adequate for the tool's complexity.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3. The description adds value by clarifying that entities is required for new groups, explaining the mutex condition, and providing examples that demonstrate parameter usage. This surpasses the schema alone.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states 'Create or update a service-based Home Assistant entity group via the group.set service.' It uses specific verbs (create, update) and resource (group), and distinguishes itself from the sibling tool ha_config_set_helper for typical group creation.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly provides when NOT to use (prefer ha_config_set_helper) and when to use (compatibility with existing groups, entity-registry membership unwanted). It also gives clear examples for new and existing groups.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_config_set_helperCreate or Update HelperADestructive
Create or update Home Assistant helper entities and config subentries (30 types, unified interface).
MUST call ha_get_skill_guide OR refer to your locally installed skills first.
SIMPLE/FLOW helper create requires name; SIMPLE/FLOW helper update
requires helper_id. Config subentry create requires entry_id and
subentry_type; config subentry update also requires subentry_id.
SIMPLE types (structured params, WebSocket API): input_boolean, input_button, input_select, input_number, input_text, input_datetime, counter, timer, schedule, zone, person, tag.
FLOW types (pass config dict, Config Entry Flow API): 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.
Note: tod is the purpose-built "is-current-time-in-range" indicator
(supports cross-midnight ranges, unlike schedule).
Note: otp is a helper in the HA UI but is not offered here โ its flow
requires a live TOTP code. Create it with ha_set_integration(domain="otp"),
as with any other helper-domain flow outside this list.
CONFIG_SUBENTRY type (Config Subentry Flow API): config_subentry.
Pass entry_id, subentry_type, and config. Pass subentry_id to
reconfigure an existing subentry; omit it to create a new subentry.
For flow-type updates, pass the existing entry_id as helper_id. Options flows
reject the name key on update โ to rename a flow helper, delete and recreate.
Behavior notes:
UPDATE preserves type-specific fields not re-passed (rename never wipes initial/icon/etc. for any simple helper). Flow-helper and config subentry updates behave the same way: a field omitted from
configkeeps its current value, and a field set to null is cleared where the schema allows that field to be empty.Pass
action="create"oraction="update"to disambiguate intent. For SIMPLE/FLOW helpers, omitted action falls back to the implicithelper_id-presence discriminator. For config subentries, omitted action falls back to thesubentry_id-presence discriminator.For flow-based helpers, config keys not declared by any step's data_schema are silently ignored by HA; submit once and the validation error returns the
data_schemafor that helper so subsequent calls use the correct field names.Validation errors raised by this tool carry the helper's
data_schemain the response context (andmenu_optionsfor menu-rooted helpers liketemplate/groupwhen 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_idas a LIST of successive selections, consumed one per menu encounter.
EXAMPLES (menu-based types + tod, where first-call payload is non-obvious):
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 (light): ha_config_set_helper(helper_type="group", name="Kitchen Lights", config={"group_type": "light", "entities": ["light.a", "light.b"]})
tod (time-of-day indicator, cross-midnight OK): ha_config_set_helper(helper_type="tod", name="Quiet Hours", config={"after_time": "22:00:00", "before_time": "07:00:00"})
config subentry (create under an existing integration): ha_config_set_helper(helper_type="config_subentry", entry_id="01HXYZ...", subentry_type="conversation", config={"name": "Local agent", "model": "gemma3:27b"})
helper-selection.md ships in this response under
skill_content by default โ decision
matrix for picking the right helper type plus worked examples
and per-type field tables. For deeper helper-design guidance
beyond what ships here, call ha_get_skill_guide.
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
| Name | Required | Description | Default |
|---|---|---|---|
| icon | No | Material Design Icon (e.g., 'mdi:bell', 'mdi:toggle-switch') | |
| mode | No | Display mode: 'box'/'slider' for input_number, 'text'/'password' for input_text | |
| name | No | Display name for simple/flow helper creation. Required when creating a helper without helper_id. Optional on helper update. Ignored for helper_type='config_subentry', which uses entry_id/subentry_type/subentry_id instead. For flow-based helper updates (template, group, utility_meter, ...), this is typically ignored because options flows don't expose renaming. Rename a flow helper by deleting and recreating instead. | |
| step | No | Step/increment value for input_number or counter | |
| wait | No | Wait for helper entity to be queryable before returning. Default: True. Set to False for bulk operations. | |
| action | No | Explicit intent: 'create' a new helper or 'update' an existing one. When omitted, falls back to the implicit discriminator: presence of helper_id => update, absence => create. Pass 'create' or 'update' to disambiguate (e.g. so a typo in helper_id surfaces as a clear 'helper not found' error instead of being mistaken for a create call). | |
| config | No | Config dict for flow-based helper types and helper_type='config_subentry' (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). Ignored for simple helper types. On update it is a patch: a field you omit keeps its current value, and a field set to null is cleared where the schema allows that field to be empty. A field two steps declare gets your one value both times; pass step_values={'<step_id>': {'<field>': <value>}} to give a step its own value, or to leave it out of that step; a LIST of those objects supplies one per encounter when the flow presents a step more than once. Field set is delivered as data_schema on the first validation error. | |
| friday | No | Schedule time ranges for Friday. List of {'from': 'HH:MM', 'to': 'HH:MM'} dicts. Optional 'data' dict for additional attributes. | |
| labels | No | Labels to categorize the helper | |
| monday | No | Schedule time ranges for Monday. List of {'from': 'HH:MM', 'to': 'HH:MM'} dicts. Optional 'data' dict for additional attributes (e.g. {'from': '07:00', 'to': '22:00', 'data': {'mode': 'comfort'}}) | |
| radius | No | Radius in meters for zone (default: 100) | |
| sunday | No | Schedule time ranges for Sunday. List of {'from': 'HH:MM', 'to': 'HH:MM'} dicts. Optional 'data' dict for additional attributes. | |
| tag_id | No | Tag ID for tag. On create, omit to auto-generate a unique uuid4 hex (HA's tag/create requires this field; the tool fills it in for you). On update, the tag's existing tag_id is required (passed via helper_id). | |
| area_id | No | Area/room ID to assign the helper to | |
| initial | No | Initial value for applicable helper types. For input_boolean, input_select, input_number, input_text, and input_datetime: setting `initial` โ even to false/0 โ disables last-state restore and forces that value on every HA restart; omit unless you want the helper to reset to that value on every restart instead of restoring its last state. For counter, `initial` is just the starting value โ restore-on-restart is controlled separately by `restore` (default True). | |
| options | No | List of options for input_select (required for input_select) | |
| passive | No | Passive zone (won't trigger state changes for person entities) | |
| picture | No | Picture URL for person entity | |
| restore | No | Restore state after restart (counter, timer). Defaults to True for counter, False for timer | |
| tuesday | No | Schedule time ranges for Tuesday. List of {'from': 'HH:MM', 'to': 'HH:MM'} dicts. Optional 'data' dict for additional attributes. | |
| user_id | No | User ID to link to person entity | |
| category | No | Category ID to assign to this helper. Use ha_config_get_category(scope='helpers') to list available categories, or ha_config_set_category() to create one. | |
| duration | No | Default duration for timer in format 'HH:MM:SS' or seconds (e.g., '0:05:00' for 5 minutes) | |
| entry_id | No | Parent config entry ID when helper_type='config_subentry'. Use ha_get_integration() to find entry IDs. | |
| has_date | No | Include date component for input_datetime | |
| has_time | No | Include time component for input_datetime | |
| latitude | No | Latitude for zone (required for zone) | |
| saturday | No | Schedule time ranges for Saturday. List of {'from': 'HH:MM', 'to': 'HH:MM'} dicts. Optional 'data' dict for additional attributes. | |
| thursday | No | Schedule time ranges for Thursday. List of {'from': 'HH:MM', 'to': 'HH:MM'} dicts. Optional 'data' dict for additional attributes. | |
| helper_id | No | REQUIRED when updating an existing helper. Bare ID ('my_button') or full entity ID ('input_button.my_button'). Omit to create a new helper. | |
| longitude | No | Longitude for zone (required for zone) | |
| max_value | No | Maximum value (input_number/counter) or maximum length (input_text). Also accepts shorthand 'max'. | |
| min_value | No | Minimum value (input_number/counter) or minimum length (input_text). Also accepts shorthand 'min'. | |
| wednesday | No | Schedule time ranges for Wednesday. List of {'from': 'HH:MM', 'to': 'HH:MM'} dicts. Optional 'data' dict for additional attributes. | |
| description | No | Description for tag | |
| helper_type | Yes | Type of helper entity to create or update | |
| subentry_id | No | Existing config subentry ID to reconfigure when helper_type='config_subentry'. Omit to create. | |
| MandatoryBPS | No | ||
| subentry_type | No | Integration-defined subentry type when helper_type='config_subentry'. | |
| BestPracticeKey | No | Read-receipt for the home-assistant-best-practices skill; required when strict best-practices mode is enabled. Not a secret or credential: the current value is an attestation phrase published openly at the top of the skill content served by ha_get_skill_guide. Read that content, then pass the value back verbatim โ this round-trip is the server's designed protocol confirming the practices were read before writing. | |
| device_trackers | No | List of device_tracker entity IDs for person | |
| unit_of_measurement | No | Unit of measurement for input_number (e.g., 'ยฐC', '%', 'W'). Also accepts shorthand 'unit'. | |
| show_advanced_options | No | When helper_type='config_subentry', ask older Home Assistant versions to expose advanced flow options. No-op on HA 2026.6+; pending removal before HA 2027.6. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the destructiveHint=true annotation, the description discloses rich behavioral traits: update patch semantics (omitted fields keep current value, null clears), silent ignoring of undeclared config keys (with the submit-once-then-read-data_schema recovery protocol), the rename trap ('Options flows reject the name key on update โ to rename a flow helper, delete and recreate'), and the multi-menu `next_step_id`-as-list behavior. It also explains that validation errors carry data_schema and menu_options in the response context for self-correction. No contradiction with the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Long (~550 words) but structurally justified for a 30-type, 43-parameter tool. It is front-loaded: purpose, prerequisite, type taxonomy, required-parameter patterns, then behavior notes, then examples. The main blemish is minor redundancy โ update-preservation semantics and the rename-delete-recreate rule appear in both the description and the schema's `config`/`name` descriptions, and the MUST-call instruction is stated twice.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For the most complex tool in its family, the description covers everything needed for a correct first call: required arguments per operation type (name vs helper_id vs entry_id/subentry_type/subentry_id), update semantics, silent-failure handling, error self-correction protocol, routing to alternatives, and worked examples for the non-obvious first-call payloads (template, group, tod, config subentry). With an output schema present and annotations covering safety, nothing essential is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 98% and the schema itself is exemplary (e.g., `initial` restore-disable semantics, `tag_id` auto-generation, `config` patch rules, `name` flow-update note). The description adds the cross-cutting semantics the schema cannot express: the SIMPLE/FLOW/CONFIG_SUBENTRY taxonomy that maps which parameters apply to which type, entry_id doubling as helper_id for flow updates, and the action-fallback discriminator. This is meaningful added value, though individual parameter meaning was already well covered.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening sentence 'Create or update Home Assistant helper entities and config subentries (30 types, unified interface)' states a specific verb pair, a concrete resource, and the scope in one line. It also distinguishes itself from siblings by explicitly routing the excluded `otp` case to ha_set_integration and clarifying that this is the create/update counterpart to list/remove tools like ha_config_list_helpers and ha_remove_helpers_integrations.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description states a hard prerequisite ('MUST call ha_get_skill_guide OR refer to your locally installed skills first'), names the one alternative for an excluded case (ha_set_integration(domain='otp')), and points to the helper-selection.md decision matrix shipped in skill_content. It also gives precise when-to guidance for the `action` parameter, explaining the implicit helper_id/subentry_id presence discriminators and when to disambiguate explicitly.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_config_set_labelCreate or Update LabelADestructive
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 flexible tagging system that can be applied to entities, devices, and areas for organization and automation purposes.
EXAMPLES:
Create simple label: ha_config_set_label("Critical")
Create colored label: ha_config_set_label("Outdoor", color="green")
Create label with icon: ha_config_set_label("Battery Powered", icon="mdi:battery")
Create full label: ha_config_set_label("Security", color="red", icon="mdi:shield", description="Security-related devices")
Update label: ha_config_set_label("Updated Name", label_id="my_label_id", color="blue")
After creating a label, use ha_set_entity(labels=["label_id"]) to assign it to entities.
| Name | Required | Description | Default |
|---|---|---|---|
| icon | No | Material Design Icon (e.g., 'mdi:tag', 'mdi:label') | |
| name | Yes | Display name for the label | |
| color | No | Color for the label (e.g., 'red', 'blue', 'green', or hex like '#FF5733') | |
| label_id | No | Label ID for updates. If not provided, creates a new label. | |
| description | No | Description of the label's purpose |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description discloses that the tool modifies state (create/update), consistent with destructiveHint annotation. It adds context about the purpose of labels and how assignments work, going beyond the annotation's simple destructive flag.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise, front-loading the core action, followed by a brief explanation and well-structured examples. Every sentence is useful with no redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the schema coverage, annotations, and presence of an output schema, the description is complete. It explains the create/update behavior, provides examples for all parameters, and links to a related tool for assignment.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema covers all 5 parameters with descriptions (100% coverage). The tool description adds value through concrete examples showing how to use parameters like color, icon, and description in context, which aids understanding beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool creates or updates a Home Assistant label, with explicit differentiation between create (no label_id) and update (with label_id). It distinguishes from siblings like ha_config_get_label and ha_config_remove_label.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explains when to use create vs update based on label_id presence, and provides examples for various use cases. It also advises on subsequent steps (use ha_set_entity to assign). While it doesn't explicitly state when not to use it, sibling tools cover other operations.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_config_set_sceneCreate or Update SceneADestructive
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.
WHEN TO USE:
python_transform: surgical edits to an existing scene (add/remove/update a single entity entry). Requiresconfig_hashfrom ha_config_get_scene() for optimistic locking.config: creating a new scene, or wholesale replacement.
WHEN NOT TO USE:
To activate a scene at runtime, use ha_call_service(domain="scene", service="turn_on", target=...) โ this tool only manages scene configuration, not the runtime turn-on/off side.
To list or look up existing scenes, use ha_search(domain_filter="scene").
SCENE SHAPE: entities is a dict keyed by entity_id (e.g.,
{'light.kitchen': {'state': 'on', 'brightness': 200}}), NOT a
list. 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.
| Name | Required | Description | Default |
|---|---|---|---|
| wait | No | Wait for scene to be queryable before returning. Default: True. Set to False for bulk operations. | |
| config | No | Scene configuration dictionary. Must include 'entities' (a dict keyed by entity_id, NOT a list). Optional fields: 'name' (defaults to scene_id), 'icon', 'id'. Mutually exclusive with python_transform. | |
| category | No | Category ID to assign to this scene. Use ha_config_get_category(scope='scene') to list available categories, or ha_config_set_category() to create one. | |
| scene_id | Yes | Scene identifier (e.g., 'movie_night') | |
| config_hash | No | Config hash from ha_config_get_scene for optimistic locking. REQUIRED for python_transform (validates scene unchanged). Optional for config updates (validates before full replacement if provided). | |
| MandatoryBPS | No | ||
| BestPracticeKey | No | Read-receipt for the home-assistant-best-practices skill; required when strict best-practices mode is enabled. Not a secret or credential: the current value is an attestation phrase published openly at the top of the skill content served by ha_get_skill_guide. Read that content, then pass the value back verbatim โ this round-trip is the server's designed protocol confirming the practices were read before writing. | |
| python_transform | No | Python expression to transform existing scene config. Mutually exclusive with config. Requires config_hash for validation. WARNING: Expressions with infinite loops will hang the server. Examples: Add entity: python_transform="config['entities']['light.bed'] = {'state': 'on'}" Update brightness: python_transform="config['entities']['light.kitchen']['brightness'] = 50" Remove entity: python_transform="del config['entities']['light.kitchen']" PYTHON TRANSFORM SECURITY: โ ALLOWED: - Dictionary/list access: config['views'][0]['cards'][1] - Slicing: config['views'][0]['cards'][1:3] - Assignment: config['key'] = 'value' - Deletion: del config['key'] or config.pop('key') - List methods: append, insert, pop, remove, clear, extend - Dict methods: update, get, setdefault, keys, values, items - Loops: for, if/else, pass, break, continue - Comprehensions: [x for x in ...], {k: v for ...}, (x for x in ...) - Ternary: x if condition else y - Iterable unpacking (* in calls/literals): f(*xs), [*xs, y] - Dict unpacking (**) in calls and dict literals: {**d, 'k': v} - Keyword arguments: func(key=value) - Lambdas (e.g. for `key=`): sorted(items, key=lambda x: x['score']) - String methods: startswith, endswith, lower, upper, strip, split, join, replace - Safe builtins: isinstance, len, range, enumerate, zip, sorted, reversed, min, max, sum, abs, any, all, round, str, int, float, bool, list, dict, tuple, set โ FORBIDDEN: - Imports: import, from, __import__ - File operations: open, read, write - Dunder access: __class__, __bases__, __subclasses__ - Dangerous builtins: eval, exec, compile, getattr, setattr, delattr, hasattr - Function definitions: def, class - Exception handling: try/except (validate with isinstance/in/.get() instead) - While loops: use bounded for loops or comprehensions instead ๐ฏ PATTERNS: - Filter cards: cards = [c for c in cards if keep(c)] - Skip in a loop: prefer `continue` over an empty `pass` branch (clearer) - Conditionally include: build a new list and `.append(x)` only the cards you want, instead of iterating the original and using if/pass branches to drop entries - Modify in place when possible (single pass, fewer surprises) over reconstructing the entire list |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Discloses destructive nature (destructiveHint true) and adds extensive behavior: optimistic locking, mutual exclusivity of parameters, infinite loop risk in python_transform, and a complete list of allowed/forbidden Python operations. No contradiction with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Well-structured with clear sections, front-loaded with purpose and mode overview. The python_transform security section, while lengthy, is justified by the need for safe execution. Could trim slightly but maintains clarity.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Handles tool complexity comprehensively: covers two modes, prerequisites, security, alternatives, and required preparatory steps (skill guide). With output schema present, return value documentation is unnecessary. No gaps remain.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Adds significant meaning beyond schema (88% coverage): explains config shape (entities as dict, not list), provides python_transform examples and security rules, clarifies config_hash role, and describes BestPracticeKey protocol. Adds example and context for each key parameter.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Clearly states 'Create or update a Home Assistant scene', distinguishing from sibling tools like ha_call_service for runtime activation and ha_search for listing. Explicitly contrasts with ha_config_get_scene and ha_config_remove_scene by defining its role.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit WHEN TO USE and WHEN NOT TO USE sections, detailing two modes (python_transform vs config) with specific prerequisites (config_hash), and names alternative tools (ha_call_service, ha_search) and prerequisite calls (ha_get_skill_guide).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_config_set_scriptCreate or Update ScriptADestructive
Create or update a Home Assistant script.
MUST call ha_get_skill_guide OR refer to your locally installed skills first.
PREFER NATIVE ACTIONS OVER TEMPLATES (read this before writing any {{ ... }}):
Native actions are validated at config load, fail loudly, and do not bypass HA's
schema. Templates in logic positions fail silently and obscure intent.
choose/if/then/elseinstead of template-based service nameswait_for_triggerinstead ofwait_templateNative
for:field onstateconditions insidechoose/if, and onstate/numeric_statetriggers inwait_for_trigger, instead of{{ now() - X.last_changed > timedelta(...) }}duration math.repeatwithfor_eachinstead of template loopsHardcode
target.entity_idliterals โ never{{ this.entity_id }}. Templates are appropriate ONLY indata.*fields, notification message/title,event_data, andvariables. The reactive best-practice checker on this tool will surface anything in a logic position that should be native; consult thebest_practice_warningsfield on the response and fix before re-submitting. The relevant skill section is auto-embedded underskill_contenton warnings, and the fullautomation-patterns.md+template-guidelines.mdreferences ship underskill_contentproactively by default. For comprehensive guidance beyond that, callha_get_skill_guide.
Supports three modes: full config replacement, Python transformation, or take_control_of_blueprint (see below).
WHEN TO USE WHICH MODE:
python_transform: RECOMMENDED for edits to existing scripts. Surgical updates.
config: Use for creating new scripts or full restructures.
take_control_of_blueprint: converts a blueprint-backed script into a standalone one. Takes no config of its own.
IMPORTANT: python_transform requires 'config_hash' from ha_config_get_script().
PYTHON TRANSFORM EXAMPLES:
Update step: python_transform="config['sequence'][0]['data']['message'] = 'Hello'"
Add step: python_transform="config['sequence'].append({'delay': {'seconds': 5}})"
Remove last step: python_transform="config['sequence'].pop()"
Creates a new script or updates an existing one with the provided configuration. Supports both regular scripts (with sequence) and blueprint-based scripts.
Required config fields (choose one): - sequence: List of actions to execute (for regular scripts) - use_blueprint: Blueprint configuration (for blueprint-based scripts)
Optional config fields: - alias: Display name (defaults to script_id) - description: Script description - icon: Icon to display - mode: Execution mode ('single', 'restart', 'queued', 'parallel') - max: Maximum concurrent executions (for queued/parallel modes) - fields: Input parameters for the script
SCRIPTS vs AUTOMATIONS: Scripts use 'sequence', NOT 'trigger' or 'action'. If you need trigger-based execution, use ha_config_set_automation instead.
EXAMPLES:
Create basic delay script: ha_config_set_script(script_id="wait_script", config={ "sequence": [{"delay": {"seconds": 5}}], "alias": "Wait 5 Seconds", "description": "Simple delay script" })
Create service call script: ha_config_set_script(script_id="blink_light", config={ "sequence": [ {"action": "light.turn_on", "target": {"entity_id": "light.living_room"}}, {"delay": {"seconds": 2}}, {"action": "light.turn_off", "target": {"entity_id": "light.living_room"}} ], "alias": "Light Blink", "mode": "single" })
Create script with parameters: ha_config_set_script(script_id="backup_script", config={ "alias": "Backup with Reference", "description": "Create backup with optional reference parameter", "fields": { "reference": { "name": "Reference", "description": "Optional reference for backup identification", "selector": {"text": None} } }, "sequence": [ { "action": "hassio.backup_partial", "data": { "compressed": False, "homeassistant": True, "homeassistant_exclude_database": True, "name": "Backup_{{ reference | default('auto') }}{{ now().strftime('%Y%m%d%H%M%S') }}" } } ] })
Update script: ha_config_set_script(script_id="morning_routine", config={ "sequence": [ {"action": "light.turn_on", "target": {"area_id": "bedroom"}}, {"action": "climate.set_temperature", "target": {"entity_id": "climate.bedroom"}, "data": {"temperature": 22}} ], "alias": "Updated Morning Routine" })
Create blueprint-based script: ha_config_set_script(script_id="notification_script", config={ "alias": "My Notification Script", "use_blueprint": { "path": "notification_script.yaml", "input": { "message": "Hello World", "title": "Test Notification" } } })
Update blueprint script inputs: ha_config_set_script(script_id="notification_script", config={ "alias": "My Notification Script", "use_blueprint": { "path": "notification_script.yaml", "input": { "message": "Updated message", "title": "Updated Title" } } })
TAKE CONTROL OF A BLUEPRINT SCRIPT:
take_control_of_blueprint=True converts a blueprint-backed script into a standalone one โ the UI's "Take control". The blueprint is rendered with the script's CURRENT inputs and the result is saved over the same script, which keeps its script_id, alias and description but gains its own sequence and loses 'use_blueprint'.
ha_config_set_script( script_id="notification_script", take_control_of_blueprint=True, )
This is one-way: the script is no longer linked to the blueprint, so later blueprint edits stop reaching it. To change an input value, update 'use_blueprint.input' instead (see the example above) โ that keeps the link. Taking control does NOT free the blueprint: Home Assistant goes on counting a converted script as a user of it, so deleting that blueprint stays refused until the script itself is removed. To see the rendering WITHOUT writing anything, call ha_manage_blueprints(action="substitute", domain="script", path=..., input=...). ha_manage_blueprints also lists, imports, saves and deletes blueprints, and action="get" reports which scripts use one.
Note: Scripts use Home Assistant's action syntax. Check the documentation for advanced features like conditions, variables, parallel execution, and service call options.
create update modify edit script sequence actions new script write save take control blueprint detach unlink standalone convert
| Name | Required | Description | Default |
|---|---|---|---|
| wait | No | Wait for script to be queryable before returning. Default: True. Set to False for bulk operations. | |
| config | No | Script configuration dictionary. Must include EITHER 'sequence' (for regular scripts) OR 'use_blueprint' (for blueprint-based scripts). Optional fields: 'alias', 'description', 'icon', 'mode', 'max', 'fields'. Mutually exclusive with python_transform. | |
| category | No | Category ID to assign to this script. Use ha_config_get_category(scope='script') to list available categories, or ha_config_set_category() to create one. | |
| script_id | Yes | Script identifier โ bare storage key ('morning_routine') or entity_id form ('script.morning_routine'); a leading 'script.' prefix is stripped before lookup. | |
| config_hash | No | Config hash from ha_config_get_script for optimistic locking. REQUIRED for python_transform (validates script unchanged). Optional for config updates (validates before full replacement if provided). | |
| MandatoryBPS | No | ||
| BestPracticeKey | No | Read-receipt for the home-assistant-best-practices skill; required when strict best-practices mode is enabled. Not a secret or credential: the current value is an attestation phrase published openly at the top of the skill content served by ha_get_skill_guide. Read that content, then pass the value back verbatim โ this round-trip is the server's designed protocol confirming the practices were read before writing. | |
| python_transform | No | Python expression to transform existing script config. Mutually exclusive with config. Requires config_hash for validation. WARNING: Expressions with infinite loops will hang the server. Examples: Simple: python_transform="config['sequence'][0]['data']['message'] = 'Hello'" Pattern: python_transform="for step in config['sequence']: if step.get('alias') == 'My Step': step['data']['value'] = 100" PYTHON TRANSFORM SECURITY: โ ALLOWED: - Dictionary/list access: config['views'][0]['cards'][1] - Slicing: config['views'][0]['cards'][1:3] - Assignment: config['key'] = 'value' - Deletion: del config['key'] or config.pop('key') - List methods: append, insert, pop, remove, clear, extend - Dict methods: update, get, setdefault, keys, values, items - Loops: for, if/else, pass, break, continue - Comprehensions: [x for x in ...], {k: v for ...}, (x for x in ...) - Ternary: x if condition else y - Iterable unpacking (* in calls/literals): f(*xs), [*xs, y] - Dict unpacking (**) in calls and dict literals: {**d, 'k': v} - Keyword arguments: func(key=value) - Lambdas (e.g. for `key=`): sorted(items, key=lambda x: x['score']) - String methods: startswith, endswith, lower, upper, strip, split, join, replace - Safe builtins: isinstance, len, range, enumerate, zip, sorted, reversed, min, max, sum, abs, any, all, round, str, int, float, bool, list, dict, tuple, set โ FORBIDDEN: - Imports: import, from, __import__ - File operations: open, read, write - Dunder access: __class__, __bases__, __subclasses__ - Dangerous builtins: eval, exec, compile, getattr, setattr, delattr, hasattr - Function definitions: def, class - Exception handling: try/except (validate with isinstance/in/.get() instead) - While loops: use bounded for loops or comprehensions instead ๐ฏ PATTERNS: - Filter cards: cards = [c for c in cards if keep(c)] - Skip in a loop: prefer `continue` over an empty `pass` branch (clearer) - Conditionally include: build a new list and `.append(x)` only the cards you want, instead of iterating the original and using if/pass branches to drop entries - Modify in place when possible (single pass, fewer surprises) over reconstructing the entire list | |
| take_control_of_blueprint | No | Convert a blueprint-backed script into an editable standalone one -- the UI's "Take control". Renders the blueprint with its current inputs and saves the result over the same script, which then has its own sequence and no 'use_blueprint'. Mutually exclusive with config and python_transform. Irreversible: the link to the blueprint is gone afterwards, so edit inputs instead if you only want to change a value. 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"). |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With annotations only providing destructiveHint:true and openWorldHint:false, the description carries full behavioral disclosure. It warns of infinite loops in python_transform, details the irreversible nature of take_control_of_blueprint, explains that it does not free the blueprint, and describes the best-practice checker and skill_content embedding. It also clarifies side effects like remaining counted as a blueprint user, far exceeding annotation coverage.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but well-structured with clear section headers (MUST call, PREFER NATIVE ACTIONS, WHEN TO USE WHICH MODE, PYTHON TRANSFORM EXAMPLES, SCRIPTS vs AUTOMATIONS, EXAMPLES, TAKE CONTROL). It front-loads the critical prerequisite and preference. Some redundancy exists (e.g., a repeated sentence about creating/updating near the end) and the note about checking documentation is generic, but the overall organization earns its length given tool complexity.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description covers all critical aspects for correct invocation: mode selection, prerequisites (config_hash), side effects (irreversibility, blueprint usage), interplay with related tools (ha_get_skill_guide, ha_manage_blueprints), and the distinction from automations. With an output schema present, return-value explanation is not required. Nothing an agent needs to call this tool correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Although schema coverage is high (89%), the description adds substantial meaning beyond the field definitions. It expands on config structure with examples, explains mutual exclusivity between config/python_transform/take_control_of_blueprint, clarifies config_hash's role in optimistic locking, and gives concrete usage examples for each parameter. This enriches the schema without redundancy.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb-resource combination ('Create or update a Home Assistant script') and clearly differentiates from the sibling tool ha_config_set_automation, noting scripts use 'sequence' not 'trigger'. It also enumerates three operation modes (config, python_transform, take_control_of_blueprint), giving the agent an unambiguous picture of scope.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives explicit when-to-use advice for each mode (python_transform for edits, config for new/full restructures, take_control_of_blueprint for converting), requires a prior call to ha_get_skill_guide or local skills, and names the alternative for trigger-based execution (ha_config_set_automation). It also states that python_transform requires config_hash from ha_config_get_script. This leaves no ambiguity about selection criteria.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_eval_templateEvaluate TemplateARead-onlyIdempotent
Evaluate Jinja2 templates using Home Assistant's template engine.
This tool allows testing and debugging of Jinja2 template expressions that are commonly used in Home Assistant automations, scripts, and configurations. It provides real-time evaluation with access to all Home Assistant states, functions, and template variables.
When NOT to use this for automation/script logic:
Templates have legitimate uses (notification bodies, dynamic data.* values,
debugging existing templates), but condition: / trigger: positions and
action service names are better expressed as native HA constructs:
native constructs are schema-validated at config load and surface
structural errors loudly, whereas equivalent template logic only errors
at runtime โ and a template that renders a non-truthy value is silently
treated as false.
Prefer:
condition: numeric_stateover{{ states('x') | float > N }}condition: stateover{{ is_state(...) }}condition: time/condition: sunovernow().hour/is_state('sun.sun', ...)Native
for:field on state/numeric_state triggers and state conditions over{{ now() - X.last_changed > timedelta(...) }}duration mathchooseaction over templatedservice:/action:strings Seeha_get_skill_guide(best-practices skill) for the full anti-pattern list.
When to use (reach for this tool, don't compute it yourself):
Any one-shot question whose answer is DERIVED from current HA state โ an
average/sum/min/max across sensors, a count of entities matching a
condition, a boolean comparison, or a rendered message with live values.
One render call beats fetching N states and doing the math yourself, and
it is the canonical way to test a template before embedding it. This is
for one-shot answers and template testing only โ NOT for putting templates
into automation logic; for condition: / trigger: positions native
constructs win.
"average temperature across the bedroom sensors" ->
{{ ([states('sensor.a'), states('sensor.b')] | map('float', 0) | sum) / 2 }}"how many lights are on" ->
{{ states.light | selectattr('state', 'eq', 'on') | list | count }}NOT for a plain single-entity value ("what's the state of X") โ that isha_get_state/ha_search; rendering{{ states('X') }}there is over-use.
Parameters:
template: The Jinja2 template string to evaluate
timeout: Maximum evaluation time in seconds (default: 3)
report_errors: Whether to return detailed error information (default: True)
Common Template Functions:
State Access:
{{ states('sensor.temperature') }} # Get entity state value
{{ states.sensor.temperature.state }} # Alternative syntax
{{ state_attr('light.bedroom', 'brightness') }} # Get entity attribute
{{ is_state('light.living_room', 'on') }} # Check if entity has specific stateNumeric Operations:
{{ states('sensor.temperature') | float(0) }} # Convert to float with default
{{ states('sensor.humidity') | int(0) }} # Convert to integer with default
{{ (states('sensor.temp') | float(0) + 5) | round(1) }} # Math operationsTime and Date:
{{ now() }} # Current datetime
{{ now().strftime('%H:%M:%S') }} # Format current time
{{ as_timestamp(now()) }} # Convert to Unix timestamp
{{ now().hour }} # Current hour (0-23)
{{ now().weekday() }} # Day of week (0=Monday)Conditional Logic (for display strings โ not for condition: positions):
{{ 'Day' if now().hour < 18 else 'Night' }} # Ternary operator
{% if is_state('alarm_control_panel.home', 'armed_away') %}
Alarm is armed
{% else %}
Alarm is disarmed
{% endif %}Lists and Loops:
{% for entity in states.light %}
{{ entity.entity_id }}: {{ entity.state }}
{% endfor %}
{{ states.light | selectattr('state', 'eq', 'on') | list | count }} # Count on lightsString Operations:
{{ states('sensor.weather') | title }} # Title case
{{ 'Hello ' + states('input_text.name') }} # String concatenation
{{ states('sensor.data') | regex_replace('pattern', 'replacement') }}Device and Area Functions:
{{ device_entities('device_id_here') }} # Get entities for device
{{ area_entities('living_room') }} # Get entities in area
{{ device_id('light.bedroom') }} # Get device ID for entityCommon Use Cases (legitimate template positions):
Dynamic Service Data:
# Dynamic brightness based on time
{{ 255 if now().hour < 22 else 50 }}
# Message with current values
"Temperature is {{ states('sensor.temp') }}ยฐC, humidity {{ states('sensor.humidity') }}%"Examples:
Test basic state access:
ha_eval_template("{{ states('light.living_room') }}")Test a string expression (e.g. for a notification body):
ha_eval_template("{{ 'Day' if now().hour < 18 else 'Night' }}")Test mathematical operations:
ha_eval_template("{{ (states('sensor.temperature') | float(0) + 5) | round(1) }}")Test entity counting:
ha_eval_template("{{ states.light | selectattr('state', 'eq', 'on') | list | count }}")IMPORTANT NOTES:
Templates have access to all current Home Assistant states and attributes
Use this tool to test templates before using them in automations or scripts
Template evaluation respects Home Assistant's security model and timeouts
Complex templates may affect Home Assistant performance - keep them efficient
Use default values (e.g.,
| float(0)) to handle missing or invalid states
For template documentation: https://www.home-assistant.io/docs/configuration/templating/
| Name | Required | Description | Default |
|---|---|---|---|
| timeout | No | ||
| template | Yes | ||
| report_errors | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already provide readOnlyHint, idempotentHint, openWorldHint. Description adds context about access to all HA states, security model, timeouts, and performance impact. No contradiction with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Well-structured with sections and examples, but overly verbose with a large catalog of common template functions. Could be more concise while retaining essential information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers purpose, usage guidelines, parameter details, common functions, examples, and important notes. Output schema exists, so return values need not be described. Complete for the tool's complexity.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, but the description compensates with a 'Parameters:' section giving clear one-line explanations for each parameter (template, timeout, report_errors). Adds meaning beyond the bare schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Clearly states 'Evaluate Jinja2 templates using Home Assistant's template engine', with specific verb and resource. Distinguishes from sibling tools like ha_get_state and ha_search by explicitly stating when not to use for plain state queries and providing alternatives.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit when-to-use (one-shot derived answers, template testing) and when-not-to-use (automation/script logic) guidance, with specific alternatives for native constructs. Includes examples and references to ha_get_skill_guide for best practices.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_get_appGet Apps (add-ons)ARead-onlyIdempotent
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. include_stats applies only
to installed-app listings.
| Name | Required | Description | Default |
|---|---|---|---|
| slug | No | App (add-on) slug for detailed info (e.g., '<prefix>_nodered'). Slug prefixes vary by app repository โ omit to list all apps and discover the actual installed slug. | |
| query | No | App (add-on) name/description filter (only for source='available') | |
| source | No | App (add-on) source: 'installed' (default) for currently installed apps, 'available' for apps in the store that can be installed. With source='available', 'version' is the version you would get by installing (Supervisor's version_latest) and 'version_installed' is the running one, null when the app is not installed โ so compare the two, not 'version' alone, to tell whether an installed app is current. | |
| repository | No | Filter by repository slug, e.g., 'core', 'community' (only for source='available') | |
| include_stats | No | Include CPU/memory usage statistics (only for source='installed') |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, openWorldHint, and idempotentHint, covering the safety profile. The description adds useful context beyond annotations: the Home Assistant OS or Supervised platform requirement and that include_stats only applies to installed-app listings. No contradiction with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact, front-loaded with the core purpose, and every sentence earns its place by either defining scope, excluding misuse, or giving usage direction. No filler or redundant restatement of the title.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a read-only, idempotent tool with a rich input schema and an output schema, the description covers the platform prerequisite, the three usage modes, the exclusion of mutation, and the parameter-specific scoping. Nothing an agent needs to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and each parameter already has a detailed description, so the schema carries the parameter-documentation burden. The description adds some high-level routing advice (slug for details, source variants), but it largely mirrors what the schema already explains.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb ('Get') and resource ('installed or available Home Assistant apps (add-ons), or details for one'). It explicitly differentiates itself from ha_manage_app, so an agent can distinguish this read-oriented tool from its mutation sibling.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly says not to use this tool for changing app state/config and directs to ha_manage_app instead. It also gives clear selection guidance: use slug for details, source='installed' for an inventory, and source='available' for store discovery.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_get_automation_tracesGet Automation TracesARead-onlyIdempotent
Retrieve execution traces for automations and scripts to debug issues.
Traces show what happened during automation/script runs:
What triggered the automation
Which conditions passed or failed
What actions were executed
Any errors that occurred
Variable values during execution
USAGE MODES:
List recent traces (omit run_id): ha_get_automation_traces("automation.motion_light") Returns a summary of recent execution runs with timestamps, triggers, and status. Use
offsetto page deeper whenhas_moreis true, ororder="oldest"to start from the earliest stored trace instead of the most recent.Get detailed trace (provide run_id): ha_get_automation_traces("automation.motion_light", run_id="1705312800.123456") Returns full execution details including trigger info, condition results, action trace with timing, and context variables.
Get detailed trace with logbook (provide run_id and detailed=True): ha_get_automation_traces("automation.motion_light", run_id="1705312800.123456", detailed=True) Returns the formatted trace plus logbook entries and context metadata. Useful when the standard trace summary doesn't reveal enough for debugging. Note: script-style action paths (sequence/, numeric) are always matched regardless of this flag.
Get full variables without deduplication (provide run_id and deduplicate=False): ha_get_automation_traces("automation.motion_light", run_id="1705312800.123456", deduplicate=False) Returns the formatted trace with full variables at every action step.
DEBUGGING EXAMPLES:
Automation not triggering:
Check if traces exist (automation may not be triggered)
Look at trigger info to see what event was received
Automation runs but conditions fail:
Get detailed trace to see condition_results
Each condition shows whether it passed (true) or failed (false)
Unexpected behavior in actions:
Get detailed trace to see action_trace
Shows each action step with result and any errors
For 'choose' actions, shows which branch was taken
Template debugging:
Detailed trace shows evaluated template values in context
Trigger variables available under trigger_variables
NOTES:
Traces are stored for a limited time by Home Assistant
Works for both automations and scripts (use full entity_id)
The 'state' field shows: 'stopped' (completed), 'running', or error state
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum number of traces to return when listing (default: 10, max: 50). | |
| order | No | Order traces are returned in. 'newest' (default) returns most-recent first; 'oldest' returns chronological-first. | newest |
| offset | No | Number of traces to skip from the start of the requested order. Use with `limit` to page through stored traces when `total_available > limit`. | |
| run_id | No | Specific trace run_id to retrieve detailed trace. Omit to list recent traces. | |
| detailed | No | Include extra diagnostic data: logbook entries and context metadata (default: False). Use when standard trace lacks detail for debugging. | |
| sections | No | Comma-separated list of trace sections to return. Valid values: trigger, conditions, actions, config, error, logbook, context. Omit to return all sections. Example: 'actions' or 'trigger,conditions'. | |
| deduplicate | No | Deduplicate variables across action steps (default: True). Set to False to include full variables at every step. | |
| automation_id | Yes | Automation or script entity_id (e.g., 'automation.motion_light' or 'script.morning_routine') |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description goes far beyond annotations (readOnlyHint, idempotentHint) by explaining trace storage limits, behavior of pagination, effect of parameters like detailed and deduplicate, and expected state field values. This fully discloses behavioral traits.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-organized with clear headings (USAGE MODES, DEBUGGING EXAMPLES, NOTES), front-loaded purpose, and no redundant text. Every sentence adds value, making it easy to scan and understand quickly.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity (8 parameters, automation debugging), the description covers all usage modes, parameter behavior, debugging scenarios, and limitations. An output schema exists, so return values are handled; the description is fully self-contained.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The description adds significant meaning beyond the input schema by demonstrating parameter usage in concrete examples (e.g., omitting run_id for listing, providing it for details, using detailed=True for extra diagnostics). Schema coverage is 100%, but the description enriches each parameter's role.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states it retrieves execution traces for automations and scripts to debug issues, detailing what traces show (triggers, conditions, actions, errors, variables). It is unambiguous and distinct from sibling tools, which focus on logs, history, or other operations.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides extensive usage modes and debugging examples, guiding when to use each mode (list vs. detailed vs. logbook). However, it does not explicitly state when not to use this tool or mention alternatives, missing the full 'when-not' guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_get_camera_imageGet Camera ImageARead-onlyIdempotent
Retrieve a snapshot image from a Home Assistant camera entity.
This tool fetches the current camera image and returns it directly for visual analysis. Use this when you need to see what a camera is currently viewing.
Parameters:
entity_id: Camera entity ID (e.g., 'camera.front_door', 'camera.living_room')
width: Optional width to resize the image (reduces token usage for large images)
height: Optional height to resize the image
Use Cases:
Security checks: "Is someone at the front door?"
Pet monitoring: "Is my dog still on the couch?"
Delivery verification: "Did my package get delivered?"
Visual confirmation: "Did the garage door actually close?"
Incident investigation: "What triggered the motion sensor?"
Example Usage:
# Get current snapshot from front door camera
ha_get_camera_image(entity_id="camera.front_door")
# Get resized image to reduce token usage
ha_get_camera_image(entity_id="camera.backyard", width=640, height=480)Notes:
Only cameras exposed to Home Assistant are accessible
The existing HA authentication/authorization applies
Images are returned in their native format (JPEG, PNG, or GIF)
Use width/height parameters for large high-resolution cameras to reduce token usage when full resolution is not needed
Related Services:
camera.snapshot: Save snapshot to file on HA server
camera.turn_on/turn_off: Control camera power
camera.enable_motion_detection: Enable motion detection
| Name | Required | Description | Default |
|---|---|---|---|
| width | No | ||
| height | No | ||
| entity_id | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and idempotentHint=true. The description adds further behavioral detail: images are returned in native format, token usage can be reduced via width/height, and only cameras exposed to HA are accessible. No contradictions.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Well-structured with sections: description, parameters, use cases, example, notes, related services. Front-loaded with main purpose. Every sentence adds valueโno fluff.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Despite no output schema, description explains return format (JPEG/PNG/GIF), authentication, camera availability, and token optimization. Covers all essential aspects for correct invocation and expectation setting.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Input schema has 0% parameter description coverage, so the description must compensate. It lists all three parameters with explanations (entity_id format, width/height purpose to 'reduce token usage') and provides example values inline, greatly enriching the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a clear verb+resource: 'Retrieve a snapshot image from a Home Assistant camera entity.' It specifies the exact action and target, and given the sibling list includes many other HA tool types, this tool is well-distinguished as the only one focused on camera snapshots.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit use cases (security, pet monitoring, etc.) and example usage with code. Also lists 'Related Services' that contrast with this tool (e.g., camera.snapshot saves to file), giving the agent clear when-to-use and when-not-to-use guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_get_deviceGet Device (incl. Zigbee/ZHA/Z2M, Z-Wave and Matter)ARead-onlyIdempotent
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.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Max devices to return per page in list mode (default: 50) | |
| offset | No | Number of devices to skip for pagination (default: 0) | |
| area_id | No | Filter devices by area ID (e.g., 'living_room') | |
| device_id | No | Device ID to retrieve details for. If omitted, lists devices. | |
| entity_id | No | Entity ID to find the associated device for (e.g., 'light.living_room') | |
| integration | No | Filter devices by integration: 'zha', 'zigbee2mqtt', 'zwave_js', 'mqtt', 'hue', etc. | |
| detail_level | No | 'summary': basic device info and protocol identifiers (default for list mode). 'full': include entities and all integration details. Single device lookups always return full detail. | summary |
| manufacturer | No | Filter devices by manufacturer name (e.g., 'Philips') |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already mark the tool as read-only and idempotent. The description adds rich behavioral context: pagination behavior, default limits, mode switching via device_id/entity_id, integration-specific return fields (e.g., ieee_address, node_id), and detail level effects. No contradictions with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-organized with clear sections, examples, and formatting. It is concise yet comprehensive, using bullet points and code blocks efficiently. No unnecessary text; every sentence adds value.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Despite the tool's complexity (multiple modes, many parameters, integration specifics), the description covers all aspects: pagination, filtering, detail levels, single lookup, integration details, and even a pointer to a sibling tool (ha_manage_radio). With an output schema present, the description is more than complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, and the description enhances every parameter with real-world examples and contextual meaning. It explains how device_id/entity_id switch modes, how detail_level affects output, and what integration values imply. Examples like ha_get_device(offset=50) clarify pagination semantics.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool retrieves device information with pagination, distinguishing between listing devices and single lookup. It specifies coverage of Zigbee, Z-Wave, and Matter integrations. While not explicitly differentiating from siblings, the purpose is highly specific and unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit usage patterns: list vs single lookup, pagination examples, filtering by area/integration, and detail levels. It also notes when to use ha_manage_radio for radio management, offering clear guidance on alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_get_entityGet EntityARead-onlyIdempotent
Get entity registry information for one or more entities.
Returns detailed entity registry metadata including area assignment, custom name/icon, enabled/hidden state, aliases, labels, and more.
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).
RELATED TOOLS:
ha_set_entity(): Modify entity properties (area, name, icon, enabled, hidden, aliases)
ha_get_state(): Get current state/attributes (on/off, temperature, etc.)
ha_search(): Find entities by name, domain, or area
EXAMPLES:
Single entity: ha_get_entity("sensor.temperature")
Multiple entities: ha_get_entity(["light.living_room", "switch.porch"])
RESPONSE FIELDS:
entity_id: Full entity identifier
name: Custom display name (null if using original_name)
original_name: Default name from integration
icon: Custom icon (null if using default)
area_id: Assigned area/room ID (null if unassigned)
disabled_by: Why disabled (null=enabled, "user"/"integration"/etc)
hidden_by: Why hidden (null=visible, "user"/"integration"/etc)
enabled: Boolean shorthand (True if disabled_by is null)
hidden: Boolean shorthand (True if hidden_by is not null)
aliases: Voice assistant aliases
labels: Assigned label IDs
categories: Category assignments (dict mapping scope to category_id)
device_class: User "Show As" override (null = use original_device_class)
original_device_class: Default device class from the integration
options: Per-domain registry options (e.g. sensor display_precision). Voice-assistant exposure is also stored here but should be set/cleared via the ha_set_entity(expose_to=...) parameter, not the options dict.
platform: Integration platform (e.g., "hue", "zwave_js")
device_id: Associated device ID (null if standalone)
config_entry_id: Parent config entry's ID (null for YAML-only entities). When 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.unique_id: Integration's unique identifier
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; resolves area_id above)
floor: Floor NAME of the assigned area
label_names: Assigned label NAMES (resolves the label ids in labels) Resolved label names live under label_names HERE (this tool's base
labelsalready carries the label ids); ha_search result_fields and ha_get_entity_exposure instead emit the resolved names underlabels.
get entity state attributes details single specific entity_id
| Name | Required | Description | Default |
|---|---|---|---|
| domain | No | Resolver filter (unique_id mode only): restrict matches to this entity domain, e.g. 'sensor'. | |
| platform | No | Resolver filter (unique_id mode only): restrict matches to this integration platform, e.g. 'hue'. | |
| entity_id | No | Entity ID or list of entity IDs to retrieve (e.g., 'sensor.temperature' or ['light.living_room', 'switch.porch']). Mutually exclusive with unique_id. | |
| unique_id | No | Resolve a stable integration unique_id to its entity_id(s) (entity_id is mutable, unique_id is not). Mutually exclusive with entity_id. Optionally narrow with domain/platform. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already indicate readOnlyHint=true and idempotentHint=true. The description adds substantial behavioral context: explains resolver mode behavior, details response fields including resolved-name enrichment, warns about aliases/device_class defaults in resolver mode, and provides guidance on using config_entry_id for helper configuration retrieval. No contradiction with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Description is long but well-structured with clear sections (RESOLVER MODE, RELATED TOOLS, EXAMPLES, RESPONSE FIELDS). Information is front-loaded with the core purpose. While some technical details could be compressed, the structure is logical and aids readability.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool complexity (4 parameters, output schema, annotations), the description is exceptionally complete. It explains all response fields, includes rich behavioral details, and links to complementary tools. The resolved-name enrichment caveat adds valuable context. No gaps identified.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3. The description adds value by explaining resolver mode, mutual exclusivity of entity_id and unique_id, and the role of domain/platform filters. It does not repeat schema details but provides contextual meaning beyond the parameter descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states 'Get entity registry information for one or more entities.' It uses a specific verb ('get') and resource ('entity registry information'), and distinguishes from sibling tools like ha_set_entity (modify), ha_get_state (current state), and ha_search (find entities).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explains the resolver mode for unique_id, provides examples for single/multiple entities, and lists related tools with brief descriptions. However, it does not explicitly state when not to use this tool or when alternatives are preferred beyond the related tools list.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_get_entity_exposureGet Entity ExposureARead-onlyIdempotent
Get entity exposure settings - list all or get settings for a specific entity.
Without an entity_id: Lists all entities and their exposure status to voice assistants (Alexa, Google Assistant, Assist).
With an entity_id: Returns which voice assistants the specific entity is exposed to.
EXAMPLES:
List all exposures: ha_get_entity_exposure()
Filter by assistant: ha_get_entity_exposure(assistant="cloud.alexa")
Get specific entity: ha_get_entity_exposure(entity_id="light.living_room")
RETURNS (when listing):
exposed_entities: Dict mapping entity_ids to their exposure status
summary: Count of entities exposed to each assistant
RETURNS (when getting specific entity):
exposed_to: Dict of assistant -> True/False for each assistant
is_exposed_anywhere: True if exposed to at least one assistant
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.
| Name | Required | Description | Default |
|---|---|---|---|
| assistant | No | Filter by assistant: 'conversation', 'cloud.alexa', or 'cloud.google_assistant'. If not specified, returns all. | |
| entity_id | No | Entity ID to check exposure settings for. If omitted, lists all entities with exposure settings. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description goes beyond annotations by detailing the return structure for both listing and single-entity cases, explaining conditional enrichment when the ha_mcp_tools component is available, and noting which fields are absent otherwise. This fully discloses behavioral traits.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured with sections for general behavior, examples, and return values. It is slightly verbose due to detailed return info, but every sentence adds value. It is front-loaded with the main purpose.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with only 2 optional parameters and an output schema, the description covers all necessary aspects: multiple usage modes, filtering, conditional enrichment, and detailed return format. It is fully complete given the tool's complexity.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% with descriptions for both parameters. The tool description adds extra value by providing usage examples and explaining the effect of omitting entity_id (list vs specific), which enriches understanding beyond the schema alone.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool gets entity exposure settings, with two distinct modes: listing all entities or getting a specific entity. The verb 'get' and resource 'entity exposure' are specific and unambiguous. It distinguishes itself from sibling tools like ha_get_entity and ha_get_state by focusing exclusively on voice assistant exposure settings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides clear usage context through examples for listing all, filtering by assistant, and getting a specific entity. It implicitly differentiates from other entity tools by its specialized purpose, but lacks explicit 'when not to use' guidance or direct comparison with alternatives like ha_get_entity.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_get_hacs_infoGet HACS InfoARead-onlyIdempotent
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. repository_id accepts a numeric HACS ID or an
owner/repo path.
| Name | Required | Description | Default |
|---|---|---|---|
| query | No | Search keyword (action='search') | |
| action | Yes | 'search' the store, or 'info' for one repository | |
| offset | No | Results to skip for pagination (action='search', default: 0) | |
| category | No | Filter by category (action='search') | |
| max_results | No | Maximum number of results (action='search', default: 10, max: 100) | |
| repository_id | No | Numeric HACS ID or 'owner/repo' path (action='info') | |
| installed_only | No | Only return installed repositories (action='search', default: False) |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already indicate readOnly, openWorld, idempotent. Description adds critical caveats: GitHub rate limits for info action, local cache for search, and format for repository_id. No contradictions.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Well-structured with overview, usage guidance, dashboard tip, examples, and caveats. Every sentence adds value without redundancy. Efficiently front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given 7 parameters, two modes, and existing output schema, description covers all necessary aspects: behavior, parameter details, constraints, and integration with ecosystem. Complete for a complex tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, baseline 3. Description adds substantial value beyond schema: explains actions, provides dashboard tip, examples, and caveats for repository_id. Demonstrates parameter usage effectively.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states it retrieves HACS data with two actions (search and info). It distinguishes from sibling tools like ha_manage_hacs for installation and non-HACS domain-specific tools, providing a specific verb and resource.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly explains when to use search vs info, and when not to use this tool (e.g., for installation, use ha_manage_hacs; for non-HACS entities, use other tools). Includes a dashboard tip and examples.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_get_historyGet Entity History or StatisticsARead-onlyIdempotent
Get historical data from Home Assistant's recorder.
Sources:
"history" (default): Raw state changes, ~10 day retention, full resolution
"statistics": Pre-aggregated data, permanent retention, requires state_class
Shared params: entity_ids, start_time, end_time, limit, offset History params: minimal_response, significant_changes_only Statistics params: period, statistic_types
Default time range: 24h for history, 30 days for statistics
Use ha_get_history (default) when:
Troubleshooting why a value changed ("Why was my bedroom cold last night?")
Checking event sequences ("Did my garage door open while I was away?")
Analyzing recent patterns ("What time does motion usually trigger?")
Use ha_get_history(source="statistics") when:
Tracking long-term trends beyond 10 days ("Energy use this month vs last month?")
Computing period averages ("Average living room temperature over 6 months?")
Entities must have state_class (measurement, total, total_increasing)
WARNING: limit and offset apply per entity (not globally across all entities). 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.
Example -- history (default):
ha_get_history(entity_ids="sensor.bedroom_temperature", start_time="24h")
ha_get_history(entity_ids=["sensor.temperature", "sensor.humidity"], start_time="3d", limit=500)
# Default order="desc" returns newest states first.
# To paginate oldest-first, use order="asc":
ha_get_history(entity_ids="sensor.temperature", start_time="7d", limit=100, offset=100, order="asc")Example -- statistics:
ha_get_history(source="statistics", entity_ids="sensor.total_energy_kwh", start_time="30d", period="day")
ha_get_history(source="statistics", entity_ids="sensor.living_room_temperature",
start_time="6m", period="month", statistic_types=["mean", "min", "max"])
ha_get_history(source="statistics", entity_ids="sensor.energy_kwh",
start_time="30d", period="5minute", limit=100, offset=200)| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Max entries per entity. Default: 100, Max: 1000. For source="history": state changes. For source="statistics": aggregated rows. With multiple entity_ids, offset must be 0 and total rows returned can reach limit ร len(entity_ids). | |
| order | No | Sort order for history entries. "desc" (default): newest first. "asc": oldest first (chronological, as returned by HA API). Ignored when source="statistics". | desc |
| fields | No | Return only the specified top-level response keys to reduce response size. None = full response (default). History keys: success, source, entities, period, query_params. Statistics keys: success, source, entities, period_type, time_range, statistic_types, query_params, warnings. | |
| offset | No | Number of entries to skip per entity for pagination. Default: 0. Offset > 0 requires a single entity_id. Use with limit and has_more/next_offset in the response. | |
| period | No | Aggregation period: "5minute", "hour", "day", "week", "month", "year". Default: "day". Ignored when source="history" | day |
| source | No | Data source: "history" (default) for raw state changes (~10 day retention), or "statistics" for pre-aggregated long-term data (permanent, requires state_class). | history |
| end_time | No | End time: ISO datetime. Default: now | |
| entity_ids | Yes | Entity ID(s) to query. Can be a single ID, comma-separated string, or JSON array. | |
| start_time | No | Start time: ISO datetime or relative (e.g., '24h', '7d', '30d'). Default: 24h ago for history, 30d ago for statistics | |
| statistic_types | No | Statistics types: "mean", "min", "max", "sum", "state", "change". Default: all. Ignored when source="history" | |
| minimal_response | No | Return only states/timestamps without attributes. Default: true. Ignored when source="statistics" | |
| significant_changes_only | No | Filter to significant state changes only. Default: true. Ignored when source="statistics" |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint and idempotentHint, and the description adds valuable behavioral context beyond that: data retention differences, client-side limit/offset slicing ('All data is fetched from HA before slicing'), per-entity pagination behavior, the has_more/next_offset pattern, optional recorder workload guardrails, and timezone considerations for calendar statistics. No annotation contradiction exists.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but tightly organized with headers, bullet lists, and code examples that each carry information. It front-loads the core purpose and source distinction, then progressively adds usage guidance, warnings, and examples. For a 12-parameter tool with two modes, the length is appropriate and nothing is redundant.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity, the description covers all essential decision points: which source to choose, default time ranges, pagination mechanics, source-specific parameters, and operational warnings. Since an output schema exists, return-value details are not required, and the description still mentions response keys and pagination fields via the fields parameter.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Even though schema description coverage is 100%, the description adds meaningful semantics: it groups parameters into Shared/History/Statistics, explains defaults ('24h for history, 30 days for statistics'), provides relative time examples, and clarifies limit/offset are per-entity rather than global. The code examples further map parameters to real usage patterns.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: 'Get historical data from Home Assistant's recorder.' It then clearly distinguishes the two operational modes, 'history' (raw state changes) and 'statistics' (pre-aggregated data), so an agent understands exactly what the tool returns. This is well differentiated from current-state tools like ha_get_state by emphasizing historical/recorder data.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit when-to-use guidance with concrete scenarios: 'Use ha_get_history (default) when: Troubleshooting why a value changed...' and 'Use ha_get_history(source="statistics") when: Tracking long-term trends beyond 10 days...'. It also gives exclusions, such as statistics requiring state_class and offset > 0 requiring a single entity_id, making selection unambiguous.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_get_integrationGet IntegrationARead-onlyIdempotent
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 all integrations: ha_get_integration()
Paginate: ha_get_integration(offset=50)
Search: ha_get_integration(query="zigbee")
Get specific entry: ha_get_integration(entry_id="abc123")
Get entry with editable fields: ha_get_integration(entry_id="abc123", include_schema=True)
Get entry with diagnostics dump: ha_get_integration(entry_id="abc123", include_diagnostics=True)
Get device-scoped diagnostics: ha_get_integration(entry_id="abc123", include_diagnostics=True, device_id="dev123")
Get the parsed KNX ETS project (group-address table): ha_get_integration(entry_id="", include_knx_project=True)
Walk a sub-tree: ha_get_integration(entry_id="abc123", include_diagnostics=True, diagnostics_data_path="")
Paginate a large list: ha_get_integration(entry_id="abc123", include_diagnostics=True, diagnostics_data_path="", diagnostics_data_limit=10, diagnostics_data_offset=20)
List config subentries: ha_get_integration(entry_id="abc123", include_subentries=True)
Inspect subentry create schema: ha_get_integration(entry_id="abc123", include_subentry_schema=True, subentry_type="conversation")
Inspect subentry reconfigure schema: ha_get_integration(entry_id="abc123", include_subentry_schema=True, subentry_type="conversation", subentry_id="sub123")
List template entries: 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; a field that
was never set may be absent (rather than shown at its schema default).
Values that match a secrets.yaml entry are returned as
"**redacted**". Use include_schema=True to see every editable
field and its default/type. Nested option sections (e.g. a template
helper's advanced_options) are additively flattened one level โ
each section's leaf keys are copied to the top of options (mirroring
the OptionsFlow-derived read) while the raw nested section is preserved
for fidelity, and an existing top-level key is never overwritten.
Each entry carries:
log_level: the canonical Python logger level name (DEBUG/INFO/WARNING/ERROR/CRITICAL) when the integration has alogger.set_leveloverride, or"DEFAULT"(uppercase sentinel) when no override is set.log_level_raw: the original numeric level (e.g.10for DEBUG) when HA returned an int,Noneotherwise (no override set, or HA provided a level name as a string).
This is distinct from the add-on side, where ha_get_app returns
Supervisor's lowercase "default" literal โ do not cross-compare.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Max entries to return per page in list mode (default: 50) | |
| query | No | When listing, search by domain or title. Uses exact substring matching by default; set exact_match=False for fuzzy. | |
| domain | No | Filter by integration domain (e.g. 'template', 'group'). When set, includes the full options/configuration for each entry. | |
| offset | No | Number of entries to skip for pagination (default: 0) | |
| entry_id | No | Config entry ID to get details for. If omitted, lists all integrations. | |
| device_id | No | Optional. When set with include_diagnostics=True, returns the device-scoped diagnostics dump for that specific device under the integration (rather than the full integration dump). Some integrations only expose config-entry-level dumps; others expose both. | |
| exact_match | No | Use exact substring matching for query filter (default: True). Set to False for fuzzy matching when the query may contain typos. | |
| subentry_id | No | Existing subentry ID used with include_subentry_schema=True to inspect a reconfigure flow. | |
| subentry_type | No | Integration-defined subentry type used with include_subentry_schema=True. | |
| include_schema | No | When entry_id is set, also return the options flow schema (available fields and their types). Use before ha_config_set_helper to understand what can be updated. Only applies when supports_options=true. | |
| include_options | No | Include the options object for each entry. Automatically enabled when domain filter is set. For UI-created flow-based helpers (template, group, utility_meter, derivative, ...), the current config โ template body, group members, source entity, etc. โ is surfaced here by probing the options flow. Prefer this over include_schema when you only need to read the current values; use include_schema when you also need the field types or selector metadata. | |
| diagnostics_fields | No | Optional list of top-level keys to keep from the diagnostics data payload (e.g. ['home_assistant', 'issues']). Trims the payload before it hits the LLM context budget. Accepts a JSON list or comma-separated string. Only applies when include_diagnostics=True and the data payload is a dict. Unknown keys are silently dropped and surfaced via the omitted_fields sub-key. | |
| include_subentries | No | When entry_id is set, include config subentries for the integration entry. Useful for integrations that expose conversation agents, devices, or other extension points as subentries. | |
| include_diagnostics | No | When entry_id is set, also fetch the integration's diagnostics dump โ integration-defined JSON (commonly includes redacted config, device list, state snapshots; exact top-level keys vary by integration). The canonical artifact users grab via Settings โ Devices & Services โ [integration] โ โฏ โ Download diagnostics. Use when triaging integration bugs or filing ha_report_issue for a specific integration. Payloads can be large (Hue ~290 KB, ZHA/MQTT/ESPHome several MB) โ pair with diagnostics_fields or diagnostics_truncate_at_bytes to fit the LLM context budget. | |
| include_knx_project | No | When entry_id is a KNX config entry, also return the parsed ETS project: the full group-address table (address, name, DPT, description) under knx_project.group_addresses, plus the group-range hierarchy and project metadata. This is the parsed-project GA table that is NOT in the diagnostics dump; per-entity GA assignments are already covered by include_diagnostics (config_store / configuration_yaml). Ignored (with a warning) when the entry is not a KNX integration. The KNX integration exposes a single project, so the result is the same regardless of which KNX entry_id is used. | |
| diagnostics_data_path | No | Optional dotted path into the diagnostics data sub-tree (e.g. '<list-valued path>' for per-device records, 'home_assistant.version' for HA core version; the exact key path varies by integration version). Walks into the post-fields payload. Resolution failures replace data with null and surface data_path_error. Use this when the interesting payload lives several levels deep โ top-level diagnostics_fields can't address sub-trees on integrations where the bulk lives under one key (ZHA, MQTT, ESPHome). Only applies when include_diagnostics=True. | |
| show_advanced_options | No | When include_subentry_schema=True, ask older Home Assistant versions to expose advanced flow options. No-op on HA 2026.6+; pending removal before HA 2027.6. | |
| diagnostics_data_limit | No | Pagination window size for list-valued diagnostics_data_path results. When set with a list-resolved path, swaps data for a pagination envelope {path, items, offset, limit, total, has_more}. Default None returns the full resolved value. Workflow: probe with a list-valued diagnostics_data_path and diagnostics_data_limit=10 to walk a large list one page at a time (the exact path varies by integration version). Only applies when include_diagnostics=True. | |
| diagnostics_data_offset | No | Pagination start index (default 0) for list-valued diagnostics_data_path results. Ignored when diagnostics_data_path is unset, diagnostics_data_limit is unset, or the resolved value is not a list. Only applies when include_diagnostics=True. | |
| include_subentry_schema | No | When entry_id is set, return introspection-only config subentry schema information; no subentry is created. Pair with subentry_type, and optionally subentry_id for reconfigure schema. | |
| diagnostics_truncate_at_bytes | No | Optional byte cap on the serialized diagnostics payload (after diagnostics_fields and diagnostics_data_path have been applied). On hit, drops data and emits truncated=true, bytes_total, byte_cap, plus available_fields (when the capped value is a dict). Recommended starting point: 20000 bytes. Only applies when include_diagnostics=True. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and idempotentHint=true, but the description adds substantial behavioral detail: pagination semantics, secrets.yaml values returned as '**redacted**', nested option sections flattened additively, log_level sentinel behavior, diagnostics byte-truncation behavior, and KNX project parsing. No contradictions with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but well-structured with clear sections: overview, examples, states, options behavior, per-entry fields, and cross-tool distinction. The first sentence immediately states the core purpose. Every section earns its place given the tool's 21 parameters and complex diagnostic/schema-probing behavior.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with 21 optional parameters, an output schema, and annotations, the description is exceptionally complete. It covers all major modes (list, detail, schema, diagnostics, subentries, KNX project, pagination), includes edge cases like redacted secrets and log_level sentinel, and provides usage guidance that complements the structured schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3, but the description goes far beyond the schema by explaining real-world semantics: how include_options surfaces flow-based helper config, how diagnostics_data_path walks sub-trees, how diagnostics_fields trims payloads, and the distinction between include_schema and include_options. The extensive examples map parameter combinations to concrete use cases.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: 'Get integration (config entry) information with pagination.' It clearly distinguishes the two primary modes (list all without entry_id vs. detailed single-entry lookup with entry_id) and includes concrete examples. This separates it cleanly from sibling tools like ha_get_app and ha_set_integration.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives explicit when-to-use guidance, including 'Prefer include_options over include_schema when you only need to read the current values' and 'use include_schema when you also need the field types or selector metadata.' It also warns not to cross-compare ha_get_integration's log_level sentinel with ha_get_app's Supervisor literal, naming the alternative tool directly.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_get_logsGet LogsARead-onlyIdempotent
Get Home Assistant logs from various sources.
Sources:
"logbook" (default): Entity state change history with pagination
"system": Structured system log entries (errors, warnings) via system_log/list
"error_log": Raw log text (home-assistant.log on container/pip installs; HA Core's journald stream on Supervisor-backed installs)
"supervisor": App (add-on) container logs (requires slug = app slug)
"system_service": HA-Supervisor-managed system service logs (requires slug โ {supervisor, host, core, dns, audio, cli, multicast, observer})
"logger": Effective log level per integration via logger/log_info (confirms logger.set_level changes took effect)
"fault_log": HA Core's faulthandler crash dump (home-assistant.log.fault). Written only when HA dies from a native fatal signal (segfault, abort, Python fatal error), which never reaches journald or error_log. Empty on a healthy install (crash_recorded=False). Whole crash blocks are ordered (newest first by default) with each block's lines kept in place so the traceback reads correctly; search keeps every block that mentions the term; offset/limit page through the assembled text. Reads through the "HA-MCP File & YAML Tools" entry (component >= 2.2.0).
Prefer source='system' for triage. It returns HA's own deduplicated system_log entries with counts, first_occurred and full tracebacks; of those only the tracebacks are unrecoverable from the structured error_log summary โ they are present in the raw text, so structured=False gets them back. Its counts also run since each error first occurred, while structured error_log counts only what is inside the fetched window (reported as window_start/window_end; every install now reads a capped window). Use error_log with structured=True for entries below system_log's WARNING+ ~50-entry cap, or for the per-component rollup.
Shared params: limit, search (keyword filter on entries/lines; matches integration domain for source='logger')
Order: order='newest' (default) returns most-recent first; order='oldest' returns chronological-first. Applies to all time-ordered sources (logbook, system, error_log, supervisor, system_service, fault_log); ignored for source='logger' and for error_log with structured=True. For raw-text sources (error_log, supervisor, system_service) it sets the read direction of the most-recent window; fault_log orders whole crash blocks instead of lines.
Logbook params: hours_back, entity_id, end_time, compact (default True โ strips attribute dicts to save context)
Pagination (logbook + error_log + fault_log): offset pages deeper; ignored for the
other sources. fault_log always reads a fixed window from the end of
the file, orders its crash blocks, and pages the assembled text
from the start with has_more/next_offset. Logbook responses carry has_more plus a
pagination_hint. On error_log, offset counts raw log lines back from
the newest entry (journald entries on Supervisor-backed installs),
both modes read a bounded window per call โ so level/search
filter and limit slice within that window only, and window_lines
reports the size actually requested โ and the response carries
has_more with a next_offset to pass back while it stays true.
System/error_log params: level (ERROR, WARNING, INFO, DEBUG, CRITICAL)
error_log params: structured, top_n. In structured mode search
matches the message and logger name only, whereas on the raw path it
matches the whole line; limit/order do not apply, issues are
ranked by count, then severity, then recency, and the summary covers
a fixed deep window rather than the caller's limit.
Supervisor params: slug = app slug, e.g. "core_mosquitto" (use
ha_get_app() to list installed slugs)
System-service params: slug = service name. The slug "supervisor"
here means the Supervisor service's own logs, NOT an app with
that name โ the source param disambiguates.
| Name | Required | Description | Default |
|---|---|---|---|
| slug | No | ||
| level | No | ||
| limit | No | ||
| order | No | Sort order for time-ordered sources (logbook, system, error_log, supervisor, system_service, fault_log): 'newest' (default) returns most-recent first; 'oldest' returns chronological-first. Ignored for source='logger', and for source='error_log' with structured=True (that summary is ranked by occurrence count, not by time). | newest |
| top_n | No | Max distinct issues to return when structured=True (default 20, capped at 500). Bounds the response regardless of log size. | |
| offset | No | Page deeper into source='logbook', 'error_log' and 'fault_log' (ignored for other sources). On error_log it counts raw log lines back from the newest entry; on fault_log it counts lines from the start of the assembled crash text. Pass the response's 'next_offset' to continue while 'has_more' is true. | |
| search | No | ||
| source | No | logbook | |
| compact | No | ||
| end_time | No | ||
| entity_id | No | ||
| hours_back | No | ||
| structured | No | source='error_log' only. When True, return a deduplicated, component-grouped summary of the log (counted issues sorted by frequency) instead of raw text. Use this on busy instances where the raw log is large enough to exhaust context. Ignored for other sources. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare readOnlyHint=true and idempotentHint=true, and the description does not contradict these. Beyond annotations, the description discloses significant behavioral details: pagination behavior (has_more, next_offset), the bounded window for error_log, how fault_log orders crash blocks, and when parameters are ignored. These go beyond the schema and help the agent understand side effects and edge cases. The only minor gap is lack of explicit mention of rate limits or error conditions, but that's not critical for a read-only tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long (over 300 words) but densely packed with critical information. It is well-structured with bold section headings for sources, shared params, order, logbook params, pagination, and source-specific params. It front-loads the key advice to prefer system source. While verbose, every sentence adds value, though it could be slightly condensed without losing meaning, so a 4.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity (13 parameters, 7 sources, pagination, different modes) and that an output schema exists (which may describe return format), the description is remarkably thorough. It covers behavior for each source, parameter applicability, pagination, and even edge cases like fault_log. However, it could be more complete by explicitly stating the return shape for each source or mentioning potential error conditions (e.g., invalid slug). The presence of an output schema mitigates some of this, so a 4.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 31%, so the description must compensate for undocumented parameters. It does so for many: it explains 'limit' and 'search' as shared params, details 'order' semantics for each source, explains 'offset' for pagination, and describes source-specific params like 'structured' and 'top_n'. However, some parameters like 'entity_id', 'end_time', and 'hours_back' are only mentioned implicitly under logbook params without detailed syntax or examples. The description adds significant value over the schema but leaves a few parameters thinly described, so a 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's purpose: retrieving Home Assistant logs from various named sources (logbook, system, error_log, etc.), each with specific details. It clearly differentiates from siblings like ha_get_history or ha_search by focusing on logs with source-specific behaviors. The verb 'Get' and resource 'logs' are specific, and the enumeration of sources provides a clear scope.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit guidance on when to use which source: for triage it says 'Prefer source='system'', and explains why (deduplicated entries, counts, tracebacks) and when to use error_log (for entries below WARNING cap, or per-component rollup). It also disambiguates similar sources, e.g., 'system_service' slug 'supervisor' means Supervisor service logs, not an app, clarifying potential confusion. This is exemplary usage guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_get_operation_statusGet Operation StatusARead-only
Get the status of one or more device operations with real-time WebSocket verification.
Pass a single operation_id string to check one operation, or a list of IDs to check multiple operations at once (bulk status).
The timeout_seconds wait window bounds both modes. Bulk checks poll all operations concurrently under one shared window and report per-item failures inside detailed_results instead of aborting the batch.
Use this to track operations initiated by ha_bulk_control or ha_call_service. For current entity states, use ha_get_state instead.
| Name | Required | Description | Default |
|---|---|---|---|
| operation_id | Yes | Single operation ID or list of operation IDs to check. Use a single string for one operation, or a list for bulk status checks. | |
| timeout_seconds | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, and the description adds substantial behavior beyond that: real-time WebSocket verification, concurrent polling of bulk operations under one shared timeout window, and per-item failures surfacing in detailed_results rather than aborting the batch. These are exactly the non-obvious behaviors an agent needs to know.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Compact and efficiently front-loaded: purpose in sentence one, usage modes in the next, timeout semantics, then routing guidance. Every sentence earns its place, and the structure mirrors how an agent would reason about the tool.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers both invocation modes, shared timeout behavior, bulk failure semantics, and the relationship to sibling tools. An output schema exists so return-value details needn't be spelled out, and nothing an agent needs to call this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 50% โ operation_id is fully documented in the schema, but timeout_seconds has no schema description. The description compensates by explaining the timeout wait window bounds both modes and that bulk checks share one window, adding real meaning beyond the schema's default/minimum values.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb-resource statement โ 'Get the status of one or more device operations' โ and adds the distinguishing real-time WebSocket verification detail. It differentiates from siblings by explicitly pointing to ha_get_state for entity states, so an agent can select it correctly without inspecting other definitions.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit when-to-use guidance: 'Use this to track operations initiated by ha_bulk_control or ha_call_service,' and an explicit exclusion: 'For current entity states, use ha_get_state instead.' This is model usage guidance with named alternatives and conditions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_get_overviewGet System OverviewARead-onlyIdempotent
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. Standard/full modes paginate entities (default 200 per page) โ use offset to fetch more. Use 'domains' filter to narrow scope.
Use fields= to project the response to only the keys you need โ a significantly smaller payload when fetching a single sub-section (e.g. fields=["system_info"] returns just that section instead of the full overview). Requests composed only of system_info, notification, repair, or server metadata fields also 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 (and only when) the ha-mcp settings-UI sidecar is running
(stdio mode, e.g. Claude Desktop / Claude Code), the response
includes a settings_url field โ the local URL to the
tool-configuration page. Hand this URL to the user when they
ask how to enable or disable tools or change server settings.
settings_url is emitted regardless of fields=
projection (so it stays discoverable even when callers
minimize the response) but only when the sidecar URL file
actually exists.
In standalone HTTP / Docker modes, when an HTTP settings prefix is
advertised, there is no sidecar URL file and the server can't know its
externally reachable host. The response instead carries a
settings_url_hint string telling the user where the page is mounted
and how to find or construct the full URL.
Hand whichever of the two fields is present to the user.
The response also carries an ha_mcp_update object
{current, latest, update_available} reporting whether a newer ha-mcp
release is available (PyPI for pip/Docker, the Supervisor add-on store
for the add-on) โ proactively tell the user when update_available is
true. Emitted regardless of fields=; omitted only for the
unknown version and when HA_MCP_DISABLE_UPDATE_CHECK is set.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Max total entities across all domains (default: unlimited for minimal, 200 for standard/full). Counts and states always complete. Use with offset for pagination. | |
| fields | No | Return only the specified top-level response keys to reduce response size (e.g. ["system_info", "domain_stats"]). None = full response (default). Available keys: success, system_summary, domain_stats, area_analysis, ai_insights, pagination, partial, warnings, device_types, service_availability, system_info, notification_count, notifications, repair_count, dismissed_repair_count, repairs, repairs_error, tool_discovery, settings_url, settings_url_hint, read_only_mode, read_only_mode_hint, ha_mcp_update. Note: ``settings_url`` (stdio mode), ``settings_url_hint`` (standalone HTTP/Docker mode), the ``read_only_mode`` / ``read_only_mode_hint`` pair (only while Read Only Mode is on), and ``ha_mcp_update`` (when an update check applies) are emitted regardless of ``fields=`` projection so the settings page, the active mode, and a newer ha-mcp release stay discoverable; see the tool description. | |
| offset | No | Number of entities to skip for pagination (default: 0) | |
| domains | No | Filter to specific domains (e.g. 'light,sensor' or ['light','sensor']). None = all domains. Useful to avoid context window overload. | |
| detail_level | No | 'minimal': 10 entities/domain, top-5 states (default); 'standard': 200 entities/page, top-10 states (use offset for more); 'full': 200 entities/page + entity_id + state + full states. Use 'domains', 'limit', or max_entities_per_domain to control size | minimal |
| include_state | No | Include state field for entities (None = auto based on level). Full defaults to True. | |
| include_entity_id | No | Include entity_id field for entities (None = auto based on level). Full defaults to True. | |
| include_notifications | No | Include active persistent notifications (default: True). Set False to skip. | |
| max_entities_per_domain | No | Override default entity cap per domain (minimal=10, standard/full=unlimited). 0 = no limit on entities or states. | |
| include_dismissed_repairs | No | Include user-dismissed/ignored repairs (default: False). Matches the HA Repairs UI which hides dismissed items by default. To dismiss/ignore a repair, call ha_call_service with ws_command="repairs/ignore_issue" and data={"domain": ..., "issue_id": ..., "ignore": true}. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover readOnlyHint, openWorldHint, and idempotentHint, but the description adds substantial behavior beyond them: pagination semantics (200/page in standard/full), the guarantee that counts/states_summary stay complete despite pagination, the mode-dependent settings_url vs settings_url_hint behavior, the always-emitted fields regardless of fields= projection, and the ha_mcp_update object with its conditional omission. This is rich behavioral disclosure that the annotations alone would not convey. No contradiction with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured and front-loaded with purpose and usage guidance, but it is genuinely long (roughly 450+ words). The settings_url/settings_url_hint/hint-handling paragraphs and the ha_mcp_update explanation are verbose, with some redundancy against the schema's own fields= note about always-emitted keys. Well-organized but over-written for what could be tightened.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a high-complexity tool (10 params, 0 required, three detail modes, pagination, conditional fields, mode-dependent behavior) with an output schema and rich annotations, the description is nearly complete: it covers return contents, mode differences, pagination, when not to use it, alternatives, projection semantics, and conditional update/settings fields. Minor gaps remain around exact error behavior, but nothing an agent needs to invoke it correctly is missing. The output schema covers return-value structure, so the description need not.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3. The description adds meaningful semantics beyond the schema: it explains how detail_level interacts with pagination and entity caps, how fields= can skip unrelated state/service/registry reads for certain key combinations, and that settings_url/settings_url_hint/ha_mcp_update are emitted regardless of projection. This goes beyond what the schema's per-parameter descriptions state, so a 4 is warranted.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb+resource ('Get AI-friendly system overview') and enumerates the concrete contents (base_url, version, location, timezone, entity overview, notifications). It distinguishes itself from siblings by explicitly naming ha_get_state, ha_get_entity, and ha_search as the correct tools for narrow entity inspection. This differentiates it clearly from the many ha_get_* siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit when-to-use guidance ('Use 'minimal' (default) for most queries'), explicit when-not-to-use ('Do not use this tool to inspect a known entity or a narrow set of entities'), and names the exact alternatives (ha_get_state, ha_get_entity, ha_search). It also flags cost/performance considerations for large installations, giving the agent a decision rule based on scope.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_get_skill_guideGet Home Assistant Best Practices Skill GuideARead-onlyIdempotent
Get bundled Home Assistant best-practice skill guides. No skill bundles are currently available on this server โ the skills directory is missing, empty, or all SKILL.md files failed to parse. Calls return an empty listing; 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
| Name | Required | Description | Default |
|---|---|---|---|
| file | No | Reference file path within the skill, relative to the skill directory (e.g., 'SKILL.md' or 'references/automation-patterns.md'). Requires skill to be set. | |
| skill | No | Skill name from the no-args listing (e.g., 'home-assistant-best-practices'). |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare readOnlyHint=true and idempotentHint=true. The description adds behavioral context: 'No skill bundles are currently available... Calls return an empty listing; ask the operator to verify the skills-vendor submodule is initialized.' This provides transparency about current state and failure modes beyond annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is relatively long but well-structured: a brief purpose, status note, usage guidance, and replacement info. Every sentence serves a purpose, though it could be slightly more compact. Still concise for the amount of useful information provided.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's simplicity (2 optional parameters, no enums, output schema present), the description covers all necessary context: current state, usage timing, replacement info, and parameter hints. It is complete for an agent to decide when and how to use it.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents both parameters. The description does not add significant meaning beyond what is in the schema (e.g., 'Skill name from the no-args listing' is already in schema). Baseline of 3 is appropriate as schema carries the burden.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's purpose: 'Get bundled Home Assistant best-practice skill guides.' It specifies the resource (skill guides) and action (get), and distinguishes from siblings by focusing on skill guides, not other config entities. It also notes the current unavailability, which sets expectations.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly states when to use: 'Use BEFORE: creating or editing automations, scripts, scenes, helpers, or dashboards; ...' and lists specific tool calls. It also clarifies that it supersedes earlier tools (ha_list_resources, etc.), providing clear alternatives and exclusion guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_get_stateGet Entity StateARead-onlyIdempotent
Get current status, state, and attributes of one or more entities (lights, switches, sensors, climate, covers, locks, fans, etc.).
SINGLE ENTITY: Pass a string entity_id. Returns the entity's full state and attributes.
MULTIPLE ENTITIES: Pass a list of entity IDs (max 100). Efficiently retrieves states using parallel requests. Duplicates are automatically deduplicated. Returns success=True if at least one entity state was retrieved. Check 'error_count' for any failed lookups in partial-success scenarios.
FIELDS PROJECTION:
fields= projects the per-entity record keys (see the fields= parameter
description for the full key list), NOT the outer bulk response wrapper.
In single-entity mode it filters keys of the returned record directly. In bulk
mode it filters keys of each record inside states[entity_id]; 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.
When attribute_keys= is set but has no effect (because attributes was
excluded by fields=), a warnings list is emitted outside the projected
entity record(s): in bulk mode at the response wrapper level (sibling of
success/count/states); in single-entity mode at the top-level result
(sibling of data/metadata, since the projected record IS data).
The warnings list is never a record key, so fields=["state"] returns a
record with only state regardless of whether the no-effect warning fires.
EXAMPLES:
Single: ha_get_state("light.kitchen")
Multiple: ha_get_state(["light.kitchen", "light.living_room", "sensor.temperature"])
State only: ha_get_state("light.kitchen", fields=["state"])
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
| Name | Required | Description | Default |
|---|---|---|---|
| fields | No | Return only the specified top-level entity record keys to reduce response size (e.g. ["state", "attributes"]). None = full entity record (default). Available keys: entity_id, state, attributes, last_changed, last_reported, last_updated, context. | |
| entity_id | Yes | Entity ID or list of entity IDs to retrieve state for (e.g., 'light.kitchen' or ['light.kitchen', 'sensor.temperature']) | |
| attribute_keys | No | Return only the specified keys from each entity's attributes dict (e.g. ["brightness", "color_temp_kelvin"] for lights). None = full attributes (default). Unknown keys are silently dropped. Requires "attributes" to be present in fields= (or fields=None). |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint and idempotentHint. The description adds significant behavioral context: bulk mode with parallel requests, deduplication, partial-success handling, fields projection behavior, and warnings for attribute_keys no-effect. No contradictions.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured with sections and examples, but slightly verbose. It front-loads the core purpose and uses clear formatting, earning its length.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description covers all modes, edge cases (partial success, no-effect warnings), and provides examples. With an output schema existing, return values are covered. Complete for a complex tool with 3 parameters.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, and the description adds meaning beyond the schema by explaining fields projection behavior in detail, attribute_keys dependency, and warnings. It clarifies the interaction between parameters.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's purpose: 'Get current status, state, and attributes of one or more entities'. It specifies the verb 'Get' and the resource 'state of entities', and distinguishes it from siblings by being a read-only state retrieval tool, unlike other tools like ha_get_entity or ha_get_history.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides detailed guidance on single vs multiple entities, fields projection, and attribute_keys, with examples. It does not explicitly mention when not to use or alternatives, but the context is clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_get_system_healthGet System Health (incl. ZHA/Z-Wave/integration diagnostics)ARead-onlyIdempotent
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.
The result also carries an ha_mcp_update object โ
{current, latest, update_available} โ reporting whether a newer
ha-mcp release is available (from PyPI for pip/Docker, or the Supervisor
add-on store for the add-on), so you can proactively tell the user to
upgrade. Present on every install type including the HA add-on (so a user
who missed the Supervisor's update prompt still hears about it); omitted
only for the unknown version and when HA_MCP_DISABLE_UPDATE_CHECK
is set.
Parameters:
include: Optional comma-separated list of additional data to include.
"repairs": Repair items from Settings > System > Repairs (active only by default; pass
include_dismissed_repairs=Truefor all). To dismiss/ignore a repair, callha_call_service(ws_command="repairs/ignore_issue", data={"domain": <domain>, "issue_id": <issue_id>, "ignore": true})."zha_network": ZHA Zigbee devices with radio signal summary (name, LQI, RSSI)
"zha_network_full": ZHA Zigbee devices with all device details (can be large on 100+ device networks; prefer "zha_network" for summary)
"zwave_network": Z-Wave JS network status and node summary (status, security, routing)
"thread_network": Thread/OpenThread Border Router (OTBR) summary โ per border-router channel, extended_pan_id, and border_agent_id (integration-presence + radio-network view, not per-node Thread health)
"matter_network": Matter integration presence summary โ config_entry_id, state, and title (per-node health is exposed separately via Matter node diagnostics, not here)
"themes": Installed theme names and defaults (sorted list of theme names, count, default_theme, default_dark_theme)
"diagnostics": Per-integration diagnostics dump โ integration-defined JSON (commonly includes redacted config, device list, state snapshots; exact top-level keys vary by integration). REQUIRES
config_entry_id. The canonical artifact users grab via Settings โ Devices & Services โ [integration] โ โฏ โ Download diagnostics. Use this when triaging integration bugs or filingha_report_issuefor a specific integration. Payloads can be large (Hue ~290 KB, ZHA/MQTT/ESPHome several MB) โ pair withdiagnostics_fieldsordiagnostics_truncate_at_bytesto fit the LLM context budget."config_check": Validate HA configuration via POST /config/core/check_config (the pre-restart safety check; ha_restart runs it automatically). Returns {result: valid|invalid, is_valid, errors}; read-only/idempotent, takes no args.
"dead_entities": Surface orphaned/stale entity-registry entries by diffing the registry against the state machine and the live config-entries set. Returns confidence-tiered buckets โ
config_entry_orphans(owning integration instance gone; definitively dead) andstale_restored(HA restored the entity from the registry on startup but the loaded integration no longer provides it). Each item carries entity_id + platform so a client can propose cleanup with ha_remove_entity. Deliberately excludesunknown-state entities and merely-offline devices to keep false positives low. Read-only; takes no args.Example: include="repairs,zha_network,zwave_network,config_check"
Example: include="diagnostics", config_entry_id="abc123..."
include_dismissed_repairs: Include user-dismissed/ignored repairs (default: False). Only meaningful when "repairs" is in
include.config_entry_id: Required when
includecontainsdiagnostics. The config entry ID of the integration (find viaha_get_integration).device_id: Optional. When set with
include=diagnostics, returns the device-scoped diagnostics dump for that specific device under the integration (rather than the full integration dump). Some integrations only expose config-entry-level dumps; others expose both.diagnostics_fields: Optional list of top-level keys to keep from the diagnostics
datapayload (e.g.["home_assistant", "issues"]). Accepts a JSON list or comma-separated string. Only applies withinclude=diagnostics.diagnostics_truncate_at_bytes: Optional byte cap on the serialized diagnostics payload (post-projection / post-data_path). On hit, drops
dataand emitstruncated=true,bytes_total,byte_cap, plusavailable_fields(when the capped value is a dict). Only applies whenincludecontainsdiagnostics. Recommended starting point: 20000 bytes.diagnostics_data_path: Optional dotted path into the diagnostics
datasub-tree (e.g."data.devices"for ZHA per-device records). Walks into the post-fields payload. Resolution failures replacedatawithnulland surfacedata_path_error. Only applies whenincludecontainsdiagnostics.diagnostics_data_offset / diagnostics_data_limit: Pagination on list-valued
diagnostics_data_pathresults. Whendata_limitis set and the resolved path is a list,databecomes{"path", "items", "offset", "limit", "total", "has_more"}. Only applies whenincludecontainsdiagnostics.Example workflow (walk a list-valued sub-tree one page at a time; the exact
data_pathvaries by integration version):ha_get_system_health(include="diagnostics", config_entry_id="abc", diagnostics_data_path="<list-valued path>", diagnostics_data_limit=10)โ inspect the page envelope'stotal/has_moreโ repeat withdiagnostics_data_offset=10for the next slice.
| Name | Required | Description | Default |
|---|---|---|---|
| include | No | ||
| device_id | No | ||
| config_entry_id | No | ||
| diagnostics_fields | No | ||
| diagnostics_data_path | No | ||
| diagnostics_data_limit | No | ||
| diagnostics_data_offset | No | ||
| include_dismissed_repairs | No | ||
| diagnostics_truncate_at_bytes | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The annotations already indicate readOnlyHint, openWorldHint, and idempotentHint=true. The description adds significant behavioral context, including the return of the ha_mcp_update object, caveats about payload sizes for diagnostics, and that operations like config_check are read-only and idempotent. No contradictions with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is lengthy due to the tool's complexity, but it is well-structured with a clear lead sentence, a separate paragraph for the ha_mcp_update object, and bullet-point-like explanations for include options. While every sentence earns its place, some redundancy exists (e.g., repeating 'Only applies when include contains diagnostics'). Minor trimming could improve conciseness.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity (9 parameters, no schema coverage, no enums), the description is exceptionally complete. It covers all parameters, explains return values (including the ha_mcp_update object), provides workflow examples, and addresses edge cases (e.g., omission when version is unknown or HA_MCP_DISABLE_UPDATE_CHECK set). The presence of an output schema does not reduce the need for this detail, and the description delivers.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With 0% schema coverage, the description fully explains all 9 parameters. It lists every possible value for include, describes the behavior of each parameter (e.g., diagnostics_data_path, diagnostics_truncate_at_bytes), provides examples, and clarifies dependencies (e.g., config_entry_id required for diagnostics). This exceeds the minimum required and compensates for the lack of schema descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's purpose: 'Get Home Assistant system health, including Zigbee (ZHA), Z-Wave JS, and per-integration diagnostics dumps.' It specifies the resource (system health) and the specific integrations covered, effectively distinguishing it from sibling tools that focus on individual integrations or other aspects.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit usage guidance for specific include options, such as 'Use this when triaging integration bugs or filing ha_report_issue for a specific integration' for diagnostics. It also hints at appropriate contexts for other options like dead_entities. However, it lacks a general statement on when to use this tool versus alternatives, which would improve clarity.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_get_todoGet TodoARead-onlyIdempotent
Get todo lists or items - list all todo lists or get items from a specific list.
Without an entity_id: Lists all todo list entities in Home Assistant. With an entity_id: Gets items from that specific todo list, optionally filtered by status.
LISTING TODO LISTS (entity_id omitted): Returns all entities in the 'todo' domain, including shopping lists and any other todo-type integrations.
Each todo list includes:
entity_id: The unique identifier (e.g., 'todo.shopping_list')
friendly_name: Human-readable name
state: Number of incomplete items or current status
GETTING TODO ITEMS (entity_id provided): Retrieves items from the specified todo list.
Status filter values:
needs_action: Items that still need to be done
completed: Items that have been marked as done
None (default): Returns all items regardless of status
Item properties:
uid: Unique identifier for the item
summary: The item text/description
status: Current status (needs_action or completed)
description: Optional detailed description
due: Optional due date (if supported)
EXAMPLES:
List all todo lists: ha_get_todo()
Get all items: ha_get_todo("todo.shopping_list")
Get incomplete items: ha_get_todo("todo.shopping_list", status="needs_action")
Get completed items: ha_get_todo("todo.shopping_list", status="completed")
USE CASES:
"What todo lists do I have?"
"Show me my shopping list"
"What's on my todo list?"
"Show completed items"
| Name | Required | Description | Default |
|---|---|---|---|
| status | No | Filter items by status: 'needs_action' for incomplete, 'completed' for done. Only applies when entity_id is provided. | |
| entity_id | No | Todo list entity ID (e.g., 'todo.shopping_list'). If omitted, lists all todo list entities. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already provide readOnlyHint=true and idempotentHint=true. The description adds behavioral details: the two modes, return structures (entity_id, friendly_name, state for lists; uid, summary, status, description, due for items), and how the status filter works. No contradictions.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured with headings, bullet points, and examples. It is front-loaded with a clear summary. While somewhat lengthy, every section adds value, and the structure aids readability.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool complexity (two modes) and high schema coverage, the description covers the tool's behavior, return structure, and common use cases. It does not rely on an output schema (though one exists) but explains return values explicitly. No critical gaps.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3. The description adds value by explaining the effect of each parameter (e.g., 'entity_id' lists all lists when omitted, 'status' filter values with defaults) and provides examples that clarify usage beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool gets todo lists or items, with two distinct modes: listing all lists (no entity_id) and getting items from a specific list (with entity_id). It is specific, uses a verb+resource structure, and distinguishes from sibling tools like ha_remove_todo_item or ha_set_todo_item.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly explains when to omit vs. provide entity_id, and optionally filter by status. It includes examples and use cases. It does not explicitly mention when not to use this tool vs. mutation siblings, but annotations (readOnlyHint=true) and the read-only nature make it clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_get_zoneGet ZoneARead-onlyIdempotent
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.
ZONE PROPERTIES:
ID, name, icon
Latitude, longitude, radius
Passive mode setting
EXAMPLES:
List all zones: ha_get_zone()
Get specific zone: ha_get_zone(zone_id="abc123")
NOTE: 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.
| Name | Required | Description | Default |
|---|---|---|---|
| zone_id | No | Zone ID to get details for (from ha_get_zone() list). If omitted, lists all zones. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already mark the tool as readOnlyHint=true and idempotentHint=true. The description adds valuable context beyond that, such as listing zone properties, the behavior difference between with/without zone_id, and a detailed note about YAML-defined vs storage zones depending on component installation. No contradictions.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured: clear main statement, bulleted list of properties, examples, and a note. Every sentence serves a purpose without redundancy. It is concise yet comprehensive.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the presence of an output schema, the description does not need to detail return values. It covers input behavior, properties, and special considerations. For a read-only tool with one optional parameter, this is complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% for the single parameter. The description reinforces the parameter's role: 'Zone ID to get details for... If omitted, lists all zones.' This adds clarity beyond the schema's description, and examples illustrate usage. A score of 4 reflects the added value while acknowledging the schema already does heavy lifting.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's purpose: 'Get zone information - list all zones or get details for a specific one.' It distinguishes two modes based on the presence of a zone_id, and the title 'Get Zone' directly maps to reading operations, differentiating it from siblings like ha_remove_zone or ha_set_zone.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly explains when to use each mode: 'Without a zone_id: Lists all Home Assistant zones... With a zone_id: Returns detailed configuration for a specific zone.' It also provides examples. However, it does not explicitly mention when not to use this tool or suggest alternatives among siblings, which would improve the score.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_list_floors_areasList Floors and AreasARead-onlyIdempotent
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. Optionally project the response with fields= (top-level keys) or area_fields= (per-area-record keys, applied uniformly across nested, unassigned, and orphaned buckets).
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.
| Name | Required | Description | Default |
|---|---|---|---|
| fields | No | Return only the specified top-level response keys to reduce response size (e.g. ["floors"]). None = full response (default). Available keys: success, floor_count, area_count, unassigned_count, orphaned_count, floors, unassigned_areas, orphaned_areas, message. | |
| area_fields | No | Project each area record (in floors[].areas, unassigned_areas, and orphaned_areas) to only the specified keys. E.g. ["area_id", "name"] returns slim area records. None = full records (default). Unknown keys yield empty records. Available keys: area_id, name, icon, floor_id, aliases, picture, labels. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and idempotentHint=true. The description goes far beyond by detailing sorting order, handling of level=None, unassigned and orphaned areas, consistency guarantees with registries, and a legacy path caveat. This provides extensive behavioral context that annotations alone do not cover.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured and front-loaded with the core purpose. It is somewhat lengthy (5 sentences plus a paragraph on consistency), but each part contributes necessary behavioral detail. Could be slightly more concise, but it remains clear and informative.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the complexity (floors, nested areas, unassigned, orphaned) and the presence of an output schema, the description covers all essential aspects: sorting, level handling, edge cases (None floors, orphaned areas), consistency guarantees, and response projection. No gaps are apparent.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% with detailed descriptions for both parameters. The description adds value by explaining how to project responses with fields= and area_fields=, giving examples (e.g., ['area_id', 'name']), and listing available keys. It enhances understanding beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description explicitly states 'List floors sorted by level ascending, each with their assigned areas nested, plus areas without a floor.' It uses a specific verb ('list') and resource ('floors and areas'), and the unique scope (nested areas, unassigned, orphaned) clearly distinguishes it from sibling tools that handle individual entities or different domain objects.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit usage context: '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.' It gives concrete use cases but does not explicitly state when not to use it or offer alternatives, though the sibling tool list implies other tools for other purposes.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_list_servicesList Available ServicesARead-onlyIdempotent
List available Home Assistant services with optional pagination and detail control.
Discovers services/actions that can be called via ha_call_service. Use domain or query filters to narrow results. Defaults to summary mode (name + description only) to keep responses compact.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Max services to return per page (default: 50) | |
| query | No | Search in service names and descriptions. | |
| domain | No | Filter by domain (e.g., 'light', 'switch', 'climate'). | |
| fields | No | Return only the specified top-level response keys to reduce response size (e.g. ["services"]). None = full response (default). Available keys: success, domains, services, total_count, count, offset, limit, has_more, next_offset, detail_level, filters_applied. | |
| offset | No | Number of services to skip for pagination (default: 0) | |
| detail_level | No | 'summary': service name + description only (default). 'full': include parameter field schemas. | summary |
| service_fields | No | Project each service record to only the specified keys. E.g. ["name", "description"] returns slim service records. None = full records (default). Unknown keys yield empty records. Available keys: name, description, domain, service, fields (full mode only), target (full mode only). |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations provide readOnlyHint and idempotentHint, so the safety profile is clear. The description adds context about pagination, response control, and the relationship to ha_call_service, which goes beyond the annotations without contradicting them.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is three sentences with no fluff. The first sentence defines action and options, the second links to another tool, and the third gives usage defaultsโefficient and front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity (7 parameters, pagination, filtering, and an output schema), the description covers all essential aspects: what the tool does, how to narrow results, detail control, and its role in the service call workflow. No important context is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3. The description summarizes key parameters (domain and query filters, detail level) but doesn't add significant new meaning beyond what the schema already provides for each parameter.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool lists available Home Assistant services with optional pagination and detail control. It distinguishes itself from sibling tools like ha_call_service by noting that it discovers services that can be called, making the purpose unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description advises using domain or query filters to narrow results and defaults to summary mode for compact responses. It implicitly guides usage before calling services but does not explicitly state when not to use it or list alternatives, though no direct alternative exists among siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_manage_appManage App (add-on)ADestructive
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.
Do not infer private app API schemas; consult version-matched app docs,
and use ha_get_skill_guide for complex Home Assistant workflows.
Use exactly one mode: lifecycle/store action, configuration fields,
path proxy, or path with array_patch.
Requires Home Assistant OS or Supervised. options merges top-level
keys and one nested mapping level; supply complete values for deeper nested
mappings because they are replaced. A non-empty network replaces the
full port override map. 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.
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
| Name | Required | Description | Default |
|---|---|---|---|
| body | No | Proxy mode only. Request body for POST/PUT/PATCH โ or, with websocket=True, the initial WebSocket message. Pass a JSON object or JSON string. | |
| boot | No | Config mode: Boot strategy โ 'auto' (start with HA) or 'manual'. | |
| path | No | Proxy mode: API path relative to the app (add-on) root (e.g., '/flows', '/api/events', '/api/stats'). Required for proxy mode; mutually exclusive with config parameters. | |
| port | No | Proxy mode only. Connect to this port instead of the Ingress port. Use ha_get_app(slug='...') to find available ports. Some apps, including Node-RED, reject direct access unless their leave_front_door_open option is enabled and the app is restarted; related errors include an actionable, security-qualified ha_manage_app options command. | |
| slug | No | App (add-on) slug (e.g., '<prefix>_nodered', '<prefix>_frigate'). Slug prefixes vary by app repository โ call ha_get_app() to discover the actual installed slug. Required for every mode except the store-repository actions (action='add_repository'/'remove_repository'), which use 'repository' instead and take no slug, and the store-wide action (action='check_updates'), which takes neither. | |
| debug | No | Proxy mode only. Include diagnostic info (request URL, headers sent, response headers). Default: false. | |
| limit | No | Proxy mode only. HTTP: return at most this many items from a JSON array response. | |
| action | No | Lifecycle mode: run a Supervisor app (add-on) action. One of 'install', 'uninstall', 'start', 'stop', 'restart', 'rebuild', 'update'. 'install'/'update' require the app's repository to be registered (it appears in ha_get_app(source='available')). Store-repository mode: 'add_repository' / 'remove_repository' register or unregister a custom app store repository โ these use the 'repository' param instead of 'slug'. Store-wide mode: 'check_updates' reloads the store so Supervisor re-scans its repositories, mirroring the Apps UI 'Check for updates' item โ it takes neither 'slug' nor 'repository', refreshes available metadata only, and installs nothing. Use it to pick up an edited local app's config.yaml on demand instead of waiting for Supervisor's own reload (every 3h). Follow with action='update' to install a new version, or action='rebuild' for a local app whose source changed but whose version did not. Returns 'changed' and 'updates_available', each null (not empty) if the store could not be read to measure it โ check 'warnings'. When ha-mcp runs as an app, it can update other apps but cannot update its own running slug; update ha-mcp from the Home Assistant Apps UI. Mutually exclusive with path / config parameters / array_patch. HA OS / Supervised only. | |
| method | No | Proxy mode only. HTTP method: GET, POST, PUT, DELETE, PATCH. Defaults to GET. | GET |
| offset | No | Proxy mode only. HTTP: skip this many items in a JSON array response. Default: 0. | |
| network | No | Config mode: Complete desired host-port override map (e.g., {'5800/tcp': 8081}). A non-empty map replaces current overrides, so omitted entries are cleared. Omit 'network' to leave mappings unchanged. An empty map is ignored and does not by itself select config mode. | |
| options | No | Config mode: App (add-on) configuration values (the 'Configuration' tab in the UI). | |
| watchdog | No | Config mode: Enable or disable Supervisor watchdog (auto-restart on crash). | |
| summarize | No | Proxy mode only. WebSocket: when True (default), collapse runs of non-signal messages (typically YAML config dumps) into short elision markers. Set to False to return the raw stream. | |
| websocket | No | Proxy mode only. Use WebSocket instead of HTTP for an app (add-on) WebSocket API. Sends 'body' as the initial message and collects responses; command names and body schemas are app/version-specific. Default: false. | |
| repository | No | Store-repository mode only (action='add_repository' or 'remove_repository'). For add_repository: the repository URL (e.g., 'https://github.com/balloob/home-assistant-addons'). For remove_repository: the repository slug (e.g., '0f1cc410', as shown in ha_get_app(source='available')). Required for those actions; rejected otherwise. | |
| array_patch | No | Array-patch mode: atomically GET a JSON array endpoint, apply ordered ops, then POST the mutated array back. Requires 'path'; mutually exclusive with body / websocket / offset / limit and config params. Use ha_get_skill_guide for operation shapes. | |
| auto_update | No | Config mode: Enable or disable automatic updates for this app (add-on). | |
| message_limit | No | Proxy mode only. WebSocket: cap on messages collected from the wire, bounded by an internal safety ceiling. None = collect up to the ceiling. Lower to save tokens on noisy streams (e.g., message_limit=50 for a quick health check). | |
| message_offset | No | Proxy mode only. WebSocket: drop this many messages from the start of the collected list before returning. Useful for paginating past known-noisy headers. Default: 0. | |
| wait_for_close | No | Proxy mode only. WebSocket: True waits for the server to close a run-to-completion stream. False returns after the first response batch; use for one-shot command/response or bounded capture on a channel that stays open. Default: true. | |
| request_headers | No | Proxy/array-patch mode: extra HTTP headers for the app (add-on) API. Useful for app-specific requirements such as Node-RED's `Node-RED-Deployment-Type: full`. Ingress routing headers override caller values on Ingress routes; direct-port calls have no internal routing headers. `Content-Type` is derived from the body when supplied. Not valid in config or websocket mode. | |
| python_transform | No | Proxy mode only. Sandboxed Python expression that post-processes the response. Variable `response` is exposed โ a list[dict | str] for WebSocket (parsed JSON or raw text), or dict/list/str for HTTP (parsed body). Supports in-place mutation (response.append(...)) or reassignment (response = [...]). Example: response = [m for m in response if 'ERROR' in str(m)]. Post-processing only โ does not provide optimistic-locking write semantics. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the destructiveHint/openWorldHint annotations, the description discloses merge/replace semantics for options and network, warns that a non-empty network map replaces the full port override map, and explains that restart/rebuild outcomes cannot be verified via ha_get_app. It also advises checking Supervisor jobs/logs and target app read APIs before retrying uncertain writes. No contradiction with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The prose is front-loaded and organized, but the description is very long and ends in a keyword dump ('manage app apps addon add-on ...') that adds no semantic value for an agent. Several dense sentences could be tightened, though the complexity of 23 parameters justifies much of the length.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 23-parameter tool with multiple mutually exclusive modes, the description covers prerequisites, mode selection, mutual exclusions, retry/verification behavior, and open-world caveats. An output schema exists, so return values do not need to be explained, and nothing essential for selecting and invoking the tool appears missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Even though schema coverage is 100%, the description adds significant parameter-level meaning: slug discovery via ha_get_app, port caveats for Node-RED, action='check_updates' store-reload semantics, array_patch atomic GET-POST behavior, and request_headers overrides. This goes well beyond the schema's per-field descriptions and materially improves correct invocation.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a clear verb-resource pair ('Manage Home Assistant apps (add-ons) or proxy an app API') and enumerates concrete modes: lifecycle/store action, configuration fields, path proxy, or path with array_patch. It differentiates itself from ha_get_app by directing inventory/status reads to that sibling, so an agent can tell what this tool is and is not.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly says to call ha_get_app first for inventory/status/metadata and to use proxy mode here only for documented app-specific read APIs. It also names ha_get_skill_guide for complex workflows, warns against inferring private schemas, and states the platform prerequisite (HA OS or Supervised). This gives clear when-to-use and when-not-to-use guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_manage_backupManage BackupsADestructive
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 |
|
| 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. |
|
| List full HA tarball snapshots (id, name, date, size). Read-only โ use to discover a |
|
| Restore a full HA tarball. Restarts HA. Last-resort recovery. |
|
| Delete one full HA tarball by |
|
| On-demand snapshot of one entity ( |
|
| List per-entity auto-backups (lightweight). Filter by |
|
| Read one auto-backup file by name; returns YAML and parsed |
|
| 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. |
|
| Re-apply one auto-backup. Existing Template helpers require a fresh safety snapshot; other domains follow auto-backup settings and may proceed without one. A deleted Template helper is recreated with a new config-entry ID; its saved entity ID is restored if unoccupied. No HA restart. |
|
| Delete one auto-backup by |
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.
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.
Template filters: edits.create accepts a Template 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="kitchen_lights_active")List recent auto-backups for one automation:
ha_manage_backup(scope="edits", action="list", domain="automation", entity_id="kitchen_lights")View an auto-backup:
ha_manage_backup(scope="edits", action="view", backup_name="automation.kitchen_lights.20260521_153000.yaml")Diff an auto-backup vs current state:
ha_manage_backup(scope="edits", action="diff", backup_name="automation.kitchen_lights.20260521_153000.yaml")Restore an auto-backup:
ha_manage_backup(scope="edits", action="restore", backup_name="automation.kitchen_lights.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)
| Name | Required | Description | Default |
|---|---|---|---|
| name | No | (snapshot.create) Tarball name. Auto-generated if not provided. | |
| limit | No | (edits.list / snapshot.list) Maximum number of entries to return. | |
| scope | Yes | 'snapshot' for full HA tarballs; 'edits' for per-entity auto-backups. | |
| action | Yes | Operation to perform. Valid (scope, action) combinations are listed in the tool description. | |
| domain | No | (edits.create / edits.list / edits.delete) Filter auto-backups by domain (e.g. 'automation', 'helper_timer'). Required for edits.create. | |
| confirm | No | (snapshot.delete) Must be True to confirm deletion โ a safety measure against accidental calls. | |
| backup_id | No | (snapshot.restore / snapshot.delete) Tarball ID (e.g. 'dd7550ed'). | |
| entity_id | No | (edits.create / edits.list / edits.delete) Filter auto-backups by entity ID. Required for edits.create. | |
| backup_name | No | (edits.view / edits.restore / edits.delete) Auto-backup filename (format '<domain>.<entity_id>.<timestamp>[_NN].yaml'). Not a tarball ID. | |
| older_than_days | No | (edits.delete) Bulk-delete auto-backups older than this many days. | |
| restore_database | No | (snapshot.restore) Include database in the restore. Default false (config-only). |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the sparse annotations, the description discloses that snapshot create can take a while with progress heartbeats, restore restarts HA, delete has layered guards, and edits.create bypasses the auto-backup toggle. It also explains Template helper recreation side effects, config-entry ID mapping, and that diff is read-only. The destructiveHint annotation is consistent with the restore and delete operations, so there is no contradiction.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but earns its length with a compact scope/action table, focused sections on usage, safety guards, toggle behavior, Template filters, and examples. It is front-loaded with the most important discriminator, scope, and each section maps to a distinct decision the agent needs to make.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For an 11-parameter tool with two scopes and six actions, the description fully specifies valid combinations, prerequisites, safety gates, side effects, and examples. With an output schema present, return-value details are unnecessary, but everything else an agent needs to invoke the tool correctly is provided.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema already covers all 11 parameters, and the description adds substantial cross-parameter meaning: valid scope/action combinations, backup_name filename format and warning that it is not a tarball ID, confirm=True requirements, older_than_days bulk behavior, and Template entity ID mapping caveats. This goes well beyond the schema's per-property descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a precise verb and resource: Manage Home Assistant backups, covering both full HA snapshots and per-edit auto-backups. It then enumerates every valid scope/action pair in a table with concrete behaviors, making the tool's purpose unmistakable and easily distinguishable from any backup-related ambiguity.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly says when to use scope edits to undo recent agent edits versus scope snapshot for system-wide recovery, and states that the backup-hint is usually unnecessary if the current definition can be fetched. It also documents when deletion is refused and that snapshot delete is off by default unless a human enables it, providing clear when-to and when-not-to guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_manage_blueprintsManage BlueprintsADestructive
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.
Use action="list" to discover installed blueprints, action="get"
for one blueprint's metadata, inputs and YAML, action="import" to
install one from a URL, action="save" to write YAML text to a
blueprint path, action="delete" to remove an installed one, and
action="substitute" to render a blueprint plus inputs into a
standalone config (the UI's "Take control"). 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, 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. save needs overwrite=True to replace an existing
path and reloads every automation/script using it. delete requires
confirm=True, and Home Assistant refuses it while any automation or
script still uses the blueprint โ the error lists the consumers. 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 ha_config_set_automation / ha_config_set_script with
take_control_of_blueprint=True: it renders with that item's own
current inputs and saves the result over itself in one call, where
substitute would need those inputs restated and the config written
back by hand. Taking control does NOT free the blueprint โ Home
Assistant goes on counting a converted automation or script as a user
of it, so delete stays refused until the consumers are removed.
EXAMPLES:
List: ha_manage_blueprints(action="list", domain="automation")
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")
Duplicate: ha_manage_blueprints(action="save", path="user/my_copy.yaml", 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)
Detach: ha_manage_blueprints(action="substitute", path="user/motion.yaml", input={"motion_sensor": "binary_sensor.hall"})
Convert an existing consumer to a standalone config: ha_config_set_automation(identifier="automation.hall", take_control_of_blueprint=True)
RELATED TOOLS: ha_config_set_automation / ha_config_set_script
to build on a blueprint or persist a substituted config,
ha_config_remove_automation / ha_config_remove_script to clear
consumers blocking a delete, ha_search to find them, and
ha_manage_backup(scope="edits") to restore a deleted blueprint.
blueprint blueprints import delete remove unused substitute take-control list ha_get_blueprint ha_import_blueprint
| Name | Required | Description | Default |
|---|---|---|---|
| url | No | URL to import from โ GitHub, Home Assistant Community, or a direct YAML link (action='import') | |
| path | No | Installed blueprint path, e.g. 'homeassistant/motion_light.yaml' (action='get' / 'save' / 'delete' / 'substitute'). 'save' appends '.yaml' when it is missing, as Home Assistant does. | |
| yaml | No | Blueprint YAML text to write (action='save') | |
| input | No | Blueprint input values keyed by input name (action='substitute'); defaults to {} | |
| action | Yes | 'list' installed blueprints, 'get' one blueprint's metadata/inputs/YAML, 'import' one from a URL, 'save' YAML text to a blueprint path, 'delete' an installed one, or 'substitute' to render a standalone config | |
| domain | No | Blueprint domain: 'automation' or 'script'. Ignored by action='import' โ the blueprint file declares its own domain. | automation |
| confirm | No | Required confirmation for action='delete' | |
| overwrite | No | Write over an already-installed blueprint (action='import' / 'save'). Home Assistant reloads every automation/script using it. | |
| source_url | No | Origin URL to stamp into the saved blueprint's metadata (action='save'); omit for a hand-authored blueprint |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare destructiveHint=true and readOnlyHint=false, and the description goes far beyond that: it details overwrite behavior, reload side effects, confirmation requirements, snapshotting for backup, refusal of delete while consumers exist, the conditions under which 'get' returns YAML, and the fact that 'substitute' writes nothing. It even explains the non-obvious persistence of consumer counts after taking control. This is exemplary transparency with no contradictions.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Despite being long, the description is tightly structured with clear sections (main description, CAVEATS, EXAMPLES, RELATED TOOLS). Every sentence earns its placeโno filler. The core purpose is front-loaded, and the detailed caveats are logically organized. For a tool with 9 parameters and 6 actions, this length is justified and well-presented.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity, the description covers all actions, all parameters, edge cases, side effects, prerequisites, and related tools. It includes practical examples for every action and explains subtle behaviors like the 'take control' caveat. The presence of an output schema presumably documents return values, so nothing an agent needs to call this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so each parameter is already documented, but the description adds substantial semantic context: the interplay between actions and parameters (e.g., overwrite for save/import, confirm for delete), the meaning of yaml_source, how to duplicate via get+save, and domain being ignored by import. It also gives concrete examples that map parameters to actions. This far exceeds the baseline 3 for high coverage.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource ('Manage Home Assistant blueprints') and enumerates all six actions (list, read, import, save, delete, substitute). It explicitly distinguishes itself from sibling tools like ha_config_set_automation/ha_config_set_script, clarifying that it does not create automations from blueprints. This fully resolves the purpose.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit when-to-use and when-not-to-use guidance, naming alternatives: '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.' It also explains preferred approaches for converting existing consumers and references related tools for cleanup. Nothing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_manage_energy_prefsManage Energy Dashboard PreferencesADestructive
Manage the Home Assistant Energy Dashboard preferences.
The Energy Dashboard configuration (grid/solar/battery/gas/water energy
sources, individual device consumption sensors for electricity and
water, cost tariffs) is stored in .storage/energy and not otherwise
reachable via REST, services, or helper flows โ this tool is the only
way for agents to inspect or modify it.
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; the caller does NOT manage config_hash. Use
water=Trueto target the water meter list instead of electricity.mode='add_source': append a single entry to
energy_sources(grid, solar, battery, gas, or water). Same atomic read-modify-write semantics.
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.
CAVEATS:
energy/save_prefshas per-key FULL-REPLACE semantics. Passing{"device_consumption": [<one entry>]}deletes every other device the user had configured โ silently, with no error. mode='set' requires a freshconfig_hashfor optimistic locking; convenience modes hide this entirely.config_hashaccepts both a singlestr(full-blob lock) and adict[_PrefsKey, str]keyed by top-level keys (per-key lock, taken from theconfig_hash_per_keyfield of the mode='get' response). The per-key form lets an agent submit only the top- level key it wants to change โ set-equality betweenconfigkeys and dict keys is enforced, and any key outside the canonical set (typo, etc.) on either side is rejected withVALIDATION_FAILEDrather than silently dropped (so an empty submission cannot succeed as a no-op). A per-key submission still fully replaces that key's value as the save endpoint requires. Mismatch on any locked key returnsRESOURCE_LOCKEDwith the offending keys in the response's top-levelmismatched_keys(create_error_responseflattens thecontextdict onto the response root).dry_run=Trueskips the hash check entirely for both forms; the per-key form is therefore silently accepted on dry runs even if its keys would mismatch the current state.A local shape check runs before every write; malformed payloads are rejected with a
shape_errorslist.After a successful write, the tool calls
energy/validateand returns any residual issues aspost_save_validation_errorsin the response. These reflect semantic problems (missing stats, unit mismatches) that shape checks can't catch; the save persists regardless โ correct the config and write again if needed.The underlying save endpoint is admin-only. Non-admin tokens will receive an authorization error from Home Assistant.
Convenience modes are NOT idempotent: 'add_device' on an existing
stat_consumptionreturns RESOURCE_ALREADY_EXISTS; 'remove_device' on a missing entry returns RESOURCE_NOT_FOUND. 'add_source' rejects duplicates by(type, stat_energy_from)for solar/battery/gas/water (RESOURCE_ALREADY_EXISTS); grid entries are appended without a duplicate check (multiple grid variants are legitimate, and grid has no single canonical uniqueness key) โ the caller is responsible for de-duplicating grid sources.Convenience modes do NOT bypass the local shape check on dry_run:
dry_run=Truestill raisesRESOURCE_ALREADY_EXISTS(duplicate add_device / add_source),RESOURCE_NOT_FOUND(missing remove_device), orVALIDATION_FAILED(post-mutator shape error) when the proposed mutation is not applicable. The mutator and shape check both run before the dry-run short-circuit.
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
| Name | Required | Description | Default |
|---|---|---|---|
| mode | Yes | Operation mode. Primitives: 'get' reads the current prefs; 'set' writes a full prefs payload (per-top-level-key full-replace). Convenience modes: 'add_device' / 'remove_device' / 'add_source' perform a single read-modify-write atomically โ no config_hash from the caller, the tool fetches it fresh internally. | |
| name | No | Optional display name for mode='add_device'. Only used when adding a new device entry; ignored otherwise. | |
| water | No | If True, mode='add_device' / 'remove_device' targets 'device_consumption_water' instead of 'device_consumption'. Default False. | |
| config | No | Full prefs payload for mode='set'. Must contain the top-level keys you intend to replace: 'energy_sources', 'device_consumption', 'device_consumption_water'. Any top-level key present in this payload REPLACES the existing list entirely; any omitted key is preserved. Call with mode='get' first, mutate the returned config, then pass the whole object back. Ignored by convenience modes. | |
| source | No | Single energy_sources entry for mode='add_source'. Must contain 'type' (one of grid|solar|battery|gas|water) and the type-specific required fields (e.g. solar/battery/gas/water require 'stat_energy_from'). Every source type also accepts an optional 'name' (display label in the energy graphs); battery additionally accepts 'stat_soc' (state-of-charge statistic). Note: HA Core's voluptuous schema for grid sources requires the full field set (cost_adjustment_day, stat_energy_to, stat_cost, entity_energy_price, number_energy_price, entity_energy_price_export, number_energy_price_export, stat_compensation) โ the local shape check is narrower, so a minimal {'type': 'grid'} passes locally but surfaces in post_save_validation_errors after writing. Pass the unused fields as None to satisfy the server. Required for mode='add_source'; ignored otherwise. | |
| dry_run | No | If True, no write is performed. For mode='set': runs a local shape check on the proposed config AND calls the server's energy/validate against the CURRENT persisted state (Home Assistant's validate endpoint cannot validate an unsubmitted payload). For convenience modes: simulates the mutation against a fresh read and reports what would change without writing โ but still raises RESOURCE_ALREADY_EXISTS (duplicate add_device, or duplicate add_source for solar/battery/gas/water), RESOURCE_NOT_FOUND (missing remove_device), or VALIDATION_FAILED (post-mutator shape error) when the proposed mutation is not applicable. Default False. | |
| config_hash | No | Hash from a previous mode='get' call. REQUIRED for mode='set' unless dry_run=True. Two forms: str (full-blob lock) or dict (per-key lock, taken from the config_hash_per_key field of mode='get'). Pass the dict form as a native object, NOT a JSON-encoded string โ a stringified dict is treated as a full-blob token and will report RESOURCE_LOCKED; clients that can only send strings should use the str full-blob form. See the tool docstring for fail-closed semantics. Ignored by convenience modes. | |
| included_in_stat | No | Optional 'parent' statistic for mode='add_device'. Set this to a statistic that already INCLUDES this device's consumption (e.g., a whole-home or circuit-level meter that this device feeds into). The Energy Dashboard will subtract this device's reading from the parent so the parent's contribution is not double-counted. Ignored otherwise. | |
| stat_consumption | No | Statistic entity_id for mode='add_device' / 'remove_device' (e.g. 'sensor.fridge_energy'). Required for those modes; ignored otherwise. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Extremely rich disclosure beyond the annotations: per-key FULL-REPLACE semantics with silent deletion of other devices, config_hash locking forms and fail-closed behavior, dry_run skipping the hash check, non-idempotency of convenience modes (RESOURCE_ALREADY_EXISTS/RESOURCE_NOT_FOUND), local shape checks, post-save validation persisting regardless of errors, and admin-only auth. All of this aligns with destructiveHint=true and idempotentHint=false with no contradiction.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but earns its length given the tool's complexity (5 modes, locking, validation, dry-run edge cases). It is well-structured with clear headers and front-loaded purpose. The trailing keyword list adds noise for a human reader, though it likely serves retrieval indexing; a slightly stronger edit would trim it.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a highly complex tool, nothing an agent needs to call it correctly is missing: mode selection, locking semantics, error conditions, prerequisites (statistics must pre-exist), auth requirements, and post-write validation behavior are all covered. Since an output schema exists, the description correctly avoids re-explaining return values and even references response fields like mismatched_keys where relevant.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Despite 100% schema coverage (baseline 3), the description adds substantial meaning beyond the schema: the stringified-dict config_hash gotcha ('a stringified dict is treated as a full-blob token and will report RESOURCE_LOCKED'), the HA Core voluptuous full-field requirement for grid sources, the double-counting semantics of included_in_stat, and dry_run's unusual behavior of still raising validation errors. The schema describes what parameters are; the description explains how they behave.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The first line names a specific verb and resource ('Manage the Home Assistant Energy Dashboard preferences') and immediately enumerates what those preferences are: grid/solar/battery/gas/water sources, device consumption sensors, and cost tariffs. It further distinguishes the tool by stating it is 'the only way for agents to inspect or modify' this config, which is not reachable via REST, services, or helper flows.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit WHEN TO USE and WHEN NOT TO USE sections map each mode to its intended scenario ('Use 'set' for bulk edits...', 'mode='add_device' / 'remove_device': add or remove a single device-consumption entry'). The exclusion is concrete: the tool must not be used to create statistics, which should be created 'via the relevant integration's config flow first'. The claim that this is the only path to the energy config implicitly differentiates it from all dashboard-related siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_manage_hacsManage HACSADestructive
Manage HACS (Home Assistant Community Store) โ install/update, remove, add custom repositories, or refresh repository information.
Use action="download" to install or update a repository,
action="remove" to uninstall a downloaded repository, or
action="add_repository" to register a custom GitHub repository with HACS. 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. repository_id accepts a
numeric HACS ID or an owner/repo path; 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.
| Name | Required | Description | Default |
|---|---|---|---|
| action | Yes | 'download' to install/update, 'add_repository' to register a custom repo, 'remove' to uninstall a downloaded repo, or 'update_information' to refresh a repository's release data from GitHub | |
| version | No | Specific version to install (action='download') | |
| category | No | Repository category (action='add_repository') | |
| repository | No | GitHub repo 'owner/repo' to add (action='add_repository') | |
| repository_id | No | Numeric HACS ID or 'owner/repo' path (action='download' / 'remove' / 'update_information') |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the destructiveHint and openWorldHint annotations, the description adds crucial caveats: the need for restart after installing integrations, browser cache clearing for Lovelace cards, the fact that removing an integration leaves the module loaded until restart, and the 48-hour refresh interval. This context is not inferred from annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but well-structured with a summary, examples, and caveats. Every sentence adds value, though it could be slightly tightened without losing critical information. It is not needlessly verbose for the tool's complexity.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
All actions, parameter combinations, and edge cases are covered. The caveats address real-world operational concerns, and the presence of an output schema means return values need not be explained. The description is self-sufficient for an agent to select and invoke the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
While the schema documents each parameter, the description adds meaningful semantics: it maps actions to parameters, clarifies that repository_id accepts numeric or owner/repo, and explains that add_repository requires owner/repo plus a matching category. Concrete examples illustrate correct usage beyond the schema's field descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool manages HACS with specific actions: install/update, remove, add repositories, and refresh. It also distinguishes itself from the read-only sibling tool ha_get_hacs_info, making its purpose unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit when-to-use guidance: it names ha_get_hacs_info as the alternative for search/read, and explains when to use each action (e.g., update_information to surface a recent release because HACS refreshes every ~48 hours). This goes beyond mere function listing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_manage_pipelineManage Assist PipelineADestructive
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. pipeline_id borrows a pipeline's conversation agent and language, but the sentence still 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:
List pipelines: ha_manage_pipeline(action="list")
Get one pipeline: ha_manage_pipeline(action="get", pipeline_id="preferred")
Create by cloning preferred: ha_manage_pipeline( action="create", name="Local Assist", conversation_engine="conversation.local_llm", )
Create by cloning a specific pipeline: ha_manage_pipeline( action="create", base_pipeline_id="preferred", name="Local Assist", conversation_engine="conversation.local_llm", )
Update conversation agent and clear TTS voice: ha_manage_pipeline( action="update", pipeline_id="preferred", conversation_engine="conversation.local_llm", tts_voice="", )
Set preferred: ha_manage_pipeline( action="set_preferred", pipeline_id="preferred", )
Run a sentence: ha_manage_pipeline( action="process", sentence="turn on the kitchen light", )
Run it 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="", )
Empty string clears nullable STT/TTS/wake-word fields. Non-nullable fields such as name, language, conversation_language, and conversation_engine must be omitted or non-empty.
| Name | Required | Description | Default |
|---|---|---|---|
| name | No | Pipeline display name. Required when action='create'. | |
| action | Yes | Pipeline operation: list, get, create, update, set_preferred, or process. | |
| agent_id | No | For process only, the conversation agent entity ID to answer, e.g. 'conversation.home_assistant'. Overrides the agent taken from pipeline_id; omit both for the default agent. | |
| language | No | Pipeline language, e.g. 'en'. For process, the language to recognise the sentence in. | |
| sentence | No | Natural-language command to run through Assist. Required when action='process'. A matched intent executes, and with the built-in agent a sentence matching a conversation trigger runs that automation. | |
| tts_voice | No | Text-to-speech voice. Pass empty string to clear. | |
| stt_engine | No | Speech-to-text engine. Pass empty string to clear. | |
| tts_engine | No | Text-to-speech engine. Pass empty string to clear. | |
| pipeline_id | No | Assist pipeline ID. Required for get, update, and set_preferred. Optional for process, where it selects the conversation agent and language that pipeline is configured with. | |
| stt_language | No | Speech-to-text language. Pass empty string to clear. | |
| tts_language | No | Text-to-speech language. Pass empty string to clear. | |
| wake_word_id | No | Wake-word ID. Pass empty string to clear. | |
| make_preferred | No | For create/update only, also set the resulting pipeline as preferred with an extra websocket call. Ignored for other actions. | |
| conversation_id | No | For process only, the conversation to continue. Returned in the response so follow-up sentences keep their context. | |
| base_pipeline_id | No | Pipeline ID to clone when creating. Omit to clone the preferred pipeline. Ignored for non-create actions. | |
| wake_word_entity | No | Wake-word entity ID. Pass empty string to clear. | |
| conversation_engine | No | Conversation agent entity ID or engine ID. Required when action='create'. | |
| prefer_local_intents | No | Whether Home Assistant local intents should be preferred before the conversation engine. | |
| conversation_language | No | Conversation language, usually '*'. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations (readOnlyHint=false, destructiveHint=true), the description adds rich behavioral context: it explains that action='process' executes intents ('it turns on the light rather than reporting that it would'), that errors are returned as fields ('does not raise an error'), and that conversation triggers only apply to the built-in agent. It also discloses the empty-string-clearing convention and the extra websocket call for make_preferred. This is far beyond annotation expectations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the action list, then dives into important behavioral nuances and examples. While long, it earns its place by covering six distinct actions and complex edge cases (e.g., agent-specific behavior). The examples are well-organized and labeled. It loses a point for densityโthe process paragraph is a wall of text that could be broken up for easier scanningโbut overall remains efficient for a complex tool.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with 19 parameters and six actions, the description is remarkably complete. It covers error handling ('Assist declining a sentence is an answer, not a tool failure'), agent behavior ('conversation triggers... are not limited to intents'), multiple examples, and the empty-string-clearing convention. The output schema is also present, and the description complements it without redundancy. No gaps identified.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema already has 100% coverage, so baseline is 3. The description adds value beyond the schema by explaining interaction semantics, e.g., that conversation_id is used for follow-ups, base_pipeline_id cloning behavior, and that pipeline_id is required for certain actions. The extensive examples further clarify parameter usage. It doesn't repeat schema descriptions verbatim but adds contextual meaning (e.g., the process action's side effects), so a 4 is warranted.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's purpose: 'Manage Home Assistant Assist pipelines' and then enumerates the six actions (list, get, create, update, set_preferred, process). It distinguishes this tool from its sibling by specifying 'Use ha_call_service to act on an entity directly; use this to test what Assist itself understands.' This is a specific verb+resource with clear scope and sibling differentiation.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly provides usage guidelines with a direct alternative: 'Use ha_call_service to act on an entity directly; use this to test what Assist itself understands.' It also differentiates when to use each action (e.g., 'action="list" to discover pipeline IDs', 'action="process" to run a sentence through Assist'). It further clarifies behavior with the built-in agent versus other agents, giving concrete when-to-use and when-not-to-use guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_manage_radioManage Radios (Z-Wave / Zigbee / Matter / Thread)ADestructive
Manage Home Assistant radios โ Z-Wave, Zigbee, Matter, and Thread.
For read-only inspection prefer ha_get_device / ha_get_system_health, which mirror the 'diagnostics' and 'network_status' actions; use this tool for writes and the active 'ping' probe (unique to this tool). Write actions perform inclusion/commissioning, removal, healing, reconfiguration, firmware updates and credential provisioning.
Caveats: destructive actions (e.g. remove_device, network restore, change_channel, hard_reset, remove_fabric) require confirm=True. 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.
| Name | Required | Description | Default |
|---|---|---|---|
| radio | Yes | Which radio to manage. | |
| action | Yes | Operation to perform. Actions vary per radio; an unknown action returns the supported list for that radio. Common: 'diagnostics', 'network_status', 'ping', 'add'/'commission', 'remove_device', 'reinterview'/'reconfigure', 'firmware_update'. | |
| params | No | Action-specific parameters (e.g. code, pin, channel, property, value). An unknown action returns that radio's supported action list with one-line summaries. | |
| confirm | No | Required (True) to run destructive actions. | |
| device_id | No | Target device (node) for node-scoped actions. | |
| entity_id | No | Resolve the device from this entity for node-scoped actions. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already mark destructiveHint=true. Description adds: destructive actions need confirm=True, long-running actions start and return with long_running=true, and S2 secure inclusion is not scriptable. These details go beyond the annotation signal.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Description is appropriately sized โ three paragraphs with front-loaded purpose and distinction. Every sentence adds meaningful information; no redundancy or fluff.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity (multiple radios, many actions, destructive/long-running behaviors, and output schema existing), the description covers when to use, behavioral caveats, error handling (unknown action returns list), and non-scriptable cases. No gaps remain.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3. Description adds value by explaining that an unknown action returns the supported list for that radio, and that params are action-specific (e.g., code, pin). This extra context justifies above baseline.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states 'Manage Home Assistant radios โ Z-Wave, Zigbee, Matter, and Thread' and distinguishes read-only inspection (prefer other tools) from write actions. It uses specific verb+resource and differentiates from sibling tools like ha_get_device and ha_get_system_health.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly states when to use this tool (writes and ping probe) versus alternatives (read-only inspection via ha_get_device/h_get_system_health). Also provides caveats: destructive actions require confirm=True, long-running actions return immediately, and interactive S2 inclusion is not scriptable.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_manage_themeManage Frontend ThemesADestructiveIdempotent
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})
| Name | Required | Description | Default |
|---|---|---|---|
| mode | No | Which mode the theme applies to when action='set'. Defaults to light. | |
| force | No | action='set_engine_theme' only: skip the expected_current guard and overwrite unconditionally. Leave false unless you intend to discard whatever is stored. | |
| value | No | Frontend user-data theme object when action='set_engine_theme', e.g. {'theme': '', 'dark': False}. An empty dict restores default/auto behavior. Take this verbatim from the warning a screenshot tool emitted. | |
| action | Yes | Theme operation: 'list' installed themes, 'set' the backend default theme, or read/restore the screenshot engine account's own per-user theme with 'get_engine_theme' / 'set_engine_theme' (a different layer from the backend default). | |
| theme_name | No | Theme name when action='set'. Must be an installed theme; 'default' restores the built-in theme, 'none' resets the chosen mode to the built-in default. | |
| expected_current | No | Guard for action='set_engine_theme': the stored theme is read immediately before the write and the write is skipped if it no longer equals this. Omitting this value or passing null both mean 'expect no stored theme', enforced like any other value; the guard is always applied unless force is set. Best-effort, not atomic -- Home Assistant exposes no conditional write, so a change landing between that read and the write is not caught. Pass the expected_current value quoted in the screenshot tool's warning. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description goes well beyond the annotations, explaining that action='set' affects only the backend default and that users with explicit theme choices keep theirs. It also discloses that screenshot-engine theme changes flip live user sessions, that the expected_current guard is best-effort and non-atomic, and that force skips the guard. This is rich, honest behavioral context that does not contradict the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but well-structured with clear sections and examples. It front-loads the core purpose and usage guidance. Some details are repeated from the schema, and the screenshot-engine section is verbose, but the complexity of the tool justifies much of the length.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with four distinct actions, multiple parameter guards, and a screenshot-engine interaction, the description covers all necessary context: when to use, caveats, examples, and behavioral warnings. An output schema exists, so return values do not need to be explained. Nothing essential is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3. The description adds value with concrete examples, guidance to pass value verbatim from screenshot warnings, and clarification of the expected_current guard semantics. It largely reinforces the schema rather than introducing entirely new meaning, so a 4 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly identifies the resource (Home Assistant frontend themes) and the specific operations: listing installed themes, setting the backend default, and managing the screenshot engine account's per-user theme. It also distinguishes itself from related tools like ha_manage_hacs and ha_config_set_yaml by explicitly stating what it is not for.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit 'When NOT to use' and 'When to use' guidance, naming alternatives for editing theme files and installing community themes. It also gives detailed context for when to use each action, including the screenshot-engine scenario.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_manage_updatesManage UpdatesADestructive
Manage Home Assistant updates -- list, read details, batch install, skip, or un-skip.
Covers Core, OS, supervisor, apps (add-ons), device firmware, and HACS update entities. 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.
EXAMPLES:
List all updates: ha_manage_updates()
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"])
RETURNS (action='list'): updates_available, updates, categories, and ha_mcp_update -- this MCP server's own update status {current, latest, update_available}, so a newer ha-mcp release can be flagged.
RETURNS (action='get'): update details, release notes; with include_release_notes=True on Core also breaking_changes.entries[], multi_version_release_notes[], and installed_integrations.
| Name | Required | Description | Default |
|---|---|---|---|
| action | No | 'list' (all pending updates, default), 'get' (details/release notes for one update), 'install' (apply pending updates), 'skip' (hide the offered version), or 'clear_skipped' (re-offer a skipped version). | list |
| backup | No | For install: create a backup before installing where the update entity supports it (apps/add-ons). Default: False. | |
| categories | No | For install: apply every pending update in these categories ('addons', 'hacs', 'devices', 'other'). Mirrors the HA 2026.7 'Update all' button: core/os/supervisor are excluded by design (target those individually via entity_ids) and skipped updates are never included. | |
| entity_ids | No | Update entity_id(s) to act on. 'get' takes exactly one; skip/clear_skipped require at least one; for install, mutually exclusive with categories. | |
| include_skipped | No | For list: include updates that have been skipped (default: False). | |
| include_release_notes | No | For get on a Core update entity: fetch multi-version release notes and breaking changes for all versions between installed and latest (default: False). Adds breaking_changes, multi_version_release_notes, and installed_integrations to the response. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the destructiveHint annotation, the description details that installs run asynchronously, take minutes, and require polling to monitor progress. It also clarifies read-only mode behavior. No contradictions with annotations; this adds significant value.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured with clear sections: overview, scope, behavioral notes, examples, and return documentation. Every sentence adds value, and the key information is front-loaded. No unnecessary verbiage.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity (multiple actions, async execution, categories, return types), the description thoroughly covers all aspects. It explains return formats, mentions the ha_mcp_update status, and provides practical examples. No gaps remain for effective use.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3. The description adds behavioral context beyond the schema, such as mutual exclusivity of entity_ids and categories for install, and the effect of include_release_notes on the response. It enhances understanding of parameter interactions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's purpose: 'Manage Home Assistant updates -- list, read details, batch install, skip, or un-skip.' It lists the covered update domains (Core, OS, supervisor, apps, device firmware, HACS), making the scope explicit. This distinguishes it from sibling tools that handle different aspects of Home Assistant.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explains when to use each action (list, get, install, skip, clear_skipped) and provides examples. It notes read-only mode behavior and asynchronous installs with polling instructions. However, it does not explicitly exclude scenarios or compare to specific sibling tools, which would elevate to a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_reload_coreReload Core ComponentsADestructive
Reload Home Assistant configuration without full restart.
This tool reloads specific configuration components, allowing changes to take effect without restarting the entire Home Assistant instance. This is much faster than a full restart.
Parameters:
target: What to reload. Options:
"all": Reload all reloadable components
"automations": Reload automation configurations
"scripts": Reload script configurations
"scenes": Reload scene configurations
"groups": Reload group configurations
"input_booleans": Reload input_boolean helpers
"input_numbers": Reload input_number helpers
"input_texts": Reload input_text helpers
"input_selects": Reload input_select helpers
"input_datetimes": Reload input_datetime helpers
"input_buttons": Reload input_button helpers
"timers": Reload timer helpers
"templates": Reload template sensors/entities
"persons": Reload person configurations
"zones": Reload zone configurations
"core": Reload core configuration (customize, packages)
"themes": Reload frontend themes
entry_id: Reload a SINGLE config entry (one integration instance) instead of sweeping subsystems โ the fast path after editing a custom component on disk. Pass it alone (leave
targetat its "all" default); combining it with an explicittargetis a validation error. Find the id via ha_get_integration.
Example Usage:
# Reload just automations after editing
ha_reload_core(target="automations")
# Reload all configurations
ha_reload_core(target="all")
# Reload input helpers after adding new ones
ha_reload_core(target="input_booleans")When to Use:
After editing automation/script YAML files
After adding new input helpers via YAML
After modifying customize.yaml
After theme changes
| Name | Required | Description | Default |
|---|---|---|---|
| target | No | all | |
| entry_id | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already indicate destructiveHint=true, so the description adds value by detailing what reload actions are available (target options) and the special behavior of entry_id (fast path for single integration). It does not repeat annotation info, but provides behavioral context beyond it.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is structured with sections, bullet points, and code examples, making it easy to scan. While somewhat lengthy due to the many target options, every sentence earns its place. Could be slightly more concise, but the structure aids comprehension.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool has only 2 parameters (both optional), an output schema exists (so return values are covered), and no nested objects, the description is fully complete. It covers all possible parameter values, usage patterns, and links to sibling tool ha_get_integration for finding entry_id.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema has no descriptions (0% coverage), but the description compensates fully by enumerating all 17 valid target options with explanations, and thoroughly explains entry_id usage including how to find the id and that combining with target is a validation error. This adds critical meaning beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description explicitly states the tool reloads Home Assistant configuration without a full restart, using a specific verb ('reload') and resource ('core components'). It distinguishes from sibling ha_restart by emphasizing speed and avoiding full restart. The extensive target list further clarifies scope.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description includes a dedicated 'When to Use' section listing specific scenarios (e.g., after editing automation YAML, modifying customize.yaml). It also explains entry_id usage and warns against combining it with an explicit target, providing clear guidance on proper invocation.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_remove_area_or_floorRemove Area or FloorADestructiveIdempotent
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.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Area ID or floor ID to delete (use ha_list_floors_areas to find IDs) | |
| kind | Yes | Which registry to delete from: 'area' or 'floor' |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already indicate destructiveHint=true. The description adds valuable context: entities/devices are unassigned (not removed), floors unassign areas, and automations may break. This goes beyond annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Description is concise with no wasted words. Main purpose is front-loaded, followed by necessary details. Every sentence is informative.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's simplicity, presence of output schema, and annotations, the description is complete. It explains side effects, risks, and how to find IDs, meeting all needs for an agent to use correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so parameters are well-documented. The description adds a helpful hint for the id parameter: 'use ha_list_floors_areas to find IDs', which adds value beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states it removes a Home Assistant area or floor, with specific verbs and resource. It distinguishes from sibling tools like ha_set_area_or_floor (create/update) and ha_list_floors_areas (list).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It says what the tool does but does not explicitly tell when not to use or recommend alternatives. It is clear for its intended use but lacks exclusions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_remove_deviceRemove DeviceADestructiveIdempotent
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
This uses the config entry removal which is the safe way to remove devices. If the device has multiple config entries, they must all be removed.
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")
| Name | Required | Description | Default |
|---|---|---|---|
| device_id | Yes | Device ID to remove from the registry |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Describes side effects (removes device entry, may remove associated entities), safe method (config entry removal), and multiple config entry requirement. Adds context beyond annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Concise, well-structured with warning, bullet points, example, and alternative. Every sentence adds value.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers purpose, usage, consequences, and alternatives. Output schema exists, so return values need not be described.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The description includes an example usage, but the input schema already fully describes the device_id parameter. No additional semantic value beyond schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Explicitly states it removes an orphaned device from the registry. Distinguishes from siblings like ha_set_device and ha_remove_entity by specifying orphaned condition.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides clear when-to-use (only for orphaned devices), when-not-to (active devices may be re-added), and an alternative (disable via ha_set_device).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_remove_entityRemove EntityADestructiveIdempotent
Remove one or more entities from the Home Assistant entity registry.
Permanently removes the entity registration from Home Assistant. The entity will no longer appear in the UI or be available to automations.
WARNING: This permanently removes the entity registration.
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 action cannot be undone without restoring from backup
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")
Remove stale helper entry: ha_remove_entity("input_boolean.deleted_helper")
Bulk cleanup: ha_remove_entity(["sensor.orphan_1", "sensor.orphan_2"])
NOTE: For most use cases, consider disabling instead: ha_set_entity(entity_id="sensor.old", enabled=False)
RELATED TOOLS:
ha_search: Find entities to verify the entity_id before removing
ha_get_entity: Check entity details before removal
| Name | Required | Description | Default |
|---|---|---|---|
| entity_id | Yes | Entity ID, or a list of entity IDs, to remove from the entity registry (e.g., 'sensor.old_temperature'). Permanently removes the registration(s). |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes beyond annotations by detailing permanent deletion, bulk mode sequential behavior, return format ({removed, skipped, errors}), idempotency of not-found, and backup implications. Though annotations already mark it destructive/idempotent, the description adds valuable operational context.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured with headings (WARNING, BULK MODE, EXAMPLES, NOTE, RELATED TOOLS) and front-loads the primary purpose. It is somewhat lengthy but each section earns its place given the tool's destructive nature and bulk mode details.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers all necessary aspects: purpose, warnings, bulk mode behavior, return format, idempotency, backup implications, and relationship to other tools. With an output schema present, the return format description in bulk mode is sufficient.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema provides 100% coverage with a clear description for entity_id. The description adds bulk mode semantics (up to 100 items, sequential removal, return format) and examples, enhancing understanding beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states 'Remove one or more entities from the Home Assistant entity registry' with specific verb and resource. It distinguishes from related tools like ha_set_entity (disabling) and ha_search (finding entities), and provides examples for different use cases.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly recommends using only for orphaned or stale entries, warns about automatic re-addition, and suggests disabling as an alternative. It also lists related tools (ha_search, ha_get_entity) for verifying before removal.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_remove_helpers_integrationsRemove Helper or IntegrationADestructiveIdempotent
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 with four routing paths driven by helper_type.
WHEN NOT TO USE:
Removing only an entity (without deleting its underlying helper or config entry) โ use
ha_remove_entityinstead.YAML-configured helpers โ they have no storage backend. Edit the YAML file and reload the relevant integration.
SUPPORTED HELPER TYPES:
SIMPLE (12, websocket-delete): input_button, input_boolean, input_select, input_number, input_text, input_datetime, counter, timer, schedule, zone, person, tag.
FLOW (17, config-entry-delete via entity lookup): 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.
ROUTING:
SIMPLE helper_type + bare helper_id or entity_id โ websocket delete.
FLOW helper_type + 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.
helper_type=None + entry_id โ direct config entry delete (any integration).
helper_type="config_subentry" + parent entry_id + subentry_id โ delete one config subentry.
MISSING-TARGET CONTRACT:
A target that is confirmed absent raises a structured error
rather than returning silent success, so a typo'd or stale
identifier surfaces immediately at the caller layer (the
success boolean is what agent wrappers branch on). The
error code per-path follows the target shape:
SIMPLE (bare helper_id or entity_id): state-machine empty AND entity registry empty โ raises
ENTITY_NOT_FOUND.FLOW (entity_id): not in entity registry โ raises
ENTITY_NOT_FOUND. YAML-configured helpers (no config entry backing) raiseRESOURCE_NOT_FOUND. A bare helper_id (no.) on a FLOW target raisesENTITY_NOT_FOUNDโ FLOW resolution needs a full entity_id. TOCTOU 404 on the resolved entry_id raisesRESOURCE_NOT_FOUND.Direct config entry (helper_type=None): backend returns HTTP 404 โ raises
RESOURCE_NOT_FOUND.Config subentry: backend returns a "not_found" error โ raises
RESOURCE_NOT_FOUND.
Idempotency at the contract level still holds (call N times =
same response). Transient connectivity failures (WebSocket
disconnected, network timeouts) 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 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. Recovery requires a usable backup and supported restore path.
| Name | Required | Description | Default |
|---|---|---|---|
| wait | No | Wait for entity removal. Default: True. Ignored when helper_type=None or helper_type='config_subentry' (no entity poll, require_restart returned). | |
| target | Yes | What to remove. One of: (a) bare helper_id for SIMPLE helpers (requires helper_type), e.g. 'my_button'; (b) full entity_id (requires helper_type), e.g. 'input_button.my_button' or 'sensor.my_meter'; (c) config entry_id for any integration (helper_type=None), e.g. value from ha_get_integration(); (d) parent config entry_id for config_subentry (requires helper_type='config_subentry' and subentry_id). | |
| confirm | No | Must be True to confirm removal. | |
| helper_type | No | Helper type. Required when target is a helper_id (bare) or entity_id. Set to None when target is a config entry_id to remove any integration. Use 'config_subentry' to remove a config subentry under target. | |
| subentry_id | No | Config subentry ID to remove when helper_type='config_subentry'. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare destructiveHint=true and idempotentHint=true, and the description adds substantial behavioral context: the missing-target contract with specific error codes per path, the TOCTOU 404 behavior, the fact that FLOW removal removes all sub-entities, and the warning about referenced helpers/integrations failing. It also clarifies idempotency at the contract level despite destructive semantics.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but every section earns its place: routing, error contract, examples, and warning are all necessary for correct invocation of a complex multi-path tool. It is well-structured with clear headers and front-loaded purpose. Slightly verbose in the error contract section, but that detail is operationally important.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a destructive, multi-path tool with 5 parameters and an output schema, the description covers routing, error codes, idempotency, connectivity failures, examples, and safety warnings. The output schema exists, so return values need not be described. Nothing an agent needs to call this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents all five parameters. The description adds value by explaining the routing logic that ties target/helper_type/subentry_id together, and by giving concrete examples of valid combinations. It doesn't add much per-parameter detail beyond the schema, but the routing section compensates for the interaction complexity.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb ('Remove') and resource ('Home Assistant helper or integration config entry'), and explicitly unifies three backend removal mechanisms behind one entry point. It clearly distinguishes itself from sibling tools like ha_remove_entity and ha_remove_device by naming them and explaining the boundary.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The 'WHEN NOT TO USE' section explicitly names ha_remove_entity for entity-only removal and explains YAML-configured helpers require editing YAML instead. The routing section further clarifies which target/helper_type combinations are valid, giving an agent concrete decision criteria.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_remove_todo_itemRemove Todo ItemADestructiveIdempotent
Remove an item from a Home Assistant todo list.
Permanently deletes an item from the specified todo list.
IDENTIFYING ITEMS:
Use the item's UID (from ha_get_todo)
Or use the exact item summary/name text
EXAMPLES:
Remove by name: ha_remove_todo_item("todo.shopping_list", "Buy milk")
Remove by UID: ha_remove_todo_item("todo.shopping_list", "abc123-uid")
USE CASES:
"Remove milk from my shopping list"
"Delete the eggs item"
"Clear 'call mom' from my todo"
WARNING: This permanently removes the item. To mark as completed instead, use ha_set_todo_item() with status="completed".
| Name | Required | Description | Default |
|---|---|---|---|
| item | Yes | Item to remove - can be the item UID or the exact item summary/name | |
| entity_id | Yes | Todo list entity ID (e.g., 'todo.shopping_list') |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already indicate destructiveHint=true and idempotentHint=true. The description reinforces the permanent deletion with a warning. However, it does not explain the idempotent behavior (e.g., removing a non-existent item may not error), though the annotation covers it.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured with clear headings (IDENTIFYING ITEMS, EXAMPLES, USE CASES, WARNING), is front-loaded with the core purpose, and every sentence adds meaningful information without redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity (simple removal operation with two parameters), the description covers identification methods, examples, use cases, and a warning about permanence. Since an output schema exists, there's no need to detail return values.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents both parameters. The description adds value by providing examples of how to use the 'item' parameter with UID or exact name, and 'entity_id' with a concrete example.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the action ('Remove an item'), the resource ('Home Assistant todo list'), and specifies it is a permanent deletion. It distinguishes from the sibling 'ha_set_todo_item' by mentioning the alternative for marking as completed.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit usage guidance, including how to identify items (by UID or exact name) and specific use cases. It clearly directs users to use 'ha_set_todo_item' for marking items as completed instead of deleting.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_remove_zoneRemove ZoneADestructiveIdempotent
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.
| Name | Required | Description | Default |
|---|---|---|---|
| zone_id | Yes | Zone ID to remove (use ha_get_zone to find IDs) |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Adds context beyond annotations: warns about automations, home zone restriction, and references ha_get_zone for ID lookup.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Concise 5 sentences with example, warning, note. Well-organized and front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers purpose, prerequisites, limitations, side effects. Output schema exists, so return values not needed.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Only one parameter with schema coverage 100%. Description adds value by explaining how to find zone_id via ha_get_zone.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Clearly states 'Remove a Home Assistant zone.' Distinguishes from siblings like ha_set_zone and ha_get_zone.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides example, warning about automations, note that 'home' zone cannot be removed, and suggests using ha_get_zone to find IDs.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_report_issueReport Issue or FeedbackARead-onlyIdempotent
Get diagnostic information and templates for filing issue reports or feedback.
This tool generates templates for TWO types of reports:
Runtime Bug Report - For ha-mcp errors, failures, unexpected behavior
Agent Behavior Feedback - For AI agent inefficiency, wrong tool usage
IMPORTANT FOR AI AGENTS: You MUST analyze the conversation context to determine which template to present:
๐ Present RUNTIME BUG template if:
User reports an error, failure, or unexpected behavior
A tool returned an error or incorrect result
Something is broken or not working in ha-mcp
๐ค Present AGENT BEHAVIOR template if:
User mentions YOU (the agent) used the wrong tool
User suggests a more efficient workflow
User reports YOUR inefficiency or mistakes
User says you should have done something differently
If unclear which type, ASK the user: "Are you reporting a bug in ha-mcp, or providing feedback on how I used the tools?"
WHEN TO USE THIS TOOL:
"I want to file a bug/issue/report"
"This isn't working"
"You should have used [other tool]"
"That was inefficient"
OUTPUT: Returns both templates plus diagnostic data. The full response is LARGE (the captured logs appear in the raw log keys AND inside each template) โ pass fields=... to fetch only the keys you need once you know which template applies. Key fields:
runtime_bug_template,agent_behavior_templateโ pick based on contextrecent_logs,startup_logsโ captured ha-mcp tool/server log entriesaddon_logsโ addon container stdout/stderr (HA add-on installs only; empty string otherwise)core_error_logโ Home Assistant error log (home-assistant.log) over REST; carries auth / integration errors that don't show in addon_logsmissing_tool_hintโ check this FIRST when the report is about a missing/unavailable tool; a stale client tool list (not a bug) is the usual cause, and refreshing the MCP connection is the fixsuggested_title,duplicate_check_urls,anonymization_guide
| Name | Required | Description | Default |
|---|---|---|---|
| fields | No | Return only the specified top-level response keys โ the full response (both templates + logs + diagnostics, with log content repeated across the raw keys and templates) is very large. None = full response. Typical for a runtime bug: 'runtime_bug_template,suggested_title,runtime_bug_submit_url,duplicate_check_urls,anonymization_guide,instructions'; for agent feedback swap in agent_behavior_template and agent_behavior_submit_url. The templates already embed the relevant logs, so the raw log keys are only needed for your own analysis. Available keys: diagnostic_info, recent_logs, startup_logs, addon_logs, core_error_log, log_count, startup_log_count, formatted_report, runtime_bug_template, agent_behavior_template, anonymization_guide, suggested_title, runtime_bug_submit_url, agent_behavior_submit_url, duplicate_check_urls, missing_tool_hint, instructions. | |
| tool_call_count | No | Number of tool calls made since the issue started. This determines how many log entries to include. Count how many ha_* tools were called from when the issue began. Default: 10. Max: 16 (limited by 200-entry log buffer: 16*4*3=192) |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare readOnlyHint=true and idempotentHint=true, so the agent knows it's safe. The description adds significant behavioral context: it returns large diagnostic data, includes log entries, and explains the `fields` parameter to manage response size. This goes well beyond what annotations provide.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-organized with headings, bullet points, and clear sections, front-loading critical information. However, it is quite long; while every sentence is useful, some details could be trimmed without losing clarity. Still, it is structured effectively for an AI agent.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Despite the tool's complexity and the presence of an output schema, the description covers all necessary context: how to choose the appropriate template, when to use the `fields` parameter, what diagnostic fields are available, and even hints about missing tools. It is fully complete for an agent to use correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% for the two parameters. The description adds substantial meaning: for `fields`, it lists all available keys and provides usage examples; for `tool_call_count`, it explains the default and maximum and the reasoning behind them. This greatly enhances understanding beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool generates diagnostic information and templates for filing issue reports or feedback, and it distinguishes between two specific report types (Runtime Bug Report and Agent Behavior Feedback). This sets it apart from all sibling tools, none of which are for reporting issues.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit conditions for when to use the tool with concrete examples (e.g., 'I want to file a bug', 'This isn't working', 'You should have used [other tool]'). It also instructs the agent to ask the user for clarification if the report type is unclear, effectively guiding the agent's decision-making.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_restartRestart Home AssistantADestructive
Restart Home Assistant.
WARNING: This will restart the entire Home Assistant instance! All automations will be temporarily unavailable during restart. The restart typically takes 1-5 minutes depending on your setup.
Parameters:
confirm: Must be set to True to confirm the restart. This is a safety measure to prevent accidental restarts.
Best Practices:
Config is validated automatically before the restart proceeds; to pre-check, call ha_get_system_health(include="config_check")
Notify users before restarting (if applicable)
Schedule restarts during low-activity periods
Example Usage:
# Optional pre-check (ha_restart also validates config automatically)
health = ha_get_system_health(include="config_check")
if health["config_check"]["is_valid"]:
# Restart with confirmation
result = ha_restart(confirm=True)Alternative: For configuration changes, consider using ha_reload_core() instead, which reloads specific components without a full restart.
| Name | Required | Description | Default |
|---|---|---|---|
| confirm | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already indicate destructiveness (destructiveHint=true). Description adds context: restart duration (1-5 minutes), temporary unavailability of automations, and automatic config validation. No contradictions with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Well-structured with clear sections (warning, parameters, best practices, example, alternative). Every sentence provides value, no redundancy. Efficient yet comprehensive.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers all essential aspects: purpose, impact, parameter meaning, pre-check option, usage example, alternative. Additionally, output schema exists (though not shown), so description needn't explain returns.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, but description fully explains the 'confirm' parameter: must be True, serves as safety measure. This adds critical meaning beyond schema's type/default.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Description clearly states 'Restart Home Assistant' as the purpose, uses a specific verb and resource, and distinguishes from siblings by mentioning ha_reload_core as an alternative for config changes.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly provides when to use (restart instance) and when not (for config changes, use ha_reload_core). Includes best practices like notifying users and scheduling during low activity.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_searchSearchARead-onlyIdempotent
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; omitqueryto enumerate a domain, area, or state.automations / scripts / scenes / helpers / dashboards: matches inside config definitions โ triggers, actions, sequences, scene entity-sets, helper bodies, dashboard cards. Driven by
query; narrow withsearch_types.
Use this whenever you need to find something in HA without deciding entity-name vs config-body search up front.
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. Pass
search_types=[...] to force config search.
Caveats:
partial: Truemeans 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 withpartial: Truemean "search failed", not "no results". The cause is inpartial_reason, also mirrored intowarnings[]with an "incomplete results: " prefix. Do not treat a partial response as complete.countis items in this response (post-pagination), not corpus totals โ useentity_total_matches+config_total_matches.limit/offsetapply per-surface. Flathas_more/next_offsetpage the next call (iterateoffset = next_offset); per-surfaceentity_*/config_*variants show which surface still has results.
For parameters, schema, and worked examples, see ha_get_skill_guide.
Examples: - List sensors in an area: ha_search(domain_filter="sensor", area_filter="Living Room") - Find a light by name: ha_search("kitchen", domain_filter="light") - 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") - Scenes touching a light: ha_search("light.kitchen", search_types=["scene"]) - Narrow the response to the entity bucket: ha_search("kitchen", fields=["entities"]) - 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
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum results per surface (entities, configs). Default: 10. | |
| query | No | What to search for (entity name fragment, free-text config term, entity_id). Searches BOTH the entity registry (entity_ids, friendly names, areas) AND configuration bodies (automation triggers/actions, script sequences, scene contents, helper bodies, dashboard cards) in one call. Use this for any find-something-in-HA question โ entity OR config. Pass the exact entity_id, not a name fragment, when checking what a rename or delete would break: that form reports automations, scripts and scenes referencing it even when their configuration could not be read. Omit `query` to enumerate by `domain_filter`, `area_filter`, and/or `state_filter` alone (registry-listing mode); configuration-body search is skipped in that mode because there is no term to match against. | |
| fields | No | Project the response to the named top-level keys (e.g. ["entities", "automations"]); None = full response. Diagnostic / pagination keys are always retained so projection cannot hide partial / error state. Distinct from `result_fields` (which projects each entity record's keys). Available keys: success, query, entities, automations, scripts, scenes, helpers, dashboards, search_types, search_type, entity_total_matches, config_total_matches, count, offset, limit, has_more, next_offset, entity_has_more, entity_next_offset, config_has_more, config_next_offset, by_domain, state_filter_note, area_names, domain_filter, area_filter, message, warnings, errors, partial, partial_reason. | |
| offset | No | Number of results to skip for pagination. | |
| area_filter | No | Narrow entity-registry results to an area (id, name, or alias), an exact floor (id, name, or alias), or an unambiguous close-spelling floor match; a floor match expands to all areas on that floor. Does not affect configuration search. | |
| exact_match | No | Exact substring matching (default). Set False for fuzzy matching when the query may have typos. | |
| search_types | No | Configuration types to include in body search: 'automation', 'script', 'scene', 'helper', 'dashboard'. Default = automation+script+scene+helper. Pass as list or JSON-array string. | |
| state_filter | No | Filter entity-registry results to a specific state (e.g. "on", "off", "unavailable"). Case-insensitive. Can be used standalone (no query/domain/area) to enumerate every entity in that state; entity_total_matches reflects the filtered count. | |
| domain_filter | No | Narrow entity-registry results to a single domain (e.g. 'light', 'sensor'). Does not affect configuration search. | |
| result_fields | No | Project each entity-registry record to only the specified keys (e.g. ["entity_id", "state"]). None = full records. Base keys: entity_id, friendly_name, domain, state, score, match_type. Opt-in enrichment/membership keys (computed on request): area, floor, labels, aliases, is_group, member_entity_ids. Membership is recognized only when HA explicitly exposes a valid group_entities or legacy entity_id collection; member IDs are sorted, direct (not recursively expanded), and omitted if visibility/include_hidden excludes a member. is_group remains true when member IDs are withheld; requesting member_entity_ids also retains is_group. An unknown key is rejected. | |
| include_config | No | Include full configuration bodies in body-search results. Default: False (summary only). | |
| include_hidden | No | Include hidden entities in registry results (with a score penalty so they sort below visible matches). Set False to exclude entirely. | |
| group_by_domain | No | Group entity-registry results by domain (entity-side only). Adds a `by_domain` map to the response. | |
| per_domain_limit | No | When `group_by_domain=True`, cap entity-registry results per domain to this number. Ignored otherwise. | |
| config_time_budget | No | Per-call override for the per-id config-fetch wall-clock budget (seconds). Replaces the per-type HAMCP_*_CONFIG_TIME_BUDGET defaults for the automation, script, AND scene branches. Use when a `partial: True` response names time-budget skipping. Stateless per-call: one caller raising the budget doesn't affect others. None = use the per-type env defaults. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations carry readOnlyHint=true and idempotentHint=true, but the description adds substantial behavior beyond that: the partial: True semantics ('empty buckets mean search failed, not no results', 'Do not treat a partial response as complete'), the distinction between count and entity_total_matches/config_total_matches, per-surface pagination mechanics, the expensive-backend cost model and when config-body search is skipped, and the withheld-member-list caveat (absence of member_entity_ids must not be read as a leaf entity). This is exactly the kind of context annotations cannot express.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but every section earns its place for a tool with 15 parameters and two search surfaces. Structure is excellent: front-loaded core purpose, explicit when-not-to-use, clearly separated caveats covering dangerous partial semantics and pagination, parameter guidance, and six compact worked examples. The keyword list at the end is mildly redundant but harmless.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a high-complexity tool with an output schema and 100% parameter coverage, the description covers everything needed to invoke it correctly: the dual-surface return shape, partial-failure semantics, per-surface pagination, projection behavior, the skip rule for config search, and the enrichment-key behavior. It even points to ha_get_skill_guide for worked examples. Nothing an agent needs to correctly select and call this tool is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3. The description genuinely adds meaning beyond the schema: the control-request pattern (include is_group and member_entity_ids in result_fields), the safety rule about excluded entities in aggregates, the exact-entity_id form for evaluating rename/delete blast radius, and the enumeration mode (omit query to enumerate by domain/area/state). These go beyond the schema's own parameter descriptions, warranting a 4.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific verb (search), a resource (entities AND config bodies), and the two parallel surfaces (entities vs automations/scripts/scenes/helpers/dashboards). It explicitly differentiates from sibling tools in the 'When NOT to use' section, naming ha_get_state, ha_config_get_*, and ha_get_app as alternatives. An agent can tell precisely what this tool does and does not do without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is an explicit 'When NOT to use' section with named alternatives and the conditions selecting them. It also gives nuanced affirmative guidance: use for any find-something-in-HA question, use the exact entity_id form for rename/delete impact checks, and a special rule for control requests with 'except/excluding/but not' โ including a safety directive not to control aggregates containing excluded members. No inference is left to the agent.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_set_area_or_floorCreate or Update Area or FloorADestructive
Create or update a Home Assistant area or floor.
Pass kind='area' (with optional floor_id, picture) 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 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="floor", name="Basement", level=-1) ha_set_area_or_floor(kind="floor", id="ground_floor", level=0)
| Name | Required | Description | Default |
|---|---|---|---|
| id | No | Existing area_id or floor_id to update (omit to create a new entry; use ha_list_floors_areas to find IDs) | |
| icon | No | Material Design Icon (e.g., 'mdi:sofa', 'mdi:home-floor-1', empty string to remove) | |
| kind | Yes | Which registry to operate on: 'area' for rooms, 'floor' for building levels | |
| name | No | Name (required when creating; optional when updating, e.g., 'Living Room', 'Ground Floor') | |
| level | No | Numeric level when kind='floor' (0=ground, 1=first, -1=basement). Only valid when kind='floor'. | |
| aliases | No | Alternative names for voice assistant recognition (e.g., ['lounge'], empty list to clear) | |
| picture | No | Picture URL when kind='area' (empty string to remove). Only valid when kind='area'. | |
| floor_id | No | Floor assignment when kind='area' (use empty string to clear). Only valid when kind='area'. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations include destructiveHint=true, and the description discloses that the tool creates or updates records, implying overwriting. It also details validation behavior (cross-kind params rejected). However, it does not explicitly mention that updates replace existing data or any side effects.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise yet complete, with a clear structure: purpose statement, parameter rules, and examples. Every sentence provides necessary information with no redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description covers creation and update for both area and floor, includes cross-kind validation, and provides examples. Since an output schema exists, return values are not required. The description fully addresses the tool's complexity.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so baseline is 3. The description adds value by showing how parameters combine in examples (e.g., floor_id with kind='area'), which clarifies usage beyond individual parameter descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The title and description clearly state the tool creates or updates Home Assistant areas or floors. It distinguishes between the two kinds ('area' vs 'floor') and between create vs update operations, providing a specific verb and resource.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit guidelines for when to use kind='area' vs kind='floor', when to create (provide name) vs update (provide id), and warns that cross-kind parameters are rejected. Examples illustrate common use cases, making usage clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_set_deviceSet DeviceADestructive
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:
ha_set_device(device_id="abc", name="Living Room Sensor") # Rename device
ha_set_entity("sensor.old", new_entity_id="sensor.living_room") # Rename entities separately
PARAMETERS:
name: Sets the user-defined display name (name_by_user)
area_id: Assigns device to an area/room. Use '' to remove from area.
disabled_by: Set to 'user' to disable, or empty to enable
labels: List of labels (replaces existing labels)
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"])
| Name | Required | Description | Default |
|---|---|---|---|
| name | No | New display name for the device (sets name_by_user) | |
| labels | No | Labels to assign to the device (replaces existing labels) | |
| area_id | No | Area/room ID to assign the device to. Use empty string '' to unassign. | |
| device_id | Yes | Device ID to update | |
| disabled_by | No | Set to 'user' to disable, or None/empty string to enable |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description discloses critical behavioral traits not in annotations: renaming device does not rename entities, labels replace existing ones, and how to disable/enable. Annotations only note destructiveHint=true, but the description adds rich context about the mutation behavior.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is somewhat long but well-structured: purpose statement, important note, workflow, parameter list, examples. It is front-loaded with critical info. Every section is valuable, though could be slightly more concise.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the moderate complexity, annotations (destructiveHint), and presence of output schema, the description covers all necessary aspects: parameters, important caveats, workflow, and examples. It is comprehensive enough for an agent to use correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and each parameter has a description. The narrative description adds value by explaining semantics like 'replaces existing labels' and 'empty string to unassign', and provides examples. This goes beyond the schema but slightly redundant.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description explicitly states 'Update device properties such as name, area, disabled state, or labels.' It clearly distinguishes from sibling tools like ha_get_device (read) and ha_set_entity (entity operations) by noting that renaming a device does not rename entities.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit guidance: it describes a common workflow for full rename combining with ha_set_entity, and explains when to use each parameter (e.g., area_id with '' to unassign). It does not explicitly state when not to use, but the important note serves as a clear alternative.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_set_entitySet EntityADestructiveIdempotent
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, icon, device_class, options, enabled, hidden, aliases, new_entity_id, new_device_name) require single entity.
LABEL OPERATIONS:
label_operation="set" (default): Replace all labels with the provided list. Use [] to clear.
label_operation="add": Add labels to existing ones without removing any.
label_operation="remove": Remove specified labels from the entity.
SHOW AS / DEVICE CLASS: device_class overrides the entity's display device class โ equivalent to the HA UI's "Show As" dropdown. Use empty string '' to clear. Applies instantly, no reload needed.
REGISTRY OPTIONS: options carries per-domain registry options (sensor display_precision, weather forecast_type, etc). Pass {domain: {key: value}}; multi-domain dicts 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: Use new_entity_id to change an entity's ID (e.g., sensor.old -> sensor.new). Domain must match. 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: Use new_device_name to rename the associated device. 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: Single entity:
Assign to area: ha_set_entity("sensor.temp", area_id="living_room")
Rename display name: ha_set_entity("sensor.temp", name="Living Room Temperature")
Set Show As: ha_set_entity("binary_sensor.zone_10", device_class="window")
Clear Show As: ha_set_entity("binary_sensor.zone_10", device_class="")
Set sensor precision: ha_set_entity("sensor.power", options={"sensor": {"display_precision": 2}})
Rename entity_id: ha_set_entity("light.old_name", new_entity_id="light.new_name")
Rename entity and device: ha_set_entity("light.old", new_entity_id="light.new", new_device_name="New Lamp")
Rename entity_id with friendly name: ha_set_entity("sensor.old", new_entity_id="sensor.new", name="New Name")
Set labels: ha_set_entity("light.lamp", labels=["outdoor", "smart"])
Add labels: ha_set_entity("light.lamp", labels=["new_label"], label_operation="add")
Remove labels: ha_set_entity("light.lamp", labels=["old_label"], label_operation="remove")
Clear labels: ha_set_entity("light.lamp", labels=[])
Expose to Alexa: ha_set_entity("light.lamp", expose_to={"cloud.alexa": True})
Bulk operations:
Set labels on multiple: ha_set_entity(["light.a", "light.b"], labels=["outdoor"])
Add labels to multiple: ha_set_entity(["light.a", "light.b"], labels=["new"], label_operation="add")
Expose multiple to Alexa: ha_set_entity(["light.a", "light.b"], expose_to={"cloud.alexa": True})
ENABLED/DISABLED WARNING: Setting enabled=False performs a registry-level disable โ the entity is completely removed from the Home Assistant state machine and hidden from the UI. It 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. Use these instead:
ha_call_service("automation", "turn_off", entity_id="automation.xxx")
ha_call_service("script", "turn_off", entity_id="script.xxx")
| Name | Required | Description | Default |
|---|---|---|---|
| icon | No | Icon for the entity (e.g., 'mdi:thermometer'). Use empty string '' to remove custom icon. Single entity only. | |
| name | No | Display name for the entity. Use empty string '' to remove custom name and revert to default. Single entity only. | |
| hidden | No | True to hide the entity from UI, False to show it. Single entity only. | |
| labels | No | List of label IDs for the entity. Behavior depends on label_operation parameter. Supports bulk operations. | |
| aliases | No | List of voice assistant aliases for the entity (replaces existing aliases). Single entity only. | |
| area_id | No | Area/room ID to assign the entity to. Use empty string '' to unassign from current area. Single entity only. | |
| enabled | No | True to enable the entity, False to disable it. Single entity only. WARNING: Setting enabled=False is a registry-level disable โ it completely removes the entity from the state machine and hides it from the UI. A reload or restart is required to restore it after re-enabling. NOT allowed for automation or script entities โ use automation.turn_off / script.turn_off via ha_call_service() instead. | |
| options | No | Per-domain entity registry options (e.g. sensor 'display_precision', weather 'forecast_type'). Pass a dict mapping domain to a sub-dict, e.g. {"sensor": {"display_precision": 2}}. Multiple domains are sent as separate registry updates. For 'Show As' use the dedicated `device_class` parameter โ that is what the HA UI Show As dropdown writes. Voice-assistant exposure is stored under `options.<assistant>.should_expose` but must be managed via the dedicated `expose_to` parameter, not this options dict. Single entity only. | |
| entity_id | Yes | Entity ID or list of entity IDs to update. Bulk operations (list) only support labels, expose_to, and categories parameters. | |
| expose_to | No | Control voice assistant exposure. Pass a dict mapping assistant IDs to booleans. Valid assistants: 'conversation' (Assist), 'cloud.alexa', 'cloud.google_assistant'. Example: {"conversation": true, "cloud.alexa": false}. Supports bulk operations. | |
| categories | No | Category assignment as a dict mapping scope to category_id. Example: {"automation": "category_id_here"}. Use null value to clear: {"automation": null}. Single entity only. | |
| device_class | No | Override the entity's display device class โ what the HA UI's 'Show As' dropdown writes. Use empty string '' to clear the override and fall back to the integration default. None (the default) means 'no change' โ pass an explicit '' to clear. Single entity only. Examples: 'window', 'door', 'motion' for binary_sensor; 'temperature', 'humidity' for sensor. | |
| new_entity_id | No | New entity ID to rename to (e.g., 'light.new_name'). Domain must match the original. Single entity only. | |
| label_operation | No | How to apply labels: 'set' replaces all labels, 'add' adds to existing, 'remove' removes specified labels. | set |
| new_device_name | No | New display name for the associated device. If provided, both entity and device are updated in one operation. Single entity only. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations indicate idempotent and destructive hints; the description adds critical behavioral details: enabling/disabling is registry-level (requires reload), rename doesn't update references, label operations semantics, and multi-domain options handling. No contradiction with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Well-structured with sections, bullet points, and examples. Front-loaded with a clear summary. Slightly verbose due to many examples, but every section serves a purpose. Could be trimmed slightly, but still very effective.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers all 15 parameters, bulk restrictions, warnings (enabled=False, rename propagation), and cross-references sibling tools. With output schema present, it provides comprehensive context for complex entity registry operations.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With 100% schema coverage, the description still adds significant value: explains label_operation enum, device_class 'Show As' usage, options multi-domain handling, expose_to valid assistants, rename limitations, and device rename combination. Goes far beyond schema descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states 'Update entity properties in the entity registry' and lists specific modifiable aspects (area, name, icon, etc.). It distinguishes from siblings like ha_get_entity (read), ha_remove_entity (delete), and ha_set_device (device-level) by focusing on entity registry properties.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly covers when to use (single vs bulk), when not to use (e.g., enabled=False for automations/scripts, alternatives provided via ha_call_service()), and includes examples for each operation. Clearly differentiates single entity and bulk operations.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_set_integrationSet IntegrationADestructive
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). Like that dialog it is a patch: omitted fields keep their current values, and a field set to null is cleared where the integration's schema allows that field to be empty.
Reconfigure: entry_id + reconfigure=True + config โ drives the existing entry's official reconfigure flow (host, port, credentials). Call it without confirm_token for a read-only preflight; repeat with the token it returns to apply.
WHEN NOT TO USE:
Helpers (template, group, utility_meter, ...): use ha_config_set_helper. The exception is
otp, which is a helper in the HA UI but is created HERE via domain="otp" โ its flow needs a live TOTP code, so ha_config_set_helper deliberately omits 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; only integrations implementing async_step_reconfigure do.
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 with a structured error 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:
Disable: ha_set_integration(entry_id="abc123", enabled=False)
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"})
Reconfigure apply: repeat that call adding confirm_token="sha256:..."
| Name | Required | Description | Default |
|---|---|---|---|
| config | No | Flow form data. With 'domain': input for the new integration's config flow. With 'entry_id' alone: input for the entry's options flow (updates its options). Updating an existing entry โ options or reconfigure โ is a patch: a field you omit keeps its current value, and a field set to null is cleared where the integration's schema allows that field to be empty. Multi-step flows consume keys per step. A field two steps declare gets your one value both times; pass step_values={'<step_id>': {'<field>': <value>}} to give a step its own value, or to leave the field out of that step; a LIST of those objects supplies one per encounter when the flow presents a step more than once. Menu steps take 'next_step_id' โ a string, or a list of successive selections for flows that present more than one menu (e.g. a menu revisited after each branch, ending in a finish option). The step's data_schema is returned on validation errors so field names can be corrected. | |
| domain | No | Integration domain to add (e.g. 'workday', 'local_calendar') โ starts and drives that domain's config flow. Pass the flow's form fields in 'config'. | |
| enabled | No | True to enable, False to disable the entry. Requires entry_id; mutually exclusive with 'domain' and 'config'. | |
| entry_id | No | Config entry ID of an existing integration (enable/disable and options-update modes). Omit when adding via 'domain'. | |
| reconfigure | No | Use the existing config entry's official reconfigure flow (its connection settings) instead of its options flow. Without confirm_token this is a read-only preflight that returns one. | |
| expected_mac | No | Requires reconfigure=True. MAC or IEEE the entry's device must still report. | |
| confirm_token | No | Requires reconfigure=True. A token from a reconfigure preflight; applies the change. Any token still matching the entry's current state and the same requested config is accepted, so a token stays valid while nothing moves. | |
| expected_device_id | No | Requires reconfigure=True. Device registry ID the entry must still own, before and after the change. | |
| expected_unique_id | No | Requires reconfigure=True, AND the ha_mcp_tools custom component: Home Assistant does not expose a config entry's unique_id over its API. Without the component this is rejected โ anchor on expected_device_id, expected_mac or expected_entity_ids instead. | |
| expected_entity_ids | No | Requires reconfigure=True. Exact entity IDs that must remain associated with the entry. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond destructiveHint=true, the description discloses concrete side effects: adding runs the config flow as the UI would (pairing devices, scanning, creating entities), OAuth/async provider steps fail at that step, and reconfigure can take a live integration offline with no automatic rollback. It also explains the preflight/confirm_token two-call contract, giving the agent accurate behavioral expectations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is structured with clear labeled sections (modes, when not to use, caveats, examples) and front-loads the core action and mode selection before detailed caveats. Despite its length, every section adds operational value rather than repeating schema content.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a complex 10-parameter tool, the description covers mode selection, scheduling of preflight vs apply, constraints on expected_* fields, failure behavior, and rollback limits. The output schema exists, so return values need not be described; nothing essential to correct invocation is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is already 100%, and the description additionally maps parameters to operational modes (entries vs domain vs reconfigure) and patch semantics ('omitted fields keep current values, null clears'). The worked examples clarify how config, entry_id, enabled, reconfigure, and confirm_token combine in real calls.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb-resource pairing ('Manage an integration (config entry)') and immediately enumerates the four distinct modes: enable/disable, add, update options, reconfigure. It also differentiates from sibling tools in 'WHEN NOT TO USE' (ha_config_set_helper, ha_remove_helpers_integrations), so an agent can select it unambiguously.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The 'WHEN NOT TO USE' section explicitly names alternatives for helpers, subentries, and removal, including the otp exception. It gives positive routing guidance ('Use ha_get_integration() to find entry IDs...') and clarifies when reconfigure is available via supports_reconfigure / async_step_reconfigure.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_set_todo_itemSet Todo ItemADestructive
Create or update a todo item in Home Assistant.
WITHOUT item parameter (create mode): Creates a new item. summary is required.
WITH item parameter (update mode): Updates an existing item identified by UID or exact name. At least one update field (rename, status, description, due_date, due_datetime) is required.
EXAMPLES:
Add item: ha_set_todo_item("todo.shopping_list", summary="Buy milk")
Add with description: ha_set_todo_item("todo.shopping_list", summary="Buy milk", description="2% organic")
Add with due date: 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")
Update due date: ha_set_todo_item("todo.tasks", item="Pay bills", due_date="2024-12-31")
Reopen item: ha_set_todo_item("todo.tasks", item="Task to redo", status="needs_action")
NOTE: Not all todo integrations support all features (description, due dates). The Shopping List integration only supports summary.
| Name | Required | Description | Default |
|---|---|---|---|
| item | No | Existing item to update - can be the item UID or the exact item summary/name. When provided, operates in update mode. When omitted, creates a new item. | |
| rename | No | New name/summary for an existing item. Only used in update mode. | |
| status | No | Item status: 'completed' to mark done, 'needs_action' to mark incomplete. Only used in update mode. | |
| summary | No | Item text/name. Required when creating a new item. Ignored in update mode โ use 'rename' to change the item name. | |
| due_date | No | Due date in YYYY-MM-DD format (e.g., '2024-12-25') | |
| entity_id | Yes | Todo list entity ID (e.g., 'todo.shopping_list') | |
| description | No | Detailed description for the item | |
| due_datetime | No | Due datetime in ISO format (e.g., '2024-12-25T14:00:00'). Overrides due_date if both provided. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations include destructiveHint: true, confirming mutation. The description adds details about create/update modes and parameter behaviors but does not disclose potential side effects, permissions required, or reversibility. It provides adequate context beyond annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured with clear sections (create mode, update mode, examples, note) and front-loads the main action. While somewhat lengthy due to multiple examples, every sentence adds value and the structure aids readability.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity (8 params, two modes), the description covers all key aspects: mode behavior, required/optional params, integration limitations, and examples. With full schema coverage and an output schema present, no return value explanation is needed.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, but the description adds significant value by explaining param relationships (summary vs rename, due_datetime override), mode-switching via 'item', and providing concrete examples that clarify parameter usage beyond the schema definitions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states 'Create or update a todo item in Home Assistant' and distinguishes two modes (create vs update) based on the 'item' parameter, which differentiates it from sibling tools like ha_remove_todo_item and ha_get_todo.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly explains when to use create mode (no item) vs update mode (with item), provides detailed examples for each scenario, and notes limitations across integrations. However, it does not explicitly state when to avoid this tool (e.g., for deletion or listing).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
ha_set_zoneSet ZoneADestructive
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).
EXAMPLES:
Create: ha_set_zone(name="Office", latitude=40.7128, longitude=-74.0060, radius=150, icon="mdi:briefcase")
Update name: ha_set_zone(zone_id="abc123", name="New Office")
Update radius: ha_set_zone(zone_id="abc123", radius=200)
Update location: ha_set_zone(zone_id="abc123", latitude=40.7128, longitude=-74.0060)
Note: The 'home' zone is typically defined in YAML and cannot be modified via this API.
| Name | Required | Description | Default |
|---|---|---|---|
| icon | No | Material Design Icon (e.g., 'mdi:briefcase', 'mdi:school') | |
| name | No | Display name for the zone (required for create) | |
| radius | No | Radius of the zone in meters (must be > 0, defaults to 100 on create) | |
| passive | No | Passive mode - if True, zone will not trigger enter/exit automations (defaults to False on create) | |
| zone_id | No | Zone ID to update (omit to create new zone, use ha_get_zone to find IDs) | |
| latitude | No | Latitude coordinate of the zone center (required for create) | |
| longitude | No | Longitude coordinate of the zone center (required for create) |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare destructiveHint: true, and the description confirms modification behavior. It adds specific constraints: only specified fields change on update, defaults for radius and passive on create, and the home zone restriction. This goes beyond the annotation's general destructiveness hint.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise and well-structured: a clear first sentence, followed by bullet-like paragraphs summarizing create vs update, then examples, and a final note. Every sentence adds value, with no redundant information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity (create/update, 7 params) and the presence of an output schema, the description is fairly complete. It covers key behavioral aspects, required fields, defaults, and a notable restriction. Lacks details on error handling or edge cases like invalid coordinates, but schema validation likely covers that.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Input schema covers all 7 parameters with descriptions (100% coverage). The description adds semantic value by clarifying which parameters are required for create (name, latitude, longitude) and showing usage via examples. It also states default values (radius 100, passive False) that are not explicitly in the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's purpose as 'Create or update a Home Assistant zone', which is a specific verb+resource. It distinguishes itself from sibling tools like ha_get_zone (read) and ha_remove_zone (delete) by explicitly covering both creation and update operations.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit guidance on when to use each mode: omit zone_id for create, provide for update. It also notes the limitation that the 'home' zone cannot be modified. Examples illustrate typical usage, and it references sibling tool ha_get_zone for finding zone IDs. However, it does not explicitly compare to alternatives like ha_remove_zone for deletion, though that is implied.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
12 tool updates
v8.5.0- Changed
ha_config_get_dashboard1 field changed- changed
Input schema / properties / force_reload / descriptionPrevious value: -"Force reload from storage (bypass cache). Not applicable in search mode (search always uses force=True for fresh results)."New value: +"Force reload from storage (bypass cache). Not applicable in search mode, which always reads fresh config."
- Changed
ha_config_set_automation3 fields changed- changed
Input schema / properties / config_hash / descriptionPrevious value: -"Config hash from ha_config_get_automation for optimistic locking. REQUIRED for python_transform (validates automation unchanged). Optional for config updates (validates before full replacement if provided)."New value: +"Config hash from ha_config_get_automation for optimistic locking. REQUIRED for python_transform (validates automation unchanged). Required when a config update changes an existing automation's alias. Otherwise optional for config updates (validates before full replacement if provided)." - changed
Input schema / properties / identifier / descriptionPrevious value: -"Automation entity_id or unique_id for updates. Required for python_transform. Omit to create new automation with generated unique_id."New value: +"Target automation entity_id or HA config 'id' (unique_id). Omit for creation with a generated ID. Values such as 'new' are literal IDs, not placeholders. Required for python_transform." - added
Input schema / properties / take_control_of_blueprintAdded value: +{ + "default": false, + "description": "Convert a blueprint-backed automation into an editable standalone one -- the UI's \"Take control\". Renders the blueprint with its current inputs and saves the result over the same automation, which then has its own triggers/conditions/actions and no 'use_blueprint'. Requires identifier; mutually exclusive with config and python_transform. Irreversible: the link to the blueprint is gone afterwards, so edit inputs instead if you only want to change a value. 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. To preview the rendering without writing anything, use ha_manage_blueprints(action=\"substitute\").", + "type": "boolean" +}
- Changed
ha_config_set_dashboard4 fields changed- changed
Input schema / properties / config / descriptionPrevious value: -"Dashboard configuration with views and cards. Omit or set to None to create dashboard without initial config. Mutually exclusive with python_transform."New value: +"Dashboard configuration with views and cards. Omit or set to None to create dashboard without initial config. Mutually exclusive with python_transform and patch." - changed
Input schema / properties / config_hash / descriptionPrevious value: -"Config hash from ha_config_get_dashboard for optimistic locking. REQUIRED for python_transform (validates dashboard unchanged). Optional for config (validates before full replacement if provided)."New value: +"Config hash from ha_config_get_dashboard for optimistic locking. REQUIRED for python_transform and patch (validates dashboard unchanged). Optional for config (validates before full replacement if provided)." - added
Input schema / properties / patchAdded value: +{ + "anyOf": [ + { + "items": { + "additionalProperties": true, + "type": "object" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Structured dashboard edits: up to 100 JSON Patch add, remove, replace or test operations using RFC 6901 paths. Use /- to append to an array; escape ~ as ~0 and / as ~1 in keys. Requires config_hash. Mutually exclusive with config and python_transform. Update title/icon/require_admin/show_in_sidebar in a separate call. Strings in value are preserved literally." +} - changed
Input schema / properties / python_transform / descriptionPrevious value: -"Python expression to transform existing dashboard config. Mutually exclusive with config. Requires config_hash for validation. See PYTHON TRANSFORM SECURITY below for allowed operations. Examples: Simple: python_transform=\"config['views'][0]['cards'][0]['icon'] = 'mdi:lamp'\" Pattern: python_transform=\"for card in config['views'][0]['cards']: if 'light' in card.get('entity', ''): card['icon'] = 'mdi:lightbulb'\" Multi-op: python_transform=\"config['views'][0]['cards'][0]['icon'] = 'mdi:lamp'; del config['views'][0]['cards'][2]\" \n\nPYTHON TRANSFORM SECURITY:\n\nโ ALLOWED:\n- Dictionary/list access: config['views'][0]['cards'][1]\n- Slicing: config['views'][0]['cards'][1:3]\n- Assignment: config['key'] = 'value'\n- Deletion: del config['key'] or config.pop('key')\n- List methods: append, insert, pop, remove, clear, extend\n- Dict methods: update, get, setdefault, keys, values, items\n- Loops: for, if/else, pass, break, continue\n- Comprehensions: [x for x in ...], {k: v for ...}, (x for x in ...)\n- Ternary: x if condition else y\n- Iterable unpacking (* in calls/literals): f(*xs), [*xs, y]\n- Dict unpacking (**) in calls and dict literals: {**d, 'k': v}\n- Keyword arguments: func(key=value)\n- Lambdas (e.g. for `key=`): sorted(items, key=lambda x: x['score'])\n- String methods: startswith, endswith, lower, upper, strip, split, join, replace\n- Safe builtins: isinstance, len, range, enumerate, zip, sorted, reversed,\n min, max, sum, abs, any, all, round, str, int, float, bool, list, dict,\n tuple, set\n\nโ FORBIDDEN:\n- Imports: import, from, __import__\n- File operations: open, read, write\n- Dunder access: __class__, __bases__, __subclasses__\n- Dangerous builtins: eval, exec, compile, getattr, setattr, delattr, hasattr\n- Function definitions: def, class\n- Exception handling: try/except (validate with isinstance/in/.get() instead)\n- While loops: use bounded for loops or comprehensions instead\n\n๐ฏ PATTERNS:\n- Filter cards: cards = [c for c in cards if keep(c)]\n- Skip in a loop: prefer `continue` over an empty `pass` branch (clearer)\n- Conditionally include: build a new list and `.append(x)` only the\n cards you want, instead of iterating the original and using if/pass\n branches to drop entries\n- Modify in place when possible (single pass, fewer surprises) over\n reconstructing the entire list"New value: +"Python expression to transform existing dashboard config. Mutually exclusive with config and patch. Requires config_hash for validation. See PYTHON TRANSFORM SECURITY below for allowed operations. Examples: Simple: python_transform=\"config['views'][0]['cards'][0]['icon'] = 'mdi:lamp'\" Pattern: python_transform=\"for card in config['views'][0]['cards']: if 'light' in card.get('entity', ''): card['icon'] = 'mdi:lightbulb'\" Multi-op: python_transform=\"config['views'][0]['cards'][0]['icon'] = 'mdi:lamp'; del config['views'][0]['cards'][2]\" \n\nPYTHON TRANSFORM SECURITY:\n\nโ ALLOWED:\n- Dictionary/list access: config['views'][0]['cards'][1]\n- Slicing: config['views'][0]['cards'][1:3]\n- Assignment: config['key'] = 'value'\n- Deletion: del config['key'] or config.pop('key')\n- List methods: append, insert, pop, remove, clear, extend\n- Dict methods: update, get, setdefault, keys, values, items\n- Loops: for, if/else, pass, break, continue\n- Comprehensions: [x for x in ...], {k: v for ...}, (x for x in ...)\n- Ternary: x if condition else y\n- Iterable unpacking (* in calls/literals): f(*xs), [*xs, y]\n- Dict unpacking (**) in calls and dict literals: {**d, 'k': v}\n- Keyword arguments: func(key=value)\n- Lambdas (e.g. for `key=`): sorted(items, key=lambda x: x['score'])\n- String methods: startswith, endswith, lower, upper, strip, split, join, replace\n- Safe builtins: isinstance, len, range, enumerate, zip, sorted, reversed,\n min, max, sum, abs, any, all, round, str, int, float, bool, list, dict,\n tuple, set\n\nโ FORBIDDEN:\n- Imports: import, from, __import__\n- File operations: open, read, write\n- Dunder access: __class__, __bases__, __subclasses__\n- Dangerous builtins: eval, exec, compile, getattr, setattr, delattr, hasattr\n- Function definitions: def, class\n- Exception handling: try/except (validate with isinstance/in/.get() instead)\n- While loops: use bounded for loops or comprehensions instead\n\n๐ฏ PATTERNS:\n- Filter cards: cards = [c for c in cards if keep(c)]\n- Skip in a loop: prefer `continue` over an empty `pass` branch (clearer)\n- Conditionally include: build a new list and `.append(x)` only the\n cards you want, instead of iterating the original and using if/pass\n branches to drop entries\n- Modify in place when possible (single pass, fewer surprises) over\n reconstructing the entire list"
- Changed
ha_config_set_script1 field changed- added
Input schema / properties / take_control_of_blueprintAdded value: +{ + "default": false, + "description": "Convert a blueprint-backed script into an editable standalone one -- the UI's \"Take control\". Renders the blueprint with its current inputs and saves the result over the same script, which then has its own sequence and no 'use_blueprint'. Mutually exclusive with config and python_transform. Irreversible: the link to the blueprint is gone afterwards, so edit inputs instead if you only want to change a value. 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\").", + "type": "boolean" +}
- Changed
ha_get_app1 field changed- changed
Input schema / properties / source / descriptionPrevious value: -"App (add-on) source: 'installed' (default) for currently installed apps, 'available' for apps in the store that can be installed."New value: +"App (add-on) source: 'installed' (default) for currently installed apps, 'available' for apps in the store that can be installed. With source='available', 'version' is the version you would get by installing (Supervisor's version_latest) and 'version_installed' is the running one, null when the app is not installed โ so compare the two, not 'version' alone, to tell whether an installed app is current."
- Removed
ha_get_blueprint - Changed
ha_get_logs3 fields changed- changed
Input schema / properties / offset / descriptionPrevious value: -"Page deeper into source='logbook' and source='error_log' (ignored for other sources). On error_log it counts raw log lines back from the newest entry; pass the response's 'next_offset' to continue while 'has_more' is true."New value: +"Page deeper into source='logbook', 'error_log' and 'fault_log' (ignored for other sources). On error_log it counts raw log lines back from the newest entry; on fault_log it counts lines from the start of the assembled crash text. Pass the response's 'next_offset' to continue while 'has_more' is true." - changed
Input schema / properties / order / descriptionPrevious value: -"Sort order for time-ordered sources (logbook, system, error_log, supervisor, system_service): 'newest' (default) returns most-recent first; 'oldest' returns chronological-first. Ignored for source='logger', and for source='error_log' with structured=True (that summary is ranked by occurrence count, not by time)."New value: +"Sort order for time-ordered sources (logbook, system, error_log, supervisor, system_service, fault_log): 'newest' (default) returns most-recent first; 'oldest' returns chronological-first. Ignored for source='logger', and for source='error_log' with structured=True (that summary is ranked by occurrence count, not by time)." - changed
Input schema / properties / source / enumPrevious value: -[ - "logbook", - "system", - "error_log", - "supervisor", - "system_service", - "logger" -]New value: +[ + "logbook", + "system", + "error_log", + "supervisor", + "system_service", + "logger", + "fault_log" +]
- Changed
ha_get_overview1 field changed- changed
Input schema / properties / fields / descriptionPrevious value: -"Return only the specified top-level response keys to reduce response size (e.g. [\"system_info\", \"domains\"]). None = full response (default). Available keys: success, system_summary, domain_stats, area_analysis, ai_insights, pagination, partial, warnings, device_types, service_availability, system_info, notification_count, notifications, repair_count, dismissed_repair_count, repairs, repairs_error, tool_discovery, settings_url, settings_url_hint, read_only_mode, read_only_mode_hint, ha_mcp_update. Note: ``settings_url`` (stdio mode), ``settings_url_hint`` (standalone HTTP/Docker mode), the ``read_only_mode`` / ``read_only_mode_hint`` pair (only while Read Only Mode is on), and ``ha_mcp_update`` (when an update check applies) are emitted regardless of ``fields=`` projection so the settings page, the active mode, and a newer ha-mcp release stay discoverable; see the tool description."New value: +"Return only the specified top-level response keys to reduce response size (e.g. [\"system_info\", \"domain_stats\"]). None = full response (default). Available keys: success, system_summary, domain_stats, area_analysis, ai_insights, pagination, partial, warnings, device_types, service_availability, system_info, notification_count, notifications, repair_count, dismissed_repair_count, repairs, repairs_error, tool_discovery, settings_url, settings_url_hint, read_only_mode, read_only_mode_hint, ha_mcp_update. Note: ``settings_url`` (stdio mode), ``settings_url_hint`` (standalone HTTP/Docker mode), the ``read_only_mode`` / ``read_only_mode_hint`` pair (only while Read Only Mode is on), and ``ha_mcp_update`` (when an update check applies) are emitted regardless of ``fields=`` projection so the settings page, the active mode, and a newer ha-mcp release stay discoverable; see the tool description."
- Removed
ha_import_blueprint - Changed
ha_manage_app2 fields changed- changed
Input schema / properties / action / descriptionPrevious value: -"Lifecycle mode: run a Supervisor app (add-on) action. One of 'install', 'uninstall', 'start', 'stop', 'restart', 'rebuild', 'update'. 'install'/'update' require the app's repository to be registered (it appears in ha_get_app(source='available')). Store-repository mode: 'add_repository' / 'remove_repository' register or unregister a custom app store repository โ these use the 'repository' param instead of 'slug'. When ha-mcp runs as an app, it can update other apps but cannot update its own running slug; update ha-mcp from the Home Assistant Apps UI. Mutually exclusive with path / config parameters / array_patch. HA OS / Supervised only."New value: +"Lifecycle mode: run a Supervisor app (add-on) action. One of 'install', 'uninstall', 'start', 'stop', 'restart', 'rebuild', 'update'. 'install'/'update' require the app's repository to be registered (it appears in ha_get_app(source='available')). Store-repository mode: 'add_repository' / 'remove_repository' register or unregister a custom app store repository โ these use the 'repository' param instead of 'slug'. Store-wide mode: 'check_updates' reloads the store so Supervisor re-scans its repositories, mirroring the Apps UI 'Check for updates' item โ it takes neither 'slug' nor 'repository', refreshes available metadata only, and installs nothing. Use it to pick up an edited local app's config.yaml on demand instead of waiting for Supervisor's own reload (every 3h). Follow with action='update' to install a new version, or action='rebuild' for a local app whose source changed but whose version did not. Returns 'changed' and 'updates_available', each null (not empty) if the store could not be read to measure it โ check 'warnings'. When ha-mcp runs as an app, it can update other apps but cannot update its own running slug; update ha-mcp from the Home Assistant Apps UI. Mutually exclusive with path / config parameters / array_patch. HA OS / Supervised only." - changed
Input schema / properties / slug / descriptionPrevious value: -"App (add-on) slug (e.g., '<prefix>_nodered', '<prefix>_frigate'). Slug prefixes vary by app repository โ call ha_get_app() to discover the actual installed slug. Required for every mode except the store-repository actions (action='add_repository'/'remove_repository'), which use 'repository' instead and take no slug."New value: +"App (add-on) slug (e.g., '<prefix>_nodered', '<prefix>_frigate'). Slug prefixes vary by app repository โ call ha_get_app() to discover the actual installed slug. Required for every mode except the store-repository actions (action='add_repository'/'remove_repository'), which use 'repository' instead and take no slug, and the store-wide action (action='check_updates'), which takes neither."
- Changed
ha_manage_backup1 field changed- changed
Input schema / properties / backup_name / descriptionPrevious value: -"(edits.view / edits.restore / edits.delete) Auto-backup filename (format '<domain>.<entity_id>.<timestamp>.yaml'). Not a tarball ID."New value: +"(edits.view / edits.restore / edits.delete) Auto-backup filename (format '<domain>.<entity_id>.<timestamp>[_NN].yaml'). Not a tarball ID."
- Added
ha_manage_blueprints
1 tool update
v8.4.3- Changed
ha_search1 field changed- changed
Input schema / properties / config_time_budget / anyOfPrevious value: -[ - { - "exclusiveMinimum": 0, - "maximum": 300, - "type": "number" - }, - { - "type": "null" - } -]New value: +[ + { + "maximum": 300, + "minimum": 0.001, + "type": "number" + }, + { + "type": "null" + } +]
14 tool updates
v8.4.1- Changed
ha_bulk_control13 fields changed- added
Input schema / properties / actionAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "One device action applied to every resolved leaf." +} - added
Input schema / properties / dry_runAdded value: +{ + "default": false, + "type": "boolean" +} - added
Input schema / properties / operations / defaultAdded value: +null - added
Input schema / properties / operations / descriptionAdded value: +"Explicit entity operations. Use this or selector, never both. Each item requires exact entity_id and action. Use action='off', not service='turn_off'." - changed
Input schema / properties / operations / items / additionalPropertiesPrevious value: -trueNew value: +false - added
Input schema / properties / operations / items / descriptionAdded value: +"One entity action in a ha_bulk_control request." - added
Input schema / properties / operations / items / propertiesAdded value: +{ + "action": { + "description": "Device action such as 'on', 'off', or 'toggle'. For lights, use 'off' instead of the ha_call_service form 'turn_off'.", + "minLength": 1, + "type": "string" + }, + "entity_id": { + "description": "Exact Home Assistant entity ID, e.g. 'light.kitchen'.", + "minLength": 1, + "type": "string" + }, + "parameters": { + "additionalProperties": true, + "description": "Optional action parameters, e.g. {'brightness_pct': 30} when action='on'. Each domain has a fixed allowlist of supported keys; keys outside it are ignored rather than rejected. Use ha_call_service for parameters this tool does not carry.", + "type": "object" + }, + "timeout_seconds": { + "description": "Optional confirmation timeout. On the component path, all operations share the maximum requested wait (default 10s, capped at 60s); 0 disables confirmation waiting.", + "minimum": 0, + "type": "number" + }, + "validate_first": { + "description": "Report an ENTITY_NOT_FOUND failure when the target entity does not exist; default true. On the component batch path this is detected from the captured pre-state rather than by preventing dispatch. The action is always validated.", + "type": "boolean" + } +} - added
Input schema / properties / operations / items / requiredAdded value: +[ + "entity_id", + "action" +] - added
Input schema / properties / parametersAdded value: +{ + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional action parameters for selector mode." +} - added
Input schema / properties / selectorAdded value: +{ + "anyOf": [ + { + "additionalProperties": false, + "description": "Exact structural scope for one deterministic bulk action.\n\nLives here (not in ``tools_service.py``) so ``_SELECTOR_KEYS`` below can\nderive from this single field set instead of duplicating it as an\nindependent literal -- the import direction (``tools_service`` already\nimports from this module) makes that safe without a cycle.", + "properties": { + "area_ids": { + "description": "Exact Home Assistant area IDs to include.", + "items": { + "type": "string" + }, + "type": "array" + }, + "domain": { + "description": "Exact Home Assistant domain, e.g. 'light'.", + "type": "string" + }, + "exclude_entity_ids": { + "description": "Exact entity or aggregate IDs to exclude after recursive membership expansion.", + "items": { + "type": "string" + }, + "type": "array" + }, + "floor_ids": { + "description": "Exact Home Assistant floor IDs to include.", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "required": [ + "domain" + ], + "type": "object" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Optional exact structural scope using domain plus area_ids and/or floor_ids, with optional exclude_entity_ids." +} - added
Input schema / properties / timeout_secondsAdded value: +{ + "anyOf": [ + { + "maximum": 60, + "minimum": 0, + "type": "number" + }, + { + "type": "null" + } + ], + "default": null +} - added
Input schema / properties / validate_firstAdded value: +{ + "default": true, + "type": "boolean" +} - removed
Input schema / requiredRemoved value: -[ - "operations" -]
- Changed
ha_call_service6 fields changed- added
Input schema / properties / data / descriptionAdded value: +"Extra service-call parameters beyond entity_id (e.g. {'temperature': 22} for climate.set_temperature). Also carries the raw command payload when ws_command is set. If entity_id is also present in data, the entity_id parameter wins." - added
Input schema / properties / domain / descriptionAdded value: +"Service domain (e.g. 'light', 'climate', 'automation'). Required for a service call; must be omitted when ws_command is set." - added
Input schema / properties / entity_id / descriptionAdded value: +"Entity ID(s) the service call targets โ one ID ('light.living_room') or several comma-separated ('light.a,light.b'). Optional for services that don't target a specific entity. Must be omitted when ws_command is set." - added
Input schema / properties / return_response / descriptionAdded value: +"If True, the service's response data is returned once, as the top-level 'service_response' key โ never nested inside 'result' (default: False). Must stay False when ws_command is set." - added
Input schema / properties / service / descriptionAdded value: +"Service name within domain (e.g. 'turn_on', 'set_temperature', 'trigger'). Required for a service call; must be omitted when ws_command is set." - added
Input schema / properties / wait / descriptionAdded value: +"If True (default), wait for the entity state to change before returning. Applies only to state-changing services called with a single entity_id. A comma-separated multi-target does not get confirmed by this: it falls through to a legacy path that polls for the literal composite entity_id and times out after 10s. Set wait=False for multi-target calls."
- Changed
ha_config_get_dashboard1 field changed- changed
Input schema / properties / include_screenshot / descriptionPrevious value: -"Get mode only: also return rendered image(s) of the dashboard for visual verification. Requires the 'dashboard screenshot' beta feature + engine add-on/sidecar. If the feature is disabled the config is returned with a warning; if the engine is configured but the render fails, the call errors (the screenshot is the requested payload). Ignored in list/search mode."New value: +"Get mode only: also return rendered image(s) of the dashboard for visual verification. Requires the 'dashboard screenshot' beta feature + engine add-on/sidecar. If the feature is disabled the config is returned with a warning; if the engine is configured but the render fails, the call errors (the screenshot is the requested payload). Ignored in list/search mode. When you already have the config and only need the render, use the dedicated ha_get_dashboard_screenshot tool (registered when the same beta feature is on) โ it returns images without echoing the config."
- Changed
ha_config_set_dashboard1 field changed- changed
Input schema / properties / return_screenshot / descriptionPrevious value: -"After writing, also return rendered image(s) of the dashboard so you can see what it looks like in a single call (the dashboard creation/iteration loop). Requires the 'dashboard screenshot' beta feature + engine add-on/sidecar; if unavailable, the write result is returned with a warning."New value: +"After writing, also return rendered image(s) of the dashboard so you can see what it looks like in a single call (the dashboard creation/iteration loop). Requires the 'dashboard screenshot' beta feature + engine add-on/sidecar; if unavailable, the write result is returned with a warning. For visual re-checks after the write (no config round-trip), use the dedicated ha_get_dashboard_screenshot tool instead."
- Changed
ha_config_set_helper1 field changed- changed
Input schema / properties / config / descriptionPrevious value: -"Config dict for flow-based helper types and helper_type='config_subentry' (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). Ignored for simple helper types. Field set is delivered as data_schema on the first validation error."New value: +"Config dict for flow-based helper types and helper_type='config_subentry' (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). Ignored for simple helper types. On update it is a patch: a field you omit keeps its current value, and a field set to null is cleared where the schema allows that field to be empty. A field two steps declare gets your one value both times; pass step_values={'<step_id>': {'<field>': <value>}} to give a step its own value, or to leave it out of that step; a LIST of those objects supplies one per encounter when the flow presents a step more than once. Field set is delivered as data_schema on the first validation error."
- Changed
ha_get_app3 fields changed- changed
Input schema / properties / query / descriptionPrevious value: -"Search filter for add-on names/descriptions (only for source='available')"New value: +"App (add-on) name/description filter (only for source='available')" - changed
Input schema / properties / slug / descriptionPrevious value: -"Add-on slug for detailed info (e.g., '<prefix>_nodered'). Slug prefixes vary by add-on repository โ omit to list all add-ons and discover the actual installed slug."New value: +"App (add-on) slug for detailed info (e.g., '<prefix>_nodered'). Slug prefixes vary by app repository โ omit to list all apps and discover the actual installed slug." - changed
Input schema / properties / source / descriptionPrevious value: -"Add-on source: 'installed' (default) for currently installed add-ons, 'available' for add-ons in the store that can be installed."New value: +"App (add-on) source: 'installed' (default) for currently installed apps, 'available' for apps in the store that can be installed."
- Changed
ha_get_logs1 field changed- added
Input schema / properties / offset / descriptionAdded value: +"Page deeper into source='logbook' and source='error_log' (ignored for other sources). On error_log it counts raw log lines back from the newest entry; pass the response's 'next_offset' to continue while 'has_more' is true."
- Changed
ha_get_operation_status2 fields changed- added
Input schema / properties / timeout_seconds / minimumAdded value: +0 - changed
Input schema / properties / timeout_seconds / typePrevious value: -"integer"New value: +"number"
- Changed
ha_get_overview1 field changed- changed
Input schema / properties / fields / descriptionPrevious value: -"Return only the specified top-level response keys to reduce response size (e.g. [\"system_info\", \"domains\"]). None = full response (default). Available keys: success, system_summary, domain_stats, area_analysis, ai_insights, pagination, partial, warnings, device_types, service_availability, system_info, notification_count, notifications, repair_count, dismissed_repair_count, repairs, repairs_error, tool_discovery, settings_url, settings_url_hint, read_only_mode, read_only_mode_hint, ha_mcp_update. Note: ``settings_url`` (stdio mode), ``settings_url_hint`` (HTTP/Docker/OAuth mode), the ``read_only_mode`` / ``read_only_mode_hint`` pair (only while Read Only Mode is on), and ``ha_mcp_update`` (when an update check applies) are emitted regardless of ``fields=`` projection so the settings page, the active mode, and a newer ha-mcp release stay discoverable; see the tool description."New value: +"Return only the specified top-level response keys to reduce response size (e.g. [\"system_info\", \"domains\"]). None = full response (default). Available keys: success, system_summary, domain_stats, area_analysis, ai_insights, pagination, partial, warnings, device_types, service_availability, system_info, notification_count, notifications, repair_count, dismissed_repair_count, repairs, repairs_error, tool_discovery, settings_url, settings_url_hint, read_only_mode, read_only_mode_hint, ha_mcp_update. Note: ``settings_url`` (stdio mode), ``settings_url_hint`` (standalone HTTP/Docker mode), the ``read_only_mode`` / ``read_only_mode_hint`` pair (only while Read Only Mode is on), and ``ha_mcp_update`` (when an update check applies) are emitted regardless of ``fields=`` projection so the settings page, the active mode, and a newer ha-mcp release stay discoverable; see the tool description."
- Changed
ha_manage_app12 fields changed- changed
Input schema / properties / action / descriptionPrevious value: -"Lifecycle mode: run a Supervisor add-on action. One of 'install', 'uninstall', 'start', 'stop', 'restart', 'rebuild', 'update'. 'install'/'update' require the add-on's repository to be registered (it appears in ha_get_app(source='available')). Store-repository mode: 'add_repository' / 'remove_repository' register or unregister a custom add-on store repository โ these use the 'repository' param instead of 'slug'. Mutually exclusive with path / config parameters / array_patch. HA OS / Supervised only."New value: +"Lifecycle mode: run a Supervisor app (add-on) action. One of 'install', 'uninstall', 'start', 'stop', 'restart', 'rebuild', 'update'. 'install'/'update' require the app's repository to be registered (it appears in ha_get_app(source='available')). Store-repository mode: 'add_repository' / 'remove_repository' register or unregister a custom app store repository โ these use the 'repository' param instead of 'slug'. When ha-mcp runs as an app, it can update other apps but cannot update its own running slug; update ha-mcp from the Home Assistant Apps UI. Mutually exclusive with path / config parameters / array_patch. HA OS / Supervised only." - changed
Input schema / properties / array_patch / descriptionPrevious value: -"Array-patch mode: atomically GET a JSON array endpoint, apply ordered ops, then POST the mutated array back. Requires 'path'; mutually exclusive with body / websocket / offset / limit and config params. See the docstring Examples and ha_get_skill_guide for op shapes."New value: +"Array-patch mode: atomically GET a JSON array endpoint, apply ordered ops, then POST the mutated array back. Requires 'path'; mutually exclusive with body / websocket / offset / limit and config params. Use ha_get_skill_guide for operation shapes." - changed
Input schema / properties / auto_update / descriptionPrevious value: -"Config mode: Enable or disable automatic updates for this add-on."New value: +"Config mode: Enable or disable automatic updates for this app (add-on)." - changed
Input schema / properties / network / descriptionPrevious value: -"Config mode: Host port mappings (e.g., {'5800/tcp': 8081})."New value: +"Config mode: Complete desired host-port override map (e.g., {'5800/tcp': 8081}). A non-empty map replaces current overrides, so omitted entries are cleared. Omit 'network' to leave mappings unchanged. An empty map is ignored and does not by itself select config mode." - changed
Input schema / properties / options / descriptionPrevious value: -"Config mode: Add-on configuration values (the 'Configuration' tab in the UI)."New value: +"Config mode: App (add-on) configuration values (the 'Configuration' tab in the UI)." - changed
Input schema / properties / path / descriptionPrevious value: -"Proxy mode: API path relative to the add-on root (e.g., '/flows', '/api/events', '/api/stats'). Required for proxy mode; mutually exclusive with config parameters."New value: +"Proxy mode: API path relative to the app (add-on) root (e.g., '/flows', '/api/events', '/api/stats'). Required for proxy mode; mutually exclusive with config parameters." - changed
Input schema / properties / port / descriptionPrevious value: -"Proxy mode only. Connect to this port instead of the Ingress port. Use ha_get_app(slug='...') to find available ports."New value: +"Proxy mode only. Connect to this port instead of the Ingress port. Use ha_get_app(slug='...') to find available ports. Some apps, including Node-RED, reject direct access unless their leave_front_door_open option is enabled and the app is restarted; related errors include an actionable, security-qualified ha_manage_app options command." - changed
Input schema / properties / repository / descriptionPrevious value: -"Store-repository mode only (action='add_repository' or 'remove_repository'). For add_repository: the repository URL (e.g., 'https://github.com/balloob/home-assistant-addons'). For remove_repository: the repository slug (e.g., '0f1cc410', as shown in ha_get_app(source='available')). Required for those actions; ignored otherwise."New value: +"Store-repository mode only (action='add_repository' or 'remove_repository'). For add_repository: the repository URL (e.g., 'https://github.com/balloob/home-assistant-addons'). For remove_repository: the repository slug (e.g., '0f1cc410', as shown in ha_get_app(source='available')). Required for those actions; rejected otherwise." - changed
Input schema / properties / request_headers / descriptionPrevious value: -"Proxy/array-patch mode: extra HTTP headers to send to the addon API. Useful for addon-specific requirements such as Node-RED's `Node-RED-Deployment-Type: full`. The proxy's internal framing (`X-Ingress-Path`, `X-Hass-Source`, `Cookie`, `Content-Type`) is layered on top, so caller-supplied values for those keys are overridden. Not valid in config or websocket mode."New value: +"Proxy/array-patch mode: extra HTTP headers for the app (add-on) API. Useful for app-specific requirements such as Node-RED's `Node-RED-Deployment-Type: full`. Ingress routing headers override caller values on Ingress routes; direct-port calls have no internal routing headers. `Content-Type` is derived from the body when supplied. Not valid in config or websocket mode." - changed
Input schema / properties / slug / descriptionPrevious value: -"Add-on slug (e.g., '<prefix>_nodered', '<prefix>_frigate'). Slug prefixes vary by add-on repository โ call ha_get_app() to discover the actual installed slug. Required for every mode except the store-repository actions (action='add_repository'/'remove_repository'), which use 'repository' instead and take no slug."New value: +"App (add-on) slug (e.g., '<prefix>_nodered', '<prefix>_frigate'). Slug prefixes vary by app repository โ call ha_get_app() to discover the actual installed slug. Required for every mode except the store-repository actions (action='add_repository'/'remove_repository'), which use 'repository' instead and take no slug." - changed
Input schema / properties / wait_for_close / descriptionPrevious value: -"Proxy mode only. WebSocket: True: wait for the server to close the stream (run-to-completion ops like an ESPHome compile/validate). False: return after the first response batch โ use for a one-shot command/response or a bounded log capture on a channel that stays open (e.g. ESPHome '/ws'). Default: true."New value: +"Proxy mode only. WebSocket: True waits for the server to close a run-to-completion stream. False returns after the first response batch; use for one-shot command/response or bounded capture on a channel that stays open. Default: true." - changed
Input schema / properties / websocket / descriptionPrevious value: -"Proxy mode only. Use WebSocket instead of HTTP โ for an add-on's WebSocket API (e.g. the ESPHome dashboard's '/ws' command channel; see the docstring's ESPHome section). Sends 'body' as the initial message, collects responses. Default: false."New value: +"Proxy mode only. Use WebSocket instead of HTTP for an app (add-on) WebSocket API. Sends 'body' as the initial message and collects responses; command names and body schemas are app/version-specific. Default: false."
- Changed
ha_manage_backup2 fields changed- changed
Input schema / properties / domain / descriptionPrevious value: -"(edits.list / edits.delete) Filter auto-backups by domain (e.g. 'automation', 'helper_timer')."New value: +"(edits.create / edits.list / edits.delete) Filter auto-backups by domain (e.g. 'automation', 'helper_timer'). Required for edits.create." - changed
Input schema / properties / entity_id / descriptionPrevious value: -"(edits.list / edits.delete) Filter auto-backups by entity ID."New value: +"(edits.create / edits.list / edits.delete) Filter auto-backups by entity ID. Required for edits.create."
- Changed
ha_manage_theme5 fields changed- changed
Input schema / properties / action / descriptionPrevious value: -"Theme operation: list installed themes or set the default theme."New value: +"Theme operation: 'list' installed themes, 'set' the backend default theme, or read/restore the screenshot engine account's own per-user theme with 'get_engine_theme' / 'set_engine_theme' (a different layer from the backend default)." - changed
Input schema / properties / action / enumPrevious value: -[ - "list", - "set" -]New value: +[ + "list", + "set", + "get_engine_theme", + "set_engine_theme" +] - added
Input schema / properties / expected_currentAdded value: +{ + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Guard for action='set_engine_theme': the stored theme is read immediately before the write and the write is skipped if it no longer equals this. Omitting this value or passing null both mean 'expect no stored theme', enforced like any other value; the guard is always applied unless force is set. Best-effort, not atomic -- Home Assistant exposes no conditional write, so a change landing between that read and the write is not caught. Pass the expected_current value quoted in the screenshot tool's warning." +} - added
Input schema / properties / forceAdded value: +{ + "default": false, + "description": "action='set_engine_theme' only: skip the expected_current guard and overwrite unconditionally. Leave false unless you intend to discard whatever is stored.", + "type": "boolean" +} - added
Input schema / properties / valueAdded value: +{ + "anyOf": [ + { + "additionalProperties": true, + "type": "object" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Frontend user-data theme object when action='set_engine_theme', e.g. {'theme': '', 'dark': False}. An empty dict restores default/auto behavior. Take this verbatim from the warning a screenshot tool emitted." +}
- Changed
ha_search4 fields changed- changed
Input schema / properties / area_filter / descriptionPrevious value: -"Narrow entity-registry results to an area (id or name). Does not affect configuration search."New value: +"Narrow entity-registry results to an area (id, name, or alias), an exact floor (id, name, or alias), or an unambiguous close-spelling floor match; a floor match expands to all areas on that floor. Does not affect configuration search." - changed
Input schema / properties / config_time_budget / descriptionPrevious value: -"Per-call override for the per-id config-fetch wall-clock budget (seconds). Replaces the per-type HAMCP_*_CONFIG_TIME_BUDGET defaults for the automation, script, AND scene branches when their bulk-fetch falls through to per-id Attempt-C. Use when a `partial: True` response names time-budget skipping. Stateless per-call: one caller raising the budget doesn't affect others. None = use the per-type env defaults."New value: +"Per-call override for the per-id config-fetch wall-clock budget (seconds). Replaces the per-type HAMCP_*_CONFIG_TIME_BUDGET defaults for the automation, script, AND scene branches. Use when a `partial: True` response names time-budget skipping. Stateless per-call: one caller raising the budget doesn't affect others. None = use the per-type env defaults." - changed
Input schema / properties / query / descriptionPrevious value: -"What to search for (entity name fragment, free-text config term, entity_id). Searches BOTH the entity registry (entity_ids, friendly names, areas) AND configuration bodies (automation triggers/actions, script sequences, scene contents, helper bodies, dashboard cards) in one call. Use this for any find-something-in-HA question โ entity OR config. Omit `query` to enumerate by `domain_filter`, `area_filter`, and/or `state_filter` alone (registry-listing mode); configuration-body search is skipped in that mode because there is no term to match against."New value: +"What to search for (entity name fragment, free-text config term, entity_id). Searches BOTH the entity registry (entity_ids, friendly names, areas) AND configuration bodies (automation triggers/actions, script sequences, scene contents, helper bodies, dashboard cards) in one call. Use this for any find-something-in-HA question โ entity OR config. Pass the exact entity_id, not a name fragment, when checking what a rename or delete would break: that form reports automations, scripts and scenes referencing it even when their configuration could not be read. Omit `query` to enumerate by `domain_filter`, `area_filter`, and/or `state_filter` alone (registry-listing mode); configuration-body search is skipped in that mode because there is no term to match against." - changed
Input schema / properties / result_fields / descriptionPrevious value: -"Project each entity-registry record to only the specified keys (e.g. [\"entity_id\", \"state\"]). None = full records. Base keys: entity_id, friendly_name, domain, state, score, match_type. Opt-in enrichment keys (joined on request): area, floor, labels, aliases. An unknown key is rejected."New value: +"Project each entity-registry record to only the specified keys (e.g. [\"entity_id\", \"state\"]). None = full records. Base keys: entity_id, friendly_name, domain, state, score, match_type. Opt-in enrichment/membership keys (computed on request): area, floor, labels, aliases, is_group, member_entity_ids. Membership is recognized only when HA explicitly exposes a valid group_entities or legacy entity_id collection; member IDs are sorted, direct (not recursively expanded), and omitted if visibility/include_hidden excludes a member. is_group remains true when member IDs are withheld; requesting member_entity_ids also retains is_group. An unknown key is rejected."
- Changed
ha_set_integration1 field changed- changed
Input schema / properties / config / descriptionPrevious value: -"Flow form data. With 'domain': input for the new integration's config flow. With 'entry_id' alone: input for the entry's options flow (updates its options). Multi-step flows consume keys per step; menu steps take 'next_step_id' โ a string, or a list of successive selections for flows that present more than one menu (e.g. a menu revisited after each branch, ending in a finish option). The step's data_schema is returned on validation errors so field names can be corrected."New value: +"Flow form data. With 'domain': input for the new integration's config flow. With 'entry_id' alone: input for the entry's options flow (updates its options). Updating an existing entry โ options or reconfigure โ is a patch: a field you omit keeps its current value, and a field set to null is cleared where the integration's schema allows that field to be empty. Multi-step flows consume keys per step. A field two steps declare gets your one value both times; pass step_values={'<step_id>': {'<field>': <value>}} to give a step its own value, or to leave the field out of that step; a LIST of those objects supplies one per encounter when the flow presents a step more than once. Menu steps take 'next_step_id' โ a string, or a list of successive selections for flows that present more than one menu (e.g. a menu revisited after each branch, ending in a finish option). The step's data_schema is returned on validation errors so field names can be corrected."
10 tool updates
v8.3.0- Changed
ha_config_list_helpers1 field changed- changed
Input schema / properties / helper_type / anyOfPrevious value: -[ - { - "enum": [ - "input_button", - "input_boolean", - "input_select", - "input_number", - "input_text", - "input_datetime", - "counter", - "timer", - "schedule", - "zone", - "person", - "tag", - "all" - ], - "type": "string" - }, - { - "enum": [ - "template", - "group", - "utility_meter", - "derivative", - "min_max", - "threshold", - "integration", - "statistics", - "trend", - "random", - "filter", - "tod", - "generic_thermostat", - "switch_as_x", - "generic_hygrostat" - ], - "type": "string" - } -]New value: +[ + { + "enum": [ + "input_button", + "input_boolean", + "input_select", + "input_number", + "input_text", + "input_datetime", + "counter", + "timer", + "schedule", + "zone", + "person", + "tag", + "all" + ], + "type": "string" + }, + { + "enum": [ + "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" + ], + "type": "string" + } +]
- Changed
ha_config_set_helper2 fields changed- changed
Input schema / properties / config / descriptionPrevious value: -"Config dict for flow-based helper types and helper_type='config_subentry' (template, group, utility_meter, derivative, min_max, threshold, integration, statistics, trend, random, filter, tod, generic_thermostat, switch_as_x, generic_hygrostat). Ignored for simple helper types. Field set is delivered as data_schema on the first validation error."New value: +"Config dict for flow-based helper types and helper_type='config_subentry' (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). Ignored for simple helper types. Field set is delivered as data_schema on the first validation error." - changed
Input schema / properties / helper_type / enumPrevious value: -[ - "counter", - "config_subentry", - "derivative", - "filter", - "generic_hygrostat", - "generic_thermostat", - "group", - "input_boolean", - "input_button", - "input_datetime", - "input_number", - "input_select", - "input_text", - "integration", - "min_max", - "person", - "random", - "schedule", - "statistics", - "switch_as_x", - "tag", - "template", - "threshold", - "timer", - "tod", - "trend", - "utility_meter", - "zone" -]New value: +[ + "counter", + "config_subentry", + "derivative", + "filter", + "generic_hygrostat", + "generic_thermostat", + "group", + "history_stats", + "input_boolean", + "input_button", + "input_datetime", + "input_number", + "input_select", + "input_text", + "integration", + "min_max", + "mold_indicator", + "person", + "random", + "schedule", + "statistics", + "switch_as_x", + "tag", + "template", + "threshold", + "timer", + "tod", + "trend", + "utility_meter", + "zone" +]
- Removed
ha_get_addon - Added
ha_get_app - Changed
ha_get_logs3 fields changed- changed
Input schema / properties / order / descriptionPrevious value: -"Sort order for time-ordered sources (logbook, system, error_log, supervisor, system_service): 'newest' (default) returns most-recent first; 'oldest' returns chronological-first. Ignored for source='logger'."New value: +"Sort order for time-ordered sources (logbook, system, error_log, supervisor, system_service): 'newest' (default) returns most-recent first; 'oldest' returns chronological-first. Ignored for source='logger', and for source='error_log' with structured=True (that summary is ranked by occurrence count, not by time)." - added
Input schema / properties / structuredAdded value: +{ + "default": false, + "description": "source='error_log' only. When True, return a deduplicated, component-grouped summary of the log (counted issues sorted by frequency) instead of raw text. Use this on busy instances where the raw log is large enough to exhaust context. Ignored for other sources.", + "type": "boolean" +} - added
Input schema / properties / top_nAdded value: +{ + "anyOf": [ + { + "minimum": 1, + "type": "integer" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Max distinct issues to return when structured=True (default 20, capped at 500). Bounds the response regardless of log size." +}
- Removed
ha_manage_addon - Added
ha_manage_app - Changed
ha_manage_pipeline7 fields changed- changed
Input schema / properties / action / descriptionPrevious value: -"Pipeline operation: list, get, create, update, or set_preferred."New value: +"Pipeline operation: list, get, create, update, set_preferred, or process." - changed
Input schema / properties / action / enumPrevious value: -[ - "list", - "get", - "create", - "update", - "set_preferred" -]New value: +[ + "list", + "get", + "create", + "update", + "set_preferred", + "process" +] - added
Input schema / properties / agent_idAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "For process only, the conversation agent entity ID to answer, e.g. 'conversation.home_assistant'. Overrides the agent taken from pipeline_id; omit both for the default agent." +} - added
Input schema / properties / conversation_idAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "For process only, the conversation to continue. Returned in the response so follow-up sentences keep their context." +} - changed
Input schema / properties / language / descriptionPrevious value: -"Pipeline language, e.g. 'en'."New value: +"Pipeline language, e.g. 'en'. For process, the language to recognise the sentence in." - changed
Input schema / properties / pipeline_id / descriptionPrevious value: -"Assist pipeline ID. Required for get, update, and set_preferred."New value: +"Assist pipeline ID. Required for get, update, and set_preferred. Optional for process, where it selects the conversation agent and language that pipeline is configured with." - added
Input schema / properties / sentenceAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Natural-language command to run through Assist. Required when action='process'. A matched intent executes, and with the built-in agent a sentence matching a conversation trigger runs that automation." +}
- Changed
ha_remove_helpers_integrations1 field changed- changed
Input schema / properties / helper_type / anyOfPrevious value: -[ - { - "enum": [ - "input_button", - "input_boolean", - "input_select", - "input_number", - "input_text", - "input_datetime", - "counter", - "timer", - "schedule", - "zone", - "person", - "tag", - "config_subentry", - "template", - "group", - "utility_meter", - "derivative", - "min_max", - "threshold", - "integration", - "statistics", - "trend", - "random", - "filter", - "tod", - "generic_thermostat", - "switch_as_x", - "generic_hygrostat" - ], - "type": "string" - }, - { - "type": "null" - } -]New value: +[ + { + "enum": [ + "input_button", + "input_boolean", + "input_select", + "input_number", + "input_text", + "input_datetime", + "counter", + "timer", + "schedule", + "zone", + "person", + "tag", + "config_subentry", + "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" + ], + "type": "string" + }, + { + "type": "null" + } +]
- Changed
ha_set_integration6 fields changed- added
Input schema / properties / confirm_tokenAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Requires reconfigure=True. A token from a reconfigure preflight; applies the change. Any token still matching the entry's current state and the same requested config is accepted, so a token stays valid while nothing moves." +} - added
Input schema / properties / expected_device_idAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Requires reconfigure=True. Device registry ID the entry must still own, before and after the change." +} - added
Input schema / properties / expected_entity_idsAdded value: +{ + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Requires reconfigure=True. Exact entity IDs that must remain associated with the entry." +} - added
Input schema / properties / expected_macAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Requires reconfigure=True. MAC or IEEE the entry's device must still report." +} - added
Input schema / properties / expected_unique_idAdded value: +{ + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "default": null, + "description": "Requires reconfigure=True, AND the ha_mcp_tools custom component: Home Assistant does not expose a config entry's unique_id over its API. Without the component this is rejected โ anchor on expected_device_id, expected_mac or expected_entity_ids instead." +} - added
Input schema / properties / reconfigureAdded value: +{ + "default": false, + "description": "Use the existing config entry's official reconfigure flow (its connection settings) instead of its options flow. Without confirm_token this is a read-only preflight that returns one.", + "type": "boolean" +}
3 tool updates
v8.2.0- Changed
ha_call_service1 field changed- changed
Input schema / properties / verbose / descriptionPrevious value: -"Return HA's raw service response unchanged (default: False). Use as an escape hatch when you need the full propagation chain or raw attribute payload (debug / inspection). WARNING: brings back token-bloat for nested-group targets โ prefer result_fields / result_attribute_keys for targeted control."New value: +"Return HA's raw changed-state records unchanged (default: False). Use as an escape hatch when you need the full propagation chain or raw attribute payload (debug / inspection). With return_response=True the response data still surfaces once as the top-level service_response key, never nested in result. WARNING: brings back token-bloat for nested-group targets โ prefer result_fields / result_attribute_keys for targeted control."
- Changed
ha_manage_hacs3 fields changed- changed
Input schema / properties / action / descriptionPrevious value: -"'download' to install/update, or 'add_repository'"New value: +"'download' to install/update, 'add_repository' to register a custom repo, 'remove' to uninstall a downloaded repo, or 'update_information' to refresh a repository's release data from GitHub" - changed
Input schema / properties / action / enumPrevious value: -[ - "download", - "add_repository" -]New value: +[ + "download", + "add_repository", + "remove", + "update_information" +] - changed
Input schema / properties / repository_id / descriptionPrevious value: -"Numeric HACS ID or 'owner/repo' path (action='download')"New value: +"Numeric HACS ID or 'owner/repo' path (action='download' / 'remove' / 'update_information')"
- Changed
ha_set_integration1 field changed- changed
Input schema / properties / config / descriptionPrevious value: -"Flow form data. With 'domain': input for the new integration's config flow. With 'entry_id' alone: input for the entry's options flow (updates its options). Multi-step flows consume keys per step; menu steps take 'next_step_id'. The step's data_schema is returned on validation errors so field names can be corrected."New value: +"Flow form data. With 'domain': input for the new integration's config flow. With 'entry_id' alone: input for the entry's options flow (updates its options). Multi-step flows consume keys per step; menu steps take 'next_step_id' โ a string, or a list of successive selections for flows that present more than one menu (e.g. a menu revisited after each branch, ending in a finish option). The step's data_schema is returned on validation errors so field names can be corrected."
78 tool updates
v7.14.2- First observed
ha_bulk_control - First observed
ha_call_event - First observed
ha_call_service - First observed
ha_config_delete_dashboard - First observed
ha_config_delete_dashboard_resource - First observed
ha_config_get_automation - First observed
ha_config_get_calendar_events - First observed
ha_config_get_category - First observed
ha_config_get_dashboard - First observed
ha_config_get_label - First observed
ha_config_get_scene - First observed
ha_config_get_script - First observed
ha_config_list_dashboard_resources - First observed
ha_config_list_groups - First observed
ha_config_list_helpers - First observed
ha_config_remove_automation - First observed
ha_config_remove_calendar_event - First observed
ha_config_remove_category - First observed
ha_config_remove_group - First observed
ha_config_remove_label - First observed
ha_config_remove_scene - First observed
ha_config_remove_script - First observed
ha_config_set_automation - First observed
ha_config_set_calendar_event - First observed
ha_config_set_category - First observed
ha_config_set_dashboard - First observed
ha_config_set_dashboard_resource - First observed
ha_config_set_group - First observed
ha_config_set_helper - First observed
ha_config_set_label - First observed
ha_config_set_scene - First observed
ha_config_set_script - First observed
ha_eval_template - First observed
ha_get_addon - First observed
ha_get_automation_traces - First observed
ha_get_blueprint - First observed
ha_get_camera_image - First observed
ha_get_device - First observed
ha_get_entity - First observed
ha_get_entity_exposure - First observed
ha_get_hacs_info - First observed
ha_get_history - First observed
ha_get_integration - First observed
ha_get_logs - First observed
ha_get_operation_status - First observed
ha_get_overview - First observed
ha_get_skill_guide - First observed
ha_get_state - First observed
ha_get_system_health - First observed
ha_get_todo - First observed
ha_get_zone - First observed
ha_import_blueprint - First observed
ha_list_floors_areas - First observed
ha_list_services - First observed
ha_manage_addon - First observed
ha_manage_backup - First observed
ha_manage_energy_prefs - First observed
ha_manage_hacs - First observed
ha_manage_pipeline - First observed
ha_manage_radio - First observed
ha_manage_theme - First observed
ha_manage_updates - First observed
ha_reload_core - First observed
ha_remove_area_or_floor - First observed
ha_remove_device - First observed
ha_remove_entity - First observed
ha_remove_helpers_integrations - First observed
ha_remove_todo_item - First observed
ha_remove_zone - First observed
ha_report_issue - First observed
ha_restart - First observed
ha_search - First observed
ha_set_area_or_floor - First observed
ha_set_device - First observed
ha_set_entity - First observed
ha_set_integration - First observed
ha_set_todo_item - First observed
ha_set_zone
TDQS
Scored across 77 tools
Most tools have clearly distinct purposes (e.g., ha_get_state vs ha_get_entity vs ha_search), but there is notable overlap between configuration management tools like ha_config_set_helper and ha_set_integration for helpers, and ha_config_remove_group vs ha_remove_helpers_integrations for groups. Also, ha_config_get_dashboard has multiple modes (list, search, get) which could confuse an agent about the primary function.
The tools predominantly follow the ha_<verb>_<noun> pattern (e.g., ha_get_state, ha_config_set_automation), which is consistent. However, there are deviations like ha_bulk_control, ha_call_event, and ha_manage_radio that don't follow the strict ha_<verb>_<noun> structure, and some tools like ha_eval_template mix the pattern with a different style.
With 77 tools, this server is far above the typical well-scoped range. The high count reflects the broad domain of Home Assistant, but it overwhelms an agent with too many choices, many of which are edge-case-specific (e.g., ha_manage_theme, ha_get_dashboard_screenshot). This could lead to decision paralysis and increased risk of misselection.
The tool surface covers a wide range of Home Assistant domains: entity management, automations, scripts, scenes, dashboards, integrations, calendars, todo lists, backups, and more. There are minor gaps such as no direct tool for managing users or advanced network settings, but these are edge cases. Overall, the coverage is very comprehensive for the platform's scope.
Maintenance
Related MCP Connectors
- ZapierOAuthcom.zapier
Hosted MCP server connecting AI assistants to 9,000+ apps and 40,000+ actions via Zapier.
MCP server for AI dialogue using various LLM models via AceDataCloud
A TypeScript MCP server for Home Assistant, enabling programmatic management of entities, automatiโฆ
A comprehensive Model Context Protocol (MCP) server that enables AI assistants to interact with yoโฆ
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceAn MCP server and Home Assistant add-on that enables AI assistants to manage smart homes by creating automations, designing dashboards, and interacting with entities. It features native access to Home Assistant APIs, built-in Git versioning for safe rollbacks, and full management of HACS integrations.632MIT
- AlicenseBqualityCmaintenanceMCP server for full Home Assistant control, enabling AI agents to manage dashboards, automations, files, apps, entities, and more via REST API, WebSocket, and SSH.6686 npmMIT
- AlicenseNot gradedqualityCmaintenanceAn MCP server that enables AI assistants to control Home Assistant via natural language, including device control, automation management, and system configuration.MIT
- AlicenseAqualityCmaintenanceA self-hosted MCP server for Home Assistant that exposes full control over entity states, service calls, history, templates, and areas via local stdio, enabling AI assistants to manage your smart home.964 npmMIT