Connect an AI tool
Mostly Right runs a Model Context Protocol server at https://mostlyright.md/api/mcp. It speaks Streamable HTTP and negotiates protocol revisions 2025-11-25, 2025-06-18, 2025-03-26 and 2024-11-05. It is stateless: it issues no session id, so every request stands alone.
Searching the catalogue, reading schemas and pulling sample rows need no account. Signing in adds querying whole tables at 10,000 rows a page and downloading a full Parquet snapshot. A paid workspace adds building: write a recipe, run it, publish the table it produces.
Add the server
Section titled “Add the server”Claude Code adds it from the shell.
claude mcp add --transport http mostlyright https://mostlyright.md/api/mcpClaude Desktop takes it under Settings → Connectors → Add custom connector, pasting https://mostlyright.md/api/mcp.
Cursor reads ~/.cursor/mcp.json:
{ "mcpServers": { "mostlyright": { "url": "https://mostlyright.md/api/mcp" } }}VS Code reads .vscode/mcp.json:
{ "servers": { "mostlyright": { "type": "http", "url": "https://mostlyright.md/api/mcp" } }}ChatGPT takes the same URL under Settings → Connectors → Add custom connector. Its connector contract requires two tools with exact names and shapes, and this server implements both. search takes a query and returns {results: [{id, title, url}]} with the dataset slug as the id. fetch takes that id and returns {id, title, text, url, metadata} with the dataset as Markdown in text. Both are anonymous. From the OpenAI Responses API, pass the server as a tool: {"type": "mcp", "server_label": "mostlyright", "server_url": "https://mostlyright.md/api/mcp"}.
Any other client handshakes by hand:
curl -sS https://mostlyright.md/api/mcp \ -H "content-type: application/json" \ -H "accept: application/json, text/event-stream" \ -H "mcp-protocol-version: 2025-06-18" \ -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"curl","version":"1"}}}'What works without an account
Section titled “What works without an account”| Tool | What it answers |
|---|---|
search |
The ChatGPT connector search. A query in, up to 20 {id, title, url} results out. |
fetch |
The ChatGPT connector fetch. One dataset by slug, as Markdown, with its metadata. |
search_datasets |
Full-text search over the public catalogue, with cursor pagination. |
get_dataset |
One dataset: summary, publisher, licence, tables, column schemas, canonical URL. |
list_tables |
The tables and their ids. The cheap call. |
get_table_schema |
Columns, types, published profiles, and the capabilities the publisher turned on. |
sample_rows |
The publisher’s materialized preview, up to 100 real rows. A sample, not a query. |
get_download_instructions |
The URL, method and header for the full Parquet snapshot. |
get_access_instructions |
What needs an account, the key classes, and the numbered steps to get one. |
A dataset://{slug} resource returns one dataset as Markdown, and a mostlyright://access resource explains access. The prompts are explore_dataset, find_dataset and build_dataset.
What needs a workspace
Section titled “What needs a workspace”| Tool | What it does |
|---|---|
query_table |
A bounded structured query: columns, filters, order, group_by, aggregates, up to 10,000 rows a page, with offset to the end of the table. Filters cover equality, ranges (between) and text (contains, starts_with, ends_with). No SQL. |
catalog_search |
Searches a fixed snapshot of public data sources for feeds that might answer a question. It swept one provider, Data.gov, and only partially, so a hit is a lead and a miss proves nothing. Every ranked candidate comes back with its disposition, and the tool scores none of them. Each includes the catalogue’s own facts: bounding boxes or null, and a record URL only where the entry names one. About one in four do not, and the tool invents nothing. format is one lowercase token sent once, because the catalogue takes a single format filter per question and has no OR. An entry that does not declare the required format comes back refused with filters_match: false rather than held back. The tool checks question, limit and format before it calls, so it rejects a malformed argument itself. One that reached the catalogue another way can surface as its 422 rather than as CATALOG_SEARCH_INVALID. |
list_connected_datasets |
The datasets this workspace has connected, which is what query_table can read. |
connect_dataset |
Connects a public dataset to the workspace. Needs the Owner, Admin or Editor role and an OAuth connection. |
OAuth is one of two routes, and it pastes no key anywhere. A client that speaks OAuth 2.1 finds the authorization server in the WWW-Authenticate header on the first refusal, registers itself, and opens a browser. You sign in there and pick one workspace. The client holds workspace-scoped credentials rather than an API key, and the server rechecks membership on every request. Settings → Access manages and revokes them.
A workspace key is the other route. Sign in, create an mr_use_… key under Settings → Access, and send it as Authorization: Bearer mr_use_…. The first query_table over a dataset connects it to the workspace. Scripted MCP clients with no browser take this route.
An mr_use_ key only reads: query_table over any public dataset and over the workspace’s own tables, plus list_connected_datasets. It never needs connect_dataset, because its first query over a public dataset connects it. An OAuth connection carries only the scopes the person approved. datasets:read reads datasets the workspace has already used. datasets:use lets it use new public datasets, on first query or through connect_dataset. datasets:build also reads the workspace’s own tables.
An mr_live_… key is a different credential. It authenticates the Hosted Table API for tables your own workspace publishes, and the MCP server says so rather than refusing silently.
Build datasets
Section titled “Build datasets”A paid workspace builds datasets through the same server, at $49 a month per workspace. It needs three things: an OAuth connection that approved the datasets:build scope, the Owner, Admin or Editor role in that workspace, and an active subscription. An mr_use_ key cannot build. Every build tool refuses it by name and points at the OAuth route. A workspace with no subscription gets subscription_required and the billing URL.
| Tools | What they do |
|---|---|
create_dataset, update_dataset, list_my_datasets, get_my_dataset |
The dataset page: create one, rename it, write its description, read its tables and their state. |
register_recipe |
Send one recipe document. Returns with recipe_id, recipe_digest, dataset_id, table_id and source_ids. |
start_run, confirm_run, cancel_run |
Start a run in sample, full, refresh or backfill mode with row and byte ceilings, settle a run held for a confirmation, or stop one. A backfill covers one exact window and rejects without a window of {start, end}. |
get_run, run_events, list_runs |
Read a run’s record, page its events until it is terminal, and find runs you did not start. |
query_run |
One bounded read-only SQL statement over a finished run’s own table, where the relation is named run_table. |
run_artifacts, get_artifact_download |
What the run wrote, and a signed URL for one artifact. Bytes never stream through MCP. |
write_note |
One cell of the decision record, on the dataset or on the run. |
promote_table, get_table |
Publish a table, and read what one is serving. |
list_source_credentials |
The names of the secrets the workspace holds. Never a value. |
The loop runs in this order:
- Read the build guide and the recipe reference.
- Propose sources.
- Write a recipe with a description on every column and units on every numeric column.
register_recipe.start_runin full mode within the user’s authorization.run_eventsuntil the run is terminal.query_runto check the rows.write_notefor each decision.- Repair the recipe and register it again only when failure evidence identifies a recipe defect.
Full builds use progressive acquisition automatically. A long build exposes an inspection checkpoint after about five minutes and continues in the same run without a second approval or acquisition. Any required spend confirmation happens before acquisition. Use sample only for a deliberately bounded experiment; a row ceiling does not limit acquisition time. The first successful run makes the table live automatically; promote_table records an authorized refresh cadence.
A person pastes credentials, never an agent. A source that needs an API key takes its value from Settings → Secrets in the dashboard. The Source credentials panel on the dataset’s page does the same. Either one stores the value under a name, and the recipe names that name. No secret passes through MCP or through a chat message.
Four resources carry the rest:
mostlyright://build-guidewalks the whole loop with the tool names, and also ships as an agent skill at /.well-known/agent-skills/mostlyright-build/SKILL.md.mostlyright://recipe-referencelists every member of the recipe document, every bound, every refusal.mostlyright://recipe-connectionscovers using a saved workspace connection instead of a named secret.mostlyright://recipes/examplesholds six recipe documents that ran, each readable atmostlyright://recipes/examples/{name}.
The build_dataset prompt walks the same loop for a question you give it.
When a tool refuses
Section titled “When a tool refuses”Every refusal names what to do next. An anonymous caller reaching query_table gets a 401. Its body carries the signup URL, the header format and the numbered steps, the same content get_access_instructions returns. A client that speaks OAuth turns that 401 into a sign-in prompt. One that does not shows the instructions to the model.
Bulk data
Section titled “Bulk data”Bytes never stream through MCP. get_download_instructions returns the one request that fetches a complete Parquet snapshot, and you make that request yourself. Applications, scripts and notebooks use the Public Dataset API directly.
Discovery
Section titled “Discovery”/.well-known/oauth-protected-resource/api/mcpcarries the ratified protected-resource metadata./.well-known/mcp.jsonis a server card for registries and directory crawlers, listing the anonymous, authenticated and build tools./.well-known/agent-skills/index.jsonlists the agent skills this deployment publishes./llms.txtand/llms-full.txtcarry the catalogue as plain text./datasets/{slug}/llms.txtcarries one dataset as Markdown.