ha-mcp-dev 7.3.0.dev403__tar.gz → 7.3.0.dev404__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 (105) hide show
  1. {ha_mcp_dev-7.3.0.dev403/src/ha_mcp_dev.egg-info → ha_mcp_dev-7.3.0.dev404}/PKG-INFO +5 -5
  2. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/README.md +4 -4
  3. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/pyproject.toml +1 -1
  4. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/tools/helpers.py +7 -0
  5. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/tools/tools_config_helpers.py +0 -267
  6. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/tools/tools_groups.py +5 -5
  7. ha_mcp_dev-7.3.0.dev404/src/ha_mcp/tools/tools_integrations.py +1163 -0
  8. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404/src/ha_mcp_dev.egg-info}/PKG-INFO +5 -5
  9. ha_mcp_dev-7.3.0.dev403/src/ha_mcp/tools/tools_integrations.py +0 -483
  10. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/LICENSE +0 -0
  11. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/MANIFEST.in +0 -0
  12. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/setup.cfg +0 -0
  13. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/__init__.py +0 -0
  14. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/__main__.py +0 -0
  15. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/_pypi_marker +0 -0
  16. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/_version.py +0 -0
  17. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/auth/__init__.py +0 -0
  18. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/auth/consent_form.py +0 -0
  19. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/auth/provider.py +0 -0
  20. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/client/__init__.py +0 -0
  21. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/client/rest_client.py +0 -0
  22. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/client/websocket_client.py +0 -0
  23. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/client/websocket_listener.py +0 -0
  24. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/config.py +0 -0
  25. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/errors.py +0 -0
  26. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/py.typed +0 -0
  27. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/resources/skills-vendor/.claude/settings.json +0 -0
  28. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/resources/skills-vendor/.claude-plugin/marketplace.json +0 -0
  29. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/resources/skills-vendor/.claude-plugin/plugin.json +0 -0
  30. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/resources/skills-vendor/.github/ISSUE_TEMPLATE/skill-rca.md +0 -0
  31. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/resources/skills-vendor/AGENTS.md +0 -0
  32. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/resources/skills-vendor/CLAUDE.md +0 -0
  33. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/resources/skills-vendor/CONTRIBUTING.md +0 -0
  34. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/resources/skills-vendor/LICENSE +0 -0
  35. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/resources/skills-vendor/README.md +0 -0
  36. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/SKILL.md +0 -0
  37. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/evals/evals.json +0 -0
  38. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/automation-patterns.md +0 -0
  39. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-cards.md +0 -0
  40. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-guide.md +0 -0
  41. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/device-control.md +0 -0
  42. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/domain-docs.md +0 -0
  43. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/examples.yaml +0 -0
  44. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/helper-selection.md +0 -0
  45. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/safe-refactoring.md +0 -0
  46. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/template-guidelines.md +0 -0
  47. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/server.py +0 -0
  48. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/smoke_test.py +0 -0
  49. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/tools/__init__.py +0 -0
  50. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/tools/backup.py +0 -0
  51. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/tools/best_practice_checker.py +0 -0
  52. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/tools/device_control.py +0 -0
  53. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/tools/enhanced.py +0 -0
  54. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/tools/reference_validator.py +0 -0
  55. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/tools/registry.py +0 -0
  56. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/tools/smart_search.py +0 -0
  57. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/tools/tools_addons.py +0 -0
  58. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/tools/tools_areas.py +0 -0
  59. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/tools/tools_blueprints.py +0 -0
  60. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/tools/tools_bug_report.py +0 -0
  61. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/tools/tools_calendar.py +0 -0
  62. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/tools/tools_camera.py +0 -0
  63. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/tools/tools_categories.py +0 -0
  64. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/tools/tools_config_automations.py +0 -0
  65. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/tools/tools_config_dashboards.py +0 -0
  66. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/tools/tools_config_entry_flow.py +0 -0
  67. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/tools/tools_config_scripts.py +0 -0
  68. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/tools/tools_energy.py +0 -0
  69. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/tools/tools_entities.py +0 -0
  70. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/tools/tools_filesystem.py +0 -0
  71. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/tools/tools_hacs.py +0 -0
  72. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/tools/tools_history.py +0 -0
  73. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/tools/tools_labels.py +0 -0
  74. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/tools/tools_mcp_component.py +0 -0
  75. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/tools/tools_registry.py +0 -0
  76. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/tools/tools_resources.py +0 -0
  77. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/tools/tools_search.py +0 -0
  78. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/tools/tools_service.py +0 -0
  79. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/tools/tools_services.py +0 -0
  80. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/tools/tools_system.py +0 -0
  81. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/tools/tools_todo.py +0 -0
  82. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/tools/tools_traces.py +0 -0
  83. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/tools/tools_updates.py +0 -0
  84. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/tools/tools_utility.py +0 -0
  85. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/tools/tools_voice_assistant.py +0 -0
  86. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/tools/tools_yaml_config.py +0 -0
  87. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/tools/tools_zones.py +0 -0
  88. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/tools/util_helpers.py +0 -0
  89. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/transforms/__init__.py +0 -0
  90. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/transforms/categorized_search.py +0 -0
  91. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/utils/__init__.py +0 -0
  92. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/utils/config_hash.py +0 -0
  93. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/utils/domain_handlers.py +0 -0
  94. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/utils/fuzzy_search.py +0 -0
  95. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/utils/operation_manager.py +0 -0
  96. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/utils/python_sandbox.py +0 -0
  97. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp/utils/usage_logger.py +0 -0
  98. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp_dev.egg-info/SOURCES.txt +0 -0
  99. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp_dev.egg-info/dependency_links.txt +0 -0
  100. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp_dev.egg-info/entry_points.txt +0 -0
  101. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp_dev.egg-info/requires.txt +0 -0
  102. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/src/ha_mcp_dev.egg-info/top_level.txt +0 -0
  103. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/tests/__init__.py +0 -0
  104. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/tests/test_constants.py +0 -0
  105. {ha_mcp_dev-7.3.0.dev403 → ha_mcp_dev-7.3.0.dev404}/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.3.0.dev403
3
+ Version: 7.3.0.dev404
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
@@ -37,7 +37,7 @@ Dynamic: license-file
37
37
  <!-- mcp-name: io.github.homeassistant-ai/ha-mcp -->
38
38
 
39
39
  <p align="center">
40
- <img src="https://img.shields.io/badge/tools-87-blue" alt="95+ Tools">
40
+ <img src="https://img.shields.io/badge/tools-86-blue" alt="95+ Tools">
41
41
  <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>
42
42
  <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>
43
43
  <a href="LICENSE.md"><img src="https://img.shields.io/github/license/homeassistant-ai/ha-mcp.svg" alt="License"></a>
@@ -180,7 +180,7 @@ Spend less time configuring, more time enjoying your smart home.
180
180
  <details>
181
181
  <!-- TOOLS_TABLE_START -->
182
182
 
183
- <summary><b>Complete Tool List (87 tools)</b></summary>
183
+ <summary><b>Complete Tool List (86 tools)</b></summary>
184
184
 
185
185
  | Category | Tools |
186
186
  |----------|-------|
@@ -197,9 +197,9 @@ Spend less time configuring, more time enjoying your smart home.
197
197
  | **Files** | `ha_delete_file` *(beta)*, `ha_list_files` *(beta)*, `ha_read_file` *(beta)*, `ha_write_file` *(beta)* |
198
198
  | **Groups** | `ha_config_list_groups`, `ha_config_remove_group`, `ha_config_set_group` |
199
199
  | **HACS** | `ha_hacs_add_repository`, `ha_hacs_download`, `ha_hacs_repository_info`, `ha_hacs_search` |
200
- | **Helper Entities** | `ha_config_list_helpers`, `ha_config_remove_helper`, `ha_config_set_helper`, `ha_get_helper_schema` |
200
+ | **Helper Entities** | `ha_config_list_helpers`, `ha_config_set_helper`, `ha_delete_helpers_integrations`, `ha_get_helper_schema` |
201
201
  | **History & Statistics** | `ha_get_automation_traces`, `ha_get_history`, `ha_get_logs` |
202
- | **Integrations** | `ha_delete_config_entry`, `ha_get_integration`, `ha_set_integration_enabled` |
202
+ | **Integrations** | `ha_get_integration`, `ha_set_integration_enabled` |
203
203
  | **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` |
204
204
  | **Scripts** | `ha_config_get_script`, `ha_config_remove_script`, `ha_config_set_script` |
205
205
  | **Search & Discovery** | `ha_deep_search`, `ha_get_overview`, `ha_get_state`, `ha_search_entities` |
@@ -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-87-blue" alt="95+ Tools">
11
+ <img src="https://img.shields.io/badge/tools-86-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 (87 tools)</b></summary>
154
+ <summary><b>Complete Tool List (86 tools)</b></summary>
155
155
 
156
156
  | Category | Tools |
157
157
  |----------|-------|
@@ -168,9 +168,9 @@ Spend less time configuring, more time enjoying your smart home.
168
168
  | **Files** | `ha_delete_file` *(beta)*, `ha_list_files` *(beta)*, `ha_read_file` *(beta)*, `ha_write_file` *(beta)* |
169
169
  | **Groups** | `ha_config_list_groups`, `ha_config_remove_group`, `ha_config_set_group` |
170
170
  | **HACS** | `ha_hacs_add_repository`, `ha_hacs_download`, `ha_hacs_repository_info`, `ha_hacs_search` |
171
- | **Helper Entities** | `ha_config_list_helpers`, `ha_config_remove_helper`, `ha_config_set_helper`, `ha_get_helper_schema` |
171
+ | **Helper Entities** | `ha_config_list_helpers`, `ha_config_set_helper`, `ha_delete_helpers_integrations`, `ha_get_helper_schema` |
172
172
  | **History & Statistics** | `ha_get_automation_traces`, `ha_get_history`, `ha_get_logs` |
173
- | **Integrations** | `ha_delete_config_entry`, `ha_get_integration`, `ha_set_integration_enabled` |
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
175
  | **Scripts** | `ha_config_get_script`, `ha_config_remove_script`, `ha_config_set_script` |
176
176
  | **Search & Discovery** | `ha_deep_search`, `ha_get_overview`, `ha_get_state`, `ha_search_entities` |
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "ha-mcp-dev"
7
- version = "7.3.0.dev403"
7
+ version = "7.3.0.dev404"
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"
@@ -308,6 +308,13 @@ def exception_to_structured_error(
308
308
  error_response = _classify_exception(error, error_str, error_msg, context)
309
309
 
310
310
  if suggestions and "error" in error_response and isinstance(error_response["error"], dict):
311
+ # Set both `suggestion` (singular, first item) and `suggestions`
312
+ # (plural, full list). create_error_response (errors.py) sets the
313
+ # singular key; existing tests for exception_to_structured_error
314
+ # rely on the plural key being present even for single-item caller
315
+ # suggestions. Setting both keeps response consumers on both code
316
+ # paths working.
317
+ error_response["error"]["suggestion"] = suggestions[0]
311
318
  error_response["error"]["suggestions"] = suggestions
312
319
 
313
320
  # Append macOS-specific hints for connection failures (after all other processing
@@ -26,7 +26,6 @@ from .util_helpers import (
26
26
  parse_json_param,
27
27
  parse_string_list_param,
28
28
  wait_for_entity_registered,
29
- wait_for_entity_removed,
30
29
  )
31
30
 
32
31
  # Simple helper types — managed via {type}/create and {type}/update WebSocket APIs
@@ -1668,269 +1667,3 @@ def register_config_helper_tools(mcp: Any, client: Any, **kwargs: Any) -> None:
1668
1667
  "Ensure required parameters are provided for the helper type",
1669
1668
  ],
1670
1669
  )
1671
-
1672
- @mcp.tool(
1673
- tags={"Helper Entities"},
1674
- annotations={
1675
- "destructiveHint": True,
1676
- "idempotentHint": True,
1677
- "title": "Remove Helper",
1678
- },
1679
- )
1680
- @log_tool_usage
1681
- async def ha_config_remove_helper(
1682
- helper_type: Annotated[
1683
- Literal[
1684
- "input_button",
1685
- "input_boolean",
1686
- "input_select",
1687
- "input_number",
1688
- "input_text",
1689
- "input_datetime",
1690
- "counter",
1691
- "timer",
1692
- "schedule",
1693
- "zone",
1694
- "person",
1695
- "tag",
1696
- ],
1697
- Field(description="Type of helper entity to delete"),
1698
- ],
1699
- helper_id: Annotated[
1700
- str,
1701
- Field(
1702
- description="Helper ID to delete (e.g., 'my_button' or 'input_button.my_button')"
1703
- ),
1704
- ],
1705
- wait: Annotated[
1706
- bool | str,
1707
- Field(
1708
- description="Wait for helper entity to be fully removed before returning. Default: True.",
1709
- default=True,
1710
- ),
1711
- ] = True,
1712
- ) -> dict[str, Any]:
1713
- """
1714
- Delete a Home Assistant helper entity.
1715
-
1716
- SUPPORTED HELPER TYPES:
1717
- - input_button, input_boolean, input_select, input_number, input_text, input_datetime
1718
- - counter, timer, schedule, zone, person, tag
1719
-
1720
- For flow-based helper types (template, group, utility_meter, derivative,
1721
- min_max, threshold, integration, statistics, trend, random, filter, tod,
1722
- generic_thermostat, switch_as_x, generic_hygrostat) use ha_delete_config_entry.
1723
-
1724
- EXAMPLES:
1725
- - Delete button: ha_config_remove_helper("input_button", "my_button")
1726
- - Delete counter: ha_config_remove_helper("counter", "my_counter")
1727
- - Delete timer: ha_config_remove_helper("timer", "my_timer")
1728
- - Delete schedule: ha_config_remove_helper("schedule", "work_hours")
1729
-
1730
- **WARNING:** Deleting a helper that is used by automations or scripts may cause those automations/scripts to fail.
1731
- Use ha_search_entities() to verify the helper exists before attempting to delete it.
1732
- """
1733
- try:
1734
- # Convert helper_id to full entity_id if needed
1735
- entity_id = (
1736
- helper_id
1737
- if helper_id.startswith(helper_type)
1738
- else f"{helper_type}.{helper_id}"
1739
- )
1740
-
1741
- # Try to get unique_id with retry logic to handle race conditions
1742
- unique_id = None
1743
- registry_result = None
1744
- max_retries = 3
1745
-
1746
- for attempt in range(max_retries):
1747
- logger.info(
1748
- f"Getting entity registry for: {entity_id} (attempt {attempt + 1}/{max_retries})"
1749
- )
1750
-
1751
- # Check if entity exists via state API first (faster check)
1752
- try:
1753
- state_check = await client.get_entity_state(entity_id)
1754
- if not state_check:
1755
- # Entity doesn't exist in state, wait a bit for registration
1756
- if attempt < max_retries - 1:
1757
- wait_time = 0.5 * (
1758
- 2**attempt
1759
- ) # Exponential backoff: 0.5s, 1s, 2s
1760
- logger.debug(
1761
- f"Entity {entity_id} not found in state, waiting {wait_time}s before retry..."
1762
- )
1763
- await asyncio.sleep(wait_time)
1764
- continue
1765
- except Exception as e:
1766
- logger.debug(f"State check failed for {entity_id}: {e}")
1767
-
1768
- # Try registry lookup
1769
- registry_msg: dict[str, Any] = {
1770
- "type": "config/entity_registry/get",
1771
- "entity_id": entity_id,
1772
- }
1773
-
1774
- try:
1775
- registry_result = await client.send_websocket_message(registry_msg)
1776
-
1777
- if registry_result.get("success"):
1778
- entity_entry = registry_result.get("result", {})
1779
- unique_id = entity_entry.get("unique_id")
1780
- if unique_id:
1781
- logger.info(f"Found unique_id: {unique_id} for {entity_id}")
1782
- break
1783
-
1784
- # If registry lookup failed but we haven't exhausted retries, wait and try again
1785
- if attempt < max_retries - 1:
1786
- wait_time = 0.5 * (2**attempt) # Exponential backoff
1787
- logger.debug(
1788
- f"Registry lookup failed for {entity_id}, waiting {wait_time}s before retry..."
1789
- )
1790
- await asyncio.sleep(wait_time)
1791
-
1792
- except Exception as e:
1793
- logger.warning(f"Registry lookup attempt {attempt + 1} failed: {e}")
1794
- if attempt < max_retries - 1:
1795
- wait_time = 0.5 * (2**attempt)
1796
- await asyncio.sleep(wait_time)
1797
-
1798
- # Fallback strategy 1: Try deletion with helper_id directly if unique_id not found
1799
- if not unique_id:
1800
- logger.info(
1801
- f"Could not find unique_id for {entity_id}, trying direct deletion with helper_id"
1802
- )
1803
-
1804
- # Try deleting using helper_id directly (fallback approach)
1805
- delete_msg: dict[str, Any] = {
1806
- "type": f"{helper_type}/delete",
1807
- f"{helper_type}_id": helper_id,
1808
- }
1809
-
1810
- logger.info(f"Sending fallback WebSocket delete message: {delete_msg}")
1811
- result = await client.send_websocket_message(delete_msg)
1812
-
1813
- if result.get("success"):
1814
- # Wait for entity to be removed
1815
- wait_bool = coerce_bool_param(wait, "wait", default=True)
1816
- response: dict[str, Any] = {
1817
- "success": True,
1818
- "action": "delete",
1819
- "helper_type": helper_type,
1820
- "helper_id": helper_id,
1821
- "entity_id": entity_id,
1822
- "method": "fallback_direct_id",
1823
- "message": f"Successfully deleted {helper_type}: {helper_id} using direct ID (entity: {entity_id})",
1824
- }
1825
- if wait_bool:
1826
- try:
1827
- removed = await wait_for_entity_removed(client, entity_id)
1828
- if not removed:
1829
- response["warning"] = (
1830
- f"Deletion confirmed but {entity_id} may still appear briefly."
1831
- )
1832
- except Exception as e:
1833
- response["warning"] = (
1834
- f"Deletion confirmed but removal verification failed: {e}"
1835
- )
1836
- return response
1837
-
1838
- # Fallback strategy 2: Check if entity was already deleted
1839
- try:
1840
- final_state_check = await client.get_entity_state(entity_id)
1841
- if not final_state_check:
1842
- logger.info(
1843
- f"Entity {entity_id} no longer exists, considering deletion successful"
1844
- )
1845
- return {
1846
- "success": True,
1847
- "action": "delete",
1848
- "helper_type": helper_type,
1849
- "helper_id": helper_id,
1850
- "entity_id": entity_id,
1851
- "method": "already_deleted",
1852
- "message": f"Helper {helper_id} was already deleted or never properly registered",
1853
- }
1854
- except Exception:
1855
- pass
1856
-
1857
- # Final fallback failed
1858
- raise_tool_error(
1859
- create_error_response(
1860
- ErrorCode.ENTITY_NOT_FOUND,
1861
- f"Helper not found in entity registry after {max_retries} attempts: {registry_result.get('error', 'Unknown error') if registry_result else 'No registry response'}",
1862
- suggestions=[
1863
- "Helper may not be properly registered or was already deleted. Use ha_search_entities() to verify.",
1864
- ],
1865
- context={"helper_id": helper_id, "entity_id": entity_id},
1866
- )
1867
- )
1868
-
1869
- # Delete helper using unique_id (correct API from docs)
1870
- delete_message: dict[str, Any] = {
1871
- "type": f"{helper_type}/delete",
1872
- f"{helper_type}_id": unique_id,
1873
- }
1874
-
1875
- logger.info(f"Sending WebSocket delete message: {delete_message}")
1876
- result = await client.send_websocket_message(delete_message)
1877
- logger.info(f"WebSocket delete response: {result}")
1878
-
1879
- if result.get("success"):
1880
- # Wait for entity to be removed
1881
- wait_bool = coerce_bool_param(wait, "wait", default=True)
1882
- response = {
1883
- "success": True,
1884
- "action": "delete",
1885
- "helper_type": helper_type,
1886
- "helper_id": helper_id,
1887
- "entity_id": entity_id,
1888
- "unique_id": unique_id,
1889
- "method": "standard",
1890
- "message": f"Successfully deleted {helper_type}: {helper_id} (entity: {entity_id})",
1891
- }
1892
- if wait_bool:
1893
- try:
1894
- removed = await wait_for_entity_removed(client, entity_id)
1895
- if not removed:
1896
- response["warning"] = (
1897
- f"Deletion confirmed but {entity_id} may still appear briefly."
1898
- )
1899
- except Exception as e:
1900
- response["warning"] = (
1901
- f"Deletion confirmed but removal verification failed: {e}"
1902
- )
1903
- return response
1904
- else:
1905
- error_msg = result.get("error", "Unknown error")
1906
- # Handle specific HA error messages
1907
- if isinstance(error_msg, dict):
1908
- error_msg = error_msg.get("message", str(error_msg))
1909
-
1910
- raise_tool_error(
1911
- create_error_response(
1912
- ErrorCode.SERVICE_CALL_FAILED,
1913
- f"Failed to delete helper: {error_msg}",
1914
- suggestions=[
1915
- "Make sure the helper exists and is not being used by automations or scripts",
1916
- ],
1917
- context={
1918
- "helper_id": helper_id,
1919
- "entity_id": entity_id,
1920
- "unique_id": unique_id,
1921
- },
1922
- )
1923
- )
1924
-
1925
- except ToolError:
1926
- raise
1927
- except Exception as e:
1928
- exception_to_structured_error(
1929
- e,
1930
- context={"helper_type": helper_type, "helper_id": helper_id},
1931
- suggestions=[
1932
- "Check Home Assistant connection",
1933
- "Verify helper_id exists using ha_search_entities()",
1934
- "Ensure helper is not being used by automations or scripts",
1935
- ],
1936
- )
@@ -250,12 +250,12 @@ class GroupTools:
250
250
  **When NOT to use:** for typical "combine these entities into one controllable group"
251
251
  requests, prefer `ha_config_set_helper(helper_type="group", ...)`. Config-entry-backed
252
252
  groups are registered in the entity registry, so `ha_set_entity` can assign them to
253
- areas and they are deletable via `ha_delete_config_entry`.
253
+ areas and they are deletable via `ha_delete_helpers_integrations`.
254
254
 
255
255
  **When to use:** compatibility with existing groups already configured via group.set
256
256
  or YAML, or the rare case where entity-registry membership is explicitly unwanted.
257
- Groups created here are only removable via `ha_config_remove_group` — neither
258
- `ha_config_remove_helper` nor `ha_delete_config_entry` will find them.
257
+ Groups created here are only removable via `ha_config_remove_group` —
258
+ `ha_delete_helpers_integrations` will not find them.
259
259
 
260
260
  **For NEW groups:** Provide object_id and entities (required).
261
261
  **For EXISTING groups:** Provide object_id and any fields to update.
@@ -343,8 +343,8 @@ class GroupTools:
343
343
  Remove a service-based Home Assistant entity group via the group.remove service.
344
344
 
345
345
  **When NOT to use:** for groups created through `ha_config_set_helper(helper_type="group", ...)`,
346
- use `ha_delete_config_entry`. Those config-entry-backed groups are not reachable via the
347
- group.remove service, and `ha_config_remove_helper` does not support helper_type="group".
346
+ use `ha_delete_helpers_integrations`. Those config-entry-backed groups are not reachable via the
347
+ group.remove service.
348
348
 
349
349
  **When to use:** removing groups created with `ha_config_set_group` or defined in YAML
350
350
  via `group:` configuration. Config-entry-backed deletion tools cannot find these.