eMCP for Evolution CMS
OfficialThis server does not currently have a deployable release on Glama. Follow the repository's setup instructions to install and configure it for your MCP client, including any required credentials and local dependencies.
eMCP for Evolution CMS
eMCP is the Evolution CMS integration layer for laravel/mcp.
It adapts Laravel MCP to Evo runtime with:
Evo-native config publishing
manager ACL and sApi scope controls
optional async dispatch through sTask
no Laravel app skeleton requirement
Evo domain MCP tools for document tree (
SiteContent+ TVs)
Implementation starts with a strict MVP gate:
web transport
manager mode
initialize+tools/list
Design style:
contract-first (
TOOLSET.md+ validators)declarative config-first server registry (
config/mcp.php)explicit handler pipeline (
validate -> authorize -> query -> map -> paginate)
If you need full architecture and contracts, see DOCS.md (EN) or DOCS.uk.md (UA).
Public canonical tool contract: TOOLSET.md.
Versioning and BC policy: PRD.md (API Stability Policy section).
Operations runbook: OPERATIONS.md.
Requirements
Evolution CMS 3.5.2+
PHP 8.3+
Composer 2.2+
seiger/sapi1.x (installed as dependency; only used whenauth.mode = sapi_jwt)seiger/stask1.x (from 1.0.10) or 2.x, installed as dependency (2.x needs PHP 8.4)
Related MCP server: terminus-mcp
Install
From your Evo core directory:
cd core
php artisan package:installrequire evolution-cms/emcp "*"
php artisan migratePublish Config and Stubs
core/custom/config/cms/settings/eMCP.php is created automatically on the first request after install when it is missing, so emcp-config is only needed to restore the defaults. emcp-mcp-config changes the MCP server list, emcp-stubs scaffolds your own servers and tools.
Site-wide switches (write tools, manager/API endpoints, token scopes, rate limit, audit log, streaming) are also available as checkboxes in Tools → MCP settings ({manager_url}/emcp/settings, requires the settings permission). The page edits the same file and keeps its comments.
php artisan vendor:publish --provider="EvolutionCMS\\eMCP\\eMCPServiceProvider" --tag=emcp-config
php artisan vendor:publish --provider="EvolutionCMS\\eMCP\\eMCPServiceProvider" --tag=emcp-mcp-config
php artisan vendor:publish --provider="EvolutionCMS\\eMCP\\eMCPServiceProvider" --tag=emcp-stubsPublished files:
core/custom/config/cms/settings/eMCP.phpcore/custom/config/mcp.phpcore/stubs/mcp-*.stub
Quick Start (Internal + External)
The default contract is concept-agnostic and follows Laravel MCP behavior first.
Create your MCP server/tool classes:
php artisan make:mcp-server ContentServer
php artisan make:mcp-tool HealthToolGenerated classes are placed in core/custom/app/Mcp/....
Register server in
core/custom/config/mcp.php(servers[]).Test manager/internal route:
POST /{manager_prefix}/{handle}with manager session + permissionemcp.
Enable external API mode (if
sApiinstalled):
keep
mode.api=trueincore/custom/config/cms/settings/eMCP.phpcall
POST /{SAPI_BASE_PATH}/{SAPI_VERSION}/mcp/{handle}with Bearer JWT and requiredmcp:*scopes.get JWT from
POST /{SAPI_BASE_PATH}/{SAPI_VERSION}/token(sApi token endpoint).
Optional async:
set
queue.driver=stask, ensuresTaskinstalled, use dispatch endpoint for long-running jobs.
Personal access tokens (default API auth)
Since this version the API endpoint needs no extra packages: a manager user creates a personal access token and every request runs as that user, with that user's role, permissions and document groups — exactly as if they were logged into the manager.
Give the role the
emcppermission (admins have it aftermigrate).Open Tools → MCP tokens in the manager (
{manager_url}/emcp/tokens), or runphp artisan emcp:token:create <username> --scopes=mcp:read,mcp:call --expires=90.Connect the agent:
claude mcp add --transport http evo https://example.com/mcp/content --header "Authorization: Bearer emcp_..."# Codex ~/.codex/config.toml
[mcp_servers.evo]
url = "https://example.com/mcp/content"
bearer_token_env_var = "EVO_MCP_TOKEN"Scopes narrow a token, never widen the user: mcp:read (list/read), mcp:call (read-only
tools), mcp:write (evo.write.* tools, also gated by security.enable_write_tools),
mcp:destructive (extension tools that delete data, also gated by
security.enable_destructive_tools), mcp:code (saving snippets, plugins and @EVAL-style
bindings, also gated by security.enable_code_tools and a snippet/plugin/module permission),
mcp:admin. Tokens are stored hashed, can expire, and are revoked from the same page or with
emcp:token:revoke. emcp:token:list shows what exists.
auth.mode in core/custom/config/cms/settings/eMCP.php selects pat (default), sapi_jwt
(seiger/sapi JWT, now also impersonating the JWT user) or none.
Write tools
evo.write.content.update|create|publish, evo.write.elements.save, evo.write.cache.clear
plus the read tools evo.elements.list|get. Each one re-checks the manager permission of the
matching manager action (save_document, publish_document, save_chunk, new_snippet, ...),
document-group access, element locks, fires the same OnBefore*FormSave/On*FormSave events
and writes a manager_log row, so an admin sees API changes next to browser ones.
Tools from other extras
An extra contributes tools by implementing EvolutionCMS\eMCP\Contracts\ToolProvider and
registering it in its service provider's boot():
if (class_exists(\EvolutionCMS\eMCP\Services\ToolRegistry::class)) {
app(\EvolutionCMS\eMCP\Services\ToolRegistry::class)->register(new MyToolProvider());
}Tools are plain Laravel\Mcp\Server\Tool classes with a #[Name('vendor.domain.action')].
Mark the ones that change the site with EvolutionCMS\eMCP\Contracts\WritesSite so
security.enable_write_tools and the mcp:write scope apply to them, the ones that delete data
with DestructiveSite, the ones that store server-side code with ExecutesCode, and declare a
required Evo permission with RequiresPermission. Tool code
runs as the impersonated manager, so evo()->hasPermission() and the extra's own guards behave as
on the page; Support\ToolError builds structured error results. Alternatively list classes under
mcp.servers[].extra_tools. Example: elcreator/aimage ships aimage.* tools this way. The full
contract (naming, identity rules, error format) is in DOCS.md.
Try it in Docker
cd docker && docker compose up --build # prints the site URL and a ready-made token
EVO_EXTRAS=elcreator/aimage AIMAGE_API_KEY=... docker compose up --build # with extras
docker/smoke.sh # runs an end-to-end check against itDesign Philosophy (Optional Reading)
Why This Product Exists (4 Core Questions, Aristotle)
This is the shortest way to understand eMCP as a product, not just a package.
Material cause: what it consists of (hard boundaries):
protocol/runtime from
laravel/mcpEvo adapter layer (
ServiceProvider, registry, routes, middleware, publish)optional access/async integrations (
sApi,sTask)canonical contracts (
SPEC.md,TOOLSET.md)
Formal cause: what form makes it a product (not components):
one execution contract from request to audited response
one policy model for manager/API access (
ACL + scopes + limits)one versioned public tool contract for ecosystem consumers
one stable extension model for third-party packages
Efficient cause: what puts it in motion (workflows + triggers):
internal trigger: manager MCP call (
/{manager_prefix}/{handle})external trigger: API MCP call (
/{SAPI_BASE_PATH}/{SAPI_VERSION}/mcp/{handle})async trigger: dispatch into
sTaskworker for long operationslifecycle trigger: package install/publish/register/test
Final cause: why it is built this way:
keep Laravel MCP semantics intact
keep Evo integration explicit and operable
support both internal and external MCP usage
allow multiple orchestration strategies on top of one neutral MCP foundation
Conceptual Model (Design Lens)
This lens helps explain architecture decisions:
set theory: CMS data is structured sets (site -> nodes -> attributes)
Peano sequence: workflows are ordered state transitions
Godel limits: self-referential rule systems need strict boundaries
Practical implication:
eMCP stays as a contract/runtime layer
orchestration logic stays in consuming packages
policy/audit/human gates prevent recursive rule loops from becoming unsafe
Install Verification (1 minute)
For Gate A, use manager endpoint /{manager_prefix}/{server_handle} (default: /emcp/content).
Gate A is manager ACL protected, so run checks as a logged-in manager with emcp permission (session cookie required).
Verify
GETreturns405on MCP endpoint:
curl -i -X GET http://localhost/<MANAGER_PREFIX>/<SERVER_HANDLE> \
-H 'Cookie: evo_session=<MANAGER_SESSION_COOKIE>'Verify JSON-RPC
initialize:
curl -i -X POST http://localhost/<MANAGER_PREFIX>/<SERVER_HANDLE> \
-H 'Cookie: evo_session=<MANAGER_SESSION_COOKIE>' \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":"init-1","method":"initialize","params":{"protocolVersion":"2025-11-25","capabilities":{},"clientInfo":{"name":"smoke","version":"1.0.0"}}}'Expected:
HTTP
200for validinitialize.MCP-Session-Idpresent in response headers.stable HTTP
405onGET.
Register MCP Servers (Evo style)
Unlike Laravel default routes/ai.php, eMCP registers servers from config.
Example in core/custom/config/mcp.php:
return [
'redirect_domains' => ['*'],
'servers' => [
[
'handle' => 'content',
'transport' => 'web',
'route' => '/mcp/content',
'class' => EvolutionCMS\eMCP\Servers\ContentServer::class,
'enabled' => true,
'auth' => 'sapi_jwt',
'scopes' => ['mcp:read', 'mcp:call'],
],
[
'handle' => 'content-local',
'transport' => 'local',
'class' => EvolutionCMS\eMCP\Servers\ContentServer::class,
'enabled' => false,
],
],
];Notes:
Gate A manager endpoint is still
/{manager_prefix}/{handle}(for example/emcp/content).servers[*].routeis used by web transport registration and becomes externally relevant in API mode (Gate B+).content-localis disabled by default to avoid duplicate tool-name registration conflict withcontent.
Access Model
Manager/internal access: Evo permission
emcpAPI access (via sApi): JWT scopes (
mcp:read,mcp:call,mcp:admin)Domain reads (
evo.content.*,evo.model.*) are read-only by default
Ecosystem Interop
eMCP is the MCP platform layer for the Evo ecosystem:
LaravelMcp: upstream protocol/runtime contract (kept intact).sApi: external API kernel + JWT route-provider discovery.sTask: async worker/task execution and progress.eAi: AI runtime can call MCP tools through manager or API mode.dAi: manager-side orchestration UI can consume eMCP tools as a stable contract.
This keeps the core declarative and neutral: one MCP foundation for multiple orchestration concepts.
Evo Domain Tools
Implemented now:
evo.content.search|get|root_tree|descendants|ancestors|children|siblingsOptional (implemented):
evo.content.neighbors|prev_siblings|next_siblings|children_range|siblings_rangeTV-aware queries via structured
with_tvs,tv_filters,tv_orderevo.model.list|getimplemented with per-model explicit allowlist projection and sensitive-field defense-in-depth blacklist
Artisan Commands
From Laravel MCP (available via eMCP adapter):
php artisan make:mcp-server ContentServer
php artisan make:mcp-tool ListResourcesTool
php artisan make:mcp-resource DocsResource
php artisan make:mcp-prompt SummaryPrompt
php artisan mcp:start content-localFor mcp:start content-local, first enable content-local in core/custom/config/mcp.php and disable conflicting server entries if they expose identical tool names.
Third-party servers
Register project-specific tools on a separate Laravel\Mcp\Server class and add
that class as its own entry in core/custom/config/mcp.php. Third-party tool
names must not use the reserved evo.* namespace. Do not subclass the package
ContentServer only to append project tools, because the inherited evo.*
toolset is package-owned and the registry will reject that external server.
php artisan emcp:test --server=<handle> runs generic initialize and
tools/list checks for third-party servers. When the selected class is the
canonical eMCP ContentServer, it also verifies the required Evolution toolset.
Use php artisan emcp:list-servers to see both accepted servers and concrete
reasons why configured entries were rejected.
eMCP operational commands:
php artisan emcp:testphp artisan emcp:list-serversphp artisan emcp:sync-workerscomposer run governance:update-lockcomposer run ci:checkcomposer run benchmark:runcomposer run benchmark:leaderboardcomposer run test:integration:clean-install
Repository Checks (for first run in package workspace)
If you are validating this repository directly:
composer run check
make test
composer run ci:check
make benchmark
make leaderboardThese checks validate composer.json and run PHP syntax lint across package sources.
One-click demo + full MCP verification:
make demo-allThis target installs demo Evo, starts php -S, issues sApi JWT, runs php artisan emcp:test, then runs composer run test with HTTP runtime integration enabled.
After run, detailed evidence is written to:
demo/logs.md(token/masked auth info, MCP request payloads, HTTP statuses, responses, manual verification commands, plus negative probes: 401/403/413/415/409/429 andevo.model.get(User)sanity)demo/logs.mdalso includes localsTasklifecycle proof (queued -> completed) viaphp artisan stask:workerin demo runtime./tmp/emcp-demo-php-server.log(php built-in server log)
If GitHub API auth is needed during install, pass token via ENV (same pattern as evolution):
GITHUB_PAT=ghp_xxx make demo-allFallback ENV names are also supported: GITHUB_TOKEN, GH_TOKEN.
Manual content-read MCP examples (same calls used in demo/logs.md):
# list tools
curl -sS -H 'Content-Type: application/json' -H 'Authorization: Bearer <TOKEN>' \
-d '{"jsonrpc":"2.0","id":"tools-1","method":"tools/list","params":{}}' \
'http://127.0.0.1:8787/api/v1/mcp/content'
# read content slice from DB
curl -sS -H 'Content-Type: application/json' -H 'Authorization: Bearer <TOKEN>' \
-d '{"jsonrpc":"2.0","id":"search-1","method":"tools/call","params":{"name":"evo.content.search","arguments":{"limit":3,"offset":0}}}' \
'http://127.0.0.1:8787/api/v1/mcp/content'
# read one document
curl -sS -H 'Content-Type: application/json' -H 'Authorization: Bearer <TOKEN>' \
-d '{"jsonrpc":"2.0","id":"get-1","method":"tools/call","params":{"name":"evo.content.get","arguments":{"id":1}}}' \
'http://127.0.0.1:8787/api/v1/mcp/content'Optional runtime integration check (against deployed environment):
EMCP_INTEGRATION_ENABLED=1 \
EMCP_BASE_URL="https://example.org" \
EMCP_API_PATH="/api/v1/mcp/{server}" \
EMCP_API_TOKEN="<jwt>" \
EMCP_SERVER_HANDLE="content" \
EMCP_DISPATCH_CHECK=1 \
composer run test:integration:runtimeCI release note:
.github/workflows/ci.ymlrunsdemo-runtime-proof,runtime-integration, andmigration-matrix(sqlite/mysql/pgsql) onrelease/*pushes.Configure branch protection to make these jobs required for RC/release merges.
Async (sTask-first)
If queue.driver=stask and sTask is installed, eMCP can run long MCP calls via worker emcp_dispatch.
If sTask is missing, fallback behavior follows queue.failover (sync or fail).
Security Notes
Keep secrets in
.envorcore/custom/config/*.Audit logs must redact tokens/secrets.
Use tool denylist and server allowlist for production hardening.
Security Defaults
deny-by-default for manager/API without explicit access.
security.enable_write_tools=falseby default.sensitive key redaction in logs is mandatory.
API scope checks (
mcp:read|call|admin) are required in Gate B+.depth/limit/payloadlimits should stay enabled.
Security release checklist: SECURITY_CHECKLIST.md.
Threat model: THREAT_MODEL.md.
Architecture freeze: ARCHITECTURE_FREEZE_CHECKLIST.md.
License
MIT (LICENSE).
This server cannot be deployed
Maintenance
Related MCP Connectors
Agent-native website builder: create, edit, and host websites via MCP
Agent-native web hosting — deploy sites, manage DNS, register domains, scale infrastructure
Agent-first web hosting: deploy sites, apps, databases and domains over MCP.
Host an agent's pages at clean, permanent URLs. Publish, organize, edit, search and re-find docs.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceEnables external AI agents to edit and manage a self-hosted website via a token-gated MCP server, including page content, data, media, and sandboxed functions with validation and rollback.3Apache 2.0
- AlicenseAqualityBmaintenanceEnables agents to create and publish content to a Terminus instance, including screen and playlist management, discovery, and documentation search.10244 npm1MIT
- FlicenseNot gradedqualityBmaintenanceConnects MCP-capable agents to an authenticated ELEMS account, enabling website creation and inventory management, page and element editing, media and template handling, structured content authoring, draft previews, and explicit publishing.-

Siglata MCPofficial
AlicenseNot gradedqualityCmaintenanceConnects MCP-compatible agents to company files, spreadsheets, ERP exports, and records with per-person permissions, enabling document search, SQL workbook queries, versioned spreadsheet edits, file management, and role administration with history.MIT