MCP Tools¶
Every expert of this bundle is also available as an MCP tool, so AI clients (Claude, ChatGPT, your own agent) can use the same capabilities editors use in the admin — without going through the admin UI.
The tools only provide the AI capabilities. Reading and writing Sulu content is the job of the Sulu MCP Bundle, which exposes pages, articles, snippets, media and taxonomies as sulu_* tools. Install both bundles together and a client can, for example, read a page, ask sulu_ai_seo_generate for SEO data, and write the result back.
Setup¶
The tools ship with this bundle and only load when sulu/mcp-bundle is installed and registered:
composer require sulu/mcp-bundle
It requires Sulu 3, registers #[RequiresPermission]-gated tools on the "sulu" MCP server, and pulls in symfony/mcp-bundle itself to expose the transport. Follow its own setup to configure the transport and secure the endpoint with OAuth2 — every tool of this bundle checks the Sulu permission of the currently authenticated user, so the endpoint has to run behind an authenticated firewall.
Experts have to be synchronized before the tools can be used, because a tool call always addresses an expert variant:
php bin/console sulu:ai:synchronize-experts
Available Tools¶
| Tool | Expert | Permission | Writes content |
|---|---|---|---|
sulu_ai_seo_generate |
SEO Generator | sulu.ai.seo_generator |
no |
sulu_ai_excerpt_generate |
Excerpt Generator | sulu.ai.excerpt_generator |
no |
sulu_ai_media_metadata_generate |
Media Metadata Generator | sulu.ai.media_metadata_generator |
no |
sulu_ai_translate |
Translator | sulu.ai.translate |
no |
sulu_ai_writing_assistant_optimize |
Writing Assistant | sulu.ai.writing_assistant |
no |
sulu_ai_content_translate_full |
Translator | sulu.ai.translate |
yes — disabled by default |
A user without the VIEW permission of the listed security context gets an error instead of a result, exactly like in the admin UI. See Experts → Permissions.
Every tool carries the MCP tool annotations (readOnlyHint, destructiveHint, idempotentHint, openWorldHint) in tools/list. The generating tools are read-only and idempotent, they return text and store nothing, so an agent client may run them without asking the user; sulu_ai_writing_assistant_optimize is read-only but not idempotent because every call adds a turn to its chat. sulu_ai_content_translate_full is marked destructive because it overwrites the stored translation, so a client should ask before calling it. All tools are open-world: they call the sulu.ai platform.
sulu_ai_seo_generate¶
Generates SEO title, description and keywords for a page, article or snippet. The expert loads the stored content itself, so only identifiers are needed. The result is returned, not persisted.
| Argument | Type | Required | Description |
|---|---|---|---|
uuid |
string | yes | UUID of the document |
locale |
string | yes | Locale of the content to analyze |
resourceKey |
string | no | pages (default), articles or snippets |
currentSeoData |
object | no | Current SEO data — pass it to optimize instead of generating from scratch |
webspace |
string | no | Resolved automatically when omitted |
expertUuid |
string | no | Expert variant, see Expert variants |
Returns { "uuid": "…", "data": { "title": "…", "description": "…", "keywords": "…" } }. The uuid identifies this generation on the sulu.ai platform.
sulu_ai_excerpt_generate¶
Same arguments as sulu_ai_seo_generate, except that the current data argument is called currentExcerptData. Returns { "uuid": "…", "data": { "title": "…", "description": "…", "more": "…" } }.
sulu_ai_media_metadata_generate¶
Generates a title (alt text) and a description (caption) for an image in the media library. Only image media types are supported.
| Argument | Type | Required | Description |
|---|---|---|---|
id |
integer | yes | Numeric id of the media item (not a UUID) |
locale |
string | yes | Locale the metadata is generated in |
currentMetadata |
object | no | Current {title, description} — pass it to optimize instead of generating from scratch |
expertUuid |
string | no | Expert variant, see Expert variants |
The platform fetches the image over HTTP, so the tool needs to know the public base URL. It uses the current request when there is one and falls back to the router request context (router.request_context.host / router.request_context.scheme) otherwise.
sulu_ai_translate¶
Translates a list of strings with the project glossary and tone of voice. It does not read or write Sulu content.
| Argument | Type | Required | Description |
|---|---|---|---|
texts |
array of strings | yes | Translated in the given order |
targetLanguage |
string | yes | For example en, de or en-gb |
sourceLanguage |
string | no | Detected automatically when omitted |
html |
boolean | no | false by default — set it when the texts contain markup |
webspace |
string | no | Webspace whose glossary and tone of voice are applied |
sulu_ai_writing_assistant_optimize¶
Asks the writing assistant to revise a piece of text in the context of a document. Unlike the generators this is conversational: one call is one turn, and the returned chatId continues the conversation on the next call.
| Argument | Type | Required | Description |
|---|---|---|---|
text |
string | yes | The text to work on |
message |
string | yes | The instruction, e.g. "shorten this to two sentences" |
resourceKey |
string | yes | Resource key of the content the text belongs to: pages, articles or snippets |
uuid |
string | yes | UUID of the document the text belongs to |
locale |
string | yes | Locale the revised text is written in |
chatId |
string | no | Continues a previous conversation |
expertUuid |
string | no | Variant to use — the platform default is used when omitted |
webspace |
string | no | Webspace whose glossary and tone of voice are applied |
The conversation history is stored in the Symfony session, the same way the admin UI does it, so continuing a conversation across calls only works for a client that sends the session cookie back — the admin UI itself, or an MCP client configured to keep cookies. A transport with no request at all (stdio) gets a clear error instead of silently losing history. A bearer-token client with no cookie — including the OAuth setup this doc recommends — gets a new, empty session on every call: the tool call still succeeds, but chatId has no effect and the history is lost without any error.
sulu_ai_content_translate_full¶
Translates every translatable field of a page, article or snippet — including blocks, SEO and excerpt data — and saves the result. This is the tool behind the translate option of Sulu's "copy locale" action.
| Argument | Type | Required | Description |
|---|---|---|---|
uuid |
string | yes | UUID of the document |
locale |
string | yes | Locale that is translated in place |
resourceKey |
string | no | pages (default), articles or snippets |
sourceLanguage |
string | no | Language the current content is written in |
webspace |
string | no | Resolved automatically when omitted |
The tool translates the content that is currently stored in locale and writes the translation back into that same locale. To translate a document into a locale that is still empty, first copy the source locale into it — with Sulu's "copy locale" action in the admin UI, or by writing the source content with the content tools of the Sulu MCP bundle — and translate afterwards. The resource locator is regenerated from the translated title, except for the homepage.
Unlike the other tools, this one checks two permissions: the sulu.ai.translate context from the table above, and — because it writes to a specific document — the EDIT permission on the target page, article or snippet in locale, exactly like the admin UI checks before a write. A user holding only sulu.ai.translate is refused for a document they cannot edit. The check always uses the document's own webspace; the webspace argument cannot be used to bypass it.
Because it overwrites many fields at once, the tool is disabled by default by sulu/mcp-bundle's dangerous-tool gate:
sulu_mcp:
dangerous_tools:
sulu_ai_full_content_translation: true
While disabled the tool is neither registered as a service nor discovered, so it does not show up in the tool list of a client at all.
Expert Variants¶
Every expert can have several variants. The admin UI lets editors pick one; a tool call takes the optional expertUuid argument instead.
- omitted — the first variant returned for the expert is used
- given — the variant is validated against the synchronized variants, an unknown UUID is reported as an error listing the available ones
When no variant exists at all, the tool asks for sulu:ai:synchronize-experts to be run.
sulu_ai_writing_assistant_optimize is the exception: it forwards the argument as-is, so omitting it uses the expert configuration of the platform without selecting a variant.
Errors¶
Tool errors are reported as MCP tool call errors with a message the client can display:
| Situation | Message |
|---|---|
| Missing permission | Names the required permission and security context |
| Unknown expert variant | Lists the available variant UUIDs |
| No expert variant at all | Asks for sulu:ai:synchronize-experts |
| Failed or invalid AI response | The message key of the underlying error, for example sulu_ai.ai_response_invalid |