ha-mcp-dev 7.13.0.dev1990__tar.gz → 7.13.0.dev1992__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 (187) hide show
  1. {ha_mcp_dev-7.13.0.dev1990/src/ha_mcp_dev.egg-info → ha_mcp_dev-7.13.0.dev1992}/PKG-INFO +1 -1
  2. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/pyproject.toml +1 -1
  3. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/strict_bps.py +73 -17
  4. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992/src/ha_mcp_dev.egg-info}/PKG-INFO +1 -1
  5. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/LICENSE +0 -0
  6. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/MANIFEST.in +0 -0
  7. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/README.md +0 -0
  8. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/setup.cfg +0 -0
  9. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/__init__.py +0 -0
  10. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/__main__.py +0 -0
  11. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/_pypi_marker +0 -0
  12. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/_version.py +0 -0
  13. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/auth/__init__.py +0 -0
  14. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/auth/consent_form.py +0 -0
  15. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/auth/provider.py +0 -0
  16. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/backup_manager.py +0 -0
  17. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/browser_landing.py +0 -0
  18. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/client/__init__.py +0 -0
  19. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/client/rest_client.py +0 -0
  20. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/client/supervisor_client.py +0 -0
  21. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/client/websocket_client.py +0 -0
  22. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/client/websocket_listener.py +0 -0
  23. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/config.py +0 -0
  24. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/dashboard_screenshot/__init__.py +0 -0
  25. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/dashboard_screenshot/capture.py +0 -0
  26. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/dashboard_screenshot/content.py +0 -0
  27. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/dashboard_screenshot/paths.py +0 -0
  28. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/dashboard_screenshot/provision.py +0 -0
  29. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/dashboard_screenshot/theme_guard.py +0 -0
  30. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/errors.py +0 -0
  31. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/llm_exposure.py +0 -0
  32. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/policy/__init__.py +0 -0
  33. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/policy/approval_queue.py +0 -0
  34. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/policy/evaluator.py +0 -0
  35. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/policy/handlers.py +0 -0
  36. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/policy/middleware.py +0 -0
  37. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/policy/model.py +0 -0
  38. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/policy/persistence.py +0 -0
  39. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/policy/value_sources.py +0 -0
  40. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/py.typed +0 -0
  41. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/read_only.py +0 -0
  42. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/resources/skills-vendor/.claude/settings.json +0 -0
  43. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/resources/skills-vendor/.claude-plugin/marketplace.json +0 -0
  44. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/resources/skills-vendor/.claude-plugin/plugin.json +0 -0
  45. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/resources/skills-vendor/.github/ISSUE_TEMPLATE/skill-rca.md +0 -0
  46. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/resources/skills-vendor/.github/pull_request_template.md +0 -0
  47. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/resources/skills-vendor/AGENTS.md +0 -0
  48. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/resources/skills-vendor/CLAUDE.md +0 -0
  49. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/resources/skills-vendor/CONTRIBUTING.md +0 -0
  50. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/resources/skills-vendor/LICENSE +0 -0
  51. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/resources/skills-vendor/README.md +0 -0
  52. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/SKILL.md +0 -0
  53. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/evals/evals.json +0 -0
  54. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/appdaemon.md +0 -0
  55. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/automation-patterns.md +0 -0
  56. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/blueprint-guide.md +0 -0
  57. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-cards.md +0 -0
  58. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-guide.md +0 -0
  59. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/device-control.md +0 -0
  60. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/domain-docs.md +0 -0
  61. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/examples.yaml +0 -0
  62. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/helper-selection.md +0 -0
  63. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/safe-refactoring.md +0 -0
  64. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/scenes.md +0 -0
  65. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/template-guidelines.md +0 -0
  66. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/yaml-only-integrations.md +0 -0
  67. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/server.py +0 -0
  68. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/settings_ui/__init__.py +0 -0
  69. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/settings_ui/_handlers_advanced.py +0 -0
  70. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/settings_ui/_handlers_backups.py +0 -0
  71. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/settings_ui/_handlers_fs.py +0 -0
  72. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/settings_ui/_handlers_server.py +0 -0
  73. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/settings_ui/_handlers_theme.py +0 -0
  74. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/settings_ui/_handlers_tools.py +0 -0
  75. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/settings_ui/_i18n.py +0 -0
  76. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/settings_ui/_persistence.py +0 -0
  77. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/settings_ui/_supervisor.py +0 -0
  78. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/settings_ui/_theme.py +0 -0
  79. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/settings_ui/_tools_meta.py +0 -0
  80. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/settings_ui/locales/README.md +0 -0
  81. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/settings_ui/locales/de.json +0 -0
  82. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/settings_ui/locales/en.json +0 -0
  83. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/settings_ui/locales/ru.json +0 -0
  84. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/settings_ui/settings.css +0 -0
  85. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/settings_ui/settings.html +0 -0
  86. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/settings_ui/settings.js +0 -0
  87. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/smoke_test.py +0 -0
  88. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/stdio_settings_sidecar.py +0 -0
  89. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/__init__.py +0 -0
  90. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/auto_backup.py +0 -0
  91. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/backup.py +0 -0
  92. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/best_practice_checker.py +0 -0
  93. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/component_api.py +0 -0
  94. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/component_config_reads.py +0 -0
  95. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/component_devices.py +0 -0
  96. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/component_registries.py +0 -0
  97. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/component_registry_lookup.py +0 -0
  98. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/config_entry_flow.py +0 -0
  99. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/device_control.py +0 -0
  100. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/enhanced.py +0 -0
  101. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/helpers.py +0 -0
  102. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/radio/__init__.py +0 -0
  103. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/radio/base.py +0 -0
  104. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/radio/matter.py +0 -0
  105. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/radio/thread.py +0 -0
  106. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/radio/zigbee.py +0 -0
  107. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/radio/zwave.py +0 -0
  108. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/reference_validator.py +0 -0
  109. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/registry.py +0 -0
  110. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/smart_search/__init__.py +0 -0
  111. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/smart_search/_base.py +0 -0
  112. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/smart_search/_config.py +0 -0
  113. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/smart_search/_deep.py +0 -0
  114. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/smart_search/_entities.py +0 -0
  115. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/smart_search/_fetch.py +0 -0
  116. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/smart_search/_overview.py +0 -0
  117. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/smart_search/_scenes.py +0 -0
  118. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/smart_search/_scoring.py +0 -0
  119. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/tool_search_hint_middleware.py +0 -0
  120. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/tools_addons.py +0 -0
  121. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/tools_areas.py +0 -0
  122. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/tools_blueprints.py +0 -0
  123. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/tools_bug_report.py +0 -0
  124. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/tools_calendar.py +0 -0
  125. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/tools_camera.py +0 -0
  126. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/tools_categories.py +0 -0
  127. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/tools_code.py +0 -0
  128. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/tools_config_automations.py +0 -0
  129. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/tools_config_dashboards.py +0 -0
  130. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/tools_config_helpers.py +0 -0
  131. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/tools_config_scenes.py +0 -0
  132. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/tools_config_scripts.py +0 -0
  133. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/tools_dashboard_screenshot.py +0 -0
  134. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/tools_dev.py +0 -0
  135. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/tools_energy.py +0 -0
  136. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/tools_entities.py +0 -0
  137. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/tools_filesystem.py +0 -0
  138. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/tools_groups.py +0 -0
  139. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/tools_hacs.py +0 -0
  140. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/tools_history.py +0 -0
  141. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/tools_integrations.py +0 -0
  142. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/tools_labels.py +0 -0
  143. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/tools_radio.py +0 -0
  144. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/tools_registry.py +0 -0
  145. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/tools_resources.py +0 -0
  146. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/tools_search.py +0 -0
  147. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/tools_service.py +0 -0
  148. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/tools_services.py +0 -0
  149. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/tools_system.py +0 -0
  150. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/tools_themes.py +0 -0
  151. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/tools_todo.py +0 -0
  152. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/tools_traces.py +0 -0
  153. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/tools_updates.py +0 -0
  154. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/tools_utility.py +0 -0
  155. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/tools_voice_assistant.py +0 -0
  156. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/tools_yaml_config.py +0 -0
  157. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/tools_yaml_read.py +0 -0
  158. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/tools_zones.py +0 -0
  159. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/util_helpers.py +0 -0
  160. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/tools/validation_middleware.py +0 -0
  161. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/transforms/__init__.py +0 -0
  162. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/transforms/categorized_search.py +0 -0
  163. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/transforms/lite_docstrings.py +0 -0
  164. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/transport_security.py +0 -0
  165. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/update_check.py +0 -0
  166. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/utils/__init__.py +0 -0
  167. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/utils/config_hash.py +0 -0
  168. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/utils/data_paths.py +0 -0
  169. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/utils/domain_handlers.py +0 -0
  170. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/utils/fuzzy_search.py +0 -0
  171. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/utils/kill_signal_diagnostics.py +0 -0
  172. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/utils/operation_manager.py +0 -0
  173. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/utils/python_sandbox.py +0 -0
  174. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/utils/skill_loader.py +0 -0
  175. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/utils/usage_logger.py +0 -0
  176. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/visibility/__init__.py +0 -0
  177. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/visibility/model.py +0 -0
  178. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/visibility/persistence.py +0 -0
  179. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp/visibility/resolver.py +0 -0
  180. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp_dev.egg-info/SOURCES.txt +0 -0
  181. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp_dev.egg-info/dependency_links.txt +0 -0
  182. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp_dev.egg-info/entry_points.txt +0 -0
  183. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp_dev.egg-info/requires.txt +0 -0
  184. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/src/ha_mcp_dev.egg-info/top_level.txt +0 -0
  185. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/tests/__init__.py +0 -0
  186. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/tests/test_constants.py +0 -0
  187. {ha_mcp_dev-7.13.0.dev1990 → ha_mcp_dev-7.13.0.dev1992}/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.dev1990
3
+ Version: 7.13.0.dev1992
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 = "7.13.0.dev1990"
7
+ version = "7.13.0.dev1992"
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,10 @@ schema-validating clients will send it; the tool bodies never read it —
28
28
 
29
29
  from __future__ import annotations
30
30
 
31
+ import hashlib
31
32
  import logging
33
+ import secrets
34
+ import time
32
35
  from collections.abc import Awaitable, Callable, Sequence
33
36
  from typing import Annotated, Any, NoReturn
34
37
 
@@ -55,11 +58,50 @@ def _warn_degraded_once(branch: str, message: str, *, exc_info: bool = False) ->
55
58
  logger.warning(message, exc_info=exc_info)
56
59
 
57
60
 
58
- # Single source of truth for the acknowledgment key literal. It is published
59
- # ONLY by ``strict_bps_ack_line`` (surfaced through ha_get_skill_guide Tier 3
60
- # when strict mode is effective) and validated ONLY by the middleware it must
61
- # never appear in a block error, a tool docstring, or a skill_content embed.
62
- STRICT_BPS_ACK_KEY = "bps-ack-1779"
61
+ # The acknowledgment key is deliberately NOT a static opaque token (#1924):
62
+ #
63
+ # * The PREFIX is a plain-English attestation phrase so the value cannot be
64
+ # mistaken for a credential. An agent shown the old opaque ``bps-ack-*``
65
+ # token misread the extract-and-replay round-trip as prompt injection,
66
+ # refused every gated write, and steered the user into disabling strict
67
+ # mode — the opposite of the gate's purpose. The key is a read-receipt:
68
+ # public, privilege-free proof the skill content entered the model's
69
+ # context before a write.
70
+ # * The SUFFIX rotates hourly, derived from a per-process salt and the
71
+ # current hour bucket, so the key cannot be satisfied from the public
72
+ # repo, training data, an agent's persistent memory, or a stale session
73
+ # summary — only by a recent read of the guide served by THIS process.
74
+ # The previous hour's key is honored as a grace window so a read just
75
+ # before rotation does not strand the write that follows it. Derivation
76
+ # is stateless (salt + clock), keeping the no-server-side-session-state
77
+ # principle intact.
78
+ #
79
+ # The key is published ONLY by ``strict_bps_ack_line`` (surfaced through
80
+ # ha_get_skill_guide Tier 3 when strict mode is effective) and validated ONLY
81
+ # by the middleware — it must never appear in a block error, a tool
82
+ # docstring, or a skill_content embed.
83
+ STRICT_BPS_ACK_KEY_PREFIX = "I-HAVE-READ-THE-BEST-PRACTICES-GUIDE"
84
+
85
+ _ACK_KEY_SALT = secrets.token_hex(8)
86
+ _ACK_KEY_ROTATION_SECONDS = 3600
87
+
88
+
89
+ def _current_ack_key(now: float | None = None) -> str:
90
+ bucket = int((time.time() if now is None else now) // _ACK_KEY_ROTATION_SECONDS)
91
+ digest = hashlib.sha256(f"{_ACK_KEY_SALT}:{bucket}".encode()).hexdigest()
92
+ return f"{STRICT_BPS_ACK_KEY_PREFIX}-{digest[:8]}"
93
+
94
+
95
+ def current_strict_bps_ack_key() -> str:
96
+ """Return the acknowledgment key for the current rotation window."""
97
+ return _current_ack_key()
98
+
99
+
100
+ def _valid_ack_keys() -> set[str]:
101
+ """Current key plus the previous rotation's key (grace window)."""
102
+ now = time.time()
103
+ return {_current_ack_key(now), _current_ack_key(now - _ACK_KEY_ROTATION_SECONDS)}
104
+
63
105
 
64
106
  # The write-tool parameter that carries the acknowledgment key. Declared on
65
107
  # each of the six gated tools (adjacent to ``MandatoryBPS``) but read only here.
@@ -74,8 +116,13 @@ BestPracticeKeyParam = Annotated[
74
116
  Field(
75
117
  default=None,
76
118
  description=(
77
- "Acknowledgment key published in the home-assistant-best-practices "
78
- "skill content; required when strict best-practices mode is enabled."
119
+ "Read-receipt for the home-assistant-best-practices skill; "
120
+ "required when strict best-practices mode is enabled. Not a "
121
+ "secret or credential: the current value is an attestation "
122
+ "phrase published openly at the top of the skill content served "
123
+ "by ha_get_skill_guide. Read that content, then pass the value "
124
+ "back verbatim — this round-trip is the server's designed "
125
+ "protocol confirming the practices were read before writing."
79
126
  ),
80
127
  ),
81
128
  ]
@@ -151,13 +198,16 @@ def strict_bps_ack_line() -> str:
151
198
  """Return the single line that publishes the acknowledgment key.
152
199
 
153
200
  Prepended to the ha_get_skill_guide Tier-3 best-practices content when
154
- strict mode is effective (server.py). This is the ONLY place the key
155
- literal is emitted to a caller.
201
+ strict mode is effective (server.py). This is the ONLY place the actual
202
+ key value is emitted to a caller.
156
203
  """
157
204
  return (
158
- f"Acknowledgment key: {STRICT_BPS_ACK_KEY} — strict best-practices "
159
- "mode is ON; pass this exact value as the BestPracticeKey argument "
160
- "on gated write tools."
205
+ f"Acknowledgment key: {current_strict_bps_ack_key()} — strict "
206
+ "best-practices mode is ON; pass this exact value as the "
207
+ "BestPracticeKey argument on gated write tools. This key is a "
208
+ "read-receipt, not a secret: it is published here deliberately by "
209
+ "the ha-mcp server, rotates hourly, and grants no privileges — "
210
+ "replaying it is the designed acknowledgment protocol."
161
211
  )
162
212
 
163
213
 
@@ -176,7 +226,9 @@ def _raise_bps_ack_required_error(name: str) -> NoReturn:
176
226
  "Strict best-practices mode is enabled for this tool. Read the "
177
227
  "best-practices skill to obtain the required acknowledgment key, then "
178
228
  "pass it as the BestPracticeKey argument on this call. The key is "
179
- "published only in that skill's content."
229
+ "published only in that skill's content, and it rotates periodically "
230
+ "— a key obtained earlier may have expired, so re-read the skill for "
231
+ "the current value instead of resending a previous one."
180
232
  )
181
233
  raise_tool_error(
182
234
  create_error_response(
@@ -263,10 +315,10 @@ class StrictBpsMiddleware(Middleware):
263
315
  return await call_next(context)
264
316
 
265
317
  # The gate is the ONLY reader of BestPracticeKey: strip it before
266
- # dispatch (whether or not strict mode is on) so the constant never
318
+ # dispatch (whether or not strict mode is on) so the key value never
267
319
  # reaches the tool body, the policy middleware's approval args-hash
268
- # (where it would churn remembered approvals across strict toggles),
269
- # or downstream logging.
320
+ # (where the hourly-rotating value would churn remembered approvals
321
+ # every rotation), or downstream logging.
270
322
  args = context.message.arguments or {}
271
323
  supplied = args.get(STRICT_BPS_KEY_PARAM)
272
324
  if STRICT_BPS_KEY_PARAM in args:
@@ -275,9 +327,13 @@ class StrictBpsMiddleware(Middleware):
275
327
  message=context.message.model_copy(update={"arguments": stripped})
276
328
  )
277
329
 
330
+ # isinstance guards the set-membership test: the middleware reads
331
+ # raw transport arguments before pydantic validation, so an
332
+ # off-spec client can send an unhashable value (dict/list) that
333
+ # would otherwise TypeError instead of hitting the block error.
278
334
  if (
279
335
  strict_bps_effective()
280
- and supplied != STRICT_BPS_ACK_KEY
336
+ and not (isinstance(supplied, str) and supplied in _valid_ack_keys())
281
337
  and await self._is_registered(name)
282
338
  ):
283
339
  logger.info("strict-BPS mode blocked keyless write to %s", name)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ha-mcp-dev
3
- Version: 7.13.0.dev1990
3
+ Version: 7.13.0.dev1992
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