strapi-mcp-server 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -11,6 +11,7 @@ Expose a Strapi v5 instance as a **Model Context Protocol** (MCP) server. AI cli
11
11
  - [External AS mode](#external-as-mode)
12
12
  - [Endpoints](#endpoints)
13
13
  - [Tools](#tools)
14
+ - [Use cases](#use-cases)
14
15
  - [Horizontal scale](#horizontal-scale)
15
16
 
16
17
  ## Quick setup
@@ -350,6 +351,79 @@ The plugin reserves `/mcp`, `/.well-known/oauth-*`, `/oauth/*`, and `/register`
350
351
 
351
352
  Delete, publish/unpublish, and user/role management are deliberately omitted. Every tool re-checks its scope and the Strapi RBAC permission at call time.
352
353
 
354
+ ## Use cases
355
+
356
+ Practical prompts you can paste into any connected AI client. Two ground rules apply to every example:
357
+
358
+ - **Every entry the AI creates or updates lands as a draft.** Publishing stays a human action in the Strapi UI — by design, no publish tool is exposed.
359
+ - **The AI sees exactly what your role sees.** Same Strapi RBAC the Content Manager uses. If your role can't read a content type, neither can the AI talking through your token.
360
+
361
+ ### Analyze (read-only)
362
+
363
+ **Tour my content model.** The AI walks the schema for every type you can read and gives you a human map.
364
+
365
+ > Walk me through every content type in my Strapi. For each, summarize what it represents, list its fields and types, and flag anything under-specified (missing meta description, no slug field, no relations).
366
+
367
+ **Editorial audit.** Scan content for problems without changing anything.
368
+
369
+ > Audit all published Articles. Tell me which are missing a meta description, have a body under 300 words, lack a featured image, or use a tag we no longer use [list of deprecated tags]. Group your findings by author.
370
+
371
+ **Find duplicates and near-duplicates.** Cross-entry comparison the AI is naturally good at; tedious manually.
372
+
373
+ > Look at all Articles tagged `product-update`. Cluster ones that cover the same release or feature so I can decide whether to merge, redirect, or unpublish. Show the documentIds for each cluster.
374
+
375
+ **Cross-type relationship mapping.** Uses `populate` to walk relations — hard to do in the UI.
376
+
377
+ > For our top 10 Products (by `popularity`), find every Article that mentions them. Build me a table: product, article count, sample titles, last-mention date.
378
+
379
+ **Locale gap report.** Find entries that should have been translated but weren't.
380
+
381
+ > For every published Article in English, check whether a French version exists. Give me the list of slugs that are English-only, sorted by publish date so I can prioritize.
382
+
383
+ **Tag taxonomy hygiene.** Find semantic duplicates humans gloss over.
384
+
385
+ > Look at every tag used across Articles. Group ones that probably mean the same thing (e.g. `ai`, `AI`, `artificial-intelligence`). Recommend a canonical form for each cluster.
386
+
387
+ **Image hygiene.** Uses `media.list`. Surfaces issues humans don't track.
388
+
389
+ > Audit our media library. Find images with no alt text, oversized images (>2 MB), or images uploaded > 1 year ago that aren't referenced by any Article. Don't delete anything — just report.
390
+
391
+ **Content brief from existing material.** Synthesize a brief out of what's already published before you write something new.
392
+
393
+ > I want to write a new pillar article on "edge caching." Before I start, find the 5 most relevant existing Articles and Products, summarize what we've already said, identify gaps we haven't covered, and suggest a structure that doesn't duplicate existing content.
394
+
395
+ ### Create (drafts)
396
+
397
+ **Bulk-create from an outline.** Turn one prompt + outline into N drafts. Beats clicking "New entry" 30 times.
398
+
399
+ > Here are 12 article ideas for our Q3 content calendar [paste list]. For each, create a draft Article with a title, slug, 60-word excerpt, and a 300-word first-draft body. Tag them with `editorial-todo` so I can find them.
400
+
401
+ **Translate / localize a batch.** AI reads the English version, creates a draft for each in another locale, preserves slug and structure.
402
+
403
+ > Find the 20 most recently updated English Articles. For each, create a French draft preserving the same slug, structure, and tone. Don't publish — I'll review in Strapi.
404
+
405
+ **Generate A/B variants.** Draft variants for testing.
406
+
407
+ > For Article `<documentId>`, create two draft variants of the headline + lead paragraph — one more curiosity-driven, one more direct. Keep the body unchanged. Use the slug pattern `<slug>-variant-a` and `<slug>-variant-b`.
408
+
409
+ **Stub the rest of a new content type.** Uses `get_schema` to understand fields, then fills realistic placeholders.
410
+
411
+ > I just created a new content type called `case-study`. Read its schema, then create 5 stub drafts so I can see how a populated listing page would look. Use realistic-sounding company names but obviously-fake numbers.
412
+
413
+ ### Update (drafts)
414
+
415
+ **Bulk fix a consistent mistake.** Find-and-update across the catalog without writing a script.
416
+
417
+ > Every Article that references our old product name "Foo" should be updated to use "Bar." Don't change the meaning of any sentence — just swap the name and any obvious derivatives (URLs, headings, CTAs). Update them as drafts so I can review.
418
+
419
+ **Missing-field backfill.** AI generates the missing piece _from_ the existing content. Especially useful for SEO fields.
420
+
421
+ > Find every published Article missing a meta description. For each, draft a 150-character meta description based on the body. Update the entries as drafts.
422
+
423
+ **Editorial style normalization.** Rewrites for tone consistency without changing semantics.
424
+
425
+ > Our older Articles (published before 2024) used a more formal voice. Pick 5 of them, rewrite the intros to match our current conversational style guide [paste guide]. Save as drafts — same documentId, just an updated draft revision.
426
+
353
427
  ## Horizontal scale
354
428
 
355
429
  For single-instance deployments, the plugin works as-is. For multi-instance, pick one of three shapes.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "strapi-mcp-server",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Expose Strapi v5 as a Model Context Protocol server with OAuth 2.1 + PKCE.",
5
5
  "keywords": [
6
6
  "strapi",
@@ -2,7 +2,8 @@
2
2
 
3
3
  import type { Core } from '@strapi/strapi';
4
4
 
5
- const INTERNAL_UID = /^(admin::|strapi::|plugin::users-permissions\.(role|permission)|plugin::i18n\.locale|plugin::upload\.(folder|file)$|plugin::mcp-server\.)/;
5
+ const INTERNAL_UID =
6
+ /^(admin::|strapi::|plugin::users-permissions\.(role|permission)|plugin::i18n\.locale|plugin::upload\.(folder|file)$|plugin::mcp-server\.)/;
6
7
 
7
8
  export interface PrincipalContext {
8
9
  user: { id: number | string; isActive?: boolean };
@@ -44,7 +45,12 @@ export default ({ strapi }: { strapi: Core.Strapi }) => ({
44
45
  const permSvc = strapi.service('admin::permission');
45
46
  let permissions: unknown[] = [];
46
47
  try {
47
- permissions = await permSvc.findUserPermissions({ user });
48
+ // Strapi v5 signature: findUserPermissions(user) — pass the user object
49
+ // directly, NOT wrapped in `{ user }`. Wrapping makes `user.id` resolve
50
+ // to undefined inside the query, producing "Undefined binding ... t4.id"
51
+ // Knex errors. Super-admins short-circuited above so this only bites
52
+ // non-super-admin roles, masquerading as "no permissions found."
53
+ permissions = await permSvc.findUserPermissions(user);
48
54
  } catch (err) {
49
55
  strapi.log.warn('[mcp-server] findUserPermissions failed', err as Error);
50
56
  }