BigQuery MCP: Querying Google Cloud Data From an Agent
Google now offers two ways to put BigQuery behind an AI assistant: a managed remote MCP server and the open-source MCP Toolbox for Databases. What each one exposes, the IAM roles to grant, how to keep it read-only, how to stop a runaway query from costing you, and setup in Claude Code and Gemini CLI.
7 min read
BigQuery MCP gives an AI assistant tools to list datasets and tables, read schemas and run SQL against your Google Cloud data. There are two routes from Google today. The managed BigQuery MCP server is a remote endpoint at https://bigquery.googleapis.com/mcp that Google runs for you, turned on with the BigQuery API and controlled with IAM. MCP Toolbox for Databases is an open-source server you run yourself, with a prebuilt BigQuery configuration and settings for read-only mode, allowed datasets and a per-query byte cap. Either way, the safe setup is the same: a separate identity for the assistant, read-only roles on the datasets it needs, the read-only query tool, and a limit on how many bytes a query may bill.
The two routes, and what each one is
- The managed remote server. Google’s guide to using the BigQuery MCP server (opens in a new tab) says it is enabled when you enable the BigQuery API, uses Streamable HTTP, and signs in with OAuth 2.0 and IAM. Google’s list of supported products marks several other Google Cloud MCP servers as Preview, such as the BigQuery Data Transfer Service one, but not BigQuery itself.
- MCP Toolbox for Databases. An open-source server that runs on your machine or your own infrastructure and talks to BigQuery with your Application Default Credentials. Its prebuilt BigQuery configuration (opens in a new tab) adds tools the managed server does not have, such as
forecast,analyze_contribution,search_catalogandask_data_insights. - Gemini CLI extensions. Google publishes BigQuery Data Analytics and Conversational Analytics extensions for Gemini CLI, which bundle the Toolbox tools so there is nothing else to install.
Google points you to the local Toolbox when you want a custom tool built over a parameterized query, or when you cannot enable the managed server in your project. Scheduling, permissions and reservations are not in either; Google routes those through the Google Cloud CLI MCP server, which is still Preview.
What the managed server can do
- Metadata:
list_dataset_ids,get_dataset_info,list_table_idsandget_table_info. - Queries:
execute_sql_readonly, which allows onlySELECTstatements, andexecute_sql, which runs anything BigQuery supports, includingINSERT,DELETE,CREATEandDROP. - Jobs:
get_query_results,get_jobandcancel_job, for queries that outlast the synchronous wait of 20 seconds.
Google’s docs say execute_sql is the only tool that is not read-only. The limits are worth knowing before you design around it: queries through either SQL tool are canceled after three minutes, results stop at 3,000 rows, Google Drive external tables are not supported, and the read-only tool rejects DML, DDL, Python UDFs and Graph Query Language. Every query it runs carries the job label goog-mcp-server: true and is billed to the project named in the call, so you can find agent queries in your job history later.
IAM: a separate identity with read-only roles
An MCP tool call needs two things: the mcp.tools.call permission on the project, and the ordinary BigQuery permission for whatever the tool touches. Google lists three roles for the managed server: MCP Tool User (roles/mcp.toolUser) to make tool calls, BigQuery Job User (roles/bigquery.jobUser) to run jobs, and BigQuery Data Viewer (roles/bigquery.dataViewer) to read data. Grant the first two on the project and Data Viewer on the datasets in scope, not the whole project.
Google recommends a separate identity for agents, rather than your own login, so its permissions can be narrower and its queries show up under its own name in the logs. Signed in as you, the assistant can do everything you can.
Then take execute_sql away. Google’s page on controlling MCP use with IAM (opens in a new tab) gives a deny policy that blocks any tool call to a tool not annotated read-only. Its example applies to every principal in the project; narrow deniedPrincipals if some people still need the write tool. Note that tools/list still shows every tool; the deny policy acts on tools/call.
{
"rules": [
{
"denyRule": {
"deniedPrincipals": ["principalSet://goog/public:all"],
"deniedPermissions": ["mcp.googleapis.com/tools.call"],
"denialCondition": {
"title": "Deny read-write tools",
"expression": "api.getAttribute('mcp.googleapis.com/tool.isReadOnly', false) == false"
}
}
}
]
}With Toolbox, the switches live in the server. Set BIGQUERY_READONLY to true and write-capable tools are suppressed and only SELECT runs; allowedDatasets in a custom configuration rejects any query that touches a dataset outside the list; and results default to 50 rows. As with any database, these are the second layer. The first is a role that cannot write, as database MCP servers explains in general.
Cost controls: dry runs and maximum bytes billed
On on-demand pricing, BigQuery bills by bytes processed, and an assistant that writes SELECT * over a wide, unpartitioned table will cheerfully scan all of it. Two controls stop that before it happens.
- A dry run. The managed server’s query tools accept a
dryRunflag: BigQuery validates the query and returns how many bytes it would process, without running it. Ask the assistant to dry-run anything that touches a large table and show you the estimate first. - Maximum bytes billed. Google’s guide to estimating and controlling costs (opens in a new tab) recommends it: BigQuery estimates the bytes before execution, and a query over the limit fails without incurring a charge. Toolbox sets it for every query with
BIGQUERY_MAXIMUM_BYTES_BILLED. The managed server’s tool reference lists no such field, so use a quota there instead. - Custom query quotas. Custom quotas (opens in a new tab) cap bytes processed per day, for the whole project or for each user and service account in it. Google calls them approximate, a safeguard rather than a hard stop, and they apply to on-demand pricing only. You cannot set a quota for one identity alone, which is one more reason to give agent work its own project.
After a week, query your job history for the goog-mcp-server label, or the labels Toolbox adds, and see what the assistant actually scanned.
Setup in Claude Code
The simplest route is Toolbox as a local stdio server. Sign in once with gcloud auth application-default login, as the identity the assistant should use, then add the server to .mcp.json in your project with read-only mode and a byte cap:
{
"mcpServers": {
"bigquery": {
"command": "./PATH/TO/toolbox",
"args": ["--prebuilt", "bigquery", "--stdio"],
"env": {
"BIGQUERY_PROJECT": "my-analytics-project",
"BIGQUERY_READONLY": "true",
"BIGQUERY_MAXIMUM_BYTES_BILLED": "10000000000"
}
}
}
}The managed server takes more setup, because Google does not offer dynamic client registration. Create an OAuth client of type Web application in Google Auth Platform with the redirect URI https://claude.ai/api/mcp/auth_callback, then add https://bigquery.googleapis.com/mcp as a custom connector in Claude with the client ID and secret under Advanced settings. Claude Code’s MCP documentation (opens in a new tab) says connectors you add in claude.ai appear in Claude Code automatically when you are signed in with that account. Run /mcp to confirm the tools, and keep every SQL call on ask; auto-approve in Claude Code covers the settings.
Setup in Gemini CLI
For Toolbox, install Google’s extension and set your project: export BIGQUERY_PROJECT="my-analytics-project", then gemini extensions install https://github.com/gemini-cli-extensions/bigquery-data-analytics. For the managed server, Google’s client guide uses an extension file that signs in with your Application Default Credentials:
{
"name": "bigquery-remote",
"version": "1.0.0",
"mcpServers": {
"bigquery": {
"httpUrl": "https://bigquery.googleapis.com/mcp",
"authProviderType": "google_credentials",
"oauth": {
"scopes": ["https://www.googleapis.com/auth/bigquery"]
},
"timeout": 30000,
"headers": {
"x-goog-user-project": "my-analytics-project"
}
}
}
}Start gemini and run /mcp to see the tools. Check how you sign in to Gemini CLI itself first: unpaid-tier and Google One accounts were moved to Antigravity CLI in June 2026, as Gemini CLI vs Claude Code notes. The Gemini CLI integration page shows how to connect a board alongside.
Prompts that keep queries cheap
- “List the tables in the sales dataset with their partitioning columns. Do not run any queries.”
- “Dry-run a query for weekly orders by region for the last 90 days, filtered on the partition column, and tell me the bytes it would process before running it.”
- “Use execute_sql_readonly only. If a query would need to write anything, stop and explain why.”
- “Summarize which of last week’s queries labeled goog-mcp-server scanned the most bytes.”
Where the findings go
BigQuery answers the question; it does not keep track of what should happen next. fenbs does that part. Connect it beside BigQuery with claude mcp add --transport http fenbs https://fenbs.ai/api/mcp, and when a query turns up a broken pipeline or a metric nobody trusts, the assistant can file it as a bug with the query and the result in the note. Each task has a plan and a test status, sits in To Do, Next Up, In Progress or Completed, and every change is recorded in History under the assistant’s name. A standing instruction, such as “always dry-run before querying the events table”, goes on the Decisions and rules page, which every connected assistant reads first. fenbs does not see your BigQuery data or log your queries; BigQuery’s own job history does that.
Related
The general checklist: database MCP servers. The same questions for another warehouse: Snowflake MCP server. How remote sign-in works: MCP OAuth explained. Connecting fenbs: the MCP docs.