From d85ff4ea60817876d8dcdf2db6dc387df4ad6e8f Mon Sep 17 00:00:00 2001 From: Sameeksha Vaity Date: Fri, 12 Jun 2026 09:31:11 -0700 Subject: [PATCH] Fix MCP server infinite respawn loop on upgrade/install failure When the upgrade check or installation fails (due to GitHub API rate limiting, 504 timeouts, or network errors), fall back to the existing binary instead of exiting with an error. This prevents the MCP client from respawning the process in a tight loop that can spawn hundreds of pwsh processes. Changes: - Check ~/bin (default install dir) when binary is not on PATH - Use azsdkCmd.Path instead of package name for upgrade check - On upgrade check failure in -Run mode, fall back to existing binary - On Install-Standalone-Tool failure in MCP mode, fall back to existing binary if available at the known install directory Fixes #15973 Fixes #15953 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- eng/common/mcp/azure-sdk-mcp.ps1 | 66 ++++++++++++++++++++++++-------- 1 file changed, 49 insertions(+), 17 deletions(-) diff --git a/eng/common/mcp/azure-sdk-mcp.ps1 b/eng/common/mcp/azure-sdk-mcp.ps1 index fd46dbe9db8b..638e2fb48b89 100755 --- a/eng/common/mcp/azure-sdk-mcp.ps1 +++ b/eng/common/mcp/azure-sdk-mcp.ps1 @@ -106,27 +106,51 @@ $tempInstallDirectory = Join-Path $tmp "azsdk-install-$($guid)" # If already installed, use first class version mechanism $azsdkCmd = Get-Command -ErrorAction Ignore $packageName +# Also check the default install directory (~/bin) in case it's not on PATH +if (!$azsdkCmd -and !$InstallDirectory) { + $existingExe = Join-Path $toolInstallDirectory ($IsWindows ? "$packageName.exe" : $packageName) + if (Test-Path -PathType Leaf $existingExe) { + $azsdkCmd = Get-Command -ErrorAction Ignore $existingExe + } +} if ($azsdkCmd -and !$InstallDirectory) { - $ErrorActionPreference = "Stop" - $upgrade = & $packageName upgrade --check --output json | out-string - if (!$LASTEXITCODE) { - $ErrorActionPreference = 'Ignore' - $localVersion = $upgrade | ConvertFrom-Json -AsHashtable - $ErrorActionPreference = 'Stop' - if ($localVersion -and $localVersion.old_version -and $localVersion.old_version -eq ($Version ? $Version : $localVersion.new_version)) { - log "Version up to date at $($localVersion.old_version)" - if ($Run) { - $proc = Start-Process -PassThru -WorkingDirectory $RunDirectory -FilePath $azsdkCmd.Path -ArgumentList 'mcp' -NoNewWindow -Wait - exit $proc.ExitCode + try { + $ErrorActionPreference = "Stop" + $upgrade = & $azsdkCmd.Path upgrade --check --output json | out-string + if (!$LASTEXITCODE) { + $ErrorActionPreference = 'Ignore' + $localVersion = $upgrade | ConvertFrom-Json -AsHashtable + $ErrorActionPreference = 'Stop' + if ($localVersion -and $localVersion.old_version -and $localVersion.old_version -eq ($Version ? $Version : $localVersion.new_version)) { + log "Version up to date at $($localVersion.old_version)" + if ($Run) { + $proc = Start-Process -PassThru -WorkingDirectory $RunDirectory -FilePath $azsdkCmd.Path -ArgumentList 'mcp' -NoNewWindow -Wait + exit $proc.ExitCode + } + exit 0 + } + if ($localVersion) { + log "Version not up to date at " + $localVersion.old_version + } else { + log "Failed to parse version:" + log $upgrade } - exit 0 + } elseif ($Run) { + # Upgrade check failed (e.g. network error, rate limit, timeout), + # but the binary already exists — fall back to running it as-is + # rather than attempting a fresh install that will likely also fail. + log -warn "Upgrade check failed, falling back to existing installation at '$($azsdkCmd.Path)'" + $proc = Start-Process -PassThru -WorkingDirectory $RunDirectory -FilePath $azsdkCmd.Path -ArgumentList 'mcp' -NoNewWindow -Wait + exit $proc.ExitCode } - if ($localVersion) { - log "Version not up to date at " + $localVersion.old_version - } else { - log "Failed to parse version:" - log $upgrade + } + catch { + if ($Run) { + log -warn "Upgrade check error: $($_.Exception.Message). Falling back to existing installation." + $proc = Start-Process -PassThru -WorkingDirectory $RunDirectory -FilePath $azsdkCmd.Path -ArgumentList 'mcp' -NoNewWindow -Wait + exit $proc.ExitCode } + throw } } @@ -147,6 +171,14 @@ if ($mcpMode) { } catch { log -err $_ + # If install failed but an existing binary is available, fall back to it + # instead of exiting (which causes the MCP client to respawn in a loop). + $existingExe = Join-Path $toolInstallDirectory ($IsWindows ? "$packageName.exe" : $packageName) + if ($Run -and (Test-Path -PathType Leaf $existingExe)) { + log -warn "Installation failed, falling back to existing installation at '$existingExe'" + $proc = Start-Process -PassThru -WorkingDirectory $RunDirectory -FilePath $existingExe -ArgumentList 'mcp' -NoNewWindow -Wait + exit $proc.ExitCode + } exit 1 } }