From dfa3fe1857f00339f92f2bd1bd49aae23c813beb Mon Sep 17 00:00:00 2001 From: jiang1997 Date: Sat, 23 May 2026 13:07:02 +0800 Subject: [PATCH] refactor(toolset): always load MCP tools in background Remove the now-redundant in_background option and update callers/tests for the background-only MCP loading flow. --- CHANGELOG.md | 2 ++ docs/en/release-notes/changelog.md | 2 ++ docs/zh/release-notes/changelog.md | 2 ++ src/kimi_cli/soul/agent.py | 2 +- src/kimi_cli/soul/toolset.py | 33 +++++++++++------------------- tests/cli/test_mcp_oauth.py | 3 ++- tests/core/test_load_agent.py | 13 ++++++------ 7 files changed, 28 insertions(+), 29 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 881d674dd..f3cae4b1f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ Only write entries that are worth mentioning to users. ## Unreleased +- MCP: Switch MCP tool loading to a background-only flow — `KimiToolset.load_mcp_tools()` no longer accepts `in_background`; await `wait_for_mcp_tools()` to observe connection failures + ## 1.44.0 (2026-05-13) - Shell: Add slash command alias resolution — aliases such as `/h`, `?`, and `status` now resolve to their canonical commands (`/help`, `/usage`); the completer and help output display alias matches as `/name (alias)` for clarity diff --git a/docs/en/release-notes/changelog.md b/docs/en/release-notes/changelog.md index b1a0e670a..ddf923777 100644 --- a/docs/en/release-notes/changelog.md +++ b/docs/en/release-notes/changelog.md @@ -4,6 +4,8 @@ This page documents the changes in each Kimi Code CLI release. ## Unreleased +- MCP: Switch MCP tool loading to a background-only flow — `KimiToolset.load_mcp_tools()` no longer accepts `in_background`; await `wait_for_mcp_tools()` to observe connection failures + ## 1.44.0 (2026-05-13) - Shell: Add slash command alias resolution — aliases such as `/h`, `?`, and `status` now resolve to their canonical commands (`/help`, `/usage`); the completer and help output display alias matches as `/name (alias)` for clarity diff --git a/docs/zh/release-notes/changelog.md b/docs/zh/release-notes/changelog.md index 731435225..f050757cd 100644 --- a/docs/zh/release-notes/changelog.md +++ b/docs/zh/release-notes/changelog.md @@ -4,6 +4,8 @@ ## 未发布 +- MCP:将 MCP 工具加载切换为仅后台执行的流程——`KimiToolset.load_mcp_tools()` 不再接受 `in_background`;如需观察连接失败,请等待 `wait_for_mcp_tools()` + ## 1.44.0 (2026-05-13) - Shell:新增斜杠命令别名解析——别名(如 `/h`、`?`、`status`)现在能正确解析到对应的正式命令(`/help`、`/usage`);补全器和帮助输出会将别名匹配项显示为 `/name (alias)`,方便识别 diff --git a/src/kimi_cli/soul/agent.py b/src/kimi_cli/soul/agent.py index a208e0879..211fe035d 100644 --- a/src/kimi_cli/soul/agent.py +++ b/src/kimi_cli/soul/agent.py @@ -479,7 +479,7 @@ async def load_agent( except pydantic.ValidationError as e: raise MCPConfigError(f"Invalid MCP config: {e}") from e if start_mcp_loading: - await toolset.load_mcp_tools(validated_mcp_configs, runtime, in_background=True) + await toolset.load_mcp_tools(validated_mcp_configs, runtime) else: toolset.defer_mcp_tool_loading(validated_mcp_configs, runtime) diff --git a/src/kimi_cli/soul/toolset.py b/src/kimi_cli/soul/toolset.py index 3868d3bdb..0f85dde59 100644 --- a/src/kimi_cli/soul/toolset.py +++ b/src/kimi_cli/soul/toolset.py @@ -464,7 +464,7 @@ async def start_deferred_mcp_tool_loading(self) -> bool: mcp_configs, runtime = self._deferred_mcp_load self._deferred_mcp_load = None - await self.load_mcp_tools(mcp_configs, runtime, in_background=True) + await self.load_mcp_tools(mcp_configs, runtime) return True def load_tools(self, tool_paths: list[str], dependencies: dict[type[Any], Any]) -> None: @@ -527,16 +527,11 @@ def _load_tool(tool_path: str, dependencies: dict[type[Any], Any]) -> ToolType | args.append(dependencies[param.annotation]) return tool_cls(*args) - # TODO(rc): remove `in_background` parameter and always load in background - async def load_mcp_tools( - self, mcp_configs: list[MCPConfig], runtime: Runtime, in_background: bool = True - ) -> None: + async def load_mcp_tools(self, mcp_configs: list[MCPConfig], runtime: Runtime) -> None: """ - Load MCP tools from specified MCP configs. + Start MCP tool loading in the background. - Raises: - MCPRuntimeError(KimiCLIException, RuntimeError): When any MCP server cannot be - connected. + Await wait_for_mcp_tools() to observe connection failures. """ import fastmcp from fastmcp.mcp_config import MCPConfig, RemoteMCPServer @@ -549,14 +544,13 @@ async def _check_oauth_tokens(server_url: str) -> bool: return await has_mcp_oauth_tokens(server_url) def _toast_mcp(message: str) -> None: - if in_background: - toast( - message, - duration=10.0, - topic="mcp", - immediate=True, - position="right", - ) + toast( + message, + duration=10.0, + topic="mcp", + immediate=True, + position="right", + ) def _mark_oauth_unauthorized(server_name: str) -> None: logger.warning( @@ -649,10 +643,7 @@ async def _connect(): status="pending", client=client, tools=[] ) - if in_background: - self._mcp_loading_task = asyncio.create_task(_connect()) - else: - await _connect() + self._mcp_loading_task = asyncio.create_task(_connect()) def has_pending_mcp_tools(self) -> bool: """Return True if the background MCP tool-loading task is still running.""" diff --git a/tests/cli/test_mcp_oauth.py b/tests/cli/test_mcp_oauth.py index 9d4a29caa..e9ab68e66 100644 --- a/tests/cli/test_mcp_oauth.py +++ b/tests/cli/test_mcp_oauth.py @@ -105,7 +105,8 @@ async def test_load_mcp_tools_treats_unreadable_oauth_storage_as_unauthorized( } ) - await toolset.load_mcp_tools([mcp_config], runtime, in_background=False) + await toolset.load_mcp_tools([mcp_config], runtime) + await toolset.wait_for_mcp_tools() snapshot = toolset.mcp_status_snapshot() assert snapshot is not None diff --git a/tests/core/test_load_agent.py b/tests/core/test_load_agent.py index 5032043c0..9c4daf9f9 100644 --- a/tests/core/test_load_agent.py +++ b/tests/core/test_load_agent.py @@ -214,11 +214,12 @@ async def test_load_agent_registers_builtin_subagent_types(runtime: Runtime): assert builtin_type.agent_file.samefile(builtin_type_yaml) -async def test_load_agent_starts_mcp_in_background(runtime: Runtime, monkeypatch): - called: dict[str, bool] = {} +async def test_load_agent_starts_mcp_loading_by_default(runtime: Runtime, monkeypatch): + load_called = False - async def fake_load_mcp_tools(self, mcp_configs, runtime, in_background: bool = True): - called["in_background"] = in_background + async def fake_load_mcp_tools(self, mcp_configs, runtime): + nonlocal load_called + load_called = True monkeypatch.setattr(KimiToolset, "load_mcp_tools", fake_load_mcp_tools) @@ -234,13 +235,13 @@ async def fake_load_mcp_tools(self, mcp_configs, runtime, in_background: bool = await load_agent(agent_yaml, runtime, mcp_configs=[{"mcpServers": {}}]) - assert called == {"in_background": True} + assert load_called is True async def test_load_agent_can_defer_mcp_loading(runtime: Runtime, monkeypatch): called: dict[str, bool] = {} - async def fake_load_mcp_tools(self, mcp_configs, runtime, in_background: bool = True): + async def fake_load_mcp_tools(self, mcp_configs, runtime): called["load_called"] = True def fake_defer_mcp_tool_loading(self, mcp_configs, runtime):