Paperboy — Open-Source Headless CMS

An open-source, headless CMS — editor-first, type-safe, batteries included. A proper headless CMS without the enterprise invoice.

Why I built it

Paperboy started as a question from my day job: what would a CMS look like if it were designed for the agent era, rather than retrofitted for it? Every write path — the admin UI, the REST API and the MCP server — runs through the same validation, permissions and audit trail, so an AI agent is a first-class editor instead of an integration afterthought.

The hardest parts were learned from real failures. Every tolerant coercion and every self-teaching error message in the codebase traces back to an actual agent run that broke: the write chokepoint either fixes a mistake unambiguously, or rejects it with an error precise enough that the agent corrects itself in one step. Never a silent success.

It runs in production today — this site is powered by it, and the blog is drafted into Paperboy over MCP by an automated pipeline, then reviewed by a human before publish.

View the source on GitHub · Related: Optimizely CMS MCP Server

7uw5qYumJ5gEwUTulYWce0q8.jpg

Highlights

  • Data-driven content types — pages, blocks, and globals defined as data, not code

  • Content areas with inline + shared blocks and per-field allowed types

  • No-leak Delivery API — one read chokepoint with a perspective; public keys see only published content, private fields never serialize, preview keys see drafts

  • Image transforms — ?w=800&format=webp&q=75 on any media URL; variants generated once with sharp and cached on disk

  • Visual on-page editing — click an element in the live preview to focus its field in the editor

  • Multi-language (document-level i18n + fallback chain), hierarchical URLs from the page tree, version history + restore, trash/restore, duplicate

  • Secure by default — Argon2id + opaque server-side sessions + CSRF, passwordless TOTP 2FA, deny-by-default RBAC with object-level scope checks, append-only audit log

  • Typed client SDK — @paperboycms/client: createClient({ baseUrl, key }), then typed getBySlug/list/search

  • Agent provenance & review — every version records whether a human or an agent wrote it, agent drafts carry a one-click-approve review flag

  • Integrations — HMAC publish webhooks, media uploads, SEO/OpenGraph metadata, optional AI editorial assistant, and a full MCP server

MCP

Mint a token in the admin (Settings → MCP), then:

MCP_TOKEN=mcp_… DATABASE_URL=postgresql://… pnpm --filter @paperboy/mcp start   # stdio (local clients)

Or serve it over Streamable HTTP for remote clients:

MCP_TOKEN=mcp_… docker compose --profile mcp up -d --no-deps mcp                 # → http://<host>:8093/mcp