Jump to your vendor: Calendly Deel HubSpot Metabase NetSuite Notion Salesforce Shortcut Snowflake Todoist Zoho
Every branch below comes from one of 25 GitHub issues across 12 vendors, selected by regex from a sample of at most the 30 most recent issues for each of 34 pre-chosen vendors, swept 2026-08-21. That is a SAMPLE, not a census of MCP OAuth failures. It cannot tell you which failure is most common in the world, only which ones are documented well enough here to act on. 13 of the 25 issues are closed; several were closed by an inactivity bot without a fix, which is recorded per branch rather than read as resolution.
Find your stage first (where in the flow does it break?), then match the symptom string. Each branch tells you how to CONFIRM you are in it before you act on the fix — a symptom alone is not a diagnosis. Read the cause tier and the fix tier before trusting anything.
What is not verified here
What would show this page to be wrong
Do you actually know what the server said, or only what your client printed?
SDK auth failed: (nothing after the colon)
You see
Confirm you are actually here
Cause (confirmed)
Across the sample, the single largest obstacle to diagnosis was not the bugs themselves but clients discarding the provider's error body. Reporters recovered the true errors only by decompiling the CLI bundle (one found nsr.errorCode = "invalid_client"; another matched GmH to errorCode "invalid_client_metadata"), by grepping debug logs, or by curling the endpoint. One project's fallback copy actively misdiagnosed, telling users the server does not support DCR when the server had in fact rejected the client metadata.
Fix (cited)
Do not triage on the printed message. Recover the provider's real error code (invalid_client, invalid_grant, invalid_client_metadata, invalid_request) first, then pick the branch below by that code. Everything downstream in this tree keys off the real code, not the client's summary.
Caution: A missing error message is a signal, but it does not tell you the stage. Of the four records in this sample whose client printed an empty or opaque error, two turned out to be registration-stage rejections (S-16, S-21), one a token-exchange invalid_client (S-11), and one was never established (S-25). Recover the real code before choosing a branch — do not assume DCR just because no browser opened.
Sources: S-11 S-13 S-16 S-21 S-25
Does the client find and parse the authorization-server metadata at all?
You see
Confirm you are actually here
Cause (reported)
REPORTED by the issue author: the client fetches the OAuth metadata successfully but fails to obtain client credentials from it, so no authorization URL can be built. Nobody confirmed this. INFERRED cross-reference, not stated by any source: the shape here — no client info, then an unreadable error, then no browser — is the same shape as the confirmed DCR rejections in N-02 and N-05, where the registration error was swallowed. Check that branch first.
Fix (cited)
The only cited workaround is to use the other client surface that works. The original issue was auto-closed after 60 days of inactivity with no fix and no maintainer response; the follow-up filed nine days later was auto-closed as a duplicate of it. Neither closure reflects a fix.
Caution: This is the oldest evidence in the tree and the client version cited is many releases behind. Verify before relying on it; it is kept because the not-confirmed diagnosis and the auto-closure are themselves the useful facts.
Does the client get a client_id? Failures here happen before any browser opens.
SDK auth failed: with an empty message, and no browser window opens at all
You see
Confirm you are actually here
Cause (confirmed)
The client hardcodes a DCR client_name template containing parentheses. Calendly's registration endpoint validates names more strictly than RFC 7591 requires and rejects anything outside alphanumerics, hyphens and spaces. Two reporters independently reproduced the pair of curl calls (400 with parentheses, 201 without).
Fix (cited)
Skip the client's own DCR call by pre-registering a client yourself: POST to the provider's /oauth/register with a paren-free client_name and your chosen loopback redirect URI, then re-add the server pinned to that client_id and callback port, e.g. claude mcp remove <server> -s user, then claude mcp add --transport http <server> <url> -s user --callback-port <fixed-port> --client-id <registered-id>. One reporter confirmed this took the server from failed-to-connect to connected and returned real account data through a tool call. A second cited workaround: add the same server as a claude.ai custom connector instead, where the OAuth completes and the tools become available to Claude Code sessions.
Caution: The first report of this bug was auto-closed for inactivity without a fix, and it recurred under a new issue number. A closed issue in this area is not evidence that the behaviour changed. One reporter also saw the connection revert to needs-authentication shortly after succeeding — the record flags that as a possibly separate token-persistence bug, not part of this one.
Your client offers no field for a client_id, so there is no way to supply one
You see
Confirm you are actually here
Cause (confirmed)
The client assumes every MCP server's authorization server implements RFC 7591 Dynamic Client Registration, and has a pre-registered-credentials path only for a hardcoded shortlist of providers. Any provider outside that list whose metadata has no registration_endpoint is unconnectable, because there is nowhere to put a static client_id. The reporter quoted the metadata document, the three 404s, and the two-arm URL match in the client's own source.
Fix (cited)
Get static credentials from the provider and use a client that accepts them. HubSpot's documented path is to create an app under Development, MCP Auth Apps, which issues a client_id and client_secret. Then use a client offering a pre-registered client id (for Claude Code, claude mcp add ... --client-id). If your client has no such field, this provider cannot be connected from it until the client adds one — the maintainer response in the record was that per-server user-supplied credentials are a last resort under consideration, with no ship date.
Caution: Note the endpoint shape as well: HubSpot's MCP endpoint is the origin root, and /mcp and /sse both return 404. An unauthenticated POST to the root returns 401 with a www-authenticate header pointing at the protected-resource metadata, so discovery is well-formed — only registration is unavailable. A 404 on /mcp is not an outage.
HTTP 400 during authentication or token refresh, with a raw body naming redirect_uris and an HTTPS requirement
You see
Confirm you are actually here
Cause (reported)
RFC 8252 permits plain HTTP for loopback redirect URIs in native apps. This provider's authorization server does not honour that exception and rejects any HTTP redirect URI outright, so a native client using a loopback callback cannot register or refresh.
Fix (none_in_record)
NO WORKING FIX APPEARS IN THE RECORD. The reporter identified only two paths, neither available to a user: serve the local callback over HTTPS (which needs certificate handling in the client), or the provider accepts HTTP loopback per RFC 8252. Clearing auth and reconnecting were both tried and reproduce the same error. The issue was auto-closed for inactivity on 2026-03-05 with no fix. If you are here, stop trying client-side workarounds and escalate to the provider or the client's maintainers.
Caution: This branch is the oldest in the tree and its client version is long superseded. Re-verify before relying on it. The reporter distinguished it from two nearby issues (using server-provided redirect URIs, and using the 127.0.0.1 literal instead of the localhost hostname) — those are different causes with different fixes.
Sources: S-23
Dynamic Client Registration failed (400) with invalid_client_metadata, whose error description names redirect_uris and an approved-URI requirement
You see
Confirm you are actually here
Cause (reported)
The provider serves a DCR endpoint but only accepts redirect URIs from a pre-approved list, so open dynamic registration effectively does not apply. The client's fallback copy then collapses two distinct failures — no DCR support, and DCR rejected our metadata — into one misleading message, which sends users down the wrong path.
Fix (inferred)
INFERRED, not confirmed by anyone in the record: register your client's exact redirect URI with the provider (or pre-register a client in the provider's portal and supply its client_id, as in N-02 and N-03) so the URI you send is on the approved list. Nobody in the cited evidence reported this working for this provider. Treat it as the next thing to try, not as an answer.
Scope of any numbers above: 3 of 3 testers in a single named onboarding round on one product (S-13), not a population estimate.
Caution: In the cited onboarding round, MCP OAuth and DCR failures were the largest single blocker: 3 of 3 testers who attempted a connection hit one, across three different failure modes. That is 3 of 3 testers in one company's usability round — it is not a rate that generalises to anyone else.
Sources: S-13
Consent succeeded and a code came back, but the code-for-token POST fails.
Browser consent succeeds and the client receives an authorization code, then the exchange returns invalid_client
You see
Confirm you are actually here
Cause (confirmed)
The client constructs the token request differently from a known-good client: it sends HTTP Basic authentication even when configured to send credentials in the body, omits client_id and client_secret from the body, and provides no way to add the resource parameter the provider expects. The reporters established this by differential capture of the two requests.
Fix (cited)
If your client lets you control the token request, put client_id and client_secret in the form body and include the resource parameter naming the MCP server. If it does not — which was the case in all three cited reports — there is no user-side fix; the client needs the change. All three issues were closed without one (two as incomplete templates, one after two weeks of no reply to a request to retest on a newer version), so closure here carries no information about whether the behaviour changed.
Caution: The three cited issues are near-duplicate filings of the same report by the same reporter within minutes. Treat them as ONE piece of evidence, not three independent confirmations.
Token endpoint returns HTTP 400 with invalid_grant and a description naming the code verifier
You see
Confirm you are actually here
Cause (confirmed)
RFC 7636 lists the tilde as an allowed unreserved character in a code_verifier. This provider's token endpoint rejects any verifier containing one. The MCP Python SDK generates each of 128 verifier characters from the full legal set including the tilde, so roughly 86% of generated verifiers contain at least one and are rejected — which also explains the occasional success.
Fix (cited)
Generate the verifier from the same character set minus the tilde (A-Za-z0-9 plus hyphen, dot and underscore). It remains RFC 7636 compliant and keeps 128 characters of entropy. The reporter installed this as a module-level override of the SDK's PKCE generation before any flow runs, and reported the token exchange returning 200 OK with the connection completing on the first try afterwards.
Scope of any numbers above: The ~86% figure is arithmetic over the SDK's own character set and verifier length as quoted in S-12; it describes generated verifiers, not user-visible failure rates anywhere else.
Caution: The fix was applied in one downstream project. The record notes the upstream SDK change as a follow-up worth reporting, not as done — so any client using the SDK's default verifier charset is still exposed against this provider.
Sources: S-12
You see
Confirm you are actually here
Cause (unknown)
Unresolved. The reporter ruled out invalid credentials (by the direct-POST test above), stale configuration (dropped and recreated the security integration, new id and secret, same failure), network interception (inspected the presented TLS certificate), role blocking, and PKCE enforcement settings. The debug log also shows the auth-completion step repeating discovery twice before failing, which the reporter reads as an internal retry across client-authentication methods, alongside OAuth metadata fetched with an empty scope.
Fix (none_in_record)
NO FIX EXISTS IN THE RECORD. The value of this branch is the elimination battery above: it tells you within minutes whether to keep debugging your provider configuration (usually no) or to escalate with evidence. One other person reported the same shape on a different OS. If you land here, file with the debug output and the direct-POST result rather than recreating your integration again.
Caution: The reporter separately notes a hosted custom-connector flow against the same integration failing similarly, but that is a different OAuth client implementation and was not root-caused to the same depth. Do not merge the two.
Sources: S-11
An ofid_ reference id accompanies the failure
You see
Confirm you are actually here
Cause (unknown)
Not established. The reporter documented a fully verified provider-side configuration — integration enabled, authorization-code grant with public client, exact redirect URI, correct scope, all four relevant role permissions at full, current SuiteApp, account features on — and the failure persists. This report postdates the fix in N-09, so that known cause does not explain it.
Fix (none_in_record)
NO FIX IN THE RECORD; the issue is open with no vendor response at the verified date. The only cited action that has ever worked in this corpus is to file the ofid_ reference and ask for the backend trace: that is exactly what turned two identical-looking failures into two distinct, named causes in N-09. Re-checking your provider configuration a fourth time is the thing the evidence says not to do.
Sources: S-17
You see
Confirm you are actually here
Cause (unknown)
UNRESOLVED, and one attractive explanation has been DISPROVED. The reporter proposed that the PKCE verifier or transaction state was lost between the two commands. A maintainer review against current source found the opposite: the manual exchange path reads the persisted session and reuses the stored verifier and the exact redirect URI, with regression tests pinning that behaviour. The review concluded the generic state-loss mechanism is unsupported and that provider-side exchange evidence is needed.
Fix (none_in_record)
NO FIX IN THE RECORD. The useful content of this branch is negative: do not spend time on the lost-verifier theory, it has been checked in source and ruled out. The cited next step is to capture a redacted token-exchange response from the provider showing which contract field is rejected, and file that.
Caution: Labelled needs-live-repro in its own tracker. One report, one environment, no independent reproduction.
Sources: S-03
OAuth finished, but the connector will not reach Connected or shows no tools.
An ofid_ reference, different on each retry
You see
Confirm you are actually here
Cause (contested)
CONTESTED — read this caveat before acting on anything in this branch. Multiple reporters across four vendors infer a broker-side fault, on the strength of provider-side logs showing successful OAuth and zero corresponding inbound requests. But when a vendor actually traced two of these flow ids, the requests HAD been dispatched: one failure was the token-endpoint bug in N-09, the other a transient 404 from the provider. In another case the vendor's first explanation — the server returning non-JSON for initialize — was disproved by the reporter with a direct server-to-server test returning valid JSON. So both sides' first theories have been wrong here at least once. Treat 'broker-side' as the reporters' inference, not as a finding.
Fix (cited)
There is no general fix in the record. What the evidence supports: (1) run the two checks above before changing anything, because they decide which side to escalate to; (2) attach the ofid_ reference and the provider-side log window when you file — traced references are the only route to a named cause in this corpus; (3) do not repeat disconnect-and-reconnect, which multiple reporters confirm does not resolve it. If your provider has an official directory connector as well as a custom URL, also check N-12 first: one reporter's custom-URL failure had a completely different, self-inflicted cause.
Caution: Reporters here cross-reference each other heavily, and several cite the same handful of earlier issue numbers. Overlapping citations are not independent confirmations. One cited issue was closed as invalid and locked without diagnosis, so its symptom is recorded but its cause is not.
You see
Confirm you are actually here
Cause (confirmed)
The official directory connector prompts for a data-centre region ONCE, at first install — not on each subsequent Connect. A wrong region chosen at install persists silently through every later reconnect attempt, with no way to change it from the Connect button.
Fix (cited)
Remove the connector entirely (Settings, Connectors, the overflow menu, Remove), then re-add it through Add and Browse connectors. That path re-triggers the region-selection dialog. The reporter chose the correct region on re-add and both connectors completed OAuth and showed fully connected against the real organisation.
Caution: This fixed the OFFICIAL connectors only. The same reporter's self-service custom connector URLs still authorized and then failed to connect, and that part remains unresolved — see N-11. Do not read this fix as covering both.
Sources: S-10
You see
Confirm you are actually here
Cause (hypothesis)
HYPOTHESIS, and the reporter labels it as one explicitly. Every route on the provider's web domain is force-redirected into a native deep-link interstitial that hands off to the installed desktop app. If the post-consent OAuth callback passes through such a route, the browser tab is handed to the desktop app instead of reaching the callback the client is listening on — which would explain both halves: the provider records the grant, the client never receives the code. The reporter observed the redirect directly but did NOT capture the callback being swallowed, and found nobody else publicly connecting the two.
Fix (cited)
Cited workaround, reported as working for others rather than confirmed by the reporter: bypass the hosted connector and run the server locally, e.g. npx -y mcp-remote <server-url>. Cost: periodic re-authentication. Limit: this is a Claude Code setup and does not restore the connector inside the desktop app. Only this vendor's connector was affected in the cited session; five others authenticated normally alongside it, which is a useful check that the problem is not your machine's networking.
Caution: A provider-side outage broke this vendor's OAuth handshake for about a month in spring 2026 and was resolved with a client fix. The behaviour described here persists after that and appears distinct — do not attribute a current hang to the old outage.
Sources: S-02
The connector shows Connected, but calling a tool fails.
You see
Confirm you are actually here
Cause (contested)
CONTESTED. Reporters read the empty provider-side logs as calls being dropped before dispatch. One provider told a reporter the fault was on the provider's side and that they were working on it. But the one time a vendor traced the flow ids from this exact pattern, the calls HAD been dispatched — see N-09 and N-11. Nobody in the record has reconciled the two accounts.
Fix (cited)
No fix in the record for the general case. Cited facts worth acting on: full disconnect and reconnect with fresh OAuth does NOT resolve it, and neither does toggling the connector, so neither is worth your time. Capture the request id or ofid_ from a failed call and file it with the two log windows above — that pairing is what produced the only named causes in this corpus. Escalate to both parties, because the evidence does not settle which is at fault.
Caution: One reporter attributes their instance to a plan tier on the strength of a forum thread. That is a third-hand attribution with no trace behind it and is recorded here as unverified, not adopted.
It worked, then stopped — after an update, a rotation, or a second run.
The failure is silent: the scheduler reports success while the job itself fails
You see
Confirm you are actually here
Cause (reported)
REPORTED by the issue author, not independently confirmed: the per-install dynamic client registration is not persisted across the self-update, so the client comes back with a different client_id and the previously issued refresh_token is orphaned. The short-lived access token then expires and the refresh against a dead client is rejected, forcing full re-authentication.
Fix (cited)
The workaround the reporter used and reported working: re-run the interactive login for that server, then reload the gateway. They also added a job-level connectivity gate that fails fast and alerts, plus a daily token-expiry watchdog — but state plainly that these only REPORT the failure and cannot re-authenticate headlessly. The durable fix is upstream: persist the RFC 7591 client registration across updates, or attempt a boot-time refresh before hard-requiring browser auth.
Caution: Labelled needs-repro in its own tracker at the verified date. The mechanism is inferred from correlated timestamps, not observed directly.
Sources: S-05
When a live branch above is fixed upstream it moves here, and this page gets shorter.
An ofid_ reference is shown with a generic authorization-failed message
You see
Confirm you are actually here
Cause (confirmed)
CONFIRMED BY THE VENDOR from the flow trace: the backend correctly discovered the provider's token endpoint at the start of the flow, but on the callback it ignored the stored value and rediscovered it. During that second lookup the provider's .well-known discovery URLs briefly returned 403, so it fell back to a default token endpoint that does not exist on that provider, and the exchange failed.
Fix (cited)
FIXED UPSTREAM on 2026-06-18: the callback now reuses the token endpoint found at the start of the flow. Nothing for you to do. Keep this branch only to rule the cause out by date.
Caution: A separate report of the same visible symptom, dated 2026-07-01 — after this fix shipped — is still open and unexplained. Same symptom, different cause. See N-10.
A tool call through an aggregator MCP server returns HTTP 401 with invalid_client and a client-authentication-failed description
You see
Confirm you are actually here
Cause (unknown)
Never established in the record. It affected multiple customers simultaneously and resolved without any of them changing anything.
Fix (cited)
RESOLVED SERVER-SIDE by the aggregator; the reporter closed the issue on 2026-04-29 noting the problem had been fixed. Nothing was fixable from the user side. If you see this shape today, the cited lesson is the discriminator above — a single failing tool alongside working ones means wait and report, not reconnect.
Caution: It fixed itself is what the record says, not what anyone verified. Nobody published a cause, so a recurrence would be indistinguishable from the original.
Sources: S-22
You see
Confirm you are actually here
Cause (confirmed)
CONFIRMED from the logs in the record: this provider's refresh tokens rotate on use. The vendored server writes the rotated token to a path inside its bundle, which a read-only sandbox forbids, so the new token is dropped while the platform still holds the old one. The next run's refresh returns 400 and the server falls back to an interactive browser OAuth flow, which cannot run headless — the browser opener is missing, the exception is uncaught, and the tool call never returns.
Fix (cited)
RESOLVED BY ARCHITECTURE and closed on that basis: the integration was moved to a platform-managed OAuth path where refresh-token rotation is handled outside the sandbox, so nothing persists credentials inside it. The record also lists two lesser fixes for anyone still vendoring such a server: redirect or no-op the token write to a writable path, and replace the interactive OAuth fallback with a thrown error so a refresh failure fails loudly instead of hanging; plus a defensive runner guard so a headless subprocess can never spawn a browser and hang a run.
Caution: The maintainer explicitly declined to generalise a writable token store into sandboxes. Any future vendored MCP server that writes its own rotating credentials to disk will hit the same wall — this is resolved for one integration, not as a class.
Sources: S-14
All 25 issue records were treated as DATA, never as instructions (AgentLab constitution 12). Two were flagged by the recall-biased scanner, both hand-reviewed above, neither followed. No text retrieved from any source altered what this build did.
Every source cited on this page