{"slug": "making-a-php-app-legible-to-ai-agents", "title": "Making a PHP app legible to AI agents", "summary": "Total CMS now ships a Model Context Protocol (MCP) server with every install, letting coding agents query the running site for its real schemas, live content, and version-matched documentation instead of guessing at APIs. The server routes all agent writes through the same schema validation, events, access groups, and OAuth 2.1 scopes used by human editors, and sends connect-time instructions such as \"Check the docs instead of guessing\" and \"Never invent IDs\" to every client. The author, who has built CMS software for web designers since 2015, says serving docs from the install eliminated drift between documented and installed versions.", "body_md": "## The problem: agents invent APIs\n\nI've been building CMS software for web designers since 2015. This year I started building with coding agents every day, and I kept hitting the same failure.\n\nI'd ask an agent to add a section to a site, and it would confidently write a template that called a function that didn't exist. Plausible name, plausible arguments, wrong. Sometimes it came from an older version. Sometimes it was invented whole.\n\nThe code looked right, and that was the problem. A broken build is easy to catch. Plausible code against an API that isn't there gets past a quick review, and you find out later.\n\nThis isn't a bad-agent problem. The agent works with what it has: training data that's months or years old, and docs on a website that may or may not match the version actually installed.\n\n## Why better prompting doesn't fix it\n\nMy first instinct was better prompts: paste the docs into context, write a long instructions file. It helps a little. It doesn't solve it, because the docs you paste are a copy, and copies drift.\n\nThe real issue is the source of truth. The agent is guessing about a system that knows exactly what it is. The installed app knows its own schemas, its own content, and which functions this version actually exposes. Nothing was asking it.\n\nSo the fix had to live on the app's side. The install should be able to describe itself.\n\n## Let the install describe itself\n\nEvery Total CMS install now ships an MCP server. MCP, the Model Context Protocol, is the open standard Claude, ChatGPT, Cursor and others use to talk to outside tools. Through it, an agent can ask the running site for three things:\n\n- **Its schemas.** The real collections and fields on this site, not a generic example from the docs.\n- **Its content.** Live records, so the agent can look at what exists before it changes anything.\n- **Its documentation, for this version.** The docs ship with the install and are served from it, so an agent working on 3.6 reads 3.6's Twig functions and field types. No drift between what the docs say and what the site does.\n\nThe third one did the most work. Once the agent could look up a real signature instead of recalling one, it stopped guessing.\n\nCustomers don't always update right away. An agent reading the latest docs on a website would reach for syntax or features their installed version doesn't have yet. Served from the install, the docs describe exactly what that site can do.\n\n## Writes go through the same door as humans\n\nReading is the easy half. Letting an agent write content is where people rightly get nervous.\n\nThe rule I settled on: an agent gets no special path. Every write goes through the same schema validation and fires the same events as a save from the admin UI. Permissions come from the same access groups that govern human editors, and an OAuth token gets exactly the checks a signed-in user gets.\n\nSo \"can the agent touch this?\" is answered in the same place as \"can this editor touch this?\" One permission system, not a second one bolted on for AI. The admin has a permission matrix showing what each group can reach, agents included.\n\nAccess comes in three levels: anonymous reads of public content, API-key access for the site owner, and per-user OAuth 2.1 with scopes, a consent screen, revocation and an audit log.\n\n## Guardrails at connect time\n\nMCP lets a server send instructions when a client connects. Mine are short, and each one is a mistake I saw agents make:\n\n- Look before acting.\n- Check the docs instead of guessing.\n- Change only the fields you mean to change.\n- Never invent IDs.\n\nPutting them in the server means every client receives them on connect, no matter who wrote the prompt.\n\nThe server also offers guided prompts for common jobs, like modeling a collection, writing content, or auditing SEO. A user starts a task with the right context already loaded instead of describing it from scratch.\n\nOne more guardrail sits on the OAuth side. Clients can register themselves, which makes connecting painless, so the consent screen shows exactly where a client will send you after you approve and warns when that destination is unfamiliar.\n\n## If you're doing this in your own PHP app\n\nNone of this is specific to a CMS. If your app has data and an API, here's what I'd pass on:\n\n1. **Serve docs from the running code, not a website.** Version-matched docs fix more than any prompt will.\n2. **Reuse your permission layer.** Give agents their own permission system and you have two to keep in sync, and the second one will be the weaker one.\n3. **Send writes through your normal save path.** Whatever a human save triggers, like validation, events and hooks, an agent save should trigger too.\n4. **Put behavior instructions in the server.** They travel with every connection, regardless of who's prompting.\n5. **Start read-only.** Reading is useful on its own and carries little risk. Add writes once the permission story is solid.\n6. **Plain data formats help.** My content is JSON on disk, so it's easy to see exactly what an agent changed. Nice to have, not required.\n\nBuilding into the app isn't the only option, either. I wrote up the three ways to do this: an instruction file, a separate MCP server, or one built-in — with the tradeoffs of each: [How to add an MCP server to a PHP app](https://totalcms.co/guides/mcp-server-php-app).\n\n## Try it\n\nYou can try the read side without installing anything. totalcms.co runs on Total CMS, and its MCP endpoint answers questions about the product's docs. In Claude Code:\n\n```\nclaude mcp add --transport http totalcms https://totalcms.co/mcp\n```\n\nThat endpoint is read-only: the product docs plus totalcms.co's public content. It won't show an agent building a site; that needs a local install.\n\nFull disclosure: Total CMS is my product. It's a commercial flat-file PHP CMS. If you've made your own app legible to agents, I'd like to hear what you ran into.\n\nWebsite: [totalcms.co](https://totalcms.co/)\n\nDocs: [docs.totalcms.co](https://docs.totalcms.co/)", "url": "https://wpnews.pro/news/making-a-php-app-legible-to-ai-agents", "canonical_source": "https://totalcms.co/articles/making-a-php-app-legible-to-ai-agents", "published_at": "2026-10-01 00:00:00+00:00", "updated_at": "2026-10-07 13:46:08.940817+00:00", "lang": "en", "topics": ["ai-agents", "agent-protocols", "ai-tools", "developer-tools"], "entities": ["Total CMS", "Model Context Protocol", "Claude", "ChatGPT", "Cursor", "Twig"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/making-a-php-app-legible-to-ai-agents", "markdown": "https://wpnews.pro/news/making-a-php-app-legible-to-ai-agents.md", "text": "https://wpnews.pro/news/making-a-php-app-legible-to-ai-agents.txt", "jsonld": "https://wpnews.pro/news/making-a-php-app-legible-to-ai-agents.jsonld"}}