Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions docs/en/release-notes/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions docs/zh/release-notes/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)`,方便识别
Expand Down
2 changes: 1 addition & 1 deletion src/kimi_cli/soul/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
33 changes: 12 additions & 21 deletions src/kimi_cli/soul/toolset.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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
Expand All @@ -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(
Expand Down Expand Up @@ -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."""
Expand Down
3 changes: 2 additions & 1 deletion tests/cli/test_mcp_oauth.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
13 changes: 7 additions & 6 deletions tests/core/test_load_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand All @@ -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):
Expand Down
Loading