ha-mcp-dev 7.0.0.dev273__tar.gz → 7.0.0.dev274__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 (95) hide show
  1. {ha_mcp_dev-7.0.0.dev273/src/ha_mcp_dev.egg-info → ha_mcp_dev-7.0.0.dev274}/PKG-INFO +1 -1
  2. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/pyproject.toml +1 -1
  3. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/server.py +91 -0
  4. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274/src/ha_mcp_dev.egg-info}/PKG-INFO +1 -1
  5. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/LICENSE +0 -0
  6. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/MANIFEST.in +0 -0
  7. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/README.md +0 -0
  8. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/setup.cfg +0 -0
  9. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/__init__.py +0 -0
  10. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/__main__.py +0 -0
  11. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/_pypi_marker +0 -0
  12. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/auth/__init__.py +0 -0
  13. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/auth/consent_form.py +0 -0
  14. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/auth/provider.py +0 -0
  15. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/client/__init__.py +0 -0
  16. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/client/rest_client.py +0 -0
  17. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/client/websocket_client.py +0 -0
  18. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/client/websocket_listener.py +0 -0
  19. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/config.py +0 -0
  20. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/errors.py +0 -0
  21. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/py.typed +0 -0
  22. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/resources/card_types.json +0 -0
  23. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/resources/dashboard_guide.md +0 -0
  24. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/resources/skills-vendor/.claude/settings.json +0 -0
  25. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/resources/skills-vendor/.claude-plugin/marketplace.json +0 -0
  26. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/resources/skills-vendor/.claude-plugin/plugin.json +0 -0
  27. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/resources/skills-vendor/.github/ISSUE_TEMPLATE/skill-rca.md +0 -0
  28. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/resources/skills-vendor/AGENTS.md +0 -0
  29. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/resources/skills-vendor/CLAUDE.md +0 -0
  30. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/resources/skills-vendor/CONTRIBUTING.md +0 -0
  31. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/resources/skills-vendor/LICENSE +0 -0
  32. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/resources/skills-vendor/README.md +0 -0
  33. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/SKILL.md +0 -0
  34. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/automation-patterns.md +0 -0
  35. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/device-control.md +0 -0
  36. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/examples.yaml +0 -0
  37. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/helper-selection.md +0 -0
  38. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/safe-refactoring.md +0 -0
  39. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/resources/skills-vendor/skills/home-assistant-best-practices/references/template-guidelines.md +0 -0
  40. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/smoke_test.py +0 -0
  41. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/tools/__init__.py +0 -0
  42. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/tools/backup.py +0 -0
  43. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/tools/best_practice_checker.py +0 -0
  44. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/tools/device_control.py +0 -0
  45. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/tools/enhanced.py +0 -0
  46. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/tools/helpers.py +0 -0
  47. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/tools/registry.py +0 -0
  48. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/tools/smart_search.py +0 -0
  49. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/tools/tools_addons.py +0 -0
  50. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/tools/tools_areas.py +0 -0
  51. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/tools/tools_blueprints.py +0 -0
  52. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/tools/tools_bug_report.py +0 -0
  53. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/tools/tools_calendar.py +0 -0
  54. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/tools/tools_camera.py +0 -0
  55. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/tools/tools_config_automations.py +0 -0
  56. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/tools/tools_config_dashboards.py +0 -0
  57. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/tools/tools_config_entry_flow.py +0 -0
  58. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/tools/tools_config_helpers.py +0 -0
  59. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/tools/tools_config_info.py +0 -0
  60. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/tools/tools_config_scripts.py +0 -0
  61. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/tools/tools_entities.py +0 -0
  62. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/tools/tools_filesystem.py +0 -0
  63. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/tools/tools_groups.py +0 -0
  64. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/tools/tools_hacs.py +0 -0
  65. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/tools/tools_history.py +0 -0
  66. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/tools/tools_integrations.py +0 -0
  67. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/tools/tools_labels.py +0 -0
  68. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/tools/tools_mcp_component.py +0 -0
  69. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/tools/tools_registry.py +0 -0
  70. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/tools/tools_resources.py +0 -0
  71. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/tools/tools_search.py +0 -0
  72. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/tools/tools_service.py +0 -0
  73. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/tools/tools_services.py +0 -0
  74. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/tools/tools_system.py +0 -0
  75. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/tools/tools_todo.py +0 -0
  76. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/tools/tools_traces.py +0 -0
  77. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/tools/tools_updates.py +0 -0
  78. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/tools/tools_utility.py +0 -0
  79. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/tools/tools_voice_assistant.py +0 -0
  80. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/tools/tools_zones.py +0 -0
  81. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/tools/util_helpers.py +0 -0
  82. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/utils/__init__.py +0 -0
  83. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/utils/domain_handlers.py +0 -0
  84. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/utils/fuzzy_search.py +0 -0
  85. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/utils/operation_manager.py +0 -0
  86. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/utils/python_sandbox.py +0 -0
  87. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp/utils/usage_logger.py +0 -0
  88. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp_dev.egg-info/SOURCES.txt +0 -0
  89. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp_dev.egg-info/dependency_links.txt +0 -0
  90. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp_dev.egg-info/entry_points.txt +0 -0
  91. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp_dev.egg-info/requires.txt +0 -0
  92. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/src/ha_mcp_dev.egg-info/top_level.txt +0 -0
  93. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/tests/__init__.py +0 -0
  94. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/tests/test_constants.py +0 -0
  95. {ha_mcp_dev-7.0.0.dev273 → ha_mcp_dev-7.0.0.dev274}/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.0.0.dev273
3
+ Version: 7.0.0.dev274
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.0.0.dev273"
7
+ version = "7.0.0.dev274"
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"
@@ -67,6 +67,7 @@ class HomeAssistantSmartMCPServer(EnhancedToolsMixin):
67
67
  self._smart_tools: Any = None
68
68
  self._device_tools: Any = None
69
69
  self._tools_registry: ToolsRegistry | None = None
70
+ self._skill_tool_names: list[str] = []
70
71
 
71
72
  # Get server name/version from settings if no client provided
72
73
  if not self._client_provided:
@@ -324,6 +325,96 @@ class HomeAssistantSmartMCPServer(EnhancedToolsMixin):
324
325
  "Failed to expose skills as tools (resources still available)"
325
326
  )
326
327
 
328
+ # Phase 4: Register skill guidance tools for clients that don't read
329
+ # server instructions (e.g., claude.ai). The tool description contains
330
+ # the trigger conditions so the AI sees them in the tool listing.
331
+ # Names stored for pinning in search transforms (always-visible).
332
+ self._register_skill_guidance_tools(skills_dir)
333
+
334
+ def _register_skill_guidance_tools(self, skills_dir: Path) -> None:
335
+ """Register a lightweight guidance tool per skill.
336
+
337
+ Clients like claude.ai don't read the MCP server instructions field,
338
+ so the bootstrap prompt (trigger conditions, symptoms) is invisible.
339
+ This registers a tool per skill whose description contains the trigger
340
+ conditions. The tool itself just lists available reference files —
341
+ actual content is loaded on demand via read_resource.
342
+ """
343
+ try:
344
+ entries = sorted(skills_dir.iterdir())
345
+ except OSError:
346
+ logger.warning("Could not read skills directory: %s", skills_dir)
347
+ return
348
+
349
+ for skill_dir in entries:
350
+ main_file = skill_dir / "SKILL.md"
351
+ if not skill_dir.is_dir() or not main_file.exists():
352
+ continue
353
+
354
+ frontmatter = self._parse_skill_frontmatter(main_file)
355
+ if not frontmatter:
356
+ continue
357
+
358
+ description = frontmatter["description"].strip()
359
+ skill_name = skill_dir.name
360
+ tool_name = f"ha_get_skill_{skill_name.replace('-', '_')}"
361
+ uri = f"skill://{skill_name}/SKILL.md"
362
+
363
+ tool_description = (
364
+ f"CALL THIS FIRST before performing matching actions. "
365
+ f"{description}\n\n"
366
+ f"Returns available reference files. Use read_resource with "
367
+ f"the file URI to load specific guides as needed."
368
+ )
369
+
370
+ # Collect available reference files for the listing.
371
+ # Filter out symlinks and verify path containment to prevent
372
+ # traversal via symlinked directories.
373
+ ref_files = []
374
+ resolved_root = skill_dir.resolve()
375
+ try:
376
+ for f in sorted(skill_dir.rglob("*")):
377
+ if not f.is_file() or f.is_symlink():
378
+ continue
379
+ # Ensure resolved path stays within the skill directory
380
+ if not f.resolve().is_relative_to(resolved_root):
381
+ continue
382
+ rel = f.relative_to(skill_dir)
383
+ ref_uri = f"skill://{skill_name}/{rel}"
384
+ ref_files.append({"name": str(rel), "uri": ref_uri})
385
+ except OSError:
386
+ logger.warning("Error reading skill files in %s", skill_dir)
387
+
388
+ # Use factory to capture ref_files in closure
389
+ def _make_skill_handler(
390
+ s_name: str, s_uri: str, files: list[dict[str, str]],
391
+ ):
392
+ async def handler() -> dict[str, Any]:
393
+ return {
394
+ "skill": s_name,
395
+ "skill_uri": s_uri,
396
+ "how_to_use": (
397
+ "Use read_resource with a file URI below to load "
398
+ "the specific reference you need. Start with "
399
+ "SKILL.md for the decision workflow."
400
+ ),
401
+ "available_files": files,
402
+ }
403
+ return handler
404
+
405
+ self.mcp.tool(
406
+ name=tool_name,
407
+ description=tool_description,
408
+ annotations={"readOnlyHint": True},
409
+ )(_make_skill_handler(skill_name, uri, ref_files))
410
+
411
+ self._skill_tool_names.append(tool_name)
412
+ logger.info(
413
+ "Registered skill guidance tool %s (%d reference files)",
414
+ tool_name,
415
+ len(ref_files),
416
+ )
417
+
327
418
  # Helper methods required by EnhancedToolsMixin
328
419
 
329
420
  async def smart_entity_search(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ha-mcp-dev
3
- Version: 7.0.0.dev273
3
+ Version: 7.0.0.dev274
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