Created
April 16, 2026 05:20
-
-
Save futuremotiondev/a08e9ad8b0875ad852b6380531235764 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using namespace System.IO | |
| using namespace System.Collections.Generic | |
| Clear-Host | |
| function Stop-MCPServerProcesses { | |
| <# | |
| .SYNOPSIS | |
| Terminates processes that are part of running MCP server stacks. | |
| .DESCRIPTION | |
| Queries running instances of python.exe, uv.exe, uvx.exe, cmd.exe, | |
| node.exe, bun.exe, and chroma-mcp.exe, then terminates only those whose | |
| command line contains "chroma-mcp" or "claude-mem". This prevents killing | |
| unrelated instances of these common host processes. | |
| .EXAMPLE | |
| Stop-MCPServerProcesses | |
| Finds and kills all matching MCP-related processes. | |
| .EXAMPLE | |
| Stop-MCPServerProcesses -Verbose | |
| Same as above with detailed tracing of each discovered and killed process. | |
| .NOTES | |
| Author: Futuremotion | |
| Date: 2026-04-15 | |
| #> | |
| [CmdletBinding(SupportsShouldProcess)] | |
| [OutputType([PSCustomObject])] | |
| param () | |
| # ── Target process names ───────────────────────────────────── | |
| [string[]] $targetNames = @( | |
| 'python' | |
| 'uv' | |
| 'uvx' | |
| 'cmd' | |
| 'node' | |
| 'bun' | |
| 'chroma-mcp' | |
| ) | |
| [string[]] $matchStrings = @('chroma-mcp', 'claude-mem') | |
| # ── Query WMI for matching processes ───────────────────────── | |
| # Build a WQL filter for all target process names at once | |
| [string] $nameFilter = ($targetNames | ForEach-Object { | |
| "Name = '$_.exe'" | |
| }) -join ' OR ' | |
| [string] $wqlQuery = "SELECT ProcessId, Name, CommandLine " + | |
| "FROM Win32_Process WHERE ($nameFilter)" | |
| Write-Verbose "WQL query: $wqlQuery" | |
| $candidates = Get-CimInstance -Query $wqlQuery -ErrorAction Stop | |
| if (-not $candidates -or $candidates.Count -eq 0) { | |
| Write-Host "No target processes found running." ` | |
| -ForegroundColor DarkYellow | |
| return [PSCustomObject]@{ | |
| Operation = 'Stop-MCPServerProcesses' | |
| Killed = 0 | |
| Skipped = 0 | |
| Details = @() | |
| ErrorMessage = $null | |
| } | |
| } | |
| Write-Verbose "Found $($candidates.Count) candidate process(es)" | |
| # ── Filter by command line and terminate ───────────────────── | |
| [List[PSCustomObject]] $details = [List[PSCustomObject]]::new() | |
| [int] $killed = 0 | |
| [int] $skipped = 0 | |
| foreach ($proc in $candidates) { | |
| [string] $cmdLine = $proc.CommandLine | |
| [int] $procId = $proc.ProcessId | |
| [string] $name = $proc.Name | |
| # Skip processes with no command line (zombie/system) | |
| if ([string]::IsNullOrWhiteSpace($cmdLine)) { | |
| Write-Verbose "PID $procId ($name): no command line, skipping" | |
| $skipped++ | |
| continue | |
| } | |
| # chroma-mcp.exe always matches by definition; others must contain a match string | |
| [bool] $isMatch = $name -eq 'chroma-mcp.exe' | |
| [string] $hitString = $null | |
| if (-not $isMatch) { | |
| foreach ($ms in $matchStrings) { | |
| if ($cmdLine.IndexOf($ms, [System.StringComparison]::OrdinalIgnoreCase) -ge 0) { | |
| $isMatch = $true | |
| $hitString = $ms | |
| break | |
| } | |
| } | |
| } | |
| if (-not $isMatch) { | |
| Write-Verbose "PID $procId ($name): no match strings in command line, skipping" | |
| $skipped++ | |
| continue | |
| } | |
| # Truncate command line for display | |
| [string] $displayCmd = if ($cmdLine.Length -gt 120) { | |
| $cmdLine.Substring(0, 117) + '...' | |
| } else { $cmdLine } | |
| if ($PSCmdlet.ShouldProcess( | |
| "PID $procId ($name)", "Terminate")) { | |
| try { | |
| Stop-Process -Id $procId -Force -ErrorAction Stop | |
| Write-Host " Killed PID $procId ($name)" ` | |
| -ForegroundColor Green | |
| Write-Verbose " CommandLine: $displayCmd" | |
| $killed++ | |
| $details.Add([PSCustomObject]@{ | |
| PID = $procId | |
| Name = $name | |
| CommandLine = $cmdLine | |
| Action = 'Killed' | |
| ErrorMessage = $null | |
| }) | |
| } | |
| catch { | |
| Write-Warning "Failed to kill PID ${procId}: $_" | |
| $details.Add([PSCustomObject]@{ | |
| PID = $procId | |
| Name = $name | |
| CommandLine = $cmdLine | |
| Action = 'Failed' | |
| ErrorMessage = $_.Exception.Message | |
| }) | |
| } | |
| } | |
| } | |
| # ── Summary ────────────────────────────────────────────────── | |
| Write-Host "" | |
| if ($killed -gt 0) { | |
| Write-Host "Terminated $killed MCP process(es)." ` | |
| -ForegroundColor Cyan | |
| } else { | |
| Write-Host "No matching MCP processes found to terminate." ` | |
| -ForegroundColor DarkYellow | |
| } | |
| if ($skipped -gt 0) { | |
| Write-Verbose "Skipped $skipped non-matching process(es)" | |
| } | |
| [PSCustomObject]@{ | |
| Operation = 'Stop-MCPServerProcesses' | |
| Killed = $killed | |
| Skipped = $skipped | |
| Details = $details.ToArray() | |
| ErrorMessage = $null | |
| } | |
| } | |
| # Self-execute | |
| Stop-MCPServerProcesses -Verbose |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment