Skip to content

Commit 6eb8533

Browse files
committed
Merge branch 'pr-857' into addon-repo
# Conflicts: # homeassistant-addon-dev/config.yaml # homeassistant-addon-dev/translations/en.yaml # homeassistant-addon/DOCS.md # homeassistant-addon/config.yaml # homeassistant-addon/start.py # homeassistant-addon/translations/en.yaml # src/ha_mcp/server.py
2 parents 63b4f9e + 1831455 commit 6eb8533

12 files changed

Lines changed: 477 additions & 50 deletions

File tree

.env.example

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,15 @@ LOG_LEVEL=INFO
2828
# Recommended for models without deferred tool support or with limited context.
2929
# ENABLE_TOOL_SEARCH=false
3030

31-
# Managed YAML config editing: allows ha_config_set_yaml to add/replace/remove
32-
# top-level keys in configuration.yaml and packages/*.yaml.
33-
# ENABLE_YAML_CONFIG_EDITING=false
31+
# Disable specific tools or tool groups (comma-separated).
32+
# Group names: HACS, System, Automations, etc. Tool names: ha_config_set_yaml, etc.
33+
# DISABLED_TOOLS=ha_config_set_yaml
34+
35+
# Additional tools to pin when tool search is enabled (comma-separated).
36+
# PINNED_TOOLS=
37+
38+
# Max results from ha_search_tools (2-10, default 5).
39+
# TOOL_SEARCH_MAX_RESULTS=5
3440

3541
# Optional: MCP Server Configuration
3642
MCP_SERVER_NAME=ha-mcp

homeassistant-addon-dev/config.yaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,27 @@ options:
2020
enable_skills: true
2121
enable_skills_as_tools: false
2222
enable_tool_search: false
23+
<<<<<<< HEAD
2324
enable_yaml_config_editing: false
2425
enable_code_mode: false
26+
=======
27+
disabled_tools: "ha_config_set_yaml"
28+
pinned_tools: ""
29+
tool_search_max_results: 5
30+
>>>>>>> pr-857
2531
schema:
2632
backup_hint: list(strong|normal|weak|auto)
2733
secret_path: str?
2834
enable_skills: bool?
2935
enable_skills_as_tools: bool?
3036
enable_tool_search: bool?
37+
<<<<<<< HEAD
3138
enable_yaml_config_editing: bool?
3239
enable_code_mode: bool?
40+
=======
41+
disabled_tools: str?
42+
pinned_tools: str?
43+
tool_search_max_results: int?
44+
>>>>>>> pr-857
3345
ports:
3446
9583/tcp: 9583

homeassistant-addon-dev/translations/en.yaml

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,10 @@ configuration:
2626
deferred tools or with smaller context windows. Tools are found via
2727
ha_search_tools and executed via categorized proxies (read/write/delete).
2828
Requires restart to take effect.
29-
enable_yaml_config_editing:
30-
name: Enable YAML config editing
29+
disabled_tools:
30+
name: Disabled tools
3131
description: >-
32+
<<<<<<< HEAD
3233
Allow AI assistants to add, replace, or remove top-level keys in
3334
configuration.yaml and packages/*.yaml. Only whitelisted keys are
3435
allowed (e.g., template, sensor, command_line, mqtt). Core keys
@@ -44,3 +45,27 @@ configuration:
4445
Sandbox code can access the HA REST API directly (api_get/api_post)
4546
or call existing MCP tools (call_tool). Includes save/reuse for
4647
frequently-used custom tools. Requires restart to take effect.
48+
=======
49+
Tools or tool groups to disable. Accepts individual tool names
50+
(e.g., "ha_hacs_download") or group names (e.g., "HACS") to
51+
disable all tools in that group. Groups: Add-ons, Areas & Floors,
52+
Automations, Blueprints, Calendar, Camera, Dashboards,
53+
Device Registry, Entity Registry, Files, Groups, HACS,
54+
Helper Entities, History & Statistics, Integrations,
55+
Labels & Categories, Scripts, Search & Discovery,
56+
Service & Device Control, System, Todo Lists, Utilities, Zones.
57+
Some core tools cannot be disabled. Requires restart.
58+
pinned_tools:
59+
name: Pinned tools
60+
description: >-
61+
Additional tools to keep always visible when tool search is
62+
enabled. These are shown alongside the default pinned tools
63+
without needing to search. Has no effect when tool search is
64+
disabled. Requires restart.
65+
tool_search_max_results:
66+
name: Tool search max results
67+
description: >-
68+
Maximum number of tools returned by ha_search_tools when tool
69+
search is enabled. Lower values (2-3) save context tokens but
70+
may miss relevant tools. Range: 2-10. Requires restart.
71+
>>>>>>> pr-857

homeassistant-addon/DOCS.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,7 @@ Replaces the full tool catalog (~92 tools, ~46K tokens) with search-based discov
225225

226226
Requires add-on restart to take effect.
227227

228+
<<<<<<< HEAD
228229
### enable_code_mode
229230

230231
**Default:** `false`
@@ -246,6 +247,36 @@ Enables the `ha_manage_custom_tool` — a sandboxed "escape hatch" that lets AI
246247
**When to leave disabled (default):**
247248
- Standard use cases covered by existing tools
248249
- You want to restrict the AI to pre-built tools only
250+
=======
251+
### disabled_tools
252+
253+
**Default:** `["ha_config_set_yaml"]`
254+
255+
A list of tools or tool groups to disable. Accepts:
256+
257+
- **Individual tool names** (e.g., `ha_hacs_download`) — disables that specific tool
258+
- **Group names** (e.g., `HACS`) — disables all tools in that group
259+
260+
**Available groups:** Add-ons, Areas & Floors, Automations, Blueprints, Calendar, Camera, Dashboards, Device Registry, Entity Registry, Files, Groups, HACS, Helper Entities, History & Statistics, Integrations, Labels & Categories, Scripts, Search & Discovery, Service & Device Control, System, Todo Lists, Utilities, Zones
261+
262+
**Mandatory tools** that cannot be disabled (silently re-enabled): `ha_search_entities`, `ha_get_overview`, `ha_get_state`, `ha_report_issue`. When tool search is enabled, the search and proxy tools are also mandatory.
263+
264+
Requires add-on restart to take effect.
265+
266+
### pinned_tools
267+
268+
**Default:** `[]` (empty)
269+
270+
Additional tool names to keep always visible when tool search is enabled. These are shown alongside the default pinned tools without requiring a search. Has no effect when tool search is disabled.
271+
272+
Requires add-on restart to take effect.
273+
274+
### tool_search_max_results
275+
276+
**Default:** `5`
277+
278+
Maximum number of results returned by `ha_search_tools` when tool search is enabled. Lower values (2-3) save context tokens but may miss relevant tools. Range: 2-10.
279+
>>>>>>> pr-857
249280
250281
Requires add-on restart to take effect.
251282

@@ -254,6 +285,12 @@ Requires add-on restart to take effect.
254285
```yaml
255286
backup_hint: normal
256287
secret_path: "" # Leave empty for auto-generation
288+
disabled_tools:
289+
- "ha_config_set_yaml"
290+
- "HACS"
291+
pinned_tools:
292+
- "ha_config_set_automation"
293+
tool_search_max_results: 3
257294
```
258295
259296
---

homeassistant-addon/config.yaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,28 @@ options:
2626
enable_skills: true
2727
enable_skills_as_tools: false
2828
enable_tool_search: false
29+
<<<<<<< HEAD
2930
enable_yaml_config_editing: false
3031
enable_code_mode: false
32+
=======
33+
disabled_tools: "ha_config_set_yaml"
34+
pinned_tools: ""
35+
tool_search_max_results: 5
36+
>>>>>>> pr-857
3137
schema:
3238
backup_hint: list(strong|normal|weak|auto)
3339
secret_path: str?
3440
enable_skills: bool?
3541
enable_skills_as_tools: bool?
3642
enable_tool_search: bool?
43+
<<<<<<< HEAD
3744
enable_yaml_config_editing: bool?
3845
enable_code_mode: bool?
46+
=======
47+
disabled_tools: str?
48+
pinned_tools: str?
49+
tool_search_max_results: int?
50+
>>>>>>> pr-857
3951
# Add-on exposes HTTP port for MCP communication (fixed internal port)
4052
ports:
4153
9583/tcp: 9583

homeassistant-addon/start.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,14 @@ def main() -> int:
109109
enable_skills = True # default
110110
enable_skills_as_tools = False # default
111111
enable_tool_search = False # default
112+
<<<<<<< HEAD
112113
enable_yaml_config_editing = False # default
113114
enable_code_mode = False # default
115+
=======
116+
disabled_tools: list[str] = ["ha_config_set_yaml"] # default
117+
pinned_tools: list[str] = [] # default
118+
tool_search_max_results = 5 # default
119+
>>>>>>> pr-857
114120

115121
if config_file.exists():
116122
try:
@@ -124,10 +130,19 @@ def main() -> int:
124130
enable_skills_as_tools = raw_skills_as_tools if isinstance(raw_skills_as_tools, bool) else False
125131
raw_tool_search = config.get("enable_tool_search", False)
126132
enable_tool_search = raw_tool_search if isinstance(raw_tool_search, bool) else False
133+
<<<<<<< HEAD
127134
raw_yaml_config = config.get("enable_yaml_config_editing", False)
128135
enable_yaml_config_editing = raw_yaml_config if isinstance(raw_yaml_config, bool) else False
129136
raw_code_mode = config.get("enable_code_mode", False)
130137
enable_code_mode = raw_code_mode if isinstance(raw_code_mode, bool) else False
138+
=======
139+
raw_disabled = config.get("disabled_tools", ["ha_config_set_yaml"])
140+
disabled_tools = raw_disabled if isinstance(raw_disabled, list) else ["ha_config_set_yaml"]
141+
raw_pinned = config.get("pinned_tools", [])
142+
pinned_tools = raw_pinned if isinstance(raw_pinned, list) else []
143+
raw_max_results = config.get("tool_search_max_results", 5)
144+
tool_search_max_results = raw_max_results if isinstance(raw_max_results, int) else 5
145+
>>>>>>> pr-857
131146
except Exception as e:
132147
log_error(f"Failed to read config: {e}, using defaults")
133148

@@ -142,8 +157,14 @@ def main() -> int:
142157
os.environ["ENABLE_SKILLS"] = str(enable_skills).lower()
143158
os.environ["ENABLE_SKILLS_AS_TOOLS"] = str(enable_skills_as_tools).lower()
144159
os.environ["ENABLE_TOOL_SEARCH"] = str(enable_tool_search).lower()
160+
<<<<<<< HEAD
145161
os.environ["ENABLE_YAML_CONFIG_EDITING"] = str(enable_yaml_config_editing).lower()
146162
os.environ["ENABLE_CODE_MODE"] = str(enable_code_mode).lower()
163+
=======
164+
os.environ["DISABLED_TOOLS"] = ",".join(disabled_tools)
165+
os.environ["PINNED_TOOLS"] = ",".join(pinned_tools)
166+
os.environ["TOOL_SEARCH_MAX_RESULTS"] = str(tool_search_max_results)
167+
>>>>>>> pr-857
147168

148169
# Validate Supervisor token
149170
supervisor_token = os.environ.get("SUPERVISOR_TOKEN")

homeassistant-addon/translations/en.yaml

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,21 +26,41 @@ configuration:
2626
deferred tools or with smaller context windows. Tools are found via
2727
ha_search_tools and executed via categorized proxies (read/write/delete).
2828
Requires restart to take effect.
29+
disabled_tools:
30+
name: Disabled tools
31+
description: >-
32+
Tools or tool groups to disable. Accepts individual tool names
33+
(e.g., "ha_hacs_download") or group names (e.g., "HACS") to
34+
disable all tools in that group. Groups: Add-ons, Areas & Floors,
35+
Automations, Blueprints, Calendar, Camera, Dashboards,
36+
Device Registry, Entity Registry, Files, Groups, HACS,
37+
Helper Entities, History & Statistics, Integrations,
38+
Labels & Categories, Scripts, Search & Discovery,
39+
Service & Device Control, System, Todo Lists, Utilities, Zones.
40+
Some core tools cannot be disabled. Requires restart.
41+
pinned_tools:
42+
name: Pinned tools
43+
description: >-
44+
Additional tools to keep always visible when tool search is
45+
enabled. These are shown alongside the default pinned tools
46+
without needing to search. Has no effect when tool search is
47+
disabled. Requires restart.
48+
tool_search_max_results:
49+
name: Tool search max results
50+
description: >-
51+
Maximum number of tools returned by ha_search_tools when tool
52+
search is enabled. Lower values (2-3) save context tokens but
53+
may miss relevant tools. Range: 2-10. Requires restart.
2954
enable_yaml_config_editing:
3055
name: Enable YAML config editing
3156
description: >-
3257
Allow AI assistants to add, replace, or remove top-level keys in
3358
configuration.yaml and packages/*.yaml. Only whitelisted keys are
34-
allowed (e.g., template, sensor, command_line, mqtt). Core keys
35-
like homeassistant, http, and recorder are blocked. A backup is
36-
created before every edit. Use for YAML-only features that have no
37-
UI or API alternative. Requires restart to take effect.
59+
allowed. Core keys are blocked. A backup is created before every
60+
edit. Requires restart to take effect.
3861
enable_code_mode:
3962
name: Enable custom tool sandbox
4063
description: >-
4164
Allow AI assistants to write and run custom Python code in a secure
42-
sandbox when no built-in tool can handle the request. Code runs in
43-
an isolated interpreter with no filesystem or network access.
44-
Sandbox code can access the HA REST API directly (api_get/api_post)
45-
or call existing MCP tools (call_tool). Includes save/reuse for
46-
frequently-used custom tools. Requires restart to take effect.
65+
sandbox when no built-in tool can handle the request. Requires
66+
restart to take effect.

src/ha_mcp/config.py

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -107,10 +107,16 @@ class Settings(BaseSettings):
107107
# Dramatically reduces idle context token usage for LLMs.
108108
enable_tool_search: bool = Field(False, alias="ENABLE_TOOL_SEARCH")
109109

110-
# Managed YAML config editing — allows ha_config_set_yaml to add,
111-
# replace, or remove top-level keys in configuration.yaml and package
112-
# files. Disabled by default; only for YAML-only features with no UI/API path.
113-
enable_yaml_config_editing: bool = Field(False, alias="ENABLE_YAML_CONFIG_EDITING")
110+
# User-configurable tool filtering — comma-separated list of tool names
111+
# or group names to disable. Group names expand to all tools with that tag.
112+
disabled_tools: str = Field("ha_config_set_yaml", alias="DISABLED_TOOLS")
113+
114+
# Additional tools to pin (always visible) when tool search is active.
115+
# Comma-separated tool names, added on top of DEFAULT_PINNED_TOOLS.
116+
pinned_tools: str = Field("", alias="PINNED_TOOLS")
117+
118+
# Max results returned by ha_search_tools (2-10).
119+
tool_search_max_results: int = Field(5, alias="TOOL_SEARCH_MAX_RESULTS")
114120

115121
# Code Mode — sandboxed Python execution via pydantic-monty.
116122
# Provides an "escape hatch" tool (ha_manage_custom_tool) that lets LLMs write
@@ -183,6 +189,12 @@ def validate_log_level(cls, v: str) -> str:
183189
raise ValueError(f"Log level must be one of {valid_levels}")
184190
return v.upper()
185191

192+
@field_validator("tool_search_max_results")
193+
@classmethod
194+
def validate_tool_search_max_results(cls, v: int) -> int:
195+
"""Clamp tool search max results to valid range."""
196+
return max(2, min(10, v))
197+
186198
@field_validator("backup_hint")
187199
@classmethod
188200
def validate_backup_hint(cls, v: str) -> str:

0 commit comments

Comments
 (0)