Skip to content

Windows: taskkill output leaks into TUI when terminating stdio MCP subprocesses #20869

@EurekaMXZ

Description

@EurekaMXZ

What version of Codex CLI is running?

codex-cli 0.128.0

What subscription do you have?

ChatGPT Pro 20x

Which model were you using?

gpt-5.4

What platform is your computer?

Microsoft Windows NT 10.0.26200.0 x64

What terminal emulator and version are you using (if applicable)?

Windows Terminal

What issue are you seeing?

On Windows, when Codex shuts down a stdio-based MCP subprocess, it appears to terminate the process tree by invoking taskkill. The taskkill command prints status messages such as:

SUCCESS: The process with PID 33216 (child process of PID 27200) has been terminated.

This output is written directly into the terminal and visually corrupts the Codex TUI.

Image Image

What steps can reproduce the bug?

  1. Configure or start a stdio-based MCP server/subagent in Codex on Windows.
  2. Enter Codex TUI.
  3. Trigger shutdown of the MCP subprocess, for example by closing the subagent or exiting Codex.
  4. Observe that Windows taskkill output is printed into the terminal/TUI.

What is the expected behavior?

Terminating stdio MCP subprocesses should be silent from the TUI user's perspective. Cleanup output from platform-specific process termination helpers should not be written to the TUI terminal.

Additional information

Relevant code:

The Windows termination path currently appears to invoke taskkill without redirecting its stdio, see codex-rs/rmcp-client/src/stdio_server_launcher.rs:

#[cfg(windows)]
fn terminate(&self) {
    let _ = std::process::Command::new("taskkill")
        .arg("/PID")
        .arg(self.pid.to_string())
        .arg("/T")
        .arg("/F")
        .status();
}

Since no stdio is specified, taskkill inherits Codex's stdout/stderr. As a result, taskkill status messages are printed directly into the terminal used by the TUI.

Possible fix:

Redirect the taskkill process stdio to null:

#[cfg(windows)]
fn terminate(&self) {
    use std::process::{Command, Stdio};

    let _ = Command::new("taskkill")
        .arg("/PID")
        .arg(self.pid.to_string())
        .arg("/T")
        .arg("/F")
        .stdin(Stdio::null())
        .stdout(Stdio::null())
        .stderr(Stdio::null())
        .status();
}

Optionally, also set CREATE_NO_WINDOW on Windows:

#[cfg(windows)]
fn terminate(&self) {
    use std::os::windows::process::CommandExt;
    use std::process::{Command, Stdio};

    const CREATE_NO_WINDOW: u32 = 0x08000000;

    let _ = Command::new("taskkill")
        .arg("/PID")
        .arg(self.pid.to_string())
        .arg("/T")
        .arg("/F")
        .stdin(Stdio::null())
        .stdout(Stdio::null())
        .stderr(Stdio::null())
        .creation_flags(CREATE_NO_WINDOW)
        .status();
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    CLIIssues related to the Codex CLITUIIssues related to the terminal user interface: text input, menus and dialogs, and terminal displaybugSomething isn't workingmcpIssues related to the use of model context protocol (MCP) serverswindows-osIssues related to Codex on Windows systems

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions