You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
mcpdo: a sign-in helper failure without a TTY loses its exit-code classification (fetch_refused reported as auth_required) #2962
Found in the v2.15.0 release smoke (#2960). It is a follow-up to #2842 / PR #2940, which classified CLI failures by exit code but only covered the front-end path.
Problem
When mcpdo connect runs without a TTY, OAuth sign-in runs in the detached sign-in helper. Any failure the helper reports before it produces the authorization URL is turned into auth_required / exit 3 by fail() in clients/mcpdo/src/connection/auth-helper.ts. That happens even when the front-end path classifies the same failure more specifically.
The case observed in the smoke was a fetch-guard refusal. The same server gives different results depending on the path:
Path
Envelope
Exit
one-shot CLI
{"error":{"code":"fetch_refused","message":"Refusing to fetch from a link-local or metadata address (169.254.169.254)","url":"http://169.254.169.254/.well-known/oauth-authorization-server"}}
12
mcpdo connect with a TTY
fetch_refused
12
mcpdo connect without a TTY
{"error":{"code":"auth_required","message":"Sign-in helper failed: Refusing to fetch from a link-local or metadata address (169.254.169.254)"}}
3
The url field is lost as well.
Reproduce
Run an OAuth composable test server with "mode":"protected-resource","authorizationServers":["http://169.254.169.254"] on a local port.
The output is auth_required / 3. The expected output is fetch_refused / 12, the same as the TTY path.
Who hits it
The path is common, but the trigger is narrow. Running without a TTY is how agents drive mcpdo (see skills/mcpdo). The issue only fires on a failure before the authorization URL exists:
a fetch-guard refusal
a discovery failure
a client-registration error
A user declining consent happens after the URL exists, so it is not affected. The message still names the cause, and exit 3 still reads as an auth problem, so only a caller that distinguishes 12 from 3 misroutes.
Expected
The helper relays enough of the original error, such as a code and a url, for the parent to raise the same classified CliExitCodeError the TTY path does. auth_required should be the fallback only for failures that have no classification.
Activity
cliffhall commentedon Nov 11, 2026
Triage: Priority Medium (total 6)
buglabel, +1 milestone (v2.16.0, filed by a maintainer).Board: #28, Status
Todo.Address review: carry the relayed cause back onto the rebuilt error (#…
Merge pull request #2971 from modelcontextprotocol/v2/fix/2962-auth-h…
cliffhall commentedon Nov 12, 2026
Fixed by #2971 (merged as a53ce55).