ha-mcp-dev 7.12.3.dev1855__tar.gz → 7.12.3.dev1859__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 (162) hide show
  1. {ha_mcp_dev-7.12.3.dev1855/src/ha_mcp_dev.egg-info → ha_mcp_dev-7.12.3.dev1859}/PKG-INFO +1 -1
  2. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/pyproject.toml +1 -1
  3. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/config_entry_flow.py +155 -18
  4. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/tools_config_helpers.py +1 -0
  5. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/tools_integrations.py +4 -6
  6. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859/src/ha_mcp_dev.egg-info}/PKG-INFO +1 -1
  7. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/LICENSE +0 -0
  8. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/MANIFEST.in +0 -0
  9. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/README.md +0 -0
  10. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/setup.cfg +0 -0
  11. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/__init__.py +0 -0
  12. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/__main__.py +0 -0
  13. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/_pypi_marker +0 -0
  14. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/_version.py +0 -0
  15. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/auth/__init__.py +0 -0
  16. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/auth/consent_form.py +0 -0
  17. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/auth/provider.py +0 -0
  18. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/backup_manager.py +0 -0
  19. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/browser_landing.py +0 -0
  20. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/client/__init__.py +0 -0
  21. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/client/rest_client.py +0 -0
  22. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/client/supervisor_client.py +0 -0
  23. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/client/websocket_client.py +0 -0
  24. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/client/websocket_listener.py +0 -0
  25. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/config.py +0 -0
  26. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/dashboard_screenshot/__init__.py +0 -0
  27. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/dashboard_screenshot/capture.py +0 -0
  28. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/dashboard_screenshot/provision.py +0 -0
  29. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/errors.py +0 -0
  30. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/policy/__init__.py +0 -0
  31. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/policy/approval_queue.py +0 -0
  32. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/policy/evaluator.py +0 -0
  33. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/policy/handlers.py +0 -0
  34. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/policy/middleware.py +0 -0
  35. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/policy/model.py +0 -0
  36. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/policy/persistence.py +0 -0
  37. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/policy/value_sources.py +0 -0
  38. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/py.typed +0 -0
  39. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/read_only.py +0 -0
  40. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/resources/skills-vendor/.claude/settings.json +0 -0
  41. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/resources/skills-vendor/.claude-plugin/marketplace.json +0 -0
  42. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/resources/skills-vendor/.claude-plugin/plugin.json +0 -0
  43. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/resources/skills-vendor/.github/ISSUE_TEMPLATE/skill-rca.md +0 -0
  44. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/resources/skills-vendor/.github/pull_request_template.md +0 -0
  45. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/resources/skills-vendor/AGENTS.md +0 -0
  46. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/resources/skills-vendor/CLAUDE.md +0 -0
  47. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/resources/skills-vendor/CONTRIBUTING.md +0 -0
  48. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/resources/skills-vendor/LICENSE +0 -0
  49. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/resources/skills-vendor/README.md +0 -0
  50. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/SKILL.md +0 -0
  51. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/evals/evals.json +0 -0
  52. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/appdaemon.md +0 -0
  53. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/automation-patterns.md +0 -0
  54. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/blueprint-guide.md +0 -0
  55. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-cards.md +0 -0
  56. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-guide.md +0 -0
  57. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/device-control.md +0 -0
  58. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/domain-docs.md +0 -0
  59. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/examples.yaml +0 -0
  60. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/helper-selection.md +0 -0
  61. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/safe-refactoring.md +0 -0
  62. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/scenes.md +0 -0
  63. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/template-guidelines.md +0 -0
  64. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/yaml-only-integrations.md +0 -0
  65. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/server.py +0 -0
  66. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/settings_ui/__init__.py +0 -0
  67. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/settings_ui/settings.css +0 -0
  68. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/settings_ui/settings.html +0 -0
  69. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/settings_ui/settings.js +0 -0
  70. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/smoke_test.py +0 -0
  71. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/stdio_settings_sidecar.py +0 -0
  72. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/__init__.py +0 -0
  73. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/auto_backup.py +0 -0
  74. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/backup.py +0 -0
  75. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/best_practice_checker.py +0 -0
  76. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/device_control.py +0 -0
  77. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/enhanced.py +0 -0
  78. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/helpers.py +0 -0
  79. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/radio/__init__.py +0 -0
  80. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/radio/base.py +0 -0
  81. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/radio/matter.py +0 -0
  82. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/radio/thread.py +0 -0
  83. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/radio/zigbee.py +0 -0
  84. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/radio/zwave.py +0 -0
  85. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/reference_validator.py +0 -0
  86. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/registry.py +0 -0
  87. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/smart_search/__init__.py +0 -0
  88. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/smart_search/_base.py +0 -0
  89. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/smart_search/_config.py +0 -0
  90. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/smart_search/_deep.py +0 -0
  91. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/smart_search/_entities.py +0 -0
  92. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/smart_search/_fetch.py +0 -0
  93. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/smart_search/_overview.py +0 -0
  94. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/smart_search/_scenes.py +0 -0
  95. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/smart_search/_scoring.py +0 -0
  96. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/tool_search_hint_middleware.py +0 -0
  97. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/tools_addons.py +0 -0
  98. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/tools_areas.py +0 -0
  99. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/tools_blueprints.py +0 -0
  100. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/tools_bug_report.py +0 -0
  101. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/tools_calendar.py +0 -0
  102. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/tools_camera.py +0 -0
  103. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/tools_categories.py +0 -0
  104. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/tools_code.py +0 -0
  105. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/tools_config_automations.py +0 -0
  106. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/tools_config_dashboards.py +0 -0
  107. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/tools_config_scenes.py +0 -0
  108. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/tools_config_scripts.py +0 -0
  109. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/tools_dashboard_screenshot.py +0 -0
  110. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/tools_dev.py +0 -0
  111. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/tools_energy.py +0 -0
  112. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/tools_entities.py +0 -0
  113. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/tools_filesystem.py +0 -0
  114. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/tools_groups.py +0 -0
  115. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/tools_hacs.py +0 -0
  116. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/tools_history.py +0 -0
  117. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/tools_labels.py +0 -0
  118. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/tools_mcp_component.py +0 -0
  119. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/tools_radio.py +0 -0
  120. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/tools_registry.py +0 -0
  121. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/tools_resources.py +0 -0
  122. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/tools_search.py +0 -0
  123. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/tools_service.py +0 -0
  124. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/tools_services.py +0 -0
  125. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/tools_system.py +0 -0
  126. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/tools_themes.py +0 -0
  127. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/tools_todo.py +0 -0
  128. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/tools_traces.py +0 -0
  129. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/tools_updates.py +0 -0
  130. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/tools_utility.py +0 -0
  131. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/tools_voice_assistant.py +0 -0
  132. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/tools_yaml_config.py +0 -0
  133. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/tools_zones.py +0 -0
  134. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/util_helpers.py +0 -0
  135. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/tools/validation_middleware.py +0 -0
  136. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/transforms/__init__.py +0 -0
  137. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/transforms/categorized_search.py +0 -0
  138. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/transforms/lite_docstrings.py +0 -0
  139. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/transport_security.py +0 -0
  140. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/update_check.py +0 -0
  141. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/utils/__init__.py +0 -0
  142. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/utils/config_hash.py +0 -0
  143. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/utils/data_paths.py +0 -0
  144. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/utils/domain_handlers.py +0 -0
  145. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/utils/fuzzy_search.py +0 -0
  146. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/utils/kill_signal_diagnostics.py +0 -0
  147. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/utils/operation_manager.py +0 -0
  148. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/utils/python_sandbox.py +0 -0
  149. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/utils/skill_loader.py +0 -0
  150. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/utils/usage_logger.py +0 -0
  151. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/visibility/__init__.py +0 -0
  152. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/visibility/model.py +0 -0
  153. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/visibility/persistence.py +0 -0
  154. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp/visibility/resolver.py +0 -0
  155. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp_dev.egg-info/SOURCES.txt +0 -0
  156. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp_dev.egg-info/dependency_links.txt +0 -0
  157. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp_dev.egg-info/entry_points.txt +0 -0
  158. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp_dev.egg-info/requires.txt +0 -0
  159. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/src/ha_mcp_dev.egg-info/top_level.txt +0 -0
  160. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/tests/__init__.py +0 -0
  161. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/tests/test_constants.py +0 -0
  162. {ha_mcp_dev-7.12.3.dev1855 → ha_mcp_dev-7.12.3.dev1859}/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.12.3.dev1855
3
+ Version: 7.12.3.dev1859
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.12.3.dev1855"
7
+ version = "7.12.3.dev1859"
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
@@ -12,6 +12,7 @@ for the 15 helper types listed in FLOW_HELPER_TYPES.
12
12
 
13
13
  import asyncio
14
14
  import logging
15
+ from collections.abc import Iterator
15
16
  from enum import StrEnum
16
17
  from typing import Any, Literal
17
18
 
@@ -128,10 +129,125 @@ def _handle_menu_step(
128
129
  return str(menu_choice)
129
130
 
130
131
 
132
+ def iter_schema_fields(data_schema: Any) -> Iterator[dict[str, Any]]:
133
+ """Yield leaf field definitions from a flow schema, descending into sections."""
134
+ if not isinstance(data_schema, list):
135
+ return
136
+ for field in data_schema:
137
+ if not isinstance(field, dict):
138
+ continue
139
+ nested_schema = field.get("schema")
140
+ if isinstance(nested_schema, list):
141
+ yield from iter_schema_fields(nested_schema)
142
+ continue
143
+ yield field
144
+
145
+
146
+ def _section_path(path_prefix: str, name: Any) -> str:
147
+ """Return the dotted config path for a named or anonymous section."""
148
+ if not isinstance(name, str):
149
+ return path_prefix
150
+ return f"{path_prefix}.{name}" if path_prefix else name
151
+
152
+
153
+ def _record_ignored_section_keys(
154
+ ignored_config_keys: set[str] | None,
155
+ remaining_config: dict[str, Any],
156
+ section_path: str,
157
+ ) -> None:
158
+ """Record undeclared keys remaining inside an explicit section dict."""
159
+ if ignored_config_keys is None:
160
+ return
161
+ ignored_config_keys.update(
162
+ f"{section_path}.{key}" if section_path else key
163
+ for key in remaining_config
164
+ if key not in _MENU_SELECTION_KEYS
165
+ )
166
+
167
+
168
+ def _consume_form_schema(
169
+ data_schema: list[Any],
170
+ remaining_config: dict[str, Any],
171
+ ignored_config_keys: set[str] | None = None,
172
+ path_prefix: str = "",
173
+ ) -> dict[str, Any]:
174
+ """Consume matching config values and shape nested flow sections.
175
+
176
+ Mutates ``remaining_config`` by removing every consumed key. Flat child
177
+ values override the same value inside an explicitly supplied section dict.
178
+ Unknown keys inside explicit section dicts are added to
179
+ ``ignored_config_keys`` with their dotted section path.
180
+ """
181
+ form_data: dict[str, Any] = {}
182
+ missing = object()
183
+
184
+ for field in data_schema:
185
+ if not isinstance(field, dict):
186
+ continue
187
+
188
+ name = field.get("name")
189
+ nested_schema = field.get("schema")
190
+ if isinstance(nested_schema, list):
191
+ section_path = _section_path(path_prefix, name)
192
+ explicit_section = (
193
+ remaining_config.pop(name, missing)
194
+ if isinstance(name, str)
195
+ else missing
196
+ )
197
+ if explicit_section is not missing and not isinstance(
198
+ explicit_section, dict
199
+ ):
200
+ if isinstance(name, str):
201
+ form_data[name] = explicit_section
202
+ continue
203
+
204
+ nested_data: dict[str, Any] = {}
205
+ if isinstance(explicit_section, dict):
206
+ explicit_remaining = dict(explicit_section)
207
+ nested_data.update(
208
+ _consume_form_schema(
209
+ nested_schema,
210
+ explicit_remaining,
211
+ ignored_config_keys,
212
+ section_path,
213
+ )
214
+ )
215
+ _record_ignored_section_keys(
216
+ ignored_config_keys,
217
+ explicit_remaining,
218
+ section_path,
219
+ )
220
+ nested_data.update(
221
+ _consume_form_schema(
222
+ nested_schema,
223
+ remaining_config,
224
+ ignored_config_keys,
225
+ section_path,
226
+ )
227
+ )
228
+
229
+ if nested_data:
230
+ if isinstance(name, str):
231
+ form_data[name] = nested_data
232
+ else:
233
+ form_data.update(nested_data)
234
+ continue
235
+
236
+ if (
237
+ isinstance(name, str)
238
+ and name not in _MENU_SELECTION_KEYS
239
+ and name in remaining_config
240
+ ):
241
+ form_data[name] = remaining_config.pop(name)
242
+
243
+ return form_data
244
+
245
+
131
246
  def _extract_schema_field_names(data_schema: Any) -> set[str] | None:
132
247
  """Extract the set of field names declared by a step's data_schema.
133
248
 
134
249
  HA returns data_schema as a list of {name, selector, required, ...} dicts.
250
+ Nested leaf names are included; section-container names are omitted.
135
251
  Returns ``None`` when the schema is absent or not a list (signalling
136
252
  the caller to fall back to legacy submit-all behaviour). Returns a
137
253
  (possibly empty) set when the schema is present and parseable.
@@ -139,11 +255,10 @@ def _extract_schema_field_names(data_schema: Any) -> set[str] | None:
139
255
  if not isinstance(data_schema, list):
140
256
  return None
141
257
  names: set[str] = set()
142
- for field in data_schema:
143
- if isinstance(field, dict):
144
- name = field.get("name")
145
- if isinstance(name, str):
146
- names.add(name)
258
+ for field in iter_schema_fields(data_schema):
259
+ name = field.get("name")
260
+ if isinstance(name, str):
261
+ names.add(name)
147
262
  return names
148
263
 
149
264
 
@@ -151,13 +266,15 @@ def _handle_form_step(
151
266
  flow_id: str,
152
267
  current_step: dict[str, Any],
153
268
  remaining_config: dict[str, Any],
269
+ ignored_config_keys: set[str] | None = None,
154
270
  ) -> dict[str, Any]:
155
271
  """Validate a form step and return form data to submit.
156
272
 
157
273
  When the step's ``data_schema`` is provided, pops ONLY the keys declared
158
274
  in that schema from ``remaining_config`` (mutating it) so any unconsumed
159
275
  keys remain available for subsequent steps. Menu selection keys are never
160
- submitted.
276
+ submitted. Fields declared inside a section are grouped under the section
277
+ key; callers may provide them flat or inside an explicit section dict.
161
278
 
162
279
  When ``data_schema`` is absent (HA didn't tell us field names), falls
163
280
  back to legacy behaviour: submit all non-menu keys and clear them. This
@@ -180,10 +297,10 @@ def _handle_form_step(
180
297
  )
181
298
  )
182
299
 
183
- schema_fields = _extract_schema_field_names(current_step.get("data_schema"))
300
+ data_schema = current_step.get("data_schema")
184
301
 
185
302
  form_data: dict[str, Any] = {}
186
- if schema_fields is None:
303
+ if not isinstance(data_schema, list):
187
304
  # Legacy fallback: no schema info — dump every non-menu key and
188
305
  # consume them all so a follow-up step (rare without schema) won't
189
306
  # re-submit the same data.
@@ -192,11 +309,9 @@ def _handle_form_step(
192
309
  continue
193
310
  form_data[key] = remaining_config.pop(key)
194
311
  else:
195
- for key in list(remaining_config.keys()):
196
- if key in _MENU_SELECTION_KEYS:
197
- continue
198
- if key in schema_fields:
199
- form_data[key] = remaining_config.pop(key)
312
+ form_data = _consume_form_schema(
313
+ data_schema, remaining_config, ignored_config_keys
314
+ )
200
315
 
201
316
  return form_data
202
317
 
@@ -512,7 +627,8 @@ async def _handle_flow_steps(
512
627
  for unstructured HA 4xx responses so the caller can react.
513
628
 
514
629
  Returns:
515
- ``{"success": True, "entry": result}`` on success.
630
+ ``{"success": True, "entry": result}`` on success, plus ``warnings``
631
+ when caller-supplied config keys were not declared by any flow step.
516
632
  Raises ToolError on any failure.
517
633
  """
518
634
  if submit_fn is None:
@@ -520,13 +636,23 @@ async def _handle_flow_steps(
520
636
  remaining_config = dict(config)
521
637
  current_step = initial_step
522
638
  last_menu_choice: str | None = None
639
+ ignored_config_keys: set[str] = set()
523
640
  max_steps = 10
524
641
 
525
642
  for step_num in range(max_steps):
526
643
  result_type = current_step.get("type")
527
644
 
528
645
  if result_type == _FlowType.CREATE_ENTRY:
529
- return {"success": True, "entry": current_step}
646
+ ignored_config_keys.update(
647
+ key for key in remaining_config if key not in _MENU_SELECTION_KEYS
648
+ )
649
+ response: dict[str, Any] = {"success": True, "entry": current_step}
650
+ if ignored_config_keys:
651
+ response["warnings"] = [
652
+ "Ignored config keys not declared by the Home Assistant flow "
653
+ f"schema: {', '.join(sorted(ignored_config_keys))}"
654
+ ]
655
+ return response
530
656
 
531
657
  if result_type == _FlowType.ABORT:
532
658
  raise_tool_error(
@@ -559,7 +685,12 @@ async def _handle_flow_steps(
559
685
  # step's data_schema, leaving any other keys in remaining_config
560
686
  # for subsequent steps (HA can present multi-step forms, e.g.
561
687
  # statistics: user step then pick-characteristic step).
562
- form_data = _handle_form_step(flow_id, current_step, remaining_config)
688
+ form_data = _handle_form_step(
689
+ flow_id,
690
+ current_step,
691
+ remaining_config,
692
+ ignored_config_keys,
693
+ )
563
694
  logger.debug(
564
695
  f"Flow step {step_num}: form submit "
565
696
  f"(step_id={current_step.get('step_id')}, keys={list(form_data.keys())})"
@@ -875,7 +1006,7 @@ async def update_flow_helper(
875
1006
  raise
876
1007
 
877
1008
  entry = result["entry"].get("result", {})
878
- return {
1009
+ response = {
879
1010
  "success": True,
880
1011
  "entry_id": entry_id,
881
1012
  "title": entry.get("title"),
@@ -883,6 +1014,9 @@ async def update_flow_helper(
883
1014
  "message": f"{helper_type} helper updated successfully",
884
1015
  "updated": True,
885
1016
  }
1017
+ if result.get("warnings"):
1018
+ response["warnings"] = result["warnings"]
1019
+ return response
886
1020
 
887
1021
 
888
1022
  async def create_flow_helper(
@@ -928,10 +1062,13 @@ async def create_flow_helper(
928
1062
  raise
929
1063
 
930
1064
  entry = result["entry"].get("result", {})
931
- return {
1065
+ response = {
932
1066
  "success": True,
933
1067
  "entry_id": entry.get("entry_id"),
934
1068
  "title": entry.get("title"),
935
1069
  "domain": helper_type,
936
1070
  "message": f"{helper_type} helper created successfully",
937
1071
  }
1072
+ if result.get("warnings"):
1073
+ response["warnings"] = result["warnings"]
1074
+ return response
@@ -1968,6 +1968,7 @@ async def _handle_flow_helper(
1968
1968
  entry_id = flow_result.get("entry_id")
1969
1969
  title = flow_result.get("title")
1970
1970
  warnings = list(pre_warnings)
1971
+ warnings.extend(flow_result.get("warnings", []))
1971
1972
  entities, wait_warnings = await _wait_for_flow_entities(
1972
1973
  client, entry_id, action, wait
1973
1974
  )
@@ -20,7 +20,7 @@ from ..client.rest_client import (
20
20
  )
21
21
  from ..errors import ErrorCode, create_error_response
22
22
  from .auto_backup import with_auto_backup
23
- from .config_entry_flow import FLOW_HELPER_TYPES
23
+ from .config_entry_flow import FLOW_HELPER_TYPES, iter_schema_fields
24
24
  from .helpers import (
25
25
  exception_to_structured_error,
26
26
  log_tool_usage,
@@ -113,8 +113,8 @@ def options_from_form_flow(flow: dict[str, Any]) -> dict[str, Any]:
113
113
  ``default``). A field can carry both ``suggested_value`` and
114
114
  ``default`` at once — e.g. a group helper's ``hide_members`` stored as
115
115
  ``True`` over a schema default of ``False`` — and the stored value
116
- must win (issue #1575). Fields with a missing or ``None`` value are
117
- skipped.
116
+ must win (issue #1575). Nested section fields are flattened into the
117
+ returned top-level map. Fields with a missing or ``None`` value are skipped.
118
118
  """
119
119
  out: dict[str, Any] = {}
120
120
  # Defensive: HA should always return a list of dict fields, but guard
@@ -123,9 +123,7 @@ def options_from_form_flow(flow: dict[str, Any]) -> dict[str, Any]:
123
123
  data_schema = flow.get("data_schema")
124
124
  if not isinstance(data_schema, list):
125
125
  return out
126
- for field in data_schema:
127
- if not isinstance(field, dict):
128
- continue
126
+ for field in iter_schema_fields(data_schema):
129
127
  name = field.get("name")
130
128
  if name is None:
131
129
  continue
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ha-mcp-dev
3
- Version: 7.12.3.dev1855
3
+ Version: 7.12.3.dev1859
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