ha-mcp-dev 7.8.0.dev708__tar.gz → 7.8.0.dev710__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 (143) hide show
  1. {ha_mcp_dev-7.8.0.dev708/src/ha_mcp_dev.egg-info → ha_mcp_dev-7.8.0.dev710}/PKG-INFO +1 -1
  2. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/pyproject.toml +1 -1
  3. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/tools/tools_utility.py +105 -10
  4. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710/src/ha_mcp_dev.egg-info}/PKG-INFO +1 -1
  5. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/LICENSE +0 -0
  6. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/MANIFEST.in +0 -0
  7. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/README.md +0 -0
  8. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/setup.cfg +0 -0
  9. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/__init__.py +0 -0
  10. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/__main__.py +0 -0
  11. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/_pypi_marker +0 -0
  12. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/_version.py +0 -0
  13. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/auth/__init__.py +0 -0
  14. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/auth/consent_form.py +0 -0
  15. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/auth/provider.py +0 -0
  16. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/backup_manager.py +0 -0
  17. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/client/__init__.py +0 -0
  18. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/client/rest_client.py +0 -0
  19. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/client/supervisor_client.py +0 -0
  20. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/client/websocket_client.py +0 -0
  21. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/client/websocket_listener.py +0 -0
  22. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/config.py +0 -0
  23. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/dashboard_screenshot/__init__.py +0 -0
  24. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/dashboard_screenshot/capture.py +0 -0
  25. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/dashboard_screenshot/provision.py +0 -0
  26. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/errors.py +0 -0
  27. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/policy/__init__.py +0 -0
  28. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/policy/approval_queue.py +0 -0
  29. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/policy/evaluator.py +0 -0
  30. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/policy/handlers.py +0 -0
  31. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/policy/middleware.py +0 -0
  32. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/policy/model.py +0 -0
  33. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/policy/persistence.py +0 -0
  34. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/policy/value_sources.py +0 -0
  35. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/py.typed +0 -0
  36. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/read_only.py +0 -0
  37. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/resources/skills-vendor/.claude/settings.json +0 -0
  38. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/resources/skills-vendor/.claude-plugin/marketplace.json +0 -0
  39. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/resources/skills-vendor/.claude-plugin/plugin.json +0 -0
  40. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/resources/skills-vendor/.github/ISSUE_TEMPLATE/skill-rca.md +0 -0
  41. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/resources/skills-vendor/.github/pull_request_template.md +0 -0
  42. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/resources/skills-vendor/AGENTS.md +0 -0
  43. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/resources/skills-vendor/CLAUDE.md +0 -0
  44. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/resources/skills-vendor/CONTRIBUTING.md +0 -0
  45. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/resources/skills-vendor/LICENSE +0 -0
  46. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/resources/skills-vendor/README.md +0 -0
  47. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/SKILL.md +0 -0
  48. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/evals/evals.json +0 -0
  49. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/automation-patterns.md +0 -0
  50. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-cards.md +0 -0
  51. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-guide.md +0 -0
  52. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/device-control.md +0 -0
  53. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/domain-docs.md +0 -0
  54. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/examples.yaml +0 -0
  55. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/helper-selection.md +0 -0
  56. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/safe-refactoring.md +0 -0
  57. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/template-guidelines.md +0 -0
  58. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/yaml-only-integrations.md +0 -0
  59. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/server.py +0 -0
  60. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/settings.css +0 -0
  61. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/settings.js +0 -0
  62. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/settings_ui.py +0 -0
  63. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/smoke_test.py +0 -0
  64. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/stdio_settings_sidecar.py +0 -0
  65. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/tools/__init__.py +0 -0
  66. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/tools/auto_backup.py +0 -0
  67. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/tools/backup.py +0 -0
  68. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/tools/best_practice_checker.py +0 -0
  69. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/tools/config_entry_flow.py +0 -0
  70. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/tools/device_control.py +0 -0
  71. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/tools/enhanced.py +0 -0
  72. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/tools/helpers.py +0 -0
  73. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/tools/reference_validator.py +0 -0
  74. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/tools/registry.py +0 -0
  75. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/tools/smart_search/__init__.py +0 -0
  76. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/tools/smart_search/_base.py +0 -0
  77. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/tools/smart_search/_config.py +0 -0
  78. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/tools/smart_search/_deep.py +0 -0
  79. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/tools/smart_search/_entities.py +0 -0
  80. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/tools/smart_search/_fetch.py +0 -0
  81. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/tools/smart_search/_overview.py +0 -0
  82. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/tools/smart_search/_scenes.py +0 -0
  83. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/tools/smart_search/_scoring.py +0 -0
  84. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/tools/tool_search_hint_middleware.py +0 -0
  85. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/tools/tools_addons.py +0 -0
  86. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/tools/tools_areas.py +0 -0
  87. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/tools/tools_blueprints.py +0 -0
  88. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/tools/tools_bug_report.py +0 -0
  89. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/tools/tools_calendar.py +0 -0
  90. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/tools/tools_camera.py +0 -0
  91. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/tools/tools_categories.py +0 -0
  92. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/tools/tools_code.py +0 -0
  93. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/tools/tools_config_automations.py +0 -0
  94. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/tools/tools_config_dashboards.py +0 -0
  95. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/tools/tools_config_helpers.py +0 -0
  96. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/tools/tools_config_scenes.py +0 -0
  97. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/tools/tools_config_scripts.py +0 -0
  98. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/tools/tools_dashboard_screenshot.py +0 -0
  99. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/tools/tools_energy.py +0 -0
  100. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/tools/tools_entities.py +0 -0
  101. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/tools/tools_filesystem.py +0 -0
  102. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/tools/tools_groups.py +0 -0
  103. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/tools/tools_hacs.py +0 -0
  104. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/tools/tools_history.py +0 -0
  105. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/tools/tools_integrations.py +0 -0
  106. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/tools/tools_labels.py +0 -0
  107. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/tools/tools_mcp_component.py +0 -0
  108. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/tools/tools_registry.py +0 -0
  109. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/tools/tools_resources.py +0 -0
  110. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/tools/tools_search.py +0 -0
  111. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/tools/tools_service.py +0 -0
  112. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/tools/tools_services.py +0 -0
  113. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/tools/tools_system.py +0 -0
  114. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/tools/tools_themes.py +0 -0
  115. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/tools/tools_todo.py +0 -0
  116. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/tools/tools_traces.py +0 -0
  117. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/tools/tools_updates.py +0 -0
  118. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/tools/tools_voice_assistant.py +0 -0
  119. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/tools/tools_yaml_config.py +0 -0
  120. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/tools/tools_zones.py +0 -0
  121. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/tools/util_helpers.py +0 -0
  122. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/tools/validation_middleware.py +0 -0
  123. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/transforms/__init__.py +0 -0
  124. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/transforms/categorized_search.py +0 -0
  125. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/transforms/lite_docstrings.py +0 -0
  126. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/utils/__init__.py +0 -0
  127. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/utils/config_hash.py +0 -0
  128. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/utils/data_paths.py +0 -0
  129. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/utils/domain_handlers.py +0 -0
  130. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/utils/fuzzy_search.py +0 -0
  131. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/utils/kill_signal_diagnostics.py +0 -0
  132. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/utils/operation_manager.py +0 -0
  133. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/utils/python_sandbox.py +0 -0
  134. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/utils/skill_loader.py +0 -0
  135. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp/utils/usage_logger.py +0 -0
  136. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp_dev.egg-info/SOURCES.txt +0 -0
  137. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp_dev.egg-info/dependency_links.txt +0 -0
  138. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp_dev.egg-info/entry_points.txt +0 -0
  139. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp_dev.egg-info/requires.txt +0 -0
  140. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/src/ha_mcp_dev.egg-info/top_level.txt +0 -0
  141. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/tests/__init__.py +0 -0
  142. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/tests/test_constants.py +0 -0
  143. {ha_mcp_dev-7.8.0.dev708 → ha_mcp_dev-7.8.0.dev710}/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.8.0.dev708
3
+ Version: 7.8.0.dev710
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.8.0.dev708"
7
+ version = "7.8.0.dev710"
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"
@@ -122,8 +122,14 @@ class UtilityTools:
122
122
  entity_id: str | None,
123
123
  end_time: str | None,
124
124
  slug: str | None,
125
+ order: Literal["newest", "oldest"],
125
126
  ) -> list[str]:
126
127
  warnings: list[str] = []
128
+ if source == "logger" and order != "newest":
129
+ warnings.append(
130
+ "Parameter 'order' does not apply to source='logger' "
131
+ "(entries are sorted by integration name); ignored"
132
+ )
127
133
  if source != "logbook" and any(p is not None for p in [entity_id, end_time]):
128
134
  ignored = [
129
135
  p
@@ -200,6 +206,7 @@ class UtilityTools:
200
206
  compact: bool,
201
207
  level: str | None,
202
208
  slug: str | None,
209
+ order: Literal["newest", "oldest"],
203
210
  ) -> dict[str, Any]:
204
211
  if source == "logbook":
205
212
  return await self._get_logbook(
@@ -210,20 +217,29 @@ class UtilityTools:
210
217
  offset=offset,
211
218
  search=search,
212
219
  compact=compact,
220
+ order=order,
213
221
  )
214
222
  if source == "system":
215
- return await self._get_system_log(limit=limit, search=search, level=level)
223
+ return await self._get_system_log(
224
+ limit=limit, search=search, level=level, order=order
225
+ )
216
226
  if source == "error_log":
217
- return await self._get_error_log(limit=limit, search=search, level=level)
227
+ return await self._get_error_log(
228
+ limit=limit, search=search, level=level, order=order
229
+ )
218
230
  if source == "logger":
231
+ # logger reports per-integration levels, not time-ordered events;
232
+ # 'order' does not apply (a warning is emitted upstream).
219
233
  return await self._get_logger_info(limit=limit, search=search)
220
234
  if source == "system_service":
221
235
  assert slug is not None # guaranteed by _validate_log_slug
222
236
  return await self._get_system_service_log(
223
- service=slug, limit=limit, search=search
237
+ service=slug, limit=limit, search=search, order=order
224
238
  )
225
239
  assert slug is not None # guaranteed by _validate_log_slug
226
- return await self._get_supervisor_log(slug=slug, limit=limit, search=search)
240
+ return await self._get_supervisor_log(
241
+ slug=slug, limit=limit, search=search, order=order
242
+ )
227
243
 
228
244
  async def get_logs(
229
245
  self,
@@ -237,9 +253,12 @@ class UtilityTools:
237
253
  compact: bool,
238
254
  level: str | None,
239
255
  slug: str | None,
256
+ order: Literal["newest", "oldest"] = "newest",
240
257
  ) -> dict[str, Any]:
241
258
  level = self._validate_log_level(level)
242
- warnings = self._collect_log_warnings(source, level, entity_id, end_time, slug)
259
+ warnings = self._collect_log_warnings(
260
+ source, level, entity_id, end_time, slug, order
261
+ )
243
262
  self._validate_log_slug(source, slug)
244
263
  result = await self._fetch_log_source(
245
264
  source,
@@ -252,6 +271,7 @@ class UtilityTools:
252
271
  compact,
253
272
  level,
254
273
  slug,
274
+ order,
255
275
  )
256
276
  if warnings:
257
277
  result["warnings"] = warnings
@@ -277,6 +297,7 @@ class UtilityTools:
277
297
  entity_id: str | None,
278
298
  search: str | None,
279
299
  compact_bool: bool,
300
+ order: Literal["newest", "oldest"] = "newest",
280
301
  ) -> str:
281
302
  """Build reproducible pagination hint string for logbook results."""
282
303
  next_offset = offset_int + effective_limit
@@ -293,6 +314,8 @@ class UtilityTools:
293
314
  param_parts.append(f"search={search}")
294
315
  if not compact_bool:
295
316
  param_parts.append("compact=False")
317
+ if order != "newest":
318
+ param_parts.append(f"order={order}")
296
319
  param_str = ", ".join(param_parts)
297
320
  return (
298
321
  f"Showing entries {offset_int + 1}-{offset_int + len(paginated_entries)} of {total_entries}. "
@@ -308,6 +331,7 @@ class UtilityTools:
308
331
  offset: int = 0,
309
332
  search: str | None = None,
310
333
  compact: bool = True,
334
+ order: Literal["newest", "oldest"] = "newest",
311
335
  ) -> dict[str, Any]:
312
336
  """Fetch logbook entries with search and pagination."""
313
337
  hours_back_int, effective_limit, offset_int = self._coerce_logbook_params(
@@ -342,8 +366,20 @@ class UtilityTools:
342
366
  total_entries = len(response) if isinstance(response, list) else 1
343
367
 
344
368
  if isinstance(response, list):
345
- paginated_entries = response[offset_int : offset_int + effective_limit]
346
- has_more = (offset_int + effective_limit) < total_entries
369
+ # HA's /logbook returns entries oldest-first. Take a window from
370
+ # the end for newest-first (default), or from the start for
371
+ # oldest-first, with offset paging deeper in the chosen order.
372
+ if order == "newest":
373
+ end = total_entries - offset_int
374
+ start = max(end - effective_limit, 0)
375
+ paginated_entries = (
376
+ list(reversed(response[start:end])) if end > 0 else []
377
+ )
378
+ else:
379
+ paginated_entries = response[
380
+ offset_int : offset_int + effective_limit
381
+ ]
382
+ has_more = offset_int + len(paginated_entries) < total_entries
347
383
  else:
348
384
  paginated_entries = response
349
385
  has_more = False
@@ -368,6 +404,7 @@ class UtilityTools:
368
404
  else 1,
369
405
  "limit": effective_limit,
370
406
  "offset": offset_int,
407
+ "order": order,
371
408
  "has_more": has_more,
372
409
  }
373
410
  if filters_applied:
@@ -383,6 +420,7 @@ class UtilityTools:
383
420
  entity_id,
384
421
  search,
385
422
  compact,
423
+ order,
386
424
  )
387
425
 
388
426
  return await add_timezone_metadata(self._client, logbook_data)
@@ -416,11 +454,28 @@ class UtilityTools:
416
454
  )
417
455
  raise # unreachable: exception_to_structured_error always raises
418
456
 
457
+ @staticmethod
458
+ def _system_log_sort_key(entry: Any) -> float:
459
+ """Total-order-safe sort key for system_log entries.
460
+
461
+ ``system_log/list`` does not guarantee a numeric ``timestamp`` on every
462
+ record. Coerce a missing / non-numeric / non-dict entry to ``0.0`` so
463
+ sorting never raises a cross-type ``TypeError`` (bools are excluded so
464
+ a stray ``True`` doesn't read as ``1.0``).
465
+ """
466
+ if not isinstance(entry, dict):
467
+ return 0.0
468
+ ts = entry.get("timestamp")
469
+ if isinstance(ts, bool) or not isinstance(ts, (int, float)):
470
+ return 0.0
471
+ return float(ts)
472
+
419
473
  async def _get_system_log(
420
474
  self,
421
475
  limit: int | None = None,
422
476
  search: str | None = None,
423
477
  level: str | None = None,
478
+ order: Literal["newest", "oldest"] = "newest",
424
479
  ) -> dict[str, Any]:
425
480
  """Fetch structured system log entries via system_log/list."""
426
481
  effective_limit = self._coerce_limit(limit)
@@ -461,6 +516,17 @@ class UtilityTools:
461
516
  ]
462
517
  filters_applied["search"] = search
463
518
 
519
+ # system_log/list entries carry a 'timestamp' (epoch float, last
520
+ # occurrence), but HA does not guarantee it on every record. Sort
521
+ # with a total-order-safe key so 'order' is deterministic regardless
522
+ # of HA's native ordering (newest-first by default) and a missing /
523
+ # non-numeric / non-dict entry can never raise a cross-type
524
+ # TypeError out of this method's narrow except clause.
525
+ entries.sort(
526
+ key=self._system_log_sort_key,
527
+ reverse=(order == "newest"),
528
+ )
529
+
464
530
  total_entries = len(entries)
465
531
  entries = entries[:effective_limit]
466
532
 
@@ -471,6 +537,7 @@ class UtilityTools:
471
537
  "total_entries": total_entries,
472
538
  "returned_entries": len(entries),
473
539
  "limit": effective_limit,
540
+ "order": order,
474
541
  }
475
542
  if filters_applied:
476
543
  data["filters_applied"] = filters_applied
@@ -500,6 +567,7 @@ class UtilityTools:
500
567
  limit: int | None = None,
501
568
  search: str | None = None,
502
569
  level: str | None = None,
570
+ order: Literal["newest", "oldest"] = "newest",
503
571
  ) -> dict[str, Any]:
504
572
  """Fetch raw error log text from home-assistant.log."""
505
573
  effective_limit = self._coerce_limit(
@@ -527,8 +595,11 @@ class UtilityTools:
527
595
  filters_applied["search"] = search
528
596
 
529
597
  total_lines = len(lines)
530
- # Return the LAST N lines (most recent)
598
+ # Always take the most-recent window (the tail of the chronological
599
+ # file); 'order' controls only the display direction of that window.
531
600
  lines = lines[-effective_limit:]
601
+ if order == "newest":
602
+ lines = list(reversed(lines))
532
603
 
533
604
  data: dict[str, Any] = {
534
605
  "success": True,
@@ -537,6 +608,7 @@ class UtilityTools:
537
608
  "total_lines": total_lines,
538
609
  "returned_lines": len(lines),
539
610
  "limit": effective_limit,
611
+ "order": order,
540
612
  "note": "Returned the most recent log lines matching filters",
541
613
  }
542
614
  if filters_applied:
@@ -665,6 +737,7 @@ class UtilityTools:
665
737
  slug: str,
666
738
  limit: int | None = None,
667
739
  search: str | None = None,
740
+ order: Literal["newest", "oldest"] = "newest",
668
741
  ) -> dict[str, Any]:
669
742
  """Fetch add-on container logs.
670
743
 
@@ -692,8 +765,11 @@ class UtilityTools:
692
765
  filters_applied["search"] = search
693
766
 
694
767
  total_lines = len(lines)
695
- # Return the LAST N lines (most recent)
768
+ # Always take the most-recent window (the tail); 'order' controls
769
+ # only the display direction of that window.
696
770
  lines = lines[-effective_limit:]
771
+ if order == "newest":
772
+ lines = list(reversed(lines))
697
773
 
698
774
  data: dict[str, Any] = {
699
775
  "success": True,
@@ -703,6 +779,7 @@ class UtilityTools:
703
779
  "total_lines": total_lines,
704
780
  "returned_lines": len(lines),
705
781
  "limit": effective_limit,
782
+ "order": order,
706
783
  }
707
784
  if filters_applied:
708
785
  data["filters_applied"] = filters_applied
@@ -797,6 +874,7 @@ class UtilityTools:
797
874
  service: str,
798
875
  limit: int | None = None,
799
876
  search: str | None = None,
877
+ order: Literal["newest", "oldest"] = "newest",
800
878
  ) -> dict[str, Any]:
801
879
  """Fetch HA system-service logs from Supervisor's per-service endpoint.
802
880
 
@@ -826,8 +904,11 @@ class UtilityTools:
826
904
  filters_applied["search"] = search
827
905
 
828
906
  total_lines = len(lines)
829
- # Return the LAST N lines (most recent)
907
+ # Always take the most-recent window (the tail); 'order' controls
908
+ # only the display direction of that window.
830
909
  lines = lines[-effective_limit:]
910
+ if order == "newest":
911
+ lines = list(reversed(lines))
831
912
 
832
913
  data: dict[str, Any] = {
833
914
  "success": True,
@@ -837,6 +918,7 @@ class UtilityTools:
837
918
  "total_lines": total_lines,
838
919
  "returned_lines": len(lines),
839
920
  "limit": effective_limit,
921
+ "order": order,
840
922
  }
841
923
  if filters_applied:
842
924
  data["filters_applied"] = filters_applied
@@ -1035,6 +1117,17 @@ def register_utility_tools(mcp: Any, client: Any, **kwargs: Any) -> None:
1035
1117
  # Shared parameters
1036
1118
  limit: int | None = None,
1037
1119
  search: str | None = None,
1120
+ order: Annotated[
1121
+ Literal["newest", "oldest"],
1122
+ Field(
1123
+ description=(
1124
+ "Sort order for time-ordered sources (logbook, system, "
1125
+ "error_log, supervisor, system_service): 'newest' (default) "
1126
+ "returns most-recent first; 'oldest' returns chronological-"
1127
+ "first. Ignored for source='logger'."
1128
+ )
1129
+ ),
1130
+ ] = "newest",
1038
1131
  # Logbook-specific (ignored for other sources)
1039
1132
  hours_back: Annotated[int, Field(ge=1)] = 1,
1040
1133
  entity_id: str | None = None,
@@ -1059,6 +1152,7 @@ def register_utility_tools(mcp: Any, client: Any, **kwargs: Any) -> None:
1059
1152
  - "logger": Effective log level per integration via logger/log_info (confirms logger.set_level changes took effect)
1060
1153
 
1061
1154
  **Shared params:** limit, search (keyword filter on entries/lines; matches integration domain for source='logger')
1155
+ **Order:** order='newest' (default) returns most-recent first; order='oldest' returns chronological-first. Applies to all time-ordered sources (logbook, system, error_log, supervisor, system_service); ignored for source='logger'. For raw-text sources (error_log, supervisor, system_service) it sets the read direction of the most-recent window.
1062
1156
  **Logbook params:** hours_back, entity_id, end_time, offset, compact (default True — strips attribute dicts to save context)
1063
1157
  **System/error_log params:** level (ERROR, WARNING, INFO, DEBUG)
1064
1158
  **Supervisor params:** slug = add-on slug, e.g. "core_mosquitto" (use
@@ -1078,6 +1172,7 @@ def register_utility_tools(mcp: Any, client: Any, **kwargs: Any) -> None:
1078
1172
  compact=compact,
1079
1173
  level=level,
1080
1174
  slug=slug,
1175
+ order=order,
1081
1176
  )
1082
1177
 
1083
1178
  @mcp.tool(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ha-mcp-dev
3
- Version: 7.8.0.dev708
3
+ Version: 7.8.0.dev710
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