Repository navigation
Releases
1.2.0
A security release. An external report (issue #11) showed the read tools checked the calling token's scope and nothing else: a token bound to a Load Only MODX user could read every resource with its content, every element, and every plugin's code — none of which that user can open in the Manager. That contract is now enforced, and mapping the fix turned up two further holes.
Highlights
- Every tool asks MODX for the permission the Manager requires for the same action, and refuses by name. Resource-group and element-category policies apply per object;
searchreports the kinds a user may not read instead of silently narrowing;site_infowithholds gated listings. - The standalone endpoint
mcp.phpnow ships disabled behind themodxmcp.enable_standalone_endpointsystem setting (404 until enabled). On the optional standalone route MODX had been evaluating no policy at all; both routes now start and discard a session, and a request MODX can't evaluate fail-closes with a 503. - Tool arguments are validated against each tool's declared
inputSchema: unknown keys refused with a suggestion, wrong-typed values refused rather than cast (an array id no longer becomes1, the start page). - The Manager connector processors (token create/revoke, audit clear, settings) now enforce the
settingspermission they declared but never checked. ToolRegistry::get()and a documented replace-on-register contract let an extra wrap a built-in tool without reflection.- The pre-install validator now refuses PHP < 8.2, matching the manifest.
Upgrade notes
The upgrade rewrites files only — system settings, tokens, the audit log and the endpoint resource are preserved. Two behaviour changes: the standalone route is off unless you enable its setting (a site using mcp.php must turn it on after upgrading), and a token bound to a user with a narrower policy than its work now gets a refusal naming the permission where it previously got data — which is the fix.
Full detail in core/components/modxmcp/docs/changelog.txt.
Package: modxmcp-1.2.0-pl.transport.zip · build 35272584d0d0 · sha256 6095428174f8cd5042a69c06d24959f1275447edb9720222665f40756da7b6e2.
1.1.0
Answers a full external audit of the tool surface against 1.0.2 — thank you @AmaZili, who filed issues #1 through #4 with reproductions cross-checked against the database rather than taken from tool responses, and sent two pull requests. That report found real data loss. This release closes all five issues and both PRs, plus one bug that fixing #3 uncovered.
Requires PHP 8.2
Not a new requirement so much as an honest one. The support traits declare constants, which PHP only permits in a trait from 8.2, and two of them have done so since 1.0.0 — so on PHP 8.1 those files fatal at include time and take modxmcp_search and the three generic object tools with them, while the package advertised >=8.1. If you are on 8.1, those four tools have never worked. The installer now refuses 8.1 instead of shipping tools that cannot load.
Data loss fixed
modxmcp_element_save replaces a snippet, plugin or template's default properties wholesale, and its own description told callers to "send every option you want to keep" — while nothing in the surface could say what those options were. Adding one property destroyed the others, invisibly. modxmcp_element_get and modxmcp_element_delete now return them, along with a template variable's caption, display, option list, rank and input/output configuration, and a plugin's event bindings gathered before the processor removes them. Element removal is permanent and that echo is the recovery path; a plugin rebuilt from the old one came back bound to nothing and never ran again.
Refusals now reach the caller
A refusal raised by a tool is reported as a result carrying isError, not as a JSON-RPC protocol error. Clients are entitled to render a 4xx as a transport failure, so the most useful messages in the extra — the ones that name the problem, list the valid values and say "Nothing was written" — were the ones arriving mangled as Error POSTing to endpoint: {...}, while "the details are in the error log" travelled the reliable path.
Fixing that exposed an older bug: the audit log recorded a framed failure as a success, and an unexpected exception inside a tool had been logged as a success since the registry was written. Both fixed.
Two new tools
modxmcp_media_source_list— the media sources a site defines, with the idfile_uploadexpects, where each is rooted, and whether the upload allowlist covers it. Credentials are never returned. Gated on MODX's ownsource_viewpermission; remote sources are not contacted unless asked, because initialising an S3 source checks the bucket over the network.modxmcp_category_delete— removes a category, refusing one that still holds elements or sub-categories and naming what is in it. Stricter than MODX, which deletes it regardless, resets everything inside to uncategorised, and cascades through sub-categories without saying so.
The core is discovered
The core namespace was registered like any other, but its model map sits one level shallower than an extra's, so no glob matched it and the entire MODX core was invisible to discovery — which meant ClassGuard's hard-block list, which names almost nothing but core classes, had never once run. Fixed, along with the deeper maps beside it (media sources, transport). A hard-blocked class now says so instead of answering "Unknown class", which was wrong twice over.
Also
tools/listis filtered by the calling token's scopes. A read-only token sees thirteen tools, all of which it can call.modxmcp_element_deletewarns when something still calls the element it removed, naming the resources and elements with their URIs and published state.modxmcp_element_savewarns when a template variable'sinput_typeis one nothing can render — its own description warned that "radio is not a type", then acceptedradiosilently.- Deleting a template that resources still use is refused up front, naming how many. MODX rejects it anyway; the description had claimed otherwise.
modxmcp_cache_refreshclears modxmcp's own discovery and advisory caches. It never had, so installing an extra and then clearing caches still showed the old site.modxmcp_resource_duplicateechoes the template variable values the copy inherited.- Media sources and package providers are permanently blocked from generic access: both keep credentials inside a serialised column where field-name masking cannot see them.
- Documented that
modxmcp.upload_path_allowlistis relative to the media source, not toassets/.
Nothing here changes any site's data. The upgrade rewrites files only, and existing system settings, tokens, the audit log and the endpoint resource are all preserved.
Full detail in the changelog.
modxmcp-1.1.0-pl.transport.zip — build e4198468564e, 81 source files
sha256 31f5d926121ac196b16d1176756d5ae3d55e1037ea45bb2529dd571c5bfe54cd
1.0.2
Protocol conformance under revision 2026-07-28.
- Results served under 2026-07-28 carry
resultType. The revision requires
it on every result and a client is entitled to refuse one without it:
absence means "complete" only for earlier revisions. Claude Code rejected
every tools/list, so no tools registered at all on any deployed site
while the endpoint otherwise looked healthy. tools/call was wrong the
same way and would have failed the moment a tool was invoked. - Complete results of server/discover, tools/list, prompts/list,
resources/list and resources/templates/list carry the caching hints
ttlMsandcacheScope, which that revision also requires. Five
minutes, andprivaterather thanpublic: the tool list is identical
for every token today, but the specification permits filtering it by
granted scopes, andpublicwould license a shared proxy to serve one
caller's list to another the day it is. - Both are stamped by the protocol revision rather than by each handler,
so a result cannot reach the wire without them. Results served to
initialization-based clients are untouched: neither field exists before
2026-07-28.
Nothing changed in the legacy path, in tool behaviour, or in any site's
data. The upgrade rewrites files only; its resolvers are idempotent, and
existing system settings, tokens, the audit log and the endpoint resource
are all preserved.
Transport package build 1db33827eaba (77 source files). Install through Package Management, or verify the running build afterwards via modxmcp_site_info.
1.0.1
Manager fixes.
- The settings Save button was rendered in the panel footer, which the autoHeight tab clips out of frame. Save now appears twice: in a top toolbar like the other tabs, and in-flow after the last fieldset.
- New Clear log button on the audit grid, behind a confirmation. It deletes every row regardless of the grid's current filters, and writes who cleared the log and how many rows to the MODX system log.
Transport package build e51b70373169 (77 source files). Install through Package Management, or verify the running build afterwards via modxmcp_site_info.
modxmcp 1.0.0
First stable release: an MCP server for MODX Revolution 3.x, installed as a regular transport package.
What it is
modxmcp lets MCP clients administer a MODX 3.x site over Streamable HTTP. The endpoint is a MODX resource calling a snippet, so the package ships no web-accessible PHP and works on installs that deny PHP under assets/. Speaks MCP revision 2026-07-28 as well as the older protocol era that every currently-shipping client uses. Stateless, no SSE, zero third-party PHP dependencies.
Highlights
- Writes go through MODX processors, so Manager-side behaviour fires natively: SeoSuite registration, Collections rules, cache invalidation and lifecycle events.
- Token authentication: hashed at rest, per-token scopes, optional expiry and IP allowlist, last-used tracking. A Manager page handles token management and audit review, and the audit log covers rejected calls as well as successful ones.
- Resource and element tools, including full element definition through
element_save— input/output types, captions, option lists and properties for template variables, so MIGX, listbox and image TVs can be created and configured, not just filled. - Schema discovery across every installed extra, handling both package layouts and both metadata formats, with field descriptions taken from each extra's own lexicon.
- Generic object access, opt-in per class for reads and writes, with a hard block on users, sessions, access-control rules and modxmcp's own tables that no setting can override.
- File uploads via
modxmcp_file_upload, written through theBrowser/File/Uploadprocessor so media source access policies, upload settings and the file-manager events all apply exactly as they would for a Manager upload. Ships disabled: the path allowlist is empty on install, and uploads are further gated by an extension allowlist, a size cap, a media source allowlist and a newwrite:mediatoken scope. Server-executable extensions are blocked in every dot-segment of the filename, content containing a PHP open tag is refused regardless of name, and every upload is verified by reading the file back. The audit log stores who wrote which path, never the payload. - Adapters for SeoSuite (redirects), MIGX (item structure) and Collections (container listing), registered only where the extra is installed, plus an
OnMCPRegisterToolsevent so third-party extras can contribute tools — a failing plugin degrades to its tools being absent, never to a dead endpoint. - Build fingerprint in
modxmcp_site_info, computed per request from the shipped PHP files, so you can always tell exactly which build a site is running.
Installing
Upload modxmcp-1.0.0-pl.transport.zip through Package Management, or place it in core/packages/ and install by signature. Requires MODX Revolution 3.x. After installing, create a token on the modxmcp Manager page and point your MCP client at the endpoint resource.
Full details in core/components/modxmcp/docs/changelog.txt.