Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 9 additions & 6 deletions homeassistant-addon-dev/translations/en.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,12 @@ configuration:
enable_yaml_config_editing:
name: Enable YAML config editing
description: >-
Allow AI assistants to add, replace, or remove top-level keys in
configuration.yaml and packages/*.yaml. Only whitelisted keys are
allowed (e.g., template, sensor, command_line, mqtt). Core keys
like homeassistant, http, and recorder are blocked. A backup is
created before every edit. Use for YAML-only features that have no
UI or API alternative. Requires restart to take effect.
WARNING, dangerous tool, use at your own risk. Allows AI assistants
to add, replace, or remove top-level keys in configuration.yaml and
packages/*.yaml. Only whitelisted keys are allowed (e.g., template,
sensor, command_line, mqtt); core keys like homeassistant, http,
and recorder are blocked. A backup is created before every edit.
Intended as a last resort for YAML-only features with no UI or API
alternative — dedicated tools exist for automations, scripts,
scenes, template sensors, and helpers and should be preferred.
Requires restart to take effect.
2 changes: 1 addition & 1 deletion homeassistant-addon/DOCS.md
Original file line number Diff line number Diff line change
Expand Up @@ -442,7 +442,7 @@ The add-on provides 86+ MCP tools for controlling Home Assistant:
- `ha_backup_create` — Create a fast Home Assistant backup (local only).
- `ha_backup_restore` — Restore Home Assistant from a backup (LAST RESORT - use with extreme caution).
- `ha_check_config` — Check Home Assistant configuration for errors.
- `ha_config_set_yaml` — Add, replace, or remove a top-level key in configuration.yaml or package files.
- `ha_config_set_yaml` — Update raw YAML configuration in configuration.yaml or packages/*.yaml (LAST RESORT).
- `ha_get_system_health` — Get Home Assistant system health, including Zigbee (ZHA) and Z-Wave JS network diagnostics.
- `ha_get_updates` — Get update information - list all updates or get details for a specific one.
- `ha_reload_core` — Reload Home Assistant configuration without full restart.
Expand Down
15 changes: 9 additions & 6 deletions homeassistant-addon/translations/en.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,12 @@ configuration:
enable_yaml_config_editing:
name: Enable YAML config editing
description: >-
Allow AI assistants to add, replace, or remove top-level keys in
configuration.yaml and packages/*.yaml. Only whitelisted keys are
allowed (e.g., template, sensor, command_line, mqtt). Core keys
like homeassistant, http, and recorder are blocked. A backup is
created before every edit. Use for YAML-only features that have no
UI or API alternative. Requires restart to take effect.
WARNING, dangerous tool, use at your own risk. Allows AI assistants
to add, replace, or remove top-level keys in configuration.yaml and
packages/*.yaml. Only whitelisted keys are allowed (e.g., template,
sensor, command_line, mqtt); core keys like homeassistant, http,
and recorder are blocked. A backup is created before every edit.
Intended as a last resort for YAML-only features with no UI or API
alternative — dedicated tools exist for automations, scripts,
scenes, template sensors, and helpers and should be preferred.
Requires restart to take effect.
10 changes: 7 additions & 3 deletions site/src/data/tools.json
Original file line number Diff line number Diff line change
Expand Up @@ -2414,12 +2414,12 @@
},
{
"name": "ha_config_set_yaml",
"title": "Set YAML Config",
"description": "Add, replace, or remove a top-level key in configuration.yaml or package files.\n\nIMPORTANT: Only use when NO UI or API alternative exists. Prefer:\n- Template sensors -> ha_config_set_helper (Template Helper)\n- Automations -> ha_config_set_automation\n- Scripts -> ha_config_set_script\n- Input helpers -> ha_config_set_helper\n- Scenes -> ha_config_set_scene\n\nThis tool is for YAML-only features with no UI/API path (e.g.,\ncommand_line sensors, platform-based MQTT sensors in YAML, rest\nsensors defined in packages).\n\nSafeguards: file backup, YAML validation, top-level key whitelist,\npath traversal blocking, post-edit config check.\n\nIMPORTANT: Check 'post_action' in the response. Most keys require\na full HA restart ('restart_required'). Only template, mqtt, and\ngroup support reload ('reload_available' with 'reload_service').\n\nPreserves YAML comments on sibling keys, file-level comments,\nand Home Assistant tags (!include, !secret, etc.). The 'replace' action\nsubstitutes the subtree as-is, so comments from the old subtree\ndo not carry over.",
"title": "Raw YAML Config Edit",
"description": "Update raw YAML configuration in configuration.yaml or packages/*.yaml (LAST RESORT).\n\n**WARNING:** Destructive, disabled by default. Dedicated tools exist for\nalmost every use case and should be preferred:\n\n- Template sensors (state-based or trigger-based) ->\n ha_set_config_entry_helper(helper_type='template')\n- Automations -> ha_config_set_automation\n- Scripts -> ha_config_set_script\n- Scenes -> ha_config_set_scene\n- Input helpers -> ha_config_set_helper\n- Groups, min/max, threshold, derivative, statistics, utility_meter,\n trend, filter, switch_as_x -> ha_set_config_entry_helper\n\nIntended for YAML-only integrations with no config-flow or API\nequivalent (command_line, rest, shell_command, notify platforms).\nA non-empty ``justification`` is required and logged. Check\n``post_action`` in the response: most keys need a full HA restart;\ntemplate, mqtt, and group support reload. Preserves YAML comments and\nHA tags (``!include``, ``!secret``) on round-trip; ``replace`` swaps\nthe subtree as-is.\n\nFor detailed routing guidance, use ha_get_skill_home_assistant_best_practices.",
"inputSchema": {
"properties": {
"yaml_path": {
"type": "Annotated[str, Field(description=\"Top-level YAML key to modify (e.g., 'template', 'sensor', 'input_boolean'). Only whitelisted keys are allowed.\")]"
"type": "Annotated[str, Field(description=\"Top-level YAML key to modify. Only a narrow allowlist of YAML-only integration keys is accepted (e.g., 'command_line', 'rest', 'shell_command', 'notify'). Not for template sensors (use ha_set_config_entry_helper), automations, scripts, scenes, or input_* helpers — those have dedicated tools.\")]"
},
"action": {
"type": "Annotated[str, Field(description=\"Action to perform: 'add' (insert/merge content under key), 'replace' (overwrite key with new content), or 'remove' (delete the key entirely).\")]"
Expand All @@ -2428,6 +2428,10 @@
"type": "Annotated[str | None, Field(default=None, description=\"YAML content for the value under yaml_path. Required for 'add' and 'replace' actions. Must be valid YAML.\")]",
"default": null
},
"justification": {
"type": "Annotated[str | None, Field(default=None, description='Required. Briefly explain why no dedicated tool fits. Logged for auditing.')]",
"default": null
},
"file": {
"type": "Annotated[str, Field(default='configuration.yaml', description=\"Relative path to the YAML config file. Defaults to 'configuration.yaml'. Also supports 'packages/*.yaml'.\")]",
"default": "configuration.yaml"
Expand Down
84 changes: 61 additions & 23 deletions src/ha_mcp/tools/tools_yaml_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def register_yaml_config_tools(mcp: Any, client: Any, **kwargs: Any) -> None:
annotations={
"destructiveHint": True,
"idempotentHint": False,
"title": "Set YAML Config",
"title": "Raw YAML Config Edit",
},
)
@log_tool_usage
Expand All @@ -57,8 +57,11 @@ async def ha_config_set_yaml(
str,
Field(
description=(
"Top-level YAML key to modify (e.g., 'template', 'sensor', "
"'input_boolean'). Only whitelisted keys are allowed."
"Top-level YAML key to modify. Only a narrow allowlist of "
"YAML-only integration keys is accepted (e.g., 'command_line', "
"'rest', 'shell_command', 'notify'). Not for template sensors "
"(use ha_set_config_entry_helper), automations, scripts, "
"scenes, or input_* helpers — those have dedicated tools."
),
),
],
Expand All @@ -82,6 +85,16 @@ async def ha_config_set_yaml(
),
),
] = None,
justification: Annotated[
str | None,
Field(
default=None,
description=(
"Required. Briefly explain why no dedicated tool fits. "
"Logged for auditing."
),
),
] = None,
file: Annotated[
str,
Field(
Expand All @@ -103,30 +116,29 @@ async def ha_config_set_yaml(
),
] = True,
) -> dict[str, Any]:
"""Add, replace, or remove a top-level key in configuration.yaml or package files.
"""Update raw YAML configuration in configuration.yaml or packages/*.yaml (LAST RESORT).

**WARNING:** Destructive, disabled by default. Dedicated tools exist for
almost every use case and should be preferred:

IMPORTANT: Only use when NO UI or API alternative exists. Prefer:
- Template sensors -> ha_config_set_helper (Template Helper)
- Template sensors (state-based or trigger-based) ->
ha_set_config_entry_helper(helper_type='template')
- Automations -> ha_config_set_automation
- Scripts -> ha_config_set_script
- Input helpers -> ha_config_set_helper
- Scenes -> ha_config_set_scene

This tool is for YAML-only features with no UI/API path (e.g.,
command_line sensors, platform-based MQTT sensors in YAML, rest
sensors defined in packages).

Safeguards: file backup, YAML validation, top-level key whitelist,
path traversal blocking, post-edit config check.

IMPORTANT: Check 'post_action' in the response. Most keys require
a full HA restart ('restart_required'). Only template, mqtt, and
group support reload ('reload_available' with 'reload_service').

Preserves YAML comments on sibling keys, file-level comments,
and Home Assistant tags (!include, !secret, etc.). The 'replace' action
substitutes the subtree as-is, so comments from the old subtree
do not carry over.
- Input helpers -> ha_config_set_helper
- Groups, min/max, threshold, derivative, statistics, utility_meter,
trend, filter, switch_as_x -> ha_set_config_entry_helper

Intended for YAML-only integrations with no config-flow or API
equivalent (command_line, rest, shell_command, notify platforms).
A non-empty ``justification`` is required and logged. Check
``post_action`` in the response: most keys need a full HA restart;
template, mqtt, and group support reload. Preserves YAML comments and
HA tags (``!include``, ``!secret``) on round-trip; ``replace`` swaps
the subtree as-is.

For detailed routing guidance, use ha_get_skill_home_assistant_best_practices.
"""
try:
# Validate action
Expand All @@ -144,6 +156,24 @@ async def ha_config_set_yaml(
)
)

# Require a non-empty justification. Lightweight friction gate
# analogous to ha_restart's `confirm` parameter — forces the
# caller to pause and articulate intent before a destructive
# raw-YAML write. The justification is logged for auditing.
if not justification or not justification.strip():
raise_tool_error(
create_error_response(
ErrorCode.VALIDATION_INVALID_PARAMETER,
"justification is required for ha_config_set_yaml",
suggestions=[
"Briefly explain why no dedicated tool fits this task",
"For template sensors, automations, scripts, scenes, "
"or input helpers, use the dedicated tool instead "
"(see ha_get_skill_home_assistant_best_practices)",
],
)
)

# Validate content is provided for add/replace
if action in ("add", "replace") and not content:
raise_tool_error(
Expand All @@ -156,6 +186,14 @@ async def ha_config_set_yaml(
)
)

logger.info(
"ha_config_set_yaml invoked (yaml_path=%s, action=%s, file=%s) — justification: %s",
yaml_path,
action,
file,
justification[:200],
)

# Coerce boolean parameter
backup_bool = coerce_bool_param(backup, "backup", default=True)

Expand Down
Loading