Repository navigation
v3.2.0 — Editors as first-class MCP users
Five pull requests from @JorisOrangeStudio, all found while giving a hotel's editors MCP
access on a production site. That is the setup this server had seen least: a user who
may write content but configures nothing.
Added
-
Scopes follow permissions (#63) — The dashboard, token creation and the OAuth consent screen offered all 21 scopes to every user,
*included. Each call was already capped by the user's Statamic permissions, so the extra scopes granted nothing, but they misled. The first thing an editor asked on the consent screen was why Claude wanted to write users. Each of those surfaces now offers only the scopes the user can exercise, derived from the permissions the routers check.*,system:writeand the content-facade scopes are for super admins. A domain the site has closed (tool switched off, or a[]resource allowlist) is offered to nobody.- Creating a token with a scope the user cannot hold returns a 422 naming it.
- Editing a token is capped by the token's owner, and only added scopes are checked. Tokens minted before 3.2 keep the scopes they have and can still be renamed.
- An OAuth client asking for
*on behalf of an editor is offered the editor's own scopes rather than refused.
Set
STATAMIC_MCP_SCOPES_FOLLOW_PERMISSIONS=falseto offer every scope again. Access is the same either way. -
Editors can read the blueprints they write against (#62) —
statamic-blueprintsrequiredconfigure fieldsfor every action, reads included, while the server's own instructions tell an agent to read the blueprint before writing an entry. A token minted for an editor could write entries but could not see their fields. The read actions (list,get,scan,types,validate) now follow the rule thestatamic://blueprintsresources got in 3.1.0: anyconfigurepermission, or none whenresources.require_statamic_permissionis off. Writes still requireconfigure fields.
Fixed
-
Updates no longer fail on stored nulls in fields they do not touch (#59) —
updatevalidates the stored record merged with the incoming data, and counted a storednullas a value. Statamic only runs a field's non-required rules when the key is present, so a null in Advanced SEO'sseo_canonical_entry(required_ifplusarray) failed an update that only changed the title, with "The Entry field must be an array". Records carry such nulls routinely: a Control Panel save leaves them in the Stache, localizations keep them on disk, andcreatewrote one per untouched field. Entries, terms and globals now leave stored nulls out of validation, andcreatestores only the fields it was given. A null the caller sends is still validated, andrequired_ifstill fires. -
Entry writes name the user behind the token (#61) — Statamic's revision methods take the user as an option and never fall back to the logged-in one, and
updateLastModified(null)removesupdated_by. So MCP revisions had no author, and an MCP publish erased the entry's last editor. Every entry write now passes the token's user, as the Control Panel does. The local stdio server has no user, so nothing is stamped or removed there. -
Refused calls are logged as errors (#60) — Routers report a validation failure, a missing record or a denied resource as an error response rather than an exception, and the audit log recorded every call that did not throw as
success. Filtering the Activity tab on errors missed all of them. Existing log lines are not rewritten. -
The configuration reference listed
*as the OAuth default scope. It has been every:readscope since 2.1.0.
Dependencies
league/commonmark2.10.3 — 2.10.0 through 2.10.1 are affected by GHSA-3q6v-r5mr-hxv8 (high: quadratic-time table parsing) and GHSA-97jj-33gv-5xf9. It reaches your site throughstatamic/cms, so this package's constraints do not pin it — runcomposer update league/commonmarkto pick up the fix. The SBOM now records 2.10.3.
Full changelog: v3.1.0...v3.2.0