From 6dcaab2f5c58b531d1349b12e332001b55e63136 Mon Sep 17 00:00:00 2001 From: Alessandro <155005371+3clyp50@users.noreply.github.com> Date: Mon, 22 Jun 2026 10:25:54 +0200 Subject: [PATCH] Fix MCP settings apply NameError Use the active settings dictionary when scheduling MCP config updates so applying global MCP servers no longer references an undefined config variable. Add a focused regression test covering the settings apply path and document the deferred MCP update contract in settings.py DOX. --- helpers/settings.py | 2 +- helpers/settings.py.dox.md | 1 + tests/test_settings_mcp.py | 81 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 tests/test_settings_mcp.py diff --git a/helpers/settings.py b/helpers/settings.py index 3f8121d26..35b3f7beb 100644 --- a/helpers/settings.py +++ b/helpers/settings.py @@ -648,7 +648,7 @@ def _apply_settings(previous: Settings | None, browser_timezone: str | None = No ) task2 = defer.DeferredTask().start_task( - update_mcp_settings, config.mcp_servers + update_mcp_settings, _settings["mcp_servers"] ) # TODO overkill, replace with background task # update token in mcp server diff --git a/helpers/settings.py.dox.md b/helpers/settings.py.dox.md index f24270c8b..d5b61ce92 100644 --- a/helpers/settings.py.dox.md +++ b/helpers/settings.py.dox.md @@ -63,6 +63,7 @@ - Important called helpers/classes observed in the source: `TypeVar`, `files.get_abs_path`, `dotenv.get_dotenv_value`, `opts.insert`, `str.strip`, `_is_valid_timezone`, `str.strip.lower`, `_normalize_timezone_setting`, `SettingsOutput`, `get_default_settings`, `_ensure_option_present`, `_resolve_runtime_timezone`, `get_default_secrets_manager`, `get_settings`, `normalize_settings`, `_load_sensitive_settings`, `settings.copy`, `_write_settings_file`, `reload_settings`, `set_settings`, `initialize_agent`. - Applying settings refreshes active context configs while preserving each subordinate agent's own profile. +- Applying settings starts a deferred `MCPConfig.update(...)` with the current `mcp_servers` string when global MCP server settings change. - Keep request/response, tool, or helper semantics documented here at the same time as source changes. ## Work Guidance diff --git a/tests/test_settings_mcp.py b/tests/test_settings_mcp.py new file mode 100644 index 000000000..e04e96f94 --- /dev/null +++ b/tests/test_settings_mcp.py @@ -0,0 +1,81 @@ +import asyncio +import sys +from pathlib import Path +from types import ModuleType + +PROJECT_ROOT = Path(__file__).resolve().parents[1] +if str(PROJECT_ROOT) not in sys.path: + sys.path.insert(0, str(PROJECT_ROOT)) + +import helpers.settings as settings_module + + +def test_apply_settings_updates_mcp_from_current_settings(monkeypatch): + base_settings = settings_module.get_default_settings() + previous_mcp_servers = '{"mcpServers": {}}' + current_mcp_servers = '{"mcpServers": {"deepwiki": {"url": "https://mcp.deepwiki.com/mcp"}}}' + previous = { + **base_settings, + "mcp_servers": previous_mcp_servers, + "mcp_server_token": "unchanged-token", + } + current = { + **base_settings, + "mcp_servers": current_mcp_servers, + "mcp_server_token": "unchanged-token", + } + received_mcp_servers: list[str] = [] + + class FakeDeferredTask: + def start_task(self, func, *args, **kwargs): + asyncio.run(func(*args, **kwargs)) + return self + + class FakePrintStyle: + def __init__(self, *args, **kwargs): + pass + + def print(self, *args, **kwargs): + pass + + class FakeMCPConfig: + @classmethod + def get_instance(cls): + return cls() + + @classmethod + def update(cls, mcp_servers): + received_mcp_servers.append(mcp_servers) + + def model_dump_json(self): + return "{}" + + agent_stub = ModuleType("agent") + agent_stub.Agent = object + + class FakeAgentContext: + @staticmethod + def all(): + return [] + + agent_stub.AgentContext = FakeAgentContext + + initialize_stub = ModuleType("initialize") + initialize_stub.initialize_agent = lambda override_settings=None: None + + mcp_handler_stub = ModuleType("helpers.mcp_handler") + mcp_handler_stub.MCPConfig = FakeMCPConfig + + monkeypatch.setitem(sys.modules, "agent", agent_stub) + monkeypatch.setitem(sys.modules, "initialize", initialize_stub) + monkeypatch.setitem(sys.modules, "helpers.mcp_handler", mcp_handler_stub) + monkeypatch.setattr(settings_module, "_settings", current) + monkeypatch.setattr(settings_module, "_apply_timezone_setting", lambda *args, **kwargs: None) + monkeypatch.setattr(settings_module.defer, "DeferredTask", FakeDeferredTask) + monkeypatch.setattr(settings_module, "PrintStyle", FakePrintStyle) + monkeypatch.setattr(settings_module.NotificationManager, "send_notification", lambda **kwargs: None) + monkeypatch.setattr(settings_module, "create_auth_token", lambda: "unchanged-token") + + settings_module._apply_settings(previous) + + assert received_mcp_servers == [current_mcp_servers]