ha-mcp-dev 7.14.2.dev2113__tar.gz → 7.14.2.dev2115__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 (190) hide show
  1. {ha_mcp_dev-7.14.2.dev2113/src/ha_mcp_dev.egg-info → ha_mcp_dev-7.14.2.dev2115}/PKG-INFO +1 -1
  2. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/pyproject.toml +1 -1
  3. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/smart_search/_deep.py +160 -3
  4. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/tools_config_dashboards.py +8 -5
  5. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/tools_search.py +35 -2
  6. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115/src/ha_mcp_dev.egg-info}/PKG-INFO +1 -1
  7. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/LICENSE +0 -0
  8. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/MANIFEST.in +0 -0
  9. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/README.md +0 -0
  10. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/setup.cfg +0 -0
  11. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/__init__.py +0 -0
  12. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/__main__.py +0 -0
  13. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/_pypi_marker +0 -0
  14. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/_version.py +0 -0
  15. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/auth/__init__.py +0 -0
  16. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/auth/consent_form.py +0 -0
  17. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/auth/provider.py +0 -0
  18. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/backup_manager.py +0 -0
  19. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/browser_landing.py +0 -0
  20. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/client/__init__.py +0 -0
  21. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/client/rest_client.py +0 -0
  22. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/client/supervisor_client.py +0 -0
  23. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/client/websocket_client.py +0 -0
  24. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/client/websocket_listener.py +0 -0
  25. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/config.py +0 -0
  26. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/dashboard_screenshot/__init__.py +0 -0
  27. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/dashboard_screenshot/capture.py +0 -0
  28. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/dashboard_screenshot/content.py +0 -0
  29. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/dashboard_screenshot/paths.py +0 -0
  30. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/dashboard_screenshot/provision.py +0 -0
  31. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/dashboard_screenshot/theme_guard.py +0 -0
  32. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/errors.py +0 -0
  33. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/llm_exposure.py +0 -0
  34. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/policy/__init__.py +0 -0
  35. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/policy/approval_queue.py +0 -0
  36. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/policy/evaluator.py +0 -0
  37. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/policy/handlers.py +0 -0
  38. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/policy/middleware.py +0 -0
  39. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/policy/model.py +0 -0
  40. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/policy/persistence.py +0 -0
  41. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/policy/value_sources.py +0 -0
  42. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/py.typed +0 -0
  43. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/read_only.py +0 -0
  44. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/resources/skills-vendor/.claude/settings.json +0 -0
  45. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/resources/skills-vendor/.claude-plugin/marketplace.json +0 -0
  46. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/resources/skills-vendor/.claude-plugin/plugin.json +0 -0
  47. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/resources/skills-vendor/.github/ISSUE_TEMPLATE/skill-rca.md +0 -0
  48. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/resources/skills-vendor/.github/pull_request_template.md +0 -0
  49. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/resources/skills-vendor/AGENTS.md +0 -0
  50. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/resources/skills-vendor/CLAUDE.md +0 -0
  51. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/resources/skills-vendor/CONTRIBUTING.md +0 -0
  52. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/resources/skills-vendor/LICENSE +0 -0
  53. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/resources/skills-vendor/README.md +0 -0
  54. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/SKILL.md +0 -0
  55. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/evals/evals.json +0 -0
  56. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/appdaemon.md +0 -0
  57. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/automation-patterns.md +0 -0
  58. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/blueprint-guide.md +0 -0
  59. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-cards.md +0 -0
  60. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-guide.md +0 -0
  61. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/device-control.md +0 -0
  62. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/domain-docs.md +0 -0
  63. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/examples.yaml +0 -0
  64. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/helper-selection.md +0 -0
  65. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/safe-refactoring.md +0 -0
  66. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/scenes.md +0 -0
  67. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/template-guidelines.md +0 -0
  68. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/yaml-only-integrations.md +0 -0
  69. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/server.py +0 -0
  70. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/settings_ui/__init__.py +0 -0
  71. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/settings_ui/_handlers_advanced.py +0 -0
  72. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/settings_ui/_handlers_backups.py +0 -0
  73. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/settings_ui/_handlers_fs.py +0 -0
  74. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/settings_ui/_handlers_server.py +0 -0
  75. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/settings_ui/_handlers_theme.py +0 -0
  76. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/settings_ui/_handlers_tools.py +0 -0
  77. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/settings_ui/_i18n.py +0 -0
  78. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/settings_ui/_persistence.py +0 -0
  79. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/settings_ui/_supervisor.py +0 -0
  80. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/settings_ui/_theme.py +0 -0
  81. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/settings_ui/_tools_meta.py +0 -0
  82. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/settings_ui/locales/README.md +0 -0
  83. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/settings_ui/locales/de.json +0 -0
  84. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/settings_ui/locales/en.json +0 -0
  85. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/settings_ui/locales/ru.json +0 -0
  86. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/settings_ui/locales/zh-Hans.json +0 -0
  87. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/settings_ui/settings.css +0 -0
  88. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/settings_ui/settings.html +0 -0
  89. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/settings_ui/settings.js +0 -0
  90. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/smoke_test.py +0 -0
  91. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/stdio_settings_sidecar.py +0 -0
  92. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/strict_bps.py +0 -0
  93. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/__init__.py +0 -0
  94. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/auto_backup.py +0 -0
  95. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/backup.py +0 -0
  96. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/best_practice_checker.py +0 -0
  97. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/component_api.py +0 -0
  98. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/component_config_reads.py +0 -0
  99. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/component_devices.py +0 -0
  100. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/component_registries.py +0 -0
  101. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/component_registry_lookup.py +0 -0
  102. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/config_entry_flow.py +0 -0
  103. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/device_control.py +0 -0
  104. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/enhanced.py +0 -0
  105. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/helpers.py +0 -0
  106. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/radio/__init__.py +0 -0
  107. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/radio/base.py +0 -0
  108. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/radio/matter.py +0 -0
  109. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/radio/thread.py +0 -0
  110. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/radio/zigbee.py +0 -0
  111. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/radio/zwave.py +0 -0
  112. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/reference_validator.py +0 -0
  113. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/registry.py +0 -0
  114. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/smart_search/__init__.py +0 -0
  115. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/smart_search/_base.py +0 -0
  116. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/smart_search/_config.py +0 -0
  117. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/smart_search/_entities.py +0 -0
  118. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/smart_search/_fetch.py +0 -0
  119. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/smart_search/_overview.py +0 -0
  120. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/smart_search/_scenes.py +0 -0
  121. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/smart_search/_scoring.py +0 -0
  122. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/tool_search_hint_middleware.py +0 -0
  123. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/tools_addons.py +0 -0
  124. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/tools_areas.py +0 -0
  125. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/tools_blueprints.py +0 -0
  126. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/tools_bug_report.py +0 -0
  127. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/tools_calendar.py +0 -0
  128. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/tools_camera.py +0 -0
  129. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/tools_categories.py +0 -0
  130. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/tools_code.py +0 -0
  131. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/tools_config_automations.py +0 -0
  132. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/tools_config_helpers.py +0 -0
  133. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/tools_config_scenes.py +0 -0
  134. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/tools_config_scripts.py +0 -0
  135. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/tools_dashboard_screenshot.py +0 -0
  136. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/tools_dev.py +0 -0
  137. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/tools_energy.py +0 -0
  138. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/tools_entities.py +0 -0
  139. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/tools_filesystem.py +0 -0
  140. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/tools_groups.py +0 -0
  141. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/tools_hacs.py +0 -0
  142. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/tools_history.py +0 -0
  143. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/tools_integrations.py +0 -0
  144. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/tools_labels.py +0 -0
  145. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/tools_radio.py +0 -0
  146. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/tools_registry.py +0 -0
  147. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/tools_resources.py +0 -0
  148. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/tools_service.py +0 -0
  149. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/tools_services.py +0 -0
  150. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/tools_system.py +0 -0
  151. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/tools_themes.py +0 -0
  152. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/tools_todo.py +0 -0
  153. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/tools_traces.py +0 -0
  154. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/tools_updates.py +0 -0
  155. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/tools_utility.py +0 -0
  156. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/tools_voice_assistant.py +0 -0
  157. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/tools_yaml_config.py +0 -0
  158. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/tools_yaml_read.py +0 -0
  159. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/tools_zones.py +0 -0
  160. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/util_helpers.py +0 -0
  161. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/tools/validation_middleware.py +0 -0
  162. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/transforms/__init__.py +0 -0
  163. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/transforms/categorized_search.py +0 -0
  164. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/transforms/lite_docstrings.py +0 -0
  165. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/transport_security.py +0 -0
  166. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/update_check.py +0 -0
  167. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/utils/__init__.py +0 -0
  168. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/utils/config_hash.py +0 -0
  169. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/utils/config_write_lock.py +0 -0
  170. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/utils/data_paths.py +0 -0
  171. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/utils/domain_handlers.py +0 -0
  172. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/utils/fuzzy_search.py +0 -0
  173. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/utils/kill_signal_diagnostics.py +0 -0
  174. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/utils/operation_manager.py +0 -0
  175. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/utils/python_sandbox.py +0 -0
  176. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/utils/skill_loader.py +0 -0
  177. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/utils/usage_logger.py +0 -0
  178. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/visibility/__init__.py +0 -0
  179. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/visibility/enforcement.py +0 -0
  180. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/visibility/model.py +0 -0
  181. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/visibility/persistence.py +0 -0
  182. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp/visibility/resolver.py +0 -0
  183. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp_dev.egg-info/SOURCES.txt +0 -0
  184. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp_dev.egg-info/dependency_links.txt +0 -0
  185. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp_dev.egg-info/entry_points.txt +0 -0
  186. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp_dev.egg-info/requires.txt +0 -0
  187. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/src/ha_mcp_dev.egg-info/top_level.txt +0 -0
  188. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/tests/__init__.py +0 -0
  189. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/tests/test_constants.py +0 -0
  190. {ha_mcp_dev-7.14.2.dev2113 → ha_mcp_dev-7.14.2.dev2115}/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.14.2.dev2113
3
+ Version: 7.14.2.dev2115
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.14.2.dev2113"
7
+ version = "7.14.2.dev2115"
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
@@ -9,9 +9,14 @@ from fastmcp import Context
9
9
  from fastmcp.exceptions import ToolError
10
10
 
11
11
  from ...client.rest_client import HomeAssistantAPIError
12
+ from ...errors import get_error_code, get_error_message
13
+ from ..component_api import component_supports, get_component_caps
12
14
  from ..config_entry_flow import FLOW_HELPER_TYPES
13
15
  from ..helpers import exception_to_structured_error, safe_info, safe_progress
14
- from ..tools_config_dashboards import fetch_dashboards_list
16
+ from ..tools_config_dashboards import (
17
+ _dashboards_via_component,
18
+ fetch_dashboards_list,
19
+ )
15
20
  from ..tools_integrations import fetch_entry_options_with_status
16
21
  from ._config import (
17
22
  AUTOMATION_CONFIG_TIME_BUDGET,
@@ -55,6 +60,40 @@ async def _scrub_results_for_enforce(
55
60
  results[category] = scrub_records(items, enforce_regex)
56
61
 
57
62
 
63
+ # The ``lovelace/config`` messages meaning "this dashboard has no stored
64
+ # config" — bare (nested error shape) and as ``send_websocket_message``'s
65
+ # flat envelope prefixes it. Mirrors ``dashboard_screenshot/paths.py``.
66
+ _NO_STORED_CONFIG_MESSAGES = frozenset(
67
+ {"No config found.", "Command failed: No config found."}
68
+ )
69
+
70
+
71
+ def _is_no_stored_config(resp: dict[str, Any]) -> bool:
72
+ """True when a failed ``lovelace/config`` envelope means the dashboard
73
+ has no stored config — an auto-generated dashboard that was never taken
74
+ control of — which is a clean no-match for a config scan rather than a
75
+ backend failure (issue #2008).
76
+
77
+ HA reports the ``config_not_found`` code for two distinct causes
78
+ (``homeassistant/components/lovelace/websocket.py``, ``_handle_errors``):
79
+ no stored config ("No config found.") and an unresolvable url_path
80
+ ("Unknown config specified: ..."), e.g. a dashboard deleted between the
81
+ registry-list snapshot and this fetch. Only the former is a clean skip,
82
+ so the message is matched too; the latter stays a counted failure.
83
+
84
+ ``send_websocket_message`` normalizes command failures to a flat envelope
85
+ (code top-level as ``error_code``, message as the ``error`` string); the
86
+ nested ``error.code``/``error.message`` shape is accepted defensively via
87
+ the canonical :func:`get_error_code` / :func:`get_error_message`
88
+ extractors, matching ``dashboard_screenshot/paths.py``'s detection of the
89
+ same HA error.
90
+ """
91
+ code = resp.get("error_code") or get_error_code(resp)
92
+ if code != "config_not_found":
93
+ return False
94
+ return get_error_message(resp) in _NO_STORED_CONFIG_MESSAGES
95
+
96
+
58
97
  class DeepSearchMixin(SceneSearchMixin):
59
98
  """deep_search orchestration + per-type automation/script/helper/dashboard/flow search."""
60
99
 
@@ -279,8 +318,11 @@ class DeepSearchMixin(SceneSearchMixin):
279
318
  (
280
319
  results["dashboards"],
281
320
  dashboard_failed,
282
- ) = await self._deep_search_dashboards(
283
- query_lower, exact_match, semaphore
321
+ ) = await self._search_dashboards_surface(
322
+ query_lower,
323
+ exact_match,
324
+ semaphore,
325
+ include_config=include_config,
284
326
  )
285
327
  phase_done += 1
286
328
  await safe_progress(
@@ -896,6 +938,106 @@ class DeepSearchMixin(SceneSearchMixin):
896
938
  failed_type_count += flow_failed_count
897
939
  return results, failed_type_count
898
940
 
941
+ async def _search_dashboards_surface(
942
+ self,
943
+ query_lower: str,
944
+ exact_match: bool,
945
+ semaphore: asyncio.Semaphore,
946
+ *,
947
+ include_config: bool,
948
+ ) -> tuple[list[dict[str, Any]], int]:
949
+ """The dashboard bucket: component-first, legacy fallback.
950
+
951
+ Returns ``(records, failed_count)``. The component's in-process
952
+ ``search`` frame (issue #2008) serves the exact-match, no-body shape
953
+ — the default ``ha_search`` call — mirroring the
954
+ ``ha_config_get_dashboard(mode="search")`` routing; fuzzy scoring and
955
+ ``include_config`` bodies are legacy-only (the component walk is
956
+ substring and its matches carry no bodies), as is every ``None``
957
+ fallback case of :meth:`_component_dashboard_search` — including a
958
+ YAML-bearing install, so component-vs-legacy never changes which
959
+ dashboards a search covers.
960
+ """
961
+ if exact_match and not include_config:
962
+ component = await self._component_dashboard_search(query_lower)
963
+ if component is not None:
964
+ return component
965
+ return await self._deep_search_dashboards(query_lower, exact_match, semaphore)
966
+
967
+ async def _component_dashboard_search(
968
+ self, query_lower: str
969
+ ) -> tuple[list[dict[str, Any]], int] | None:
970
+ """The dashboard bucket via the component's in-process ``search`` frame.
971
+
972
+ Returns ``(records, failed_count)`` — one legacy-shaped record per
973
+ matching dashboard from the component's ``document_matches`` (a
974
+ whole-document substring verdict per storage dashboard, ported from
975
+ ``_search_in_dict`` leaf for leaf, so view titles and dashboard-level
976
+ keys match exactly as the legacy walk matches them); ``failed_count``
977
+ is the component's ``load_failed`` (storage dashboards whose config
978
+ load raised — surfaced as the same ``dashboard(s) not scanned``
979
+ partial the legacy scan reports). A config-less auto-generated
980
+ dashboard is skipped in-process (nothing to scan), consistent with
981
+ :func:`_is_no_stored_config`.
982
+
983
+ ``None`` ⇒ run the legacy per-dashboard walk instead: the component
984
+ lacks the ``dashboards_doc_search`` capability (older components
985
+ emit only the card-scoped ``matches``, which would silently narrow
986
+ coverage), any ``_dashboards_via_component`` fallback (capability
987
+ miss / command error / lovelace unavailable), an empty query, a
988
+ malformed ``document_matches`` — or a non-zero ``yaml_skipped``.
989
+ The component never reads YAML-mode dashboard bodies, but the legacy
990
+ walk this path replaces does (``lovelace/config`` loads them, and the
991
+ fuzzy / ``include_config`` routes still read the same resolved
992
+ configs), so serving the component result on a YAML-bearing install
993
+ would make the DEFAULT call shape permanently narrower and
994
+ permanently ``partial``. Falling back keeps coverage identical to
995
+ the pre-component behaviour; storage-only installs — where the
996
+ exclusion costs nothing — keep the single-frame win (review
997
+ follow-up on issue #2008).
998
+ """
999
+ if not query_lower:
1000
+ return None
1001
+ caps = await get_component_caps(self.client)
1002
+ if not component_supports(caps, "dashboards_doc_search"):
1003
+ return None
1004
+ result = await _dashboards_via_component(
1005
+ self.client, "search", query=query_lower
1006
+ )
1007
+ if result is None:
1008
+ return None
1009
+ document_matches = result.get("document_matches")
1010
+ if not isinstance(document_matches, list):
1011
+ return None
1012
+ if int(result.get("yaml_skipped", 0) or 0) > 0:
1013
+ return None
1014
+ failed = int(result.get("load_failed", 0) or 0)
1015
+
1016
+ records: dict[str, dict[str, Any]] = {}
1017
+ for match in document_matches:
1018
+ if not isinstance(match, dict):
1019
+ continue
1020
+ raw_url_path = match.get("url_path")
1021
+ url_path = raw_url_path or "default"
1022
+ if url_path in records:
1023
+ continue
1024
+ # The default dashboard: the legacy walk always labels it
1025
+ # ("default", "Default Dashboard") — a taken-control default
1026
+ # may carry its own body title, but emitting it would change
1027
+ # the record shape between the component and legacy paths.
1028
+ title = (
1029
+ "Default Dashboard"
1030
+ if not raw_url_path
1031
+ else (match.get("title") or url_path)
1032
+ )
1033
+ records[url_path] = {
1034
+ "dashboard_url": url_path,
1035
+ "dashboard_title": title,
1036
+ "score": 100,
1037
+ "match_in_config": True,
1038
+ }
1039
+ return list(records.values()), failed
1040
+
899
1041
  async def _search_one_dashboard(
900
1042
  self,
901
1043
  url_path: str,
@@ -912,6 +1054,15 @@ class DeepSearchMixin(SceneSearchMixin):
912
1054
  distinct from a successful no-match. Surfacing it lets
913
1055
  ``ha_search(search_types=["dashboard"])`` report ``partial`` instead
914
1056
  of a complete-looking empty result.
1057
+
1058
+ The no-stored-config envelope (``config_not_found`` + "No config
1059
+ found.", see :func:`_is_no_stored_config`) is the deliberate
1060
+ exception: an auto-generated dashboard (strategy-backed, never taken
1061
+ control of) has nothing to scan, so it reads as a clean no-match.
1062
+ Counting it as failed made every dashboard search on a stock install
1063
+ report ``partial`` (issue #2008). The code's other cause — "Unknown
1064
+ config specified", a dashboard deleted since the registry-list
1065
+ snapshot — stays a counted failure.
915
1066
  """
916
1067
  async with semaphore:
917
1068
  try:
@@ -932,6 +1083,12 @@ class DeepSearchMixin(SceneSearchMixin):
932
1083
  # shape explicitly (``success is False``) so a missing-success
933
1084
  # raw response still falls through to the ``result`` fallback.
934
1085
  if isinstance(resp, dict) and resp.get("success") is False:
1086
+ if _is_no_stored_config(resp):
1087
+ logger.debug(
1088
+ f"Dashboard has no stored config ({url_path}); "
1089
+ "auto-generated — nothing to scan"
1090
+ )
1091
+ return [], False
935
1092
  logger.debug(
936
1093
  f"Dashboard config returned non-success ({url_path}): {resp!r}"
937
1094
  )
@@ -813,10 +813,12 @@ def _card_matches(
813
813
  #
814
814
  # Source: homeassistant/components/lovelace/websocket.py, _handle_errors —
815
815
  # emits f"Unknown config specified: {url_path}" paired with structured
816
- # error.code "config_not_found". The websocket client currently surfaces only
817
- # the message string, so substring matching is the only signal available at
818
- # the tool layer. If HA reformats this string, the lazy fallback regresses
819
- # silently to never firing re-verify with major HA upgrades.
816
+ # error.code "config_not_found". The client envelope does surface that code
817
+ # top-level (``error_code``), but HA reuses it for the no-stored-config case
818
+ # ("No config found." an auto-generated dashboard), so the code alone cannot
819
+ # identify an unresolved identifier; the message substring remains the only
820
+ # discriminating signal. If HA reformats this string, the lazy fallback
821
+ # regresses silently to never firing — re-verify with major HA upgrades.
820
822
  _LAZY_RESOLVE_TRIGGER = "Unknown config specified"
821
823
 
822
824
 
@@ -1283,7 +1285,8 @@ async def fetch_dashboards_list(
1283
1285
  every fetch site rather than silently degrading.
1284
1286
 
1285
1287
  When the ``ha_mcp_tools`` component advertises the ``dashboards`` capability
1286
- the storage-only rows are served from one in-process ``list`` frame (the
1288
+ the rows YAML rows included, tagged with ``mode`` (see
1289
+ ``_component_dashboard_rows``) — are served from one in-process ``list`` frame (the
1287
1290
  ``_resolve_dashboard`` / ``_lookup_existing_dashboards`` / list-mode callers
1288
1291
  all funnel here); otherwise the legacy ``lovelace/dashboards/list`` WS read
1289
1292
  runs unchanged.
@@ -917,6 +917,33 @@ def _normalize_component_config_record(
917
917
  return out
918
918
 
919
919
 
920
+ # Body surfaces the ``ha_mcp_tools`` component's ``search`` command accepts
921
+ # (its voluptuous allowlist also has ``entity``, appended separately by
922
+ # ``_build_component_search_request``). ``dashboard`` is deliberately absent:
923
+ # the component has no dashboard scanner, so a request naming it must stay on
924
+ # the legacy path — forwarding it just bounced off the component schema into a
925
+ # warning-laden fallback on every call (issue #2008).
926
+ _COMPONENT_BODY_SEARCH_TYPES: frozenset[str] = frozenset(
927
+ {"automation", "script", "scene", "helper"}
928
+ )
929
+
930
+
931
+ def _component_serves_search_types(req: _ResolvedSearch) -> bool:
932
+ """True when the component's search command accepts every requested surface.
933
+
934
+ Only an explicit ``search_types`` list can name an unsupported surface, and
935
+ only the body-eligible branch forwards it to the component — a
936
+ body-ineligible request sends the entity surface alone, which the component
937
+ always accepts. Routing is all-or-nothing per command, so one unsupported
938
+ surface sends the whole request to the legacy path, silently — the same
939
+ treatment as the other route-ineligible modes, not the warning-emitting
940
+ failure fallback.
941
+ """
942
+ if not req.body_eligible or req.parsed_search_types is None:
943
+ return True
944
+ return all(t in _COMPONENT_BODY_SEARCH_TYPES for t in req.parsed_search_types)
945
+
946
+
920
947
  def _build_component_search_request(req: _ResolvedSearch) -> dict[str, Any]:
921
948
  """Translate resolved ha_search inputs into an ``ha_mcp_tools/search`` request.
922
949
 
@@ -1958,7 +1985,9 @@ class SearchTools:
1958
1985
  # response keys) — keep the legacy path: their response contracts
1959
1986
  # differ per mode, and after the request-dedup work they are cheap
1960
1987
  # registry-only calls, so the component round-trip buys nothing worth
1961
- # the shape risk.
1988
+ # the shape risk. A ``search_types`` naming a surface the component
1989
+ # lacks (``dashboard``) also stays legacy — see
1990
+ # ``_component_serves_search_types`` (issue #2008).
1962
1991
  #
1963
1992
  # Entity-visibility gate. A plain ``search`` component applies no
1964
1993
  # filtering, so an install with an ACTIVE visibility filter would leak
@@ -1973,7 +2002,11 @@ class SearchTools:
1973
2002
  # needs no analogous gate — it re-applies the filter server-side over the
1974
2003
  # component's raw slices. Checked only when the component would otherwise
1975
2004
  # serve, so the common (no-component / filter-off) install pays nothing.
1976
- if req.query_text and not (req.area_filter or "").strip():
2005
+ if (
2006
+ req.query_text
2007
+ and not (req.area_filter or "").strip()
2008
+ and _component_serves_search_types(req)
2009
+ ):
1977
2010
  caps = await get_component_caps(self._client)
1978
2011
  if component_supports(caps, "search"):
1979
2012
  (
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ha-mcp-dev
3
- Version: 7.14.2.dev2113
3
+ Version: 7.14.2.dev2115
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