Documentation Index
Fetch the complete documentation index at: https://modelcontextprotocol.io/llms.txt Use this file to discover all available pages before exploring further.
Authorization
How the MCP Inspector performs OAuth, re-authorizes mid-session, and shares tokens between its clients
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
<Steps>
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.
Callback URLs
The web app listens for the OAuth callback on its own URL, while the CLI and TUI deliberately share a second one:
| Surface | Default callback | Why |
|---|---|---|
| Web | http://localhost:6274/oauth/callback | The main app server already has an HTTP listener. |
| CLI | http://127.0.0.1:6276/oauth/callback | A dedicated loopback listener, so it doesn’t collide with a running web Inspector. |
| TUI | http://127.0.0.1:6276/oauth/callback | The same listener as the CLI. |
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.
<Warning>
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.
<Note>
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
| File | Contents |
|---|---|
~/.mcp-inspector/storage/oauth.json | Tokens and client information, keyed by canonicalized server URL. Written owner-only. |
~/.mcp-inspector/storage/client.json | Install-level client settings (client metadata URL, enterprise IdP). The same file the web client’s Client Settings dialog writes. |
The server’s oauth block in the catalog file | Per-server client id/secret, scopes, the enterprise-managed flag, and the step-up policy. |
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-Authenticatechallenge 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:
Proceed with step-up authorization? [y/N]
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:
mcp-inspector --cli "$URL" --transport http --stored-auth-only --method tools/list
--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.
| Flag | Behavior |
|---|---|
--use-stored-auth | Read the stored auth for --server-url and inject Authorization: Bearer. When a refresh token is stored, run the refresh grant first and inject the fresh token, persisting the rotation. Exits 3 (listing the stored server URLs) when nothing matches. |
--wait-for-auth <sec> | Poll the state file until a token for --server-url appears, then inject it. Times out at <sec> with exit 3. Use after handing a login off to a human. |
--list-stored-auth | Print { oauthStatePath, storedServerUrls } and exit without connecting. |
--print-handoff | Print a JSON block (deepLink, portForwardCmd, oauthStatePath, apiToken) for --server-url and exit; this is everything a remote script needs to drive the browser side. |
--relogin | Delete the stored OAuth for this server URL before connecting. HTTP/SSE only. |
A typical remote-VM sequence:
# On the VM: print what the human needs in order to complete OAuth in their browser
mcp-inspector --cli --server-url https://api.example/mcp --print-handoff
# Then block until the token lands, and run the call with it
mcp-inspector --cli --transport http --server-url https://api.example/mcp \
--wait-for-auth 120 --method tools/list
The deepLink in the handoff block navigates a browser straight to a connected Inspector; see Deep links.
<Note>
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-authshows what’s on disk, and--relogindiscards it and starts over.
Last updated Oct 08, 2026