payload-mcp-toolkit 0.2.0 → 0.3.1
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 +150 -133
- package/dist/__tests__/introspection.test.js +141 -46
- package/dist/__tests__/introspection.test.js.map +1 -1
- package/dist/draft-workflow.d.ts +24 -19
- package/dist/draft-workflow.js +89 -42
- package/dist/draft-workflow.js.map +1 -1
- package/dist/index.d.ts +10 -15
- package/dist/index.js +36 -76
- package/dist/index.js.map +1 -1
- package/dist/introspection.d.ts +18 -7
- package/dist/introspection.js +113 -84
- package/dist/introspection.js.map +1 -1
- package/dist/prompts.d.ts +4 -4
- package/dist/prompts.js +47 -38
- package/dist/prompts.js.map +1 -1
- package/dist/resources.d.ts +9 -4
- package/dist/resources.js +43 -58
- package/dist/resources.js.map +1 -1
- package/dist/tools/_helpers.d.ts +14 -0
- package/dist/tools/_helpers.js +35 -0
- package/dist/tools/_helpers.js.map +1 -0
- package/dist/tools/patch-layout.d.ts +15 -85
- package/dist/tools/patch-layout.js +142 -69
- package/dist/tools/patch-layout.js.map +1 -1
- package/dist/tools/publish-draft.d.ts +1 -11
- package/dist/tools/publish-draft.js +8 -39
- package/dist/tools/publish-draft.js.map +1 -1
- package/dist/tools/resolve-reference.d.ts +1 -12
- package/dist/tools/resolve-reference.js +45 -85
- package/dist/tools/resolve-reference.js.map +1 -1
- package/dist/tools/safe-delete.d.ts +8 -13
- package/dist/tools/safe-delete.js +68 -100
- package/dist/tools/safe-delete.js.map +1 -1
- package/dist/tools/schedule-publish.d.ts +11 -21
- package/dist/tools/schedule-publish.js +18 -61
- package/dist/tools/schedule-publish.js.map +1 -1
- package/dist/tools/search-content.d.ts +1 -6
- package/dist/tools/search-content.js +52 -64
- package/dist/tools/search-content.js.map +1 -1
- package/dist/tools/update-document.d.ts +4 -14
- package/dist/tools/update-document.js +23 -72
- package/dist/tools/update-document.js.map +1 -1
- package/dist/tools/upload-media.d.ts +1 -10
- package/dist/tools/upload-media.js +11 -54
- package/dist/tools/upload-media.js.map +1 -1
- package/dist/tools/versions.d.ts +7 -20
- package/dist/tools/versions.js +25 -82
- package/dist/tools/versions.js.map +1 -1
- package/dist/types.d.ts +82 -53
- package/dist/types.js +6 -1
- package/dist/types.js.map +1 -1
- package/package.json +1 -1
- package/dist/rate-limiter.d.ts +0 -25
- package/dist/rate-limiter.js +0 -51
- package/dist/rate-limiter.js.map +0 -1
- package/dist/tools/compose-helpers.d.ts +0 -117
- package/dist/tools/compose-helpers.js +0 -236
- package/dist/tools/compose-helpers.js.map +0 -1
- package/dist/tools/compose-layout.d.ts +0 -139
- package/dist/tools/compose-layout.js +0 -61
- package/dist/tools/compose-layout.js.map +0 -1
package/dist/draft-workflow.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { CollectionConfig, PayloadRequest } from 'payload';
|
|
2
|
-
import type { DraftBehavior } from './types';
|
|
3
2
|
/** MCP response shape used by overrideResponse */
|
|
4
3
|
interface McpResponse {
|
|
5
4
|
content: Array<{
|
|
@@ -16,42 +15,48 @@ interface McpCollectionConfig {
|
|
|
16
15
|
find: boolean;
|
|
17
16
|
update: boolean;
|
|
18
17
|
};
|
|
19
|
-
overrideResponse?: (response: McpResponse, doc: Record<string, unknown>, req: PayloadRequest) => McpResponse
|
|
18
|
+
overrideResponse?: (response: McpResponse, doc: Record<string, unknown>, req: PayloadRequest) => McpResponse | Promise<McpResponse>;
|
|
20
19
|
}
|
|
21
20
|
interface GenerateOptions {
|
|
22
|
-
/** Base site URL for preview links */
|
|
23
|
-
siteUrl: string;
|
|
24
|
-
/** Preview authentication secret */
|
|
25
|
-
previewSecret: string;
|
|
26
21
|
/**
|
|
27
|
-
*
|
|
28
|
-
*
|
|
22
|
+
* Optional absolute base URL prepended to relative preview paths returned
|
|
23
|
+
* by the collection's own preview URL function. Resolved upstream from
|
|
24
|
+
* (in order): `options.preview.siteUrl`, `incomingConfig.serverURL`,
|
|
25
|
+
* `process.env.NEXT_PUBLIC_SERVER_URL`, `process.env.SITE_URL`. May be
|
|
26
|
+
* undefined — relative-path returns will then be skipped.
|
|
29
27
|
*/
|
|
30
|
-
|
|
28
|
+
siteUrl?: string;
|
|
31
29
|
/** Per-collection draft behavior overrides */
|
|
32
|
-
draftBehavior?: Record<string,
|
|
30
|
+
draftBehavior?: Record<string, 'always-draft' | 'always-publish'>;
|
|
33
31
|
/** Collection slugs to exclude from MCP */
|
|
34
32
|
excludeCollections?: string[];
|
|
33
|
+
/** Disable preview URL injection entirely */
|
|
34
|
+
previewDisabled?: boolean;
|
|
35
35
|
}
|
|
36
36
|
/**
|
|
37
|
-
* Determines the draft behavior for a collection
|
|
37
|
+
* Determines the draft behavior for a collection.
|
|
38
38
|
*
|
|
39
|
-
* -
|
|
40
|
-
* -
|
|
41
|
-
* -
|
|
39
|
+
* - No drafts configured → 'publish' (raw update allowed; no draft concept)
|
|
40
|
+
* - Drafts configured + override given → use override
|
|
41
|
+
* - Drafts configured + no override → 'always-draft' (raw update locked)
|
|
42
42
|
*/
|
|
43
43
|
export declare function getDraftBehavior(collection: CollectionConfig, options?: {
|
|
44
|
-
draftBehavior?: Record<string,
|
|
44
|
+
draftBehavior?: Record<string, 'always-draft' | 'always-publish'>;
|
|
45
45
|
}): 'always-draft' | 'always-publish' | 'publish';
|
|
46
46
|
/**
|
|
47
47
|
* Generates the mcpCollections config object for the official mcpPlugin.
|
|
48
48
|
*
|
|
49
|
-
* For each collection:
|
|
49
|
+
* For each non-excluded collection:
|
|
50
50
|
* - Determines enabled CRUD operations based on draft behavior
|
|
51
|
-
* - For 'always-draft' collections: disables raw `update` to force clients
|
|
52
|
-
*
|
|
51
|
+
* - For 'always-draft' collections: disables raw `update` to force clients
|
|
52
|
+
* through publishDraft / patchLayout / updateDocument (which preserve
|
|
53
|
+
* draft semantics)
|
|
54
|
+
* - For draft collections: attaches an `overrideResponse` that appends a
|
|
55
|
+
* preview URL — sourced from the collection's own livePreview/preview
|
|
56
|
+
* function — to draft documents. Falls back to a generic admin-panel
|
|
57
|
+
* message when no preview function is configured.
|
|
53
58
|
*
|
|
54
|
-
* @returns
|
|
59
|
+
* @returns Map of slug → MCP collection config, plus the set of draft slugs
|
|
55
60
|
*/
|
|
56
61
|
export declare function generateMcpCollectionConfigs(collections: CollectionConfig[], options: GenerateOptions): {
|
|
57
62
|
mcpCollections: Record<string, McpCollectionConfig>;
|
package/dist/draft-workflow.js
CHANGED
|
@@ -1,40 +1,81 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* -
|
|
6
|
-
* -
|
|
1
|
+
import { hasCollectionDrafts } from './introspection';
|
|
2
|
+
/**
|
|
3
|
+
* Determines the draft behavior for a collection.
|
|
4
|
+
*
|
|
5
|
+
* - No drafts configured → 'publish' (raw update allowed; no draft concept)
|
|
6
|
+
* - Drafts configured + override given → use override
|
|
7
|
+
* - Drafts configured + no override → 'always-draft' (raw update locked)
|
|
7
8
|
*/ export function getDraftBehavior(collection, options) {
|
|
8
|
-
|
|
9
|
-
if (!hasDrafts) return 'publish';
|
|
9
|
+
if (!hasCollectionDrafts(collection)) return 'publish';
|
|
10
10
|
const override = options?.draftBehavior?.[collection.slug];
|
|
11
11
|
if (override) return override;
|
|
12
12
|
return 'always-draft';
|
|
13
13
|
}
|
|
14
|
-
/**
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
14
|
+
/**
|
|
15
|
+
* Build a preview URL for a draft document by delegating to the collection's
|
|
16
|
+
* own configured preview URL function. Tries `admin.livePreview.url` first
|
|
17
|
+
* (the modern API), then `admin.preview` (the older `GeneratePreviewURL`).
|
|
18
|
+
*
|
|
19
|
+
* If neither is configured, or the function returns null/undefined/empty,
|
|
20
|
+
* returns null and the override response will skip preview injection.
|
|
21
|
+
*/ async function resolvePreviewUrl(collection, doc, req, siteUrl) {
|
|
22
|
+
const admin = collection.admin ?? {};
|
|
23
|
+
const locale = req.locale ?? 'en';
|
|
24
|
+
let raw;
|
|
25
|
+
const livePreviewUrl = admin.livePreview?.url;
|
|
26
|
+
if (typeof livePreviewUrl === 'function') {
|
|
27
|
+
try {
|
|
28
|
+
raw = await livePreviewUrl({
|
|
29
|
+
data: doc,
|
|
30
|
+
locale: {
|
|
31
|
+
code: locale,
|
|
32
|
+
label: locale
|
|
33
|
+
},
|
|
34
|
+
req,
|
|
35
|
+
payload: req.payload,
|
|
36
|
+
collectionConfig: collection
|
|
37
|
+
});
|
|
38
|
+
} catch {
|
|
39
|
+
raw = null;
|
|
40
|
+
}
|
|
41
|
+
} else if (typeof livePreviewUrl === 'string') {
|
|
42
|
+
raw = livePreviewUrl;
|
|
43
|
+
}
|
|
44
|
+
if (!raw && typeof admin.preview === 'function') {
|
|
45
|
+
try {
|
|
46
|
+
raw = await admin.preview(doc, {
|
|
47
|
+
locale,
|
|
48
|
+
req,
|
|
49
|
+
token: null
|
|
50
|
+
});
|
|
51
|
+
} catch {
|
|
52
|
+
raw = null;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
if (!raw || typeof raw !== 'string') return null;
|
|
56
|
+
if (raw.startsWith('http://') || raw.startsWith('https://')) {
|
|
57
|
+
return raw;
|
|
58
|
+
}
|
|
59
|
+
if (!siteUrl) return null;
|
|
60
|
+
const base = siteUrl.endsWith('/') ? siteUrl.slice(0, -1) : siteUrl;
|
|
61
|
+
const path = raw.startsWith('/') ? raw : `/${raw}`;
|
|
62
|
+
return `${base}${path}`;
|
|
30
63
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
* When a document has `_status === 'draft'`, appends a preview URL to the response.
|
|
34
|
-
*/ function createOverrideResponse(collectionSlug, siteUrl, previewSecret, previewPaths) {
|
|
35
|
-
return (response, doc)=>{
|
|
64
|
+
function createOverrideResponse(collection, siteUrl) {
|
|
65
|
+
return async (response, doc, req)=>{
|
|
36
66
|
if (doc._status !== 'draft') return response;
|
|
37
|
-
const previewUrl =
|
|
67
|
+
const previewUrl = await resolvePreviewUrl(collection, doc, req, siteUrl);
|
|
68
|
+
if (!previewUrl) {
|
|
69
|
+
return {
|
|
70
|
+
content: [
|
|
71
|
+
...response.content,
|
|
72
|
+
{
|
|
73
|
+
type: 'text',
|
|
74
|
+
text: '\n📋 This document is a draft. Use the admin panel to preview it.'
|
|
75
|
+
}
|
|
76
|
+
]
|
|
77
|
+
};
|
|
78
|
+
}
|
|
38
79
|
return {
|
|
39
80
|
content: [
|
|
40
81
|
...response.content,
|
|
@@ -46,25 +87,31 @@
|
|
|
46
87
|
};
|
|
47
88
|
};
|
|
48
89
|
}
|
|
49
|
-
/**
|
|
50
|
-
* Generates the mcpCollections config object for the official mcpPlugin.
|
|
51
|
-
*
|
|
52
|
-
* For each collection:
|
|
53
|
-
* - Determines enabled CRUD operations based on draft behavior
|
|
54
|
-
* - For 'always-draft' collections: disables raw `update` to force clients
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
90
|
+
/**
|
|
91
|
+
* Generates the mcpCollections config object for the official mcpPlugin.
|
|
92
|
+
*
|
|
93
|
+
* For each non-excluded collection:
|
|
94
|
+
* - Determines enabled CRUD operations based on draft behavior
|
|
95
|
+
* - For 'always-draft' collections: disables raw `update` to force clients
|
|
96
|
+
* through publishDraft / patchLayout / updateDocument (which preserve
|
|
97
|
+
* draft semantics)
|
|
98
|
+
* - For draft collections: attaches an `overrideResponse` that appends a
|
|
99
|
+
* preview URL — sourced from the collection's own livePreview/preview
|
|
100
|
+
* function — to draft documents. Falls back to a generic admin-panel
|
|
101
|
+
* message when no preview function is configured.
|
|
102
|
+
*
|
|
103
|
+
* @returns Map of slug → MCP collection config, plus the set of draft slugs
|
|
58
104
|
*/ export function generateMcpCollectionConfigs(collections, options) {
|
|
59
105
|
const mcpCollections = {};
|
|
60
106
|
const draftCollections = new Set();
|
|
61
107
|
const excludeSlugs = new Set([
|
|
62
|
-
'users',
|
|
63
108
|
'payload-mcp-api-keys',
|
|
64
109
|
...options.excludeCollections ?? []
|
|
65
110
|
]);
|
|
66
111
|
for (const collection of collections){
|
|
67
112
|
if (excludeSlugs.has(collection.slug)) continue;
|
|
113
|
+
// Auth-enabled collections are users — never expose them via MCP.
|
|
114
|
+
if (collection.auth) continue;
|
|
68
115
|
const behavior = getDraftBehavior(collection, options);
|
|
69
116
|
if (behavior !== 'publish') {
|
|
70
117
|
draftCollections.add(collection.slug);
|
|
@@ -79,8 +126,8 @@
|
|
|
79
126
|
description: `Manage ${collection.slug} content`,
|
|
80
127
|
enabled
|
|
81
128
|
};
|
|
82
|
-
if (draftCollections.has(collection.slug)) {
|
|
83
|
-
config.overrideResponse = createOverrideResponse(collection
|
|
129
|
+
if (draftCollections.has(collection.slug) && !options.previewDisabled) {
|
|
130
|
+
config.overrideResponse = createOverrideResponse(collection, options.siteUrl);
|
|
84
131
|
}
|
|
85
132
|
mcpCollections[collection.slug] = config;
|
|
86
133
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/draft-workflow.ts"],"sourcesContent":["import type { CollectionConfig, PayloadRequest } from 'payload'\nimport type { DraftBehavior } from './types'\n\n/** MCP response shape used by overrideResponse */\ninterface McpResponse {\n content: Array<{ text: string; type: string }>\n}\n\n/** Per-collection MCP config with enabled operations and optional overrideResponse */\ninterface McpCollectionConfig {\n description: string\n enabled: {\n create: boolean\n delete: boolean\n find: boolean\n update: boolean\n }\n overrideResponse?: (\n response: McpResponse,\n doc: Record<string, unknown>,\n req: PayloadRequest,\n ) => McpResponse\n}\n\ninterface GenerateOptions {\n /** Base site URL for preview links */\n siteUrl: string\n /** Preview authentication secret */\n previewSecret: string\n /**\n * Per-collection URL path prefix used when constructing preview URLs.\n * Defaults to `/{slug}` for collections not in the map.\n */\n previewPaths?: Record<string, string>\n /** Per-collection draft behavior overrides */\n draftBehavior?: Record<string, DraftBehavior>\n /** Collection slugs to exclude from MCP */\n excludeCollections?: string[]\n}\n\n/**\n * Determines the draft behavior for a collection based on its config and user overrides.\n *\n * - If the collection has no `versions.drafts`: always 'publish' regardless of override\n * - If the user specified an override: use that override\n * - Default: 'always-draft' for draft-enabled collections, 'publish' for others\n */\nexport function getDraftBehavior(\n collection: CollectionConfig,\n options?: { draftBehavior?: Record<string, DraftBehavior> },\n): 'always-draft' | 'always-publish' | 'publish' {\n const hasDrafts =\n typeof collection.versions === 'object' &&\n collection.versions !== null &&\n 'drafts' in collection.versions &&\n Boolean(collection.versions.drafts)\n\n if (!hasDrafts) return 'publish'\n\n const override = options?.draftBehavior?.[collection.slug]\n if (override) return override\n\n return 'always-draft'\n}\n\n/**\n * Builds a preview URL for a draft document.\n *\n * Path is `${siteUrl}/next/preview?...`. Path prefix per collection comes\n * from `previewPaths`, defaulting to `/{collectionSlug}` when not configured.\n */\nfunction buildPreviewUrl(\n doc: Record<string, unknown>,\n collectionSlug: string,\n siteUrl: string,\n previewSecret: string,\n previewPaths?: Record<string, string>,\n): string {\n const slug = (doc.slug as string) || ''\n const prefix = previewPaths?.[collectionSlug] ?? `/${collectionSlug}`\n const path = `${prefix}/${slug}`\n\n const params = new URLSearchParams({\n slug,\n collection: collectionSlug,\n path,\n previewSecret,\n })\n\n return `${siteUrl}/next/preview?${params.toString()}`\n}\n\n/**\n * Creates an overrideResponse function for a draft-enabled collection.\n * When a document has `_status === 'draft'`, appends a preview URL to the response.\n */\nfunction createOverrideResponse(\n collectionSlug: string,\n siteUrl: string,\n previewSecret: string,\n previewPaths?: Record<string, string>,\n): McpCollectionConfig['overrideResponse'] {\n return (response: McpResponse, doc: Record<string, unknown>): McpResponse => {\n if (doc._status !== 'draft') return response\n\n const previewUrl = buildPreviewUrl(doc, collectionSlug, siteUrl, previewSecret, previewPaths)\n\n return {\n content: [\n ...response.content,\n {\n type: 'text',\n text: `\\n📋 This document is a draft. Preview it here: ${previewUrl}`,\n },\n ],\n }\n }\n}\n\n/**\n * Generates the mcpCollections config object for the official mcpPlugin.\n *\n * For each collection:\n * - Determines enabled CRUD operations based on draft behavior\n * - For 'always-draft' collections: disables raw `update` to force clients through publishDraft tool\n * - Generates `overrideResponse` that appends preview URLs for draft documents\n *\n * @returns A record of collection slug to MCP collection config, plus the set of draft collection slugs\n */\nexport function generateMcpCollectionConfigs(\n collections: CollectionConfig[],\n options: GenerateOptions,\n): {\n mcpCollections: Record<string, McpCollectionConfig>\n draftCollections: Set<string>\n} {\n const mcpCollections: Record<string, McpCollectionConfig> = {}\n const draftCollections = new Set<string>()\n\n const excludeSlugs = new Set([\n 'users',\n 'payload-mcp-api-keys',\n ...(options.excludeCollections ?? []),\n ])\n\n for (const collection of collections) {\n if (excludeSlugs.has(collection.slug)) continue\n\n const behavior = getDraftBehavior(collection, options)\n\n if (behavior !== 'publish') {\n draftCollections.add(collection.slug)\n }\n\n const enabled = {\n find: true,\n create: true,\n update: behavior !== 'always-draft',\n delete: true,\n }\n\n const config: McpCollectionConfig = {\n description: `Manage ${collection.slug} content`,\n enabled,\n }\n\n if (draftCollections.has(collection.slug)) {\n config.overrideResponse = createOverrideResponse(\n collection.slug,\n options.siteUrl,\n options.previewSecret,\n options.previewPaths,\n )\n }\n\n mcpCollections[collection.slug] = config\n }\n\n return { mcpCollections, draftCollections }\n}\n"],"names":["getDraftBehavior","collection","options","hasDrafts","versions","Boolean","drafts","override","draftBehavior","slug","buildPreviewUrl","doc","collectionSlug","siteUrl","previewSecret","previewPaths","prefix","path","params","URLSearchParams","toString","createOverrideResponse","response","_status","previewUrl","content","type","text","generateMcpCollectionConfigs","collections","mcpCollections","draftCollections","Set","excludeSlugs","excludeCollections","has","behavior","add","enabled","find","create","update","delete","config","description","overrideResponse"],"mappings":"AAwCA;;;;;;CAMC,GACD,OAAO,SAASA,iBACdC,UAA4B,EAC5BC,OAA2D;IAE3D,MAAMC,YACJ,OAAOF,WAAWG,QAAQ,KAAK,YAC/BH,WAAWG,QAAQ,KAAK,QACxB,YAAYH,WAAWG,QAAQ,IAC/BC,QAAQJ,WAAWG,QAAQ,CAACE,MAAM;IAEpC,IAAI,CAACH,WAAW,OAAO;IAEvB,MAAMI,WAAWL,SAASM,eAAe,CAACP,WAAWQ,IAAI,CAAC;IAC1D,IAAIF,UAAU,OAAOA;IAErB,OAAO;AACT;AAEA;;;;;CAKC,GACD,SAASG,gBACPC,GAA4B,EAC5BC,cAAsB,EACtBC,OAAe,EACfC,aAAqB,EACrBC,YAAqC;IAErC,MAAMN,OAAO,AAACE,IAAIF,IAAI,IAAe;IACrC,MAAMO,SAASD,cAAc,CAACH,eAAe,IAAI,CAAC,CAAC,EAAEA,gBAAgB;IACrE,MAAMK,OAAO,GAAGD,OAAO,CAAC,EAAEP,MAAM;IAEhC,MAAMS,SAAS,IAAIC,gBAAgB;QACjCV;QACAR,YAAYW;QACZK;QACAH;IACF;IAEA,OAAO,GAAGD,QAAQ,cAAc,EAAEK,OAAOE,QAAQ,IAAI;AACvD;AAEA;;;CAGC,GACD,SAASC,uBACPT,cAAsB,EACtBC,OAAe,EACfC,aAAqB,EACrBC,YAAqC;IAErC,OAAO,CAACO,UAAuBX;QAC7B,IAAIA,IAAIY,OAAO,KAAK,SAAS,OAAOD;QAEpC,MAAME,aAAad,gBAAgBC,KAAKC,gBAAgBC,SAASC,eAAeC;QAEhF,OAAO;YACLU,SAAS;mBACJH,SAASG,OAAO;gBACnB;oBACEC,MAAM;oBACNC,MAAM,CAAC,gDAAgD,EAAEH,YAAY;gBACvE;aACD;QACH;IACF;AACF;AAEA;;;;;;;;;CASC,GACD,OAAO,SAASI,6BACdC,WAA+B,EAC/B3B,OAAwB;IAKxB,MAAM4B,iBAAsD,CAAC;IAC7D,MAAMC,mBAAmB,IAAIC;IAE7B,MAAMC,eAAe,IAAID,IAAI;QAC3B;QACA;WACI9B,QAAQgC,kBAAkB,IAAI,EAAE;KACrC;IAED,KAAK,MAAMjC,cAAc4B,YAAa;QACpC,IAAII,aAAaE,GAAG,CAAClC,WAAWQ,IAAI,GAAG;QAEvC,MAAM2B,WAAWpC,iBAAiBC,YAAYC;QAE9C,IAAIkC,aAAa,WAAW;YAC1BL,iBAAiBM,GAAG,CAACpC,WAAWQ,IAAI;QACtC;QAEA,MAAM6B,UAAU;YACdC,MAAM;YACNC,QAAQ;YACRC,QAAQL,aAAa;YACrBM,QAAQ;QACV;QAEA,MAAMC,SAA8B;YAClCC,aAAa,CAAC,OAAO,EAAE3C,WAAWQ,IAAI,CAAC,QAAQ,CAAC;YAChD6B;QACF;QAEA,IAAIP,iBAAiBI,GAAG,CAAClC,WAAWQ,IAAI,GAAG;YACzCkC,OAAOE,gBAAgB,GAAGxB,uBACxBpB,WAAWQ,IAAI,EACfP,QAAQW,OAAO,EACfX,QAAQY,aAAa,EACrBZ,QAAQa,YAAY;QAExB;QAEAe,cAAc,CAAC7B,WAAWQ,IAAI,CAAC,GAAGkC;IACpC;IAEA,OAAO;QAAEb;QAAgBC;IAAiB;AAC5C"}
|
|
1
|
+
{"version":3,"sources":["../src/draft-workflow.ts"],"sourcesContent":["import type { CollectionConfig, PayloadRequest } from 'payload'\r\nimport { hasCollectionDrafts } from './introspection'\r\n\r\n/** MCP response shape used by overrideResponse */\r\ninterface McpResponse {\r\n content: Array<{ text: string; type: string }>\r\n}\r\n\r\n/** Per-collection MCP config with enabled operations and optional overrideResponse */\r\ninterface McpCollectionConfig {\r\n description: string\r\n enabled: {\r\n create: boolean\r\n delete: boolean\r\n find: boolean\r\n update: boolean\r\n }\r\n overrideResponse?: (\r\n response: McpResponse,\r\n doc: Record<string, unknown>,\r\n req: PayloadRequest,\r\n ) => McpResponse | Promise<McpResponse>\r\n}\r\n\r\ninterface GenerateOptions {\r\n /**\r\n * Optional absolute base URL prepended to relative preview paths returned\r\n * by the collection's own preview URL function. Resolved upstream from\r\n * (in order): `options.preview.siteUrl`, `incomingConfig.serverURL`,\r\n * `process.env.NEXT_PUBLIC_SERVER_URL`, `process.env.SITE_URL`. May be\r\n * undefined — relative-path returns will then be skipped.\r\n */\r\n siteUrl?: string\r\n /** Per-collection draft behavior overrides */\r\n draftBehavior?: Record<string, 'always-draft' | 'always-publish'>\r\n /** Collection slugs to exclude from MCP */\r\n excludeCollections?: string[]\r\n /** Disable preview URL injection entirely */\r\n previewDisabled?: boolean\r\n}\r\n\r\n/**\r\n * Determines the draft behavior for a collection.\r\n *\r\n * - No drafts configured → 'publish' (raw update allowed; no draft concept)\r\n * - Drafts configured + override given → use override\r\n * - Drafts configured + no override → 'always-draft' (raw update locked)\r\n */\r\nexport function getDraftBehavior(\r\n collection: CollectionConfig,\r\n options?: { draftBehavior?: Record<string, 'always-draft' | 'always-publish'> },\r\n): 'always-draft' | 'always-publish' | 'publish' {\r\n if (!hasCollectionDrafts(collection)) return 'publish'\r\n\r\n const override = options?.draftBehavior?.[collection.slug]\r\n if (override) return override\r\n\r\n return 'always-draft'\r\n}\r\n\r\n/**\r\n * Build a preview URL for a draft document by delegating to the collection's\r\n * own configured preview URL function. Tries `admin.livePreview.url` first\r\n * (the modern API), then `admin.preview` (the older `GeneratePreviewURL`).\r\n *\r\n * If neither is configured, or the function returns null/undefined/empty,\r\n * returns null and the override response will skip preview injection.\r\n */\r\nasync function resolvePreviewUrl(\r\n collection: CollectionConfig,\r\n doc: Record<string, unknown>,\r\n req: PayloadRequest,\r\n siteUrl: string | undefined,\r\n): Promise<string | null> {\r\n const admin = (collection.admin ?? {}) as Record<string, any>\r\n const locale = (req as any).locale ?? 'en'\r\n\r\n let raw: string | null | undefined\r\n\r\n const livePreviewUrl = admin.livePreview?.url\r\n if (typeof livePreviewUrl === 'function') {\r\n try {\r\n raw = await livePreviewUrl({\r\n data: doc,\r\n locale: { code: locale, label: locale },\r\n req,\r\n payload: req.payload,\r\n collectionConfig: collection as any,\r\n })\r\n } catch {\r\n raw = null\r\n }\r\n } else if (typeof livePreviewUrl === 'string') {\r\n raw = livePreviewUrl\r\n }\r\n\r\n if (!raw && typeof admin.preview === 'function') {\r\n try {\r\n raw = await admin.preview(doc, {\r\n locale,\r\n req,\r\n token: null,\r\n })\r\n } catch {\r\n raw = null\r\n }\r\n }\r\n\r\n if (!raw || typeof raw !== 'string') return null\r\n\r\n if (raw.startsWith('http://') || raw.startsWith('https://')) {\r\n return raw\r\n }\r\n\r\n if (!siteUrl) return null\r\n\r\n const base = siteUrl.endsWith('/') ? siteUrl.slice(0, -1) : siteUrl\r\n const path = raw.startsWith('/') ? raw : `/${raw}`\r\n return `${base}${path}`\r\n}\r\n\r\nfunction createOverrideResponse(\r\n collection: CollectionConfig,\r\n siteUrl: string | undefined,\r\n): McpCollectionConfig['overrideResponse'] {\r\n return async (response, doc, req): Promise<McpResponse> => {\r\n if (doc._status !== 'draft') return response\r\n\r\n const previewUrl = await resolvePreviewUrl(collection, doc, req, siteUrl)\r\n if (!previewUrl) {\r\n return {\r\n content: [\r\n ...response.content,\r\n {\r\n type: 'text',\r\n text: '\\n📋 This document is a draft. Use the admin panel to preview it.',\r\n },\r\n ],\r\n }\r\n }\r\n\r\n return {\r\n content: [\r\n ...response.content,\r\n {\r\n type: 'text',\r\n text: `\\n📋 This document is a draft. Preview it here: ${previewUrl}`,\r\n },\r\n ],\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Generates the mcpCollections config object for the official mcpPlugin.\r\n *\r\n * For each non-excluded collection:\r\n * - Determines enabled CRUD operations based on draft behavior\r\n * - For 'always-draft' collections: disables raw `update` to force clients\r\n * through publishDraft / patchLayout / updateDocument (which preserve\r\n * draft semantics)\r\n * - For draft collections: attaches an `overrideResponse` that appends a\r\n * preview URL — sourced from the collection's own livePreview/preview\r\n * function — to draft documents. Falls back to a generic admin-panel\r\n * message when no preview function is configured.\r\n *\r\n * @returns Map of slug → MCP collection config, plus the set of draft slugs\r\n */\r\nexport function generateMcpCollectionConfigs(\r\n collections: CollectionConfig[],\r\n options: GenerateOptions,\r\n): {\r\n mcpCollections: Record<string, McpCollectionConfig>\r\n draftCollections: Set<string>\r\n} {\r\n const mcpCollections: Record<string, McpCollectionConfig> = {}\r\n const draftCollections = new Set<string>()\r\n\r\n const excludeSlugs = new Set([\r\n 'payload-mcp-api-keys',\r\n ...(options.excludeCollections ?? []),\r\n ])\r\n\r\n for (const collection of collections) {\r\n if (excludeSlugs.has(collection.slug)) continue\r\n\r\n // Auth-enabled collections are users — never expose them via MCP.\r\n if ((collection as any).auth) continue\r\n\r\n const behavior = getDraftBehavior(collection, options)\r\n\r\n if (behavior !== 'publish') {\r\n draftCollections.add(collection.slug)\r\n }\r\n\r\n const enabled = {\r\n find: true,\r\n create: true,\r\n update: behavior !== 'always-draft',\r\n delete: true,\r\n }\r\n\r\n const config: McpCollectionConfig = {\r\n description: `Manage ${collection.slug} content`,\r\n enabled,\r\n }\r\n\r\n if (draftCollections.has(collection.slug) && !options.previewDisabled) {\r\n config.overrideResponse = createOverrideResponse(collection, options.siteUrl)\r\n }\r\n\r\n mcpCollections[collection.slug] = config\r\n }\r\n\r\n return { mcpCollections, draftCollections }\r\n}\r\n"],"names":["hasCollectionDrafts","getDraftBehavior","collection","options","override","draftBehavior","slug","resolvePreviewUrl","doc","req","siteUrl","admin","locale","raw","livePreviewUrl","livePreview","url","data","code","label","payload","collectionConfig","preview","token","startsWith","base","endsWith","slice","path","createOverrideResponse","response","_status","previewUrl","content","type","text","generateMcpCollectionConfigs","collections","mcpCollections","draftCollections","Set","excludeSlugs","excludeCollections","has","auth","behavior","add","enabled","find","create","update","delete","config","description","previewDisabled","overrideResponse"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -3,22 +3,17 @@ import type { ContentToolkitOptions } from './types';
|
|
|
3
3
|
/**
|
|
4
4
|
* Payload MCP Toolkit
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
6
|
+
* Layered on top of the official @payloadcms/plugin-mcp. The toolkit
|
|
7
|
+
* introspects your Payload config and registers schema-aware prompts,
|
|
8
|
+
* resources, and tools so AI clients can drive the CMS without
|
|
9
|
+
* hand-built plumbing.
|
|
8
10
|
*
|
|
9
|
-
*
|
|
11
|
+
* Zero-config usage:
|
|
10
12
|
* ```ts
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* plugins: [
|
|
14
|
-
* contentToolkitPlugin({
|
|
15
|
-
* siteUrl: process.env.SITE_URL!,
|
|
16
|
-
* previewSecret: process.env.PREVIEW_SECRET!,
|
|
17
|
-
* previewPaths: { posts: '/blog', pages: '' },
|
|
18
|
-
* draftBehavior: { pages: 'always-draft' },
|
|
19
|
-
* }),
|
|
20
|
-
* ]
|
|
13
|
+
* plugins: [contentToolkitPlugin()]
|
|
21
14
|
* ```
|
|
15
|
+
*
|
|
16
|
+
* Every option below is an optional escape hatch — see ContentToolkitOptions.
|
|
22
17
|
*/
|
|
23
|
-
export declare function contentToolkitPlugin(options
|
|
24
|
-
export type { ContentToolkitOptions, DomainPrompt,
|
|
18
|
+
export declare function contentToolkitPlugin(options?: ContentToolkitOptions): Plugin;
|
|
19
|
+
export type { ContentToolkitOptions, DomainPrompt, CollectionSchema, BlockCatalog, BlockSchema, BlockNestingMap, BlockNestingEdge, RelationshipEdge, FieldSchema, } from './types';
|
package/dist/index.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { mcpPlugin } from '@payloadcms/plugin-mcp';
|
|
2
|
-
import { introspectCollections, introspectBlocks, buildRelationshipGraph } from './introspection';
|
|
2
|
+
import { introspectCollections, introspectBlocks, buildBlockNestingMap, buildRelationshipGraph } from './introspection';
|
|
3
3
|
import { generatePrompts } from './prompts';
|
|
4
4
|
import { generateResources } from './resources';
|
|
5
5
|
import { generateMcpCollectionConfigs } from './draft-workflow';
|
|
6
|
-
import { createComposeLayoutTool } from './tools/compose-layout';
|
|
7
6
|
import { createPatchLayoutTool } from './tools/patch-layout';
|
|
8
7
|
import { createPublishDraftTool } from './tools/publish-draft';
|
|
9
8
|
import { createResolveReferenceTool } from './tools/resolve-reference';
|
|
@@ -13,83 +12,47 @@ import { createSearchContentTool } from './tools/search-content';
|
|
|
13
12
|
import { createUpdateDocumentTool } from './tools/update-document';
|
|
14
13
|
import { createUploadMediaTool } from './tools/upload-media';
|
|
15
14
|
import { createListVersionsTool, createRestoreVersionTool } from './tools/versions';
|
|
16
|
-
/**
|
|
17
|
-
* Payload MCP Toolkit
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* plugins: [
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
|
|
31
|
-
* draftBehavior: { pages: 'always-draft' },
|
|
32
|
-
* }),
|
|
33
|
-
* ]
|
|
34
|
-
* ```
|
|
35
|
-
*/ export function contentToolkitPlugin(options) {
|
|
15
|
+
/**
|
|
16
|
+
* Payload MCP Toolkit
|
|
17
|
+
*
|
|
18
|
+
* Layered on top of the official @payloadcms/plugin-mcp. The toolkit
|
|
19
|
+
* introspects your Payload config and registers schema-aware prompts,
|
|
20
|
+
* resources, and tools so AI clients can drive the CMS without
|
|
21
|
+
* hand-built plumbing.
|
|
22
|
+
*
|
|
23
|
+
* Zero-config usage:
|
|
24
|
+
* ```ts
|
|
25
|
+
* plugins: [contentToolkitPlugin()]
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* Every option below is an optional escape hatch — see ContentToolkitOptions.
|
|
29
|
+
*/ export function contentToolkitPlugin(options = {}) {
|
|
36
30
|
return (incomingConfig)=>{
|
|
37
31
|
const collections = incomingConfig.collections ?? [];
|
|
38
32
|
const allBlocks = incomingConfig.blocks ?? [];
|
|
39
|
-
// Separate section blocks from leaf blocks.
|
|
40
|
-
//
|
|
41
|
-
// Preferred: `options.sectionBlockSlugs` — explicit, unambiguous.
|
|
42
|
-
// Fallback heuristic: blocks containing a nested `blocks`-type field are
|
|
43
|
-
// sections, all others are leaves. The heuristic mis-classifies "fixed"
|
|
44
|
-
// sections (no nested blocks but their own standalone fields), so prefer
|
|
45
|
-
// the explicit option whenever the schema has any fixed sections.
|
|
46
|
-
const sectionBlocks = [];
|
|
47
|
-
const leafBlocks = [];
|
|
48
|
-
if (options.sectionBlockSlugs && options.sectionBlockSlugs.length > 0) {
|
|
49
|
-
const sectionSlugs = new Set(options.sectionBlockSlugs);
|
|
50
|
-
for (const block of allBlocks){
|
|
51
|
-
if (sectionSlugs.has(block.slug)) {
|
|
52
|
-
sectionBlocks.push(block);
|
|
53
|
-
} else {
|
|
54
|
-
leafBlocks.push(block);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
} else {
|
|
58
|
-
for (const block of allBlocks){
|
|
59
|
-
const hasBlocksField = block.fields.some((f)=>f.type === 'blocks' || f.type === 'tabs' && 'tabs' in f && f.tabs.some((tab)=>'fields' in tab && tab.fields.some((tf)=>tf.type === 'blocks')));
|
|
60
|
-
if (hasBlocksField) {
|
|
61
|
-
sectionBlocks.push(block);
|
|
62
|
-
} else {
|
|
63
|
-
leafBlocks.push(block);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
// 1. Schema Introspection
|
|
68
33
|
const collectionSchemas = introspectCollections(collections);
|
|
69
|
-
const blockCatalog = introspectBlocks(
|
|
34
|
+
const blockCatalog = introspectBlocks(allBlocks);
|
|
35
|
+
const blockNesting = buildBlockNestingMap(collections, allBlocks);
|
|
70
36
|
const relationships = buildRelationshipGraph(collectionSchemas);
|
|
71
|
-
//
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
const
|
|
75
|
-
|
|
37
|
+
// Preview siteUrl resolves: explicit option → Payload serverURL → env vars.
|
|
38
|
+
// May be undefined; relative-path preview URLs are skipped in that case.
|
|
39
|
+
const previewSiteUrl = options.preview?.siteUrl ?? incomingConfig.serverURL ?? process.env.NEXT_PUBLIC_SERVER_URL ?? process.env.SITE_URL;
|
|
40
|
+
const prompts = generatePrompts(collectionSchemas, blockCatalog, blockNesting, relationships, options.domainPrompts);
|
|
41
|
+
const resources = generateResources(collectionSchemas, blockCatalog, blockNesting, relationships);
|
|
42
|
+
const { mcpCollections, draftCollections } = generateMcpCollectionConfigs(collections, {
|
|
43
|
+
siteUrl: previewSiteUrl,
|
|
44
|
+
draftBehavior: options.draftBehavior,
|
|
45
|
+
excludeCollections: options.exclude?.collections,
|
|
46
|
+
previewDisabled: options.preview?.disabled
|
|
47
|
+
});
|
|
76
48
|
const searchableCollections = new Map();
|
|
77
49
|
for (const [slug, schema] of collectionSchemas){
|
|
78
50
|
if (schema.searchableFields.length > 0) {
|
|
79
51
|
searchableCollections.set(slug, schema.searchableFields);
|
|
80
52
|
}
|
|
81
53
|
}
|
|
82
|
-
// 5. Generate MCP Collection Configs with draft workflow
|
|
83
|
-
const { mcpCollections, draftCollections } = generateMcpCollectionConfigs(collections, {
|
|
84
|
-
siteUrl: options.siteUrl,
|
|
85
|
-
previewSecret: options.previewSecret,
|
|
86
|
-
previewPaths: options.previewPaths,
|
|
87
|
-
draftBehavior: options.draftBehavior,
|
|
88
|
-
excludeCollections: options.excludeCollections
|
|
89
|
-
});
|
|
90
54
|
const tools = [
|
|
91
|
-
|
|
92
|
-
createPatchLayoutTool(blockCatalog, draftCollections),
|
|
55
|
+
createPatchLayoutTool(blockCatalog, blockNesting, draftCollections),
|
|
93
56
|
createPublishDraftTool(draftCollections),
|
|
94
57
|
createResolveReferenceTool(searchableCollections),
|
|
95
58
|
createSafeDeleteTool(relationships),
|
|
@@ -102,12 +65,10 @@ import { createListVersionsTool, createRestoreVersionTool } from './tools/versio
|
|
|
102
65
|
createListVersionsTool(draftCollections),
|
|
103
66
|
createRestoreVersionTool(draftCollections)
|
|
104
67
|
];
|
|
105
|
-
// schedulePublish only registers when at least one draft collection has a `publishedAt` date field
|
|
106
68
|
const schedulePublish = createSchedulePublishTool(collectionSchemas, draftCollections);
|
|
107
69
|
if (schedulePublish) tools.push(schedulePublish);
|
|
108
|
-
// Build MCP global configs
|
|
109
70
|
const mcpGlobals = {};
|
|
110
|
-
const excludeGlobalSlugs = new Set(options.
|
|
71
|
+
const excludeGlobalSlugs = new Set(options.exclude?.globals ?? []);
|
|
111
72
|
for (const global of incomingConfig.globals ?? []){
|
|
112
73
|
if (excludeGlobalSlugs.has(global.slug)) continue;
|
|
113
74
|
mcpGlobals[global.slug] = {
|
|
@@ -115,20 +76,19 @@ import { createListVersionsTool, createRestoreVersionTool } from './tools/versio
|
|
|
115
76
|
description: `Manage ${global.slug} global settings`
|
|
116
77
|
};
|
|
117
78
|
}
|
|
118
|
-
//
|
|
79
|
+
// overrideAuth rebinds req.user from the API key's linked user so our
|
|
80
|
+
// custom tools' `overrideAccess: false` checks run against the right
|
|
81
|
+
// identity. userCollection passthrough lets the official plugin fall
|
|
82
|
+
// back to `incomingConfig.admin.user`.
|
|
119
83
|
const withMcp = mcpPlugin({
|
|
120
84
|
collections: mcpCollections,
|
|
121
85
|
globals: mcpGlobals,
|
|
86
|
+
userCollection: options.userCollection,
|
|
122
87
|
mcp: {
|
|
123
88
|
tools: tools,
|
|
124
89
|
prompts: prompts,
|
|
125
90
|
resources: resources
|
|
126
91
|
},
|
|
127
|
-
// Set req.user from the API key's linked user so custom tools
|
|
128
|
-
// can use overrideAccess: false and relationship field validation
|
|
129
|
-
// has a valid user context for access control checks.
|
|
130
|
-
// Safe: getDefault() throws inside the official plugin if the API key
|
|
131
|
-
// has no linked user, so settings.user is guaranteed to exist here.
|
|
132
92
|
overrideAuth: async (req, getDefault)=>{
|
|
133
93
|
const settings = await getDefault();
|
|
134
94
|
req.user = settings.user;
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { Block, CollectionConfig, Config, Plugin } from 'payload'\nimport { mcpPlugin } from '@payloadcms/plugin-mcp'\nimport type { ContentToolkitOptions } from './types'\nimport { introspectCollections, introspectBlocks, buildRelationshipGraph } from './introspection'\nimport { generatePrompts } from './prompts'\nimport { generateResources } from './resources'\nimport { generateMcpCollectionConfigs } from './draft-workflow'\nimport { createComposeLayoutTool } from './tools/compose-layout'\nimport { createPatchLayoutTool } from './tools/patch-layout'\nimport { createPublishDraftTool } from './tools/publish-draft'\nimport { createResolveReferenceTool } from './tools/resolve-reference'\nimport { createSafeDeleteTool } from './tools/safe-delete'\nimport { createSchedulePublishTool } from './tools/schedule-publish'\nimport { createSearchContentTool } from './tools/search-content'\nimport { createUpdateDocumentTool } from './tools/update-document'\nimport { createUploadMediaTool } from './tools/upload-media'\nimport { createListVersionsTool, createRestoreVersionTool } from './tools/versions'\n\n/**\n * Payload MCP Toolkit\n *\n * A wrapper plugin that introspects the Payload config and generates\n * domain-aware MCP tools, prompts, and resources for AI content management.\n *\n * Usage in payload.config.ts:\n * ```ts\n * import { contentToolkitPlugin } from 'payload-mcp-toolkit'\n *\n * plugins: [\n * contentToolkitPlugin({\n * siteUrl: process.env.SITE_URL!,\n * previewSecret: process.env.PREVIEW_SECRET!,\n * previewPaths: { posts: '/blog', pages: '' },\n * draftBehavior: { pages: 'always-draft' },\n * }),\n * ]\n * ```\n */\nexport function contentToolkitPlugin(options: ContentToolkitOptions): Plugin {\n return (incomingConfig: Config): Config => {\n const collections = (incomingConfig.collections ?? []) as CollectionConfig[]\n const allBlocks = (incomingConfig.blocks ?? []) as Block[]\n\n // Separate section blocks from leaf blocks.\n //\n // Preferred: `options.sectionBlockSlugs` — explicit, unambiguous.\n // Fallback heuristic: blocks containing a nested `blocks`-type field are\n // sections, all others are leaves. The heuristic mis-classifies \"fixed\"\n // sections (no nested blocks but their own standalone fields), so prefer\n // the explicit option whenever the schema has any fixed sections.\n const sectionBlocks: Block[] = []\n const leafBlocks: Block[] = []\n\n if (options.sectionBlockSlugs && options.sectionBlockSlugs.length > 0) {\n const sectionSlugs = new Set(options.sectionBlockSlugs)\n for (const block of allBlocks) {\n if (sectionSlugs.has(block.slug)) {\n sectionBlocks.push(block)\n } else {\n leafBlocks.push(block)\n }\n }\n } else {\n for (const block of allBlocks) {\n const hasBlocksField = block.fields.some(\n (f) => f.type === 'blocks' ||\n (f.type === 'tabs' && 'tabs' in f && f.tabs.some(\n (tab: any) => 'fields' in tab && tab.fields.some((tf: any) => tf.type === 'blocks')\n ))\n )\n if (hasBlocksField) {\n sectionBlocks.push(block)\n } else {\n leafBlocks.push(block)\n }\n }\n }\n\n // 1. Schema Introspection\n const collectionSchemas = introspectCollections(collections)\n const blockCatalog = introspectBlocks(sectionBlocks, leafBlocks)\n const relationships = buildRelationshipGraph(collectionSchemas)\n\n // 2. Generate Prompts\n const prompts = generatePrompts(\n collectionSchemas,\n blockCatalog,\n relationships,\n options.domainPrompts,\n )\n\n // 3. Generate Resources\n const resources = generateResources(collectionSchemas, blockCatalog, relationships)\n\n // 4. Generate Tools\n const searchableCollections = new Map<string, string[]>()\n for (const [slug, schema] of collectionSchemas) {\n if (schema.searchableFields.length > 0) {\n searchableCollections.set(slug, schema.searchableFields)\n }\n }\n\n // 5. Generate MCP Collection Configs with draft workflow\n const { mcpCollections, draftCollections } = generateMcpCollectionConfigs(collections, {\n siteUrl: options.siteUrl,\n previewSecret: options.previewSecret,\n previewPaths: options.previewPaths,\n draftBehavior: options.draftBehavior,\n excludeCollections: options.excludeCollections,\n })\n\n const tools: any[] = [\n createComposeLayoutTool(blockCatalog),\n createPatchLayoutTool(blockCatalog, draftCollections),\n createPublishDraftTool(draftCollections),\n createResolveReferenceTool(searchableCollections),\n createSafeDeleteTool(relationships),\n createSearchContentTool(collectionSchemas),\n createUpdateDocumentTool(collectionSchemas, draftCollections),\n createUploadMediaTool({\n maxFileSize: options.mediaUpload?.maxFileSize,\n collectionSlug: options.mediaUpload?.collectionSlug,\n }),\n createListVersionsTool(draftCollections),\n createRestoreVersionTool(draftCollections),\n ]\n\n // schedulePublish only registers when at least one draft collection has a `publishedAt` date field\n const schedulePublish = createSchedulePublishTool(collectionSchemas, draftCollections)\n if (schedulePublish) tools.push(schedulePublish)\n\n // Build MCP global configs\n const mcpGlobals: Record<string, { enabled: boolean; description?: string }> = {}\n const excludeGlobalSlugs = new Set(options.excludeGlobals ?? [])\n\n for (const global of (incomingConfig.globals ?? []) as Array<{ slug: string }>) {\n if (excludeGlobalSlugs.has(global.slug)) continue\n mcpGlobals[global.slug] = {\n enabled: true,\n description: `Manage ${global.slug} global settings`,\n }\n }\n\n // Apply the official MCP plugin with our generated config\n const withMcp = mcpPlugin({\n collections: mcpCollections as any,\n globals: mcpGlobals as any,\n mcp: {\n tools: tools as any[],\n prompts: prompts as any[],\n resources: resources as any[],\n },\n // Set req.user from the API key's linked user so custom tools\n // can use overrideAccess: false and relationship field validation\n // has a valid user context for access control checks.\n // Safe: getDefault() throws inside the official plugin if the API key\n // has no linked user, so settings.user is guaranteed to exist here.\n overrideAuth: async (req, getDefault) => {\n const settings = await getDefault()\n req.user = (settings as any).user\n return settings\n },\n })\n\n return withMcp(incomingConfig)\n }\n}\n\nexport type {\n ContentToolkitOptions,\n DomainPrompt,\n DraftBehavior,\n CollectionSchema,\n BlockCatalog,\n SectionBlockSchema,\n LeafBlockSchema,\n RelationshipEdge,\n FieldSchema,\n} from './types'\n"],"names":["mcpPlugin","introspectCollections","introspectBlocks","buildRelationshipGraph","generatePrompts","generateResources","generateMcpCollectionConfigs","createComposeLayoutTool","createPatchLayoutTool","createPublishDraftTool","createResolveReferenceTool","createSafeDeleteTool","createSchedulePublishTool","createSearchContentTool","createUpdateDocumentTool","createUploadMediaTool","createListVersionsTool","createRestoreVersionTool","contentToolkitPlugin","options","incomingConfig","collections","allBlocks","blocks","sectionBlocks","leafBlocks","sectionBlockSlugs","length","sectionSlugs","Set","block","has","slug","push","hasBlocksField","fields","some","f","type","tabs","tab","tf","collectionSchemas","blockCatalog","relationships","prompts","domainPrompts","resources","searchableCollections","Map","schema","searchableFields","set","mcpCollections","draftCollections","siteUrl","previewSecret","previewPaths","draftBehavior","excludeCollections","tools","maxFileSize","mediaUpload","collectionSlug","schedulePublish","mcpGlobals","excludeGlobalSlugs","excludeGlobals","global","globals","enabled","description","withMcp","mcp","overrideAuth","req","getDefault","settings","user"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { Block, CollectionConfig, Config, Plugin } from 'payload'\r\nimport { mcpPlugin } from '@payloadcms/plugin-mcp'\r\nimport type { ContentToolkitOptions } from './types'\r\nimport {\r\n introspectCollections,\r\n introspectBlocks,\r\n buildBlockNestingMap,\r\n buildRelationshipGraph,\r\n} from './introspection'\r\nimport { generatePrompts } from './prompts'\r\nimport { generateResources } from './resources'\r\nimport { generateMcpCollectionConfigs } from './draft-workflow'\r\nimport { createPatchLayoutTool } from './tools/patch-layout'\r\nimport { createPublishDraftTool } from './tools/publish-draft'\r\nimport { createResolveReferenceTool } from './tools/resolve-reference'\r\nimport { createSafeDeleteTool } from './tools/safe-delete'\r\nimport { createSchedulePublishTool } from './tools/schedule-publish'\r\nimport { createSearchContentTool } from './tools/search-content'\r\nimport { createUpdateDocumentTool } from './tools/update-document'\r\nimport { createUploadMediaTool } from './tools/upload-media'\r\nimport { createListVersionsTool, createRestoreVersionTool } from './tools/versions'\r\n\r\n/**\r\n * Payload MCP Toolkit\r\n *\r\n * Layered on top of the official @payloadcms/plugin-mcp. The toolkit\r\n * introspects your Payload config and registers schema-aware prompts,\r\n * resources, and tools so AI clients can drive the CMS without\r\n * hand-built plumbing.\r\n *\r\n * Zero-config usage:\r\n * ```ts\r\n * plugins: [contentToolkitPlugin()]\r\n * ```\r\n *\r\n * Every option below is an optional escape hatch — see ContentToolkitOptions.\r\n */\r\nexport function contentToolkitPlugin(options: ContentToolkitOptions = {}): Plugin {\r\n return (incomingConfig: Config): Config => {\r\n const collections = (incomingConfig.collections ?? []) as CollectionConfig[]\r\n const allBlocks = (incomingConfig.blocks ?? []) as Block[]\r\n\r\n const collectionSchemas = introspectCollections(collections)\r\n const blockCatalog = introspectBlocks(allBlocks)\r\n const blockNesting = buildBlockNestingMap(collections, allBlocks)\r\n const relationships = buildRelationshipGraph(collectionSchemas)\r\n\r\n // Preview siteUrl resolves: explicit option → Payload serverURL → env vars.\r\n // May be undefined; relative-path preview URLs are skipped in that case.\r\n const previewSiteUrl =\r\n options.preview?.siteUrl ??\r\n incomingConfig.serverURL ??\r\n process.env.NEXT_PUBLIC_SERVER_URL ??\r\n process.env.SITE_URL\r\n\r\n const prompts = generatePrompts(\r\n collectionSchemas,\r\n blockCatalog,\r\n blockNesting,\r\n relationships,\r\n options.domainPrompts,\r\n )\r\n const resources = generateResources(\r\n collectionSchemas,\r\n blockCatalog,\r\n blockNesting,\r\n relationships,\r\n )\r\n\r\n const { mcpCollections, draftCollections } = generateMcpCollectionConfigs(collections, {\r\n siteUrl: previewSiteUrl,\r\n draftBehavior: options.draftBehavior,\r\n excludeCollections: options.exclude?.collections,\r\n previewDisabled: options.preview?.disabled,\r\n })\r\n\r\n const searchableCollections = new Map<string, string[]>()\r\n for (const [slug, schema] of collectionSchemas) {\r\n if (schema.searchableFields.length > 0) {\r\n searchableCollections.set(slug, schema.searchableFields)\r\n }\r\n }\r\n\r\n const tools: any[] = [\r\n createPatchLayoutTool(blockCatalog, blockNesting, draftCollections),\r\n createPublishDraftTool(draftCollections),\r\n createResolveReferenceTool(searchableCollections),\r\n createSafeDeleteTool(relationships),\r\n createSearchContentTool(collectionSchemas),\r\n createUpdateDocumentTool(collectionSchemas, draftCollections),\r\n createUploadMediaTool({\r\n maxFileSize: options.mediaUpload?.maxFileSize,\r\n collectionSlug: options.mediaUpload?.collectionSlug,\r\n }),\r\n createListVersionsTool(draftCollections),\r\n createRestoreVersionTool(draftCollections),\r\n ]\r\n\r\n const schedulePublish = createSchedulePublishTool(collectionSchemas, draftCollections)\r\n if (schedulePublish) tools.push(schedulePublish)\r\n\r\n const mcpGlobals: Record<string, { enabled: boolean; description?: string }> = {}\r\n const excludeGlobalSlugs = new Set(options.exclude?.globals ?? [])\r\n for (const global of (incomingConfig.globals ?? []) as Array<{ slug: string }>) {\r\n if (excludeGlobalSlugs.has(global.slug)) continue\r\n mcpGlobals[global.slug] = {\r\n enabled: true,\r\n description: `Manage ${global.slug} global settings`,\r\n }\r\n }\r\n\r\n // overrideAuth rebinds req.user from the API key's linked user so our\r\n // custom tools' `overrideAccess: false` checks run against the right\r\n // identity. userCollection passthrough lets the official plugin fall\r\n // back to `incomingConfig.admin.user`.\r\n const withMcp = mcpPlugin({\r\n collections: mcpCollections as any,\r\n globals: mcpGlobals as any,\r\n userCollection: options.userCollection as any,\r\n mcp: {\r\n tools: tools as any[],\r\n prompts: prompts as any[],\r\n resources: resources as any[],\r\n },\r\n overrideAuth: async (req, getDefault) => {\r\n const settings = await getDefault()\r\n req.user = (settings as any).user\r\n return settings\r\n },\r\n })\r\n\r\n return withMcp(incomingConfig)\r\n }\r\n}\r\n\r\nexport type {\r\n ContentToolkitOptions,\r\n DomainPrompt,\r\n CollectionSchema,\r\n BlockCatalog,\r\n BlockSchema,\r\n BlockNestingMap,\r\n BlockNestingEdge,\r\n RelationshipEdge,\r\n FieldSchema,\r\n} from './types'\r\n"],"names":["mcpPlugin","introspectCollections","introspectBlocks","buildBlockNestingMap","buildRelationshipGraph","generatePrompts","generateResources","generateMcpCollectionConfigs","createPatchLayoutTool","createPublishDraftTool","createResolveReferenceTool","createSafeDeleteTool","createSchedulePublishTool","createSearchContentTool","createUpdateDocumentTool","createUploadMediaTool","createListVersionsTool","createRestoreVersionTool","contentToolkitPlugin","options","incomingConfig","collections","allBlocks","blocks","collectionSchemas","blockCatalog","blockNesting","relationships","previewSiteUrl","preview","siteUrl","serverURL","process","env","NEXT_PUBLIC_SERVER_URL","SITE_URL","prompts","domainPrompts","resources","mcpCollections","draftCollections","draftBehavior","excludeCollections","exclude","previewDisabled","disabled","searchableCollections","Map","slug","schema","searchableFields","length","set","tools","maxFileSize","mediaUpload","collectionSlug","schedulePublish","push","mcpGlobals","excludeGlobalSlugs","Set","globals","global","has","enabled","description","withMcp","userCollection","mcp","overrideAuth","req","getDefault","settings","user"],"mappings":"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"}
|
package/dist/introspection.d.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import type { Block, CollectionConfig } from 'payload';
|
|
2
|
-
import type { BlockCatalog, CollectionSchema, RelationshipEdge } from './types';
|
|
2
|
+
import type { BlockCatalog, BlockNestingMap, CollectionSchema, RelationshipEdge } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* True if the collection has Payload drafts enabled in its versions config.
|
|
5
|
+
*/
|
|
6
|
+
export declare function hasCollectionDrafts(collection: CollectionConfig): boolean;
|
|
3
7
|
/**
|
|
4
8
|
* Introspect a Payload collection config into structured metadata.
|
|
5
9
|
*/
|
|
@@ -9,14 +13,21 @@ export declare function introspectCollection(collection: CollectionConfig): Coll
|
|
|
9
13
|
*/
|
|
10
14
|
export declare function introspectCollections(collections: CollectionConfig[]): Map<string, CollectionSchema>;
|
|
11
15
|
/**
|
|
12
|
-
*
|
|
16
|
+
* Build a flat catalog of every block in the schema. Whether a block can
|
|
17
|
+
* nest other blocks is represented separately in the BlockNestingMap, not
|
|
18
|
+
* as a section/leaf classification — the AI reads both and composes
|
|
19
|
+
* arbitrarily-nested layouts from there.
|
|
20
|
+
*/
|
|
21
|
+
export declare function introspectBlocks(blocks: Block[]): BlockCatalog;
|
|
22
|
+
/**
|
|
23
|
+
* Walk every collection and every block, recording each `blocks`-typed
|
|
24
|
+
* field's owner, dotted path, and accepted slugs.
|
|
13
25
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* - If field.blocks is empty and field.blockReferences exists, uses those slugs directly
|
|
26
|
+
* The AI uses this to compose layouts at any depth: it looks up which
|
|
27
|
+
* slugs the relevant field accepts, picks one, then if that block has
|
|
28
|
+
* its own `blocks` fields it recurses against the same map.
|
|
18
29
|
*/
|
|
19
|
-
export declare function
|
|
30
|
+
export declare function buildBlockNestingMap(collections: CollectionConfig[], blocks: Block[]): BlockNestingMap;
|
|
20
31
|
/**
|
|
21
32
|
* Build a relationship graph from introspected collection schemas.
|
|
22
33
|
*/
|