ha-mcp-dev 7.1.0.dev305__tar.gz → 7.1.0.dev307__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.
- {ha_mcp_dev-7.1.0.dev305/src/ha_mcp_dev.egg-info → ha_mcp_dev-7.1.0.dev307}/PKG-INFO +29 -25
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/README.md +28 -24
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/pyproject.toml +2 -1
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/tools/backup.py +2 -2
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/tools/tools_addons.py +49 -48
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/tools/tools_areas.py +6 -6
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/tools/tools_blueprints.py +2 -2
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/tools/tools_bug_report.py +2 -2
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/tools/tools_calendar.py +3 -3
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/tools/tools_camera.py +1 -1
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/tools/tools_categories.py +6 -6
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/tools/tools_config_automations.py +6 -6
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/tools/tools_config_dashboards.py +11 -12
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/tools/tools_config_entry_flow.py +4 -4
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/tools/tools_config_helpers.py +6 -6
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/tools/tools_config_scripts.py +6 -6
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/tools/tools_entities.py +8 -8
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/tools/tools_filesystem.py +8 -8
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/tools/tools_groups.py +3 -3
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/tools/tools_hacs.py +6 -6
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/tools/tools_history.py +2 -2
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/tools/tools_integrations.py +6 -6
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/tools/tools_labels.py +3 -3
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/tools/tools_mcp_component.py +2 -2
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/tools/tools_registry.py +8 -7
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/tools/tools_resources.py +9 -10
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/tools/tools_search.py +25 -24
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/tools/tools_service.py +4 -4
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/tools/tools_services.py +1 -1
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/tools/tools_system.py +4 -4
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/tools/tools_todo.py +4 -4
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/tools/tools_traces.py +1 -1
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/tools/tools_updates.py +1 -1
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/tools/tools_utility.py +4 -4
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/tools/tools_voice_assistant.py +2 -1
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/tools/tools_zones.py +3 -3
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307/src/ha_mcp_dev.egg-info}/PKG-INFO +29 -25
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/LICENSE +0 -0
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/MANIFEST.in +0 -0
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/setup.cfg +0 -0
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/__init__.py +0 -0
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/__main__.py +0 -0
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/_pypi_marker +0 -0
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/auth/__init__.py +0 -0
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/auth/consent_form.py +0 -0
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/auth/provider.py +0 -0
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/client/__init__.py +0 -0
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/client/rest_client.py +0 -0
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/client/websocket_client.py +0 -0
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/client/websocket_listener.py +0 -0
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/config.py +0 -0
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/errors.py +0 -0
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/py.typed +0 -0
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/resources/skills-vendor/.claude/settings.json +0 -0
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/resources/skills-vendor/.claude-plugin/marketplace.json +0 -0
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/resources/skills-vendor/.claude-plugin/plugin.json +0 -0
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/resources/skills-vendor/.github/ISSUE_TEMPLATE/skill-rca.md +0 -0
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/resources/skills-vendor/AGENTS.md +0 -0
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/resources/skills-vendor/CLAUDE.md +0 -0
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/resources/skills-vendor/CONTRIBUTING.md +0 -0
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/resources/skills-vendor/LICENSE +0 -0
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/resources/skills-vendor/README.md +0 -0
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/SKILL.md +0 -0
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/evals/evals.json +0 -0
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/automation-patterns.md +0 -0
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-cards.md +0 -0
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-guide.md +0 -0
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/device-control.md +0 -0
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/domain-docs.md +0 -0
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/examples.yaml +0 -0
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/helper-selection.md +0 -0
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/safe-refactoring.md +0 -0
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/template-guidelines.md +0 -0
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/server.py +0 -0
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/smoke_test.py +0 -0
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/tools/__init__.py +0 -0
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/tools/best_practice_checker.py +0 -0
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/tools/device_control.py +0 -0
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/tools/enhanced.py +0 -0
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/tools/helpers.py +0 -0
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/tools/registry.py +0 -0
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/tools/smart_search.py +0 -0
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/tools/util_helpers.py +0 -0
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/transforms/__init__.py +0 -0
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/transforms/categorized_search.py +0 -0
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/utils/__init__.py +0 -0
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/utils/domain_handlers.py +0 -0
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/utils/fuzzy_search.py +0 -0
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/utils/operation_manager.py +0 -0
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/utils/python_sandbox.py +0 -0
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp/utils/usage_logger.py +0 -0
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp_dev.egg-info/SOURCES.txt +0 -0
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp_dev.egg-info/dependency_links.txt +0 -0
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp_dev.egg-info/entry_points.txt +0 -0
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp_dev.egg-info/requires.txt +0 -0
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/src/ha_mcp_dev.egg-info/top_level.txt +0 -0
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/tests/__init__.py +0 -0
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/tests/test_constants.py +0 -0
- {ha_mcp_dev-7.1.0.dev305 → ha_mcp_dev-7.1.0.dev307}/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.1.0.
|
|
3
|
+
Version: 7.1.0.dev307
|
|
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-
|
|
40
|
+
<img src="https://img.shields.io/badge/tools-93-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>
|
|
@@ -158,33 +158,37 @@ Spend less time configuring, more time enjoying your smart home.
|
|
|
158
158
|
| **💾 System** | Backup/restore, updates, add-ons, device registry |
|
|
159
159
|
|
|
160
160
|
<details>
|
|
161
|
-
|
|
161
|
+
<!-- TOOLS_TABLE_START -->
|
|
162
|
+
|
|
163
|
+
<summary><b>Complete Tool List (93 tools)</b></summary>
|
|
162
164
|
|
|
163
165
|
| Category | Tools |
|
|
164
166
|
|----------|-------|
|
|
165
|
-
| **
|
|
166
|
-
| **
|
|
167
|
-
| **Automations** | `ha_config_get_automation`, `
|
|
168
|
-
| **
|
|
169
|
-
| **
|
|
170
|
-
| **Dashboards** | `ha_config_get_dashboard`, `ha_config_set_dashboard`, `ha_config_delete_dashboard` + dashboard skill references |
|
|
171
|
-
| **Areas & Floors** | `ha_config_list_areas`, `ha_config_set_area`, `ha_config_remove_area`, `ha_config_list_floors`, `ha_config_set_floor`, `ha_config_remove_floor` |
|
|
172
|
-
| **Labels** | `ha_config_get_label`, `ha_config_set_label`, `ha_config_remove_label`, `ha_manage_entity_labels` |
|
|
173
|
-
| **Zones** | `ha_get_zone`, `ha_set_zone`, `ha_remove_zone` |
|
|
174
|
-
| **Groups** | `ha_config_list_groups`, `ha_config_set_group`, `ha_config_remove_group` |
|
|
175
|
-
| **Todo Lists** | `ha_get_todo`, `ha_add_todo_item`, `ha_update_todo_item`, `ha_remove_todo_item` |
|
|
176
|
-
| **Calendar** | `ha_config_get_calendar_events`, `ha_config_set_calendar_event`, `ha_config_remove_calendar_event` |
|
|
177
|
-
| **Blueprints** | `ha_list_blueprints`, `ha_get_blueprint`, `ha_import_blueprint` |
|
|
178
|
-
| **Device Registry** | `ha_get_device`, `ha_update_device`, `ha_remove_device`, `ha_rename_entity` |
|
|
179
|
-
| **ZHA & Integrations** | `ha_get_zha_devices`, `ha_get_entity_integration_source` |
|
|
180
|
-
| **Add-ons** | `ha_get_addon`, `ha_call_addon_api` (HTTP & WebSocket, direct port access) |
|
|
167
|
+
| **Add-ons** | `ha_call_addon_api`, `ha_get_addon` |
|
|
168
|
+
| **Areas & Floors** | `ha_config_list_areas`, `ha_config_list_floors`, `ha_config_remove_area`, `ha_config_remove_floor`, `ha_config_set_area`, `ha_config_set_floor` |
|
|
169
|
+
| **Automations** | `ha_config_get_automation`, `ha_config_remove_automation`, `ha_config_set_automation` |
|
|
170
|
+
| **Blueprints** | `ha_get_blueprint`, `ha_import_blueprint` |
|
|
171
|
+
| **Calendar** | `ha_config_get_calendar_events`, `ha_config_remove_calendar_event`, `ha_config_set_calendar_event` |
|
|
181
172
|
| **Camera** | `ha_get_camera_image` |
|
|
182
|
-
| **
|
|
183
|
-
| **
|
|
184
|
-
| **
|
|
185
|
-
| **
|
|
186
|
-
| **
|
|
187
|
-
|
|
173
|
+
| **Dashboards** | `ha_config_delete_dashboard_resource`, `ha_config_delete_dashboard`, `ha_config_get_dashboard`, `ha_config_list_dashboard_resources`, `ha_config_set_dashboard_resource`, `ha_config_set_dashboard`, `ha_dashboard_find_card` |
|
|
174
|
+
| **Device Registry** | `ha_get_device`, `ha_remove_device`, `ha_rename_entity_and_device`, `ha_rename_entity`, `ha_update_device` |
|
|
175
|
+
| **Entity Registry** | `ha_get_entity_exposure`, `ha_get_entity`, `ha_set_entity` |
|
|
176
|
+
| **Files** | `ha_delete_file`, `ha_list_files`, `ha_read_file`, `ha_write_file` |
|
|
177
|
+
| **Groups** | `ha_config_list_groups`, `ha_config_remove_group`, `ha_config_set_group` |
|
|
178
|
+
| **HACS** | `ha_hacs_add_repository`, `ha_hacs_download`, `ha_hacs_info`, `ha_hacs_list_installed`, `ha_hacs_repository_info`, `ha_hacs_search` |
|
|
179
|
+
| **Helper Entities** | `ha_config_list_helpers`, `ha_config_remove_helper`, `ha_config_set_helper`, `ha_get_helper_schema`, `ha_set_config_entry_helper` |
|
|
180
|
+
| **History & Statistics** | `ha_get_automation_traces`, `ha_get_history`, `ha_get_logbook`, `ha_get_statistics` |
|
|
181
|
+
| **Integrations** | `ha_delete_config_entry`, `ha_get_integration`, `ha_set_integration_enabled` |
|
|
182
|
+
| **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` |
|
|
183
|
+
| **Scripts** | `ha_config_get_script`, `ha_config_remove_script`, `ha_config_set_script` |
|
|
184
|
+
| **Search & Discovery** | `ha_deep_search`, `ha_get_overview`, `ha_get_state`, `ha_get_states`, `ha_search_entities` |
|
|
185
|
+
| **Service & Device Control** | `ha_bulk_control`, `ha_call_service`, `ha_get_bulk_status`, `ha_get_operation_status`, `ha_list_services` |
|
|
186
|
+
| **System** | `ha_backup_create`, `ha_backup_restore`, `ha_check_config`, `ha_get_system_health`, `ha_get_updates`, `ha_reload_core`, `ha_restart` |
|
|
187
|
+
| **Todo Lists** | `ha_add_todo_item`, `ha_get_todo`, `ha_remove_todo_item`, `ha_update_todo_item` |
|
|
188
|
+
| **Utilities** | `ha_eval_template`, `ha_install_mcp_tools`, `ha_report_issue` |
|
|
189
|
+
| **Zones** | `ha_get_zone`, `ha_remove_zone`, `ha_set_zone` |
|
|
190
|
+
|
|
191
|
+
<!-- TOOLS_TABLE_END -->
|
|
188
192
|
</details>
|
|
189
193
|
|
|
190
194
|
---
|
|
@@ -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-
|
|
11
|
+
<img src="https://img.shields.io/badge/tools-93-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>
|
|
@@ -129,33 +129,37 @@ Spend less time configuring, more time enjoying your smart home.
|
|
|
129
129
|
| **💾 System** | Backup/restore, updates, add-ons, device registry |
|
|
130
130
|
|
|
131
131
|
<details>
|
|
132
|
-
|
|
132
|
+
<!-- TOOLS_TABLE_START -->
|
|
133
|
+
|
|
134
|
+
<summary><b>Complete Tool List (93 tools)</b></summary>
|
|
133
135
|
|
|
134
136
|
| Category | Tools |
|
|
135
137
|
|----------|-------|
|
|
136
|
-
| **
|
|
137
|
-
| **
|
|
138
|
-
| **Automations** | `ha_config_get_automation`, `
|
|
139
|
-
| **
|
|
140
|
-
| **
|
|
141
|
-
| **Dashboards** | `ha_config_get_dashboard`, `ha_config_set_dashboard`, `ha_config_delete_dashboard` + dashboard skill references |
|
|
142
|
-
| **Areas & Floors** | `ha_config_list_areas`, `ha_config_set_area`, `ha_config_remove_area`, `ha_config_list_floors`, `ha_config_set_floor`, `ha_config_remove_floor` |
|
|
143
|
-
| **Labels** | `ha_config_get_label`, `ha_config_set_label`, `ha_config_remove_label`, `ha_manage_entity_labels` |
|
|
144
|
-
| **Zones** | `ha_get_zone`, `ha_set_zone`, `ha_remove_zone` |
|
|
145
|
-
| **Groups** | `ha_config_list_groups`, `ha_config_set_group`, `ha_config_remove_group` |
|
|
146
|
-
| **Todo Lists** | `ha_get_todo`, `ha_add_todo_item`, `ha_update_todo_item`, `ha_remove_todo_item` |
|
|
147
|
-
| **Calendar** | `ha_config_get_calendar_events`, `ha_config_set_calendar_event`, `ha_config_remove_calendar_event` |
|
|
148
|
-
| **Blueprints** | `ha_list_blueprints`, `ha_get_blueprint`, `ha_import_blueprint` |
|
|
149
|
-
| **Device Registry** | `ha_get_device`, `ha_update_device`, `ha_remove_device`, `ha_rename_entity` |
|
|
150
|
-
| **ZHA & Integrations** | `ha_get_zha_devices`, `ha_get_entity_integration_source` |
|
|
151
|
-
| **Add-ons** | `ha_get_addon`, `ha_call_addon_api` (HTTP & WebSocket, direct port access) |
|
|
138
|
+
| **Add-ons** | `ha_call_addon_api`, `ha_get_addon` |
|
|
139
|
+
| **Areas & Floors** | `ha_config_list_areas`, `ha_config_list_floors`, `ha_config_remove_area`, `ha_config_remove_floor`, `ha_config_set_area`, `ha_config_set_floor` |
|
|
140
|
+
| **Automations** | `ha_config_get_automation`, `ha_config_remove_automation`, `ha_config_set_automation` |
|
|
141
|
+
| **Blueprints** | `ha_get_blueprint`, `ha_import_blueprint` |
|
|
142
|
+
| **Calendar** | `ha_config_get_calendar_events`, `ha_config_remove_calendar_event`, `ha_config_set_calendar_event` |
|
|
152
143
|
| **Camera** | `ha_get_camera_image` |
|
|
153
|
-
| **
|
|
154
|
-
| **
|
|
155
|
-
| **
|
|
156
|
-
| **
|
|
157
|
-
| **
|
|
158
|
-
|
|
144
|
+
| **Dashboards** | `ha_config_delete_dashboard_resource`, `ha_config_delete_dashboard`, `ha_config_get_dashboard`, `ha_config_list_dashboard_resources`, `ha_config_set_dashboard_resource`, `ha_config_set_dashboard`, `ha_dashboard_find_card` |
|
|
145
|
+
| **Device Registry** | `ha_get_device`, `ha_remove_device`, `ha_rename_entity_and_device`, `ha_rename_entity`, `ha_update_device` |
|
|
146
|
+
| **Entity Registry** | `ha_get_entity_exposure`, `ha_get_entity`, `ha_set_entity` |
|
|
147
|
+
| **Files** | `ha_delete_file`, `ha_list_files`, `ha_read_file`, `ha_write_file` |
|
|
148
|
+
| **Groups** | `ha_config_list_groups`, `ha_config_remove_group`, `ha_config_set_group` |
|
|
149
|
+
| **HACS** | `ha_hacs_add_repository`, `ha_hacs_download`, `ha_hacs_info`, `ha_hacs_list_installed`, `ha_hacs_repository_info`, `ha_hacs_search` |
|
|
150
|
+
| **Helper Entities** | `ha_config_list_helpers`, `ha_config_remove_helper`, `ha_config_set_helper`, `ha_get_helper_schema`, `ha_set_config_entry_helper` |
|
|
151
|
+
| **History & Statistics** | `ha_get_automation_traces`, `ha_get_history`, `ha_get_logbook`, `ha_get_statistics` |
|
|
152
|
+
| **Integrations** | `ha_delete_config_entry`, `ha_get_integration`, `ha_set_integration_enabled` |
|
|
153
|
+
| **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` |
|
|
154
|
+
| **Scripts** | `ha_config_get_script`, `ha_config_remove_script`, `ha_config_set_script` |
|
|
155
|
+
| **Search & Discovery** | `ha_deep_search`, `ha_get_overview`, `ha_get_state`, `ha_get_states`, `ha_search_entities` |
|
|
156
|
+
| **Service & Device Control** | `ha_bulk_control`, `ha_call_service`, `ha_get_bulk_status`, `ha_get_operation_status`, `ha_list_services` |
|
|
157
|
+
| **System** | `ha_backup_create`, `ha_backup_restore`, `ha_check_config`, `ha_get_system_health`, `ha_get_updates`, `ha_reload_core`, `ha_restart` |
|
|
158
|
+
| **Todo Lists** | `ha_add_todo_item`, `ha_get_todo`, `ha_remove_todo_item`, `ha_update_todo_item` |
|
|
159
|
+
| **Utilities** | `ha_eval_template`, `ha_install_mcp_tools`, `ha_report_issue` |
|
|
160
|
+
| **Zones** | `ha_get_zone`, `ha_remove_zone`, `ha_set_zone` |
|
|
161
|
+
|
|
162
|
+
<!-- TOOLS_TABLE_END -->
|
|
159
163
|
</details>
|
|
160
164
|
|
|
161
165
|
---
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "ha-mcp-dev"
|
|
7
|
-
version = "7.1.0.
|
|
7
|
+
version = "7.1.0.dev307"
|
|
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"
|
|
@@ -177,6 +177,7 @@ dev = [
|
|
|
177
177
|
"lefthook>=1.10.0",
|
|
178
178
|
"ruff>=0.12.12",
|
|
179
179
|
"testcontainers>=4.13.0",
|
|
180
|
+
"ast-grep-cli>=0.42.0",
|
|
180
181
|
]
|
|
181
182
|
|
|
182
183
|
# Semantic versioning configuration
|
|
@@ -391,7 +391,7 @@ def register_backup_tools(mcp: "FastMCP", client: HomeAssistantClient, **kwargs:
|
|
|
391
391
|
|
|
392
392
|
**Returns:** Backup ID and job status"""
|
|
393
393
|
|
|
394
|
-
@mcp.tool(description=backup_create_description, annotations={"destructiveHint": True, "title": "Create Backup"})
|
|
394
|
+
@mcp.tool(description=backup_create_description, tags={"System"}, annotations={"destructiveHint": True, "title": "Create Backup"})
|
|
395
395
|
@log_tool_usage
|
|
396
396
|
async def ha_backup_create(
|
|
397
397
|
name: Annotated[
|
|
@@ -405,7 +405,7 @@ def register_backup_tools(mcp: "FastMCP", client: HomeAssistantClient, **kwargs:
|
|
|
405
405
|
"""Create a fast Home Assistant backup (local only)."""
|
|
406
406
|
return await create_backup(client, name)
|
|
407
407
|
|
|
408
|
-
@mcp.tool(annotations={"destructiveHint": True, "title": "Restore Backup"})
|
|
408
|
+
@mcp.tool(tags={"System"}, annotations={"destructiveHint": True, "title": "Restore Backup"})
|
|
409
409
|
@log_tool_usage
|
|
410
410
|
async def ha_backup_restore(
|
|
411
411
|
backup_id: Annotated[
|
|
@@ -87,19 +87,19 @@ async def _supervisor_api_call(
|
|
|
87
87
|
if not result.get("success"):
|
|
88
88
|
error_msg = str(result.get("error", ""))
|
|
89
89
|
if "not_found" in error_msg.lower() or "unknown" in error_msg.lower():
|
|
90
|
-
|
|
90
|
+
raise_tool_error(create_error_response(
|
|
91
91
|
ErrorCode.RESOURCE_NOT_FOUND,
|
|
92
92
|
"Supervisor API not available",
|
|
93
93
|
details=str(result),
|
|
94
94
|
suggestions=[
|
|
95
95
|
"This feature requires Home Assistant OS or Supervised installation",
|
|
96
96
|
],
|
|
97
|
-
)
|
|
98
|
-
|
|
97
|
+
))
|
|
98
|
+
raise_tool_error(create_error_response(
|
|
99
99
|
ErrorCode.SERVICE_CALL_FAILED,
|
|
100
100
|
f"Supervisor API call failed: {endpoint}",
|
|
101
101
|
details=str(result),
|
|
102
|
-
)
|
|
102
|
+
))
|
|
103
103
|
|
|
104
104
|
return {"success": True, "result": result.get("result", {})}
|
|
105
105
|
|
|
@@ -107,10 +107,9 @@ async def _supervisor_api_call(
|
|
|
107
107
|
raise
|
|
108
108
|
except Exception as e:
|
|
109
109
|
logger.error(f"Error calling Supervisor API {endpoint}: {e}")
|
|
110
|
-
|
|
110
|
+
exception_to_structured_error(
|
|
111
111
|
e,
|
|
112
112
|
context={"endpoint": endpoint},
|
|
113
|
-
raise_error=False,
|
|
114
113
|
suggestions=["Check Home Assistant connection and Supervisor availability"],
|
|
115
114
|
)
|
|
116
115
|
finally:
|
|
@@ -311,23 +310,23 @@ async def _call_addon_ws(
|
|
|
311
310
|
# 1. Sanitize path
|
|
312
311
|
normalized = unquote(path).lstrip("/")
|
|
313
312
|
if ".." in normalized.split("/"):
|
|
314
|
-
|
|
313
|
+
raise_tool_error(create_validation_error(
|
|
315
314
|
"Path contains '..' traversal component",
|
|
316
315
|
parameter="path",
|
|
317
316
|
details=f"Rejected path: {path}",
|
|
318
|
-
)
|
|
317
|
+
))
|
|
319
318
|
|
|
320
319
|
# 2. Get add-on info
|
|
321
320
|
addon_response = await get_addon_info(client, slug)
|
|
322
321
|
if not addon_response.get("success"):
|
|
323
|
-
|
|
322
|
+
raise_tool_error(addon_response)
|
|
324
323
|
|
|
325
324
|
addon = addon_response["addon"]
|
|
326
325
|
addon_name = addon.get("name", slug)
|
|
327
326
|
|
|
328
327
|
# 3. Verify add-on supports Ingress (unless using direct port override)
|
|
329
328
|
if not port and not addon.get("ingress"):
|
|
330
|
-
|
|
329
|
+
raise_tool_error(create_error_response(
|
|
331
330
|
ErrorCode.VALIDATION_FAILED,
|
|
332
331
|
f"Add-on '{addon_name}' does not support Ingress",
|
|
333
332
|
suggestions=[
|
|
@@ -335,37 +334,37 @@ async def _call_addon_ws(
|
|
|
335
334
|
f"Use ha_get_addon(slug='{slug}') to see available ports",
|
|
336
335
|
],
|
|
337
336
|
context={"slug": slug},
|
|
338
|
-
)
|
|
337
|
+
))
|
|
339
338
|
|
|
340
339
|
# 4. Verify add-on is running
|
|
341
340
|
if addon.get("state") != "started":
|
|
342
|
-
|
|
341
|
+
raise_tool_error(create_error_response(
|
|
343
342
|
ErrorCode.SERVICE_CALL_FAILED,
|
|
344
343
|
f"Add-on '{addon_name}' is not running (state: {addon.get('state')})",
|
|
345
344
|
suggestions=[
|
|
346
345
|
f"Start the add-on first with: ha_call_service('hassio', 'addon_start', {{'addon': '{slug}'}})",
|
|
347
346
|
],
|
|
348
347
|
context={"slug": slug, "state": addon.get("state")},
|
|
349
|
-
)
|
|
348
|
+
))
|
|
350
349
|
|
|
351
350
|
# 5. Build WebSocket URL
|
|
352
351
|
addon_ip = addon.get("ip_address", "")
|
|
353
352
|
if port:
|
|
354
353
|
if not addon_ip:
|
|
355
|
-
|
|
354
|
+
raise_tool_error(create_error_response(
|
|
356
355
|
ErrorCode.INTERNAL_ERROR,
|
|
357
356
|
f"Add-on '{addon_name}' is missing ip_address",
|
|
358
357
|
context={"slug": slug},
|
|
359
|
-
)
|
|
358
|
+
))
|
|
360
359
|
target_port = port
|
|
361
360
|
else:
|
|
362
361
|
ingress_port = addon.get("ingress_port")
|
|
363
362
|
if not addon_ip or not ingress_port:
|
|
364
|
-
|
|
363
|
+
raise_tool_error(create_error_response(
|
|
365
364
|
ErrorCode.INTERNAL_ERROR,
|
|
366
365
|
f"Add-on '{addon_name}' is missing network info",
|
|
367
366
|
context={"slug": slug},
|
|
368
|
-
)
|
|
367
|
+
))
|
|
369
368
|
target_port = ingress_port
|
|
370
369
|
|
|
371
370
|
ws_url = f"ws://{addon_ip}:{target_port}/{normalized}"
|
|
@@ -439,7 +438,7 @@ async def _call_addon_ws(
|
|
|
439
438
|
total_size += len(clean)
|
|
440
439
|
|
|
441
440
|
except websockets.exceptions.InvalidHandshake as e:
|
|
442
|
-
|
|
441
|
+
raise_tool_error(create_error_response(
|
|
443
442
|
ErrorCode.SERVICE_CALL_FAILED,
|
|
444
443
|
f"WebSocket handshake failed with '{addon_name}': {e!s}",
|
|
445
444
|
suggestions=[
|
|
@@ -447,9 +446,9 @@ async def _call_addon_ws(
|
|
|
447
446
|
f"Use ha_get_addon(slug='{slug}') to inspect available endpoints",
|
|
448
447
|
],
|
|
449
448
|
context={"slug": slug, "path": path},
|
|
450
|
-
)
|
|
449
|
+
))
|
|
451
450
|
except websockets.exceptions.ConnectionClosed as e:
|
|
452
|
-
|
|
451
|
+
raise_tool_error(create_error_response(
|
|
453
452
|
ErrorCode.SERVICE_CALL_FAILED,
|
|
454
453
|
f"WebSocket connection to '{addon_name}' closed unexpectedly: {e!s}",
|
|
455
454
|
suggestions=[
|
|
@@ -457,20 +456,20 @@ async def _call_addon_ws(
|
|
|
457
456
|
"Try again or check add-on logs for errors",
|
|
458
457
|
],
|
|
459
458
|
context={"slug": slug, "path": path},
|
|
460
|
-
)
|
|
459
|
+
))
|
|
461
460
|
except TimeoutError:
|
|
462
|
-
|
|
461
|
+
raise_tool_error(create_timeout_error(
|
|
463
462
|
f"WebSocket connection to '{addon_name}'",
|
|
464
463
|
timeout,
|
|
465
464
|
details=f"path={path}",
|
|
466
465
|
context={"slug": slug, "path": path},
|
|
467
|
-
)
|
|
466
|
+
))
|
|
468
467
|
except OSError as e:
|
|
469
|
-
|
|
468
|
+
raise_tool_error(create_connection_error(
|
|
470
469
|
f"Failed to connect to add-on '{addon_name}' WebSocket: {e!s}",
|
|
471
470
|
details="Check that the add-on is running and the port is correct",
|
|
472
471
|
context={"slug": slug},
|
|
473
|
-
)
|
|
472
|
+
))
|
|
474
473
|
|
|
475
474
|
elapsed = round(time.monotonic() - start_time, 2)
|
|
476
475
|
|
|
@@ -554,23 +553,23 @@ async def _call_addon_api(
|
|
|
554
553
|
# 1. Sanitize path to prevent traversal attacks (including URL-encoded)
|
|
555
554
|
normalized = unquote(path).lstrip("/")
|
|
556
555
|
if ".." in normalized.split("/"):
|
|
557
|
-
|
|
556
|
+
raise_tool_error(create_validation_error(
|
|
558
557
|
"Path contains '..' traversal component",
|
|
559
558
|
parameter="path",
|
|
560
559
|
details=f"Rejected path: {path}",
|
|
561
|
-
)
|
|
560
|
+
))
|
|
562
561
|
|
|
563
562
|
# 2. Get add-on info to verify ingress support and get entry path
|
|
564
563
|
addon_response = await get_addon_info(client, slug)
|
|
565
564
|
if not addon_response.get("success"):
|
|
566
|
-
|
|
565
|
+
raise_tool_error(addon_response)
|
|
567
566
|
|
|
568
567
|
addon = addon_response["addon"]
|
|
569
568
|
addon_name = addon.get("name", slug)
|
|
570
569
|
|
|
571
570
|
# 3. Verify add-on supports Ingress (unless using direct port override)
|
|
572
571
|
if not port and not addon.get("ingress"):
|
|
573
|
-
|
|
572
|
+
raise_tool_error(create_error_response(
|
|
574
573
|
ErrorCode.VALIDATION_FAILED,
|
|
575
574
|
f"Add-on '{addon_name}' does not support Ingress",
|
|
576
575
|
suggestions=[
|
|
@@ -579,18 +578,18 @@ async def _call_addon_api(
|
|
|
579
578
|
"Use the 'port' parameter to connect to a direct access port",
|
|
580
579
|
],
|
|
581
580
|
context={"slug": slug},
|
|
582
|
-
)
|
|
581
|
+
))
|
|
583
582
|
|
|
584
583
|
# 4. Verify add-on is running
|
|
585
584
|
if addon.get("state") != "started":
|
|
586
|
-
|
|
585
|
+
raise_tool_error(create_error_response(
|
|
587
586
|
ErrorCode.SERVICE_CALL_FAILED,
|
|
588
587
|
f"Add-on '{addon_name}' is not running (state: {addon.get('state')})",
|
|
589
588
|
suggestions=[
|
|
590
589
|
f"Start the add-on first with: ha_call_service('hassio', 'addon_start', {{'addon': '{slug}'}})",
|
|
591
590
|
],
|
|
592
591
|
context={"slug": slug, "state": addon.get("state")},
|
|
593
|
-
)
|
|
592
|
+
))
|
|
594
593
|
|
|
595
594
|
# 5. Build URL to the add-on container
|
|
596
595
|
addon_ip = addon.get("ip_address", "")
|
|
@@ -600,21 +599,21 @@ async def _call_addon_api(
|
|
|
600
599
|
# (e.g., 1880 for Node-RED, 6052 for ESPHome) instead of the ingress port.
|
|
601
600
|
# Requires 'leave_front_door_open' or equivalent setting on the add-on.
|
|
602
601
|
if not addon_ip:
|
|
603
|
-
|
|
602
|
+
raise_tool_error(create_error_response(
|
|
604
603
|
ErrorCode.INTERNAL_ERROR,
|
|
605
604
|
f"Add-on '{addon_name}' is missing ip_address",
|
|
606
605
|
context={"slug": slug, "ip_address": addon_ip},
|
|
607
|
-
)
|
|
606
|
+
))
|
|
608
607
|
target_port = port
|
|
609
608
|
else:
|
|
610
609
|
# Default: use the ingress port for direct container communication
|
|
611
610
|
ingress_port = addon.get("ingress_port")
|
|
612
611
|
if not addon_ip or not ingress_port:
|
|
613
|
-
|
|
612
|
+
raise_tool_error(create_error_response(
|
|
614
613
|
ErrorCode.INTERNAL_ERROR,
|
|
615
614
|
f"Add-on '{addon_name}' is missing network info (ip_address or ingress_port)",
|
|
616
615
|
context={"slug": slug, "ip_address": addon_ip, "ingress_port": ingress_port},
|
|
617
|
-
)
|
|
616
|
+
))
|
|
618
617
|
target_port = ingress_port
|
|
619
618
|
|
|
620
619
|
url = f"http://{addon_ip}:{target_port}/{normalized}"
|
|
@@ -648,18 +647,18 @@ async def _call_addon_api(
|
|
|
648
647
|
content=request_content,
|
|
649
648
|
)
|
|
650
649
|
except httpx.TimeoutException:
|
|
651
|
-
|
|
650
|
+
raise_tool_error(create_timeout_error(
|
|
652
651
|
f"add-on API call to '{addon_name}'",
|
|
653
652
|
timeout,
|
|
654
653
|
details=f"path={path}, method={method}",
|
|
655
654
|
context={"slug": slug, "path": path},
|
|
656
|
-
)
|
|
655
|
+
))
|
|
657
656
|
except httpx.ConnectError as e:
|
|
658
|
-
|
|
657
|
+
raise_tool_error(create_connection_error(
|
|
659
658
|
f"Failed to connect to add-on '{addon_name}': {e!s}",
|
|
660
659
|
details="Check that the add-on is running and Home Assistant Ingress is working",
|
|
661
660
|
context={"slug": slug},
|
|
662
|
-
)
|
|
661
|
+
))
|
|
663
662
|
|
|
664
663
|
# 7. Parse response
|
|
665
664
|
content_type = response.headers.get("content-type", "")
|
|
@@ -783,7 +782,7 @@ def register_addon_tools(mcp: Any, client: HomeAssistantClient, **kwargs: Any) -
|
|
|
783
782
|
**kwargs: Additional arguments (ignored, for auto-discovery compatibility)
|
|
784
783
|
"""
|
|
785
784
|
|
|
786
|
-
@mcp.tool(annotations={"idempotentHint": True, "readOnlyHint": True, "
|
|
785
|
+
@mcp.tool(tags={"Add-ons"}, annotations={"idempotentHint": True, "readOnlyHint": True, "title": "Get Add-ons"})
|
|
787
786
|
@log_tool_usage
|
|
788
787
|
async def ha_get_addon(
|
|
789
788
|
source: Annotated[
|
|
@@ -878,13 +877,15 @@ def register_addon_tools(mcp: Any, client: HomeAssistantClient, **kwargs: Any) -
|
|
|
878
877
|
raise_tool_error(result)
|
|
879
878
|
return result
|
|
880
879
|
|
|
881
|
-
@mcp.tool(
|
|
882
|
-
"
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
880
|
+
@mcp.tool(
|
|
881
|
+
tags={"Add-ons"},
|
|
882
|
+
annotations={
|
|
883
|
+
"destructiveHint": True,
|
|
884
|
+
"idempotentHint": False,
|
|
885
|
+
"readOnlyHint": False,
|
|
886
|
+
"title": "Call Add-on API",
|
|
887
|
+
},
|
|
888
|
+
)
|
|
888
889
|
@log_tool_usage
|
|
889
890
|
async def ha_call_addon_api(
|
|
890
891
|
slug: Annotated[
|
|
@@ -25,7 +25,7 @@ def register_area_tools(mcp: Any, client: Any, **kwargs: Any) -> None:
|
|
|
25
25
|
# AREA TOOLS
|
|
26
26
|
# ============================================================
|
|
27
27
|
|
|
28
|
-
@mcp.tool(annotations={"idempotentHint": True, "readOnlyHint": True, "
|
|
28
|
+
@mcp.tool(tags={"Areas & Floors"}, annotations={"idempotentHint": True, "readOnlyHint": True, "title": "List Areas"})
|
|
29
29
|
@log_tool_usage
|
|
30
30
|
async def ha_config_list_areas() -> dict[str, Any]:
|
|
31
31
|
"""
|
|
@@ -63,7 +63,7 @@ def register_area_tools(mcp: Any, client: Any, **kwargs: Any) -> None:
|
|
|
63
63
|
"Verify WebSocket connection is active",
|
|
64
64
|
])
|
|
65
65
|
|
|
66
|
-
@mcp.tool(
|
|
66
|
+
@mcp.tool(tags={"Areas & Floors"}, annotations={"destructiveHint": True, "title": "Create or Update Area"})
|
|
67
67
|
@log_tool_usage
|
|
68
68
|
async def ha_config_set_area(
|
|
69
69
|
name: Annotated[
|
|
@@ -208,7 +208,7 @@ def register_area_tools(mcp: Any, client: Any, **kwargs: Any) -> None:
|
|
|
208
208
|
"If assigning to a floor, verify floor_id exists",
|
|
209
209
|
])
|
|
210
210
|
|
|
211
|
-
@mcp.tool(annotations={"destructiveHint": True, "idempotentHint": True, "
|
|
211
|
+
@mcp.tool(tags={"Areas & Floors"}, annotations={"destructiveHint": True, "idempotentHint": True, "title": "Remove Area"})
|
|
212
212
|
@log_tool_usage
|
|
213
213
|
async def ha_config_remove_area(
|
|
214
214
|
area_id: Annotated[
|
|
@@ -258,7 +258,7 @@ def register_area_tools(mcp: Any, client: Any, **kwargs: Any) -> None:
|
|
|
258
258
|
# FLOOR TOOLS
|
|
259
259
|
# ============================================================
|
|
260
260
|
|
|
261
|
-
@mcp.tool(annotations={"idempotentHint": True, "readOnlyHint": True, "
|
|
261
|
+
@mcp.tool(tags={"Areas & Floors"}, annotations={"idempotentHint": True, "readOnlyHint": True, "title": "List Floors"})
|
|
262
262
|
@log_tool_usage
|
|
263
263
|
async def ha_config_list_floors() -> dict[str, Any]:
|
|
264
264
|
"""
|
|
@@ -296,7 +296,7 @@ def register_area_tools(mcp: Any, client: Any, **kwargs: Any) -> None:
|
|
|
296
296
|
"Verify WebSocket connection is active",
|
|
297
297
|
])
|
|
298
298
|
|
|
299
|
-
@mcp.tool(
|
|
299
|
+
@mcp.tool(tags={"Areas & Floors"}, annotations={"destructiveHint": True, "title": "Create or Update Floor"})
|
|
300
300
|
@log_tool_usage
|
|
301
301
|
async def ha_config_set_floor(
|
|
302
302
|
name: Annotated[
|
|
@@ -429,7 +429,7 @@ def register_area_tools(mcp: Any, client: Any, **kwargs: Any) -> None:
|
|
|
429
429
|
"For update: Verify the floor_id exists using ha_config_list_floors()",
|
|
430
430
|
])
|
|
431
431
|
|
|
432
|
-
@mcp.tool(annotations={"destructiveHint": True, "idempotentHint": True, "
|
|
432
|
+
@mcp.tool(tags={"Areas & Floors"}, annotations={"destructiveHint": True, "idempotentHint": True, "title": "Remove Floor"})
|
|
433
433
|
@log_tool_usage
|
|
434
434
|
async def ha_config_remove_floor(
|
|
435
435
|
floor_id: Annotated[
|
|
@@ -56,7 +56,7 @@ def register_blueprint_tools(mcp: Any, client: Any, **kwargs: Any) -> None:
|
|
|
56
56
|
"blueprints": blueprints,
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
@mcp.tool(annotations={"idempotentHint": True, "readOnlyHint": True, "
|
|
59
|
+
@mcp.tool(tags={"Blueprints"}, annotations={"idempotentHint": True, "readOnlyHint": True, "title": "Get Blueprint"})
|
|
60
60
|
@log_tool_usage
|
|
61
61
|
async def ha_get_blueprint(
|
|
62
62
|
path: Annotated[
|
|
@@ -183,7 +183,7 @@ def register_blueprint_tools(mcp: Any, client: Any, **kwargs: Any) -> None:
|
|
|
183
183
|
],
|
|
184
184
|
)
|
|
185
185
|
|
|
186
|
-
@mcp.tool(
|
|
186
|
+
@mcp.tool(tags={"Blueprints"}, annotations={"destructiveHint": True, "title": "Import Blueprint"})
|
|
187
187
|
@log_tool_usage
|
|
188
188
|
async def ha_import_blueprint(
|
|
189
189
|
url: Annotated[
|
|
@@ -85,11 +85,11 @@ def register_bug_report_tools(mcp: Any, client: Any, **kwargs: Any) -> None:
|
|
|
85
85
|
"""Register bug report tools with the MCP server."""
|
|
86
86
|
|
|
87
87
|
@mcp.tool(
|
|
88
|
+
tags={"Utilities"},
|
|
88
89
|
annotations={
|
|
89
90
|
"idempotentHint": True,
|
|
90
91
|
"readOnlyHint": True,
|
|
91
|
-
"
|
|
92
|
-
"title": "Report Issue or Feedback",
|
|
92
|
+
"title": "Report Issue or Feedback"
|
|
93
93
|
}
|
|
94
94
|
)
|
|
95
95
|
@log_tool_usage
|
|
@@ -23,7 +23,7 @@ logger = logging.getLogger(__name__)
|
|
|
23
23
|
def register_calendar_tools(mcp: Any, client: Any, **kwargs: Any) -> None:
|
|
24
24
|
"""Register calendar management tools with the MCP server."""
|
|
25
25
|
|
|
26
|
-
@mcp.tool(annotations={"idempotentHint": True, "readOnlyHint": True, "
|
|
26
|
+
@mcp.tool(tags={"Calendar"}, annotations={"idempotentHint": True, "readOnlyHint": True, "title": "Get Calendar Events"})
|
|
27
27
|
@log_tool_usage
|
|
28
28
|
async def ha_config_get_calendar_events(
|
|
29
29
|
entity_id: Annotated[
|
|
@@ -144,7 +144,7 @@ def register_calendar_tools(mcp: Any, client: Any, **kwargs: Any) -> None:
|
|
|
144
144
|
|
|
145
145
|
exception_to_structured_error(error, context={"entity_id": entity_id}, suggestions=suggestions)
|
|
146
146
|
|
|
147
|
-
@mcp.tool(
|
|
147
|
+
@mcp.tool(tags={"Calendar"}, annotations={"destructiveHint": True, "title": "Create or Update Calendar Event"})
|
|
148
148
|
@log_tool_usage
|
|
149
149
|
async def ha_config_set_calendar_event(
|
|
150
150
|
entity_id: Annotated[
|
|
@@ -263,7 +263,7 @@ def register_calendar_tools(mcp: Any, client: Any, **kwargs: Any) -> None:
|
|
|
263
263
|
|
|
264
264
|
exception_to_structured_error(error, context={"entity_id": entity_id}, suggestions=suggestions)
|
|
265
265
|
|
|
266
|
-
@mcp.tool(annotations={"destructiveHint": True, "idempotentHint": True, "
|
|
266
|
+
@mcp.tool(tags={"Calendar"}, annotations={"destructiveHint": True, "idempotentHint": True, "title": "Remove Calendar Event"})
|
|
267
267
|
@log_tool_usage
|
|
268
268
|
async def ha_config_remove_calendar_event(
|
|
269
269
|
entity_id: Annotated[
|
|
@@ -18,7 +18,7 @@ logger = logging.getLogger(__name__)
|
|
|
18
18
|
def register_camera_tools(mcp: Any, client: Any, **kwargs: Any) -> None:
|
|
19
19
|
"""Register Home Assistant camera tools."""
|
|
20
20
|
|
|
21
|
-
@mcp.tool(annotations={"idempotentHint": True, "readOnlyHint": True, "
|
|
21
|
+
@mcp.tool(tags={"Camera"}, annotations={"idempotentHint": True, "readOnlyHint": True, "title": "Get Camera Image"})
|
|
22
22
|
@log_tool_usage
|
|
23
23
|
async def ha_get_camera_image(
|
|
24
24
|
entity_id: str,
|
|
@@ -24,11 +24,11 @@ def register_category_tools(mcp: Any, client: Any, **kwargs: Any) -> None:
|
|
|
24
24
|
"""Register Home Assistant category management tools."""
|
|
25
25
|
|
|
26
26
|
@mcp.tool(
|
|
27
|
+
tags={"Labels & Categories"},
|
|
27
28
|
annotations={
|
|
28
29
|
"idempotentHint": True,
|
|
29
30
|
"readOnlyHint": True,
|
|
30
|
-
"
|
|
31
|
-
"title": "Get Category",
|
|
31
|
+
"title": "Get Category"
|
|
32
32
|
}
|
|
33
33
|
)
|
|
34
34
|
@log_tool_usage
|
|
@@ -143,10 +143,10 @@ def register_category_tools(mcp: Any, client: Any, **kwargs: Any) -> None:
|
|
|
143
143
|
)
|
|
144
144
|
|
|
145
145
|
@mcp.tool(
|
|
146
|
+
tags={"Labels & Categories"},
|
|
146
147
|
annotations={
|
|
147
148
|
"destructiveHint": True,
|
|
148
|
-
"
|
|
149
|
-
"title": "Create or Update Category",
|
|
149
|
+
"title": "Create or Update Category"
|
|
150
150
|
}
|
|
151
151
|
)
|
|
152
152
|
@log_tool_usage
|
|
@@ -246,11 +246,11 @@ def register_category_tools(mcp: Any, client: Any, **kwargs: Any) -> None:
|
|
|
246
246
|
)
|
|
247
247
|
|
|
248
248
|
@mcp.tool(
|
|
249
|
+
tags={"Labels & Categories"},
|
|
249
250
|
annotations={
|
|
250
251
|
"destructiveHint": True,
|
|
251
252
|
"idempotentHint": True,
|
|
252
|
-
"
|
|
253
|
-
"title": "Remove Category",
|
|
253
|
+
"title": "Remove Category"
|
|
254
254
|
}
|
|
255
255
|
)
|
|
256
256
|
@log_tool_usage
|