Summary
Let the CLI reuse OAuth credentials obtained in the web inspector on the same machine (web → CLI handoff):
--use-stored-auth — read oauth.json (the shared store the web backend writes) and inject Authorization: Bearer <token> for --server-url; error (exit 3, auth_required) listing stored keys when no token matches.
--wait-for-auth <sec> — poll oauth.json (500ms interval) for the URL-normalized server key, then proceed.
--list-stored-auth — print stored server keys and exit (short-circuit, no connect).
--print-handoff <serverUrl> — emit {deepLink, portForwardCmd, oauthStatePath, apiToken} for driving the browser-side OAuth dance from a script/remote VM.
- State-path resolution precedence:
MCP_INSPECTOR_OAUTH_STATE_PATH → MCP_STORAGE_DIR/oauth.json → ~/.mcp-inspector/storage/oauth.json.
- Server keys normalized with the same
new URL().href scheme the web store uses, so both sides agree.
Reference implementation (PR #1510)
Re-implement informed by these changes at 33fac3f:
- clients/cli/src/cli.ts —
normalizeServerUrl(), resolveOAuthStatePath(), readOAuthServers(), waitForStoredToken(), buildHandoff(), async parseArgs with short-circuit modes, token-injection block
- clients/cli/tests/stored-auth.test.ts — injection, polling/timeout, listing, handoff, normalization (+373)
Depends on
Notes
- The reference implementation reads the Zustand-persist blob directly from disk (not through
NodeOAuthStorage) so polling works — decide deliberately whether to keep that or route through the storage class.
- Tokens are injected blindly; a stale token surfaces as HTTP 401 → exit 3. Document this and all four flags in
clients/cli/README.md.
- Coverage gate ≥90 on all four dimensions.
Part of the PR #1510 decomposition (see tracking issue).
Summary
Let the CLI reuse OAuth credentials obtained in the web inspector on the same machine (web → CLI handoff):
--use-stored-auth— readoauth.json(the shared store the web backend writes) and injectAuthorization: Bearer <token>for--server-url; error (exit 3,auth_required) listing stored keys when no token matches.--wait-for-auth <sec>— polloauth.json(500ms interval) for the URL-normalized server key, then proceed.--list-stored-auth— print stored server keys and exit (short-circuit, no connect).--print-handoff <serverUrl>— emit{deepLink, portForwardCmd, oauthStatePath, apiToken}for driving the browser-side OAuth dance from a script/remote VM.MCP_INSPECTOR_OAUTH_STATE_PATH→MCP_STORAGE_DIR/oauth.json→~/.mcp-inspector/storage/oauth.json.new URL().hrefscheme the web store uses, so both sides agree.Reference implementation (PR #1510)
Re-implement informed by these changes at
33fac3f:normalizeServerUrl(),resolveOAuthStatePath(),readOAuthServers(),waitForStoredToken(),buildHandoff(), asyncparseArgswith short-circuit modes, token-injection blockDepends on
AUTH_REQUIRED = 3)oauth.jsonformat and normalization this reads)deepLinkURL format--print-handoffemits (soft dependency; the format is specified there)--app-info/--format jsonissue (samecli.tslane; land first)Notes
NodeOAuthStorage) so polling works — decide deliberately whether to keep that or route through the storage class.clients/cli/README.md.Part of the PR #1510 decomposition (see tracking issue).