ha-mcp-dev 7.6.0.dev629__tar.gz → 7.6.0.dev630__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. {ha_mcp_dev-7.6.0.dev629/src/ha_mcp_dev.egg-info → ha_mcp_dev-7.6.0.dev630}/PKG-INFO +1 -1
  2. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/pyproject.toml +1 -1
  3. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/settings_ui.py +59 -10
  4. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/tools/tools_code.py +11 -0
  5. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630/src/ha_mcp_dev.egg-info}/PKG-INFO +1 -1
  6. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/LICENSE +0 -0
  7. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/MANIFEST.in +0 -0
  8. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/README.md +0 -0
  9. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/setup.cfg +0 -0
  10. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/__init__.py +0 -0
  11. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/__main__.py +0 -0
  12. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/_pypi_marker +0 -0
  13. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/_version.py +0 -0
  14. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/auth/__init__.py +0 -0
  15. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/auth/consent_form.py +0 -0
  16. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/auth/provider.py +0 -0
  17. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/backup_manager.py +0 -0
  18. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/client/__init__.py +0 -0
  19. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/client/rest_client.py +0 -0
  20. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/client/supervisor_client.py +0 -0
  21. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/client/websocket_client.py +0 -0
  22. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/client/websocket_listener.py +0 -0
  23. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/config.py +0 -0
  24. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/errors.py +0 -0
  25. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/policy/__init__.py +0 -0
  26. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/policy/approval_queue.py +0 -0
  27. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/policy/evaluator.py +0 -0
  28. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/policy/handlers.py +0 -0
  29. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/policy/middleware.py +0 -0
  30. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/policy/model.py +0 -0
  31. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/policy/persistence.py +0 -0
  32. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/policy/value_sources.py +0 -0
  33. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/py.typed +0 -0
  34. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/resources/skills-vendor/.claude/settings.json +0 -0
  35. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/resources/skills-vendor/.claude-plugin/marketplace.json +0 -0
  36. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/resources/skills-vendor/.claude-plugin/plugin.json +0 -0
  37. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/resources/skills-vendor/.github/ISSUE_TEMPLATE/skill-rca.md +0 -0
  38. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/resources/skills-vendor/.github/pull_request_template.md +0 -0
  39. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/resources/skills-vendor/AGENTS.md +0 -0
  40. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/resources/skills-vendor/CLAUDE.md +0 -0
  41. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/resources/skills-vendor/CONTRIBUTING.md +0 -0
  42. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/resources/skills-vendor/LICENSE +0 -0
  43. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/resources/skills-vendor/README.md +0 -0
  44. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/SKILL.md +0 -0
  45. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/evals/evals.json +0 -0
  46. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/automation-patterns.md +0 -0
  47. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-cards.md +0 -0
  48. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-guide.md +0 -0
  49. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/device-control.md +0 -0
  50. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/domain-docs.md +0 -0
  51. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/examples.yaml +0 -0
  52. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/helper-selection.md +0 -0
  53. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/safe-refactoring.md +0 -0
  54. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/template-guidelines.md +0 -0
  55. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/yaml-only-integrations.md +0 -0
  56. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/server.py +0 -0
  57. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/smoke_test.py +0 -0
  58. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/stdio_settings_sidecar.py +0 -0
  59. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/tools/__init__.py +0 -0
  60. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/tools/auto_backup.py +0 -0
  61. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/tools/backup.py +0 -0
  62. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/tools/best_practice_checker.py +0 -0
  63. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/tools/device_control.py +0 -0
  64. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/tools/enhanced.py +0 -0
  65. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/tools/helpers.py +0 -0
  66. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/tools/reference_validator.py +0 -0
  67. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/tools/registry.py +0 -0
  68. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/tools/smart_search.py +0 -0
  69. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/tools/tools_addons.py +0 -0
  70. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/tools/tools_areas.py +0 -0
  71. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/tools/tools_blueprints.py +0 -0
  72. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/tools/tools_bug_report.py +0 -0
  73. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/tools/tools_calendar.py +0 -0
  74. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/tools/tools_camera.py +0 -0
  75. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/tools/tools_categories.py +0 -0
  76. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/tools/tools_config_automations.py +0 -0
  77. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/tools/tools_config_dashboards.py +0 -0
  78. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/tools/tools_config_entry_flow.py +0 -0
  79. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/tools/tools_config_helpers.py +0 -0
  80. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/tools/tools_config_scenes.py +0 -0
  81. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/tools/tools_config_scripts.py +0 -0
  82. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/tools/tools_energy.py +0 -0
  83. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/tools/tools_entities.py +0 -0
  84. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/tools/tools_filesystem.py +0 -0
  85. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/tools/tools_groups.py +0 -0
  86. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/tools/tools_hacs.py +0 -0
  87. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/tools/tools_history.py +0 -0
  88. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/tools/tools_integrations.py +0 -0
  89. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/tools/tools_labels.py +0 -0
  90. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/tools/tools_mcp_component.py +0 -0
  91. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/tools/tools_registry.py +0 -0
  92. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/tools/tools_resources.py +0 -0
  93. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/tools/tools_search.py +0 -0
  94. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/tools/tools_service.py +0 -0
  95. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/tools/tools_services.py +0 -0
  96. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/tools/tools_system.py +0 -0
  97. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/tools/tools_todo.py +0 -0
  98. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/tools/tools_traces.py +0 -0
  99. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/tools/tools_updates.py +0 -0
  100. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/tools/tools_utility.py +0 -0
  101. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/tools/tools_voice_assistant.py +0 -0
  102. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/tools/tools_yaml_config.py +0 -0
  103. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/tools/tools_zones.py +0 -0
  104. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/tools/util_helpers.py +0 -0
  105. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/tools/validation_middleware.py +0 -0
  106. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/transforms/__init__.py +0 -0
  107. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/transforms/categorized_search.py +0 -0
  108. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/transforms/lite_docstrings.py +0 -0
  109. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/utils/__init__.py +0 -0
  110. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/utils/config_hash.py +0 -0
  111. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/utils/data_paths.py +0 -0
  112. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/utils/domain_handlers.py +0 -0
  113. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/utils/fuzzy_search.py +0 -0
  114. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/utils/kill_signal_diagnostics.py +0 -0
  115. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/utils/operation_manager.py +0 -0
  116. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/utils/python_sandbox.py +0 -0
  117. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/utils/skill_loader.py +0 -0
  118. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp/utils/usage_logger.py +0 -0
  119. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp_dev.egg-info/SOURCES.txt +0 -0
  120. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp_dev.egg-info/dependency_links.txt +0 -0
  121. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp_dev.egg-info/entry_points.txt +0 -0
  122. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp_dev.egg-info/requires.txt +0 -0
  123. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/src/ha_mcp_dev.egg-info/top_level.txt +0 -0
  124. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/tests/__init__.py +0 -0
  125. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/tests/test_constants.py +0 -0
  126. {ha_mcp_dev-7.6.0.dev629 → ha_mcp_dev-7.6.0.dev630}/tests/test_env_manager.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ha-mcp-dev
3
- Version: 7.6.0.dev629
3
+ Version: 7.6.0.dev630
4
4
  Summary: Home Assistant MCP Server - Complete control of Home Assistant through MCP
5
5
  Author-email: Julien <github@qc-h.net>
6
6
  License: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "ha-mcp-dev"
7
- version = "7.6.0.dev629"
7
+ version = "7.6.0.dev630"
8
8
  description = "Home Assistant MCP Server - Complete control of Home Assistant through MCP"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.13,<3.14"
@@ -602,6 +602,10 @@ _SETTINGS_HTML = (
602
602
  <meta charset="UTF-8">
603
603
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
604
604
  <title>HA-MCP Tool Settings</title>
605
+ <!-- Empty data URI: tells the browser "no favicon" so it never requests
606
+ /favicon.ico (which would 404 and log a console error, since the
607
+ settings server serves no such asset in any deployment mode). -->
608
+ <link rel="icon" href="data:,">
605
609
  <style>
606
610
  :root {
607
611
  --bg: #1c1c1e; --surface: #2c2c2e; --surface-hover: #3a3a3c;
@@ -2548,9 +2552,36 @@ function renderCodeModeSubRows(parentEl, masterOn, codeModeOn) {
2548
2552
 
2549
2553
  const info = document.createElement('div');
2550
2554
  info.className = 'feature-info';
2551
- const lockedNote = f.origin === 'env'
2552
- ? `<div class="feature-locked-note">Set via env var <code>${escapeHtml(f.env_var)}</code> unset it to edit here.</div>`
2553
- : '';
2555
+ // code_mode_saved_tools_path needs honest, field-specific copy:
2556
+ // - add-on mode: hardcoded by start.py (setdefault to /data); not
2557
+ // Supervisor-managed and absent from the addon schema, so it
2558
+ // genuinely can't be changed — don't imply a lever exists.
2559
+ // - standalone with the env var set: the "unset it" hint IS
2560
+ // actionable (the operator controls the env var), so keep it.
2561
+ // - standalone with no path: a blank path disables persistence —
2562
+ // warn that saved tools live in memory only.
2563
+ // Other env-locked code-mode sub-fields keep the shared helper.
2564
+ let lockedNote = '';
2565
+ if (f.field === 'code_mode_saved_tools_path') {
2566
+ if (IS_ADDON_MODE) {
2567
+ lockedNote =
2568
+ '<div class="feature-locked-note">Hardcoded to ' +
2569
+ '<code>/data/saved_tools.json</code> in add-on mode and cannot ' +
2570
+ 'be changed (fixed here so saved tools survive add-on updates).' +
2571
+ '</div>';
2572
+ } else if (f.origin === 'env') {
2573
+ lockedNote =
2574
+ `<div class="feature-locked-note">${envLockedNoteHtml(f.env_var, f.field)}</div>`;
2575
+ } else if (!f.value) {
2576
+ lockedNote =
2577
+ '<div class="feature-locked-note">If blank, custom tools are kept ' +
2578
+ 'in memory only and lost on restart. Set a path on persistent ' +
2579
+ 'storage to keep them.</div>';
2580
+ }
2581
+ } else if (f.origin === 'env') {
2582
+ lockedNote =
2583
+ `<div class="feature-locked-note">${envLockedNoteHtml(f.env_var, f.field)}</div>`;
2584
+ }
2554
2585
  info.innerHTML =
2555
2586
  `<div class="feature-name">${escapeHtml(meta.label)}</div>` +
2556
2587
  `<div class="feature-help">${escapeHtml(meta.help)}</div>` +
@@ -5373,16 +5404,34 @@ def build_settings_handlers(
5373
5404
  if is_addon_synced:
5374
5405
  addon_writes_present = True
5375
5406
  elif os.environ.get(env_name) is not None:
5407
+ # Add-on mode has no env-var surface for non-schema keys
5408
+ # (e.g. CODE_MODE_SAVED_TOOLS_PATH, set by start.py), so
5409
+ # "unset it to edit here" is unactionable there — give
5410
+ # add-on-aware copy instead of implying a lever exists.
5411
+ if addon_mode:
5412
+ message = (
5413
+ f"{fname!r} is fixed by the add-on runtime and "
5414
+ "cannot be changed from the web UI."
5415
+ )
5416
+ suggestions = [
5417
+ "This value is baked into the add-on and is not "
5418
+ "exposed as an editable setting.",
5419
+ ]
5420
+ else:
5421
+ message = (
5422
+ f"{fname!r} is set via {env_name} env var — "
5423
+ "unset it to edit here."
5424
+ )
5425
+ suggestions = [
5426
+ f"Unset the {env_name} environment variable (or "
5427
+ "remove it from your Docker config), then restart "
5428
+ "to edit this setting from the UI.",
5429
+ ]
5376
5430
  return JSONResponse(
5377
5431
  create_error_response(
5378
5432
  ErrorCode.VALIDATION_INVALID_PARAMETER,
5379
- f"{fname!r} is set via {env_name} env var — "
5380
- "unset it to edit here.",
5381
- suggestions=[
5382
- f"Unset the {env_name} environment variable (or "
5383
- "remove it from your addon/Docker config), then "
5384
- "restart to edit this setting from the UI.",
5385
- ],
5433
+ message,
5434
+ suggestions=suggestions,
5386
5435
  context={"env_var": env_name},
5387
5436
  ),
5388
5437
  status_code=409,
@@ -1290,5 +1290,16 @@ def register_code_tools(mcp: Any, client: Any, **kwargs: Any) -> None:
1290
1290
  "in-memory cache. Check operator logs for the "
1291
1291
  "underlying I/O error."
1292
1292
  )
1293
+ elif not settings.code_mode_saved_tools_path:
1294
+ # Blank path = persistence disabled: the in-memory save
1295
+ # succeeded but is lost on restart. Surface a warning so
1296
+ # the agent doesn't assume the entry is durable — mirrors
1297
+ # the write-failure branch above.
1298
+ response["data"]["save_warning"] = (
1299
+ f"save_as={save_as!r} is kept in memory only — "
1300
+ "code_mode_saved_tools_path is unset, so custom tools "
1301
+ "are not persisted and are lost on restart. Set a path "
1302
+ "on persistent storage to keep them."
1303
+ )
1293
1304
 
1294
1305
  return response
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ha-mcp-dev
3
- Version: 7.6.0.dev629
3
+ Version: 7.6.0.dev630
4
4
  Summary: Home Assistant MCP Server - Complete control of Home Assistant through MCP
5
5
  Author-email: Julien <github@qc-h.net>
6
6
  License: MIT