ha-mcp-dev 7.13.0.dev1975__tar.gz → 7.13.0.dev1977__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.13.0.dev1975/src/ha_mcp_dev.egg-info → ha_mcp_dev-7.13.0.dev1977}/PKG-INFO +2 -1
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/README.md +1 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/pyproject.toml +2 -1
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/__main__.py +220 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977/src/ha_mcp_dev.egg-info}/PKG-INFO +2 -1
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp_dev.egg-info/entry_points.txt +1 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/LICENSE +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/MANIFEST.in +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/setup.cfg +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/__init__.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/_pypi_marker +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/_version.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/auth/__init__.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/auth/consent_form.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/auth/provider.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/backup_manager.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/browser_landing.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/client/__init__.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/client/rest_client.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/client/supervisor_client.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/client/websocket_client.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/client/websocket_listener.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/config.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/dashboard_screenshot/__init__.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/dashboard_screenshot/capture.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/dashboard_screenshot/content.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/dashboard_screenshot/paths.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/dashboard_screenshot/provision.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/errors.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/llm_exposure.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/policy/__init__.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/policy/approval_queue.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/policy/evaluator.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/policy/handlers.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/policy/middleware.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/policy/model.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/policy/persistence.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/policy/value_sources.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/py.typed +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/read_only.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/resources/skills-vendor/.claude/settings.json +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/resources/skills-vendor/.claude-plugin/marketplace.json +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/resources/skills-vendor/.claude-plugin/plugin.json +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/resources/skills-vendor/.github/ISSUE_TEMPLATE/skill-rca.md +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/resources/skills-vendor/.github/pull_request_template.md +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/resources/skills-vendor/AGENTS.md +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/resources/skills-vendor/CLAUDE.md +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/resources/skills-vendor/CONTRIBUTING.md +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/resources/skills-vendor/LICENSE +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/resources/skills-vendor/README.md +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/SKILL.md +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/evals/evals.json +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/appdaemon.md +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/automation-patterns.md +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/blueprint-guide.md +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-cards.md +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-guide.md +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/device-control.md +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/domain-docs.md +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/examples.yaml +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/helper-selection.md +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/safe-refactoring.md +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/scenes.md +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/template-guidelines.md +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/yaml-only-integrations.md +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/server.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/settings_ui/__init__.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/settings_ui/_handlers_advanced.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/settings_ui/_handlers_backups.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/settings_ui/_handlers_fs.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/settings_ui/_handlers_server.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/settings_ui/_handlers_theme.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/settings_ui/_handlers_tools.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/settings_ui/_i18n.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/settings_ui/_persistence.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/settings_ui/_supervisor.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/settings_ui/_theme.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/settings_ui/_tools_meta.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/settings_ui/locales/README.md +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/settings_ui/locales/en.json +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/settings_ui/locales/ru.json +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/settings_ui/settings.css +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/settings_ui/settings.html +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/settings_ui/settings.js +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/smoke_test.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/stdio_settings_sidecar.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/strict_bps.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/__init__.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/auto_backup.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/backup.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/best_practice_checker.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/component_api.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/component_config_reads.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/component_devices.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/component_registries.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/component_registry_lookup.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/config_entry_flow.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/device_control.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/enhanced.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/helpers.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/radio/__init__.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/radio/base.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/radio/matter.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/radio/thread.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/radio/zigbee.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/radio/zwave.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/reference_validator.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/registry.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/smart_search/__init__.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/smart_search/_base.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/smart_search/_config.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/smart_search/_deep.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/smart_search/_entities.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/smart_search/_fetch.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/smart_search/_overview.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/smart_search/_scenes.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/smart_search/_scoring.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/tool_search_hint_middleware.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/tools_addons.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/tools_areas.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/tools_blueprints.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/tools_bug_report.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/tools_calendar.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/tools_camera.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/tools_categories.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/tools_code.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/tools_config_automations.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/tools_config_dashboards.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/tools_config_helpers.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/tools_config_scenes.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/tools_config_scripts.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/tools_dashboard_screenshot.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/tools_dev.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/tools_energy.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/tools_entities.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/tools_filesystem.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/tools_groups.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/tools_hacs.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/tools_history.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/tools_integrations.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/tools_labels.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/tools_radio.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/tools_registry.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/tools_resources.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/tools_search.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/tools_service.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/tools_services.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/tools_system.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/tools_themes.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/tools_todo.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/tools_traces.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/tools_updates.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/tools_utility.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/tools_voice_assistant.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/tools_yaml_config.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/tools_yaml_read.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/tools_zones.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/util_helpers.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/validation_middleware.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/transforms/__init__.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/transforms/categorized_search.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/transforms/lite_docstrings.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/transport_security.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/update_check.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/utils/__init__.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/utils/config_hash.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/utils/data_paths.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/utils/domain_handlers.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/utils/fuzzy_search.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/utils/kill_signal_diagnostics.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/utils/operation_manager.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/utils/python_sandbox.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/utils/skill_loader.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/utils/usage_logger.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/visibility/__init__.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/visibility/model.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/visibility/persistence.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/visibility/resolver.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp_dev.egg-info/SOURCES.txt +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp_dev.egg-info/dependency_links.txt +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp_dev.egg-info/requires.txt +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp_dev.egg-info/top_level.txt +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/tests/__init__.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/tests/test_constants.py +0 -0
- {ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/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.13.0.
|
|
3
|
+
Version: 7.13.0.dev1977
|
|
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
|
|
@@ -118,6 +118,7 @@ These run the server outside Home Assistant — useful for **Container** / **Cor
|
|
|
118
118
|
- **Docker (HTTP server):** run `ghcr.io/homeassistant-ai/ha-mcp` in HTTP mode, pointed at your Home Assistant URL and a long-lived token, and connect your client to its secret URL. See the [Setup Wizard](https://homeassistant-ai.github.io/ha-mcp/setup/) for the full command and per-client config.
|
|
119
119
|
- **PyPI / uvx (HTTP server):** run the published `ha-mcp` package with `uvx ha-mcp@latest` (or pip) as a streamable-HTTP server the same way. Details in the [Setup Wizard](https://homeassistant-ai.github.io/ha-mcp/setup/).
|
|
120
120
|
- **Local stdio (not recommended):** runs ha-mcp on your own machine over stdio. The one-command installers in the **Demo server** section below use this path; the [Setup Wizard](https://homeassistant-ai.github.io/ha-mcp/setup/) covers connecting it to your own Home Assistant.
|
|
121
|
+
- **OIDC authentication:** gate remote access behind an external identity provider (Authentik, Keycloak, Auth0, Google, etc.) instead of a secret URL — all authenticated users share the server's Home Assistant credentials. See [OIDC Mode](docs/oidc.md).
|
|
121
122
|
|
|
122
123
|
> ⚠️ **stdio has known transport issues.** The stdio transport has connection problems that streamable HTTP does not ([#1713](https://github.com/homeassistant-ai/ha-mcp/issues/1713)). It is recommended only for demo/testing tinkering — for a real setup, use the custom component or an HTTP method above.
|
|
123
124
|
|
|
@@ -85,6 +85,7 @@ These run the server outside Home Assistant — useful for **Container** / **Cor
|
|
|
85
85
|
- **Docker (HTTP server):** run `ghcr.io/homeassistant-ai/ha-mcp` in HTTP mode, pointed at your Home Assistant URL and a long-lived token, and connect your client to its secret URL. See the [Setup Wizard](https://homeassistant-ai.github.io/ha-mcp/setup/) for the full command and per-client config.
|
|
86
86
|
- **PyPI / uvx (HTTP server):** run the published `ha-mcp` package with `uvx ha-mcp@latest` (or pip) as a streamable-HTTP server the same way. Details in the [Setup Wizard](https://homeassistant-ai.github.io/ha-mcp/setup/).
|
|
87
87
|
- **Local stdio (not recommended):** runs ha-mcp on your own machine over stdio. The one-command installers in the **Demo server** section below use this path; the [Setup Wizard](https://homeassistant-ai.github.io/ha-mcp/setup/) covers connecting it to your own Home Assistant.
|
|
88
|
+
- **OIDC authentication:** gate remote access behind an external identity provider (Authentik, Keycloak, Auth0, Google, etc.) instead of a secret URL — all authenticated users share the server's Home Assistant credentials. See [OIDC Mode](docs/oidc.md).
|
|
88
89
|
|
|
89
90
|
> ⚠️ **stdio has known transport issues.** The stdio transport has connection problems that streamable HTTP does not ([#1713](https://github.com/homeassistant-ai/ha-mcp/issues/1713)). It is recommended only for demo/testing tinkering — for a real setup, use the custom component or an HTTP method above.
|
|
90
91
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "ha-mcp-dev"
|
|
7
|
-
version = "7.13.0.
|
|
7
|
+
version = "7.13.0.dev1977"
|
|
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
|
|
@@ -59,6 +59,7 @@ hamcp-test-env = "tests.test_env_manager:main"
|
|
|
59
59
|
ha-mcp-web = "ha_mcp.__main__:main_web"
|
|
60
60
|
ha-mcp-sse = "ha_mcp.__main__:main_sse"
|
|
61
61
|
ha-mcp-oauth = "ha_mcp.__main__:main_oauth"
|
|
62
|
+
ha-mcp-oidc = "ha_mcp.__main__:main_oidc"
|
|
62
63
|
|
|
63
64
|
[tool.setuptools]
|
|
64
65
|
package-dir = {"" = "src", "tests" = "tests"}
|
|
@@ -979,6 +979,39 @@ def _healthz_enabled() -> bool:
|
|
|
979
979
|
return os.getenv("MCP_HEALTHZ", "").strip().lower() in ("1", "true", "yes", "on")
|
|
980
980
|
|
|
981
981
|
|
|
982
|
+
def _oidc_verify_id_token_enabled() -> bool:
|
|
983
|
+
"""True when OIDC_VERIFY_ID_TOKEN opts in to ID-token verification.
|
|
984
|
+
|
|
985
|
+
Off by default: FastMCP's OIDCProxy verifies the access token as a JWT,
|
|
986
|
+
which works for providers like Authentik and Keycloak. Providers that
|
|
987
|
+
issue opaque access tokens (Google always; Auth0 without an API
|
|
988
|
+
audience) need ``verify_id_token=True`` so FastMCP verifies the ID token
|
|
989
|
+
instead.
|
|
990
|
+
"""
|
|
991
|
+
return os.getenv("OIDC_VERIFY_ID_TOKEN", "").strip().lower() in (
|
|
992
|
+
"1",
|
|
993
|
+
"true",
|
|
994
|
+
"yes",
|
|
995
|
+
"on",
|
|
996
|
+
)
|
|
997
|
+
|
|
998
|
+
|
|
999
|
+
def _oidc_allowed_client_redirect_uris() -> list[str] | None:
|
|
1000
|
+
"""Parse OIDC_ALLOWED_CLIENT_REDIRECT_URIS into a list, or None if unset.
|
|
1001
|
+
|
|
1002
|
+
Comma-separated list of redirect URI patterns FastMCP's OIDCProxy will
|
|
1003
|
+
accept from dynamically-registered clients. With no allow-list set,
|
|
1004
|
+
FastMCP still validates a client's redirect URI against that same
|
|
1005
|
+
client's own registered redirect URIs — the exposure is that open DCR
|
|
1006
|
+
lets an attacker register their own client with their own redirect URI;
|
|
1007
|
+
internet-facing deployments should set this to constrain what any
|
|
1008
|
+
dynamically-registered client may register in the first place.
|
|
1009
|
+
"""
|
|
1010
|
+
raw = os.getenv("OIDC_ALLOWED_CLIENT_REDIRECT_URIS", "")
|
|
1011
|
+
uris = [uri.strip() for uri in raw.split(",") if uri.strip()]
|
|
1012
|
+
return uris or None
|
|
1013
|
+
|
|
1014
|
+
|
|
982
1015
|
def register_browser_landing(
|
|
983
1016
|
mcp_instance: "FastMCP | _DeferredMCP",
|
|
984
1017
|
path: str,
|
|
@@ -1225,5 +1258,192 @@ async def _run_oauth_server(
|
|
|
1225
1258
|
)
|
|
1226
1259
|
|
|
1227
1260
|
|
|
1261
|
+
def main_oidc() -> None:
|
|
1262
|
+
"""Run server with OIDC authentication over HTTP.
|
|
1263
|
+
|
|
1264
|
+
This mode enables authentication via an external OIDC provider
|
|
1265
|
+
(Authentik, Keycloak, Auth0, Google, etc.). All authenticated users
|
|
1266
|
+
share the same Home Assistant instance via the configured credentials.
|
|
1267
|
+
|
|
1268
|
+
Unlike OAuth mode which collects per-user HA credentials via a consent form,
|
|
1269
|
+
OIDC mode is purely an access gate — users authenticate through the OIDC provider,
|
|
1270
|
+
then all requests use the shared HA credentials from environment variables.
|
|
1271
|
+
|
|
1272
|
+
Environment:
|
|
1273
|
+
- OIDC_CONFIG_URL (required): OIDC discovery URL (.well-known/openid-configuration)
|
|
1274
|
+
- OIDC_CLIENT_ID (required): OAuth client ID registered with your OIDC provider
|
|
1275
|
+
- OIDC_CLIENT_SECRET (required): OAuth client secret from your OIDC provider
|
|
1276
|
+
- MCP_BASE_URL (required): Public HTTPS URL where this server is accessible
|
|
1277
|
+
- HOMEASSISTANT_URL (required): Home Assistant instance URL
|
|
1278
|
+
- HOMEASSISTANT_TOKEN (required): Home Assistant long-lived access token or supervisor token
|
|
1279
|
+
- OIDC_JWT_SIGNING_KEY (optional): Secret key for signing FastMCP JWTs. Sessions
|
|
1280
|
+
persist across restarts by default (the key is derived from OIDC_CLIENT_SECRET);
|
|
1281
|
+
set this to decouple the signing key from the client secret. Generate with:
|
|
1282
|
+
python -c "import secrets; print(secrets.token_urlsafe(32))"
|
|
1283
|
+
- OIDC_ALLOWED_CLIENT_REDIRECT_URIS (optional): Comma-separated list of redirect URI
|
|
1284
|
+
patterns accepted from dynamically-registered clients. Strongly recommended for
|
|
1285
|
+
internet-facing deployments.
|
|
1286
|
+
- OIDC_VERIFY_ID_TOKEN (optional, default: false): Set true for providers that issue
|
|
1287
|
+
opaque access tokens (e.g. Google, or Auth0 without an API audience).
|
|
1288
|
+
- OIDC_AUDIENCE (optional): Expected `aud` claim for IdP-issued access tokens.
|
|
1289
|
+
Without it (and with OIDC_VERIFY_ID_TOKEN off), FastMCP's JWT verifier checks
|
|
1290
|
+
issuer, signature, and expiry but not audience. With OIDC_VERIFY_ID_TOKEN=true,
|
|
1291
|
+
verification pins `aud` to OIDC_CLIENT_ID instead and this value is only
|
|
1292
|
+
forwarded to the IdP's authorize/token endpoints (it is what makes Auth0
|
|
1293
|
+
issue JWT rather than opaque access tokens).
|
|
1294
|
+
- MCP_HOST (optional, default: "0.0.0.0"; set 127.0.0.1 to restrict to loopback
|
|
1295
|
+
behind a same-host reverse proxy)
|
|
1296
|
+
- MCP_PORT (optional, default: 8086)
|
|
1297
|
+
- MCP_SECRET_PATH (optional, default: "/mcp")
|
|
1298
|
+
- LOG_LEVEL (optional, default: INFO)
|
|
1299
|
+
"""
|
|
1300
|
+
# Configure logging for OIDC mode (force=True needed since logging may already be configured)
|
|
1301
|
+
log_level = os.getenv("LOG_LEVEL", "INFO").upper()
|
|
1302
|
+
_setup_logging(log_level, force=True)
|
|
1303
|
+
for logger_name in ["ha_mcp", "ha_mcp.auth", "ha_mcp.auth.provider"]:
|
|
1304
|
+
logging.getLogger(logger_name).setLevel(getattr(logging, log_level))
|
|
1305
|
+
logger.info(f"OIDC mode logging configured at {log_level} level")
|
|
1306
|
+
_log_startup_version()
|
|
1307
|
+
|
|
1308
|
+
# Validate HA credentials (OIDC mode needs them — unlike OAuth mode)
|
|
1309
|
+
from ha_mcp.config import get_settings
|
|
1310
|
+
|
|
1311
|
+
settings = get_settings()
|
|
1312
|
+
_validate_standard_credentials(settings)
|
|
1313
|
+
|
|
1314
|
+
# Validate OIDC-specific env vars
|
|
1315
|
+
oidc_config_url = os.getenv("OIDC_CONFIG_URL")
|
|
1316
|
+
oidc_client_id = os.getenv("OIDC_CLIENT_ID")
|
|
1317
|
+
oidc_client_secret = os.getenv("OIDC_CLIENT_SECRET")
|
|
1318
|
+
base_url = os.getenv("MCP_BASE_URL")
|
|
1319
|
+
|
|
1320
|
+
missing = []
|
|
1321
|
+
if not oidc_config_url:
|
|
1322
|
+
missing.append("OIDC_CONFIG_URL")
|
|
1323
|
+
if not oidc_client_id:
|
|
1324
|
+
missing.append("OIDC_CLIENT_ID")
|
|
1325
|
+
if not oidc_client_secret:
|
|
1326
|
+
missing.append("OIDC_CLIENT_SECRET")
|
|
1327
|
+
if not base_url:
|
|
1328
|
+
missing.append("MCP_BASE_URL")
|
|
1329
|
+
|
|
1330
|
+
if missing:
|
|
1331
|
+
logger.error(
|
|
1332
|
+
f"Missing required environment variables for OIDC mode: {', '.join(missing)}"
|
|
1333
|
+
)
|
|
1334
|
+
logger.error(
|
|
1335
|
+
"OIDC mode requires an external OIDC provider (Authentik, Keycloak, Auth0, etc.)"
|
|
1336
|
+
)
|
|
1337
|
+
sys.exit(1)
|
|
1338
|
+
|
|
1339
|
+
assert oidc_config_url is not None
|
|
1340
|
+
assert oidc_client_id is not None
|
|
1341
|
+
assert oidc_client_secret is not None
|
|
1342
|
+
assert base_url is not None
|
|
1343
|
+
|
|
1344
|
+
host, port, path = _get_http_runtime(default_port=8086)
|
|
1345
|
+
|
|
1346
|
+
_run_entrypoint(
|
|
1347
|
+
_run_oidc_server(
|
|
1348
|
+
config_url=oidc_config_url,
|
|
1349
|
+
client_id=oidc_client_id,
|
|
1350
|
+
client_secret=oidc_client_secret,
|
|
1351
|
+
base_url=base_url,
|
|
1352
|
+
host=host,
|
|
1353
|
+
port=port,
|
|
1354
|
+
path=path,
|
|
1355
|
+
),
|
|
1356
|
+
"OIDC server",
|
|
1357
|
+
)
|
|
1358
|
+
|
|
1359
|
+
|
|
1360
|
+
async def _run_oidc_server(
|
|
1361
|
+
config_url: str,
|
|
1362
|
+
client_id: str,
|
|
1363
|
+
client_secret: str,
|
|
1364
|
+
base_url: str,
|
|
1365
|
+
host: str,
|
|
1366
|
+
port: int,
|
|
1367
|
+
path: str,
|
|
1368
|
+
) -> None:
|
|
1369
|
+
"""Run the OIDC-authenticated MCP server.
|
|
1370
|
+
|
|
1371
|
+
Unlike OAuth mode which uses OAuthProxyClient for per-user credential routing,
|
|
1372
|
+
OIDC mode uses the standard HomeAssistantClient with shared credentials.
|
|
1373
|
+
OIDC is purely an access gate — all authenticated users share the same HA instance.
|
|
1374
|
+
|
|
1375
|
+
Args:
|
|
1376
|
+
config_url: OIDC discovery URL (.well-known/openid-configuration)
|
|
1377
|
+
client_id: OAuth client ID from the OIDC provider
|
|
1378
|
+
client_secret: OAuth client secret from the OIDC provider
|
|
1379
|
+
base_url: Public HTTPS URL where this server is accessible
|
|
1380
|
+
host: Bind host (typically 0.0.0.0; override via MCP_HOST)
|
|
1381
|
+
port: Port to listen on
|
|
1382
|
+
path: MCP endpoint path
|
|
1383
|
+
"""
|
|
1384
|
+
from fastmcp.server.auth.oidc_proxy import OIDCProxy
|
|
1385
|
+
|
|
1386
|
+
from ha_mcp.server import HomeAssistantSmartMCPServer
|
|
1387
|
+
from ha_mcp.transport_security import ensure_host_origin_guard_default_off
|
|
1388
|
+
|
|
1389
|
+
# OIDC mode is deployed behind a public reverse proxy or LAN hostname;
|
|
1390
|
+
# disable FastMCP's Host/Origin rebinding guard so proxied requests are
|
|
1391
|
+
# not rejected with 421/403 before OIDC auth runs.
|
|
1392
|
+
ensure_host_origin_guard_default_off()
|
|
1393
|
+
|
|
1394
|
+
proxy_kwargs: dict[str, Any] = {
|
|
1395
|
+
"config_url": config_url,
|
|
1396
|
+
"client_id": client_id,
|
|
1397
|
+
"client_secret": client_secret,
|
|
1398
|
+
"base_url": base_url,
|
|
1399
|
+
# "external" tells FastMCP that consent is handled by the upstream
|
|
1400
|
+
# IdP (Authentik, Keycloak, etc.) -- unlike `False`, this does not
|
|
1401
|
+
# log a security warning at startup that consent is disabled.
|
|
1402
|
+
"require_authorization_consent": "external",
|
|
1403
|
+
# Preserve `or None`: an empty-but-set env var must not bypass
|
|
1404
|
+
# FastMCP's derive-from-client-secret default for jwt_signing_key.
|
|
1405
|
+
"jwt_signing_key": os.getenv("OIDC_JWT_SIGNING_KEY") or None,
|
|
1406
|
+
}
|
|
1407
|
+
|
|
1408
|
+
allowed_redirect_uris = _oidc_allowed_client_redirect_uris()
|
|
1409
|
+
if allowed_redirect_uris:
|
|
1410
|
+
proxy_kwargs["allowed_client_redirect_uris"] = allowed_redirect_uris
|
|
1411
|
+
else:
|
|
1412
|
+
logger.warning(
|
|
1413
|
+
"OIDC_ALLOWED_CLIENT_REDIRECT_URIS is not set: any dynamically-registered "
|
|
1414
|
+
"(DCR) client's own redirect URIs are accepted. Internet-facing "
|
|
1415
|
+
"deployments should set it."
|
|
1416
|
+
)
|
|
1417
|
+
|
|
1418
|
+
if _oidc_verify_id_token_enabled():
|
|
1419
|
+
proxy_kwargs["verify_id_token"] = True
|
|
1420
|
+
|
|
1421
|
+
audience = os.getenv("OIDC_AUDIENCE", "").strip()
|
|
1422
|
+
if audience:
|
|
1423
|
+
proxy_kwargs["audience"] = audience
|
|
1424
|
+
|
|
1425
|
+
# Create OIDC auth provider — auto-discovers endpoints from config_url
|
|
1426
|
+
auth = OIDCProxy(**proxy_kwargs)
|
|
1427
|
+
|
|
1428
|
+
# Standard server with shared credentials (no proxy client needed)
|
|
1429
|
+
global _server
|
|
1430
|
+
_server = HomeAssistantSmartMCPServer()
|
|
1431
|
+
mcp_instance = _server.mcp
|
|
1432
|
+
mcp_instance.auth = auth
|
|
1433
|
+
|
|
1434
|
+
logger.info("Server created with OIDC authentication")
|
|
1435
|
+
# Unlike standard/OAuth HTTP modes, OIDC mode intentionally registers no
|
|
1436
|
+
# browser landing page and no settings-UI sidecar: an unauthenticated
|
|
1437
|
+
# browser GET gets a bare 405 rather than a friendly page, and there is
|
|
1438
|
+
# no settings UI surface here.
|
|
1439
|
+
if _healthz_enabled():
|
|
1440
|
+
_register_healthz_route(mcp_instance)
|
|
1441
|
+
logger.info(f"Starting OIDC-enabled MCP server at {base_url}{path}")
|
|
1442
|
+
|
|
1443
|
+
await _run_with_shutdown(
|
|
1444
|
+
mcp_instance.run_async(**_http_run_kwargs("http", host, port, path))
|
|
1445
|
+
)
|
|
1446
|
+
|
|
1447
|
+
|
|
1228
1448
|
if __name__ == "__main__":
|
|
1229
1449
|
main()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ha-mcp-dev
|
|
3
|
-
Version: 7.13.0.
|
|
3
|
+
Version: 7.13.0.dev1977
|
|
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
|
|
@@ -118,6 +118,7 @@ These run the server outside Home Assistant — useful for **Container** / **Cor
|
|
|
118
118
|
- **Docker (HTTP server):** run `ghcr.io/homeassistant-ai/ha-mcp` in HTTP mode, pointed at your Home Assistant URL and a long-lived token, and connect your client to its secret URL. See the [Setup Wizard](https://homeassistant-ai.github.io/ha-mcp/setup/) for the full command and per-client config.
|
|
119
119
|
- **PyPI / uvx (HTTP server):** run the published `ha-mcp` package with `uvx ha-mcp@latest` (or pip) as a streamable-HTTP server the same way. Details in the [Setup Wizard](https://homeassistant-ai.github.io/ha-mcp/setup/).
|
|
120
120
|
- **Local stdio (not recommended):** runs ha-mcp on your own machine over stdio. The one-command installers in the **Demo server** section below use this path; the [Setup Wizard](https://homeassistant-ai.github.io/ha-mcp/setup/) covers connecting it to your own Home Assistant.
|
|
121
|
+
- **OIDC authentication:** gate remote access behind an external identity provider (Authentik, Keycloak, Auth0, Google, etc.) instead of a secret URL — all authenticated users share the server's Home Assistant credentials. See [OIDC Mode](docs/oidc.md).
|
|
121
122
|
|
|
122
123
|
> ⚠️ **stdio has known transport issues.** The stdio transport has connection problems that streamable HTTP does not ([#1713](https://github.com/homeassistant-ai/ha-mcp/issues/1713)). It is recommended only for demo/testing tinkering — for a real setup, use the custom component or an HTTP method above.
|
|
123
124
|
|
{ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp_dev.egg-info/entry_points.txt
RENAMED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
ha-mcp = ha_mcp.__main__:main
|
|
3
3
|
ha-mcp-dev = ha_mcp.__main__:main_dev
|
|
4
4
|
ha-mcp-oauth = ha_mcp.__main__:main_oauth
|
|
5
|
+
ha-mcp-oidc = ha_mcp.__main__:main_oidc
|
|
5
6
|
ha-mcp-smoke-test = ha_mcp.smoke_test:main
|
|
6
7
|
ha-mcp-sse = ha_mcp.__main__:main_sse
|
|
7
8
|
ha-mcp-web = ha_mcp.__main__:main_web
|
|
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.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/client/supervisor_client.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/client/websocket_client.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/client/websocket_listener.py
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/dashboard_screenshot/__init__.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/dashboard_screenshot/capture.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/dashboard_screenshot/content.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/dashboard_screenshot/paths.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/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.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/resources/skills-vendor/AGENTS.md
RENAMED
|
File without changes
|
{ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/resources/skills-vendor/CLAUDE.md
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/resources/skills-vendor/LICENSE
RENAMED
|
File without changes
|
{ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/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
|
{ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/settings_ui/_handlers_advanced.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/settings_ui/_handlers_backups.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/settings_ui/_handlers_fs.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/settings_ui/_handlers_server.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/settings_ui/_handlers_theme.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/settings_ui/_handlers_tools.py
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/settings_ui/_persistence.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/settings_ui/_supervisor.py
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/settings_ui/_tools_meta.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/settings_ui/locales/README.md
RENAMED
|
File without changes
|
{ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/settings_ui/locales/en.json
RENAMED
|
File without changes
|
{ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/settings_ui/locales/ru.json
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/settings_ui/settings.html
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/stdio_settings_sidecar.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/best_practice_checker.py
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/component_config_reads.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/component_devices.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/component_registries.py
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/config_entry_flow.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-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/reference_validator.py
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/smart_search/__init__.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/smart_search/_base.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/smart_search/_config.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/smart_search/_deep.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/smart_search/_entities.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/smart_search/_fetch.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/smart_search/_overview.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/smart_search/_scenes.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/smart_search/_scoring.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/tools_blueprints.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/tools_bug_report.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/tools_categories.py
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/tools_config_automations.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/tools_config_dashboards.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/tools_config_helpers.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/tools_config_scenes.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/tools_config_scripts.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/tools_filesystem.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/tools_integrations.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
|
{ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/tools_voice_assistant.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/tools_yaml_config.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/tools/validation_middleware.py
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/transforms/categorized_search.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/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
|
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/utils/kill_signal_diagnostics.py
RENAMED
|
File without changes
|
{ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/utils/operation_manager.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp/visibility/persistence.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp_dev.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp_dev.egg-info/requires.txt
RENAMED
|
File without changes
|
{ha_mcp_dev-7.13.0.dev1975 → ha_mcp_dev-7.13.0.dev1977}/src/ha_mcp_dev.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|