Prism
Dataset Analysis MCP for Mac
A stateful Model Context Protocol server that turns LLMs into data scientists.
Load a CSV. Ask your LLM to clean it, find outliers, normalize categories, encode features, split for ML, and export a reproducible pipeline config — all through natural language.
The server maintains in-memory state across tool calls, so the LLM doesn't need to pass DataFrames back and forth. Just talk to your data.
⚡ Quick Start (macOS)
Website: kushals256.github.io/mcp-server · Download: Latest release
# Recommended
pip install dataset-analysis-mcp
dataset-analysis-mcp-setup
dataset-analysis-mcp-doctor
Then quit Claude Desktop (Cmd+Q), reopen it, and try:
Load ~/datasets/sample_sales.csv and run a data quality check
Menu bar companion
Download the DMG for the native Mac menu bar app. When active, a chart icon appears in your menu bar — click it to disable the server, open your data folder, or run a health check.
The pip setup wizard configures Claude only; it does not include the menu bar app bundle.
Claude Desktop config (auto-written by setup)
{
"mcpServers": {
"dataset-analysis": {
"command": "dataset-analysis-mcp",
"args": [],
"env": { "MCP_DATA_DIR": "~/datasets" }
}
}
}
If you use uv instead of pip, uvx dataset-analysis-mcp also works.
Developer setup
git clone <repository_url> && cd mcp-server
uv sync
source .venv/bin/activate
python main.py
Releasing
- Bump
versioninpyproject.toml - Commit, tag, and push:
git tag v0.1.2 && git push origin main --tags - The Release GitHub Action builds the DMG, uploads assets, and publishes to PyPI
For PyPI trusted publishing, add a pending publisher for workflow release.yml at pypi.org/manage/account/publishing/.
📥 Loading Datasets
There are two ways to load data into the server:
Option 1: Load from anywhere (recommended)
Use load_dataset to load files from any location on your machine — no copying required:
User: "Analyze the file at ~/Downloads/sales.csv"
→ AI calls load_dataset("~/Downloads/sales.csv")
Supported path formats:
- Absolute:
/Users/me/data/sales.csv - Home shorthand:
~/Downloads/sales.csv - Relative (from CWD):
../data/sales.csv
Supported file types: .csv, .json, .parquet, .xlsx
Option 2: Use the data/ directory
Place files in the data/ folder and use the classic workflow:
1. list_datasets() → see what's available
2. load_dataset_metadata("sales.csv") → load into memory
By default, data/ is resolved relative to where you start the server. You can override this with the MCP_DATA_DIR environment variable (see Configuration).
🏗️ Architecture
┌──────────────────────────────────────────────────────────────────┐
│ LLM (Claude, etc.) │
└─────────────────────────────┬────────────────────────────────────┘
│ MCP Protocol
┌─────────────────────────────▼────────────────────────────────────┐
│ FastMCP Server (main.py) │
│ ┌─────────────────────────────────────────────────────────────┐ │
│ │ GlobalStateManager (Singleton) │ │
│ │ ┌──────────┐ ┌───────────┐ ┌──────────┐ ┌────────────┐ │ │
│ │ │ DataFrame│ │ Test Set │ │ Pipeline │ │Transformers│ │ │
│ │ │ (active) │ │ (hidden) │ │ History │ │ (fitted) │ │ │
│ │ └──────────┘ └───────────┘ └──────────┘ └────────────┘ │ │
│ └─────────────────────────────────────────────────────────────┘ │
│ │
│ Phase 1 Phase 3 Phase 4 Phase 4.5 │
│ ┌─────────┐ ┌───────────┐ ┌────────────┐ ┌───────────┐ │
│ │Discovery│──▶│ Analysis │──▶│ Transform │──▶│ Normalize │ │
│ └─────────┘ └───────────┘ └────────────┘ └─────┬─────┘ │
│ │ │
│ Phase 5 Phase 6 Phase 2 │ │
│ ┌──────────┐ ┌───────────┐ ┌────────────┐ │ │
│ │ Feature │◀──│ Validate │ │ Persist │◀───────┘ │
│ │ Eng. │ │ (Dry-run)│ │ (Save) │ │
│ └──────────┘ └───────────┘ └────────────┘ │
└──────────────────────────────────────────────────────────────────┘
🛠️ All 29 Tools
Phase 1 — Discovery
| Tool | Description |
|---|---|
list_datasets |
Scan data/ for CSV & JSON files |
load_dataset_metadata |
Load a file from data/ into memory + return metadata |
peek_dataset_metadata |
Read-only inspection — no state mutation |
load_dataset |
Load a dataset from any path on your machine (absolute, ~, relative) |
Phase 2 — Persistence
| Tool | Description |
|---|---|
save_processed_dataset |
Save to CSV / JSON / Parquet (train or test split) |
export_pipeline_config |
Export all operations as reproducible JSON / YAML |
Phase 3 — Analysis
| Tool | Description |
|---|---|
describe_dataset |
Statistical summary (mean, std, quantiles, value counts) |
correlation_analysis |
Pearson · Spearman · Kendall · Cramér's V · Eta |
detect_data_quality_issues |
Missing values · outliers · duplicates · high cardinality · zero-variance |
Phase 4 — Transformation
| Tool | Description |
|---|---|
drop_duplicate_rows |
Remove exact-match duplicate rows |
handle_missing_values |
Impute or drop missing values (multiple strategies) |
remove_outliers |
Z-score · IQR · Modified Z · Isolation Forest · LOF |
cast_column_type |
Cast columns to int, float, str, bool, datetime, category |
drop_columns |
Drop columns with duplicate-creation warnings for identity columns |
encode_categorical_feature |
8 methods: one-hot · label · ordinal · frequency · target · binary · hashing · leave-one-out |
train_test_split |
Stratified splitting with immutability guarantees |
Phase 4.5 — Categorical Normalization Pipeline
A 4-layer pipeline that runs before encoding to clean messy categorical data:
① normalize_categorical_text surface cleanup (unicode, accents, casing)
↓
② harmonize_categorical_values synonym → canonical mapping (FlashText)
↓
③ cluster_similar_categories fuzzy typo clustering (RapidFuzz)
↓
④ ml_prepare_categorical ML-aware dedup / GapEncoder (skrub)
| Layer | Tool | Engine |
|---|---|---|
| 1 | normalize_categorical_text |
unicodedata · clean-text · text-unidecode |
| 2 | harmonize_categorical_values |
flashtext (Aho-Corasick) |
| 3 | cluster_similar_categories |
rapidfuzz |
| 4 | ml_prepare_categorical |
skrub (lazy-loaded) |
Phase 5 — Feature Engineering
| Tool | Description |
|---|---|
create_feature |
Create derived columns from Python/pandas expressions |
extract_features |
Extract numeric features from text or datetime columns |
reduce_features |
Dimensionality reduction (PCA, feature selection) |
remove_features |
Drop engineered or redundant feature columns |
generate_preprocessing_report |
Generate a summary report of all transformations |
Phase 6 — Validation & Safety
| Tool | Description |
|---|---|
validate_action |
Dry-run any tool — get memory estimates and risk flags before executing |
Phase 7 — Versioning
| Tool | Description |
|---|---|
list_versions |
List saved dataset versions in memory |
rollback_version |
Restore a previous dataset version |
diff_versions |
Compare two versions side by side |
🔒 Safety Features
| Feature | How |
|---|---|
| Dry-run validation | validate_action estimates memory, flags leakage risk, blocks unsafe cardinality |
| Source file protection | save_processed_dataset blocks overwriting the loaded source file |
| Identity column warnings | drop_columns warns when dropping ID columns would create duplicates |
| Split immutability | train_test_split prevents re-splitting; test set is hidden from training operations |
| Cardinality guards | One-hot encoding blocked at >100 unique values, warned at >20 |
| Zero-variance detection | detect_data_quality_issues flags constant and near-constant columns |
| NaN preservation | All encoders explicitly preserve NaN rows through transformations |
📂 Project Structure
mcp-server/
├── main.py # Server entry point — registers all 29 tools
├── config.py # Centralized thresholds & constants
├── tools/ # Tool implementations
│ ├── discovery.py # list, load, peek datasets
│ ├── save_dataset.py # save data + export pipeline
│ ├── persistence.py # preprocessing reports
│ ├── eda.py # describe + correlation
│ ├── data_quality.py # quality issue detection
│ ├── cleaning.py # drop duplicates
│ ├── handle_missing_values.py # missing value strategies
│ ├── remove_outliers.py # 5 outlier removal methods
│ ├── cast_column_type.py # type casting
│ ├── drop_columns.py # column dropping + warnings
│ ├── encode_categorical.py # 8 encoding methods
│ ├── train_test_split.py # stratified splitting
│ ├── normalize_categorical.py # Layer 1: surface cleanup
│ ├── harmonize_categorical.py # Layer 2: synonym mapping
│ ├── cluster_categorical.py # Layer 3: fuzzy clustering
│ ├── ml_prepare_categorical.py # Layer 4: ML-aware prep
│ ├── feature_engineering.py # expression-based features
│ ├── versioning.py # list, rollback, diff versions
│ └── validation.py # dry-run safety checks
├── utils/
│ └── state_manager.py # GlobalStateManager singleton
├── tests/ # 18 test suites
├── data/ # Input/output datasets
├── pyproject.toml # Dependencies & build config
└── requirements.txt # Pip-compatible deps
🧪 Testing
# Run all tests
python -m pytest tests/ -v
# Run a specific suite
python -m pytest tests/test_encode_categorical.py -v
# Run normalization pipeline tests
python -m pytest tests/test_normalize_categorical.py \
tests/test_harmonize_categorical.py \
tests/test_cluster_categorical.py \
tests/test_ml_prepare_categorical.py -v
# With coverage
python -m pytest tests/ --cov=tools --cov-report=term-missing
🧑💻 Adding a New Tool
# 1. Create tools/my_tool.py
from utils.state_manager import GlobalStateManager
def my_tool(dataset_name: str, column: str) -> dict:
manager = GlobalStateManager()
df = manager.get_data()
if df is None:
return {"error": "No dataset loaded"}
# ... transform df ...
manager.load_data(df_modified, dataset_name, reset_split=False)
manager.log_action("my_tool", {"column": column})
return {"result": "done"}
# 2. Register in main.py
from tools.my_tool import my_tool
mcp.tool()(my_tool)
# 3. Add to validate_action (tools/validation.py)
elif tool == "my_tool":
return ValidateActionResponse(allowed=True, reason="...", estimated_memory_mb=current_memory_mb)
⚙️ Configuration
Data Directory (MCP_DATA_DIR)
The data/ directory used by list_datasets, load_dataset_metadata, and save_processed_dataset defaults to ./data/ relative to your current working directory. Override it with an environment variable:
CLI:
export MCP_DATA_DIR=/Users/me/my-datasets
python main.py
Claude Desktop:
{
"mcpServers": {
"dataset-analysis": {
"command": "/path/to/.venv/bin/python",
"args": ["/path/to/mcp-server/main.py"],
"env": { "MCP_DATA_DIR": "/Users/me/my-datasets" }
}
}
}
Note:
load_datasetaccepts full file paths directly, so it works regardless ofMCP_DATA_DIR.
Algorithm Thresholds
All thresholds live in config.py:
| Category | Key Constants |
|---|---|
| Outlier Detection | DEFAULT_ZSCORE_THRESHOLD=3.0, DEFAULT_IQR_MULTIPLIER=1.5 |
| Encoding Limits | ONE_HOT_MAX_CARDINALITY=20, ONE_HOT_BLOCK_CARDINALITY=100 |
| Fuzzy Matching | FUZZY_SCORE_THRESHOLD=85, FUZZY_MAX_COMPARISONS=1000 |
| Missing Values | Low/Medium/High severity thresholds |
| Quality Detection | Cardinality ratios, skewness/kurtosis bounds |
📦 Dependencies
| Package | Purpose |
|---|---|
mcp |
Model Context Protocol server framework |
pandas |
DataFrame operations |
scikit-learn |
Outlier detection, label encoding, train/test split |
category-encoders |
Target, binary, hashing, leave-one-out encoding |
rapidfuzz |
Fuzzy string matching for category clustering |
flashtext |
Aho-Corasick keyword replacement for synonym mapping |
skrub |
ML-aware deduplication and GapEncoder |
clean-text |
Unicode fixing, control char stripping |
scipy |
Statistical tests for correlation analysis |
🛠️ Troubleshooting
Server won't start
source .venv/bin/activate
python --version # Must be 3.10+
uv sync # or pip install -r requirements.txt
Dataset not found
- Quickest fix: Use
load_dataset("~/path/to/your/file.csv")to load from any location. - Using
data/folder: Make sure you're running the server from the directory that containsdata/, or setMCP_DATA_DIRto point to the right place. - Verify: Run
list_datasets()to see what the server can find.
"Unknown tool" in validate_action
Ensure the tool name matches exactly — use the registered function name, not aliases.
All 29 tools are covered in validate_action as of the latest version.
Import errors
Run from the project root. Ensure __init__.py exists in tools/ and utils/.
Built with ❤️ using Model Context Protocol
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file dataset_analysis_mcp-0.1.2.tar.gz.
File metadata
- Download URL: dataset_analysis_mcp-0.1.2.tar.gz
- Upload date:
- Size: 2.9 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7d5d3a8e2c8f0789d53b86eea4894c4fb77ffdaba64f854aa763e5a6958f29f2
|
|
| MD5 |
5b972b418da65fd89c3bb587995b3c3e
|
|
| BLAKE2b-256 |
1b01cba6559de71eb112aadf59d1d54c723d4e5af20fc6d58cf1341565084d9d
|
Provenance
The following attestation bundles were made for dataset_analysis_mcp-0.1.2.tar.gz:
Publisher:
publish-pypi.yml on kushals256/mcp-server
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dataset_analysis_mcp-0.1.2.tar.gz -
Subject digest:
7d5d3a8e2c8f0789d53b86eea4894c4fb77ffdaba64f854aa763e5a6958f29f2 - Sigstore transparency entry: 2501242271
- Sigstore integration time:
-
Permalink:
kushals256/mcp-server@c8c9c18fd2595dd16c5560fc79a017f6c744ae7f -
Branch / Tag:
refs/heads/main - Owner: https://github.com/kushals256
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@c8c9c18fd2595dd16c5560fc79a017f6c744ae7f -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file dataset_analysis_mcp-0.1.2-py3-none-any.whl.
File metadata
- Download URL: dataset_analysis_mcp-0.1.2-py3-none-any.whl
- Upload date:
- Size: 89.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f574b419f898bbac86966394af42cf398375a9f895aa7681400afe40e8957e88
|
|
| MD5 |
123505a6989b489b82c1aca738b4d447
|
|
| BLAKE2b-256 |
3a3d1edc83c3b8be55a97a225bd4868303d47700c9e3b400e41842739d716f79
|
Provenance
The following attestation bundles were made for dataset_analysis_mcp-0.1.2-py3-none-any.whl:
Publisher:
publish-pypi.yml on kushals256/mcp-server
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dataset_analysis_mcp-0.1.2-py3-none-any.whl -
Subject digest:
f574b419f898bbac86966394af42cf398375a9f895aa7681400afe40e8957e88 - Sigstore transparency entry: 2501242288
- Sigstore integration time:
-
Permalink:
kushals256/mcp-server@c8c9c18fd2595dd16c5560fc79a017f6c744ae7f -
Branch / Tag:
refs/heads/main - Owner: https://github.com/kushals256
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@c8c9c18fd2595dd16c5560fc79a017f6c744ae7f -
Trigger Event:
workflow_dispatch
-
Statement type: