One Sulu. Any agent. Here's how to connect them.
Your editors don't all use the same assistant. One team works in Claude, another has ChatGPT through the company plan, and your developers live in Claude Code or Codex. If your content platform only talks to one of them, you end up with copy-paste for everyone else.
The Sulu MCP Bundle speaks the Model Context Protocol, the open standard all of these assistants support. This tutorial connects one Sulu installation to claude.ai, ChatGPT, Claude Code, Codex, and Mistral Vibe. Whichever assistant connects, it works with the permissions of the person who logged in, never more.
Prerequisites
- A Sulu 3.0 project with the MCP Bundle 1.0.0-RC4 installed and configured (see the configuration guide and the RC4 release notes)
- The installation reachable over https under its public domain (for a quick test, a tunnel works too, see below)
- The OAuth tables in place:
persistence: doctrineforleague/oauth2-server-bundleand its migration. Without them, no client survives the second request. - A Sulu user for each person who connects an assistant
Your MCP server URL is your public Sulu URL plus /admin/mcp, for example https://sulu.example.com/admin/mcp. You need it for every client below.
Excursion: Try it on your machine with ngrok
claude.ai and ChatGPT connect from the internet, so they can't reach localhost. For a test, a tunnel is enough. ngrok gives your local Sulu a public https URL:
ngrok http 8000Sulu builds the OAuth addresses it advertises from its server URL, so set it to the forwarding URL ngrok shows, and clear the cache:
# .env.local
SULU_MCP_SERVER_URL=https://<your-subdomain>.ngrok-free.appYour MCP server URL for the steps below is then https://<your-subdomain>.ngrok-free.app/admin/mcp. On ngrok's free plan, the URL changes with every start. Update the variable and reconnect the assistant when it does.
Step 1: Know the three ways in
Before an assistant gets a token, your Sulu has to know which client is asking. There are three ways, and each assistant picks the one it supports:
- Client ID Metadata Document (CIMD): nothing to do in Sulu. Used by claude.ai, ChatGPT, Claude Code, and Codex.
- Dynamic Client Registration (DCR): nothing to do in Sulu. Used by Mistral Vibe.
- Manual client: run
sulu:mcp:create-clientonce. A fallback for ChatGPT when your workspace doesn't offer custom MCP servers.
CIMD is the path the current MCP specification recommends. The client identifies itself with an https URL that serves its name and redirect URIs, and Sulu fetches that document when you authorize. DCR still works but is deprecated in the specification. CIMD and DCR each have their own switch, so you can turn off whichever your clients don't need.
Whichever way a client takes, the next screen is always the same: the Sulu login, then a consent page that names the client and the scopes it asks for. Nothing gets a token without that click.
Step 2: Connect your assistant
claude.ai
In Settings → Connectors, add a custom connector with your MCP server URL and click Connect. Log in to Sulu and approve. There is no client to create and no secret to copy.
ChatGPT
Open Plugins (chatgpt.com/plugins), choose Add → Add custom MCP server, enter your MCP server URL, and connect. Log in to Sulu and approve. If your workspace doesn't offer that option, create a client by hand, as described in the ChatGPT guide.
Claude Code
Add the server from your project directory. On first use, Claude Code opens the Sulu login in your browser. Log in and approve.
claude mcp add --transport http sulu https://sulu.example.com/admin/mcpCodex
Add the server. Codex opens the Sulu login in your browser right away. Log in and approve.
codex mcp add sulu --url https://sulu.example.com/admin/mcpMistral Vibe
Open Context → Connectors (chat.mistral.ai/connections), choose Add custom connector, enter your MCP server URL, and connect. Log in to Sulu and approve. Vibe registers itself, so there is no client to create.
Step 3: Teach the assistant your content model
Every assistant gets the same tools, but it works better when it knows how Sulu thinks: webspaces, templates, blocks. The bundle ships a system prompt for that in CONTENT_ASSISTANT_PROMPT.md. Treat it as a starting point, not a finished prompt: add your webspaces, your templates, and the rules your editors follow, such as tone, languages, and what may be published. Then paste it where your assistant keeps standing instructions: the project or connector instructions in claude.ai and ChatGPT, your CLAUDE.md in Claude Code, your project instructions in Codex, and the agent instructions in Vibe.
Tips
- Connect as the person, not as admin. Every tool runs with the permissions of the Sulu user who logged in. Tools that user can't use are hidden from the assistant entirely.
- Keep the dangerous tools off until you need them. Delete, publish, block removal, and media upload are disabled by default.
- Revoke in the admin. Remove a user's access in Sulu, and the assistant loses it too.
- Login works, then
403 Invalid Host header? Checkallowed_hostsof the MCP transport: your public host has to be on the list. The bundle's Flex recipe derives it fromSULU_MCP_SERVER_URL.
What's next
You now have one Sulu that every assistant on your team can work with, each under its own user's permissions. In the next part of this series, we look at the security model behind that promise.
Questions, or a client that doesn't connect? Tell us in GitHub Discussions or in the Sulu Slack.
