Skip to content

[macOS] Commands via invoke_expression require manual Enter in Terminal.app console #38

@davidbordenwi

Description

@davidbordenwi

Environment

  • OS: macOS 15 Sequoia (Intel x86_64)
  • PowerShell: 7.5.2
  • PowerShell.MCP: 1.7.0
  • MCP Client: Claude Code (CLI)
  • PSWSMan: Installed (for PSRemoting to on-prem AD)

Behavior

Commands sent via invoke_expression appear in the Terminal.app console (syntax-highlighted via Write-ColoredCommand) but do not execute until I manually press Enter in Terminal.app. The MCP client blocks waiting for results.

Commands that reliably work: Fast commands sent in rapid succession (e.g., Get-Date, Import-PowerShellDataFile, short .ps1 scripts). These seem to catch a brief window where the main runspace is idle between REPL iterations.

Commands that get stuck: Any command sent after a pause of a few seconds, or longer-running commands like Invoke-Command with PSRemoting. The command text is displayed in Terminal.app but execution does not begin until I press Enter.

Analysis

I extracted the embedded MCPPollingEngine.ps1 from the DLL and traced the execution path:

  1. Command is stored in McpServerHost._executeCommand via the named pipe
  2. The 100ms one-shot timer (AutoReset = $false) fires on a thread pool thread
  3. The Register-ObjectEvent action block is queued for the main runspace
  4. The main runspace is blocked by Console.ReadLine() in the REPL input loop
  5. The event handler cannot execute until ReadLine() returns
  6. Pressing Enter returns from ReadLine(), the event handler fires, and the command executes

I see that the .psm1 already removes PSReadLine on non-Windows (Remove-Module PSReadLine -ErrorAction SilentlyContinue), which addresses the Console.ReadKey() blocking issue documented in PSReadLine#835. However, the built-in PSConsoleHostReadLine still calls Console.ReadLine() which blocks the runspace on macOS/Linux.

Reproduction

  1. Start a PowerShell.MCP session on macOS via start_powershell_console
  2. Run a command via invoke_expression — observe it works (catches the idle window)
  3. Wait 5+ seconds
  4. Run another command via invoke_expression — observe it appears in Terminal.app but does not execute
  5. Press Enter in Terminal.app — command executes and results return to MCP client

Questions

  1. Is the Terminal.app console interaction intentional — i.e., is the expected workflow that the user actively monitors Terminal.app and presses Enter to approve/execute commands?
  2. If not, is there a configuration or workaround to keep the runspace available for timer events while the REPL is idle? For example:
    • A custom PSConsoleHostReadLine that yields periodically
    • Headless mode (v1.6.3 mentions headless/CI support) — would this bypass the REPL blocking?
    • A background runspace for command execution instead of the main runspace
  3. Are other macOS users experiencing this? I couldn't find an existing issue matching this behavior.

Thank you for the excellent tool — just trying to understand the intended workflow on macOS.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions