diff --git a/navi/core/container.py b/navi/core/container.py index b565508..84be58d 100644 --- a/navi/core/container.py +++ b/navi/core/container.py @@ -2,10 +2,13 @@ from __future__ import annotations +import structlog from dataclasses import dataclass, field from typing import TYPE_CHECKING from navi.config import settings + +logger = structlog.get_logger() from navi.context_providers._loader import ContextProviderRegistry from navi.llm.ollama import OllamaBackend @@ -122,15 +125,43 @@ workers = build_default_workers() - # Callback: register MCP tools whenever a server connects (startup or health-check reconnect) + # Register MCP tools for servers that connected during startup. + # This must happen AFTER build_default_registries creates tool_registry. + for srv_name, client in mcp_manager.clients.items(): + if not client.connected: + continue + try: + tools = await client.list_tools() + logger.info( + "Registering startup MCP tools for %r -> %d tools", + srv_name, len(tools), + ) + for tool in tools: + mcp_tool = McpTool( + server_name=srv_name, + tool_name=tool.name, + description=tool.description or "", + parameters=tool.inputSchema, + manager=mcp_manager, + ) + tool_registry.register_external(mcp_tool) + except Exception as exc: + logger.warning("Failed to register MCP tools for %r: %s", srv_name, exc) + + # Callback for health-check reconnects (server comes back online later) async def _on_mcp_server_connected(server_name: str) -> None: from navi.core.event_bus import get_event_bus from navi.core.events import McpStatusUpdate client = mcp_manager.clients.get(server_name) if not client: + logger.warning("_on_mcp_server_connected: no client for %r", server_name) return try: tools = await client.list_tools() + logger.info( + "_on_mcp_server_connected: %r -> %d tools", + server_name, len(tools), + ) for tool in tools: mcp_tool = McpTool( server_name=server_name, @@ -140,6 +171,9 @@ manager=mcp_manager, ) tool_registry.register_external(mcp_tool) + logger.debug( + "Registered MCP tool: %s", mcp_tool.name, + ) await get_event_bus().publish( McpStatusUpdate( server_name=server_name, diff --git a/navi/core/tool_utils.py b/navi/core/tool_utils.py index d8821e7..4041b40 100644 --- a/navi/core/tool_utils.py +++ b/navi/core/tool_utils.py @@ -1,10 +1,13 @@ """Tool list construction shared between Agent and SubAgentRunner.""" +import logging from pathlib import Path from navi.config import settings from navi.tools._internal.base import Tool +log = logging.getLogger(__name__) + _USER_ENABLED_FILE = Path(settings.tools_dir) / "enabled.json" @@ -47,9 +50,12 @@ names.append(full_name) result = [] + missing = [] for name in names: try: result.append(tool_registry.get(name)) except Exception: - pass + missing.append(name) + if missing: + log.warning("build_tool_list missing tools: %s", missing) return result diff --git a/navi/mcp/client.py b/navi/mcp/client.py index 7d10f30..9807441 100644 --- a/navi/mcp/client.py +++ b/navi/mcp/client.py @@ -58,10 +58,6 @@ if self._connected: return - # Ensure any stale transport/session from a prior disconnect or - # mark_disconnected() is fully torn down before we open fresh ones. - await self._cleanup() - try: if self.config.is_stdio: if not self.config.command: @@ -138,7 +134,6 @@ Used by the health-check loop when a server drops silently. """ self._connected = False - self._session = None async def _cleanup(self) -> None: try: