mcp-data-tools
A governed MCP server enabling LLM agents to query BigQuery, inspect GCS, trigger Airflow DAGs, and run data-quality checks with built-in security guardrails like allow-lists, cost ceilings, and audit trails.
README
mcp-data-tools
A governed Model Context Protocol (MCP) server for data-platform operations.
Give an LLM agent the ability to query BigQuery, inspect GCS, trigger Airflow DAGs, and run data-quality checks — without giving it the ability to scan an unbounded table, touch a dataset outside its remit, or run anything but a read-only query. Every tool call is dry-run estimated, checked against an explicit allow-list, capped by a cost/row ceiling, and written to an audit trail before it ever reaches a real backend.
Why this exists
Agentic data platforms (NL2SQL assistants, on-call/triage agents, data
copilots) all eventually hit the same problem: an LLM agent that can call
a real query engine is, by construction, an LLM agent that can be
prompt-injected or simply mistaken into running a full-table scan, reading
a dataset it shouldn't, or mutating data it was only supposed to read.
Most MCP servers for data tools wrap the backend SDK directly and call it
done. mcp-data-tools treats the guardrail layer as the actual product:
- Allow-listed resources. BigQuery tables, GCS buckets, and Airflow DAGs are matched against explicit glob patterns. Nothing is reachable by default.
- Enforced read-only SQL. A lexical check rejects anything that isn't
a bare
SELECT/WITH, with comments and string literals stripped first so neither can be used to smuggle a write statement past the check. - Two-phase table authorization. A cheap preflight check denies
obviously out-of-policy queries before any backend call — so an agent
can't even use a dry run to probe the existence/schema of a
non-allow-listed table — followed by an authoritative check against the
backend's own dry-run result. See
docs/SECURITY.md. - Real, enforced cost ceilings.
max_bytes_billedis passed straight through to the backend's execution API, so it holds even if a stale estimate undercounts a table that grew in the meantime. - A fail-closed audit trail. Every decision — allowed or denied — is logged. If the audit sink itself is unavailable, the request is denied rather than let through unaudited.
Architecture at a glance
flowchart LR
Agent[LLM Agent] -->|MCP / JSON-RPC| Server[mcp-data-tools]
Server --> Guardrails[GuardrailEngine]
Guardrails --> Audit[(Audit Trail)]
Server --> BigQuery[(BigQuery)]
Server --> GCS[(GCS)]
Server --> Airflow[(Airflow)]
Full component and sequence diagrams, plus the design decisions and
trade-offs behind them, are in docs/ARCHITECTURE.md.
Tools exposed
| Tool | What it does | Guarded by |
|---|---|---|
bigquery_estimate_cost |
Dry-runs SQL, returns projected bytes/cost/tables — no data returned | Read-only check, table allow-list |
bigquery_query |
Executes a read-only SQL query | Read-only check, table allow-list, byte/row ceiling |
data_quality_check |
Runs null_rate / uniqueness / freshness / row_count checks against a table |
Same as bigquery_query, per check |
gcs_inspect_object |
Fetches metadata for one GCS object | Bucket allow-list |
gcs_list_objects |
Lists objects under a prefix | Bucket allow-list |
airflow_trigger_dag |
Triggers a new Airflow DAG run | DAG-id allow-list |
airflow_get_dag_run_status |
Fetches a DAG run's status | DAG-id allow-list |
Quick start
No cloud credentials required — this runs entirely against in-memory mock adapters, the same ones the test suite uses:
git clone https://github.com/umamahesh-ade/mcp-data-tools.git
cd mcp-data-tools
python -m venv .venv && source .venv/bin/activate
pip install -e .
python examples/quickstart.py
You should see an allowed query, a data-quality report, a denied query (hitting a table outside the allow-list), and the resulting audit trail — all in a few dozen lines of output.
Installation
pip install -e ".[dev]" # base + testing/linting
pip install -e ".[gcp]" # + google-cloud-bigquery, google-cloud-storage
pip install -e ".[azure]" # + Azure Key Vault secret resolution
pip install -e ".[all]" # everything
Running the real MCP server
cp configs/full-example.yaml configs/my-config.yaml
# edit configs/my-config.yaml: project ids, allow-list patterns, Airflow URL
cp .env.example .env
# fill in AIRFLOW_TOKEN, GOOGLE_APPLICATION_CREDENTIALS, etc.
mcp-data-tools validate-config --config configs/my-config.yaml
mcp-data-tools serve --config configs/my-config.yaml
The server speaks MCP over stdio, so it's meant to be launched by an MCP
client host (Claude Desktop, an agent framework's MCP client, etc.), not
run standalone as a long-lived network service. See
docs/CONFIGURATION.md for every config field.
Wiring into an MCP client
Most MCP client hosts take a command + args:
{
"mcpServers": {
"data-tools": {
"command": "mcp-data-tools",
"args": ["serve", "--config", "/path/to/configs/my-config.yaml"],
"env": { "AIRFLOW_TOKEN": "..." }
}
}
}
Docker
make docker-build
make docker-run # docker compose run --rm mcp-data-tools
Testing
make test # pytest
make test-cov # pytest with coverage (fails under 85%)
The suite includes a real MCP-protocol integration test
(tests/integration/test_mcp_server_e2e.py) built on the official mcp
SDK's in-memory client/server harness — it exercises the exact
list_tools/call_tool JSON-RPC path a real agent host uses, not a
hand-rolled fake.
Examples
examples/quickstart.py— guarded query, data-quality check, and a denied query, end to end, no credentials needed.tests/unit/test_tools_data_quality.py— shows the publicmcp_data_tools.testing.ScriptedQueryEnginetest double for unit-testing a newCheckStrategyor tool of your own.
FAQ
Does this replace IAM? No. It's a fast, auditable policy layer in
front of your backends; the service account/role this server runs as
should still be scoped to least privilege. See
docs/SECURITY.md for the full defense-in-depth
argument.
Can it write data? No tool in this package can execute DDL/DML,
delete/write a GCS object, or do anything to Airflow beyond triggering a
run and reading status. guardrails.read_only: false is not currently a
supported configuration surface for SQL tools.
Does it support Databricks/Snowflake instead of BigQuery? Not yet —
the query engine is behind ports.QueryEnginePort, so adding one is a new
adapter, not a rewrite. See "Extensibility" in docs/ARCHITECTURE.md.
Why do dry runs still get preflight-checked if they don't cost anything?
Because a dry run against BigQuery still reveals whether a table exists
and its schema/referenced-table list, which is itself information the
allow-list is meant to gate. See docs/SECURITY.md.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Server starts with zero tools registered | No bigquery/gcs/airflow section in config |
Add the relevant section — see configs/full-example.yaml |
ConfigurationError: Environment variable 'X' is not set |
A ${ENV:X} placeholder or SecretRef references an unset var |
Export it or add it to .env |
| Every query is denied with "not in the allow-list" | guardrails.allowed_table_patterns doesn't match your tables |
Check the exact project.dataset.table string in the denial's audit event |
BackendOperationError: google-cloud-bigquery is required... |
bigquery section configured but [gcp] extra not installed |
pip install -e ".[gcp]" |
Docker build fails on pip install |
No network egress in your build environment | Use docker build --network=host or a proxy-aware base image |
Performance
- Dry runs are always performed before execution (
require_dry_run), so every query pays one extra round-trip to BigQuery — a deliberate trade-off of latency for cost/safety guarantees. Seedocs/ARCHITECTURE.mdfor why this isn't optional. - The regex-based preflight check (
core/sql_tables.py) avoids that round-trip entirely for queries that are obviously out of policy. - All adapters use a bounded exponential-backoff retry
(
core/retry.py) with jitter, so a single transient failure doesn't multiply into a retry storm against the backend. guardrails.max_rows_returnedandmax_bytes_billedbound both the memory footprint of a single tool call and the backend cost, regardless of how a caller phrases the query.
Security
See SECURITY.md for the threat model, the two-phase SQL
authorization design, secret handling, and how to report a vulnerability.
Roadmap
See the [Unreleased] section of CHANGELOG.md:
BigQuery-backed audit sink, a Databricks/Delta Lake query-engine adapter,
and column/row-level masking policy.
Contributing
See CONTRIBUTING.md for the dev setup, the
architecture ground rules new contributions are expected to follow, and
the lint/type/security/test gate every PR must pass.
License
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.