All notable changes to PowerShell.MCP are documented here. Each release is
grouped under a # Version: X.Y.Z heading, newest first. Releases earlier than
1.7.7 are listed on the
GitHub Releases page.
canceltool — stops whatever command is currently running in the agent's active console. It ends a runaway or long-running PowerShell command (Start-Sleep, a loop, a slow cmdlet), and sends Ctrl+C to break out of a native CLI that is looping or waiting for input (git/npm/ssh/ping). A command that is stuck in an operation that can't be interrupted (e.g.[Threading.Thread]::Sleep, a blocking socket or file read) may not stop — useclose_console. A PowerShell prompt waiting for you to type something (Read-Host, a missing required parameter,Get-Credential) also can't be canceled — answer it at the console or useclose_console. The console itself stays alive and ready for the next command.close_consoletool — terminates a session-owned console by PID; use it to abandon a console stuck on a host prompt that cannot be answered programmatically.
- The
invoke_expressionMCP tool is renamed toexecute_command. The old name implied theInvoke-Expressioncmdlet (which the tool never actually used) and tripped AMSI / antivirus security heuristics. Behavior and thepipelineparameter are unchanged. Migration: if you pinned the tool in an MCP permission allowlist (e.g.mcp__PowerShell__invoke_expression), update it toexecute_command. - Interactive prompts no longer wedge the console. When an AI-run command hits a PowerShell host prompt (
Read-Host, a missing mandatory parameter,Get-Credential, a confirmation), control returns to the AI immediately instead of waiting out the full timeout, with guidance to answer at the console or close it. The command stays blocked so a human can still answer at the terminal.
- The console reacts almost instantly when its AI session goes away. When the AI process that owns a console exits (you close the client, it crashes, or the session ends), the console now shows the "AI session disconnected" notice and clears its
#PID ____title within ~100ms instead of taking up to ~5s. It reacts to the process actually exiting rather than waiting for the next slow health-check poll. - File edits no longer fail across drives, and keep the right permissions (#51).
Add-LinesToFile,Update-LinesInFile,Update-MatchInFile, andRemove-LinesFromFilenow write their temporary file in the same folder as the file being edited. This keeps the final swap a rename within one drive — fixing the "not same device" failure that happened when the temp file landed on a different drive — and lets a newly created file inherit its folder's permissions.
- Completed the
execute_commandrename through the Named Pipe wire protocol, DTOs, and handlers (previously only the MCP tool surface was renamed). - Translated the remaining Japanese documentation and test names/comments to English.
Restart-MCPServercommand to retry starting the console engine in the affected console — no need to restart PowerShell.
- Resume-safe console handling (new server session). On the proxy's first console attach after a (re)start — the resume / cold-start boundary, where the runtime is fresh but the AI still carries cwd/variable/module assumptions from earlier in the conversation —
invoke_expressionnormalizes the working directory to$HOMEand announces a new server session (with a one-line restore hint for a reclaimed console's prior cwd), whileget_current_location/start_consolepreserve the console's current cwd and only announce. This stops a resumed session from silently running at an unexpected cwd or relying on state that didn't carry over. - Reuse-first console acquisition. Without a
reason,start_consolenow reclaims any available console — an owned standby or an unowned one (a prior session's released console, or a user-started one) — and only launches a new window when nothing is available. Previously an unowned console was reclaimed only whenstart_locationwas given; that guard is gone (the new-session normalization above handles the cwd concern), so the desktop no longer fills with console windows.
- Reduced an AMSI / antivirus false positive that could block startup (#50). The embedded polling engine no longer uses
Invoke-Expression. Its three call sites only wrapped literal strings (cmdlet/type resolution is already deferred to runtime, and each was insidetry/catch), so they added nothing but the single highest-weighted AMSI heuristic token — which helped the engine script get flagged as malicious atImport-Module. They are now direct calls; the engine contains zeroInvoke-Expression. - No more spurious "cwd changed" warnings caused by the AI's own work. A directory change left by an AI command (including one harvested in the background via
wait_for_completion) is now recorded, so the next command no longer misreads it as a user-typedcd. Paths that differ only by a trailing separator (C:\projvsC:\proj\) no longer trip a false drift warning either. - A disconnected AI session no longer leaks its output to the next one. When the owning AI goes away, the console discards its undrained cached output and returns to a clean
standbystate, so a freshly-connecting AI can't drain the previous session's results. - Fixed a possible
NullReferenceExceptionwhen resolving a console's display name while no pipe was active.
- Graceful degradation when the engine is blocked at startup. If an antivirus/AMSI scan blocks the embedded engine during
Import-Module(often transient), the module now stays loaded and emits one actionable warning instead of failing with a bare error. While the engine is down, commands fast-fail with guidance (runRestart-MCPServer) instead of hanging until the request times out. - A green
AI session connected.line is now shown when the AI claims or spawns a console — the visible counterpart to the yellowAI session disconnectednotice. Get-MCPOwnerandRestart-MCPServershare onePowerShell.MCP.Statusoutput type with identical columns (EngineReady / Owned / ProxyPid / AgentId / ClientName / LastError).
- Hardened console launching: the Windows init command is built from the shared helper (escaping the agent id like the other platforms), console-readiness checks go through a single
PipeStatus.IsReadydefinition, and dead launcher code was removed. - Release safety gates: tagged releases now run the full unit suite (net8.0 + net9.0) and an
Import-Modulesmoke test of the assembled package before publishing to PSGallery; a missing CHANGELOG section fails fast; PRs are gated and the polling engine is checked to stay free ofInvoke-Expression(the #50 regression guard). - Expanded automated tests: multi-console identity/routing, per-agent isolation, cross-AI console visibility (via real named pipes), cwd-drift detection and normalization, the resume / first-attach new-session treatment, and engine graceful-degradation.
--no-profileflag for lean interactive consoles (#49, thanks @sharpninja). Pass--no-profilein the MCP server'sargsand the interactive launchers (Windows / macOS / Linux) start pwsh with-NoProfile, skipping the user's$PROFILE(prompt, aliases, PSReadLine, theme). Default off — those consoles are real human-facing shells, so the profile loads unless the operator opts out. One line in the client config makes every console the server launches lean.
- The headless / CI launcher always starts pwsh with
-NoProfile, independent of the--no-profileflag. It only runs when no terminal emulator is available — no window, stdout redirected — so there is no interactive experience to preserve, and a profile there only adds nondeterminism, startup latency, and the risk of blocking on input (e.g.Read-Host) in a process with no console.
- Launcher command-line construction is centralized in shared per-platform
Build*helpers (#49);-NoProfileis emitted from a singlenoProfile-gated point per interactive platform, covered by unit tests for both flag states plus the always-on headless path.
AI working-directory tracking now follows Set-Location correctly, and the elevation consent prompt is gone. Pre-1.9 the DLL tracked the OS process cwd, but PowerShell's Set-Location moves only $PWD / the PSDrive — so once the AI cd'd anywhere, cwd tracking was silently pinned to the startup directory, and busy-route / auto-start spawned new consoles at $HOME instead of resuming the AI's workspace. That tracking is now correct. Separately, the sudo / runas / gsudo Y/N consent prompt has been removed (#48) — it blocked unattended use, was never a real security boundary, and PowerShell.MCP's safety model is the visible, human-watched console.
- Removed the
sudo/runas/gsudoelevation consent prompt (#48). TheRead-HostY/N gate hung with no human to answer under unattended / SSH-admin use, and was never a real security boundary: any startup-read flag is settable by the agent itself and inherited by a freshly spawned console, so the gate never actually contained a misaligned agent. PowerShell.MCP's real safety model is the visible, human-watched console; singling out elevation was arbitrary, and the matching regex also misfired on incidental mentions ofsudo.
- PSDrive-aware working-directory tracking. The DLL now captures
$PWDon the polling engine's home thread (instead of the OS process cwd, whichSet-Locationnever updates) and uses it for every cwd-emitting response — busy, status, and post-execution success / timeout / completed. Busy-route and auto-start now resume the AI's actual workspace instead of$HOME. User-cddrift between AI calls is handled safety-first: the proxy returns aPipeline NOT executednotice carrying prev → new cwd and a single-quote-escapedSet-Locationrevert hint, rather than silently auto-cd'ing.
- Tab-completion menus no longer mojibake on CJK Windows. Consoles created via
CREATE_NEW_CONSOLEinherited the system code page (932 / 936 / 949 on JP / CN / KR Windows). A shared encoding prelude now runschcp 65001plus the[Console]::*Encodingsets before PSReadLine loads, so e.g. Japanese asset names render cleanly in aGet-OrchAsset <Tab>menu. - Sub-agents no longer lose their
🔑 agent_idnotice. The notice — a freshly allocated sub-agent's only way to learn its own ID — was emitted on just a few return paths; a sub-agent whose first call landed on a timeout / cached / error / drift-bail branch could lose its ID forever. Every return now routes through one helper that prepends the notice exactly when the ID was newly allocated. Remove-LinesFromFilepreserves the trailing newline when the last line is removed. Deleting the final line of a file with a CRLF tail previously dropped the tail.-Encoding gb18030no longer collapses to GB2312. GB18030 (CP 54936) is a 4-byte Unicode superset; it was aliased to CP 936 (GBK), which silently substituted out-of-GBK 4-byte CJK characters with?. It now resolves to CP 54936.- Regex display and combined
-Contains -Patternmatching corrected.Update-MatchInFileregex mode now expands$1/$2capture-group references in the AI-visible display (the written file and-WhatIfpath were already correct).Show-TextFilesandRemove-LinesFromFilenow wrap each side of the combinedContains | Patternregex in a non-capturing group, so a Pattern with top-level alternation or a{0,3}-style quantifier no longer matches every line. - Proxy-liveness poll no longer leaks process handles.
GetProcessByIdreturns aProcessholding an OS handle; it is now disposed on every ~5 s poll instead of waiting on the GC finalizer.
- Full-codebase review cleanup: removed an unreachable prompt-localization overload (
WithLocalizedPromptsFromAssembly+LocalizedParameterNameAttribute), dead helpers, stale comments, a doc-comment segment-count error, and a literal typo — no behavior change. - Test / CI reliability: each test instance now allocates a unique sub-agent id to deflake parallel xunit runs; the Linux Named-Pipe integration test was updated for the same-call switch-and-execute shape; the CwdDrift revert-hint assertion was made platform-agnostic.
- Dropped the orphan
dist/PowerShell.MCP.psm1snapshot and added an explicitdist/gitignore rule —Staging/is the only module source.
Verbose / Debug / native exe stderr are now visible to the AI. Pre-1.8 the tool description explicitly told you "Verbose and Debug streams are NOT visible to you" and native exe stderr (e.g. cmd /c '... 1>&2') was effectively swallowed. They now appear in the AI response in the same time-ordered position as everything else — closing the AI's biggest documented blind spot in the Output→Error→Warning→Verbose→Debug capture surface.
- Hybrid stream capture: chronological pipeline replaces bucketed sections. Output, Error, Warning, Verbose, and Debug records now interleave in a single time-ordered text block in the AI response — the AI sees each event in its actual position relative to surrounding output. Pre-1.8 the four separate
=== ERRORS ===/=== WARNINGS ===etc. sections lost the "warning fired between step-A and step-B, then the error hit" context. - Five output channels that used to bypass the AI's view are now captured:
Write-Verbose(was the AI's blind spot that the tool description explicitly called out as "Verbose and Debug streams are NOT visible to you").Write-Debug(same).[Console]::WriteLine/[Console]::Error.WriteLinedirect writes (and any .NET interop that writes toSystem.Consolewithout going through PowerShell streams) → new=== CONSOLE.OUT (direct) ===/=== CONSOLE.ERR (direct) ===sections.- Native exe stderr (
cmd /c "..."-style) → ErrorRecord in the chronological pipeline, in emit order alongside surrounding output. What if:text from$PSCmdlet.ShouldProcessand direct$Host.UI.WriteLinecalls → new=== HOST.UI (direct) ===section.
- Auto-route on busy console. When
invoke_expressionfinds the chosen PowerShell console busy with a user-typed or another AI command, the proxy now spawns a new console at the source's cwd and re-runs the pipeline there in the same tool call. Pre-1.8 the AI gotPipeline NOT executed - verify location and re-executeand had to re-send manually with whatever cwd they wanted, costing two MCP round-trips for every busy race. LastExit: Nstatus-line tag surfaces the case where a pipeline overall succeeded ($?is true) but a native exe within it returned non-zero. The green ✓ badge no longer silently hides those signals.
get_current_locationnow sets the window title when it claims an unowned console. Pre-fix, an AI whose first tool call wasget_current_location(instead ofinvoke_expressionorstart_console, both of which already handled this) left the user's pre-existingImport-Module PowerShell.MCPconsole with the placeholder title#PID ____until some later tool call redrew it. Symptom appeared intermittently depending on which tool the AI happened to call first.
- Real-time streaming preserved through the new capture wiring — items render to the visible console as they arrive, not collected and rendered after the pipeline finishes.
- Color preserved on the visible console for every stream type: red
Write-Error, yellowWARNING:, yellowVERBOSE:/DEBUG:prefixes, andWrite-Host's user-chosenForegroundColor. Write-Progresskeeps rendering on the visible console for AI-initiated commands (Compress-Archive,Invoke-WebRequest, etc.) so the user can watch progress. Each redraw of pwsh 7's "Minimal" Progress view also writes the bar text toConsole.Out; the polling engine recognizes those overlay blocks by their reverse-video bracketed-status framing — an ANSI SGR escape, then[, then a reverse-video toggle (ESC[7m…ESC[27m), then]and reset (ESC[0m) — and strips them from the captured=== CONSOLE.OUT (direct) ===buffer before surfacing to the AI, so the response stays clean.
- New
TeeTextWriterfor[Console]::Out/[Console]::Errortee, written to in parallel with the original streams so visible-console output is unaffected. - New
TeePSHostUserInterfacedecorator wrapping$Host.UI(reflected swap on_externalUI) for host-UI-level capture ofWrite/WriteLinepaths that bypass both PowerShell streams and[Console]::Out. - Stream merge map widened to
2>&1 3>&1 4>&1 5>&1. Stream 6 (Information) remains unmerged soWrite-Host's user-chosenForegroundColorsurvives to the visible console. - Single shared
BuildInitCommandnow drives the PowerShell init script for every non-Windows launcher (macOS tempFile, Linux Base64-encoded terminal launch, Linux headless ArgumentList path). Each platform keeps its own delivery mechanism for documented reasons — AppleScript echo on macOS, multi-shell quoting on Linux — but the script body and its single-quote escaping are now built in one place. xUnit pins the escaping for every platform that calls the helper.
- Authenticode-signed Windows binaries (
PowerShell.MCP.dll,bin/win-x64/PowerShell.MCP.Proxy.exe) so the module is accepted on WDAC / Device Guard machines with a one-time trust of the signer. Closes #46.
- Bundle LGPL-2.1 license texts for Ude.NetStandard (compliance obligation).
- Build-AllPlatforms.ps1 gains
-Signswitch with interactive PFX passphrase for local release builds.
- Status line truncation was broken for pipelines beginning with leading whitespace.