{"slug": "craft-cms-5-12-0-added-an-authenticated-http-mcp-server", "title": "Craft CMS 5.12.0: Added an authenticated HTTP MCP server", "summary": "Craft CMS 5.12.0 added an authenticated HTTP MCP server that MCP clients can connect to after a user signs in and authorizes them via OAuth, with clients acting as that user within their permissions and a granted access level of read only, read and write, or full access for admins. The release also adds a public HTTP MCP server exposing only capabilities and content approved from Settings → MCP, discoverable via /.well-known/ai-catalog.json and a Server Card at <endpoint>/server-card per SEP-2127, plus an OAuth authorization server with PKCE and refresh token rotation and a My Account → Tokens screen for managing personal access tokens and authorized MCP clients. Dynamic OAuth client registration is limited to 10 clients per IP address per hour by default via the new registrationRateLimit and registrationRateLimitDuration settings.", "body_md": "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\n\nAdded 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)\n\nThe 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)\n\nAdded 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)\n\nThe 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)\n\nAdded the mcp/serve command, which runs a stdio MCP server acting as a given user. (#20145)\n\nAdded 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)\n\nAdded support for config/mcp.php and config/oauth.php config files. (#20145)\n\nAdded the oauth/generate-keys command, which generates the keys used to sign OAuth access tokens. (#20145)\n\nAdded an OAuth authorization server, with discovery metadata, dynamic client registration, PKCE, and refresh token rotation, which the MCP servers and GraphQL API use. (#20145)\n\nDynamic 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)\n\nGarbage collection now deletes expired and revoked OAuth authorization codes and tokens, and registered OAuth clients that were revoked or never authorized. (#20303)\n\nPlugins 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)\n\nPlain Text, Email, Link, Number, Money, Lightswitch, Date, Time, Color, Country, Table, and option fields now implement craft\\base\\InputSchemaFieldInterface. (#20145)\n\nPersonal Access Tokens\n\nAdded 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)\n\nMCP clients that users have authorized are listed on their My Account → Tokens screen, where they can be revoked. (#20291)\n\nGraphQL API requests can now be authenticated with OAuth access tokens, granting access to the content the authorizing user has permission to access. (#20147)\n\nGraphQL schema components can now support authenticated requests via an authenticated key on their config. (#20147)\n\nAdded the currentUser GraphQL query, which returns the user that authenticated the request. (#20147)\n\nGraphQL schemas can now include read-only components for sites, sections, entry types, volumes, user groups, category groups, and tag groups. (#20055)\n\nAdded 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)\n\nElements now have site fields in GraphQL, when the schema includes the “Query for sites” component. (#20055)\n\nEntries now have section and type fields in GraphQL, when the schema includes the “Query for sections” and “Query for entry types” components. (#20055)\n\nAssets now have volume fields in GraphQL, when the schema includes the “Query for volumes” component. (#20055)\n\nUsers now have groups fields in GraphQL, when the schema includes the “Query for user groups” component. (#20055)\n\nCategories and tags now have group fields in GraphQL, when the schema includes the “Query for category groups” and “Query for tag groups” components. (#20055)\n\nElement 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)\n\nElement editor slideouts can now be switched to other sites, by clicking on a site name within the “Sites” pane. (#20061)\n\nSites that are added to elements within the “Sites” pane can now be removed again. (#20061)\n\nElement edit pages’ sidebar pane headings now line up with the labels within the panes. (#20061)\n\nDeleting an element for the only site it exists in now soft-deletes it, unless it’s a draft or nested element. (#20060)\n\nelements/save-draft action responses now include a canDeleteForSite key. (#20061)\n\nAssets\n\nAssets are now initially saved to the site they were uploaded from. (#20060)\n\nVolumes 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)\n\nAssets 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)\n\nAssets 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)\n\nFiles can now be uploaded to Assets fields by pasting them from the clipboard while the field has focus. (#20183, #20212)\n\nAdded 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.\n\nBMP images can now be transformed and edited in the Image Editor.\n\nCraft can now determine the dimensions of BMP and JPEG XL images on remote volumes without downloading them.\n\nAdded 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)\n\nCraft.BaseUploader now supports a pasteZone setting. Files pasted while focus is within it are passed to addFiles(), which custom uploader classes must implement to support pasted files. (#20183, #20212)\n\ncraft\\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)\n\nAddresses\n\nAddresses 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)\n\nAddresses now support drafts.\n\nColor Fields\n\nColor 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)\n\nColor 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)\n\nColor fields now have an “Allow opacity for custom colors” setting. (#8983, #20274)\n\nColor 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)\n\nColor 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)\n\nColor field values now have alpha, rgba, hsla, rgbChannels, oklch, and contrastColor properties, and a contrastRatio() method. (#8983, #20274)\n\nColor 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)\n\ncraft\\fields\\data\\ColorData::getHex() now has a $withAlpha argument, which defaults to true. (#8983, #20274)\n\ncraft\\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)\n\nIcon Fields\n\nIcon pickers can now include icons from custom icon sets. (#17101, #20277)\n\nIcon 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)\n\nAdded 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)\n\nIcon 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)\n\nIcons selected from custom icon sets are stored as set-handle:icon-name. (#17101, #20277)\n\nIconData GraphQL objects now have set, svg, and keywords fields. (#17101, #20277)\n\nIcon field values now have getSvg() and getKeywords() methods. (#17101, #20277)\n\nPlugins can register custom icon sets via craft\\services\\Icons::EVENT_REGISTER_ICON_SETS. (#17101, #20277)\n\ncraft\\helpers\\Cp::iconSvg() now supports set-handle:icon-name values. (#17101, #20277)\n\nCraft.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)\n\nCustom Fields\n\nCustom fields now have “Default Tip” and “Default Warning” settings. (#19976)\n\nIlluminate\\Support\\Collection now has a render() macro, which replaces craft\\elements\\ElementCollection::render(). (#19988)\n\ncraft\\helpers\\ElementHelper::normalizeSlug() now has a $language argument, which defaults to the current application language. (#19558)\n\ncraft\\helpers\\StringHelper::toLowerCase(), ::toTitleCase(), and ::toUpperCase() now have $language arguments, which default to the current application language. (#19558)\n\nDeprecated craft\\helpers\\ElementHelper::renderElements(). craft\\helpers\\Template::render() should be used instead. (#19988)\n\nControl Panel\n\nThe global Settings page now has an “Extend” section, which contains Plugins and MCP.\n\nAssets settings are now in the “Content” section of the global Settings page, and the “Media” section has been removed.\n\nFilesystem settings are now within Assets settings, at Settings → Assets → Filesystems.\n\nQueue jobs’ Job Data is now syntax-highlighted in the Queue Manager utility.\n\nThe Project Config utility’s “Loaded Project Config Data” is now syntax-highlighted.\n\nAsset previews and the Project Config utility now use TanStack Highlight for syntax highlighting, rather than Prism. (#20088)\n\nDeprecated 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)\n\nSecurity\n\nA rate limit is now enforced for users/login, auth/verify-totp, and auth/verify-recovery-code requests. (#20054)\n\nAdded 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)\n\nRemoved support for the non-standard ED256 passkey algorithm. (#19701)\n\nUploaded file names and search keywords no longer retain bidirectional override characters and other invisible characters.\n\ncraft\\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.\n\nFixed a moderate-severity information disclosure vulnerability. (GHSA-hgwm-4xxx-w8jq)\n\nFixed a moderate-severity authorization bypass vulnerability. (GHSA-vvm6-wrc8-5fgh)\n\nPerformance\n\nSaving nested elements on multi-site installs now executes fewer database queries. (#20090)\n\nSearch indexing now executes fewer database queries. (#20090)\n\nUser permission checks are now faster for users with many permissions. (#20149)\n\nOther Changes\n\nAdded the project-config/check command, which checks project config schema compatibility without applying changes.\n\nMySQL 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)\n\nMySQL database backups and restores now respect the PDO::MYSQL_ATTR_SSL_CAPATH and PDO::MYSQL_ATTR_SSL_CIPHER database connection attributes. (#19366)\n\nElement fixtures no longer create revisions by default. Set their createRevisions property to true to retain the previous behavior. (#19626)\n\nFixed a bug where entry and address indexes weren’t showing any results if they had a “Field” condition rule set to “is empty”.\n\nFixed a bug where craft\\services\\Elements::deleteElementsForSite() would remove elements’ site rows without deleting the elements, on single-site installs. (#20060)\n\nFixed 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)\n\nFixed a bug where deleting an element for a site while editing a provisional draft would delete the provisional draft for all sites. (#20061)\n\nFixed 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)\n\nFixed 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)\n\nFixed a bug where batched queue jobs weren’t splitting into additional batches before reaching their time limits. (#20304)\n\nFixed an error that occurred when passing withProvisionalDrafts to a Matrix field via GraphQL. (#20308)\n\nFixed a bug where users who logged into the control panel with “Remember me” checked could get logged out after an hour of inactivity.\n\nFixed a bug where default titles of assets with long filenames were taken from the end of the filename. (#20112)\n\nFixed 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)\n\nFixed a bug where the fields/merge and fields/auto-merge commands weren’t updating field condition rules that referenced the merged fields. (#19901)\n\nFixed a bug where the fields/merge and fields/auto-merge commands weren’t updating Content Block fields’ layouts. (#19901)\n\nFixed a bug where curly quotes were allowed within asset folder and filenames. (#19904)\n\nFixed a bug where the “Instructions” setting’s placeholder text wasn’t getting updated when changing a field layout element’s selected field.\n\nFixed a bug where renaming an asset without including its file extension resulted in a validation error. (#19950)\n\nFixed a bug where the Image Editor’s crop box couldn’t be resized in some cases. (#19980)\n\nFixed an error that occurred when opening element selector modals on element edit pages with a returnUrl param. (#19983)\n\nFixed a bug where orderBy criteria wasn’t getting applied to eager-loaded elements. (#19994)\n\nFixed a bug where orderBy, offset, and limit params weren’t getting applied to element queries executed via eagerly(). (#19994)\n\nFixed a bug where eager-loaded elements were getting reversed twice when both orderBy and inReverse criteria were set. (#19994)\n\nFixed a bug where skipped revisions were getting reported as root element lookup errors when resaving elements. (#20026)\n\nFixed a bug where pruning revisions could delete nested element revisions in other sites that newer revisions still referenced. (#20042)\n\nFixed a bug where “Save as a new draft” didn’t carry nested entries over to the new draft. (#20226)\n\nFixed an error that occurred when logging in with a passkey that was registered with an older version of Craft. (#20052)\n\nFixed a bug where closing an element selector modal while it was loading caused it to keep loading all of the source’s elements in the background. (#20100)\n\nFixed a bug where moving assets and replacing existing files with the same name could fail. (#20128)\n\nFixed 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)\n\nFixed 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)", "url": "https://wpnews.pro/news/craft-cms-5-12-0-added-an-authenticated-http-mcp-server", "canonical_source": "https://github.com/craftcms/cms/releases/tag/5.12.0", "published_at": "2026-11-03 23:38:08+00:00", "updated_at": "2026-11-03 23:50:15.057646+00:00", "lang": "en", "topics": ["ai-agents", "agent-protocols", "developer-tools", "artificial-intelligence"], "entities": ["Craft CMS", "Craft CMS 5.12.0", "SEP-2127", "GraphQL", "OAuth"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/craft-cms-5-12-0-added-an-authenticated-http-mcp-server", "markdown": "https://wpnews.pro/news/craft-cms-5-12-0-added-an-authenticated-http-mcp-server.md", "text": "https://wpnews.pro/news/craft-cms-5-12-0-added-an-authenticated-http-mcp-server.txt", "jsonld": "https://wpnews.pro/news/craft-cms-5-12-0-added-an-authenticated-http-mcp-server.jsonld"}}