ha-mcp-dev 7.7.0.dev694__tar.gz → 7.7.0.dev696__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.7.0.dev694/src/ha_mcp_dev.egg-info → ha_mcp_dev-7.7.0.dev696}/PKG-INFO +3 -1
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/README.md +2 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/pyproject.toml +1 -1
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/server.py +7 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/settings_ui.py +8 -2
- ha_mcp_dev-7.7.0.dev696/src/ha_mcp/tools/tool_search_hint_middleware.py +99 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/tools_config_helpers.py +60 -21
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696/src/ha_mcp_dev.egg-info}/PKG-INFO +3 -1
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp_dev.egg-info/SOURCES.txt +1 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/LICENSE +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/MANIFEST.in +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/setup.cfg +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/__init__.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/__main__.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/_pypi_marker +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/_version.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/auth/__init__.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/auth/consent_form.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/auth/provider.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/backup_manager.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/client/__init__.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/client/rest_client.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/client/supervisor_client.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/client/websocket_client.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/client/websocket_listener.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/config.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/dashboard_screenshot/__init__.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/dashboard_screenshot/capture.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/dashboard_screenshot/provision.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/errors.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/policy/__init__.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/policy/approval_queue.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/policy/evaluator.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/policy/handlers.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/policy/middleware.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/policy/model.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/policy/persistence.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/policy/value_sources.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/py.typed +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/read_only.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/resources/skills-vendor/.claude/settings.json +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/resources/skills-vendor/.claude-plugin/marketplace.json +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/resources/skills-vendor/.claude-plugin/plugin.json +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/resources/skills-vendor/.github/ISSUE_TEMPLATE/skill-rca.md +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/resources/skills-vendor/.github/pull_request_template.md +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/resources/skills-vendor/AGENTS.md +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/resources/skills-vendor/CLAUDE.md +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/resources/skills-vendor/CONTRIBUTING.md +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/resources/skills-vendor/LICENSE +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/resources/skills-vendor/README.md +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/SKILL.md +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/evals/evals.json +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/automation-patterns.md +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-cards.md +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-guide.md +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/device-control.md +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/domain-docs.md +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/examples.yaml +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/helper-selection.md +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/safe-refactoring.md +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/template-guidelines.md +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/yaml-only-integrations.md +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/settings.css +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/settings.js +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/smoke_test.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/stdio_settings_sidecar.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/__init__.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/auto_backup.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/backup.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/best_practice_checker.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/config_entry_flow.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/device_control.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/enhanced.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/helpers.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/reference_validator.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/registry.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/smart_search/__init__.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/smart_search/_base.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/smart_search/_config.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/smart_search/_deep.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/smart_search/_entities.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/smart_search/_fetch.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/smart_search/_overview.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/smart_search/_scenes.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/smart_search/_scoring.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/tools_addons.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/tools_areas.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/tools_blueprints.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/tools_bug_report.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/tools_calendar.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/tools_camera.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/tools_categories.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/tools_code.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/tools_config_automations.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/tools_config_dashboards.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/tools_config_scenes.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/tools_config_scripts.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/tools_dashboard_screenshot.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/tools_energy.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/tools_entities.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/tools_filesystem.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/tools_groups.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/tools_hacs.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/tools_history.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/tools_integrations.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/tools_labels.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/tools_mcp_component.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/tools_registry.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/tools_resources.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/tools_search.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/tools_service.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/tools_services.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/tools_system.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/tools_themes.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/tools_todo.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/tools_traces.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/tools_updates.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/tools_utility.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/tools_voice_assistant.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/tools_yaml_config.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/tools_zones.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/util_helpers.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/validation_middleware.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/transforms/__init__.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/transforms/categorized_search.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/transforms/lite_docstrings.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/utils/__init__.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/utils/config_hash.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/utils/data_paths.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/utils/domain_handlers.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/utils/fuzzy_search.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/utils/kill_signal_diagnostics.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/utils/operation_manager.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/utils/python_sandbox.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/utils/skill_loader.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/utils/usage_logger.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp_dev.egg-info/dependency_links.txt +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp_dev.egg-info/entry_points.txt +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp_dev.egg-info/requires.txt +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp_dev.egg-info/top_level.txt +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/tests/__init__.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/tests/test_constants.py +0 -0
- {ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/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.7.0.
|
|
3
|
+
Version: 7.7.0.dev696
|
|
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
|
|
@@ -349,6 +349,8 @@ The proxy split lets MCP clients apply different permission policies per categor
|
|
|
349
349
|
|
|
350
350
|
Leave it off when using Claude Sonnet/Opus or any client with deferred tool loading; the full catalog has no idle cost there and direct calls skip the search step. If you choose to use our toolsearch then you should disable the native Claude Opus/Sonnet toolsearch, which is called deferred tools in the settings.
|
|
351
351
|
|
|
352
|
+
> 🔄 **Refresh your client's tool list after changing this (or any) setting.** Toggling `ENABLE_TOOL_SEARCH` (or changing pinned/disabled tools, Read Only Mode, etc.) changes the tools the server exposes, but your AI client keeps serving its **cached** tool list until it re-fetches. Restarting the add-on or Home Assistant does **not** refresh the client — reconnect or refresh the MCP server in your client (e.g. re-add/refresh the connector in ChatGPT, or close and reopen Claude Desktop). If you skip this, tools shown as available will return `Unknown tool` when called.
|
|
353
|
+
|
|
352
354
|
For the HA add-on, the same option is documented in [`homeassistant-addon/DOCS.md`](homeassistant-addon/DOCS.md#enable_tool_search) along with the in-add-on settings UI for fine-grained tool enable/disable/pin.
|
|
353
355
|
|
|
354
356
|
---
|
|
@@ -319,6 +319,8 @@ The proxy split lets MCP clients apply different permission policies per categor
|
|
|
319
319
|
|
|
320
320
|
Leave it off when using Claude Sonnet/Opus or any client with deferred tool loading; the full catalog has no idle cost there and direct calls skip the search step. If you choose to use our toolsearch then you should disable the native Claude Opus/Sonnet toolsearch, which is called deferred tools in the settings.
|
|
321
321
|
|
|
322
|
+
> 🔄 **Refresh your client's tool list after changing this (or any) setting.** Toggling `ENABLE_TOOL_SEARCH` (or changing pinned/disabled tools, Read Only Mode, etc.) changes the tools the server exposes, but your AI client keeps serving its **cached** tool list until it re-fetches. Restarting the add-on or Home Assistant does **not** refresh the client — reconnect or refresh the MCP server in your client (e.g. re-add/refresh the connector in ChatGPT, or close and reopen Claude Desktop). If you skip this, tools shown as available will return `Unknown tool` when called.
|
|
323
|
+
|
|
322
324
|
For the HA add-on, the same option is documented in [`homeassistant-addon/DOCS.md`](homeassistant-addon/DOCS.md#enable_tool_search) along with the in-add-on settings UI for fine-grained tool enable/disable/pin.
|
|
323
325
|
|
|
324
326
|
---
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "ha-mcp-dev"
|
|
7
|
-
version = "7.7.0.
|
|
7
|
+
version = "7.7.0.dev696"
|
|
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"
|
|
@@ -236,6 +236,13 @@ class HomeAssistantSmartMCPServer(EnhancedToolsMixin):
|
|
|
236
236
|
|
|
237
237
|
self.mcp.add_middleware(ValidationErrorMiddleware())
|
|
238
238
|
|
|
239
|
+
# Replace the opaque "Unknown tool" FastMCP raises when a client calls
|
|
240
|
+
# ha_search_tools / the ha_call_* proxies while Tool Search is off
|
|
241
|
+
# (stale client tool-list cache) with an actionable refresh hint.
|
|
242
|
+
from .tools.tool_search_hint_middleware import ToolSearchHintMiddleware
|
|
243
|
+
|
|
244
|
+
self.mcp.add_middleware(ToolSearchHintMiddleware())
|
|
245
|
+
|
|
239
246
|
# Read Only Mode write blocker (discussion #1569) — always
|
|
240
247
|
# installed, consults the live flag per call. Before
|
|
241
248
|
# PolicyMiddleware so a write blocked by Read Only Mode never
|
|
@@ -812,6 +812,10 @@ _SETTINGS_HTML = (
|
|
|
812
812
|
<span class="restart-notice-text" id="restartNoticeText">
|
|
813
813
|
⚠ Changes saved. Restart ha-mcp for them to take effect — disabled
|
|
814
814
|
tools will be fully removed from the MCP tool list on next startup.
|
|
815
|
+
Then reconnect or refresh the MCP server in your AI client (e.g.
|
|
816
|
+
re-add/refresh the connector in ChatGPT, or close and reopen Claude
|
|
817
|
+
Desktop) so it reloads the tool list — restarting the add-on or Home
|
|
818
|
+
Assistant does NOT refresh your client's cached tool list.
|
|
815
819
|
</span>
|
|
816
820
|
<button class="restart-btn" id="restartBtn" style="display:none">Restart Add-on</button>
|
|
817
821
|
</div>
|
|
@@ -857,8 +861,10 @@ _SETTINGS_HTML = (
|
|
|
857
861
|
</div>
|
|
858
862
|
<div class="panel" id="panel-server">
|
|
859
863
|
<div class="features-sub">
|
|
860
|
-
Tool Search, advanced settings. Changes
|
|
861
|
-
|
|
864
|
+
Tool Search, advanced settings. Changes take effect only after you
|
|
865
|
+
restart the add-on (applies the change server-side) AND reconnect or
|
|
866
|
+
refresh the MCP server in your AI client (reloads the tool list) — e.g.
|
|
867
|
+
re-add/refresh the connector in ChatGPT, or close + reopen Claude Desktop.
|
|
862
868
|
</div>
|
|
863
869
|
|
|
864
870
|
<!-- Two-step note + top Save button. The Save +
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"""FastMCP middleware: actionable error for stale tool-search proxy/search calls.
|
|
2
|
+
|
|
3
|
+
When ``enable_tool_search`` is off, the synthetic tool-search tools —
|
|
4
|
+
``ha_search_tools`` and the ``ha_call_{read,write,delete}_tool`` proxies — are
|
|
5
|
+
never registered (the ``CategorizedSearchTransform`` is not installed). If a
|
|
6
|
+
client calls one of them anyway, FastMCP raises a bare ``NotFoundError``
|
|
7
|
+
("Unknown tool: 'ha_search_tools'") with no recovery guidance.
|
|
8
|
+
|
|
9
|
+
That is exactly what happens when an MCP client that caches its tool list is
|
|
10
|
+
still advertising one captured from a previous session when Tool Search was on:
|
|
11
|
+
the client shows ``ha_search_tools`` as available, calls it, and the live
|
|
12
|
+
server — now in Tool-Search-off mode — rejects it. Restarting the add-on or
|
|
13
|
+
Home Assistant does not help because the stale list lives in the client, not
|
|
14
|
+
the server.
|
|
15
|
+
|
|
16
|
+
This middleware intercepts that one case and replaces the opaque "Unknown tool"
|
|
17
|
+
with a structured error that tells the user their tool list is stale and to
|
|
18
|
+
reconnect/refresh the MCP server. It only acts on a *top-level* resolution miss
|
|
19
|
+
for one of those four names while Tool Search is off; in every other case —
|
|
20
|
+
including a ``NotFoundError`` bubbling up from inside an executing tool — the
|
|
21
|
+
original error propagates unchanged.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
from __future__ import annotations
|
|
25
|
+
|
|
26
|
+
import logging
|
|
27
|
+
from typing import Any
|
|
28
|
+
|
|
29
|
+
from fastmcp.exceptions import NotFoundError
|
|
30
|
+
from fastmcp.server.middleware.middleware import CallNext, Middleware, MiddlewareContext
|
|
31
|
+
|
|
32
|
+
from ..config import get_global_settings
|
|
33
|
+
from ..errors import ErrorCode, create_error_response
|
|
34
|
+
from ..policy.middleware import PROXY_META_TOOLS
|
|
35
|
+
from .helpers import raise_tool_error
|
|
36
|
+
|
|
37
|
+
logger = logging.getLogger(__name__)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class ToolSearchHintMiddleware(Middleware):
|
|
41
|
+
"""Turn the opaque "Unknown tool" for tool-search synthetic tools into a
|
|
42
|
+
stale-tool-list hint when Tool Search is disabled."""
|
|
43
|
+
|
|
44
|
+
async def on_call_tool(
|
|
45
|
+
self, context: MiddlewareContext, call_next: CallNext
|
|
46
|
+
) -> Any:
|
|
47
|
+
try:
|
|
48
|
+
return await call_next(context)
|
|
49
|
+
except NotFoundError as exc:
|
|
50
|
+
name = context.message.name
|
|
51
|
+
# Only rewrite a TOP-LEVEL "Unknown tool" miss for one of the four
|
|
52
|
+
# tool-search synthetic names while Tool Search is off:
|
|
53
|
+
# - match the dispatch-layer message so a NotFoundError bubbling up
|
|
54
|
+
# from INSIDE an executing tool (a different name) is never
|
|
55
|
+
# mislabeled as a stale cache; on any wording change this simply
|
|
56
|
+
# fails closed and re-raises the original error.
|
|
57
|
+
# - require Tool Search to be off (when on, the names resolve, so a
|
|
58
|
+
# miss would be a different, real problem we must not mask).
|
|
59
|
+
top_level_miss = str(exc) == f"Unknown tool: {name!r}"
|
|
60
|
+
if (
|
|
61
|
+
top_level_miss
|
|
62
|
+
and name in PROXY_META_TOOLS
|
|
63
|
+
and not get_global_settings().enable_tool_search
|
|
64
|
+
):
|
|
65
|
+
logger.info(
|
|
66
|
+
"Stale tool-search call for %r while enable_tool_search is off "
|
|
67
|
+
"- returning refresh-your-tool-list hint",
|
|
68
|
+
name,
|
|
69
|
+
)
|
|
70
|
+
raise_tool_error(
|
|
71
|
+
create_error_response(
|
|
72
|
+
code=ErrorCode.RESOURCE_NOT_FOUND,
|
|
73
|
+
message=(
|
|
74
|
+
f"'{name}' only exists when Tool Search is enabled, and "
|
|
75
|
+
"Tool Search is currently OFF on this ha-mcp server. Your "
|
|
76
|
+
"MCP client is showing a cached tool list from when Tool "
|
|
77
|
+
"Search was on. After changing any ha-mcp setting (Tool "
|
|
78
|
+
"Search, pinned/disabled tools, etc.) the client must "
|
|
79
|
+
"reconnect or refresh the MCP server to re-fetch the "
|
|
80
|
+
"current tools — restarting the add-on or Home Assistant "
|
|
81
|
+
"does not refresh the client's cached list. With Tool "
|
|
82
|
+
f"Search off, every tool is available directly by name, "
|
|
83
|
+
f"so {name} is not needed."
|
|
84
|
+
),
|
|
85
|
+
suggestions=[
|
|
86
|
+
(
|
|
87
|
+
"Reconnect or refresh the ha-mcp MCP server in your "
|
|
88
|
+
"client to reload the current tool list."
|
|
89
|
+
),
|
|
90
|
+
(
|
|
91
|
+
"Then call the tool you need directly by its name "
|
|
92
|
+
"(with Tool Search off, ha_search_tools and the "
|
|
93
|
+
"ha_call_* proxies do not exist)."
|
|
94
|
+
),
|
|
95
|
+
],
|
|
96
|
+
context={"tool_name": name, "enable_tool_search": False},
|
|
97
|
+
)
|
|
98
|
+
)
|
|
99
|
+
raise
|
{ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/tools_config_helpers.py
RENAMED
|
@@ -737,12 +737,15 @@ def _validate_applicable_params(
|
|
|
737
737
|
|
|
738
738
|
if helper_type in FLOW_HELPER_TYPES:
|
|
739
739
|
# Flow types accept `config` (handled before this call) plus
|
|
740
|
-
# cross-cutting params (name/helper_id/area_id/labels/category/wait).
|
|
741
|
-
#
|
|
740
|
+
# cross-cutting params (name/helper_id/area_id/labels/category/icon/wait).
|
|
741
|
+
# `icon` is applied to the resulting entity(ies) via the entity registry
|
|
742
|
+
# (like area_id/labels), so it is allowed even though the config-flow
|
|
743
|
+
# form has no icon field. Any other simple-helper-typed param passed
|
|
744
|
+
# here is inapplicable.
|
|
742
745
|
inapplicable.extend(
|
|
743
746
|
param_name
|
|
744
747
|
for param_name in _ALL_TYPED_PARAMS
|
|
745
|
-
if passed.get(param_name) is not None
|
|
748
|
+
if param_name != "icon" and passed.get(param_name) is not None
|
|
746
749
|
)
|
|
747
750
|
else:
|
|
748
751
|
applicable = _TYPE_TYPED_PARAMS.get(helper_type, frozenset())
|
|
@@ -760,7 +763,7 @@ def _validate_applicable_params(
|
|
|
760
763
|
if helper_type in FLOW_HELPER_TYPES:
|
|
761
764
|
applicable_msg = (
|
|
762
765
|
"config (see data_schema on a validation error for the field set), "
|
|
763
|
-
"name, helper_id, area_id, labels, category, wait"
|
|
766
|
+
"name, helper_id, area_id, labels, category, icon, wait"
|
|
764
767
|
)
|
|
765
768
|
else:
|
|
766
769
|
type_specific = sorted(_TYPE_TYPED_PARAMS.get(helper_type, frozenset()))
|
|
@@ -1453,7 +1456,11 @@ async def _get_entities_for_config_entry(
|
|
|
1453
1456
|
|
|
1454
1457
|
|
|
1455
1458
|
async def _entity_registry_update_coro(
|
|
1456
|
-
client: Any,
|
|
1459
|
+
client: Any,
|
|
1460
|
+
entity_id: str,
|
|
1461
|
+
area_id: str | None,
|
|
1462
|
+
labels: list[str] | None,
|
|
1463
|
+
icon: str | None = None,
|
|
1457
1464
|
) -> Any:
|
|
1458
1465
|
"""Build and send a config/entity_registry/update WS message."""
|
|
1459
1466
|
update_message: dict[str, Any] = {
|
|
@@ -1464,6 +1471,8 @@ async def _entity_registry_update_coro(
|
|
|
1464
1471
|
update_message["area_id"] = area_id if area_id else None
|
|
1465
1472
|
if labels is not None:
|
|
1466
1473
|
update_message["labels"] = labels
|
|
1474
|
+
if icon is not None:
|
|
1475
|
+
update_message["icon"] = icon if icon else None
|
|
1467
1476
|
return await client.send_websocket_message(update_message)
|
|
1468
1477
|
|
|
1469
1478
|
|
|
@@ -1482,6 +1491,7 @@ def _process_reg_update_result(
|
|
|
1482
1491
|
reg_result: Any,
|
|
1483
1492
|
area_id: str | None,
|
|
1484
1493
|
labels: list[str] | None,
|
|
1494
|
+
icon: str | None,
|
|
1485
1495
|
applied: dict[str, Any],
|
|
1486
1496
|
entity_id: str,
|
|
1487
1497
|
warnings: list[str],
|
|
@@ -1495,9 +1505,21 @@ def _process_reg_update_result(
|
|
|
1495
1505
|
applied["area_id"] = area_id if area_id else None
|
|
1496
1506
|
if labels is not None:
|
|
1497
1507
|
applied["labels"] = labels
|
|
1508
|
+
if icon is not None:
|
|
1509
|
+
applied["icon"] = icon if icon else None
|
|
1498
1510
|
else:
|
|
1511
|
+
# area_id/labels/icon share one WS message, so a rejection of any
|
|
1512
|
+
# one sinks the others. Name the batched fields so the caller can
|
|
1513
|
+
# tell which touchups didn't land instead of guessing.
|
|
1514
|
+
sent_fields = [
|
|
1515
|
+
f
|
|
1516
|
+
for f, v in (("area_id", area_id), ("labels", labels), ("icon", icon))
|
|
1517
|
+
if v is not None
|
|
1518
|
+
]
|
|
1519
|
+
field_note = f" (fields: {', '.join(sent_fields)})" if sent_fields else ""
|
|
1499
1520
|
warnings.append(
|
|
1500
|
-
f"{entity_id}: entity registry update failed:
|
|
1521
|
+
f"{entity_id}: entity registry update failed{field_note}: "
|
|
1522
|
+
f"{_ws_error_msg(reg_result)}"
|
|
1501
1523
|
)
|
|
1502
1524
|
|
|
1503
1525
|
|
|
@@ -1523,9 +1545,10 @@ async def _apply_registry_updates_to_entity(
|
|
|
1523
1545
|
area_id: str | None,
|
|
1524
1546
|
labels: list[str] | None,
|
|
1525
1547
|
category: str | None,
|
|
1548
|
+
icon: str | None,
|
|
1526
1549
|
warnings: list[str],
|
|
1527
1550
|
) -> dict[str, Any]:
|
|
1528
|
-
"""Apply area_id/labels (single WS call) and category (shared helper) to one entity.
|
|
1551
|
+
"""Apply area_id/labels/icon (single WS call) and category (shared helper) to one entity.
|
|
1529
1552
|
|
|
1530
1553
|
Appends human-readable warning strings to `warnings` on any failure.
|
|
1531
1554
|
Returns a small dict summarizing what was applied (for result building).
|
|
@@ -1536,13 +1559,13 @@ async def _apply_registry_updates_to_entity(
|
|
|
1536
1559
|
# `is not None` distinguishes "not provided" from "explicit clear" (empty
|
|
1537
1560
|
# string / empty list). A transient raise on either call is captured via
|
|
1538
1561
|
# return_exceptions so a multi-entity flow helper can still report partial success.
|
|
1539
|
-
needs_registry = area_id is not None or labels is not None
|
|
1562
|
+
needs_registry = area_id is not None or labels is not None or icon is not None
|
|
1540
1563
|
needs_category = bool(category)
|
|
1541
1564
|
if not (needs_registry or needs_category):
|
|
1542
1565
|
return applied
|
|
1543
1566
|
|
|
1544
1567
|
reg_task = (
|
|
1545
|
-
_entity_registry_update_coro(client, entity_id, area_id, labels)
|
|
1568
|
+
_entity_registry_update_coro(client, entity_id, area_id, labels, icon)
|
|
1546
1569
|
if needs_registry
|
|
1547
1570
|
else None
|
|
1548
1571
|
)
|
|
@@ -1557,7 +1580,7 @@ async def _apply_registry_updates_to_entity(
|
|
|
1557
1580
|
cat_result = raw_results.pop(0) if needs_category else None
|
|
1558
1581
|
|
|
1559
1582
|
_process_reg_update_result(
|
|
1560
|
-
reg_result, area_id, labels, applied, entity_id, warnings
|
|
1583
|
+
reg_result, area_id, labels, icon, applied, entity_id, warnings
|
|
1561
1584
|
)
|
|
1562
1585
|
_process_cat_apply_result(cat_result, entity_id, applied, warnings)
|
|
1563
1586
|
return applied
|
|
@@ -1772,31 +1795,45 @@ async def _apply_flow_registry_updates(
|
|
|
1772
1795
|
area_id: str | None,
|
|
1773
1796
|
labels_list: list[str] | None,
|
|
1774
1797
|
category: str | None,
|
|
1798
|
+
icon: str | None,
|
|
1775
1799
|
extras: dict[str, Any],
|
|
1776
1800
|
warnings: list[str],
|
|
1777
1801
|
) -> None:
|
|
1778
|
-
"""Apply area/labels/category to every entity from a flow helper, in parallel."""
|
|
1802
|
+
"""Apply area/labels/category/icon to every entity from a flow helper, in parallel."""
|
|
1779
1803
|
if not (
|
|
1780
1804
|
entity_ids
|
|
1781
|
-
and (
|
|
1805
|
+
and (
|
|
1806
|
+
area_id is not None
|
|
1807
|
+
or labels_list is not None
|
|
1808
|
+
or category is not None
|
|
1809
|
+
or icon is not None
|
|
1810
|
+
)
|
|
1782
1811
|
):
|
|
1783
1812
|
return
|
|
1784
1813
|
applied_per_entity = list(
|
|
1785
1814
|
await asyncio.gather(
|
|
1786
1815
|
*(
|
|
1787
1816
|
_apply_registry_updates_to_entity(
|
|
1788
|
-
client, eid, area_id, labels_list, category, warnings
|
|
1817
|
+
client, eid, area_id, labels_list, category, icon, warnings
|
|
1789
1818
|
)
|
|
1790
1819
|
for eid in entity_ids
|
|
1791
1820
|
)
|
|
1792
1821
|
)
|
|
1793
1822
|
)
|
|
1794
|
-
|
|
1823
|
+
# Echo a top-level convenience key only when it was actually applied to at
|
|
1824
|
+
# least one entity. The per-entity ``applied`` dicts are the source of
|
|
1825
|
+
# truth — a failed entity_registry/update leaves its key out and records a
|
|
1826
|
+
# warning instead — so echoing straight from the inputs would assert
|
|
1827
|
+
# success that the accompanying warnings contradict.
|
|
1828
|
+
applied_keys = {k for entry in applied_per_entity for k in entry}
|
|
1829
|
+
if area_id is not None and "area_id" in applied_keys:
|
|
1795
1830
|
extras["area_id"] = area_id if area_id else None
|
|
1796
|
-
if labels_list is not None:
|
|
1831
|
+
if labels_list is not None and "labels" in applied_keys:
|
|
1797
1832
|
extras["labels"] = labels_list
|
|
1798
|
-
if category:
|
|
1833
|
+
if category and "category" in applied_keys:
|
|
1799
1834
|
extras["category"] = category
|
|
1835
|
+
if icon is not None and "icon" in applied_keys:
|
|
1836
|
+
extras["icon"] = icon if icon else None
|
|
1800
1837
|
extras["applied"] = applied_per_entity
|
|
1801
1838
|
|
|
1802
1839
|
|
|
@@ -1810,16 +1847,17 @@ async def _handle_flow_helper(
|
|
|
1810
1847
|
labels: str | list[str] | None,
|
|
1811
1848
|
category: str | None,
|
|
1812
1849
|
wait: bool,
|
|
1850
|
+
icon: str | None = None,
|
|
1813
1851
|
action: str | None = None,
|
|
1814
1852
|
) -> dict[str, Any]:
|
|
1815
1853
|
"""Create or update a flow-based helper and apply registry updates to all entities.
|
|
1816
1854
|
|
|
1817
1855
|
Routes between create_flow_helper and update_flow_helper based on helper_id,
|
|
1818
1856
|
then resolves the resulting config_entry_id to its entity(ies) and applies
|
|
1819
|
-
area_id / labels / category across the full set.
|
|
1857
|
+
area_id / labels / category / icon across the full set.
|
|
1820
1858
|
|
|
1821
|
-
For utility_meter with tariffs, this means the same label/area is
|
|
1822
|
-
to every tariff sensor (and the select entity) uniformly.
|
|
1859
|
+
For utility_meter with tariffs, this means the same label/area/icon is
|
|
1860
|
+
applied to every tariff sensor (and the select entity) uniformly.
|
|
1823
1861
|
|
|
1824
1862
|
`action` may be passed by the caller (Bug 11 explicit-intent path) — when
|
|
1825
1863
|
None, falls back to the legacy implicit discriminator (presence of
|
|
@@ -1903,7 +1941,7 @@ async def _handle_flow_helper(
|
|
|
1903
1941
|
extras["updated"] = True
|
|
1904
1942
|
|
|
1905
1943
|
await _apply_flow_registry_updates(
|
|
1906
|
-
client, entity_ids, area_id, labels_list, category, extras, warnings
|
|
1944
|
+
client, entity_ids, area_id, labels_list, category, icon, extras, warnings
|
|
1907
1945
|
)
|
|
1908
1946
|
|
|
1909
1947
|
return _helper_response(
|
|
@@ -3886,7 +3924,8 @@ class HelperConfigTools:
|
|
|
3886
3924
|
labels,
|
|
3887
3925
|
category,
|
|
3888
3926
|
wait,
|
|
3889
|
-
|
|
3927
|
+
icon=icon,
|
|
3928
|
+
action=action,
|
|
3890
3929
|
)
|
|
3891
3930
|
_attach_helper_skill(flow_response, MandatoryBPS)
|
|
3892
3931
|
return flow_response
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ha-mcp-dev
|
|
3
|
-
Version: 7.7.0.
|
|
3
|
+
Version: 7.7.0.dev696
|
|
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
|
|
@@ -349,6 +349,8 @@ The proxy split lets MCP clients apply different permission policies per categor
|
|
|
349
349
|
|
|
350
350
|
Leave it off when using Claude Sonnet/Opus or any client with deferred tool loading; the full catalog has no idle cost there and direct calls skip the search step. If you choose to use our toolsearch then you should disable the native Claude Opus/Sonnet toolsearch, which is called deferred tools in the settings.
|
|
351
351
|
|
|
352
|
+
> 🔄 **Refresh your client's tool list after changing this (or any) setting.** Toggling `ENABLE_TOOL_SEARCH` (or changing pinned/disabled tools, Read Only Mode, etc.) changes the tools the server exposes, but your AI client keeps serving its **cached** tool list until it re-fetches. Restarting the add-on or Home Assistant does **not** refresh the client — reconnect or refresh the MCP server in your client (e.g. re-add/refresh the connector in ChatGPT, or close and reopen Claude Desktop). If you skip this, tools shown as available will return `Unknown tool` when called.
|
|
353
|
+
|
|
352
354
|
For the HA add-on, the same option is documented in [`homeassistant-addon/DOCS.md`](homeassistant-addon/DOCS.md#enable_tool_search) along with the in-add-on settings UI for fine-grained tool enable/disable/pin.
|
|
353
355
|
|
|
354
356
|
---
|
|
@@ -68,6 +68,7 @@ src/ha_mcp/tools/enhanced.py
|
|
|
68
68
|
src/ha_mcp/tools/helpers.py
|
|
69
69
|
src/ha_mcp/tools/reference_validator.py
|
|
70
70
|
src/ha_mcp/tools/registry.py
|
|
71
|
+
src/ha_mcp/tools/tool_search_hint_middleware.py
|
|
71
72
|
src/ha_mcp/tools/tools_addons.py
|
|
72
73
|
src/ha_mcp/tools/tools_areas.py
|
|
73
74
|
src/ha_mcp/tools/tools_blueprints.py
|
|
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.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/dashboard_screenshot/__init__.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/dashboard_screenshot/capture.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/dashboard_screenshot/provision.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
|
{ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/resources/skills-vendor/AGENTS.md
RENAMED
|
File without changes
|
{ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/resources/skills-vendor/CLAUDE.md
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/resources/skills-vendor/LICENSE
RENAMED
|
File without changes
|
{ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/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
|
{ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/smart_search/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/smart_search/_config.py
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/smart_search/_entities.py
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/smart_search/_overview.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/smart_search/_scenes.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/smart_search/_scoring.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.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/tools_config_automations.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/tools_config_dashboards.py
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/tools_config_scripts.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/tools_dashboard_screenshot.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
|
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/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.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/tools/validation_middleware.py
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/transforms/categorized_search.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/transforms/lite_docstrings.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp/utils/kill_signal_diagnostics.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/src/ha_mcp_dev.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{ha_mcp_dev-7.7.0.dev694 → ha_mcp_dev-7.7.0.dev696}/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
|