ha-mcp-dev 8.1.1.dev2296__tar.gz → 8.2.0.dev2307__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {ha_mcp_dev-8.1.1.dev2296/src/ha_mcp_dev.egg-info → ha_mcp_dev-8.2.0.dev2307}/PKG-INFO +3 -3
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/README.md +1 -1
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/pyproject.toml +2 -2
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/__init__.py +4 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/__main__.py +30 -7
- ha_mcp_dev-8.2.0.dev2307/src/ha_mcp/_rich_compat.py +109 -0
- ha_mcp_dev-8.2.0.dev2307/src/ha_mcp/auth/oidc_compat.py +106 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307/src/ha_mcp_dev.egg-info}/PKG-INFO +3 -3
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp_dev.egg-info/SOURCES.txt +2 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp_dev.egg-info/requires.txt +1 -1
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/LICENSE +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/MANIFEST.in +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/setup.cfg +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_pypi_marker +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/__init__.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/requirements.txt +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/LICENSE +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/MANIFEST.sha256 +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/VENDORED +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/__init__.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/__main__.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/asyncio/__init__.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/asyncio/client.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/asyncio/connection.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/asyncio/messages.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/asyncio/router.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/asyncio/server.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/auth.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/cli.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/client.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/connection.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/datastructures.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/exceptions.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/extensions/__init__.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/extensions/base.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/extensions/permessage_deflate.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/frames.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/headers.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/http11.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/imports.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/legacy/__init__.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/legacy/auth.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/legacy/client.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/legacy/exceptions.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/legacy/framing.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/legacy/handshake.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/legacy/http.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/legacy/protocol.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/legacy/server.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/protocol.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/proxy.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/py.typed +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/server.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/streams.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/sync/__init__.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/sync/client.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/sync/connection.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/sync/messages.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/sync/router.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/sync/server.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/sync/utils.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/trio/__init__.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/trio/client.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/trio/connection.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/trio/messages.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/trio/router.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/trio/server.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/trio/utils.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/typing.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/uri.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/utils.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/version.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_version.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/auth/__init__.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/auth/consent_form.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/auth/provider.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/backup_manager.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/browser_landing.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/client/__init__.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/client/rest_client.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/client/supervisor_client.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/client/websocket_client.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/client/websocket_listener.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/config.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/dashboard_screenshot/__init__.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/dashboard_screenshot/capture.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/dashboard_screenshot/content.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/dashboard_screenshot/paths.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/dashboard_screenshot/provision.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/dashboard_screenshot/theme_guard.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/errors.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/hacs_auto_refresh.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/llm_exposure.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/policy/__init__.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/policy/approval_queue.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/policy/editing.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/policy/evaluator.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/policy/handlers.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/policy/middleware.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/policy/model.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/policy/persistence.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/policy/value_sources.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/py.typed +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/read_only.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/redaction.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/resources/skills-vendor/.claude/settings.json +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/resources/skills-vendor/.claude-plugin/marketplace.json +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/resources/skills-vendor/.claude-plugin/plugin.json +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/resources/skills-vendor/.github/ISSUE_TEMPLATE/skill-rca.md +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/resources/skills-vendor/.github/pull_request_template.md +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/resources/skills-vendor/AGENTS.md +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/resources/skills-vendor/CLAUDE.md +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/resources/skills-vendor/CONTRIBUTING.md +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/resources/skills-vendor/LICENSE +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/resources/skills-vendor/README.md +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/SKILL.md +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/evals/evals.json +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/appdaemon.md +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/automation-patterns.md +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/blueprint-guide.md +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-cards.md +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-guide.md +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/device-control.md +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/domain-docs.md +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/examples.yaml +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/helper-selection.md +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/safe-refactoring.md +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/scenes.md +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/template-guidelines.md +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/yaml-only-integrations.md +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/server.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/settings_ui/__init__.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/settings_ui/_handlers_advanced.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/settings_ui/_handlers_backups.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/settings_ui/_handlers_fs.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/settings_ui/_handlers_server.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/settings_ui/_handlers_theme.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/settings_ui/_handlers_tools.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/settings_ui/_i18n.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/settings_ui/_persistence.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/settings_ui/_supervisor.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/settings_ui/_theme.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/settings_ui/_tools_meta.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/settings_ui/locales/README.md +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/settings_ui/locales/de.json +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/settings_ui/locales/en.json +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/settings_ui/locales/es.json +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/settings_ui/locales/fr.json +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/settings_ui/locales/it.json +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/settings_ui/locales/nl.json +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/settings_ui/locales/pl.json +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/settings_ui/locales/ru.json +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/settings_ui/locales/sv.json +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/settings_ui/locales/zh-Hans.json +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/settings_ui/settings.css +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/settings_ui/settings.html +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/settings_ui/settings.js +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/smoke_test.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/stdio_settings_sidecar.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/strict_bps.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/__init__.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/auto_backup.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/backup.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/best_practice_checker.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/best_practice_result.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/best_practice_variables.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/component_api.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/component_config_reads.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/component_devices.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/component_registries.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/component_registry_lookup.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/config_entry_flow.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/config_entry_flow_form.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/config_entry_flow_menu.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/config_entry_flow_walker.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/device_control.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/hacs_registration.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/helpers.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/radio/__init__.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/radio/base.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/radio/matter.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/radio/thread.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/radio/zigbee.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/radio/zwave.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/reference_validator.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/registry.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/smart_search/__init__.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/smart_search/_base.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/smart_search/_config.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/smart_search/_deep.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/smart_search/_entities.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/smart_search/_fetch.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/smart_search/_overview.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/smart_search/_scenes.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/smart_search/_scoring.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/tool_search_hint_middleware.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/tools_addons.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/tools_areas.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/tools_blueprints.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/tools_bug_report.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/tools_calendar.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/tools_camera.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/tools_categories.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/tools_code.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/tools_config_automations.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/tools_config_dashboards.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/tools_config_helpers.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/tools_config_scenes.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/tools_config_scripts.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/tools_dashboard_screenshot.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/tools_dev.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/tools_energy.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/tools_entities.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/tools_filesystem.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/tools_groups.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/tools_hacs.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/tools_history.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/tools_integrations.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/tools_labels.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/tools_radio.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/tools_registry.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/tools_resources.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/tools_search.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/tools_security_policy.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/tools_service.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/tools_services.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/tools_system.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/tools_themes.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/tools_todo.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/tools_traces.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/tools_updates.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/tools_utility.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/tools_voice_assistant.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/tools_yaml_config.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/tools_yaml_read.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/tools_zones.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/util_helpers.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/tools/validation_middleware.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/transforms/__init__.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/transforms/categorized_search.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/transforms/lite_docstrings.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/transport_security.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/update_check.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/utils/__init__.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/utils/config_hash.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/utils/config_write_lock.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/utils/data_paths.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/utils/domain_handlers.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/utils/fuzzy_search.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/utils/kill_signal_diagnostics.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/utils/operation_manager.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/utils/python_sandbox.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/utils/skill_loader.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/utils/usage_logger.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/visibility/__init__.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/visibility/enforcement.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/visibility/model.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/visibility/persistence.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/visibility/resolver.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp_dev.egg-info/dependency_links.txt +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp_dev.egg-info/entry_points.txt +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp_dev.egg-info/top_level.txt +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/tests/__init__.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/tests/test_constants.py +0 -0
- {ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/tests/test_env_manager.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ha-mcp-dev
|
|
3
|
-
Version: 8.
|
|
3
|
+
Version: 8.2.0.dev2307
|
|
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
|
|
@@ -19,7 +19,7 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
|
19
19
|
Requires-Python: <3.15,>=3.13
|
|
20
20
|
Description-Content-Type: text/markdown
|
|
21
21
|
License-File: LICENSE
|
|
22
|
-
Requires-Dist: fastmcp==3.4.
|
|
22
|
+
Requires-Dist: fastmcp==3.4.6
|
|
23
23
|
Requires-Dist: httpx[socks]==0.28.1
|
|
24
24
|
Requires-Dist: pydantic==2.13.4
|
|
25
25
|
Requires-Dist: python-dotenv==1.2.2
|
|
@@ -117,7 +117,7 @@ These run the server outside Home Assistant — useful for **Container** / **Cor
|
|
|
117
117
|
- **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.
|
|
118
118
|
- **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/).
|
|
119
119
|
- **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.
|
|
120
|
-
- **OIDC authentication:** gate remote access behind an external identity provider (Authentik, Keycloak, Auth0,
|
|
120
|
+
- **OIDC authentication:** gate remote access behind an external identity provider (Authentik, Keycloak, Auth0, etc.) instead of a secret URL — all authenticated users share the server's Home Assistant credentials. See [OIDC Mode](docs/oidc.md).
|
|
121
121
|
|
|
122
122
|
> ⚠️ **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
123
|
|
|
@@ -85,7 +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,
|
|
88
|
+
- **OIDC authentication:** gate remote access behind an external identity provider (Authentik, Keycloak, Auth0, etc.) instead of a secret URL — all authenticated users share the server's Home Assistant credentials. See [OIDC Mode](docs/oidc.md).
|
|
89
89
|
|
|
90
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.
|
|
91
91
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "ha-mcp-dev"
|
|
7
|
-
version = "8.
|
|
7
|
+
version = "8.2.0.dev2307"
|
|
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
|
|
@@ -28,7 +28,7 @@ classifiers = [
|
|
|
28
28
|
]
|
|
29
29
|
|
|
30
30
|
dependencies = [
|
|
31
|
-
"fastmcp==3.4.
|
|
31
|
+
"fastmcp==3.4.6",
|
|
32
32
|
"httpx[socks]==0.28.1",
|
|
33
33
|
"pydantic==2.13.4",
|
|
34
34
|
"python-dotenv==1.2.2",
|
|
@@ -5,6 +5,10 @@ A Model Context Protocol server that provides complete control over Home Assista
|
|
|
5
5
|
through REST API and WebSocket integration.
|
|
6
6
|
"""
|
|
7
7
|
|
|
8
|
+
# Must be imported before anything that reaches fastmcp (``.auth`` below does),
|
|
9
|
+
# because fastmcp configures rich logging at import time and dies on a rich
|
|
10
|
+
# older than 13.9.4. Importing this module applies the shim. See #2186.
|
|
11
|
+
from . import _rich_compat as _rich_compat
|
|
8
12
|
from ._version import get_version
|
|
9
13
|
|
|
10
14
|
__version__ = get_version()
|
|
@@ -503,15 +503,31 @@ def _setup_logging(log_level_str: str, force: bool = True) -> None:
|
|
|
503
503
|
of the sweep ``force`` performs (which removes *and closes* every root
|
|
504
504
|
handler) so ``ha_report_issue`` keeps its startup diagnostics.
|
|
505
505
|
"""
|
|
506
|
+
log_level = getattr(logging, log_level_str)
|
|
507
|
+
|
|
508
|
+
import fastmcp
|
|
509
|
+
|
|
506
510
|
from ha_mcp.utils.usage_logger import preserve_startup_collector
|
|
507
511
|
|
|
508
512
|
with preserve_startup_collector():
|
|
509
513
|
logging.basicConfig(
|
|
510
|
-
level=
|
|
514
|
+
level=log_level,
|
|
511
515
|
format="%(asctime)s %(name)s %(levelname)s: %(message)s",
|
|
512
516
|
datefmt=_LOG_DATE_FORMAT,
|
|
513
517
|
force=force,
|
|
514
518
|
)
|
|
519
|
+
|
|
520
|
+
fastmcp_logger = logging.getLogger("fastmcp")
|
|
521
|
+
if fastmcp.settings.log_enabled:
|
|
522
|
+
# FastMCP configures its own handler and disables propagation, so the root
|
|
523
|
+
# level above does not control its OIDC diagnostics. Preserve that handler
|
|
524
|
+
# and formatting while honoring ha-mcp's LOG_LEVEL setting.
|
|
525
|
+
fastmcp_logger.setLevel(log_level)
|
|
526
|
+
else:
|
|
527
|
+
# FastMCP deliberately leaves its logger unconfigured when logging is
|
|
528
|
+
# disabled. Prevent that NOTSET namespace from inheriting our root handler.
|
|
529
|
+
fastmcp_logger.setLevel(logging.CRITICAL + 1)
|
|
530
|
+
|
|
515
531
|
logging.getLogger("mcp.server.streamable_http").addFilter(
|
|
516
532
|
StatelessSessionLogFilter()
|
|
517
533
|
)
|
|
@@ -1159,7 +1175,7 @@ def _oidc_verify_id_token_enabled() -> bool:
|
|
|
1159
1175
|
|
|
1160
1176
|
Off by default: FastMCP's OIDCProxy verifies the access token as a JWT,
|
|
1161
1177
|
which works for providers like Authentik and Keycloak. Providers that
|
|
1162
|
-
issue opaque access tokens (
|
|
1178
|
+
issue opaque access tokens (such as Authelia, or Auth0 without an API
|
|
1163
1179
|
audience) need ``verify_id_token=True`` so FastMCP verifies the ID token
|
|
1164
1180
|
instead.
|
|
1165
1181
|
"""
|
|
@@ -1599,7 +1615,7 @@ def main_oidc() -> None:
|
|
|
1599
1615
|
"""Run server with OIDC authentication over HTTP.
|
|
1600
1616
|
|
|
1601
1617
|
This mode enables authentication via an external OIDC provider
|
|
1602
|
-
(Authentik, Keycloak, Auth0,
|
|
1618
|
+
(Authentik, Keycloak, Auth0, etc.). All authenticated users
|
|
1603
1619
|
share the same Home Assistant instance via the configured credentials.
|
|
1604
1620
|
|
|
1605
1621
|
Unlike OAuth mode which collects per-user HA credentials via a consent form,
|
|
@@ -1621,7 +1637,7 @@ def main_oidc() -> None:
|
|
|
1621
1637
|
patterns accepted from dynamically-registered clients. Strongly recommended for
|
|
1622
1638
|
internet-facing deployments.
|
|
1623
1639
|
- OIDC_VERIFY_ID_TOKEN (optional, default: false): Set true for providers that issue
|
|
1624
|
-
opaque access tokens (e.g.
|
|
1640
|
+
opaque access tokens (e.g. Authelia, or Auth0 without an API audience).
|
|
1625
1641
|
- OIDC_AUDIENCE (optional): Expected `aud` claim for IdP-issued access tokens.
|
|
1626
1642
|
Without it (and with OIDC_VERIFY_ID_TOKEN off), FastMCP's JWT verifier checks
|
|
1627
1643
|
issuer, signature, and expiry but not audience. With OIDC_VERIFY_ID_TOKEN=true,
|
|
@@ -1638,6 +1654,8 @@ def main_oidc() -> None:
|
|
|
1638
1654
|
- HA_MCP_DISABLE_SETTINGS_UI (optional): set truthy to not serve the
|
|
1639
1655
|
settings UI at all
|
|
1640
1656
|
- LOG_LEVEL (optional, default: INFO)
|
|
1657
|
+
- FASTMCP_LOG_ENABLED (optional, default: true): Set false to suppress
|
|
1658
|
+
FastMCP framework logs while leaving ha-mcp logs at LOG_LEVEL.
|
|
1641
1659
|
"""
|
|
1642
1660
|
# Configure logging for OIDC mode (force=True needed since logging may already be configured)
|
|
1643
1661
|
log_level = os.getenv("LOG_LEVEL", "INFO").upper()
|
|
@@ -1723,8 +1741,7 @@ async def _run_oidc_server(
|
|
|
1723
1741
|
port: Port to listen on
|
|
1724
1742
|
path: MCP endpoint path
|
|
1725
1743
|
"""
|
|
1726
|
-
from
|
|
1727
|
-
|
|
1744
|
+
from ha_mcp.auth.oidc_compat import HaMcpOIDCProxy
|
|
1728
1745
|
from ha_mcp.server import HomeAssistantSmartMCPServer
|
|
1729
1746
|
from ha_mcp.transport_security import ensure_host_origin_guard_default_off
|
|
1730
1747
|
|
|
@@ -1742,6 +1759,11 @@ async def _run_oidc_server(
|
|
|
1742
1759
|
# IdP (Authentik, Keycloak, etc.) -- unlike `False`, this does not
|
|
1743
1760
|
# log a security warning at startup that consent is disabled.
|
|
1744
1761
|
"require_authorization_consent": "external",
|
|
1762
|
+
# This entrypoint provides OIDC, so request the protocol-level scope
|
|
1763
|
+
# that makes upstream providers return an ID token. FastMCP also
|
|
1764
|
+
# advertises this scope through protected resource metadata so MCP
|
|
1765
|
+
# clients include it in the authorization flow.
|
|
1766
|
+
"required_scopes": ["openid"],
|
|
1745
1767
|
# Preserve `or None`: an empty-but-set env var must not bypass
|
|
1746
1768
|
# FastMCP's derive-from-client-secret default for jwt_signing_key.
|
|
1747
1769
|
"jwt_signing_key": os.getenv("OIDC_JWT_SIGNING_KEY") or None,
|
|
@@ -1765,7 +1787,8 @@ async def _run_oidc_server(
|
|
|
1765
1787
|
proxy_kwargs["audience"] = audience
|
|
1766
1788
|
|
|
1767
1789
|
# Create OIDC auth provider — auto-discovers endpoints from config_url
|
|
1768
|
-
auth =
|
|
1790
|
+
auth = HaMcpOIDCProxy(**proxy_kwargs)
|
|
1791
|
+
auth.setup_scope_compatibility()
|
|
1769
1792
|
|
|
1770
1793
|
# Standard server with shared credentials (no proxy client needed)
|
|
1771
1794
|
global _server
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"""Tolerate a ``rich`` older than fastmcp's logging setup expects (#2186).
|
|
2
|
+
|
|
3
|
+
``fastmcp/__init__.py`` calls ``configure_logging()`` at import time, which
|
|
4
|
+
builds a ``rich.logging.RichHandler`` with ``tracebacks_max_frames`` and
|
|
5
|
+
``tracebacks_suppress`` unconditionally — no version guard, no ``try``. Both
|
|
6
|
+
keywords require ``rich>=13.9.4`` (``fastmcp-slim``'s declared floor), so an
|
|
7
|
+
environment holding an older ``rich`` cannot ``import fastmcp`` at all::
|
|
8
|
+
|
|
9
|
+
TypeError: RichHandler.__init__() got an unexpected keyword argument
|
|
10
|
+
'tracebacks_max_frames'
|
|
11
|
+
|
|
12
|
+
Since ``ha_mcp/__init__.py`` imports ``.auth`` -> ``fastmcp``, that takes the
|
|
13
|
+
whole package down before any of our code runs. It is not hypothetical: the
|
|
14
|
+
official Home Assistant container ships ``rich 10.16.2`` (held below 11 by
|
|
15
|
+
``surepy``'s ``rich>=10.1.0,<11.0.0``) and ``rich`` is absent from HA's
|
|
16
|
+
``package_constraints.txt``, so whether installing ``ha-mcp`` pulls ``rich``
|
|
17
|
+
forward is left entirely to the resolver — it usually does, and when it does
|
|
18
|
+
not the integration cannot start.
|
|
19
|
+
|
|
20
|
+
The declared dependency floor is correct upstream and this module does not
|
|
21
|
+
second-guess it: it only intervenes when the *installed* ``RichHandler``
|
|
22
|
+
genuinely cannot accept a keyword, dropping the unsupported ones so logging
|
|
23
|
+
setup degrades instead of aborting the import. On ``rich>=13.9.4`` it is a
|
|
24
|
+
no-op. Handlers still attach and still render; such installs lose only
|
|
25
|
+
traceback frame-limiting and framework-frame suppression, which beats not
|
|
26
|
+
importing.
|
|
27
|
+
|
|
28
|
+
Remove this once the upstream fix is released and ha-mcp's floor excludes the
|
|
29
|
+
affected fastmcp versions.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
from __future__ import annotations
|
|
33
|
+
|
|
34
|
+
import functools
|
|
35
|
+
import inspect
|
|
36
|
+
import logging
|
|
37
|
+
from typing import Any
|
|
38
|
+
|
|
39
|
+
logger = logging.getLogger(__name__)
|
|
40
|
+
|
|
41
|
+
# Marker set on our wrapper so repeated calls do not stack wrappers.
|
|
42
|
+
_PATCH_MARKER = "_ha_mcp_filters_unsupported_kwargs"
|
|
43
|
+
|
|
44
|
+
# Present only on rich>=13.9.4; its absence is what makes fastmcp's call fatal.
|
|
45
|
+
_PROBE_KWARG = "tracebacks_max_frames"
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def ensure_rich_handler_compat() -> bool:
|
|
49
|
+
"""Make ``RichHandler`` ignore keywords the installed ``rich`` lacks.
|
|
50
|
+
|
|
51
|
+
Returns ``True`` when a shim is in place (freshly applied or already
|
|
52
|
+
applied), ``False`` when none is needed or none could be applied — an
|
|
53
|
+
unimportable ``rich``, an uninspectable ``__init__``, or a signature that
|
|
54
|
+
already absorbs ``**kwargs``.
|
|
55
|
+
"""
|
|
56
|
+
try:
|
|
57
|
+
from rich.logging import RichHandler
|
|
58
|
+
except Exception: # pragma: no cover - rich absent or broken
|
|
59
|
+
# fastmcp depends on rich, so this means the import would fail anyway
|
|
60
|
+
# for reasons this shim cannot address.
|
|
61
|
+
logger.debug("rich.logging unavailable; skipping RichHandler shim")
|
|
62
|
+
return False
|
|
63
|
+
|
|
64
|
+
original_init = RichHandler.__init__
|
|
65
|
+
if getattr(original_init, _PATCH_MARKER, False):
|
|
66
|
+
return True
|
|
67
|
+
|
|
68
|
+
try:
|
|
69
|
+
parameters = inspect.signature(original_init).parameters
|
|
70
|
+
except (TypeError, ValueError): # pragma: no cover - exotic rich build
|
|
71
|
+
logger.debug("RichHandler.__init__ is not introspectable; skipping shim")
|
|
72
|
+
return False
|
|
73
|
+
|
|
74
|
+
if any(p.kind is inspect.Parameter.VAR_KEYWORD for p in parameters.values()):
|
|
75
|
+
# Already tolerant of anything fastmcp passes.
|
|
76
|
+
return False
|
|
77
|
+
|
|
78
|
+
if _PROBE_KWARG in parameters:
|
|
79
|
+
return False
|
|
80
|
+
|
|
81
|
+
supported = frozenset(parameters)
|
|
82
|
+
|
|
83
|
+
@functools.wraps(original_init)
|
|
84
|
+
def _init(self: Any, *args: Any, **kwargs: Any) -> Any:
|
|
85
|
+
dropped = kwargs.keys() - supported
|
|
86
|
+
if dropped:
|
|
87
|
+
logger.debug(
|
|
88
|
+
"Dropping RichHandler kwargs this rich does not accept: %s",
|
|
89
|
+
", ".join(sorted(dropped)),
|
|
90
|
+
)
|
|
91
|
+
return original_init(
|
|
92
|
+
self, *args, **{k: v for k, v in kwargs.items() if k in supported}
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
setattr(_init, _PATCH_MARKER, True)
|
|
96
|
+
RichHandler.__init__ = _init # type: ignore[method-assign]
|
|
97
|
+
|
|
98
|
+
logger.debug(
|
|
99
|
+
"Installed RichHandler compatibility shim: rich is older than "
|
|
100
|
+
"fastmcp expects, so tracebacks lose frame-limiting and "
|
|
101
|
+
"framework-frame suppression. Upgrade to rich>=13.9.4 to restore them."
|
|
102
|
+
)
|
|
103
|
+
return True
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
# Applied as an import side effect: ``ha_mcp/__init__.py`` imports this module
|
|
107
|
+
# ahead of anything that reaches fastmcp, and that is the only window in which
|
|
108
|
+
# the shim can do any good.
|
|
109
|
+
ensure_rich_handler_compat()
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"""FastMCP OIDC compatibility behavior scoped to ha-mcp's OIDC entrypoint."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
from typing import override
|
|
7
|
+
|
|
8
|
+
from fastmcp.server.auth.oauth_proxy.models import ProxyDCRClient
|
|
9
|
+
from fastmcp.server.auth.oidc_proxy import OIDCProxy
|
|
10
|
+
from mcp.server.auth.provider import AuthorizationParams, RefreshToken
|
|
11
|
+
from mcp.shared.auth import OAuthClientInformationFull
|
|
12
|
+
|
|
13
|
+
logger = logging.getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class HaMcpOIDCProxy(OIDCProxy):
|
|
17
|
+
"""OIDC proxy with ha-mcp's FastMCP 3.4.6 compatibility behavior."""
|
|
18
|
+
|
|
19
|
+
def _add_required_scopes(self, scopes: list[str]) -> list[str]:
|
|
20
|
+
"""Prepend any configured required scopes missing from ``scopes``."""
|
|
21
|
+
missing_scopes = [
|
|
22
|
+
scope for scope in self.required_scopes if scope not in scopes
|
|
23
|
+
]
|
|
24
|
+
return [*missing_scopes, *scopes]
|
|
25
|
+
|
|
26
|
+
def setup_scope_compatibility(self) -> None:
|
|
27
|
+
"""Allow optional DCR scopes without advertising them as requirements.
|
|
28
|
+
|
|
29
|
+
FastMCP 3.4.6 copies ``required_scopes`` into both the DCR default and
|
|
30
|
+
valid-scope allow-list. The MCP SDK then rejects clients that add
|
|
31
|
+
ordinary optional OIDC scopes. ``None`` restores upstream IdP scope
|
|
32
|
+
validation while FastMCP continues to default, advertise, and enforce
|
|
33
|
+
ha-mcp's required ``openid`` scope.
|
|
34
|
+
"""
|
|
35
|
+
if self.required_scopes != ["openid"]:
|
|
36
|
+
raise RuntimeError(
|
|
37
|
+
"HaMcpOIDCProxy requires exactly the openid scope before setup"
|
|
38
|
+
)
|
|
39
|
+
options = self.client_registration_options
|
|
40
|
+
if options is None:
|
|
41
|
+
raise RuntimeError("FastMCP OIDCProxy did not enable client registration")
|
|
42
|
+
if options.default_scopes != ["openid"] or self._default_scope_str != "openid":
|
|
43
|
+
raise RuntimeError("FastMCP OIDCProxy did not preserve the openid default")
|
|
44
|
+
options.valid_scopes = None
|
|
45
|
+
|
|
46
|
+
@override
|
|
47
|
+
async def register_client(self, client_info: OAuthClientInformationFull) -> None:
|
|
48
|
+
"""Persist DCR clients with every required scope included."""
|
|
49
|
+
current_scopes = client_info.scope.split() if client_info.scope else []
|
|
50
|
+
normalized_scopes = self._add_required_scopes(current_scopes)
|
|
51
|
+
if normalized_scopes != current_scopes:
|
|
52
|
+
client_info.scope = " ".join(normalized_scopes)
|
|
53
|
+
await super().register_client(client_info)
|
|
54
|
+
|
|
55
|
+
@override
|
|
56
|
+
async def authorize(
|
|
57
|
+
self,
|
|
58
|
+
client: OAuthClientInformationFull,
|
|
59
|
+
params: AuthorizationParams,
|
|
60
|
+
) -> str:
|
|
61
|
+
"""Forward every authorization with required scopes included."""
|
|
62
|
+
current_scopes = params.scopes or []
|
|
63
|
+
normalized_scopes = self._add_required_scopes(current_scopes)
|
|
64
|
+
if normalized_scopes != current_scopes:
|
|
65
|
+
params = params.model_copy(update={"scopes": normalized_scopes})
|
|
66
|
+
return await super().authorize(client, params)
|
|
67
|
+
|
|
68
|
+
@override
|
|
69
|
+
async def get_client(self, client_id: str) -> OAuthClientInformationFull | None:
|
|
70
|
+
"""Load a client, adding required scopes to persisted legacy records once."""
|
|
71
|
+
was_persisted = await self._client_store.get(key=client_id) is not None
|
|
72
|
+
client = await super().get_client(client_id)
|
|
73
|
+
if client is None or not was_persisted:
|
|
74
|
+
return client
|
|
75
|
+
if not isinstance(client, ProxyDCRClient):
|
|
76
|
+
raise RuntimeError("FastMCP returned an unexpected persisted client type")
|
|
77
|
+
|
|
78
|
+
current_scopes = client.scope.split() if client.scope else []
|
|
79
|
+
normalized_scopes = self._add_required_scopes(current_scopes)
|
|
80
|
+
if normalized_scopes == current_scopes:
|
|
81
|
+
return client
|
|
82
|
+
|
|
83
|
+
migrated = client.model_copy(update={"scope": " ".join(normalized_scopes)})
|
|
84
|
+
await self._client_store.put(key=client_id, value=migrated)
|
|
85
|
+
return migrated
|
|
86
|
+
|
|
87
|
+
@override
|
|
88
|
+
async def load_refresh_token(
|
|
89
|
+
self,
|
|
90
|
+
client: OAuthClientInformationFull,
|
|
91
|
+
refresh_token: str,
|
|
92
|
+
) -> RefreshToken | None:
|
|
93
|
+
"""Reject legacy refresh tokens that predate required OIDC scopes."""
|
|
94
|
+
loaded = await super().load_refresh_token(client, refresh_token)
|
|
95
|
+
if loaded is None:
|
|
96
|
+
return None
|
|
97
|
+
missing_scopes = set(self.required_scopes) - set(loaded.scopes)
|
|
98
|
+
if missing_scopes:
|
|
99
|
+
logger.debug(
|
|
100
|
+
"Rejecting legacy refresh token for client_id=%s: "
|
|
101
|
+
"missing required scopes %s",
|
|
102
|
+
client.client_id,
|
|
103
|
+
sorted(missing_scopes),
|
|
104
|
+
)
|
|
105
|
+
return None
|
|
106
|
+
return loaded
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ha-mcp-dev
|
|
3
|
-
Version: 8.
|
|
3
|
+
Version: 8.2.0.dev2307
|
|
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
|
|
@@ -19,7 +19,7 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
|
19
19
|
Requires-Python: <3.15,>=3.13
|
|
20
20
|
Description-Content-Type: text/markdown
|
|
21
21
|
License-File: LICENSE
|
|
22
|
-
Requires-Dist: fastmcp==3.4.
|
|
22
|
+
Requires-Dist: fastmcp==3.4.6
|
|
23
23
|
Requires-Dist: httpx[socks]==0.28.1
|
|
24
24
|
Requires-Dist: pydantic==2.13.4
|
|
25
25
|
Requires-Dist: python-dotenv==1.2.2
|
|
@@ -117,7 +117,7 @@ These run the server outside Home Assistant — useful for **Container** / **Cor
|
|
|
117
117
|
- **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.
|
|
118
118
|
- **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/).
|
|
119
119
|
- **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.
|
|
120
|
-
- **OIDC authentication:** gate remote access behind an external identity provider (Authentik, Keycloak, Auth0,
|
|
120
|
+
- **OIDC authentication:** gate remote access behind an external identity provider (Authentik, Keycloak, Auth0, etc.) instead of a secret URL — all authenticated users share the server's Home Assistant credentials. See [OIDC Mode](docs/oidc.md).
|
|
121
121
|
|
|
122
122
|
> ⚠️ **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
123
|
|
|
@@ -5,6 +5,7 @@ pyproject.toml
|
|
|
5
5
|
src/ha_mcp/__init__.py
|
|
6
6
|
src/ha_mcp/__main__.py
|
|
7
7
|
src/ha_mcp/_pypi_marker
|
|
8
|
+
src/ha_mcp/_rich_compat.py
|
|
8
9
|
src/ha_mcp/_version.py
|
|
9
10
|
src/ha_mcp/backup_manager.py
|
|
10
11
|
src/ha_mcp/browser_landing.py
|
|
@@ -81,6 +82,7 @@ src/ha_mcp/_vendor/websockets/trio/server.py
|
|
|
81
82
|
src/ha_mcp/_vendor/websockets/trio/utils.py
|
|
82
83
|
src/ha_mcp/auth/__init__.py
|
|
83
84
|
src/ha_mcp/auth/consent_form.py
|
|
85
|
+
src/ha_mcp/auth/oidc_compat.py
|
|
84
86
|
src/ha_mcp/auth/provider.py
|
|
85
87
|
src/ha_mcp/client/__init__.py
|
|
86
88
|
src/ha_mcp/client/rest_client.py
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/MANIFEST.sha256
RENAMED
|
File without changes
|
{ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/VENDORED
RENAMED
|
File without changes
|
{ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/__init__.py
RENAMED
|
File without changes
|
{ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/__main__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/client.py
RENAMED
|
File without changes
|
{ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/connection.py
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/exceptions.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/frames.py
RENAMED
|
File without changes
|
{ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/headers.py
RENAMED
|
File without changes
|
{ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/http11.py
RENAMED
|
File without changes
|
{ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/imports.py
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/legacy/auth.py
RENAMED
|
File without changes
|
{ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/legacy/client.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/legacy/http.py
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/legacy/server.py
RENAMED
|
File without changes
|
{ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/protocol.py
RENAMED
|
File without changes
|
{ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/proxy.py
RENAMED
|
File without changes
|
{ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/py.typed
RENAMED
|
File without changes
|
{ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/server.py
RENAMED
|
File without changes
|
{ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/streams.py
RENAMED
|
File without changes
|
{ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/sync/__init__.py
RENAMED
|
File without changes
|
{ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/sync/client.py
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/sync/messages.py
RENAMED
|
File without changes
|
{ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/sync/router.py
RENAMED
|
File without changes
|
{ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/sync/server.py
RENAMED
|
File without changes
|
{ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/sync/utils.py
RENAMED
|
File without changes
|
{ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/trio/__init__.py
RENAMED
|
File without changes
|
{ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/trio/client.py
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/trio/messages.py
RENAMED
|
File without changes
|
{ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/trio/router.py
RENAMED
|
File without changes
|
{ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/trio/server.py
RENAMED
|
File without changes
|
{ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/trio/utils.py
RENAMED
|
File without changes
|
{ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/typing.py
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/utils.py
RENAMED
|
File without changes
|
{ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/_vendor/websockets/version.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/client/supervisor_client.py
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/client/websocket_listener.py
RENAMED
|
File without changes
|
|
File without changes
|
{ha_mcp_dev-8.1.1.dev2296 → ha_mcp_dev-8.2.0.dev2307}/src/ha_mcp/dashboard_screenshot/__init__.py
RENAMED
|
File without changes
|