2.10.0
September 10th, 2026
Minor release. New entry, blueprint and extensibility features, two format-spec fixes, and a quadratic write path in the file token store made linear.
One behaviour change to be aware of on upgrade — see the note under reject_unknown_fields.
Added
localize action on statamic-entries (#48) — Creates an entry's localization in another site through Statamic's makeLocalization(), so the origin is set and untranslated fields keep falling back to it. Only the fields actually sent are stored; writing an explicit null for every untouched field would defeat that fallback. Gated as a write action throughout: entries:write, a write-mode resource policy check, and the create {collection} entries permission.
merge_sets on statamic-entries update (#47) — Merges a top-level replicator field into the stored array by item id rather than replacing it, so changing one section of a page builder no longer means resending every other. Opt-in, off by default.
field path on statamic-blueprints get (#51) — Scopes the response to one field or set with a dot path (page_builder.ContentSection.media). A page builder's format spec is proportional to every set it can hold, so on a real blueprint the full response could not be returned at any useful depth.
FieldtypeExtensions registry (#46) — Lets a site or addon describe the wire format of a fieldtype this package does not ship support for, and coerce or reject incoming values for it. Without a registration nothing changes. See Extending fieldtypes.
Icon field format spec (#43) — Icon names live in the set's directory on disk, not in the blueprint, so icon used to report only "this is a string" and a plausible-looking guess rendered nothing. Sets are now listed once per response rather than inlined per field.
Configurable response size limit (#49) — STATAMIC_MCP_MAX_RESPONSE_SIZE, default unchanged at 100000 bytes, 0 disables.
reject_unknown_fields (#45) — Refuses a write carrying a key that is not a field handle inside a replicator set, grid row, bard set or group. processRow() merges the raw row back over the processed one, so such a key is written to the content file as inert data no template reads — and the write reports success.
This changes write behaviour and is on by default. A caller that has been sending a stray key inside a set was silently writing junk and being told it succeeded; it now gets an error naming the valid handles. That is the point, but it surfaces on upgrade rather than when the junk was written. Set
STATAMIC_MCP_REJECT_UNKNOWN_FIELDS=falseto restore the old behaviour while you fix the caller.The check does not apply at the top level of a record, where non-blueprint keys such as
template,layoutandparentare legitimate.
Fixed
Select options are read in every shape Statamic accepts (#50) — selectSpec() dropped the list of ['key' => ..., 'value' => ...] maps that the Control Panel actually writes, so any select, radio, button_group or checkboxes field configured through the CP reported allowed_values: [].
The link fieldtype spec described references that do not resolve (#44) — It advertised statamic://entry/<uuid>, which is Bard link-mark syntax. ResolveRedirect does not understand it and stores the value verbatim as a dead link. The spec now describes what actually resolves: plain URLs, entry::<id>, asset::<container>::<path> and @child.
pruneExpired() and deleteForUser() were quadratic — Both removed tokens from the hash index one at a time, and each removal re-read, re-encoded and rewrote the whole index under an exclusive lock. Pruning n tokens wrote on the order of n² bytes; at 500 tokens that was megabytes of index writes. Batched into a single locked read-modify-write, roughly halving prune time at 500 tokens.
Thanks
Seven of the nine changes in this release came from @JorisOrangeStudio, including the two format-spec fixes and the silent-corruption case behind reject_unknown_fields.
Full changelog: https://github.com/cboxdk/statamic-mcp/compare/v2.9.1...v2.10.0
2.9.1
September 4th, 2026
Patch release fixing asset field handling. No breaking changes.
Fixed
Asset field values are round-trip safe (#41)
statamic-entries get returns an assets field the way Statamic stores it — a container-relative path, icons/heart.svg. Everything downstream of a Control Panel form submission expects the other form: the canonical container::path asset ID, in a list. So sending a value straight back into create or update failed:
The page_builder cards icon field must be a file of type: svg.
MimesRule resolves the value with Asset::find(), and a bare path finds nothing. On a field with no file rules it would have got further and then broken in Assets::process(), which calls Asset::findOrFail(). It also hit fields the caller never touched, because update validates incoming data merged with the entry's stored data — all paths.
Incoming asset paths now resolve to canonical IDs before validation, covering nested replicator, bard, grid and group fields as well as top-level ones, across entries, terms and globals.
content_validate no longer flags every valid assets field
The read-side sweep ran the blueprint's rules against stored values, so it reported up to three false errors for a perfectly valid single-file assets field — the mimes failure above, plus "must be an array" and "must not have more than 1 items" from the fieldtype's own rules, which expect a list rather than the bare string Statamic stores. The rule pass now sees bridged references; the structural pass still sees stored values verbatim, so a missing_asset finding keeps quoting what is actually on disk.
content_validate resolves single-container asset fields — a field omitting container where the site has exactly one was skipped by the missing-asset check; it now resolves the same way the fieldtype does.
Notes
Values that resolve to no asset are passed through untouched, so validation reports the real problem rather than silently dropping content. Canonical container::path IDs continue to work unchanged.
Thanks to @florianbouvot for the report.
Full changelog: https://github.com/cboxdk/statamic-mcp/compare/v2.9.0...v2.9.1
2.9.0
August 27th, 2026
Added
-
content_validateaction onstatamic-content-facade— Validates content that is already stored against its blueprints. Writes through this addon are validated on the way in; content that arrives another way (git merges, hand-edited YAML, blueprints changed after the content was written) was previously invisible. Each record gets two passes: the blueprint's own validation rules, evaluated the same way a Control Panel save evaluates them, plus structural checks the rule engine cannot express — replicator/bard blocks naming a set that no longer exists, sets and grid rows storing keys the blueprint dropped,select/radio/button_group/checkboxesvalues outside the declared options, assets fields pointing at missing files, and navigation items linking to deleted entries. All of these pass rule validation silently while breaking at render time. Supportsscope,collection/taxonomyfilters,severityfiltering, offset/limit paging across the combined record stream, and amax_findingscap that keeps summary counts accurate when the list is truncated -
ValidatesContentRecordsconcern — The two-pass record validation above, extracted so other routers can reuse it. The rule pass is isolated per record: a malformed stored value that makes a fieldtype's rule builder throw is reported as arule_engine_errorwarning rather than aborting the sweep, and the structural pass still runs to name the underlying shape problem -
MCP resources for blueprints — The server now exposes the
resourcescapability, which it previously left unused.statamic://blueprintslists every readable blueprint with its URI;statamic://blueprints/{namespace}/{handle}returns one blueprint's fields, so a client can look up field structure to shape a write without spending a tool call. BecauseRequireMcpPermissiondefers scope checks to the primitive, resources run the same four gates a router read does — tool enablement, token scope (blueprints:read), resource policy, and Statamic permissions — via a newAuthorizesResourceAccessconcern. Blueprints the resource policy hides are absent from the index, not merely refused on read -
#[Title]on every tool —tools/listhas always carried atitlefield; without the attribute it fell back toStr::headline(class_basename()), so clients displayed "Entries Router". Tools now declare their own display titles -
Typed validation model —
Finding,RecordRef, and theSeverity/FindingType/RecordTypeenums replace thearray<string, mixed>bags the validation sweep threaded through its call chain. Severity is derived from the finding type rather than passed alongside it, so a finding cannot be built with a severity that contradicts what it describes; findings become arrays only at the MCP response boundary -
Testing/InteractsWithMcpandTesting/FakeTransport— Shipped testing helpers for driving this addon's MCP server, dogfooded by the package's own suite. Atests/Fixturescomposition site is included in the PHPStan paths so the traits are analysed where they are actually mixed in — which immediately caught a wrongclass-stringbound in the trait itself -
Supply-chain gate —
bin/check-licenses.phpfails the build on any non-permissive dependency (SPDX dual-licensing handled: a package passes if any arm is permissive), andbin/generate-sbom.phpemits a deterministic CycloneDX 1.5sbom.jsonwith sorted components and a content-derived serial number, so it only changes when dependencies do. Wired into CI along withcomposer audit --no-dev, plus a newcomposer qaaggregate. CI validates the generated document rather than diffing it against the committed one:composer.lockis gitignored because this is a library, so a freshly resolved lock legitimately differs and a drift check would fail whenever any transitive dependency publishes. The license check found one real case:statamic/cmsis proprietary, recorded as a justified exception because a Statamic addon cannot avoid depending on Statamic -
SECURITY.md— Private vulnerability reporting via GitHub, an explicit split between what this addon secures and what the operator does, and a limitations section stating plainly that the audit log is append-only by convention with no hash chain (neither tamper-proof nor tamper-evident), that confirmation tokens are replayable within their window, and thatrequire_httpsfalls back to off when the published config predates the key
Fixed
- The MIT license text actually ships —
composer.jsonhas always declared MIT, but the repository never contained aLICENSEfile, so the grant existed only as metadata. The standard MIT text is now included - Entry updates no longer fail on blueprints with a required slug (#39) — The #27 fix removed the slug from the validated payload entirely, so Statamic's default slug field (
validate: [required, UniqueEntryValue…]) could never be satisfied: every update failed with "The Slug field is required", whether the caller omitted the slug or resent the current one. The entry's effective slug is now injected back into the validation payload, and bothFieldsValidatorinvocations (including theTypeErrorfallback) resolve theUniqueEntryValue({collection}, {id}, {site})placeholders viawithReplacements(), so the rule excludes the entry being updated — the false positive #27 was about — while a slug owned by another entry is still rejected dateno longer has to be resent on every update of a dated collection — Like the slug, the date is an entry property absent from the merged data payload, so a blueprint with a required date field failed any update that did not repeat a date the caller never meant to change. The entry's current date now satisfies the rule when the payload omits it- Explicit slug on create actually works —
createEntry()read$arguments['slug'], but the tool schema never declared the parameter, so no client could send it and the slug was always derived from the title. The schema now declaresslug, and create also accepts it asdata.slug— the shape update uses — storing it as an entry property in both cases, never as a data key - PHPStan level 9 is no longer partly disabled — The config carried blanket
ignoreErrorspatterns (#Method .* should return .* but returns mixed#,#Cannot call method .* on .*\|null#,#Parameter .* expects .*, mixed given#, and four more) that suppressed whole error classes acrosssrc/, so "level 9 clean" meant considerably less than it sounded. Removing them surfaced 54 real errors — almost all method calls onBlueprint|null,Entry|null, orGlobalSet|nullafter a lookup, becauserequireResource()returned an error array without narrowing the variable. Every site now checks for null explicitly (identical messages, identical behaviour, and the analyser can see it), the untyped Statamic/Eloquent return values are narrowed rather than cast, and the four@phpstan-ignoreannotations onabort()calls are gone.requireResource()itself is removed, having no callers left - CI verifies formatting instead of rewriting it — The Tests workflow ran Pint in fix mode, committed the result, and pushed it back to the branch; it now runs
pint --testand fails on violations, matching what the release workflow already does - CI exercises both Laravel majors —
composer.jsonclaims Laravel 12 and 13 viaorchestra/testbench: ^10.0 || ^11.0, but the matrix only varied PHP, so every job resolved testbench 11 and the Laravel 12 claim was never verified. The matrix now spans both. The suite passes on Laravel 12 - Package classes are no longer
final— Nine classes were sealed, blocking consumers from extending or decorating what the package ships - Failed tool calls set the MCP
isErrorflag — Every response was returned viaResponse::structured(), which never marks an error, so a failed call arrived at the client indistinguishable from a successful one; only a model parsing the JSON body would notice"success": false. Failures are now assembled fromResponse::error()plus the same structured content, so both the protocol flag and the full envelope (including confirmation tokens) survive - Plaintext credentials no longer reach stack traces —
TokenService::validateToken()/findByPlainText(),ConfirmationTokenManager's token methods,AuthenticateForMcp::authenticateWithCredentials(), and everyClientConfigGeneratormethod took secrets as plain parameters. In the stdio server,setupErrorHandling()writesgetTraceAsString()to stderr, so a throw anywhere in those call chains logged the bearer token verbatim. All are now marked#[\SensitiveParameter], matching the hardening laravel/mcp applied upstream in v0.9.0 - Server version no longer hardcoded —
StatamicMcpServer::$versionwas the literal'2.8.0'and would have drifted at the next release. It is read from Composer's installed-package metadata, falling back to0.0.0only when that is unavailable - Release workflow no longer hangs — The release job ran
pest --parallel, which is not parallel-safe:Statamic\Testing\AddonTestCasepoints every Stache store, andPreventsSavingStacheItemsToDisk'sdev-nulldirectory, at one sharedtests/__fixtures__path, so ParaTest workers deleted each other's fixtures. This produced ~34 spurious failures or, when workers collided on the file-storeflock()calls, a hang that burned the 6h job timeout (v2.6.1 and v2.8.0 both died this way, and both releases had to be published by hand). The release job now runs the same single-processpestthat gates pull requests, and every job has an explicittimeout-minutesso a hang fails in minutes instead of hours - Release notes are no longer empty — The changelog extraction matched
[v2.8.0]against headings written as[2.8.0], so it never selected anything. The tag'svprefix is now stripped, with a fallback message if the section is missing - Release workflow verifies formatting instead of rewriting it — The
Fix code formattingstep ran Pint in fix mode and discarded the result; it now runspint --testand fails on violations
Changed
- Docs follow the standard topic layout —
introduction.mdbecameindex.md,quickstart.mdmoved to the docs root, and a generatedrequirements.mdstates only what the resolver enforces.docs/superpowers/and its subfolders gained the_index.mdlandings and frontmatter they were missing, which had been downgrading the docs site's grading fromcompletetopartial. All relative links repaired and verified - Pest constraint widened to
^4.1 || ^5.0— Pest 5 is stable; the package was a major behind - Tests now exercise the real MCP protocol — Every test drove tools through
execute()directly, so JSON-RPC argument delivery, response serialization, theisErrorflag, and outputSchema conformance had no coverage at all;StatamicMcpServerTesteven read protected properties by reflection. A newMcpProtocolSurfaceTestdrives tools throughStatamicMcpServer::tool(). This required registeringLaravel\Mcp\Server\McpServiceProviderinTestCase::getPackageProviders()— Testbench does not run package auto-discovery, so without itLaravel\Mcp\Requestnever receives arguments and protocol-level tests pass while asserting nothing composer stanpasses--memory-limit=2G— PHPStan crashed its parallel worker at PHP's default 128M; 1G proved marginal oncetests/Fixturesjoined the analysis paths- Removed the
composer test:parallelscript — It could not work for the reason above; usecomposer test
2.8.0
July 29th, 2026
Changed
- laravel/mcp ^0.9 support — Widens the dependency constraint to
^0.6 || ^0.7 || ^0.8 || ^0.9. The 0.9 breaking changes are client-side only (theLaravel\Mcp\Client\Contracts\Transportcontract gainedsetProtocolVersion(), and the MCP client now only negotiates2025-11-25/2025-06-18); this addon ships a server and does not implement either, so no code changes were needed. Server-side gains come for free: stricter JSON-RPCparams/argumentsvalidation (-32602on non-object payloads), aCursorPaginatorfix for negative cursor offsets, and hardened OAuth dynamic client registration
2.7.0
July 5th, 2026
Changed
- laravel/mcp ^0.8 support — Widens the dependency constraint to
^0.6 || ^0.7 || ^0.8, allowing the latest laravel/mcp release (v0.8.x) with MCP client support, MCP UI Apps,ResourceLinkcontent type, and OAuth improvements. All patterns used by this addon are unchanged across 0.6–0.8
Fixed
- Blueprint
typesaction null handles — Blueprints without a handle are now skipped during type analysis instead of triggering a type error - Output buffer cleanup type safety — Shutdown output-buffer sweep in the MCP server no longer relies on an impossible
falsecomparison flagged by stricter dependency types
Full Changelog: https://github.com/cboxdk/statamic-mcp/compare/v2.6.1...v2.7.0
2.6.1
June 30th, 2026
[2.6.1] - 2026-06-30
Fixed
- Confirmation token retry loop — Router schemas now expose
confirmation_tokenas an optional top-level argument, giving MCP clients a valid schema slot for the token returned by confirmation-required responses (#34) - Confirmation payload drift on retry — Confirmation tokens now preserve the originally confirmed arguments, tolerate associative key reordering, and restore the confirmed payload before executing the gated action while still rejecting changed payloads and reordered lists (#34)
Tests
- Added regression coverage for schema exposure, two-step confirmation retries, nested associative argument reordering, and confirmed payload restoration
2.6.0
June 2nd, 2026
[2.6.0] - 2026-06-02
Fixed
- Eloquent user ID compatibility — Normalizes Statamic user IDs before MCP token ownership checks so sites using the Eloquent users driver no longer hit strict type errors in the MCP dashboard or token flows (#31)
- OAuth authorization user IDs — Applies the same user ID normalization when creating OAuth authorization codes for Eloquent-backed users
- Fresh install dependency compatibility — Allows
laravel/mcp^0.7alongside^0.6and updates installation docs/generated guidance to match (#31)
Tests
- Added regression coverage for integer Eloquent user IDs, string user IDs, and missing current users in MCP dashboard user resolution
2.5.0
May 6th, 2026
[2.5.0] - 2026-05-06
Added
- Revision-aware entry workflows — When a collection has revisions enabled, the MCP server now respects Statamic's editorial workflow instead of bypassing it with direct saves. Updates to published entries create a working copy (published content unchanged), creates use
store()for draft + initial revision, and publish/unpublish delegate to Statamic's built-in revision-aware methods (#30) - New entry actions:
list_revisions,get_revision,restore_revision,publish_working_copy— full revision lifecycle management via thestatamic-entriesrouter versionparameter on entry get — Retrievepublished,working_copy, orlatestversion of an entryHandlesRevisionstrait — Encapsulates revision-aware save, list, get, and restore operations matching the Statamic CP's exact editorial workflow- Confirmation gate defaults for revision actions —
restore_revisionandpublish_working_copynow require confirmation in production by default - 31 new tests covering the full revision lifecycle (create → working copy → list revisions → restore → publish)
Fixed
- Multi-site response in
publishWorkingCopyAction— Re-fetches entry with site context to return correct localized data - Stale revision metadata after restore —
revision_statusandrestored_as_working_copynow reflect actual state afterrestoreRevisionAction normalizeTableCellunbounded recursion — Table cell normalization now unwraps one level only, preventing stack overflow on deeply nested structuresfilterOutputFieldsdenied field stripping — Denied fields are now correctly stripped from list responses and nested entry data, not just top-level get responsesgenerateBlueprintfield array shape — Blueprint generation now produces the correct indexed handle/field formatrevision_messagetype safety —publishWorkingCopyActionvalidates that revision message is a string before passing to Statamic- PHPStan L8 compliance — Resolved mixed offset access in
filterOutputFieldsrecursive field filtering
2.4.0
May 5th, 2026
What's new
Per-field wire-format spec
BlueprintsRouter::get now emits a _format_spec per field describing the exact wire format — shape, allowed node types/marks, set handles, recursive set definitions, and canonical examples. Covers bard (inline + full), replicator, grid, group, markdown, scalar, select/checkbox, relationship, asset, table, and date fields. This eliminates the guessing game that caused agents to produce malformed bard/replicator payloads. (#29)
Configurable confirmation actions
New confirmation.actions config block allows per-domain control over which MCP actions require confirmation tokens. Operators can now gate entries.update, entries.publish, globals.update, etc. without forking the package. Domains not listed fall back to default. * gates every action; [] disables the gate. Shipped defaults preserve existing behaviour. (#26)
Client-safe exception messages
FieldFormatException, ValidationException, FieldtypeNotFoundException, and BlueprintNotFoundException messages now survive production sanitization — agents get actionable error messages instead of a generic placeholder.
Bug fixes
- Entry slug self-collision on update —
updateEntry()no longer fails with "slug already taken" when updating an entry without changing its slug (#28) - Table cell normalization —
SanitizesFieldDatanow correctly normalizes{value: …}objects in table cells to plain strings, preventing[object Object]rendering in the CP - Playwright CI stability — Browser tests now use shared auth state (single login per run), preventing Statamic's login throttle from failing tests
Full Changelog: https://github.com/cboxdk/statamic-mcp/compare/v2.3.0...v2.4.0
2.3.0
April 23rd, 2026
What's Changed
- feat: confirmation tokens and granular resource policy by @sylvesterdamgaard in https://github.com/cboxdk/statamic-mcp/pull/22
- docs: add Node.js TLS certificate fix for Laravel Herd/Valet by @sylvesterdamgaard in https://github.com/cboxdk/statamic-mcp/pull/24
- fix(sanitizer): normalize table cells to scalars before persist by @sylvesterdamgaard in https://github.com/cboxdk/statamic-mcp/pull/25
Full Changelog: https://github.com/cboxdk/statamic-mcp/compare/v2.2.4...v2.3.0
2.2.4
April 14th, 2026
Fixed
- Critical: Update action on entries, terms, and globals no longer crashes with
Cannot access offset of type string on stringwhen blueprints include third-party fieldtypes (e.g., SEO Pro) — validation falls back to incoming-only fields on TypeError - OAuth CIMD discovery:
cimd_enabledconfig checks use(bool)cast withtruedefault — previously silently disabled by strict comparison, env strings, and missing config keys from shallow merge - OAuth path-suffixed discovery: Added
/.well-known/oauth-authorization-server/{path}and/.well-known/oauth-protected-resource/{path}routes per RFC 8414 §3.1 — MCP clients (incl. ChatGPT) use path insertion for discovery and previously got 403
Added
- OAuth 2.1 CIMD support: Client ID Metadata Document resolution — MCP clients can present verified application identity on consent screen
- CIMD resolver with SSRF protection, JSON-LD validation, and configurable caching
- 10 update validation tests (deep nested replicator/bard/grid/group, round-trip, crashing fieldtype simulation)
- 24 discovery endpoint tests (CIMD config edge cases, path-suffixed routes, CP route changes, revocation endpoint, full ChatGPT-style client discovery flow)
- Comprehensive CIMD test suite (unit, feature, E2E)
See CHANGELOG for full details.
2.2.3
April 14th, 2026
Fixed
- CIMD still not detected by ChatGPT: Added path-suffixed discovery routes per RFC 8414 §3.1. MCP clients following the 2025-11-25 spec resolve discovery for
/mcp/statamicat/.well-known/oauth-authorization-server/mcp/statamic— without these routes the request returned 403, so ChatGPT never sawclient_id_metadata_document_supportedand disabled CIMD.
2.2.2
April 14th, 2026
Fixed
- CIMD still not detected: All
cimd_enabledconfig lookups now default totruewhen the key is missing.mergeConfigFrom()only does a shallow merge — published config files from before v2.2.0 don't have thecimd_enabledkey, so it returnednulland CIMD stayed disabled. No config republish needed.
2.2.1
April 14th, 2026
Fixed
- CIMD not detected by clients:
cimd_enabledconfig check used strict=== truecomparison against an env string — CIMD was never advertised in discovery metadata. Fixed in DiscoveryController, AuthorizeController, and OAuthTokenController.
2.2.0
April 14th, 2026
Fixed
- Critical: Update action on entries, terms, and globals no longer crashes with
Cannot access offset of type string on stringwhen blueprints include third-party fieldtypes (e.g., SEO Pro)
Added
- OAuth 2.1 CIMD support: Client ID Metadata Document resolution — MCP clients present verified identity on the consent screen
- 10 new update validation tests covering deeply nested blueprints
- Comprehensive CIMD test suite
See CHANGELOG for full details.
2.1.0
April 13th, 2026
Highlights
Fieldtype process() pipeline — Data saved via MCP now matches the Statamic CP format. All content routers call $fields->process()->values() after validation, ensuring Terms strip prefixes, Bard normalizes nodes, and Relationships wrap values correctly.
ENG-697 fix — Entry updates with terms field type no longer crash. Relationship fields (terms, entries, users, assets) and checkboxes normalize bare strings to arrays before validation.
Security hardening — OAuth auth code/refresh token double-spend prevented, client_name XSS sanitized, HTTPS enforced on OAuth endpoints, default scopes restricted to read-only.
See CHANGELOG.md for full details.
Upgrading
No breaking changes. composer update cboxdk/statamic-mcp is sufficient.
OAuth default scopes changed from * to read-only. If your OAuth clients need write access, set STATAMIC_MCP_OAUTH_DEFAULT_SCOPES in your .env:
STATAMIC_MCP_OAUTH_DEFAULT_SCOPES#89DDFF;">=#89DDFF;">"content:read,content:write,blueprints:read,entries:read,entries:write#89DDFF;">"
Existing tokens are not affected — only new OAuth clients created after upgrade will use the new defaults.
2.0.4
April 10th, 2026
Fixed
- Critical: Entry creation no longer crashes with "Cannot access offset of type string on string" when data contains complex nested fields (Bard, Replicator)
- Date fields now accept any common format (Y-m-d, Y-m-d H:i, ISO 8601,
{date, time}objects) — values are normalized to the Zulu format Statamic expects before validation dateandpublishedin entry data are now correctly extracted as first-class entry properties instead of failing blueprint validation on dated collections
Added
NormalizesDateFieldstrait for consistent date handling across all routers (Entries, Terms, Globals)- 13 new integration tests covering date normalization, published extraction, and error handling
2.0.3
April 9th, 2026
Fixed
- Critical: Blueprint update action no longer destroys existing fields — fields are now merged by default instead of replaced
- Blueprint update preserves tab and section organization in multi-tab blueprints
Added
replace_fieldsparameter on blueprint update for explicit full-replacement when needed
2.0.2
March 19th, 2026
Fixed
- Install command no longer crashes on sites without a database — migrations are now skipped automatically when file-based storage drivers are configured (the default)
- Config publish prompt: confirming "Overwrite? yes" now actually overwrites the file (previously
--forcestayed false, sovendor:publishsilently skipped it) - Migration failures are caught with actionable guidance instead of crashing the installer
- Completion message now reflects what actually happened during install
Added
--skip-migrationsflag onmcp:statamic:installas an explicit escape hatch
Full Changelog: https://github.com/cboxdk/statamic-mcp/compare/v2.0.1...v2.0.2
2.0.1
March 18th, 2026
Fixed
- Token expiry date validation no longer blocks submission —
max_token_lifetime_daysis now a default suggestion, not a hard server-side rejection - Token form error feedback uses Statamic toast notifications and native
ui-error-messagecomponents with red border highlighting
Added
- Scope presets (Read Only, Content Editor, Full Access) in token create/edit form, matching documented common combinations
- Preset-aware badge display in admin token table — shows preset name instead of listing individual scopes
- Admin token form now uses Statamic-style grouped permission cards with per-group "Check All"
Removed
- Internal development plans and specs (
docs/superpowers/) accidentally included in v2.0.0
2.0.0
March 18th, 2026
v2.0.0 — Storage drivers, OAuth 2.1, audit overhaul, security hardening
Major release: storage driver abstraction, MCP OAuth 2.1 with PKCE, comprehensive audit logging, router-based tool architecture, and security hardening.
Breaking Changes
- Statamic v5 dropped — requires Statamic v6.6+, Laravel 12/13, PHP 8.3+
- Laravel MCP v0.6 — new tool attribute pattern
- Router architecture — 140+ tools consolidated into 11 domain routers
- Tool names changed —
statamic.blueprints.list→statamic-blueprintswithaction: list - Config restructured — re-publish required
Highlights
- Storage drivers: File (YAML/JSONL, default) and Database (Eloquent)
- OAuth 2.1: PKCE S256, Dynamic Client Registration, refresh token rotation, revocation
- 21 scoped API tokens with fine-grained access control
- CP Dashboard: User + Admin pages with token management and audit log
- Security: 8 review rounds, 30+ findings fixed
- Laravel 13 support
- 772 tests, PHPStan Level 8, full CI matrix
Upgrade Guide
See UPGRADE.md for migration steps from v1.x.
Full Changelog
See CHANGELOG.md for complete details.