Google Cloud BigQuery connector: redirect_uri_mismatch, and the pasted OAuth Client ID appears unused (reopening #43959 / #48957 / #62271 with a full repro)
Summary
The Google Cloud BigQuery directory connector fails OAuth with Error 400: redirect_uri_mismatch, and the Client ID / Client Secret the install dialog asks for do not appear to change the outcome. Other Google connectors (Gmail, Google Calendar, Google Drive) connect normally on the same account and machine.
This has been reported at least three times — #43959, #48957, #62271 — all closed as not planned. I am reopening it with a full reproduction because those reports were closed without one, and the failure is total: there is no way to use this connector.
Environment
- Claude Desktop (Windows 11 x64), installed fresh from the official download during this test
- Plan: Max
- Google Cloud project with BigQuery enabled; user has
roles/bigquery.jobUserand dataset-leveldataViewer - Same account and machine: Gmail / Calendar / Drive connectors all connect successfully
Steps to reproduce
- Settings → Connectors → Add → Browse connectors → search
bigquery→ Google Cloud BigQuery - The install dialog asks for four things: get an OAuth Client ID from Google, paste it, get a Client Secret, paste it
- Paste a Client ID and Secret from an OAuth client in your own Google Cloud project
- Continue → sign in with Google
Expected: the Google consent screen for the pasted OAuth client.
Actual: Access blocked: This app's request is invalid — Error 400: redirect_uri_mismatch. Error details give only flowName=GeneralOAuthFlow.
What I tried, and what it ruled out
I assumed this was my misconfiguration and worked through it systematically:
| Attempt | Result |
|---|---|
| OAuth client of type Desktop app | redirect_uri_mismatch |
| OAuth client of type Web application, with https://claude.ai/api/mcp/auth_callback in Authorized redirect URIs (the URI Anthropic's own docs specify) | redirect_uri_mismatch, identical |
| Re-run via the connector's retry / Connect button after registering the new client | identical error — the flow appears to reuse credentials cached from the first attempt rather than re-reading the dialog values |
The second row is the important one: a Web-application client with the documented redirect URI registered is exactly the configuration the docs describe, and it fails the same way.
I could not find any UI to clear or re-enter the stored credentials for an already-installed connector, so I could not force a clean retry with the new client. If that path exists, pointing me at it would let me narrow this further.
The likely cause, from the earlier reports
I did not capture the client id from the failing request myself, so I am citing rather than asserting: reporters on #43959 and #62271 state the failing request carries Anthropic's own OAuth client id (699272716442-c8vv4tojssh38erhltaj70k0lmi7p449.apps.googleusercontent.com) rather than the pasted one. That would explain why the pasted credentials make no difference, and why the redirect URI on our client is irrelevant.
If that is right, the dialog is asking users for credentials it does not use, and the fix is on the server side.
Impact
- The connector is unusable — not degraded, unusable.
- The dialog actively misleads: it asks for a Client ID and Secret, so every user reasonably concludes the failure is their Google Cloud configuration and goes looking there. I spent about an hour creating and re-creating OAuth clients before checking the issue tracker.
- Three separate people filed this and were closed as
not planned, so the next person will also start by assuming it is their own setup.
Suggestions, in order of cost
- If the pasted credentials genuinely are not used, remove or disable those fields for this connector, or label them clearly. That alone would save every future user the hour.
- Surface the actual
client_idandredirect_uriin the error surface so a user can tell in one glance whose client failed. - Register the correct redirect URI on the connector's OAuth client, if that is all this is.
- If the connector is not currently supported, marking it as such in the directory would be kinder than an install flow that cannot complete.
Workaround for anyone who lands here
Skip the directory connector. A ~250-line stdio MCP server calling bq with your own gcloud credentials works today, on any plan, with no OAuth involved:
claude mcp add bigquery \
-e BQ_PROJECT=your-project \
-e BQ_DATA_PROJECT=project-that-owns-the-data \
-e BQ_LOCATION=your-location \
-- /path/to/bigquery_mcp.py
Points worth building in if you write your own: enforce read-only in code rather than in the prompt (asked to delete rows, a model will write DELETE FROM), --dry_run every query first and refuse above a byte cap, and grant the identity bigquery.jobUser + dataViewer and not dataEditor so the warehouse refuses writes even if the code is wrong.
3 Comments
Follow-up from the same investigation — I filed this about the built-in connector's
redirect_uri_mismatch, then hit a second, separate problem while running the stdio-MCP workaround. Posting it here rather than as a new issue because it's one thread start to finish.To be clear about scope: this is not a claim that the built-in BigQuery connector is fixed, or that the workaround is verified end-to-end. The OAuth problem in the original post stands. This is one additional, reproducible finding about the MCP client's behaviour.
What happened. Running a custom stdio MCP server (BigQuery over the user's own
gcloudcredentials), Claude Desktop loaded it, discovered its tools, and called them — but queries appeared to "crash the connector."The numbers that make it actionable:
bqquery on that machine measured 30–90 seconds (a slow/nested VM; eachbqinvocation cold-starts Python + gcloud).%APPDATA%\Claude\logs\mcp-server-*.log) showed zero errors, zero exceptions, zero disconnects across the whole session — the server was still servicing the call.So a slow-but-correct tool is indistinguishable from a crashed one from the user's seat, and the surfaced error points at the wrong layer.
Requests, most useful first:
For anyone hitting this meanwhile: the server-side fix is to stop paying a per-call subprocess — call the BigQuery REST API directly and cache the access token (and prime it at server start), which took a 30–90s call down to well under a second. That's a workaround for slow backends, not a substitute for a configurable client timeout.
Second repro, different symptom —
Authorization with the MCP server failed, notredirect_uri_mismatchAdding a data point from claude.ai web (Max plan, consumer Google account, macOS). Same connector, but the failure surfaces later in the flow than in the original report: Google consent succeeds, then the connector fails with
Authorization with the MCP server failed. Three attempts, three references:ofid_956d55c61d0815d2,ofid_94db99e472885a96,ofid_8ce1af5a60ecfe7d.Posting because I spent roughly two hours assuming it was my Google Cloud config, exactly as the original reporter predicted. It wasn't. Everything on the Google side verified correct:
| Checked | Result |
|---|---|
| MCP endpoint auth |
tools/callonbigquery.googleapis.com/mcp→ HTTP 200 with my own gcloud token; 401 without one (control) || Scope |
/.well-known/oauth-protected-resource/mcpadvertisesauth/bigquery; the consent screen granted exactly that || IAM |
roles/mcp.toolUser+roles/bigquery.jobUser+roles/bigquery.dataViewer, all verified by read-back || OAuth client | Web application,
https://claude.ai/api/mcp/auth_callbackregistered || Audience | In production — no test-user gate |
| Discovery |
/.well-known/oauth-protected-resource/{mcp,list_dataset_ids}→ 200, valid metadata |So the MCP server accepts my identity and advertises the scope I hold, while the connector cannot authorise. That is consistent with this issue's hypothesis that the pasted client isn't used — I did not capture the outgoing
client_idmyself, so I'm corroborating rather than confirming it.One caution on the existing workaround, re: the timeout comment above — shelling out to
bqper call is what makes it slow enough to look like a crash. Calling the REST API (POST /bigquery/v2/projects/{p}/queries) with a token cached at server start keeps queries well under a second and avoids the issue entirely. Worth building in from the start rather than as a fix.Echoing the original suggestion: if the pasted Client ID and Secret genuinely are unused, removing or labelling those fields would save every future user the detour.
**Workaround that actually works: skip the directory connector, add the same URL as a custom connector**
Following up on my earlier comment — I got this working. The directory connector still fails, but the custom-connector path succeeds, and the difference is visible in the OAuth request.
The recipe
Google Cloud BigQuerydirectory connector (Connectors → the connector → ⋮ → Remove). This is also the "clean retry" the original post couldn't find — removing is the only way to clear stored credentials.https://bigquery.googleapis.com/mcphttps://claude.ai/api/mcp/auth_callbackin Authorized redirect URIsAuthorization with Google Cloud BigQuery failedfor me every time.Why this works where the directory connector doesn't
With the custom connector, the authorization request carries my client id:
That is direct evidence for this issue's hypothesis: the custom path uses the client you supply, and the directory path apparently does not.
Verified end to end
A query through the connector returned rows matching what
bqreturns independently on the same data (top 3 USA names 1910-2013: James 4,942,431 / John 4,834,422 / Robert 4,718,787).Two things worth doing afterwards
Execute sql(write-capable) sits under Write/delete tools. Set that group to Blocked, and grant the identitybigquery.jobUser+bigquery.dataViewerand notdataEditor, so writes fail at IAM too.bigquery.googleapis.com/quota/query/usage(unit1/d/{project}, value in MiB) to 30720 = 30 GiB/day via the Service Usage API, so a month at the daily maximum still fits inside the 1 TiB/month free tier.The suggestion in the original post stands, with one addition: if the directory connector's credential fields are genuinely unused, remove them — and in the custom connector, the secret field being labelled "(optional)" is what cost me four failed attempts.