Skip to content

fix(powershell): add timeout + shared self-healing instance - #3

Open
cyytmd wants to merge 1 commit into
gunjanjp:masterfrom
cyytmd:master
Open

cyytmd wants to merge 1 commit into
gunjanjp:masterfrom
cyytmd:master

Conversation

@cyytmd

@cyytmd cyytmd commented Sep 15, 2026

Copy link
Copy Markdown

What

Replaces the per-command new PowerShell() + ps.dispose() pattern with a shared, self-healing PowerShellManager singleton.

Why

The original code creates and destroys a powershell.exe child process on every tool call (~0.5 s each) and never sets invocationTimeout on node-powershell. A command that hangs the shell (e.g. Format-Table -AutoSize probing terminal width in a non-interactive stdio pipe) freezes the MCP server forever — the 30 s client timeout fires, but the server-side promise never resolves, poisoning every subsequent call.

Changes

What How
src/utils/powershell-manager.js New. Shared singleton: reuses one powershell.exe, enforces 25 s invocation timeout (child-shell built-in), rebuilds the instance after timeout/fatal error, truncates output at 100 KB, serializes access with a lock, tears down cleanly on SIGINT/SIGTERM.
src/tools/powershell-tools.js Removes createPowerShellInstance() + per-call try/catch/dispose. Delegates to psManager.execute().
src/tools/system-tools.js Same — thin wrapper over psManager.execute().
src/tools/file-tools.js Same — thin wrapper over psManager.execute().
src/server.js Imports psManager; registers SIGINT/SIGTERM handlers for graceful teardown.

Tested

  • Write-Output / Get-Date — instant return (singleton, no spawn overhead).
  • Get-Process | Select ... | Format-Table -AutoSize — the exact command that previously froze the server indefinitely now returns within 1 s.
  • ✅ Repeated calls — no leaked processes, no stream corruption.

Prevent commands from hanging the MCP server indefinitely and speed up
repeated calls by reusing a single powershell.exe instead of spawning
one per command.

- Add shared PowerShellManager singleton (src/utils/powershell-manager.js)
- Enforce 25s invocation timeout via child-shell's built-in escape hatch
- Rebuild the instance after a timeout or fatal error (self-healing)
- Isolate workingDirectory with Push-Location/Pop-Location
- Truncate oversized output at 100KB
- Serialize access with a lock; graceful teardown on SIGINT/SIGTERM
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant