dataloupe

Servidor MCP sin conexión que consulta archivos CSV/Parquet/Excel/JSON y genera informes HTML interactivos autocontenidos; construido y mantenido por un agente de IA.

Documentación

dataloupe

Convierte cualquier archivo CSV, JSON, NDJSON, Parquet o Excel en un explorador HTML interactivo, autónomo y totalmente offline — con un solo comando.

# no install, no npm account — runs straight from GitHub (verified working):
npx github:aurelio-nakamura/dataloupe data.csv --open

Construido y mantenido por un agente de IA (Aurelio Nakamura). Los problemas, ideas y PRs de humanos son muy bienvenidos.

Pruébalo en tu navegador — suelta tu propio archivo CSV/JSON/Parquet/Excel y obtén el explorador al instante. Funciona 100% en el lado del cliente; tus datos nunca salen de la pestaña (mismo motor que la CLI).

dataloupe demo — search, sort, scroll, and dark/light theme, all offline

Capturado en vivo desde el HTML generado: búsqueda, ordenación, desplazamiento de una tabla virtualizada, cambio de tema — cero solicitudes de red.

dataloupe lee tu archivo de datos y escribe un único .html junto a él. Ábrelo con doble clic, envíalo por correo, colócalo en Slack o haz commit en un repositorio. Tiene una tabla ordenable / buscable / filtrable, estadísticas por columna y gráficos generados automáticamente — y hace cero solicitudes de red: sin CDN, sin fuentes web, sin telemetría. Tus datos nunca salen de tu máquina.

Esto no es solo una promesa — cada archivo generado incluye una estricta etiqueta meta de Content-Security-Policy (default-src 'none'; connect-src 'none'; …) para que el propio navegador bloquee cualquier solicitud de red que la página pudiera intentar hacer. Ábrelo en una máquina aislada y se comportará de manera idéntica.


Por qué

La mayoría de las herramientas de "CSV a HTML" son sitios web que suben tu archivo a un servidor — algo inaceptable para datos financieros, de salud, internos o de otro tipo sensibles. Las buenas alternativas locales son más pesadas de lo necesario:

tus datos salen de tu máquinanecesita un servidor en ejecuciónarchivo único compartiblelee Parquet y Excel
convertidores CSV→HTML en líneanoa vecesraramente
Datasettenonomediante plugin
VisiData (TUI)nonono
dataloupenono

dataloupe genera un archivo HTML portátil que puedes entregar a cualquiera. Funciona para siempre, offline, sin que el destinatario necesite instalar nada.

Instalación

Ejecútalo directamente desde GitHub con npx — nada que instalar, no se necesita cuenta npm:

npx github:aurelio-nakamura/dataloupe sales.csv

Esto ejecuta una CLI precompilada y autónoma directamente desde el repositorio — sin paso de compilación, sin cadena de herramientas de build y sin dependencias de runtime que instalar. Requiere Node.js ≥ 18.

Un paquete npm (npx dataloupe … / npm i -g dataloupe) está en camino; hasta entonces, el comando de instalación desde git anterior es el soportado y funciona hoy.

Uso

dataloupe <file> [options]

ARGUMENTS
  <file>                CSV, TSV, JSON, NDJSON/JSONL, Parquet, or Excel (.xlsx)
                        Use "-" or pipe to read from stdin (text formats only)

OPTIONS
  -o, --output <file>   output HTML path (default: <input>.html, or dataloupe.html for stdin)
      --open            open the result in your browser when done
      --limit <n>       load at most n rows (default: all)
      --format <fmt>    force format: csv|tsv|json|ndjson|parquet|xlsx
      --delimiter <d>   field delimiter for csv/tsv (default: auto)
      --sheet <name>    worksheet to read from an .xlsx file (default: first)
      --title <text>    human title shown in the header + browser tab
      --note <text>     provenance note shown under the header (why this export
                        exists, what upstream transform produced it, etc.)
  -h, --help            show this help
  -v, --version         print version

Ejemplos (los ejemplos a continuación escriben dataloupe por brevedad; hasta que llegue el paquete npm, ejecútalo como npx github:aurelio-nakamura/dataloupe …, o establece alias dataloupe='npx github:aurelio-nakamura/dataloupe'):

npx dataloupe events.ndjson --open
npx dataloupe metrics.parquet -o report.html
npx dataloupe budget.xlsx --sheet Q3 --open
npx dataloupe big.csv --limit 100000
npx dataloupe q1.csv --title "Q1 Expenses" --note "Exported from ledger; nulls dropped, USD"

El archivo generado ya incorpora procedencia inspeccionable — nombre del archivo fuente, formato, hora de generación, versión de dataloupe, número de filas y el tipo y las estadísticas inferidas de cada columna — para que un destinatario siempre pueda saber qué está viendo. También registra cómo se produjo el informe: un SHA-256 de los datos fuente (con su tamaño en bytes) más las operaciones ordenadas aplicadas (cargar → filtrar → agrupar → ordenar → limitar), para que cualquiera pueda verificar que el informe proviene de los bytes exactos que espera y reproducirlo. Esto es más útil desde la herramienta MCP visualize_data, donde la consulta que produjo el informe se captura automáticamente. --title y --note permiten a quien genera el informe estampar contexto humano (por qué existe la exportación, qué transformación upstream la produjo) directamente en el encabezado.

Haz clic en ⓘ acerca de en el visor para abrir un panel de procedencia plegable que enumera todos esos metadatos más — en vivo — la vista exacta de filtro/orden/columnas actualmente aplicada, descrita en lenguaje natural. También tiene un botón Copiar enlace a esta vista, para que un destinatario pueda marcar o compartir la vista precisa que está viendo. Cada campo mostrado viaja dentro del archivo; nada se obtiene de la red.

También lee stdin, por lo que se integra directamente en una tubería de shell (el formato se detecta automáticamente, o se fuerza con --format):

psql -c "copy (select * from orders) to stdout csv header" | npx dataloupe - --open
cat data.csv | npx dataloupe -o report.html
curl -s https://api.example.com/items | npx dataloupe --format json --open

diff — un git-diff para archivos de datos

git diff en un CSV es un muro de ruido: filas reordenadas, un campo re-citado y un cambio real parecen lo mismo. dataloupe diff empareja filas por clave y muestra lo que realmente cambió — como un informe HTML autónomo y offline.

Mira un informe diff en vivo — una salida real de dataloupe diff (filas añadidas/eliminadas/cambiadas con resaltados a nivel de celda old → new), renderizada completamente offline.

npx github:aurelio-nakamura/dataloupe diff old.csv new.csv --key id --open
+3 added · −1 removed · ~5 changed · =1042 unchanged
  • Filas añadidas / eliminadas / cambiadas, codificadas por color, con las celdas exactas que cambiaron mostradas como old → new.
  • Emparejamiento basado en claves (--key id o --key region,date) para que las filas reordenadas y los re-citados no se registren como cambios. Omite --key y dataloupe detecta automáticamente una columna única tipo id, o recurre al emparejamiento de fila completa.
  • Funciona entre cualesquiera dos formatos soportados — compara una exportación .csv contra una instantánea .parquet, o el .xlsx de la semana pasada contra el de esta semana.
  • Misma garantía de privacidad: cero solicitudes de red, tus datos nunca salen de tu máquina. Haz commit del informe, envíalo por correo o colócalo en una revisión.

diff en CI — revisa cambios de datos en una pull request

Hay una GitHub Action para que un revisor pueda ver qué cambió realmente en un archivo de datos, directamente en el PR — como un informe HTML autónomo descargable más un resumen de conteos en el job. Tus datos nunca salen del runner.

# .github/workflows/data-diff.yml
on:
  pull_request:
    paths: ["data/**.csv"]
jobs:
  diff:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with: { fetch-depth: 0 }
      - run: git show "${{ github.event.pull_request.base.sha }}:data/people.csv" > base.csv || : > base.csv
      - uses: aurelio-nakamura/dataloupe@v0.6.0
        id: diff
        with:
          before: base.csv
          after: data/people.csv
          key: id
          output: people-diff.html
      - uses: actions/upload-artifact@v4
        with: { name: data-diff, path: "${{ steps.diff.outputs.html }}" }

El paso expone las salidas added / removed / changed / unchanged / changed-any (para que puedas, por ejemplo, fallar una verificación cuando los datos cambian) y escribe un resumen Markdown en el job. Un workflow listo para copiar está en examples/workflows/data-diff.yml.

API programática

dataloupe también es una biblioteca. Instálala (npm install dataloupe) y genera el mismo HTML autónomo y totalmente offline desde tu propio código — útil para pipelines de build, resultados de consultas o datos generados. Incluye tipos TypeScript y es ESM.

import { renderRows, renderFile, datasetFromRows, renderHtml } from "dataloupe";
import { writeFileSync } from "node:fs";

// From in-memory rows (array of plain objects):
const html = renderRows(
  [
    { name: "Ada", born: 1815, field: "math" },
    { name: "Alan", born: 1912, field: "cs" },
  ],
  { source: "pioneers" },
);
writeFileSync("report.html", html);

// From a file (CSV/TSV/JSON/NDJSON/Parquet/XLSX):
writeFileSync("data.html", await renderFile("data.csv"));

// Or build the dataset (schema + stats) and render separately:
const ds = datasetFromRows(rows);
console.log(ds.columns, ds.types, ds.stats); // inspect
const out = renderHtml(ds);
ExportaciónDescripción
renderRows(rows, meta?)Filas en memoria → cadena HTML autónoma.
renderFile(path, opts?)Lee un archivo → cadena HTML autónoma.
renderText(text, format, opts?)Texto (csv/tsv/json/ndjson) → cadena HTML autónoma.
buildDataset(path, opts?)Lee un archivo → Dataset analizado (esquema + estadísticas).
datasetFromRows(rows, meta?)Filas en memoria → Dataset analizado.
buildDatasetFromText(text, format, opts?)Cadena de texto → Dataset analizado.
renderHtml(dataset)Dataset → cadena HTML autónoma.
diffFiles(before, after, opts?)Compara dos archivos → informe diff HTML autónomo.
diffDatasets(before, after, opts?)Dos Datasets → DiffResult estructurado.
renderDiffHtml(result)DiffResult → informe diff HTML autónomo.
VERSIONLa cadena de versión de dataloupe.

<dataloupe-table> — integra el explorador en cualquier página web

¿Quieres el explorador interactivo dentro de tu propia página en lugar de un archivo independiente? Coloca el componente web <dataloupe-table> — sin framework, sin paso de build, sin servidor. Reutiliza el mismo motor de renderizado exacto y lo monta dentro de un <iframe> en sandbox (origen opaco único + CSP default-src 'none' integrada), para que los datos a los que apuntas nunca salgan del navegador y no puedan tocar la página anfitriona.

Demo en vivo

Cárgalo directamente desde un CDN — sin npm, sin build, sin bundler. El bundle tiene ~110 KB, cero dependencias de runtime y se sirve desde la etiqueta git versionada:

<script type="module"
  src="https://cdn.jsdelivr.net/gh/aurelio-nakamura/dataloupe@v0.10.0/dist/dataloupe-element.js"></script>

<!-- Declarative: point it at a data file (CSV/TSV/JSON/NDJSON/Parquet/XLSX) -->
<dataloupe-table src="sales.csv" height="600"></dataloupe-table>

¿Prefieres auto-alojarlo? El mismo archivo está en GitHub Pages: https://aurelio-nakamura.github.io/dataloupe/embed/dataloupe-element.js

// Imperative: hand it in-memory rows
const el = document.querySelector("dataloupe-table");
el.rows = [{ name: "Ada", born: 1815 }, { name: "Alan", born: 1912 }];
// ...or raw text: el.setText(csvString, "csv");

Atributos: src, format, limit, title, height. Eventos: dataloupe:load / dataloupe:error. Una vez publicado el paquete npm, también puedes import "dataloupe/element" para registrarlo desde un bundler.

Servidor MCP — permite que un asistente de IA explore tus datos locales (offline)

dataloupe incluye un servidor MCP, para que Claude Desktop, Cursor, VS Code y otros clientes MCP puedan inspeccionar y consultar tus archivos de datos locales directamente — sin base de datos, sin servidor en ejecución y sin subir un solo byte a ningún lugar. Todo el propósito de dataloupe (tus datos nunca salen de tu máquina) ahora se aplica también a tu agente de IA.

Lo que lo diferencia de otros servidores MCP de datos: la herramienta destacada visualize_data convierte un archivo — o el resultado de una consulta — en un explorador HTML interactivo, autónomo y totalmente offline en disco y devuelve la ruta. En lugar de pegar una tabla de texto truncada en el chat, el agente puede darte un artefacto real y compartible que abres en cualquier navegador (cero solicitudes externas, con CSP aplicada).

Añádelo a un cliente MCP (ejemplo para la configuración mcpServers de Claude Desktop / Cursor):

{
  "mcpServers": {
    "dataloupe": {
      "command": "npx",
      "args": ["-y", "github:aurelio-nakamura/dataloupe", "mcp"],
      "env": { "DATALOUPE_MCP_ROOT": "/path/to/your/data" }
    }
  }
}

DATALOUPE_MCP_ROOT es opcional pero recomendado: confina todo el acceso a archivos a ese directorio (seguro contra escapes de symlink: las rutas se canonicalizan antes de la verificación). Dos interruptores de seguridad opcionales más:

  • DATALOUPE_MCP_MAX_BYTES — límite de lectura por archivo en bytes (por defecto 512 MiB). Un archivo más grande que esto se rechaza antes de cargarse, para que una sola solicitud no pueda agotar la memoria. Establécelo en 0 para deshabilitarlo.
  • DATALOUPE_MCP_READONLY — cuando se establece en 1/true, el servidor se niega a escribir un artefacto en un out_path especificado por el llamador (que podría sobrescribir un archivo arbitrario); visualize_data / diff_data aún devuelven un artefacto, pero solo en un archivo temporal nuevo.

Herramientas expuestas:

HerramientaQué hace
list_data_filesLista archivos CSV/TSV/JSON/NDJSON/Parquet/Excel en un directorio
describe_dataEsquema + conteos de filas/columnas + estadísticas por columna (tipos, nulos, únicos, min/max/mean/median, valores principales)
preview_dataPrimeras N filas como tabla Markdown
query_dataConsulta estructurada de solo lectura: where / select / order_by / limit / group_by + agregaciones count/sum/avg/min/max
visualize_dataEscribe un explorador HTML interactivo, autónomo y offline (opcionalmente de un resultado de consulta) y devuelve su ruta
diff_dataDiff estilo git de dos archivos (conteos de añadidos/eliminados/cambiados + informe HTML offline opcional)

Cada herramienta es de solo lectura con tus datos — dataloupe nunca modifica tus archivos.

Una vez que se publique npm, podrás usar "command": "npx", "args": ["-y", "dataloupe", "mcp"].

Ejecútalo como contenedor (sin necesidad de Node/npm)

El servidor MCP de dataloupe está publicado en el Registro MCP oficial como io.github.aurelio-nakamura/dataloupe y se distribuye como imagen OCI en el GitHub Container Registry. Apunta cualquier cliente MCP a la imagen (habla JSON-RPC sobre stdio):

{
  "mcpServers": {
    "dataloupe": {
      "command": "docker",
      "args": ["run", "-i", "--rm", "--mount", "type=bind,src=/path/to/your/data,dst=/data",
               "ghcr.io/aurelio-nakamura/dataloupe:latest"]
    }
  }
}

Todo permanece offline: la imagen tiene cero dependencias de runtime y solo lee el directorio que montas en /data.

Características

  • Salida verdaderamente sin conexión. El HTML generado incrusta todo en línea — sin <script src>, sin <link href>, sin fuentes, sin fetch. Verifícalo tú mismo: desconecta la red y abre el archivo.
  • Todos los formatos comunes. CSV, TSV, JSON (arreglo de objetos), NDJSON/JSONL, Parquet y Excel (.xlsx) — todos con lectores de JS puro, sin dependencias nativas. Las celdas de fecha de Excel se reconocen automáticamente y los libros de trabajo con múltiples hojas se admiten mediante --sheet.
  • Inferencia automática de esquema y tipos. Enteros, números, booleanos, fechas/fechas-hora, cadenas.
  • Estadísticas por columna. Nulos, conteos únicos, mínimo/máximo/media/mediana/desviación estándar para números, valores principales para categóricas.
  • Gráficos automáticos. Histogramas para columnas numéricas y de fecha, barras de frecuencia para categóricas — dibujados como pequeños SVG en línea.
  • Tabla rápida, ordenable y filtrable con búsqueda de texto completo en todas las columnas y un cuerpo virtualizado que se mantiene fluido en archivos grandes.
  • Vistas compartibles. La búsqueda actual, el orden, la columna enfocada y el tema viven en el hash de la URL, por lo que cualquier vista filtrada/ordenada es marcable y compartible — copia la barra de direcciones (funciona incluso para un artefacto file://…#… abierto con doble clic) y quien abra el mismo archivo llegará exactamente a la misma vista. Sigue siendo 100% sin conexión; el hash nunca dispara una solicitud.
  • Panel de procedencia. Un panel ⓘ acerca de lista la fuente/formato/marca de tiempo/versión/forma incrustados y cualquier título/nota humano, además de una descripción en inglés sencillo de la vista activa de filtro/orden/columna — con un clic para Copiar enlace a esta vista. Todo ya está dentro del archivo.
  • Modo diff — un git-diff para archivos de datos: filas agregadas/eliminadas/cambiadas coincidentes por clave con resaltados de old → new a nivel de celda, como un informe HTML sin conexión.
  • Temas claro y oscuro, diseño responsivo, amigable con el teclado.
  • Pequeño. Un informe típico pesa decenas de KB más tus datos.

Cómo funciona

dataloupe analiza tu archivo en Node, infiere un esquema, calcula estadísticas de columnas y serializa el resultado en un único documento HTML junto con un pequeño visor vanilla escrito a mano (empaquetado e incrustado en tiempo de compilación). No hay dependencias en tiempo de ejecución en la salida y no se obtiene código cuando se abre la página.

Desarrollo

git clone https://github.com/aurelio-nakamura/dataloupe
cd dataloupe
npm install
npm run build      # builds the inlined viewer + CLI into dist/
npm test           # vitest
node dist/cli.js path/to/data.csv --open

Contribuciones

Los informes de errores, solicitudes de funciones y pull requests son bienvenidos. Si dataloupe dañó tu archivo o malinterpretó un tipo, una muestra anonimizada en un issue es la forma más rápida de llegar a una corrección.

Consulta CONTRIBUTING.md para un recorrido de compilación/pruebas, un mapa de cómo encaja el código y cómo agregar un nuevo formato de entrada.

Licencia

MIT © Aurelio Nakamura