Sign in

The MCP server

Updated Jul 3, 2026

Every Devani site is an MCP server, served at /devani/mcp/?api_key=<key>. The implementation lives in devani/mcp/index.php (transport), auth.php, and ToolService.php (the tool catalog and all handlers).

Authentication & roles

Keys are created in Settings, stored hashed in the mcp_api_keys table, and verified per request. Keys carry a role; write operations are gated by an explicit writeTools list in ToolService — any tool that mutates state must be on that list or non-editor keys get refused. When you add a mutating tool, adding it to writeTools is part of the change, not an afterthought (granular style editors were once missed here; the gap was a real write-gate bypass).

Safety invariants (don't break these)

  • Snapshot before write. Every content mutation calls the snapshot helper before writing. Snapshots land in devani/snapshots/mcp/<timestamp-id>/, pruned to the newest few per file group. list_snapshots / restore_snapshot expose them; restore takes a safety snapshot of current state first, so restores are reversible.
  • Integration settings are write-only. update_integration_settings accepts only an allowlisted set of keys (allowedIntegrationSettings), and no tool ever returns a stored secret. get_integration_settings reports configured/not-configured, never values.
  • Restricted paths. Page tools refuse reserved slugs (devani, header, footer, blog, products, …) so a generic page write can never clobber the header, the blog tree, or the application.
  • Audit everything. Calls are logged with key identity; recent activity is visible in Settings.

The catalog, briefly

Tools cover pages/blog (CRUD + meta incl. Open Graph/Twitter/canonical/robots as of 2.4), regions (header, footer, navigation, global styles with line/region-level editors), media (upload registration, Tonta resize, AltText triggers), commerce (products, inventory, discounts, orders, fulfillment), redirects, users (admin-only), reviews, snapshots, and integration modules (Sendl form embed, Pinpic interactive images). Call the server's tools/list for the authoritative, versioned catalog.

Adding a tool

  1. Schema in listTools() via toolSchema() — description written for an AI caller: say when to use it, not just what it does.
  2. Dispatch case + handler. Validate inputs with InvalidArgumentException; snapshot before writes.
  3. Gate it: writeTools if it mutates; required-args entry for audit summaries.
  4. If it inserts content, emit module-convention markup (see the sanitizer doc) and mirror it in the editor's block picker.
Was this helpful?

Related articles

Powered by Subido