Session resume blocks on MCP OAuth tokens that cannot be refreshed, timing out after 60s instead of failing fast

Aperta
#3,640 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
4/5
Tempo stimato
3-5 giorni
Idoneità per principianti
48/100
Tipo di issue
Bug
Chiarezza
Abbastanza chiara
Stato di attività
Attiva

Direzione di ricerca

Non sono indicati né un file sorgente né un test. Riproduci la ripresa della sessione con file scaduti privi di refreshToken in ~/.copilot/mcp-oauth-config, quindi traccia il percorso di ripresa della sessione e riconnessione MCP usando i log di timeout riportati. Il lavoro è completato quando i server non rinnovabili falliscono rapidamente o vengono segnalati come server che richiedono l'accesso, senza impedire la ripresa della sessione.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

App version

1.1.15 (Windows)

OS

Windows 11 Enterprise 10.0.26100 (build 26100), AMD64

Summary

When a cached MCP OAuth token has expired and has no refresh token, it
cannot be renewed without interactive sign-in. On session resume the app still
attempts a cached-token reconnect for each such server and waits, rather than
recognising the token as unrenewable and failing fast. With enough of these,
resume exhausts its 60s ceiling and fails.

Steps to reproduce
  1. Configure one or more MCP servers that authenticate via OAuth.
  2. Let their cached tokens expire without completing a re-auth prompt. Tokens
    accumulate in ~/.copilot/mcp-oauth-config/*.tokens.json; the ones that
    matter have a past expiresAt and no refreshToken field.
  3. Restart the app and resume an existing session.

Count the unrenewable tokens:

$now = Get-Date
Get-ChildItem "$env:USERPROFILE\.copilot\mcp-oauth-config" -Filter *.tokens.json |
  ForEach-Object {
      $j = Get-Content $_.FullName -Raw | ConvertFrom-Json
      if (-not $j.expiresAt) { return }
      # expiresAt is Unix seconds on Windows 1.1.15; handle ISO strings too.
      $exp = if ($j.expiresAt -is [string]) { [datetime]::Parse($j.expiresAt) }
             else { [DateTimeOffset]::FromUnixTimeSeconds([int64]$j.expiresAt).LocalDateTime }
      if ($exp -lt $now -and -not $j.refreshToken) { $_.Name }
  } | Measure-Object | Select-Object -ExpandProperty Count
Expected behavior

A token that is expired and has no refresh token is known-unrenewable before
any network call. Resume should skip it immediately (surfacing "needs sign-in"
for that server) and continue. One unreachable MCP server should not be able to
delay or fail session resume.

Actual behavior

The app attempts a cached-token reconnect per server and waits. Once enough of
them cannot answer, resume hits its ceiling and the session fails to open:

WARN  session::manager::lifecycle: session resume timed out; releasing CLI and surfacing error
WARN  session::manager::cli_pool:  force-retiring pooled CLI process
ERROR handlers::session:            extensibility RPC failed method=session.mcp.list error=request cancelled
ERROR handlers::session:            failed to resume session error=operation timed out:
                                    session resume timed out after 60s

I had 51 of 53 cached tokens expired, 45 of them with no refresh token.
Every resume of a previously working session failed at exactly 60s.

Impact — it cascades

The failure is not contained to one resume:

  1. Resume times out at 60s and the pooled CLI process is force-retired.
  2. The UI appears to hang. Windows logged AppHangB1 for github.exe 1.1.15
    twice within seven minutes, both under the same fault bucket
    (1215446218445078001) — so it is reproducible, not a one-off.
  3. The natural user response is to end the task in Task Manager, which kills
    only the root process and orphans its children (see companion issue about
    there being no way to fully quit the app).
  4. The next launch starts a fresh set of child processes on top of the strays.

After a few cycles I had ~23 app-related processes holding 4.3 GB, with
free RAM down from 12 GB to 7 GB. Every new session I opened was also affected,
so the app looked broadly broken rather than "one MCP server needs sign-in".

Fix that worked

Deleting only the expired token files resolved it completely:

before after
session resume timed out at 60s 6.6s – 8.2s
unreachable MCP server consumed the resume budget fails in < 1s
resume timeouts in log repeated 0

Same MCP servers, same config — only the dead tokens removed. That points at
the retry/wait path rather than the servers themselves.

Suggested fixes
  1. Fast-fail unrenewable tokens. If expiresAt is past and there is no
    refreshToken, skip the reconnect attempt entirely and mark the server as
    needing sign-in. This requires no network call to determine.
  2. Don't let MCP reconnect block resume. Resume the session first and let
    MCP servers attach asynchronously, or give MCP a budget well under the
    overall resume ceiling.
  3. Surface it in the UI. "3 MCP servers need sign-in" is actionable;
    a hang is not. Nothing in the UI indicated auth was the problem — I only
    found it by reading the logs.
  4. Prune or flag stale tokens. Tokens accumulated to 53 files over months
    with no visible signal. Even a warning at a threshold would have prevented
    this.
Workaround

Delete expired token files (valid ones are preserved):

$now = Get-Date
Get-ChildItem "$env:USERPROFILE\.copilot\mcp-oauth-config" -Filter *.tokens.json |
  Where-Object {
      $j = Get-Content $_.FullName -Raw | ConvertFrom-Json
      if (-not $j.expiresAt) { return $false }
      $exp = if ($j.expiresAt -is [string]) { [datetime]::Parse($j.expiresAt) }
             else { [DateTimeOffset]::FromUnixTimeSeconds([int64]$j.expiresAt).LocalDateTime }
      $exp -lt $now
  } | Remove-Item

Servers you actually use will prompt to re-authenticate on next launch.

Logs

Happy to attach /collect-debug-logs output if useful.

Lingua principale
Nessun dato sulla lingua
Stelle
2.1k
Fork
157
Metriche di merge delle PR
Nessuna PR unita negli ultimi 30g

Guida per i contributori

Apri la guida per i contributori

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di github/app

Tutte le issue di github/app

Issue simili

Altre issue su Security

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.