MCP Server
Connect Claude, ChatGPT and other AI assistants to a Nimbu site through the remote MCP server: setup, permissions, access tokens, the tool reference and limits.
Nimbu runs a remote Model Context Protocol (MCP) server. Connect an AI assistant to it and the assistant can work on one of your Nimbu sites: look up products, orders and customers, read and edit pages, channel entries and translations, upload images, and read or update theme files.
The server URL is:
https://mcp.nimbu.io/mcpEnter it exactly as shown, including the /mcp path. Some clients compare it character by
character with the address the server reports during setup, and the connection fails if the two
differ.
Every connection belongs to one Nimbu user and one site. The assistant acts as you, so it can never do more than your own Nimbu account can do on that site. It is limited further by the permissions (OAuth scopes) you approve when you connect.
Connect an assistant
Most assistants connect with OAuth: you paste the server URL, sign in to Nimbu, pick a site and approve the access. Clients that only accept a fixed bearer token use a dedicated MCP access token instead.
Claude
- In Claude, open Settings → Connectors and choose Add custom connector.
- Paste
https://mcp.nimbu.io/mcpas the server URL and connect. - Claude opens the Nimbu sign-in and consent screen. Sign in, choose the site and approve.
For Claude Code, add the server from a terminal and follow the browser prompt:
claude mcp add --transport http nimbu https://mcp.nimbu.io/mcpChatGPT
Custom MCP connectors in ChatGPT need developer mode, which depends on your ChatGPT plan and workspace settings.
- In ChatGPT settings, open the connectors section, go to the advanced settings and turn on developer mode.
- Create a connector with
https://mcp.nimbu.io/mcpas the server URL and OAuth as the authentication method. - ChatGPT sends you to the same Nimbu sign-in and consent screen.
Menu names in Claude and ChatGPT change from time to time. If a label above doesn't match what you see, look for the place to add a custom or remote MCP connector. The URL and the sign-in flow stay the same.
Other MCP clients
The server speaks Streamable HTTP on a single stateless endpoint and returns JSON (no SSE stream, no session id). For OAuth, clients discover everything from the server:
- Protected resource metadata:
https://mcp.nimbu.io/.well-known/oauth-protected-resource - OAuth 2.1 authorization code flow with PKCE (
S256) - Client registration through dynamic client registration or a Client ID Metadata Document
If your client can't do OAuth, create an MCP access token and send it as a
bearer token. For clients configured with an mcp.json file (Cursor, VS Code and others):
{
"mcpServers": {
"nimbu": {
"url": "https://mcp.nimbu.io/mcp",
"headers": {
"Authorization": "Bearer <your-mcp-token>"
}
}
}
}With Claude Code:
claude mcp add --transport http nimbu https://mcp.nimbu.io/mcp \
--header "Authorization: Bearer <your-mcp-token>"The consent screen
When an assistant connects through OAuth, Nimbu shows a consent screen before anything is granted. It shows:
- The name of the app asking for access. For self-registered clients Nimbu marks that name as self-reported, because anyone can pick any name. When a client identifies itself by a domain, Nimbu shows that domain.
- Where you will be sent after approving. Nimbu verifies this host, so check that it belongs to the
assistant you are connecting (for example
claude.aiorchatgpt.com). A desktop or command-line client shows an address on your own device instead. - The permissions requested, grouped as Read content, Manage content, Read commerce, Manage commerce and Theme & code.
- A site picker (Grant access to) if your account has access to more than one site.
Only continue if you started this
If a consent screen appears that you didn't start yourself, or the redirect host isn't the assistant you meant to connect, click Cancel. Approving hands that app access to your site as you.
Access tokens issued through OAuth last two hours and the client refreshes them in the background. If a client later needs a permission you didn't grant, it can ask again and you'll see the consent screen for the extra access.
Permissions
A connection can use two things at once: the scopes you approved, and your own permissions on the selected site. Both have to allow an action. If an admin narrows your role later, the connection narrows with it on the next request. It stops working altogether if your account is locked, you lose access to the site, or the connection is revoked.
These are the scopes an MCP connection can request:
| Scope | Shown as | Allows |
|---|---|---|
read_content | read content | Pages, menus, translations, the media library |
write_content | update content | Create, edit, publish and delete pages; translations; uploads |
read_channels | read channels | Channels and their entries |
write_channels | update channels | Create, edit and delete channel entries |
read_sensitive_channels | read privacy-sensitive channels | Entries in channels marked as privacy-sensitive |
write_sensitive_channels | update privacy-sensitive channels | Changing entries in privacy-sensitive channels |
read_products | read products | Products and collections |
write_products | update products | Create and edit products |
read_orders | read orders | Orders |
read_customers | read customers | Customers |
read_themes | read theme code | Theme layouts, templates, snippets and assets |
write_themes | update themes | Create and update theme files |
A few rules follow from how scopes are checked:
- A write scope includes its read scope.
write_contentis enough to read pages. - Tools the connection can't use are hidden. A connection without write scopes never sees the write tools in its tool list, so the assistant can't even try to call them.
search,fetch,list_sitesandget_siteneed no scope.searchandfetchonly return the kinds of records your scopes allow.- A connection with no scopes at all only sees its own connection details.
Orders and customers are read-only through MCP. There are no write scopes for them.
Revoke access
Connections and tokens are listed in the Nimbu admin under Settings → Apps:
- Connected AI agents lists every OAuth connection to the site, with the user it acts as and when it was last used. Click Disconnect to revoke one.
- MCP Access Tokens lists the dedicated tokens. Click Revoke and confirm to delete one.
Revoking takes effect right away. If you don't see Apps in the settings menu, ask someone who manages the site's settings to disconnect the assistant for you.
MCP access tokens
For clients that take a token in their configuration instead of doing OAuth (Cursor, VS Code, CI jobs, your own scripts), create a dedicated MCP access token:
- Go to Settings → Apps and click Create new MCP token in the MCP Access Tokens section.
- Give it a name you'll recognise later, and pick only the scopes the assistant needs.
- Pick an expiry: 90 days, 1 year (the default) or never.
- Save and copy the token into your client's configuration.
An MCP token acts as the user who created it, on the site it was created for, and it follows that
user's permissions just like an OAuth connection. It only works on mcp.nimbu.io; the REST API at
api.nimbu.io rejects it. The reverse is true as well: a regular Site Access Token or REST token
won't work on the MCP server. Create one MCP token per assistant so you can revoke one without
touching the others.
Tools
The server exposes 37 tools. Your client shows the subset your scopes allow.
Search
| Tool | What it does | Scope |
|---|---|---|
search | Full-text search across pages, products, collections and channel entries; customers and orders only when asked for explicitly | none (results follow scopes) |
fetch | Fetch the full record for a search result | none (results follow scopes) |
Customers and orders hold personal data, so search leaves them out unless the request names them
and the connection has read_customers or read_orders.
| Type | Searched by default | Scope | fetch id |
|---|---|---|---|
page | yes | read_content | page:<id> |
product | yes | read_products | product:<id> |
collection | yes | read_products | collection:<id> |
entry | yes | read_channels | entry:<channel-slug>:<id> |
customer | no, name it in types | read_customers | customer:<id> |
order | no, name it in types | read_orders | order:<id> |
Pass a result's id to fetch unchanged. Types the connection has no scope for are dropped, and
the response's types lists what was actually searched. degraded: true means the search for one
type failed and its results are missing, so retry instead of treating the answer as complete.
Pages and navigation
| Tool | What it does | Scope |
|---|---|---|
list_pages | List the site's pages | read_content |
get_page | Read a page's content, including a content_etag | read_content |
create_page | Create a page (a draft unless you ask for it to be published) | write_content |
update_page | Change a page's title, slug, template, parent or SEO fields | write_content |
update_page_content | Edit a page's content with up to 10 operations per call | write_content |
publish_page | Publish a page or take it offline | write_content |
delete_page | Permanently delete a page and its child pages | write_content |
list_menus | List the site's navigation menus | read_content |
get_menu | Read one menu and its items | read_content |
Page edits are protected against overwriting someone else's work. update_page and
update_page_content need the content_etag from a recent get_page; if the page changed in the
meantime, the write is refused and the assistant has to read the page again. delete_page only
proceeds when the assistant passes the page's current title.
Channels and translations
| Tool | What it does | Scope |
|---|---|---|
list_channels | List the site's channels | read_channels |
describe_channel | Show a channel's fields | read_channels |
query_channel_entries | Query entries with filters, sorting and pagination | read_channels |
get_channel_entry | Read one entry | read_channels |
create_channel_entry | Create an entry | write_channels |
update_channel_entry | Change only the fields you pass | write_channels |
delete_channel_entry | Permanently delete one entry | write_channels |
list_translations | List the site's translation strings | read_content |
upsert_translations | Create or update up to 100 translation strings in one call | write_content |
Channels marked as privacy-sensitive also need read_sensitive_channels or
write_sensitive_channels. Per-entry access rules apply to MCP just as they do to the API.
On channels with publishing enabled, create_channel_entry and update_channel_entry take two
arguments for the publication state:
status:draft,publishedorscheduled. A create withoutstatusis a draft; an update without it leaves the state alone.publish_at: an ISO 8601 timestamp, required whenstatusisscheduled.
An unknown status, scheduled without publish_at, or a malformed timestamp is refused before
anything is written. On a channel without publishing, passing status returns a 422. To find
unpublished entries, call query_channel_entries with filters: {"_status": "draft"} (or
published, scheduled).
Products, orders and customers
| Tool | What it does | Scope |
|---|---|---|
query_products | Query products with filters, sorting and pagination | read_products |
get_product | Read one product by id or slug | read_products |
create_product | Create a product | write_products |
update_product | Change only the fields you pass | write_products |
list_collections | List product collections | read_products |
get_collection | Read one collection by id or slug | read_products |
query_orders | Query orders with filters, sorting and pagination | read_orders |
get_order | Read one order by id or order number | read_orders |
query_customers | Query customers with filters, sorting and pagination | read_customers |
get_customer | Read one customer by id or email | read_customers |
Stock and inventory fields are ignored on product writes. Customer passwords and tokens are never returned, and you can't filter customers on them.
Files
| Tool | What it does | Scope |
|---|---|---|
list_uploads | List the files in the site's media library | read_content |
upload_file | Upload a small file to the media library | write_content |
An upload returns a file_ref that the assistant can put in an image or file field of a channel
entry or product. Channel entries, products and pages can also take a small file inline in the same
write call.
Theme
| Tool | What it does | Scope |
|---|---|---|
list_theme_files | List a theme's layouts, templates, snippets and assets | read_themes |
get_theme_file | Read one theme file's source | read_themes |
update_theme_file | Create or update a layout, template or snippet | write_themes |
A change to a file in the active theme goes live on your storefront immediately, the same as
saving it in the admin or pushing it with the CLI. Nimbu doesn't ask for a second confirmation.
Grant write_themes only when you want the assistant to change theme code.
A theme file that someone last edited in the Nimbu admin is locked, and update_theme_file won't
overwrite it.
Site
| Tool | What it does | Scope |
|---|---|---|
list_sites | Return the site this connection is bound to | none |
get_site | Read that site's details, including its languages | none |
Tools never take a site argument. To work on another site, connect again and pick that site.
Languages
Content tools for pages, menus, channel entries, products, collections, translations, search and
fetch take an optional locale argument, such as "nl" or "fr". Leave it out and the tool
uses the site's default language. A write with locale only changes that language and leaves the
others alone. A language the site hasn't enabled is refused; get_site lists the enabled ones.
Page reads always include every language under translations, whatever locale you pass.
Writes and retries
create_page,create_channel_entry,create_productandupload_filerequire anidempotency_key(a UUID). Retrying with the same key and the same input returns the original result instead of creating a duplicate. The same key with different input is refused withidempotency_conflict. While the first attempt is still running, or when its outcome is unknown, the answer isidempotency_in_progress: check whether the record exists, and don't retry with a new key.update_productandupdate_channel_entryare not idempotent. Repeating an update can apply an increment twice or add another file or nested record. After a timeout or a lost response, read the record again and check what changed before you retry.update_page_contentneeds the page's currentcontent_etag, so a retry after a write that did land is refused. Read the page again to see the result and get the new etag.- Tools publish
destructiveHint,idempotentHintandopenWorldHintannotations. They help a client explain what a tool does, but they are hints, not a permission or confirmation check.
Limits
- Uploads are limited to 700 KB after base64 decoding, for
upload_fileand for inline files. Accepted types are PNG, JPEG, GIF, WebP and PDF. SVG is not accepted. Use the Nimbu admin or the CLI for larger files. - Each connection can make 600 read calls and 60 write calls per five minutes.
searchhas its own budget that depends on how many record types and results it asks for. Over the limit, the server answers with429and aRetry-Afterheader. - A single request may batch at most 20 tool calls.
- Lists return at most 50 items per page. Responses over roughly 50 KB are cut short, so narrow a
query with filters or a smaller
per_page. - Menus are read-only. Edit them in the Nimbu admin.
- Some things are deliberately not available through MCP: stock changes, order status changes, customer account actions, coupons, webhooks, site settings, Cloud Code, and bulk or filtered deletes.
For client developers
- Protocol version. The server checks the
MCP-Protocol-Versionheader. It currently accepts2026-07-28,2025-11-25,2025-06-18,2025-03-26and2024-11-05; without the header it assumes2025-03-26. Any other value returns400 unsupported_protocol_version, before authentication. - Tool list changes. The server doesn't advertise
listChangedand never sendsnotifications/tools/list_changed. The tool list still depends on the granted scopes, so calltools/listagain after a scope step-up or when a call returns403 insufficient_scope. - Structured content. Every result has
structuredContentand the same JSON in a text block.structuredContentis always an object: a list comes back as{"items": [...]}, while the text block keeps the bare array. - Partial bulk writes. When a bulk write such as
upsert_translationsdoesn't fully succeed, the tool returns an error withcode: "multi_status", asummaryand per-itemresults. Check each item'sappliedflag: some items may have been written. - Client registration. Nimbu only issues public OAuth clients with PKCE and no client secret.
Dynamic client registration requires
token_endpoint_auth_method: "none". A Client ID Metadata Document that declares an auth method must prefernoneor list it intoken_endpoint_auth_methods_supported.
Security
- Give each assistant the fewest scopes that do the job. Start with read scopes and add write scopes when you actually want changes made.
- Watch for prompt injection. An assistant reads whatever your site contains, including text that visitors and customers typed into forms, orders or channel entries. That text can contain instructions aimed at the assistant. With write scopes granted, a client may carry out an allowed write without asking you first, so review what the assistant proposes before you let it act.
- Records the assistant reads, including customer and order data, are sent to the AI provider
behind your assistant. Check that your agreement with that provider covers this data before you
grant
read_customersorread_orders. - Disconnect assistants and revoke MCP tokens you no longer use under Settings → Apps.