# Datasets

<!-- Generated by scripts/gen-docs-mcp.mjs from the shared tool catalog. Do not edit by hand —
     edit the catalog in packages/shared/src/mcp.ts and regenerate. -->

## Tools

An agent brings its own data with `upload_file`: a table or text file is parsed into datasets, and an image or PDF is stored as a source you read yourself. `list_datasets` returns your own uploads plus the tables wired into dashboards you can view. To chart one, wire a widget pipeline to mcpId `mcp-vistazo`, toolName `read_dataset`: it is the only Vistazo tool a pipeline may call.

| Tool | What it does | |
|---|---|---|
| [`upload_file`](#upload_file) | Upload file | Additive write |
| [`get_upload`](#get_upload) | Get upload | Read-only |
| [`delete_upload`](#delete_upload) | Delete upload | Destructive write |
| [`list_datasets`](#list_datasets) | List datasets | Read-only |
| [`describe_dataset`](#describe_dataset) | Describe dataset | Read-only |
| [`read_dataset`](#read_dataset) | Read dataset | Read-only |

## upload_file

`Additive write`

Bring a file into a workspace so its tables become datasets you can chart — the way to chart data you have locally instead of pasting rows into a widget config (which freezes the chart at today's numbers). `name` is the filename WITH its extension, which decides the type: csv, tsv, xlsx, json, txt and md are PARSED, and every table in them becomes a dataset (each xlsx sheet its own); png, jpg, webp, gif and pdf are stored as SOURCES — Vistazo never reads an image with a model, and a PDF gives up only its text layer. To chart a scan, a photo or a screenshot: read the table out of it yourself, upload the scan, then upload the table as a csv naming the scan's `fileId` as `sourceFileId`, which records where the numbers came from. Two ways to send the bytes. With no `content`, the reply carries an `uploadUrl` good for ONE upload within 15 minutes: send the file with `curl -T <path> "<uploadUrl>"` (a PUT with a Content-Length), then call get_upload. For a small text file (up to 64 KB) with no shell to hand, pass it as `content` and the reply is get_upload's. Caps: 10 MB for an image, 20 MB otherwise, all of it on YOUR storage quota. The file is yours alone until a dashboard uses it, in either of two ways: SHOWN (add_widget type file, or `![alt](attachment:<fileId>)` in a markdown widget — images and PDFs), or CHARTED (a widget pipeline reading one of its datasets with read_dataset). Everyone who can view that dashboard can then open the file, and the public too when the dashboard is public. Needs full workspace membership — guests and view-only members cannot upload.

## get_upload

`Read-only`

Check a file you sent with upload_file. `status` is uploading | extracting | ready | failed | deleted, and `tables` lists what was found as {name, columns, rowCount, datasetId} — one per xlsx sheet, named for it — and a `datasetId` goes straight into describe_dataset, read_dataset or a widget pipeline. Sheets that became no dataset (blank, or past the 20-sheet or 100,000-row workbook limits) are listed in `skippedSheets` with the reason. Waits up to 3 seconds for extraction to finish; a big spreadsheet or PDF can take longer, so call again while `status` is extracting. `uploading` means the bytes have not arrived — send them to the uploadUrl first. An image or a scanned PDF lands `ready` with no tables: it is a source, stored unread, so read its table yourself and upload that. A `ready` file the parser could not turn into a table (a .json with a syntax error, or valid JSON that is not an array of flat row objects) carries a `note` saying which, and the repair. A failure says why in `error`; `errorCode: password` is a locked PDF, and the fix is an unlocked copy. Only the uploader can see an upload.

## delete_upload

`Destructive write`

Delete a file uploaded with upload_file. The bytes go and your storage is credited at once; every dataset made from it is marked deleted rather than erased, so a chart wired to one says "Source file deleted" instead of breaking silently. There is no undo — re-upload to restore. Pass the `fileId` upload_file returned: that id IS the confirmation, so resolve it first (get_upload) when unsure. The uploader may delete their file, and so may a workspace admin.

## list_datasets

`Read-only`

List your own uploaded tables plus the tables wired into dashboards you can view — tables extracted from uploaded files (CSV, spreadsheets, JSON, and tables found in PDFs/screenshots). Returns {id, workspaceId, name, columns, rowCount, updatedAt, deleted} per dataset; chart one by wiring mcpId 'mcp-vistazo', toolName 'read_dataset' (not in list_mcp_connections). THE DISCOVERY CALL: dataset ids are opaque and never guessable, so start here (or take the id the user's attached file gave you) before describe_dataset / read_dataset. `deleted: true` means the source file was deleted — the columns still describe what it held, but reading it fails; wire a chart to a live dataset instead. Pass `workspaceId` to narrow to one workspace; a workspace this connection was not granted is refused, not silently empty, and omitting it on a connection reaching several workspaces is refused (workspace_ambiguous). Carry the `workspaceId` a dataset comes back with into describe_dataset / read_dataset — that is the workspace the call is billed to.

## describe_dataset

`Read-only`

Inspect one dataset before charting it: its column names and inferred types (string | number | date | boolean), its row count, and a 5-row SAMPLE of the actual data. Call this between list_datasets and read_dataset — the sample is what tells you whether a column labelled `date` really holds dates, which column is the measure, and what the category values look like, so read_dataset's `columns`/`where`/`orderBy` can be written once instead of guessed at. Cheap: it reads only the head of the file. Pass the `workspaceId` list_datasets reported for this dataset: it is the workspace the call is billed to, and without it a connection covering several workspaces is refused with the list to pick from.

## read_dataset

`Read-only`

Read rows from a dataset — the tool a WIDGET is wired to. Returns {columns, rows, total}: `rows` are objects keyed by column name with values already coerced to the column's type (numbers as numbers, dates as ISO strings, empty cells as null), and `total` is how many rows matched before `limit`. Narrow server-side rather than client-side: `columns` picks the fields to return, `where` filters (an AND of {column, op, value} with op eq | neq | gt | gte | lt | lte | in | contains — `in` takes an array, `contains` is a case-insensitive substring test on the text form), `orderBy` sorts ({column, dir}), and `limit` caps the result (default 5000). When building a chart, wire the widget's pipeline to THIS tool as mcpId 'mcp-vistazo', toolName 'read_dataset', with the filters it needs; the transform's rawResponse is that same {columns, rows, total}. Never paste rows into the widget's config, or the chart freezes at today's data and stops following the file. If the source file was deleted the call fails with `dataset_deleted`, naming the file and who removed it; the fix is a re-upload, not a retry. Pass the `workspaceId` list_datasets reported for this dataset: it is the workspace the call is billed to, and without it a connection covering several workspaces is refused with the list to pick from.
