Skip to content

Commit 252320f

Browse files
chore(internal): sync tool docs after merge [skip ci]
1 parent 32ea392 commit 252320f

1 file changed

Lines changed: 4 additions & 4 deletions

File tree

site/src/data/tools.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
{
4040
"name": "ha_manage_addon",
4141
"title": "Manage Add-on",
42-
"description": "Manage a Home Assistant add-on — update its configuration or call its internal API.\n\nFive mutually exclusive operating modes:\n\n**Lifecycle mode** (when ``action`` is one of install/uninstall/start/\nstop/restart/rebuild/update):\nRuns a Supervisor add-on action on ``slug``. ``install`` / ``update`` go\nthrough the store (the add-on's repository must be registered — it shows\nup in ``ha_get_addon(source=\"available\")``); the rest act on an installed\nadd-on. This is how an assistant brings an add-on online for the user\n(e.g. installing + starting the dashboard screenshot engine).\n\n**Store-repository mode** (when ``action`` is ``add_repository`` or\n``remove_repository``):\nRegisters or unregisters a custom add-on store repository. These actions\noperate on the store rather than an installed add-on, so they take the\n``repository`` param and no ``slug``: ``add_repository`` POSTs the\nrepository URL to ``/store/repositories``; ``remove_repository`` DELETEs\n``/store/repositories/{slug}`` by the repository's slug. Adding a\nrepository (e.g. balloob's add-ons) is the missing step that lets an\nassistant then install an add-on from it via ``action=\"install\"``.\n\n**Config mode** (when any of options/network/boot/auto_update/watchdog is provided):\nUpdates the add-on's Supervisor configuration via POST /addons/{slug}/options.\nAll config parameters are optional; only provided fields are updated — current values\nare fetched and merged automatically (including one level of nested dicts).\n\n**Proxy mode** (when path is provided without array_patch):\nRoutes HTTP or WebSocket requests through Home Assistant's Ingress\nproxy by default (works on HAOS, Supervised, and off-host PyPI/uvx\ninstalls). Pass `port=...` to bypass Ingress and connect directly to\nan add-on's container port — that mode requires the MCP host to\nshare Home Assistant's container network (i.e. only the HAOS addon).\nUse ha_get_addon(slug=\"...\") to discover available ports and endpoints.\n\n**Array-patch mode** (when path AND array_patch are provided):\nAtomic \"GET array, mutate, POST array\" workflow for addon APIs whose write\ncontract is \"send the whole resource collection back\". Operations are applied\nin order to a working copy; if any op fails validation (unknown id, collision,\nmalformed shape) nothing is posted. Returns a compact summary instead of the\nfull array. Designed for Node-RED /flows and similar endpoints.\n\n**Response shaping (proxy mode):**\n- WebSocket streams can be noisy (ESPHome /validate often emits hundreds of\n config-dump lines). By default, `summarize=True` collapses long runs of\n non-signal messages into short elision markers; INFO/WARNING/ERROR/exit\n lines always pass through. Pagination via `message_offset` / `message_limit`\n works on the raw collected list before summarize runs.\n- `python_transform` applies a sandboxed Python expression as a final\n post-processing step in both HTTP and WebSocket modes. The variable\n `response` is bound to:\n * WebSocket: `list[dict | str]` — parsed JSON messages are dicts,\n undecodable frames stay as ANSI-stripped strings. Elision markers\n appear as `{\"elided\": N, \"note\": \"...\"}` dicts when summarize ran.\n * HTTP: `dict | list | str` — whichever the content-type produced.\n Transforms may mutate in place (response.append(...), del response[k])\n or reassign (response = [...]). This is post-processing only — it does\n NOT provide optimistic-locking or write-back semantics.\n\n**WARNING:** Setting boot=\"auto\"/\"manual\" will fail for add-ons whose Supervisor\nmetadata locks the boot mode. The Supervisor returns an error in this case.\n\n**NOTE:** This tool only works with Home Assistant OS or Supervised installations.\n\n**Examples:**\n- Install an add-on: ha_manage_addon(slug=\"...\", action=\"install\")\n- Start an add-on: ha_manage_addon(slug=\"...\", action=\"start\")\n- Add a store repository: ha_manage_addon(action=\"add_repository\", repository=\"https://github.com/balloob/home-assistant-addons\")\n- Remove a store repository: ha_manage_addon(action=\"remove_repository\", repository=\"0f1cc410\")\n- Set add-on option: ha_manage_addon(slug=\"...\", options={\"log_level\": \"debug\"})\n Note: only the fields you provide are updated — current values are fetched first\n and merged automatically. Fields not in the add-on's schema are ignored with a warning.\n- Disable auto-update: ha_manage_addon(slug=\"...\", auto_update=False)\n- Change host port: ha_manage_addon(slug=\"...\", network={\"5800/tcp\": 8082})\n- Set boot mode: ha_manage_addon(slug=\"...\", boot=\"manual\")\n- Call HTTP API: ha_manage_addon(slug=\"...\", path=\"/api/events\")\n- Direct port: ha_manage_addon(slug=\"...\", path=\"/flows\", port=1880)\n- WebSocket: ha_manage_addon(slug=\"...\", path=\"/validate\", port=6052, websocket=True, body={\"type\": \"spawn\", \"configuration\": \"device.yaml\"})\n- Quick WS health check (50 msgs, raw): ha_manage_addon(slug=\"...\", path=\"/logs\", websocket=True, message_limit=50, summarize=False)\n- Filter WS errors only: ha_manage_addon(slug=\"...\", path=\"/validate\", websocket=True, python_transform=\"response = [m for m in response if 'ERROR' in str(m) or 'WARN' in str(m)]\")\n- HTTP subset: ha_manage_addon(slug=\"...\", path=\"/flows\", python_transform=\"response = [f['id'] for f in response]\")\n- Array-patch (Node-RED, rename a node):\n ha_manage_addon(\n slug=\"a0d7b954_nodered\", path=\"/flows\",\n array_patch={\"operations\": [\n {\"op\": \"patch\", \"id\": \"abc123\", \"patches\": {\"name\": \"New Name\"}},\n ]},\n )\n- Array-patch (Node-RED, replace one tab's nodes atomically):\n ha_manage_addon(\n slug=\"a0d7b954_nodered\", path=\"/flows\",\n array_patch={\"operations\": [\n {\"op\": \"delete_where\", \"field\": \"z\", \"value\": \"tab-id\"},\n {\"op\": \"add\", \"item\": {\"id\": \"n1\", \"type\": \"inject\", \"z\": \"tab-id\", ...}},\n {\"op\": \"add\", \"item\": {\"id\": \"n2\", \"type\": \"function\", \"z\": \"tab-id\", ...}},\n ]},\n request_headers={\"Node-RED-Deployment-Type\": \"full\"},\n )\n- Custom request headers (proxy mode):\n ha_manage_addon(slug=\"...\", path=\"/api/state\",\n request_headers={\"Accept\": \"text/plain\"})",
42+
"description": "Manage a Home Assistant add-on — update its configuration or call its internal API.\n\nFive mutually exclusive operating modes:\n\n**Lifecycle mode** (when ``action`` is one of install/uninstall/start/\nstop/restart/rebuild/update):\nRuns a Supervisor add-on action on ``slug``. ``install`` / ``update`` go\nthrough the store (the add-on's repository must be registered — it shows\nup in ``ha_get_addon(source=\"available\")``); the rest act on an installed\nadd-on. This is how an assistant brings an add-on online for the user\n(e.g. installing + starting the dashboard screenshot engine).\n\n**Store-repository mode** (when ``action`` is ``add_repository`` or\n``remove_repository``):\nRegisters or unregisters a custom add-on store repository. These actions\noperate on the store rather than an installed add-on, so they take the\n``repository`` param and no ``slug``: ``add_repository`` POSTs the\nrepository URL to ``/store/repositories``; ``remove_repository`` DELETEs\n``/store/repositories/{slug}`` by the repository's slug. Adding a\nrepository (e.g. balloob's add-ons) is the missing step that lets an\nassistant then install an add-on from it via ``action=\"install\"``.\n\n**Config mode** (when any of options/network/boot/auto_update/watchdog is provided):\nUpdates the add-on's Supervisor configuration via POST /addons/{slug}/options.\nAll config parameters are optional; only provided fields are updated — current values\nare fetched and merged automatically (including one level of nested dicts).\n\n**Proxy mode** (when path is provided without array_patch):\nRoutes HTTP or WebSocket requests through Home Assistant's Ingress\nproxy by default (works on HAOS, Supervised, and off-host PyPI/uvx\ninstalls). Pass `port=...` to bypass Ingress and connect directly to\nan add-on's container port — that mode requires the MCP host to\nshare Home Assistant's container network (i.e. only the HAOS addon).\nUse ha_get_addon(slug=\"...\") to discover available ports and endpoints.\n\n**ESPHome Device Builder dashboard (current rewrite):** config and log\naccess is a WebSocket JSON-command API, NOT REST. The legacy endpoints\nare gone — `GET /edit?configuration=` now returns the dashboard SPA, and\nthe old `/compile` `/validate` `/logs` WebSocket paths (which took\n`{\"type\": \"spawn\", ...}` bodies) reject the upgrade (HTTP 200). Use\ninstead:\n- HTTP `GET /devices` → JSON list of configured devices; each entry's\n `configuration` field is the YAML filename to pass below.\n- WebSocket `path=\"/ws\"` with body\n `{\"command\": \"<cmd>\", \"message_id\": \"1\", \"args\": {...}}`. The server\n sends a `server_info` message first, then one reply per `message_id`.\n Wire-confirmed commands: `devices/get_config` `{configuration}` → raw\n YAML (in the reply's `result`); `devices/logs` (stream)\n `{configuration, port: \"OTA\"}` → live device logs. Also exposed by the\n dashboard frontend (command/arg names not wire-tested here):\n `devices/update_config` `{configuration, content}` → save,\n `devices/validate`, `firmware/compile`.\n- The `/ws` channel stays open, so for a one-shot read or a bounded log\n capture pass `wait_for_close=False` with `message_limit` (and\n `message_offset` to skip the server_info / config-banner preamble).\n Reach the dashboard through Ingress — omit `port`; direct `port=` does\n not route to it.\n\n**Array-patch mode** (when path AND array_patch are provided):\nAtomic \"GET array, mutate, POST array\" workflow for addon APIs whose write\ncontract is \"send the whole resource collection back\". Operations are applied\nin order to a working copy; if any op fails validation (unknown id, collision,\nmalformed shape) nothing is posted. Returns a compact summary instead of the\nfull array. Designed for Node-RED /flows and similar endpoints.\n\n**Response shaping (proxy mode):**\n- WebSocket streams can be noisy (e.g. the ESPHome dashboard's devices/logs\n dumps the device's full config banner on connect). By default, `summarize=True` collapses long runs of\n non-signal messages into short elision markers; INFO/WARNING/ERROR/exit\n lines always pass through. Pagination via `message_offset` / `message_limit`\n works on the raw collected list before summarize runs.\n- `python_transform` applies a sandboxed Python expression as a final\n post-processing step in both HTTP and WebSocket modes. The variable\n `response` is bound to:\n * WebSocket: `list[dict | str]` — parsed JSON messages are dicts,\n undecodable frames stay as ANSI-stripped strings. Elision markers\n appear as `{\"elided\": N, \"note\": \"...\"}` dicts when summarize ran.\n * HTTP: `dict | list | str` — whichever the content-type produced.\n Transforms may mutate in place (response.append(...), del response[k])\n or reassign (response = [...]). This is post-processing only — it does\n NOT provide optimistic-locking or write-back semantics.\n\n**WARNING:** Setting boot=\"auto\"/\"manual\" will fail for add-ons whose Supervisor\nmetadata locks the boot mode. The Supervisor returns an error in this case.\n\n**NOTE:** This tool only works with Home Assistant OS or Supervised installations.\n\n**Examples:**\n- Install an add-on: ha_manage_addon(slug=\"...\", action=\"install\")\n- Start an add-on: ha_manage_addon(slug=\"...\", action=\"start\")\n- Add a store repository: ha_manage_addon(action=\"add_repository\", repository=\"https://github.com/balloob/home-assistant-addons\")\n- Remove a store repository: ha_manage_addon(action=\"remove_repository\", repository=\"0f1cc410\")\n- Set add-on option: ha_manage_addon(slug=\"...\", options={\"log_level\": \"debug\"})\n Note: only the fields you provide are updated — current values are fetched first\n and merged automatically. Fields not in the add-on's schema are ignored with a warning.\n- Disable auto-update: ha_manage_addon(slug=\"...\", auto_update=False)\n- Change host port: ha_manage_addon(slug=\"...\", network={\"5800/tcp\": 8082})\n- Set boot mode: ha_manage_addon(slug=\"...\", boot=\"manual\")\n- Call HTTP API: ha_manage_addon(slug=\"...\", path=\"/api/events\")\n- Direct port: ha_manage_addon(slug=\"...\", path=\"/flows\", port=1880)\n- ESPHome list devices (HTTP): ha_manage_addon(slug=\"<prefix>_esphome\", path=\"/devices\")\n- ESPHome read a device's YAML (WS one-shot): ha_manage_addon(slug=\"<prefix>_esphome\", path=\"/ws\", websocket=True, wait_for_close=False, message_limit=2, body={\"command\": \"devices/get_config\", \"message_id\": \"1\", \"args\": {\"configuration\": \"device.yaml\"}})\n- ESPHome live logs (WS, bounded): ha_manage_addon(slug=\"<prefix>_esphome\", path=\"/ws\", websocket=True, wait_for_close=False, message_limit=60, body={\"command\": \"devices/logs\", \"message_id\": \"1\", \"args\": {\"configuration\": \"device.yaml\", \"port\": \"OTA\"}})\n- Filter WS errors only: ha_manage_addon(slug=\"...\", path=\"/ws\", websocket=True, python_transform=\"response = [m for m in response if 'ERROR' in str(m) or 'WARN' in str(m)]\")\n- HTTP subset: ha_manage_addon(slug=\"...\", path=\"/flows\", python_transform=\"response = [f['id'] for f in response]\")\n- Array-patch (Node-RED, rename a node):\n ha_manage_addon(\n slug=\"a0d7b954_nodered\", path=\"/flows\",\n array_patch={\"operations\": [\n {\"op\": \"patch\", \"id\": \"abc123\", \"patches\": {\"name\": \"New Name\"}},\n ]},\n )\n- Array-patch (Node-RED, replace one tab's nodes atomically):\n ha_manage_addon(\n slug=\"a0d7b954_nodered\", path=\"/flows\",\n array_patch={\"operations\": [\n {\"op\": \"delete_where\", \"field\": \"z\", \"value\": \"tab-id\"},\n {\"op\": \"add\", \"item\": {\"id\": \"n1\", \"type\": \"inject\", \"z\": \"tab-id\", ...}},\n {\"op\": \"add\", \"item\": {\"id\": \"n2\", \"type\": \"function\", \"z\": \"tab-id\", ...}},\n ]},\n request_headers={\"Node-RED-Deployment-Type\": \"full\"},\n )\n- Custom request headers (proxy mode):\n ha_manage_addon(slug=\"...\", path=\"/api/state\",\n request_headers={\"Accept\": \"text/plain\"})",
4343
"inputSchema": {
4444
"properties": {
4545
"slug": {
@@ -55,7 +55,7 @@
5555
"default": "GET"
5656
},
5757
"body": {
58-
"type": "Annotated[dict[str, Any] | str | None, Field(description='Proxy mode only. Request body for POST/PUT/PATCH. Pass a JSON object or JSON string.', default=None)]",
58+
"type": "Annotated[dict[str, Any] | str | None, Field(description='Proxy mode only. Request body for POST/PUT/PATCH — or, with websocket=True, the initial WebSocket message. Pass a JSON object or JSON string.', default=None)]",
5959
"default": null
6060
},
6161
"debug": {
@@ -75,11 +75,11 @@
7575
"default": null
7676
},
7777
"websocket": {
78-
"type": "Annotated[bool, Field(description=\"Proxy mode only. Use WebSocket instead of HTTP. For streaming endpoints (e.g., ESPHome /compile, /validate). Sends 'body' as initial message, collects responses. Default: false.\", default=False)]",
78+
"type": "Annotated[bool, Field(description=\"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.\", default=False)]",
7979
"default": false
8080
},
8181
"wait_for_close": {
82-
"type": "Annotated[bool, Field(description='Proxy mode only. WebSocket: True: wait for server to close (for compile/validate). False: return after first response batch (for quick commands). Default: true.', default=True)]",
82+
"type": "Annotated[bool, Field(description=\"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.\", default=True)]",
8383
"default": true
8484
},
8585
"message_limit": {

0 commit comments

Comments
 (0)