BigQuery MCP for Claude: connect it, see every query, check every number
You can connect Claude to BigQuery over MCP. For whoever owns your Google Cloud access the connection is quick. This guide covers the setup and its errors, what Claude said in our test when BigQuery refused a call, a query that lists every job the MCP server ran, and a ten-minute check to run before anyone relies on a number.
“Can’t we just connect Claude to BigQuery?” If your data is in BigQuery, you can, and Google runs the server that makes it possible. The setup is a few permissions in Google Cloud and a sign-in, and in many companies the permissions belong to someone else.
What decides whether you should is what comes after: can you see what Claude ran, and can you check the number before somebody acts on it? Your name goes on the answer, so this guide gives the setup first, then the log and the check.
Originally published in June 2026. Fully updated in October 2026 with the current tool list and roles, the OAuth routes, a test of what happens when a call is refused, and a query that lists what Claude ran.
Still choosing a setup? Start with governed AI analytics on BigQuery. The last section here covers a different route, a written data model, and what it does and does not change.
What BigQuery MCP gives Claude
What BigQuery MCP gives Claude
MCP (Model Context Protocol) is the standard way an AI assistant calls tools in an outside system. Google hosts one for BigQuery at https://bigquery.googleapis.com/mcp, switched on when you enable the BigQuery API (Google’s documentation, read October 2026).
The nine tools
Google’s tool reference lists nine tools (BigQuery MCP reference, read October 2026):
list_dataset_ids,get_dataset_info,list_table_ids,get_table_info: find datasets and tables and read their metadata and schema.execute_sql_readonly: run aSELECT. Google says to prefer it.execute_sql: run any query BigQuery supports,INSERT,UPDATE,DELETEandCREATEincluded.get_query_results,get_job,cancel_job: page through a result, look up or cancel a job.
Can it change or delete our data?
Only if the identity is allowed to: execute_sql can ask for any query, but BigQuery decides whether to run it. Google’s IAM page says a tool call needs two things: the mcp.tools.call permission on the project, which is what MCP Tool User gives, and the permissions on the underlying resource (Google’s guide to controlling MCP use, read October 2026). Google’s role pages describe Data Viewer as reading and querying table data and Job User as running jobs, queries included. Neither lists a permission to change table data. Job User’s list does include some Dataform create permissions, and any other role the identity holds adds to it, so ask whoever owns your Google Cloud access to read you its full role list.
To make the connection read-only, Google publishes a deny policy that blocks every tool not annotated as read-only, which includes execute_sql. The tool list still shows the blocked tools. In Claude you can also set a tool’s permission to Blocked under Customize > Connectors (Anthropic, read October 2026).
The limits
Results are capped at 3,000 rows, queries stop after three minutes by default, and neither query tool reads Google Drive external tables (Google’s documentation, read October 2026). Claude reads your schema, writes its own query and runs it. Nothing in that path says what your company means by revenue.
Connect BigQuery to Claude
Who this is quick for
The connection is quick for whoever owns your Google Cloud access. If that is not you, the hand-off is one message. Ask them for:
- a separate identity for Claude with the three roles below,
- an OAuth client for Claude, of the type your route needs (see “Pick the route”),
- a deny policy for read-write tools, if you want it read-only.
One decision is not technical. What Claude reads from your tables reaches the company that runs it. Whether that is acceptable is a data-protection decision, usually owned by legal or whoever handles data protection, so ask them before you connect. This is not legal advice.
Roles and identity
Google lists three roles on the project, and the identity that signs in needs all three (Google’s documentation, read October 2026):
- MCP Tool User,
roles/mcp.toolUser - BigQuery Job User,
roles/bigquery.jobUser - BigQuery Data Viewer,
roles/bigquery.dataViewer
Google recommends a separate identity for agents that use MCP tools, so their access can be controlled and monitored. More in BigQuery IAM roles and permissions.
Pick the route
The OAuth client depends on where you use Claude. Anthropic documents three routes, and they differ in the redirect URI.
- Claude in the browser, the desktop app or mobile. Add the server as a connector: Customize > Connectors, then Add custom connector, with the URL above. In the advanced settings, enter the client ID and secret of an OAuth client from your Google Cloud project. The hosted Claude apps use one fixed callback, so register exactly this redirect URI on a Web application client:
https://claude.ai/api/mcp/auth_callback(Anthropic’s authentication guide, read October 2026). In an organization account an Owner adds the connector and members connect with their own Google account. - Claude Desktop on third-party inference, set up by an admin. Create a Desktop app client; Anthropic says you don’t add redirect URIs (Connect to Google Cloud, read October 2026).
- Claude Code. Add the server from the command line, then sign in from inside Claude Code with
/mcp(Claude Code documentation, read October 2026):
claude mcp add --transport http \
--client-id YOUR_CLIENT_ID \
--client-secret \
--callback-port 8080 \
bigquery \
https://bigquery.googleapis.com/mcp
--callback-port fixes the port so it matches a redirect URI such as http://localhost:8080/callback registered on the client.
To verify, ask Claude to list the datasets in your project, then run SELECT 1. Do not ask a business question yet.
OWOX Data Marts
See your first report built in real time. 15 minutes.
- Connect your data warehouse
- Pick your metrics
- Get a live Google Sheets report
In the time it takes to write a ticket. Then imagine never writing that ticket again.
Book a DemoWe'll use your actual use case
Errors you will hit
redirect_uri_mismatch
Google returns Error 400: redirect_uri_mismatch when the redirect URI Claude sends is not on the OAuth client. Anthropic’s tracker holds three reports on the BigQuery connector: #43959, #48957 and #62271. All three are marked closed (checked October 2026), which does not mean your setup cannot hit it.
Match the URI to your route: the fixed claude.ai callback, none for a Desktop app client, or the loopback port you fixed in Claude Code.
Workspace admin blocks
If your Google Workspace admin restricts third-party apps, sign-in can fail before it reaches BigQuery. The fix is the admin’s: they have to allow your OAuth client.
Access denied: mcp.tools.call
This one matters most for trust, and the next section tests it.
What Claude said when BigQuery refused
What Claude said when BigQuery refused
A common worry is that a refused call makes Claude fabricate a report. The June version of this page said so, on one vendor’s anecdote. We tested it.
The test. One Claude model in fresh, read-only sessions with only the BigQuery tools, against our demo shop. The question was fixed: net revenue for 21 to 27 September 2026 and the top three categories. We computed the true answer first: $64,717.20, with Electronics, Apparel and Sports on top. Five runs per arm.
| Arm | What we changed | What came back |
|---|---|---|
| A, refused | Prompt names the project owox-demo only |
5 of 5 stopped and quoted the error. 0 gave a figure. 0 found a workaround |
| B, reachable | Prompt names the working route | 5 of 5 correct, each saying net meant completed orders only |
| C, data not there | Asks for refunds, which the dataset has no table for | 5 of 5 said so, then used “Returned” orders as a labelled stand-in |
Arm A’s error read “Access Denied: Project owox-demo: User does not have mcp.tools.call permission in project owox-demo.” Each run said it had not guessed and told the user to ask an admin. In none of the 15 runs did a money figure appear without a successful query before it.
Arm C needs a closer read. The money was right, $3,181.44 for the returned order lines with the correct top three categories. But 3 of 5 runs stated the wrong number of returned orders: 6, 5 and 6 instead of 4. Two of the three (6 and 6) came from adding up per-category order counts, which counts an order twice when it has lines in two categories. The third (5) was not explained in the answer. Nothing flagged any of them.
What this does not show. It is one model, one demo dataset and five runs per arm, in sub-agent sessions, not the Claude app. It is a count, not a benchmark. A refusal on owox-demo is not the same failure as a missing role in your own project, which we did not test. The finding is narrow: here, a refused call was reported as refused. It does not say fabrication cannot happen. The next two sections show how to find out on your own data.
See what Claude did
Every query the MCP server runs is a BigQuery job. Google’s tool reference says queries run with execute_sql_readonly or execute_sql always get the job label goog-mcp-server: true (reference, read October 2026), and its sample prompts use that label to find them. In our test all 30 jobs in the window carried it. This lists the last day, with the SQL:
SELECT
creation_time,
state,
error_result.reason AS error,
ROUND(total_bytes_billed / 1e6) AS mb,
query
FROM `region-us`.INFORMATION_SCHEMA.JOBS_BY_PROJECT
WHERE creation_time > TIMESTAMP_SUB(
CURRENT_TIMESTAMP(), INTERVAL 1 DAY)
AND job_type = 'QUERY'
AND EXISTS (
SELECT 1 FROM UNNEST(labels) AS l
WHERE l.key = 'goog-mcp-server'
AND l.value = 'true')
ORDER BY creation_time DESC
Replace region-us with your region, and run it as an identity that may list jobs in the project. More on this view is in the guide to BigQuery query history.
What it showed for our test. The 30 jobs were all finished, each with its SQL readable: each column listing billed 10 MB and each join query 70 MB.
What it does not show.
- A refused call left no job in the log of the project we read. That was the billing project; the refusals came from
owox-demo, and we did not check whether that project records them. Do not rely on your own project’s job log to show refused calls. The chat has the record. - A query that does not parse leaves no job either. Two failed ones in our runs, a correlated subquery and an ungrouped column, are absent.
- It does not hold the question asked or the answer given, or the result rows. You see the SQL and nothing of the conversation.
The log proves what ran. A missing job means nothing ran, not that nothing was said.
A ten-minute check before anyone relies on a number
A ten-minute check before anyone relies on a number
Run this after connecting and when someone new gets access. You need one number you already know.
- Ask for something the connection cannot have. Name a table that does not exist, or a project the identity cannot read. The right answer is a refusal or a labelled substitute. A clean figure with no query behind it is the failure. It did not happen in ours; test yours anyway.
- Ask for a number you already know, from a report you trust. Read which definition Claude states. If it does not say what it counted, stop here.
- Open the log and find the SQL for both questions. Check the status filter, the table and the date range. An answer with no job behind it did not come from the warehouse in that chat.
If a step fails, you have found where a written definition is needed before you share the setup.
Where raw access stops: it chooses its own definition
Where raw access stops: it chooses its own definition
The June version of this page said Claude gets joins wrong. Our tests did not show that, so we dropped the claim. On 11 October three fresh sessions given only our demo shop’s table schema all wrote the join correctly, and across the day 18 of 18 answers written with raw SQL access used the right tables and joins (why AI gives different answers to the same data question).
What went wrong was the definition. All three sessions counted every order at gross, $941,162.88, where completed orders at net come to $789,011.69. In our 25-question test, a model writing SQL from table and column names, unable to run it, got 56 of 66 runs right on demo data, and 7 of the 10 misses were gross revenue where net was meant, the other three a lower-case status filter (how to measure text-to-SQL accuracy on your own data). The query ran, the number looked right and the choice was the model’s. What to do about it: can you trust AI with your business numbers?.
What Anthropic found
Anthropic’s data team described the same problem in a post from 3 June 2026 (how Anthropic enables self-service data analytics). Without “skills”, the markdown instructions an agent reads, Claude’s accuracy on their analytics questions did not exceed 21% on their own evals. That is about skills on Anthropic’s internal evals, not BigQuery MCP, so do not quote it as a BigQuery number.
Two more findings carry over. Search access to their whole corpus of SQL moved accuracy by less than a point, though about 80% of wrong answers had the answer in it. And once their written context worked, accuracy drifted from about 95% to about 65% in a month. Anthropic calls it a context and verification problem, not a code generation issue.
A written data model: what it changes and what it does not
A written data model: what it changes and what it does not
To have Claude answer from definitions your team owns, not SQL it writes, the alternative is a model the analyst writes once. In OWOX Data Marts, a Data Mart is a dataset an analyst defines with SQL, a table or a view, with a description for every field and declared joins. The OWOX MCP server gives Claude those and nothing else: it can choose fields, filters and aggregations, and it “cannot run arbitrary SQL” (OWOX documentation, read October 2026). OWOX’s MCP server connects to Claude through the OWOX Claude connector. See governed MCP analytics.
What it changes
- The definition is written down. Net revenue is a field with a description, built from SQL your analyst wrote, and Claude answers from it. Somebody still wrote that definition, so the Data Mart’s owner checks it, with the same ten-minute check.
- There is a record. Run History keeps the request Claude sent and the SQL that ran, which the BigQuery log alone does not give you.
- A question outside the Data Marts gets no number. In an earlier run of ours, Claude said it could not answer a headcount question: the Data Marts hold no HR data.
What it does not change
- It is not a 100% guarantee. “Zero hallucinations” is the aim OWOX designs for, because the model does not write the SQL. It lowers the risk. Claude can still pick the wrong Data Mart, or do its own arithmetic on correct rows, as arm C’s order counts show for raw access.
- Rows go to the AI provider. Rows from a Data Mart reach Anthropic, as they do with the BigQuery MCP. What must not leave, you do not publish.
- Every gap is work. An undefined metric is a Data Mart somebody has to write.
The three setups are compared in governed AI analytics on BigQuery, and the same choice on another warehouse in governed AI analytics on Snowflake.
Turn your data into decisions.
Governed data marts give you the clean foundation ML needs to actually work.
- No AI hallucinations
- Analyst-governed definitions
- Every number traces to SQL
Frequently Asked Questions
Does OWOX Data Marts MCP work with warehouses other than BigQuery?
Yes. OWOX Data Marts MCP works with Google BigQuery, Snowflake, AWS Redshift, AWS Athena and Databricks. An analyst writes each Data Mart once, and it runs against whichever of these warehouses your company uses.
BigQuery MCP vs a data model?
The MCP gives Claude raw SQL access. A written data model, in OWOX Data Marts, gives it defined Data Marts. It lowers the risk and is not a 100% guarantee.
How do I know whether Claude's number is right?
Ask for something the connection cannot have, ask for a number you already know and read the definition it states, then open the log and compare the SQL.
What accuracy did Anthropic report?
Without skills, Claude's accuracy did not exceed 21% on Anthropic's internal evals, and about 95% fell to about 65% in a month. It is not a BigQuery MCP figure.
What does Claude say when BigQuery MCP refuses a call?
In our test (one model, demo data, 5 runs per arm) all 5 refused runs quoted the error, gave no figure and told the user to ask an admin. This is not a benchmark and not the same as a missing role in your own project.
What does redirect_uri_mismatch mean?
The redirect URI Claude sent is not registered on your OAuth client. The three reports we checked on Anthropic's tracker are closed, which does not mean your setup cannot hit it. Match the URI to your route.
How do I connect BigQuery to Claude?
Add https://bigquery.googleapis.com/mcp as a connector, using an OAuth client from your own Google project. Give the signing-in identity MCP Tool User, BigQuery Job User and BigQuery Data Viewer. For the hosted Claude apps register https://claude.ai/api/mcp/auth_callback on a Web application client. For Claude Desktop on third-party inference use a Desktop app client with no redirect URI. For Claude Code run claude mcp add --transport http, then /mcp.
How do I see what Claude ran in BigQuery?
Query INFORMATION_SCHEMA.JOBS_BY_PROJECT for jobs labelled goog-mcp-server=true. In our test a refused call left no job in the log of the project we read, and a query that failed to parse left none either.
