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.
Alessandro committed
Jun 22, 2026 at 10:25 UTC
6dcaab2f5c58b531d1349b12e332001b55e63136
3 files changed
+83
-1
helpers/settings.py
+1
-1
@@ -648,7 +648,7 @@ def _apply_settings(previous: Settings | None, browser_timezone: str | None = No
648
)
649
650
task2 = defer.DeferredTask().start_task(
651
- update_mcp_settings, config.mcp_servers
651
+ update_mcp_settings, _settings["mcp_servers"]
652
) # TODO overkill, replace with background task
653
654
# update token in mcp server
helpers/settings.py.dox.md
+1
@@ -63,6 +63,7 @@
63
64
- 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`.
65
- Applying settings refreshes active context configs while preserving each subordinate agent's own profile.
66
+- Applying settings starts a deferred `MCPConfig.update(...)` with the current `mcp_servers` string when global MCP server settings change.
67
- Keep request/response, tool, or helper semantics documented here at the same time as source changes.
68
69
## Work Guidance
tests/test_settings_mcp.py
new
+81
@@ -0,0 +1,81 @@
1
+import asyncio
2
+import sys
3
+from pathlib import Path
4
+from types import ModuleType
5
+
6
+PROJECT_ROOT = Path(__file__).resolve().parents[1]
7
+if str(PROJECT_ROOT) not in sys.path:
8
+ sys.path.insert(0, str(PROJECT_ROOT))
9
+
10
+import helpers.settings as settings_module
11
+
12
+
13
+def test_apply_settings_updates_mcp_from_current_settings(monkeypatch):
14
+ base_settings = settings_module.get_default_settings()
15
+ previous_mcp_servers = '{"mcpServers": {}}'
16
+ current_mcp_servers = '{"mcpServers": {"deepwiki": {"url": "https://mcp.deepwiki.com/mcp"}}}'
17
+ previous = {
18
+ **base_settings,
19
+ "mcp_servers": previous_mcp_servers,
20
+ "mcp_server_token": "unchanged-token",
21
+ }
22
+ current = {
23
+ **base_settings,
24
+ "mcp_servers": current_mcp_servers,
25
+ "mcp_server_token": "unchanged-token",
26
+ }
27
+ received_mcp_servers: list[str] = []
28
+
29
+ class FakeDeferredTask:
30
+ def start_task(self, func, *args, **kwargs):
31
+ asyncio.run(func(*args, **kwargs))
32
+ return self
33
+
34
+ class FakePrintStyle:
35
+ def __init__(self, *args, **kwargs):
36
+ pass
37
+
38
+ def print(self, *args, **kwargs):
39
+ pass
40
+
41
+ class FakeMCPConfig:
42
+ @classmethod
43
+ def get_instance(cls):
44
+ return cls()
45
+
46
+ @classmethod
47
+ def update(cls, mcp_servers):
48
+ received_mcp_servers.append(mcp_servers)
49
+
50
+ def model_dump_json(self):
51
+ return "{}"
52
+
53
+ agent_stub = ModuleType("agent")
54
+ agent_stub.Agent = object
55
+
56
+ class FakeAgentContext:
57
+ @staticmethod
58
+ def all():
59
+ return []
60
+
61
+ agent_stub.AgentContext = FakeAgentContext
62
+
63
+ initialize_stub = ModuleType("initialize")
64
+ initialize_stub.initialize_agent = lambda override_settings=None: None
65
+
66
+ mcp_handler_stub = ModuleType("helpers.mcp_handler")
67
+ mcp_handler_stub.MCPConfig = FakeMCPConfig
68
+
69
+ monkeypatch.setitem(sys.modules, "agent", agent_stub)
70
+ monkeypatch.setitem(sys.modules, "initialize", initialize_stub)
71
+ monkeypatch.setitem(sys.modules, "helpers.mcp_handler", mcp_handler_stub)
72
+ monkeypatch.setattr(settings_module, "_settings", current)
73
+ monkeypatch.setattr(settings_module, "_apply_timezone_setting", lambda *args, **kwargs: None)
74
+ monkeypatch.setattr(settings_module.defer, "DeferredTask", FakeDeferredTask)
75
+ monkeypatch.setattr(settings_module, "PrintStyle", FakePrintStyle)
76
+ monkeypatch.setattr(settings_module.NotificationManager, "send_notification", lambda **kwargs: None)
77
+ monkeypatch.setattr(settings_module, "create_auth_token", lambda: "unchanged-token")
78
+
79
+ settings_module._apply_settings(previous)
80
+
81
+ assert received_mcp_servers == [current_mcp_servers]