diff --git a/tests/tools/test_mcp_park_log_dedupe.py b/tests/tools/test_mcp_park_log_dedupe.py index bd4ed3aa51..a303515190 100644 --- a/tests/tools/test_mcp_park_log_dedupe.py +++ b/tests/tools/test_mcp_park_log_dedupe.py @@ -19,10 +19,13 @@ import pytest from tools.mcp_tool import MCPServerTask -def _fast_time(monkeypatch): - """Zero out the retry sleeps and the parked self-probe interval.""" +def _fast_time(monkeypatch, tmp_path): + """Zero out the retry sleeps and the parked self-probe interval; keep ``blender`` + enabled in the temp home's config.yaml so the self-probe gate lets it wake.""" from tools import mcp_tool + (tmp_path / "config.yaml").write_text( + "mcp_servers:\n blender:\n command: x\n", encoding="utf-8") monkeypatch.setattr(mcp_tool, "_PARKED_RETRY_INTERVAL", 0) real_sleep = asyncio.sleep @@ -42,7 +45,7 @@ def test_reparked_server_logs_once_not_per_probe(monkeypatch, tmp_path, caplog): from tools import mcp_tool monkeypatch.setattr(mcp_tool, "_MAX_INITIAL_CONNECT_RETRIES", 1) - _fast_time(monkeypatch) + _fast_time(monkeypatch, tmp_path) state = {"calls": 0} @@ -92,7 +95,7 @@ def test_park_after_revival_warns_again(monkeypatch, tmp_path, caplog): monkeypatch.setattr(mcp_tool, "_MAX_INITIAL_CONNECT_RETRIES", 1) monkeypatch.setattr(mcp_tool, "_MAX_RECONNECT_RETRIES", 1) - _fast_time(monkeypatch) + _fast_time(monkeypatch, tmp_path) state = {"calls": 0} diff --git a/tools/mcp_tool_server_run.py b/tools/mcp_tool_server_run.py index 377b84c089..5d999e8589 100644 --- a/tools/mcp_tool_server_run.py +++ b/tools/mcp_tool_server_run.py @@ -202,6 +202,7 @@ class MCPServerRunMixin: self._park_reason = revival_reason self._deregister_tools() self._reconnect_event.clear() + paused = False while True: outcome = await self._wait_for_reconnect_or_shutdown( timeout=_core._PARKED_RETRY_INTERVAL) @@ -213,12 +214,13 @@ class MCPServerRunMixin: # the process (background loops that do not run the gateway reconcile tick # never learn the entry changed). An explicit reconnect request — manual # refresh or `hermes mcp login` — still revives immediately regardless of the - # config gate; only the unattended probe honours it. + # config gate; only the unattended probe honours it. Announce the pause once: + # a line per skipped wake would be the very flood this gate exists to stop. if outcome == "self-probe" and not self._still_configured_enabled(): - logger.info( - "MCP server '%s': skipping self-probe revival — entry is disabled or " - "gone from mcp_servers config", - self.name) + (logger.debug if paused else logger.info)( + "MCP server '%s': parked entry is disabled or gone from mcp_servers; pausing the " + "self-probe until it is re-enabled", self.name) + paused = True continue # Nobody asked for this revival: a self-probe must never open a browser OAuth flow. The # OAuth provider runs inside THIS task (the SDK's auth flow sits in the transport), so a