ha-mcp-dev 7.12.3.dev1940__tar.gz → 7.12.3.dev1942__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.12.3.dev1940/src/ha_mcp_dev.egg-info → ha_mcp_dev-7.12.3.dev1942}/PKG-INFO +4 -4
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/README.md +3 -3
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/pyproject.toml +1 -1
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/server.py +11 -11
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_config_helpers.py +112 -8
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_groups.py +42 -10
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_resources.py +30 -5
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942/src/ha_mcp_dev.egg-info}/PKG-INFO +4 -4
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/LICENSE +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/MANIFEST.in +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/setup.cfg +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/__init__.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/__main__.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/_pypi_marker +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/_version.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/auth/__init__.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/auth/consent_form.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/auth/provider.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/backup_manager.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/browser_landing.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/client/__init__.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/client/rest_client.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/client/supervisor_client.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/client/websocket_client.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/client/websocket_listener.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/config.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/dashboard_screenshot/__init__.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/dashboard_screenshot/capture.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/dashboard_screenshot/content.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/dashboard_screenshot/paths.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/dashboard_screenshot/provision.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/errors.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/llm_exposure.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/policy/__init__.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/policy/approval_queue.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/policy/evaluator.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/policy/handlers.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/policy/middleware.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/policy/model.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/policy/persistence.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/policy/value_sources.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/py.typed +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/read_only.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/resources/skills-vendor/.claude/settings.json +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/resources/skills-vendor/.claude-plugin/marketplace.json +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/resources/skills-vendor/.claude-plugin/plugin.json +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/resources/skills-vendor/.github/ISSUE_TEMPLATE/skill-rca.md +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/resources/skills-vendor/.github/pull_request_template.md +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/resources/skills-vendor/AGENTS.md +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/resources/skills-vendor/CLAUDE.md +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/resources/skills-vendor/CONTRIBUTING.md +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/resources/skills-vendor/LICENSE +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/resources/skills-vendor/README.md +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/SKILL.md +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/evals/evals.json +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/appdaemon.md +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/automation-patterns.md +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/blueprint-guide.md +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-cards.md +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-guide.md +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/device-control.md +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/domain-docs.md +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/examples.yaml +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/helper-selection.md +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/safe-refactoring.md +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/scenes.md +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/template-guidelines.md +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/yaml-only-integrations.md +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/settings_ui/__init__.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/settings_ui/_handlers_advanced.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/settings_ui/_handlers_backups.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/settings_ui/_handlers_fs.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/settings_ui/_handlers_server.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/settings_ui/_handlers_theme.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/settings_ui/_handlers_tools.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/settings_ui/_persistence.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/settings_ui/_supervisor.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/settings_ui/_theme.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/settings_ui/_tools_meta.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/settings_ui/settings.css +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/settings_ui/settings.html +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/settings_ui/settings.js +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/smoke_test.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/stdio_settings_sidecar.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/strict_bps.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/__init__.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/auto_backup.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/backup.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/best_practice_checker.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/component_api.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/config_entry_flow.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/device_control.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/enhanced.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/helpers.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/radio/__init__.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/radio/base.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/radio/matter.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/radio/thread.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/radio/zigbee.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/radio/zwave.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/reference_validator.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/registry.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/smart_search/__init__.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/smart_search/_base.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/smart_search/_config.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/smart_search/_deep.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/smart_search/_entities.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/smart_search/_fetch.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/smart_search/_overview.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/smart_search/_scenes.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/smart_search/_scoring.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tool_search_hint_middleware.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_addons.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_areas.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_blueprints.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_bug_report.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_calendar.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_camera.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_categories.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_code.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_config_automations.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_config_dashboards.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_config_scenes.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_config_scripts.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_dashboard_screenshot.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_dev.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_energy.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_entities.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_filesystem.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_hacs.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_history.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_integrations.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_labels.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_radio.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_registry.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_search.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_service.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_services.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_system.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_themes.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_todo.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_traces.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_updates.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_utility.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_voice_assistant.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_yaml_config.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_yaml_read.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_zones.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/util_helpers.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/validation_middleware.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/transforms/__init__.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/transforms/categorized_search.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/transforms/lite_docstrings.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/transport_security.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/update_check.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/utils/__init__.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/utils/config_hash.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/utils/data_paths.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/utils/domain_handlers.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/utils/fuzzy_search.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/utils/kill_signal_diagnostics.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/utils/operation_manager.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/utils/python_sandbox.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/utils/skill_loader.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/utils/usage_logger.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/visibility/__init__.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/visibility/model.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/visibility/persistence.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/visibility/resolver.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp_dev.egg-info/SOURCES.txt +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp_dev.egg-info/dependency_links.txt +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp_dev.egg-info/entry_points.txt +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp_dev.egg-info/requires.txt +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp_dev.egg-info/top_level.txt +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/tests/__init__.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/tests/test_constants.py +0 -0
- {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/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.12.3.
|
|
3
|
+
Version: 7.12.3.dev1942
|
|
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
|
|
@@ -41,7 +41,7 @@ Dynamic: license-file
|
|
|
41
41
|
<!-- mcp-name: io.github.homeassistant-ai/ha-mcp -->
|
|
42
42
|
|
|
43
43
|
<p align="center">
|
|
44
|
-
<img src="https://img.shields.io/badge/tools-
|
|
44
|
+
<img src="https://img.shields.io/badge/tools-87-blue" alt="95+ Tools">
|
|
45
45
|
<a href="https://github.com/homeassistant-ai/ha-mcp/releases"><img src="https://img.shields.io/github/v/release/homeassistant-ai/ha-mcp" alt="Release"></a>
|
|
46
46
|
<a href="https://github.com/homeassistant-ai/ha-mcp/actions/workflows/e2e-tests.yml"><img src="https://img.shields.io/github/actions/workflow/status/homeassistant-ai/ha-mcp/e2e-tests.yml?branch=master&label=E2E%20Tests" alt="E2E Tests"></a>
|
|
47
47
|
<a href="LICENSE.md"><img src="https://img.shields.io/github/license/homeassistant-ai/ha-mcp.svg" alt="License"></a>
|
|
@@ -247,7 +247,7 @@ Spend less time configuring, more time enjoying your smart home.
|
|
|
247
247
|
<details>
|
|
248
248
|
<!-- TOOLS_TABLE_START -->
|
|
249
249
|
|
|
250
|
-
<summary><b>Complete Tool List (
|
|
250
|
+
<summary><b>Complete Tool List (87 tools)</b></summary>
|
|
251
251
|
|
|
252
252
|
| Category | Tools |
|
|
253
253
|
|----------|-------|
|
|
@@ -278,7 +278,7 @@ Spend less time configuring, more time enjoying your smart home.
|
|
|
278
278
|
| **Service & Device Control** | `ha_bulk_control`, `ha_call_event`, `ha_call_service`, `ha_get_operation_status`, `ha_list_services` |
|
|
279
279
|
| **System** | `ha_config_get_yaml` *(beta)*, `ha_config_set_yaml` *(beta)*, `ha_manage_backup`, `ha_manage_custom_tool` *(beta)*, `ha_manage_theme`, `ha_manage_updates`, `ha_reload_core`, `ha_restart` |
|
|
280
280
|
| **Todo Lists** | `ha_get_todo`, `ha_remove_todo_item`, `ha_set_todo_item` |
|
|
281
|
-
| **Utilities** | `ha_eval_template`, `
|
|
281
|
+
| **Utilities** | `ha_eval_template`, `ha_report_issue` |
|
|
282
282
|
| **Zones** | `ha_get_zone`, `ha_remove_zone`, `ha_set_zone` |
|
|
283
283
|
|
|
284
284
|
<!-- TOOLS_TABLE_END -->
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
<!-- mcp-name: io.github.homeassistant-ai/ha-mcp -->
|
|
9
9
|
|
|
10
10
|
<p align="center">
|
|
11
|
-
<img src="https://img.shields.io/badge/tools-
|
|
11
|
+
<img src="https://img.shields.io/badge/tools-87-blue" alt="95+ Tools">
|
|
12
12
|
<a href="https://github.com/homeassistant-ai/ha-mcp/releases"><img src="https://img.shields.io/github/v/release/homeassistant-ai/ha-mcp" alt="Release"></a>
|
|
13
13
|
<a href="https://github.com/homeassistant-ai/ha-mcp/actions/workflows/e2e-tests.yml"><img src="https://img.shields.io/github/actions/workflow/status/homeassistant-ai/ha-mcp/e2e-tests.yml?branch=master&label=E2E%20Tests" alt="E2E Tests"></a>
|
|
14
14
|
<a href="LICENSE.md"><img src="https://img.shields.io/github/license/homeassistant-ai/ha-mcp.svg" alt="License"></a>
|
|
@@ -214,7 +214,7 @@ Spend less time configuring, more time enjoying your smart home.
|
|
|
214
214
|
<details>
|
|
215
215
|
<!-- TOOLS_TABLE_START -->
|
|
216
216
|
|
|
217
|
-
<summary><b>Complete Tool List (
|
|
217
|
+
<summary><b>Complete Tool List (87 tools)</b></summary>
|
|
218
218
|
|
|
219
219
|
| Category | Tools |
|
|
220
220
|
|----------|-------|
|
|
@@ -245,7 +245,7 @@ Spend less time configuring, more time enjoying your smart home.
|
|
|
245
245
|
| **Service & Device Control** | `ha_bulk_control`, `ha_call_event`, `ha_call_service`, `ha_get_operation_status`, `ha_list_services` |
|
|
246
246
|
| **System** | `ha_config_get_yaml` *(beta)*, `ha_config_set_yaml` *(beta)*, `ha_manage_backup`, `ha_manage_custom_tool` *(beta)*, `ha_manage_theme`, `ha_manage_updates`, `ha_reload_core`, `ha_restart` |
|
|
247
247
|
| **Todo Lists** | `ha_get_todo`, `ha_remove_todo_item`, `ha_set_todo_item` |
|
|
248
|
-
| **Utilities** | `ha_eval_template`, `
|
|
248
|
+
| **Utilities** | `ha_eval_template`, `ha_report_issue` |
|
|
249
249
|
| **Zones** | `ha_get_zone`, `ha_remove_zone`, `ha_set_zone` |
|
|
250
250
|
|
|
251
251
|
<!-- TOOLS_TABLE_END -->
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "ha-mcp-dev"
|
|
7
|
-
version = "7.12.3.
|
|
7
|
+
version = "7.12.3.dev1942"
|
|
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
|
|
@@ -632,9 +632,8 @@ class HomeAssistantSmartMCPServer(EnhancedToolsMixin):
|
|
|
632
632
|
"Create or update a Home Assistant script.\n\n"
|
|
633
633
|
"Supports two modes: full `config` replacement, or surgical "
|
|
634
634
|
"`python_transform` on an existing script (requires "
|
|
635
|
-
"`
|
|
636
|
-
"
|
|
637
|
-
"script.\n\n"
|
|
635
|
+
"`config_hash` from ha_config_get_script). `script_id` names "
|
|
636
|
+
"the script in both modes.\n\n"
|
|
638
637
|
"For schema details and examples, see "
|
|
639
638
|
"ha_get_skill_guide."
|
|
640
639
|
),
|
|
@@ -650,19 +649,20 @@ class HomeAssistantSmartMCPServer(EnhancedToolsMixin):
|
|
|
650
649
|
"Create or update a Home Assistant scene.\n\n"
|
|
651
650
|
"Supports two modes: full `config` replacement, or surgical "
|
|
652
651
|
"`python_transform` on an existing scene (requires "
|
|
653
|
-
"`
|
|
652
|
+
"`config_hash`). `scene_id` names the scene in both modes.\n\n"
|
|
654
653
|
"For schema details and examples, see "
|
|
655
654
|
"ha_get_skill_guide."
|
|
656
655
|
),
|
|
657
656
|
"ha_config_list_helpers": (
|
|
658
|
-
"List Home Assistant helpers of a given
|
|
659
|
-
"
|
|
660
|
-
"
|
|
657
|
+
"List Home Assistant helpers of a given type, one page per "
|
|
658
|
+
"call (`limit`/`offset`; `total_count` and `has_more` "
|
|
659
|
+
"describe the full set). The 12 storage-backed types "
|
|
660
|
+
"(input_button, input_boolean, input_select, input_number, "
|
|
661
661
|
"input_text, input_datetime, counter, timer, schedule, "
|
|
662
|
-
"zone, person, tag. Flow-based
|
|
663
|
-
"
|
|
664
|
-
"
|
|
665
|
-
"
|
|
662
|
+
"zone, person, tag) are listed on every install. Flow-based "
|
|
663
|
+
"types (template, group, utility_meter, derivative, and the "
|
|
664
|
+
"rest) and `helper_type='all'` are served only through the "
|
|
665
|
+
"ha_mcp_tools custom component.\n\n"
|
|
666
666
|
"For per-type schemas and decision guidance, see "
|
|
667
667
|
"ha_get_skill_guide."
|
|
668
668
|
),
|
{ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_config_helpers.py
RENAMED
|
@@ -53,6 +53,7 @@ from .util_helpers import (
|
|
|
53
53
|
attach_skill_content,
|
|
54
54
|
augment_error_dict_with_skill_content,
|
|
55
55
|
augment_tool_error_with_skill_content,
|
|
56
|
+
build_pagination_metadata,
|
|
56
57
|
parse_json_param,
|
|
57
58
|
parse_string_list_param,
|
|
58
59
|
wait_for_entity_registered,
|
|
@@ -1356,21 +1357,36 @@ def _flatten_helper_list_result(result: Any) -> list[Any]:
|
|
|
1356
1357
|
"""Flatten a {type}/list WS response into a flat list of helper dicts.
|
|
1357
1358
|
|
|
1358
1359
|
Handles the person/list shape ({"storage": [...], "config": [...]}) and
|
|
1359
|
-
the standard list shape ([...]).
|
|
1360
|
+
the standard list shape ([...]). An unrecognised shape yields an empty
|
|
1361
|
+
list, which downstream is indistinguishable from a helper type that has no
|
|
1362
|
+
entries, so it is logged rather than dropped in silence.
|
|
1360
1363
|
"""
|
|
1361
1364
|
if isinstance(result, dict):
|
|
1362
1365
|
inner = result.get("result", [])
|
|
1363
1366
|
if isinstance(inner, dict):
|
|
1364
1367
|
items: list[Any] = []
|
|
1368
|
+
matched = False
|
|
1365
1369
|
for key in ("storage", "config"):
|
|
1366
1370
|
sub = inner.get(key)
|
|
1367
1371
|
if isinstance(sub, list):
|
|
1372
|
+
matched = True
|
|
1368
1373
|
items.extend(sub)
|
|
1374
|
+
if not matched:
|
|
1375
|
+
logger.warning(
|
|
1376
|
+
"Helper listing has neither a 'storage' nor a 'config' list "
|
|
1377
|
+
"(keys: %s); treating it as empty",
|
|
1378
|
+
sorted(inner),
|
|
1379
|
+
)
|
|
1369
1380
|
return items
|
|
1370
1381
|
if isinstance(inner, list):
|
|
1371
1382
|
return inner
|
|
1372
1383
|
if isinstance(result, list):
|
|
1373
1384
|
return result
|
|
1385
|
+
logger.warning(
|
|
1386
|
+
"Cannot flatten a helper listing: expected a list or a storage/config "
|
|
1387
|
+
"split, got %s; treating it as empty",
|
|
1388
|
+
type(result).__name__,
|
|
1389
|
+
)
|
|
1374
1390
|
return []
|
|
1375
1391
|
|
|
1376
1392
|
|
|
@@ -3508,6 +3524,53 @@ def _shape_flow_helper_record(rec: dict[str, Any]) -> dict[str, Any]:
|
|
|
3508
3524
|
return out
|
|
3509
3525
|
|
|
3510
3526
|
|
|
3527
|
+
def _paginate_helpers_response(
|
|
3528
|
+
response: dict[str, Any], offset: int, limit: int
|
|
3529
|
+
) -> dict[str, Any]:
|
|
3530
|
+
"""Slice a helper listing envelope down to one page.
|
|
3531
|
+
|
|
3532
|
+
The single normalization point for every ``ha_config_list_helpers`` route
|
|
3533
|
+
(all-types, component, legacy): each builds the same
|
|
3534
|
+
``success``/``helper_type``/``count``/``helpers``/``message`` envelope, so
|
|
3535
|
+
the slice is applied once here instead of in each builder. ``count`` becomes
|
|
3536
|
+
the page size and ``total_count`` carries the full size, matching
|
|
3537
|
+
``ha_list_services``.
|
|
3538
|
+
"""
|
|
3539
|
+
helpers = response.get("helpers")
|
|
3540
|
+
if not isinstance(helpers, list):
|
|
3541
|
+
# Every builder owes this function a flat list; anything else is a bug in
|
|
3542
|
+
# the caller (a {type}/list shape that escaped _flatten_helper_list_result).
|
|
3543
|
+
# The records are still usable, so return them unpaginated rather than
|
|
3544
|
+
# raising -- but say so in warnings[], not just the log: the caller is an
|
|
3545
|
+
# agent that never sees server logs, and absent metadata otherwise reads
|
|
3546
|
+
# as "the collection fits on one page".
|
|
3547
|
+
shape = type(helpers).__name__
|
|
3548
|
+
logger.warning(
|
|
3549
|
+
"Cannot paginate %r listing: expected a list of helpers, got %s; "
|
|
3550
|
+
"returning the envelope unpaginated",
|
|
3551
|
+
response.get("helper_type"),
|
|
3552
|
+
shape,
|
|
3553
|
+
)
|
|
3554
|
+
warning = (
|
|
3555
|
+
f"Listing could not be paginated (expected a list of helpers, got "
|
|
3556
|
+
f"{shape}); returned in full, without pagination metadata."
|
|
3557
|
+
)
|
|
3558
|
+
existing = response.get("warnings")
|
|
3559
|
+
return {
|
|
3560
|
+
**response,
|
|
3561
|
+
"warnings": [*existing, warning]
|
|
3562
|
+
if isinstance(existing, list)
|
|
3563
|
+
else [warning],
|
|
3564
|
+
}
|
|
3565
|
+
total_count = len(helpers)
|
|
3566
|
+
page = helpers[offset : offset + limit]
|
|
3567
|
+
return {
|
|
3568
|
+
**response,
|
|
3569
|
+
"helpers": page,
|
|
3570
|
+
**build_pagination_metadata(total_count, offset, limit, len(page)),
|
|
3571
|
+
}
|
|
3572
|
+
|
|
3573
|
+
|
|
3511
3574
|
def _shape_component_helpers_response(
|
|
3512
3575
|
helper_type: str, result: dict[str, Any]
|
|
3513
3576
|
) -> dict[str, Any]:
|
|
@@ -3643,11 +3706,30 @@ class HelperConfigTools:
|
|
|
3643
3706
|
)
|
|
3644
3707
|
),
|
|
3645
3708
|
],
|
|
3709
|
+
limit: Annotated[
|
|
3710
|
+
int,
|
|
3711
|
+
Field(
|
|
3712
|
+
default=100,
|
|
3713
|
+
ge=1,
|
|
3714
|
+
le=500,
|
|
3715
|
+
description="Max helpers to return per page (default: 100)",
|
|
3716
|
+
),
|
|
3717
|
+
] = 100,
|
|
3718
|
+
offset: Annotated[
|
|
3719
|
+
int,
|
|
3720
|
+
Field(
|
|
3721
|
+
default=0,
|
|
3722
|
+
ge=0,
|
|
3723
|
+
description="Number of helpers to skip for pagination (default: 0)",
|
|
3724
|
+
),
|
|
3725
|
+
] = 0,
|
|
3646
3726
|
) -> dict[str, Any]:
|
|
3647
3727
|
"""
|
|
3648
|
-
List
|
|
3728
|
+
List Home Assistant helpers of a specific type with their configurations.
|
|
3649
3729
|
|
|
3650
|
-
Returns
|
|
3730
|
+
Returns one page of helpers; `total_count` and `has_more` report the full
|
|
3731
|
+
set. Each record carries the complete configuration for its helper,
|
|
3732
|
+
including:
|
|
3651
3733
|
- id (immutable storage key), entity_id (current — address the helper by
|
|
3652
3734
|
this, where available), name (current display name), original_name
|
|
3653
3735
|
(creation-time name), icon
|
|
@@ -3682,8 +3764,12 @@ class HelperConfigTools:
|
|
|
3682
3764
|
- List all persons: ha_config_list_helpers("person")
|
|
3683
3765
|
- List all tags: ha_config_list_helpers("tag")
|
|
3684
3766
|
- List every helper type at once: ha_config_list_helpers("all")
|
|
3767
|
+
- Next page: ha_config_list_helpers("input_boolean", offset=100)
|
|
3685
3768
|
|
|
3686
|
-
**NOTE:**
|
|
3769
|
+
**NOTE:** Storage types list what HA's ``{type}/list`` command returns:
|
|
3770
|
+
the storage-backed helpers (created via UI/API), not the YAML-defined
|
|
3771
|
+
ones. ``person`` is the exception — HA lists its YAML-configured persons
|
|
3772
|
+
alongside the storage ones, so both appear here.
|
|
3687
3773
|
|
|
3688
3774
|
Flow-based types (template / group / utility_meter / derivative / etc.)
|
|
3689
3775
|
require the ha_mcp_tools custom component (>= 1.1.0) and are served only
|
|
@@ -3702,7 +3788,9 @@ class HelperConfigTools:
|
|
|
3702
3788
|
# No legacy equivalent exists (no single WS command enumerates all
|
|
3703
3789
|
# types), so it is component-only — see ``_list_all_helpers``.
|
|
3704
3790
|
if helper_type == "all":
|
|
3705
|
-
return
|
|
3791
|
+
return _paginate_helpers_response(
|
|
3792
|
+
await self._list_all_helpers(), offset, limit
|
|
3793
|
+
)
|
|
3706
3794
|
|
|
3707
3795
|
# Flow-based helper types have no ``{type}/list`` command, so only the
|
|
3708
3796
|
# component's ``helpers_list`` can enumerate them: they are served
|
|
@@ -3723,7 +3811,7 @@ class HelperConfigTools:
|
|
|
3723
3811
|
helper_type, is_flow=is_flow
|
|
3724
3812
|
)
|
|
3725
3813
|
if component_response is not None:
|
|
3726
|
-
return component_response
|
|
3814
|
+
return _paginate_helpers_response(component_response, offset, limit)
|
|
3727
3815
|
if is_flow:
|
|
3728
3816
|
# No usable component path and the legacy body cannot serve flow
|
|
3729
3817
|
# helpers: hard error rather than an empty or misleading list.
|
|
@@ -3751,7 +3839,7 @@ class HelperConfigTools:
|
|
|
3751
3839
|
}
|
|
3752
3840
|
if warnings:
|
|
3753
3841
|
response["warnings"] = warnings
|
|
3754
|
-
return response
|
|
3842
|
+
return _paginate_helpers_response(response, offset, limit)
|
|
3755
3843
|
raise_tool_error(
|
|
3756
3844
|
create_error_response(
|
|
3757
3845
|
ErrorCode.SERVICE_CALL_FAILED,
|
|
@@ -3880,7 +3968,11 @@ class HelperConfigTools:
|
|
|
3880
3968
|
context={"helper_type": helper_type},
|
|
3881
3969
|
)
|
|
3882
3970
|
)
|
|
3883
|
-
|
|
3971
|
+
# Flatten like the inline body: person/list returns {"storage": [...],
|
|
3972
|
+
# "config": [...]} rather than a flat list, so a raw result["result"]
|
|
3973
|
+
# would be a dict here — breaking count, the pagination slice and the
|
|
3974
|
+
# all-types merge, which all expect a list of records.
|
|
3975
|
+
items = _flatten_helper_list_result(result)
|
|
3884
3976
|
return {
|
|
3885
3977
|
"success": True,
|
|
3886
3978
|
"helper_type": helper_type,
|
|
@@ -4005,11 +4097,23 @@ class HelperConfigTools:
|
|
|
4005
4097
|
)
|
|
4006
4098
|
for helper_type in sorted(SIMPLE_HELPER_TYPES - covered_set):
|
|
4007
4099
|
legacy = await self._legacy_helper_list(helper_type)
|
|
4100
|
+
skipped = 0
|
|
4008
4101
|
for item in legacy.get("helpers", []):
|
|
4009
4102
|
if isinstance(item, dict):
|
|
4010
4103
|
row = dict(item)
|
|
4011
4104
|
row.setdefault("helper_type", helper_type)
|
|
4012
4105
|
helpers.append(row)
|
|
4106
|
+
else:
|
|
4107
|
+
skipped += 1
|
|
4108
|
+
if skipped:
|
|
4109
|
+
# This is how the unflattened person/list dict used to vanish:
|
|
4110
|
+
# iterating it yielded its keys, and each failed the check here.
|
|
4111
|
+
logger.warning(
|
|
4112
|
+
"Dropped %d unrecognised item(s) from the %s listing while "
|
|
4113
|
+
"merging all types; the merged listing is incomplete",
|
|
4114
|
+
skipped,
|
|
4115
|
+
helper_type,
|
|
4116
|
+
)
|
|
4013
4117
|
|
|
4014
4118
|
return {
|
|
4015
4119
|
"success": True,
|
|
@@ -27,6 +27,7 @@ from .helpers import (
|
|
|
27
27
|
)
|
|
28
28
|
from .util_helpers import (
|
|
29
29
|
JSON_STRING_COERCION,
|
|
30
|
+
build_pagination_metadata,
|
|
30
31
|
wait_for_entity_registered,
|
|
31
32
|
wait_for_entity_removed,
|
|
32
33
|
)
|
|
@@ -143,12 +144,32 @@ class GroupTools:
|
|
|
143
144
|
},
|
|
144
145
|
)
|
|
145
146
|
@log_tool_usage
|
|
146
|
-
async def ha_config_list_groups(
|
|
147
|
+
async def ha_config_list_groups(
|
|
148
|
+
self,
|
|
149
|
+
limit: Annotated[
|
|
150
|
+
int,
|
|
151
|
+
Field(
|
|
152
|
+
default=100,
|
|
153
|
+
ge=1,
|
|
154
|
+
le=500,
|
|
155
|
+
description="Max groups to return per page (default: 100)",
|
|
156
|
+
),
|
|
157
|
+
] = 100,
|
|
158
|
+
offset: Annotated[
|
|
159
|
+
int,
|
|
160
|
+
Field(
|
|
161
|
+
default=0,
|
|
162
|
+
ge=0,
|
|
163
|
+
description="Number of groups to skip for pagination (default: 0)",
|
|
164
|
+
),
|
|
165
|
+
] = 0,
|
|
166
|
+
) -> dict[str, Any]:
|
|
147
167
|
"""
|
|
148
|
-
List
|
|
168
|
+
List Home Assistant entity groups with their member entities.
|
|
149
169
|
|
|
150
|
-
Returns
|
|
151
|
-
|
|
170
|
+
Returns one page of groups created via group.set service or YAML
|
|
171
|
+
configuration; `total_count` and `has_more` report the full set. Each
|
|
172
|
+
group includes:
|
|
152
173
|
- Entity ID (group.xxx)
|
|
153
174
|
- Friendly name
|
|
154
175
|
- State (on/off based on member states)
|
|
@@ -157,7 +178,8 @@ class GroupTools:
|
|
|
157
178
|
- All mode (if all entities must be on)
|
|
158
179
|
|
|
159
180
|
EXAMPLES:
|
|
160
|
-
-
|
|
181
|
+
- First page of groups: ha_config_list_groups()
|
|
182
|
+
- Next page: ha_config_list_groups(offset=100)
|
|
161
183
|
|
|
162
184
|
**NOTE:** This returns old-style groups (created via group.set or YAML).
|
|
163
185
|
Platform-specific groups (light groups, cover groups) are separate entities.
|
|
@@ -184,16 +206,26 @@ class GroupTools:
|
|
|
184
206
|
}
|
|
185
207
|
)
|
|
186
208
|
|
|
187
|
-
# Sort by friendly name
|
|
209
|
+
# Sort by friendly name, then entity_id: the unique tiebreaker keeps
|
|
210
|
+
# groups with the same name in a stable order, so a page boundary
|
|
211
|
+
# cannot duplicate or skip one when get_states() order shifts.
|
|
188
212
|
groups.sort(
|
|
189
|
-
key=lambda g: (
|
|
213
|
+
key=lambda g: (
|
|
214
|
+
(g.get("friendly_name") or g.get("entity_id", "")).lower(),
|
|
215
|
+
g.get("entity_id", ""),
|
|
216
|
+
)
|
|
190
217
|
)
|
|
191
218
|
|
|
219
|
+
total_count = len(groups)
|
|
220
|
+
paginated_groups = groups[offset : offset + limit]
|
|
221
|
+
|
|
192
222
|
return {
|
|
193
223
|
"success": True,
|
|
194
|
-
"
|
|
195
|
-
|
|
196
|
-
|
|
224
|
+
"groups": paginated_groups,
|
|
225
|
+
**build_pagination_metadata(
|
|
226
|
+
total_count, offset, limit, len(paginated_groups)
|
|
227
|
+
),
|
|
228
|
+
"message": f"Found {total_count} group(s)",
|
|
197
229
|
}
|
|
198
230
|
|
|
199
231
|
except Exception as e:
|
|
@@ -25,6 +25,7 @@ from .helpers import (
|
|
|
25
25
|
register_tool_methods,
|
|
26
26
|
validate_identifier_not_empty,
|
|
27
27
|
)
|
|
28
|
+
from .util_helpers import build_pagination_metadata
|
|
28
29
|
|
|
29
30
|
logger = logging.getLogger(__name__)
|
|
30
31
|
|
|
@@ -162,14 +163,34 @@ class ResourceTools:
|
|
|
162
163
|
"Default False to save tokens (shows 150-char preview instead)."
|
|
163
164
|
),
|
|
164
165
|
] = False,
|
|
166
|
+
limit: Annotated[
|
|
167
|
+
int,
|
|
168
|
+
Field(
|
|
169
|
+
default=100,
|
|
170
|
+
ge=1,
|
|
171
|
+
le=500,
|
|
172
|
+
description="Max resources to return per page (default: 100)",
|
|
173
|
+
),
|
|
174
|
+
] = 100,
|
|
175
|
+
offset: Annotated[
|
|
176
|
+
int,
|
|
177
|
+
Field(
|
|
178
|
+
default=0,
|
|
179
|
+
ge=0,
|
|
180
|
+
description="Number of resources to skip for pagination (default: 0)",
|
|
181
|
+
),
|
|
182
|
+
] = 0,
|
|
165
183
|
) -> dict[str, Any]:
|
|
166
184
|
"""
|
|
167
|
-
List
|
|
185
|
+
List Lovelace dashboard resources (custom cards, themes, CSS/JS).
|
|
168
186
|
|
|
169
|
-
Returns
|
|
187
|
+
Returns one page of registered resources; `total_count` and `has_more`
|
|
188
|
+
report the full set. For inline resources (created with
|
|
170
189
|
ha_config_set_dashboard_resource(content=...)), shows a preview of the content
|
|
171
190
|
instead of the full encoded URL to save tokens.
|
|
172
191
|
|
|
192
|
+
`inline_count` and `by_type` summarise every resource, not just this page.
|
|
193
|
+
|
|
173
194
|
Args:
|
|
174
195
|
include_content: If True, includes full decoded content for inline
|
|
175
196
|
resources in "_content" field. Default False (150-char preview only).
|
|
@@ -182,7 +203,8 @@ class ResourceTools:
|
|
|
182
203
|
Each resource has a unique ID for update/delete operations.
|
|
183
204
|
|
|
184
205
|
EXAMPLES:
|
|
185
|
-
-
|
|
206
|
+
- First page of resources: ha_config_list_dashboard_resources()
|
|
207
|
+
- Next page: ha_config_list_dashboard_resources(offset=100)
|
|
186
208
|
- List with full content: ha_config_list_dashboard_resources(include_content=True)
|
|
187
209
|
|
|
188
210
|
Note: Home Assistant 2026.6+ exposes resource management in the UI by
|
|
@@ -214,11 +236,14 @@ class ResourceTools:
|
|
|
214
236
|
if res.get("_inline"):
|
|
215
237
|
inline_count += 1
|
|
216
238
|
|
|
239
|
+
total_count = len(processed)
|
|
240
|
+
paginated = processed[offset : offset + limit]
|
|
241
|
+
|
|
217
242
|
return {
|
|
218
243
|
"success": True,
|
|
219
244
|
"action": "list",
|
|
220
|
-
"resources":
|
|
221
|
-
|
|
245
|
+
"resources": paginated,
|
|
246
|
+
**build_pagination_metadata(total_count, offset, limit, len(paginated)),
|
|
222
247
|
"inline_count": inline_count,
|
|
223
248
|
"by_type": {
|
|
224
249
|
"module": len(categorized["module"]),
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ha-mcp-dev
|
|
3
|
-
Version: 7.12.3.
|
|
3
|
+
Version: 7.12.3.dev1942
|
|
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
|
|
@@ -41,7 +41,7 @@ Dynamic: license-file
|
|
|
41
41
|
<!-- mcp-name: io.github.homeassistant-ai/ha-mcp -->
|
|
42
42
|
|
|
43
43
|
<p align="center">
|
|
44
|
-
<img src="https://img.shields.io/badge/tools-
|
|
44
|
+
<img src="https://img.shields.io/badge/tools-87-blue" alt="95+ Tools">
|
|
45
45
|
<a href="https://github.com/homeassistant-ai/ha-mcp/releases"><img src="https://img.shields.io/github/v/release/homeassistant-ai/ha-mcp" alt="Release"></a>
|
|
46
46
|
<a href="https://github.com/homeassistant-ai/ha-mcp/actions/workflows/e2e-tests.yml"><img src="https://img.shields.io/github/actions/workflow/status/homeassistant-ai/ha-mcp/e2e-tests.yml?branch=master&label=E2E%20Tests" alt="E2E Tests"></a>
|
|
47
47
|
<a href="LICENSE.md"><img src="https://img.shields.io/github/license/homeassistant-ai/ha-mcp.svg" alt="License"></a>
|
|
@@ -247,7 +247,7 @@ Spend less time configuring, more time enjoying your smart home.
|
|
|
247
247
|
<details>
|
|
248
248
|
<!-- TOOLS_TABLE_START -->
|
|
249
249
|
|
|
250
|
-
<summary><b>Complete Tool List (
|
|
250
|
+
<summary><b>Complete Tool List (87 tools)</b></summary>
|
|
251
251
|
|
|
252
252
|
| Category | Tools |
|
|
253
253
|
|----------|-------|
|
|
@@ -278,7 +278,7 @@ Spend less time configuring, more time enjoying your smart home.
|
|
|
278
278
|
| **Service & Device Control** | `ha_bulk_control`, `ha_call_event`, `ha_call_service`, `ha_get_operation_status`, `ha_list_services` |
|
|
279
279
|
| **System** | `ha_config_get_yaml` *(beta)*, `ha_config_set_yaml` *(beta)*, `ha_manage_backup`, `ha_manage_custom_tool` *(beta)*, `ha_manage_theme`, `ha_manage_updates`, `ha_reload_core`, `ha_restart` |
|
|
280
280
|
| **Todo Lists** | `ha_get_todo`, `ha_remove_todo_item`, `ha_set_todo_item` |
|
|
281
|
-
| **Utilities** | `ha_eval_template`, `
|
|
281
|
+
| **Utilities** | `ha_eval_template`, `ha_report_issue` |
|
|
282
282
|
| **Zones** | `ha_get_zone`, `ha_remove_zone`, `ha_set_zone` |
|
|
283
283
|
|
|
284
284
|
<!-- TOOLS_TABLE_END -->
|
|
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.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/client/supervisor_client.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/client/websocket_client.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/client/websocket_listener.py
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/dashboard_screenshot/__init__.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/dashboard_screenshot/capture.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/dashboard_screenshot/content.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/dashboard_screenshot/paths.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/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
|
|
File without changes
|
{ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/resources/skills-vendor/AGENTS.md
RENAMED
|
File without changes
|
{ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/resources/skills-vendor/CLAUDE.md
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/resources/skills-vendor/LICENSE
RENAMED
|
File without changes
|
{ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/resources/skills-vendor/README.md
RENAMED
|
File without changes
|
|
File without changes
|