developers
Mash Prime API
Everything on mashprime.dev is readable by software. A versioned, read-only JSON API, an MCP server for AI agents, and markdown variants of every page. No keys, no sign-up.
Quickstart
List the posts, then read one by slug:
curl https://mashprime.dev/api/v1/posts
curl https://mashprime.dev/api/v1/posts/one-folder-to-autonomy
curl "https://mashprime.dev/api/v1/search?q=memory"
Responses are JSON. Every endpoint, parameter and response
schema is described in the
OpenAPI 3.1 spec, which you can
load straight into an LLM tool-calling layer: every
operation has a unique operationId, a
description and typed schemas.
Authentication
None. The API is public and read-only, so there are no API
keys, tokens or accounts. Send requests from anywhere; CORS
is open (Access-Control-Allow-Origin: *).
Endpoints
Base URL: https://mashprime.dev/api/v1
| Method | Path | operationId | What it does |
|---|---|---|---|
GET | /api/v1 | getApiIndex | API index: version, documentation links, and available endpoints |
GET | /api/v1/site | getSiteInfo | Who Mash Prime is, what the site covers, and where the machine-readable resources live |
GET | /api/v1/posts | listPosts | List published blog posts, newest first |
GET | /api/v1/posts/{slug} | getPost | Read one blog post, including its full markdown text |
GET | /api/v1/search | searchPosts | Search blog posts by keyword across titles, descriptions, and full text |
posts pages with optional limit
(1–100) and offset, and reports
total. search takes a required
q (1–200 characters) and an optional
limit, and ranks posts by BM25 over the
site's passage index (best match first).
posts/{slug} returns the post's
metadata plus its full text in markdown.
The passage index behind search is a static file too:
/search/index.json
holds every post split into heading-level passages (with
the anchor of each section) plus one 384-dimension int8
embedding per post, which powers related posts. The site's
own search box ranks it in your browser; no query is sent
anywhere.
Errors
Every 4xx and 5xx response is an
RFC 9457 application/problem+json object. Branch on the
stable code; show detail to
humans; follow hint to recover.
{
"type": "https://mashprime.dev/developers/#error-post_not_found",
"title": "Post not found",
"status": 404,
"detail": "No published post has the slug 'no-such-post'.",
"instance": "/api/v1/posts/no-such-post",
"code": "post_not_found",
"hint": "Get valid slugs from GET /api/v1/posts.",
"documentation": "https://mashprime.dev/developers/#errors"
} | Status | code | Meaning and fix |
|---|---|---|
400 | invalid_slug | Invalid post slug. Slugs are lowercase letters, digits, and hyphens. Get valid slugs from GET /api/v1/posts. |
400 | missing_query | Missing search query. Pass a keyword in the q parameter, e.g. GET /api/v1/search?q=memory. |
400 | invalid_parameter | Invalid query parameter. limit must be a whole number from 1 to 100; offset must be a whole number of 0 or more. |
400 | query_too_long | Search query too long. Keep q to 200 characters or fewer. |
404 | not_found | Resource not found. See GET /api/v1 for the available endpoints. |
404 | post_not_found | Post not found. Get valid slugs from GET /api/v1/posts. |
404 | unsupported_version | Unsupported API version. Supported versions: v1. Use paths under /api/v1/. |
405 | method_not_allowed | Method not allowed. This API is read-only. Use GET (or HEAD / OPTIONS). |
429 | rate_limited | Rate limit exceeded. Wait for the number of seconds in Retry-After, then retry. Watch the RateLimit header to stay under the limit. |
500 | internal_error | Internal error. Retry with exponential backoff. If it persists, report it via https://mashprime.dev/contact/. |
502 | upstream_unavailable | Content source unavailable. The site's content index could not be read. Retry with exponential backoff. |
Rate limits
60 requests per 60 seconds per client IP. Every response, including errors, tells you where you stand:
RateLimit-Policy: "default";q=60;w=60
RateLimit: "default";r=57;t=42
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 57
X-RateLimit-Reset: 1790467242 RateLimit and RateLimit-Policy
follow the IETF
RateLimit header fields draft:
r is requests remaining, t is
seconds until the window resets. The
X-RateLimit-* headers carry the same numbers,
with X-RateLimit-Reset as Unix epoch seconds.
Over the limit you get a 429 with
code: "rate_limited" and a
Retry-After header in seconds. Throttle when
r gets low rather than waiting for the 429.
Versioning and deprecation
-
The major version is in the path
(
/api/v1/) and echoed in theAPI-Versionresponse header. - Within a version, changes are additive only: new endpoints, new optional fields, new error codes. Ignore fields you don't recognise.
- Breaking changes ship as a new path version. The old version keeps working alongside it.
-
A version being retired first sends
Deprecation(RFC 9745) andLink: rel="successor-version"headers, then aSunset(RFC 8594) date at least 90 days before it stops responding. -
Unknown versions return
404withcode: "unsupported_version".
Currently deprecated: the unversioned
/api/posts.json build index. It still works and
has no sunset date yet; it sends Deprecation
and a successor link to /api/v1/posts.
MCP server
A remote Model Context Protocol server gives Claude, ChatGPT and other agents the site as native tools. Transport: streamable HTTP (stateless). No auth.
- Endpoint:
https://mashprime.dev/mcp - Server card:
/.well-known/mcp.json -
Tools:
site_info,list_posts,read_post,search_posts,related_posts
Claude Code:
claude mcp add --transport http mashprime https://mashprime.dev/mcp Clients that take a JSON config:
{
"mcpServers": {
"mashprime": {
"type": "http",
"url": "https://mashprime.dev/mcp"
}
}
} WebMCP
The pages are tool servers too.
WebMCP is a W3C
Web Machine Learning Community Group draft, started by
Microsoft and Google, that lets a web page hand JavaScript
tools to an AI agent running in the browser. When the browser
exposes document.modelContext, every page here
registers the tools below. Without it, the tool code isn't
even downloaded. The site-wide read tools have the same names
and schemas as the MCP server.
The rest act on the open tab.
| Tool | Registered on | Read-only | What it does |
|---|---|---|---|
site_info | Every page | Yes | Orientation: who Mash Prime is, what the site covers, when to use it, and every page — returned as markdown (the site's llms.txt). |
list_posts | Every page | Yes | List all published blog posts with slug, title, description, and publication date, newest first. |
read_post | Every page | Yes | Read the full markdown text of one blog post by slug (get slugs from list_posts). |
search_posts | Every page | Yes | Search blog posts across titles, descriptions, and full text, ranked best match first. Returns matching posts with the most relevant passage as a snippet. |
related_posts | Every page | Yes | Posts closest in meaning to a given post, by similarity of their text embeddings, most similar first. Use to follow a thread of ideas from one post to the next. |
navigate | Every page | No | Navigate this browser tab to another page on mashprime.dev. Takes a same-origin path such as '/blog/one-folder-to-autonomy/' or '/developers/#mcp'; absolute and cross-origin URLs are rejected. This page's tools are replaced by the new page's tools once it loads. |
set_theme | Every page | No | Switch the site between light and dark colour themes. Same as the header toggle: applies immediately and is remembered for future visits on this device. |
get_current_post | Blog posts | Yes | Describe the blog post open in this tab: slug, title, URL, markdown URL, and its section headings with anchors (use an anchor with scroll_to_section). |
scroll_to_section | Blog posts | No | Scroll the open blog post to a section heading so the reader can see it. Takes an anchor from get_current_post, e.g. '#memory' or 'memory'. |
Read-only tools carry the readOnlyHint
annotation. Results are MCP-style text content
({ content: [{ type: "text", text }] }). Bad
input gets isError: true and a message that says
what to fix. Every argument is checked against its schema.
Tools only fetch this site's public files from the same
origin, and only change local UI state: the page, the scroll
position, the theme.
Try it
-
Chrome 149 or later: turn on
chrome://flags/#enable-webmcp-testing, then list and call the tools with a WebMCP client such as the Model Context Tool Inspector extension. Chrome and Edge also run WebMCP origin trials. This site is not enrolled, so use the flag. -
Other browsers: a polyfill such as MCP-B's
@mcp-b/webmcp-polyfillinstallsdocument.modelContext. This site does not ship a polyfill. The tools only appear when your browser or extension provides WebMCP. -
From DevTools on any page:
await document.modelContext.getTools(), thendocument.modelContext.executeTool(tool, { slug: "one-folder-to-autonomy" }).
When tools are live, the footer shows how many the page registered.
Implemented against
WebMCP,
Draft Community Group Report, 8 October 2026 (spec commit
4999377).
It uses the imperative registerTool() API only:
that revision dropped the declarative form API, and the
spec defines no discovery file.
CLI
mashprime is a zero-dependency Node CLI that
reads the site from a terminal: mashprime posts,
mashprime read <slug>,
mashprime search <query>,
mashprime mcp. It is built on this API and
published on npm as
mashprime
(Node 18+). No install needed:
npx mashprime
npx mashprime read one-folder-to-autonomy
Or install it: npm install -g mashprime. The
in-browser terminal runs the same
commands.
Machine-readable files
| File | What it is |
|---|---|
/openapi.json | OpenAPI 3.1 description of the Mash Prime API |
/.well-known/api-catalog | RFC 9727 API catalog (linkset) |
/.well-known/mcp.json | MCP server card |
/llms.txt | Agent-readable site index |
/rss.xml | RSS feed of posts |
/sitemap-index.xml | Sitemap |
Every HTML page also has a markdown variant: send
Accept: text/markdown. This page's is
/developers/index.md.
Sandbox
The API is read-only, so production is the sandbox: nothing you send can change anything. Try a request (it counts toward your rate limit).