eMCP for Evolution CMS
Otorga a los agentes de IA acceso de lectura y escritura al árbol de documentos, variables de plantilla y elementos, con permisos de administrador, grupos de documentos, bloqueos de elementos y auditoría de manager_log aplicados a cada llamada. Además, generadores artisan para crear tus propios servidores y herramientas MCP dentro de Evo.
Documentación
eMCP para Evolution CMS
eMCP es la capa de integración de Evolution CMS para laravel/mcp.
Adapta Laravel MCP al runtime de Evo con:
- Publicación de configuración nativa de Evo
- Controles de ACL del administrador y ámbito de sApi
- Despacho asíncrono opcional a través de sTask
- Sin requisito de esqueleto de aplicación Laravel
- Herramientas MCP de dominio Evo para el árbol de documentos (
SiteContent+ TVs)
La implementación comienza con una puerta MVP estricta:
- Transporte web
- Modo administrador
initialize+tools/list
Estilo de diseño:
- Primero el contrato (
TOOLSET.md+ validadores) - Registro de servidores declarativo y basado en configuración (
config/mcp.php) - Pipeline de manejadores explícito (
validate -> authorize -> query -> map -> paginate)
Si necesitas la arquitectura completa y los contratos, consulta DOCS.md (EN) o DOCS.uk.md (UA).
Contrato canónico público de herramientas: TOOLSET.md.
Política de versionado y BC: PRD.md (sección API Stability Policy).
Manual de operaciones: OPERATIONS.md.
Requisitos
- Evolution CMS 3.5.2+
- PHP 8.3+
- Composer 2.2+
seiger/sapi1.x (instalado como dependencia; solo se usa cuandoauth.mode = sapi_jwt)seiger/stask1.x (instalado como dependencia)
Instalación
Desde tu directorio core de Evo:
cd core
php artisan package:installrequire evolution-cms/emcp "*"
php artisan migrate
Publicar Configuración y Stubs
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-stubs
Archivos publicados:
core/custom/config/cms/settings/eMCP.phpcore/custom/config/mcp.phpcore/stubs/mcp-*.stub
Inicio Rápido (Interno + Externo)
El contrato predeterminado es agnóstico al concepto y sigue el comportamiento de Laravel MCP en primer lugar.
- Crea tus clases de servidor/herramienta MCP:
php artisan make:mcp-server ContentServer
php artisan make:mcp-tool HealthTool
Las clases generadas se colocan en core/custom/app/Mcp/....
- Registra el servidor en
core/custom/config/mcp.php(servers[]). - Prueba la ruta interna/administrador:
POST /{manager_prefix}/{handle}con sesión de administrador y permisoemcp.
- Habilita el modo API externo (si
sApiestá instalado):
- mantén
mode.api=trueencore/custom/config/cms/settings/eMCP.php - llama a
POST /{SAPI_BASE_PATH}/{SAPI_VERSION}/mcp/{handle}con Bearer JWT y los ámbitosmcp:*requeridos. - obtén el JWT desde
POST /{SAPI_BASE_PATH}/{SAPI_VERSION}/token(endpoint de token sApi).
- Asíncrono opcional:
- establece
queue.driver=stask, asegúrate de quesTaskesté instalado, usa el endpoint de despacho para trabajos de larga duración.
Tokens de acceso personal (autenticación API predeterminada)
Desde esta versión, el endpoint de API no necesita paquetes adicionales: un usuario administrador crea un token de acceso personal y cada solicitud se ejecuta como ese usuario, con el rol, los permisos y los grupos de documentos de ese usuario — exactamente como si estuvieran conectados al administrador.
- Otorga al rol el permiso
emcp(los administradores lo tienen después demigrate). - Abre Herramientas → Tokens MCP en el administrador (
{manager_url}/emcp/tokens), o ejecutaphp artisan emcp:token:create <username> --scopes=mcp:read,mcp:call --expires=90. - Conecta el agente:
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"
Los ámbitos restringen un token, nunca amplían al usuario: mcp:read (listar/leer), mcp:call (herramientas
de solo lectura), mcp:write (herramientas evo.write.*, también controladas por security.enable_write_tools),
mcp:admin. Los tokens se almacenan con hash, pueden expirar y se revocan desde la misma página o con
emcp:token:revoke. emcp:token:list muestra lo que existe.
auth.mode en core/custom/config/cms/settings/eMCP.php selecciona pat (predeterminado), sapi_jwt
(JWT de seiger/sapi, ahora también suplantando al usuario del JWT) o none.
Herramientas de escritura
evo.write.content.update|create|publish, evo.write.elements.save, evo.write.cache.clear
más las herramientas de lectura evo.elements.list|get. Cada una vuelve a verificar el permiso de administrador de la
acción de administrador correspondiente (save_document, publish_document, save_chunk, new_snippet, ...),
el acceso a grupos de documentos, los bloqueos de elementos, dispara los mismos eventos OnBefore*FormSave/On*FormSave
y escribe una fila manager_log, para que un administrador vea los cambios de API junto a los del navegador.
Herramientas de otros extras
Un extra contribuye con herramientas implementando EvolutionCMS\eMCP\Contracts\ToolProvider y
registrándolo en el boot() de su proveedor de servicios:
if (class_exists(\EvolutionCMS\eMCP\Services\ToolRegistry::class)) {
app(\EvolutionCMS\eMCP\Services\ToolRegistry::class)->register(new MyToolProvider());
}
Las herramientas son clases Laravel\Mcp\Server\Tool simples; marca las que cambian el sitio con
EvolutionCMS\eMCP\Contracts\WritesSite para que security.enable_write_tools y el ámbito mcp:write
se apliquen a ellas. El código de la herramienta se ejecuta como el administrador suplantado, por lo que evo()->hasPermission() y
las propias protecciones del extra se comportan como en la página. Alternativamente, lista las clases bajo
mcp.servers[].extra_tools. Ejemplo: elcreator/aimage incluye herramientas aimage.* de esta manera.
Pruébalo en 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 it
Filosofía de Diseño (Lectura Opcional)
Por Qué Existe Este Producto (4 Preguntas Centrales, Aristóteles)
Esta es la forma más corta de entender eMCP como producto, no solo como paquete.
- Causa material: de qué consiste (límites duros):
- protocolo/runtime de
laravel/mcp - capa adaptadora de Evo (
ServiceProvider, registro, rutas, middleware, publicación) - integraciones opcionales de acceso/asíncrono (
sApi,sTask) - contratos canónicos (
SPEC.md,TOOLSET.md)
- Causa formal: qué forma lo convierte en producto (no componentes):
- un contrato de ejecución desde la solicitud hasta la respuesta auditada
- un modelo de política para acceso administrador/API (
ACL + scopes + limits) - un contrato público de herramientas versionado para consumidores del ecosistema
- un modelo de extensión estable para paquetes de terceros
- Causa eficiente: qué lo pone en movimiento (flujos de trabajo + disparadores):
- disparador interno: llamada MCP del administrador (
/{manager_prefix}/{handle}) - disparador externo: llamada MCP de API (
/{SAPI_BASE_PATH}/{SAPI_VERSION}/mcp/{handle}) - disparador asíncrono: despacho al trabajador
sTaskpara operaciones largas - disparador de ciclo de vida: instalación/publicación/registro/prueba del paquete
- Causa final: por qué está construido de esta manera:
- mantener intacta la semántica de Laravel MCP
- mantener la integración de Evo explícita y operable
- soportar uso MCP interno y externo
- permitir múltiples estrategias de orquestación sobre una base MCP neutral
Modelo Conceptual (Lente de Diseño)
Esta lente ayuda a explicar las decisiones de arquitectura:
- teoría de conjuntos: los datos del CMS son conjuntos estructurados (sitio -> nodos -> atributos)
- secuencia de Peano: los flujos de trabajo son transiciones de estado ordenadas
- límites de Godel: los sistemas de reglas autorreferenciales necesitan límites estrictos
Implicación práctica:
- eMCP permanece como capa de contrato/runtime
- la lógica de orquestación permanece en los paquetes consumidores
- las puertas de política/auditoría/humanas evitan que los bucles de reglas recursivas se vuelvan inseguros
Verificación de Instalación (1 minuto)
Para la Puerta A, usa el endpoint de administrador /{manager_prefix}/{server_handle} (predeterminado: /emcp/content).
La Puerta A está protegida por ACL del administrador, así que ejecuta las comprobaciones como administrador conectado con permiso emcp (se requiere cookie de sesión).
- Verifica que
GETdevuelva405en el endpoint MCP:
curl -i -X GET http://localhost/<MANAGER_PREFIX>/<SERVER_HANDLE> \
-H 'Cookie: evo_session=<MANAGER_SESSION_COOKIE>'
- Verifica 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"}}}'
Esperado:
- HTTP
200parainitializeválido. MCP-Session-Idpresente en los encabezados de respuesta.- HTTP
405estable enGET.
Registrar Servidores MCP (estilo Evo)
A diferencia del routes/ai.php predeterminado de Laravel, eMCP registra servidores desde configuración.
Ejemplo en 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,
],
],
];
Notas:
- El endpoint de administrador de la Puerta A sigue siendo
/{manager_prefix}/{handle}(por ejemplo/emcp/content). servers[*].routees usado por el registro de transporte web y se vuelve relevante externamente en modo API (Puerta B+).content-localestá deshabilitado por defecto para evitar conflictos de registro de nombres de herramientas duplicados concontent.
Modelo de Acceso
- Acceso administrador/interno: permiso de Evo
emcp - Acceso API (vía sApi): ámbitos JWT (
mcp:read,mcp:call,mcp:admin) - Lecturas de dominio (
evo.content.*,evo.model.*) son de solo lectura por defecto
Interoperabilidad del Ecosistema
eMCP es la capa de plataforma MCP para el ecosistema Evo:
LaravelMcp: contrato de protocolo/runtime ascendente (mantenido intacto).sApi: kernel de API externa + descubrimiento de proveedores de rutas JWT.sTask: ejecución de trabajos/tareas asíncronas y progreso.eAi: el runtime de IA puede llamar herramientas MCP a través del modo administrador o API.dAi: la UI de orquestación del lado del administrador puede consumir herramientas eMCP como contrato estable.
Esto mantiene el núcleo declarativo y neutral: una base MCP para múltiples conceptos de orquestación.
Herramientas de Dominio Evo
- Implementadas ahora:
evo.content.search|get|root_tree|descendants|ancestors|children|siblings - Opcionales (implementadas):
evo.content.neighbors|prev_siblings|next_siblings|children_range|siblings_range - Consultas conscientes de TV vía
with_tvs,tv_filters,tv_orderestructurados evo.model.list|getimplementado con proyección de lista blanca explícita por modelo y lista negra de defensa en profundidad para campos sensibles
Comandos Artisan
De Laravel MCP (disponibles vía adaptador eMCP):
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-local
Para mcp:start content-local, primero habilita content-local en core/custom/config/mcp.php y deshabilita entradas de servidor conflictivas si exponen nombres de herramientas idénticos.
Servidores de terceros
Registra herramientas específicas del proyecto en una clase Laravel\Mcp\Server separada y agrega
esa clase como su propia entrada en core/custom/config/mcp.php. Los nombres de herramientas de terceros
no deben usar el espacio de nombres reservado evo.*. No subclases el ContentServer
del paquete solo para agregar herramientas del proyecto, porque el conjunto de herramientas evo.*
heredado es propiedad del paquete y el registro rechazará ese servidor externo.
php artisan emcp:test --server=<handle> ejecuta comprobaciones genéricas initialize y
tools/list para servidores de terceros. Cuando la clase seleccionada es el
ContentServer canónico de eMCP, también verifica el conjunto de herramientas de Evolution requerido.
Usa php artisan emcp:list-servers para ver tanto los servidores aceptados como las razones
concretas por las que las entradas configuradas fueron rechazadas.
Comandos operativos de eMCP:
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
Comprobaciones del Repositorio (para primera ejecución en el espacio de trabajo del paquete)
Si estás validando este repositorio directamente:
composer run check
make test
composer run ci:check
make benchmark
make leaderboard
Estas comprobaciones validan composer.json y ejecutan lint de sintaxis PHP en las fuentes del paquete.
Demo de un clic + verificación MCP completa:
make demo-all
Este objetivo instala Evo demo, inicia php -S, emite sApi JWT, ejecuta php artisan emcp:test, luego ejecuta composer run test con integración de runtime HTTP habilitada.
Después de la ejecución, la evidencia detallada se escribe en:
demo/logs.md(información de autenticación enmascarada/token, cargas útiles de solicitud MCP, estados HTTP, respuestas, comandos de verificación manual, más sondas negativas: 401/403/413/415/409/429 y verificación de sanidadevo.model.get(User))demo/logs.mdtambién incluye prueba de ciclo de vida localsTask(queued -> completed) víaphp artisan stask:workeren el runtime demo./tmp/emcp-demo-php-server.log(log del servidor integrado de PHP)
Si se necesita autenticación de API de GitHub durante la instalación, pasa el token vía ENV (mismo patrón que evolution):
GITHUB_PAT=ghp_xxx make demo-all
También se admiten nombres ENV alternativos: GITHUB_TOKEN, GH_TOKEN.
Ejemplos manuales de MCP de lectura de contenido (mismas llamadas usadas en 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'
Comprobación opcional de integración de runtime (contra entorno desplegado):
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:runtime
Nota de release de CI:
.github/workflows/ci.ymlejecutademo-runtime-proof,runtime-integrationymigration-matrix(sqlite/mysql/pgsql) en pushesrelease/*.- Configura protección de rama para hacer estos trabajos obligatorios para merges de RC/release.
Asíncrono (sTask primero)
Si queue.driver=stask y sTask están instalados, eMCP puede ejecutar llamadas MCP largas vía trabajador emcp_dispatch.
Si falta sTask, el comportamiento de respaldo sigue queue.failover (sync o fail).
Notas de Seguridad
- Mantén los secretos en
.envocore/custom/config/*. - Los logs de auditoría deben redactar tokens/secretos.
- Usa lista negra de herramientas y lista blanca de servidores para endurecer producción.
Valores Predeterminados de Seguridad
- denegar por defecto para administrador/API sin acceso explícito.
security.enable_write_tools=falsepor defecto.- La redacción de claves sensibles en logs es obligatoria.
- Las comprobaciones de ámbito de API (
mcp:read|call|admin) son requeridas en la Puerta B+. - Los límites de
depth/limit/payloaddeben permanecer habilitados.
Lista de verificación de seguridad de release: SECURITY_CHECKLIST.md.
Modelo de amenazas: THREAT_MODEL.md.
Congelación de arquitectura: ARCHITECTURE_FREEZE_CHECKLIST.md.
Licencia
MIT (LICENSE).