# jDataMunch MCP (pypi · jdatamunch-mcp)

Tabular data retrieval. Index CSV/Excel, query rows, aggregate. 99%+ savings vs raw file reads.

- Trust score: 80/100 (high trust)
- Change this week: −1
- Registry status: active
- Liveness: live
- Owner verified: no
- Last scored: 2026-09-20

## Components

- pypi · `jdatamunch-mcp`: 80/100 (this document), [markdown](https://verifymcp.io/servers/jgravelle-jdatamunch-mcp/jdatamunch-mcp.md), [page](https://verifymcp.io/servers/jgravelle-jdatamunch-mcp/jdatamunch-mcp)

## Channel facts

- Registry: `pypi`
- Package: `jdatamunch-mcp`
- Version: `1.31.13`
- Transport: `stdio`

## Trust breakdown

How this component scores in each security and reliability category. Every signal is checked automatically from public evidence about the published package, including repeated runs of it in an isolated sandbox, and we only credit what we can confirm. Scores are 0–100 per category. Scoring method: https://verifymcp.io/docs/scoring (what has changed: https://verifymcp.io/docs/scoring/changelog)

Scored 2026-09-20.

- **Supply Chain Security**: 100/100
  - No malware found by supply-chain analysis.
  - No known CVEs affecting this package version or its production dependencies.
  - Runs hatchling.build at install time, a recognised native-build step with no shell scripting around it.
  - 0 of 30 dependencies flagged as unhealthy.
- **Provenance & Transparency**: 32/100
  - Source repository is publicly reachable at the declared URL.
  - Provenance check failed: no build-provenance attestation is published.
  - License check failed: no license is declared.
  - Actively maintained (last published 19 days ago).
  - Security-disclosure policy not yet verified: we couldn't inspect the source repository.
- **Schema Quality & AI Usability**: 82/100
  - 100% of prompts and resources have a non-trivial description (not blank, and not just the item's name).
  - AI-judged instruction clarity (excellent).
  - Context-footprint check failed: tool/resource definitions use about 6333 tokens (~158/item across 40 items; 39 tools + 1 resources), over budget; trim descriptions and params.
  - Usage-examples check failed: none of the tools include examples.
- **Stability & Change Management**: 90/100
  - Stability observed for 27 of 30 days with no destabilising changes; credit accrues until the full window elapses.
- **Tool Coverage**: 98/100
  - 100% of tools have a non-trivial description (not blank, and not just the tool's name).
  - 95% of tool parameters carry a description.
- **Tool Safety**: 75/100
  - No prompt-injection markers were found in the server instructions, tool names or descriptions we captured.
  - 0 of 2 tool(s) whose name or description implies an irreversible operation declare an MCP destructiveHint annotation; "delete_dataset" implies "delete" and declares no destructiveHint at all, which the MCP spec reads as destructive by default.
  - An AI judge read all 41 captured unit(s) of tool text and found none that tries to manipulate the model reading it.
- **Capabilities**: 100/100
  - Implements a supported MCP spec version (2025-11-25); the latest is 2026-07-28.

## Install

### How do I install the jDataMunch MCP server?

jDataMunch MCP runs locally as a PyPI package, launched with uvx jdatamunch-mcp. Ready-made configuration for Claude, Cursor, VS Code, Codex and 5 more is on this page, copied from each client's own documentation.

### Claude

```bash
claude mcp add jgravelle-jdatamunch-mcp -- uvx jdatamunch-mcp
```

### Cursor

```json
{
  "mcpServers": {
    "jgravelle-jdatamunch-mcp": {
      "command": "uvx",
      "args": [
        "jdatamunch-mcp"
      ]
    }
  }
}
```

### VS Code

```json
{
  "servers": {
    "jgravelle-jdatamunch-mcp": {
      "command": "uvx",
      "args": [
        "jdatamunch-mcp"
      ]
    }
  }
}
```

### Codex

```bash
codex mcp add jgravelle-jdatamunch-mcp -- uvx jdatamunch-mcp
```

### opencode

```json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "jgravelle-jdatamunch-mcp": {
      "type": "local",
      "command": [
        "uvx",
        "jdatamunch-mcp"
      ],
      "enabled": true
    }
  }
}
```

### OpenClaw

```bash
openclaw mcp add jgravelle-jdatamunch-mcp --command uvx --arg jdatamunch-mcp
```

### Hermes

```yaml
mcp_servers:
  jgravelle-jdatamunch-mcp:
    command: "uvx"
    args: ["jdatamunch-mcp"]
```

### Netclaw

```json
{
  "McpServers": {
    "jgravelle-jdatamunch-mcp": {
      "Transport": "stdio",
      "Command": "uvx",
      "Arguments": [
        "jdatamunch-mcp"
      ]
    }
  }
}
```

### Vellum

```bash
assistant mcp add jgravelle-jdatamunch-mcp -t stdio -c uvx -a jdatamunch-mcp
```

### Other

```json
{
  "mcpServers": {
    "jgravelle-jdatamunch-mcp": {
      "command": "uvx",
      "args": [
        "jdatamunch-mcp"
      ]
    }
  }
}
```

## Changelog

Every change recorded for this component, newest first. Days that predate change tracking, or that we cannot explain, say so: "we were watching and nothing happened" and "we were not watching" are different claims.

### 2026-09-20 (score 80, −2)

- [functional regression] Security disclosure: pass → unverified
- [functional] Stability: pass → 0.90

### 2026-09-19 (score 82, 0)

- [security] Stability: 0.97 → pass

### 2026-09-18 (score 82, +1)

No change was recorded against any check on this day. Stability & Change Management went from 93 to 97. That category is still filling its 30-day observation window: 28 days of observed history at the previous scan, 29 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-09-16 (score 81, −1)

- [functional] Stability: pass → 0.90

### 2026-09-15 (score 82, +15)

- [security improvement] Malware scan: unverified → pass
- [security] Stability: 0.97 → pass

### 2026-09-14 (score 67, −14)

- [security regression] Malware scan: pass → unverified

### 2026-09-12 (score 81, +1)

No change was recorded against any check on this day. Stability & Change Management went from 87 to 90. That category is still filling its 30-day observation window: 26 days of observed history at the previous scan, 27 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-09-10 (score 80, +1)

No change was recorded against any check on this day. Stability & Change Management went from 80 to 83. That category is still filling its 30-day observation window: 24 days of observed history at the previous scan, 25 at this one. The score rises as the window fills, whether or not the server changes.

## MCP tools (39)

### `index_local` (~264 tokens)

Index a local data file (CSV, Excel, Parquet, or JSONL). Profiles all columns, detects types, computes statistics, and loads rows into SQLite for fast filtered retrieval. Set incremental=true (default) to skip re-indexing if file is unchanged. CSV, Excel, Parquet and JSONL only; any other format is rejected.

Input parameters:

- `delimiter` (string): CSV delimiter override (auto-detected if omitted)
- `depth` (string): Profiling depth (B7). 'shallow' caps at 100k rows for fast first-look; 'standard' is the full profile (default); 'deep' additionally precomputes correlations.
- `encoding` (string): File encoding override (auto-detected if omitted)
- `header_row` (integer): Row number containing column headers, 0-indexed (default 0)
- `incremental` (boolean): Skip re-index if file hash unchanged (default true)
- `name` (string): Dataset identifier override (defaults to filename stem)
- `path` (string, required): Absolute path to data file (.csv, .tsv, .xlsx, .xls, .parquet, .jsonl, .ndjson)
- `sheet` (string): Excel sheet name to index (default: first sheet)

### `index_repo` (~163 tokens)

Index data files from a GitHub repository. Discovers CSV, Excel, Parquet, and JSONL files, downloads them, and indexes each via the same pipeline as index_local. Datasets are named {owner}--{repo}--{filename}. Max 50 MB per file, 20 files per repo. Set GITHUB_TOKEN env var for private repos or to avoid rate limits.

Input parameters:

- `github_token` (string): GitHub token override (defaults to GITHUB_TOKEN env var)
- `incremental` (boolean): Skip re-index if HEAD SHA unchanged (default true)
- `url` (string, required): GitHub repo URL or owner/repo string (e.g. 'pandas-dev/pandas' or 'https://github.com/pandas-dev/pandas')

### `list_datasets` (~56 tokens)

List every indexed dataset with its row count, column count, and source file. Call it first to find the dataset name every other tool needs, and to confirm a file was actually indexed. Lists only datasets under the active storage_path.

### `list_repos` (~57 tokens)

List GitHub repositories indexed via index_repo. Shows repo name, HEAD SHA, dataset count, total rows, and dataset names for each repo. Covers repos indexed with index_repo only; a dataset added by index_local is not listed here.

### `describe_dataset` (~133 tokens)

Primary orientation tool. Returns every column's name, type, cardinality, null%, and sample values. A single call replaces reading the entire source file. Equivalent to opening a spreadsheet and reading the column headers + stats. On wide tables (60+ columns), results are auto-paginated — use columns=[] to select specific ones, or columns_offset to page through remaining columns.

Input parameters:

- `columns` (array): Filter to specific columns (default: all)
- `columns_offset` (integer): Pagination offset for wide tables (default 0)
- `dataset` (string, required): Dataset identifier (from list_datasets or index_local)

### `describe_column` (~187 tokens)

Deep profile of a single column. Full value distribution for low-cardinality columns, histogram bins for numeric, temporal range for datetime. top_n capped at 200; histogram_bins capped at 50.

Input parameters:

- `column` (string, required): Column name or column ID (e.g. 'lapd-crime::AREA NAME#column')
- `dataset` (string, required): Dataset identifier
- `histogram_bins` (integer): Bins for numeric histograms (default 10)
- `redact` (boolean): Scrub PII / credentials from value_distribution, top_values, and sample_values (default true). Numeric stats and counts are never altered. Set false for raw values when working with data you own.
- `redact_patterns` (array): Additional Python regex patterns to redact on top of the built-in set.
- `top_n` (integer): Top values to return for categorical columns (default 20)

### `search_data` (~214 tokens)

Search across column names and values. Returns column-level results with IDs — tells you where to look, not the data itself. Use before get_rows or describe_column. max_results capped at 50. Set semantic=true for embedding-based search (requires an embedding provider: JDATAMUNCH_EMBED_MODEL, GOOGLE_API_KEY, or OPENAI_API_KEY).

Input parameters:

- `dataset` (string, required): Dataset identifier
- `max_results` (integer): Maximum results to return (default 10)
- `query` (string, required): Natural-language or keyword query
- `search_scope` (string): Limit search to schema only, values only, or all (default 'all')
- `semantic` (boolean): Enable semantic search via embeddings (default false). Requires embedding provider.
- `semantic_only` (boolean): Skip keyword scoring entirely; use only embeddings (default false).
- `semantic_weight` (number): Weight for semantic score in hybrid ranking. 0.0 = pure keyword, 1.0 = pure semantic (default 0.5).

### `get_rows` (~353 tokens)

Filtered row retrieval via structured filters. All filters are SQL-parameterized (no injection). Operators: eq, neq, gt, gte, lt, lte, contains, in, is_null, between. Use columns=[] to project — reduces tokens significantly on wide tables. Prefer aggregate() for summaries over paginating through rows. Returns at most limit rows (default 50); page with offset instead of raising it.

Input parameters:

- `columns` (array): Column projection — reduces tokens (default: all)
- `dataset` (string, required): Dataset identifier
- `filters` (array): Filter conditions (ANDed). E.g. [{"column": "AREA NAME", "op": "eq", "value": "Hollywood"}]
- `limit` (integer): Max rows returned (default 50, hard cap 500)
- `offset` (integer): Pagination offset (default 0)
- `order_by` (string): Column to sort by
- `order_dir` (string): Sort direction (default 'asc')
- `redact` (boolean): Scrub PII / credentials (emails, SSNs, Luhn-valid credit cards, JWTs, API keys, PEM blocks, AWS keys, GitHub/Slack tokens) from row cells before return (default true). Numeric cells are never altered…
- `redact_patterns` (array): Additional Python regex patterns to layer on top of the built-in set. Invalid patterns are silently skipped (reported in _meta.redaction.invalid_custom_patterns).
- `redact_skip_columns` (array): Column names to exempt from redaction (e.g. an `email_hashed` column where the email pattern would false-positive).

### `aggregate` (~339 tokens)

Server-side aggregations (GROUP BY). Saves orders of magnitude in tokens vs returning rows for the LLM to aggregate. Functions: count, sum, avg, min, max, count_distinct, median. limit capped at 1000.

Input parameters:

- `aggregations` (array, required): Aggregation specs. Use column='*' for COUNT(*).
- `approximate` (boolean): Approximate-mode aggregation (C1). Routes count_distinct → HyperLogLog (~2% error), median → t-digest (~1% error), sum/avg → sampled estimator with 95% confidence interval. Whole-dataset only.
- `dataset` (string, required): Dataset identifier
- `filters` (array): Pre-filter rows before aggregating (same syntax as get_rows)
- `group_by` (array): Group-by columns. Empty = whole-dataset aggregate.
- `having` (array): Post-aggregation filter on aggregation aliases (B11). Each item: {"column": <alias>, "op": eq|neq|gt|gte|lt|lte|in|between|is_null, "value": ...}
- `limit` (integer): Max groups returned (default 50)
- `order_by` (string): Column or alias to sort by
- `order_dir` (string)
- `redact` (boolean): Scrub PII / credentials from group-by column values (default true). Aggregate values (counts, sums, etc.) are never altered.
- `redact_patterns` (array): Additional Python regex patterns to layer on top of the built-in set.
- `redact_skip_columns` (array): Group-by column names to exempt from redaction.

### `sample_rows` (~215 tokens)

Return a sample of rows. Useful for understanding data shape without prior knowledge. Method: 'head', 'tail', or 'random'. Use columns=[] on wide tables to reduce response size. Pass seed (int) with method='random' for deterministic, reproducible sampling. A sample shows shape, not distribution; use get_distribution when you need the spread.

Input parameters:

- `columns` (array): Column projection (default: all)
- `dataset` (string, required): Dataset identifier
- `method` (string): Sampling method (default 'head')
- `n` (integer): Rows to sample (default 5, max 100)
- `redact` (boolean): Scrub PII / credentials from sampled cells before return (default true).
- `redact_patterns` (array): Additional Python regex patterns to layer on top of the built-in set.
- `redact_skip_columns` (array): Column names to exempt from redaction.
- `seed` (integer): Deterministic seed for method='random' (omitted = non-deterministic)

### `get_schema_drift` (~114 tokens)

Compare schema (columns, types, nullability) between two indexed datasets. Detects added/removed columns, type changes, and null-rate shifts. Pure in-memory comparison — no re-reading source files. Useful for detecting schema changes between dataset versions. Assessment: 'identical' | 'additive' (only additions) | 'breaking' (removals or type changes).

Input parameters:

- `dataset_a` (string, required): First dataset identifier (baseline)
- `dataset_b` (string, required): Second dataset identifier (comparison target)

### `get_data_hotspots` (~167 tokens)

Return the highest-risk columns in a dataset ranked by a composite score combining: null rate, cardinality anomalies, numeric outlier spread, and (v1.10.0) runtime traffic from runtime_query_calls when traces exist. When include_runtime is true but no traces are ingested, the response carries an honest-hint caveat in _meta.runtime_caveat rather than silently scoring on static signals alone. top_n capped at 50.

Input parameters:

- `dataset` (string, required): Dataset identifier
- `include_runtime` (boolean): Fuse traffic signal from runtime_query_calls when available.
- `top_n` (integer): Number of hotspot columns to return (default 10, max 50)
- `window_days` (integer): Lookback window for the traffic signal. Default 30.

### `get_correlations` (~157 tokens)

Compute pairwise Pearson correlations between numeric columns. Returns pairs sorted by |r| descending, filtered to significant correlations. Use this to discover relationships in the data without manual exploration. top_n capped at 200.

Input parameters:

- `columns` (array): Restrict to specific numeric columns (default: all numeric)
- `dataset` (string, required): Dataset identifier
- `method` (string): Correlation method (default 'pearson'). Spearman is rank-based — robust to outliers and monotonic non-linear relationships (B10).
- `min_abs_correlation` (number): Minimum |r| to include in results (default 0.3)
- `top_n` (integer): Max pairs to return (default 20, max 200)

### `join_datasets` (~289 tokens)

Join two indexed datasets via SQL JOIN. Uses ATTACH DATABASE to combine two SQLite stores into one query. Supports inner, left, right, and cross joins. Use columns_a/columns_b to project — reduces tokens on wide tables. Row limit capped at 500. Prefer aggregate() on join results for summaries.

Input parameters:

- `columns_a` (array): Columns to select from dataset_a (default: first 30)
- `columns_b` (array): Columns to select from dataset_b (default: first 30)
- `dataset_a` (string, required): First dataset identifier (left side of join)
- `dataset_b` (string, required): Second dataset identifier (right side of join)
- `filters_a` (array): Pre-filter dataset_a rows (same syntax as get_rows filters)
- `filters_b` (array): Pre-filter dataset_b rows (same syntax as get_rows filters)
- `join_column_a` (string, required): Column from dataset_a to join on
- `join_column_b` (string, required): Column from dataset_b to join on
- `join_type` (string): Join type (default 'inner')
- `limit` (integer): Max rows returned (default 50, hard cap 500)
- `offset` (integer): Pagination offset (default 0)
- `order_by` (string): Column to sort results by
- `order_dir` (string): Sort direction (default 'asc')

### `summarize_dataset` (~73 tokens)

Generate natural-language summaries for a dataset and all its columns. Works on already-indexed datasets — reads profiles from index.json, generates summaries, and writes them back. No re-parsing of source files. Summaries are also auto-generated during index_local.

Input parameters:

- `dataset` (string, required): Dataset identifier (from list_datasets)

### `delete_dataset` (~53 tokens)

Delete an indexed dataset and its SQLite store. Frees disk space. Irreversible — the dataset must be re-indexed to use again.

Input parameters:

- `dataset` (string, required): Dataset identifier to delete (from list_datasets)

### `embed_dataset` (~94 tokens)

Precompute column embeddings for semantic search. Optional warm-up — search_data with semantic=true lazily embeds on first use. Running embed_dataset upfront eliminates that latency. Requires an embedding provider (JDATAMUNCH_EMBED_MODEL, GOOGLE_API_KEY, or OPENAI_API_KEY).

Input parameters:

- `dataset` (string, required): Dataset identifier (from list_datasets)
- `force` (boolean): Recompute all embeddings even if cached (default false)

### `get_session_stats` (~32 tokens)

Return cumulative token savings and cost avoided across all tool calls. Savings are modelled estimates, not per-call measurements.

### `validate_index` (~93 tokens)

Verify an indexed dataset's on-disk integrity. Runs SQLite PRAGMA integrity_check, cross-checks row count and column list against index.json, and verifies index.json content hash. Reports stale-lock state from interrupted index_local runs. Returns overall_status: 'ok' | 'warning' | 'error'. Checks the integrity of the index, never the correctness of the underlying data.

Input parameters:

- `dataset` (string, required): Dataset identifier

### `get_dataset_history` (~80 tokens)

Return the last N profile snapshots for a dataset. Snapshots are appended on every successful index_local — use this to detect schema/content drift over multiple ingests of the same dataset. n capped at 50.

Input parameters:

- `dataset` (string, required): Dataset identifier
- `n` (integer): Number of snapshots to return (default 10, max 50)

### `get_dataset_health` (~78 tokens)

Composite quality grade (A–F) for a dataset (B4). Combines null severity, type-confidence, constant-column count, primary-key presence, semantic-typing coverage, and drift history into a single score with a structured breakdown. Grades structure and completeness, not whether the values are right.

Input parameters:

- `dataset` (string, required): Dataset identifier

### `suggest_keys` (~75 tokens)

Rank primary-key candidates for a dataset (B5). Each entry carries a confidence score plus the reasons that raised it (integer column, UUID format, no nulls, exact-count unique). Candidates are ranked from profile statistics, so confirm against the source system before treating one as the key.

Input parameters:

- `dataset` (string, required): Dataset identifier

### `suggest_joins` (~72 tokens)

Discover FK candidates between this dataset and other indexed datasets (B5). For each non-PK column in the source, scans up to 20 other datasets' PK candidates and proposes joins where containment ≥ 95%. Sample-based (500 distinct values per source column).

Input parameters:

- `dataset` (string, required): Source dataset identifier

### `get_distribution` (~119 tokens)

Unified bin-counts for any column type (B8). Numeric → equal-width bins between min/max; datetime → time-bucket bins; categorical / string → top-n + 'other' bucket. Token-cheap way to ask 'what does this column look like?'. Bin counts only (default 20 bins); it never returns the underlying rows.

Input parameters:

- `bins` (integer): Number of bins / categories to return (default 20, max 100)
- `column` (string, required): Column name
- `dataset` (string, required): Dataset identifier

### `plan_query` (~100 tokens)

Map a natural-language intent into a ranked tool-call sequence for the given dataset (B3). Pure routing — no LLM call. Built-in intents: summarize, anomalies, compare, join, filter, trend, correlate.

Input parameters:

- `dataset` (string, required): Dataset identifier
- `intent` (string): Natural-language intent (e.g. 'summarize', 'find anomalies', 'join with X', 'trend over time'). Default 'summarize'.

### `run_sql` (~215 tokens)

Read-only sandboxed SQL escape hatch (B1). Accepts a single SELECT (or WITH … SELECT) statement. The first dataset is the main connection; additional datasets are ATTACHed under schema names (e.g. `<dataset>.rows`). Statement runs under PRAGMA query_only=1 with a 10-second budget and 500-row cap. Use this for HAVING / window functions / CTEs / multi-way joins that the structured tools don't cover.

Input parameters:

- `datasets` (array, required): Indexed datasets to attach. Order matters: datasets[0] is the main connection.
- `limit` (integer): Row cap (default 500, hard max 500)
- `redact` (boolean): Scrub PII / credentials from result cells before return (default true).
- `redact_patterns` (array): Additional Python regex patterns to layer on top of the built-in set.
- `redact_skip_columns` (array): Result column names to exempt from redaction.
- `sql` (string, required): SELECT or WITH … SELECT statement

### `get_schema_impact` (~176 tokens)

Transitive impact of a column-level schema change (drop_column, rename_column, retype_column). Walks the inferred FK graph to max_depth, surfaces direct + transitive hits across datasets, and normalises blast_score to [0, 1]. For retype_column, also flags type_mismatch entries at FK edges whose partner type wouldn't survive the retype. Read-only.

Input parameters:

- `column` (string, required): Column name (case-insensitive).
- `dataset_id` (string, required)
- `kind` (string)
- `max_depth` (integer): BFS depth over the inferred FK graph.
- `new_name` (string): Required for rename_column.
- `new_type` (string): Required for retype_column. e.g. integer / string / float.
- `window_days` (integer): Runtime traffic look-back.

### `check_column_drop_safe` (~135 tokens)

Composite preflight: is this column safe to drop? Fuses four signals — primary-key status, foreign-key participation, cross-dataset name match, and runtime traffic — into a single verdict plus ranked blockers and a recommended_action. Verdict tiers: pk_blocking, fk_blocking, runtime_observed, cross_dataset_blocking, safe_to_drop. Read-only. The killer feature of the Phase-1 sibling-parity batch.

Input parameters:

- `column` (string, required): Column name (case-insensitive).
- `dataset_id` (string, required)
- `window_days` (integer): Look-back window for runtime traffic. Default 30.

### `find_unused_columns` (~174 tokens)

Surface columns with zero or stale runtime traffic. Reads runtime_query_calls (populated by ingest_sql_log) and surfaces columns that haven't been queried within `window_days`. Excludes primary-key candidates and audit fields (created_at / updated_at / dbt_*) by default. Refuses to run with explicit error when no runtime data has been ingested — would otherwise trivially flag every column.

Input parameters:

- `dataset_id` (string, required)
- `exclude_audit` (boolean): Skip audit columns (created_at, updated_at, dbt_*, etc). Default true.
- `exclude_pk` (boolean): Skip primary-key candidates. Default true.
- `min_calls` (integer): Floor for 'considered used' within window. Default 0.
- `window_days` (integer): Look-back window. Default 30.

### `ingest_sql_log` (~212 tokens)

Ingest a SQL log file (pg_stat_statements CSV or generic JSONL, .gz transparently) into the per-dataset runtime tables. Each query is parsed for table + column refs, redacted at the chokepoint (string + numeric literals + cell-PII registry), and rolled up into runtime_query_calls keyed by (fingerprint, table, column). Tables in the log that don't match any indexed dataset count as unmapped. Foundational primitive for find_unused_columns, check_column_drop_safe, and data_health_radar (v1.6.0 sibling-parity Phase 1).

Input parameters:

- `file_path` (string, required): Path to a CSV / JSONL / .gz log file.
- `max_rows` (integer): Hard cap on ingested rows. Default 100000.
- `redact` (boolean): Scrub PII / literals before persisting. Default true.
- `source` (string): pg_stat_statements | jsonl | auto (default — sniff by extension).

### `find_similar_columns` (~199 tokens)

Multi-signal cross-dataset column consolidation. Fuses name (token Jaccard), type, top-value overlap, cardinality similarity, and (when present) embedding cosine into a composite score. Clusters via union-find and classifies each cluster: near_duplicate, naming_drift, parallel_definition, or overlapping_topic. Use to find duplicate columns across datasets, surface naming drift (`email` vs `email_address`), or detect the same conceptual column spread across multiple datasets. Mirrors jcm's find_similar_symbols. Every signal is heuristic, so a high score means investigate, not merge.

Input parameters:

- `datasets` (array): Datasets to scan. Omit to scan every indexed dataset.
- `min_score` (number): Composite-score floor for surfacing pairs.
- `same_type_only` (boolean): Drop pairs where types don't match.
- `top_n` (integer): Max clusters returned. Default 50, capped at 200.

### `data_health_radar` (~139 tokens)

Six-axis health radar for a dataset: null_health, type_confidence, cardinality_health, pk_presence, semantic_coverage, schema_stability (omitted when <2 history snapshots). Optional 7th axis runtime_coverage when traces ingested. Returns 0-100 score per axis + composite + A-F grade. Pairs with diff_data_health_radar for snapshot deltas. Mirrors jcm's six-axis health radar.

Input parameters:

- `dataset` (string, required)
- `include_runtime` (boolean): Fuse runtime_coverage axis when traces exist.
- `window_days` (integer): Lookback for the runtime axis. Default 30.

### `diff_data_health_radar` (~107 tokens)

Diff two data_health_radar payloads. Pure function — pass the `radar` sub-field from two data_health_radar responses (e.g. yesterday vs today). Returns per-axis deltas, composite delta, grade change, regression and improvement lists (threshold: 3 points), one-line verdict.

Input parameters:

- `baseline` (object, required): Baseline radar payload (e.g. yesterday's snapshot).
- `current` (object, required): Current radar payload (e.g. today's snapshot).

### `get_redaction_log` (~128 tokens)

Forensic accounting of PII redactions for a dataset. Returns per-pattern counts from runtime_redaction_log (populated by ingest_sql_log with redact=True), so operators can verify the chokepoint is firing on production traffic. Filter by source and lookback window. Empty result with no traces ingested is not an error — it just means no scrubbing has happened yet.

Input parameters:

- `dataset_id` (string, required)
- `since_days` (integer): Lookback window for last_seen. Default 30.
- `source` (string): Optional source filter. Today: 'sql_log'.

### `tune_weights` (~240 tokens)

Inspect, set, or reset the weight vector search_data uses to rank columns (name/value/type match weights plus the BM25 and semantic blend scales). Omit all args to inspect the effective weights and their source. Pass set_weights (a {weight: number} object) to override, or reset=true to clear. Scope with dataset (per-dataset overrides win over the global default, which wins over built-ins). Honored by search_data at query time. Unlike jcodemunch/jdocmunch, weights are tuned explicitly here (no ranking ledger). Tunable: name_exact, name_substr, name_word, ai_summary_word, value_exact, value_substr, type_boost, bm25_scale, semantic_scale, default_semantic_weight. Affects search_data ranking only; no other tool reads these weights.

Input parameters:

- `dataset` (string): Tune one dataset. Omit for the global default.
- `reset` (boolean): Clear this scope overrides.
- `set_weights` (object): Weight overrides, e.g. name_exact=30. Unknown names or non-numeric values are rejected; values are clamped to each weight bounds.

### `check_embedding_drift` (~170 tokens)

Detect whether the embedding provider has drifted since it was pinned. Column embeddings power semantic search_data and find_similar_columns; if the provider model changes underneath a stored index, saved vectors stop matching the live encoder and semantic ranking quietly degrades. Pins a 16-string canary in <index_path>/embed_canary.json and recomputes it on demand, reporting cosine drift. Call with force=true once to set the baseline, then again after a suspected provider change. Sibling of jcodemunch / jdocmunch check_embedding_drift.

Input parameters:

- `force` (boolean): Re-embed and re-pin the canary baseline (set once to establish it).
- `threshold` (number): Cosine-distance alarm threshold; alarm is true when the worst canary drifts past it.

### `analyze_perf` (~166 tokens)

Per-tool latency and cache-hit telemetry. Returns p50/p95/max latency and error rate per tool, the slowest tools by p95, and result-cache hit rates (aggregate / get_correlations / get_data_hotspots are the cached tools). window=session reads the always-on in-memory ring; window=1h/24h/7d/all reads the persistent SQLite sink (requires JDATAMUNCH_PERF_TELEMETRY=1). Sibling of jcodemunch / jdocmunch analyze_perf.

Input parameters:

- `tool` (string): Restrict the analysis to a single tool name.
- `top` (integer): Max slowest-tools / coldest-caches returned.
- `window` (string): session = in-memory ring; others read the persistent perf db.

### `finalize_handoff` (~311 tokens)

Finalize one canonical Markdown handoff for a completed data audit/analysis (jdatamunch.handoff/v1; suite parity with jCodeMunch). The server assembles YOUR sections deterministically, validates every evidence_refs entry against what this session actually retrieved (column ids like '<dataset>::<column>#column' or dataset names served by search_data / describe_dataset / describe_column — unknown refs fail closed), persists the result session-scoped, and returns a compact receipt {handoff_id, resource_uri, sha256, length, canonical:true}. Read the immutable body via the munch://handoff/<id> resource; repeated reads are byte-identical. Appendices are included exactly once; no character limit; never writes to your data.

Input parameters:

- `appendices` (array): Optional named appendices, each {name, content, content_type?}; names must be unique.
- `dataset` (string, required): Dataset the handoff is about.
- `evidence_refs` (array, required): Column ids or dataset names retrieved this session; validated against the session retrieval record.
- `profile` (string): Handoff profile label (e.g. data_audit).
- `sections` (array, required): Ordered report sections, each {heading, content} (markdown). The caller authors these; the server only assembles. Optional per-section claims[] bind evidence to an individual claim instead of one glo…
- `task` (string, required): The task/question this handoff answers (becomes the title).

### `jdatamunch_guide` (~104 tokens)

Return the version-current CLAUDE.md / AGENT.md policy snippet for jdatamunch-mcp. Lets an agent keep a one-line CLAUDE.md (e.g. "Call jdatamunch_guide and strictly follow its instructions.") instead of pasting a static snippet that drifts from the installed version. Idempotent, no dataset context required. Sibling of jcodemunch_guide and jdocmunch_guide.

## Diagnostics

Captured diagnostic sections: Provenance, Install scripts, Dependencies. The full working is on the page: https://verifymcp.io/servers/jgravelle-jdatamunch-mcp/jdatamunch-mcp#diagnostics

## Score history

- 2026-09-20: 80
- 2026-09-19: 82
- 2026-09-18: 82
- 2026-09-17: 81
- 2026-09-16: 81
- 2026-09-15: 82
- 2026-09-14: 67
- 2026-09-13: 81
- 2026-09-12: 81
- 2026-09-11: 80
- 2026-09-10: 80
- 2026-09-09: 79
- 2026-09-08: 82
- 2026-09-07: 82
- 2026-09-06: 82
- 2026-09-05: 82
- 2026-09-04: 82
- 2026-09-03: 81
- 2026-09-02: 81
- 2026-09-01: 80
- 2026-08-31: 65
- 2026-08-30: 79
- 2026-08-29: 79
- 2026-08-28: 78
- 2026-08-27: 78
- 2026-08-26: 77
- 2026-08-25: 78
- 2026-08-24: 77
- 2026-08-23: 77
- 2026-08-22: 76

## Common questions

### What is the jDataMunch MCP server?

jDataMunch MCP is listed in the public MCP registry as io.github.jgravelle/jdatamunch-mcp. Tabular data retrieval. Index CSV/Excel, query rows, aggregate. 99%+ savings vs raw file reads. This page covers its PyPI package (jdatamunch-mcp).

### Is the jDataMunch MCP server safe to use?

jDataMunch MCP scores 80 out of 100 on VerifyMCP. We found no known CVEs affecting it as of 20 September 2026. That is a record of what we were able to check automatically, not an endorsement. The category breakdown on this page shows every signal behind the number, including the ones we could not confirm.

### What tools does the jDataMunch MCP server expose?

jDataMunch MCP exposes 39 tools: index_local, index_repo, list_datasets, list_repos, describe_dataset, and 34 more. Their descriptions and schemas cost roughly 6,053 tokens of context every time the server is loaded.

### Is the jDataMunch MCP server still maintained?

jDataMunch MCP is still listed as active in the MCP registry. We last reached this channel on 20 September 2026. Those dates come from our own scans of the registry and the channel itself, not from anything the publisher announced.

## Links

- PyPI project: https://pypi.org/project/jdatamunch-mcp/
- Socket report: https://socket.dev/pypi/package/jdatamunch-mcp
- Repository: https://github.com/jgravelle/jdatamunch-mcp
- Changelog RSS feed: https://verifymcp.io/servers/jgravelle-jdatamunch-mcp/jdatamunch-mcp.xml
- Changelog JSON feed: https://verifymcp.io/servers/jgravelle-jdatamunch-mcp/jdatamunch-mcp.json
- HTML version of this page: https://verifymcp.io/servers/jgravelle-jdatamunch-mcp/jdatamunch-mcp
