Skip to content

[FEATURE] Advanced settings panel in web UI + beta-features opt-in #1164

Description

@kingpanther13

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 fieldbeta_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-onlyload_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.

Metadata

Metadata

Assignees

Labels

enhancementNew feature or requestissue-analyzedDeep Claude analysis completeneeds-choicesImplementation requires decisions/choices to be madepriority: mediumMedium priority featuretriaged

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions