ha-mcp-dev 7.12.3.dev1940__tar.gz → 7.12.3.dev1942__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 (177) hide show
  1. {ha_mcp_dev-7.12.3.dev1940/src/ha_mcp_dev.egg-info → ha_mcp_dev-7.12.3.dev1942}/PKG-INFO +4 -4
  2. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/README.md +3 -3
  3. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/pyproject.toml +1 -1
  4. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/server.py +11 -11
  5. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_config_helpers.py +112 -8
  6. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_groups.py +42 -10
  7. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_resources.py +30 -5
  8. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942/src/ha_mcp_dev.egg-info}/PKG-INFO +4 -4
  9. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/LICENSE +0 -0
  10. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/MANIFEST.in +0 -0
  11. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/setup.cfg +0 -0
  12. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/__init__.py +0 -0
  13. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/__main__.py +0 -0
  14. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/_pypi_marker +0 -0
  15. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/_version.py +0 -0
  16. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/auth/__init__.py +0 -0
  17. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/auth/consent_form.py +0 -0
  18. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/auth/provider.py +0 -0
  19. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/backup_manager.py +0 -0
  20. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/browser_landing.py +0 -0
  21. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/client/__init__.py +0 -0
  22. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/client/rest_client.py +0 -0
  23. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/client/supervisor_client.py +0 -0
  24. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/client/websocket_client.py +0 -0
  25. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/client/websocket_listener.py +0 -0
  26. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/config.py +0 -0
  27. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/dashboard_screenshot/__init__.py +0 -0
  28. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/dashboard_screenshot/capture.py +0 -0
  29. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/dashboard_screenshot/content.py +0 -0
  30. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/dashboard_screenshot/paths.py +0 -0
  31. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/dashboard_screenshot/provision.py +0 -0
  32. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/errors.py +0 -0
  33. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/llm_exposure.py +0 -0
  34. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/policy/__init__.py +0 -0
  35. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/policy/approval_queue.py +0 -0
  36. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/policy/evaluator.py +0 -0
  37. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/policy/handlers.py +0 -0
  38. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/policy/middleware.py +0 -0
  39. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/policy/model.py +0 -0
  40. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/policy/persistence.py +0 -0
  41. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/policy/value_sources.py +0 -0
  42. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/py.typed +0 -0
  43. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/read_only.py +0 -0
  44. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/resources/skills-vendor/.claude/settings.json +0 -0
  45. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/resources/skills-vendor/.claude-plugin/marketplace.json +0 -0
  46. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/resources/skills-vendor/.claude-plugin/plugin.json +0 -0
  47. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/resources/skills-vendor/.github/ISSUE_TEMPLATE/skill-rca.md +0 -0
  48. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/resources/skills-vendor/.github/pull_request_template.md +0 -0
  49. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/resources/skills-vendor/AGENTS.md +0 -0
  50. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/resources/skills-vendor/CLAUDE.md +0 -0
  51. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/resources/skills-vendor/CONTRIBUTING.md +0 -0
  52. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/resources/skills-vendor/LICENSE +0 -0
  53. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/resources/skills-vendor/README.md +0 -0
  54. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/SKILL.md +0 -0
  55. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/evals/evals.json +0 -0
  56. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/appdaemon.md +0 -0
  57. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/automation-patterns.md +0 -0
  58. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/blueprint-guide.md +0 -0
  59. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-cards.md +0 -0
  60. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-guide.md +0 -0
  61. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/device-control.md +0 -0
  62. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/domain-docs.md +0 -0
  63. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/examples.yaml +0 -0
  64. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/helper-selection.md +0 -0
  65. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/safe-refactoring.md +0 -0
  66. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/scenes.md +0 -0
  67. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/template-guidelines.md +0 -0
  68. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/yaml-only-integrations.md +0 -0
  69. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/settings_ui/__init__.py +0 -0
  70. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/settings_ui/_handlers_advanced.py +0 -0
  71. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/settings_ui/_handlers_backups.py +0 -0
  72. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/settings_ui/_handlers_fs.py +0 -0
  73. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/settings_ui/_handlers_server.py +0 -0
  74. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/settings_ui/_handlers_theme.py +0 -0
  75. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/settings_ui/_handlers_tools.py +0 -0
  76. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/settings_ui/_persistence.py +0 -0
  77. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/settings_ui/_supervisor.py +0 -0
  78. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/settings_ui/_theme.py +0 -0
  79. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/settings_ui/_tools_meta.py +0 -0
  80. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/settings_ui/settings.css +0 -0
  81. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/settings_ui/settings.html +0 -0
  82. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/settings_ui/settings.js +0 -0
  83. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/smoke_test.py +0 -0
  84. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/stdio_settings_sidecar.py +0 -0
  85. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/strict_bps.py +0 -0
  86. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/__init__.py +0 -0
  87. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/auto_backup.py +0 -0
  88. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/backup.py +0 -0
  89. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/best_practice_checker.py +0 -0
  90. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/component_api.py +0 -0
  91. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/config_entry_flow.py +0 -0
  92. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/device_control.py +0 -0
  93. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/enhanced.py +0 -0
  94. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/helpers.py +0 -0
  95. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/radio/__init__.py +0 -0
  96. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/radio/base.py +0 -0
  97. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/radio/matter.py +0 -0
  98. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/radio/thread.py +0 -0
  99. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/radio/zigbee.py +0 -0
  100. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/radio/zwave.py +0 -0
  101. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/reference_validator.py +0 -0
  102. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/registry.py +0 -0
  103. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/smart_search/__init__.py +0 -0
  104. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/smart_search/_base.py +0 -0
  105. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/smart_search/_config.py +0 -0
  106. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/smart_search/_deep.py +0 -0
  107. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/smart_search/_entities.py +0 -0
  108. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/smart_search/_fetch.py +0 -0
  109. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/smart_search/_overview.py +0 -0
  110. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/smart_search/_scenes.py +0 -0
  111. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/smart_search/_scoring.py +0 -0
  112. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tool_search_hint_middleware.py +0 -0
  113. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_addons.py +0 -0
  114. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_areas.py +0 -0
  115. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_blueprints.py +0 -0
  116. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_bug_report.py +0 -0
  117. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_calendar.py +0 -0
  118. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_camera.py +0 -0
  119. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_categories.py +0 -0
  120. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_code.py +0 -0
  121. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_config_automations.py +0 -0
  122. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_config_dashboards.py +0 -0
  123. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_config_scenes.py +0 -0
  124. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_config_scripts.py +0 -0
  125. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_dashboard_screenshot.py +0 -0
  126. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_dev.py +0 -0
  127. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_energy.py +0 -0
  128. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_entities.py +0 -0
  129. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_filesystem.py +0 -0
  130. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_hacs.py +0 -0
  131. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_history.py +0 -0
  132. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_integrations.py +0 -0
  133. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_labels.py +0 -0
  134. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_radio.py +0 -0
  135. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_registry.py +0 -0
  136. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_search.py +0 -0
  137. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_service.py +0 -0
  138. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_services.py +0 -0
  139. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_system.py +0 -0
  140. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_themes.py +0 -0
  141. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_todo.py +0 -0
  142. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_traces.py +0 -0
  143. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_updates.py +0 -0
  144. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_utility.py +0 -0
  145. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_voice_assistant.py +0 -0
  146. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_yaml_config.py +0 -0
  147. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_yaml_read.py +0 -0
  148. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/tools_zones.py +0 -0
  149. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/util_helpers.py +0 -0
  150. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/tools/validation_middleware.py +0 -0
  151. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/transforms/__init__.py +0 -0
  152. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/transforms/categorized_search.py +0 -0
  153. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/transforms/lite_docstrings.py +0 -0
  154. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/transport_security.py +0 -0
  155. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/update_check.py +0 -0
  156. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/utils/__init__.py +0 -0
  157. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/utils/config_hash.py +0 -0
  158. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/utils/data_paths.py +0 -0
  159. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/utils/domain_handlers.py +0 -0
  160. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/utils/fuzzy_search.py +0 -0
  161. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/utils/kill_signal_diagnostics.py +0 -0
  162. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/utils/operation_manager.py +0 -0
  163. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/utils/python_sandbox.py +0 -0
  164. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/utils/skill_loader.py +0 -0
  165. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/utils/usage_logger.py +0 -0
  166. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/visibility/__init__.py +0 -0
  167. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/visibility/model.py +0 -0
  168. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/visibility/persistence.py +0 -0
  169. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp/visibility/resolver.py +0 -0
  170. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp_dev.egg-info/SOURCES.txt +0 -0
  171. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp_dev.egg-info/dependency_links.txt +0 -0
  172. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp_dev.egg-info/entry_points.txt +0 -0
  173. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp_dev.egg-info/requires.txt +0 -0
  174. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/src/ha_mcp_dev.egg-info/top_level.txt +0 -0
  175. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/tests/__init__.py +0 -0
  176. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/tests/test_constants.py +0 -0
  177. {ha_mcp_dev-7.12.3.dev1940 → ha_mcp_dev-7.12.3.dev1942}/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.dev1940
3
+ Version: 7.12.3.dev1942
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
@@ -41,7 +41,7 @@ Dynamic: license-file
41
41
  <!-- mcp-name: io.github.homeassistant-ai/ha-mcp -->
42
42
 
43
43
  <p align="center">
44
- <img src="https://img.shields.io/badge/tools-88-blue" alt="95+ Tools">
44
+ <img src="https://img.shields.io/badge/tools-87-blue" alt="95+ Tools">
45
45
  <a href="https://github.com/homeassistant-ai/ha-mcp/releases"><img src="https://img.shields.io/github/v/release/homeassistant-ai/ha-mcp" alt="Release"></a>
46
46
  <a href="https://github.com/homeassistant-ai/ha-mcp/actions/workflows/e2e-tests.yml"><img src="https://img.shields.io/github/actions/workflow/status/homeassistant-ai/ha-mcp/e2e-tests.yml?branch=master&label=E2E%20Tests" alt="E2E Tests"></a>
47
47
  <a href="LICENSE.md"><img src="https://img.shields.io/github/license/homeassistant-ai/ha-mcp.svg" alt="License"></a>
@@ -247,7 +247,7 @@ Spend less time configuring, more time enjoying your smart home.
247
247
  <details>
248
248
  <!-- TOOLS_TABLE_START -->
249
249
 
250
- <summary><b>Complete Tool List (88 tools)</b></summary>
250
+ <summary><b>Complete Tool List (87 tools)</b></summary>
251
251
 
252
252
  | Category | Tools |
253
253
  |----------|-------|
@@ -278,7 +278,7 @@ Spend less time configuring, more time enjoying your smart home.
278
278
  | **Service & Device Control** | `ha_bulk_control`, `ha_call_event`, `ha_call_service`, `ha_get_operation_status`, `ha_list_services` |
279
279
  | **System** | `ha_config_get_yaml` *(beta)*, `ha_config_set_yaml` *(beta)*, `ha_manage_backup`, `ha_manage_custom_tool` *(beta)*, `ha_manage_theme`, `ha_manage_updates`, `ha_reload_core`, `ha_restart` |
280
280
  | **Todo Lists** | `ha_get_todo`, `ha_remove_todo_item`, `ha_set_todo_item` |
281
- | **Utilities** | `ha_eval_template`, `ha_install_mcp_tools` *(beta)*, `ha_report_issue` |
281
+ | **Utilities** | `ha_eval_template`, `ha_report_issue` |
282
282
  | **Zones** | `ha_get_zone`, `ha_remove_zone`, `ha_set_zone` |
283
283
 
284
284
  <!-- TOOLS_TABLE_END -->
@@ -8,7 +8,7 @@
8
8
  <!-- mcp-name: io.github.homeassistant-ai/ha-mcp -->
9
9
 
10
10
  <p align="center">
11
- <img src="https://img.shields.io/badge/tools-88-blue" alt="95+ Tools">
11
+ <img src="https://img.shields.io/badge/tools-87-blue" alt="95+ Tools">
12
12
  <a href="https://github.com/homeassistant-ai/ha-mcp/releases"><img src="https://img.shields.io/github/v/release/homeassistant-ai/ha-mcp" alt="Release"></a>
13
13
  <a href="https://github.com/homeassistant-ai/ha-mcp/actions/workflows/e2e-tests.yml"><img src="https://img.shields.io/github/actions/workflow/status/homeassistant-ai/ha-mcp/e2e-tests.yml?branch=master&label=E2E%20Tests" alt="E2E Tests"></a>
14
14
  <a href="LICENSE.md"><img src="https://img.shields.io/github/license/homeassistant-ai/ha-mcp.svg" alt="License"></a>
@@ -214,7 +214,7 @@ Spend less time configuring, more time enjoying your smart home.
214
214
  <details>
215
215
  <!-- TOOLS_TABLE_START -->
216
216
 
217
- <summary><b>Complete Tool List (88 tools)</b></summary>
217
+ <summary><b>Complete Tool List (87 tools)</b></summary>
218
218
 
219
219
  | Category | Tools |
220
220
  |----------|-------|
@@ -245,7 +245,7 @@ Spend less time configuring, more time enjoying your smart home.
245
245
  | **Service & Device Control** | `ha_bulk_control`, `ha_call_event`, `ha_call_service`, `ha_get_operation_status`, `ha_list_services` |
246
246
  | **System** | `ha_config_get_yaml` *(beta)*, `ha_config_set_yaml` *(beta)*, `ha_manage_backup`, `ha_manage_custom_tool` *(beta)*, `ha_manage_theme`, `ha_manage_updates`, `ha_reload_core`, `ha_restart` |
247
247
  | **Todo Lists** | `ha_get_todo`, `ha_remove_todo_item`, `ha_set_todo_item` |
248
- | **Utilities** | `ha_eval_template`, `ha_install_mcp_tools` *(beta)*, `ha_report_issue` |
248
+ | **Utilities** | `ha_eval_template`, `ha_report_issue` |
249
249
  | **Zones** | `ha_get_zone`, `ha_remove_zone`, `ha_set_zone` |
250
250
 
251
251
  <!-- TOOLS_TABLE_END -->
@@ -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.dev1940"
7
+ version = "7.12.3.dev1942"
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
@@ -632,9 +632,8 @@ class HomeAssistantSmartMCPServer(EnhancedToolsMixin):
632
632
  "Create or update a Home Assistant script.\n\n"
633
633
  "Supports two modes: full `config` replacement, or surgical "
634
634
  "`python_transform` on an existing script (requires "
635
- "`identifier` and `config_hash` from "
636
- "ha_config_get_script). Omit `identifier` to create a new "
637
- "script.\n\n"
635
+ "`config_hash` from ha_config_get_script). `script_id` names "
636
+ "the script in both modes.\n\n"
638
637
  "For schema details and examples, see "
639
638
  "ha_get_skill_guide."
640
639
  ),
@@ -650,19 +649,20 @@ class HomeAssistantSmartMCPServer(EnhancedToolsMixin):
650
649
  "Create or update a Home Assistant scene.\n\n"
651
650
  "Supports two modes: full `config` replacement, or surgical "
652
651
  "`python_transform` on an existing scene (requires "
653
- "`identifier` and `config_hash`).\n\n"
652
+ "`config_hash`). `scene_id` names the scene in both modes.\n\n"
654
653
  "For schema details and examples, see "
655
654
  "ha_get_skill_guide."
656
655
  ),
657
656
  "ha_config_list_helpers": (
658
- "List Home Assistant helpers of a given simple type. "
659
- "Accepts the 12 storage-backed helper types only: "
660
- "input_button, input_boolean, input_select, input_number, "
657
+ "List Home Assistant helpers of a given type, one page per "
658
+ "call (`limit`/`offset`; `total_count` and `has_more` "
659
+ "describe the full set). The 12 storage-backed types "
660
+ "(input_button, input_boolean, input_select, input_number, "
661
661
  "input_text, input_datetime, counter, timer, schedule, "
662
- "zone, person, tag. Flow-based helpers (template, group, "
663
- "utility_meter, derivative, statistics, trend, threshold, "
664
- "filter, switch_as_x, etc.) cannot be listed through this "
665
- "tool — use ha_search.\n\n"
662
+ "zone, person, tag) are listed on every install. Flow-based "
663
+ "types (template, group, utility_meter, derivative, and the "
664
+ "rest) and `helper_type='all'` are served only through the "
665
+ "ha_mcp_tools custom component.\n\n"
666
666
  "For per-type schemas and decision guidance, see "
667
667
  "ha_get_skill_guide."
668
668
  ),
@@ -53,6 +53,7 @@ from .util_helpers import (
53
53
  attach_skill_content,
54
54
  augment_error_dict_with_skill_content,
55
55
  augment_tool_error_with_skill_content,
56
+ build_pagination_metadata,
56
57
  parse_json_param,
57
58
  parse_string_list_param,
58
59
  wait_for_entity_registered,
@@ -1356,21 +1357,36 @@ def _flatten_helper_list_result(result: Any) -> list[Any]:
1356
1357
  """Flatten a {type}/list WS response into a flat list of helper dicts.
1357
1358
 
1358
1359
  Handles the person/list shape ({"storage": [...], "config": [...]}) and
1359
- the standard list shape ([...]).
1360
+ the standard list shape ([...]). An unrecognised shape yields an empty
1361
+ list, which downstream is indistinguishable from a helper type that has no
1362
+ entries, so it is logged rather than dropped in silence.
1360
1363
  """
1361
1364
  if isinstance(result, dict):
1362
1365
  inner = result.get("result", [])
1363
1366
  if isinstance(inner, dict):
1364
1367
  items: list[Any] = []
1368
+ matched = False
1365
1369
  for key in ("storage", "config"):
1366
1370
  sub = inner.get(key)
1367
1371
  if isinstance(sub, list):
1372
+ matched = True
1368
1373
  items.extend(sub)
1374
+ if not matched:
1375
+ logger.warning(
1376
+ "Helper listing has neither a 'storage' nor a 'config' list "
1377
+ "(keys: %s); treating it as empty",
1378
+ sorted(inner),
1379
+ )
1369
1380
  return items
1370
1381
  if isinstance(inner, list):
1371
1382
  return inner
1372
1383
  if isinstance(result, list):
1373
1384
  return result
1385
+ logger.warning(
1386
+ "Cannot flatten a helper listing: expected a list or a storage/config "
1387
+ "split, got %s; treating it as empty",
1388
+ type(result).__name__,
1389
+ )
1374
1390
  return []
1375
1391
 
1376
1392
 
@@ -3508,6 +3524,53 @@ def _shape_flow_helper_record(rec: dict[str, Any]) -> dict[str, Any]:
3508
3524
  return out
3509
3525
 
3510
3526
 
3527
+ def _paginate_helpers_response(
3528
+ response: dict[str, Any], offset: int, limit: int
3529
+ ) -> dict[str, Any]:
3530
+ """Slice a helper listing envelope down to one page.
3531
+
3532
+ The single normalization point for every ``ha_config_list_helpers`` route
3533
+ (all-types, component, legacy): each builds the same
3534
+ ``success``/``helper_type``/``count``/``helpers``/``message`` envelope, so
3535
+ the slice is applied once here instead of in each builder. ``count`` becomes
3536
+ the page size and ``total_count`` carries the full size, matching
3537
+ ``ha_list_services``.
3538
+ """
3539
+ helpers = response.get("helpers")
3540
+ if not isinstance(helpers, list):
3541
+ # Every builder owes this function a flat list; anything else is a bug in
3542
+ # the caller (a {type}/list shape that escaped _flatten_helper_list_result).
3543
+ # The records are still usable, so return them unpaginated rather than
3544
+ # raising -- but say so in warnings[], not just the log: the caller is an
3545
+ # agent that never sees server logs, and absent metadata otherwise reads
3546
+ # as "the collection fits on one page".
3547
+ shape = type(helpers).__name__
3548
+ logger.warning(
3549
+ "Cannot paginate %r listing: expected a list of helpers, got %s; "
3550
+ "returning the envelope unpaginated",
3551
+ response.get("helper_type"),
3552
+ shape,
3553
+ )
3554
+ warning = (
3555
+ f"Listing could not be paginated (expected a list of helpers, got "
3556
+ f"{shape}); returned in full, without pagination metadata."
3557
+ )
3558
+ existing = response.get("warnings")
3559
+ return {
3560
+ **response,
3561
+ "warnings": [*existing, warning]
3562
+ if isinstance(existing, list)
3563
+ else [warning],
3564
+ }
3565
+ total_count = len(helpers)
3566
+ page = helpers[offset : offset + limit]
3567
+ return {
3568
+ **response,
3569
+ "helpers": page,
3570
+ **build_pagination_metadata(total_count, offset, limit, len(page)),
3571
+ }
3572
+
3573
+
3511
3574
  def _shape_component_helpers_response(
3512
3575
  helper_type: str, result: dict[str, Any]
3513
3576
  ) -> dict[str, Any]:
@@ -3643,11 +3706,30 @@ class HelperConfigTools:
3643
3706
  )
3644
3707
  ),
3645
3708
  ],
3709
+ limit: Annotated[
3710
+ int,
3711
+ Field(
3712
+ default=100,
3713
+ ge=1,
3714
+ le=500,
3715
+ description="Max helpers to return per page (default: 100)",
3716
+ ),
3717
+ ] = 100,
3718
+ offset: Annotated[
3719
+ int,
3720
+ Field(
3721
+ default=0,
3722
+ ge=0,
3723
+ description="Number of helpers to skip for pagination (default: 0)",
3724
+ ),
3725
+ ] = 0,
3646
3726
  ) -> dict[str, Any]:
3647
3727
  """
3648
- List all Home Assistant helpers of a specific type with their configurations.
3728
+ List Home Assistant helpers of a specific type with their configurations.
3649
3729
 
3650
- Returns complete configuration for all helpers of the specified type including:
3730
+ Returns one page of helpers; `total_count` and `has_more` report the full
3731
+ set. Each record carries the complete configuration for its helper,
3732
+ including:
3651
3733
  - id (immutable storage key), entity_id (current — address the helper by
3652
3734
  this, where available), name (current display name), original_name
3653
3735
  (creation-time name), icon
@@ -3682,8 +3764,12 @@ class HelperConfigTools:
3682
3764
  - List all persons: ha_config_list_helpers("person")
3683
3765
  - List all tags: ha_config_list_helpers("tag")
3684
3766
  - List every helper type at once: ha_config_list_helpers("all")
3767
+ - Next page: ha_config_list_helpers("input_boolean", offset=100)
3685
3768
 
3686
- **NOTE:** This only returns storage-based helpers (created via UI/API), not YAML-defined helpers.
3769
+ **NOTE:** Storage types list what HA's ``{type}/list`` command returns:
3770
+ the storage-backed helpers (created via UI/API), not the YAML-defined
3771
+ ones. ``person`` is the exception — HA lists its YAML-configured persons
3772
+ alongside the storage ones, so both appear here.
3687
3773
 
3688
3774
  Flow-based types (template / group / utility_meter / derivative / etc.)
3689
3775
  require the ha_mcp_tools custom component (>= 1.1.0) and are served only
@@ -3702,7 +3788,9 @@ class HelperConfigTools:
3702
3788
  # No legacy equivalent exists (no single WS command enumerates all
3703
3789
  # types), so it is component-only — see ``_list_all_helpers``.
3704
3790
  if helper_type == "all":
3705
- return await self._list_all_helpers()
3791
+ return _paginate_helpers_response(
3792
+ await self._list_all_helpers(), offset, limit
3793
+ )
3706
3794
 
3707
3795
  # Flow-based helper types have no ``{type}/list`` command, so only the
3708
3796
  # component's ``helpers_list`` can enumerate them: they are served
@@ -3723,7 +3811,7 @@ class HelperConfigTools:
3723
3811
  helper_type, is_flow=is_flow
3724
3812
  )
3725
3813
  if component_response is not None:
3726
- return component_response
3814
+ return _paginate_helpers_response(component_response, offset, limit)
3727
3815
  if is_flow:
3728
3816
  # No usable component path and the legacy body cannot serve flow
3729
3817
  # helpers: hard error rather than an empty or misleading list.
@@ -3751,7 +3839,7 @@ class HelperConfigTools:
3751
3839
  }
3752
3840
  if warnings:
3753
3841
  response["warnings"] = warnings
3754
- return response
3842
+ return _paginate_helpers_response(response, offset, limit)
3755
3843
  raise_tool_error(
3756
3844
  create_error_response(
3757
3845
  ErrorCode.SERVICE_CALL_FAILED,
@@ -3880,7 +3968,11 @@ class HelperConfigTools:
3880
3968
  context={"helper_type": helper_type},
3881
3969
  )
3882
3970
  )
3883
- items = result.get("result", [])
3971
+ # Flatten like the inline body: person/list returns {"storage": [...],
3972
+ # "config": [...]} rather than a flat list, so a raw result["result"]
3973
+ # would be a dict here — breaking count, the pagination slice and the
3974
+ # all-types merge, which all expect a list of records.
3975
+ items = _flatten_helper_list_result(result)
3884
3976
  return {
3885
3977
  "success": True,
3886
3978
  "helper_type": helper_type,
@@ -4005,11 +4097,23 @@ class HelperConfigTools:
4005
4097
  )
4006
4098
  for helper_type in sorted(SIMPLE_HELPER_TYPES - covered_set):
4007
4099
  legacy = await self._legacy_helper_list(helper_type)
4100
+ skipped = 0
4008
4101
  for item in legacy.get("helpers", []):
4009
4102
  if isinstance(item, dict):
4010
4103
  row = dict(item)
4011
4104
  row.setdefault("helper_type", helper_type)
4012
4105
  helpers.append(row)
4106
+ else:
4107
+ skipped += 1
4108
+ if skipped:
4109
+ # This is how the unflattened person/list dict used to vanish:
4110
+ # iterating it yielded its keys, and each failed the check here.
4111
+ logger.warning(
4112
+ "Dropped %d unrecognised item(s) from the %s listing while "
4113
+ "merging all types; the merged listing is incomplete",
4114
+ skipped,
4115
+ helper_type,
4116
+ )
4013
4117
 
4014
4118
  return {
4015
4119
  "success": True,
@@ -27,6 +27,7 @@ from .helpers import (
27
27
  )
28
28
  from .util_helpers import (
29
29
  JSON_STRING_COERCION,
30
+ build_pagination_metadata,
30
31
  wait_for_entity_registered,
31
32
  wait_for_entity_removed,
32
33
  )
@@ -143,12 +144,32 @@ class GroupTools:
143
144
  },
144
145
  )
145
146
  @log_tool_usage
146
- async def ha_config_list_groups(self) -> dict[str, Any]:
147
+ async def ha_config_list_groups(
148
+ self,
149
+ limit: Annotated[
150
+ int,
151
+ Field(
152
+ default=100,
153
+ ge=1,
154
+ le=500,
155
+ description="Max groups to return per page (default: 100)",
156
+ ),
157
+ ] = 100,
158
+ offset: Annotated[
159
+ int,
160
+ Field(
161
+ default=0,
162
+ ge=0,
163
+ description="Number of groups to skip for pagination (default: 0)",
164
+ ),
165
+ ] = 0,
166
+ ) -> dict[str, Any]:
147
167
  """
148
- List all Home Assistant entity groups with their member entities.
168
+ List Home Assistant entity groups with their member entities.
149
169
 
150
- Returns all groups created via group.set service or YAML configuration,
151
- including:
170
+ Returns one page of groups created via group.set service or YAML
171
+ configuration; `total_count` and `has_more` report the full set. Each
172
+ group includes:
152
173
  - Entity ID (group.xxx)
153
174
  - Friendly name
154
175
  - State (on/off based on member states)
@@ -157,7 +178,8 @@ class GroupTools:
157
178
  - All mode (if all entities must be on)
158
179
 
159
180
  EXAMPLES:
160
- - List all groups: ha_config_list_groups()
181
+ - First page of groups: ha_config_list_groups()
182
+ - Next page: ha_config_list_groups(offset=100)
161
183
 
162
184
  **NOTE:** This returns old-style groups (created via group.set or YAML).
163
185
  Platform-specific groups (light groups, cover groups) are separate entities.
@@ -184,16 +206,26 @@ class GroupTools:
184
206
  }
185
207
  )
186
208
 
187
- # Sort by friendly name or entity_id
209
+ # Sort by friendly name, then entity_id: the unique tiebreaker keeps
210
+ # groups with the same name in a stable order, so a page boundary
211
+ # cannot duplicate or skip one when get_states() order shifts.
188
212
  groups.sort(
189
- key=lambda g: (g.get("friendly_name") or g.get("entity_id", "")).lower()
213
+ key=lambda g: (
214
+ (g.get("friendly_name") or g.get("entity_id", "")).lower(),
215
+ g.get("entity_id", ""),
216
+ )
190
217
  )
191
218
 
219
+ total_count = len(groups)
220
+ paginated_groups = groups[offset : offset + limit]
221
+
192
222
  return {
193
223
  "success": True,
194
- "count": len(groups),
195
- "groups": groups,
196
- "message": f"Found {len(groups)} group(s)",
224
+ "groups": paginated_groups,
225
+ **build_pagination_metadata(
226
+ total_count, offset, limit, len(paginated_groups)
227
+ ),
228
+ "message": f"Found {total_count} group(s)",
197
229
  }
198
230
 
199
231
  except Exception as e:
@@ -25,6 +25,7 @@ from .helpers import (
25
25
  register_tool_methods,
26
26
  validate_identifier_not_empty,
27
27
  )
28
+ from .util_helpers import build_pagination_metadata
28
29
 
29
30
  logger = logging.getLogger(__name__)
30
31
 
@@ -162,14 +163,34 @@ class ResourceTools:
162
163
  "Default False to save tokens (shows 150-char preview instead)."
163
164
  ),
164
165
  ] = False,
166
+ limit: Annotated[
167
+ int,
168
+ Field(
169
+ default=100,
170
+ ge=1,
171
+ le=500,
172
+ description="Max resources to return per page (default: 100)",
173
+ ),
174
+ ] = 100,
175
+ offset: Annotated[
176
+ int,
177
+ Field(
178
+ default=0,
179
+ ge=0,
180
+ description="Number of resources to skip for pagination (default: 0)",
181
+ ),
182
+ ] = 0,
165
183
  ) -> dict[str, Any]:
166
184
  """
167
- List all Lovelace dashboard resources (custom cards, themes, CSS/JS).
185
+ List Lovelace dashboard resources (custom cards, themes, CSS/JS).
168
186
 
169
- Returns all registered resources. For inline resources (created with
187
+ Returns one page of registered resources; `total_count` and `has_more`
188
+ report the full set. For inline resources (created with
170
189
  ha_config_set_dashboard_resource(content=...)), shows a preview of the content
171
190
  instead of the full encoded URL to save tokens.
172
191
 
192
+ `inline_count` and `by_type` summarise every resource, not just this page.
193
+
173
194
  Args:
174
195
  include_content: If True, includes full decoded content for inline
175
196
  resources in "_content" field. Default False (150-char preview only).
@@ -182,7 +203,8 @@ class ResourceTools:
182
203
  Each resource has a unique ID for update/delete operations.
183
204
 
184
205
  EXAMPLES:
185
- - List all resources: ha_config_list_dashboard_resources()
206
+ - First page of resources: ha_config_list_dashboard_resources()
207
+ - Next page: ha_config_list_dashboard_resources(offset=100)
186
208
  - List with full content: ha_config_list_dashboard_resources(include_content=True)
187
209
 
188
210
  Note: Home Assistant 2026.6+ exposes resource management in the UI by
@@ -214,11 +236,14 @@ class ResourceTools:
214
236
  if res.get("_inline"):
215
237
  inline_count += 1
216
238
 
239
+ total_count = len(processed)
240
+ paginated = processed[offset : offset + limit]
241
+
217
242
  return {
218
243
  "success": True,
219
244
  "action": "list",
220
- "resources": processed,
221
- "count": len(processed),
245
+ "resources": paginated,
246
+ **build_pagination_metadata(total_count, offset, limit, len(paginated)),
222
247
  "inline_count": inline_count,
223
248
  "by_type": {
224
249
  "module": len(categorized["module"]),
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ha-mcp-dev
3
- Version: 7.12.3.dev1940
3
+ Version: 7.12.3.dev1942
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
@@ -41,7 +41,7 @@ Dynamic: license-file
41
41
  <!-- mcp-name: io.github.homeassistant-ai/ha-mcp -->
42
42
 
43
43
  <p align="center">
44
- <img src="https://img.shields.io/badge/tools-88-blue" alt="95+ Tools">
44
+ <img src="https://img.shields.io/badge/tools-87-blue" alt="95+ Tools">
45
45
  <a href="https://github.com/homeassistant-ai/ha-mcp/releases"><img src="https://img.shields.io/github/v/release/homeassistant-ai/ha-mcp" alt="Release"></a>
46
46
  <a href="https://github.com/homeassistant-ai/ha-mcp/actions/workflows/e2e-tests.yml"><img src="https://img.shields.io/github/actions/workflow/status/homeassistant-ai/ha-mcp/e2e-tests.yml?branch=master&label=E2E%20Tests" alt="E2E Tests"></a>
47
47
  <a href="LICENSE.md"><img src="https://img.shields.io/github/license/homeassistant-ai/ha-mcp.svg" alt="License"></a>
@@ -247,7 +247,7 @@ Spend less time configuring, more time enjoying your smart home.
247
247
  <details>
248
248
  <!-- TOOLS_TABLE_START -->
249
249
 
250
- <summary><b>Complete Tool List (88 tools)</b></summary>
250
+ <summary><b>Complete Tool List (87 tools)</b></summary>
251
251
 
252
252
  | Category | Tools |
253
253
  |----------|-------|
@@ -278,7 +278,7 @@ Spend less time configuring, more time enjoying your smart home.
278
278
  | **Service & Device Control** | `ha_bulk_control`, `ha_call_event`, `ha_call_service`, `ha_get_operation_status`, `ha_list_services` |
279
279
  | **System** | `ha_config_get_yaml` *(beta)*, `ha_config_set_yaml` *(beta)*, `ha_manage_backup`, `ha_manage_custom_tool` *(beta)*, `ha_manage_theme`, `ha_manage_updates`, `ha_reload_core`, `ha_restart` |
280
280
  | **Todo Lists** | `ha_get_todo`, `ha_remove_todo_item`, `ha_set_todo_item` |
281
- | **Utilities** | `ha_eval_template`, `ha_install_mcp_tools` *(beta)*, `ha_report_issue` |
281
+ | **Utilities** | `ha_eval_template`, `ha_report_issue` |
282
282
  | **Zones** | `ha_get_zone`, `ha_remove_zone`, `ha_set_zone` |
283
283
 
284
284
  <!-- TOOLS_TABLE_END -->