diff --git a/CHANGELOG.md b/CHANGELOG.md index 745066e7d..6b79dec7d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ Only write entries that are worth mentioning to users. ## Unreleased +- Core: Fix MCP server stderr pollution — stderr redirection is now installed before MCP servers start, so subprocess logs (e.g., OAuth debug output from `mcp-remote`) are captured into the log file instead of being printed to the terminal - Shell: Fix subprocess hang on interactive prompts — the `Shell` tool now closes stdin immediately and sets `GIT_TERMINAL_PROMPT=0` so commands that require credentials (e.g. `git push` over HTTPS) fail fast instead of blocking until timeout - Core: Fix JSON parsing error when LLM tool call arguments contain unescaped control characters — use `json.loads(strict=False)` across all LLM output parsing paths to prevent tool execution failure and session corruption - Shell: Auto-trigger agent when background tasks complete while idle — the shell now detects when a background bash command or agent task finishes and automatically starts a new agent turn to process the results, instead of waiting for the user to type something diff --git a/docs/en/release-notes/changelog.md b/docs/en/release-notes/changelog.md index d56f8f666..675f7bdf1 100644 --- a/docs/en/release-notes/changelog.md +++ b/docs/en/release-notes/changelog.md @@ -4,6 +4,7 @@ This page documents the changes in each Kimi Code CLI release. ## Unreleased +- Core: Fix MCP server stderr pollution — stderr redirection is now installed before MCP servers start, so subprocess logs (e.g., OAuth debug output from `mcp-remote`) are captured into the log file instead of being printed to the terminal - Shell: Fix subprocess hang on interactive prompts — the `Shell` tool now closes stdin immediately and sets `GIT_TERMINAL_PROMPT=0` so commands that require credentials (e.g. `git push` over HTTPS) fail fast instead of blocking until timeout - Core: Fix JSON parsing error when LLM tool call arguments contain unescaped control characters — use `json.loads(strict=False)` across all LLM output parsing paths to prevent tool execution failure and session corruption - Shell: Auto-trigger agent when background tasks complete while idle — the shell now detects when a background bash command or agent task finishes and automatically starts a new agent turn to process the results, instead of waiting for the user to type something diff --git a/docs/zh/release-notes/changelog.md b/docs/zh/release-notes/changelog.md index 68942c798..dca3b65bd 100644 --- a/docs/zh/release-notes/changelog.md +++ b/docs/zh/release-notes/changelog.md @@ -4,6 +4,7 @@ ## 未发布 +- Core:修复 MCP 服务器 stderr 污染问题——stderr 重定向现在在 MCP 服务器启动前安装,子进程日志(如 `mcp-remote` 的 OAuth 调试输出)将被捕获到日志文件,而非输出到终端 - Shell:修复子进程遇到交互式提示时挂起的问题——`Shell` 工具现在会立即关闭 stdin 并设置 `GIT_TERMINAL_PROMPT=0`,使需要凭证的命令(如通过 HTTPS 执行 `git push`)快速失败,而非阻塞至超时 - Core:修复 LLM 工具调用参数包含未转义控制字符时 JSON 解析失败的问题——在所有 LLM 输出解析路径使用 `json.loads(strict=False)`,防止工具执行失败和会话永久损坏 - Shell:空闲时自动响应后台任务完成——Shell 现在会检测后台 Bash 命令或 Agent 任务的完成,并自动发起新的 Agent 轮次处理结果,无需等待用户输入 diff --git a/src/kimi_cli/cli/__init__.py b/src/kimi_cli/cli/__init__.py index 9fbf83cb5..fc93eb70d 100644 --- a/src/kimi_cli/cli/__init__.py +++ b/src/kimi_cli/cli/__init__.py @@ -337,9 +337,10 @@ def kimi( from .mcp import get_global_mcp_config_file - # Don't redirect stderr yet. Our stderr redirector replaces fd=2 with a pipe, which - # would swallow Click/Typer startup errors (e.g. config parsing / BadParameter). - # We re-enable stderr redirection after KimiCLI.create() succeeds. + # Don't redirect stderr during argument parsing. Our stderr redirector + # replaces fd=2 with a pipe, which would swallow Click/Typer startup errors. + # Redirection is installed later, right before KimiCLI.create(), so that + # MCP server stderr noise is captured into logs from the start. enable_logging(debug, redirect_stderr=False) def _emit_fatal_error(message: str) -> None: @@ -526,6 +527,15 @@ async def _run(session_id: str | None) -> tuple[Session, bool]: if changed: session.save_state() + # Redirect stderr *before* KimiCLI.create() so that MCP server + # subprocesses (e.g. mcp-remote OAuth debug logs) write to the log + # file instead of polluting the user's terminal. CLI argument + # parsing has already succeeded at this point, so Typer/Click + # startup errors are no longer a concern. Fatal errors from + # create() are still visible because _emit_fatal_error() writes to + # the saved original stderr fd. + redirect_stderr_to_logger() + instance = await KimiCLI.create( session, config=config, @@ -542,10 +552,6 @@ async def _run(session_id: str | None) -> tuple[Session, bool]: defer_mcp_loading=ui == "shell" and prompt is None, ) startup_progress.stop() - - # Install stderr redirection only after initialization succeeded, so runtime - # stderr noise is captured into logs without hiding startup failures. - redirect_stderr_to_logger() preserve_background_tasks = False try: match ui: