Files
AI-Profile-Router/platform/hermes/patch-api-mcp-refresh.py

68 lines
2.5 KiB
Python

#!/usr/bin/env python3
"""Apply the upstream Hermes API-server MCP refresh workaround.
Hermes 0.20.5 creates an API-server AIAgent without rebuilding its tool
snapshot from the live MCP registry. Healthy MCP servers that finish
discovery after process startup are therefore invisible through the OpenAI
compatible API even though ``hermes mcp test`` can reach them.
This startup patch is deliberately small and fail-closed: it accepts either
the pristine upstream source or an already patched source, and refuses to
modify an unknown future implementation.
"""
from pathlib import Path
API_TARGET = Path("/opt/hermes/gateway/platforms/api_server.py")
API_ANCHOR = " agent = AIAgent(**agent_kwargs)\n"
API_PATCHED = """ # Athena workaround for upstream issue #69746: the API platform
# otherwise snapshots tools before the live MCP registry is attached.
agent = AIAgent(**agent_kwargs)
try:
from tools.mcp_tool import refresh_agent_mcp_tools
refresh_agent_mcp_tools(agent, quiet_mode=True)
except Exception:
logger.warning(
"api_server failed to refresh the live MCP tool registry",
exc_info=True,
)
"""
REFRESH_TARGET = Path("/opt/hermes/tools/mcp_tool.py")
REFRESH_ANCHOR = """ if new_names == current:
# No change → leave the live snapshot untouched (no churn), but
"""
REFRESH_PATCHED = """ if (
new_names == current
and new_defs == (getattr(agent, "tools", None) or [])
):
# Names and schemas are unchanged. Comparing schemas is required
# for the tool_search bridge, whose three public names stay fixed
# while its embedded deferred-tool catalog changes (#72560).
"""
def apply_patch(target: Path, anchor: str, replacement: str, label: str) -> None:
source = target.read_text(encoding="utf-8")
if replacement in source:
print(f"Hermes {label} patch already present")
elif source.count(anchor) == 1:
target.write_text(source.replace(anchor, replacement, 1), encoding="utf-8")
print(f"Applied Hermes {label} patch")
else:
raise SystemExit(
f"HERMES_START_REFUSED: upstream {target.name} changed; "
f"review the {label} patch before upgrading"
)
apply_patch(API_TARGET, API_ANCHOR, API_PATCHED, "API MCP refresh")
apply_patch(
REFRESH_TARGET,
REFRESH_ANCHOR,
REFRESH_PATCHED,
"tool-search catalog refresh",
)