What would you like to see?
Extend the web settings UI from #960 with two new sections.
Advanced settings
Render every Settings field that's plausibly user-tweakable on a running server. Verified field list from src/ha_mcp/config.py (23 env-aliased fields total):
Connection (display only — source of truth is env / addon options):
HOMEASSISTANT_URL, HOMEASSISTANT_TOKEN, HA_TIMEOUT, HA_MAX_RETRIES, HA_VERIFY_SSL
Search & matching:
FUZZY_THRESHOLD (0-100, validator-enforced), ENTITY_SEARCH_LIMIT, ENABLE_TOOL_SEARCH, TOOL_SEARCH_MAX_RESULTS (2-10, Pydantic-enforced)
Tool surface:
ENABLED_TOOL_MODULES, ENABLE_SKILLS, ENABLE_SKILLS_AS_TOOLS, DISABLED_TOOLS, PINNED_TOOLS (last two already covered by existing UI section — link, don't duplicate)
Operations:
BACKUP_HINT (strong/normal/weak/auto, validator-enforced), ENABLE_WEBSOCKET
Identity / diagnostics:
MCP_SERVER_NAME, MCP_SERVER_VERSION, ENVIRONMENT, LOG_LEVEL, DEBUG
Fields not listed: ENABLE_DASHBOARD_PARTIAL_TOOLS (defined but not read anywhere in src/ha_mcp/ — separate cleanup), ENABLE_YAML_CONFIG_EDITING (covered in beta panel below).
Each field renders with current value, default, and validation bounds where Pydantic enforces them. Apply-mode (live vs. requires restart) needs an audit during implementation — LOG_LEVEL is set once via _setup_logging at startup so it needs restart; tool-registration flags (ENABLE_TOOL_SEARCH, ENABLE_SKILLS*) also gate startup paths; the others haven't been traced.
Beta features
Two compatible entry points:
1. Web UI panel — checkboxes that flip the underlying gate flags, replacing #960's locked-stub note with an actual opt-in. Each entry links to the relevant section of docs/beta.md. Initial set, matching the 6 stub tools #960 already renders:
ENABLE_YAML_CONFIG_EDITING (on Settings) → unlocks ha_config_set_yaml
HAMCP_ENABLE_FILESYSTEM_TOOLS (read via os.getenv in tools_filesystem.py) → unlocks ha_list_files, ha_read_file, ha_write_file, ha_delete_file
HAMCP_ENABLE_CUSTOM_COMPONENT_INTEGRATION (read via os.getenv in tools_mcp_component.py) → unlocks ha_install_mcp_tools
Architectural note: the two HAMCP_ENABLE_* flags are not on the Settings class. To present them in the UI alongside Settings-backed fields, either migrate them onto Settings first, or give the UI a separate read/write path for raw env-gated flags. Worth deciding before implementation.
2. Stable addon config.yaml text field — beta_features: "" option (parsed by homeassistant-addon/start.py into the corresponding env vars before the server starts), comma-separated feature names matching docs/beta.md keys. For users who don't use the web UI.
Both write to the same persistence file so the surfaces stay coherent.
Why do you need this?
Three threads collapse into one surface:
Additional context
#942 (docs/beta.md, removes enable_yaml_config_editing from stable addon UI) merged 2026-04-15. #960 (settings UI) merged 2026-05-02. This issue extends an already-merged surface — no upstream blockers.
Persistence: tool_config.json (at get_data_dir() / "tool_config.json") is keyed for per-tool state. Runtime settings + beta flags need their own channel — sibling JSON file or new top-level blocks in the existing one. Don't mutate the in-memory pydantic singleton without persisting (gotcha Patch76 flagged on #863 — edits would be lost on restart).
Apply model: match #960's "save now, restart to apply" pattern (per #960's description: runtime mcp.disable() accumulates transforms unreliably; startup-time apply is the clean path). Mark each field's apply-mode in the UI once audited.
Connection settings stay read-only. Editing HOMEASSISTANT_URL / _TOKEN from a web UI served by the running server is a chicken-and-egg footgun.
More context: as part of this we need to make sure that the web UI is always synced with the addon settings (in other words, changing settings will always require addon restart) and making sure the toggles in addon settings sync both directions between web UI. We may need to find a way to include the current pinned and/or disabled tools in the text boxes in the addon side. Similarly, we need to make sure the web UI syncs up with env vars in the non addon versions; I'm thinking if someone has set something up in the environment vars, it should be displayed in the web UI as read only, stating that the setting either needs to be modified in the env vars OR the setting can be removed from the env vars and then the web UI can take over. The beginning framework for this is being introduced in PR #1403 (if it doesn't already exist with the pinned tools and whatnot, then 1403 def adds it )
Addendum (2026-05-22): per-field env-pin pattern verified in PR #1403
PR #1403 (auto-backup web UI editor) implemented the env-var / web-UI sync
contract described in the "More context" paragraph above for the 3 new
auto-backup scalar settings (enable_auto_backup, auto_backup_throttle_minutes,
auto_backup_retain_per_entity). Behavior shipped there:
- Addon mode: web UI POST routes through Supervisor
/addons/self/options
→ addon restart; config.yaml stays authoritative; both UIs stay in sync.
- Standalone, env var not set: web UI edits write
<data_dir>/backup_settings.json,
Settings cache invalidates, change takes effect immediately (no restart).
- Standalone, env var set on that specific field: web UI shows the field
read-only with a banner pointing at the env var; POST returns 409 if a write
is attempted. Detection is per-field via os.environ.get(env_name) — having a
.env file present is not enough; the specific key must be present.
Verification of the existing disabled_tools / pinned_tools panel (settings_ui.py:158-204):
those env vars are currently seed-only — load_tool_config reads
tool_config.json if present and falls back to env-var seeding only on first
run. After the file exists, env-var changes are silently ignored and the web
UI POST writes the file without any env-pin check. The addon translation for
both fields documents this as "text fallback ... seeds the initial config when
the web UI hasn't been used yet."
This violates the principle laid out in the "More context" paragraph (env vars
should not be silently overridden). Two options for the eventual #1164 PR:
Option A (leaning) — per-tool env-pinning (mirrors PR #1403 for scalars):
DISABLED_TOOLS=ha_hacs_search,ha_hacs_download locks the ha_hacs_search
and ha_hacs_download rows read-only in the web UI; other tools remain
freely toggleable. Same for PINNED_TOOLS. Most semantically correct match
for the existing pattern. Documented "text fallback" behavior needs updating
in homeassistant-addon-dev/translations/en.yaml.
Option B — blanket env-pinning: if either env var is set at all, the
entire Tools tab is read-only. Simpler implementation but crude — blocks
managing tools the env var didn't mention.
Same treatment likely applies to every other env-mediated setting that the
advanced-settings panel from this issue eventually surfaces. The PR that
closes this issue should bundle the tools-panel fix with the new advanced-
settings panel so the env-pin contract is implemented in one consistent pass.
What would you like to see?
Extend the web settings UI from #960 with two new sections.
Advanced settings
Render every
Settingsfield that's plausibly user-tweakable on a running server. Verified field list fromsrc/ha_mcp/config.py(23 env-aliased fields total):Connection (display only — source of truth is env / addon options):
HOMEASSISTANT_URL,HOMEASSISTANT_TOKEN,HA_TIMEOUT,HA_MAX_RETRIES,HA_VERIFY_SSLSearch & matching:
FUZZY_THRESHOLD(0-100, validator-enforced),ENTITY_SEARCH_LIMIT,ENABLE_TOOL_SEARCH,TOOL_SEARCH_MAX_RESULTS(2-10, Pydantic-enforced)Tool surface:
ENABLED_TOOL_MODULES,ENABLE_SKILLS,ENABLE_SKILLS_AS_TOOLS,DISABLED_TOOLS,PINNED_TOOLS(last two already covered by existing UI section — link, don't duplicate)Operations:
BACKUP_HINT(strong/normal/weak/auto, validator-enforced),ENABLE_WEBSOCKETIdentity / diagnostics:
MCP_SERVER_NAME,MCP_SERVER_VERSION,ENVIRONMENT,LOG_LEVEL,DEBUGFields not listed:
ENABLE_DASHBOARD_PARTIAL_TOOLS(defined but not read anywhere insrc/ha_mcp/— separate cleanup),ENABLE_YAML_CONFIG_EDITING(covered in beta panel below).Each field renders with current value, default, and validation bounds where Pydantic enforces them. Apply-mode (live vs. requires restart) needs an audit during implementation —
LOG_LEVELis set once via_setup_loggingat startup so it needs restart; tool-registration flags (ENABLE_TOOL_SEARCH,ENABLE_SKILLS*) also gate startup paths; the others haven't been traced.Beta features
Two compatible entry points:
1. Web UI panel — checkboxes that flip the underlying gate flags, replacing #960's locked-stub note with an actual opt-in. Each entry links to the relevant section of
docs/beta.md. Initial set, matching the 6 stub tools #960 already renders:ENABLE_YAML_CONFIG_EDITING(onSettings) → unlocksha_config_set_yamlHAMCP_ENABLE_FILESYSTEM_TOOLS(read viaos.getenvintools_filesystem.py) → unlocksha_list_files,ha_read_file,ha_write_file,ha_delete_fileHAMCP_ENABLE_CUSTOM_COMPONENT_INTEGRATION(read viaos.getenvintools_mcp_component.py) → unlocksha_install_mcp_toolsArchitectural note: the two
HAMCP_ENABLE_*flags are not on theSettingsclass. To present them in the UI alongside Settings-backed fields, either migrate them ontoSettingsfirst, or give the UI a separate read/write path for raw env-gated flags. Worth deciding before implementation.2. Stable addon
config.yamltext field —beta_features: ""option (parsed byhomeassistant-addon/start.pyinto the corresponding env vars before the server starts), comma-separated feature names matchingdocs/beta.mdkeys. For users who don't use the web UI.Both write to the same persistence file so the surfaces stay coherent.
Why do you need this?
Three threads collapse into one surface:
schema:, so arbitrary env vars aren't available. Switching to the dev channel addon to get one beta feature pulls in every other dev change.Additional context
#942 (docs/beta.md, removes
enable_yaml_config_editingfrom stable addon UI) merged 2026-04-15. #960 (settings UI) merged 2026-05-02. This issue extends an already-merged surface — no upstream blockers.Persistence:
tool_config.json(atget_data_dir() / "tool_config.json") is keyed for per-tool state. Runtime settings + beta flags need their own channel — sibling JSON file or new top-level blocks in the existing one. Don't mutate the in-memory pydantic singleton without persisting (gotcha Patch76 flagged on #863 — edits would be lost on restart).Apply model: match #960's "save now, restart to apply" pattern (per #960's description: runtime
mcp.disable()accumulates transforms unreliably; startup-time apply is the clean path). Mark each field's apply-mode in the UI once audited.Connection settings stay read-only. Editing
HOMEASSISTANT_URL/_TOKENfrom a web UI served by the running server is a chicken-and-egg footgun.More context: as part of this we need to make sure that the web UI is always synced with the addon settings (in other words, changing settings will always require addon restart) and making sure the toggles in addon settings sync both directions between web UI. We may need to find a way to include the current pinned and/or disabled tools in the text boxes in the addon side. Similarly, we need to make sure the web UI syncs up with env vars in the non addon versions; I'm thinking if someone has set something up in the environment vars, it should be displayed in the web UI as read only, stating that the setting either needs to be modified in the env vars OR the setting can be removed from the env vars and then the web UI can take over. The beginning framework for this is being introduced in PR #1403 (if it doesn't already exist with the pinned tools and whatnot, then 1403 def adds it )
Addendum (2026-05-22): per-field env-pin pattern verified in PR #1403
PR #1403 (auto-backup web UI editor) implemented the env-var / web-UI sync
contract described in the "More context" paragraph above for the 3 new
auto-backup scalar settings (
enable_auto_backup,auto_backup_throttle_minutes,auto_backup_retain_per_entity). Behavior shipped there:/addons/self/options→ addon restart;
config.yamlstays authoritative; both UIs stay in sync.<data_dir>/backup_settings.json,Settings cache invalidates, change takes effect immediately (no restart).
read-only with a banner pointing at the env var; POST returns 409 if a write
is attempted. Detection is per-field via
os.environ.get(env_name)— having a.envfile present is not enough; the specific key must be present.Verification of the existing
disabled_tools/pinned_toolspanel (settings_ui.py:158-204):those env vars are currently seed-only —
load_tool_configreadstool_config.jsonif present and falls back to env-var seeding only on firstrun. After the file exists, env-var changes are silently ignored and the web
UI POST writes the file without any env-pin check. The addon translation for
both fields documents this as "text fallback ... seeds the initial config when
the web UI hasn't been used yet."
This violates the principle laid out in the "More context" paragraph (env vars
should not be silently overridden). Two options for the eventual #1164 PR:
Option A (leaning) — per-tool env-pinning (mirrors PR #1403 for scalars):
DISABLED_TOOLS=ha_hacs_search,ha_hacs_downloadlocks theha_hacs_searchand
ha_hacs_downloadrows read-only in the web UI; other tools remainfreely toggleable. Same for
PINNED_TOOLS. Most semantically correct matchfor the existing pattern. Documented "text fallback" behavior needs updating
in
homeassistant-addon-dev/translations/en.yaml.Option B — blanket env-pinning: if either env var is set at all, the
entire Tools tab is read-only. Simpler implementation but crude — blocks
managing tools the env var didn't mention.
Same treatment likely applies to every other env-mediated setting that the
advanced-settings panel from this issue eventually surfaces. The PR that
closes this issue should bundle the tools-panel fix with the new advanced-
settings panel so the env-pin contract is implemented in one consistent pass.