dataset-pipeline-mcp
An MCP server that searches HuggingFace/Kaggle for datasets, detects their domain, and generates a matching preprocessing script. It turns natural-language dataset queries into runnable, domain-aware preprocessing pipelines.
README
Dataset-Pipeline-MCP
An MCP server that turns "find me a dataset" into "find me a dataset AND a correct, domain-aware preprocessing script for it" — callable from any MCP client (Claude Code, Claude Desktop) without leaving your terminal.
Why this one, specifically
Kaggle ships an official MCP server, and there are several community HuggingFace/Kaggle MCP connectors already. They cover search, download, and (in one case) an EDA-notebook prompt. None of them detect what kind of data a dataset actually is and generate a matching preprocessing pipeline and time-series/sensor data in particular gets silently treated as generic tabular data by every generic tool, which means wrong resampling, ignored sensor drift, and no windowing.
This server's actual job is: search → detect domain → generate a
correct, runnable preprocessing script, with time_series_sensor as a
first-class domain alongside tabular, nlp_text, image, and audio.
Tools
| Tool | Description |
|---|---|
search_datasets(query, max_results, include_kaggle) |
Searches HuggingFace Hub (no auth needed) and optionally Kaggle (needs credentials). Annotates every result with a lightweight detected domain. |
detect_domain(text, tags) |
Classifies free text/tags into a domain, with a confidence score and the signals that were matched — not a black box. |
generate_preprocessing_pipeline(dataset_id, domain, source, description_hint) |
Renders a complete, runnable Python script. domain="auto" triggers metadata lookup + detection. |
find_related_papers(topic, max_results) |
arXiv search for preprocessing/methodology context. |
Plus one resource (domains://catalog) and one prompt (dataset_report)
to demonstrate full MCP surface coverage, not just tools.
Repository layout
server.py <- FastMCP wiring: tools, resource, prompt
core/
domain_detector.py <- pure heuristic classifier, fully unit-tested
templates.py <- one preprocessing script generator per domain
connectors/
huggingface.py <- public search, optional token
arxiv_search.py <- public search, no auth
kaggle_connector.py <- optional, requires user-supplied credentials
scripts/
verify_live.py <- live end-to-end check against real APIs
tests/ <- pytest suite, network-independent by design
Dockerfile
.mcp.json <- project-level Claude Code config
.env.example
mcp-config.example.json
requirements.txt / requirements-dev.txt
core/ has zero network dependencies by design — it's the part that has to
be correct every time, so it's the part that's cheap to test exhaustively.
connectors/ is where the world can fail, so every connector fails
loudly and specifically, but never silently or fatally.
Setup
git clone https://github.com/pranjalisr/dataset-pipeline-mcp.git
cd dataset-pipeline-mcp
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
pip install -r requirements.txt
No credentials are required for basic use — HuggingFace dataset search is
public. Copy .env.example to .env and fill in HUGGINGFACE_TOKEN /
Kaggle credentials only if you want higher rate limits or Kaggle search.
.env is gitignored — double check with git check-ignore -v .env
before committing if you're ever unsure.
Running generated scripts locally
generate_preprocessing_pipeline produces a script that depends on
pandas, numpy, and scipy — these are not required to run the MCP
server itself (the server only generates this code as text, it never
imports these libraries), so they're kept in a separate
scripts/requirements.txt rather than the top-level one:
pip install -r scripts/requirements.txt
Running it standalone
python server.py
This starts the server on stdio, which is how MCP clients launch local
servers. Running it directly just makes it sit and wait for a client to
connect — use one of the methods below to actually exercise it.
Verifying live network calls work
The automated test suite intentionally does not depend on live HuggingFace/arXiv/Kaggle access, so it passes even offline. To confirm the real network calls work end-to-end:
python scripts/verify_live.py
python scripts/verify_live.py --query "wearable sensor human activity recognition"
This calls the tools through the real MCP protocol layer for every supported domain plus a live Kaggle check when credentials are configured, and prints a PASS/FAIL summary with the resolved domain and confidence for each — including a hard failure if a result comes back with zero confidence, since a generated script with no real domain signal isn't trustworthy even though it's technically valid Python.
Interactively testing tools with MCP Inspector
npx @modelcontextprotocol/inspector python server.py
Prints a local URL with a UI listing all tools/resources/prompts where you can fill in arguments and see live JSON responses.
Running with Docker
docker build -t dataset-pipeline-mcp .
docker run -i --rm dataset-pipeline-mcp
npx @modelcontextprotocol/inspector docker run -i --rm --env-file .env dataset-pipeline-mcp
Connecting to Claude Code
This repo includes a project-level .mcp.json, so opening it in Claude
Code prompts you to trust the dataset-pipeline server automatically. To
wire it up manually instead:
claude mcp add --transport stdio dataset-pipeline -- python /absolute/path/to/dataset-pipeline-mcp/server.py
Once connected, just ask naturally — e.g. "find me a wearable sensor dataset for activity recognition and give me a preprocessing pipeline for it" — and the model decides which tools to call and in what order; you never name a tool directly.
Testing
pip install -r requirements-dev.txt
pytest tests/ -v
The bug hunt
This project's test suite didn't just check coverage gaps — every bug below was found by actually running the server against live data, a real Docker container, or a real Claude Code session, not by reading the code and assuming it was correct.
-
Lazy-generator exception escape.
huggingface_hub.list_datasets()returns a lazy generator — the HTTP request only fires on iteration, so wrapping just the call in try/except let real API failures escape uncaught. Fixed by materializing the generator inside the try block. -
HuggingFace's
searchparam is a repo-name substring match, not full text search. A natural-language query like"human activity recognition sensor"returned zero results on a200 OK— matching datasets existed, but not with that literal string in their name. Fixed with a keyword-fallback search plus relevance ranking. -
Domain detection was reading empty YAML frontmatter.
dataset_info().cardDatais the README's front matter, which authors almost never fill in — the real description lives in the Markdown body, a separate fetch (DatasetCard.load().text). Detection was running on empty input for most real datasets until this was fixed. -
Single-keyword overconfidence. The confidence formula (
winning_score / total_score) reports1.0whenever only one domain has any signal — even a single ambiguous keyword. A wearable video dataset scored 100% confidence fortime_series_sensoroff the word "wearable" alone. Fixed with an evidence floor that dampens confidence when total signal strength is thin, verified to leave strong multi-signal matches untouched. -
Kaggle SDK crash bug.
import kagglecallssys.exit(1)internally when credentials aren't recognized — andSystemExitis not caught byexcept Exception(it inherits fromBaseException). A single bad Kaggle token could have crashed the entire server process, not just failed that one call. Confirmed against the real installed package and fixed by explicitly catchingSystemExitat every Kaggle API boundary. -
Image domain had no standalone keyword. Unlike
tabular/nlp/audio, which all have their own name as a strong signal,imageonly classified correctly by accident (via an unrelated"x-ray"match) on a real chest X-ray dataset. Fixed by adding"image"itself as a signal. -
Blank
HUGGINGFACE_TOKENbreaks auth..env.exampleshowsHUGGINGFACE_TOKEN=(blank) as a template — butos.environ.get()returns""for a set-but-empty variable, notNone, so an empty string was passed as a literal bearer token (Illegal header value b'Bearer ') instead of being treated as "no token." Fixed in the HuggingFace API client setup. -
Client-side paste artifacts. A real MCP Inspector session had its own placeholder hint text (
query: "wearable sensor") submitted literally instead of being replaced, polluting search results with unrelated matches on the stray word "query." Fixed with input sanitization that strips a recognized<label>:prefix and one layer of fully-wrapping quotes, verified not to touch genuine queries that happen to contain those words ("search query logs dataset"passes through unchanged).
Every fix above shipped with a regression test that reproduces the original failure, not just a check that the happy path still works.
Proof it works end-to-end
Beyond unit tests, this was verified through the full real stack: local
stdio, live HuggingFace search across all five domains, live arXiv search,
a live Kaggle call (crash-fixed and confirmed safe on invalid credentials),
a built and running Docker container connected via MCP Inspector, and
finally a real Claude Code session — asked in plain English, with no tool
names given — that correctly chained search_datasets →
generate_preprocessing_pipeline, found DiFronzo/Human_Activity_Recognition,
generated the time_series_sensor template, then independently discovered
the template's assumptions didn't match that dataset's real file layout
(separate accelerometer/gyroscope files + a label-segment file, no
timestamps) and rewrote the script to handle it correctly — producing
3,289 labeled windows across 5 balanced activity classes with a proper
subject-wise train/test split.
Known limitations
- Domain detection is keyword/heuristic-based, not a trained classifier —
transparent and fast, but a genuinely ambiguous or sparsely-described
dataset can be misclassified.
detect_domainalways returns its confidence and matched signals so a caller can tell when to double-check. search_datasets's per-resultdomainfield is a lightweight, free estimate (id words + whatever description/tags came back in the list response) —generate_preprocessing_pipeline(domain="auto")does a deeper per-dataset fetch and is the one to trust for a real classification.- Kaggle search requires the user's own API credentials
(
KAGGLE_API_TOKENrecommended); this server never requests, stores, or proxies them beyond reading environment variables. The full success path with a genuinely valid token hasn't been verified in this project's own testing — only the credential-missing and credential-invalid paths have live coverage. - Preprocessing templates are strong starting points, not final pipelines — they're meant to be read and adapted (target columns, window sizes, actual file formats), not run blindly in production.
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.