I gave my CMS an MCP server (and deleted half my portfolio in one message)

Apr 2026 4 min read

payloadmcpnextjs

I deleted six projects and four blog posts from this site today by typing two sentences into Claude Code. No SQL, no admin clicks, no panic. The CMS understood me because I gave it an MCP server.

That is the part of this build I want to talk about first. The rest of the stack is normal.

The stack, briefly

Next.js 16 with the App Router. Payload 3 as the CMS, sitting in the same Next.js app. MongoDB for storage, Vercel Blob for media. Tailwind 4 for styling. Motion for the few animations I actually wanted. Bun as the package manager because I got tired of waiting for pnpm.

That is it. No tRPC, no GraphQL layer of my own, no state library. Payload gives me REST, Next gives me server components, and that turned out to be plenty.

The MCP server

The site exposes an MCP endpoint behind a bearer token. Every collection in Payload gets a set of tools: list, create, update, delete. From any authenticated MCP client, I can talk to my own CMS in plain language.

It sounds like a gimmick until you use it. Earlier today I asked Claude to "delete every work item except StoryXen" and it called the list tool, showed me the six it would delete, asked once, and ran the deletes in parallel. Total time: under a minute. Equivalent in the admin UI: ten minutes of clicking and second-guessing.

The implementation is small. mcp-handler wraps the protocol. Each tool is a thin function that calls Payload's local API. The auth wrapper does a timing-safe bearer check and rate-limits per IP, so a leaked path is not enough to brute-force the token. The tool descriptions matter more than the code. A vague description means the model picks the wrong tool, or asks for fields that do not exist. I have rewritten most of mine twice.

Why Payload, not Sanity

I tried Sanity first. It is good. The studio is polished and the developer experience is fine. But I kept bouncing between two repos for what is essentially one website, and the content shape lived in a place I could not grep.

Payload runs as routes inside the Next app. The collections are TypeScript files in src/collections. When I rename a field, the types regenerate and the rest of the codebase yells at me until I fix it. That feedback loop is the whole reason I switched.

The downside: hosting is now my problem. Payload needs a long-running Node process for the admin UI, and that does not fit cleanly into Vercel's serverless model for the heaviest routes. I am running it anyway and watching the timings.

Analytics, hand-rolled

I added Vercel Analytics for the basic counts, but I also wrote my own pageview pipeline. A Pageviews collection in Payload, a tracking endpoint that filters bots with isbot and rate-limits per IP hash, and an admin view that draws charts with Recharts.

Why bother? Two reasons. First, I wanted country and device breakdowns without sending visitor data to a third party I do not fully trust. Second, I wanted the data inside the same admin I already log into. Now when I check the site, the dashboard shows views, top pages, and referrers next to the content I am editing.

The IP hashing uses a salt I keep in an env var. No raw IPs touch the database. That was the only part where I read the GDPR docs more than once.

Theme switching

Light and dark, with a circular wipe between them using the View Transitions API. No library. The whole thing is about forty lines of CSS and a click handler that calls document.startViewTransition. I wrote it up separately if you want the code.

What I would change

The Payload admin loads slowly on cold starts. I have not decided whether to move it to a separate long-running host or keep paying the cold-start cost for the simpler deploy.

Recharts is heavier than I want for the size of the charts I am drawing. I will probably swap it for something hand-rolled with SVG when I get bored.

The MCP tool descriptions need another pass. I keep finding cases where the model picks the wrong list call because two of them sound too similar.

What I would keep

Payload in the same repo. The MCP server. Owning the analytics. The bun lockfile.

If you are starting one of these, my honest advice: pick the CMS that lets you grep your content shape, write the smallest analytics pipeline you can stand, and put an MCP server on top of whatever admin you build. The third one sounds like overkill until the first time you delete six things in a sentence.