Skip to content

Commit ddaffa7

Browse files
kingpanther13claude
andcommitted
feat: add category gateway proxy for tool consolidation
Replace direct MCP registration of lesser-used tools with domain-named gateway tools that combine discovery and execution in a single step. Phase 1 implements ha_manage_dashboards, which consolidates 12 dashboard and resource tools behind one gateway. This reduces idle context tokens while maintaining full functionality through 1-step access: - gateway() → lists all sub-tools with full parameter schemas - gateway(tool="ha_config_set_dashboard", args='{...}') → executes This approach addresses discoverability issues found in PR homeassistant-ai#627's 3-step meta-tool pattern (ha_find_tools → ha_get_tool_details → ha_execute_tool), where LLMs failed to discover proxied capabilities. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 8914b26 commit ddaffa7

2 files changed

Lines changed: 554 additions & 2 deletions

File tree

src/ha_mcp/tools/registry.py

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@
1616
- "all" (default): Load all tools
1717
- "automation": Load only automation-related tools (automations, scripts, traces, blueprints)
1818
- Comma-separated list: Load specific modules (e.g., "tools_config_automations,tools_search")
19+
20+
Category gateways:
21+
Modules listed in tool_proxy.PROXY_CATEGORIES are NOT registered with MCP directly.
22+
Instead, they are captured into a proxy registry and exposed via domain-named
23+
gateway tools (e.g., ha_manage_dashboards). See tool_proxy.py for details.
1924
"""
2025

2126
import logging
@@ -137,13 +142,23 @@ def register_all_tools(self) -> None:
137142
138143
Tool modules are imported and registered only when this method is called,
139144
which happens after the MCP server is ready to accept connections.
145+
146+
Modules listed in tool_proxy.PROXY_CATEGORIES are NOT registered with MCP.
147+
Instead, they are captured into a proxy registry and served via category
148+
gateway tools (e.g., ha_manage_dashboards).
140149
"""
141150
if self._modules_registered:
142151
logger.debug("Tools already registered, skipping")
143152
return
144153

145154
import importlib
146155

156+
from .tool_proxy import (
157+
PROXY_CATEGORIES,
158+
discover_proxy_tools,
159+
register_category_gateways,
160+
)
161+
147162
# Build kwargs with all available dependencies (lazy access)
148163
kwargs = {
149164
"smart_tools": self.smart_tools,
@@ -152,12 +167,21 @@ def register_all_tools(self) -> None:
152167

153168
registered_count = 0
154169

155-
# Import and register tools_*.py modules
170+
# Determine which discovered modules should be proxied
171+
proxied_modules: set[str] = set()
172+
for modules in PROXY_CATEGORIES.values():
173+
proxied_modules.update(modules)
174+
175+
# Import and register tools_*.py modules (skip proxied ones)
156176
for module_name in self._discovered_modules:
157177
# Skip explicit modules - handled separately
158178
if module_name in EXPLICIT_MODULES:
159179
continue
160180

181+
# Skip proxied modules — they'll be captured below
182+
if module_name in proxied_modules:
183+
continue
184+
161185
try:
162186
module = importlib.import_module(f".{module_name}", "ha_mcp.tools")
163187

@@ -186,6 +210,9 @@ def register_all_tools(self) -> None:
186210
for module_name, func_name in EXPLICIT_MODULES.items():
187211
if module_name not in self._discovered_modules:
188212
continue
213+
# Skip proxied explicit modules
214+
if module_name in proxied_modules:
215+
continue
189216
try:
190217
module = importlib.import_module(f".{module_name}", "ha_mcp.tools")
191218
register_func = getattr(module, func_name)
@@ -196,5 +223,23 @@ def register_all_tools(self) -> None:
196223
logger.error(f"Failed to register tools from {module_name}: {e}")
197224
raise
198225

226+
# Capture proxied modules and register category gateways
227+
if proxied_modules:
228+
proxy_registry = discover_proxy_tools(
229+
self.mcp, self.client, PROXY_CATEGORIES, **kwargs
230+
)
231+
register_category_gateways(
232+
self.mcp, self.client, proxy_registry, PROXY_CATEGORIES, **kwargs
233+
)
234+
logger.info(
235+
f"Category gateways: {proxy_registry.tool_count} tools from "
236+
f"{len(proxied_modules)} modules routed through "
237+
f"{len(PROXY_CATEGORIES)} gateway(s)"
238+
)
239+
199240
self._modules_registered = True
200-
logger.info(f"Auto-discovery registered tools from {registered_count} modules")
241+
logger.info(
242+
f"Auto-discovery registered tools from {registered_count} modules"
243+
+ (f" (+ {len(PROXY_CATEGORIES)} category gateway(s))"
244+
if proxied_modules else "")
245+
)

0 commit comments

Comments
 (0)