ha-mcp-dev 8.1.0.dev2247__tar.gz → 8.1.1.dev2254__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 (256) hide show
  1. {ha_mcp_dev-8.1.0.dev2247/src/ha_mcp_dev.egg-info → ha_mcp_dev-8.1.1.dev2254}/PKG-INFO +1 -1
  2. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/pyproject.toml +1 -1
  3. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/config.py +34 -0
  4. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/policy/middleware.py +3 -1
  5. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/settings_ui/locales/en.json +3 -0
  6. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/settings_ui/settings.js +15 -0
  7. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/tools_dev.py +159 -10
  8. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254/src/ha_mcp_dev.egg-info}/PKG-INFO +1 -1
  9. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/LICENSE +0 -0
  10. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/MANIFEST.in +0 -0
  11. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/README.md +0 -0
  12. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/setup.cfg +0 -0
  13. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/__init__.py +0 -0
  14. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/__main__.py +0 -0
  15. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/_pypi_marker +0 -0
  16. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/_vendor/__init__.py +0 -0
  17. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/_vendor/requirements.txt +0 -0
  18. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/_vendor/websockets/LICENSE +0 -0
  19. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/_vendor/websockets/MANIFEST.sha256 +0 -0
  20. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/_vendor/websockets/VENDORED +0 -0
  21. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/_vendor/websockets/__init__.py +0 -0
  22. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/_vendor/websockets/__main__.py +0 -0
  23. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/_vendor/websockets/asyncio/__init__.py +0 -0
  24. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/_vendor/websockets/asyncio/client.py +0 -0
  25. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/_vendor/websockets/asyncio/connection.py +0 -0
  26. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/_vendor/websockets/asyncio/messages.py +0 -0
  27. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/_vendor/websockets/asyncio/router.py +0 -0
  28. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/_vendor/websockets/asyncio/server.py +0 -0
  29. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/_vendor/websockets/auth.py +0 -0
  30. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/_vendor/websockets/cli.py +0 -0
  31. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/_vendor/websockets/client.py +0 -0
  32. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/_vendor/websockets/connection.py +0 -0
  33. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/_vendor/websockets/datastructures.py +0 -0
  34. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/_vendor/websockets/exceptions.py +0 -0
  35. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/_vendor/websockets/extensions/__init__.py +0 -0
  36. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/_vendor/websockets/extensions/base.py +0 -0
  37. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/_vendor/websockets/extensions/permessage_deflate.py +0 -0
  38. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/_vendor/websockets/frames.py +0 -0
  39. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/_vendor/websockets/headers.py +0 -0
  40. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/_vendor/websockets/http11.py +0 -0
  41. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/_vendor/websockets/imports.py +0 -0
  42. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/_vendor/websockets/legacy/__init__.py +0 -0
  43. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/_vendor/websockets/legacy/auth.py +0 -0
  44. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/_vendor/websockets/legacy/client.py +0 -0
  45. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/_vendor/websockets/legacy/exceptions.py +0 -0
  46. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/_vendor/websockets/legacy/framing.py +0 -0
  47. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/_vendor/websockets/legacy/handshake.py +0 -0
  48. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/_vendor/websockets/legacy/http.py +0 -0
  49. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/_vendor/websockets/legacy/protocol.py +0 -0
  50. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/_vendor/websockets/legacy/server.py +0 -0
  51. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/_vendor/websockets/protocol.py +0 -0
  52. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/_vendor/websockets/proxy.py +0 -0
  53. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/_vendor/websockets/py.typed +0 -0
  54. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/_vendor/websockets/server.py +0 -0
  55. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/_vendor/websockets/streams.py +0 -0
  56. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/_vendor/websockets/sync/__init__.py +0 -0
  57. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/_vendor/websockets/sync/client.py +0 -0
  58. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/_vendor/websockets/sync/connection.py +0 -0
  59. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/_vendor/websockets/sync/messages.py +0 -0
  60. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/_vendor/websockets/sync/router.py +0 -0
  61. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/_vendor/websockets/sync/server.py +0 -0
  62. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/_vendor/websockets/sync/utils.py +0 -0
  63. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/_vendor/websockets/trio/__init__.py +0 -0
  64. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/_vendor/websockets/trio/client.py +0 -0
  65. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/_vendor/websockets/trio/connection.py +0 -0
  66. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/_vendor/websockets/trio/messages.py +0 -0
  67. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/_vendor/websockets/trio/router.py +0 -0
  68. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/_vendor/websockets/trio/server.py +0 -0
  69. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/_vendor/websockets/trio/utils.py +0 -0
  70. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/_vendor/websockets/typing.py +0 -0
  71. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/_vendor/websockets/uri.py +0 -0
  72. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/_vendor/websockets/utils.py +0 -0
  73. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/_vendor/websockets/version.py +0 -0
  74. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/_version.py +0 -0
  75. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/auth/__init__.py +0 -0
  76. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/auth/consent_form.py +0 -0
  77. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/auth/provider.py +0 -0
  78. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/backup_manager.py +0 -0
  79. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/browser_landing.py +0 -0
  80. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/client/__init__.py +0 -0
  81. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/client/rest_client.py +0 -0
  82. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/client/supervisor_client.py +0 -0
  83. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/client/websocket_client.py +0 -0
  84. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/client/websocket_listener.py +0 -0
  85. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/dashboard_screenshot/__init__.py +0 -0
  86. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/dashboard_screenshot/capture.py +0 -0
  87. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/dashboard_screenshot/content.py +0 -0
  88. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/dashboard_screenshot/paths.py +0 -0
  89. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/dashboard_screenshot/provision.py +0 -0
  90. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/dashboard_screenshot/theme_guard.py +0 -0
  91. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/errors.py +0 -0
  92. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/llm_exposure.py +0 -0
  93. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/policy/__init__.py +0 -0
  94. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/policy/approval_queue.py +0 -0
  95. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/policy/evaluator.py +0 -0
  96. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/policy/handlers.py +0 -0
  97. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/policy/model.py +0 -0
  98. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/policy/persistence.py +0 -0
  99. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/policy/value_sources.py +0 -0
  100. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/py.typed +0 -0
  101. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/read_only.py +0 -0
  102. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/resources/skills-vendor/.claude/settings.json +0 -0
  103. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/resources/skills-vendor/.claude-plugin/marketplace.json +0 -0
  104. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/resources/skills-vendor/.claude-plugin/plugin.json +0 -0
  105. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/resources/skills-vendor/.github/ISSUE_TEMPLATE/skill-rca.md +0 -0
  106. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/resources/skills-vendor/.github/pull_request_template.md +0 -0
  107. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/resources/skills-vendor/AGENTS.md +0 -0
  108. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/resources/skills-vendor/CLAUDE.md +0 -0
  109. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/resources/skills-vendor/CONTRIBUTING.md +0 -0
  110. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/resources/skills-vendor/LICENSE +0 -0
  111. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/resources/skills-vendor/README.md +0 -0
  112. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/SKILL.md +0 -0
  113. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/evals/evals.json +0 -0
  114. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/appdaemon.md +0 -0
  115. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/automation-patterns.md +0 -0
  116. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/blueprint-guide.md +0 -0
  117. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-cards.md +0 -0
  118. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-guide.md +0 -0
  119. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/device-control.md +0 -0
  120. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/domain-docs.md +0 -0
  121. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/examples.yaml +0 -0
  122. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/helper-selection.md +0 -0
  123. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/safe-refactoring.md +0 -0
  124. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/scenes.md +0 -0
  125. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/template-guidelines.md +0 -0
  126. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/yaml-only-integrations.md +0 -0
  127. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/server.py +0 -0
  128. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/settings_ui/__init__.py +0 -0
  129. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/settings_ui/_handlers_advanced.py +0 -0
  130. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/settings_ui/_handlers_backups.py +0 -0
  131. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/settings_ui/_handlers_fs.py +0 -0
  132. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/settings_ui/_handlers_server.py +0 -0
  133. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/settings_ui/_handlers_theme.py +0 -0
  134. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/settings_ui/_handlers_tools.py +0 -0
  135. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/settings_ui/_i18n.py +0 -0
  136. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/settings_ui/_persistence.py +0 -0
  137. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/settings_ui/_supervisor.py +0 -0
  138. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/settings_ui/_theme.py +0 -0
  139. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/settings_ui/_tools_meta.py +0 -0
  140. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/settings_ui/locales/README.md +0 -0
  141. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/settings_ui/locales/de.json +0 -0
  142. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/settings_ui/locales/es.json +0 -0
  143. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/settings_ui/locales/fr.json +0 -0
  144. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/settings_ui/locales/it.json +0 -0
  145. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/settings_ui/locales/ru.json +0 -0
  146. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/settings_ui/locales/zh-Hans.json +0 -0
  147. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/settings_ui/settings.css +0 -0
  148. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/settings_ui/settings.html +0 -0
  149. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/smoke_test.py +0 -0
  150. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/stdio_settings_sidecar.py +0 -0
  151. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/strict_bps.py +0 -0
  152. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/__init__.py +0 -0
  153. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/auto_backup.py +0 -0
  154. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/backup.py +0 -0
  155. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/best_practice_checker.py +0 -0
  156. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/best_practice_result.py +0 -0
  157. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/best_practice_variables.py +0 -0
  158. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/component_api.py +0 -0
  159. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/component_config_reads.py +0 -0
  160. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/component_devices.py +0 -0
  161. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/component_registries.py +0 -0
  162. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/component_registry_lookup.py +0 -0
  163. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/config_entry_flow.py +0 -0
  164. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/config_entry_flow_form.py +0 -0
  165. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/config_entry_flow_menu.py +0 -0
  166. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/config_entry_flow_walker.py +0 -0
  167. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/device_control.py +0 -0
  168. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/hacs_registration.py +0 -0
  169. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/helpers.py +0 -0
  170. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/radio/__init__.py +0 -0
  171. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/radio/base.py +0 -0
  172. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/radio/matter.py +0 -0
  173. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/radio/thread.py +0 -0
  174. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/radio/zigbee.py +0 -0
  175. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/radio/zwave.py +0 -0
  176. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/reference_validator.py +0 -0
  177. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/registry.py +0 -0
  178. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/smart_search/__init__.py +0 -0
  179. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/smart_search/_base.py +0 -0
  180. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/smart_search/_config.py +0 -0
  181. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/smart_search/_deep.py +0 -0
  182. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/smart_search/_entities.py +0 -0
  183. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/smart_search/_fetch.py +0 -0
  184. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/smart_search/_overview.py +0 -0
  185. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/smart_search/_scenes.py +0 -0
  186. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/smart_search/_scoring.py +0 -0
  187. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/tool_search_hint_middleware.py +0 -0
  188. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/tools_addons.py +0 -0
  189. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/tools_areas.py +0 -0
  190. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/tools_blueprints.py +0 -0
  191. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/tools_bug_report.py +0 -0
  192. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/tools_calendar.py +0 -0
  193. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/tools_camera.py +0 -0
  194. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/tools_categories.py +0 -0
  195. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/tools_code.py +0 -0
  196. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/tools_config_automations.py +0 -0
  197. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/tools_config_dashboards.py +0 -0
  198. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/tools_config_helpers.py +0 -0
  199. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/tools_config_scenes.py +0 -0
  200. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/tools_config_scripts.py +0 -0
  201. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/tools_dashboard_screenshot.py +0 -0
  202. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/tools_energy.py +0 -0
  203. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/tools_entities.py +0 -0
  204. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/tools_filesystem.py +0 -0
  205. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/tools_groups.py +0 -0
  206. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/tools_hacs.py +0 -0
  207. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/tools_history.py +0 -0
  208. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/tools_integrations.py +0 -0
  209. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/tools_labels.py +0 -0
  210. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/tools_radio.py +0 -0
  211. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/tools_registry.py +0 -0
  212. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/tools_resources.py +0 -0
  213. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/tools_search.py +0 -0
  214. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/tools_service.py +0 -0
  215. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/tools_services.py +0 -0
  216. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/tools_system.py +0 -0
  217. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/tools_themes.py +0 -0
  218. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/tools_todo.py +0 -0
  219. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/tools_traces.py +0 -0
  220. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/tools_updates.py +0 -0
  221. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/tools_utility.py +0 -0
  222. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/tools_voice_assistant.py +0 -0
  223. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/tools_yaml_config.py +0 -0
  224. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/tools_yaml_read.py +0 -0
  225. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/tools_zones.py +0 -0
  226. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/util_helpers.py +0 -0
  227. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/tools/validation_middleware.py +0 -0
  228. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/transforms/__init__.py +0 -0
  229. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/transforms/categorized_search.py +0 -0
  230. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/transforms/lite_docstrings.py +0 -0
  231. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/transport_security.py +0 -0
  232. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/update_check.py +0 -0
  233. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/utils/__init__.py +0 -0
  234. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/utils/config_hash.py +0 -0
  235. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/utils/config_write_lock.py +0 -0
  236. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/utils/data_paths.py +0 -0
  237. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/utils/domain_handlers.py +0 -0
  238. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/utils/fuzzy_search.py +0 -0
  239. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/utils/kill_signal_diagnostics.py +0 -0
  240. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/utils/operation_manager.py +0 -0
  241. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/utils/python_sandbox.py +0 -0
  242. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/utils/skill_loader.py +0 -0
  243. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/utils/usage_logger.py +0 -0
  244. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/visibility/__init__.py +0 -0
  245. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/visibility/enforcement.py +0 -0
  246. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/visibility/model.py +0 -0
  247. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/visibility/persistence.py +0 -0
  248. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp/visibility/resolver.py +0 -0
  249. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp_dev.egg-info/SOURCES.txt +0 -0
  250. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp_dev.egg-info/dependency_links.txt +0 -0
  251. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp_dev.egg-info/entry_points.txt +0 -0
  252. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp_dev.egg-info/requires.txt +0 -0
  253. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/src/ha_mcp_dev.egg-info/top_level.txt +0 -0
  254. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/tests/__init__.py +0 -0
  255. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/tests/test_constants.py +0 -0
  256. {ha_mcp_dev-8.1.0.dev2247 → ha_mcp_dev-8.1.1.dev2254}/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.1.0.dev2247
3
+ Version: 8.1.1.dev2254
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.1.0.dev2247"
7
+ version = "8.1.1.dev2254"
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
@@ -302,6 +302,29 @@ class Settings(BaseSettings):
302
302
  # schemas so it stays out of the add-on Configuration page.
303
303
  enable_dev_mode: bool = Field(False, alias="HAMCP_ENABLE_DEV_MODE")
304
304
 
305
+ # Dev-tools access to tool-security policy state (issue #2141).
306
+ # Developer mode may stay on while this stays off: the dev tools'
307
+ # policy-override surfaces — set_policy, set_tool(gated=...),
308
+ # approve/deny of queued approvals, and set/reset of
309
+ # enable_tool_security_policies — are refused while it is off, so a
310
+ # connected agent cannot rewrite the rules that gate it nor click
311
+ # "accept" on its own gated calls. The guard reads env var + override
312
+ # file fresh per call (NOT this cached Settings object), so a change
313
+ # applies live without a restart even in stdio mode, where the web
314
+ # settings UI runs in a detached sidecar process whose POST cannot
315
+ # reset this process' settings singleton. Editable
316
+ # from the web settings UI (Developer section) or the env var ONLY —
317
+ # the dev tools' own settings surfaces refuse to write this field, in
318
+ # either direction, and it is absent from the add-on config schemas
319
+ # like enable_dev_mode. A leash on those surfaces, NOT a sandbox: dev
320
+ # mode's update_source/restart can still replace the running server
321
+ # build, and in add-on mode ha_manage_addon can reach the add-on's
322
+ # own options and ingress — gate those tools with policy rules (or
323
+ # keep dev mode off) where that boundary matters.
324
+ dev_tools_security_policy_access: bool = Field(
325
+ False, alias="HAMCP_DEV_SECURITY_POLICY_ACCESS"
326
+ )
327
+
305
328
  # Code Mode — sandboxed Python execution via pydantic-monty.
306
329
  # Provides an "escape hatch" tool (ha_manage_custom_tool) that lets LLMs write
307
330
  # custom one-off Python code when no existing tool covers the request.
@@ -912,6 +935,17 @@ ADVANCED_SETTINGS_FIELDS: tuple[AdvancedField, ...] = (
912
935
  # among the feature toggles, and stays independent of the beta
913
936
  # master gate.
914
937
  AdvancedField("enable_dev_mode", "HAMCP_ENABLE_DEV_MODE", bool, "developer", True),
938
+ # Dev-tools security-policy access (issue #2141). Renders directly
939
+ # below the dev-mode toggle in the same Developer section. Editable
940
+ # here and via the env var; the dev tools themselves refuse to write
941
+ # it, so the AI cannot grant itself policy access.
942
+ AdvancedField(
943
+ "dev_tools_security_policy_access",
944
+ "HAMCP_DEV_SECURITY_POLICY_ACCESS",
945
+ bool,
946
+ "developer",
947
+ True,
948
+ ),
915
949
  )
916
950
 
917
951
 
@@ -41,7 +41,9 @@ PROXY_META_TOOLS = frozenset(
41
41
  # itself require approval — creating a second pending entry instead of
42
42
  # deciding the first, so nothing can ever be approved through the tool.
43
43
  # Only the queue-management actions are exempt; update_source / restart
44
- # remain gateable like any other high-stakes action.
44
+ # remain gateable like any other high-stakes action. The exemption is not
45
+ # a free self-approval: approve/deny separately require the
46
+ # dev_tools_security_policy_access setting (off by default, issue #2141).
45
47
  _APPROVAL_MANAGEMENT_TOOL = "ha_dev_manage_server"
46
48
  _APPROVAL_MANAGEMENT_ACTIONS = frozenset({"list_pending", "approve", "deny"})
47
49
 
@@ -289,6 +289,7 @@
289
289
  "advanced.errors.json": "Advanced settings response was not valid JSON.",
290
290
  "advanced.sidecar.stdio_only": "Available in stdio mode only. This HTTP server has no settings-UI sidecar to pin.",
291
291
  "advanced.enable_dev_mode.confirm": "⚠ Enable developer mode?\n\nAfter restart, hidden developer tools will be exposed to connected AI agents. Enable only for development and testing.",
292
+ "advanced.dev_tools_security_policy_access.confirm": "⚠ Let developer tools change security policies?\n\nWhile developer mode is on, connected AI agents will be able to rewrite tool security policies, add or remove per-tool approval gates, and approve or deny pending approvals — including their own gated calls. Enable only while testing policies.",
292
293
  "advanced.code_mode_saved_tools_path.addon_locked": "Hardcoded to <code>/data/saved_tools.json</code> in App (add-on) mode so saved tools survive updates.",
293
294
  "advanced.code_mode_saved_tools_path.blank_warning": "If blank, custom tools are kept in memory only and lost on restart.",
294
295
  "policies.errors.conflict": "{operation} failed: policy was modified in another tab or session. Reload and re-apply your changes.",
@@ -423,6 +424,8 @@
423
424
  "advanced.sidecar_pin_port.help": "0 picks a free port on first start and keeps it for later restarts; 1024–65535 pins a preferred port (falls back to a free one if taken). Restart required.",
424
425
  "advanced.enable_dev_mode.label": "Developer mode",
425
426
  "advanced.enable_dev_mode.help": "⚠ Registers hidden tools that can change settings and replace the running server. Development and testing only. Restart required.",
427
+ "advanced.dev_tools_security_policy_access.label": "Dev tools security policy access",
428
+ "advanced.dev_tools_security_policy_access.help": "⚠ While developer mode is on, lets the developer tools rewrite tool security policies, add or remove per-tool approval gates, and approve or deny pending approvals on your behalf — an AI agent can accept its own gated calls. Policy testing only. Takes effect without a restart.",
426
429
  "addon.backup_hint.name": "Full-HA snapshot suggestion level (LLM-facing)",
427
430
  "addon.backup_hint.description": "Tunes the wording of the hint the LLM sees in the\n`ha_manage_backup(scope='snapshot')` tool description for when to\nsuggest a full Home Assistant tarball backup before risky operations\n(e.g. mass device deletes). Affects ONLY this one LLM-facing prompt\nsentence.\n\nFor per-edit automatic snapshots of automations / scripts / helpers /\netc., use the separate **Enable auto-backup of edits** toggle below.",
428
431
  "addon.secret_path.name": "Secret path override",
@@ -3536,6 +3536,7 @@ const ADVANCED_FIELD_META = {
3536
3536
  extra_yaml_write_keys: { label: "Extra YAML write keys", help: "Comma-separated top-level keys ha_config_set_yaml may write in addition to the built-in ones, for YAML-first integrations on this install (e.g. alert2). Keys that redefine Home Assistant's own trust boundary can never be added and are ignored. Requires custom component 1.2.4 or newer." },
3537
3537
  sidecar_pin_port: { label: "Settings UI sidecar port", help: "0 picks a free port on first start and keeps it for later restarts; 1024–65535 pins a preferred port (falls back to a free one if taken). Restart required." },
3538
3538
  enable_dev_mode: { label: "Developer mode", help: "⚠ DANGER: registers hidden developer tools (ha_dev_manage_server, ha_dev_manage_settings) that let AI agents change server settings and replace the running server version (e.g. install a PR build). For development and testing only. Restart required." },
3539
+ dev_tools_security_policy_access: { label: "Dev tools security policy access", help: "⚠ DANGER: while developer mode is on, lets the developer tools rewrite tool security policies, add or remove per-tool approval gates, and approve or deny pending approvals on your behalf — an AI agent can accept its own gated calls. For policy testing only. Takes effect without a restart." },
3539
3540
  };
3540
3541
 
3541
3542
  // Fields that require an MCP-host restart to take effect when changed
@@ -3754,6 +3755,20 @@ function renderAdvancedSection(containerId, fields) {
3754
3755
  input.checked = false;
3755
3756
  return;
3756
3757
  }
3758
+ // Policy access hands the same agents the security policies that
3759
+ // gate them (and the approval queue) — its own confirm, since it
3760
+ // is stored independently of the dev-mode toggle above (it only
3761
+ // takes effect while dev mode is on).
3762
+ if (fname === 'dev_tools_security_policy_access' && input.checked && !confirm(
3763
+ t(
3764
+ 'advanced.dev_tools_security_policy_access.confirm',
3765
+ {},
3766
+ '⚠ Let developer tools change security policies?\n\nWhile developer mode is on, connected AI agents will be able to rewrite tool security policies, add or remove per-tool approval gates, and approve or deny pending approvals — including their own gated calls. Enable only while testing policies.'
3767
+ )
3768
+ )) {
3769
+ input.checked = false;
3770
+ return;
3771
+ }
3757
3772
  let v;
3758
3773
  if (input.type === 'checkbox') v = input.checked;
3759
3774
  else if (input.type === 'number') v = (f.type === 'float') ? parseFloat(input.value) : parseInt(input.value, 10);
@@ -124,6 +124,129 @@ def is_dev_mode_enabled() -> bool:
124
124
  return bool(getattr(get_global_settings(), "enable_dev_mode", False))
125
125
 
126
126
 
127
+ def _security_policy_access_enabled() -> bool:
128
+ """Check whether dev tools may change tool-security policy state.
129
+
130
+ Deliberately NOT read through the ``get_global_settings()`` singleton:
131
+ in stdio deployments the web settings UI runs in a detached sidecar
132
+ process, so its POST resets only the sidecar's own cached settings —
133
+ this process would keep serving the stale value until restart. Reading
134
+ the env var, then the override file, fresh per call keeps the toggle
135
+ live in every deployment mode, in the same env-over-file ORDER the
136
+ settings loader applies. Coercion is per source: an env string is
137
+ parsed with pydantic's truthy set (matching what ``Settings`` would
138
+ have read from the same var), and a file value goes through the
139
+ loader's own ``_coerce_advanced_override_value`` — so the guard can
140
+ never disagree with what Settings and the web UI checkbox read from
141
+ the same file (a hand-edited ``"true"`` string, which the loader
142
+ rejects and renders as OFF, must fail closed here too). The read is a
143
+ tiny synchronous stat/parse; guard call sites take it inline, and the
144
+ ``_settings_rows`` caller already runs on a worker thread.
145
+ """
146
+ import os
147
+
148
+ from ..config import (
149
+ _coerce_advanced_override_value,
150
+ _read_feature_flag_override_file,
151
+ )
152
+
153
+ env_raw = os.environ.get("HAMCP_DEV_SECURITY_POLICY_ACCESS")
154
+ if env_raw is not None:
155
+ return env_raw.strip().lower() in ("1", "true", "t", "yes", "y", "on")
156
+ # The override file is keyed by FIELD name (see
157
+ # _apply_one_advanced_override), not env-var name.
158
+ raw = _read_feature_flag_override_file().get("dev_tools_security_policy_access")
159
+ if raw is None:
160
+ return False
161
+ ok, coerced = _coerce_advanced_override_value(
162
+ "dev_tools_security_policy_access", bool, raw
163
+ )
164
+ return bool(coerced) if ok else False
165
+
166
+
167
+ def _apply_policy_guard_row_locks(fname: str, row: dict[str, Any]) -> None:
168
+ """Reflect the policy-access write guards in the ``list`` matrix rows.
169
+
170
+ Without this, agents reading the matrix to choose writable settings
171
+ see ``editable: true`` on rows whose set/reset the guards refuse:
172
+ ``enable_tool_security_policies`` while access is off, and
173
+ ``dev_tools_security_policy_access`` always (web UI / env var only).
174
+ A row that is ALREADY non-editable (env-pinned) keeps its plain env
175
+ story: the pin refuses the write before these guards would, and
176
+ stamping a policy reason there would misdirect the fix toward the
177
+ wrong lock. The toggle's displayed value is also re-read fresh so a
178
+ sidecar-process edit shows here without a restart, matching what the
179
+ guard enforces.
180
+ """
181
+ if fname == "enable_tool_security_policies":
182
+ if row["editable"] and not _security_policy_access_enabled():
183
+ row["editable"] = False
184
+ row["locked_reason"] = "policy_access_required"
185
+ elif fname == "dev_tools_security_policy_access":
186
+ if row["editable"]:
187
+ row["editable"] = False
188
+ row["locked_reason"] = "web_ui_or_env_only"
189
+ row["value"] = _security_policy_access_enabled()
190
+
191
+
192
+ def _require_security_policy_access(operation: str) -> None:
193
+ """Refuse ``operation`` unless security-policy access is enabled (#2141).
194
+
195
+ Guards every dev-tools surface that can weaken the tool-security
196
+ policies gating the agent itself, so dev mode can stay on for
197
+ everything else while policy override stays off.
198
+ """
199
+ if _security_policy_access_enabled():
200
+ return
201
+ raise_tool_error(
202
+ create_error_response(
203
+ ErrorCode.AUTH_INSUFFICIENT_PERMISSIONS,
204
+ f"Dev tools may not {operation}: security-policy access is "
205
+ "disabled (dev_tools_security_policy_access=false).",
206
+ context={
207
+ "operation": operation,
208
+ "setting": "dev_tools_security_policy_access",
209
+ },
210
+ suggestions=[
211
+ "Enable 'Dev tools security policy access' in the web "
212
+ "settings UI (Server Settings tab, Developer section), or set "
213
+ "HAMCP_DEV_SECURITY_POLICY_ACCESS=true — it takes effect "
214
+ "without a restart.",
215
+ ],
216
+ )
217
+ )
218
+
219
+
220
+ def _guard_security_policy_setting(setting: str) -> None:
221
+ """Gate set/reset of the two settings that define the dev tools' leash.
222
+
223
+ ``dev_tools_security_policy_access`` is refused unconditionally — even
224
+ with access ON — so the agent can neither grant itself policy access
225
+ nor revoke it; that toggle belongs to the web settings UI and the env
226
+ var alone. ``enable_tool_security_policies`` is the whole gating
227
+ engine's master switch, so writing it needs access.
228
+ """
229
+ if setting == "dev_tools_security_policy_access":
230
+ raise_tool_error(
231
+ create_error_response(
232
+ ErrorCode.AUTH_INSUFFICIENT_PERMISSIONS,
233
+ "'dev_tools_security_policy_access' cannot be changed by dev "
234
+ "tools: it is the toggle governing their own access to tool "
235
+ "security policies.",
236
+ context={"setting": setting},
237
+ suggestions=[
238
+ "Change it in the web settings UI (Server Settings tab, "
239
+ "Developer section) or via the "
240
+ "HAMCP_DEV_SECURITY_POLICY_ACCESS env var.",
241
+ ],
242
+ )
243
+ )
244
+ if setting == "enable_tool_security_policies":
245
+ _require_security_policy_access(
246
+ "enable or disable the tool-security-policy engine"
247
+ )
248
+
249
+
127
250
  def _spawn_background(coro: Any) -> None:
128
251
  """Run ``coro`` as a strongly-referenced fire-and-forget task."""
129
252
  task = asyncio.get_running_loop().create_task(coro)
@@ -410,6 +533,7 @@ class DevTools:
410
533
  bounds = _FEATURE_FLAG_INT_BOUNDS.get(fname)
411
534
  if bounds is not None:
412
535
  row["min"], row["max"] = bounds
536
+ _apply_policy_guard_row_locks(fname, row)
413
537
  rows.append(row)
414
538
  for (
415
539
  fname,
@@ -443,6 +567,7 @@ class DevTools:
443
567
  choices = _ADVANCED_SETTINGS_CHOICES.get(fname)
444
568
  if choices is not None:
445
569
  row["choices"] = list(choices)
570
+ _apply_policy_guard_row_locks(fname, row)
446
571
  rows.append(row)
447
572
  return rows
448
573
 
@@ -698,7 +823,8 @@ class DevTools:
698
823
  default=None,
699
824
  description=(
700
825
  "set_policy: the full policy object "
701
- "{wait_seconds, approval_ttl_minutes, rules, version}"
826
+ "{wait_seconds, approval_ttl_minutes, rules, version, "
827
+ "schema_version}"
702
828
  ),
703
829
  ),
704
830
  ] = None,
@@ -742,7 +868,13 @@ class DevTools:
742
868
  LLM-API exposure, security gates, and policy edits apply live.
743
869
  Env-pinned settings/tools are read-only until the env var is unset.
744
870
  These actions can flip security-sensitive state — treat with the
745
- same care as editing the web UI.
871
+ same care as editing the web UI. The policy-override surfaces
872
+ (set_policy, set_tool with gated=, and set/reset of
873
+ enable_tool_security_policies) additionally require the
874
+ 'dev_tools_security_policy_access' setting, which is off by
875
+ default; reads are always available. That setting itself is never
876
+ writable by these tools — change it in the web settings UI or via
877
+ HAMCP_DEV_SECURITY_POLICY_ACCESS.
746
878
 
747
879
  EXAMPLES:
748
880
  ha_dev_manage_settings("list_tools")
@@ -808,6 +940,8 @@ class DevTools:
808
940
  f"'setting' is required for action={action!r}",
809
941
  )
810
942
  )
943
+ # set/reset only; 'list' returned above, and reads are never gated.
944
+ _guard_security_policy_setting(setting)
811
945
 
812
946
  from ..config import (
813
947
  _ADVANCED_SETTINGS_BOUNDS,
@@ -1027,6 +1161,11 @@ class DevTools:
1027
1161
  "set_tool needs at least one of state / llm_api / gated",
1028
1162
  )
1029
1163
  )
1164
+ # The gate flag writes a security-policy rule (#2141); state /
1165
+ # llm_api changes stay available without policy access. Checked
1166
+ # before any write so a combined state+gated call is refused whole.
1167
+ if gated is not None:
1168
+ _require_security_policy_access("change a tool's security gate")
1030
1169
  # Reject unknown tool names BEFORE persisting anything: a typo'd
1031
1170
  # security gate ("ha_call_servce") would otherwise save a rule for a
1032
1171
  # nonexistent tool and report success while the intended tool stays
@@ -1387,6 +1526,8 @@ class DevTools:
1387
1526
  self, policy: dict[str, Any] | None, expected_version: int | None
1388
1527
  ) -> dict[str, Any]:
1389
1528
  """Write the full tool-security policy (validated, version-guarded)."""
1529
+ _require_security_policy_access("rewrite the tool security policy")
1530
+
1390
1531
  from pydantic import ValidationError
1391
1532
 
1392
1533
  from ..policy.model import Policy
@@ -1796,11 +1937,12 @@ class DevTools:
1796
1937
  arrives just before the server goes down) and supports those
1797
1938
  two deployments only (standalone processes must be restarted
1798
1939
  externally). list_pending/approve/deny are exempt from policy
1799
- gating (gating queue management would deadlock approvals) —
1800
- and since gated-call errors include the approval token, an
1801
- agent can self-approve its own gated calls while dev mode is
1802
- on. Dev mode is a trusted-operator feature; leave it off
1803
- otherwise.
1940
+ gating (gating queue management would deadlock approvals), so
1941
+ approve/deny instead require the separate
1942
+ 'dev_tools_security_policy_access' setting — off by default,
1943
+ because gated-call errors carry the approval token and an agent
1944
+ could otherwise self-approve its own gated calls. Dev mode is a
1945
+ trusted-operator feature; leave it off otherwise.
1804
1946
 
1805
1947
  EXAMPLES:
1806
1948
  ha_dev_manage_server("info")
@@ -2277,6 +2419,10 @@ class DevTools:
2277
2419
  self, token: str | None, *, approve: bool
2278
2420
  ) -> dict[str, Any]:
2279
2421
  """Approve or deny one blocked tool call by token."""
2422
+ # Deciding an approval is the agent clicking "accept" on its own
2423
+ # gated call — the surface #2141 exists to close. list_pending
2424
+ # stays open: reading the queue decides nothing.
2425
+ _require_security_policy_access("decide a pending approval")
2280
2426
  if not token:
2281
2427
  raise_tool_error(
2282
2428
  create_error_response(
@@ -2326,9 +2472,12 @@ def register_dev_tools(mcp: Any, client: Any, **kwargs: Any) -> None:
2326
2472
  logger.debug(f"Dev tools disabled (set {FEATURE_FLAG}=true to enable)")
2327
2473
  return
2328
2474
 
2475
+ access = "on" if _security_policy_access_enabled() else "off"
2329
2476
  logger.warning(
2330
- "Developer mode is ON: ha_dev_manage_server / ha_dev_manage_settings "
2331
- "are registered. These tools can change server settings, tool "
2332
- "visibility, security policies, and replace the running server version."
2477
+ f"Developer mode is ON: ha_dev_manage_server / ha_dev_manage_settings "
2478
+ f"are registered. These tools can change server settings, tool "
2479
+ f"visibility, and replace the running server version. Rewriting tool "
2480
+ f"security policies and deciding approvals additionally require "
2481
+ f"dev_tools_security_policy_access (currently {access})."
2333
2482
  )
2334
2483
  register_tool_methods(mcp, DevTools(client, server=kwargs.get("server")))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ha-mcp-dev
3
- Version: 8.1.0.dev2247
3
+ Version: 8.1.1.dev2254
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