For agents
This page is the shortest path from “I have never seen this API” to a cited result. Every step is one curl. The first four need no key at all.
An agent that would rather read one machine-readable file first should fetch /llms.txt for the short index, or /llms-full.txt for the same index plus every public dataset, its tables, and the API paths that read them. The OpenAPI document is the complete request and response contract.
The examples use https://api.mostlyright.md. The same routes answer on the app’s own origin.
1. Search the catalog
Section titled “1. Search the catalog”curl -sS "https://api.mostlyright.md/api/v2/public/datasets?q=weather&limit=20"Anonymous. Returns dataset identity, publisher (handle, display name, avatar), topics, published and updated dates, cover image, all-time views and likes, and a canonical page URL for each match, with a next_cursor when there is another page. Pass cursor= to continue; limit is 20 by default and 100 at most.
2. Read a dataset
Section titled “2. Read a dataset”curl -sS "https://api.mostlyright.md/api/v2/public/datasets/$DATASET_SLUG"Anonymous. Returns the dataset’s tables, each with the id every later step needs, the current version_id, its licence, and whether preview and download are enabled for it.
3. Read a table’s schema
Section titled “3. Read a table’s schema”curl -sS "https://api.mostlyright.md/api/v2/public/tables/$TABLE_ID/schema"Anonymous. Returns the column names and types to write a query against, plus the table’s capabilities. Check the schema before you compose a query: unknown columns are rejected before a table is scanned, and guessing costs you a request.
4. Preview the rows
Section titled “4. Preview the rows”curl -sS "https://api.mostlyright.md/api/v2/public/tables/$TABLE_ID/preview"Anonymous. Returns a small materialized sample of at most 100 rows, from the table’s current immutable version. It is cached, so it is the cheapest way to see what the data actually looks like before deciding whether you need it.
rows is an array of row arrays positionally aligned with columns, and the response tells you what you are holding: row_count_in_preview against total_row_count, and preview_truncated, which is true whenever what you received is only a prefix. Do not infer completeness from a short result — read the flag.
Preview is a fixed sample. It does not take filters, and it is not a substitute for a query.
5. Query with a key
Section titled “5. Query with a key”Everything past this point reads real data on behalf of a workspace, so it needs one. Open the dataset’s canonical public page, choose Use dataset, and create a personal mr_use_… key in its API access section. See Use a public dataset for the full connection flow.
curl -sS \ -H "x-api-key: $MOSTLYRIGHT_API_KEY" \ -H "content-type: application/json" \ -d '{ "columns": ["city", "date", "temperature"], "filters": [{ "column": "date", "operator": "gte", "value": "2026-08-01" }], "order_by": [{ "column": "temperature", "direction": "desc" }], "limit": 25 }' \ "https://api.mostlyright.md/api/v2/public/tables/$TABLE_ID/query"The request body is a closed query grammar, not SQL. It accepts columns, filters, order_by, aggregates, and limit, and nothing else. Do not attempt to send a SQL string; there is no endpoint that will run one.
The response carries the rows, the columns with their types, the exact version_id and content_digest the result came from, and an execution block reporting returned_rows, scanned_bytes, elapsed_ms, and whether the result was truncated.
mr_use_… is the only key type these two endpoints accept. The legacy SDK key mr_live_… and the device credential mr_cli_… are refused with a 401.
6. Download the current Parquet version
Section titled “6. Download the current Parquet version”curl -sS -o table.parquet \ -H "x-api-key: $MOSTLYRIGHT_API_KEY" \ "https://api.mostlyright.md/api/v2/public/tables/$TABLE_ID/current"The body is application/vnd.apache.parquet — the complete current snapshot, with a strong ETag and a SHA-256 Content-Digest. Save the ETag and send it as If-None-Match next time; a 304 means nothing changed and nothing is downloaded.
Query the file locally once you have it:
import duckdb
rows = duckdb.sql(""" select city, avg(temperature) as mean_temperature from read_parquet('table.parquet') group by city order by mean_temperature desc""").fetchall()Limits
Section titled “Limits”| Limit | Value |
|---|---|
Rows returned by query | 25 by default, 100 maximum |
| Result size | 64 KiB of JSON |
| Execution time | 15 seconds |
| Columns, filters, sort keys | 20, 8, 2 |
Rows returned by preview | 100 maximum |
Do not page a whole table through query. It is built for a bounded answer to a specific question, and a loop that walks a large table with it will hit the rate limit long before it finishes. Download Current once instead, verify the digest, and scan the Parquet file locally with DuckDB, Polars, Pandas, or Arrow. Refresh it on a schedule rather than on every request.
A 429 means you have reached a rate limit; respect Retry-After. A 413 means the artifact or result is too large; narrow the query or switch to Current. See Public Dataset API for the complete error table.
Cite what you used
Section titled “Cite what you used”A result is only reproducible if the reader can fetch the same bytes. Cite five things:
- the dataset name and its canonical page URL
- the table
- the immutable
version_idthe result came from - the
content_digest - the time you ran the query
A query response gives you table.version_id, table.content_digest, and citation.dataset_url directly. A Current download gives you the ETag and Content-Digest headers. The anonymous preview is citable too — it carries version.id, version.content_digest, and both citation.dataset_url and citation.table_url — so you can cite rows you have seen without ever holding a key.
content_digest is null on versions published before all-rows analytics existed; cite the version id alone in that case rather than implying a digest. And a version_id printed in a listing is the version that was current when the listing was generated — always cite the one your own response returned.
Or connect over MCP
Section titled “Or connect over MCP”If you are an AI client rather than a script, point it at https://mostlyright.md/api/mcp and skip the curl ladder entirely — see connect an AI tool.
Steps 1 to 4 above have MCP equivalents that need no credential at all: search_datasets, get_dataset, get_table_schema and sample_rows. query_table is the same gate step 5 is, and takes either an OAuth connection your client negotiates in a browser or the same mr_use_… key sent as Authorization: Bearer. Bulk Parquet stays on the HTTP API; get_download_instructions hands you the exact request.