Skip to main content
Glama
zhuylanz

@lapage/strapi-mcp

by zhuylanz
README.md
# @lapage/strapi-mcp

MCP server for Strapi CMS content and media management. Built by LaPage Digital.

## Install

Run with `npx`:

```sh
npx -y @lapage/strapi-mcp
```

Or install globally:

```sh
npm install -g @lapage/strapi-mcp
```

## Environment

| Variable | Required | Description |
| --- | --- | --- |
| `STRAPI_URL` | Yes | Strapi base URL, for example `https://cms.example.com`. |
| `STRAPI_API_TOKEN` | Yes | Strapi API token for REST content and media operations. |
| `STRAPI_ADMIN_TOKEN` | Optional | Token for content-manager/admin schema discovery. Falls back to `STRAPI_API_TOKEN`. |

`STRAPI_TOKEN` is also accepted as an alias for `STRAPI_API_TOKEN`.
`STRAPI_API_URL` is also accepted as an alias for `STRAPI_URL`.

## Agent Config

### Codex

`~/.codex/config.toml` or project-local `.codex/config.toml`:

```toml
[mcp_servers.lapage-strapi-mcp]
command = "npx"
args = ["-y", "@lapage/strapi-mcp"]
env = {
  "STRAPI_URL" = "https://cms.example.com",
  "STRAPI_API_TOKEN" = "your-strapi-api-token",
  "STRAPI_ADMIN_TOKEN" = "optional-admin-token"
}

[mcp_servers.lapage-strapi-mcp.tools.strapi_create_entry]
approval_mode = "approve"

[mcp_servers.lapage-strapi-mcp.tools.strapi_update_entry]
approval_mode = "approve"

[mcp_servers.lapage-strapi-mcp.tools.strapi_delete_entry]
approval_mode = "approve"

[mcp_servers.lapage-strapi-mcp.tools.strapi_request]
approval_mode = "approve"

[mcp_servers.lapage-strapi-mcp.tools.strapi_upload_media_from_url]
approval_mode = "approve"

[mcp_servers.lapage-strapi-mcp.tools.strapi_upload_media_from_file]
approval_mode = "approve"

[mcp_servers.lapage-strapi-mcp.tools.strapi_update_media_info]
approval_mode = "approve"

[mcp_servers.lapage-strapi-mcp.tools.strapi_delete_media]
approval_mode = "approve"
```

### Claude Desktop

`claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "lapage-strapi-mcp": {
      "command": "npx",
      "args": ["-y", "@lapage/strapi-mcp"],
      "env": {
        "STRAPI_URL": "https://cms.example.com",
        "STRAPI_API_TOKEN": "your-strapi-api-token",
        "STRAPI_ADMIN_TOKEN": "optional-admin-token"
      }
    }
  }
}
```

### Cursor

`.cursor/mcp.json`:

```json
{
  "mcpServers": {
    "lapage-strapi-mcp": {
      "command": "npx",
      "args": ["-y", "@lapage/strapi-mcp"],
      "env": {
        "STRAPI_URL": "https://cms.example.com",
        "STRAPI_API_TOKEN": "your-strapi-api-token",
        "STRAPI_ADMIN_TOKEN": "optional-admin-token"
      }
    }
  }
}
```

### Windsurf

MCP config:

```json
{
  "mcpServers": {
    "lapage-strapi-mcp": {
      "command": "npx",
      "args": ["-y", "@lapage/strapi-mcp"],
      "env": {
        "STRAPI_URL": "https://cms.example.com",
        "STRAPI_API_TOKEN": "your-strapi-api-token",
        "STRAPI_ADMIN_TOKEN": "optional-admin-token"
      }
    }
  }
}
```

## Tools

### Server

- `strapi_health` — checks Strapi reachability.
- `strapi_request` — performs an arbitrary authenticated Strapi HTTP request.

### Content Types

- `strapi_list_content_types` — lists available Strapi content types.
- `strapi_get_content_type_schema` — returns one content type schema by UID.

### Entries

- `strapi_list_entries` — lists entries for a collection type.
- `strapi_get_entry` — gets one entry by Strapi 5 `documentId` or Strapi 4 `id`.
- `strapi_create_entry` — creates an entry.
- `strapi_update_entry` — updates an entry.
- `strapi_delete_entry` — deletes an entry.

## Strapi 5 i18n notes

### `locale: "all"` list queries

For `strapi_list_entries`, this server treats `locale: "all"` as a request to
fetch every configured Strapi locale separately and merge the results. It first
calls `/api/i18n/locales`, then queries the collection once per locale, for
example `locale=en` and `locale=vi`.

This is intentional. Some Strapi 5 REST configurations can return a bogus empty
array for filtered queries such as:

```json
{
  "filters": { "projectId": { "$eq": "lp_homepage" } },
  "locale": "all",
  "pagination": { "pageSize": 100 },
  "populate": "*"
}
```

while the equivalent per-locale queries return data. The merged response includes
`meta.localeAll.resolvedLocales` so callers can see which locales were queried.

Pagination metadata for merged `locale: "all"` responses is synthetic. The tool
applies the requested pagination to each locale request, merges the returned
rows, and reports a single combined `meta.pagination.total`. If you need a strict
cross-locale audit, query each locale explicitly and compare entries by
`documentId`.

### Localized relation updates

When updating localized entries, relation fields that point to localized content
must use the numeric `id` for the target entry in the same locale. This matters
especially for post categories. Do not attach Vietnamese posts to English
category IDs just because the categories share the same `documentId`.

Concrete LaPage category examples:

- EN `n8n Tutorials` numeric id `105` maps to VI `Hướng Dẫn n8n` numeric id `111`.
- EN `Archived` numeric id `113` maps to VI `Archived` numeric id `115`.

For a VI post update, use `[111, 115]` rather than `[105, 113]` for those
categories.

### Media Library

- `strapi_list_media` — lists Media Library files.
- `strapi_get_media` — gets one Media Library file by id.
- `strapi_upload_media_from_url` — uploads media from a URL.
- `strapi_upload_media_from_file` — uploads media from a local file path.
- `strapi_update_media_info` — updates media metadata.
- `strapi_delete_media` — deletes a Media Library file.

TDQS

A3.7/5.0

Scored across 15 tools

Disambiguation5/5

Each tool targets a distinct resource and action: health check, generic request, content types (list/schema), entries CRUD, and media operations. The overlapping upload tools are differentiated by source (URL vs local file), and the generic strapi_request is clearly scoped to custom endpoints.

Naming Consistency5/5

All tools follow a consistent snake_case pattern starting with 'strapi_', followed by a verb (list, get, create, update, delete, upload) and an object (content_types, entries, media). Even compound names like upload_media_from_url maintain a regular structure.

Tool Count5/5

With 15 tools, the server covers health, content type introspection, entry lifecycle, and media management without being bloated. Each tool serves a clear purpose within the Strapi domain, and the count falls well within the ideal 3-15 range.

Completeness4/5

The server provides comprehensive CRUD for both entries and media, plus schema access and a generic request fallback for custom endpoints. Minor gaps exist, such as no explicit publish/unpublish tool (though update_entry may handle it) and no dedicated filtering/search tool, but these are workable via list_entries parameters or strapi_request.

Maintenance

ActivityInactive
ResponsivenessNo issues