You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Added an authenticated HTTP MCP server, which MCP clients can connect to after a user signs in and authorizes them via OAuth. Clients act as that user, within their permissions and the access level they grant (read only, read and write, or full access for admins). (#20145, #20189)
The authenticated MCP server’s endpoints default to /{cpTrigger}/mcp and /{cpTrigger}/mcp/auth, or /mcp and /mcp/auth when public registration is enabled. Endpoints within the control panel can only be used by users with control panel access. (#20189)
Added a public HTTP MCP server, which exposes only the capabilities and content approved from Settings → MCP, without signing in. Its endpoint defaults to /mcp. (#20145, #20189)
The HTTP MCP servers are discoverable via /.well-known/ai-catalog.json and a Server Card at <endpoint>/server-card, per SEP-2127. Servers on control panel URLs are never advertised, and the authenticated server is only advertised when public registration is enabled. (#20283)
Added the mcp/serve command, which runs a stdio MCP server acting as a given user. (#20145)
Added Settings → MCP, where administrators can enable the authenticated and public MCP servers, set their endpoints, and approve the capabilities and content that the public server exposes. (#20145, #20189)
Added support for config/mcp.php and config/oauth.php config files. (#20145)
Added the oauth/generate-keys command, which generates the keys used to sign OAuth access tokens. (#20145)
Added an OAuth authorization server, with discovery metadata, dynamic client registration, PKCE, and refresh token rotation, which the MCP servers and GraphQL API use. (#20145)
Dynamic OAuth client registration is limited to 10 clients per IP address per hour by default, via the new registrationRateLimit and registrationRateLimitDuration OAuth config settings. (#20303)
Garbage collection now deletes expired and revoked OAuth authorization codes and tokens, and registered OAuth clients that were revoked or never authorized. (#20303)
Plugins can register MCP capabilities via craft\services\Mcp::EVENT_REGISTER_CAPABILITY_TYPES, OAuth resources via craft\services\OAuth::EVENT_REGISTER_RESOURCES, and personal access token scopes via craft\services\PersonalAccessTokens::registerScopeGroup(). (#20145, #20147)
Plain Text, Email, Link, Number, Money, Lightswitch, Date, Time, Color, Country, Table, and option fields now implement craft\base\InputSchemaFieldInterface. (#20145)
Personal Access Tokens
Added the My Account → Tokens screen, where users can create personal access tokens for the APIs that offer them (such as the GraphQL API), rename them, and revoke tokens and the apps they’ve authorized. (#20147)
MCP clients that users have authorized are listed on their My Account → Tokens screen, where they can be revoked. (#20291)
GraphQL API requests can now be authenticated with OAuth access tokens, granting access to the content the authorizing user has permission to access. (#20147)
GraphQL schema components can now support authenticated requests via an authenticated key on their config. (#20147)
Added the currentUser GraphQL query, which returns the user that authenticated the request. (#20147)
GraphQL schemas can now include read-only components for sites, sections, entry types, volumes, user groups, category groups, and tag groups. (#20055)
Added the sites, site, sections, section, entryTypes, entryType, volumes, volume, userGroups, userGroup, categoryGroups, categoryGroup, tagGroups, and tagGroup GraphQL queries, which are available when the schema includes the corresponding components. (#20055)
Elements now have site fields in GraphQL, when the schema includes the “Query for sites” component. (#20055)
Entries now have section and type fields in GraphQL, when the schema includes the “Query for sections” and “Query for entry types” components. (#20055)
Assets now have volume fields in GraphQL, when the schema includes the “Query for volumes” component. (#20055)
Users now have groups fields in GraphQL, when the schema includes the “Query for user groups” component. (#20055)
Categories and tags now have group fields in GraphQL, when the schema includes the “Query for category groups” and “Query for tag groups” components. (#20055)
Element edit pages now have a “Sites” pane in their sidebars on multi-site installs, in place of the “Status” pane, which lists the sites the element is saved to (that the user can edit), with status toggles and links to the element in each site, and lets authors add the element to other sites. (#20061)
Element editor slideouts can now be switched to other sites, by clicking on a site name within the “Sites” pane. (#20061)
Sites that are added to elements within the “Sites” pane can now be removed again. (#20061)
Element edit pages’ sidebar pane headings now line up with the labels within the panes. (#20061)
Deleting an element for the only site it exists in now soft-deletes it, unless it’s a draft or nested element. (#20060)
elements/save-draft action responses now include a canDeleteForSite key. (#20061)
Assets
Assets are now initially saved to the site they were uploaded from. (#20060)
Volumes now have a “Propagation Method” setting, which can be set to “Let each asset choose which sites it should be saved to”. New volumes default to this, as do existing volumes on single-site installs. Existing volumes on multi-site installs continue to save assets to all sites. (#20060)
Assets in volumes set to let each asset choose which sites it should be saved to now have a “Sites” pane in their edit pages’ sidebars. (#20060)
Assets in volumes set to let each asset choose which sites it should be saved to can now be deleted for individual sites, as long as they exist in another site. (#20060)
Files can now be uploaded to Assets fields by pasting them from the clipboard while the field has focus. (#20183, #20212)
Added support for JPEG XL (.jxl) images, when ImageMagick supports it. JPEG XL images can now be uploaded, transformed, and set as a transform’s output format.
BMP images can now be transformed and edited in the Image Editor.
Craft can now determine the dimensions of BMP and JPEG XL images on remote volumes without down them.
Added the “Markdown” file kind, and md and markdown are now included in the default allowedFileExtensions config setting value. Markdown files can be previewed with syntax highlighting. (#20089)
Craft.BaseUp now supports a pasteZone setting. Files pasted while focus is within it are passed to addFiles(), which custom up classes must implement to support pasted files. (#20183, #20212)
craft\services\Assets::getAssetById() now returns the asset in another site if it doesn’t exist in the current site, when no site ID is passed. (#20060)
Addresses
Addresses within Addresses fields can now be edited from drafts of their owner elements, by users who can save the drafts but not the canonical owner elements. (#19881)
Addresses now support drafts.
Color Fields
Color fields now support translucent colors. Authors can choose translucent palette colors, and set custom colors’ opacity when the field allows it, via the color picker in browsers that support it or by entering an 8-digit hex value. (#8983, #20274)
Color fields’ palette colors can now have an alpha channel, by entering an 8-digit hex value or via the color picker in browsers that support it. (#8983, #20274)
Color fields now have an “Allow opacity for custom colors” setting. (#8983, #20274)
Color fields now have a “GraphQL Mode” setting, which can be set to “Full data” or “Hex only”. New Color fields default to “Full data”, and existing Color fields default to “Hex only”. (#8983, #20274)
Color field values’ hex properties and GraphQL values now include an alpha channel (e.g. #0000ff80) when the color isn’t fully opaque. Fully-opaque colors are still output as 6-digit hex values. (#8983, #20274)
Color field values now have alpha, rgba, hsla, rgbChannels, oklch, and contrastColor properties, and a contrastRatio() method. (#8983, #20274)
Color fields set to the “Full data” GraphQL mode now return objects with hex, label, red, green, blue, alpha, hue, saturation, lightness, luma, rgb, rgba, rgbChannels, hsl, hsla, oklch, contrastColor, and contrastRatio fields. (#8983, #20274)
craft\fields\data\ColorData::getHex() now has a $withAlpha argument, which defaults to true. (#8983, #20274)
craft\validators\ColorValidator::normalizeColor() now expands 4-digit hex values to 8 digits, and removes fully-opaque alpha channels from 8-digit hex values. (#8983, #20274)
Icon Fields
Icon pickers can now include icons from custom icon sets. (#17101, #20277)
Icon fields now have an “Icon Sets” setting, when any custom icon sets are registered, which determines which icon sets are selectable and in what order. (#17101, #20277)
Added the customIconPath config setting, which registers a “Custom” icon set made up of the SVG files within a directory, such as @config/icons. (#17101, #20277)
Icon field values now have a set property, set to the handle of the custom icon set the icon was selected from (or null for Font Awesome icons). (#17101, #20277)
Icons selected from custom icon sets are stored as set-handle:icon-name. (#17101, #20277) IconData GraphQL objects now have set, svg, and keywords fields. (#17101, #20277)
Icon field values now have getSvg() and getKeywords() methods. (#17101, #20277) Plugins can register custom icon sets via craft\services\Icons::EVENT_REGISTER_ICON_SETS. (#17101, #20277)
craft\helpers\Cp::iconSvg() now supports set-handle:icon-name values. (#17101, #20277) Craft.IconPicker now supports a sets setting, which can be set to an array of icon set handles (fontawesome for Font Awesome), or '*' for all icon sets. (#17101, #20277)
Custom Fields
Custom fields now have “Default Tip” and “Default Warning” settings. (#19976)
Illuminate\Support\Collection now has a render() macro, which replaces craft\elements\ElementCollection::render(). (#19988) craft\helpers\ElementHelper::normalizeSlug() now has a $language argument, which defaults to the current application language. (#19558)
craft\helpers\StringHelper::toLowerCase(), ::toTitleCase(), and ::toUpperCase() now have $language arguments, which default to the current application language. (#19558)
Deprecated craft\helpers\ElementHelper::renderElements(). craft\helpers\Template::render() should be used instead. (#19988)
Control Panel
The global Settings page now has an “Extend” section, which contains Plugins and MCP.
Assets settings are now in the “Content” section of the global Settings page, and the “Media” section has been removed.
Filesystem settings are now within Assets settings, at Settings → Assets → Filesystems.
Queue jobs’ Job Data is now syntax-highlighted in the Queue Manager utility.
The Project Config utility’s “Loaded Project Config Data” is now syntax-highlighted.
Asset previews and the Project Config utility now use TanStack Highlight for syntax highlighting, rather than Prism. (#20088)
Deprecated craft\web\assets\prismjs\PrismJsAsset. craft\web\assets\highlight\HighlightAsset should be used instead. PrismJsAsset now registers a Prism shim backed by TanStack Highlight, which supports Prism’s commonly-used APIs, but not grammar customization, hooks, or plugins. (#20088)
Security
A rate limit is now enforced for users/login, auth/verify-totp, and auth/verify-recovery-code requests. (#20054)
Added the defaultRateLimit and defaultRateLimitDuration config settings, which configure the rate limits for users/login, users/send-password-reset-email, auth/verify-totp, and auth/verify-recovery-code requests. (#20054)
Removed support for the non-standard ED256 passkey algorithm. (#19701)
Uploaded file names and search keywords no longer retain bidirectional override characters and other invisible characters.
craft\helpers\StringHelper::invisibleCharsRegex() now also matches bidirectional embedding, override, and isolate characters; non-whitespace control characters; the word joiner, function application, combining grapheme joiner, and Mongolian vowel separator characters; and blank Hangul filler and braille characters.
Fixed a moderate-severity information disclosure vulnerability. (GHSA-hgwm-4xxx-w8jq)
Fixed a moderate-severity authorization bypass vulnerability. (GHSA-vvm6-wrc8-5fgh)
Performance
Saving nested elements on multi-site installs now executes fewer database queries. (#20090)
Search indexing now executes fewer database queries. (#20090)
User permission checks are now faster for users with many permissions. (#20149)
Other Changes
Added the project-config/check command, which checks project config schema compatibility without applying changes.
MySQL database backups and restores now carry over SSL/TLS settings from the system’s MySQL option files (e.g. ssl-ca or disable-ssl-verify-server-cert), if the database connection doesn’t have any PDO::MYSQL_ATTR_SSL_* attributes set. (#19366)
MySQL database backups and restores now respect the PDO::MYSQL_ATTR_SSL_CAPATH and PDO::MYSQL_ATTR_SSL_CIPHER database connection attributes. (#19366)
Element fixtures no longer create revisions by default. Set their createRevisions property to true to retain the previous behavior. (#19626)
Fixed a bug where entry and address indexes weren’t showing any results if they had a “Field” condition rule set to “is empty”.
Fixed a bug where craft\services\Elements::deleteElementsForSite() would remove elements’ site rows without deleting the elements, on single-site installs. (#20060)
Fixed a bug where saving a deeply-nested element on its own wouldn’t update its owners’ dateUpdated timestamps, which could cause new revisions to reuse stale nested content. (#19594)
Fixed a bug where deleting an element for a site while editing a provisional draft would delete the provisional draft for all sites. (#20061)
Fixed a bug where DSNs set via database config arrays weren’t getting parsed, so MySQL’s utf8 charset wasn’t getting normalized to utf8mb4. (#20248)
Fixed a bug where craft\i18n\Locale::getOrientation() was returning ltr for some right-to-left locales, such as Central Kurdish (ckb) and Punjabi in Arabic script (pa-Arab). (#20301) Fixed a bug where batched queue jobs weren’t splitting into additional batches before reaching their time limits. (#20304)
Fixed an error that occurred when passing withProvisionalDrafts to a Matrix field via GraphQL. (#20308)
Fixed a bug where users who logged into the control panel with “Remember me” checked could get logged out after an hour of inactivity.
Fixed a bug where default titles of assets with long filenames were taken from the end of the filename. (#20112)
Fixed a bug where characters were stripped from text that wasn’t UTF-8 when it was converted to UTF-8, such as alt text read from images’ IPTC captions. (#20111)
Fixed a bug where the fields/merge and fields/auto-merge commands weren’t updating field condition rules that referenced the merged fields. (#19901)
Fixed a bug where the fields/merge and fields/auto-merge commands weren’t updating Content Block fields’ layouts. (#19901)
Fixed a bug where curly quotes were allowed within asset folder and filenames. (#19904)
Fixed a bug where the “Instructions” setting’s placeholder text wasn’t getting updated when changing a field layout element’s selected field.
Fixed a bug where renaming an asset without including its file extension resulted in a validation error. (#19950)
Fixed a bug where the Image Editor’s crop box couldn’t be resized in some cases. (#19980)
Fixed an error that occurred when opening element selector modals on element edit pages with a returnUrl param. (#19983)
Fixed a bug where orderBy criteria wasn’t getting applied to eager-loaded elements. (#19994)
Fixed a bug where orderBy, offset, and limit params weren’t getting applied to element queries executed via eagerly(). (#19994)
Fixed a bug where eager-loaded elements were getting reversed twice when both orderBy and inReverse criteria were set. (#19994)
Fixed a bug where skipped revisions were getting reported as root element lookup errors when resaving elements. (#20026)
Fixed a bug where pruning revisions could delete nested element revisions in other sites that newer revisions still referenced. (#20042)
Fixed a bug where “Save as a new draft” didn’t carry nested entries over to the new draft. (#20226)
Fixed an error that occurred when logging in with a passkey that was registered with an older version of Craft. (#20052)
Fixed a bug where closing an element selector modal while it was caused it to keep all of the source’s elements in the background. (#20100)
Fixed a bug where moving assets and replacing existing files with the same name could fail. (#20128)
Fixed a bug where nested entries added via drafts on multi-site installs could get an incomplete first revision, causing their nested content to be deleted when reverting to it. (#20151)
Fixed a bug where nested entries owned by drafts could get their own revisions, which could cause a foreign key error when applying the draft on PostgreSQL. (#20151)