Home Assistant MCP Server
OfficialThe Home Assistant MCP server provides extensive capabilities for AI assistants to interact with and manage a Home Assistant smart home installation via natural language. It includes over 87 tools spanning:
Smart Home Control & Monitoring: Control any device by calling services, execute bulk operations, query real-time states and attributes, retrieve historical data and statistics, capture camera snapshots, and monitor system health including radio networks (Z-Wave, Zigbee, Matter, Thread).
Automations & Scripts: Create, edit, delete, and debug automations and scripts with support for triggers, conditions, actions, blueprints, and Python transforms for surgical edits; analyze execution traces.
Configuration & Organization: Manage scenes, helpers (28+ types), areas, floors, zones, labels, categories, groups, and dashboards (Lovelace) with card-level editing; manage dashboard resources.
Entity & Device Registry: Manage entities and devices: rename, assign areas/labels, enable/disable, configure voice assistant exposure, remove orphans.
Integrations & Add-ons: List, install, configure, update, enable/disable integrations; manage HACS repositories; manage add-ons (install, start/stop, configure, proxy APIs); manage add-on store repositories.
System Administration: Manage backups (full snapshots and per-entity auto-backups), restarts, core/OS/add-on/firmware updates, reload components, manage themes, get logs, system health, repairs, radio network management (Z-Wave, Zigbee, Matter, Thread), energy dashboard preferences, Assist pipelines, template evaluation.
Calendar, Todo & Blueprints: Manage calendar events (including recurring), todo items; list and import blueprints.
File & YAML Tools (beta): Safely read, write, list, delete files; edit configuration.yaml and packages.
Safety & Best Practices: Read-only mode, per-tool enable/disable and security policies, automatic edit backups, bundled skill guides.
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 "Install 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 |
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 |
All other tools work without the component. These five 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 (~84 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.
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 84.
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 returnUnknown toolwhen called. 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.
๐งช 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
78 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.
| 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?
Beyond the destructiveHint annotation, the description discloses significant behavior: result compaction defaults, verbose/projection escape hatches, WebSocket command limitations, the multi-target wait timeout fallback, and the priority of entity_id over data. This gives an agent a strong model of what happens when the tool is invoked.
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, code examples, and front-loaded purpose. It is appropriately detailed for a universal 10-parameter tool with multiple modes. Minor redundancy with the schema's parameter descriptions keeps it from being perfect.
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 tool with 10 parameters, an output schema, and multiple invocation modes, the description covers everything an agent needs: basic usage, common patterns, result-format behavior, escape hatches, and WebSocket restrictions. The output schema covers return values, so that omission is not a gap.
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 by showing parameter combinations in worked examples, explaining when ws_command replaces domain/service, and clarifying how result_fields/result_attribute_keys interact with default compaction. This is useful context beyond the raw 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 action ('Execute Home Assistant services to control entities and trigger automations') and the resource ('all Home Assistant entities'). It gives the domain.service pattern and concrete examples, making it easy to distinguish from sibling tools like ha_call_event or ha_get_state.
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: use ha_get_state() before changes, ha_search() for entity IDs, and ha_get_skill_guide for detailed service docs. It also explains when the WebSocket escape hatch is needed. However, it does not explicitly call out alternatives like ha_bulk_control or ha_call_event for batch or event-specific operations.
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 (force=True).
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 (search always uses force=True for fresh results). | |
| 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 already declare readOnlyHint and idempotentHint; the description adds substantial non-obvious behavior on top: search 'Always fetches fresh config (force=True)', YAML dashboards are never searched because 'searching one could surface resolved secrets', config bodies are withheld for unconfirmed storage mode, unknown view_path errors and 'lists the available view paths', and non-traversed shapes produce a `warnings` entry so hidden content 'is not mistaken for absent'. This is far beyond 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 the length is earned: 11 parameters and 4 modes make it genuinely complex. MODE headers, a leading summary sentence, and grouped EXAMPLES make navigation easy. Minor redundancy exists โ the screenshot guidance appears in both MODE 3 and the include_screenshot parameter โ so it is not maximally tight, but no sentence is wasted.
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 no output schema and no required parameters, the description covers everything an agent needs: return shapes per mode (metadata vs matches with python_path/jq_path vs config vs view+view_index), config_hash stability contract, error conditions, security caveats, and cross-tool workflow. The only thing absent is a literal response schema, which is not the description's job in this exercise.
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 real semantic value for parameters: mode precedence over list_only/entity_id/card_type/heading, view_path returning 'view' + 'view_index' while 'config_hash still covers the FULL config', include_config's descendant-multiplication caveat, and the python_path requiring a `config` prefix to be valid. These behaviors are not derivable from 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?
Opening sentence names a specific verb and resource ('Get dashboard info - list all dashboards, get config, or search for cards') and then enumerates four distinct modes with their activation conditions. The read-only purpose is immediately distinguishable from siblings like ha_config_set_dashboard and ha_config_delete_dashboard.
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 routes to alternatives: 'use the dedicated ha_get_dashboard_screenshot tool instead' when only a render is needed (stated twice), and the SEARCH WORKFLOW EXAMPLE shows chaining with ha_config_set_dashboard. It also gives precise mode-selection rules ('Takes precedence over the other modes', 'Active when list_only=False and no search parameters are provided') plus exclusions (YAML dashboards, strategy dashboards, default dashboard without the component).
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 two modes: full config replacement OR Python transformation.
WHEN TO USE WHICH MODE:
python_transform: RECOMMENDED for edits to existing automations. Surgical updates.
config: Use for creating new automations or full restructures.
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()"
Creates a new automation (if identifier omitted) or updates existing automation with provided configuration.
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: ha_config_set_automation( identifier="automation.morning_routine", 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 } } } )
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
| 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 | Automation entity_id or unique_id for updates. Required for python_transform. Omit to create new automation with generated unique_id. | |
| config_hash | No | 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). | |
| 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 |
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 reinforces this by detailing that updates are possible. Beyond annotations, it explains the return value (automation_id), warns about templates vs native solutions, mentions best practice warnings, and describes the two operational modes. 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 section headers, bullet points, and examples. It front-loads critical info (purpose, native vs templates, modes) and then provides detailed examples. Some redundancy in examples, but the complexity of automation creation justifies the length. 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 tool's complexity (multiple automation types, two modes, template guidelines, python transform security, output schema exists), the description covers all necessary aspects: return values, prerequisites, best practices, troubleshooting, and references to other tools. It is remarkably 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?
With 88% schema description coverage, the schema already documents most parameters, but the description adds significant meaning: detailed examples for config, extensive security rules and examples for python_transform, explanation of identifier and config_hash usage, and the BestPracticeKey parameter. The description elevates 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's purpose: 'Create or update a Home Assistant automation.' It differentiates between creation and update, covers two modes (config and python_transform), and explicitly distinguishes from sibling tools like ha_config_set_scene and ha_config_set_helper by providing comparisons in the 'Before reaching for' section.
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 guidelines: when to use config vs python_transform, prerequisites for python_transform (identifier and config_hash), and alternatives for different use cases. It includes explicit 'when to use which mode' and 'Before reaching for' guidance, making it very clear for the agent to decide.
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 two modes: full config replacement OR Python transformation.
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:
python_transform: RECOMMENDED for edits. Surgical/pattern-based updates, works on all platforms.
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 (RECOMMENDED):
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: When updating an existing dashboard, title/icon/require_admin/show_in_sidebar are also updated if explicitly provided alongside (or instead of) a config change.
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' | |
| 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. | |
| 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 (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. 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?
No contradiction with the destructiveHint annotation - the description openly states 'Replaces everything,' 'After delete/add operations, indices shift!,' and shows deletion expressions, so the destructive profile is consistent. It adds substantial behavioral context beyond the annotation: optimistic locking via config_hash, the index-shift gotcha requiring fresh hashes, the storage-mode vs YAML-mode scope boundary, the strategy-dashboard conversion limitation, and the rule that title/icon/require_admin/show_in_sidebar only update when explicitly provided.
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 headers, scannable bullets, code examples, and front-loaded critical information (mode selection, index-shift warning, default-dashboard targeting). It carries some redundancy - the python_transform examples overlap with the schema's own extensive examples, and the MODERN DASHBOARD BEST PRACTICES section is content guidance arguably better placed in the skill guide.
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 12-parameter tool with no output schema, the description is unusually complete: prerequisites, mode semantics, optimistic locking, YAML-mode exclusion, strategy-dashboard limitation, and entity-discovery workflow are all covered. Remaining gaps are minor but real - MandatoryBPS is never explained, and the write-result/return format is not 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?
Schema coverage is 92%, so the baseline is 3, but the description adds genuine value beyond the schema: the hyphenated url_path rule for new dashboards, the mode-selection semantics mapping python_transform to edits and config to full replacement, and the rationale for always fetching a fresh config_hash after structural changes. The one gap is MandatoryBPS, which remains unexplained in both the schema and the description.
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 a Home Assistant dashboard' pairs specific verbs (create/update) with a concrete resource, and the two-mode breakdown (config vs python_transform) makes the operation unambiguous. It is easily distinguished from siblings like ha_config_get_dashboard (read), ha_config_delete_dashboard (delete), and ha_config_set_scene (scenes).
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?
Gives explicit when-to-use guidance: 'python_transform: RECOMMENDED for edits... config: New dashboards only, or full restructure.' It also names alternatives for adjacent tasks - ha_config_get_dashboard for fetching structure/hashes, ha_get_overview/ha_search for entity discovery, ha_get_dashboard_screenshot for visual re-checks, and ha_config_set_yaml with a clear exclusion for YAML-mode dashboards. The MUST-call ha_get_skill_guide prerequisite is also stated up front.
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 two modes: full config replacement OR Python transformation.
WHEN TO USE WHICH MODE:
python_transform: RECOMMENDED for edits to existing scripts. Surgical updates.
config: Use for creating new scripts or full restructures.
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" } } })
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
| 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 |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already set destructiveHint=true. The description adds significant behavioral context: optimistic locking via config_hash, python transform security restrictions (allowed/forbidden operations), wait parameter for bulk operations, and best-practice checker that surfaces warnings. This exceeds 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 long but well-structured with sections, bullet points, and examples. It is front-loaded with critical usage guidance. Some redundancy exists (e.g., repeated examples), but given tool complexity, the structure is appropriate and earns 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 8 parameters, two modes, Python transform security, and integration with best-practice skills, the description covers all necessary aspects. Includes examples for both config and python_transform, references to related tools, and proactive skill content. Output schema exists, so return values are not required.
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 88%, but description adds extensive meaning: explains config sub-keys (sequence, use_blueprint, alias, etc.), python_transform with examples and allowed patterns, wait behavior, category linking to other tools, and BestPracticeKey attestation. Every parameter is 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 'Create or update a Home Assistant script', distinguishes two modes (config vs python_transform), and explicitly differentiates from sibling tool ha_config_set_automation via the 'SCRIPTS vs AUTOMATIONS' section. The verb and resource are specific, and examples confirm 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?
Provides explicit when-to-use guidance: python_transform for edits, config for new/full restructures. Requires config_hash for python_transform. Details prerequisites, best-practice preferences (native over templates), and when to use automation instead. Examples cover multiple scenarios.
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. | |
| 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 cover read-only/idempotent behavior, and the description adds beyond that: the requirement for Home Assistant OS or Supervised and the mode-specific applicability of include_stats. No contradiction with the annotations; it doesn't discuss potential failures or return shape, but the output schema covers return details.
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?
Three short paragraphs front-load the purpose, then give routing guidance and constraints. Every sentence carries useful information, and there is no filler or redundant explanation.
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 five optional parameters with mode-specific behavior, an output schema, and read-only annotations, the description covers the essential usage modes, exclusions, and environment requirements. An agent has enough context to select and call 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?
Schema description coverage is 100%, so the baseline is 3. The main description rephrases the schema's mode guidance (slug, source, include_stats) but does not add substantive new meaning to the parameters beyond what the schema already documents.
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 installed or available Home Assistant apps (add-ons), or details for one.' It clearly distinguishes this read-only retrieval tool from the sibling ha_manage_app by stating it is not for changing state or configuration.
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 gives explicit routing: use ha_manage_app for changes, slug for details, source='installed' for inventory, and source='available' for store discovery. It also states the environment prerequisite (Home Assistant OS or Supervised), leaving little ambiguity about when to invoke this tool.
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_blueprintGet BlueprintARead-onlyIdempotent
Get blueprint information - list all blueprints or get details for a specific one.
Without a path: Lists all installed blueprints for the specified domain.
With a path: Returns the blueprint's metadata and input definitions. The
full body (triggers/conditions/actions for automations, sequence for
scripts) is included under config ONLY when the ha_mcp_tools custom
component is installed โ core's blueprint API exposes metadata alone, so
without the component the body cannot be read.
EXAMPLES:
List all automation blueprints: ha_get_blueprint(domain="automation")
List script blueprints: ha_get_blueprint(domain="script")
Get specific blueprint: ha_get_blueprint(path="homeassistant/motion_light.yaml", domain="automation")
RETURNS (when listing):
List of blueprints with path, name, and domain information
Count of blueprints found
RETURNS (when getting specific blueprint):
Blueprint metadata (name, description, author, source_url)
Input definitions with selectors and defaults
config: the full parsed blueprint body (only with the ha_mcp_tools component;!inputsubstitution points appear as{"__input__": name})
| Name | Required | Description | Default |
|---|---|---|---|
| path | No | Blueprint path to get details for (e.g., 'homeassistant/motion_light.yaml'). If omitted, lists all blueprints in the domain. | |
| domain | No | Blueprint domain: 'automation' or 'script' | automation |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Discloses critical behavior: the `config` key is only available with the ha_mcp_tools custom component. Annotations already indicate readOnly, idempotent, open world, and description adds 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 for general description, mode explanation, examples, and return values. Front-loaded with main purpose. Slightly long but 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?
Fully covers the tool's complexity: two modes, conditional behavior of `config`, return structures. No gaps given the output schema exists and is 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?
Schema covers 100% of parameters with descriptions. The description adds context by explaining the effect of each parameter (e.g., path omission triggers listing) and provides examples.
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 tool gets blueprint information, distinguishing between listing all blueprints and getting details for a specific one. The verb and resource are explicit, and it differentiates from sibling tools like ha_import_blueprint.
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?
Describes when to use without path (list all) and with path (get details), with concrete examples. Does not explicitly compare to alternatives but the context is sufficient.
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
Retrieve 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.
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="7d", 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 indicate readOnlyHint=true and idempotentHint=true, but the description adds significant behavioral context: data retention durations (10 days for history, permanent for statistics), client-side slicing of limit/offset, per-entity application of pagination, and the fact that order is ignored for statistics. This goes well beyond the annotations to fully disclose tool 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 well-structured with sections for sources, shared/history/statistics params, warnings, and examples. It is front-loaded with the core purpose, uses bullet points for readability, and every sentence provides useful information. Despite its length, it is concise and avoids 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 (two data sources, pagination, multiple parameter interactions), the description covers all essential aspects: default time ranges, offset limitations, client-side slicing, order behavior, and examples for both modes. With an output schema present, no further detail on return values is needed. The description is fully complete for agent decision-making.
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 the input schema already has 100% description coverage, the description adds substantial meaning by explaining parameter behavior across sources, providing defaults, and offering examples that illustrate parameter combinations. It clarifies interactions like limit and offset per entity, and which parameters are ignored in each mode, adding 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 retrieves historical data from Home Assistant's recorder, specifying two distinct sources ('history' and 'statistics') and their use cases. This distinguishes it from sibling tools like ha_get_state or ha_get_entity, which handle current state or entity configuration. The purpose is specific and actionable.
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 for each source, with concrete examples like 'Troubleshooting why a value changed' for history and 'Tracking long-term trends beyond 10 days' for statistics. It also includes warnings about limit/offset behavior, offset constraints with multiple entities, and pagination hints, making it clear when and how to use the tool correctly.
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)
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); 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.
Logbook params: hours_back, entity_id, end_time, compact (default True โ strips attribute dicts to save context)
Pagination (logbook + error_log): offset pages deeper; ignored for the
other sources. 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): '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' 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. | |
| 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 already declare readOnlyHint=true, openWorldHint=false, and idempotentHint=true, and the description adds substantial behavioral context beyond those: pagination semantics, bounded windows, per-source ordering behavior, structured-mode ranking, and what response fields like has_more and next_offset mean. It also exposes nuanced caveats like system_log counts running since first occurrence versus error_log's windowed counts. 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 the structure is excellent: bold source headers, bulleted groups, and shared-parameter sections make it scannable. Some sentences are dense and could be trimmed, but for a 13-parameter, six-source tool the length is largely justified.
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 operational concerns: source selection, default source, pagination, ordering, structured versus raw modes, slug requirements, and filtering. An output schema exists, so the description does not need to re-document return values. Nothing an agent needs to call or route this tool correctly 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?
Schema description coverage is only 31%, so the description carries the burden, and it does so thoroughly. It explains shared params (limit, search), source-specific params (level, structured, top_n, slug), when order is ignored, how offset paginates for logbook versus error_log, and what compact strips. Every parameter is given semantic meaning beyond its bare schema type.
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: 'Get Home Assistant logs from various sources,' then enumerates six distinct log sources with clear semantics. This differentiates ha_get_logs from sibling tools like ha_get_history and ha_get_system_health without 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?
The description provides explicit routing guidance, such as 'Prefer source="system" for triage' and when to use error_log with structured=True. It also names ha_get_app as the way to list installed slugs. It does not explicitly contrast this tool with ha_get_history, so it stops short of full alternative-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_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).
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", "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. | |
| 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?
The description discloses non-obvious behaviors beyond annotations: settings_url only appears when the sidecar is running and is emitted regardless of fields= projection; settings_url_hint appears in HTTP/Docker modes; ha_mcp_update is omitted under unknown version or HA_MCP_DISABLE_UPDATE_CHECK; counts/states_summary are complete regardless of pagination. This is rich, actionable behavioral context that annotations alone do not 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 long but every sentence adds unique information, and it is front-loaded with the core purpose and default behavior before edge cases. The structure is coherent (main purpose, pagination, fields projection, settings_url, update object). It slightly overexplains settings_url variants, but the added detail is operationally relevant for the 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?
The tool has 10 optional parameters, an output schema, and complex conditional behavior. The description covers mode-dependent fields, override behavior, user handoff instructions, and update-check logic. The output schema covers return values, so the description reasonably focuses on conditions and side effects. Nothing needed for correct invocation appears to be 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 every parameter. The description adds context for fields= and detail_level and mentions offset/domains, but most parameter semantics are already in the schema. Baseline 3 applies; the description doesn't need to compensate.
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'), a clear resource ('system overview'), and adds 'AI-friendly ... with intelligent categorization', which sets it apart from sibling getters like ha_get_system_health and ha_get_entity. It names the main contents (base_url, version, location, timezone, entity overview, notifications), so an agent can tell exactly what this tool returns.
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 guidance is abundant: 'Use minimal (default) for most queries', 'Use fields= to project the response', 'Use domains filter to narrow scope', and 'Use with offset for pagination'. It also directs user-facing handling of settings_url and ha_mcp_update. This clearly tells the agent when and how to use the tool, including alternatives like pagination controls.
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_import_blueprintImport BlueprintADestructive
Import a blueprint from a URL.
Imports a blueprint from GitHub, Home Assistant Community forums, or any direct URL to a blueprint YAML file. Set overwrite=true to re-import a blueprint that is already installed (equivalent to the UI's "Re-import blueprint" action) - Home Assistant then reloads all automations/scripts that use it.
EXAMPLES:
Import from GitHub: ha_import_blueprint("https://github.com/user/repo/blob/main/blueprint.yaml")
Import from HA Community: ha_import_blueprint("https://community.home-assistant.io/t/motion-light/123456")
Import direct YAML: ha_import_blueprint("https://example.com/my-blueprint.yaml")
Re-import an installed blueprint: ha_import_blueprint("https://example.com/my-blueprint.yaml", overwrite=True)
SUPPORTED SOURCES:
GitHub repository URLs (will be converted to raw URLs)
Home Assistant Community forum posts with blueprint code
Direct URLs to YAML blueprint files
RETURNS:
Import result with the blueprint path where it was saved
Blueprint metadata (name, domain, description)
overrides_existing: true when an installed blueprint was overwritten
Error details if import fails
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | URL to import blueprint from (GitHub, Home Assistant Community, or direct YAML URL) | |
| overwrite | No | Overwrite the blueprint if it is already installed (re-import). Home Assistant reloads all automations/scripts using the blueprint. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations include openWorldHint and destructiveHint, and the description adds valuable context: overwrite=true triggers reload of automations/scripts, conversion of URLs to raw, and return of error details. No contradiction. The description supplements the annotations effectively.
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, examples, supported sources, returns). Every sentence serves a purpose, and the length is appropriate for the tool's complexity. No extraneous text.
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, the description still explains return values (import result, metadata, overrides_existing, error details). It covers input, behavior, output, and examples comprehensively for a moderately 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?
Input schema covers 100% of parameters with descriptions. The description adds examples of URL formats, explains the overwrite flag's effect, and lists supported sources. Despite high schema coverage, the description provides substantial additional meaning beyond the schema itself.
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 'Import a blueprint from a URL', specifying the verb (import), resource (blueprint), and source (URL). It distinguishes from sibling tools like ha_get_blueprint (which retrievs existing blueprints) and ha_manage_hacs. No tautology; the purpose is 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 explains when to use the tool (importing blueprints from various sources) and provides examples and supported sources. It also describes the overwrite behavior and re-import action. However, it lacks explicit when-not scenarios or direct comparisons to alternatives, which would earn a 5.
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. | |
| 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'. 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?
Annotations already signal destructive and non-idempotent behavior, and the description adds substantial behavioral context: options merge only shallowly, network replaces the full port map, unknown write outcomes should be verified with ha_get_app, restart/rebuild cannot be proven and should not be automatically replayed, and direct-port access may require weakening authentication. This goes well beyond 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 prose is front-loaded with purpose and mode selection, and the length is justified by the tool's 23-parameter complexity. The only deduction is for the trailing keyword list ('manage app apps addon add-on ...'), which adds bulk without aiding an agent's selection or invocation decision.
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 this complex, the description covers all major operational concerns: mode selection, prerequisites, discovery via ha_get_app, schema uncertainty, destructive-write verification, and fallback to ha_get_skill_guide. An output schema exists, so the absence of return-value detail is not a gap.
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 critical cross-parameter semantics: mode exclusivity, the difference between slug and repository, the shallow-merge behavior of options, the full-replacement behavior of network, and the array_patch GET-then-POST flow. These insights are not inferable from the parameter descriptions 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 opens with a specific verb and resource: 'Manage Home Assistant apps (add-ons) or proxy an app API.' It clearly differentiates from the sibling ha_get_app by assigning inventory, status, and metadata reads to that tool, while this tool covers lifecycle, configuration, proxy, and store actions.
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: call ha_get_app first for inventory/status, use proxy mode only for documented app-specific read APIs, do not infer private schemas, and consult ha_get_skill_guide for complex workflows. It also names exclusions and prerequisites such as 'Requires Home Assistant OS or Supervised' and the 'exactly one mode' rule.
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. Creates a fresh safety snapshot first. 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.
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>.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?
This is exemplary transparency. It discloses that snapshot restore restarts HA, snapshot delete is disabled by default and layered with guards (age floor, not delete newest, no scheduled backups), edits restore creates a safety snapshot first and does not restart HA, list/diff are read-only, and create sends progress heartbeats. This goes far beyond the destructiveHint annotation and aligns with 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 long, but the tool is genuinely complex: two scopes ร six actions with different parameter sets and safety guards. The table, section headers, and example list make the length navigable and front-loaded. No filler or redundant prose; each section 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?
For a tool with 11 parameters, two scopes, six actions, destructive operations, and configuration toggles, the description covers everything an agent needs: valid combinations, safety locks, operational side effects, when to use alternatives, and concrete invocation examples. The output schema exists, so return-value documentation is not required here.
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 substantial semantic value: backup_name format, backup_id example, confirm requirement for snapshot.delete, older_than_days bulk deletion, restore_database default false, and domain/entity_id requirements for edits.create. The examples map parameter combinations to concrete calls, eliminating ambiguity about which params apply to which scope/action.
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: 'Manage Home Assistant backups โ both full HA snapshots AND per-edit auto-backups.' The scope/action table enumerates every supported combination, so an agent immediately understands what the tool does and how it differs from sibling tools like ha_manage_app or ha_manage_updates.
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 has an explicit 'When to use which scope' section, telling the agent to use scope='edits' for undoing recent edits and scope='snapshot' only for system-wide recovery. It also warns when the tool is NOT needed ('If the current definition was fetched or can be fetched, this tool is usually not needed'), plus safety preconditions such as enable_snapshot_delete and confirm=True.
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. Cannot be undone.
| 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 provide destructiveHint=true and idempotentHint=true, but the description goes far beyond: it details three backend mechanisms, routing paths, missing-target error codes, idempotency behavior, transient failure codes, and a warning about dependencies. This adds critical context beyond 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 every section earns its place: WHEN NOT TO USE, SUPPORTED HELPER TYPES, ROUTING, MISSING-TARGET CONTRACT, EXAMPLES, and WARNING. It is well-structured, front-loaded with a summary, and uses clear headings, making it easy to navigate despite 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?
Given the tool's complexity (5 parameters, multiple routing paths, error handling) and the presence of an output schema, the description is exceptionally complete. It covers all use cases, error codes, examples, and risk warnings, leaving no gaps 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 100%, the description adds substantial meaning: it explains the four target shapes, the helper_type routing, the difference between helper_id and entity_id, and the config_subentry case. This goes well beyond the schema's property descriptions, enriching agent understanding.
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: 'Remove a Home Assistant helper or integration config entry.' It specifies the verb (remove) and resource (helper/integration config entry) and distinguishes from sibling tools like ha_remove_entity, which is explicitly mentioned in the WHEN NOT TO USE section.
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 guidance naming alternatives (ha_remove_entity) and covers YAML-configured helpers. It also explains routing paths based on helper_type, giving clear criteria for when to use this tool vs others.
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. Dates show when Glama detected each change.
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
The tool set covers many distinct Home Assistant domains (automation, script, dashboard, entity, helper, integration, device, calendar, todo, etc.), but there is significant overlap between some tools, e.g. ha_config_set_automation vs ha_config_set_script vs ha_config_set_helper, and ha_set_entity vs ha_set_device vs ha_manage_* tools. Also ha_manage_app and ha_manage_updates have overlapping lifecycle actions. However, descriptions are detailed and often clarify when to use each, so an agent can usually disambiguate.
Names mostly follow a consistent pattern: ha_config_get/set/remove_<resource> for configuration, ha_get_<resource> for read, ha_set_<resource> for write, ha_call_service, ha_manage_<resource> for management actions. There are some deviations like ha_bulk_control, ha_get_overview, and ha_config_list_helpers vs ha_config_get_dashboard, but overall the convention is predictable.
78 tools is far beyond the typical well-scoped server size (3-15). The server attempts to cover an enormous range of Home Assistant functionality, which is ambitious but results in a heavy, bloated tool surface. Many tools are highly specialized (e.g. ha_config_list_dashboard_resources, ha_manage_energy_prefs, ha_get_entity_exposure) and could be merged or omitted, but the count is not extreme enough to warrant a 1.
The tool surface is remarkably extensive and covers almost every aspect of Home Assistant management: configuration CRUD for automations/scripts/scenes/dashboards/helpers, entity registry management, state/service calls, history/logs, system health, backups, updates, HACS, and integrations. Some gaps exist (e.g. no direct tool for managing YAML configuration files beyond ha_config_set_yaml, no dedicated tool for creating templates beyond ha_config_set_helper), but most workflows are covered.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
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 gradedqualityCmaintenanceAn 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.619MIT
- AlicenseAqualityCmaintenanceMCP server for full Home Assistant control, enabling AI agents to manage dashboards, automations, files, apps, entities, and more via REST API, WebSocket, and SSH.6692MIT
- AlicenseNot gradedqualityCmaintenanceAn MCP server that enables AI assistants to control Home Assistant via natural language, including device control, automation management, and system configuration.MIT
- AlicenseAqualityBmaintenanceA 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.991MIT
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/homeassistant-ai/ha-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server