-
Notifications
You must be signed in to change notification settings - Fork 4
Description
🐛 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:
- 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. - Syntax Errors: The resulting command string sent to
pwshis 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):
- Construct the
initCommandusing standard single quotes. - Encode the command string to a Base64 UTF-16LE string.
- Execute
pwshusing-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