Skip to content

MCP Server

The Content Island MCP server (@content-island/mcp) is a Model Context Protocol server that exposes your Content Island project to any MCP-compatible AI client — VS Code, Cursor, Windsurf, Claude Desktop, Claude Code, and others.

Once configured, the agent can read your project schema, list and filter contents, create new entries, update field values, publish drafts, upload media, and even manage the project’s schema — creating, editing and deleting models (Entities) and Enums — all without leaving the editor. Under the hood every tool wraps the same operations already documented in the REST API and the JavaScript client library.

Installation

The server is published to npm and runs via npx — no global install is needed. Your MCP client will spawn it on demand using the config snippet below.

shell
npx @content-island/mcp@latest

Requirements: Node.js 18 or newer, plus any MCP client (VS Code, Cursor, Windsurf, Claude Desktop, Claude Code, …).

Configure your MCP client

All major MCP clients accept the same JSON configuration shape. Add the snippet below to your client’s MCP servers config — the file location varies per client (e.g. claude_desktop_config.json for Claude Desktop, MCP settings UI for Cursor / Windsurf / VS Code).

mcp client config
{
"mcpServers": {
"contentIsland": {
"command": "npx",
"args": ["@content-island/mcp@latest"],
"env": {
"CONTENT_ISLAND_ACCESS_TOKEN": "<YOUR_CONTENT_ISLAND_ACCESS_TOKEN>"
}
}
}
}

Replace <YOUR_CONTENT_ISLAND_ACCESS_TOKEN> with your project’s token from the General tab.

Environment variables

NameRequiredDefaultDescription
CONTENT_ISLAND_ACCESS_TOKENyesProject access token. Use a Write Token if you want the agent to perform write operations.
CONTENT_ISLAND_DOMAINnoapi.contentisland.netAPI domain. Override this when running Content Island on premise.
CONTENT_ISLAND_SECURE_PROTOCOLnotrueWhether to use HTTPS. Set to false to fall back to HTTP.
CONTENT_ISLAND_API_VERSIONno1.0Version of the REST API to talk to.

Tools reference

The server registers twelve tools. Two are read-only; the other ten are gated by the write token. The first six manage content; the last six manage the project’s schema (models & enums — see Managing your project schema).

ToolTypeWrapsClient equivalent
get-content-island-projectreadGET /projectclient.getProject
list-content-island-contentsreadGET /contentsclient.getContentList
create-content-island-contentwritePOST /contentclient.createContent
update-content-island-field-valuewritePUT /content/:idclient.updateContentFieldValue
publish-content-island-contentwritePOST /content/:id/publishclient.publishContent
upload-content-island-mediawritePOST /resource/uploadclient.uploadMedia
create-content-island-modelwritePOST /model/entityclient.createModel
update-content-island-modelwritePUT /model/entity/:idclient.updateModel
delete-content-island-modelwriteDELETE /model/entity/:idclient.deleteModel
create-content-island-enumwritePOST /model/enumclient.createEnum
update-content-island-enumwritePUT /model/enum/:idclient.updateEnum
delete-content-island-enumwriteDELETE /model/enum/:idclient.deleteEnum

get-content-island-project

Returns the project’s schema: languages, content types, and the fields of each content type. The agent should normally call this first to know which contentType names, field names and languages are valid.

No input parameters.

list-content-island-contents

Lists content entries with optional filters and pagination. Returns { items, skip, take, hasMore } so the agent can page through large projects.

InputTypeDescription
contentTypestringFilter by content type name.
idstring | string[]A single content id, or an array of ids.
languagestringRestrict which field values are included (does not remove contents that lack a translation).
status'draft' | 'changed' | 'published' | array thereofFilter by publication state. Pass ['draft', 'changed'] to find contents with unpublished data.
includeRelatedContentbooleanExpand related content references inline.
sort{ contentType?: 'asc' | 'desc'; lastUpdate?: 'asc' | 'desc' }Sort order.
takenumber (1–100)Page size. Default 25.
skipnumberOffset. Use together with take for pagination.

create-content-island-content

Creates a new content entry. The agent is expected to call get-content-island-project first so it knows the valid contentType, field names, and language codes.

InputTypeDescription
contentTypestring (required)The content type name (must match an existing model).
namestring (required)Display name for the new entry.
contentArray<{ language?: string; fields: { name: string; value: any }[] }> (optional)One entry per language. If omitted, the entry is created without any field values — they can be filled in later with the next tool.

update-content-island-field-value

Updates (or upserts, when the value doesn’t exist yet) a single field on an existing content entry.

InputTypeDescription
contentIdstring (required)ID of the content entry.
fieldNamestring (required)Field name as defined in the model.
languagestring (required)Language code of the value being updated.
valueany (required)The new value. Type depends on the field’s definition.

publish-content-island-content

Promotes the current draft of a content entry to the live state.

InputTypeDescription
contentIdstring (required)ID of the content entry.

upload-content-island-media

Uploads a file from a local path or a public URL to the project’s storage. Returns { name, url }.

InputTypeDescription
sourcestring (required)Local file path (e.g. ./assets/hero.png) or HTTP(S) URL (e.g. https://example.com/photo.jpg).
fileNamestring (optional)Override the file name registered in Content Island. Defaults to the file name derived from source.

Managing your project schema (models & enums)

The last six tools let an agent evolve the project’s schema — not just its content. With them the agent can create an Entity (a content type) with a structured field list, create an Enum (a closed list of values), and edit or delete either. All six require a Write Token.

The agent should call get-content-island-project first: it returns every model with its id, name, type (entity / enum) and field/value ids, so the agent can reference things by name in your prompt and resolve the ids itself.

Field types

A field’s type is one of eight primitives — short-text, long-text, number, date, date-time, media, boolean, color — or one of two relational types:

  • relation — points at another entity. Pass the target entity’s id as relatedModelId.
  • enum — points at an enum. Pass the enum’s id as relatedModelId.

Any field can set isArray: true to store a list of that type. You never build the stored "<id>|<Name>" composite — the server assembles it from relatedModelId.

Validations

Each field may carry validations, stored at model creation and enforced when content is saved or published:

ValidationArgs
required
unique
min-length{ length: <number> }
max-length{ length: <number> }
media-type{ allowedExtensions: ["png", "jpg"] }

Name rules

Model, enum, field and value names must match /^[a-zA-Z0-9_ -]+$/, be at most 128 characters, not be a reserved field-type word (the eight primitives above), and be unique in their scope (models/enums unique in the project; field names and enum values unique within their model, case-insensitive). A violation comes back as 400 VALIDATION_ERROR.

Declarative edits

The update-* tools are declarative: the tool reads the current model and applies your operations on top, so untouched fields/values (and their ids) are preserved automatically — you never re-send the whole list.

  • update-content-island-model: rename, addFields, updateFields (by id), removeFieldIds.
  • update-content-island-enum: rename, addValues, renameValues (by id), removeValueIds.

Destructive 2-step gate

Removing a field/value or deleting a model/enum is destructive (it cascade-deletes content values). These tools enforce a two-step gate: without confirm: true they return a dry-run describing the impact and mutate nothing. The agent is instructed to never pass confirm: true on the first call — it must show you the dry-run and only re-invoke with confirm: true after you explicitly approve.

// delete-content-island-model, first call (no confirm) → dry-run, nothing deleted
{
"dryRun": true,
"wouldDeleteContentCount": 12,
"summary": "Deleting \"Author\" would also delete 12 content(s) of this type. Re-invoke with confirm: true to apply. …"
}

Reference protection

Deleting a model or enum that is referenced by a field on another model is rejected with 409 CONFLICT — there is no force override. Remove or repoint the referencing field first, then delete.

create-content-island-model

Creates an Entity with a structured field list.

InputTypeDescription
namestring (required)Model name. Non-empty, matches the name rules, not a reserved word, unique in the project.
fieldListarray (required)The fields, in order (≥1). Each: { name, type, relatedModelId?, isArray?, validations? }.

update-content-island-model

Declarative edit of an Entity.

InputTypeDescription
modelIdstring (required)The id of the entity to update.
renamestring (optional)New model name.
addFieldsarray (optional)Fields to append.
updateFieldsarray (optional)Existing fields to modify, keyed by id.
removeFieldIdsstring[] (opt.)Ids of fields to remove. Destructive — gated by confirm.
confirmboolean (opt.)Apply a destructive change. Never set on the first call (see above).

delete-content-island-model

Deletes an Entity and all of its content (dry-run unless confirm: true; 409 if referenced).

InputTypeDescription
modelIdstring (required)The id of the entity to delete.
confirmboolean (opt.)Perform the deletion. Never set on the first call — confirm a dry-run.

create-content-island-enum

Creates an Enum (closed list of string values).

InputTypeDescription
namestring (required)Enum name (same rules as a model name).
valuesstring[] (req.)The values, in order (≥1). Plain strings; the server assigns ids.

update-content-island-enum

Declarative edit of an Enum.

InputTypeDescription
enumIdstring (required)The id of the enum to update.
renamestring (optional)New enum name.
addValuesstring[] (opt.)Values to append.
renameValuesarray (optional)Existing values to rename, as { id, value }.
removeValueIdsstring[] (opt.)Ids of values to remove. Destructive — gated by confirm.
confirmboolean (opt.)Apply a destructive change. Never set on the first call.

delete-content-island-enum

Deletes an Enum (dry-run unless confirm: true; 409 if referenced by an enum field).

InputTypeDescription
enumIdstring (required)The id of the enum to delete.
confirmboolean (opt.)Perform the deletion. Never set on the first call — confirm a dry-run.

Worked example

A typical end-to-end flow, driven entirely by natural-language prompts (the agent resolves names → ids via get-content-island-project):

  1. Create an enum“Create an enum called Size with the values S, M and L.”create-content-island-enum.
  2. Create an entity with a relation + enum field“Create an Author entity with a short-text fullName, then an Article entity with a required title (max 120 chars), a body long-text, a tags list of short-text, a writtenBy relation to Author, and a size field pointing at the Size enum.” → two create-content-island-model calls.
  3. Edit declaratively“Rename Article to BlogArticle, add a readingMinutes number, and raise title’s max length to 200.”update-content-island-model (untouched fields preserved).
  4. Delete safely“Delete the Author entity.”delete-content-island-model returns a dry-run (it’s still referenced by Article.writtenBy); after you remove that field, confirming the deletion succeeds. Trying to confirm while the reference exists returns 409 CONFLICT.

Prompt: create-content-island-project

The server also registers a prompt that asks the agent to scaffold a complete frontend project (Astro, Next.js, Nuxt, SvelteKit, Vite, …) wired up to your Content Island project. After the agent fills in the five inputs below, the prompt outputs a detailed step-by-step instruction set the agent must follow — including running the framework CLI, calling get-content-island-project to discover the schema, generating TypeScript interfaces, installing @content-island/api-client, and so on.

InputDescription
frameworkFramework of choice (Next.js, Astro, Nuxt, SvelteKit, Vite, …).
pagesPages to scaffold (e.g. “Homepage, Blog listing, Blog detail, Contact”).
locationProject location (root directory or a subfolder name).
stylingStyling preference (Tailwind CSS, CSS Modules, Styled Components, …).
designDesign assets (wireframes, mockups, or “use best practices”).