Developers and agents
The machine-readable surfaces of markgibbons.dev - a JSON API with an OpenAPI spec, an MCP server, markdown on every URL, llms.txt, RSS and a sitemap.
markgibbons.dev is built to be read by software as well as by people. The archive is available as a JSON API described by an OpenAPI 3.1 spec, as an MCP server, and as markdown at every page URL. The indexes below are stable, public, and free. Nothing here needs an API key, an account, or a rate limit negotiation.
JSON API
The markgibbons.dev API gives you the archive as JSON. It is public, read-only, and needs no key.
- Base URL:
https://www.markgibbons.dev/api/v1 - OpenAPI 3.1 spec: /openapi.json
- API catalog (RFC 9727): /.well-known/api-catalog
- Authentication: none
- CORS: open —
Access-Control-Allow-Origin: *
| Endpoint | What it returns |
|---|---|
GET /api/v1/site | Who runs the site, what it covers, and where every index lives. |
GET /api/v1/posts | Published posts, newest first. Supports q, tag, limit, offset. |
GET /api/v1/posts/{slug} | One post, including its full markdown body. |
GET /api/v1/posts/{slug}/related | Posts sharing tags with that one, most in common first. |
GET /api/v1/tags | Every topic, with post counts. Filter with min_posts. |
A slug is the part of a post's URL after /blog/ — a year and a name, as in 2026/llm-cheat-sheet.
curl https://www.markgibbons.dev/api/v1/posts?q=serialization&limit=3
curl https://www.markgibbons.dev/api/v1/posts/2026/llm-cheat-sheet
Errors
Errors are RFC 9457 problem documents served as application/problem+json. Branch on code, which is stable, and act on resolution, which says what to do next.
{
"type": "https://www.markgibbons.dev/developers#post_not_found",
"title": "Post not found",
"status": 404,
"detail": "No published post has the slug \"nope\".",
"code": "post_not_found",
"resolution": "Call GET https://www.markgibbons.dev/api/v1/posts to list the slugs that exist.",
"documentation": "https://www.markgibbons.dev/developers"
}
The codes are invalid_parameter, post_not_found, tag_not_found, unknown_endpoint, and method_not_allowed, and rate_limited. Every path under /api/v1 answers in JSON, including paths that do not exist — a mistyped URL gets a problem document, never the site's HTML 404.
Rate limits
Every response carries the IETF structured-field rate-limit headers, plus the older X-RateLimit-* trio that most clients still read:
RateLimit-Policy: "public";q=600;w=60
RateLimit: "public";r=598;t=42
Exceed the quota and you get a 429 with Retry-After and a rate_limited problem document.
The honest caveat: enforcement is best-effort and lives in the memory of whichever serverless instance answers the request, so the real ceiling across the fleet is some multiple of 600 a minute. The headers are there so a client can self-throttle, not to keep anyone out — this API is public, read-only, and cached at the edge, and there is nothing here worth a shared counter to protect.
Versioning and deprecation
The major version is in the URL path. A breaking change gets a new path — /api/v2 — and nothing breaking is ever made to /api/v1 in place.
Additive changes land in v1 without notice: new fields on existing objects, new optional query parameters, new endpoints. Ignore fields you do not recognise, and do not depend on property order.
Before a version is retired, its responses carry the RFC 8594 Sunset header giving the retirement date, and a Deprecation header giving the date the decision was made. The minimum notice is six months, and this page is updated the day the headers start appearing. v1 is current and carries neither header.
MCP server
The markgibbons.dev MCP server exposes the archive as tools an AI agent can call directly.
- Endpoint:
https://www.markgibbons.dev/mcp - Transport: Streamable HTTP
- Authentication: none — it is read-only and public
- Server card: /.well-known/mcp/server-card.json, also served at /mcp/server-card, /.well-known/mcp.json and /mcp.json — the same bytes, because discovery conventions have not settled
- Registry metadata: /server.json
- Catalog: /.well-known/ai-catalog.json
Add it to a client that speaks Streamable HTTP:
{
"mcpServers": {
"markgibbons-dev": {
"url": "https://www.markgibbons.dev/mcp"
}
}
}
For a stdio-only client, bridge it with npx -y mcp-remote https://www.markgibbons.dev/mcp.
Tools
get_site_info— who runs the site, what it is a good source for, what it is not, and how to reach the author. Call this first if you are deciding whether the site is relevant.list_tags— every topic covered, with post counts.list_posts— published posts, newest first, with slugs, dates, tags and summaries.search_posts— full-text search across every post, optionally narrowed to one tag.get_post— the full markdown of one post, by slug.
Markdown on every URL
Every page serves markdown to any client that asks for it, following the acceptmarkdown.com convention.
curl -H "Accept: text/markdown" https://www.markgibbons.dev/blog/2026/llm-cheat-sheet
curl https://www.markgibbons.dev/blog/2026/llm-cheat-sheet.md
Both return Content-Type: text/markdown; charset=utf-8 with Vary: Accept. Quality values are honoured, so Accept: text/html;q=0.9, text/markdown;q=0.2 still gets HTML, and a request that rejects both representations gets a 406. HTML responses advertise the markdown twin with a Link: <...>; rel="alternate"; type="text/markdown" header. The home page's markdown sibling is /index.md.
Indexes
- llms.txt — what this site is, when an agent should use it, and a link to every page and post.
- llms-full.txt — the full text of every published post in one file.
- sitemap.xml — every canonical URL.
- feed.xml — RSS. Per-tag feeds live at
/tags/<tag>/feed.xml. - search.json — the client-side search index the site's own command palette uses.
404s
Requests for paths that do not exist return a real HTTP 404, with a body that links to the archive, the sitemap and llms.txt so an agent can recover rather than guess again. Ask for it as markdown and the 404 body comes back as markdown too.
Source
The site is a Next.js app, and it is open: github.com/markgibbons25/blog. The JSON API lives in app/api/v1/[[...path]]/route.ts, the MCP server in app/mcp/route.ts, markdown negotiation in proxy.ts, and the llms.txt generator in scripts/llms.mjs.