Publishing one article in five languages by hand means five trips through the Content Manager: switch the locale, paste the translated body, fix the slug, save, publish, and do it again. Strapi is an open-source headless CMS, and its MCP server replaces that loop with tool calls an AI client can make against your Content Manager. The MCP locale parameter points each call at a specific language.
Pair it with Strapi's Internationalization (i18n) feature and a scoped Admin token, and a single conversation with Claude Code or Cursor can create the source entry, write each localized version, check coverage, and publish every locale, provided you verify that each localization remains attached to the source document.
This guide walks through that flow on Strapi 5, with the exact prompts the docs use, the config you need in place first, and the constraints that will bite if you don't plan for them.
In brief:
- When i18n is enabled on a Content-Type, every MCP tool accepts an optional
localeparameter; omit it and Strapi uses the default locale. - Admin token permissions can narrow locales per action, so an agent might read
enandfrbut only create inen. - Strapi 5 removed
locale=all, so coverage checks and publishing happen one locale at a time. - The MCP locale parameter and the AI auto-translation feature solve different problems; the second one overwrites manual edits to non-default locales.
Those constraints shape the setup, permissions, and verification steps throughout the workflow.
How Strapi MCP Handles Locales
The MCP server docs state the rule in one sentence: when i18n is enabled on a Content-Type, MCP tools accept an optional locale parameter (e.g., "en", "fr"), and "If omitted, the default locale is used." That default isn't applied by guesswork on the agent's side. Strapi sets it as a Zod schema default in the tool definition, so a client that never mentions a language still gets a valid call against your default locale.
The parameter shows up on every content-management tool. list uses it to filter results to one language. create uses it to set the locale of the new entry. The document-scoped tools (get, update, delete, publish, unpublish, discard_draft) take locale alongside documentId to select which variant of a document they touch.
That last part depends on how Strapi 5 models localized content. A document is "an API-only concept which represents all the variations of content (for different locales, for the draft and published versions) for a given entry found in the Content Manager", per the REST API docs. The documentId is a 24-character alphanumeric string shared by the locale versions of an entry.
Each localized variant can have different localized field values, database records, record identifiers, and publication data, as well as a different locale field. So when an agent says "update article abc123 in French," the documentId names the entry and locale: 'fr' names the variant. The MCP locale argument maps straight onto the Document Service API's locale parameter documented in the Document Service locale docs.
The docs also explain how the agent knows which languages exist: "The AI client sees which locales are available in each tool's schema, so you can ask it to create or update content in a specific language. For example, asking 'Create an article in French titled 'Bonjour'' passes locale: 'fr' to the create tool. Which locales are available depends on the Admin token's permissions."
For reference, these are the tools a Collection Type exposes and the RBAC permission each one needs:
| Tool | Permission Required |
|---|---|
list, get | read |
create | create |
update | update |
delete | delete |
publish, unpublish, discard_draft | publish |
The three publish-related tools only appear when Draft and Publish is active on the Content-Type. Single Types skip list and merge create and update into a single write tool.
Prerequisites for Multilingual Automation
Four things need to be true before an agent can write localized content through MCP.
1. A Strapi version with the MCP server. Use a Strapi 5 project with the MCP server available, as described in the GA announcement.
2. i18n enabled on the Content-Type, with locales configured. In the Content-Type Builder, open the Content-Type's Advanced settings, tick "Internationalization" at the Content-Type level, then tick "Enable localization for this field" on each field that should vary per language. Fields you leave unticked share one value across every locale. Add your target locales under Settings > Global Settings > Internationalization. The default locale comes from the STRAPI_PLUGIN_I18N_INIT_LOCALE_CODE environment variable and falls back to 'en'. The Internationalization docs cover each of these steps.
3. The MCP server turned on. server.mcp.enabled is false by default. Add this to config/server.ts and restart:
// config/server.ts
export default () => ({
mcp: {
enabled: true,
},
});The endpoint comes up at /mcp. No extra package to install.
4. An Admin token. Generate one under Settings → Admin Panel → Admin Tokens. The MCP server accepts Admin tokens only; a Content API token gets a 401. The next section covers how to scope it.
With those in place, connect a client. The docs name Claude Desktop, Claude Code, Cursor, Windsurf, and OpenAI agents as compatible over Streamable HTTP. For Claude Code:
claude mcp add strapi-mcp --transport http <STRAPI_URL>/mcp \
-H "Authorization: Bearer YOUR_ADMIN_TOKEN"Run /mcp afterwards to confirm strapi-mcp reports as connected. For Cursor, use the following file.
// .cursor/mcp.json
{
"mcpServers": {
"strapi-mcp": {
"type": "streamable-http",
"url": "<STRAPI_URL>/mcp",
"headers": { "Authorization": "Bearer YOUR_ADMIN_TOKEN" }
}
}
}One more thing worth having on: Draft and Publish. Without it, the publish tool doesn't exist, and the "verify then publish" half of the workflow below collapses into "create and hope."
Scoping Tokens by Locale
Token permissions decide which locales an agent can touch, and they decide it per action. The permission boundaries section of the docs puts it this way:
"When the Internationalization (i18n) feature is enabled and locale-level permissions are configured, the
localeparameter is narrowed per action. For example, a token might allow reading content inenandfrbut only creating content inen."
That example is the useful pattern for translation pipelines. A token that reads every language but writes only the default locale lets an agent pull the English source and compare translations without being able to overwrite the French editor's work. Flip it around for a translation agent: read en, create and update fr only, no publish at all, and leave the publish step to a human or a second, tighter token.
Enforcement happens in four layers:
- At connection time, Strapi exposes only the tools the token's permissions cover.
- Input and output schemas drop fields the token can't access for that action.
- With i18n active, the
localeenum in each schema shrinks to the permitted values. - At runtime, "Each handler calls Strapi's permission checker at runtime to verify access on the specific document being read, written, or published."
Condition-based rules like "only update entries you own" live in that last layer, which is why an agent that requests a disallowed locale gets a runtime error rather than a schema rejection. Together, these layers keep both the available tools and document-level actions inside the token's permission boundary.
Building a least-privilege token follows the steps in Strapi's token scoping guide: click Create new Admin Token, set a name and duration (seven days, 30 days, 90 days, or Unlimited), tick only the Content-Types and actions the agent needs, expand the field list to untick fields you want out of the schemas, and, since i18n is installed, set permissions per locale at that same step. The plaintext token appears once. The docs' standing advice: "Create dedicated Admin tokens for each AI client or use case. Use the most restrictive permissions that still allow the AI to accomplish its task."
Two properties make scoping less scary than it sounds. A token can never exceed its owner's permission ceiling, and it "is automatically re-clamped when the owner's roles change or revoked the moment the owner is deactivated." And because each POST to /mcp spins up a fresh server instance scoped to the token, with no session persistence, "revoking or re-scoping a token takes effect on the next request."
The Multilingual Publishing Workflow
The repeatable core has three steps: create the source entry in the default locale, create or attach one localized version per target locale, then list and publish each locale. Every step below uses prompts from the content management prompts section of the docs, so you can paste them into any connected client.
The locale-targeted create prompt is documented, but the supplied MCP documentation does not confirm that it attaches a missing locale to an existing documentId. Verify the returned documentId before treating that entry as a localization.
Create the Source Entry in the Default Locale
Start with the entry every translation branches from. The documented prompt is:
Create a new article titled 'Hello World' with body 'First post'.This calls create with no locale, so Strapi applies the default locale via the schema default. With Draft and Publish active, the entry lands as a draft. The Claude Desktop guide notes you can create straight into a published state by having the request specify status: 'published', though for a translation flow you'll want the draft so nothing goes live before the other locales exist.
Ask the agent to return the documentId in the same turn. You'll need it for every later document-scoped step, and it's the identifier shared by correctly linked locale variants.
Two gotchas show up right here. Strapi doesn't fill uid fields when a tool creates an entry, so a slug stays empty unless the agent sends one; either include the slug in the prompt or set a default in a lifecycle hook, as the custom tools guide suggests. And media fields accept references to existing assets only, so upload the hero image through the Media Library first and tell the agent which asset to attach.
Create Localized Versions per Locale
The docs give one locale-targeted creation prompt:
Create an article in French with the title 'Bonjour le monde'.The Cursor guide confirms this maps to create with locale: "fr". This pattern reliably targets the requested locale, but the available evidence does not confirm that a generic create call attaches the entry to an existing source documentId. Use it for a standalone French entry, or only as part of a localization workflow when your client returns the same documentId as the source. Each locale still needs its own call, because content in Strapi is managed one locale at a time.
Where does the translated text come from? From you, or from the model doing the prompting. The MCP server doesn't translate anything. It writes whatever text the agent hands it into the locale you name.
If you want the model to translate, ask it explicitly in the same prompt: read the English article by documentId, translate the title and body into French, and create the French version associated with that source document. The read step needs read permission on en and the write step needs create on fr, which is exactly the split token from the previous section.
The MCP docs document creating a French article, but they don't show a confirmed prompt or tool call that attaches a missing locale to an existing documentId. After the call, compare the returned documentId with the source. If they differ, stop before publishing because the French entry is unrelated.
The Document Service API handles locale-specific operations directly, and update({ documentId, locale: 'fr', ... }) writes only the French variant of a known document. For a workflow that requires guaranteed linkage, treat a tested Document Service step as required rather than relying on generic MCP create behavior.
Verify and Publish Each Locale
Before anything goes live, confirm every locale actually exists and belongs to the expected document. Strapi 5 dropped the locale=all query. The breaking change note is blunt: "Getting documents in all locales at the same time is not possible anymore. A specific locale value must be passed." So the agent calls list once per locale:
List the 5 most recent articles in French.
List the 5 most recent articles in Spanish.Per the content management tools reference, list paginates with page (1-indexed) and pageSize (default 25, max 100), and it supports filtering and sorting on scalar attributes. Filter on the shared title or a scalar field, check that each locale returns the entry, and confirm that the returned documentId matches the source. A locale that returns nothing is a missing translation; a different documentId is a separate document rather than a linked localization.
Draft and Publish gives each variant its own status: Published (no pending changes), Modified (draft changes saved but not published), or Draft (never published), per the Draft and Publish docs. Have the agent read those back per locale so you can see which variants still need a publish.
Then publish, one locale at a time. The i18n docs state: "It is not possible to edit or publish content for several locales at the same time (e.g. Clicking on the Publish button will only publish the content for the locale you are currently working on)." The same holds for MCP. "Publish article abc123." publishes the default locale only, so follow it with:
Publish article abc123 in French.
Publish article abc123 in Spanish.If you'd rather script the publish step outside the agent, the Document Service API accepts a locale on publish(). Here is a generic service-method snippet:
// Example: publishing a single locale via the Document Service API
await strapi
.documents('api::restaurant.restaurant')
.publish({ documentId: 'a1b2c3d4e5f6g7h8i9j0klm', locale: 'fr' });Passing locale: '*' publishes every locale version at once through the Document Service, which is handy in a post-translation job. The research found no equivalent wildcard documented for MCP publish calls, so inside the agent conversation, plan on one publish per language.
Strapi MCP Locales vs. Strapi AI Auto-Translation
Strapi offers two paths under the heading of CMS AI translation, and they aren't interchangeable.
The MCP locale parameter is a targeting mechanism: when i18n is enabled, it tells the tool which locale to work with, and if it is omitted, the default permitted locale is used. Create and update operations are scoped to the selected locale rather than automatically inferred from the content. Nothing happens unless a tool call asks for it.
AI-powered internationalization is an automation trigger. Once you enable it under Settings > Global Settings > Internationalization by setting AI Translations to Enabled, "whenever you edit a Content-Type in the default locale and click Save, all other locales for the Content-Type should be translated automatically." Strapi generates the translations, including Dynamic Zones and blocks.
The constraint that decides most teams' choice is directionality. The docs warn that the feature "only works one way, keeping the default locale content as the unique source of truth," and that "When editing the content for the default locale, the manual modifications made to other locales will be overwritten." If a French editor polishes a translation and then someone fixes a typo in the English source, the polish is gone. Editing a non-default locale doesn't trigger any translation either.
| Dimension | AI-Powered i18n | MCP locale Parameter |
|---|---|---|
| Who produces the translation | Strapi AI | The agent or developer |
| Trigger | Save on the default locale | Explicit locale in a tool call |
| Direction | Default locale → all others | Any permitted locale |
| Overwrites manual edits | Yes, on non-default locales | No |
Pick auto-translation when you have no per-locale editorial process and want every save fanned out immediately. Pick the MCP route when translators or reviewers own specific locales or when you want a reviewable draft per language before anything publishes. The two can coexist, but if auto-translation is on, any MCP write to a non-default locale is one English save away from being replaced.
Writing Prompts That Avoid Locale Ambiguity
Because the default locale kicks in silently whenever locale is omitted, a vague prompt produces a wrong-language entry with no error. The docs address this directly:
"When working with localized content, explicitly mention the target language in your prompt so the AI client passes the correct
localevalue. For instance, prefer 'Create an article in French' over 'Create an article titled 'Bonjour'' to avoid ambiguity."
The Windsurf guide explains the failure mode: "'Create an article in French with the title 'Bonjour le monde'' gets Cascade to pass locale: fr correctly," whereas "a French-looking title alone leaves the model guessing." A model may notice that "Bonjour" is French and set the locale, or it may treat it as an English article with a French title. Both are plausible, and only one is what you meant.
A few habits that follow from this:
- Name the language in every prompt that creates, updates, lists, or publishes, including the default locale. "Publish article abc123 in English" is redundant to Strapi but removes any chance the model reaches for the wrong variant.
- Use the language name, not just the code, unless your locale codes are unambiguous to the model. "In French" reliably becomes
fr; a regional code likefr-CAdeserves spelling out as "Canadian French (fr-CA)." - For multi-step prompts, restate the locale at each step: "Read article abc123 in English, translate the title and body into German, and create the German version."
- Ask the agent to echo back the
localeanddocumentIdit used before it publishes. It costs one line and catches a mismatched call or unrelated document before it goes live.
These checks keep every operation explicit and make locale and document-linkage mistakes easier to catch before publication.
Limitations to Plan Around
The known limitations section and the i18n docs together describe the edges of what an MCP-driven translation pipeline can do.
- The default locale is silent. Omitting
localeuses the default locale. Every ambiguity in a prompt resolves toward your default language. - Creating in a locale does not confirm document linkage. The documented MCP prompt proves that
createcan target a locale, but the available evidence does not establish a confirmed MCP call for attaching a missing locale to an existingdocumentId. Compare identifiers after creation, and use a tested Document Service step when linked localizations are required. - No bulk multi-locale operations through MCP. Coverage checks should pass a
localetolistfor each locale being inspected, and publishing localized content is typically done by passing alocaletopublishfor the locale you want to publish. For a project with 12 locales that's 24 calls per entry, which is fine for an agent but worth knowing when you estimate how long a batch will take. - Media can't be uploaded through MCP. The docs state: "Media fields accept existing media asset references but the MCP server cannot upload new files." Localized images still go through the Media Library or upload API first, then get referenced by ID in the tool call.
- Dynamic Zones arrive untyped. "Dynamic zone fields are passed as untyped arrays in tool schemas. The internal structure of each component within a dynamic zone is not described." Strapi's own workaround is to have the agent put all prose in a single
shared.rich-textblock and let a human editor split it into other component types afterward. For translated long-form content, that means the French draft will be structurally flatter than the hand-built English original. uidfields stay empty. Send a slug per locale in the prompt, or generate it in a lifecycle hook.- Relations are shallow.
listandgetdon't support nested population. An agent verifying that a French article links to the French category will see the relation's identity, not its fields. - Custom fields may map to
unknown. Plugin-registered custom fields fall back to anunknowntype if the registry isn't populated when tools are registered. - Sorting and filtering are scalar-only. Relation, component, Dynamic Zone, media, and JSON fields can't be sorted or filtered on, so coverage queries need to key off a title, date, or other scalar.
- Permission errors surface at runtime. A token scoped to read
enandfrbut create onlyenwill let the agent attempt a French create and fail at the handler. Check the token's per-locale permissions before blaming the prompt.
From Five Tabs to One Conversation: What MCP Locale Automation Gets You
With i18n enabled, a scoped Admin token, and prompts that name their language, the MCP locale parameter turns much of the five-tab publishing grind into a scripted sequence: create the source, target each locale, list per locale to confirm coverage and document linkage, and publish per locale.
Correctly linked variants share a documentId, and token scoping keeps the agent from writing where it shouldn't. Because the documented locale-targeted create prompt does not by itself confirm linkage to an existing document, verify every returned documentId and use a tested Document Service step where guaranteed localization attachment is required.
Start with a two-locale Content-Type on a Strapi 5 project, give a translation agent read on the default locale and create on one target locale, and run the workflow end to end before widening the token. The Strapi MCP docs have the full tool reference, and strapi.io is the place to start if you're setting up the project from scratch.




