ha-mcp-dev 7.4.1.dev462__tar.gz → 7.4.1.dev464__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 (109) hide show
  1. {ha_mcp_dev-7.4.1.dev462/src/ha_mcp_dev.egg-info → ha_mcp_dev-7.4.1.dev464}/PKG-INFO +4 -3
  2. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/README.md +3 -2
  3. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/pyproject.toml +1 -1
  4. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/tools/tools_config_automations.py +92 -0
  5. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/tools/tools_config_scenes.py +13 -7
  6. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464/src/ha_mcp_dev.egg-info}/PKG-INFO +4 -3
  7. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/LICENSE +0 -0
  8. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/MANIFEST.in +0 -0
  9. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/setup.cfg +0 -0
  10. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/__init__.py +0 -0
  11. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/__main__.py +0 -0
  12. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/_pypi_marker +0 -0
  13. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/_version.py +0 -0
  14. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/auth/__init__.py +0 -0
  15. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/auth/consent_form.py +0 -0
  16. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/auth/provider.py +0 -0
  17. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/client/__init__.py +0 -0
  18. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/client/rest_client.py +0 -0
  19. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/client/websocket_client.py +0 -0
  20. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/client/websocket_listener.py +0 -0
  21. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/config.py +0 -0
  22. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/errors.py +0 -0
  23. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/py.typed +0 -0
  24. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/resources/skills-vendor/.claude/settings.json +0 -0
  25. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/resources/skills-vendor/.claude-plugin/marketplace.json +0 -0
  26. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/resources/skills-vendor/.claude-plugin/plugin.json +0 -0
  27. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/resources/skills-vendor/.github/ISSUE_TEMPLATE/skill-rca.md +0 -0
  28. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/resources/skills-vendor/AGENTS.md +0 -0
  29. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/resources/skills-vendor/CLAUDE.md +0 -0
  30. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/resources/skills-vendor/CONTRIBUTING.md +0 -0
  31. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/resources/skills-vendor/LICENSE +0 -0
  32. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/resources/skills-vendor/README.md +0 -0
  33. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/SKILL.md +0 -0
  34. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/evals/evals.json +0 -0
  35. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/automation-patterns.md +0 -0
  36. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-cards.md +0 -0
  37. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-guide.md +0 -0
  38. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/device-control.md +0 -0
  39. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/domain-docs.md +0 -0
  40. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/examples.yaml +0 -0
  41. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/helper-selection.md +0 -0
  42. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/safe-refactoring.md +0 -0
  43. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/template-guidelines.md +0 -0
  44. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/server.py +0 -0
  45. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/settings_ui.py +0 -0
  46. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/smoke_test.py +0 -0
  47. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/tools/__init__.py +0 -0
  48. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/tools/backup.py +0 -0
  49. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/tools/best_practice_checker.py +0 -0
  50. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/tools/device_control.py +0 -0
  51. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/tools/enhanced.py +0 -0
  52. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/tools/helpers.py +0 -0
  53. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/tools/reference_validator.py +0 -0
  54. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/tools/registry.py +0 -0
  55. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/tools/smart_search.py +0 -0
  56. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/tools/tools_addons.py +0 -0
  57. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/tools/tools_areas.py +0 -0
  58. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/tools/tools_blueprints.py +0 -0
  59. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/tools/tools_bug_report.py +0 -0
  60. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/tools/tools_calendar.py +0 -0
  61. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/tools/tools_camera.py +0 -0
  62. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/tools/tools_categories.py +0 -0
  63. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/tools/tools_code.py +0 -0
  64. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/tools/tools_config_dashboards.py +0 -0
  65. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/tools/tools_config_entry_flow.py +0 -0
  66. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/tools/tools_config_helpers.py +0 -0
  67. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/tools/tools_config_scripts.py +0 -0
  68. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/tools/tools_energy.py +0 -0
  69. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/tools/tools_entities.py +0 -0
  70. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/tools/tools_filesystem.py +0 -0
  71. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/tools/tools_groups.py +0 -0
  72. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/tools/tools_hacs.py +0 -0
  73. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/tools/tools_history.py +0 -0
  74. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/tools/tools_integrations.py +0 -0
  75. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/tools/tools_labels.py +0 -0
  76. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/tools/tools_mcp_component.py +0 -0
  77. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/tools/tools_registry.py +0 -0
  78. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/tools/tools_resources.py +0 -0
  79. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/tools/tools_search.py +0 -0
  80. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/tools/tools_service.py +0 -0
  81. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/tools/tools_services.py +0 -0
  82. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/tools/tools_system.py +0 -0
  83. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/tools/tools_todo.py +0 -0
  84. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/tools/tools_traces.py +0 -0
  85. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/tools/tools_updates.py +0 -0
  86. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/tools/tools_utility.py +0 -0
  87. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/tools/tools_voice_assistant.py +0 -0
  88. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/tools/tools_yaml_config.py +0 -0
  89. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/tools/tools_zones.py +0 -0
  90. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/tools/util_helpers.py +0 -0
  91. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/transforms/__init__.py +0 -0
  92. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/transforms/categorized_search.py +0 -0
  93. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/utils/__init__.py +0 -0
  94. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/utils/config_hash.py +0 -0
  95. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/utils/data_paths.py +0 -0
  96. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/utils/domain_handlers.py +0 -0
  97. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/utils/fuzzy_search.py +0 -0
  98. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/utils/kill_signal_diagnostics.py +0 -0
  99. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/utils/operation_manager.py +0 -0
  100. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/utils/python_sandbox.py +0 -0
  101. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp/utils/usage_logger.py +0 -0
  102. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp_dev.egg-info/SOURCES.txt +0 -0
  103. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp_dev.egg-info/dependency_links.txt +0 -0
  104. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp_dev.egg-info/entry_points.txt +0 -0
  105. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp_dev.egg-info/requires.txt +0 -0
  106. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/src/ha_mcp_dev.egg-info/top_level.txt +0 -0
  107. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/tests/__init__.py +0 -0
  108. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/tests/test_constants.py +0 -0
  109. {ha_mcp_dev-7.4.1.dev462 → ha_mcp_dev-7.4.1.dev464}/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.4.1.dev462
3
+ Version: 7.4.1.dev464
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
@@ -38,7 +38,7 @@ Dynamic: license-file
38
38
  <!-- mcp-name: io.github.homeassistant-ai/ha-mcp -->
39
39
 
40
40
  <p align="center">
41
- <img src="https://img.shields.io/badge/tools-85-blue" alt="95+ Tools">
41
+ <img src="https://img.shields.io/badge/tools-88-blue" alt="95+ Tools">
42
42
  <a href="https://github.com/homeassistant-ai/ha-mcp/releases"><img src="https://img.shields.io/github/v/release/homeassistant-ai/ha-mcp" alt="Release"></a>
43
43
  <a href="https://github.com/homeassistant-ai/ha-mcp/actions/workflows/e2e-tests.yml"><img src="https://img.shields.io/github/actions/workflow/status/homeassistant-ai/ha-mcp/e2e-tests.yml?branch=master&label=E2E%20Tests" alt="E2E Tests"></a>
44
44
  <a href="LICENSE.md"><img src="https://img.shields.io/github/license/homeassistant-ai/ha-mcp.svg" alt="License"></a>
@@ -181,7 +181,7 @@ Spend less time configuring, more time enjoying your smart home.
181
181
  <details>
182
182
  <!-- TOOLS_TABLE_START -->
183
183
 
184
- <summary><b>Complete Tool List (85 tools)</b></summary>
184
+ <summary><b>Complete Tool List (88 tools)</b></summary>
185
185
 
186
186
  | Category | Tools |
187
187
  |----------|-------|
@@ -202,6 +202,7 @@ Spend less time configuring, more time enjoying your smart home.
202
202
  | **History & Statistics** | `ha_get_automation_traces`, `ha_get_history`, `ha_get_logs` |
203
203
  | **Integrations** | `ha_get_integration`, `ha_set_integration_enabled` |
204
204
  | **Labels & Categories** | `ha_config_get_category`, `ha_config_get_label`, `ha_config_remove_category`, `ha_config_remove_label`, `ha_config_set_category`, `ha_config_set_label` |
205
+ | **Scenes** | `ha_config_get_scene`, `ha_config_remove_scene`, `ha_config_set_scene` |
205
206
  | **Scripts** | `ha_config_get_script`, `ha_config_remove_script`, `ha_config_set_script` |
206
207
  | **Search & Discovery** | `ha_deep_search`, `ha_get_overview`, `ha_get_state`, `ha_search_entities` |
207
208
  | **Service & Device Control** | `ha_bulk_control`, `ha_call_service`, `ha_get_operation_status`, `ha_list_services` |
@@ -8,7 +8,7 @@
8
8
  <!-- mcp-name: io.github.homeassistant-ai/ha-mcp -->
9
9
 
10
10
  <p align="center">
11
- <img src="https://img.shields.io/badge/tools-85-blue" alt="95+ Tools">
11
+ <img src="https://img.shields.io/badge/tools-88-blue" alt="95+ Tools">
12
12
  <a href="https://github.com/homeassistant-ai/ha-mcp/releases"><img src="https://img.shields.io/github/v/release/homeassistant-ai/ha-mcp" alt="Release"></a>
13
13
  <a href="https://github.com/homeassistant-ai/ha-mcp/actions/workflows/e2e-tests.yml"><img src="https://img.shields.io/github/actions/workflow/status/homeassistant-ai/ha-mcp/e2e-tests.yml?branch=master&label=E2E%20Tests" alt="E2E Tests"></a>
14
14
  <a href="LICENSE.md"><img src="https://img.shields.io/github/license/homeassistant-ai/ha-mcp.svg" alt="License"></a>
@@ -151,7 +151,7 @@ Spend less time configuring, more time enjoying your smart home.
151
151
  <details>
152
152
  <!-- TOOLS_TABLE_START -->
153
153
 
154
- <summary><b>Complete Tool List (85 tools)</b></summary>
154
+ <summary><b>Complete Tool List (88 tools)</b></summary>
155
155
 
156
156
  | Category | Tools |
157
157
  |----------|-------|
@@ -172,6 +172,7 @@ Spend less time configuring, more time enjoying your smart home.
172
172
  | **History & Statistics** | `ha_get_automation_traces`, `ha_get_history`, `ha_get_logs` |
173
173
  | **Integrations** | `ha_get_integration`, `ha_set_integration_enabled` |
174
174
  | **Labels & Categories** | `ha_config_get_category`, `ha_config_get_label`, `ha_config_remove_category`, `ha_config_remove_label`, `ha_config_set_category`, `ha_config_set_label` |
175
+ | **Scenes** | `ha_config_get_scene`, `ha_config_remove_scene`, `ha_config_set_scene` |
175
176
  | **Scripts** | `ha_config_get_script`, `ha_config_remove_script`, `ha_config_set_script` |
176
177
  | **Search & Discovery** | `ha_deep_search`, `ha_get_overview`, `ha_get_state`, `ha_search_entities` |
177
178
  | **Service & Device Control** | `ha_bulk_control`, `ha_call_service`, `ha_get_operation_status`, `ha_list_services` |
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "ha-mcp-dev"
7
- version = "7.4.1.dev462"
7
+ version = "7.4.1.dev464"
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"
@@ -168,6 +168,38 @@ def _normalize_trigger_keys(triggers: list[dict[str, Any]]) -> list[dict[str, An
168
168
  return normalized_triggers
169
169
 
170
170
 
171
+ def _action_contains_scene_create(action: Any) -> bool:
172
+ """True if the action — or any nested action under HA's wrapper keys —
173
+ invokes ``scene.create``.
174
+
175
+ Walks the standard wrappers: ``sequence``, ``parallel``, ``choose``
176
+ (with options' inner ``sequence``), ``default``, and the ``then``/
177
+ ``else`` siblings of ``if``. Returns True on the first hit, so a deep
178
+ misroute is caught before the upsert reaches HA.
179
+ """
180
+ if not isinstance(action, dict):
181
+ return False
182
+ # 'service:' is the legacy key, 'action:' the modern HA service-call
183
+ # key (HA 2024.8+). Both reach scene.create.
184
+ if "scene.create" in (action.get("service"), action.get("action")):
185
+ return True
186
+ # Wrappers whose value is a list of nested actions.
187
+ for nested_key in ("sequence", "parallel", "default", "then", "else"):
188
+ nested = action.get(nested_key)
189
+ if isinstance(nested, list):
190
+ for sub in nested:
191
+ if _action_contains_scene_create(sub):
192
+ return True
193
+ # ``choose``: list of ``{conditions, sequence}`` options.
194
+ if isinstance(action.get("choose"), list):
195
+ for opt in action["choose"]:
196
+ if isinstance(opt, dict) and isinstance(opt.get("sequence"), list):
197
+ for sub in opt["sequence"]:
198
+ if _action_contains_scene_create(sub):
199
+ return True
200
+ return False
201
+
202
+
171
203
  def _normalize_config_for_roundtrip(config: dict[str, Any]) -> dict[str, Any]:
172
204
  """
173
205
  Normalize automation config from GET response for direct use in SET.
@@ -371,6 +403,17 @@ class AutomationConfigTools:
371
403
  """
372
404
  Create or update a Home Assistant automation.
373
405
 
406
+ Before reaching for ``ha_config_set_automation``, consider whether a
407
+ dedicated tool fits the use case better:
408
+
409
+ - State snapshot of one or more entities (capture-then-replay,
410
+ no trigger needed) -> ha_config_set_scene
411
+ - State-derived value that recomputes when its inputs change
412
+ (template sensor / binary sensor / number / select)
413
+ -> ha_config_set_helper(helper_type='template')
414
+ - Stateful counter / timer / schedule / boolean / etc.
415
+ -> ha_config_set_helper(helper_type='counter' | 'timer' | ...)
416
+
374
417
  PREFER NATIVE SOLUTIONS OVER TEMPLATES (read this before writing any `{{ ... }}`):
375
418
  Native triggers/conditions/actions are validated at config load, fail loudly, and
376
419
  do not bypass HA's schema. Templates fail silently at runtime and obscure intent.
@@ -824,6 +867,55 @@ class AutomationConfigTools:
824
867
  missing_fields=missing_fields,
825
868
  ))
826
869
 
870
+ # Issue #1169: reject configs that wrap ``scene.create`` in an
871
+ # automation with no functional trigger. Models occasionally produce
872
+ # these when they want a state snapshot but pattern-match to
873
+ # ``ha_config_set_automation`` instead of ``ha_config_set_scene``.
874
+ # HA's REST endpoint accepts ``trigger: []`` (or ``null``/missing)
875
+ # and stores a never-firing automation — corruption marker, not a
876
+ # draft. Only the narrow misroute pattern is rejected so legitimate
877
+ # empty-trigger drafts paired with other actions still pass.
878
+ trigger_value = config_dict.get("trigger")
879
+ trigger_empty = trigger_value is None or (
880
+ isinstance(trigger_value, list) and not trigger_value
881
+ )
882
+ if trigger_empty:
883
+ actions_list = coerce_to_list(config_dict.get("action"))
884
+ # Walks the standard HA wrappers (``sequence`` / ``parallel`` /
885
+ # ``choose`` / ``if``-``then``/``else``) so a nested
886
+ # ``scene.create`` is caught alongside the top-level case.
887
+ scene_create_indices = [
888
+ i
889
+ for i, a in enumerate(actions_list)
890
+ if _action_contains_scene_create(a)
891
+ ]
892
+ if scene_create_indices:
893
+ raise_tool_error(create_error_response(
894
+ code=ErrorCode.VALIDATION_INVALID_PARAMETER,
895
+ message=(
896
+ "Empty trigger paired with a scene.create action — "
897
+ "this automation can never fire. For a state snapshot "
898
+ "of one or more entities, use ha_config_set_scene "
899
+ "directly instead of wrapping scene.create in an "
900
+ "automation."
901
+ ),
902
+ suggestions=[
903
+ "ha_config_set_scene(scene_id='...', config={'name': "
904
+ "'...', 'entities': {'<entity_id>': {...}}}) creates "
905
+ "a scene without a trigger.",
906
+ "If the snapshot really should be the result of an "
907
+ "event, add the trigger that should fire it and keep "
908
+ "the automation.",
909
+ "For a state-derived value that recomputes when its "
910
+ "inputs change, use "
911
+ "ha_config_set_helper(helper_type='template') instead.",
912
+ ],
913
+ context={
914
+ "scene_create_action_indices": scene_create_indices,
915
+ "identifier": identifier,
916
+ },
917
+ ))
918
+
827
919
  # HA accepts conditions with 'platform' (trigger syntax) but then crashes
828
920
  # with an unhelpful 500 rather than a 400 validation error.
829
921
  for idx, cond in enumerate(coerce_to_list(config_dict.get("condition"))):
@@ -795,13 +795,19 @@ class ConfigSceneTools:
795
795
  # the python_transform branch — a phantom category must not
796
796
  # rewrite the scene before erroring.
797
797
  #
798
- # Issue #1168 R7 blocker 22: gate on the user-facing ``category``
799
- # param, not ``effective_category``. ``_validate_scene_config``
800
- # promotes a metadata-embedded category into ``effective_category``
801
- # when the user passed ``category=None``; validating that on
802
- # every call costs a category-registry round-trip even when the
803
- # user wasn't trying to change the category at all.
804
- if category is not None and effective_category:
798
+ # Issue #1168 R8 (post-merge follow-up): gate on
799
+ # ``effective_category`` truthy, not on the user-facing
800
+ # ``category`` param. ``_validate_scene_config`` promotes a
801
+ # top-level ``config["category"]`` into ``effective_category``
802
+ # when the user passed ``category=None``; the R7 fix gated on
803
+ # ``category is not None`` to skip the WS round-trip when no
804
+ # category was supplied, but that left the dict-promoted path
805
+ # uncovered — a phantom category in ``config["category"]``
806
+ # would skip validation and reach ``apply_entity_category``,
807
+ # which attaches the phantom ID to the entity registry without
808
+ # checking it exists. Truthy check covers both sources and
809
+ # still skips the WS call when neither produces a category.
810
+ if effective_category:
805
811
  await self._validate_category_id(effective_category)
806
812
 
807
813
  # Issue #1168 R3 blocker 7: when caller passes ``config_hash``,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ha-mcp-dev
3
- Version: 7.4.1.dev462
3
+ Version: 7.4.1.dev464
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
@@ -38,7 +38,7 @@ Dynamic: license-file
38
38
  <!-- mcp-name: io.github.homeassistant-ai/ha-mcp -->
39
39
 
40
40
  <p align="center">
41
- <img src="https://img.shields.io/badge/tools-85-blue" alt="95+ Tools">
41
+ <img src="https://img.shields.io/badge/tools-88-blue" alt="95+ Tools">
42
42
  <a href="https://github.com/homeassistant-ai/ha-mcp/releases"><img src="https://img.shields.io/github/v/release/homeassistant-ai/ha-mcp" alt="Release"></a>
43
43
  <a href="https://github.com/homeassistant-ai/ha-mcp/actions/workflows/e2e-tests.yml"><img src="https://img.shields.io/github/actions/workflow/status/homeassistant-ai/ha-mcp/e2e-tests.yml?branch=master&label=E2E%20Tests" alt="E2E Tests"></a>
44
44
  <a href="LICENSE.md"><img src="https://img.shields.io/github/license/homeassistant-ai/ha-mcp.svg" alt="License"></a>
@@ -181,7 +181,7 @@ Spend less time configuring, more time enjoying your smart home.
181
181
  <details>
182
182
  <!-- TOOLS_TABLE_START -->
183
183
 
184
- <summary><b>Complete Tool List (85 tools)</b></summary>
184
+ <summary><b>Complete Tool List (88 tools)</b></summary>
185
185
 
186
186
  | Category | Tools |
187
187
  |----------|-------|
@@ -202,6 +202,7 @@ Spend less time configuring, more time enjoying your smart home.
202
202
  | **History & Statistics** | `ha_get_automation_traces`, `ha_get_history`, `ha_get_logs` |
203
203
  | **Integrations** | `ha_get_integration`, `ha_set_integration_enabled` |
204
204
  | **Labels & Categories** | `ha_config_get_category`, `ha_config_get_label`, `ha_config_remove_category`, `ha_config_remove_label`, `ha_config_set_category`, `ha_config_set_label` |
205
+ | **Scenes** | `ha_config_get_scene`, `ha_config_remove_scene`, `ha_config_set_scene` |
205
206
  | **Scripts** | `ha_config_get_script`, `ha_config_remove_script`, `ha_config_set_script` |
206
207
  | **Search & Discovery** | `ha_deep_search`, `ha_get_overview`, `ha_get_state`, `ha_search_entities` |
207
208
  | **Service & Device Control** | `ha_bulk_control`, `ha_call_service`, `ha_get_operation_status`, `ha_list_services` |