Skip to content

Commit 5a5cb00

Browse files
kingpanther13claude
andcommitted
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>
1 parent eaddd22 commit 5a5cb00

6 files changed

Lines changed: 105 additions & 98 deletions

File tree

docs/beta.md

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Some ha-mcp tools are gated behind feature flags and available only in the **dev
1212
| `ha_write_file` | `enable_filesystem_tools` (dev add-on) / `HAMCP_ENABLE_FILESYSTEM_TOOLS=true` (env var) | Write files to allowed directories. Requires `ha_mcp_tools` custom component. |
1313
| `ha_delete_file` | `enable_filesystem_tools` (dev add-on) / `HAMCP_ENABLE_FILESYSTEM_TOOLS=true` (env var) | Delete files from allowed directories. Requires `ha_mcp_tools` custom component. |
1414
| `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`). |
1516

1617
## How to enable
1718

@@ -23,7 +24,7 @@ Some ha-mcp tools are gated behind feature flags and available only in the **dev
2324
4. Enable the desired toggle (e.g., `enable_yaml_config_editing`, `enable_filesystem_tools`).
2425
5. Restart the add-on.
2526

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.
2728

2829
### Option 2: Environment variable (non-add-on installs)
2930

@@ -67,3 +68,21 @@ These tools provide direct file access to your Home Assistant filesystem and req
6768
**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.
6869

6970
**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

homeassistant-addon/DOCS.md

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -262,30 +262,6 @@ Replaces the full tool catalog (~86 tools, ~46K tokens) with search-based discov
262262

263263
Requires add-on restart to take effect.
264264

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
286-
287-
Requires add-on restart to take effect.
288-
289265
**Example Configuration:**
290266

291267
```yaml

homeassistant-addon/config.yaml

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,20 +24,19 @@ host_network: true
2424
# Use pre-built Docker images
2525
image: "ghcr.io/homeassistant-ai/ha-mcp-addon-{arch}"
2626
# Options for user configuration
27-
# NOTE: enable_yaml_config_editing, enable_filesystem_tools, and
28-
# enable_custom_component_integration are intentionally NOT exposed here.
29-
# They are dev-channel-only beta features — see docs/beta.md. Do not re-mirror
30-
# from homeassistant-addon-dev/config.yaml without reading that doc first.
27+
# NOTE: enable_yaml_config_editing, enable_filesystem_tools,
28+
# enable_custom_component_integration, and enable_code_mode are
29+
# intentionally NOT exposed here. They are dev-channel-only beta
30+
# features — see docs/beta.md. Do not re-mirror from
31+
# homeassistant-addon-dev/config.yaml without reading that doc first.
3132
options:
3233
backup_hint: "normal"
3334
enable_tool_search: false
34-
enable_code_mode: false
3535
verify_ssl: true
3636
schema:
3737
backup_hint: list(strong|normal|weak|auto)
3838
secret_path: str?
3939
enable_tool_search: bool?
40-
enable_code_mode: bool?
4140
verify_ssl: bool?
4241
advanced_debug_logging: bool?
4342
# Add-on exposes HTTP port for MCP communication (fixed internal port)

homeassistant-addon/translations/en.yaml

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,6 @@ configuration:
3131
OpenAI-compatible models) or with smaller context windows. Tools
3232
are found via ha_search_tools and executed via categorized proxies
3333
(read/write/delete). Requires restart to take effect.
34-
enable_code_mode:
35-
name: Enable custom tool sandbox
36-
description: >-
37-
Enables the ha_manage_custom_tool tool, which lets AI assistants
38-
create, run, and save custom Python code in a secure sandbox when
39-
no built-in tool can handle the request. Code runs in an isolated
40-
interpreter with no filesystem or network access. Sandbox code can
41-
access the HA REST API directly (api_get/api_post) or call existing
42-
MCP tools (call_tool). Requires restart to take effect.
4334
verify_ssl:
4435
name: Verify TLS certificate
4536
description: >-

src/ha_mcp/tools/tools_code.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ def register_code_tools(mcp: Any, client: Any, **kwargs: Any) -> None:
247247
)
248248

249249
@mcp.tool(
250-
tags={"System"},
250+
tags={"System", "beta"},
251251
annotations={
252252
"title": "Custom Tool",
253253
"destructiveHint": True,

0 commit comments

Comments
 (0)