Writing was never our bottleneck. Publishing was.
Every article on this blog exists three times, in English, German and Serbian. Getting one of them live used to take between one and two hours, and almost none of that was writing. It was pasting a body into an editor, then the excerpt, then the meta title, the meta description, the keyword list, the slug, the FAQ items, and then doing it twice more in two other languages. It now takes about five minutes. The Strapi MCP server removed the mechanical half. A Claude skill removed the editorial half, and that part was harder.
If you run a content site on a headless CMS and you have quietly stopped publishing to it, this is a write up of what it actually took to fix that. Including the part where the fast version produced three articles that turned out to be one article wearing two costumes.
What the problem actually was
Our blog runs on Strapi v5. One article is one document with three locales hanging off it, which is the right model and not the problem.
The problem was that the article lives in one shape in my head and a completely different shape in the database. I think in Markdown. Strapi stores the body as a Blocks array, which is a JSON tree of nodes. Those two things are not interchangeable, so somewhere between the draft and the database a human has to do a format conversion by hand, in a browser, at three in the afternoon, for the third time that day.
Then there is the metadata. Per locale, an article carries about a dozen fields: slug, excerpt, reading time, meta title, meta description, keywords, an Open Graph block, structured data, a set of FAQ items, a category, tags, an author. None of them are hard. All of them are boring. Multiply by three languages and you have an hour of clerical work standing between a finished draft and a published post.
Here is the honest consequence, and it is the reason any of this mattered. We did not publish less because we had nothing to say. We published less because the last hour was miserable, and a task that is miserable gets postponed until it is stale. The overhead was not a cost on publishing. It was a filter on what got published at all.
The three ways in
There are three ways to get content into Strapi without a person typing it, and they are not equally good.
Keep using the admin panel. Zero setup, zero risk, and you pay the hour forever. This is the option most teams are actually on, usually without having decided to be.
Write a script against the REST API. It works. You will spend a day on it and then you own it. Every time the content type changes, and it will, the script breaks in a way you find out about three weeks later when a field silently stops being populated. It also does nothing at all for the part of the job that involves judgment, so you have automated the typing and kept the thinking, which was never the expensive bit anyway.
Connect an agent through the MCP server. Strapi ships one from version 5.47. You enable it with mcp: { enabled: true } in config/server.js, restart, and the endpoint appears at /mcp. Authentication is an Admin token, and this is the part worth understanding properly: the token's permissions decide which tools the agent can even see. If the token has no delete on articles, there is no delete tool in the agent's world. Not a blocked one. An absent one.
There is a fourth option, which is pointing something at the database directly. Don't. You lose validation, lifecycle hooks, and the draft system, and you gain nothing you couldn't get from the endpoint.
We went with the MCP server. But the MCP server on its own would have bought us maybe a third of that hour back, and I want to be exact about why.
What the MCP server does and does not solve
An MCP server is not an integration. It is an API with a friendlier front door. It makes the CMS reachable in the same conversation where the writing happens, which is genuinely a big deal, because the format conversion stops being a task and becomes a side effect. Nobody converts Markdown to Blocks anymore. It just arrives as Blocks.
What it does not do is know what a good article looks like on our blog. It does not know that every post needs one real concession, or that the German version has to be composed rather than translated, or that the meta description is between 50 and 160 characters and should not read like a slogan. Wire an agent straight to a CMS with no editorial rules and you have built a very fast way to publish mediocre content. The speed is real and so is the mediocrity.
That is what the skill is for. A Claude skill is a folder with a SKILL.md file in it, plus reference files and scripts, and the agent loads the whole thing only when the task matches. Ours holds the five article formats we write in, the voice rules, the banned phrases, the field constraints, the exact sequence of MCP calls, and the rules for the German and Serbian versions. It is roughly a small style guide that happens to be executable.
So the honest split is this. The MCP server made publishing mechanical. The skill made it repeatable at a standard I am willing to sign my name to. If you only do one of the two, do the second one.
Every post we have published since has gone out this way, in all three languages, and none of them went through the admin panel by hand.
What it cost, and what broke anyway
The MCP setup was an afternoon. The skill has taken weeks and is still not finished. That ratio surprised me and it should probably have been obvious.
Four things bit us, and three of them are worth writing down.
Relations attach silently or not at all. The documentation says a to-one relation accepts either a bare document ID string or an object with a documentId key. In practice, passing the object form validated fine, returned a success, and attached nothing. The article existed, looked correct in the response, and had no author, no category and no tags on the live site. Worse, the create and update responses report relations as null even when they did attach, so the response cannot be trusted either way. The only reliable check is a get call after the write. That cost me a debugging session on 25 July, most of it spent suspecting the frontend, which was innocent.
Update refuses to be partial. Changing only a relation still requires title and slug in the payload. Harmless once you know. Confusing for an hour if you don't.
Media cannot be uploaded through MCP. This one is documented, and it is a real constraint rather than a bug: media fields will reference an asset that already exists, but the server will not upload a new file. So cover images stay manual. I generate the card, upload it in the media library, hand the asset ID back, and the agent references it. About ninety seconds of the five minutes is that.
And the one that actually mattered. On the QA article we published on 25 July, all three language versions came out at exactly 47 blocks, with one to one paragraph correspondence between English, German and Serbian. That is not what independent composition looks like. That is a translation that had been polished until it read native. The German was correct. It was also, structurally, the English article with German words in it, and a German reader feels that even when they cannot name it.
Nothing in the tooling failed there. The pipeline did exactly what it was told, quickly, and the speed is precisely what hid the problem. When publishing took ninety minutes I would have noticed. At five minutes I shipped it.
That is the real lesson from all of this, and it is not a flattering one. Removing friction removes the pause where you would have caught something. If you automate a workflow, you have to put a check back in on purpose, because the one you used to get for free is gone.
What we would do differently
Build the check before you build the second article, not after. We now have a script that compares the three versions on figure parity, on names that appear in one language and not another, and on paragraph structure, and it will tell you plainly that your German is a translation. Twenty lines of Python would have caught the 47 block problem on the day.
Scope the admin token down from the start. Ours was broader than it needed to be, out of impatience. Since tool visibility follows token permissions, a narrow token is not just a safety measure, it is a smaller and clearer surface for the agent to reason about.
And do not give the agent publish rights. Everything lands as a draft, a human reads it, a human presses publish. I have heard the argument that this is the last piece of theatre in an otherwise automated pipeline. I disagree, and after the 47 block article I disagree more strongly. The final read is not a formality, it is the only place the process has judgment in it.
If your Strapi blog is the slow part
We build blog and content frontends on top of Strapi. That is the actual work: the React or Next.js front end, a Blocks renderer that handles your real content instead of the happy path, localized routing that does not break your URLs, and the SEO and Open Graph fields wired to tags that Google and the AI answer engines can read. Then, if you want it, the publishing pipeline behind it, so your team stops living in the admin panel.
If your CMS is fine but publishing to it is the part everyone avoids, that is a fixable problem and usually a smaller one than it looks. Write to us at [email protected] and tell us what your current hour looks like.
