From dbe2f6964d44d4d881144197fdf0aa2fd2aed0c1 Mon Sep 17 00:00:00 2001 From: alt-glitch Date: Wed, 23 Sep 2026 11:10:30 +0530 Subject: [PATCH] fix: installing or connecting one MCP server no longer strips other servers' tools from the profile connect_plugin_mcp and the connector flow call register_mcp_servers with only the server they connect. The scope reconcile treated that dict as the profile's whole config, so every other server in the profile looked removed and lost its overlay while its connection stayed up: after onboarding installed nvidia-app then nvidia-broadcast, the Plugins tab said nvidia-app was connected but no chat could see its 12 tools. A name the caller omits is now judged against the profile's own MCP config. --- tools/mcp_tool_registration.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/tools/mcp_tool_registration.py b/tools/mcp_tool_registration.py index 2170d8120a..5a16e82201 100644 --- a/tools/mcp_tool_registration.py +++ b/tools/mcp_tool_registration.py @@ -10,6 +10,7 @@ from dataclasses import dataclass from types import SimpleNamespace from typing import TYPE_CHECKING, Any, Callable, Dict, Iterable, List, Optional from tools.mcp_tool_common import _parse_boolish, _core, _resolve_tool_timeout, mcp_field, mcp_server_enabled +from tools import mcp_tool_config as _config from tools import mcp_tool_handlers as _handlers from tools import mcp_tool_schema as _schema from tools.mcp_tool_handlers import ( @@ -461,13 +462,24 @@ def _register_connected_into_current_scope(servers: dict) -> int: if scope is None: return 0 + # Callers that connect a subset (plugin go-live, a connector, orphan re-registration) pass only + # those names. A name they omit is judged against this profile's own config, or connecting one + # server would strip every other server's tools from the profile while their connections live on. + with _core._lock: + omitted = {_key_name(key) for key, scopes in _core._server_tool_scopes.items() + if scope in scopes and _key_name(key) not in servers} + profile_servers = _config._load_mcp_config() if omitted else {} + with _core._lock: stale = [] for key, scopes in _core._server_tool_scopes.items(): if scope not in scopes: continue + name = _key_name(key) + if name not in servers and name not in omitted: + continue # attached after the config read; the next pass judges it server = _core._servers.get(key) - config = servers.get(_key_name(key)) + config = servers[name] if name in servers else profile_servers.get(name) cross_profile = _key_scope(key) != scope if (config is None or not mcp_server_enabled(config) or server is None or getattr(server, "session", None) is None