Skip to content

Linux Terminal Launch Fails: PowerShell Console Closes Immediately Due to Incorrect Shell Quoting #39

@Fabelwesen

Description

@Fabelwesen

🐛 Bug Description

On Linux systems (specifically tested on CachyOS/Arch Linux using KDE Plasma/konsole), the PowerShell.MCP server fails to start the persistent console. When calling start_powershell_console or any tool that triggers auto-start, a terminal window (e.g., konsole) opens for a fraction of a second and closes immediately.

The MCP client reports a Not connected or Failed to start PowerShell console error.


🔍 Root Cause Analysis

The issue lies in the PwshLauncherLinux.cs (or PowerShellProcessManager.cs depending on the version) within the PowerShell.MCP.Proxy project.

The current implementation attempts to launch pwsh via a login shell using the following command structure:

var pwshCommand = $"exec pwsh -NoExit -WorkingDirectory '{workingDir}' -Command ''{initCommand}''";

When this is passed to bash -l -c, the double single quotes ('') are interpreted by Bash as an empty string. This results in several critical failures:

  1. Variable Expansion: Because the command is not effectively quoted, Bash attempts to expand PowerShell variables (like $global:PowerShellMCPProxyPid) as Bash variables. Since they don't exist in the Bash environment, they resolve to empty strings.
  2. Syntax Errors: The resulting command string sent to pwsh is corrupted/empty, causing PowerShell to exit immediately with a syntax error, which in turn closes the terminal window.

💡 Proposed Solution: Base64 EncodedCommand

The most robust way to pass complex initialization commands to PowerShell across different shells (Bash, Zsh, etc.) without hitting quoting or expansion issues is using the -EncodedCommand parameter.

Recommended Change:

In PowerShellProcessManager.cs (Linux launcher section):

  1. Construct the initCommand using standard single quotes.
  2. Encode the command string to a Base64 UTF-16LE string.
  3. Execute pwsh using -EncodedCommand.

Example Implementation (C#):

// 1. Build the command normally (no more double-single-quote escaping needed)
string initCommand = $"$global:PowerShellMCPProxyPid = {proxyPid}; $global:PowerShellMCPAgentId = '{agentId}'; {caseFix}Import-Module PowerShell.MCP -Force; Remove-Module PSReadLine -ErrorAction SilentlyContinue; {startupCommands}";

// 2. Encode to Base64 (UTF-16LE is required for -EncodedCommand)
var initBytes = System.Text.Encoding.Unicode.GetBytes(initCommand);
var encodedCommand = System.Convert.ToBase64String(initBytes);

// 3. Launch with -EncodedCommand
var pwshCommand = $"exec pwsh -NoExit -WorkingDirectory '{workingDir}' -EncodedCommand {encodedCommand}";

🛠️ Additional Minor Fix: Join-Path in caseFix

While debugging, I also encountered an error in the caseFix logic:
Join-Path: Cannot bind argument to parameter 'Path' because it is an empty string.

This happens if the user's $env:PSModulePath contains empty entries (e.g., trailing separators).

Fix: Add a check for null or whitespace before calling Join-Path:

var caseFix = "foreach ($p in ($env:PSModulePath -split [IO.Path]::PathSeparator)) { if ([string]::IsNullOrWhiteSpace($p)) { continue }; $lc = Join-Path $p 'powershell.mcp'; ... }";

✅ Verification

After applying these changes and rebuilding the Proxy, the PowerShell console now starts perfectly and remains stable on Linux (KDE/konsole).

Environment tested:

  • OS: CachyOS (Arch based)
  • Kernel: 6.18.x
  • Desktop: KDE Plasma 6 (Wayland)
  • Terminal: konsole
  • PowerShell: 7.4.x
  • MCP Module: 1.7.0

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