diff --git a/tests/tui_gateway/test_mcp_reload_all_sessions.py b/tests/tui_gateway/test_mcp_reload_all_sessions.py index e89b4cf46f..03403a2cdf 100644 --- a/tests/tui_gateway/test_mcp_reload_all_sessions.py +++ b/tests/tui_gateway/test_mcp_reload_all_sessions.py @@ -12,6 +12,7 @@ from types import SimpleNamespace import pytest +import hermes_constants from tools import mcp_tool_agent as _mcp_agent from tools import mcp_tool_discovery as _mcp_discovery from tools import mcp_tool_lifecycle as _mcp_lifecycle @@ -19,10 +20,12 @@ import tui_gateway.server as srv @pytest.fixture() -def reload_env(monkeypatch): +def reload_env(monkeypatch, tmp_path): refreshed: list[str] = [] + discovered_homes: list[str] = [] monkeypatch.setattr(_mcp_lifecycle, "shutdown_mcp_servers", lambda: None) - monkeypatch.setattr(_mcp_discovery, "discover_mcp_tools", lambda: None) + monkeypatch.setattr(_mcp_discovery, "discover_mcp_tools", + lambda: discovered_homes.append(hermes_constants.hermes_home_key())) monkeypatch.setattr(_mcp_agent, "refresh_agent_mcp_tools", lambda agent, **_kw: refreshed.append(agent.name) or set()) monkeypatch.setattr(srv, "_compute_mcp_rev", lambda: "rev-a") @@ -31,25 +34,38 @@ def reload_env(monkeypatch): monkeypatch.setattr(srv, "_mcp_reload_gen", 0) monkeypatch.setattr(srv, "_mcp_reload_loaded_rev", "") - def _session(name): - return {"agent": SimpleNamespace(name=name), "history": [], "history_lock": threading.RLock(), "running": False} + def _session(name, profile_home=None): + return {"agent": SimpleNamespace(name=name), "history": [], "history_lock": threading.RLock(), + "running": False, "profile_home": profile_home} + profile_b = tmp_path / "profile-b" + profile_b.mkdir() monkeypatch.setattr(srv, "_sessions", { - "A": _session("agent-A"), "B": _session("agent-B"), + "A": _session("agent-A"), "B": _session("agent-B", profile_home=str(profile_b)), "lazy": {"agent": None, "history_lock": threading.RLock()}, }) - return refreshed + return SimpleNamespace(refreshed=refreshed, discovered_homes=discovered_homes, profile_b=profile_b) def test_reload_from_one_session_refreshes_every_live_agent(reload_env): resp = srv._methods["reload.mcp"](1, {"session_id": "A", "confirm": True}) assert resp["result"]["status"] == "reloaded" - assert sorted(reload_env) == ["agent-A", "agent-B"] + assert sorted(reload_env.refreshed) == ["agent-A", "agent-B"] def test_reload_without_session_id_still_refreshes_live_agents(reload_env): resp = srv._methods["reload.mcp"](1, {"confirm": True}) assert resp["result"]["status"] == "reloaded" - assert sorted(reload_env) == ["agent-A", "agent-B"] + assert sorted(reload_env.refreshed) == ["agent-A", "agent-B"] + + +def test_reload_rediscovers_under_each_live_profile_scope(reload_env): + """The unscoped shutdown tears down every profile's servers; discovery under the ambient home + alone would leave a secondary-profile session refreshing against a registry that never + regained its overlay, so it loses its MCP tools until its own reload.""" + srv._methods["reload.mcp"](1, {"session_id": "A", "confirm": True}) + + assert hermes_constants.hermes_home_key() in reload_env.discovered_homes + assert hermes_constants.hermes_home_key(reload_env.profile_b) in reload_env.discovered_homes diff --git a/tui_gateway/methods_tools.py b/tui_gateway/methods_tools.py index 358cedb604..3424139267 100644 --- a/tui_gateway/methods_tools.py +++ b/tui_gateway/methods_tools.py @@ -314,6 +314,17 @@ def _(rid, params: dict) -> dict: if after == loaded: break loaded = after + # The unscoped shutdown tore down every profile's servers, but discover_mcp_tools() above + # only rebuilt the launch profile's overlay; a secondary-profile session refreshed against + # that registry would lose its MCP tools until its own reload. + with _sessions_lock: + homes = {sess.get("profile_home") for sess in _sessions.values() if sess.get("agent") is not None} + for home in sorted(homes - {None}): + try: + with _session_profile_runtime_scope({"profile_home": home}): + _mcp_discovery.discover_mcp_tools() + except Exception as _exc: + logger.warning("MCP rediscovery failed for profile %s: %s", home, _exc) _refresh_session_agent() _mcp_reload_loaded_rev = loaded _mcp_reload_gen += 1