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
- Configure one or more MCP servers that authenticate via OAuth.
- 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.
- 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:
- Resume times out at 60s and the pooled CLI process is force-retired.
- 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.
- 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).
- 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
- 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.
- 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.
- 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.
- 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.
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
accumulate in
~/.copilot/mcp-oauth-config/*.tokens.json; the ones thatmatter have a past
expiresAtand norefreshTokenfield.Count the unrenewable tokens:
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:
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:
AppHangB1forgithub.exe1.1.15twice within seven minutes, both under the same fault bucket
(
1215446218445078001) — so it is reproducible, not a one-off.only the root process and orphans its children (see companion issue about
there being no way to fully quit the app).
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:
Same MCP servers, same config — only the dead tokens removed. That points at
the retry/wait path rather than the servers themselves.
Suggested fixes
expiresAtis past and there is norefreshToken, skip the reconnect attempt entirely and mark the server asneeding sign-in. This requires no network call to determine.
MCP servers attach asynchronously, or give MCP a budget well under the
overall resume ceiling.
a hang is not. Nothing in the UI indicated auth was the problem — I only
found it by reading the logs.
with no visible signal. Even a warning at a threshold would have prevented
this.
Workaround
Delete expired token files (valid ones are preserved):
Servers you actually use will prompt to re-authenticate on next launch.
Logs
Happy to attach
/collect-debug-logsoutput if useful.