ha-mcp-dev 7.4.1.dev424__tar.gz → 7.4.1.dev426__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.4.1.dev424/src/ha_mcp_dev.egg-info → ha_mcp_dev-7.4.1.dev426}/PKG-INFO +1 -1
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/pyproject.toml +1 -1
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/tools/tools_filesystem.py +10 -6
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/tools/tools_yaml_config.py +76 -3
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426/src/ha_mcp_dev.egg-info}/PKG-INFO +1 -1
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/LICENSE +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/MANIFEST.in +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/README.md +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/setup.cfg +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/__init__.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/__main__.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/_pypi_marker +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/_version.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/auth/__init__.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/auth/consent_form.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/auth/provider.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/client/__init__.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/client/rest_client.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/client/websocket_client.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/client/websocket_listener.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/config.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/errors.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/py.typed +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/resources/skills-vendor/.claude/settings.json +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/resources/skills-vendor/.claude-plugin/marketplace.json +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/resources/skills-vendor/.claude-plugin/plugin.json +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/resources/skills-vendor/.github/ISSUE_TEMPLATE/skill-rca.md +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/resources/skills-vendor/AGENTS.md +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/resources/skills-vendor/CLAUDE.md +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/resources/skills-vendor/CONTRIBUTING.md +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/resources/skills-vendor/LICENSE +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/resources/skills-vendor/README.md +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/SKILL.md +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/evals/evals.json +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/automation-patterns.md +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-cards.md +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-guide.md +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/device-control.md +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/domain-docs.md +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/examples.yaml +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/helper-selection.md +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/safe-refactoring.md +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/template-guidelines.md +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/server.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/settings_ui.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/smoke_test.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/tools/__init__.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/tools/backup.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/tools/best_practice_checker.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/tools/device_control.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/tools/enhanced.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/tools/helpers.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/tools/reference_validator.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/tools/registry.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/tools/smart_search.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/tools/tools_addons.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/tools/tools_areas.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/tools/tools_blueprints.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/tools/tools_bug_report.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/tools/tools_calendar.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/tools/tools_camera.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/tools/tools_categories.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/tools/tools_config_automations.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/tools/tools_config_dashboards.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/tools/tools_config_entry_flow.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/tools/tools_config_helpers.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/tools/tools_config_scripts.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/tools/tools_energy.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/tools/tools_entities.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/tools/tools_groups.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/tools/tools_hacs.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/tools/tools_history.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/tools/tools_integrations.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/tools/tools_labels.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/tools/tools_mcp_component.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/tools/tools_registry.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/tools/tools_resources.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/tools/tools_search.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/tools/tools_service.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/tools/tools_services.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/tools/tools_system.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/tools/tools_todo.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/tools/tools_traces.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/tools/tools_updates.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/tools/tools_utility.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/tools/tools_voice_assistant.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/tools/tools_zones.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/tools/util_helpers.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/transforms/__init__.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/transforms/categorized_search.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/utils/__init__.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/utils/config_hash.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/utils/domain_handlers.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/utils/fuzzy_search.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/utils/operation_manager.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/utils/python_sandbox.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/utils/usage_logger.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp_dev.egg-info/SOURCES.txt +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp_dev.egg-info/dependency_links.txt +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp_dev.egg-info/entry_points.txt +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp_dev.egg-info/requires.txt +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp_dev.egg-info/top_level.txt +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/tests/__init__.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/tests/test_constants.py +0 -0
- {ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/tests/test_env_manager.py +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "ha-mcp-dev"
|
|
7
|
-
version = "7.4.1.
|
|
7
|
+
version = "7.4.1.dev426"
|
|
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"
|
|
@@ -51,10 +51,11 @@ READABLE_PATTERNS = [
|
|
|
51
51
|
"www/**",
|
|
52
52
|
"themes/**",
|
|
53
53
|
"custom_templates/**",
|
|
54
|
+
"dashboards/**",
|
|
54
55
|
"custom_components/**/*.py",
|
|
55
56
|
]
|
|
56
57
|
|
|
57
|
-
WRITABLE_DIRS = ["www", "themes", "custom_templates"]
|
|
58
|
+
WRITABLE_DIRS = ["www", "themes", "custom_templates", "dashboards"]
|
|
58
59
|
|
|
59
60
|
|
|
60
61
|
def is_filesystem_tools_enabled() -> bool:
|
|
@@ -115,7 +116,7 @@ class FilesystemTools:
|
|
|
115
116
|
Field(
|
|
116
117
|
description=(
|
|
117
118
|
"Relative directory path from config directory. "
|
|
118
|
-
"Allowed paths: www/, themes/, custom_templates/. "
|
|
119
|
+
"Allowed paths: www/, themes/, custom_templates/, dashboards/. "
|
|
119
120
|
"Example: 'www/' or 'themes/my_theme'"
|
|
120
121
|
),
|
|
121
122
|
),
|
|
@@ -133,13 +134,14 @@ class FilesystemTools:
|
|
|
133
134
|
) -> dict[str, Any]:
|
|
134
135
|
"""List files in a directory within the Home Assistant config directory.
|
|
135
136
|
|
|
136
|
-
Lists files in allowed directories (www/, themes/, custom_templates/) with
|
|
137
|
+
Lists files in allowed directories (www/, themes/, custom_templates/, dashboards/) with
|
|
137
138
|
optional glob pattern filtering. Returns file names, sizes, and modification times.
|
|
138
139
|
|
|
139
140
|
**Allowed Directories:**
|
|
140
141
|
- `www/` - Web assets (CSS, JS, images for dashboards)
|
|
141
142
|
- `themes/` - Theme files
|
|
142
143
|
- `custom_templates/` - Jinja2 template files
|
|
144
|
+
- `dashboards/` - YAML-mode dashboard files
|
|
143
145
|
|
|
144
146
|
**Security:** Only directories in the allowed list can be accessed.
|
|
145
147
|
Path traversal attempts (../) are blocked.
|
|
@@ -237,7 +239,7 @@ class FilesystemTools:
|
|
|
237
239
|
- `secrets.yaml` (values masked)
|
|
238
240
|
- `packages/*.yaml`
|
|
239
241
|
- `home-assistant.log` (tail only)
|
|
240
|
-
- `www/**`, `themes/**`, `custom_templates/**`
|
|
242
|
+
- `www/**`, `themes/**`, `custom_templates/**`, `dashboards/**`
|
|
241
243
|
- `custom_components/**/*.py` (read-only)
|
|
242
244
|
|
|
243
245
|
**Security:**
|
|
@@ -322,7 +324,7 @@ class FilesystemTools:
|
|
|
322
324
|
Field(
|
|
323
325
|
description=(
|
|
324
326
|
"Relative path from config directory. "
|
|
325
|
-
"Must be in www/, themes/, or
|
|
327
|
+
"Must be in www/, themes/, custom_templates/, or dashboards/. "
|
|
326
328
|
"Example: 'www/custom.css', 'themes/my_theme.yaml'"
|
|
327
329
|
),
|
|
328
330
|
),
|
|
@@ -365,6 +367,7 @@ class FilesystemTools:
|
|
|
365
367
|
- `www/` - Web assets for dashboards
|
|
366
368
|
- `themes/` - Theme YAML files
|
|
367
369
|
- `custom_templates/` - Jinja2 template files
|
|
370
|
+
- `dashboards/` - YAML-mode dashboard files
|
|
368
371
|
|
|
369
372
|
**Security:**
|
|
370
373
|
- Only the directories above allow writes
|
|
@@ -453,7 +456,7 @@ class FilesystemTools:
|
|
|
453
456
|
Field(
|
|
454
457
|
description=(
|
|
455
458
|
"Relative path from config directory. "
|
|
456
|
-
"Must be in www/, themes/, or
|
|
459
|
+
"Must be in www/, themes/, custom_templates/, or dashboards/. "
|
|
457
460
|
"Example: 'www/old-file.css'"
|
|
458
461
|
),
|
|
459
462
|
),
|
|
@@ -478,6 +481,7 @@ class FilesystemTools:
|
|
|
478
481
|
- `www/` - Web assets
|
|
479
482
|
- `themes/` - Theme files
|
|
480
483
|
- `custom_templates/` - Template files
|
|
484
|
+
- `dashboards/` - YAML-mode dashboard files
|
|
481
485
|
|
|
482
486
|
**Security:**
|
|
483
487
|
- Only the directories above allow deletions
|
|
@@ -28,6 +28,68 @@ from .util_helpers import coerce_bool_param, unwrap_service_response
|
|
|
28
28
|
|
|
29
29
|
logger = logging.getLogger(__name__)
|
|
30
30
|
|
|
31
|
+
_LOVELACE_DASHBOARD_PREFIX = "lovelace.dashboards."
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
async def _check_storage_mode_dashboard_collision(
|
|
35
|
+
client: Any, yaml_path: str
|
|
36
|
+
) -> None:
|
|
37
|
+
"""Raise a ToolError if a storage-mode dashboard already owns the requested
|
|
38
|
+
url_path; otherwise return without doing anything.
|
|
39
|
+
|
|
40
|
+
Only runs for yaml_path values starting with 'lovelace.dashboards.'.
|
|
41
|
+
A WebSocket failure or unexpected response shape warns and skips the check
|
|
42
|
+
(fail-open) so that a transient HA outage doesn't block dashboard creation.
|
|
43
|
+
"""
|
|
44
|
+
if not yaml_path.startswith(_LOVELACE_DASHBOARD_PREFIX):
|
|
45
|
+
return
|
|
46
|
+
url_path = yaml_path[len(_LOVELACE_DASHBOARD_PREFIX):]
|
|
47
|
+
try:
|
|
48
|
+
result = await client.send_websocket_message(
|
|
49
|
+
{"type": "lovelace/dashboards/list"}
|
|
50
|
+
)
|
|
51
|
+
except Exception as exc:
|
|
52
|
+
logger.warning(
|
|
53
|
+
"lovelace/dashboards/list WS query failed (%s); skipping collision check",
|
|
54
|
+
exc,
|
|
55
|
+
)
|
|
56
|
+
return
|
|
57
|
+
|
|
58
|
+
if isinstance(result, dict) and "result" in result:
|
|
59
|
+
dashboards = result["result"]
|
|
60
|
+
elif isinstance(result, list):
|
|
61
|
+
dashboards = result
|
|
62
|
+
else:
|
|
63
|
+
logger.warning(
|
|
64
|
+
"lovelace/dashboards/list returned unexpected shape (%s); "
|
|
65
|
+
"skipping collision check",
|
|
66
|
+
type(result).__name__,
|
|
67
|
+
)
|
|
68
|
+
return
|
|
69
|
+
|
|
70
|
+
for entry in dashboards or []:
|
|
71
|
+
if (
|
|
72
|
+
isinstance(entry, dict)
|
|
73
|
+
and entry.get("url_path") == url_path
|
|
74
|
+
and entry.get("mode") == "storage"
|
|
75
|
+
):
|
|
76
|
+
raise_tool_error(
|
|
77
|
+
create_error_response(
|
|
78
|
+
ErrorCode.VALIDATION_INVALID_PARAMETER,
|
|
79
|
+
(
|
|
80
|
+
f"A storage-mode dashboard already owns url_path "
|
|
81
|
+
f"'{url_path}'. Delete it via ha_config_delete_dashboard "
|
|
82
|
+
"or pick a different url_path before registering a "
|
|
83
|
+
"YAML-mode dashboard."
|
|
84
|
+
),
|
|
85
|
+
context={"url_path": url_path, "existing_id": entry.get("id")},
|
|
86
|
+
suggestions=[
|
|
87
|
+
f"ha_config_delete_dashboard(url_path='{url_path}')",
|
|
88
|
+
"Pick a different url_path for your YAML-mode dashboard.",
|
|
89
|
+
],
|
|
90
|
+
)
|
|
91
|
+
)
|
|
92
|
+
|
|
31
93
|
|
|
32
94
|
def register_yaml_config_tools(mcp: Any, client: Any, **kwargs: Any) -> None:
|
|
33
95
|
"""Register YAML config editing tools with the MCP server.
|
|
@@ -59,8 +121,11 @@ def register_yaml_config_tools(mcp: Any, client: Any, **kwargs: Any) -> None:
|
|
|
59
121
|
description=(
|
|
60
122
|
"Top-level YAML key to modify. Only a narrow allowlist of "
|
|
61
123
|
"YAML-only integration keys is accepted (e.g., 'command_line', "
|
|
62
|
-
"'rest', 'shell_command', 'notify').
|
|
63
|
-
"
|
|
124
|
+
"'rest', 'shell_command', 'notify'). For YAML-mode dashboards, "
|
|
125
|
+
"use the dotted form 'lovelace.dashboards.<url_path>' where "
|
|
126
|
+
"<url_path> is lowercase, hyphenated, and not a reserved HA "
|
|
127
|
+
"route. No other dotted paths are supported. Not for template "
|
|
128
|
+
"sensors (use ha_config_set_helper), automations, scripts, "
|
|
64
129
|
"scenes, or input_* helpers — those have dedicated tools."
|
|
65
130
|
),
|
|
66
131
|
),
|
|
@@ -121,7 +186,9 @@ def register_yaml_config_tools(mcp: Any, client: Any, **kwargs: Any) -> None:
|
|
|
121
186
|
trend, filter, switch_as_x, etc.) -> ha_config_set_helper
|
|
122
187
|
|
|
123
188
|
Intended for YAML-only integrations with no config-flow or API
|
|
124
|
-
equivalent (command_line, rest, shell_command, notify platforms)
|
|
189
|
+
equivalent (command_line, rest, shell_command, notify platforms),
|
|
190
|
+
and for registering YAML-mode dashboards via
|
|
191
|
+
``lovelace.dashboards.<url_path>`` (no other ``lovelace.*`` keys).
|
|
125
192
|
Check ``post_action`` in the response: most keys need a full HA
|
|
126
193
|
restart; template, mqtt, and group support reload. Preserves YAML
|
|
127
194
|
comments and HA tags (``!include``, ``!secret``) on round-trip;
|
|
@@ -160,6 +227,12 @@ def register_yaml_config_tools(mcp: Any, client: Any, **kwargs: Any) -> None:
|
|
|
160
227
|
# Coerce boolean parameter
|
|
161
228
|
backup_bool = coerce_bool_param(backup, "backup", default=True)
|
|
162
229
|
|
|
230
|
+
# Storage-mode dashboard collision check (only for lovelace.dashboards.*).
|
|
231
|
+
# Skip on `remove` so users can clean up YAML entries that conflict
|
|
232
|
+
# with a storage-mode dashboard (e.g., during a migration).
|
|
233
|
+
if action in ("add", "replace"):
|
|
234
|
+
await _check_storage_mode_dashboard_collision(client, yaml_path)
|
|
235
|
+
|
|
163
236
|
# Check if custom component is available
|
|
164
237
|
await _assert_mcp_tools_available(client)
|
|
165
238
|
|
|
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
|
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/resources/skills-vendor/AGENTS.md
RENAMED
|
File without changes
|
{ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/resources/skills-vendor/CLAUDE.md
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/resources/skills-vendor/LICENSE
RENAMED
|
File without changes
|
{ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/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
|
|
File without changes
|
{ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/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
|
|
File without changes
|
{ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/tools/tools_config_automations.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/tools/tools_config_dashboards.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/tools/tools_config_entry_flow.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/tools/tools_config_helpers.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/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.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp/tools/tools_voice_assistant.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/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
|
|
File without changes
|
{ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/src/ha_mcp_dev.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{ha_mcp_dev-7.4.1.dev424 → ha_mcp_dev-7.4.1.dev426}/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
|