ha-mcp-dev 7.7.0.dev683__tar.gz → 7.7.0.dev684__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 (141) hide show
  1. {ha_mcp_dev-7.7.0.dev683/src/ha_mcp_dev.egg-info → ha_mcp_dev-7.7.0.dev684}/PKG-INFO +1 -1
  2. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/pyproject.toml +1 -1
  3. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/tools/tools_config_automations.py +2 -0
  4. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/tools/tools_config_dashboards.py +2 -0
  5. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/tools/tools_config_helpers.py +2 -0
  6. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/tools/tools_config_scenes.py +2 -0
  7. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/tools/tools_config_scripts.py +2 -0
  8. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/tools/tools_entities.py +8 -1
  9. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/tools/tools_service.py +4 -3
  10. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/tools/util_helpers.py +30 -1
  11. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684/src/ha_mcp_dev.egg-info}/PKG-INFO +1 -1
  12. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/LICENSE +0 -0
  13. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/MANIFEST.in +0 -0
  14. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/README.md +0 -0
  15. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/setup.cfg +0 -0
  16. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/__init__.py +0 -0
  17. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/__main__.py +0 -0
  18. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/_pypi_marker +0 -0
  19. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/_version.py +0 -0
  20. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/auth/__init__.py +0 -0
  21. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/auth/consent_form.py +0 -0
  22. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/auth/provider.py +0 -0
  23. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/backup_manager.py +0 -0
  24. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/client/__init__.py +0 -0
  25. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/client/rest_client.py +0 -0
  26. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/client/supervisor_client.py +0 -0
  27. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/client/websocket_client.py +0 -0
  28. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/client/websocket_listener.py +0 -0
  29. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/config.py +0 -0
  30. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/dashboard_screenshot/__init__.py +0 -0
  31. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/dashboard_screenshot/capture.py +0 -0
  32. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/dashboard_screenshot/provision.py +0 -0
  33. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/errors.py +0 -0
  34. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/policy/__init__.py +0 -0
  35. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/policy/approval_queue.py +0 -0
  36. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/policy/evaluator.py +0 -0
  37. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/policy/handlers.py +0 -0
  38. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/policy/middleware.py +0 -0
  39. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/policy/model.py +0 -0
  40. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/policy/persistence.py +0 -0
  41. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/policy/value_sources.py +0 -0
  42. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/py.typed +0 -0
  43. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/read_only.py +0 -0
  44. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/resources/skills-vendor/.claude/settings.json +0 -0
  45. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/resources/skills-vendor/.claude-plugin/marketplace.json +0 -0
  46. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/resources/skills-vendor/.claude-plugin/plugin.json +0 -0
  47. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/resources/skills-vendor/.github/ISSUE_TEMPLATE/skill-rca.md +0 -0
  48. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/resources/skills-vendor/.github/pull_request_template.md +0 -0
  49. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/resources/skills-vendor/AGENTS.md +0 -0
  50. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/resources/skills-vendor/CLAUDE.md +0 -0
  51. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/resources/skills-vendor/CONTRIBUTING.md +0 -0
  52. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/resources/skills-vendor/LICENSE +0 -0
  53. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/resources/skills-vendor/README.md +0 -0
  54. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/SKILL.md +0 -0
  55. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/evals/evals.json +0 -0
  56. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/automation-patterns.md +0 -0
  57. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-cards.md +0 -0
  58. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-guide.md +0 -0
  59. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/device-control.md +0 -0
  60. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/domain-docs.md +0 -0
  61. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/examples.yaml +0 -0
  62. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/helper-selection.md +0 -0
  63. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/safe-refactoring.md +0 -0
  64. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/template-guidelines.md +0 -0
  65. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/yaml-only-integrations.md +0 -0
  66. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/server.py +0 -0
  67. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/settings.css +0 -0
  68. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/settings.js +0 -0
  69. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/settings_ui.py +0 -0
  70. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/smoke_test.py +0 -0
  71. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/stdio_settings_sidecar.py +0 -0
  72. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/tools/__init__.py +0 -0
  73. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/tools/auto_backup.py +0 -0
  74. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/tools/backup.py +0 -0
  75. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/tools/best_practice_checker.py +0 -0
  76. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/tools/config_entry_flow.py +0 -0
  77. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/tools/device_control.py +0 -0
  78. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/tools/enhanced.py +0 -0
  79. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/tools/helpers.py +0 -0
  80. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/tools/reference_validator.py +0 -0
  81. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/tools/registry.py +0 -0
  82. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/tools/smart_search/__init__.py +0 -0
  83. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/tools/smart_search/_base.py +0 -0
  84. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/tools/smart_search/_config.py +0 -0
  85. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/tools/smart_search/_deep.py +0 -0
  86. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/tools/smart_search/_entities.py +0 -0
  87. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/tools/smart_search/_fetch.py +0 -0
  88. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/tools/smart_search/_overview.py +0 -0
  89. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/tools/smart_search/_scenes.py +0 -0
  90. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/tools/smart_search/_scoring.py +0 -0
  91. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/tools/tools_addons.py +0 -0
  92. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/tools/tools_areas.py +0 -0
  93. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/tools/tools_blueprints.py +0 -0
  94. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/tools/tools_bug_report.py +0 -0
  95. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/tools/tools_calendar.py +0 -0
  96. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/tools/tools_camera.py +0 -0
  97. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/tools/tools_categories.py +0 -0
  98. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/tools/tools_code.py +0 -0
  99. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/tools/tools_dashboard_screenshot.py +0 -0
  100. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/tools/tools_energy.py +0 -0
  101. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/tools/tools_filesystem.py +0 -0
  102. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/tools/tools_groups.py +0 -0
  103. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/tools/tools_hacs.py +0 -0
  104. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/tools/tools_history.py +0 -0
  105. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/tools/tools_integrations.py +0 -0
  106. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/tools/tools_labels.py +0 -0
  107. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/tools/tools_mcp_component.py +0 -0
  108. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/tools/tools_registry.py +0 -0
  109. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/tools/tools_resources.py +0 -0
  110. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/tools/tools_search.py +0 -0
  111. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/tools/tools_services.py +0 -0
  112. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/tools/tools_system.py +0 -0
  113. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/tools/tools_todo.py +0 -0
  114. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/tools/tools_traces.py +0 -0
  115. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/tools/tools_updates.py +0 -0
  116. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/tools/tools_utility.py +0 -0
  117. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/tools/tools_voice_assistant.py +0 -0
  118. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/tools/tools_yaml_config.py +0 -0
  119. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/tools/tools_zones.py +0 -0
  120. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/tools/validation_middleware.py +0 -0
  121. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/transforms/__init__.py +0 -0
  122. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/transforms/categorized_search.py +0 -0
  123. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/transforms/lite_docstrings.py +0 -0
  124. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/utils/__init__.py +0 -0
  125. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/utils/config_hash.py +0 -0
  126. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/utils/data_paths.py +0 -0
  127. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/utils/domain_handlers.py +0 -0
  128. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/utils/fuzzy_search.py +0 -0
  129. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/utils/kill_signal_diagnostics.py +0 -0
  130. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/utils/operation_manager.py +0 -0
  131. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/utils/python_sandbox.py +0 -0
  132. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/utils/skill_loader.py +0 -0
  133. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp/utils/usage_logger.py +0 -0
  134. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp_dev.egg-info/SOURCES.txt +0 -0
  135. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp_dev.egg-info/dependency_links.txt +0 -0
  136. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp_dev.egg-info/entry_points.txt +0 -0
  137. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp_dev.egg-info/requires.txt +0 -0
  138. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/src/ha_mcp_dev.egg-info/top_level.txt +0 -0
  139. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/tests/__init__.py +0 -0
  140. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/tests/test_constants.py +0 -0
  141. {ha_mcp_dev-7.7.0.dev683 → ha_mcp_dev-7.7.0.dev684}/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.7.0.dev683
3
+ Version: 7.7.0.dev684
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.7.0.dev683"
7
+ version = "7.7.0.dev684"
8
8
  description = "Home Assistant MCP Server - Complete control of Home Assistant through MCP"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.13,<3.14"
@@ -46,6 +46,7 @@ from .helpers import (
46
46
  )
47
47
  from .reference_validator import validate_config_references
48
48
  from .util_helpers import (
49
+ JSON_STRING_COERCION,
49
50
  apply_entity_category,
50
51
  attach_skill_content,
51
52
  augment_error_dict_with_skill_content,
@@ -435,6 +436,7 @@ class AutomationConfigTools:
435
436
  self,
436
437
  config: Annotated[
437
438
  dict[str, Any] | None,
439
+ JSON_STRING_COERCION,
438
440
  Field(
439
441
  description="Complete automation configuration with required fields: 'alias', 'triggers', 'actions'. "
440
442
  "Optional: 'description', 'conditions', 'mode', 'max', 'initial_state', 'variables'. "
@@ -32,6 +32,7 @@ from .helpers import (
32
32
  validate_identifier_not_empty,
33
33
  )
34
34
  from .util_helpers import (
35
+ JSON_STRING_COERCION,
35
36
  attach_skill_content,
36
37
  augment_error_dict_with_skill_content,
37
38
  augment_tool_error_with_skill_content,
@@ -1021,6 +1022,7 @@ def register_config_dashboard_tools(mcp: Any, client: Any, **kwargs: Any) -> Non
1021
1022
  ],
1022
1023
  config: Annotated[
1023
1024
  dict[str, Any] | None,
1025
+ JSON_STRING_COERCION,
1024
1026
  Field(
1025
1027
  description="Dashboard configuration with views and cards. "
1026
1028
  "Omit or set to None to create dashboard without initial config. "
@@ -35,6 +35,7 @@ from .helpers import (
35
35
  validate_identifier_not_empty,
36
36
  )
37
37
  from .util_helpers import (
38
+ JSON_STRING_COERCION,
38
39
  apply_entity_category,
39
40
  attach_skill_content,
40
41
  augment_error_dict_with_skill_content,
@@ -3686,6 +3687,7 @@ class HelperConfigTools:
3686
3687
  ] = None,
3687
3688
  config: Annotated[
3688
3689
  dict[str, Any] | None,
3690
+ JSON_STRING_COERCION,
3689
3691
  Field(
3690
3692
  description=(
3691
3693
  "Config dict for flow-based helper types and "
@@ -38,6 +38,7 @@ from .helpers import (
38
38
  )
39
39
  from .reference_validator import validate_config_references
40
40
  from .util_helpers import (
41
+ JSON_STRING_COERCION,
41
42
  apply_entity_category,
42
43
  attach_skill_content,
43
44
  augment_error_dict_with_skill_content,
@@ -438,6 +439,7 @@ class ConfigSceneTools:
438
439
  ],
439
440
  config: Annotated[
440
441
  dict[str, Any] | None,
442
+ JSON_STRING_COERCION,
441
443
  Field(
442
444
  description=(
443
445
  "Scene configuration dictionary. Must include 'entities' "
@@ -41,6 +41,7 @@ from .helpers import (
41
41
  )
42
42
  from .reference_validator import validate_config_references
43
43
  from .util_helpers import (
44
+ JSON_STRING_COERCION,
44
45
  apply_entity_category,
45
46
  attach_skill_content,
46
47
  augment_error_dict_with_skill_content,
@@ -399,6 +400,7 @@ class ConfigScriptTools:
399
400
  ],
400
401
  config: Annotated[
401
402
  dict[str, Any] | None,
403
+ JSON_STRING_COERCION,
402
404
  Field(
403
405
  description="Script configuration dictionary. Must include EITHER 'sequence' (for regular scripts) OR 'use_blueprint' (for blueprint-based scripts). "
404
406
  "Optional fields: 'alias', 'description', 'icon', 'mode', 'max', 'fields'. "
@@ -22,7 +22,11 @@ from .helpers import (
22
22
  validate_identifier_not_empty,
23
23
  )
24
24
  from .tools_voice_assistant import KNOWN_ASSISTANTS
25
- from .util_helpers import parse_json_param, parse_string_list_param
25
+ from .util_helpers import (
26
+ JSON_STRING_COERCION,
27
+ parse_json_param,
28
+ parse_string_list_param,
29
+ )
26
30
 
27
31
  logger = logging.getLogger(__name__)
28
32
 
@@ -596,6 +600,7 @@ def register_entity_tools(mcp: Any, client: Any, **kwargs: Any) -> None:
596
600
  ] = None,
597
601
  options: Annotated[
598
602
  dict[str, dict[str, Any]] | None,
603
+ JSON_STRING_COERCION,
599
604
  Field(
600
605
  description=(
601
606
  "Per-domain entity registry options (e.g. sensor 'display_precision', "
@@ -641,6 +646,7 @@ def register_entity_tools(mcp: Any, client: Any, **kwargs: Any) -> None:
641
646
  ] = None,
642
647
  categories: Annotated[
643
648
  dict[str, str | None] | None,
649
+ JSON_STRING_COERCION,
644
650
  Field(
645
651
  description=(
646
652
  "Category assignment as a dict mapping scope to category_id. "
@@ -667,6 +673,7 @@ def register_entity_tools(mcp: Any, client: Any, **kwargs: Any) -> None:
667
673
  ] = "set",
668
674
  expose_to: Annotated[
669
675
  dict[str, bool] | None,
676
+ JSON_STRING_COERCION,
670
677
  Field(
671
678
  description=(
672
679
  "Control voice assistant exposure. Pass a dict mapping assistant IDs to booleans. "
@@ -24,6 +24,7 @@ from .helpers import (
24
24
  register_tool_methods,
25
25
  )
26
26
  from .util_helpers import (
27
+ JSON_STRING_COERCION,
27
28
  compact_service_result,
28
29
  parse_json_param,
29
30
  parse_string_list_param,
@@ -297,7 +298,7 @@ class ServiceTools:
297
298
  domain: str,
298
299
  service: str,
299
300
  entity_id: str | None = None,
300
- data: dict[str, Any] | None = None,
301
+ data: Annotated[dict[str, Any] | None, JSON_STRING_COERCION] = None,
301
302
  return_response: bool = False,
302
303
  wait: bool = True,
303
304
  verbose: Annotated[
@@ -584,7 +585,7 @@ class ServiceTools:
584
585
  @log_tool_usage
585
586
  async def ha_bulk_control(
586
587
  self,
587
- operations: list[dict[str, Any]],
588
+ operations: Annotated[list[dict[str, Any]], JSON_STRING_COERCION],
588
589
  parallel: bool = True,
589
590
  ctx: Context | None = None,
590
591
  ) -> dict[str, Any]:
@@ -632,7 +633,7 @@ class ServiceTools:
632
633
  async def ha_call_event(
633
634
  self,
634
635
  event_type: str,
635
- data: dict[str, Any] | None = None,
636
+ data: Annotated[dict[str, Any] | None, JSON_STRING_COERCION] = None,
636
637
  ) -> dict[str, Any]:
637
638
  """Execute a custom event on the Home Assistant event bus.
638
639
 
@@ -13,7 +13,7 @@ from collections.abc import Awaitable, Callable
13
13
  from typing import Any
14
14
 
15
15
  from fastmcp.exceptions import ToolError
16
- from pydantic import ValidationError
16
+ from pydantic import BeforeValidator, ValidationError
17
17
 
18
18
  from ..client.rest_client import (
19
19
  HomeAssistantAPIError,
@@ -119,6 +119,35 @@ def parse_json_param(
119
119
  )
120
120
 
121
121
 
122
+ def _loads_if_json_container_str(value: Any) -> Any:
123
+ """Parse a JSON-encoded object/array string into its container value.
124
+
125
+ Anything that isn't a string encoding a JSON object or array passes
126
+ through unchanged, so Pydantic still raises dict_type/list_type for
127
+ genuinely-malformed input (which ValidationErrorMiddleware rewrites
128
+ into an actionable message).
129
+ """
130
+ if isinstance(value, str):
131
+ try:
132
+ parsed = json.loads(value)
133
+ except (ValueError, RecursionError):
134
+ # RecursionError (deeply-nested input) must not escape: Pydantic
135
+ # only converts ValueError/AssertionError into ValidationError.
136
+ return value
137
+ if isinstance(parsed, (dict, list)):
138
+ return parsed
139
+ return value
140
+
141
+
142
+ # Annotated metadata for MCP-exposed dict/list params (issue #1581): coerces a
143
+ # JSON-encoded string to its parsed container before validation, without
144
+ # re-advertising string in the tool schema (the #1485/#1487/#1492 fix). Some
145
+ # MCP client stacks (Claude Desktop stdio among them) pass model-emitted
146
+ # stringified objects through unrepaired, so the strict schema boundary alone
147
+ # rejects previously-valid traffic.
148
+ JSON_STRING_COERCION = BeforeValidator(_loads_if_json_container_str)
149
+
150
+
122
151
  def _parse_json_to_str_list(s: str, param_name: str) -> list[str]:
123
152
  """Parse a JSON string as a list of strings, raising ValueError on failure."""
124
153
  try:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ha-mcp-dev
3
- Version: 7.7.0.dev683
3
+ Version: 7.7.0.dev684
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