| list_sourcesA | List every data source currently loaded in this MCP session. Output size: small (<2KB typical). No arguments. Cheap.
|
| load_sourceA | Load a CSV / TSV / Parquet / JSON / NDJSON file (or glob, or directory) and register it as a queryable source. Auto-detects format from extension; pass format= to override. For globs and
directories, files are unioned (must share schema). Returns the new source's
id, format, modality, schema, row count, size, and a stable fingerprint.
Output size: small-to-medium (schema scales with column count).
|
| describe_sourceA | Return schema (name, dtype, nullability), N sample rows, and footprint for a loaded source. Output size: small. Sample row count is capped at the requested value (default 5).
|
| unload_sourceA | Unregister a previously loaded source and free its DuckDB view. Idempotent. Output size: tiny.
|
| list_filesA | List files under path (file, directory, or glob). Useful when you don't know what's in a directory and need to find a
specific file before calling load_source. For HDF5/array directories,
prefer detect_pattern() which also classifies the multi-file structure.
Output size: small (file list capped at max_files).
|
| detect_patternA | Scan a directory (or single file) and identify its multi-file structure. Recognizes: partitioned_parquet, partitioned_csv, mysql_dump, multi_hdf5,
related_tables, image_folder, text_corpus, single_file. Returns suggested
load_source(args) the agent can invoke directly.
Output size: small to medium (file lists capped at 50).
|
| detect_metadataA | Find sidecar metadata in or alongside path: README, LICENSE, data dictionary, dataset card, manifest YAML/JSON. Excerpts long files at 1500 chars. Output size: small to medium.
|
| fingerprint_sourceA | Compute a stable hash of (schema + content sniff) for a loaded source. Use the returned `fingerprint` to detect whether a dataset has changed
across MCP sessions without re-running EDA. Output size: tiny.
|
| infer_recipesA | Generate ready-to-paste loader code for the source: Python (DuckDB), Polars, Pandas, and SQL. Lets users reproduce loading without the MCP. target='all' returns every
flavor; specify one (python|polars|pandas|sql) for just that. Output size: small.
|
| run_sqlA | Run arbitrary SQL against the session's DuckDB connection. Read-only by default. Cross-source JOINs work because every loaded source is a view in the same
connection. Rows are capped at `limit` (default 100). Returns rows + schema +
a `truncated` flag.
Output size: scales with limit; default ~10–50KB.
|
| sample_rowsA | Pull a sample from a loaded source. modes: 'random' (USING SAMPLE), 'head', 'tail', 'stratified' (requires stratify_by).
`columns` scopes the projection — useful on wide sources (20+ cols) where
returning everything inflates the JSON response. Default returns all columns.
Output size: scales with n × columns; default ~5KB on a typical narrow source.
|
| profileA | Per-column profile: type, kind, null %, cardinality, basic stats, top values. For numeric columns: mean, median, std, min/max, percentiles, skew, kurtosis.
For string/categorical: cardinality, top values, length stats.
Single DuckDB SUMMARIZE pass + per-column extras; fast on millions of rows.
Output size: scales with column count; ~1-3KB per column.
|
| check_qualityA | Reality + univariate quality checks (Levels 0–1). Detects: schema sanity (duplicate column names, weird identifiers), empty
or constant columns, structured missingness (>20% nulls), sentinel values
masquerading as data (-999, 'N/A'), and string columns that should be numeric.
Output size: small; full report in artifact.
|
| check_distributionsA | Distribution shape per numeric column (Level 1). Flags heavy skew (|γ₁|>2), multimodality (peak count), zero-inflation,
heavy tails. Suggests transforms (log/sqrt/yeo-johnson). Output size: small.
|
| check_correlationsA | Pairwise correlation analysis (Level 2). methods: ['pearson'] (default), or include 'spearman' for monotonic.
target: when given, also returns target-correlations and flags r>0.95 as
likely target leakage. Caps at 50 numeric columns. Output: top 50 pairs in
result; full matrix in artifact.
|
| check_duplicatesA | Exact duplicate detection (Level 2). Reports row-level exact duplicates and (if keys=[...] given) duplicate
groups under those keys. near=True is a placeholder for Phase 3 fuzzy
matching. Output size: small.
|
| check_multicollinearityA | Variance Inflation Factor + correlated-group detection (Level 3). Reports per-column VIF, flags VIF>10 as problematic and VIF>5 as moderate.
Groups mutually-correlated features (|r|≥0.8) and suggests one drop per
group. Skips ID-like (unique) columns. Caps at 50 numeric columns.
Output size: small.
|
| check_temporalA | Time-series sanity (Level 4). Requires time_column (DATE/TIMESTAMP). Detects: gaps (period > median × 5), monotonicity, sampling frequency,
drift (first-half vs second-half mean shift > 1σ per numeric column),
and seasonality (autocorrelation peaks in daily counts). Output size: small.
|
| check_leakageA | Three-layer leakage detection (Level 6). Layer 1 (always): name heuristics — flags columns named like 'label_*',
'outcome_*', 'pred_*', 'post_*'. Layer 2 (with target): features whose
Pearson correlation with target > 0.95. Layer 3 (with target + time):
features that are constant within each time bucket but vary across
buckets (likely backfilled). Output size: small.
|
| check_biasA | Class imbalance + sampling bias + (with hints) disparate impact (Level 5). Always runs class-balance (2-20 cardinality cats) and chi-square sampling
bias. With both `outcome_column` + `protected_attributes`, also runs the
80%-rule disparate-impact ratio. Output size: small.
|
| check_piiA | Detect PII via regex + column-name heuristics. Patterns: email, phone, SSN, credit-card (Luhn-validated), IPv4, URL,
plus name/address/SSN field-name heuristics. Samples N rows per column
(default 5000). Returns redacted examples — never the raw values.
Output size: small.
|
| check_geospatialA | Auto-detect lat/lon columns and validate ranges. Detection by name (lat/latitude/y, lon/longitude/x) or numeric range fit.
Flags out-of-range values (lat>±90, lon>±180), (0, 0) Null Island sentinel
clusters, and tiny-bbox concentration. Reports bbox + center + spread (km)
and (when a country column is present) the distinct geographies seen.
|
| check_nested_structureA | For JSON-loaded sources, walk the nested STRUCT/LIST schema. Per leaf path: declared type + presence percentage. Flags type-drift
(DuckDB JSON fallback indicates rows have inconsistent types) and
sparse paths (<80% presence). Returns a paste-ready flatten SQL using
struct_extract.
|
| check_arraysA | HDF5 / scientific-array EDA. Source must be loaded as hdf5 modality. Walks the h5py tree and aggregates leaf datasets by their leaf name (so
all `.../energies` arrays across groups become one schema). Reports
per-leaf shape examples, dtype consistency, finite/NaN/Inf %, range,
units, valid_range. Flags NaN/Inf >1%, dtype drift across groups, fill
values (~9.97e36 / ±9999), and out-of-range values vs declared valid_range.
`max_groups` caps the walk depth for very large files. When the cap is
hit, the result's `cap_hit=true` and a critical finding is surfaced —
raise `max_groups` and re-run to cover the full file. Result also
reports `n_groups_total` (true total) vs `n_groups_walked` (visited).
Output size: scales with distinct leaf names; ~0.5–2KB per schema.
|
| peek_arrayA | Read a small slice from one HDF5 dataset (the missing companion to check_arrays). HDF5 sources don't have SQL views, so `sample_rows` / `run_sql` can't
inspect them. Use this to read raw values.
`path` accepts either:
- an absolute h5py path like `/gdb11_s08/molecule_1/coordinates`, or
- a leaf name like `coordinates`, which resolves to the first match
and reports other matching paths in `other_matches`.
`n` controls how many rows along the leading axis to return (default 5;
capped at ~500 values total for payload safety).
Output: dtype, full shape, returned slice shape, JSON-safe values,
plus `units` and `valid_range` if declared as HDF5 attributes.
|
| check_dimensionalityA | PCA-based dimensionality + Hopkins clustering tendency (Level 3). Standardizes the numeric matrix, runs SVD-based PCA. Returns variance-
explained curve, intrinsic dim (95% / 99% cumulative variance), effective
rank (entropy of variance shares), and Hopkins statistic (0.5 random,
>0.75 clustered, <0.3 grid-like). Caps at 50 features.
Output size: small.
|
| check_stabilityA | Bootstrap stability of column means + signal-to-noise ratio (Level 6). For each numeric column draws `n_bootstrap` resamples (with replacement),
computes the mean each time, and reports bootstrap_std, coefficient of
variation, and SNR. Flags CV>0.1 (unstable means) and SNR<1 (low signal).
Output size: small.
|
| check_text_columnsA | Analyze text-heavy string columns (avg length ≥ 20). Per column: length distribution (avg/p50/p95/max), vocab size + top
tokens, near-duplicate %, content kind (prose/code/html/url/numeric/
categorical/mixed), encoding-artifact (mojibake) %. Flags high dedup
rate, mojibake, HTML content. Sample size cap on big data. Output size: small.
|
| get_eda_findingsA | Fetch a filtered, paginated view of findings from a prior run_eda artifact. Filters compose with AND. severity ∈ {critical, warn, info}. Use offset/limit
to page through. Cheap — reads cached JSON, no recomputation.
Output size: scales with limit; default ~5–50KB.
|
| suggest_plotsA | Recommend the most informative plots for a loaded source. Inspects the column kinds, missingness, and (if hints provided) target/
time columns to rank plot suggestions. Returns pre-filled tool calls
(similar to recommend_next): label, plot_kind, call, args, why, priority.
Profiles from a reservoir sample of `max_rows` rows on large sources;
the suggested plot calls themselves still reference the original
source_id. `sample_info` in the result tells you what was sampled.
Output size: small.
|
| check_outliersA | Detect outliers in numeric columns using three methods side-by-side. Methods: z-score (>3σ), IQR (>1.5×IQR beyond Q1/Q3), modified z-score
(median-MAD-based, robust to outliers themselves). Returns counts +
sample extreme values + row indices per method per column. Disagreement
between methods is itself diagnostic.
`verbose=False` (default) drops per-method extreme-value arrays from
the response (top-5 per flagged column is still in top_findings); set
True for the full dump. Full arrays are always in the artifact.
|
| compare_groupsA | Statistical comparison of metric_column across group_column levels. 2 groups → Welch's t-test or Mann-Whitney U (depending on normality)
+ Cohen's d / rank-biserial effect size + 95% CI on mean difference.
>2 groups → ANOVA or Kruskal-Wallis + eta-squared. Returns per-group
stats, the test result, and a plain-English interpretation.
|
| check_feature_signalA | Score every feature for signal strength relative to target_column. Picks the right test by type pair: Pearson + Spearman for num↔num,
ANOVA F + η² for num↔cat, χ² + Cramér's V for cat↔cat, Welch t-test +
Cohen's d for boolean target × numeric. Returns ranked features with
effect sizes + plain-English strength buckets. Pairs with auto_modeling_audit.
|
| eda_storyboardA | Use ONLY for "walk me through the dataset" / full visual tour requests —
generates a 5–8-plot sequence (missingness → distribution → Q-Q →
correlations → pairs → time → grouped) with narrative between each plot. For specific questions like "show me distribution of X", call
`plot_distribution` directly — single-image responses render more
reliably across chat UIs and don't risk filename-collision bugs in
clients that name images by ms-resolution timestamp.
Returns full JSON (paste-ready Markdown + section list) AND, when
`inline_images=True` (default), interleaves per-section narrative +
inline ImageContent so capable chat UIs display the tour inline. Pass
`inline_images=False` if your client errors with "Maximum call stack
size exceeded" on the multi-image response — JSON + file:// paths only.
Plots are written to disk either way.
Downsamples to `max_rows` via reservoir sampling on large sources —
seven plots × millions of rows materializes hundreds of MB of
intermediate Python objects and can OOM the MCP process. `sample_info`
in the result tells you what was sampled.
|
| clean_drop_columnsA | New source with the named columns dropped. Original is preserved. Returns the new source_id (auto-named `{source}_v{N}` unless `alias`
is provided), row/col deltas, and a Recipe with SQL/Polars/Pandas
equivalents for replay outside the MCP.
|
| clean_rename_columnsA | New source with columns renamed per {old: new} mapping. |
| clean_castA | New source with columns TRY_CAST to new dtypes per mapping. Uses `TRY_CAST` so non-castable values become NULL rather than erroring
— appropriate for the type-drift workflow where a few outliers are fine.
Common casts: 'DOUBLE', 'INTEGER', 'BIGINT', 'VARCHAR', 'BOOLEAN', 'DATE'.
|
| clean_replaceA | New source with column values replaced per mapping. Use the JSON value `null` (Python `None`) to map to SQL NULL — the
canonical way to remove sentinel values like 'NA' or -999.
Example: `mapping={"NA": null, "?": null, -999: null}`.
|
| clean_filterA | New source with rows matching where_sql dropped (default) or kept. `where_sql` is a DuckDB WHERE clause without the WHERE keyword:
e.g. `"age < 0 OR age > 130"` or `"region IS NULL"`. Defaults to
drop-matching (filter-out semantics); pass `keep=True` to keep instead.
|
| clean_drop_duplicatesA | New source with duplicates removed. Without `keys`: exact full-row deduplication (`SELECT DISTINCT *`).
With `keys`: keeps the first row per key combination via ROW_NUMBER.
|
| clean_imputeA | Fill nulls in named columns with a strategy. `mapping` is `{column: {"strategy": "median", "value": optional}}`.
Strategies: `mean`, `median`, `mode`, `zero`, `constant` (requires
`value`). Example:
`{"customer_rating": {"strategy": "median"},`
` "country": {"strategy": "constant", "value": "UNKNOWN"}}`
|
| clean_transformA | Apply mathematical transforms to numeric columns in place. `mapping` is `{column: kind}` where kind is one of:
`log1p` → LN(x + 1) — handles zeros, common for skewed counts
`sqrt` → SQRT(MAX(0, x)) — gentler than log
`z_score` → (x - mean) / std — zero-mean, unit-variance
`min_max` → (x - min) / (max - min) — rescale to [0, 1]
|
| auto_cleanA | Inspect quality + duplicate findings and PROPOSE a cleaning plan. **Plan-only — does NOT modify data.** Returns Markdown plan + structured
ops list. Caller reviews and (optionally edits then) passes ops into
`clean_pipeline` to actually execute.
Auto-maps: constant cols → drop, all-null cols → drop, sentinel values
→ replace with NULL, type-drift → TRY_CAST, exact duplicates → dedupe.
|
| clean_pipelineA | Apply a sequence of cleaning ops in order. Returns one new source. `ops` is a list of `{"kind": str, "args": dict}` (the same shape that
`auto_clean` produces). Each op runs sequentially against the previous
stage's output. Final stage gets `alias` (default `{source}_clean`).
`materialize=True` (default) collapses the final result into a real
DuckDB TABLE so downstream queries (run_sql, auto_modeling_audit,
suggest_plots, etc.) don't have to re-evaluate the whole filter/
replace chain. Turn off for short-lived exploratory cleanups where
you won't query the output much.
|
| export_sourceB | Write a source (cleaned or original) to disk via DuckDB COPY. `format`: `parquet` (default), `csv`, `json` (array), `ndjson` (one obj
per line). `path` may be a directory (auto-named) or a full file path.
Returns path, row/col counts, and file size.
|
| recommend_tasksA | Propose ML / analytical tasks the data is well-suited for. Heuristic-driven: scans column types and shapes to suggest classification,
regression, time-series forecasting, segmentation, anomaly detection, or
recommendation tasks. Each suggestion includes target candidate, predictor
list, feasibility (high/medium/low), challenges, and a one-line first step.
|
| generate_reportB | Generate a self-contained HTML report for source_id. Single offline-viewable HTML file with: identity header, severity-counted
verdict, all findings from a deep audit, embedded plots (missingness +
distributions + correlation heatmap, all as base64 PNGs), per-column
profile table, sample rows. No external assets — emailable, attachable.
Output: small (path-only); the HTML itself is large (~100–500KB).
|
| plot_distributionA | The right tool to answer "show me the distribution of X" — single
column gets one histogram; multiple columns get a faceted grid. Numeric columns are server-side binned (small spec, fast); categorical
columns get top-50 value counts. Returns the structured JSON + the
rendered PNG as inline MCP ImageContent (chat UIs that render images
natively will display it directly). Single-image responses render
reliably across all MCP clients — prefer this over eda_storyboard for
focused per-column questions.
|
| plot_correlation_heatmapC | Correlation matrix as a colored heatmap. JSON + inline PNG. |
| plot_scatterB | Scatter of x vs y. Auto-samples >sample rows. JSON + inline PNG. |
| plot_timeseriesC | Line plot over time. JSON + inline PNG. |
| plot_boxplotC | Box plot, optional group_by categorical. JSON + inline PNG. |
| plot_missingnessB | Per-column null-percentage bar chart. JSON + inline PNG. |
| plot_pairB | N×N scatter matrix across top numeric columns. JSON + inline PNG. |
| plot_qqC | Q-Q plot vs normal. JSON + inline PNG. |
| plot_violinC | Density-violin plot. JSON + inline PNG. |
| plot_facetB | Distribution faceted by a categorical (small multiples). JSON + inline PNG. `ncols` controls the grid width (panels per row). Renamed from
`columns` to avoid clashing with `columns: list[str]` used by other
plot tools.
|
| compare_sourcesA | Schema diff + per-column distribution drift between two loaded sources. Returns a 'drop-in verdict' (safe / risky / incompatible). Numeric drift
via PSI (Population Stability Index, scale-invariant) + KS test p-value.
Categorical drift via PSI + chi-square + value-set diff. Auto-samples
sources over 500K rows. Pass `keys` for join-key overlap stats.
|
| detect_schema_evolutionA | Walk an ordered list of source_ids and report schema changes over time. Detects: column added (first appearance), column removed (last appearance),
type changed. Useful for monitoring partitioned data (monthly parquets,
API version snapshots) for breaking changes. Output size: small.
|
| data_cardA | Synthesize a paste-ready brief about source_id. Either runs `run_eda deep` fresh or, if `run_id` is provided, reuses that
artifact. Returns a Markdown document by default with sections: Bottom
Line · Critical Issues · Cleaning Steps · Modeling Concerns · Compliance &
Sharing · What's Missing · How to Load · Suggested Next Actions.
audience ∈ {auto, ml, analyst, engineer} — controls section ordering and
emphasis. The Markdown is the primary output for chat UIs. The structured
per-section breakdown is omitted by default (same content as `markdown`,
doubles response size); set `include_sections=True` if you need it
programmatically. The full structured data is always in the artifact.
|
| summarize_runA | Re-summarize a prior run_eda artifact through a different lens. focus ∈ {quality, bias, modeling, all} — filters findings to the
relevant categories without recomputing.
|
| recommend_nextA | Return ranked, pre-filled next-action tool calls. Pass `source_id` (will run quick EDA if no run cached) or `run_id`
(reads from artifact). Suggestions come back with full args ready to
invoke — designed for local models that pick from a numbered menu.
|
| auto_exploreB | The flagship blind-audit macro. 'I have no idea what this is.' Chains: detect_pattern → detect_metadata → load_source → modality classify
→ data_card. Returns a paste-ready introduction to an unknown dataset.
|
| auto_qualityA | 'Is this data safe and clean?' — quality + duplicates + PII + bias in one call. |
| auto_modeling_auditA | 'Can I train a model on this without footguns?' Chains leakage + multicollinearity + stability + temporal* + class imbalance
into a single ranked-blocker brief with a verdict (do_not_train_yet /
train_with_mitigations / ready_to_train).
Downsamples to `max_rows` via reservoir sampling when the source is
larger — the per-column correlations these checks run can time out on
7M+ row sources but converge to the same conclusions at ~500K rows.
Set `max_rows` higher (or to a number above the source size) for the
full pass. The sample is materialized once and surfaced in `sample_info`.
|
| auto_share_checkB | 'Is this safe to share externally?' — strict PII scan + bias + critical quality. Verdicts: safe_to_share / redact_first / review_fairness / do_not_share.
Returns a redact-list of column names when applicable.
|
| auto_compareA | 'Is B a safe drop-in for A?' — schema diff + drift + verdict (safe / risky / incompatible). |
| check_customA | Run every loaded plugin (custom YAML+SQL check) against source_id. Plugins are loaded from the bundled `plugins_builtin/` directory plus any
directories passed via `--plugins`. Plugins skip themselves if their
`applies_to.has_columns` doesn't match the source schema. Output: each
finding includes the plugin name in `evidence.plugin`.
|
| run_edaA | Run a preset bundle of checks. Returns one summary card + run_id + artifact path. Presets:
- 'quick' — Level 0–1 (profile + check_quality), <1s for typical data.
- 'standard' — Level 0–2 (adds distributions, correlations, duplicates), <10s.
- 'deep' — Level 0–6 (adds multicollinearity, temporal*, leakage, bias, pii).
- 'exhaustive' — deep + dimensionality + stability + text columns.
*temporal only runs when hints.time_column is provided.
hints (optional): {target_column, time_column, group_columns,
protected_attributes, id_columns, domain}. Pre-fills follow-up tool calls
and unlocks target-leakage / disparate-impact checks. Output size: small
(top-10 findings); full results written to artifact.
|