# mcp-bigquery-dryrun
[](https://pypi.org/project/mcp-bigquery-dryrun/)

The `mcp-bugquery-dryrun` package provides a minimal MCP server for BigQuery SQL validation and dry-run analysis. This server provides exactly two tools for validating and analyzing BigQuery SQL queries without executing them.
** IMPORTANT: This server does NOT execute queries. All operations are dry-run only. Cost estimates are approximations based on bytes processed.**
## Features
- **SQL Validation**: Check BigQuery SQL syntax without running queries
- **Dry-Run Analysis**: Get cost estimates, referenced tables, and schema preview
- **Parameter Support**: Validate parameterized queries
- **Cost Estimation**: Calculate USD estimates based on bytes processed
## Quick Start
### Prerequisites
- Python 3.10+
- Google Cloud SDK with BigQuery API enabled
- Application Default Credentials configured
### Installation
#### From PyPI (Recommended)
```bash
# Install from PyPI
pip install mcp-bigquery-dryrun
# Or with uv
uv pip install mcp-bigquery-dryrun
```
#### From Source
```bash
# Clone the repository
git clone https://github.com/caron14/mcp-bigquery-dryrun.git
cd mcp-bigquery-dryrun
# Install with uv (recommended)
uv pip install -e .
# Or install with pip
pip install -e .
```
### Authentication
Set up Application Default Credentials:
```bash
gcloud auth application-default login
```
Or use a service account key:
```bash
export GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account-key.json
```
### Configuration
#### Environment Variables
| Variable | Description | Default |
|----------|-------------|---------|
| `BQ_PROJECT` | GCP project ID | From ADC |
| `BQ_LOCATION` | BigQuery location (e.g., US, EU, asia-northeast1) | None |
| `SAFE_PRICE_PER_TIB` | Default price per TiB for cost estimation | 5.0 |
#### Claude Code Integration
Add to your Claude Code configuration:
```json
{
"mcpServers": {
"bq-dryrun": {
"command": "mcp-bigquery-dryrun",
"env": {
"BQ_PROJECT": "your-gcp-project",
"BQ_LOCATION": "asia-northeast1",
"SAFE_PRICE_PER_TIB": "5.0"
}
}
}
}
```
Or if installed from source:
```json
{
"mcpServers": {
"bq-dryrun": {
"command": "python",
"args": ["-m", "mcp_bigquery_dryrun"],
"env": {
"BQ_PROJECT": "your-gcp-project",
"BQ_LOCATION": "asia-northeast1",
"SAFE_PRICE_PER_TIB": "5.0"
}
}
}
}
```
## Tools
### bq_validate_sql
Validate BigQuery SQL syntax without executing the query.
**Input:**
```json
{
"sql": "SELECT * FROM dataset.table WHERE id = @id",
"params": {"id": "123"} // Optional
}
```
**Success Response:**
```json
{
"isValid": true
}
```
**Error Response:**
```json
{
"isValid": false,
"error": {
"code": "INVALID_SQL",
"message": "Syntax error at [3:15]",
"location": {
"line": 3,
"column": 15
},
"details": [...] // Optional
}
}
```
### bq_dry_run_sql
Perform a dry-run to get cost estimates and metadata without executing the query.
**Input:**
```json
{
"sql": "SELECT * FROM dataset.table",
"params": {"id": "123"}, // Optional
"pricePerTiB": 6.0 // Optional, overrides default
}
```
**Success Response:**
```json
{
"totalBytesProcessed": 1073741824,
"usdEstimate": 0.005,
"referencedTables": [
{
"project": "my-project",
"dataset": "my_dataset",
"table": "my_table"
}
],
"schemaPreview": [
{
"name": "id",
"type": "STRING",
"mode": "NULLABLE"
},
{
"name": "created_at",
"type": "TIMESTAMP",
"mode": "REQUIRED"
}
]
}
```
**Error Response:**
```json
{
"error": {
"code": "INVALID_SQL",
"message": "Table not found: dataset.table",
"details": [...] // Optional
}
}
```
## Examples
### Validate a Simple Query
```python
# Tool: bq_validate_sql
{
"sql": "SELECT 1"
}
# Returns: {"isValid": true}
```
### Validate with Parameters
```python
# Tool: bq_validate_sql
{
"sql": "SELECT * FROM users WHERE name = @name AND age > @age",
"params": {
"name": "Alice",
"age": 25
}
}
```
### Get Cost Estimate
```python
# Tool: bq_dry_run_sql
{
"sql": "SELECT * FROM `bigquery-public-data.samples.shakespeare`",
"pricePerTiB": 5.0
}
# Returns bytes processed, USD estimate, and schema
```
### Analyze Complex Query
```python
# Tool: bq_dry_run_sql
{
"sql": """
WITH user_stats AS (
SELECT user_id, COUNT(*) as order_count
FROM orders
GROUP BY user_id
)
SELECT * FROM user_stats WHERE order_count > 10
"""
}
```
## Testing
Run tests with pytest:
```bash
# Run all tests (requires BigQuery credentials)
pytest tests/
# Run only tests that don't require credentials
pytest tests/test_min.py::TestWithoutCredentials
```
## Development
```bash
# Install development dependencies
uv pip install -e ".[dev]"
# Run the server locally
python -m mcp_bigquery_dryrun
# Or using the console script
mcp-bigquery-dryrun
```
## Limitations
- **No Query Execution**: This server only performs dry-runs and validation
- **Cost Estimates**: USD estimates are approximations based on bytes processed
- **Parameter Types**: Initial implementation treats all parameters as STRING type
- **Cache Disabled**: Queries always run with `use_query_cache=False` for accurate estimates
## License
Apache-2.0
## Changelog
### 0.1.0 (2024-08-12)
- Initial release
Raw data
{
"_id": null,
"home_page": null,
"name": "mcp-bigquery-dryrun",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.10",
"maintainer_email": "caron14 <caron14@users.noreply.github.com>",
"keywords": "bigquery, claude, dry-run, gcp, mcp, sql, validation",
"author": null,
"author_email": "caron14 <caron14@users.noreply.github.com>",
"download_url": "https://files.pythonhosted.org/packages/7a/21/5e4f8527d3ea758216d88c4b6cf23789d07aabad894d1fa1fc01f40bfef9/mcp_bigquery_dryrun-0.2.0.tar.gz",
"platform": null,
"description": "# mcp-bigquery-dryrun\n\n[](https://pypi.org/project/mcp-bigquery-dryrun/)\n\n\nThe `mcp-bugquery-dryrun` package provides a minimal MCP server for BigQuery SQL validation and dry-run analysis. This server provides exactly two tools for validating and analyzing BigQuery SQL queries without executing them.\n\n** IMPORTANT: This server does NOT execute queries. All operations are dry-run only. Cost estimates are approximations based on bytes processed.**\n\n## Features\n\n- **SQL Validation**: Check BigQuery SQL syntax without running queries\n- **Dry-Run Analysis**: Get cost estimates, referenced tables, and schema preview\n- **Parameter Support**: Validate parameterized queries\n- **Cost Estimation**: Calculate USD estimates based on bytes processed\n\n## Quick Start\n\n### Prerequisites\n\n- Python 3.10+\n- Google Cloud SDK with BigQuery API enabled\n- Application Default Credentials configured\n\n### Installation\n\n#### From PyPI (Recommended)\n\n```bash\n# Install from PyPI\npip install mcp-bigquery-dryrun\n\n# Or with uv\nuv pip install mcp-bigquery-dryrun\n```\n\n#### From Source\n\n```bash\n# Clone the repository\ngit clone https://github.com/caron14/mcp-bigquery-dryrun.git\ncd mcp-bigquery-dryrun\n\n# Install with uv (recommended)\nuv pip install -e .\n\n# Or install with pip\npip install -e .\n```\n\n### Authentication\n\nSet up Application Default Credentials:\n\n```bash\ngcloud auth application-default login\n```\n\nOr use a service account key:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account-key.json\n```\n\n### Configuration\n\n#### Environment Variables\n\n| Variable | Description | Default |\n|----------|-------------|---------|\n| `BQ_PROJECT` | GCP project ID | From ADC |\n| `BQ_LOCATION` | BigQuery location (e.g., US, EU, asia-northeast1) | None |\n| `SAFE_PRICE_PER_TIB` | Default price per TiB for cost estimation | 5.0 |\n\n#### Claude Code Integration\n\nAdd to your Claude Code configuration:\n\n```json\n{\n \"mcpServers\": {\n \"bq-dryrun\": {\n \"command\": \"mcp-bigquery-dryrun\",\n \"env\": {\n \"BQ_PROJECT\": \"your-gcp-project\",\n \"BQ_LOCATION\": \"asia-northeast1\",\n \"SAFE_PRICE_PER_TIB\": \"5.0\"\n }\n }\n }\n}\n```\n\nOr if installed from source:\n\n```json\n{\n \"mcpServers\": {\n \"bq-dryrun\": {\n \"command\": \"python\",\n \"args\": [\"-m\", \"mcp_bigquery_dryrun\"],\n \"env\": {\n \"BQ_PROJECT\": \"your-gcp-project\",\n \"BQ_LOCATION\": \"asia-northeast1\",\n \"SAFE_PRICE_PER_TIB\": \"5.0\"\n }\n }\n }\n}\n```\n\n## Tools\n\n### bq_validate_sql\n\nValidate BigQuery SQL syntax without executing the query.\n\n**Input:**\n```json\n{\n \"sql\": \"SELECT * FROM dataset.table WHERE id = @id\",\n \"params\": {\"id\": \"123\"} // Optional\n}\n```\n\n**Success Response:**\n```json\n{\n \"isValid\": true\n}\n```\n\n**Error Response:**\n```json\n{\n \"isValid\": false,\n \"error\": {\n \"code\": \"INVALID_SQL\",\n \"message\": \"Syntax error at [3:15]\",\n \"location\": {\n \"line\": 3,\n \"column\": 15\n },\n \"details\": [...] // Optional\n }\n}\n```\n\n### bq_dry_run_sql\n\nPerform a dry-run to get cost estimates and metadata without executing the query.\n\n**Input:**\n```json\n{\n \"sql\": \"SELECT * FROM dataset.table\",\n \"params\": {\"id\": \"123\"}, // Optional\n \"pricePerTiB\": 6.0 // Optional, overrides default\n}\n```\n\n**Success Response:**\n```json\n{\n \"totalBytesProcessed\": 1073741824,\n \"usdEstimate\": 0.005,\n \"referencedTables\": [\n {\n \"project\": \"my-project\",\n \"dataset\": \"my_dataset\",\n \"table\": \"my_table\"\n }\n ],\n \"schemaPreview\": [\n {\n \"name\": \"id\",\n \"type\": \"STRING\",\n \"mode\": \"NULLABLE\"\n },\n {\n \"name\": \"created_at\",\n \"type\": \"TIMESTAMP\",\n \"mode\": \"REQUIRED\"\n }\n ]\n}\n```\n\n**Error Response:**\n```json\n{\n \"error\": {\n \"code\": \"INVALID_SQL\",\n \"message\": \"Table not found: dataset.table\",\n \"details\": [...] // Optional\n }\n}\n```\n\n## Examples\n\n### Validate a Simple Query\n\n```python\n# Tool: bq_validate_sql\n{\n \"sql\": \"SELECT 1\"\n}\n# Returns: {\"isValid\": true}\n```\n\n### Validate with Parameters\n\n```python\n# Tool: bq_validate_sql\n{\n \"sql\": \"SELECT * FROM users WHERE name = @name AND age > @age\",\n \"params\": {\n \"name\": \"Alice\",\n \"age\": 25\n }\n}\n```\n\n### Get Cost Estimate\n\n```python\n# Tool: bq_dry_run_sql\n{\n \"sql\": \"SELECT * FROM `bigquery-public-data.samples.shakespeare`\",\n \"pricePerTiB\": 5.0\n}\n# Returns bytes processed, USD estimate, and schema\n```\n\n### Analyze Complex Query\n\n```python\n# Tool: bq_dry_run_sql\n{\n \"sql\": \"\"\"\n WITH user_stats AS (\n SELECT user_id, COUNT(*) as order_count\n FROM orders\n GROUP BY user_id\n )\n SELECT * FROM user_stats WHERE order_count > 10\n \"\"\"\n}\n```\n\n## Testing\n\nRun tests with pytest:\n\n```bash\n# Run all tests (requires BigQuery credentials)\npytest tests/\n\n# Run only tests that don't require credentials\npytest tests/test_min.py::TestWithoutCredentials\n```\n\n## Development\n\n```bash\n# Install development dependencies\nuv pip install -e \".[dev]\"\n\n# Run the server locally\npython -m mcp_bigquery_dryrun\n\n# Or using the console script\nmcp-bigquery-dryrun\n```\n\n## Limitations\n\n- **No Query Execution**: This server only performs dry-runs and validation\n- **Cost Estimates**: USD estimates are approximations based on bytes processed\n- **Parameter Types**: Initial implementation treats all parameters as STRING type\n- **Cache Disabled**: Queries always run with `use_query_cache=False` for accurate estimates\n\n## License\n\nApache-2.0\n\n## Changelog\n\n### 0.1.0 (2024-08-12)\n- Initial release",
"bugtrack_url": null,
"license": "Apache-2.0",
"summary": "Minimal MCP server for BigQuery SQL validation and dry-run analysis",
"version": "0.2.0",
"project_urls": {
"Documentation": "https://github.com/caron14/mcp-bigquery-dryrun#readme",
"Homepage": "https://github.com/caron14/mcp-bigquery-dryrun",
"Issues": "https://github.com/caron14/mcp-bigquery-dryrun/issues",
"Repository": "https://github.com/caron14/mcp-bigquery-dryrun.git"
},
"split_keywords": [
"bigquery",
" claude",
" dry-run",
" gcp",
" mcp",
" sql",
" validation"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "6df652a835dde00393912173805d19f79dc5a7a5b6a988ad16d982aec54e0631",
"md5": "1a3e2edfc9ee393877497ad2f667e15d",
"sha256": "0d917b90451beb462ef631630ca38ea9ead3de26697cde655d3bd4c62997ff1d"
},
"downloads": -1,
"filename": "mcp_bigquery_dryrun-0.2.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "1a3e2edfc9ee393877497ad2f667e15d",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.10",
"size": 8040,
"upload_time": "2025-08-16T06:21:15",
"upload_time_iso_8601": "2025-08-16T06:21:15.265002Z",
"url": "https://files.pythonhosted.org/packages/6d/f6/52a835dde00393912173805d19f79dc5a7a5b6a988ad16d982aec54e0631/mcp_bigquery_dryrun-0.2.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "7a215e4f8527d3ea758216d88c4b6cf23789d07aabad894d1fa1fc01f40bfef9",
"md5": "cb1992adea8136c90b442cb241d9a472",
"sha256": "0c7339234ab2c69849ebc6dce6cfeb25b886a5cd17d0c3736f6dc825106b41bb"
},
"downloads": -1,
"filename": "mcp_bigquery_dryrun-0.2.0.tar.gz",
"has_sig": false,
"md5_digest": "cb1992adea8136c90b442cb241d9a472",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.10",
"size": 12191,
"upload_time": "2025-08-16T06:21:19",
"upload_time_iso_8601": "2025-08-16T06:21:19.225696Z",
"url": "https://files.pythonhosted.org/packages/7a/21/5e4f8527d3ea758216d88c4b6cf23789d07aabad894d1fa1fc01f40bfef9/mcp_bigquery_dryrun-0.2.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-08-16 06:21:19",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "caron14",
"github_project": "mcp-bigquery-dryrun#readme",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"lcname": "mcp-bigquery-dryrun"
}