ha-mcp-dev 7.2.0.dev331__tar.gz → 7.2.0.dev332__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.dev331/src/ha_mcp_dev.egg-info → ha_mcp_dev-7.2.0.dev332}/PKG-INFO +3 -3
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/README.md +2 -2
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/pyproject.toml +1 -1
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/tools/backup.py +24 -23
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/tools/device_control.py +22 -20
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/tools/tools_entities.py +26 -51
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332/src/ha_mcp_dev.egg-info}/PKG-INFO +3 -3
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/LICENSE +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/MANIFEST.in +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/setup.cfg +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/__init__.py +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/__main__.py +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/_pypi_marker +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/auth/__init__.py +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/auth/consent_form.py +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/auth/provider.py +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/client/__init__.py +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/client/rest_client.py +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/client/websocket_client.py +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/client/websocket_listener.py +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/config.py +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/errors.py +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/py.typed +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/resources/skills-vendor/.claude/settings.json +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/resources/skills-vendor/.claude-plugin/marketplace.json +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/resources/skills-vendor/.claude-plugin/plugin.json +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/resources/skills-vendor/.github/ISSUE_TEMPLATE/skill-rca.md +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/resources/skills-vendor/AGENTS.md +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/resources/skills-vendor/CLAUDE.md +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/resources/skills-vendor/CONTRIBUTING.md +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/resources/skills-vendor/LICENSE +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/resources/skills-vendor/README.md +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/SKILL.md +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/evals/evals.json +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/automation-patterns.md +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-cards.md +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-guide.md +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/device-control.md +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/domain-docs.md +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/examples.yaml +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/helper-selection.md +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/safe-refactoring.md +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/template-guidelines.md +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/server.py +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/smoke_test.py +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/tools/__init__.py +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/tools/best_practice_checker.py +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/tools/enhanced.py +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/tools/helpers.py +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/tools/registry.py +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/tools/smart_search.py +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/tools/tools_addons.py +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/tools/tools_areas.py +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/tools/tools_blueprints.py +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/tools/tools_bug_report.py +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/tools/tools_calendar.py +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/tools/tools_camera.py +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/tools/tools_categories.py +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/tools/tools_config_automations.py +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/tools/tools_config_dashboards.py +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/tools/tools_config_entry_flow.py +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/tools/tools_config_helpers.py +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/tools/tools_config_scripts.py +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/tools/tools_filesystem.py +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/tools/tools_groups.py +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/tools/tools_hacs.py +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/tools/tools_history.py +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/tools/tools_integrations.py +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/tools/tools_labels.py +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/tools/tools_mcp_component.py +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/tools/tools_registry.py +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/tools/tools_resources.py +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/tools/tools_search.py +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/tools/tools_service.py +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/tools/tools_services.py +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/tools/tools_system.py +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/tools/tools_todo.py +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/tools/tools_traces.py +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/tools/tools_updates.py +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/tools/tools_utility.py +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/tools/tools_voice_assistant.py +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/tools/tools_yaml_config.py +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/tools/tools_zones.py +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/tools/util_helpers.py +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/transforms/__init__.py +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/transforms/categorized_search.py +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/utils/__init__.py +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/utils/domain_handlers.py +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/utils/fuzzy_search.py +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/utils/operation_manager.py +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/utils/python_sandbox.py +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/utils/usage_logger.py +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp_dev.egg-info/SOURCES.txt +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp_dev.egg-info/dependency_links.txt +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp_dev.egg-info/entry_points.txt +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp_dev.egg-info/requires.txt +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp_dev.egg-info/top_level.txt +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/tests/__init__.py +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/tests/test_constants.py +0 -0
- {ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/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.dev332
|
|
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-91-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 (91 tools)</b></summary>
|
|
164
164
|
|
|
165
165
|
| Category | Tools |
|
|
166
166
|
|----------|-------|
|
|
@@ -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-91-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 (91 tools)</b></summary>
|
|
135
135
|
|
|
136
136
|
| Category | Tools |
|
|
137
137
|
|----------|-------|
|
|
@@ -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.dev332"
|
|
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,7 +51,7 @@ def _get_backup_hint_text() -> str:
|
|
|
51
51
|
|
|
52
52
|
async def _get_backup_password(
|
|
53
53
|
ws_client: HomeAssistantWebSocketClient,
|
|
54
|
-
) ->
|
|
54
|
+
) -> str:
|
|
55
55
|
"""
|
|
56
56
|
Retrieve default backup password from Home Assistant configuration.
|
|
57
57
|
|
|
@@ -59,27 +59,30 @@ async def _get_backup_password(
|
|
|
59
59
|
ws_client: Connected WebSocket client
|
|
60
60
|
|
|
61
61
|
Returns:
|
|
62
|
-
|
|
62
|
+
The backup password string.
|
|
63
|
+
|
|
64
|
+
Raises:
|
|
65
|
+
ToolError: If backup config cannot be retrieved or no password is configured.
|
|
63
66
|
"""
|
|
64
67
|
backup_config = await ws_client.send_command("backup/config/info")
|
|
65
68
|
if not backup_config.get("success"):
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
"
|
|
69
|
-
"details": backup_config,
|
|
70
|
-
|
|
69
|
+
raise_tool_error(create_error_response(
|
|
70
|
+
ErrorCode.SERVICE_CALL_FAILED,
|
|
71
|
+
"Failed to retrieve backup configuration",
|
|
72
|
+
context={"details": backup_config},
|
|
73
|
+
))
|
|
71
74
|
|
|
72
75
|
config_data = backup_config.get("result", {}).get("config", {})
|
|
73
76
|
default_password = config_data.get("create_backup", {}).get("password")
|
|
74
77
|
|
|
75
78
|
if not default_password:
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
"
|
|
79
|
-
"
|
|
80
|
-
|
|
79
|
+
raise_tool_error(create_error_response(
|
|
80
|
+
ErrorCode.SERVICE_CALL_FAILED,
|
|
81
|
+
"No default backup password configured in Home Assistant",
|
|
82
|
+
suggestions=["Configure automatic backups in Home Assistant settings to set a default password"],
|
|
83
|
+
))
|
|
81
84
|
|
|
82
|
-
return
|
|
85
|
+
return cast(str, default_password)
|
|
83
86
|
|
|
84
87
|
|
|
85
88
|
async def create_backup(
|
|
@@ -107,13 +110,8 @@ async def create_backup(
|
|
|
107
110
|
))
|
|
108
111
|
ws_client = cast(HomeAssistantWebSocketClient, ws_client)
|
|
109
112
|
|
|
110
|
-
# Get backup password
|
|
111
|
-
password
|
|
112
|
-
if error:
|
|
113
|
-
raise_tool_error(create_error_response(
|
|
114
|
-
ErrorCode.SERVICE_CALL_FAILED,
|
|
115
|
-
error.get("error", "Failed to retrieve backup password"),
|
|
116
|
-
))
|
|
113
|
+
# Get backup password (raises ToolError on failure)
|
|
114
|
+
password = await _get_backup_password(ws_client)
|
|
117
115
|
|
|
118
116
|
# Generate backup name if not provided
|
|
119
117
|
if not name:
|
|
@@ -283,12 +281,15 @@ async def restore_backup(
|
|
|
283
281
|
safety_backup_name = f"PreRestore_Safety_{now.strftime('%Y-%m-%d_%H:%M:%S')}"
|
|
284
282
|
|
|
285
283
|
# Get backup password
|
|
286
|
-
|
|
287
|
-
|
|
284
|
+
try:
|
|
285
|
+
password = await _get_backup_password(ws_client)
|
|
286
|
+
except ToolError:
|
|
288
287
|
# Password error - log warning but continue (restore might still work)
|
|
289
288
|
logger.warning("No default password - proceeding without safety backup")
|
|
289
|
+
password = None
|
|
290
290
|
safety_backup_id = None
|
|
291
|
-
|
|
291
|
+
|
|
292
|
+
if password is not None:
|
|
292
293
|
safety_backup = await ws_client.send_command(
|
|
293
294
|
"backup/generate",
|
|
294
295
|
name=safety_backup_name,
|
|
@@ -421,38 +421,40 @@ class DeviceControlTools:
|
|
|
421
421
|
}
|
|
422
422
|
|
|
423
423
|
elif operation.status.value == "failed":
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
"
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
424
|
+
raise_tool_error(create_error_response(
|
|
425
|
+
ErrorCode.SERVICE_CALL_FAILED,
|
|
426
|
+
operation.error_message or "Device operation failed",
|
|
427
|
+
context={
|
|
428
|
+
"operation_id": operation_id,
|
|
429
|
+
"entity_id": operation.entity_id,
|
|
430
|
+
"action": operation.action,
|
|
431
|
+
"duration_ms": operation.duration_ms,
|
|
432
|
+
},
|
|
433
|
+
suggestions=[
|
|
433
434
|
"Check if device is available and responding",
|
|
434
435
|
"Verify device supports the requested action",
|
|
435
436
|
"Check Home Assistant logs for error details",
|
|
436
437
|
"Try a simpler action like toggle",
|
|
437
438
|
],
|
|
438
|
-
|
|
439
|
+
))
|
|
439
440
|
|
|
440
441
|
elif operation.status.value == "timeout":
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
"
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
442
|
+
raise_tool_error(create_error_response(
|
|
443
|
+
ErrorCode.TIMEOUT_OPERATION,
|
|
444
|
+
f"Operation timed out after {operation.timeout_ms}ms",
|
|
445
|
+
context={
|
|
446
|
+
"operation_id": operation_id,
|
|
447
|
+
"entity_id": operation.entity_id,
|
|
448
|
+
"action": operation.action,
|
|
449
|
+
"elapsed_ms": operation.elapsed_ms,
|
|
450
|
+
},
|
|
451
|
+
suggestions=[
|
|
450
452
|
"Device may be slow to respond or offline",
|
|
451
453
|
"Check device connectivity",
|
|
452
454
|
"Try increasing timeout for slow devices",
|
|
453
455
|
"Verify device is powered on",
|
|
454
456
|
],
|
|
455
|
-
|
|
457
|
+
))
|
|
456
458
|
|
|
457
459
|
else: # pending
|
|
458
460
|
return {
|
|
@@ -240,21 +240,20 @@ def register_entity_tools(mcp: Any, client: Any, **kwargs: Any) -> None:
|
|
|
240
240
|
else str(error)
|
|
241
241
|
)
|
|
242
242
|
failed = dict.fromkeys(assistants, should_expose)
|
|
243
|
-
|
|
244
|
-
"success": False,
|
|
245
|
-
"error": {
|
|
246
|
-
"code": ErrorCode.SERVICE_CALL_FAILED.value,
|
|
247
|
-
"message": f"Exposure failed: {error_msg}",
|
|
248
|
-
"suggestion": "Check Home Assistant connection and entity availability",
|
|
249
|
-
},
|
|
243
|
+
context: dict[str, Any] = {
|
|
250
244
|
"entity_id": entity_id,
|
|
251
245
|
"exposure_succeeded": succeeded,
|
|
252
246
|
"exposure_failed": failed,
|
|
253
247
|
}
|
|
254
248
|
if has_registry_updates:
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
249
|
+
context["partial"] = True
|
|
250
|
+
context["entity_entry"] = _format_entity_entry(entity_entry)
|
|
251
|
+
raise_tool_error(create_error_response(
|
|
252
|
+
ErrorCode.SERVICE_CALL_FAILED,
|
|
253
|
+
f"Exposure failed: {error_msg}",
|
|
254
|
+
context=context,
|
|
255
|
+
suggestions=["Check Home Assistant connection and entity availability"],
|
|
256
|
+
))
|
|
258
257
|
|
|
259
258
|
# Track successful exposures
|
|
260
259
|
for a in assistants:
|
|
@@ -272,21 +271,15 @@ def register_entity_tools(mcp: Any, client: Any, **kwargs: Any) -> None:
|
|
|
272
271
|
if get_result.get("success"):
|
|
273
272
|
entity_entry = get_result.get("result", {})
|
|
274
273
|
else:
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
"
|
|
278
|
-
"
|
|
279
|
-
|
|
280
|
-
"message": f"Entity '{entity_id}' not found in registry after applying exposure changes",
|
|
281
|
-
"suggestion": "Use ha_search_entities() to verify the entity exists",
|
|
282
|
-
},
|
|
283
|
-
"entity_id": entity_id,
|
|
284
|
-
"suggestions": [
|
|
274
|
+
raise_tool_error(create_error_response(
|
|
275
|
+
ErrorCode.ENTITY_NOT_FOUND,
|
|
276
|
+
f"Entity '{entity_id}' not found in registry after applying exposure changes",
|
|
277
|
+
context={"entity_id": entity_id, "exposure_succeeded": exposure_result},
|
|
278
|
+
suggestions=[
|
|
285
279
|
"Verify the entity_id exists using ha_search_entities()",
|
|
286
280
|
"The entity's exposure settings were likely changed, but its current state could not be confirmed.",
|
|
287
281
|
],
|
|
288
|
-
|
|
289
|
-
}
|
|
282
|
+
))
|
|
290
283
|
|
|
291
284
|
response_data: dict[str, Any] = {
|
|
292
285
|
"success": True,
|
|
@@ -831,15 +824,10 @@ def register_entity_tools(mcp: Any, client: Any, **kwargs: Any) -> None:
|
|
|
831
824
|
if isinstance(error, dict)
|
|
832
825
|
else str(error)
|
|
833
826
|
)
|
|
834
|
-
|
|
835
|
-
"success": False,
|
|
836
|
-
"entity_id": eid,
|
|
837
|
-
"error": error_msg,
|
|
838
|
-
}
|
|
827
|
+
raise ValueError(error_msg)
|
|
839
828
|
|
|
840
829
|
entry = result.get("result", {})
|
|
841
830
|
return {
|
|
842
|
-
"success": True,
|
|
843
831
|
"entity_id": entry.get("entity_id"),
|
|
844
832
|
"name": entry.get("name"),
|
|
845
833
|
"original_name": entry.get("original_name"),
|
|
@@ -861,21 +849,13 @@ def register_entity_tools(mcp: Any, client: Any, **kwargs: Any) -> None:
|
|
|
861
849
|
if not is_bulk:
|
|
862
850
|
eid = entity_ids[0]
|
|
863
851
|
logger.info(f"Getting entity registry entry for {eid}")
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
return {
|
|
868
|
-
"success": True,
|
|
869
|
-
"entity_id": eid,
|
|
870
|
-
"entity_entry": {
|
|
871
|
-
k: v for k, v in result.items() if k not in ("success",)
|
|
872
|
-
},
|
|
873
|
-
}
|
|
874
|
-
else:
|
|
852
|
+
try:
|
|
853
|
+
result = await _fetch_entity(eid)
|
|
854
|
+
except ValueError as e:
|
|
875
855
|
raise_tool_error(
|
|
876
856
|
create_error_response(
|
|
877
857
|
ErrorCode.SERVICE_CALL_FAILED,
|
|
878
|
-
f"Entity not found: {
|
|
858
|
+
f"Entity not found: {e}",
|
|
879
859
|
context={"entity_id": eid},
|
|
880
860
|
suggestions=[
|
|
881
861
|
"Use ha_search_entities() to find valid entity IDs",
|
|
@@ -883,6 +863,11 @@ def register_entity_tools(mcp: Any, client: Any, **kwargs: Any) -> None:
|
|
|
883
863
|
],
|
|
884
864
|
)
|
|
885
865
|
)
|
|
866
|
+
return {
|
|
867
|
+
"success": True,
|
|
868
|
+
"entity_id": eid,
|
|
869
|
+
"entity_entry": result,
|
|
870
|
+
}
|
|
886
871
|
|
|
887
872
|
# Bulk case - fetch all entities
|
|
888
873
|
logger.info(
|
|
@@ -904,18 +889,8 @@ def register_entity_tools(mcp: Any, client: Any, **kwargs: Any) -> None:
|
|
|
904
889
|
"error": str(fetch_result),
|
|
905
890
|
}
|
|
906
891
|
)
|
|
907
|
-
continue
|
|
908
|
-
if fetch_result.get("success"):
|
|
909
|
-
entity_entries.append(
|
|
910
|
-
{k: v for k, v in fetch_result.items() if k not in ("success",)}
|
|
911
|
-
)
|
|
912
892
|
else:
|
|
913
|
-
|
|
914
|
-
{
|
|
915
|
-
"entity_id": eid,
|
|
916
|
-
"error": fetch_result.get("error", "Unknown error"),
|
|
917
|
-
}
|
|
918
|
-
)
|
|
893
|
+
entity_entries.append(fetch_result)
|
|
919
894
|
|
|
920
895
|
response: dict[str, Any] = {
|
|
921
896
|
"success": True,
|
|
@@ -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.dev332
|
|
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-91-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 (91 tools)</b></summary>
|
|
164
164
|
|
|
165
165
|
| Category | Tools |
|
|
166
166
|
|----------|-------|
|
|
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.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/resources/skills-vendor/AGENTS.md
RENAMED
|
File without changes
|
{ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/resources/skills-vendor/CLAUDE.md
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/resources/skills-vendor/LICENSE
RENAMED
|
File without changes
|
{ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/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
|
{ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/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
|
{ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/tools/tools_config_automations.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/tools/tools_config_dashboards.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/tools/tools_config_entry_flow.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp/tools/tools_config_helpers.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/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
|
{ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/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.dev331 → ha_mcp_dev-7.2.0.dev332}/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.dev331 → ha_mcp_dev-7.2.0.dev332}/src/ha_mcp_dev.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{ha_mcp_dev-7.2.0.dev331 → ha_mcp_dev-7.2.0.dev332}/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
|