ha-mcp-dev 8.4.3.dev2548__tar.gz → 8.4.3.dev2552__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-8.4.3.dev2548/src/ha_mcp_dev.egg-info → ha_mcp_dev-8.4.3.dev2552}/PKG-INFO +4 -2
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/README.md +3 -1
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/pyproject.toml +1 -1
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/transforms/categorized_search.py +116 -30
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552/src/ha_mcp_dev.egg-info}/PKG-INFO +4 -2
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/LICENSE +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/MANIFEST.in +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/setup.cfg +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/__init__.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/__main__.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_pypi_marker +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_rich_compat.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/__init__.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/requirements.txt +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/LICENSE +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/MANIFEST.sha256 +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/VENDORED +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/__init__.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/__main__.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/asyncio/__init__.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/asyncio/client.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/asyncio/connection.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/asyncio/messages.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/asyncio/router.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/asyncio/server.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/auth.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/cli.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/client.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/connection.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/datastructures.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/exceptions.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/extensions/__init__.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/extensions/base.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/extensions/permessage_deflate.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/frames.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/headers.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/http11.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/imports.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/legacy/__init__.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/legacy/auth.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/legacy/client.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/legacy/exceptions.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/legacy/framing.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/legacy/handshake.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/legacy/http.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/legacy/protocol.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/legacy/server.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/protocol.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/proxy.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/py.typed +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/server.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/streams.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/sync/__init__.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/sync/client.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/sync/connection.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/sync/messages.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/sync/router.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/sync/server.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/sync/utils.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/trio/__init__.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/trio/client.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/trio/connection.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/trio/messages.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/trio/router.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/trio/server.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/trio/utils.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/typing.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/uri.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/utils.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/version.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_version.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/auth/__init__.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/auth/consent_form.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/auth/oidc_compat.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/auth/provider.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/backup_manager.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/browser_landing.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/client/__init__.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/client/rest_client.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/client/supervisor_client.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/client/websocket_client.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/client/websocket_listener.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/config.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/dashboard_screenshot/__init__.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/dashboard_screenshot/capture.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/dashboard_screenshot/content.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/dashboard_screenshot/paths.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/dashboard_screenshot/provision.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/dashboard_screenshot/theme_guard.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/errors.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/hacs_auto_refresh.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/llm_exposure.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/log_filters.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/policy/__init__.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/policy/approval_queue.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/policy/editing.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/policy/evaluator.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/policy/handlers.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/policy/middleware.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/policy/model.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/policy/persistence.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/policy/value_sources.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/py.typed +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/read_only.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/redaction.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/renamed_tools.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/resources/skills-vendor/.claude/settings.json +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/resources/skills-vendor/.claude-plugin/marketplace.json +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/resources/skills-vendor/.claude-plugin/plugin.json +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/resources/skills-vendor/.github/ISSUE_TEMPLATE/skill-rca.md +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/resources/skills-vendor/.github/pull_request_template.md +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/resources/skills-vendor/AGENTS.md +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/resources/skills-vendor/CLAUDE.md +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/resources/skills-vendor/CONTRIBUTING.md +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/resources/skills-vendor/LICENSE +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/resources/skills-vendor/README.md +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/resources/skills-vendor/evals/area-target-over-entity-list/case.yaml +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/resources/skills-vendor/evals/arrive-home-automation/case.yaml +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/resources/skills-vendor/evals/assist-shortcut-card/case.yaml +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/resources/skills-vendor/evals/avg-temperature/case.yaml +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/resources/skills-vendor/evals/backup-deletion-confirmation/case.yaml +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/resources/skills-vendor/evals/blueprint-authoring/case.yaml +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/resources/skills-vendor/evals/button-event-entity/case.yaml +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/resources/skills-vendor/evals/device-id-trigger-migration/case.yaml +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/resources/skills-vendor/evals/helper-flow-fields-not-platform-yaml/case.yaml +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/resources/skills-vendor/evals/media-player-song/case.yaml +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/resources/skills-vendor/evals/motion-light-automation-mode/case.yaml +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/resources/skills-vendor/evals/rename-entity-impact-analysis/case.yaml +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/resources/skills-vendor/evals/template-attributes-yaml-exception/case.yaml +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/resources/skills-vendor/evals/timer-finished-automation/case.yaml +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/resources/skills-vendor/evals/vacuum-last-clean/case.yaml +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/resources/skills-vendor/scripts/check_eval_cases.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/SKILL.md +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/appdaemon.md +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/automation-patterns.md +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/backups.md +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/blueprint-guide.md +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-cards.md +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-guide.md +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/device-control.md +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/domain-docs.md +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/examples.yaml +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/helper-selection.md +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/safe-refactoring.md +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/scenes.md +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/template-guidelines.md +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/yaml-only-integrations.md +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/server.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/settings_ui/__init__.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/settings_ui/_handlers_advanced.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/settings_ui/_handlers_backups.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/settings_ui/_handlers_fs.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/settings_ui/_handlers_server.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/settings_ui/_handlers_theme.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/settings_ui/_handlers_tools.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/settings_ui/_i18n.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/settings_ui/_locale_policy.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/settings_ui/_persistence.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/settings_ui/_supervisor.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/settings_ui/_theme.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/settings_ui/_tools_meta.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/settings_ui/locales/README.md +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/settings_ui/locales/cs.json +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/settings_ui/locales/de.json +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/settings_ui/locales/en.json +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/settings_ui/locales/eo.json +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/settings_ui/locales/es.json +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/settings_ui/locales/fr.json +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/settings_ui/locales/it.json +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/settings_ui/locales/ko.json +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/settings_ui/locales/nl.json +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/settings_ui/locales/pl.json +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/settings_ui/locales/ru.json +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/settings_ui/locales/sv.json +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/settings_ui/locales/tlh.json +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/settings_ui/locales/zh-Hans.json +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/settings_ui/settings.css +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/settings_ui/settings.html +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/settings_ui/settings.js +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/smoke_test.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/stdio_settings_sidecar.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/strict_bps.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/__init__.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/auto_backup.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/backup.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/best_practice_checker.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/best_practice_result.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/best_practice_variables.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/blueprint_sources.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/blueprint_substitute.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/blueprint_write.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/bulk_selector.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/component_api.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/component_config_entries.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/component_config_reads.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/component_devices.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/component_registries.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/component_registry_lookup.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/config_entry_flow.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/config_entry_flow_form.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/config_entry_flow_menu.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/config_entry_flow_walker.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/config_entry_identity.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/config_entry_reconfigure.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/config_entry_reload_watch.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/device_control.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/error_log_parsing.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/hacs_registration.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/helpers.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/integration_reconfigure.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/log_common.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/log_sources.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/log_sources_fault.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/log_sources_supervisor.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/radio/__init__.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/radio/base.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/radio/matter.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/radio/thread.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/radio/zigbee.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/radio/zwave.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/reference_validator.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/registry.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/renamed_tool_middleware.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/smart_search/__init__.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/smart_search/_base.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/smart_search/_config.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/smart_search/_deep.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/smart_search/_entities.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/smart_search/_fetch.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/smart_search/_graph.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/smart_search/_overview.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/smart_search/_scenes.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/smart_search/_scoring.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/tool_search_hint_middleware.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/tools_addons.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/tools_areas.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/tools_assist_pipeline.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/tools_blueprints.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/tools_bug_report.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/tools_calendar.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/tools_camera.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/tools_categories.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/tools_code.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/tools_config_automations.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/tools_config_dashboards.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/tools_config_helpers.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/tools_config_scenes.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/tools_config_scripts.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/tools_dashboard_screenshot.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/tools_dev.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/tools_energy.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/tools_entities.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/tools_filesystem.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/tools_groups.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/tools_hacs.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/tools_history.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/tools_integrations.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/tools_labels.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/tools_logs.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/tools_radio.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/tools_registry.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/tools_resources.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/tools_search.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/tools_security_policy.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/tools_service.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/tools_services.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/tools_system.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/tools_themes.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/tools_todo.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/tools_traces.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/tools_updates.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/tools_utility.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/tools_voice_assistant.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/tools_yaml_config.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/tools_yaml_read.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/tools_zones.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/util_helpers.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/tools/validation_middleware.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/transforms/__init__.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/transforms/lite_docstrings.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/transport_security.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/update_check.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/utils/__init__.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/utils/config_hash.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/utils/config_write_lock.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/utils/data_paths.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/utils/device_registry_semantics.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/utils/domain_handlers.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/utils/entity_membership.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/utils/fuzzy_search.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/utils/kill_signal_diagnostics.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/utils/operation_manager.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/utils/python_sandbox.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/utils/skill_loader.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/utils/usage_logger.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/visibility/__init__.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/visibility/enforcement.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/visibility/model.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/visibility/persistence.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/visibility/resolver.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp_dev.egg-info/SOURCES.txt +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp_dev.egg-info/dependency_links.txt +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp_dev.egg-info/entry_points.txt +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp_dev.egg-info/requires.txt +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp_dev.egg-info/top_level.txt +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/tests/__init__.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/tests/test_constants.py +0 -0
- {ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/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: 8.4.3.
|
|
3
|
+
Version: 8.4.3.dev2552
|
|
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
|
|
@@ -380,6 +380,8 @@ Set ENABLE_TOOL_SEARCH=true (or toggle the option in the HA app). The full catal
|
|
|
380
380
|
|
|
381
381
|
The proxy split lets MCP clients apply different permission policies per category (e.g. auto-approve reads, prompt for writes, confirm deletes) without parsing tool docstrings.
|
|
382
382
|
|
|
383
|
+
A `ha_manage_*` tool combines several operations, so it is reachable from more than one proxy: `ha_call_write_tool` and `ha_call_delete_tool` run the whole tool, while `ha_call_read_tool` runs only the read actions Read Only Mode approves (the same per-call verdict), so a manage tool with no approved read actions is not reachable there. Search results list each proxy the tool can be reached through. In Read Only Mode only `ha_call_read_tool` is listed; the other two still answer a client that holds them in a cached tool list, and any write they carry gets the Read Only Mode error rather than `Unknown tool`.
|
|
384
|
+
|
|
383
385
|
| Setting | Default | Description |
|
|
384
386
|
|---------|---------|-------------|
|
|
385
387
|
| `ENABLE_TOOL_SEARCH` | `false` | Replace full tool catalog with search-based discovery (tools deferred behind on-demand search). |
|
|
@@ -394,7 +396,7 @@ The proxy split lets MCP clients apply different permission policies per categor
|
|
|
394
396
|
|
|
395
397
|
Leave it off in clients with deferred tool loading (claude.ai, Claude Desktop, Claude Code); the full catalog has no idle cost there, direct calls skip the search step, and the client's built-in tool search is the better choice — there is no benefit to running ha-mcp's on top of it. Whether tools are deferred depends on the client and model combination: the same model can behave differently per client — GitHub Copilot CLI running Claude Sonnet/Opus inlines the full catalog and still benefits from tool search here. Some Codex models and ChatGPT include deferred tools too — check your client/model directly to confirm its features so you don't leave this enabled unnecessarily.
|
|
396
398
|
|
|
397
|
-
> 🔄 **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 app 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, newly enabled tools won't appear in the client at all, and tools the server no longer exposes still show as available but
|
|
399
|
+
> 🔄 **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 app 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, newly enabled tools won't appear in the client at all, and tools the server no longer exposes still show as available but fail when called (`Unknown tool`, or the Read Only Mode error for a write tool that mode hides). ChatGPT sometimes keeps serving the stale list even after the connector is removed and re-added under the same name — if tools are still missing after re-adding, delete the connector and create a new one with a **different name**.
|
|
398
400
|
|
|
399
401
|
For the HA app, the same option is documented in [`homeassistant-addon/DOCS.md`](homeassistant-addon/DOCS.md#enable_tool_search) along with the in-app settings UI for fine-grained tool enable/disable/pin.
|
|
400
402
|
|
|
@@ -348,6 +348,8 @@ Set ENABLE_TOOL_SEARCH=true (or toggle the option in the HA app). The full catal
|
|
|
348
348
|
|
|
349
349
|
The proxy split lets MCP clients apply different permission policies per category (e.g. auto-approve reads, prompt for writes, confirm deletes) without parsing tool docstrings.
|
|
350
350
|
|
|
351
|
+
A `ha_manage_*` tool combines several operations, so it is reachable from more than one proxy: `ha_call_write_tool` and `ha_call_delete_tool` run the whole tool, while `ha_call_read_tool` runs only the read actions Read Only Mode approves (the same per-call verdict), so a manage tool with no approved read actions is not reachable there. Search results list each proxy the tool can be reached through. In Read Only Mode only `ha_call_read_tool` is listed; the other two still answer a client that holds them in a cached tool list, and any write they carry gets the Read Only Mode error rather than `Unknown tool`.
|
|
352
|
+
|
|
351
353
|
| Setting | Default | Description |
|
|
352
354
|
|---------|---------|-------------|
|
|
353
355
|
| `ENABLE_TOOL_SEARCH` | `false` | Replace full tool catalog with search-based discovery (tools deferred behind on-demand search). |
|
|
@@ -362,7 +364,7 @@ The proxy split lets MCP clients apply different permission policies per categor
|
|
|
362
364
|
|
|
363
365
|
Leave it off in clients with deferred tool loading (claude.ai, Claude Desktop, Claude Code); the full catalog has no idle cost there, direct calls skip the search step, and the client's built-in tool search is the better choice — there is no benefit to running ha-mcp's on top of it. Whether tools are deferred depends on the client and model combination: the same model can behave differently per client — GitHub Copilot CLI running Claude Sonnet/Opus inlines the full catalog and still benefits from tool search here. Some Codex models and ChatGPT include deferred tools too — check your client/model directly to confirm its features so you don't leave this enabled unnecessarily.
|
|
364
366
|
|
|
365
|
-
> 🔄 **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 app 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, newly enabled tools won't appear in the client at all, and tools the server no longer exposes still show as available but
|
|
367
|
+
> 🔄 **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 app 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, newly enabled tools won't appear in the client at all, and tools the server no longer exposes still show as available but fail when called (`Unknown tool`, or the Read Only Mode error for a write tool that mode hides). ChatGPT sometimes keeps serving the stale list even after the connector is removed and re-added under the same name — if tools are still missing after re-adding, delete the connector and create a new one with a **different name**.
|
|
366
368
|
|
|
367
369
|
For the HA app, the same option is documented in [`homeassistant-addon/DOCS.md`](homeassistant-addon/DOCS.md#enable_tool_search) along with the in-app settings UI for fine-grained tool enable/disable/pin.
|
|
368
370
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "ha-mcp-dev"
|
|
7
|
-
version = "8.4.3.
|
|
7
|
+
version = "8.4.3.dev2552"
|
|
8
8
|
description = "Home Assistant MCP Server - Complete control of Home Assistant through MCP"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
# Upper bound widened to <3.15 so the package installs on Home Assistant's
|
{ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/transforms/categorized_search.py
RENAMED
|
@@ -9,6 +9,12 @@ Tools are categorized by their existing MCP annotations:
|
|
|
9
9
|
- readOnlyHint=True → "read" category
|
|
10
10
|
- destructiveHint=True with remove/delete in name → "delete" category
|
|
11
11
|
- destructiveHint=True (other) → "write" category
|
|
12
|
+
|
|
13
|
+
A ``manage`` tool combines several operations behind one name, so it is
|
|
14
|
+
reachable from every proxy — read-approved calls only on the read proxy,
|
|
15
|
+
the whole tool on the write and delete proxies (see ``_admits``) — and
|
|
16
|
+
search results point each kind of action at its own proxy. In Read Only
|
|
17
|
+
Mode only the read proxy is listed.
|
|
12
18
|
"""
|
|
13
19
|
|
|
14
20
|
from __future__ import annotations
|
|
@@ -85,6 +91,12 @@ DEFAULT_PINNED_TOOLS: tuple[str, ...] = (
|
|
|
85
91
|
# Tool name patterns that indicate delete/remove operations
|
|
86
92
|
_DELETE_PATTERNS = ("_remove_", "_delete_")
|
|
87
93
|
|
|
94
|
+
# ``manage`` names one interface that intentionally combines several
|
|
95
|
+
# operations (.gemini/styleguide.md, Tool Naming Convention). Such a tool is
|
|
96
|
+
# categorised by its annotations like any other, but every call proxy can
|
|
97
|
+
# reach it — see ``_admits``.
|
|
98
|
+
_MANAGE_PATTERNS = ("_manage_",)
|
|
99
|
+
|
|
88
100
|
# Capability tier a tool falls into — shared by the call-proxy routing and
|
|
89
101
|
# the settings-UI capability badges. See ``categorize_capability``.
|
|
90
102
|
Capability = Literal["read", "write", "delete"]
|
|
@@ -192,22 +204,26 @@ def categorize_capability(
|
|
|
192
204
|
return "write"
|
|
193
205
|
|
|
194
206
|
|
|
207
|
+
def _is_manage_tool(name: str) -> bool:
|
|
208
|
+
"""Whether *name* follows the ``manage`` convention for a multi-operation tool."""
|
|
209
|
+
return any(pattern in name for pattern in _MANAGE_PATTERNS)
|
|
210
|
+
|
|
211
|
+
|
|
195
212
|
def _is_read_call_on_write_tool(name: str, arguments: dict[str, Any] | None) -> bool:
|
|
196
213
|
"""Whether this call on a non-read-category tool is one of its read actions.
|
|
197
214
|
|
|
198
215
|
A mixed read/write tool (``ha_manage_backup``, ``ha_manage_updates``,
|
|
199
|
-
``ha_manage_blueprints``, ...) is categorised ``write`` by its annotations
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
proxy
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
that changes state is still refused here.
|
|
216
|
+
``ha_manage_blueprints``, ...) is categorised ``write`` by its annotations
|
|
217
|
+
and lives in that category set only. But refusing its list/get actions on
|
|
218
|
+
the read proxy would strip real read surface from a client that only holds
|
|
219
|
+
that proxy — for blueprints, folding the old read tool into the merged one
|
|
220
|
+
would otherwise have removed listing entirely (#2329).
|
|
221
|
+
|
|
222
|
+
Read-only mode already enumerates, per call, which invocations of such a
|
|
223
|
+
tool are reads (``READ_ONLY_EXEMPT_TOOLS``), and the proxies reuse that
|
|
224
|
+
verdict so the two surfaces cannot disagree about what counts as a read.
|
|
225
|
+
The verdict fails closed: a tool without an exemption entry, or a missing
|
|
226
|
+
or unknown action, is never a read.
|
|
211
227
|
"""
|
|
212
228
|
from ..read_only import READ_ONLY_EXEMPT_TOOLS
|
|
213
229
|
|
|
@@ -215,6 +231,74 @@ def _is_read_call_on_write_tool(name: str, arguments: dict[str, Any] | None) ->
|
|
|
215
231
|
return exemption is not None and exemption.blocked_write(arguments or {}) is None
|
|
216
232
|
|
|
217
233
|
|
|
234
|
+
def _has_read_actions(name: str) -> bool:
|
|
235
|
+
"""Whether a write-category tool has read actions the read proxy can approve."""
|
|
236
|
+
from ..read_only import READ_ONLY_EXEMPT_TOOLS
|
|
237
|
+
|
|
238
|
+
return name in READ_ONLY_EXEMPT_TOOLS
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
def _admits(
|
|
242
|
+
transform: CategorizedSearchTransform,
|
|
243
|
+
category: Capability,
|
|
244
|
+
name: str,
|
|
245
|
+
arguments: dict[str, Any] | None,
|
|
246
|
+
) -> bool:
|
|
247
|
+
"""Whether the *category* proxy may dispatch this call.
|
|
248
|
+
|
|
249
|
+
Membership in the category set is the rule. A ``manage`` tool (#2358) is
|
|
250
|
+
the exception: it is reachable from every proxy. The read proxy is the
|
|
251
|
+
one hard boundary — it carries ``readOnlyHint`` — so it admits only a
|
|
252
|
+
call the read-only predicate approves. The write and delete proxies both
|
|
253
|
+
carry ``destructiveHint`` and run the whole tool: its delete actions are
|
|
254
|
+
not statically enumerable (``ha_manage_radio`` and ``ha_manage_updates``
|
|
255
|
+
take a free-form ``action``), so neither proxy pretends to carve them out.
|
|
256
|
+
"""
|
|
257
|
+
if category == "read":
|
|
258
|
+
return name in transform._read_tools or (
|
|
259
|
+
name in transform._write_tools
|
|
260
|
+
and _is_read_call_on_write_tool(name, arguments)
|
|
261
|
+
)
|
|
262
|
+
if category == "write":
|
|
263
|
+
return name in transform._write_tools
|
|
264
|
+
return name in transform._delete_tools or (
|
|
265
|
+
name in transform._write_tools and _is_manage_tool(name)
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
def _execute_via(proxy: str, tool_name: str) -> str:
|
|
270
|
+
"""Render the call form a search result advertises for *tool_name*."""
|
|
271
|
+
return (
|
|
272
|
+
f'client.{proxy}(name="{tool_name}", arguments={{...}}) '
|
|
273
|
+
f'or {proxy}(name="{tool_name}", arguments={{...}})'
|
|
274
|
+
)
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
def _read_only_mode() -> bool:
|
|
278
|
+
"""Whether Read Only Mode is on — consulted per request, like its filter."""
|
|
279
|
+
from ..config import get_global_settings
|
|
280
|
+
|
|
281
|
+
return bool(get_global_settings().read_only_mode)
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
def _advertised_routes(name: str, category: Capability) -> list[Capability]:
|
|
285
|
+
"""Proxies a search result points at for *name*, in listing order.
|
|
286
|
+
|
|
287
|
+
A manage tool lists every proxy it is reachable through (see
|
|
288
|
+
``_admits``); the read route exists only when the read-only predicate can
|
|
289
|
+
approve calls to it. In Read Only Mode the destructive proxies are not
|
|
290
|
+
listed, so only the read route remains. The ``["write", "delete"]`` case
|
|
291
|
+
cannot occur in that mode: ``ReadOnlyToolsTransform`` drops every
|
|
292
|
+
non-exempt write tool from the catalog before the search index is built,
|
|
293
|
+
and every exempt tool has read actions.
|
|
294
|
+
"""
|
|
295
|
+
if category != "write" or not _is_manage_tool(name):
|
|
296
|
+
return [category]
|
|
297
|
+
if _has_read_actions(name):
|
|
298
|
+
return ["read"] if _read_only_mode() else ["read", "write", "delete"]
|
|
299
|
+
return ["write", "delete"]
|
|
300
|
+
|
|
301
|
+
|
|
218
302
|
def _categorize_tool(tool: Tool) -> Capability:
|
|
219
303
|
"""Categorize a Tool as read, write, or delete based on annotations and name."""
|
|
220
304
|
annotations = tool.annotations
|
|
@@ -443,11 +527,15 @@ class CategorizedSearchTransform(BM25SearchTransform):
|
|
|
443
527
|
results = []
|
|
444
528
|
for tool in tools:
|
|
445
529
|
data = tool.to_mcp_tool().model_dump(mode="json", exclude_none=True)
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
530
|
+
routes = _advertised_routes(tool.name, _categorize_tool(tool))
|
|
531
|
+
if len(routes) == 1:
|
|
532
|
+
data["execute_via"] = _execute_via(proxy_map[routes[0]], tool.name)
|
|
533
|
+
else:
|
|
534
|
+
hint = "; ".join(
|
|
535
|
+
f"{route} actions: {_execute_via(proxy_map[route], tool.name)}"
|
|
536
|
+
for route in routes
|
|
537
|
+
)
|
|
538
|
+
data["execute_via"] = hint[:1].upper() + hint[1:]
|
|
451
539
|
results.append(data)
|
|
452
540
|
return results
|
|
453
541
|
|
|
@@ -487,14 +575,6 @@ class CategorizedSearchTransform(BM25SearchTransform):
|
|
|
487
575
|
# needs the action its old signature never carried.
|
|
488
576
|
arguments = adapt_retired_arguments(requested, arguments)
|
|
489
577
|
|
|
490
|
-
# Determine which category set to check
|
|
491
|
-
if category == "read":
|
|
492
|
-
allowed = transform._read_tools
|
|
493
|
-
elif category == "delete":
|
|
494
|
-
allowed = transform._delete_tools
|
|
495
|
-
else:
|
|
496
|
-
allowed = transform._write_tools
|
|
497
|
-
|
|
498
578
|
# Detect and unwrap double-wrapped arguments where the LLM
|
|
499
579
|
# accidentally nested name/arguments inside the arguments param
|
|
500
580
|
# e.g. ha_call_read_tool(name="ha_call_read_tool",
|
|
@@ -540,11 +620,7 @@ class CategorizedSearchTransform(BM25SearchTransform):
|
|
|
540
620
|
_raise_non_object_arguments(nested, proxy_name, inner_name)
|
|
541
621
|
arguments = adapt_retired_arguments(requested_inner, nested or {})
|
|
542
622
|
|
|
543
|
-
|
|
544
|
-
# actions are additionally admitted here (see the helper).
|
|
545
|
-
if name not in allowed and not (
|
|
546
|
-
category == "read" and _is_read_call_on_write_tool(name, arguments)
|
|
547
|
-
):
|
|
623
|
+
if not _admits(transform, category, name, arguments):
|
|
548
624
|
_raise_wrong_category_error(name, transform, proxy_name)
|
|
549
625
|
|
|
550
626
|
return await ctx.fastmcp.call_tool(name, arguments)
|
|
@@ -590,6 +666,16 @@ class CategorizedSearchTransform(BM25SearchTransform):
|
|
|
590
666
|
description=self._proxy_descs["delete"],
|
|
591
667
|
)
|
|
592
668
|
|
|
669
|
+
if _read_only_mode():
|
|
670
|
+
# ReadOnlyToolsTransform runs before this one and never sees the
|
|
671
|
+
# proxies synthesised here; with every write blocked at call time
|
|
672
|
+
# the destructive proxies would only advertise dead ends. They
|
|
673
|
+
# stay resolvable by name so a client holding a stale catalog gets
|
|
674
|
+
# the proxy's own structured answer (ReadOnlyMiddleware blocks a
|
|
675
|
+
# write before the proxy is even resolved) rather than a bare
|
|
676
|
+
# not-found that ToolSearchHintMiddleware declines to explain
|
|
677
|
+
# while tool search is on.
|
|
678
|
+
return [*pinned, search_tool, call_read]
|
|
593
679
|
return [*pinned, search_tool, call_read, call_write, call_delete]
|
|
594
680
|
|
|
595
681
|
async def get_tool(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ha-mcp-dev
|
|
3
|
-
Version: 8.4.3.
|
|
3
|
+
Version: 8.4.3.dev2552
|
|
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
|
|
@@ -380,6 +380,8 @@ Set ENABLE_TOOL_SEARCH=true (or toggle the option in the HA app). The full catal
|
|
|
380
380
|
|
|
381
381
|
The proxy split lets MCP clients apply different permission policies per category (e.g. auto-approve reads, prompt for writes, confirm deletes) without parsing tool docstrings.
|
|
382
382
|
|
|
383
|
+
A `ha_manage_*` tool combines several operations, so it is reachable from more than one proxy: `ha_call_write_tool` and `ha_call_delete_tool` run the whole tool, while `ha_call_read_tool` runs only the read actions Read Only Mode approves (the same per-call verdict), so a manage tool with no approved read actions is not reachable there. Search results list each proxy the tool can be reached through. In Read Only Mode only `ha_call_read_tool` is listed; the other two still answer a client that holds them in a cached tool list, and any write they carry gets the Read Only Mode error rather than `Unknown tool`.
|
|
384
|
+
|
|
383
385
|
| Setting | Default | Description |
|
|
384
386
|
|---------|---------|-------------|
|
|
385
387
|
| `ENABLE_TOOL_SEARCH` | `false` | Replace full tool catalog with search-based discovery (tools deferred behind on-demand search). |
|
|
@@ -394,7 +396,7 @@ The proxy split lets MCP clients apply different permission policies per categor
|
|
|
394
396
|
|
|
395
397
|
Leave it off in clients with deferred tool loading (claude.ai, Claude Desktop, Claude Code); the full catalog has no idle cost there, direct calls skip the search step, and the client's built-in tool search is the better choice — there is no benefit to running ha-mcp's on top of it. Whether tools are deferred depends on the client and model combination: the same model can behave differently per client — GitHub Copilot CLI running Claude Sonnet/Opus inlines the full catalog and still benefits from tool search here. Some Codex models and ChatGPT include deferred tools too — check your client/model directly to confirm its features so you don't leave this enabled unnecessarily.
|
|
396
398
|
|
|
397
|
-
> 🔄 **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 app 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, newly enabled tools won't appear in the client at all, and tools the server no longer exposes still show as available but
|
|
399
|
+
> 🔄 **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 app 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, newly enabled tools won't appear in the client at all, and tools the server no longer exposes still show as available but fail when called (`Unknown tool`, or the Read Only Mode error for a write tool that mode hides). ChatGPT sometimes keeps serving the stale list even after the connector is removed and re-added under the same name — if tools are still missing after re-adding, delete the connector and create a new one with a **different name**.
|
|
398
400
|
|
|
399
401
|
For the HA app, the same option is documented in [`homeassistant-addon/DOCS.md`](homeassistant-addon/DOCS.md#enable_tool_search) along with the in-app settings UI for fine-grained tool enable/disable/pin.
|
|
400
402
|
|
|
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-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/MANIFEST.sha256
RENAMED
|
File without changes
|
{ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/VENDORED
RENAMED
|
File without changes
|
{ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/__init__.py
RENAMED
|
File without changes
|
{ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/__main__.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-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/client.py
RENAMED
|
File without changes
|
{ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/connection.py
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/exceptions.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/frames.py
RENAMED
|
File without changes
|
{ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/headers.py
RENAMED
|
File without changes
|
{ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/http11.py
RENAMED
|
File without changes
|
{ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/imports.py
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/legacy/auth.py
RENAMED
|
File without changes
|
{ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/legacy/client.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/legacy/http.py
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/legacy/server.py
RENAMED
|
File without changes
|
{ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/protocol.py
RENAMED
|
File without changes
|
{ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/proxy.py
RENAMED
|
File without changes
|
{ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/py.typed
RENAMED
|
File without changes
|
{ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/server.py
RENAMED
|
File without changes
|
{ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/streams.py
RENAMED
|
File without changes
|
{ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/sync/__init__.py
RENAMED
|
File without changes
|
{ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/sync/client.py
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/sync/messages.py
RENAMED
|
File without changes
|
{ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/sync/router.py
RENAMED
|
File without changes
|
{ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/sync/server.py
RENAMED
|
File without changes
|
{ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/sync/utils.py
RENAMED
|
File without changes
|
{ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/trio/__init__.py
RENAMED
|
File without changes
|
{ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/trio/client.py
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/trio/messages.py
RENAMED
|
File without changes
|
{ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/trio/router.py
RENAMED
|
File without changes
|
{ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/trio/server.py
RENAMED
|
File without changes
|
{ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/trio/utils.py
RENAMED
|
File without changes
|
{ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/typing.py
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/utils.py
RENAMED
|
File without changes
|
{ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/_vendor/websockets/version.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
|
{ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/client/supervisor_client.py
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/client/websocket_listener.py
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/dashboard_screenshot/__init__.py
RENAMED
|
File without changes
|
{ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/dashboard_screenshot/capture.py
RENAMED
|
File without changes
|
{ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/dashboard_screenshot/content.py
RENAMED
|
File without changes
|
{ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/dashboard_screenshot/paths.py
RENAMED
|
File without changes
|
{ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/dashboard_screenshot/provision.py
RENAMED
|
File without changes
|
{ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/dashboard_screenshot/theme_guard.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
|
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/resources/skills-vendor/AGENTS.md
RENAMED
|
File without changes
|
{ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/resources/skills-vendor/CLAUDE.md
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/resources/skills-vendor/LICENSE
RENAMED
|
File without changes
|
{ha_mcp_dev-8.4.3.dev2548 → ha_mcp_dev-8.4.3.dev2552}/src/ha_mcp/resources/skills-vendor/README.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|