ha-mcp-dev 7.2.0.dev341__tar.gz → 7.2.0.dev342__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.2.0.dev341/src/ha_mcp_dev.egg-info → ha_mcp_dev-7.2.0.dev342}/PKG-INFO +4 -4
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/README.md +3 -3
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/pyproject.toml +1 -1
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/tools/tools_config_dashboards.py +171 -236
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342/src/ha_mcp_dev.egg-info}/PKG-INFO +4 -4
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/LICENSE +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/MANIFEST.in +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/setup.cfg +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/__init__.py +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/__main__.py +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/_pypi_marker +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/auth/__init__.py +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/auth/consent_form.py +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/auth/provider.py +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/client/__init__.py +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/client/rest_client.py +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/client/websocket_client.py +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/client/websocket_listener.py +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/config.py +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/errors.py +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/py.typed +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/resources/skills-vendor/.claude/settings.json +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/resources/skills-vendor/.claude-plugin/marketplace.json +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/resources/skills-vendor/.claude-plugin/plugin.json +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/resources/skills-vendor/.github/ISSUE_TEMPLATE/skill-rca.md +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/resources/skills-vendor/AGENTS.md +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/resources/skills-vendor/CLAUDE.md +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/resources/skills-vendor/CONTRIBUTING.md +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/resources/skills-vendor/LICENSE +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/resources/skills-vendor/README.md +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/SKILL.md +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/evals/evals.json +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/automation-patterns.md +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-cards.md +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-guide.md +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/device-control.md +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/domain-docs.md +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/examples.yaml +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/helper-selection.md +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/safe-refactoring.md +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/template-guidelines.md +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/server.py +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/smoke_test.py +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/tools/__init__.py +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/tools/backup.py +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/tools/best_practice_checker.py +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/tools/device_control.py +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/tools/enhanced.py +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/tools/helpers.py +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/tools/registry.py +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/tools/smart_search.py +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/tools/tools_addons.py +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/tools/tools_areas.py +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/tools/tools_blueprints.py +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/tools/tools_bug_report.py +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/tools/tools_calendar.py +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/tools/tools_camera.py +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/tools/tools_categories.py +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/tools/tools_config_automations.py +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/tools/tools_config_entry_flow.py +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/tools/tools_config_helpers.py +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/tools/tools_config_scripts.py +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/tools/tools_entities.py +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/tools/tools_filesystem.py +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/tools/tools_groups.py +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/tools/tools_hacs.py +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/tools/tools_history.py +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/tools/tools_integrations.py +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/tools/tools_labels.py +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/tools/tools_mcp_component.py +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/tools/tools_registry.py +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/tools/tools_resources.py +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/tools/tools_search.py +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/tools/tools_service.py +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/tools/tools_services.py +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/tools/tools_system.py +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/tools/tools_todo.py +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/tools/tools_traces.py +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/tools/tools_updates.py +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/tools/tools_utility.py +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/tools/tools_voice_assistant.py +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/tools/tools_yaml_config.py +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/tools/tools_zones.py +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/tools/util_helpers.py +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/transforms/__init__.py +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/transforms/categorized_search.py +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/utils/__init__.py +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/utils/domain_handlers.py +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/utils/fuzzy_search.py +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/utils/operation_manager.py +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/utils/python_sandbox.py +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/utils/usage_logger.py +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp_dev.egg-info/SOURCES.txt +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp_dev.egg-info/dependency_links.txt +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp_dev.egg-info/entry_points.txt +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp_dev.egg-info/requires.txt +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp_dev.egg-info/top_level.txt +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/tests/__init__.py +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/tests/test_constants.py +0 -0
- {ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/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.2.0.
|
|
3
|
+
Version: 7.2.0.dev342
|
|
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-87-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>
|
|
@@ -160,7 +160,7 @@ Spend less time configuring, more time enjoying your smart home.
|
|
|
160
160
|
<details>
|
|
161
161
|
<!-- TOOLS_TABLE_START -->
|
|
162
162
|
|
|
163
|
-
<summary><b>Complete Tool List (
|
|
163
|
+
<summary><b>Complete Tool List (87 tools)</b></summary>
|
|
164
164
|
|
|
165
165
|
| Category | Tools |
|
|
166
166
|
|----------|-------|
|
|
@@ -170,7 +170,7 @@ Spend less time configuring, more time enjoying your smart home.
|
|
|
170
170
|
| **Blueprints** | `ha_get_blueprint`, `ha_import_blueprint` |
|
|
171
171
|
| **Calendar** | `ha_config_get_calendar_events`, `ha_config_remove_calendar_event`, `ha_config_set_calendar_event` |
|
|
172
172
|
| **Camera** | `ha_get_camera_image` |
|
|
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
|
|
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` |
|
|
174
174
|
| **Device Registry** | `ha_get_device`, `ha_remove_device`, `ha_update_device` |
|
|
175
175
|
| **Entity Registry** | `ha_get_entity_exposure`, `ha_get_entity`, `ha_remove_entity`, `ha_set_entity` |
|
|
176
176
|
| **Files** | `ha_delete_file`, `ha_list_files`, `ha_read_file`, `ha_write_file` |
|
|
@@ -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-87-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>
|
|
@@ -131,7 +131,7 @@ Spend less time configuring, more time enjoying your smart home.
|
|
|
131
131
|
<details>
|
|
132
132
|
<!-- TOOLS_TABLE_START -->
|
|
133
133
|
|
|
134
|
-
<summary><b>Complete Tool List (
|
|
134
|
+
<summary><b>Complete Tool List (87 tools)</b></summary>
|
|
135
135
|
|
|
136
136
|
| Category | Tools |
|
|
137
137
|
|----------|-------|
|
|
@@ -141,7 +141,7 @@ Spend less time configuring, more time enjoying your smart home.
|
|
|
141
141
|
| **Blueprints** | `ha_get_blueprint`, `ha_import_blueprint` |
|
|
142
142
|
| **Calendar** | `ha_config_get_calendar_events`, `ha_config_remove_calendar_event`, `ha_config_set_calendar_event` |
|
|
143
143
|
| **Camera** | `ha_get_camera_image` |
|
|
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
|
|
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` |
|
|
145
145
|
| **Device Registry** | `ha_get_device`, `ha_remove_device`, `ha_update_device` |
|
|
146
146
|
| **Entity Registry** | `ha_get_entity_exposure`, `ha_get_entity`, `ha_remove_entity`, `ha_set_entity` |
|
|
147
147
|
| **Files** | `ha_delete_file`, `ha_list_files`, `ha_read_file`, `ha_write_file` |
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "ha-mcp-dev"
|
|
7
|
-
version = "7.2.0.
|
|
7
|
+
version = "7.2.0.dev342"
|
|
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"
|
{ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/tools/tools_config_dashboards.py
RENAMED
|
@@ -4,7 +4,6 @@ Configuration management tools for Home Assistant Lovelace dashboards.
|
|
|
4
4
|
This module provides tools for managing dashboard metadata and content.
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
-
import asyncio
|
|
8
7
|
import hashlib
|
|
9
8
|
import json
|
|
10
9
|
import logging
|
|
@@ -14,7 +13,6 @@ from typing import Annotated, Any, cast
|
|
|
14
13
|
from fastmcp.exceptions import ToolError
|
|
15
14
|
from pydantic import Field
|
|
16
15
|
|
|
17
|
-
from ..config import get_global_settings
|
|
18
16
|
from ..errors import ErrorCode, create_error_response, create_resource_not_found_error
|
|
19
17
|
from ..utils.python_sandbox import (
|
|
20
18
|
PythonSandboxError,
|
|
@@ -285,26 +283,78 @@ def register_config_dashboard_tools(mcp: Any, client: Any, **kwargs: Any) -> Non
|
|
|
285
283
|
),
|
|
286
284
|
] = False,
|
|
287
285
|
force_reload: Annotated[
|
|
288
|
-
bool, Field(description="Force reload from storage (bypass cache)")
|
|
286
|
+
bool, Field(description="Force reload from storage (bypass cache). Not applicable in search mode (search always uses force=True for fresh results).")
|
|
287
|
+
] = False,
|
|
288
|
+
entity_id: Annotated[
|
|
289
|
+
str | None,
|
|
290
|
+
Field(
|
|
291
|
+
description="Find cards by entity ID. Supports wildcards, e.g. "
|
|
292
|
+
"'sensor.temperature_*'. Matches cards with this entity in "
|
|
293
|
+
"'entity' or 'entities' field, view-level badges, and header cards. "
|
|
294
|
+
"When provided, activates search mode (returns matches, not full config)."
|
|
295
|
+
),
|
|
296
|
+
] = None,
|
|
297
|
+
card_type: Annotated[
|
|
298
|
+
str | None,
|
|
299
|
+
Field(
|
|
300
|
+
description="Find cards by type, e.g. 'tile', 'button', 'heading'. "
|
|
301
|
+
"When provided, activates search mode."
|
|
302
|
+
),
|
|
303
|
+
] = None,
|
|
304
|
+
heading: Annotated[
|
|
305
|
+
str | None,
|
|
306
|
+
Field(
|
|
307
|
+
description="Find cards by heading/title text (case-insensitive partial match). "
|
|
308
|
+
"When provided, activates search mode."
|
|
309
|
+
),
|
|
310
|
+
] = None,
|
|
311
|
+
include_config: Annotated[
|
|
312
|
+
bool,
|
|
313
|
+
Field(
|
|
314
|
+
description="In search mode: include each matched card's own configuration "
|
|
315
|
+
"object in results (increases output size). Does not affect whether the full "
|
|
316
|
+
"dashboard config is returned — search mode always returns matches only, "
|
|
317
|
+
"not the full dashboard. Ignored outside search mode."
|
|
318
|
+
),
|
|
289
319
|
] = False,
|
|
290
320
|
) -> dict[str, Any]:
|
|
291
321
|
"""
|
|
292
|
-
Get dashboard info - list all dashboards
|
|
322
|
+
Get dashboard info - list all dashboards, get config, or search for cards.
|
|
293
323
|
|
|
294
|
-
|
|
295
|
-
|
|
324
|
+
MODE 1 — List: list_only=True
|
|
325
|
+
Lists all storage-mode dashboards with metadata (url_path, title, icon).
|
|
296
326
|
|
|
297
|
-
|
|
298
|
-
|
|
327
|
+
MODE 2 — Search: any of entity_id / card_type / heading provided
|
|
328
|
+
Finds cards, badges, and header cards matching the criteria.
|
|
329
|
+
Returns matches with jq_path for use with ha_config_set_dashboard(python_transform=...).
|
|
330
|
+
Multiple criteria are AND-ed. Always fetches fresh config (force=True).
|
|
331
|
+
Strategy dashboards are not searchable (no explicit cards).
|
|
332
|
+
|
|
333
|
+
MODE 3 — Get: Active when list_only=False and no search parameters are provided.
|
|
334
|
+
Returns the full Lovelace dashboard config, defaulting to the
|
|
335
|
+
main dashboard if url_path is omitted.
|
|
299
336
|
|
|
300
337
|
EXAMPLES:
|
|
301
338
|
- List all dashboards: ha_config_get_dashboard(list_only=True)
|
|
302
339
|
- Get default dashboard: ha_config_get_dashboard(url_path="default")
|
|
303
340
|
- Get custom dashboard: ha_config_get_dashboard(url_path="lovelace-mobile")
|
|
304
341
|
- Force reload: ha_config_get_dashboard(url_path="lovelace-home", force_reload=True)
|
|
342
|
+
- Find cards by entity: ha_config_get_dashboard(url_path="my-dash", entity_id="light.living_room")
|
|
343
|
+
- Find by wildcard: ha_config_get_dashboard(url_path="my-dash", entity_id="sensor.temperature_*")
|
|
344
|
+
- Find by type: ha_config_get_dashboard(url_path="my-dash", card_type="tile")
|
|
345
|
+
- Find heading: ha_config_get_dashboard(url_path="my-dash", heading="Climate", card_type="heading")
|
|
346
|
+
|
|
347
|
+
SEARCH WORKFLOW EXAMPLE:
|
|
348
|
+
1. find = ha_config_get_dashboard(url_path="my-dash", entity_id="light.bedroom")
|
|
349
|
+
2. ha_config_set_dashboard(
|
|
350
|
+
url_path="my-dash",
|
|
351
|
+
config_hash=find["config_hash"],
|
|
352
|
+
python_transform=f'config{find["matches"][0]["jq_path"]}["icon"] = "mdi:lamp"'
|
|
353
|
+
)
|
|
305
354
|
|
|
306
355
|
Note: YAML-mode dashboards (defined in configuration.yaml) are not included in list.
|
|
307
356
|
"""
|
|
357
|
+
search_mode = entity_id is not None or card_type is not None or heading is not None
|
|
308
358
|
try:
|
|
309
359
|
# List mode
|
|
310
360
|
if list_only:
|
|
@@ -325,6 +375,86 @@ def register_config_dashboard_tools(mcp: Any, client: Any, **kwargs: Any) -> Non
|
|
|
325
375
|
"count": len(dashboards),
|
|
326
376
|
}
|
|
327
377
|
|
|
378
|
+
# Search mode — find cards, badges, or header cards
|
|
379
|
+
if search_mode:
|
|
380
|
+
get_data: dict[str, Any] = {"type": "lovelace/config", "force": True}
|
|
381
|
+
if url_path and url_path != "default":
|
|
382
|
+
get_data["url_path"] = url_path
|
|
383
|
+
|
|
384
|
+
response = await client.send_websocket_message(get_data)
|
|
385
|
+
|
|
386
|
+
if isinstance(response, dict) and not response.get("success", True):
|
|
387
|
+
error_msg = response.get("error", {})
|
|
388
|
+
if isinstance(error_msg, dict):
|
|
389
|
+
error_msg = error_msg.get("message", str(error_msg))
|
|
390
|
+
raise_tool_error(
|
|
391
|
+
create_error_response(
|
|
392
|
+
ErrorCode.SERVICE_CALL_FAILED,
|
|
393
|
+
f"Failed to get dashboard: {error_msg}",
|
|
394
|
+
suggestions=[
|
|
395
|
+
"Verify dashboard exists with ha_config_get_dashboard(list_only=True)",
|
|
396
|
+
"Check HA connection",
|
|
397
|
+
],
|
|
398
|
+
context={"action": "find_card", "url_path": url_path},
|
|
399
|
+
)
|
|
400
|
+
)
|
|
401
|
+
|
|
402
|
+
config = (
|
|
403
|
+
response.get("result") if isinstance(response, dict) else response
|
|
404
|
+
)
|
|
405
|
+
if not isinstance(config, dict):
|
|
406
|
+
raise_tool_error(
|
|
407
|
+
create_error_response(
|
|
408
|
+
ErrorCode.SERVICE_CALL_FAILED,
|
|
409
|
+
"Dashboard config is empty or invalid",
|
|
410
|
+
suggestions=[
|
|
411
|
+
"Initialize dashboard with ha_config_set_dashboard"
|
|
412
|
+
],
|
|
413
|
+
context={"action": "find_card", "url_path": url_path},
|
|
414
|
+
)
|
|
415
|
+
)
|
|
416
|
+
|
|
417
|
+
if "strategy" in config:
|
|
418
|
+
raise_tool_error(
|
|
419
|
+
create_error_response(
|
|
420
|
+
ErrorCode.VALIDATION_FAILED,
|
|
421
|
+
"Strategy dashboards have no explicit cards to search",
|
|
422
|
+
suggestions=[
|
|
423
|
+
"Use 'Take Control' in HA UI to convert to editable",
|
|
424
|
+
"Or create a non-strategy dashboard",
|
|
425
|
+
],
|
|
426
|
+
context={"action": "find_card", "url_path": url_path},
|
|
427
|
+
)
|
|
428
|
+
)
|
|
429
|
+
|
|
430
|
+
matches = _find_cards_in_config(config, entity_id, card_type, heading)
|
|
431
|
+
|
|
432
|
+
if not include_config:
|
|
433
|
+
for match in matches:
|
|
434
|
+
del match["card_config"]
|
|
435
|
+
|
|
436
|
+
config_hash: str | None = _compute_config_hash(config)
|
|
437
|
+
|
|
438
|
+
return {
|
|
439
|
+
"success": True,
|
|
440
|
+
"action": "find_card",
|
|
441
|
+
"url_path": url_path,
|
|
442
|
+
"config_hash": config_hash,
|
|
443
|
+
"search_criteria": {
|
|
444
|
+
"entity_id": entity_id,
|
|
445
|
+
"card_type": card_type,
|
|
446
|
+
"heading": heading,
|
|
447
|
+
},
|
|
448
|
+
"matches": matches,
|
|
449
|
+
"match_count": len(matches),
|
|
450
|
+
"hint": (
|
|
451
|
+
"Use jq_path with ha_config_set_dashboard(python_transform=...) "
|
|
452
|
+
"for targeted updates"
|
|
453
|
+
if matches
|
|
454
|
+
else "No matches found. Try broader search criteria."
|
|
455
|
+
),
|
|
456
|
+
}
|
|
457
|
+
|
|
328
458
|
# Get mode - build WebSocket message
|
|
329
459
|
data: dict[str, Any] = {"type": "lovelace/config", "force": force_reload}
|
|
330
460
|
# Handle "default" as special value for default dashboard
|
|
@@ -375,7 +505,8 @@ def register_config_dashboard_tools(mcp: Any, client: Any, **kwargs: Any) -> Non
|
|
|
375
505
|
if config_size >= 10000:
|
|
376
506
|
result["hint"] = (
|
|
377
507
|
f"Large config ({config_size:,} bytes). For edits, use "
|
|
378
|
-
"
|
|
508
|
+
"ha_config_get_dashboard(entity_id=...) to find card positions, "
|
|
509
|
+
"then ha_config_set_dashboard(python_transform=...) "
|
|
379
510
|
"instead of full config replacement."
|
|
380
511
|
)
|
|
381
512
|
|
|
@@ -383,18 +514,39 @@ def register_config_dashboard_tools(mcp: Any, client: Any, **kwargs: Any) -> Non
|
|
|
383
514
|
except ToolError:
|
|
384
515
|
raise
|
|
385
516
|
except Exception as e:
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
"
|
|
517
|
+
if search_mode:
|
|
518
|
+
logger.error(
|
|
519
|
+
f"Error finding card in dashboard: url_path={url_path}, "
|
|
520
|
+
f"entity_id={entity_id}, card_type={card_type}, heading={heading}, "
|
|
521
|
+
f"error={e}",
|
|
522
|
+
exc_info=True,
|
|
523
|
+
)
|
|
524
|
+
suggestions = [
|
|
525
|
+
"Check HA connection",
|
|
526
|
+
"Verify dashboard with ha_config_get_dashboard(list_only=True)",
|
|
527
|
+
]
|
|
528
|
+
context: dict[str, Any] = {
|
|
529
|
+
"action": "find_card",
|
|
391
530
|
"url_path": url_path,
|
|
392
|
-
|
|
393
|
-
|
|
531
|
+
"entity_id": entity_id,
|
|
532
|
+
"card_type": card_type,
|
|
533
|
+
"heading": heading,
|
|
534
|
+
}
|
|
535
|
+
else:
|
|
536
|
+
logger.error(f"Error getting dashboard: {e}", exc_info=True)
|
|
537
|
+
suggestions = [
|
|
394
538
|
"Use ha_config_get_dashboard(list_only=True) to see available dashboards",
|
|
395
539
|
"Check if you have permission to access this dashboard",
|
|
396
540
|
"Use url_path='default' for default dashboard",
|
|
397
|
-
]
|
|
541
|
+
]
|
|
542
|
+
context = {
|
|
543
|
+
"action": "get" if not list_only else "list",
|
|
544
|
+
"url_path": url_path,
|
|
545
|
+
}
|
|
546
|
+
exception_to_structured_error(
|
|
547
|
+
e,
|
|
548
|
+
context=context,
|
|
549
|
+
suggestions=suggestions,
|
|
398
550
|
)
|
|
399
551
|
|
|
400
552
|
@mcp.tool(
|
|
@@ -485,10 +637,10 @@ def register_config_dashboard_tools(mcp: Any, client: Any, **kwargs: Any) -> Non
|
|
|
485
637
|
- config: New dashboards only, or full restructure. Replaces everything.
|
|
486
638
|
|
|
487
639
|
IMPORTANT: After delete/add operations, indices shift! Subsequent python_transform calls
|
|
488
|
-
must use fresh config_hash from
|
|
640
|
+
must use fresh config_hash from ha_config_get_dashboard()
|
|
489
641
|
to get updated structure. Chain multiple ops in ONE expression when possible.
|
|
490
642
|
|
|
491
|
-
TIP: Use
|
|
643
|
+
TIP: Use ha_config_get_dashboard(entity_id=...) to get the path for any card.
|
|
492
644
|
|
|
493
645
|
PYTHON TRANSFORM EXAMPLES (RECOMMENDED):
|
|
494
646
|
- Update card icon: 'config["views"][0]["cards"][0]["icon"] = "mdi:thermometer"'
|
|
@@ -1142,220 +1294,3 @@ def register_config_dashboard_tools(mcp: Any, client: Any, **kwargs: Any) -> Non
|
|
|
1142
1294
|
# - ha_config_delete_dashboard_resource: Delete resources
|
|
1143
1295
|
# =========================================================================
|
|
1144
1296
|
|
|
1145
|
-
# =========================================================================
|
|
1146
|
-
# Card Search Tool (partial update tools - controlled by feature flag)
|
|
1147
|
-
# Card add/update/remove replaced by python_transform in ha_config_set_dashboard
|
|
1148
|
-
# =========================================================================
|
|
1149
|
-
|
|
1150
|
-
# Check feature flag for partial update tools (lazy check, default enabled)
|
|
1151
|
-
try:
|
|
1152
|
-
settings = get_global_settings()
|
|
1153
|
-
if not settings.enable_dashboard_partial_tools:
|
|
1154
|
-
return # Skip registering find_card if partial tools disabled
|
|
1155
|
-
except Exception:
|
|
1156
|
-
pass # Default: register the tool if settings unavailable
|
|
1157
|
-
|
|
1158
|
-
@mcp.tool(
|
|
1159
|
-
tags={"Dashboards"},
|
|
1160
|
-
annotations={
|
|
1161
|
-
"idempotentHint": True,
|
|
1162
|
-
"readOnlyHint": True,
|
|
1163
|
-
"title": "Find Dashboard Card"
|
|
1164
|
-
}
|
|
1165
|
-
)
|
|
1166
|
-
@log_tool_usage
|
|
1167
|
-
async def ha_dashboard_find_card(
|
|
1168
|
-
url_path: Annotated[
|
|
1169
|
-
str | None,
|
|
1170
|
-
Field(
|
|
1171
|
-
description="Dashboard URL path, e.g. 'lovelace-home'. Omit for default."
|
|
1172
|
-
),
|
|
1173
|
-
] = None,
|
|
1174
|
-
entity_id: Annotated[
|
|
1175
|
-
str | None,
|
|
1176
|
-
Field(
|
|
1177
|
-
description="Find cards by entity ID. Supports wildcards, e.g. 'sensor.temperature_*'. "
|
|
1178
|
-
"Matches cards with this entity in 'entity' or 'entities' field."
|
|
1179
|
-
),
|
|
1180
|
-
] = None,
|
|
1181
|
-
card_type: Annotated[
|
|
1182
|
-
str | None,
|
|
1183
|
-
Field(description="Find cards by type, e.g. 'tile', 'button', 'heading'."),
|
|
1184
|
-
] = None,
|
|
1185
|
-
heading: Annotated[
|
|
1186
|
-
str | None,
|
|
1187
|
-
Field(
|
|
1188
|
-
description="Find cards by heading/title text (case-insensitive partial match). "
|
|
1189
|
-
"Useful for finding section headings (type: 'heading')."
|
|
1190
|
-
),
|
|
1191
|
-
] = None,
|
|
1192
|
-
include_config: Annotated[
|
|
1193
|
-
bool,
|
|
1194
|
-
Field(
|
|
1195
|
-
description="Include full card configuration in results (increases output size)."
|
|
1196
|
-
),
|
|
1197
|
-
] = False,
|
|
1198
|
-
) -> dict[str, Any]:
|
|
1199
|
-
"""
|
|
1200
|
-
Find cards, badges, and header cards in a dashboard by entity_id, type, or heading text.
|
|
1201
|
-
|
|
1202
|
-
Returns card/badge/header locations (view_index, section_index, card_index/badge_index)
|
|
1203
|
-
and path for use with ha_config_set_dashboard(python_transform=...).
|
|
1204
|
-
|
|
1205
|
-
Also searches view-level badges (views[n].badges) and sections-view header cards
|
|
1206
|
-
(views[n].header.card). Badges are the chip row at the top of a view, and header
|
|
1207
|
-
cards are Markdown cards in the view header — both reference entities and are
|
|
1208
|
-
often missed during entity rename operations.
|
|
1209
|
-
|
|
1210
|
-
Use this tool BEFORE targeted updates to find exact card positions without
|
|
1211
|
-
manually parsing the full dashboard config.
|
|
1212
|
-
|
|
1213
|
-
SEARCH CRITERIA (at least one required):
|
|
1214
|
-
- entity_id: Match cards and badges containing this entity (supports wildcards with *)
|
|
1215
|
-
- card_type: Match cards of this type (e.g., 'tile', 'button', 'heading')
|
|
1216
|
-
- heading: Match cards with this text in heading/title (partial, case-insensitive)
|
|
1217
|
-
|
|
1218
|
-
Multiple criteria are AND-ed together.
|
|
1219
|
-
|
|
1220
|
-
EXAMPLES:
|
|
1221
|
-
|
|
1222
|
-
Find all tile cards:
|
|
1223
|
-
ha_dashboard_find_card(url_path="my-dashboard", card_type="tile")
|
|
1224
|
-
|
|
1225
|
-
Find cards for a specific entity:
|
|
1226
|
-
ha_dashboard_find_card(url_path="my-dashboard", entity_id="light.living_room")
|
|
1227
|
-
|
|
1228
|
-
Find all temperature sensors (wildcard):
|
|
1229
|
-
ha_dashboard_find_card(url_path="my-dashboard", entity_id="sensor.temperature_*")
|
|
1230
|
-
|
|
1231
|
-
Find the "Climate" section heading:
|
|
1232
|
-
ha_dashboard_find_card(url_path="my-dashboard", heading="Climate", card_type="heading")
|
|
1233
|
-
|
|
1234
|
-
WORKFLOW EXAMPLE:
|
|
1235
|
-
1. find = ha_dashboard_find_card(url_path="my-dash", entity_id="light.bedroom")
|
|
1236
|
-
2. # Use jq_path and config_hash from result to update:
|
|
1237
|
-
3. ha_config_set_dashboard(
|
|
1238
|
-
url_path="my-dash",
|
|
1239
|
-
config_hash=find["config_hash"],
|
|
1240
|
-
python_transform=f'config{find["matches"][0]["jq_path"]}["icon"] = "mdi:lamp"'
|
|
1241
|
-
)
|
|
1242
|
-
"""
|
|
1243
|
-
try:
|
|
1244
|
-
# Validate at least one search criteria
|
|
1245
|
-
if entity_id is None and card_type is None and heading is None:
|
|
1246
|
-
raise_tool_error(
|
|
1247
|
-
create_error_response(
|
|
1248
|
-
ErrorCode.VALIDATION_INVALID_PARAMETER,
|
|
1249
|
-
"At least one search criteria required",
|
|
1250
|
-
suggestions=[
|
|
1251
|
-
"Provide entity_id, card_type, or heading parameter",
|
|
1252
|
-
"Use entity_id='sensor.*' to find all sensor cards",
|
|
1253
|
-
"Use card_type='heading' to find section headings",
|
|
1254
|
-
],
|
|
1255
|
-
context={"action": "find_card"},
|
|
1256
|
-
)
|
|
1257
|
-
)
|
|
1258
|
-
|
|
1259
|
-
# Fetch dashboard config
|
|
1260
|
-
get_data: dict[str, Any] = {"type": "lovelace/config", "force": True}
|
|
1261
|
-
if url_path:
|
|
1262
|
-
get_data["url_path"] = url_path
|
|
1263
|
-
|
|
1264
|
-
response = await client.send_websocket_message(get_data)
|
|
1265
|
-
|
|
1266
|
-
if isinstance(response, dict) and not response.get("success", True):
|
|
1267
|
-
error_msg = response.get("error", {})
|
|
1268
|
-
if isinstance(error_msg, dict):
|
|
1269
|
-
error_msg = error_msg.get("message", str(error_msg))
|
|
1270
|
-
raise_tool_error(
|
|
1271
|
-
create_error_response(
|
|
1272
|
-
ErrorCode.SERVICE_CALL_FAILED,
|
|
1273
|
-
f"Failed to get dashboard: {error_msg}",
|
|
1274
|
-
suggestions=[
|
|
1275
|
-
"Verify dashboard exists with ha_config_get_dashboard(list_only=True)",
|
|
1276
|
-
"Check HA connection",
|
|
1277
|
-
],
|
|
1278
|
-
context={"action": "find_card", "url_path": url_path},
|
|
1279
|
-
)
|
|
1280
|
-
)
|
|
1281
|
-
|
|
1282
|
-
config = response.get("result") if isinstance(response, dict) else response
|
|
1283
|
-
if not isinstance(config, dict):
|
|
1284
|
-
raise_tool_error(
|
|
1285
|
-
create_error_response(
|
|
1286
|
-
ErrorCode.SERVICE_CALL_FAILED,
|
|
1287
|
-
"Dashboard config is empty or invalid",
|
|
1288
|
-
suggestions=[
|
|
1289
|
-
"Initialize dashboard with ha_config_set_dashboard"
|
|
1290
|
-
],
|
|
1291
|
-
context={"action": "find_card", "url_path": url_path},
|
|
1292
|
-
)
|
|
1293
|
-
)
|
|
1294
|
-
|
|
1295
|
-
# Check for strategy dashboard
|
|
1296
|
-
if "strategy" in config:
|
|
1297
|
-
raise_tool_error(
|
|
1298
|
-
create_error_response(
|
|
1299
|
-
ErrorCode.VALIDATION_FAILED,
|
|
1300
|
-
"Strategy dashboards have no explicit cards to search",
|
|
1301
|
-
suggestions=[
|
|
1302
|
-
"Use 'Take Control' in HA UI to convert to editable",
|
|
1303
|
-
"Or create a non-strategy dashboard",
|
|
1304
|
-
],
|
|
1305
|
-
context={"action": "find_card", "url_path": url_path},
|
|
1306
|
-
)
|
|
1307
|
-
)
|
|
1308
|
-
|
|
1309
|
-
# Find matching cards
|
|
1310
|
-
matches = _find_cards_in_config(config, entity_id, card_type, heading)
|
|
1311
|
-
|
|
1312
|
-
# Optionally strip config to reduce output size
|
|
1313
|
-
if not include_config:
|
|
1314
|
-
for match in matches:
|
|
1315
|
-
del match["card_config"]
|
|
1316
|
-
|
|
1317
|
-
# Compute config hash for potential follow-up operations
|
|
1318
|
-
config_hash = _compute_config_hash(config)
|
|
1319
|
-
|
|
1320
|
-
return {
|
|
1321
|
-
"success": True,
|
|
1322
|
-
"action": "find_card",
|
|
1323
|
-
"url_path": url_path,
|
|
1324
|
-
"config_hash": config_hash,
|
|
1325
|
-
"search_criteria": {
|
|
1326
|
-
"entity_id": entity_id,
|
|
1327
|
-
"card_type": card_type,
|
|
1328
|
-
"heading": heading,
|
|
1329
|
-
},
|
|
1330
|
-
"matches": matches,
|
|
1331
|
-
"match_count": len(matches),
|
|
1332
|
-
"hint": "Use jq_path with ha_config_set_dashboard(python_transform=...) for targeted updates"
|
|
1333
|
-
if matches
|
|
1334
|
-
else "No matches found. Try broader search criteria.",
|
|
1335
|
-
}
|
|
1336
|
-
|
|
1337
|
-
except asyncio.CancelledError:
|
|
1338
|
-
raise
|
|
1339
|
-
except ToolError:
|
|
1340
|
-
raise
|
|
1341
|
-
except Exception as e:
|
|
1342
|
-
logger.error(
|
|
1343
|
-
f"Error finding card: url_path={url_path}, "
|
|
1344
|
-
f"entity_id={entity_id}, card_type={card_type}, heading={heading}, "
|
|
1345
|
-
f"error={e}",
|
|
1346
|
-
exc_info=True,
|
|
1347
|
-
)
|
|
1348
|
-
exception_to_structured_error(
|
|
1349
|
-
e,
|
|
1350
|
-
context={
|
|
1351
|
-
"action": "find_card",
|
|
1352
|
-
"url_path": url_path,
|
|
1353
|
-
"entity_id": entity_id,
|
|
1354
|
-
"card_type": card_type,
|
|
1355
|
-
"heading": heading,
|
|
1356
|
-
},
|
|
1357
|
-
suggestions=[
|
|
1358
|
-
"Check HA connection",
|
|
1359
|
-
"Verify dashboard with ha_config_get_dashboard(list_only=True)",
|
|
1360
|
-
],
|
|
1361
|
-
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ha-mcp-dev
|
|
3
|
-
Version: 7.2.0.
|
|
3
|
+
Version: 7.2.0.dev342
|
|
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-87-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>
|
|
@@ -160,7 +160,7 @@ Spend less time configuring, more time enjoying your smart home.
|
|
|
160
160
|
<details>
|
|
161
161
|
<!-- TOOLS_TABLE_START -->
|
|
162
162
|
|
|
163
|
-
<summary><b>Complete Tool List (
|
|
163
|
+
<summary><b>Complete Tool List (87 tools)</b></summary>
|
|
164
164
|
|
|
165
165
|
| Category | Tools |
|
|
166
166
|
|----------|-------|
|
|
@@ -170,7 +170,7 @@ Spend less time configuring, more time enjoying your smart home.
|
|
|
170
170
|
| **Blueprints** | `ha_get_blueprint`, `ha_import_blueprint` |
|
|
171
171
|
| **Calendar** | `ha_config_get_calendar_events`, `ha_config_remove_calendar_event`, `ha_config_set_calendar_event` |
|
|
172
172
|
| **Camera** | `ha_get_camera_image` |
|
|
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
|
|
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` |
|
|
174
174
|
| **Device Registry** | `ha_get_device`, `ha_remove_device`, `ha_update_device` |
|
|
175
175
|
| **Entity Registry** | `ha_get_entity_exposure`, `ha_get_entity`, `ha_remove_entity`, `ha_set_entity` |
|
|
176
176
|
| **Files** | `ha_delete_file`, `ha_list_files`, `ha_read_file`, `ha_write_file` |
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/resources/skills-vendor/AGENTS.md
RENAMED
|
File without changes
|
{ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/resources/skills-vendor/CLAUDE.md
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/resources/skills-vendor/LICENSE
RENAMED
|
File without changes
|
{ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/resources/skills-vendor/README.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/tools/best_practice_checker.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/tools/tools_config_automations.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/tools/tools_config_entry_flow.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/tools/tools_config_helpers.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/tools/tools_config_scripts.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/tools/tools_voice_assistant.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp/transforms/categorized_search.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp_dev.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{ha_mcp_dev-7.2.0.dev341 → ha_mcp_dev-7.2.0.dev342}/src/ha_mcp_dev.egg-info/entry_points.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|