“invalid_redirect_uri”

The authorization server refused the redirect URI the client sent, because it does not exactly match one it has registered for that client. The three common causes: (1) The client's metadata document lists loopback redirect URIs without a port and the server compares ports, which RFC 8252 §7.3 says it should not do for loopback. To tell: The client uses a client ID metadata document (the doctor's client lines say so) and the rejected URI has a port. (2) The identity provider allowlists redirect URIs and the client's is not on the list. To tell: Compare the doctor's "Redirect URIs to allow" lines with your allowlist. (3) localhost versus 127.0.0.1, or a custom scheme such as cursor:// with a host part the server does not accept. To tell: The rejected URI differs from the registered one only in the host or the scheme. One command shows which step breaks: npx --allow-git=root github:agentwares/mcp-oauth-doctor https://your-server.example/mcp.

Check your server now

npx --allow-git=root github:agentwares/mcp-oauth-doctor https://your-server.example/mcp

Discovery only: no credential, no client registration. It prints the first broken step, whose it is, and the fix with the spec section.

Who prints it

the authorization server, shown by Claude Code, Codex, Cursor and others after the consent redirect.

The three causes, and how to tell them apart

  1. Cause 1. The client's metadata document lists loopback redirect URIs without a port and the server compares ports, which RFC 8252 §7.3 says it should not do for loopback.
    The check cannot see this one from outside: it happens after consent, or inside the client. The client uses a client ID metadata document (the doctor's client lines say so) and the rejected URI has a port.
  2. Cause 2. The identity provider allowlists redirect URIs and the client's is not on the list.
    The check cannot see this one from outside: it happens after consent, or inside the client. Compare the doctor's "Redirect URIs to allow" lines with your allowlist.
  3. Cause 3. localhost versus 127.0.0.1, or a custom scheme such as cursor:// with a host part the server does not accept.
    The check cannot see this one from outside: it happens after consent, or inside the client. The rejected URI differs from the registered one only in the host or the scheme.

Public reports

Keep checking

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.

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).

Other messages

Written 8 October 2026 from the public issues above. The sign-in check · MCP Liveness · Terms · Privacy