bq-cost-guard
Allows estimating the cost of a BigQuery query before running it by performing a free dry run. Reports bytes processed, estimated on-demand cost in USD, and warnings for wasteful patterns such as SELECT * and missing partition filters, using Google Cloud Application Default Credentials.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@bq-cost-guardestimate the cost of this query before running it: SELECT * FROMmy-proj.sales.orders"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
bq-cost-guard
An MCP server that estimates the cost of a
BigQuery query before you run it. It exposes a single tool,
estimate_query_cost, which:
runs a BigQuery dry run (free — no data is read or billed) using your Application Default Credentials,
reports bytes processed and the estimated on-demand cost in USD, and
returns warnings for common sources of wasted spend:
SELECT *(andSELECT t.*) — scanning columns you don't needNo partition filter — a partitioned table referenced by the query is scanned without a filter on its partition column (or
_PARTITIONTIME/_PARTITIONDATE)
Example output
{
"bytesProcessed": 1099511627776,
"bytesProcessedHuman": "1.00 TiB",
"estimatedCostUsd": 6.25,
"currency": "USD",
"usdPerTib": 6.25,
"cacheHit": false,
"warnings": [
{
"type": "SELECT_STAR",
"message": "Query selects every column (SELECT *). Request only the columns you need to reduce bytes scanned."
},
{
"type": "NO_PARTITION_FILTER",
"table": "my-proj.sales.orders",
"partitionColumn": "created_at",
"message": "`my-proj.sales.orders` is partitioned by the partition column `created_at`, but the query has no filter on it, so the whole table will be scanned. Add a filter on the partition column (or _PARTITIONTIME / _PARTITIONDATE)."
}
]
}Errors (invalid SQL, missing permissions, ...) are returned as normal tool errors and never crash the server.
Related MCP server: BigQuery FinOps MCP Server
Prerequisites
Node.js ≥ 22.18
A Google Cloud project with the BigQuery API enabled
Permission to run dry runs (
bigquery.jobs.create) and to read table metadata (bigquery.tables.get) — the latter is only needed for the partition-filter warnings; if metadata can't be read, the cost estimate still works and the warning is silently skipped
Install
git clone <this repo> bq-cost-guard
cd bq-cost-guard
npm install
npm run buildThis produces the executable entry point at dist/src/index.js.
Authentication (Application Default Credentials)
No credentials live in this repository. The server authenticates with Application Default Credentials. Pick one of:
gcloud (recommended for development)
gcloud auth application-default login gcloud config set project your-project-idService-account key file (kept outside the repo)
export GOOGLE_APPLICATION_CREDENTIALS="$HOME/keys/bq-cost-guard-sa.json"Point it at a key file stored anywhere outside the checkout — the
.gitignorein this repo blocks key files from being committed, but you should still keep keys outside the project tree.Workload identity — on GCE / GKE / Cloud Run / Cloud Shell, ADC is provided automatically; set
GOOGLE_CLOUD_PROJECTif it cannot be inferred.
MCP client configuration
The server communicates over stdio. Replace /absolute/path/to/bq-cost-guard
with the real checkout path.
Claude Desktop
Edit claude_desktop_config.json
(macOS: ~/Library/Application Support/Claude/claude_desktop_config.json,
Windows: %APPDATA%\Claude\claude_desktop_config.json):
{
"mcpServers": {
"bq-cost-guard": {
"command": "node",
"args": ["/absolute/path/to/bq-cost-guard/dist/src/index.js"],
"env": {
"GOOGLE_CLOUD_PROJECT": "your-project-id"
}
}
}
}Claude Code
claude mcp add bq-cost-guard \
--env GOOGLE_CLOUD_PROJECT=your-project-id \
-- node /absolute/path/to/bq-cost-guard/dist/src/index.jsCursor
Add the same block to ~/.cursor/mcp.json (project-level: .cursor/mcp.json):
{
"mcpServers": {
"bq-cost-guard": {
"command": "node",
"args": ["/absolute/path/to/bq-cost-guard/dist/src/index.js"],
"env": {
"GOOGLE_CLOUD_PROJECT": "your-project-id"
}
}
}
}Any other stdio MCP client can use the same command/args/env shape. If
you rely on a key file, add "GOOGLE_APPLICATION_CREDENTIALS": "/abs/path/to/key.json"
to env (or export it in the shell the client inherits).
Environment variables
Variable | Required | Default | Purpose |
| no | inferred | Default project for the BigQuery client |
| no | — | Absolute path to a service-account key file (outside the repo) |
| no |
| On-demand price in USD per TiB scanned |
Tool reference
estimate_query_cost
Argument | Type | Description |
|
| BigQuery standard SQL to estimate |
Returns bytesProcessed, bytesProcessedHuman, estimatedCostUsd,
currency, usdPerTib, cacheHit, and warnings[] (see example above).
How the warnings work
SELECT * — heuristic token scan of the SQL with comments and string literals removed;
count(*)and friends do not trigger it.NO_PARTITION_FILTER — the tool extracts
FROM/JOINtable references (skipping CTEs, subqueries,UNNEST, wildcard and INFORMATION_SCHEMA references), reads each table's metadata to see whether it is partitioned (time- or range-partitioned), and checks the query'sWHERE/ONclauses for the partition column or the_PARTITIONTIME/_PARTITIONDATEpseudo columns. Tables whose metadata can't be read are skipped silently.
Both are best-effort heuristics meant to prompt a second look, not a full SQL parser.
Pricing notes
The cost figure is bytesProcessed / 1024^4 × usdPerTib at the on-demand
list price (default $6.25/TiB, override with BQ_COST_GUARD_USD_PER_TIB).
It ignores reservations/editions and flat-rate pricing, free-tier monthly
credits, storage and other charges, and result-cache effects (a cacheHit
flag is reported instead). Treat it as an estimate, not a bill.
Development
npm test # unit tests (BigQuery client fully mocked, no network/GCP access)
npm run typecheck # tsc --noEmit
npm run build # emit dist/
npm start # run the built server on stdioTests use Node's built-in test runner with the BigQuery client replaced by a
mock of the exact client surface used here (query({ dryRun: true }) and
dataset().table().getMetadata()), so the suite runs without credentials or
network access. The MCP protocol surface is tested end-to-end over an
in-memory transport.
Project layout:
src/
index.ts # entry point: wires real BigQuery client + stdio transport
server.ts # MCP server + estimate_query_cost tool registration
estimator.ts # bytes/cost/warnings orchestration
bigquery.ts # thin adapter over @google-cloud/bigquery (dry run + metadata)
sql.ts # pure SQL text analysis (SELECT *, table refs, partition filters)
cost.ts # pricing math and formatting
test/ # unit tests with the BigQuery client mockedLicense
Available Tools
1 toolestimate_query_costEstimate BigQuery query costARead-onlyIdempotent
Runs a BigQuery dry run (free; no data is read or billed) for the given standard SQL and returns bytes processed, the estimated on-demand cost in USD, and warnings such as SELECT * usage or missing filters on partitioned tables.
| Name | Required | Description | Default |
|---|---|---|---|
| sql | Yes | BigQuery standard SQL query to estimate, e.g. SELECT ... FROM ... |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/openWorld/idempotent, so the bar is lower, yet the description adds real value beyond them: the dry run is free and reads/bills no data, and it enumerates what comes back (bytes processed, USD estimate, warnings). It does not mention permission requirements or rate limits, so not a full 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single sentence with the core action, the cost constraint, and the return payload front-loaded. No filler and no redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, so the description must cover returns, and it does (bytes processed, cost in USD, warnings like SELECT * or missing partition filters). Combined with annotations carrying the safety profile, an agent has everything needed to invoke and interpret it.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Only one parameter exists and schema description coverage is 100%, so the schema already documents the `sql` field. The description's restatement ('for the given standard SQL') matches, not exceeds, that documentation. Baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Runs a BigQuery dry run ... for the given standard SQL') and immediately scopes the outcome (bytes processed, estimated cost, warnings). No siblings exist, so no differentiation is needed, and the tool's function is unmistakable.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Clearly conveys the context for use: estimate cost before an actual query, and the dry run is free. It stops short of explicit when-not guidance (e.g., non-standard SQL, unsupported statements), but there are no siblings to route between.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
1 tool update
v0.1.0- First observed
estimate_query_cost
TDQS
Scored across 1 tool
There is only one tool, so there is no possibility of confusion or misselection. Its purpose (dry-run cost estimation) is unmistakable.
The single name 'estimate_query_cost' follows a clean verb_noun convention and is descriptive. No inconsistent conventions exist to penalize.
A single tool is thin even for a narrow 'cost guard' purpose; there is no way to estimate multiple queries, compare variants, or inspect table metadata. It functions but feels minimal.
Core dry-run cost estimation is covered with useful warnings, but the surface is a dead end: no schema/table inspection, partition discovery, or cost comparison to support the guard workflow. Notable gaps remain for a cost-management domain.
Maintenance
Related MCP Connectors
Query OneLens cloud-cost data in natural language: breakdowns, trends, cost centers. Read-only.
Create AWS cost estimates and shareable AWS Pricing Calculator URLs.
AWS pricing and cost estimates with no signup, plus read-only idle-resource scans of your account.
Query cloud, AI and SaaS spend across 25+ providers: costs, budgets, anomalies, unit economics.
Related MCP Servers
- AlicenseBqualityBmaintenanceEnables validation and dry-run analysis of BigQuery SQL queries without execution. Provides cost estimates, schema previews, and syntax validation for BigQuery queries.958 PyPI1MIT
- FlicenseNot gradedqualityDmaintenanceEnables cost optimization and financial operations for Google BigQuery through natural language interactions. Provides insights into BigQuery spending, usage patterns, and cost management recommendations.-
- AlicenseAqualityFmaintenanceValidates BigQuery SQL syntax and performs dry-run analysis without executing queries, providing cost estimates, referenced tables, and schema previews.2Apache 2.0
- FlicenseNot gradedqualityDmaintenanceEnables reviewing BigQuery SQL queries for performance issues, cost estimation, and suggested rewrites via an MCP interface.1-