You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Follow-up to #75 (HERMES_TOOLS_SUBSET) + #82/#83/#85 (mcp_serve autowire).
Bug
With autowire merged, fresh workers boot with 52 tools (built-ins + 36 MCP from hermes-internal). The model hits the tool-paralysis ceiling — emits text-with-affirmation pattern instead of tool_call for verticals that should be one-shot tool invocations.
HERMES_TOOLS_SUBSET (#75) was supposed to let operators narrow the surface per worker, but it only filters BUILT-IN tools at agent_init.py:838. MCP-discovered tools sneak through three ways:
The feat(env): HERMES_TOOLS_SUBSET — operator-side tool surface narrowing (closes #74) #75 filter runs after get_tool_definitions() which includes MCP tools — so HERMES_TOOLS_SUBSET=foo correctly drops MCP tools at that filter. BUT the user-facing UX gap: subset values must match the prefixed names (mcp_hermes-internal_grafted_context_fetch), which most operators won't know.
Even if filtering works at agent.tools assembly time, registry still carries the unwanted MCP tools, costing schema-conversion + collision-check work per tool per boot.
Fix
Apply the HERMES_TOOLS_SUBSET allow-list at MCP tool registration time in tools/mcp_tool.py::_register_server_tools. Tools that fail the filter never enter the registry, so:
Both initial discovery AND /reload-mcp paths honor the subset uniformly (closes the cli.py:9790 hole)
Registry stays clean — no stale entries to filter downstream
Extract a shared helper hermes_cli/tool_subset.py with get_subset_allow() / is_allowed()
Call it inside the per-tool loop AND the utility-tools loop in _register_server_tools
Subset matches against the prefixed name (mcp_<server>_<tool>) — exact match, predictable behavior. Fuzzy/unprefixed matching is a separate feature request.
Acceptance
Worker boot with HERMES_TOOLS_SUBSET=mcp_hermes-internal_grafted_context_fetch,doc_view → registry contains exactly those 2 tools (no other MCP tools registered).
Empty/unset HERMES_TOOLS_SUBSET → all MCP tools register (baseline preserved).
/reload-mcp post-boot → subset still respected.
Worker can emit tool_call against grafted_context_fetch (out of tool-paralysis range).
Severity
Final blocker for poly-explorer end-to-end. After this lands, the cascade closes — workers can be configured with a 5-tool surface that includes their specific MCP needs.
Follow-up to #75 (HERMES_TOOLS_SUBSET) + #82/#83/#85 (mcp_serve autowire).
Bug
With autowire merged, fresh workers boot with 52 tools (built-ins + 36 MCP from hermes-internal). The model hits the tool-paralysis ceiling — emits text-with-affirmation pattern instead of
tool_callfor verticals that should be one-shot tool invocations.HERMES_TOOLS_SUBSET(#75) was supposed to let operators narrow the surface per worker, but it only filters BUILT-IN tools atagent_init.py:838. MCP-discovered tools sneak through three ways:get_tool_definitions()which includes MCP tools — soHERMES_TOOLS_SUBSET=foocorrectly drops MCP tools at that filter. BUT the user-facing UX gap: subset values must match the prefixed names (mcp_hermes-internal_grafted_context_fetch), which most operators won't know./reload-mcp+ auto-reload on config change) re-assignsagent.tools = get_tool_definitions(...)WITHOUT applying the feat(env): HERMES_TOOLS_SUBSET — operator-side tool surface narrowing (closes #74) #75 filter — regression: any post-init MCP server reload nukes the subset.agent.toolsassembly time, registry still carries the unwanted MCP tools, costing schema-conversion + collision-check work per tool per boot.Fix
Apply the HERMES_TOOLS_SUBSET allow-list at MCP tool registration time in
tools/mcp_tool.py::_register_server_tools. Tools that fail the filter never enter the registry, so:/reload-mcppaths honor the subset uniformly (closes the cli.py:9790 hole)Scope:
hermes_cli/tool_subset.pywithget_subset_allow()/is_allowed()_register_server_toolsmcp_<server>_<tool>) — exact match, predictable behavior. Fuzzy/unprefixed matching is a separate feature request.Acceptance
HERMES_TOOLS_SUBSET=mcp_hermes-internal_grafted_context_fetch,doc_view→ registry contains exactly those 2 tools (no other MCP tools registered).HERMES_TOOLS_SUBSET→ all MCP tools register (baseline preserved)./reload-mcppost-boot → subset still respected.tool_callagainstgrafted_context_fetch(out of tool-paralysis range).Severity
Final blocker for poly-explorer end-to-end. After this lands, the cascade closes — workers can be configured with a 5-tool surface that includes their specific MCP needs.