ha-mcp-dev 7.13.0.dev1997__tar.gz → 7.13.0.dev2001__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 (187) hide show
  1. {ha_mcp_dev-7.13.0.dev1997/src/ha_mcp_dev.egg-info → ha_mcp_dev-7.13.0.dev2001}/PKG-INFO +1 -1
  2. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/pyproject.toml +1 -1
  3. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/settings_ui/_i18n.py +34 -0
  4. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/settings_ui/settings.js +48 -20
  5. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001/src/ha_mcp_dev.egg-info}/PKG-INFO +1 -1
  6. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/LICENSE +0 -0
  7. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/MANIFEST.in +0 -0
  8. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/README.md +0 -0
  9. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/setup.cfg +0 -0
  10. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/__init__.py +0 -0
  11. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/__main__.py +0 -0
  12. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/_pypi_marker +0 -0
  13. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/_version.py +0 -0
  14. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/auth/__init__.py +0 -0
  15. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/auth/consent_form.py +0 -0
  16. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/auth/provider.py +0 -0
  17. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/backup_manager.py +0 -0
  18. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/browser_landing.py +0 -0
  19. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/client/__init__.py +0 -0
  20. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/client/rest_client.py +0 -0
  21. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/client/supervisor_client.py +0 -0
  22. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/client/websocket_client.py +0 -0
  23. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/client/websocket_listener.py +0 -0
  24. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/config.py +0 -0
  25. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/dashboard_screenshot/__init__.py +0 -0
  26. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/dashboard_screenshot/capture.py +0 -0
  27. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/dashboard_screenshot/content.py +0 -0
  28. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/dashboard_screenshot/paths.py +0 -0
  29. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/dashboard_screenshot/provision.py +0 -0
  30. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/dashboard_screenshot/theme_guard.py +0 -0
  31. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/errors.py +0 -0
  32. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/llm_exposure.py +0 -0
  33. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/policy/__init__.py +0 -0
  34. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/policy/approval_queue.py +0 -0
  35. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/policy/evaluator.py +0 -0
  36. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/policy/handlers.py +0 -0
  37. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/policy/middleware.py +0 -0
  38. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/policy/model.py +0 -0
  39. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/policy/persistence.py +0 -0
  40. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/policy/value_sources.py +0 -0
  41. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/py.typed +0 -0
  42. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/read_only.py +0 -0
  43. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/resources/skills-vendor/.claude/settings.json +0 -0
  44. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/resources/skills-vendor/.claude-plugin/marketplace.json +0 -0
  45. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/resources/skills-vendor/.claude-plugin/plugin.json +0 -0
  46. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/resources/skills-vendor/.github/ISSUE_TEMPLATE/skill-rca.md +0 -0
  47. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/resources/skills-vendor/.github/pull_request_template.md +0 -0
  48. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/resources/skills-vendor/AGENTS.md +0 -0
  49. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/resources/skills-vendor/CLAUDE.md +0 -0
  50. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/resources/skills-vendor/CONTRIBUTING.md +0 -0
  51. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/resources/skills-vendor/LICENSE +0 -0
  52. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/resources/skills-vendor/README.md +0 -0
  53. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/SKILL.md +0 -0
  54. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/evals/evals.json +0 -0
  55. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/appdaemon.md +0 -0
  56. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/automation-patterns.md +0 -0
  57. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/blueprint-guide.md +0 -0
  58. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-cards.md +0 -0
  59. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-guide.md +0 -0
  60. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/device-control.md +0 -0
  61. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/domain-docs.md +0 -0
  62. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/examples.yaml +0 -0
  63. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/helper-selection.md +0 -0
  64. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/safe-refactoring.md +0 -0
  65. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/scenes.md +0 -0
  66. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/template-guidelines.md +0 -0
  67. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/yaml-only-integrations.md +0 -0
  68. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/server.py +0 -0
  69. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/settings_ui/__init__.py +0 -0
  70. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/settings_ui/_handlers_advanced.py +0 -0
  71. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/settings_ui/_handlers_backups.py +0 -0
  72. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/settings_ui/_handlers_fs.py +0 -0
  73. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/settings_ui/_handlers_server.py +0 -0
  74. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/settings_ui/_handlers_theme.py +0 -0
  75. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/settings_ui/_handlers_tools.py +0 -0
  76. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/settings_ui/_persistence.py +0 -0
  77. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/settings_ui/_supervisor.py +0 -0
  78. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/settings_ui/_theme.py +0 -0
  79. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/settings_ui/_tools_meta.py +0 -0
  80. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/settings_ui/locales/README.md +0 -0
  81. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/settings_ui/locales/de.json +0 -0
  82. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/settings_ui/locales/en.json +0 -0
  83. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/settings_ui/locales/ru.json +0 -0
  84. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/settings_ui/settings.css +0 -0
  85. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/settings_ui/settings.html +0 -0
  86. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/smoke_test.py +0 -0
  87. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/stdio_settings_sidecar.py +0 -0
  88. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/strict_bps.py +0 -0
  89. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/__init__.py +0 -0
  90. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/auto_backup.py +0 -0
  91. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/backup.py +0 -0
  92. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/best_practice_checker.py +0 -0
  93. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/component_api.py +0 -0
  94. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/component_config_reads.py +0 -0
  95. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/component_devices.py +0 -0
  96. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/component_registries.py +0 -0
  97. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/component_registry_lookup.py +0 -0
  98. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/config_entry_flow.py +0 -0
  99. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/device_control.py +0 -0
  100. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/enhanced.py +0 -0
  101. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/helpers.py +0 -0
  102. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/radio/__init__.py +0 -0
  103. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/radio/base.py +0 -0
  104. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/radio/matter.py +0 -0
  105. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/radio/thread.py +0 -0
  106. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/radio/zigbee.py +0 -0
  107. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/radio/zwave.py +0 -0
  108. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/reference_validator.py +0 -0
  109. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/registry.py +0 -0
  110. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/smart_search/__init__.py +0 -0
  111. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/smart_search/_base.py +0 -0
  112. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/smart_search/_config.py +0 -0
  113. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/smart_search/_deep.py +0 -0
  114. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/smart_search/_entities.py +0 -0
  115. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/smart_search/_fetch.py +0 -0
  116. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/smart_search/_overview.py +0 -0
  117. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/smart_search/_scenes.py +0 -0
  118. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/smart_search/_scoring.py +0 -0
  119. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/tool_search_hint_middleware.py +0 -0
  120. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/tools_addons.py +0 -0
  121. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/tools_areas.py +0 -0
  122. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/tools_blueprints.py +0 -0
  123. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/tools_bug_report.py +0 -0
  124. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/tools_calendar.py +0 -0
  125. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/tools_camera.py +0 -0
  126. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/tools_categories.py +0 -0
  127. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/tools_code.py +0 -0
  128. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/tools_config_automations.py +0 -0
  129. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/tools_config_dashboards.py +0 -0
  130. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/tools_config_helpers.py +0 -0
  131. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/tools_config_scenes.py +0 -0
  132. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/tools_config_scripts.py +0 -0
  133. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/tools_dashboard_screenshot.py +0 -0
  134. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/tools_dev.py +0 -0
  135. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/tools_energy.py +0 -0
  136. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/tools_entities.py +0 -0
  137. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/tools_filesystem.py +0 -0
  138. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/tools_groups.py +0 -0
  139. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/tools_hacs.py +0 -0
  140. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/tools_history.py +0 -0
  141. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/tools_integrations.py +0 -0
  142. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/tools_labels.py +0 -0
  143. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/tools_radio.py +0 -0
  144. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/tools_registry.py +0 -0
  145. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/tools_resources.py +0 -0
  146. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/tools_search.py +0 -0
  147. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/tools_service.py +0 -0
  148. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/tools_services.py +0 -0
  149. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/tools_system.py +0 -0
  150. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/tools_themes.py +0 -0
  151. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/tools_todo.py +0 -0
  152. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/tools_traces.py +0 -0
  153. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/tools_updates.py +0 -0
  154. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/tools_utility.py +0 -0
  155. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/tools_voice_assistant.py +0 -0
  156. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/tools_yaml_config.py +0 -0
  157. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/tools_yaml_read.py +0 -0
  158. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/tools_zones.py +0 -0
  159. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/util_helpers.py +0 -0
  160. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/tools/validation_middleware.py +0 -0
  161. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/transforms/__init__.py +0 -0
  162. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/transforms/categorized_search.py +0 -0
  163. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/transforms/lite_docstrings.py +0 -0
  164. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/transport_security.py +0 -0
  165. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/update_check.py +0 -0
  166. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/utils/__init__.py +0 -0
  167. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/utils/config_hash.py +0 -0
  168. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/utils/data_paths.py +0 -0
  169. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/utils/domain_handlers.py +0 -0
  170. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/utils/fuzzy_search.py +0 -0
  171. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/utils/kill_signal_diagnostics.py +0 -0
  172. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/utils/operation_manager.py +0 -0
  173. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/utils/python_sandbox.py +0 -0
  174. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/utils/skill_loader.py +0 -0
  175. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/utils/usage_logger.py +0 -0
  176. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/visibility/__init__.py +0 -0
  177. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/visibility/model.py +0 -0
  178. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/visibility/persistence.py +0 -0
  179. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp/visibility/resolver.py +0 -0
  180. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp_dev.egg-info/SOURCES.txt +0 -0
  181. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp_dev.egg-info/dependency_links.txt +0 -0
  182. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp_dev.egg-info/entry_points.txt +0 -0
  183. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp_dev.egg-info/requires.txt +0 -0
  184. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/src/ha_mcp_dev.egg-info/top_level.txt +0 -0
  185. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/tests/__init__.py +0 -0
  186. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/tests/test_constants.py +0 -0
  187. {ha_mcp_dev-7.13.0.dev1997 → ha_mcp_dev-7.13.0.dev2001}/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.13.0.dev1997
3
+ Version: 7.13.0.dev2001
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.13.0.dev1997"
7
+ version = "7.13.0.dev2001"
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
@@ -112,6 +112,7 @@ def load_catalogs(directory: Path = LOCALES_DIR) -> dict[str, dict[str, Any]]:
112
112
  f"The settings UI requires {DEFAULT_LOCALE}.json in {directory}"
113
113
  )
114
114
  _validate_placeholder_parity(catalogs)
115
+ _validate_inline_markup(catalogs)
115
116
  return catalogs
116
117
 
117
118
 
@@ -154,6 +155,39 @@ def _validate_placeholder_parity(catalogs: dict[str, dict[str, Any]]) -> None:
154
155
  )
155
156
 
156
157
 
158
+ # Anything that looks like an HTML tag in a catalog message. A bare "<" in
159
+ # prose (e.g. "< 5") deliberately does not match — it renders fine escaped.
160
+ _TAG_LIKE_RE = re.compile(r"</?[a-zA-Z][^>]*>")
161
+ # The exact tag shapes settings.js::tHtml restores after escaping. Keep in
162
+ # sync with the restore regexes there — any other spelling (case, spacing,
163
+ # attribute order) survives escaping and shows the user literal markup text.
164
+ _ALLOWED_TAGS_RE = re.compile(
165
+ r'</?code>|</?strong>|</a>|<a href="#" data-panel-link="[a-z][a-z-]*">'
166
+ )
167
+
168
+
169
+ def _validate_inline_markup(catalogs: dict[str, dict[str, Any]]) -> None:
170
+ """Reject catalog messages whose markup ``tHtml`` cannot restore.
171
+
172
+ ``settings.js::tHtml`` escapes every translated value and restores only
173
+ the exact allowlisted tag shapes, so a translation written with
174
+ ``<CODE>`` or ``<code >`` would silently render as literal escaped text.
175
+ Fail fast at load time instead, mirroring the placeholder-parity check.
176
+ Scoped to ``messages``: tool translations are plain text rendered through
177
+ ``escapeHtml`` and carry no markup contract.
178
+ """
179
+ for locale, catalog in catalogs.items():
180
+ for key, value in catalog["messages"].items():
181
+ for tag in _TAG_LIKE_RE.findall(value):
182
+ if _ALLOWED_TAGS_RE.fullmatch(tag) is None:
183
+ raise ValueError(
184
+ f"Locale {locale} message {key!r} contains inline "
185
+ f"markup {tag!r} that the settings UI cannot render; "
186
+ f"allowed: <code>, <strong>, </a>, and "
187
+ f'<a href="#" data-panel-link="...">'
188
+ )
189
+
190
+
157
191
  CATALOGS = load_catalogs()
158
192
 
159
193
 
@@ -23,6 +23,27 @@ function t(key, params = {}, fallback = key) {
23
23
  return value;
24
24
  }
25
25
 
26
+ // Translation for HTML contexts (innerHTML sinks). Catalog strings are data,
27
+ // not markup: the whole value is HTML-escaped first, then only the allowlist
28
+ // of inline formatting tags the catalogs use (<code>, <strong>, and the
29
+ // internal tab links) is restored, so a translated string can never
30
+ // contribute any other markup. Placeholders are substituted AFTER escaping:
31
+ // params are trusted HTML fragments built by the caller (escape any dynamic
32
+ // text inside them with escapeHtml at the call site).
33
+ function tHtml(key, params = {}, fallback = key) {
34
+ const raw = Object.prototype.hasOwnProperty.call(I18N_PAYLOAD.messages || {}, key)
35
+ ? I18N_PAYLOAD.messages[key]
36
+ : fallback;
37
+ let value = escapeHtml(raw)
38
+ .replace(/&lt;(\/?)(code|strong)&gt;/g, '<$1$2>')
39
+ .replace(/&lt;a href=&quot;#&quot; data-panel-link=&quot;([a-z][a-z-]*)&quot;&gt;/g, '<a href="#" data-panel-link="$1">')
40
+ .replace(/&lt;\/a&gt;/g, '</a>');
41
+ Object.keys(params).forEach(name => {
42
+ value = value.replaceAll(`{${name}}`, String(params[name]));
43
+ });
44
+ return value;
45
+ }
46
+
26
47
  function localizeMeta(section, field, meta) {
27
48
  return {
28
49
  ...meta,
@@ -76,7 +97,14 @@ function applyStaticTranslations(root = document) {
76
97
  el.textContent = t(el.dataset.i18n, {}, el.textContent);
77
98
  });
78
99
  root.querySelectorAll('[data-i18n-html]').forEach(el => {
79
- el.innerHTML = t(el.dataset.i18nHtml, {}, el.innerHTML);
100
+ // Rewrite only from the catalog: the server-rendered markup already is
101
+ // the English copy, and routing it back through the escape+allowlist
102
+ // pipeline would depend on attribute serialization being round-trip
103
+ // stable, which it is not guaranteed to be.
104
+ const key = el.dataset.i18nHtml;
105
+ if (Object.prototype.hasOwnProperty.call(I18N_PAYLOAD.messages || {}, key)) {
106
+ el.innerHTML = tHtml(key);
107
+ }
80
108
  });
81
109
  for (const attribute of ['placeholder', 'title', 'aria-label']) {
82
110
  const dataName = `i18n${attribute.split('-').map(part => part[0].toUpperCase() + part.slice(1)).join('')}`;
@@ -908,17 +936,17 @@ function render() {
908
936
  else badges += `<span class="badge unknown">${escapeHtml(category) || '?'}</span>`;
909
937
 
910
938
  const gatedNote = disabledBy
911
- ? `<div class="disabled-by-note">${tr(
939
+ ? `<div class="disabled-by-note">${tHtml(
912
940
  'tools.notes.beta_disabled',
913
941
  {setting: `<code>${escapeHtml(disabledBy)}</code>`},
914
- `Beta. Set <code>${escapeHtml(disabledBy)}</code> in the dev App (add-on) config or the matching env var (see docs/beta.md).`
942
+ 'Beta. Set {setting} in the dev App (add-on) config or the matching env var (see docs/beta.md).'
915
943
  )}</div>`
916
944
  : '';
917
945
  const envPinnedNote = isEnvPinned
918
- ? `<div class="feature-locked-note">${tr(
946
+ ? `<div class="feature-locked-note">${tHtml(
919
947
  'tools.notes.env_pinned',
920
948
  {variable: `<code>${escapeHtml(envPinVar)}</code>`},
921
- `env-pinned via <code>${envPinVar}</code>. Unset the env var to edit here.`
949
+ 'Pinned by {variable}. Unset the environment variable to edit here.'
922
950
  )}</div>`
923
951
  : '';
924
952
  const bpsLockedNote = isBpsLocked
@@ -1277,10 +1305,10 @@ const BACKUP_FIELD_LABELS = {
1277
1305
  };
1278
1306
 
1279
1307
  const BACKUP_ORIGIN_LABELS = {
1280
- addon: t('backup.origins.addon', {}, 'Synced to Supervisor. Restart required after save.'),
1308
+ addon: escapeHtml(t('backup.origins.addon', {}, 'Synced to Supervisor. Restart required after save.')),
1281
1309
  env: null, // banner generated dynamically with the env var name
1282
- file: t('backup.origins.file', {}, 'Persisted locally; takes effect immediately.'),
1283
- default: t('backup.origins.default', {}, 'Using default; first save creates a local override file.'),
1310
+ file: escapeHtml(t('backup.origins.file', {}, 'Persisted locally; takes effect immediately.')),
1311
+ default: escapeHtml(t('backup.origins.default', {}, 'Using default; first save creates a local override file.')),
1284
1312
  };
1285
1313
 
1286
1314
  async function loadBackupConfig() {
@@ -1476,8 +1504,8 @@ function renderFsCustomPathsSubForm(parentEl, masterOn, fsOn) {
1476
1504
  : '.storage, secrets.yaml';
1477
1505
  info.innerHTML =
1478
1506
  `<div class="feature-name">${escapeHtml(t('filesystem.custom.title', {}, 'Custom filesystem directories (advanced)'))}</div>` +
1479
- `<div class="feature-help">${t('filesystem.custom.help', {}, 'Extra directories (one per line) that the file tools may READ and WRITE, either relative to your config dir or an absolute allowed HAOS sibling volume. Each entry grants both read and write. Applies immediately; no restart needed.')}</div>` +
1480
- `<div class="feature-help">${t('filesystem.custom.blocked', {paths: `<code>${escapeHtml(denyList)}</code>`}, `Always blocked (cannot be added): <code>${escapeHtml(denyList)}</code>, path traversal (<code>..</code>), and any absolute path outside the HAOS sibling volumes.`)}</div>`;
1507
+ `<div class="feature-help">${tHtml('filesystem.custom.help', {}, 'Extra directories (one per line) that the file tools may READ and WRITE, either relative to your config dir or an absolute allowed HAOS sibling volume. Each entry grants both read and write. Applies immediately; no restart needed.')}</div>` +
1508
+ `<div class="feature-help">${tHtml('filesystem.custom.blocked', {paths: `<code>${escapeHtml(denyList)}</code>`}, 'Always blocked (cannot be added): {paths}, path traversal (<code>..</code>), and any absolute path outside the HAOS sibling volumes.')}</div>`;
1481
1509
 
1482
1510
  const control = document.createElement('div');
1483
1511
  control.className = 'feature-control';
@@ -1922,19 +1950,19 @@ const ORIGIN_INFO_NOTE = {
1922
1950
  function envLockedNoteHtml(envVar, fieldName) {
1923
1951
  const envVarTag = `<code>${escapeHtml(envVar)}</code>`;
1924
1952
  if (!IS_ADDON_MODE) {
1925
- return t('origins.env_var_unset', {variable: envVarTag}, `Set via env var ${envVarTag}; unset it to edit here.`);
1953
+ return tHtml('origins.env_var_unset', {variable: envVarTag}, 'Set via env var {variable}; unset it to edit here.');
1926
1954
  }
1927
1955
  if (fieldName === 'enable_beta_features') {
1928
- return t(
1956
+ return tHtml(
1929
1957
  'origins.beta_legacy_bridge',
1930
1958
  {variable: envVarTag},
1931
- `Auto-enabled in App (add-on) mode (legacy bridge; your options.json predates the master toggle schema entry). Set <code>enable_beta_features</code> explicitly in the App (add-on) Configuration tab to take direct control. (env: ${envVarTag})`
1959
+ 'Auto-enabled in App (add-on) mode (legacy bridge; your options.json predates the master toggle schema entry). Set <code>enable_beta_features</code> explicitly in the App (add-on) Configuration tab to take direct control. (env: {variable})'
1932
1960
  );
1933
1961
  }
1934
- return t(
1962
+ return tHtml(
1935
1963
  'origins.addon_runtime',
1936
1964
  {variable: envVarTag},
1937
- `Set by the App (add-on) runtime environment, managed by Home Assistant Supervisor; cannot be changed from this web UI. (env: ${envVarTag})`
1965
+ 'Set by the App (add-on) runtime environment, managed by Home Assistant Supervisor; cannot be changed from this web UI. (env: {variable})'
1938
1966
  );
1939
1967
  }
1940
1968
 
@@ -2035,7 +2063,7 @@ function renderFeatureFlags(flags) {
2035
2063
  `${escapeHtml(ORIGIN_INFO_NOTE[f.origin])}</div>`
2036
2064
  : '';
2037
2065
  info.innerHTML =
2038
- `<div class="feature-name" id="label-feature-${fieldName}">${escapeHtml(meta.label)}</div>` +
2066
+ `<div class="feature-name" id="label-feature-${escapeHtml(fieldName)}">${escapeHtml(meta.label)}</div>` +
2039
2067
  `<div class="feature-help">${escapeHtml(meta.help)}</div>` +
2040
2068
  lockedNote + infoNote;
2041
2069
 
@@ -2209,7 +2237,7 @@ function renderSubFlagRows(flags, parentEl, subFieldNames, { cssClass, lockedByG
2209
2237
  `${escapeHtml(ORIGIN_INFO_NOTE[f.origin])}</div>`
2210
2238
  : '';
2211
2239
  info.innerHTML =
2212
- `<div class="feature-name" id="label-feature-${fieldName}">${escapeHtml(meta.label)}</div>` +
2240
+ `<div class="feature-name" id="label-feature-${escapeHtml(fieldName)}">${escapeHtml(meta.label)}</div>` +
2213
2241
  `<div class="feature-help">${escapeHtml(meta.help)}</div>` +
2214
2242
  lockedNote + infoNote;
2215
2243
 
@@ -2275,7 +2303,7 @@ function renderCodeModeSubRows(parentEl, masterOn, codeModeOn) {
2275
2303
  let lockedNote = '';
2276
2304
  if (f.field === 'code_mode_saved_tools_path') {
2277
2305
  if (IS_ADDON_MODE) {
2278
- lockedNote = `<div class="feature-locked-note">${t(
2306
+ lockedNote = `<div class="feature-locked-note">${tHtml(
2279
2307
  'advanced.code_mode_saved_tools_path.addon_locked',
2280
2308
  {},
2281
2309
  'Hardcoded to <code>/data/saved_tools.json</code> in App (add-on) mode and cannot be changed (fixed here so saved tools survive App (add-on) updates).'
@@ -2295,7 +2323,7 @@ function renderCodeModeSubRows(parentEl, masterOn, codeModeOn) {
2295
2323
  `<div class="feature-locked-note">${envLockedNoteHtml(f.env_var, f.field)}</div>`;
2296
2324
  }
2297
2325
  info.innerHTML =
2298
- `<div class="feature-name" id="label-feature-${f.field}">${escapeHtml(meta.label)}</div>` +
2326
+ `<div class="feature-name" id="label-feature-${escapeHtml(f.field)}">${escapeHtml(meta.label)}</div>` +
2299
2327
  `<div class="feature-help">${escapeHtml(meta.help)}</div>` +
2300
2328
  lockedNote;
2301
2329
 
@@ -2472,7 +2500,7 @@ function renderPolicyCards(policy) {
2472
2500
  // see/edit them all.
2473
2501
  const byTool = {};
2474
2502
  rules.forEach((r, idx) => {
2475
- const key = r.tool_name + '' + idx;
2503
+ const key = r.tool_name + '\0' + idx;
2476
2504
  byTool[key] = {tool_name: r.tool_name, rule: r, originalIndex: idx};
2477
2505
  });
2478
2506
  Object.keys(byTool).forEach(key => {
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ha-mcp-dev
3
- Version: 7.13.0.dev1997
3
+ Version: 7.13.0.dev2001
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