ha-mcp-dev 8.0.0.dev2230__tar.gz → 8.0.0.dev2235__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.
Files changed (198) hide show
  1. {ha_mcp_dev-8.0.0.dev2230/src/ha_mcp_dev.egg-info → ha_mcp_dev-8.0.0.dev2235}/PKG-INFO +1 -1
  2. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/pyproject.toml +1 -1
  3. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/__main__.py +48 -6
  4. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/client/websocket_client.py +30 -2
  5. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/settings_ui/__init__.py +9 -0
  6. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/tools_code.py +14 -2
  7. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/transport_security.py +6 -0
  8. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235/src/ha_mcp_dev.egg-info}/PKG-INFO +1 -1
  9. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/LICENSE +0 -0
  10. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/MANIFEST.in +0 -0
  11. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/README.md +0 -0
  12. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/setup.cfg +0 -0
  13. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/__init__.py +0 -0
  14. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/_pypi_marker +0 -0
  15. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/_version.py +0 -0
  16. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/auth/__init__.py +0 -0
  17. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/auth/consent_form.py +0 -0
  18. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/auth/provider.py +0 -0
  19. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/backup_manager.py +0 -0
  20. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/browser_landing.py +0 -0
  21. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/client/__init__.py +0 -0
  22. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/client/rest_client.py +0 -0
  23. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/client/supervisor_client.py +0 -0
  24. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/client/websocket_listener.py +0 -0
  25. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/config.py +0 -0
  26. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/dashboard_screenshot/__init__.py +0 -0
  27. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/dashboard_screenshot/capture.py +0 -0
  28. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/dashboard_screenshot/content.py +0 -0
  29. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/dashboard_screenshot/paths.py +0 -0
  30. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/dashboard_screenshot/provision.py +0 -0
  31. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/dashboard_screenshot/theme_guard.py +0 -0
  32. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/errors.py +0 -0
  33. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/llm_exposure.py +0 -0
  34. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/policy/__init__.py +0 -0
  35. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/policy/approval_queue.py +0 -0
  36. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/policy/evaluator.py +0 -0
  37. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/policy/handlers.py +0 -0
  38. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/policy/middleware.py +0 -0
  39. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/policy/model.py +0 -0
  40. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/policy/persistence.py +0 -0
  41. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/policy/value_sources.py +0 -0
  42. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/py.typed +0 -0
  43. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/read_only.py +0 -0
  44. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/resources/skills-vendor/.claude/settings.json +0 -0
  45. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/resources/skills-vendor/.claude-plugin/marketplace.json +0 -0
  46. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/resources/skills-vendor/.claude-plugin/plugin.json +0 -0
  47. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/resources/skills-vendor/.github/ISSUE_TEMPLATE/skill-rca.md +0 -0
  48. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/resources/skills-vendor/.github/pull_request_template.md +0 -0
  49. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/resources/skills-vendor/AGENTS.md +0 -0
  50. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/resources/skills-vendor/CLAUDE.md +0 -0
  51. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/resources/skills-vendor/CONTRIBUTING.md +0 -0
  52. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/resources/skills-vendor/LICENSE +0 -0
  53. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/resources/skills-vendor/README.md +0 -0
  54. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/SKILL.md +0 -0
  55. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/evals/evals.json +0 -0
  56. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/appdaemon.md +0 -0
  57. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/automation-patterns.md +0 -0
  58. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/blueprint-guide.md +0 -0
  59. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-cards.md +0 -0
  60. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-guide.md +0 -0
  61. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/device-control.md +0 -0
  62. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/domain-docs.md +0 -0
  63. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/examples.yaml +0 -0
  64. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/helper-selection.md +0 -0
  65. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/safe-refactoring.md +0 -0
  66. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/scenes.md +0 -0
  67. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/template-guidelines.md +0 -0
  68. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/yaml-only-integrations.md +0 -0
  69. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/server.py +0 -0
  70. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/settings_ui/_handlers_advanced.py +0 -0
  71. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/settings_ui/_handlers_backups.py +0 -0
  72. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/settings_ui/_handlers_fs.py +0 -0
  73. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/settings_ui/_handlers_server.py +0 -0
  74. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/settings_ui/_handlers_theme.py +0 -0
  75. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/settings_ui/_handlers_tools.py +0 -0
  76. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/settings_ui/_i18n.py +0 -0
  77. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/settings_ui/_persistence.py +0 -0
  78. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/settings_ui/_supervisor.py +0 -0
  79. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/settings_ui/_theme.py +0 -0
  80. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/settings_ui/_tools_meta.py +0 -0
  81. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/settings_ui/locales/README.md +0 -0
  82. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/settings_ui/locales/de.json +0 -0
  83. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/settings_ui/locales/en.json +0 -0
  84. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/settings_ui/locales/es.json +0 -0
  85. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/settings_ui/locales/fr.json +0 -0
  86. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/settings_ui/locales/it.json +0 -0
  87. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/settings_ui/locales/ru.json +0 -0
  88. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/settings_ui/locales/zh-Hans.json +0 -0
  89. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/settings_ui/settings.css +0 -0
  90. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/settings_ui/settings.html +0 -0
  91. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/settings_ui/settings.js +0 -0
  92. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/smoke_test.py +0 -0
  93. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/stdio_settings_sidecar.py +0 -0
  94. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/strict_bps.py +0 -0
  95. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/__init__.py +0 -0
  96. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/auto_backup.py +0 -0
  97. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/backup.py +0 -0
  98. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/best_practice_checker.py +0 -0
  99. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/best_practice_result.py +0 -0
  100. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/best_practice_variables.py +0 -0
  101. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/component_api.py +0 -0
  102. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/component_config_reads.py +0 -0
  103. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/component_devices.py +0 -0
  104. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/component_registries.py +0 -0
  105. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/component_registry_lookup.py +0 -0
  106. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/config_entry_flow.py +0 -0
  107. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/config_entry_flow_form.py +0 -0
  108. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/config_entry_flow_menu.py +0 -0
  109. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/config_entry_flow_walker.py +0 -0
  110. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/device_control.py +0 -0
  111. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/hacs_registration.py +0 -0
  112. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/helpers.py +0 -0
  113. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/radio/__init__.py +0 -0
  114. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/radio/base.py +0 -0
  115. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/radio/matter.py +0 -0
  116. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/radio/thread.py +0 -0
  117. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/radio/zigbee.py +0 -0
  118. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/radio/zwave.py +0 -0
  119. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/reference_validator.py +0 -0
  120. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/registry.py +0 -0
  121. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/smart_search/__init__.py +0 -0
  122. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/smart_search/_base.py +0 -0
  123. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/smart_search/_config.py +0 -0
  124. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/smart_search/_deep.py +0 -0
  125. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/smart_search/_entities.py +0 -0
  126. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/smart_search/_fetch.py +0 -0
  127. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/smart_search/_overview.py +0 -0
  128. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/smart_search/_scenes.py +0 -0
  129. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/smart_search/_scoring.py +0 -0
  130. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/tool_search_hint_middleware.py +0 -0
  131. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/tools_addons.py +0 -0
  132. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/tools_areas.py +0 -0
  133. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/tools_blueprints.py +0 -0
  134. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/tools_bug_report.py +0 -0
  135. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/tools_calendar.py +0 -0
  136. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/tools_camera.py +0 -0
  137. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/tools_categories.py +0 -0
  138. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/tools_config_automations.py +0 -0
  139. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/tools_config_dashboards.py +0 -0
  140. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/tools_config_helpers.py +0 -0
  141. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/tools_config_scenes.py +0 -0
  142. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/tools_config_scripts.py +0 -0
  143. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/tools_dashboard_screenshot.py +0 -0
  144. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/tools_dev.py +0 -0
  145. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/tools_energy.py +0 -0
  146. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/tools_entities.py +0 -0
  147. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/tools_filesystem.py +0 -0
  148. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/tools_groups.py +0 -0
  149. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/tools_hacs.py +0 -0
  150. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/tools_history.py +0 -0
  151. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/tools_integrations.py +0 -0
  152. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/tools_labels.py +0 -0
  153. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/tools_radio.py +0 -0
  154. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/tools_registry.py +0 -0
  155. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/tools_resources.py +0 -0
  156. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/tools_search.py +0 -0
  157. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/tools_service.py +0 -0
  158. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/tools_services.py +0 -0
  159. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/tools_system.py +0 -0
  160. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/tools_themes.py +0 -0
  161. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/tools_todo.py +0 -0
  162. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/tools_traces.py +0 -0
  163. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/tools_updates.py +0 -0
  164. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/tools_utility.py +0 -0
  165. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/tools_voice_assistant.py +0 -0
  166. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/tools_yaml_config.py +0 -0
  167. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/tools_yaml_read.py +0 -0
  168. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/tools_zones.py +0 -0
  169. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/util_helpers.py +0 -0
  170. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/tools/validation_middleware.py +0 -0
  171. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/transforms/__init__.py +0 -0
  172. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/transforms/categorized_search.py +0 -0
  173. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/transforms/lite_docstrings.py +0 -0
  174. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/update_check.py +0 -0
  175. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/utils/__init__.py +0 -0
  176. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/utils/config_hash.py +0 -0
  177. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/utils/config_write_lock.py +0 -0
  178. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/utils/data_paths.py +0 -0
  179. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/utils/domain_handlers.py +0 -0
  180. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/utils/fuzzy_search.py +0 -0
  181. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/utils/kill_signal_diagnostics.py +0 -0
  182. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/utils/operation_manager.py +0 -0
  183. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/utils/python_sandbox.py +0 -0
  184. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/utils/skill_loader.py +0 -0
  185. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/utils/usage_logger.py +0 -0
  186. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/visibility/__init__.py +0 -0
  187. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/visibility/enforcement.py +0 -0
  188. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/visibility/model.py +0 -0
  189. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/visibility/persistence.py +0 -0
  190. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp/visibility/resolver.py +0 -0
  191. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp_dev.egg-info/SOURCES.txt +0 -0
  192. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp_dev.egg-info/dependency_links.txt +0 -0
  193. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp_dev.egg-info/entry_points.txt +0 -0
  194. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp_dev.egg-info/requires.txt +0 -0
  195. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/src/ha_mcp_dev.egg-info/top_level.txt +0 -0
  196. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/tests/__init__.py +0 -0
  197. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/tests/test_constants.py +0 -0
  198. {ha_mcp_dev-8.0.0.dev2230 → ha_mcp_dev-8.0.0.dev2235}/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.0.0.dev2230
3
+ Version: 8.0.0.dev2235
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
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "ha-mcp-dev"
7
- version = "8.0.0.dev2230"
7
+ version = "8.0.0.dev2235"
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
@@ -609,6 +609,25 @@ async def _cleanup_resources() -> None:
609
609
  logger.info("Server resources cleaned up")
610
610
 
611
611
 
612
+ def _log_cleanup_result(task: "asyncio.Future[None]") -> None:
613
+ """Consume the cleanup task's outcome so a failure is never silent.
614
+
615
+ ``asyncio.wait`` does not retrieve results, and the timeout path
616
+ deliberately abandons rather than awaits (see the ``finally`` block), so
617
+ without this nothing observes ``cleanup_task``. An exception left
618
+ unretrieved this close to loop teardown surfaces only as a GC-time "Task
619
+ exception was never retrieved" error, which is unstructured and not
620
+ guaranteed to be emitted before exit. Mirrors what ``_cancel_tasks`` does
621
+ for the tasks it reaps. Cancellation is the expected abandoned-timeout
622
+ outcome and stays silent.
623
+ """
624
+ if task.cancelled():
625
+ return
626
+ exc = task.exception()
627
+ if exc is not None:
628
+ logger.warning(f"Resource cleanup raised: {exc!r}")
629
+
630
+
612
631
  async def _cancel_tasks(*tasks: asyncio.Task) -> None:
613
632
  """Cancel tasks and wait for completion, bounding the wait.
614
633
 
@@ -690,11 +709,19 @@ async def _run_with_shutdown(server_coro: Coroutine[Any, Any, Any]) -> None:
690
709
  logger.error("Server task cancelled without a shutdown signal")
691
710
  raise
692
711
  finally:
693
- try:
694
- await asyncio.wait_for(
695
- _cleanup_resources(), timeout=SHUTDOWN_TIMEOUT_SECONDS
696
- )
697
- except TimeoutError:
712
+ # Cancel-and-abandon, not wait_for: wait_for awaits the cancelled
713
+ # coroutine before raising, and the cleanup stack swallows
714
+ # CancelledError at several layers (per-client in
715
+ # WebSocketManager.disconnect, in client.disconnect's own task-cancel
716
+ # guard), so a hung close handshake could block shutdown past the
717
+ # budget. A straggler is left to the runner's own task sweep.
718
+ cleanup_task = asyncio.ensure_future(_cleanup_resources())
719
+ cleanup_task.add_done_callback(_log_cleanup_result)
720
+ _done, cleanup_pending = await asyncio.wait(
721
+ {cleanup_task}, timeout=SHUTDOWN_TIMEOUT_SECONDS
722
+ )
723
+ if cleanup_pending:
724
+ cleanup_task.cancel()
698
725
  logger.warning("Resource cleanup timed out")
699
726
 
700
727
  try:
@@ -997,6 +1024,19 @@ def _get_http_runtime(default_port: int = 8086) -> tuple[str, int, str]:
997
1024
  ``run_async``, any ``FASTMCP_HOST`` value in the environment is
998
1025
  ignored — ``MCP_HOST`` is the only env var that affects bind host
999
1026
  for ha-mcp's CLI entry points.
1027
+
1028
+ The ``0.0.0.0`` default is deliberate and documented: SECURITY.md
1029
+ § "Local network is the trusted zone for standard mode" states that the
1030
+ HTTP entrypoints bind to all interfaces so LAN peers can reach them, and
1031
+ its Scope section excludes "LAN-peer access to standard-mode HTTP
1032
+ endpoints".
1033
+
1034
+ The default ``/mcp`` path is *not* blessed the same way once the bind
1035
+ leaves loopback. That combination is what ``_warn_if_default_path_exposed``
1036
+ warns about, and SECURITY.md's Scope classes it under "a misconfigured
1037
+ deployment" — meaning such reports are declined, not that the
1038
+ configuration is endorsed. Operators on a non-loopback bind are still
1039
+ expected to set a high-entropy ``MCP_SECRET_PATH``.
1000
1040
  """
1001
1041
 
1002
1042
  host = os.getenv("MCP_HOST", "0.0.0.0")
@@ -1013,7 +1053,9 @@ def _get_http_runtime(default_port: int = 8086) -> tuple[str, int, str]:
1013
1053
  # Default ``MCP_SECRET_PATH`` value, shared by ``_get_http_runtime`` (the
1014
1054
  # read-from-env fallback) and ``_warn_if_default_path_exposed`` (the
1015
1055
  # hardening-nudge predicate). Single source of truth so the two sites
1016
- # can't drift.
1056
+ # can't drift. Safe on a loopback bind; on a non-loopback bind it is the
1057
+ # misconfiguration ``_warn_if_default_path_exposed`` flags, which SECURITY.md
1058
+ # declines to action without endorsing — see ``_get_http_runtime`` above.
1017
1059
  DEFAULT_MCP_PATH = "/mcp"
1018
1060
 
1019
1061
  # Hostname literals (not IP addresses) treated as loopback by
@@ -1251,10 +1251,31 @@ class WebSocketManager:
1251
1251
  self._last_used[key] = time.monotonic()
1252
1252
  return existing
1253
1253
 
1254
- # Remove stale client if present
1254
+ # Remove stale client if present. Disconnect it too: a client
1255
+ # whose connection dropped can still own a parked reader task and
1256
+ # a half-open socket, and simply dropping the reference abandons
1257
+ # both to garbage collection — the GC's asyncgen finalizer then
1258
+ # acloses the reader's ``Connection.__aiter__`` mid-``__anext__``
1259
+ # and logs ``aclose(): asynchronous generator is already
1260
+ # running`` (issue #2127). Same-loop by construction: a loop
1261
+ # change already detached the pool above, so ``existing`` was
1262
+ # built on ``current_loop`` and can be awaited here.
1255
1263
  if existing:
1256
1264
  self._clients.pop(key, None)
1257
1265
  self._last_used.pop(key, None)
1266
+ try:
1267
+ await existing.disconnect()
1268
+ except asyncio.CancelledError:
1269
+ # The caller itself was cancelled mid-cleanup: propagate.
1270
+ # Swallowing here would let a cancelled operation keep
1271
+ # doing network I/O and leave a fresh connection retained
1272
+ # in the pool.
1273
+ raise
1274
+ except (OSError, RuntimeError):
1275
+ logger.warning(
1276
+ "Error disconnecting stale WebSocket client",
1277
+ exc_info=True,
1278
+ )
1258
1279
 
1259
1280
  factory = self._client_factory or HomeAssistantWebSocketClient
1260
1281
  client = (
@@ -1291,7 +1312,14 @@ class WebSocketManager:
1291
1312
  if stale:
1292
1313
  try:
1293
1314
  await stale.disconnect()
1294
- except (OSError, RuntimeError, asyncio.CancelledError):
1315
+ except asyncio.CancelledError:
1316
+ # The caller itself was cancelled mid-eviction: propagate.
1317
+ # Eviction runs after the fresh client was pooled, so a
1318
+ # swallow here would hand a connected client back to a
1319
+ # cancelled caller (mirror of the stale-replacement clause
1320
+ # in get_client).
1321
+ raise
1322
+ except (OSError, RuntimeError):
1295
1323
  logger.warning(
1296
1324
  "Error disconnecting evicted WebSocket client",
1297
1325
  exc_info=True,
@@ -566,6 +566,15 @@ def register_settings_routes(
566
566
  and serve the "Open Web UI" button. Stdio transports use a separate
567
567
  side-process sidecar instead — see :mod:`ha_mcp.stdio_settings_sidecar`.
568
568
 
569
+ The ``RequireAuthMiddleware`` bypass is the documented posture, not an
570
+ oversight: SECURITY.md § "OAuth Mode — Beta Warning" states that the
571
+ settings UI "is **not** gated by the OAuth token", and its Scope section
572
+ excludes "The web settings UI not being gated by the OAuth/OIDC token".
573
+ OAuth and OIDC modes compensate by passing a *dedicated* secret path here
574
+ rather than the client-known MCP path (GHSA-mx64-982r-65vg); standard mode
575
+ and the add-on pass the MCP secret path, which already gates the whole
576
+ tool surface.
577
+
569
578
  Args:
570
579
  mcp: The FastMCP instance to register routes on.
571
580
  server: The HomeAssistantSmartMCPServer wrapping ``mcp``.
@@ -53,8 +53,20 @@ logger = logging.getLogger(__name__)
53
53
  # boundary.
54
54
  #
55
55
  # WARNING: This is shared across all clients in the same server process.
56
- # In multi-user modes (OAuth, HTTP), one user's saved tools are visible to
57
- # all other users. Scope to per-session/user before multi-user support.
56
+ # One client's saved tools are listable and runnable by every other client,
57
+ # and ``save_as`` overwrites by name without an ownership check. OAuth is the
58
+ # only mode with distinct per-user credentials for that to cross; standard,
59
+ # OIDC and add-on modes are single-tenant already (SECURITY.md § "Standard
60
+ # mode is single-tenant"), so every caller there shares one HA token anyway.
61
+ #
62
+ # That exposure is accepted design, not a pending TODO — SECURITY.md § Scope
63
+ # excludes "Saved custom tools (code mode, off by default) visible to other
64
+ # clients of the same server process", on the grounds that they are shared
65
+ # scaffolding rather than per-user data, that ``run_saved`` executes with the
66
+ # caller's own HA token (granting no access the caller lacks), and that any
67
+ # client which can reach ha-mcp is a trusted principal (SECURITY.md § "MCP
68
+ # clients are trusted principals"). Scoping per session/user would be a
69
+ # feature, not a security fix.
58
70
  _saved_tools: dict[str, dict[str, str]] = {}
59
71
 
60
72
  # Tools that sandbox code must not call. Includes ``ha_manage_custom_tool``
@@ -23,6 +23,12 @@ exactly the pre-3.4.3 behaviour without giving up the protection that matters.
23
23
  Operators who front ha-mcp differently can re-enable the guard (and pin their
24
24
  own allow-lists) via ``FASTMCP_HTTP_HOST_ORIGIN_PROTECTION=true`` plus
25
25
  ``FASTMCP_HTTP_ALLOWED_HOSTS`` / ``FASTMCP_HTTP_ALLOWED_ORIGINS``.
26
+
27
+ Turning the guard off is the documented posture, not an oversight: it has its
28
+ own SECURITY.md section, § "Host/Origin validation (DNS-rebinding guard) is off
29
+ by default", and the Scope section there excludes "DNS rebinding against the
30
+ HTTP entrypoints" on the grounds that URL-path secrecy is the boundary and the
31
+ local network is already the trusted zone.
26
32
  """
27
33
 
28
34
  from __future__ import annotations
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ha-mcp-dev
3
- Version: 8.0.0.dev2230
3
+ Version: 8.0.0.dev2235
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