dc-mcp
by iishanmakkar
README.md
# Agentic Data Cleaner -- notebook + Muse connector
Finds and fixes problems in tabular data (CSV, TSV, Excel, JSON, Parquet, ...): duplicates, placeholder nulls (`N/A`, `?`),
numbers/dates stored as text, spelling variants, encoding damage, outliers, personal data. Safe fixes apply automatically;
anything that deletes or invents data waits for a human yes. Every run produces the cleaned file, an audit report and a
standalone replay script.
One engine, three ways to use it:
```
datacleaner/engine.py ──► agentic_data_cleaner.ipynb (generated by tools/build_notebook.py -- can't drift)
│
└──────────────► server/ ──► MCP endpoint /mcp (what Muse connects to)
└──► REST API /v1/... (OpenAPI at /docs)
```
## 1. Use the notebook
```bash
pip install -r requirements.txt jupyter
jupyter lab agentic_data_cleaner.ipynb # Run All -- cleans input/uncleaned_data.csv into output/
```
Or as a library: `from datacleaner import AgenticDataCleaner; AgenticDataCleaner("data.csv").run(interactive=False)`.
A model is optional (`LLM_*` in `.env`); without one, deterministic rules plan everything.
## 2. Run the Muse connector locally
```bash
pip install -r requirements.txt
cp .env.example .env # then edit: API_KEYS, PUBLIC_BASE_URL, ALLOWED_HOSTS
set -a; . ./.env; set +a
uvicorn server.app:app --port 8000
curl localhost:8000/healthz # {"ok":true}
```
MCP endpoint: `http://localhost:8000/mcp` (Streamable HTTP, `Authorization: Bearer <key>`). REST docs: `/docs`.
### Tools Muse sees
| Tool | What it does |
|---|---|
| `clean_dataset` | One call: scan -> apply every safe fix -> export links. Returns `needs_your_decision` for risky items |
| `scan_dataset` | Load a file, list every problem, change nothing. Returns `dataset_id` |
| `get_cleaning_plan` | Proposed fix per problem, with risk and "applies automatically?" |
| `apply_cleaning_plan` | Apply low/medium items; high-risk items only via `approve_ids` (the user's explicit yes) |
| `apply_cleaning_action` | One specific action (Muse as the planner); risky ones need `confirm=true` |
| `preview_dataset` / `export_dataset` | Look at rows / get time-limited download links (csv, tsv, xlsx, json, jsonl, parquet) |
| `create_upload_url` | One-time URL for files too big to pass inline |
| `delete_dataset` / `list_cleaning_actions` | Delete now / list actions |
Input can be `file_base64`, `csv_text`, a public `file_url` (https only, SSRF-guarded) or an `upload_id`.
## 3. Deploy
Pick one -- both configs are in this folder:
```bash
# Fly.io (fly.toml): fly launch --no-deploy -> fly secrets set API_KEYS=... -> fly deploy
# Render (render.yaml): push to GitHub -> New + -> Blueprint -> read the API key from the dashboard
```
Or anywhere with Docker (untested -- no Docker here): `docker build -t data-cleaner . && docker run -p 8000:8000 --env-file .env data-cleaner`
Then set the env vars to your real domain (`PUBLIC_BASE_URL`, `ALLOWED_HOSTS`) and **always set `API_KEYS`** (empty means open).
Generate a key with: `python -c "import secrets; print(secrets.token_urlsafe(32))"`.
**Before you submit, run the reviewer test against your live URL:**
```bash
python tools/preflight.py https://your-domain.example YOUR_API_KEY
```
It checks everything Muse's reviewers will touch (public pages, auth, MCP handshake, a real clean + download) and exits 0
only when all pass. **Scaling:** datasets live in process memory, so run one instance/worker; to go multi-instance, move
`server/store.py` and the meters in `server/quota.py` to Redis/S3.
## Security model (what is actually enforced, and tested)
* Bearer-key auth (constant-time compare); each client's datasets are isolated -- "not yours" and "doesn't exist" look identical.
* Unguessable dataset/download/upload tokens; datasets, artifacts and upload slots expire (default 1 h) and can be deleted on demand.
* Only allow-listed formats are parsed (csv/tsv/txt/json/jsonl/xlsx/parquet). No pickle, HDF5, SQLite, HTML/XML, legacy `.xls`;
no server file paths; row/column/size caps; zip-bomb checks on `.xlsx`; Parquet metadata checked before reading.
* URL fetching: https/443 only, no credentials, every address must be public (DNS is resolved once and the connection is pinned
to that IP), redirects re-validated, size and time capped.
* The actions are a fixed registry -- no code execution, no user regexes. A model (if you enable one) cannot lower risk, invent
actions or touch missing columns; and `LLM_ENABLED` is **off** by default with cell values redacted when on.
* Errors return generic messages (stack traces stay in server logs); logs hold ids and counts, never data.
* DNS-rebinding protection on `/mcp` (`ALLOWED_HOSTS`), `nosniff`, `no-store`, strict CSP on the public pages.
## Tests
```bash
pip install -r requirements-dev.txt
pytest # 89 tests: engine, planner guard rails, server, SSRF, tiers, live MCP client, notebook end-to-end
```
## What is *not* done / not verified (please read)
* **Not deployed and not submitted** -- I can't do either from here. You need a host, a domain, real legal text and to fill the form (`muse/submission.md`).
* **Muse's exact requirements are unverified.** I could not confirm how Muse authenticates to a connector (bearer key vs OAuth), how
payment entitlement reaches your server, or the review criteria. Check Meta's current developer docs. Auth is one function
(`server/app.py::_client_id`); entitlement is one function (`server/quota.py::tier_for`).
* **The Dockerfile is untested** (no Docker in the build environment); the app itself was tested via uvicorn + a real MCP client.
* **Scheduled cleaning is not built** -- it is the feature most likely to justify a subscription (see `docs/monetization.md`).
* Long calls: a 200k-row file took ~8 s in the sandbox. Confirm Muse's tool timeout before advertising that size.
* Legal pages are drafts, not legal advice.
See `CHANGELOG.md` for every bug fixed in the original notebook, and `docs/monetization.md` for the earning model.
Built by **Ishan Makkar** -- https://github.com/iishanmakkar/dc-mcp
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues