ledric
OfficialClick on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@ledricSet up a blog with posts and authors"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
ledric
A CMS that speaks AI.
A small, self-hosted content engine built from the ground up for the age of agents. It runs from one binary, stores everything in one file, and ships with a proper MCP interface so Claude (or anything else that speaks the Model Context Protocol) can read, write, and evolve your content model — with the same validation, history, and safety rails you'd get from a clicky admin panel.
The pitch
You've got content. You've got AI tools. In a sane world they'd just talk to each other. In the current world, your CMS wraps every entry in six layers of metadata, your rich text is a proprietary JSON tree only one SDK can render, and every time Claude tries to help it burns half its context just parsing the response.
ledric sits in the middle and gets out of the way.
Concretely: ledric is a Node 22+ process you run in a content directory. It exposes an MCP server over stdio for desktop clients (Claude Desktop, Cursor, Claude Code), an HTTP API that includes the same tool surface at POST /rpc, and an admin SPA at /admin. Content lives in a single ledric.db file (SQLite by default; Postgres and MySQL also supported). Your consumer site is a separate process that fetches over HTTP via @ledric/sdk (TypeScript) or ledric/sdk (Composer/PHP).
Contents
Two minutes to running
Needs Node 22+. That's it.
# Interactive: walks you through DB path, port, MCP client wiring, key minting.
npx -y ledric init
# Or skip the prompts — same flow, all defaults:
npx -y ledric init --yesinit writes a ledric.config.json, patches your project's .mcp.json so Claude Code picks up the server automatically, mints admin + reader API keys, drops them into .env.local, and adds the usual entries to .gitignore. After that:
npx ledric serve # MCP stdio only — perfect for Claude Desktop
npx ledric serve --gui # also: HTTP API + admin GUI at http://127.0.0.1:3000/adminA ./ledric.db file just appeared next to you. The admin GUI is at http://127.0.0.1:3000/admin — paste the admin key from .env.local to get in. Same key works for the inline editor on any consumer site that loads /admin/inline.js.
Wire it into your MCP client
Client | How |
Claude Code |
|
Claude Desktop | Run |
Cursor | Cursor reads the same |
Manual Claude Desktop config:
{
"mcpServers": {
"ledric": {
"command": "npx",
"args": ["-y", "ledric", "serve", "--gui"],
"cwd": "/absolute/path/to/your/content/dir"
}
}
}cwd matters — ledric.db lives in the working directory.
Restart your MCP client. In Claude, ask: "Call describe_model, then set up a blog with posts and authors." Watch it call create_type twice, then ask it to draft and publish a post. That's the entire onboarding path — there is no separate admin tutorial to read.
See your content from the outside
npx ledric ls # what types do I have?
npx ledric ls blog_post # what posts?
npx ledric get blog_post/hello-world # one post, in the shape a website would render
npx ledric asset upload hero.jpg # store an imageWhat you get
For agents
A first-class surface so an LLM can do real work without burning context.
describe_modelreturns the entire content model — every type's fields, summary fields, hand-written example, plus the runtime capabilities of this instance — in one call. No separate docs to keep in sync.Structured errors. Validation failures come back as machine-parseable objects with field paths and codes, not prose strings the model has to re-parse.
Token-cheap responses. Lists come in three budgets (full, summary, list); responses are flat, not wrapped in
sys/fields/metadataenvelopes.Draft → publish primitives.
draft,publish,rename_entry,delete_entry— all withparent_versionoptimistic concurrency so an agent can't silently clobber a concurrent edit.Version history is readable over MCP. Every save writes a new version; pass
version: Ntoreadto fetch any historical version.
For humans
Two places to edit, both built in.
Admin GUI at
/admin— types list, entry forms, asset library, keys management. Paste the admin key once, you're in.Inline editor. Drop one
<script>tag on your rendered site and a floating pencil appears next to anything you tag withdata-ledric-ref. Click → drawer slides in with the right form → save → page reloads with the new content.Schema by chat. "I want a blog with posts, authors, and tags" — Claude writes the canonical types and calls
create_type. Coders who still code getdefineType()from@ledric/schemafor the autocomplete vibes — same canonical output, same row in the DB.Drafts don't leak. Publishing is a pointer move — instant. Unpublishing is the same move in reverse.
For ops
Boring on purpose.
One file by default. Your content lives in a SQLite file you can commit, scp, or
cplike any other file. Postgres and MySQL are first-class options when you outgrow that.Slug-history redirects. Rename a post and the old URL keeps resolving forever. Every retired slug is remembered; reads of the old slug return the entry with
_redirectpointing at the new one.Imgix-compatible image transforms, no SaaS bill. Asset URLs accept the usual
w,h,fit(clip/crop),q,fm(jpg/png/webp/avif),auto=format,dpr—sharp(libvips) does the work, transformed bytes are cached on disk. URLs are version-pinned, so browser and CDN caches stay correct even when you replace the source image in place. Example:/assets/<ref_key>?w=800&fit=crop&auto=format.Localization. Per-type locales,
localized: truefields, fallback chains, locale-specific slugs — all under the same versioning, publish, and history flow as the original.Auth without ceremony.
ledric initmints an admin key and a reader key on the way through; if you skip init, the first HTTP boot does it instead. By default writes need the admin key; reads stay open. Flip--require-reader-keyfor closed-reads mode. Rotate withledric keys create --role admin --raw | pbcopyand revoke the old one.Asset bytes go in the DB or on disk — your call. (External-bucket adapters for S3 / R2 are on the roadmap.)
For your codebase
The shapes you'll actually import.
@ledric/sdk(TypeScript) — read client, inline-editorrefAttrs()helpers, types generated from your schema.Ledric\LedricClient(PHP, Composer packageledric/sdk) — read client, same wire format.ledricCLI —init,serve,ls,get,asset upload,keys create, etc.HTTP
POST /rpc— every MCP tool exposed as plain JSON over HTTP for non-MCP callers, with the same auth split (reader vs admin) as the MCP server.Markdown rich text with embedding magic. Rich-text fields are Markdown strings — diff them in git, paste them into Slack, open them in any editor. Embed a section, asset, or another entry inline with
:::ref{to="section/hero"}:::and ledric resolves it on read.
The 20 MCP tools
Reads | Writes | Schema | Assets | Tags |
|
|
|
|
|
Asset uploads and bytes-fetching are HTTP-only by design — POST /assets (multipart) and GET /assets/<ref_key> — they don't go through MCP.
Full reference: docs/mcp-tools.md.
How I actually use it
This is a personal project first. After 25 years of building bespoke content management systems for clients (pre-headless CMS days) and working with the major players since, and being annoyed by most of them, ledric is my attempt at the one I'd actually want to use.
Most pages I build aren't just "title, body, hero image." They're collections of sections — a hero with desktop and mobile backgrounds, a pricing table that gets reused on three pages, a testimonials block, a CTA, a feature grid — sometimes with prose flowing around them, sometimes entirely composed of them.
The shape of the work I kept doing on every project:
Design and copy land in Figma.
I shuttle assets and content to the CMS, structure it as best as the CMS lets me.
I build a rendering / template engine on top of the headless CMS that turns those content rows back into pages — section ordering, asset variants per breakpoint, linked blocks, fallbacks for missing fields, the cache layer, the lot.
The rendering engine becomes the actual CMS, with its own template-module system. The "real" CMS is just a poorly-shaped ORM underneath. Non-technical maintainers can't touch any of it.
I've built that pile too many times. ledric is what the data layer wants to look like before the rendering engine grows tentacles: sections are first-class entries you can compose into a page (top-level via references, inline via :::ref{to="section/hero"}::: in any markdown field), assets are version-pinned with imgix-style transforms baked in, and the inline editor lets a non-technical maintainer change what they see without owning the rendering pipeline.
A typical session against the MCP server now looks like:
"Go through this page design in Figma and prepare all required asset exports."
"Import all assets into ledric, tagging them appropriately."
"Build out the required sections, and roll them into a page."
Without ledric in the loop, Claude could write static HTML and call it a day. ledric exists because I want my marketing team to roll out updates without me — and I want them to be able to wire up their own LLM tools to the same content store.
The design philosophy
Three constraints we don't break:
Tokens are the new bandwidth. Every default is tuned for minimal agent-side overhead.
Agents edit differently than humans. They batch, they diff, they need dry-runs and structured errors. The API is shaped for both.
The schema is the API.
describe_modeltells an LLM everything it needs in one call. No separate docs to keep in sync.
Everything else in this project is a consequence of those three.
Docs
Pages are short, scoped, and self-contained — pick the one that matches what you're trying to do.
The mental model in one page: types, entries, ids vs slugs vs refs, versions, structural vs inline references, assets, locales, environments, the wire format. Read this first. | |
End-to-end walkthrough: ask Claude to set up the schema, seed content, build an Astro site that renders it, wire up inline editing. Anchored to the committed | |
Same walkthrough, vanilla PHP consumer using | |
Field types catalogue, | |
Example prompts you can paste into Claude: project setup, drafting, schema evolution, bulk ops, refactoring, localization. | |
The full 20-tool surface — args, returns, examples. Same surface as | |
REST routes for reads, multipart upload, generic | |
Two modes: local ( | |
| |
| |
The id / ref_key split, db vs local backends, uploads, image transforms, in-place bytes replacement, the transforms cache. | |
Per-type locales, | |
Roles, key minting via | |
What's running when ledric boots: the packages, the storage adapters, the asset pipeline, the inline editor, process lifecycle. | |
Production shape: CDN in front of | |
Honest comparison vs Contentful, Sanity, Payload, Strapi, Directus — and when ledric is the wrong choice. | |
The questions that come up most: production-readiness, SQLite limits, hosting, the agent angle, migration. | |
What's stable, in progress, planned, and explicitly out of scope. |
From source
git clone https://github.com/getledric/ledric
cd ledric
corepack enable # one time, ever — wires up pnpm
pnpm install
pnpm build
pnpm cli serve --gui # same as `npx ledric serve --gui`, but against your dev treepnpm dev watches and rebuilds. pnpm test runs the unit suite (vitest, ~360 tests sqlite-only; an extra ~18 Postgres + ~18 MySQL tests opt-in via LEDRIC_TEST_POSTGRES_URL / LEDRIC_TEST_MYSQL_URL env vars). pnpm e2e runs the Playwright smoke suite against a freshly-booted CLI (admin GUI flows — needs pnpm exec playwright install chromium once); use pnpm e2e:ui for the interactive runner.
Status
Alpha. The core works end-to-end, shapes will shift before v1. AI did most of the typing and it's in no way production-tested yet. If you try it and something breaks, open an issue — I'll see it.
A few things to be upfront about:
It's probably confusing in places.
It definitely has gaps.
Does AI make headless CMSes redundant? Maybe. I'm shipping this anyway.
It was clearly coded quickly using AI. That's exactly what has happened here. It's in no way production-tested.
If you want a battle-tested CMS, this isn't it yet. If you like the shape of the bet — that the schema is the API, that agents deserve a real interface, that one SQLite file is enough — give it a try and tell me what's wrong with it.
What's planned
External asset backends — S3 / R2 / generic-bucket adapters for asset bytes. The backend interface is in place; the implementations aren't.
Vector / embeddings. The
vectorfield type is wired through the schema and validator, but there is no similarity-search query path yet. Don't rely on it.Multi-environment branching. The storage schema reserves environment columns (
env_id,parent_env); the API to fork, edit, and merge environments isn't exposed yet.
License
Apache License 2.0 — see LICENSE.
"ledric" is a trademark of James Turle; the Apache License grants you the code, not the name. See NOTICE for details.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/getledric/ledric'
If you have feedback or need assistance with the MCP directory API, please join our Discord server