dq-mcp
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., "@dq-mcpCheck that order_id is unique and customer_id is not null in fixtures/orders.csv"
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.
dq-mcp
An MCP server that gives a language model real data-quality tools instead of guesses.
Ask an LLM about a dataset it cannot inspect and it will describe the table it expects to see. This server closes that gap: it exposes profiling and assertion tools over the Model Context Protocol, so an agent has to go and look before it says anything about your data.
The checks deliberately mirror the dbt test vocabulary — not_null, unique,
relationships, accepted_values — so the assertions you already enforce in a
pipeline are available to an agent at query time, under the same names.
Try it without installing anything: jyoshnagoshika-spec.github.io/dq-mcp
— the demo page runs this repository's own dq/core.py in your browser under
Pyodide, on the included fixtures or on a file you open. Nothing is uploaded.
Tools
Tool | What it does |
| Column names, dtypes, row count. Cheap; run it first. |
| Per-column null rate, distinct count, examples, numeric range |
| Asserts columns are fully populated |
| Asserts a single or composite key is unique |
| Asserts every foreign key exists in the parent |
| Asserts a column stays inside an allowed set |
| Asserts a number stays between bounds |
| Asserts the newest row is recent enough |
| Proposes a starting suite from the data, with a reason for each test |
| Runs several checks in one call, returns a combined report |
| Same report in dbt's |
There is also a dq://conventions resource holding the rules for reading a
report — most usefully, that a passing test means the assertion held, not that
the data is correct.
Reads CSV, TSV, JSON, JSONL and Parquet. Files above 512 MB are refused rather than silently loaded into memory.
Related MCP server: tabulite-mcp
Reading a result
Every check returns the same envelope:
{
"test": "unique",
"status": "fail",
"target": { "key": ["order_id"] },
"rows_checked": 900,
"failing_rows": [400, 401, 402, 12, 300],
"detail": {
"duplicate_rows": 5,
"worst_offenders": { "ORD-00013": 3, "ORD-00301": 2 }
},
"message": "5 row(s) share a key that should be unique — ORD-00013 appears 3 times."
}status has three values, not two. error means the check could not run — a
column name that does not exist, a missing file — and says nothing about the
data. fail means it ran and the assertion did not hold. Reporting a typo as
a data-quality failure buries the real ones, so the two are kept apart
everywhere, including in the CLI's exit code.
failing_rows holds row positions, capped at 200, so a caller can show the
offending rows rather than just a count. Failures name the worst offenders,
because "this column is not unique" is not actionable and "ORD-00013 appears
three times" is.
Quickstart
git clone https://github.com/jyoshnagoshika-spec/dq-mcp.git
cd dq-mcp
python3 -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e ".[mcp,dev]"
python dq_server.py # starts on stdio; Ctrl+C to stopThe server speaks MCP over stdio, so running it directly just waits for a client. Nothing will print. That is correct behaviour — connect a client to use it.
Connect it to Claude Desktop
Add this to claude_desktop_config.json:
macOS —
~/Library/Application Support/Claude/claude_desktop_config.jsonWindows —
%APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"dq": {
"command": "/absolute/path/to/dq-mcp/.venv/bin/python",
"args": ["/absolute/path/to/dq-mcp/dq_server.py"]
}
}
}Use the absolute path to the virtual environment's Python, not plain
python. Claude Desktop does not inherit your shell's PATH, so a bare python
will find a system interpreter without mcp or pandas installed. This is the
single most common reason the server fails to appear.
Restart Claude Desktop fully — quit it, don't just close the window.
Use it in CI
An MCP server is only reachable from an agent. A pipeline needs something it can run and get an exit code from, so the same engine has a command line:
dq schema fixtures/orders.csv
dq profile fixtures/orders.csv
dq suggest fixtures/orders.csv > suite.json
dq suite fixtures/orders.csv --spec suite.json
dq suite fixtures/orders.csv --spec suite.json --run-results run_results.jsonfixtures/orders.csv — 7 check(s)
[PASS] not_null order_id fully populated across 900 row(s).
[FAIL] not_null 5 row(s) have a null in customer_id (worst null rate 0.56%).
[FAIL] unique 5 row(s) share a key that should be unique — ORD-00013 appears 3 times.
[FAIL] accepted_values 2 row(s) hold a value outside the allowed set — pending_review.
[FAIL] range 2 row(s) fall outside the expected range for amount — lowest -240.0, highest -19.99.
[FAIL] freshness Newest ordered_at is 30.0h old, past the 24.0h limit.
[FAIL] relationships 3 row(s) reference a customer_id that does not exist — for example CUST-9991.
1 passed, 6 failed, 0 could not run.Exit 0 when everything passed, 1 when an assertion failed, 2 when a check
could not run at all.
--run-results writes the report in dbt's run_results.json shape, so CI
tooling that already understands dbt artifacts can read these results without
learning a second format.
Try it on the included fixtures
fixtures/ holds 900 orders and 200 customers with six deliberate problems
planted in them, one per check:
Problem | Tool that catches it | Result |
5 rows share a duplicated |
|
|
5 null |
| 0.56% null rate |
3 orphaned foreign keys |
|
|
2 rows with status |
| outside the allowed set |
2 negative |
| −19.99 and −240.00 |
newest |
| fails a 24h bound, passes 48h |
Ask Claude:
Profile
fixtures/orders.csv, suggest a test suite for it, then run that suite and tell me which failures are worth escalating.
fixtures/make_fixtures.py regenerates both files from a fixed seed, so the
counts above are asserted in the test suite rather than being folklore in a
README.
Layout
dq/core.py the checks. Plain functions over a DataFrame, no I/O, no MCP.
dq/suite.py running many checks, proposing a suite, dbt export
dq/loaders.py reading files, size limits, load errors worth showing a user
dq/server.py the MCP surface — thin wrappers, no logic
dq/cli.py the terminal surface, for CI
docs/ the browser surface, which imports dq/core.py as-isOne engine, three surfaces. That is the reason run_suite calls dq.core
directly: the previous version called the MCP-decorated tool functions, which
works on SDK 1.x and breaks on 2.x where the decorator returns a wrapper rather
than the original function. There is a regression test asserting the suite runner
works with no MCP SDK imported at all.
Compatibility
The MCP Python SDK renamed its high-level server class in 2.0 (FastMCP became
MCPServer). dq/server.py imports whichever is present, so it runs on both 1.x
and 2.x without changes. Tested on Python 3.10, 3.11 and 3.12.
Roadmap
Warehouse-backed checks (Redshift, Snowflake) rather than files only
Custom SQL-style expression assertions
A GitHub Action wrapping the CLI, so a repo can add checks with four lines of YAML
Licence
MIT — see LICENSE.
This server cannot be deployed
Maintenance
Related MCP Connectors
Deterministic validation for AI-generated artifacts: JSON Schema, OpenAPI response, SQL syntax.
- OleanderOAuthdev.oleander
The all-in-one data stack for agents. Upload files, run SQL, evolve tables, and render charts.
Auto-discover validation rules from data — scan, profile, health-score. No rules to write.
The grounded data layer for any LLM: governed SQL, metrics, lineage and catalog over your data.
Related MCP Servers
- AlicenseAqualityAmaintenanceEnables LLMs to profile and analyze tabular data files (CSV, Parquet, Excel, JSON) by extracting schema, statistics, data quality issues, and dtype suggestions, returning structured JSON.745 PyPI2MIT
- AlicenseNot gradedqualityBmaintenanceEnables AI assistants to analyze large CSV files locally by importing them into SQLite, profiling columns, and running read-only SQL queries without data leaving the machine.MIT
- AlicenseBqualityCmaintenanceProfiles authorized local datasets into inspectable Data Context for AI assistants, with optional local model-assisted interpretation.1MIT
- AlicenseNot gradedqualityBmaintenanceEnables agents to inspect dbt model semantics, retrieve contracts and lineage, and verify that edits do not change what models mean.Apache 2.0