ha-mcp-dev 7.6.0.dev640__tar.gz → 7.6.0.dev642__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 (136) hide show
  1. {ha_mcp_dev-7.6.0.dev640/src/ha_mcp_dev.egg-info → ha_mcp_dev-7.6.0.dev642}/PKG-INFO +1 -1
  2. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/pyproject.toml +1 -1
  3. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/tools/tools_bug_report.py +28 -2
  4. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/utils/usage_logger.py +71 -1
  5. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642/src/ha_mcp_dev.egg-info}/PKG-INFO +1 -1
  6. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/LICENSE +0 -0
  7. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/MANIFEST.in +0 -0
  8. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/README.md +0 -0
  9. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/setup.cfg +0 -0
  10. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/__init__.py +0 -0
  11. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/__main__.py +0 -0
  12. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/_pypi_marker +0 -0
  13. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/_version.py +0 -0
  14. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/auth/__init__.py +0 -0
  15. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/auth/consent_form.py +0 -0
  16. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/auth/provider.py +0 -0
  17. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/backup_manager.py +0 -0
  18. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/client/__init__.py +0 -0
  19. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/client/rest_client.py +0 -0
  20. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/client/supervisor_client.py +0 -0
  21. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/client/websocket_client.py +0 -0
  22. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/client/websocket_listener.py +0 -0
  23. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/config.py +0 -0
  24. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/errors.py +0 -0
  25. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/policy/__init__.py +0 -0
  26. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/policy/approval_queue.py +0 -0
  27. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/policy/evaluator.py +0 -0
  28. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/policy/handlers.py +0 -0
  29. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/policy/middleware.py +0 -0
  30. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/policy/model.py +0 -0
  31. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/policy/persistence.py +0 -0
  32. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/policy/value_sources.py +0 -0
  33. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/py.typed +0 -0
  34. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/resources/skills-vendor/.claude/settings.json +0 -0
  35. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/resources/skills-vendor/.claude-plugin/marketplace.json +0 -0
  36. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/resources/skills-vendor/.claude-plugin/plugin.json +0 -0
  37. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/resources/skills-vendor/.github/ISSUE_TEMPLATE/skill-rca.md +0 -0
  38. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/resources/skills-vendor/.github/pull_request_template.md +0 -0
  39. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/resources/skills-vendor/AGENTS.md +0 -0
  40. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/resources/skills-vendor/CLAUDE.md +0 -0
  41. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/resources/skills-vendor/CONTRIBUTING.md +0 -0
  42. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/resources/skills-vendor/LICENSE +0 -0
  43. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/resources/skills-vendor/README.md +0 -0
  44. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/SKILL.md +0 -0
  45. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/evals/evals.json +0 -0
  46. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/automation-patterns.md +0 -0
  47. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-cards.md +0 -0
  48. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/dashboard-guide.md +0 -0
  49. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/device-control.md +0 -0
  50. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/domain-docs.md +0 -0
  51. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/examples.yaml +0 -0
  52. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/helper-selection.md +0 -0
  53. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/safe-refactoring.md +0 -0
  54. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/template-guidelines.md +0 -0
  55. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/yaml-only-integrations.md +0 -0
  56. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/server.py +0 -0
  57. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/settings.css +0 -0
  58. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/settings.js +0 -0
  59. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/settings_ui.py +0 -0
  60. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/smoke_test.py +0 -0
  61. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/stdio_settings_sidecar.py +0 -0
  62. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/tools/__init__.py +0 -0
  63. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/tools/auto_backup.py +0 -0
  64. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/tools/backup.py +0 -0
  65. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/tools/best_practice_checker.py +0 -0
  66. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/tools/device_control.py +0 -0
  67. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/tools/enhanced.py +0 -0
  68. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/tools/helpers.py +0 -0
  69. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/tools/reference_validator.py +0 -0
  70. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/tools/registry.py +0 -0
  71. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/tools/smart_search/__init__.py +0 -0
  72. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/tools/smart_search/_base.py +0 -0
  73. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/tools/smart_search/_config.py +0 -0
  74. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/tools/smart_search/_deep.py +0 -0
  75. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/tools/smart_search/_entities.py +0 -0
  76. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/tools/smart_search/_fetch.py +0 -0
  77. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/tools/smart_search/_overview.py +0 -0
  78. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/tools/smart_search/_scenes.py +0 -0
  79. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/tools/smart_search/_scoring.py +0 -0
  80. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/tools/tools_addons.py +0 -0
  81. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/tools/tools_areas.py +0 -0
  82. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/tools/tools_blueprints.py +0 -0
  83. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/tools/tools_calendar.py +0 -0
  84. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/tools/tools_camera.py +0 -0
  85. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/tools/tools_categories.py +0 -0
  86. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/tools/tools_code.py +0 -0
  87. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/tools/tools_config_automations.py +0 -0
  88. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/tools/tools_config_dashboards.py +0 -0
  89. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/tools/tools_config_entry_flow.py +0 -0
  90. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/tools/tools_config_helpers.py +0 -0
  91. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/tools/tools_config_scenes.py +0 -0
  92. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/tools/tools_config_scripts.py +0 -0
  93. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/tools/tools_energy.py +0 -0
  94. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/tools/tools_entities.py +0 -0
  95. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/tools/tools_filesystem.py +0 -0
  96. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/tools/tools_groups.py +0 -0
  97. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/tools/tools_hacs.py +0 -0
  98. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/tools/tools_history.py +0 -0
  99. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/tools/tools_integrations.py +0 -0
  100. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/tools/tools_labels.py +0 -0
  101. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/tools/tools_mcp_component.py +0 -0
  102. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/tools/tools_registry.py +0 -0
  103. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/tools/tools_resources.py +0 -0
  104. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/tools/tools_search.py +0 -0
  105. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/tools/tools_service.py +0 -0
  106. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/tools/tools_services.py +0 -0
  107. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/tools/tools_system.py +0 -0
  108. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/tools/tools_todo.py +0 -0
  109. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/tools/tools_traces.py +0 -0
  110. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/tools/tools_updates.py +0 -0
  111. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/tools/tools_utility.py +0 -0
  112. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/tools/tools_voice_assistant.py +0 -0
  113. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/tools/tools_yaml_config.py +0 -0
  114. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/tools/tools_zones.py +0 -0
  115. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/tools/util_helpers.py +0 -0
  116. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/tools/validation_middleware.py +0 -0
  117. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/transforms/__init__.py +0 -0
  118. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/transforms/categorized_search.py +0 -0
  119. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/transforms/lite_docstrings.py +0 -0
  120. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/utils/__init__.py +0 -0
  121. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/utils/config_hash.py +0 -0
  122. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/utils/data_paths.py +0 -0
  123. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/utils/domain_handlers.py +0 -0
  124. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/utils/fuzzy_search.py +0 -0
  125. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/utils/kill_signal_diagnostics.py +0 -0
  126. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/utils/operation_manager.py +0 -0
  127. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/utils/python_sandbox.py +0 -0
  128. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp/utils/skill_loader.py +0 -0
  129. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp_dev.egg-info/SOURCES.txt +0 -0
  130. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp_dev.egg-info/dependency_links.txt +0 -0
  131. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp_dev.egg-info/entry_points.txt +0 -0
  132. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp_dev.egg-info/requires.txt +0 -0
  133. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/src/ha_mcp_dev.egg-info/top_level.txt +0 -0
  134. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/tests/__init__.py +0 -0
  135. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/tests/test_constants.py +0 -0
  136. {ha_mcp_dev-7.6.0.dev640 → ha_mcp_dev-7.6.0.dev642}/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.6.0.dev640
3
+ Version: 7.6.0.dev642
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.6.0.dev640"
7
+ version = "7.6.0.dev642"
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"
@@ -293,7 +293,8 @@ def _sanitize_log_text(text: str) -> str:
293
293
  review (see ``_generate_anonymization_guide``). Rules cover the most common
294
294
  leak shapes seen in HA add-on logs:
295
295
  JWTs, bearer tokens, long hex tokens, ``key=value`` style credentials,
296
- URL userinfo, and IPv4 addresses with network context.
296
+ URL userinfo, IPv4 addresses with network context, and the MCP connect-URL
297
+ secret path (the add-on's LAN auth).
297
298
  """
298
299
  # JWT tokens (header.payload.signature)
299
300
  text = re.sub(
@@ -338,6 +339,20 @@ def _sanitize_log_text(text: str) -> str:
338
339
  text = _IPV4_WITH_PORT_OR_CIDR_RE.sub("[IP]", text)
339
340
  text = _IPV4_IN_URL_RE.sub(r"\1[IP]", text)
340
341
  text = _IPV4_AFTER_KEYWORD_RE.sub(r"\1[IP]", text)
342
+ # MCP connect-URL secret path — the add-on's LAN auth. Redact by the
343
+ # configured value (catches custom paths) and the generated
344
+ # ``/private_<token>`` convention. Only bug-report output is scrubbed here;
345
+ # the raw logs this text is copied from are left intact.
346
+ configured = os.getenv("MCP_SECRET_PATH", "").rstrip("/")
347
+ if configured and configured != "/mcp":
348
+ # Anchor on a path-segment boundary so a short/substring-prone configured
349
+ # value (e.g. "/ha") cannot corrupt unrelated text (e.g. "/happy").
350
+ text = re.sub(
351
+ re.escape(configured) + r"(?![A-Za-z0-9_-])",
352
+ "[REDACTED_SECRET_PATH]",
353
+ text,
354
+ )
355
+ text = re.sub(r"/private_[A-Za-z0-9_-]+", "[REDACTED_SECRET_PATH]", text)
341
356
  return text
342
357
 
343
358
 
@@ -623,7 +638,18 @@ class BugReportTools:
623
638
  "success": True,
624
639
  "diagnostic_info": diagnostic_info,
625
640
  "recent_logs": recent_logs,
626
- "startup_logs": startup_logs,
641
+ # Scrub the startup-log *messages* — they aren't sanitized at source,
642
+ # so the connect-URL secret path can otherwise surface here.
643
+ # recent_logs is also returned, but its sensitive *parameters* are
644
+ # key-masked at the logging chokepoint and its error_message is
645
+ # returned as-is to the trusted client by design (see SECURITY.md);
646
+ # formatted_report and addon_logs already route through
647
+ # _sanitize_log_text. This copies entries — the underlying log
648
+ # records stay raw.
649
+ "startup_logs": [
650
+ {**entry, "message": _sanitize_log_text(entry.get("message", ""))}
651
+ for entry in startup_logs
652
+ ],
627
653
  "addon_logs": addon_logs,
628
654
  "log_count": len(recent_logs),
629
655
  "startup_log_count": len(startup_logs),
@@ -94,6 +94,72 @@ def get_startup_logs() -> list[dict[str, Any]]:
94
94
  return _startup_collector.get_logs()
95
95
 
96
96
 
97
+ # Parameter keys whose values are masked before a tool call is recorded to the
98
+ # in-memory ring buffer or persisted to disk. Tool kwargs can carry secrets
99
+ # (alarm/lock ``code``, tokens, passwords); these must never reach the usage
100
+ # log, which ``ha_report_issue`` surfaces and which is written verbatim to
101
+ # plaintext ``mcp_usage.jsonl``. Matching is by key name (case-insensitive) and
102
+ # recursive, so a secret nested under a non-sensitive key — e.g.
103
+ # ``ha_call_service(data={"code": ...})`` — is caught while ``data`` siblings
104
+ # like ``entity_id``/``brightness`` survive for debugging.
105
+ _SENSITIVE_PARAM_KEYS = frozenset(
106
+ {
107
+ "code",
108
+ "pin",
109
+ "password",
110
+ "passwd",
111
+ "secret",
112
+ "token",
113
+ "access_token",
114
+ "refresh_token",
115
+ "api_key",
116
+ "apikey",
117
+ "client_secret",
118
+ "authorization",
119
+ }
120
+ )
121
+ # Suffix match only for families with a low false-positive rate. Deliberately
122
+ # excludes ``_code``/``_key`` so ``status_code``/``cache_key`` stay readable;
123
+ # the exact ``code``/``pin``/``api_key`` entries above already cover the real
124
+ # Home Assistant service-call surface.
125
+ _SENSITIVE_KEY_SUFFIXES = ("_token", "_secret", "_password", "_passwd")
126
+ _REDACTED_VALUE = "[REDACTED]"
127
+ _MAX_REDACT_DEPTH = 6
128
+
129
+
130
+ def _is_sensitive_key(key: Any) -> bool:
131
+ """Return True if a parameter key's value should be masked."""
132
+ if not isinstance(key, str):
133
+ return False
134
+ lowered = key.lower()
135
+ return lowered in _SENSITIVE_PARAM_KEYS or lowered.endswith(_SENSITIVE_KEY_SUFFIXES)
136
+
137
+
138
+ def _redact_parameters(value: Any, _depth: int = 0) -> Any:
139
+ """Return a copy of ``value`` with sensitive values masked by key name.
140
+
141
+ Never mutates the input: it is the live tool ``kwargs`` dict, still
142
+ referenced by the caller after this returns. Recurses through nested
143
+ dicts/lists/tuples so secrets nested under non-sensitive keys are caught
144
+ (a tuple is returned as a list). Fails closed past ``_MAX_REDACT_DEPTH`` —
145
+ a subtree too deep to walk is masked wholesale rather than returned verbatim.
146
+ """
147
+ if _depth > _MAX_REDACT_DEPTH:
148
+ return _REDACTED_VALUE
149
+ if isinstance(value, dict):
150
+ return {
151
+ key: (
152
+ _REDACTED_VALUE
153
+ if _is_sensitive_key(key)
154
+ else _redact_parameters(item, _depth + 1)
155
+ )
156
+ for key, item in value.items()
157
+ }
158
+ if isinstance(value, (list, tuple)):
159
+ return [_redact_parameters(item, _depth + 1) for item in value]
160
+ return value
161
+
162
+
97
163
  @dataclass
98
164
  class ToolUsageLog:
99
165
  """Single tool usage log entry."""
@@ -201,10 +267,14 @@ class UsageLogger:
201
267
  if not self._enabled:
202
268
  return
203
269
  try:
270
+ # Mask secrets (alarm/lock codes, tokens, passwords) before the entry
271
+ # reaches the ring buffer or disk. Returns a copy — never mutates the
272
+ # caller's live kwargs dict.
273
+ redacted_parameters = _redact_parameters(parameters)
204
274
  log_entry = ToolUsageLog(
205
275
  timestamp=datetime.now(UTC).isoformat(),
206
276
  tool_name=tool_name,
207
- parameters=parameters,
277
+ parameters=redacted_parameters,
208
278
  execution_time_ms=execution_time_ms,
209
279
  success=success,
210
280
  error_message=error_message,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ha-mcp-dev
3
- Version: 7.6.0.dev640
3
+ Version: 7.6.0.dev642
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