Five MCP Components for MODX Tested for Failures: Agent Reports Success When Only Half the Edits Were Saved
A web studio developer was choosing an MCP component for MODX, but dug into the source code and discovered that setTVValue() is never checked anywhere, so when a write fails the agent gets "success" even though the data was only half saved. He ran 25 checks across five projects and compared permissions, repeated requests, and protection against overwriting other people's edits.
AI-processed from Habr AI; edited by Hamidun News
A routine task: pick an MCP component to hand routine site work over to an AI agent. But a developer at a web studio working with MODX 2 and 3 looked into the code and saw a loop that updates a page's extra fields and does not check the result of setTVValue(). The first field was written, the second was not, and the handler reported success. The agent will believe that response and tell the user everything is done.
A small investigation grew out of this. The author selected five projects: karamble/modxmcp, dampilov94/mcp-component, rumata-estor/modx3-mcp, modxcms/modAI and ShevArtV/mxBoard. He pinned the source code on October 26, 2026 and ran 25 checks on PHP 8.3.6. The real component classes were used, but test objects stood in for a live MODX and database. Some tests deliberately reproduced errors, so PASS does not always mean the component behaves correctly.
Whose permissions the agent acts with
Imagine a content manager who is allowed to edit only news. If you give them an AI assistant, what permissions does the assistant itself get? The source code revealed two schemes. In karamble, both the permission for the operation and access to the specific resource are checked. Issue #11 even described a real bug: a restricted user could get data through MCP that they could not see in the admin panel. It was fixed in version 1.2.0.
In dampilov94 and rumata-estor, command groups can be restricted, but they run through a service user with admin rights. That is fine for administrator tasks. It is not fine for personal assistants of employees who have their own restrictions.
Stale data and lost responses
The price on a page is 1000 rubles, the agent reads it, and meanwhile an employee sets it to 1100. The agent writes 1200, and the human's edit disappears. In dampilov94's code the old value is not compared. In rumata-estor there is an expected-value check with a STALE_STATE status, and in the test it preserved the human's edit. But the check is optional: if the client does not pass the precondition, the write goes through. Moreover, the check and the write are performed separately, with no atomic comparison at the database level.
Retries are a different story. If the server created a page but the response was lost, the agent may repeat the command and create a duplicate. dampilov94's RequestStore keeps state by request identifier. A parallel duplicate gets a 409, a completed request returns the saved response, and if the arguments change under the same identifier, the request is rejected. But with a new identifier the command will run again.
The file lock in rumata-estor made a second process wait 350 ms. However, a third process that did not know about it calmly modified the file. The regular MODX admin panel would behave the same way. A request identifier, a lock, and an expected-value check solve different problems and do not replace one another.
Partial writes and acceptance
rumata-estor wraps the TV write in a transaction: if setTVValue() returned false, a rollback is called. In the test the values returned to their originals. In modAI the result of the cache refresh is not checked, and in the test the tool reported success despite false. In karamble, the resource is read again after the change. mxBoard separates task execution from acceptance: the assignee could not close someone else's task.
What to do about it
The limitations are honest: the author has not yet run a real MODX with MySQL and a language model, and the rollback was verified only against a stub. Still, the conclusion applies to any CMS and any application where an agent is allowed to change production data. Before launch, decide on whose behalf it works. Require the client to pass a request identifier and an expected value. Check the result of every write, not just the last call. And do not take an agent's "success" as confirmation that everything was saved on the site.
- Nov 8, 2026Microsoft and Berkeley Release TokenEconomizer: Coding Agents Run 18–31% Cheaper
- Nov 8, 2026A Check of 600 Links Found That Up to 94% of AI Sources Remain Accessible
- Nov 8, 2026OpenAI: GPT-6 Astra designed the entire Codex device by itself in one week
- Nov 8, 2026GateRook checks AI agent requests in 3 steps before granting infrastructure access
Key Questions Answered
Whose permissions the agent acts with?
Imagine a content manager who is allowed to edit only news. If you give them an AI assistant, what permissions does the assistant itself get? The source code revealed two schemes. In karamble, both the permission for the operation and access to the specific resource are checked. Issue #11 even described a real bug: a restricted user could get data through MCP that they could not see in the admin panel. It was fixed in version 1.2.0.
What are the key details on Stale data and lost responses?
The price on a page is 1000 rubles, the agent reads it, and meanwhile an employee sets it to 1100. The agent writes 1200, and the human's edit disappears. In dampilov94's code the old value is not compared. In rumata-estor there is an expected-value check with a STALE_STATE status, and in the test it preserved the human's edit. But the check is optional: if the client does not pass the precondition, the write goes through.
What are the key details on Partial writes and acceptance?
rumata-estor wraps the TV write in a transaction: if setTVValue() returned false, a rollback is called. In the test the values returned to their originals. In modAI the result of the cache refresh is not checked, and in the test the tool reported success despite false. In karamble, the resource is read again after the change. mxBoard separates task execution from acceptance: the assignee could not close someone else's task.
Build & Ship Production AI Agents Without Boilerplate Code
Start your free 72-hour trial at Hamidun Academy (academy.hamidun.com) — interactive lessons on Claude Code & Cursor, live Tech Radar, and production agent templates.
The AI world, distilled — once a week
Seven stories that actually mattered, hand-picked. No noise, no reposts, no press releases.
Done! Check your inbox for a confirmation.