mcp-oauth-doctor
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@mcp-oauth-doctorwhy can't claude.ai sign in to https://api.example.com/mcp"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
mcp-oauth-doctor
The step where your MCP server's sign-in breaks.
npx --allow-git=root github:agentwares/mcp-oauth-doctor https://your-server.example/mcpIt walks a remote MCP server's OAuth chain from outside, the way a client does, with no credential and no client registration, and prints:
the first broken step;
whose it is: the server, its identity provider, or a known client bug, with the issue;
the fix, citing the section of the 2026-07-28 MCP authorization spec or the RFC that requires it;
a verdict per client — claude.ai, Claude Code, ChatGPT, VS Code and Cursor — emulated from each client's published requirements and the issues filed against it. No client is run.
The same check is a web page, /auth?url=, and
an MCP tool, mcp_liveness_check_auth on https://agentwares-mcp-liveness.vercel.app/mcp.
What it walks
The 401. One unauthenticated request, the way a dual-era client opens (
server/discoverat 2026-07-28, theninitialize). It must answer 401 — clients start sign-in only on 401 — with aWWW-Authenticate: Bearer resource_metadata="…"challenge, or serve the well-known document.RFC 9728 protected-resource metadata: the URL in the challenge (a client that has one uses it and stops there), then
/.well-known/oauth-protected-resource/<path>, then the root. Itsresourcemust be the server's URL; it must name an authorization server.RFC 8414 or OpenID Connect discovery, at the locations the spec lists, in its order. A document found only where the spec does not tell clients to look is reported as such. The
issuermust be identical to the URL it was looked up for (RFC 8414 §3.3, which clients must enforce since 2026-07-28), andcode_challenge_methods_supportedmust listS256(clients must refuse to proceed without it).How a client gets a client ID: a client ID metadata document (preferred since 2026-07-28), RFC 7591 dynamic registration (deprecated, kept for compatibility), or a pasted one.
Each client's published rules: which registration it uses, the redirect URIs it sends, and known bugs that match this server — every rule with its source and date; a rule seen only in an issue is labelled observed in, never presented as documented.
A metadata document behind a bot challenge (Cloudflare, Vercel, DataDome, …) is named: clients fetch it from servers and CLIs, which cannot solve one.
Related MCP server: Remote MCP Server on Cloudflare
Options
npx --allow-git=root github:agentwares/mcp-oauth-doctor <url> [--json] [--client <name>]
--json the full report as JSON (schema mcp-oauth-doctor/1), plus `next` and `also`
--client <name> judge for one client only: claude-ai, claude-code, chatgpt, vscode, cursorExit code 1 when sign-in is broken or nothing answered, 0 otherwise, 2 for a usage error. Usage
errors carry code, cause, fix and retryable (as JSON with --json).
In CI
- uses: agentwares/mcp-oauth-doctor@main
with:
url: https://your-server.example/mcp
# client: claude-ai # one client only
# fail-on: at_risk # broken (default) | at_risk | neverThe Action runs the committed dist/ from its own checkout (no npm install), writes the report to
the job summary, and sets verdict, first-broken and report (the JSON's path) as outputs.
A recorded run
Recorded on 9 October 2026 with pnpm record (scripts/record.mjs): our own servers, live, and
two synthetic broken servers that the script serves on 127.0.0.1 for the length of the run
(src/vendor/mcp-oauth-walk/synthetic.ts). The synthetic ones are not anyone's real server. Our
own servers ask for no credential, so the doctor says there is no sign-in to check and offers the
free hourly watch. The synthetic servers have a sign-in, but nothing outside this machine can
reach 127.0.0.1, so their hand-off is the watch form left empty, for once a server is deployed,
then the nightly checks.
## Our own server, live (2026-10-09)
$ npx --allow-git=root github:agentwares/mcp-oauth-doctor https://agentwares-mcp-liveness.vercel.app/mcp
mcp-oauth-doctor 0.1.0
https://agentwares-mcp-liveness.vercel.app/mcp · 2026-10-09 18:19 UTC · 0.8 s
Discovery only: no credential sent, no client registered.
The server answered without asking for a credential, so there is no sign-in to break.
Steps
info Unauthenticated request HTTP 200: the server accepts requests without a token, so there is no sign-in to check.
Re-check it every hour and email me when it stops answering: agentcheck's free watch, no account. https://agentwares-agentcheck.vercel.app/watch?target=https%3A%2F%2Fagentwares-mcp-liveness.vercel.app%2Fmcp&ref=mcp-oauth-doctor
(exit 0)
## Our own server, live (2026-10-09)
$ npx --allow-git=root github:agentwares/mcp-oauth-doctor https://agentwares-agentcheck.vercel.app/api/mcp
mcp-oauth-doctor 0.1.0
https://agentwares-agentcheck.vercel.app/api/mcp · 2026-10-09 18:19 UTC · 0.5 s
Discovery only: no credential sent, no client registered.
The server answered without asking for a credential, so there is no sign-in to break.
Steps
info Unauthenticated request HTTP 200: the server accepts requests without a token, so there is no sign-in to check.
Re-check it every hour and email me when it stops answering: agentcheck's free watch, no account. https://agentwares-agentcheck.vercel.app/watch?target=https%3A%2F%2Fagentwares-agentcheck.vercel.app%2Fapi%2Fmcp&ref=mcp-oauth-doctor
(exit 0)
## SYNTHETIC broken server ("issuer-mismatch"), served on 127.0.0.1 for this recording — not anyone's real server
$ npx --allow-git=root github:agentwares/mcp-oauth-doctor http://127.0.0.1:56268/mcp
mcp-oauth-doctor 0.1.0
http://127.0.0.1:56268/mcp · 2026-10-09 18:19 UTC · 0.0 s
Discovery only: no credential sent, no client registered.
Sign-in breaks at "Metadata `issuer` is identical to the advertised authorization server", and
the fix is the identity provider's.
Steps
ok Unauthenticated request returns 401 HTTP 401
ok WWW-Authenticate points at the resource metadata resource_metadata=http://127.0.0.1:56268/.well-known/oauth-protected-resource/mcp
info Challenge advertises the scope to request scope="mcp:tools"
ok Protected resource metadata is discoverable http://127.0.0.1:56268/.well-known/oauth-protected-resource/mcp (header)
ok PRM `resource` is this server's canonical URI resource=http://127.0.0.1:56268/mcp
ok PRM lists an authorization server http://127.0.0.1:56269/tenant1
info Scopes advertised mcp:tools
ok Authorization server metadata is discoverable http://127.0.0.1:56269/.well-known/oauth-authorization-server/tenant1; issuer=http://127.0.0.1:56269; token_e…
FAIL Metadata `issuer` is identical to the advertised au… issuer=http://127.0.0.1:56269 vs http://127.0.0.1:56269/tenant1
ok PKCE S256 advertised S256
ok Client registration client ID metadata documents and dynamic registration (registration_endpoint=http://127.0.0.1:56269/tenant1/r…
ok Refresh tokens supported authorization_code, refresh_token
ok Public clients can use the token endpoint none, client_secret_basic
First broken step: Metadata `issuer` is identical to the advertised authorization server
whose: the identity provider
what: issuer=http://127.0.0.1:56269 vs http://127.0.0.1:56269/tenant1
fix: Make `issuer` in the metadata exactly the URL listed in the protected-resource
metadata's authorization_servers (http://127.0.0.1:56269/tenant1), character for
character, or list exactly the issuer the metadata states.
spec: RFC 8414 §3.3; MCP 2026-07-28 "Authorization Server Metadata Discovery"
about "Issuer mismatch": https://agentwares-mcp-liveness.vercel.app/auth/issuer-mismatch?ref=mcp-oauth-doctor
Clients (emulated from each client's published requirements and known issues; no client was run)
claude.ai BLOCKED Metadata `issuer` is identical to the advertised authorization server: issuer=http://127.0.0.1:56269 vs http://127.0.0.…
Claude Code BLOCKED Metadata `issuer` is identical to the advertised authorization server: issuer=http://127.0.0.1:56269 vs http://127.0.0.…
ChatGPT BLOCKED Metadata `issuer` is identical to the advertised authorization server: issuer=http://127.0.0.1:56269 vs http://127.0.0.…
VS Code BLOCKED Metadata `issuer` is identical to the advertised authorization server: issuer=http://127.0.0.1:56269 vs http://127.0.0.…
Cursor BLOCKED Metadata `issuer` is identical to the advertised authorization server: issuer=http://127.0.0.1:56269 vs http://127.0.0.…
Redirect URIs to allow if your identity provider restricts them
claude.ai https://claude.ai/api/mcp/auth_callback
Claude Code http://localhost/callback http://127.0.0.1/callback
ChatGPT https://chatgpt.com/connector_platform_oauth_redirect
VS Code http://127.0.0.1:33418 https://vscode.dev/redirect
Cursor http://localhost:8787/callback https://www.cursor.com/agents/mcp/oauth/callback cursor://anysphere.cursor-mcp/oauth/callback
Once it is deployed, re-check it every hour and email me when a step breaks: agentcheck's free watch, no account — it follows the sign-in a new client follows, with these same rules. https://agentwares-agentcheck.vercel.app/watch?ref=mcp-oauth-doctor
Nightly, with history: mcpcheck Server Pro re-runs these sign-in checks against the server every night, with 90 days of history, and emails when one fails ($49 a server a month; the first run is free). https://agentwares-agentcheck.vercel.app/mcpcheck?ref=mcp-oauth-doctor
(exit 1)
## SYNTHETIC broken server ("second-issuer"), served on 127.0.0.1 for this recording — not anyone's real server
$ npx --allow-git=root github:agentwares/mcp-oauth-doctor http://127.0.0.1:56268/mcp --client claude-ai
mcp-oauth-doctor 0.1.0
http://127.0.0.1:56268/mcp · 2026-10-09 18:19 UTC · 0.0 s
Discovery only: no credential sent, no client registered.
Sign-in breaks at "claude.ai cannot sign in", and the fix is the server's (only claude.ai is
affected).
Steps
ok Unauthenticated request returns 401 HTTP 401
ok WWW-Authenticate points at the resource metadata resource_metadata=http://127.0.0.1:56268/.well-known/oauth-protected-resource/mcp
info Challenge advertises the scope to request scope="mcp:tools"
ok Protected resource metadata is discoverable http://127.0.0.1:56268/.well-known/oauth-protected-resource/mcp (header)
ok PRM `resource` is this server's canonical URI resource=http://127.0.0.1:56268/mcp
ok PRM lists an authorization server http://127.0.0.1:56269/gone, http://127.0.0.1:56269/tenant1
info Scopes advertised mcp:tools
ok Authorization server metadata is discoverable http://127.0.0.1:56269/.well-known/oauth-authorization-server/tenant1; issuer=http://127.0.0.1:56269/tenant1;…
ok PKCE S256 advertised S256
ok Client registration client ID metadata documents and dynamic registration (registration_endpoint=http://127.0.0.1:56269/tenant1/r…
ok Refresh tokens supported authorization_code, refresh_token
ok Public clients can use the token endpoint none, client_secret_basic
First broken step: claude.ai cannot sign in
whose: the server — claude.com/docs connectors: authentication (2026-10-08)
what: claude.ai uses only the first authorization_servers entry (http://127.0.0.1:56269/gone),
and it published no metadata; the one that answered is http://127.0.0.1:56269/tenant1
fix: Put the authorization server that serves metadata first in authorization_servers, or
serve metadata for the first one.
spec: MCP 2026-07-28 "Authorization Server Location"
docs: https://claude.com/docs/connectors/building/authentication
Clients (emulated from each client's published requirements and known issues; no client was run)
claude.ai BLOCKED claude.ai uses only the first authorization_servers entry (http://127.0.0.1:56269/gone), and it published no metadata; …
Redirect URIs to allow if your identity provider restricts them
claude.ai https://claude.ai/api/mcp/auth_callback
Once it is deployed, re-check it every hour and email me when a step breaks: agentcheck's free watch, no account — it follows the sign-in a new client follows, with these same rules. https://agentwares-agentcheck.vercel.app/watch?ref=mcp-oauth-doctor
Nightly, with history: mcpcheck Server Pro re-runs these sign-in checks against the server every night, with 90 days of history, and emails when one fails ($49 a server a month; the first run is free). https://agentwares-agentcheck.vercel.app/mcpcheck?ref=mcp-oauth-doctor
(exit 1)What it will not do
It never sends a credential, never registers a client and never requests a token.
It never retries. Each request has a 10-second timeout and the whole walk a 30-second budget.
It makes one POST (two for a server on the older protocol revision) and GETs of public discovery documents. It sends no telemetry and needs no account.
Error messages people paste
One page each, saying what the message means, its three common causes and how to tell them apart, with the public issues and their dates:
Sources, read 8 October 2026
MCP authorization, revision 2026-07-28: main, Authorization Server Discovery, Client Registration, Security Considerations.
claude.ai: connectors, authentication.
Claude Code: MCP.
ChatGPT: Apps SDK, authentication.
VS Code: MCP configuration, MCP extension guide.
Cursor: MCP; client ID metadata documents are not supported yet, observed in forum thread 148096 (opened 6 January 2026, staff reply 22 September 2026).
The per-client rules and known issues are in
src/vendor/mcp-oauth-walk/clients.ts, each with its
source and date.
Keep checking
A check is one look. The doctor's last lines say how to keep looking:
Every hour, free: agentcheck's watch takes an email address and the server's URL, with no account. For a server with a sign-in it follows the sign-in a new client follows, with these same rules, and emails the step when one breaks, then again when it is fixed. For a server without one, it emails when the server stops answering or its tools change. A server on localhost cannot be watched from outside, so the doctor offers the form empty, for once it is deployed.
Every night, with history: mcpcheck Server Pro re-runs these sign-in checks with 90 days of history and emails when one fails ($49 a server a month; the first run is free). The doctor offers it to a server with a sign-in, after the watch.
With --json, the watch is next and Server Pro is also (null for a server with no sign-in).
Library
npm install github:agentwares/mcp-oauth-doctorimport { diagnose } from "mcp-oauth-doctor";
const report = await diagnose("https://your-server.example/mcp", { clients: ["claude-ai"] });Web-standard (fetch, URL, AbortSignal), no runtime dependencies.
MIT, by agentwares.
This server cannot be deployed
Maintenance
Related MCP Connectors
Preflight MCP OAuth compatibility with structured evidence and remediation guidance.
Check public MCP reachability, protocol handshake, auth and tool schemas before connecting.
Diagnoses whether an MCP server is reachable, by live HTTP probe.
Let Claude or ChatGPT search, read and send your WhatsApp messages over MCP. OAuth sign-in.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceDiagnose MCP servers — health checks, tool testing, token cost audits, conflict detection, and security scanning with 50+ prompt injection patterns. Works as CLI or MCP server inside Claude Desktop.1MIT
- AlicenseNot gradedqualityCmaintenanceEnables deploying and connecting to MCP servers on Cloudflare Workers with OAuth login, allowing remote access to tools via MCP clients like Claude Desktop.204 npmMIT
- FlicenseNot gradedqualityCmaintenanceEnables running an MCP server remotely on Cloudflare Workers with OAuth authentication, allowing MCP clients like Claude Desktop to connect and use tools such as a math calculator.1-
- FlicenseNot gradedqualityDmaintenanceRemote MCP server with built-in OAuth authentication via Cloudflare Access, enabling secure tool invocation after user sign-in.-