Spelunk
A multi-source DuckDB query + transformation-pipeline MCP server. Point it at files (CSV/Parquet/JSON/Excel) and databases (SQLite/PostgreSQL/MySQL), and an agent like Claude Code can query across all of them — and build step-by-step pipelines — through one DuckDB engine.
Architecture in one line
A single DuckDB session is both the query engine and the workspace: every source is ATTACHed
(databases) or scanned (files) into one connection, so one query can join a Parquet file to a
Postgres table to a result you built two steps ago — all in DuckDB SQL.
| Path | Role |
|---|---|
spelunk/core/duck.py |
DuckSession — the one DuckDB connection: query / profile / export / catalog / drop / lineage / replay + introspection. |
spelunk/core/sources.py |
Source registry — maps a spec to a DuckDB attach/scan. DuckDB-only: a source it can't attach (e.g. SQL Server) is rejected. |
spelunk/core/guard.py |
sqlglot AST safety: read-only enforcement (assert_read_only). |
spelunk/mcp/server.py |
Thin FastMCP wrapper over DuckSession. |
tests |
Acceptance tests. |
Tools
query(sql, name, flow?) # run a read-only SELECT over sources + results; store the full
# result as table `name` for immediate reuse. The ONE tool for
# looking and building — every result is named and chainable.
profile(sql, flow?) # per-column stats (null_rate, min/max/mean/std, percentiles, top/freq)
export(target, fmt, path) # write a saved result name OR a full SELECT to csv/json/parquet
catalog(flow?) # list flows, or the results in one flow
drop(name?, flow?) # drop one result, or a whole flow
lineage(name?, flow?) # provenance DAG: the SQL + deps that built a result (or a whole flow)
replay(flow?, into?) # rebuild a flow from its recorded SQL, in dependency order
Discovery resources: db://tables (queryable source objects) and db://{table} (columns, PK,
sample, row count). A flow is an isolated result namespace (a DuckDB schema); give each
concurrent line of analysis its own flow.
Install & run
The fastest path is uvx — no clone, no venv. It fetches Spelunk
into an ephemeral environment and runs the spelunk command. The package is published as
spelunk-mcp (the command is spelunk), so pass it via --from:
uvx --from spelunk-mcp spelunk \
--source sales=./data/sales.parquet \
--source sqlite:///path/to/app.db \
--session-dir .spelunk_session # omit for an ephemeral (non-durable) workspace
Want the latest commit instead of the released version? Point uvx straight at the repo:
uvx --from git+https://github.com/shaunak2512/spelunk spelunk --source sales=./data/sales.parquet
Either way, wire it into Claude Code with a .mcp.json:
{
"mcpServers": {
"spelunk": {
"command": "uvx",
"args": ["--from", "spelunk-mcp", "spelunk", "--source", "sales=./data/sales.parquet"]
}
}
}
Prefer a local checkout? python -m spelunk.mcp.server --source ... is equivalent to the spelunk
command.
Sources auto-detect by extension/scheme; prefix with name= to set the catalog/view name.
Optional resource guards: --memory-limit 4GB, --temp-dir <dir>, --max-temp-size 50GB.
DuckDB is out-of-core, so a source larger than RAM is the normal case — scans read on demand and
buffering operators spill to the temp directory.
Dev
uv sync --extra dev
uv run --extra dev python -m pytest -q
uv run --extra dev ruff check spelunk/
Metadata
Release files for spelunk-mcp 0.2.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| spelunk_mcp-0.2.1.tar.gz | 163.0 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| spelunk_mcp-0.2.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 209.4 kB
Release files / spelunk_mcp-0.2.1.tar.gz
| Download URL | spelunk_mcp-0.2.1.tar.gz |
|---|---|
| Size | 163.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
bb98b01558e56962ee4abfc534cc4fdad2aa78142dafc824b59ff31a98e74bde
|
|
BLAKE2b-256 checksum How to use checksums |
a0eaf2a74decdaf8004838e1a56049c8a377dc8aa0f8d8ca255b9b17bd8323f0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.13
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 28, 2026.
Transparency logRelease files / spelunk_mcp-0.2.1-py3-none-any.whl
| Download URL | spelunk_mcp-0.2.1-py3-none-any.whl |
|---|---|
| Size | 46.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
b8d20809d99941327d72351bb5f7562b95da33df598ea7b3ef5667fa9d6a5d18
|
|
BLAKE2b-256 checksum How to use checksums |
b1419a13daee1c1edf1fec668eba0756b5fcffb2b3de78e0f65432ed0d41b10d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.13
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 28, 2026.
Transparency logSecurity for spelunk-mcp 0.2.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for spelunk_mcp-0.2.1.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 28, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.