Connect an AI tool
Mostly Right runs a Model Context Protocol server at https://mostlyright.md/api/mcp. It speaks Streamable HTTP, negotiates protocol revisions 2025-11-25, 2025-06-18, 2025-03-26 and 2024-11-05, and is stateless — no session id is issued, so every request stands alone.
Searching the catalogue, reading schemas and pulling sample rows need no account. Add the server, ask a question, and your agent can start answering immediately. Signing in is what unlocks querying whole tables (10,000 rows a page) and downloading a full Parquet snapshot. A paid workspace unlocks building: writing a recipe, running it, and publishing the table it produces.
Add the server
Section titled “Add the server”Claude Code
claude mcp add --transport http mostlyright https://mostlyright.md/api/mcpClaude Desktop — Settings → Connectors → Add custom connector, and paste https://mostlyright.md/api/mcp.
Cursor — ~/.cursor/mcp.json:
{ "mcpServers": { "mostlyright": { "url": "https://mostlyright.md/api/mcp" } }}VS Code — .vscode/mcp.json:
{ "servers": { "mostlyright": { "type": "http", "url": "https://mostlyright.md/api/mcp" } }}ChatGPT — Settings → Connectors → Add custom connector, and paste the same URL. ChatGPT’s connector contract requires two tools with exact names and shapes, and this server implements both: search, which takes a query and returns {results: [{id, title, url}]} with the dataset slug as the id, and fetch, which 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"}.
Anything else — the handshake 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 |
Just the tables and their ids — the cheap call. |
get_table_schema |
Columns, types, published profiles, and which capabilities the publisher enabled. |
sample_rows |
The publisher’s materialized preview, up to 100 real rows. A sample, not a query. |
get_download_instructions |
The exact 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. |
There is also a dataset://{slug} resource that returns one dataset as Markdown, a mostlyright://access resource explaining access, and three prompts — 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, aggregates, up to 10,000 rows a page and offset to the end of the table. No SQL. |
catalog_search |
Searches a sealed snapshot of public data sources for feeds that might answer a question. One provider — Data.gov — partially swept, so a hit is a lead to read and a miss proves nothing. Every ranked candidate comes back with its disposition, and nothing is scored. Each carries the catalogue’s own facts: a list of bounding boxes or null, and a record URL only where the entry is identified by one — about one in four are not, and none is invented. format is one lowercase token, sent once — the catalogue admits a single format filter per question and has no OR. It withholds nothing: it states the format the question requires, and an entry that does not declare it comes back refused, with filters_match: false, rather than being held back. The tool checks question, limit and format itself before calling, so a malformed argument is refused here; 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 — exactly what query_table can read. |
connect_dataset |
Connects a public dataset to the workspace. Owner, Admin or Editor, and an OAuth connection — see below. |
Two ways to authenticate:
OAuth, no key pasted anywhere. Clients that speak OAuth 2.1 discover the authorization server from the WWW-Authenticate header the first refusal carries, register themselves, and open a browser where you sign in and pick one workspace. The client holds workspace-scoped credentials, never an API key, and membership is rechecked on every request. Manage or revoke these under Settings → Access.
A workspace key. Sign in and create an mr_use_… key under Settings → Access. Send it as Authorization: Bearer mr_use_…. The first query_table over a dataset connects it to your workspace. This is the route for scripted MCP clients that have no browser.
An mr_use_ key is read-only: it unlocks query_table over any public dataset and the workspace’s own tables, and list_connected_datasets. It never needs connect_dataset; its first query over a public dataset connects it. An OAuth connection is bounded by the scopes the person approved: datasets:read reads the datasets the workspace has already used, datasets:use lets the connection use new public datasets (on first query, or explicitly with connect_dataset), and 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. The MCP server says so rather than refusing silently.
Build datasets
Section titled “Build datasets”A paid workspace can use the same server to build a dataset rather than only read one. It costs $29 a month per workspace, and it needs three things at once: 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 — it is read-only, and every build tool refuses it by name and points at the OAuth route. A workspace with no subscription is refused with subscription_required and the billing URL.
The tools are grouped by what they act on rather than by the word “build”:
| Tools | What they do |
|---|---|
create_dataset, update_dataset, list_my_datasets, get_my_dataset |
The dataset page: mint one, rename it, write its description, read its tables and their state. |
register_recipe |
Send one recipe document. Answers 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 spend confirmation; stop one. A backfill covers one exact window and is refused 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 sealed, 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 is: read the guide and the reference, propose sources, write a recipe with a description on every column and units on every numeric column, register_recipe, start_run in sample mode with ceilings, run_events until it is terminal, query_run to check the rows, write_note for each decision, then fix and register again. A full run happens only when the user asks for one, and promote_table only when they approve that exact table.
Credentials are pasted by a person, not by an agent. A source that needs an API key gets its value from Settings → Secrets in the dashboard, or from the Source credentials panel on the dataset’s own page, where it is stored under a name. The recipe references that name. No secret passes through MCP or through a chat message.
Four resources carry the rest:
mostlyright://build-guide— the whole loop with the exact tool names. Also published as an agent skill at /.well-known/agent-skills/mostlyright-build/SKILL.md.mostlyright://recipe-reference— every member of the recipe document, every bound, every refusal.mostlyright://recipe-connections— using a saved workspace connection instead of a named secret.mostlyright://recipes/examples— 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 carries what to do next. An anonymous caller reaching query_table gets a 401 whose body includes the signup URL, the header format and the numbered steps — the same content get_access_instructions returns. Clients that support OAuth turn that 401 into a sign-in prompt; clients that do not show 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, which you make yourself. For applications, scripts and notebooks, use the Public Dataset API directly.
Discovery
Section titled “Discovery”/.well-known/oauth-protected-resource/api/mcp— the ratified protected-resource metadata./.well-known/mcp.json— a server card for registries and directory crawlers, listing the anonymous, authenticated and build tools./.well-known/agent-skills/index.json— the agent skills this deployment publishes./llms.txtand/llms-full.txt— the catalogue as plain text./datasets/{slug}/llms.txt— one dataset as Markdown.