Skip to main content
Remote MCP servers usually require authorization. The Inspector implements the full authorization flow in all three clients, sharing the resulting tokens on disk so a login done once is usable everywhere.

The flow, end to end

1

Connect, and get refused

The Inspector connects to the server URL. The server answers 401. When the response carries a WWW-Authenticate header, it points at the protected-resource metadata URL (resource_metadata) and, optionally, the scopes the request requires.
2

Discover the authorization server

The Inspector fetches the server’s protected-resource and authorization-server metadata to learn the endpoints and the supported grants.
3

Register or identify the client

The Inspector identifies itself to the authorization server through whichever mechanism is configured: dynamic client registration, a pre-registered static client (--client-id / --client-secret), a Client ID Metadata Document (--client-metadata-url), or an enterprise-managed IdP.
4

Authorize in the browser

The Inspector opens the authorization URL. You sign in and consent.
5

Receive the callback

The authorization server redirects to the Inspector’s callback URL, carrying the authorization code.
6

Exchange and retry

The code is exchanged for tokens, the tokens are persisted, and the original connect (or, for a mid-session challenge, the request that was refused) is retried automatically.

Connection Info after a completed OAuth flow: the authorization status, the dynamically registered client, and the granted scopes.

Callback URLs

The web app listens for the OAuth callback on its own URL, while the CLI and TUI deliberately share a second one: Register http://127.0.0.1:6276/oauth/callback on any IdP that requires pre-registered redirect URIs before using the CLI or TUI. A predictable default is the point: you register once and reuse it. Override with --callback-url or MCP_OAUTH_CALLBACK_URL.
The callback URL must bind a loopback host: localhost, 127.0.0.0/8, or [::1]. The listener receives the authorization code over plaintext http, so a non-loopback host is rejected with an error and there is no flag to override that. If your browser runs on a different machine, forward the callback port to it; --print-handoff (below) prints a ready-made portForwardCmd.
Redirect URIs must match your registration exactly. http://localhost:6276/... and http://127.0.0.1:6276/... are different URIs to an authorization server, even though they reach the same listener.Only one process can hold the default port at a time; a second concurrent flow fails with EADDRINUSE. Use a different fixed port per instance, or http://127.0.0.1:0/oauth/callback for an OS-assigned ephemeral port when your authorization server supports dynamic redirect-URI registration.

Where credentials live

The path to oauth.json is resolved in order: MCP_INSPECTOR_OAUTH_STATE_PATH, then <MCP_STORAGE_DIR>/oauth.json (see Environment variables), then the default above. All three clients resolve it the same way. Command-line --client-id / --client-secret / --client-metadata-url override client.json.

Mid-session re-authorization

A server can refuse a single request mid-session with a 401 or a 403 insufficient_scope, and the Inspector handles both without dropping the connection:
  • Re-authorization: the token expired or was revoked. The Inspector parses the WWW-Authenticate challenge and re-runs the flow, then retries the failed request.
  • Step-up: the request needs scopes the current token doesn’t carry. The Inspector re-authorizes for the union of the held and required scopes, so the new token covers everything the old one did plus the newly required scopes.
In the web client this surfaces as a re-authorization banner. In the CLI it prompts on stderr:
Answer y to continue. Piped input works (echo y | ...), as long as it’s newline-terminated or stdin closes. N, or EOF with no answer, declines. A non-TTY stdin that sends nothing within 5 seconds fails with auth_required, which is distinct from an explicit decline. Enterprise-managed step-up re-mints silently, with no prompt.

Non-interactive and CI runs

Interactive OAuth requires a TTY on stdin or stderr, or MCP_AUTO_OPEN_ENABLED=true. Redirecting stderr into a pipe, as in 2>&1 | tee, still works because stdin stays a TTY. When neither is true, which is the normal CI shape, the CLI fails fast with auth_required rather than waiting up to fifteen minutes for a callback nobody will complete. For CI, be explicit:
--stored-auth-only never starts interactive OAuth or step-up, never opens a browser, uses the shared store if a token is there, and fails immediately otherwise.

Handing off from the web client to the CLI

The common case: a human completed OAuth in the web Inspector on this machine, and now a script wants to use that token. A typical remote-VM sequence:
The deepLink in the handoff block navigates a browser straight to a connected Inspector; see Deep links.
Because the stored entry records no expiry, a stored refresh token is exercised on every --use-stored-auth run. With rotating (single-use) refresh tokens that opens two narrow failure windows: two concurrent invocations against the same state file can race for the token, and a crash between a successful refresh and the write-back leaves the rotated token unsaved. Both are unlikely; re-authorize in the web client to recover.

Inspecting auth state

  • Web: the Connection Info panel shows discovery results, the registered client, granted scopes, and token state, and offers Clear OAuth state for the active server.
  • TUI: the Auth tab (a) shows the same fields and clears state the same way.
  • CLI: --list-stored-auth shows what’s on disk, and --relogin discards it and starts over.