ChaiBuilder Logo

chaipro v0.4.0

Released 2026-09-21. Upgrading from v0.3.7.

A minor bump, so in the pre 1.0 line this is where breaking changes land. The headline is an MCP server: Claude, Cursor, VS Code or any MCP client can now read, edit and publish pages on your site, signed in as a real user and limited to that user's permissions. Around it, permission rules that used to live only in the builder interface are enforced on the server for every caller, revision restore becomes selective and attributed, and Tailwind v3 support is retired.

Read the breaking group before upgrading. One import path moves, one Tailwind version goes, and some roles may lose SEO write access through the API.

Breaking

  • Tailwind CSS v3 is no longer supported. The chaipro/tailwind/v3 entry point is removed, CHAI_TAILWIND_VERSION is ignored, the tailwindcss peer is now ^4.0.0, and autoprefixer is no longer a peer dependency. Projects still on a v3 config need to migrate first. See Theming. Persisted page styles recompile once after the upgrade, so the first render of each page is slower than usual.
  • ChaiAnimationProvider moves to its own entry point. Import it from chaipro/plugins/animation/render instead of chaipro/nextjs/render-client, and import its stylesheet once from chaipro/plugins/animation/render.css. The old import fails at build time.
  • SEO writes require pages:edit_seo on the server. Saving a page's SEO fields, its JSON-LD or its shared JSON-LD now needs pages:edit_seo in addition to pages:update, for every caller: the builder, the HTTP API, the instance API and MCP. The rule used to be checked only in the builder interface, so API callers could bypass it. pages:* and * satisfy both, so the default roles are unaffected. A custom role with pages:update but not pages:edit_seo that writes SEO through the API will now be refused.
  • Restoring a revision requires page permissions too. revisions:restore is no longer enough on its own: a restore also needs pages:update, plus pages:edit_seo when it restores SEO or JSON-LD. A restore writes the same fields a save does, so it now needs the same rights.

Added

  • A built-in MCP server. Register mcpPlugin from chaipro/plugins/server and mount one route with createChaiMcpRouteHandlers from chaipro/mcp, and an MCP client can work on your site through 33 tools covering page discovery and management, block reads and edits, SEO, publishing, revisions, translations, image upload, redirects and edit sessions. The plugin is opt in and is not part of the Pro preset, because it exposes an agent driven write surface. It needs @modelcontextprotocol/sdk installed, a new optional peer dependency (>=1.26.0 <2). See MCP Server Setup.
  • An mcp:use permission gates the MCP surface as a whole, separately from the per tool permissions, so an account can edit in the builder without being allowed to drive an agent. Editors and designers get it by default, viewers do not. Tools the caller lacks permission for are hidden from the tool list and refused if called anyway.
  • The tool set adapts to your config. Revision tools appear only with the revisions plugin, image upload only with a media backend, and edit session tools only with the AI plugin. mcpPlugin takes previewUrl to build preview links against your own preview route, getLivePageEditors to tell agents when a person has a page open, and excludeInstructionSections to drop built-in agent instructions you want to replace.
  • Custom MCP tools. Apps and plugins register their own tools and agent instructions through the same API the built-in ones use. See MCP Custom Tools.
  • Payload API keys authenticate builder requests. A headless caller such as an MCP client, a script or CI can send a Payload API key, either as a plain bearer token or in Payload's own header format, and gets the permissions of the user who owns the key. Nothing new is issued or stored. The permissions option now receives authStrategy, so you can treat a machine credential differently from a person's session, for example capping API keys at read only.
  • "AI is editing" status in the builder. When an agent holds an edit session on a page, the builder opens that page read only and shows who is editing, since when, their last activity and last action, with a Check now button. When the session ends, the page reloads without saving. A person who already has the page open keeps it: the agent's writes are refused instead. The check is served by aiAdvancedPlugin and displayed by the realtime client plugin.
  • Selective revision restore. The restore dialog offers four parts, blocks, SEO, tracking and JSON-LD, with blocks only selected by default. Rolling back an AI SEO edit no longer requires restoring the page body too. The restore itself is recorded as a labelled revision saying what it restored and what it kept, and the snapshot taken before it covers all four parts, so undoing a restore brings everything back. See Revisions.
  • Revisions record where an edit came from: the builder, the settings panel, an MCP agent or a service account. Bulk writes from the settings panel get their own revision rows instead of merging into your open builder draft.
  • A data provider can return a 404. A page type data provider can return $notFound: true when no item matches the URL, and the dynamic route responds with a 404 instead of an empty page served as 200. Cache tags are still registered, so publishing the item later brings the route to life. The Payload collection provider does this out of the box. See Data Providers.
  • New pages get your default shared JSON-LD. Shared schemas flagged to be added to new pages are attached on create for every caller, not only the builder. Language pages, partials and folders are skipped.
  • Favicon and markdown uploads. The media manager accepts .ico and .md files.
  • Children override props. A block config can declare childrenOverrideProps, the props it stops rendering once it has children. The settings panel hides those fields while the block has a child, instead of offering edits that never reach the page. Heading, Span, Paragraph, ListItem, Link and Button declare it for content, and Button for its icon props too. Stored values are kept, so removing the children brings the field back. See Custom Blocks.
  • Two plugin API seams. Server plugins can read an incoming request header with getChaiRequestHeader(name), and client plugins can add headers to and observe every builder request with registerChaiFetchInterceptor. See Developing Plugins.
  • Binding pickers show collection names instead of collection ids.

Changed

  • Images are served from your origin. The Image block no longer routes through the Next.js image optimizer at /_next/image. The file is served as stored, and next/image is kept only for layout and sizing. On Vercel this removes image optimization usage for ChaiBuilder pages.
  • The revision compare view is rebuilt. It diffs the two versions as structured data, scrolls smoothly on large pages, and follows the builder's light or dark theme. It is side by side only; the Split View toggle is gone.
  • Node.js 22 or later. The package now declares node >=22 in engines. Package managers warn on older versions and fail the install when engine strict mode is on.
  • Faster builder and render path. The builder boots without an artificial delay, save state no longer re-renders on every block change, and the top bar re-renders less. On the server, data binding and link resolution no longer deep copy every block, and a memory leak that grew with every styled block is fixed.
  • Saves from any caller now behave the same way. Whether a save creates a draft revision is decided on the server from your revisions config, rather than by a flag the builder happened to send.

Security

  • Revision lookups are scoped to your site. Reading or comparing a revision by id now checks that it belongs to the calling site. This matters most on multi tenant deployments sharing one database.
  • The MCP route authenticates by header only. It ignores browser session cookies, so a signed in browser tab cannot be used to drive it. Request bodies are size capped before authentication, error responses never include internal details such as connection strings or SQL, and audit arguments are truncated with secrets redacted.
  • Server side SEO and restore permissions, described under Breaking above, close paths that let API callers change titles, canonicals, noindex and JSON-LD without pages:edit_seo.
  • Extensionless AVIF and HEIF images are rejected instead of being mislabelled and stored as video.

Fixed

  • Block props keep their types after an AI edit. Arrays, objects, booleans and numbers came back from the AI panel, HTML import or an agent edit as strings, so a gallery could crash the page and "false" read as true. Props are restored to the type their schema declares, and a nullable prop saved as "null" comes back as null.
  • AI edits keep block identity. An AI edit replaced a block's internal id, breaking anything that referenced it, and rewrote props the model never touched. Only props that actually changed are updated now.
  • Pending changes are not lost. A save that touched only SEO or tracking cleared the marker left by an earlier block save, so the page stopped showing as having changes to publish. Markers accumulate now, and tracking changes get their own label.
  • Saves from callers other than the builder no longer blank a page's links and design tokens, which also broke revalidation of pages linking to it.
  • Saving right after a restore no longer overwrites the restore's revision row.
  • {{page.*}} bindings resolve correctly on rendered pages: page.slug rendered the full path, and page.path, page.pathWithParams, page.querySeparator and page.basePath were undefined.
  • Sites whose default language is not English link correctly from data providers, sitemaps and feeds. The fallback language is read from site settings instead of being assumed to be English.
  • Newly picked gallery images render at their real size instead of 100x100.
  • Uploads with # or ? in the file name, such as Capture #3.png, are accepted, and so are large PNGs the media manager converts to JPEG before upload.
  • Unpublished drafts no longer appear in Payload backed repeaters.
  • Removing a redirect asks for confirmation.
  • Activity in settings screens such as custom blocks, the translation center and revisions is attributed to the right user again.
  • Builder menus, selects, popovers and tooltips keep their positioning and height limits under Tailwind v4.
  • The fetchpriority attribute on blocks reaches the rendered page.
  • The chaipro/plugins/plans/client entry point is published. The plans client plugin from v0.3.0 had no import path until now.

Removed

  • The chaipro/tailwind/v3 entry point, the CHAI_TAILWIND_VERSION setting and the autoprefixer peer dependency.
  • ChaiAnimationProvider from chaipro/nextjs/render-client.
  • The Split View toggle in the revision compare view.

Upgrade notes

  1. Move to Tailwind v4 if you have not already, then remove CHAI_TAILWIND_VERSION from your environment and autoprefixer from your dependencies if nothing else uses it.
  2. Update the animation import. Import ChaiAnimationProvider from chaipro/plugins/animation/render and add import 'chaipro/plugins/animation/render.css' once in your layout.
  3. Check custom roles. Any role that writes SEO through the API needs pages:edit_seo, and any role that restores revisions needs pages:update as well as revisions:restore.
  4. Run your database migrations. aiAdvancedPlugin contributes a new ai_page_edits table that holds agent edit sessions. Generate and apply migrations as usual; see Database Setup.
  5. Check your Node version. Build and runtime should be on Node 22 or later.
  6. Dynamic pages backed by Payload collections now 404 for URLs with no matching document. If you relied on the empty page rendering, handle the missing item yourself.
  7. MCP is opt in. Nothing changes until you register mcpPlugin and mount the route. Follow MCP Server Setup when you are ready.

© ChaiBuilder. All rights reserved.