ha-mcp-dev 7.7.0.dev696__tar.gz → 7.7.0.dev698__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {ha_mcp_dev-7.7.0.dev696/src/ha_mcp_dev.egg-info → ha_mcp_dev-7.7.0.dev698}/PKG-INFO +1 -1
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/pyproject.toml +1 -1
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/__main__.py +69 -2
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698/src/ha_mcp_dev.egg-info}/PKG-INFO +1 -1
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/LICENSE +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/MANIFEST.in +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/README.md +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/setup.cfg +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/__init__.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/_pypi_marker +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/_version.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/auth/__init__.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/auth/consent_form.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/auth/provider.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/backup_manager.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/client/__init__.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/client/rest_client.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/client/supervisor_client.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/client/websocket_client.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/client/websocket_listener.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/config.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/dashboard_screenshot/__init__.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/dashboard_screenshot/capture.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/dashboard_screenshot/provision.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/errors.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/policy/__init__.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/policy/approval_queue.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/policy/evaluator.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/policy/handlers.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/policy/middleware.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/policy/model.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/policy/persistence.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/policy/value_sources.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/py.typed +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/read_only.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/resources/skills-vendor/.claude/settings.json +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/resources/skills-vendor/.claude-plugin/marketplace.json +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/resources/skills-vendor/.claude-plugin/plugin.json +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/resources/skills-vendor/.github/ISSUE_TEMPLATE/skill-rca.md +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/resources/skills-vendor/.github/pull_request_template.md +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/resources/skills-vendor/AGENTS.md +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/resources/skills-vendor/CLAUDE.md +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/resources/skills-vendor/CONTRIBUTING.md +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/resources/skills-vendor/LICENSE +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/resources/skills-vendor/README.md +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/SKILL.md +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/evals/evals.json +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/automation-patterns.md +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-cards.md +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-guide.md +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/device-control.md +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/domain-docs.md +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/examples.yaml +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/helper-selection.md +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/safe-refactoring.md +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/template-guidelines.md +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/yaml-only-integrations.md +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/server.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/settings.css +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/settings.js +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/settings_ui.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/smoke_test.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/stdio_settings_sidecar.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/__init__.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/auto_backup.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/backup.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/best_practice_checker.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/config_entry_flow.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/device_control.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/enhanced.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/helpers.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/reference_validator.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/registry.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/smart_search/__init__.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/smart_search/_base.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/smart_search/_config.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/smart_search/_deep.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/smart_search/_entities.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/smart_search/_fetch.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/smart_search/_overview.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/smart_search/_scenes.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/smart_search/_scoring.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/tool_search_hint_middleware.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/tools_addons.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/tools_areas.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/tools_blueprints.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/tools_bug_report.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/tools_calendar.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/tools_camera.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/tools_categories.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/tools_code.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/tools_config_automations.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/tools_config_dashboards.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/tools_config_helpers.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/tools_config_scenes.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/tools_config_scripts.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/tools_dashboard_screenshot.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/tools_energy.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/tools_entities.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/tools_filesystem.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/tools_groups.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/tools_hacs.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/tools_history.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/tools_integrations.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/tools_labels.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/tools_mcp_component.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/tools_registry.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/tools_resources.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/tools_search.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/tools_service.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/tools_services.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/tools_system.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/tools_themes.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/tools_todo.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/tools_traces.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/tools_updates.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/tools_utility.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/tools_voice_assistant.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/tools_yaml_config.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/tools_zones.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/util_helpers.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/validation_middleware.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/transforms/__init__.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/transforms/categorized_search.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/transforms/lite_docstrings.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/utils/__init__.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/utils/config_hash.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/utils/data_paths.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/utils/domain_handlers.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/utils/fuzzy_search.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/utils/kill_signal_diagnostics.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/utils/operation_manager.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/utils/python_sandbox.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/utils/skill_loader.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/utils/usage_logger.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp_dev.egg-info/SOURCES.txt +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp_dev.egg-info/dependency_links.txt +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp_dev.egg-info/entry_points.txt +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp_dev.egg-info/requires.txt +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp_dev.egg-info/top_level.txt +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/tests/__init__.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/tests/test_constants.py +0 -0
- {ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/tests/test_env_manager.py +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "ha-mcp-dev"
|
|
7
|
-
version = "7.7.0.
|
|
7
|
+
version = "7.7.0.dev698"
|
|
8
8
|
description = "Home Assistant MCP Server - Complete control of Home Assistant through MCP"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.13,<3.14"
|
|
@@ -402,6 +402,46 @@ class ToolValidationLogFilter(logging.Filter):
|
|
|
402
402
|
return True
|
|
403
403
|
|
|
404
404
|
|
|
405
|
+
class ProbeAccessLogFilter(logging.Filter):
|
|
406
|
+
"""Drop benign, non-MCP HTTP probe noise from the uvicorn access log.
|
|
407
|
+
|
|
408
|
+
* ``GET``/``HEAD`` ``/favicon.ico`` -> ``404``: browsers auto-request a
|
|
409
|
+
favicon that doesn't exist. Pure noise, always dropped.
|
|
410
|
+
* ``GET``/``HEAD`` on the MCP path -> ``405``: a non-MCP caller (browser,
|
|
411
|
+
health check, reverse proxy, or a connector's SSE-style pre-flight) hit a
|
|
412
|
+
POST-only Streamable HTTP endpoint. The raw access line is dropped and the
|
|
413
|
+
landing handler logs one annotated "(NORMAL for most non-SSE connections)"
|
|
414
|
+
line in its place. Dropped only when ``drop_mcp_405`` is set — SSE callers
|
|
415
|
+
pass False, since there a GET answers 200 and a GET-405 is a genuine fault.
|
|
416
|
+
"""
|
|
417
|
+
|
|
418
|
+
def __init__(self, mcp_path: str, *, drop_mcp_405: bool = True) -> None:
|
|
419
|
+
super().__init__()
|
|
420
|
+
self._mcp_path = mcp_path.rstrip("/") or "/"
|
|
421
|
+
self._drop_mcp_405 = drop_mcp_405
|
|
422
|
+
|
|
423
|
+
def filter(self, record: logging.LogRecord) -> bool:
|
|
424
|
+
# uvicorn.access records carry structured args: (client, method, path,
|
|
425
|
+
# http_version, status_int). Match on those, not the formatted string.
|
|
426
|
+
args = record.args
|
|
427
|
+
if not isinstance(args, tuple) or len(args) != 5:
|
|
428
|
+
return True
|
|
429
|
+
method, raw_path, status = args[1], args[2], args[4]
|
|
430
|
+
if method not in ("GET", "HEAD"):
|
|
431
|
+
return True
|
|
432
|
+
path = str(raw_path).split("?", 1)[0].rstrip("/") or "/"
|
|
433
|
+
if status == 404 and path == "/favicon.ico":
|
|
434
|
+
return False # browser favicon auto-request — pure noise
|
|
435
|
+
# By-design probe 405 on the MCP path; the handler logs an annotated line
|
|
436
|
+
# instead. This trusts that the landing route is the only GET/HEAD responder
|
|
437
|
+
# on the MCP path (true today). Kept in SSE mode (drop_mcp_405=False), where
|
|
438
|
+
# a GET answers 200 and a 405 is a real fault.
|
|
439
|
+
is_dropped_probe = (
|
|
440
|
+
status == 405 and path == self._mcp_path and self._drop_mcp_405
|
|
441
|
+
)
|
|
442
|
+
return not is_dropped_probe
|
|
443
|
+
|
|
444
|
+
|
|
405
445
|
def _setup_logging(log_level_str: str, force: bool = False) -> None:
|
|
406
446
|
"""Configure root logger with consistent timestamp format."""
|
|
407
447
|
logging.basicConfig(
|
|
@@ -858,7 +898,12 @@ async def _run_http_with_graceful_shutdown(
|
|
|
858
898
|
_registered_landing_paths: set[str] = set()
|
|
859
899
|
|
|
860
900
|
|
|
861
|
-
def register_browser_landing(
|
|
901
|
+
def register_browser_landing(
|
|
902
|
+
mcp_instance: "FastMCP | _DeferredMCP",
|
|
903
|
+
path: str,
|
|
904
|
+
*,
|
|
905
|
+
quiet_probe_log: bool = True,
|
|
906
|
+
) -> None:
|
|
862
907
|
"""Register a GET handler that returns 405 with a helpful message.
|
|
863
908
|
|
|
864
909
|
Browsers and misconfigured clients that send GET instead of POST will see
|
|
@@ -869,6 +914,10 @@ def register_browser_landing(mcp_instance: "FastMCP | _DeferredMCP", path: str)
|
|
|
869
914
|
Args:
|
|
870
915
|
mcp_instance: The FastMCP server to register the route on.
|
|
871
916
|
path: The MCP endpoint path (e.g. "/mcp" or a secret path).
|
|
917
|
+
quiet_probe_log: When True (default, for Streamable HTTP), drop the
|
|
918
|
+
by-design GET/HEAD-405 probe line on the MCP path from the uvicorn
|
|
919
|
+
access log (the handler logs an annotated replacement). Pass False
|
|
920
|
+
for SSE, where a GET answers 200 and a 405 is a genuine fault.
|
|
872
921
|
"""
|
|
873
922
|
if path in _registered_landing_paths:
|
|
874
923
|
logger.warning(
|
|
@@ -905,6 +954,12 @@ def register_browser_landing(mcp_instance: "FastMCP | _DeferredMCP", path: str)
|
|
|
905
954
|
# Custom routes are registered at lowest precedence (after the MCP route).
|
|
906
955
|
@mcp_instance.custom_route(path, methods=["GET"])
|
|
907
956
|
async def _browser_landing(_: Request) -> PlainTextResponse:
|
|
957
|
+
# Any GET here is a non-MCP caller (browser, health check, proxy, or a
|
|
958
|
+
# connector's SSE-style pre-flight) hitting this POST-only Streamable HTTP
|
|
959
|
+
# endpoint, which answers 405 by design. Log one annotated line so the 405
|
|
960
|
+
# reads as expected; ProbeAccessLogFilter drops the raw uvicorn access line
|
|
961
|
+
# so there's no cryptic duplicate.
|
|
962
|
+
logger.info("GET %s -> 405 (NORMAL for most non-SSE connections)", path)
|
|
908
963
|
return PlainTextResponse(
|
|
909
964
|
_landing_message,
|
|
910
965
|
status_code=405,
|
|
@@ -913,6 +968,16 @@ def register_browser_landing(mcp_instance: "FastMCP | _DeferredMCP", path: str)
|
|
|
913
968
|
headers={"Allow": "POST, DELETE"},
|
|
914
969
|
)
|
|
915
970
|
|
|
971
|
+
# Tidy uvicorn's access log: always drop browser favicon 404s, and drop the
|
|
972
|
+
# raw by-design GET/HEAD-405 probe line on the MCP path (the handler above logs
|
|
973
|
+
# an annotated replacement). The 405 drop is skipped for SSE
|
|
974
|
+
# (quiet_probe_log=False), where a GET answers 200 and a 405 is a real fault.
|
|
975
|
+
# Attach to uvicorn.access directly — it has propagate=False, so a root-logger
|
|
976
|
+
# filter would miss it.
|
|
977
|
+
logging.getLogger("uvicorn.access").addFilter(
|
|
978
|
+
ProbeAccessLogFilter(path, drop_mcp_405=quiet_probe_log)
|
|
979
|
+
)
|
|
980
|
+
|
|
916
981
|
|
|
917
982
|
def _log_settings_url(host: str, port: int, path: str) -> None:
|
|
918
983
|
"""Log the web settings-UI URL at HTTP startup.
|
|
@@ -946,7 +1011,9 @@ def _run_http_server(transport: str, default_port: int = 8086) -> None:
|
|
|
946
1011
|
|
|
947
1012
|
host, port, path = _get_http_runtime(default_port)
|
|
948
1013
|
_warn_if_default_path_exposed(host, port, path)
|
|
949
|
-
|
|
1014
|
+
# SSE transport answers GET with 200 (the event stream), so a GET->405 there
|
|
1015
|
+
# would be a real fault, not a benign probe — keep its access log intact.
|
|
1016
|
+
register_browser_landing(_get_mcp(), path, quiet_probe_log=transport != "sse")
|
|
950
1017
|
register_settings_routes(_get_mcp(), _get_server(), secret_path=path)
|
|
951
1018
|
_log_settings_url(host, port, path)
|
|
952
1019
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/dashboard_screenshot/__init__.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/dashboard_screenshot/capture.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/dashboard_screenshot/provision.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/resources/skills-vendor/AGENTS.md
RENAMED
|
File without changes
|
{ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/resources/skills-vendor/CLAUDE.md
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/resources/skills-vendor/LICENSE
RENAMED
|
File without changes
|
{ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/resources/skills-vendor/README.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/best_practice_checker.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/smart_search/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/smart_search/_config.py
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/smart_search/_entities.py
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/smart_search/_overview.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/smart_search/_scenes.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/smart_search/_scoring.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/tool_search_hint_middleware.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/tools_config_automations.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/tools_config_dashboards.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/tools_config_helpers.py
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/tools_config_scripts.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/tools_dashboard_screenshot.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/tools_voice_assistant.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/tools/validation_middleware.py
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/transforms/categorized_search.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/transforms/lite_docstrings.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp/utils/kill_signal_diagnostics.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp_dev.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{ha_mcp_dev-7.7.0.dev696 → ha_mcp_dev-7.7.0.dev698}/src/ha_mcp_dev.egg-info/entry_points.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|