You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
refactor(addon): move ha_manage_custom_tool to dev channel only (beta)
Mirrors the homeassistant-ai#942 pattern that ha_config_set_yaml uses: the
ha_manage_custom_tool sandboxed code-execution tool stays available via
the dev channel add-on and the ENABLE_CODE_MODE env var, but the toggle
is removed from the stable add-on UI so it ships dev-channel-only.
- Drop enable_code_mode from homeassistant-addon/config.yaml options +
schema. Update the maintainer comment to list it alongside the other
beta toggles that are intentionally not mirrored from the dev addon.
- Drop the enable_code_mode entry from homeassistant-addon/translations/
en.yaml.
- Tag the @mcp.tool with {"System", "beta"} so scripts/extract_tools.py
appends the (beta — dev channel only) marker in the regenerated
README.md / DOCS.md / tools.json on merge.
- Add ha_manage_custom_tool to docs/beta.md (table + Known limitations
section covering composition risk, in-memory saved tools, best-effort
resource limits, ARM async path).
- Remove the hand-written ### enable_code_mode toggle docs from
homeassistant-addon/DOCS.md (the auto-generated tools section between
ADDON_TOOLS markers gets the beta marker added by CI on merge).
Dev addon (homeassistant-addon-dev/) still exposes the toggle and the
shared start.py still maps it to ENABLE_CODE_MODE so dev users can opt
in. src/ha_mcp/config.py still reads the env var so non-addon installs
(pip / uv / uvx / Docker direct) can opt in via ENABLE_CODE_MODE=true.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|`ha_install_mcp_tools`|`enable_custom_component_integration` (dev add-on) / `HAMCP_ENABLE_CUSTOM_COMPONENT_INTEGRATION=true` (env var) | Installs the `ha_mcp_tools` custom component via HACS. |
15
+
|`ha_manage_custom_tool`|`enable_code_mode` (dev add-on) / `ENABLE_CODE_MODE=true` (env var) | Sandboxed Python "escape hatch" that lets AI assistants write, run, and save custom tools when no built-in tool covers the request. Code runs in pydantic-monty (no filesystem, no network); sandbox can call the HA REST API (`api_get`/`api_post`) or registered MCP tools (`call_tool`). |
15
16
16
17
## How to enable
17
18
@@ -23,7 +24,7 @@ Some ha-mcp tools are gated behind feature flags and available only in the **dev
23
24
4. Enable the desired toggle (e.g., `enable_yaml_config_editing`, `enable_filesystem_tools`).
24
25
5. Restart the add-on.
25
26
26
-
`enable_yaml_config_editing`, `enable_filesystem_tools`, and `enable_custom_component_integration` are only available in the dev channel add-on. The stable add-on does not expose these beta toggles.
27
+
`enable_yaml_config_editing`, `enable_filesystem_tools`, `enable_custom_component_integration`, and `enable_code_mode` are only available in the dev channel add-on. The stable add-on does not expose these beta toggles.
@@ -67,3 +68,21 @@ These tools provide direct file access to your Home Assistant filesystem and req
67
68
**No undo.**`ha_delete_file` and `ha_write_file` (with `overwrite=True`) are irreversible. There is no recycle bin or automatic backup for file operations.
68
69
69
70
**Requires the custom component.** If `ha_mcp_tools` is not installed and active, all file tools will return an error with installation instructions.
71
+
72
+
### `ha_manage_custom_tool`
73
+
74
+
This tool exposes a sandboxed Python interpreter (`pydantic-monty`) to the AI as an escape hatch for operations no built-in tool covers. It also lets the AI save tools for reuse via `save_as` / `run_saved` / `list_saved`. Sandbox code can either hit the HA REST API directly (`api_get`/`api_post`) or call other registered MCP tools (`call_tool`). The sandbox blocks filesystem and network I/O, but operators should still be aware of the following:
75
+
76
+
**The AI gets to write and run code on your HA instance.** Even though the sandbox prevents it from touching the filesystem or the public network, code can still call any tool the MCP server has registered, including write/destructive tools, and can hit any endpoint reachable via the HA REST API. Treat this like giving the AI a generic "do whatever existing tools allow you to do, in any combination" capability — not a tightly scoped per-feature tool.
77
+
78
+
**Saved tools are stored in process memory only.** Tools you ask the AI to `save_as` live in the running ha-mcp process. They are lost on add-on / server restart. There is no on-disk persistence and no `ha_remove_saved_tool` — the only way to drop a saved tool is to restart.
79
+
80
+
**Recursive self-call is blocked, but composition is not.** The sandbox refuses to invoke `ha_manage_custom_tool` from inside itself, so it can't directly recurse, but it can chain together every other tool the server registers. A buggy or adversarial prompt can still cause unexpected fan-out across destructive tools.
81
+
82
+
**Resource limits are best-effort.** 30s wall-clock, 10 MB memory, recursion depth 100, and 100 API/tool calls per execution are enforced by the sandbox (configurable via `CODE_MODE_*` env vars). They protect against runaway loops, not against intentionally crafted abuse — keep `ENABLE_CODE_MODE=false` in any environment where untrusted prompts can reach the server.
83
+
84
+
**ARM platforms require the async sandbox path.** On systems where `Monty.run_async` is unavailable, the tool fails fast with a clear error rather than falling back silently.
85
+
86
+
**Recommended prerequisites:**
87
+
- You're comfortable with the AI authoring small Python snippets that wrap existing tools or HA REST endpoints
88
+
- You have `destructiveHint=True` confirmation enabled on the MCP client and you actually read the prompts
Copy file name to clipboardExpand all lines: homeassistant-addon/DOCS.md
-24Lines changed: 0 additions & 24 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -262,30 +262,6 @@ Replaces the full tool catalog (~86 tools, ~46K tokens) with search-based discov
262
262
263
263
Requires add-on restart to take effect.
264
264
265
-
### enable_code_mode
266
-
267
-
**Default:**`false`
268
-
269
-
Enables the `ha_manage_custom_tool` — a sandboxed "escape hatch" that lets AI agents write and run custom Python code when no existing tool covers the request. Code runs in pydantic-monty, a Rust-based sandbox with no filesystem or network access. Sandbox code can access the HA REST API directly via `api_get()`/`api_post()`, or call existing MCP tools via `call_tool()`.
270
-
271
-
**Safety guardrails:**
272
-
- Code runs in a sandboxed interpreter (no filesystem, no network, no third-party imports)
273
-
-`destructiveHint=True` — MCP clients prompt for confirmation before execution
274
-
- AI must provide a justification explaining why no existing tool works
275
-
- Configurable time (30s), memory (10MB), and recursion (100) limits
276
-
- Rate limited to 100 tool calls per execution
277
-
- Cannot recursively invoke itself
278
-
279
-
**When to enable:**
280
-
- You need an "escape hatch" for operations not covered by the 92+ built-in tools
281
-
- You trust the AI agent's judgment on when to write custom code
282
-
283
-
**When to leave disabled (default):**
284
-
- Standard use cases covered by existing tools
285
-
- You want to restrict the AI to pre-built tools only
0 commit comments