An MCP Server in the Database: Why I Skipped the API Layer Entirely

Pillar: Agent-Direct Architecture

I started out building this the normal way: a database, and a REST API in front of it, and an MCP server that called that API on behalf of whatever LLM was doing the writing. Three layers, each one talking to the layer below it.

Partway through, I noticed the middle layer wasn't doing anything the outer two couldn't do without it. The API existed to enforce a contract — valid fields, safe values, who's allowed to write what. But an MCP server already sits in exactly that position. It's already the thing every write passes through. Adding a REST API between the agent and the data wasn't adding safety. It was adding a network hop.

What's actually left without it

Carapace has no runtime API layer at all. Git is the database. The MCP server is the only writer, and it enforces the same rules an API layer would have — a small, explicit set of safe HTML, validated the moment it's written and again every time it's rendered — directly, without a service in between to keep running, patch, and pay for.

"No API layer" doesn't mean the content is locked away. It cuts one way, not both. There's no query service — nothing you point traffic at — but every entry is still structured, readable data: one directory per entry, a JSON file for its fields, an HTML file for its body. Anything with repository access can read it directly. What's missing isn't access to the data. It's a process that has to stay up just to hand that data back to you.

A visitor's request never touches any of this. The MCP server only ever sits in the write path — publishing produces a static build, and the build is what actually serves traffic.

The part that surprised me

I expected dropping the API layer to feel like giving something up. It didn't. Every constraint an API would enforce — schema validation, safe values, access control — was already something the MCP server had to do anyway, because it's the only thing writing. Building the API layer would have meant writing that logic twice and keeping two systems agreeing with each other. Skipping it meant writing it once, in the one place it actually needed to live.

The result is a CMS with no CMS server. Not a smaller one — none. If you want the full shape of it, including how content gets from an agent's tool call to a live page with nothing running in between, the architecture docs walk through the whole path.