MCP Server
El servidor MCP de Content Island (@content-island/mcp) es un servidor Model Context Protocol que expone tu proyecto Content Island a cualquier cliente MCP compatible — VS Code, Cursor, Windsurf, Claude Desktop, Claude Code, etc.
Una vez configurado, el agente puede leer el esquema del proyecto, listar y filtrar contenidos, crear nuevas entradas, actualizar valores de campo, publicar drafts, subir recursos e incluso gestionar el esquema del proyecto — creando, editando y eliminando modelos (Entities) y Enums — todo sin salir del editor. Por debajo, cada tool envuelve las mismas operaciones que ya documentamos en la API REST y en la librería cliente JavaScript.
Instalación
El servidor está publicado en npm y se ejecuta vía npx — no hace falta instalación global. Tu cliente MCP lo levantará bajo demanda con el fragmento de configuración de abajo.
npx @content-island/mcp@latestRequisitos: Node.js 18 o superior, y cualquier cliente MCP (VS Code, Cursor, Windsurf, Claude Desktop, Claude Code, …).
Configura tu cliente MCP
La mayoría de clientes MCP aceptan el mismo formato de configuración JSON. Añade el siguiente fragmento de configuración a la configuración de servidores MCP de tu cliente — la ubicación del archivo cambia según el cliente (p. ej. claude_desktop_config.json para Claude Desktop, la UI de configuración MCP en Cursor / Windsurf / VS Code).
{"mcpServers": { "contentIsland": { "command": "npx", "args": ["@content-island/mcp@latest"], "env": { "CONTENT_ISLAND_ACCESS_TOKEN": "<TU_TOKEN_DE_CONTENT_ISLAND>" } }}}Sustituye <TU_TOKEN_DE_CONTENT_ISLAND> por el token de tu proyecto, que puedes copiar desde la pestaña General.
Variables de entorno
| Nombre | Obligatoria | Por defecto | Descripción |
|---|---|---|---|
CONTENT_ISLAND_ACCESS_TOKEN | sí | — | Token de acceso del proyecto. Usa un Write Token si quieres que el agente haga operaciones de escritura. |
CONTENT_ISLAND_DOMAIN | no | api.contentisland.net | Dominio de la API. Sobreescríbelo si usas Content Island On Premise. |
CONTENT_ISLAND_SECURE_PROTOCOL | no | true | Si usar HTTPS. Pon false para caer a HTTP. |
CONTENT_ISLAND_API_VERSION | no | 1.0 | Versión de la API REST con la que hablar. |
Referencia de tools
El servidor registra doce tools. Dos son de solo lectura; las otras diez están protegidas por write token. Las primeras seis gestionan contenido; las últimas seis gestionan el esquema del proyecto (modelos y enums — consulta Gestionar el esquema de tu proyecto).
| Tool | Tipo | Envuelve | Equivalente en el cliente |
|---|---|---|---|
get-content-island-project | lectura | GET /project | client.getProject |
list-content-island-contents | lectura | GET /contents | client.getContentList |
create-content-island-content | escritura | POST /content | client.createContent |
update-content-island-field-value | escritura | PUT /content/:id | client.updateContentFieldValue |
publish-content-island-content | escritura | POST /content/:id/publish | client.publishContent |
upload-content-island-media | escritura | POST /resource/upload | client.uploadMedia |
create-content-island-model | escritura | POST /model/entity | client.createModel |
update-content-island-model | escritura | PUT /model/entity/:id | client.updateModel |
delete-content-island-model | escritura | DELETE /model/entity/:id | client.deleteModel |
create-content-island-enum | escritura | POST /model/enum | client.createEnum |
update-content-island-enum | escritura | PUT /model/enum/:id | client.updateEnum |
delete-content-island-enum | escritura | DELETE /model/enum/:id | client.deleteEnum |
get-content-island-project
Devuelve el esquema del proyecto: idiomas, content types y los campos de cada content type. El agente debería normalmente llamarlo primero para saber qué nombres de contentType, nombres de campo e idiomas son válidos.
Sin parámetros de entrada.
list-content-island-contents
Lista entradas de contenido con filtros opcionales y paginación. Devuelve { items, skip, take, hasMore } para que el agente pueda recorrer proyectos grandes.
| Input | Tipo | Descripción |
|---|---|---|
contentType | string | Filtra por nombre de content type. |
id | string | string[] | Un único id, o un array de ids. |
language | string | Restringe qué valores de campo se incluyen (no quita los contenidos que no tengan traducción). |
status | 'draft' | 'changed' | 'published' | array de los anteriores | Filtra por estado de publicación. Pasa ['draft', 'changed'] para encontrar contenidos con datos sin publicar. |
includeRelatedContent | boolean | Expande referencias a contenidos relacionados en línea. |
sort | { contentType?: 'asc' | 'desc'; lastUpdate?: 'asc' | 'desc' } | Orden. |
take | number (1–100) | Tamaño de página. Por defecto 25. |
skip | number | Offset. Úsalo junto con take para paginar. |
create-content-island-content
Crea una nueva entrada de contenido. Se espera que el agente llame antes a get-content-island-project para conocer el contentType válido, los nombres de campo y los códigos de idioma.
| Input | Tipo | Descripción |
|---|---|---|
contentType | string (obligatorio) | Nombre del content type (debe coincidir con un modelo existente). |
name | string (obligatorio) | Nombre legible para la nueva entrada. |
content | Array<{ language?: string; fields: { name: string; value: any }[] }> (opcional) | Una entrada por idioma. Si se omite, la entrada se crea sin valores — se pueden rellenar después con la siguiente tool. |
update-content-island-field-value
Actualiza (o hace upsert, cuando el valor aún no existe) un único campo de una entrada existente.
| Input | Tipo | Descripción |
|---|---|---|
contentId | string (obligatorio) | ID de la entrada de contenido. |
fieldName | string (obligatorio) | Nombre del campo tal como está definido en el modelo. |
language | string (obligatorio) | Código del idioma del valor que se está actualizando. |
value | any (obligatorio) | Nuevo valor. El tipo depende de la definición del campo. |
publish-content-island-content
Promociona el draft actual de una entrada al estado live.
| Input | Tipo | Descripción |
|---|---|---|
contentId | string (obligatorio) | ID de la entrada de contenido. |
upload-content-island-media
Sube un fichero desde una ruta local o una URL pública al almacenamiento del proyecto. Devuelve { name, url }.
| Input | Tipo | Descripción |
|---|---|---|
source | string (obligatorio) | Ruta a fichero local (p. ej. ./assets/hero.png) o URL HTTP(S) (p. ej. https://example.com/photo.jpg). |
fileName | string (opcional) | Sobreescribe el nombre con el que se registra el fichero. Por defecto, se deriva del source. |
Gestionar el esquema de tu proyecto (modelos y enums)
Las últimas seis tools permiten a un agente evolucionar el esquema del proyecto — no solo su contenido. Con ellas el agente puede crear una Entity (un content type) con una lista de campos estructurada, crear un Enum (una lista cerrada de valores) y editar o eliminar cualquiera de los dos. Las seis requieren un Write Token.
El agente debería llamar primero a get-content-island-project: devuelve cada modelo con su id, name, type
(entity / enum) e ids de campo/valor, de modo que el agente pueda referirse a las cosas por nombre en tu prompt y
resolver los ids él mismo.
Tipos de campo
El type de un campo es uno de ocho primitivos — short-text, long-text, number, date, date-time, media,
boolean, color — o uno de los dos tipos relacionales:
relation— apunta a otra entidad. Pasa el id de la entidad de destino comorelatedModelId.enum— apunta a un enum. Pasa el id del enum comorelatedModelId.
Cualquier campo puede poner isArray: true para almacenar una lista de ese tipo. Nunca construyes el compuesto
almacenado "<id>|<Name>" — el servidor lo ensambla a partir de relatedModelId.
Validaciones
Cada campo puede llevar validaciones, almacenadas al crear el modelo y aplicadas cuando el contenido se guarda o se publica:
| Validación | Args |
|---|---|
required | — |
unique | — |
min-length | { length: <number> } |
max-length | { length: <number> } |
media-type | { allowedExtensions: ["png", "jpg"] } |
Reglas de nombres
Los nombres de modelo, enum, campo y valor deben coincidir con /^[a-zA-Z0-9_ -]+$/, tener como máximo 128
caracteres, no ser una palabra reservada de tipo de campo (los ocho primitivos de arriba) y ser únicos en su ámbito
(modelos/enums únicos en el proyecto; nombres de campo y valores de enum únicos dentro de su modelo, sin distinguir
mayúsculas/minúsculas). Una violación se devuelve como 400 VALIDATION_ERROR.
Edición declarativa
Las tools update-* son declarativas: la tool lee el modelo actual y aplica tus operaciones por encima, de modo que
los campos/valores no tocados (y sus ids) se preservan automáticamente — nunca reenvías la lista completa.
update-content-island-model:rename,addFields,updateFields(por id),removeFieldIds.update-content-island-enum:rename,addValues,renameValues(por id),removeValueIds.
Protección de 2 pasos para operaciones destructivas
Eliminar un campo/valor o borrar un modelo/enum es destructivo (borra en cascada valores de contenido). Estas tools
imponen una protección de dos pasos: sin confirm: true devuelven un dry-run que describe el impacto y no mutan
nada. El agente tiene la instrucción de nunca pasar confirm: true en la primera llamada — debe mostrarte el dry-run
y solo reinvocar con confirm: true después de que lo apruebes explícitamente.
// delete-content-island-model, primera llamada (sin confirm) → dry-run, nada eliminado{ "dryRun": true, "wouldDeleteContentCount": 12, "summary": "Deleting \"Author\" would also delete 12 content(s) of this type. Re-invoke with confirm: true to apply. …"}Protección por referencias
Eliminar un modelo o enum que está referenciado por un campo de otro modelo se rechaza con 409 CONFLICT — no hay
forma de forzarlo. Elimina o reapunta primero el campo que lo referencia, y luego elimina.
create-content-island-model
Crea una Entity con una lista de campos estructurada.
| Input | Tipo | Descripción |
|---|---|---|
name | string (obligatorio) | Nombre del modelo. No vacío, cumple las reglas de nombres, no es palabra reservada, único en el proyecto. |
fieldList | array (obligatorio) | Los campos, en orden (≥1). Cada uno: { name, type, relatedModelId?, isArray?, validations? }. |
update-content-island-model
Edición declarativa de una Entity.
| Input | Tipo | Descripción |
|---|---|---|
modelId | string (obligatorio) | El id de la entidad a actualizar. |
rename | string (opcional) | Nuevo nombre del modelo. |
addFields | array (opcional) | Campos a añadir al final. |
updateFields | array (opcional) | Campos existentes a modificar, identificados por id. |
removeFieldIds | string[] (opc.) | Ids de campos a eliminar. Destructivo — protegido por confirm. |
confirm | boolean (opc.) | Aplica un cambio destructivo. Nunca lo pongas en la primera llamada (ver arriba). |
delete-content-island-model
Elimina una Entity y todo su contenido (dry-run salvo confirm: true; 409 si está referenciada).
| Input | Tipo | Descripción |
|---|---|---|
modelId | string (obligatorio) | El id de la entidad a eliminar. |
confirm | boolean (opc.) | Realiza la eliminación. Nunca lo pongas en la primera llamada — confirma un dry-run. |
create-content-island-enum
Crea un Enum (lista cerrada de valores de texto).
| Input | Tipo | Descripción |
|---|---|---|
name | string (obligatorio) | Nombre del enum (mismas reglas que el nombre de un modelo). |
values | string[] (oblig.) | Los valores, en orden (≥1). Strings simples; el servidor asigna los ids. |
update-content-island-enum
Edición declarativa de un Enum.
| Input | Tipo | Descripción |
|---|---|---|
enumId | string (obligatorio) | El id del enum a actualizar. |
rename | string (opcional) | Nuevo nombre del enum. |
addValues | string[] (opc.) | Valores a añadir al final. |
renameValues | array (opcional) | Valores existentes a renombrar, como { id, value }. |
removeValueIds | string[] (opc.) | Ids de valores a eliminar. Destructivo — protegido por confirm. |
confirm | boolean (opc.) | Aplica un cambio destructivo. Nunca lo pongas en la primera llamada. |
delete-content-island-enum
Elimina un Enum (dry-run salvo confirm: true; 409 si está referenciado por un campo enum).
| Input | Tipo | Descripción |
|---|---|---|
enumId | string (obligatorio) | El id del enum a eliminar. |
confirm | boolean (opc.) | Realiza la eliminación. Nunca lo pongas en la primera llamada — confirma un dry-run. |
Ejemplo completo
Un flujo típico de extremo a extremo, dirigido enteramente por prompts en lenguaje natural (el agente resuelve nombres →
ids vía get-content-island-project):
- Crear un enum — “Crea un enum llamado Size con los valores S, M y L.” →
create-content-island-enum. - Crear una entidad con un campo de relación + enum — “Crea una entidad Author con un fullName de tipo short-text, luego una entidad Article con un title obligatorio (máx. 120 caracteres), un body long-text, una lista tags de short-text, una relación writtenBy a Author, y un campo size apuntando al enum Size.” → dos llamadas a
create-content-island-model. - Editar de forma declarativa — “Renombra Article a BlogArticle, añade un readingMinutes de tipo number, y sube la longitud máxima de title a 200.” →
update-content-island-model(los campos no tocados se preservan). - Eliminar de forma segura — “Elimina la entidad Author.” →
delete-content-island-modeldevuelve un dry-run (todavía está referenciada porArticle.writtenBy); después de que elimines ese campo, confirmar la eliminación tiene éxito. Intentar confirmar mientras la referencia existe devuelve409 CONFLICT.
Prompt: create-content-island-project
El servidor también registra una prompt que le pide al agente que haga scaffolding de un proyecto frontend completo (Astro, Next.js, Nuxt, SvelteKit, Vite, …) conectado a tu proyecto Content Island. Después de que el agente rellene los cinco inputs siguientes, la prompt devuelve un conjunto detallado de instrucciones que el agente debe seguir paso a paso — incluido ejecutar el CLI del framework, llamar a get-content-island-project para descubrir el esquema, generar interfaces TypeScript, instalar @content-island/api-client, etc.
| Input | Descripción |
|---|---|
framework | Framework elegido (Next.js, Astro, Nuxt, SvelteKit, Vite, …). |
pages | Páginas a generar (p. ej. “Homepage, Blog listing, Blog detail, Contact”). |
location | Ubicación del proyecto (directorio raíz o un subdirectorio). |
styling | Preferencia de estilos (Tailwind CSS, CSS Modules, Styled Components, …). |
design | Recursos de diseño (wireframes, mockups, o “usa buenas prácticas”). |