From 44f44b305a60ba27adf4ed8bdfb577412b6d9176 Mon Sep 17 00:00:00 2001 From: Nikolas de Hor Date: Fri, 20 Feb 2026 09:24:48 -0300 Subject: [PATCH 1/2] fix: move MCP connected flag after successful connection to allow retry The flag was set before the connection attempt, so if any MCP server was temporarily unavailable, the flag stayed True and MCP tools were permanently lost for the session. Closes #889 --- nanobot/agent/loop.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/nanobot/agent/loop.py b/nanobot/agent/loop.py index 3016d92..9078318 100644 --- a/nanobot/agent/loop.py +++ b/nanobot/agent/loop.py @@ -128,11 +128,20 @@ class AgentLoop: """Connect to configured MCP servers (one-time, lazy).""" if self._mcp_connected or not self._mcp_servers: return - self._mcp_connected = True from nanobot.agent.tools.mcp import connect_mcp_servers - self._mcp_stack = AsyncExitStack() - await self._mcp_stack.__aenter__() - await connect_mcp_servers(self._mcp_servers, self.tools, self._mcp_stack) + try: + self._mcp_stack = AsyncExitStack() + await self._mcp_stack.__aenter__() + await connect_mcp_servers(self._mcp_servers, self.tools, self._mcp_stack) + self._mcp_connected = True + except Exception as e: + logger.error("Failed to connect MCP servers (will retry next message): {}", e) + if self._mcp_stack: + try: + await self._mcp_stack.aclose() + except Exception: + pass + self._mcp_stack = None def _set_tool_context(self, channel: str, chat_id: str, message_id: str | None = None) -> None: """Update context for all tools that need routing info.""" From 37222f9c0a118c449f0ef291c380916e3ad7ae62 Mon Sep 17 00:00:00 2001 From: Nikolas de Hor Date: Fri, 20 Feb 2026 09:38:22 -0300 Subject: [PATCH 2/2] fix: add connecting guard to prevent concurrent MCP connection attempts Addresses Codex review: concurrent callers could both pass the _mcp_connected guard and race through _connect_mcp(). Added _mcp_connecting flag set immediately to serialize attempts. --- nanobot/agent/loop.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/nanobot/agent/loop.py b/nanobot/agent/loop.py index 9078318..d14b6ea 100644 --- a/nanobot/agent/loop.py +++ b/nanobot/agent/loop.py @@ -89,6 +89,7 @@ class AgentLoop: self._mcp_servers = mcp_servers or {} self._mcp_stack: AsyncExitStack | None = None self._mcp_connected = False + self._mcp_connecting = False self._consolidating: set[str] = set() # Session keys with consolidation in progress self._register_default_tools() @@ -126,8 +127,9 @@ class AgentLoop: async def _connect_mcp(self) -> None: """Connect to configured MCP servers (one-time, lazy).""" - if self._mcp_connected or not self._mcp_servers: + if self._mcp_connected or self._mcp_connecting or not self._mcp_servers: return + self._mcp_connecting = True from nanobot.agent.tools.mcp import connect_mcp_servers try: self._mcp_stack = AsyncExitStack() @@ -142,6 +144,8 @@ class AgentLoop: except Exception: pass self._mcp_stack = None + finally: + self._mcp_connecting = False def _set_tool_context(self, channel: str, chat_id: str, message_id: str | None = None) -> None: """Update context for all tools that need routing info."""