Skip to content
Externa

Externa Core 1.4.0 — MCP, AI approvals, and accessibility

A rebuilt admin with transparent AI answers, an optional MCP server, human approval for AI write tools, theme presets, GCS and Azure file storage, WCAG 2.2 AA accessibility work, and new Public API batch writes and filters.

Luca Giardi10 November 20268 min read

Externa Core v1.4.0 opens Externa to external AI agents through an optional MCP server, puts human approval in front of every AI write, and continues the admin accessibility work toward WCAG 2.2 AA. The admin is rebuilt on shadcn/ui and AI Elements, and every assistant answer now shows its reasoning, tool calls and sources. It also adds theme presets, Google Cloud Storage and Azure Blob file disks, and new Public API batch writes and filters. The MCP server and AI write tools are off by default. Notes will live at GitHub Release v1.4.0 · Changelog.

Who should upgrade

  • Teams that want external AI agents and MCP clients to read (and, if you allow it, write) CMS content with the same permissions as the admin.
  • Operators who need an audit trail and approval step before the assistant creates, changes, or deletes anything.
  • Self-hosters storing files on Google Cloud Storage or Azure Blob.
  • Frontends that need batch item writes, filters on system columns or related items, and sorting in the Public API.
  • Anyone on 1.3.0 with scoped API keys or private files: 1.4.0 fixes how the Files API lists private files on upgraded installs (#434).

What matters

A rebuilt admin and transparent AI answers

  • Rebuilt on shadcn/ui and AI Elements: pickers, lists, forms, loaders, tables and both chats now use standard shadcn/ui components, so the admin looks and behaves the same everywhere, in light and dark (#517–#586).
  • See how the assistant got its answer: each answer shows the model's reasoning (open while it thinks, then "Thought for N seconds"), every tool call as a plain sentence such as "List collections" with its state, the sources it cited, and the tokens it used. It all streams live and is shown again after a reload (#565 / #566 / #570 / #572 / #615 / #621).
  • Clear approvals: a write the assistant wants to make waits on an approval card with the call in words; Approve turns red only when the call deletes data (#619).
  • Reasoning you can tune: the assistant asks OpenAI, Anthropic and Gemini for medium reasoning effort. Set OPENAI_REASONING_EFFORT, ANTHROPIC_REASONING_EFFORT, GEMINI_REASONING_EFFORT or LOCAL_AI_REASONING_EFFORT, pick the assistant's provider with AI_ASSISTANT_PROVIDER, and set the context size shown next to token usage with *_CONTEXT_WINDOW (#570).
  • Team chat: reactions show who reacted, names and mentions open a user card with role and online status, and reply quotes and pinned messages jump to the original. Files are attachment cards and photos fill their bubble (#575 / #576 / #578 / #582).
  • Files: square cards, Drive-style: the preview fills the card edge to edge on the image's focal point, with one row below for the name, the tags (on hover) and a ⋮ menu. Folders look the same. You set the focal point by clicking the image in the details panel, and the crop of every transform follows it (#583 / #592 / #596).
  • Admin lists: users, groups, roles, API keys, permissions, the activity log and jobs are server-driven tables with sorting, filters and row actions, and deletes ask for confirmation (#522 / #523–#537 / #561).

AI: MCP server and human approval

  • Optional MCP server at /mcp (laravel/mcp), off until you set AI_MCP_ENABLED. Clients authenticate with owned API keys that carry mcp:read / mcp:write scopes, and the server has its own mcp rate limiter. Write tools are only registered when AI_MCP_WRITE_ENABLED is also on. OAuth is not part of this release (#121).
  • Same permissions as chat: MCP tools and resources share one permission-aware tool registry with the in-app assistant. Collection, item, field and file permissions apply, plus the API key's collection scopes, files_scope and read_only (#202 / #435).
  • Human approval for AI writes: write and destructive tools are denied by default. Turn them on with the AI_WRITE_TOOLS switch and a per-tool allowlist; each write then needs approval. Chat asks before it acts. MCP writes wait in an admin inbox of pending tool calls for 15 minutes. Tool calls land in a redacted ai_tool audit log, pruned with php artisan ai:prune-tool-audit (#203).
  • With AI writes off, chat keeps the read actions (list, get, search) of the Manage* tools (#439).
  • A prompt-injection and denied-permission test suite covers chat and MCP (#204).
  • Context attachments: attach items, files, and project-level saved prompts to a conversation. Access is checked again at send time (#195). On-demand Agent Skills give the assistant CMS playbooks (#181).

Admin, theming, and accessibility

  • Theme presets: six built-in presets (qiick Teal by default, Blue, Indigo, Violet, Rose, Slate) with a live preview, plus an optional custom brand color (#243 / #437).
  • Accessibility work toward WCAG 2.2 AA: focus restore on overlays, focus moves to the main content after navigation, live announcements, reduced-motion rules, landmarks, and translated labels (#252–#254). The focus ring keeps 3:1 contrast even when a custom brand color is low contrast (#453).
  • Accessibility checks in CI: eslint-plugin-jsx-a11y, axe smoke tests on key admin routes (a required check on code PRs), and a theme-token contrast check (npm run a11y:contrast) (#255).
  • Shared empty states, shadcn form fields with linked errors, and table, sidebar and button cleanups across the admin (#229–#241).
  • Safe field conversion for fields that already hold content, with a dry-run preview and externa:field-convert (#220).
  • Server-side flash and validation messages in German and Italian (#282).

Files and storage

  • Google Cloud Storage (FILES_DISK=gcs) and Azure Blob (FILES_DISK=azure) disks for the file manager, alongside local and S3 (#188).
  • Per-project upload allowlist for extensions and MIME types, with SVG as an opt-in. Executables, HTML and SSI stay blocked (#327).
  • Per-key files_scope (none / read / all) to keep scoped API keys out of the Files API (#322).

Public CMS API

  • Batch create / update / delete at /api/v1/collections/{slug}/items/batch, capped by API_MAX_BATCH_SIZE (default 100) (#125).
  • Filters on system columns (id, created_at, updated_at, published_at) and on depth-1 relations, e.g. filter[author.name][_eq]=…, on SQLite, MySQL/MariaDB and PostgreSQL (#333 / #124 / #436).
  • sort on system and sortable fields (#224), and the new @qiick/externa-sdk TypeScript client, version 0.1.0 (#119).

Publishing and integrations

  • Deploy hooks for Vercel, Netlify, Cloudflare Pages and Forge, with an optional deploy on publish (#196).
  • Live Preview "Preview at…" shows scheduled content as of a future date (#222).

Security

  • Security headers (CSP, X-Frame-Options, Referrer-Policy, Permissions-Policy) on admin responses, configurable in config/security.php (#187 / #440).
  • Secure-by-default fresh installs (registration off, auth throttles) (#272), timestamped webhook signatures (#273), stricter SSRF checks including OIDC (#274), and Docker workers running as www-data (#320).
  • API keys can be bound to an owner, so access is the key role ∩ scopes ∩ the owner's permissions (#215).

Upgrade steps (from 1.3.x)

  1. Back up the database, .env, and file storage.
  2. Move code to v1.4.0 (git tag, Packagist qiick/externa-core:1.4.0, or the Docker image ghcr.io/qiick-io/externa-core:1.4.0).
  3. Install and build:
composer install
npm ci && npm run build
php artisan externa:upgrade
# or: migrate --force && permissions:sync && optimize:clear
  1. Restart Horizon / queue workers, the scheduler, and Reverb if enabled.
  2. Optional: set AI_MCP_ENABLED, AI_WRITE_TOOLS and the tool allowlist, a theme preset in Settings → Appearance, or FILES_DISK=gcs / azure.

Behavior notes

  • Inbound AI collection-import webhooks must now send X-AI-Webhook-Timestamp (within 300 seconds) and sign "{timestamp}.{body}". Outbound webhooks add X-Externa-Signature-V2; the legacy X-Externa-Signature stays for one minor (#273).
  • Docker: workers run as www-data. Bind-mounted storage/ and bootstrap/cache created as root may need a one-time chown -R www-data:www-data storage bootstrap/cache (#320).
  • Files: the upgrade migration computes files.effective_access for existing files, and files without a computed value are hidden from roles without read_private (#434).
  • API key owners: existing keys are bound to their creator, or to the first active super-admin when the creator is deactivated. Review those keys after the upgrade (#215 / #439).
  • Permissions: externa:upgrade grants the built-in admin role the new deploy.trigger and ai.prompts.manage permissions (#439).
  • Security headers: if you embed the admin or load assets from other origins, set SECURITY_CSP (#187).
  • AI reasoning: with a cloud provider the assistant now asks for medium reasoning effort, which makes answers slower and uses more tokens. Lower it, or turn it off, with the *_REASONING_EFFORT variables (#570).
  • Removed packages: laravel/sail, @headlessui/react, the unused Radix packages and the Wayfinder Vite plugin are gone. Run composer install and npm ci after pulling (#520 / #568).

Sources

Try Externa on your own server

Open source under MIT, self-hosted, built on Laravel.