@payloadcms/plugin-mcp 4.0.0-internal.bc5cf8c → 4.0.0-internal.bf4bcce
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/LICENSE.md +1 -1
- package/dist/defaultAccess.d.ts.map +1 -1
- package/dist/defineTool.d.ts +8 -8
- package/dist/defineTool.d.ts.map +1 -1
- package/dist/endpoint/access.d.ts +2 -7
- package/dist/endpoint/access.d.ts.map +1 -1
- package/dist/endpoint/access.js +17 -14
- package/dist/endpoint/access.js.map +1 -1
- package/dist/endpoint/index.d.ts +1 -1
- package/dist/endpoint/index.d.ts.map +1 -1
- package/dist/endpoint/index.js +91 -16
- package/dist/endpoint/index.js.map +1 -1
- package/dist/endpoint/oauth.d.ts +27 -0
- package/dist/endpoint/oauth.d.ts.map +1 -0
- package/dist/endpoint/oauth.js +61 -0
- package/dist/endpoint/oauth.js.map +1 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -2
- package/dist/index.js.map +1 -1
- package/dist/mcp/buildMcpServer.d.ts +6 -6
- package/dist/mcp/buildMcpServer.d.ts.map +1 -1
- package/dist/mcp/buildMcpServer.js +68 -34
- package/dist/mcp/buildMcpServer.js.map +1 -1
- package/dist/mcp/builtin/collections/authTools.d.ts.map +1 -1
- package/dist/mcp/builtin/collections/authTools.js +80 -56
- package/dist/mcp/builtin/collections/authTools.js.map +1 -1
- package/dist/mcp/builtin/collections/countTool.d.ts.map +1 -1
- package/dist/mcp/builtin/collections/countTool.js +10 -16
- package/dist/mcp/builtin/collections/countTool.js.map +1 -1
- package/dist/mcp/builtin/collections/countVersionsTool.d.ts.map +1 -1
- package/dist/mcp/builtin/collections/countVersionsTool.js +10 -15
- package/dist/mcp/builtin/collections/countVersionsTool.js.map +1 -1
- package/dist/mcp/builtin/collections/createTool.d.ts +1 -1
- package/dist/mcp/builtin/collections/createTool.d.ts.map +1 -1
- package/dist/mcp/builtin/collections/createTool.js +104 -54
- package/dist/mcp/builtin/collections/createTool.js.map +1 -1
- package/dist/mcp/builtin/collections/deleteTool.d.ts.map +1 -1
- package/dist/mcp/builtin/collections/deleteTool.js +45 -45
- package/dist/mcp/builtin/collections/deleteTool.js.map +1 -1
- package/dist/mcp/builtin/collections/duplicateTool.d.ts.map +1 -1
- package/dist/mcp/builtin/collections/duplicateTool.js +32 -39
- package/dist/mcp/builtin/collections/duplicateTool.js.map +1 -1
- package/dist/mcp/builtin/collections/fileInput.d.ts +28 -0
- package/dist/mcp/builtin/collections/fileInput.d.ts.map +1 -0
- package/dist/mcp/builtin/collections/fileInput.js +88 -0
- package/dist/mcp/builtin/collections/fileInput.js.map +1 -0
- package/dist/mcp/builtin/collections/findDistinctTool.d.ts.map +1 -1
- package/dist/mcp/builtin/collections/findDistinctTool.js +12 -28
- package/dist/mcp/builtin/collections/findDistinctTool.js.map +1 -1
- package/dist/mcp/builtin/collections/findTool.d.ts.map +1 -1
- package/dist/mcp/builtin/collections/findTool.js +29 -48
- package/dist/mcp/builtin/collections/findTool.js.map +1 -1
- package/dist/mcp/builtin/collections/findVersionByIDTool.d.ts.map +1 -1
- package/dist/mcp/builtin/collections/findVersionByIDTool.js +18 -28
- package/dist/mcp/builtin/collections/findVersionByIDTool.js.map +1 -1
- package/dist/mcp/builtin/collections/findVersionsTool.d.ts.map +1 -1
- package/dist/mcp/builtin/collections/findVersionsTool.js +17 -32
- package/dist/mcp/builtin/collections/findVersionsTool.js.map +1 -1
- package/dist/mcp/builtin/collections/getCollectionSchemaTool.d.ts.map +1 -1
- package/dist/mcp/builtin/collections/getCollectionSchemaTool.js +68 -12
- package/dist/mcp/builtin/collections/getCollectionSchemaTool.js.map +1 -1
- package/dist/mcp/builtin/collections/restoreVersionTool.d.ts.map +1 -1
- package/dist/mcp/builtin/collections/restoreVersionTool.js +15 -28
- package/dist/mcp/builtin/collections/restoreVersionTool.js.map +1 -1
- package/dist/mcp/builtin/collections/updateTool.d.ts.map +1 -1
- package/dist/mcp/builtin/collections/updateTool.js +67 -87
- package/dist/mcp/builtin/collections/updateTool.js.map +1 -1
- package/dist/mcp/builtin/collections/uploadInstructionsTool.d.ts +2 -0
- package/dist/mcp/builtin/collections/uploadInstructionsTool.d.ts.map +1 -0
- package/dist/mcp/builtin/collections/uploadInstructionsTool.js +55 -0
- package/dist/mcp/builtin/collections/uploadInstructionsTool.js.map +1 -0
- package/dist/mcp/builtin/formatEntityError.d.ts +16 -0
- package/dist/mcp/builtin/formatEntityError.d.ts.map +1 -0
- package/dist/mcp/builtin/formatEntityError.js +55 -0
- package/dist/mcp/builtin/formatEntityError.js.map +1 -0
- package/dist/mcp/builtin/getConfigInfoTool.d.ts.map +1 -1
- package/dist/mcp/builtin/getConfigInfoTool.js +5 -7
- package/dist/mcp/builtin/getConfigInfoTool.js.map +1 -1
- package/dist/mcp/builtin/globals/countVersionsTool.d.ts.map +1 -1
- package/dist/mcp/builtin/globals/countVersionsTool.js +10 -15
- package/dist/mcp/builtin/globals/countVersionsTool.js.map +1 -1
- package/dist/mcp/builtin/globals/findTool.d.ts.map +1 -1
- package/dist/mcp/builtin/globals/findTool.js +12 -18
- package/dist/mcp/builtin/globals/findTool.js.map +1 -1
- package/dist/mcp/builtin/globals/findVersionByIDTool.d.ts.map +1 -1
- package/dist/mcp/builtin/globals/findVersionByIDTool.js +14 -26
- package/dist/mcp/builtin/globals/findVersionByIDTool.js.map +1 -1
- package/dist/mcp/builtin/globals/findVersionsTool.d.ts.map +1 -1
- package/dist/mcp/builtin/globals/findVersionsTool.js +14 -31
- package/dist/mcp/builtin/globals/findVersionsTool.js.map +1 -1
- package/dist/mcp/builtin/globals/getGlobalSchemaTool.d.ts.map +1 -1
- package/dist/mcp/builtin/globals/getGlobalSchemaTool.js +46 -12
- package/dist/mcp/builtin/globals/getGlobalSchemaTool.js.map +1 -1
- package/dist/mcp/builtin/globals/restoreVersionTool.d.ts.map +1 -1
- package/dist/mcp/builtin/globals/restoreVersionTool.js +16 -24
- package/dist/mcp/builtin/globals/restoreVersionTool.js.map +1 -1
- package/dist/mcp/builtin/globals/updateTool.d.ts.map +1 -1
- package/dist/mcp/builtin/globals/updateTool.js +28 -37
- package/dist/mcp/builtin/globals/updateTool.js.map +1 -1
- package/dist/mcp/builtinTools.d.ts +6 -0
- package/dist/mcp/builtinTools.d.ts.map +1 -1
- package/dist/mcp/builtinTools.js +9 -3
- package/dist/mcp/builtinTools.js.map +1 -1
- package/dist/mcp/sanitizeMCPConfig.d.ts.map +1 -1
- package/dist/mcp/sanitizeMCPConfig.js +6 -1
- package/dist/mcp/sanitizeMCPConfig.js.map +1 -1
- package/dist/stdio.d.ts +3 -4
- package/dist/stdio.d.ts.map +1 -1
- package/dist/stdio.js +65 -45
- package/dist/stdio.js.map +1 -1
- package/dist/types.d.ts +94 -16
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +2 -4
- package/dist/types.js.map +1 -1
- package/dist/utils/camelCase.d.ts.map +1 -1
- package/dist/utils/resolveProjectRoot.d.ts.map +1 -1
- package/dist/utils/toStandardSchema.d.ts.map +1 -1
- package/package.json +9 -13
- package/src/endpoint/access.ts +14 -14
- package/src/endpoint/index.ts +79 -14
- package/src/endpoint/oauth.ts +72 -0
- package/src/index.ts +11 -4
- package/src/mcp/buildMcpServer.ts +80 -50
- package/src/mcp/builtin/collections/authTools.ts +80 -69
- package/src/mcp/builtin/collections/countTool.ts +10 -23
- package/src/mcp/builtin/collections/countVersionsTool.ts +10 -20
- package/src/mcp/builtin/collections/createTool.ts +110 -77
- package/src/mcp/builtin/collections/deleteTool.ts +36 -65
- package/src/mcp/builtin/collections/duplicateTool.ts +36 -87
- package/src/mcp/builtin/collections/fileInput.spec.ts +93 -0
- package/src/mcp/builtin/collections/fileInput.ts +127 -0
- package/src/mcp/builtin/collections/findDistinctTool.ts +12 -65
- package/src/mcp/builtin/collections/findTool.ts +25 -108
- package/src/mcp/builtin/collections/findVersionByIDTool.ts +16 -60
- package/src/mcp/builtin/collections/findVersionsTool.ts +15 -87
- package/src/mcp/builtin/collections/getCollectionSchemaTool.ts +60 -15
- package/src/mcp/builtin/collections/restoreVersionTool.ts +15 -58
- package/src/mcp/builtin/collections/updateTool.ts +63 -101
- package/src/mcp/builtin/collections/uploadInstructionsTool.ts +64 -0
- package/src/mcp/builtin/formatEntityError.ts +77 -0
- package/src/mcp/builtin/getConfigInfoTool.ts +4 -5
- package/src/mcp/builtin/globals/countVersionsTool.ts +10 -19
- package/src/mcp/builtin/globals/findTool.ts +14 -53
- package/src/mcp/builtin/globals/findVersionByIDTool.ts +14 -54
- package/src/mcp/builtin/globals/findVersionsTool.ts +15 -94
- package/src/mcp/builtin/globals/getGlobalSchemaTool.ts +41 -9
- package/src/mcp/builtin/globals/restoreVersionTool.ts +15 -47
- package/src/mcp/builtin/globals/updateTool.ts +39 -62
- package/src/mcp/builtinTools.ts +9 -2
- package/src/mcp/sanitizeMCPConfig.ts +6 -1
- package/src/stdio.ts +63 -45
- package/src/types.ts +95 -16
- package/dist/@types/assets.d.js +0 -2
- package/dist/@types/assets.d.js.map +0 -1
- package/dist/mcp/builtin/collections/formatCollectionError.d.ts +0 -9
- package/dist/mcp/builtin/collections/formatCollectionError.d.ts.map +0 -1
- package/dist/mcp/builtin/collections/formatCollectionError.js +0 -60
- package/dist/mcp/builtin/collections/formatCollectionError.js.map +0 -1
- package/dist/mcp/builtin/validateEntityData.d.ts +0 -14
- package/dist/mcp/builtin/validateEntityData.d.ts.map +0 -1
- package/dist/mcp/builtin/validateEntityData.js +0 -82
- package/dist/mcp/builtin/validateEntityData.js.map +0 -1
- package/dist/utils/getVirtualFieldNames.d.ts +0 -14
- package/dist/utils/getVirtualFieldNames.d.ts.map +0 -1
- package/dist/utils/getVirtualFieldNames.js +0 -35
- package/dist/utils/getVirtualFieldNames.js.map +0 -1
- package/dist/utils/localAPIDefaults.d.ts +0 -20
- package/dist/utils/localAPIDefaults.d.ts.map +0 -1
- package/dist/utils/localAPIDefaults.js +0 -19
- package/dist/utils/localAPIDefaults.js.map +0 -1
- package/dist/utils/schemaConversion/getEntityInputSchema.d.ts +0 -11
- package/dist/utils/schemaConversion/getEntityInputSchema.d.ts.map +0 -1
- package/dist/utils/schemaConversion/getEntityInputSchema.js +0 -34
- package/dist/utils/schemaConversion/getEntityInputSchema.js.map +0 -1
- package/dist/utils/schemaConversion/removeVirtualFieldsFromSchema.d.ts +0 -7
- package/dist/utils/schemaConversion/removeVirtualFieldsFromSchema.d.ts.map +0 -1
- package/dist/utils/schemaConversion/removeVirtualFieldsFromSchema.js +0 -20
- package/dist/utils/schemaConversion/removeVirtualFieldsFromSchema.js.map +0 -1
- package/dist/utils/schemaConversion/sanitizeEntitySchema.d.ts +0 -15
- package/dist/utils/schemaConversion/sanitizeEntitySchema.d.ts.map +0 -1
- package/dist/utils/schemaConversion/sanitizeEntitySchema.js +0 -464
- package/dist/utils/schemaConversion/sanitizeEntitySchema.js.map +0 -1
- package/dist/utils/schemaConversion/sanitizeEntitySchema.spec.js +0 -158
- package/dist/utils/schemaConversion/sanitizeEntitySchema.spec.js.map +0 -1
- package/dist/utils/transformPointDataToPayload.d.ts +0 -7
- package/dist/utils/transformPointDataToPayload.d.ts.map +0 -1
- package/dist/utils/transformPointDataToPayload.js +0 -28
- package/dist/utils/transformPointDataToPayload.js.map +0 -1
- package/dist/utils/whereSchema.d.ts +0 -9
- package/dist/utils/whereSchema.d.ts.map +0 -1
- package/dist/utils/whereSchema.js +0 -13
- package/dist/utils/whereSchema.js.map +0 -1
- package/src/@types/assets.d.ts +0 -3
- package/src/mcp/builtin/collections/formatCollectionError.ts +0 -84
- package/src/mcp/builtin/validateEntityData.ts +0 -132
- package/src/utils/getVirtualFieldNames.ts +0 -53
- package/src/utils/localAPIDefaults.ts +0 -22
- package/src/utils/schemaConversion/getEntityInputSchema.ts +0 -78
- package/src/utils/schemaConversion/removeVirtualFieldsFromSchema.ts +0 -27
- package/src/utils/schemaConversion/sanitizeEntitySchema.spec.ts +0 -103
- package/src/utils/schemaConversion/sanitizeEntitySchema.ts +0 -529
- package/src/utils/transformPointDataToPayload.ts +0 -40
- package/src/utils/whereSchema.ts +0 -24
|
@@ -1,12 +1,14 @@
|
|
|
1
|
+
import { getAccessResults, getGlobalInputSchema, getGlobalSchemaInputSchema } from 'payload'
|
|
2
|
+
import { getLLMInstructions } from 'payload/internal'
|
|
3
|
+
|
|
1
4
|
import { defaultAccess } from '../../../defaultAccess.js'
|
|
2
5
|
import { defineGlobalTool } from '../../../defineTool.js'
|
|
3
|
-
import { getGlobalInputSchema } from '../../../utils/schemaConversion/getEntityInputSchema.js'
|
|
4
6
|
|
|
5
7
|
export const getGlobalSchemaTool = defineGlobalTool({
|
|
6
8
|
access: (args) => {
|
|
7
|
-
const permissions = args.permissions?.globals?.[args.
|
|
9
|
+
const permissions = args.permissions?.globals?.[args.slug]
|
|
8
10
|
|
|
9
|
-
return defaultAccess(args) && Boolean(permissions?.
|
|
11
|
+
return defaultAccess(args) && Boolean(permissions?.update)
|
|
10
12
|
},
|
|
11
13
|
annotations: {
|
|
12
14
|
destructiveHint: false,
|
|
@@ -15,27 +17,57 @@ export const getGlobalSchemaTool = defineGlobalTool({
|
|
|
15
17
|
readOnlyHint: true,
|
|
16
18
|
title: 'Get Global Schema',
|
|
17
19
|
},
|
|
18
|
-
description: 'Get the input schema
|
|
19
|
-
|
|
20
|
-
|
|
20
|
+
description: 'Get the input schema and LLM instructions before updating a global.',
|
|
21
|
+
input: getGlobalSchemaInputSchema,
|
|
22
|
+
}).handler(async ({ slug, authorizedMCP, req }) => {
|
|
23
|
+
const permissions = authorizedMCP.overrideAccess
|
|
24
|
+
? null
|
|
25
|
+
: (await getAccessResults({ req })).globals?.[slug]
|
|
26
|
+
|
|
27
|
+
if (!authorizedMCP.overrideAccess && !permissions?.update) {
|
|
28
|
+
return {
|
|
29
|
+
content: [
|
|
30
|
+
{
|
|
31
|
+
type: 'text',
|
|
32
|
+
text: `Error: MCP access to "getGlobalSchema" is not enabled for global "${slug}"`,
|
|
33
|
+
},
|
|
34
|
+
],
|
|
35
|
+
isError: true,
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const inputSchema = getGlobalInputSchema({
|
|
40
|
+
globalSlug: slug,
|
|
41
|
+
req,
|
|
42
|
+
...(permissions ? { permissions } : {}),
|
|
43
|
+
})
|
|
21
44
|
|
|
22
45
|
if (!inputSchema) {
|
|
23
46
|
return {
|
|
24
|
-
content: [{ type: 'text', text: `Error: Global "${
|
|
47
|
+
content: [{ type: 'text', text: `Error: Global "${slug}" not found` }],
|
|
25
48
|
isError: true,
|
|
26
49
|
}
|
|
27
50
|
}
|
|
28
51
|
|
|
52
|
+
const instructions = await getLLMInstructions({
|
|
53
|
+
slug,
|
|
54
|
+
type: 'global',
|
|
55
|
+
overrideAccess: authorizedMCP.overrideAccess,
|
|
56
|
+
req,
|
|
57
|
+
})
|
|
58
|
+
|
|
29
59
|
return {
|
|
30
60
|
content: [
|
|
31
61
|
{
|
|
32
62
|
type: 'text',
|
|
33
|
-
text: `Schema for global "${
|
|
63
|
+
text: `Schema for global "${slug}":\n\`\`\`json\n${JSON.stringify(inputSchema)}\n\`\`\``,
|
|
34
64
|
},
|
|
65
|
+
...(instructions ? [{ type: 'text' as const, text: instructions }] : []),
|
|
35
66
|
],
|
|
36
67
|
structuredContent: {
|
|
37
|
-
|
|
68
|
+
slug,
|
|
38
69
|
schema: inputSchema,
|
|
70
|
+
...(instructions ? { instructions } : {}),
|
|
39
71
|
},
|
|
40
72
|
}
|
|
41
73
|
})
|
|
@@ -1,18 +1,14 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
import { z } from 'zod'
|
|
1
|
+
import { restoreGlobalVersionInputSchema } from 'payload'
|
|
4
2
|
|
|
5
3
|
import { defaultAccess } from '../../../defaultAccess.js'
|
|
6
4
|
import { defineGlobalTool } from '../../../defineTool.js'
|
|
7
5
|
import { getLogger } from '../../../utils/getLogger.js'
|
|
8
|
-
import { localAPIDefaults } from '../../../utils/localAPIDefaults.js'
|
|
9
6
|
|
|
10
7
|
const DEFAULT_DESCRIPTION =
|
|
11
8
|
'Restore a global from a previous version in any version-enabled global.'
|
|
12
9
|
|
|
13
10
|
export const restoreGlobalVersionTool = defineGlobalTool({
|
|
14
|
-
access: (args) =>
|
|
15
|
-
defaultAccess(args) && Boolean(args.permissions?.globals?.[args.globalSlug]?.update),
|
|
11
|
+
access: (args) => defaultAccess(args) && Boolean(args.permissions?.globals?.[args.slug]?.update),
|
|
16
12
|
annotations: {
|
|
17
13
|
destructiveHint: true,
|
|
18
14
|
idempotentHint: false,
|
|
@@ -21,53 +17,25 @@ export const restoreGlobalVersionTool = defineGlobalTool({
|
|
|
21
17
|
title: 'Restore Global Version',
|
|
22
18
|
},
|
|
23
19
|
description: DEFAULT_DESCRIPTION,
|
|
24
|
-
input:
|
|
25
|
-
|
|
26
|
-
depth: z
|
|
27
|
-
.number()
|
|
28
|
-
.int()
|
|
29
|
-
.min(0)
|
|
30
|
-
.max(10)
|
|
31
|
-
.describe('How many levels deep to populate relationships in response')
|
|
32
|
-
.optional()
|
|
33
|
-
.default(0),
|
|
34
|
-
fallbackLocale: z
|
|
35
|
-
.string()
|
|
36
|
-
.describe('Optional: fallback locale code to use when requested locale is not available')
|
|
37
|
-
.optional(),
|
|
38
|
-
locale: z
|
|
39
|
-
.string()
|
|
40
|
-
.describe('Optional: locale code to restore in (e.g., "en", "es")')
|
|
41
|
-
.optional(),
|
|
42
|
-
populate: z
|
|
43
|
-
.record(z.string(), z.unknown())
|
|
44
|
-
.describe(
|
|
45
|
-
'Optional: control which fields to include from populated relationship or upload documents.',
|
|
46
|
-
)
|
|
47
|
-
.optional(),
|
|
48
|
-
showHiddenFields: z
|
|
49
|
-
.boolean()
|
|
50
|
-
.describe('Optional: include hidden fields in the restored global response')
|
|
51
|
-
.optional(),
|
|
52
|
-
}),
|
|
53
|
-
}).handler(async ({ authorizedMCP, globalSlug, input, req }) => {
|
|
20
|
+
input: restoreGlobalVersionInputSchema,
|
|
21
|
+
}).handler(async ({ slug, authorizedMCP, input, req }) => {
|
|
54
22
|
const payload = req.payload
|
|
55
23
|
const logger = getLogger({ payload })
|
|
56
|
-
const { id, depth, fallbackLocale, locale, populate,
|
|
24
|
+
const { id, depth, fallbackLocale, locale, populate, select } = input
|
|
57
25
|
|
|
58
|
-
logger.info(`Restoring version for global: ${
|
|
26
|
+
logger.info(`Restoring version for global: ${slug} with ID: ${id}`)
|
|
59
27
|
|
|
60
28
|
try {
|
|
61
29
|
const result = await payload.restoreGlobalVersion({
|
|
62
|
-
id,
|
|
63
|
-
slug
|
|
30
|
+
id: String(id),
|
|
31
|
+
slug,
|
|
64
32
|
depth,
|
|
33
|
+
overrideAccess: authorizedMCP.overrideAccess,
|
|
65
34
|
req,
|
|
66
|
-
...
|
|
67
|
-
...(fallbackLocale ? { fallbackLocale } : {}),
|
|
35
|
+
...(fallbackLocale !== undefined ? { fallbackLocale } : {}),
|
|
68
36
|
...(locale ? { locale } : {}),
|
|
69
|
-
...(populate ? { populate
|
|
70
|
-
...(
|
|
37
|
+
...(populate ? { populate } : {}),
|
|
38
|
+
...(select ? { select } : {}),
|
|
71
39
|
})
|
|
72
40
|
const resultObject = result as Record<string, unknown>
|
|
73
41
|
const restoredGlobal =
|
|
@@ -79,19 +47,19 @@ export const restoreGlobalVersionTool = defineGlobalTool({
|
|
|
79
47
|
content: [
|
|
80
48
|
{
|
|
81
49
|
type: 'text',
|
|
82
|
-
text: `Version "${id}" restored successfully for global "${
|
|
50
|
+
text: `Version "${id}" restored successfully for global "${slug}"!\nRestored global:\n\`\`\`json\n${JSON.stringify(restoredGlobal)}\n\`\`\``,
|
|
83
51
|
},
|
|
84
52
|
],
|
|
85
53
|
doc: restoredGlobal,
|
|
86
54
|
}
|
|
87
55
|
} catch (error) {
|
|
88
56
|
const errorMessage = error instanceof Error ? error.message : 'Unknown error'
|
|
89
|
-
logger.error(`Error restoring version ${id} for global ${
|
|
57
|
+
logger.error(`Error restoring version ${id} for global ${slug}: ${errorMessage}`)
|
|
90
58
|
return {
|
|
91
59
|
content: [
|
|
92
60
|
{
|
|
93
61
|
type: 'text',
|
|
94
|
-
text: `❌ **Error restoring version "${id}" for global "${
|
|
62
|
+
text: `❌ **Error restoring version "${id}" for global "${slug}":** ${errorMessage}`,
|
|
95
63
|
},
|
|
96
64
|
],
|
|
97
65
|
isError: true,
|
|
@@ -1,23 +1,20 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import {
|
|
2
|
+
getGlobalVirtualFieldNames,
|
|
3
|
+
stripVirtualFields,
|
|
4
|
+
transformPointDataToPayload,
|
|
5
|
+
updateGlobalInputSchema,
|
|
6
|
+
validateGlobalData,
|
|
7
|
+
} from 'payload'
|
|
4
8
|
|
|
5
9
|
import { defaultAccess } from '../../../defaultAccess.js'
|
|
6
10
|
import { defineGlobalTool } from '../../../defineTool.js'
|
|
7
11
|
import { getLogger } from '../../../utils/getLogger.js'
|
|
8
|
-
import {
|
|
9
|
-
getGlobalVirtualFieldNames,
|
|
10
|
-
stripVirtualFields,
|
|
11
|
-
} from '../../../utils/getVirtualFieldNames.js'
|
|
12
|
-
import { localAPIDefaults } from '../../../utils/localAPIDefaults.js'
|
|
13
|
-
import { transformPointDataToPayload } from '../../../utils/transformPointDataToPayload.js'
|
|
14
|
-
import { validateGlobalData } from '../validateEntityData.js'
|
|
12
|
+
import { formatEntityError } from '../formatEntityError.js'
|
|
15
13
|
|
|
16
14
|
const DEFAULT_DESCRIPTION = 'Update any Payload global by passing the global slug and data.'
|
|
17
15
|
|
|
18
16
|
export const updateGlobalTool = defineGlobalTool({
|
|
19
|
-
access: (args) =>
|
|
20
|
-
defaultAccess(args) && Boolean(args.permissions?.globals?.[args.globalSlug]?.update),
|
|
17
|
+
access: (args) => defaultAccess(args) && Boolean(args.permissions?.globals?.[args.slug]?.update),
|
|
21
18
|
annotations: {
|
|
22
19
|
destructiveHint: true,
|
|
23
20
|
idempotentHint: false,
|
|
@@ -26,72 +23,54 @@ export const updateGlobalTool = defineGlobalTool({
|
|
|
26
23
|
title: 'Update Global',
|
|
27
24
|
},
|
|
28
25
|
description: DEFAULT_DESCRIPTION,
|
|
29
|
-
input:
|
|
30
|
-
|
|
31
|
-
depth: z
|
|
32
|
-
.number()
|
|
33
|
-
.describe('Optional: Depth of relationships to populate')
|
|
34
|
-
.optional()
|
|
35
|
-
.default(0),
|
|
36
|
-
draft: z
|
|
37
|
-
.boolean()
|
|
38
|
-
.describe('Optional: Whether to save as draft (default: false)')
|
|
39
|
-
.optional()
|
|
40
|
-
.default(false),
|
|
41
|
-
fallbackLocale: z
|
|
42
|
-
.string()
|
|
43
|
-
.describe('Optional: fallback locale code to use when requested locale is not available')
|
|
44
|
-
.optional(),
|
|
45
|
-
locale: z
|
|
46
|
-
.string()
|
|
47
|
-
.describe(
|
|
48
|
-
'Optional: locale code to update data in (e.g., "en", "es"). Use "all" to update all locales for localized fields',
|
|
49
|
-
)
|
|
50
|
-
.optional(),
|
|
51
|
-
select: z
|
|
52
|
-
.record(z.string(), z.unknown())
|
|
53
|
-
.describe(
|
|
54
|
-
'Optional: define exactly which fields you\'d like to return in the response, e.g., {"siteName": true}',
|
|
55
|
-
)
|
|
56
|
-
.optional(),
|
|
57
|
-
}),
|
|
58
|
-
}).handler(async ({ authorizedMCP, globalSlug, input, req }) => {
|
|
26
|
+
input: updateGlobalInputSchema,
|
|
27
|
+
}).handler(async ({ slug, authorizedMCP, input, req }) => {
|
|
59
28
|
const payload = req.payload
|
|
60
29
|
const logger = getLogger({ payload })
|
|
61
30
|
|
|
62
|
-
const {
|
|
31
|
+
const {
|
|
32
|
+
data,
|
|
33
|
+
depth,
|
|
34
|
+
draft,
|
|
35
|
+
fallbackLocale,
|
|
36
|
+
locale,
|
|
37
|
+
overrideLock,
|
|
38
|
+
populate,
|
|
39
|
+
publishAllLocales,
|
|
40
|
+
select,
|
|
41
|
+
unpublishAllLocales,
|
|
42
|
+
} = input
|
|
63
43
|
|
|
64
|
-
logger.info(
|
|
65
|
-
`Updating global: ${globalSlug}, draft: ${draft}${locale ? `, locale: ${locale}` : ''}`,
|
|
66
|
-
)
|
|
44
|
+
logger.info(`Updating global: ${slug}, draft: ${draft}${locale ? `, locale: ${locale}` : ''}`)
|
|
67
45
|
|
|
68
46
|
try {
|
|
69
|
-
const virtualFieldNames = getGlobalVirtualFieldNames(payload.config,
|
|
47
|
+
const virtualFieldNames = getGlobalVirtualFieldNames(payload.config, slug)
|
|
70
48
|
const inputData = stripVirtualFields(data, virtualFieldNames)
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
if (validationError) {
|
|
74
|
-
return validationError
|
|
75
|
-
}
|
|
49
|
+
validateGlobalData({ slug, data: inputData, req })
|
|
76
50
|
|
|
77
51
|
const parsedData = transformPointDataToPayload(inputData)
|
|
78
52
|
|
|
79
53
|
const updateOptions: Parameters<typeof payload.updateGlobal>[0] = {
|
|
80
|
-
slug
|
|
54
|
+
slug,
|
|
81
55
|
data: parsedData,
|
|
82
56
|
depth,
|
|
83
57
|
draft,
|
|
84
|
-
|
|
58
|
+
overrideAccess: authorizedMCP.overrideAccess,
|
|
59
|
+
overrideLock,
|
|
60
|
+
populate,
|
|
61
|
+
publishAllLocales,
|
|
62
|
+
req,
|
|
63
|
+
unpublishAllLocales,
|
|
85
64
|
}
|
|
86
65
|
|
|
87
66
|
if (locale) {
|
|
88
67
|
updateOptions.locale = locale
|
|
89
68
|
}
|
|
90
|
-
if (fallbackLocale) {
|
|
69
|
+
if (fallbackLocale !== undefined) {
|
|
91
70
|
updateOptions.fallbackLocale = fallbackLocale
|
|
92
71
|
}
|
|
93
72
|
if (select) {
|
|
94
|
-
updateOptions.select = select
|
|
73
|
+
updateOptions.select = select
|
|
95
74
|
}
|
|
96
75
|
|
|
97
76
|
const result = await payload.updateGlobal(updateOptions)
|
|
@@ -100,16 +79,14 @@ export const updateGlobalTool = defineGlobalTool({
|
|
|
100
79
|
content: [
|
|
101
80
|
{
|
|
102
81
|
type: 'text',
|
|
103
|
-
text: `Global "${
|
|
82
|
+
text: `Global "${slug}" updated successfully!\n\`\`\`json\n${JSON.stringify(result)}\n\`\`\``,
|
|
104
83
|
},
|
|
105
84
|
],
|
|
106
85
|
doc: result as Record<string, unknown>,
|
|
107
86
|
}
|
|
108
87
|
} catch (error) {
|
|
109
|
-
const
|
|
110
|
-
logger.error(`Error updating global ${
|
|
111
|
-
return {
|
|
112
|
-
content: [{ type: 'text', text: `Error updating global "${globalSlug}": ${errorMessage}` }],
|
|
113
|
-
}
|
|
88
|
+
const message = error instanceof Error ? error.message : 'Unknown error'
|
|
89
|
+
logger.error(`Error updating global ${slug}: ${message}`)
|
|
90
|
+
return formatEntityError({ slug, action: 'updating', entity: 'global', error, req })
|
|
114
91
|
}
|
|
115
92
|
})
|
package/src/mcp/builtinTools.ts
CHANGED
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
} from './builtin/collections/authTools.js'
|
|
11
11
|
import { countDocumentsTool } from './builtin/collections/countTool.js'
|
|
12
12
|
import { countVersionsTool } from './builtin/collections/countVersionsTool.js'
|
|
13
|
-
import {
|
|
13
|
+
import { createDocumentsTool } from './builtin/collections/createTool.js'
|
|
14
14
|
import { deleteDocumentsTool } from './builtin/collections/deleteTool.js'
|
|
15
15
|
import { duplicateDocumentTool } from './builtin/collections/duplicateTool.js'
|
|
16
16
|
import { findDistinctTool } from './builtin/collections/findDistinctTool.js'
|
|
@@ -20,6 +20,7 @@ import { findVersionsTool } from './builtin/collections/findVersionsTool.js'
|
|
|
20
20
|
import { getCollectionSchemaTool } from './builtin/collections/getCollectionSchemaTool.js'
|
|
21
21
|
import { restoreVersionTool } from './builtin/collections/restoreVersionTool.js'
|
|
22
22
|
import { updateDocumentTool } from './builtin/collections/updateTool.js'
|
|
23
|
+
import { getUploadInstructionsTool } from './builtin/collections/uploadInstructionsTool.js'
|
|
23
24
|
import { getConfigInfoTool } from './builtin/getConfigInfoTool.js'
|
|
24
25
|
import { countGlobalVersionsTool } from './builtin/globals/countVersionsTool.js'
|
|
25
26
|
import { findGlobalTool } from './builtin/globals/findTool.js'
|
|
@@ -32,6 +33,7 @@ import { updateGlobalTool } from './builtin/globals/updateTool.js'
|
|
|
32
33
|
type CollectionBuiltin = {
|
|
33
34
|
mcpName: string
|
|
34
35
|
requiresDuplicateEnabled?: boolean
|
|
36
|
+
requiresUpload?: boolean
|
|
35
37
|
requiresVersions?: boolean
|
|
36
38
|
tool: CollectionTool
|
|
37
39
|
}
|
|
@@ -54,7 +56,7 @@ export const TOOL_BUILTINS = {
|
|
|
54
56
|
export const COLLECTION_BUILTINS = {
|
|
55
57
|
count: { mcpName: 'countDocuments', tool: countDocumentsTool },
|
|
56
58
|
countVersions: { mcpName: 'countVersions', requiresVersions: true, tool: countVersionsTool },
|
|
57
|
-
create: { mcpName: '
|
|
59
|
+
create: { mcpName: 'createDocuments', tool: createDocumentsTool },
|
|
58
60
|
delete: { mcpName: 'deleteDocuments', tool: deleteDocumentsTool },
|
|
59
61
|
duplicate: {
|
|
60
62
|
mcpName: 'duplicateDocument',
|
|
@@ -70,6 +72,11 @@ export const COLLECTION_BUILTINS = {
|
|
|
70
72
|
},
|
|
71
73
|
findVersions: { mcpName: 'findVersions', requiresVersions: true, tool: findVersionsTool },
|
|
72
74
|
getCollectionSchema: { mcpName: 'getCollectionSchema', tool: getCollectionSchemaTool },
|
|
75
|
+
getUploadInstructions: {
|
|
76
|
+
mcpName: 'getUploadInstructions',
|
|
77
|
+
requiresUpload: true,
|
|
78
|
+
tool: getUploadInstructionsTool,
|
|
79
|
+
},
|
|
73
80
|
restoreVersion: { mcpName: 'restoreVersion', requiresVersions: true, tool: restoreVersionTool },
|
|
74
81
|
update: { mcpName: 'updateDocument', tool: updateDocumentTool },
|
|
75
82
|
} satisfies Record<string, CollectionBuiltin>
|
|
@@ -100,8 +100,10 @@ export const sanitizeMCPConfig = ({
|
|
|
100
100
|
|
|
101
101
|
return {
|
|
102
102
|
disabled: pluginConfig.disabled,
|
|
103
|
+
hooks: pluginConfig.hooks,
|
|
103
104
|
items,
|
|
104
105
|
mcp: pluginConfig.mcp,
|
|
106
|
+
oauth: pluginConfig.oauth,
|
|
105
107
|
overrideGetAuthorizedMCP: pluginConfig.overrideGetAuthorizedMCP,
|
|
106
108
|
}
|
|
107
109
|
}
|
|
@@ -126,7 +128,7 @@ const sanitizeCollectionConfig = ({
|
|
|
126
128
|
|
|
127
129
|
for (const [
|
|
128
130
|
toolKey,
|
|
129
|
-
{ mcpName, requiresDuplicateEnabled, requiresVersions, tool },
|
|
131
|
+
{ mcpName, requiresDuplicateEnabled, requiresUpload, requiresVersions, tool },
|
|
130
132
|
] of COLLECTION_BUILTIN_ENTRIES) {
|
|
131
133
|
if (requiresVersions && !collection.versions) {
|
|
132
134
|
continue
|
|
@@ -134,6 +136,9 @@ const sanitizeCollectionConfig = ({
|
|
|
134
136
|
if (requiresDuplicateEnabled && isDuplicateDisabled) {
|
|
135
137
|
continue
|
|
136
138
|
}
|
|
139
|
+
if (requiresUpload && !collection.upload) {
|
|
140
|
+
continue
|
|
141
|
+
}
|
|
137
142
|
const matchedConfigEntry = collectionPluginConfig?.tools?.[toolKey]
|
|
138
143
|
if (matchedConfigEntry === false) {
|
|
139
144
|
continue
|
package/src/stdio.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Config, Plugin, SanitizedConfig } from 'payload'
|
|
2
2
|
|
|
3
3
|
/* eslint-disable no-console */
|
|
4
|
-
import {
|
|
4
|
+
import { serveStdio } from '@modelcontextprotocol/server/stdio'
|
|
5
5
|
import { fileURLToPath, pathToFileURL } from 'node:url'
|
|
6
|
-
import {
|
|
7
|
-
import { findConfig } from 'payload/node'
|
|
6
|
+
import { createPayloadRequest, getPayload } from 'payload'
|
|
7
|
+
import { findConfig, loadEnv } from 'payload/node'
|
|
8
8
|
|
|
9
9
|
import type { SanitizedMCPPluginConfig } from './types.js'
|
|
10
10
|
|
|
@@ -15,53 +15,62 @@ import { getPluginConfig } from './utils/getPluginConfig.js'
|
|
|
15
15
|
import { resolveProjectRoot } from './utils/resolveProjectRoot.js'
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
|
-
*
|
|
18
|
+
* Starts Payload's MCP server over stdin and stdout.
|
|
19
19
|
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* skips access control for local setup.
|
|
20
|
+
* Set `PAYLOAD_MCP_AUTHORIZATION` to authenticate. In development,
|
|
21
|
+
* `PAYLOAD_MCP_OVERRIDE_ACCESS=true` skips access checks.
|
|
23
22
|
*/
|
|
24
23
|
export const runMcpStdio = async (): Promise<void> => {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
* Payload's cwd-anchored `findConfig()` can't locate the project on
|
|
28
|
-
* its own. This module always lives inside the project's `node_modules`, so
|
|
29
|
-
* we derive the project root from its own path and `chdir` into it.
|
|
30
|
-
*
|
|
31
|
-
* An absolute `PAYLOAD_CONFIG_PATH` still overrides everything; unusual
|
|
32
|
-
* layouts (e.g. a monorepo where the package is hoisted above the app) can
|
|
33
|
-
* fall back to it. See the implementation of findConfig for details.
|
|
34
|
-
*/
|
|
24
|
+
// MCP clients may start this command from another folder. Move to the Payload
|
|
25
|
+
// project so findConfig() can find the config.
|
|
35
26
|
const projectRoot = resolveProjectRoot(fileURLToPath(import.meta.url))
|
|
36
27
|
if (projectRoot) {
|
|
37
28
|
process.chdir(projectRoot)
|
|
38
29
|
}
|
|
39
30
|
|
|
31
|
+
loadEnv()
|
|
40
32
|
const configPath = findConfig()
|
|
41
33
|
const configModule = await import(pathToFileURL(configPath).toString())
|
|
42
|
-
const config = (await (configModule.default ?? configModule)) as
|
|
43
|
-
|
|
44
|
-
const payload = await getPayload({ config })
|
|
34
|
+
const config = (await (configModule.default ?? configModule)) as SanitizedConfig
|
|
45
35
|
|
|
46
36
|
/**
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
37
|
+
* stdout is only for MCP messages. The spec says the server must not write
|
|
38
|
+
* logs there and may write them to stderr instead.
|
|
39
|
+
*
|
|
40
|
+
* The 2.0 client library recovers from stray stdout logs, but that behavior is not
|
|
41
|
+
* guaranteed. Move Payload logs to stderr so Payload does not add invalid data
|
|
42
|
+
* to stdout. Keep options from configurable loggers. Replace pre-built loggers
|
|
43
|
+
* because their output cannot be redirected.
|
|
44
|
+
*
|
|
45
|
+
* @see https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#stdio
|
|
51
46
|
*/
|
|
47
|
+
const loggerConfig: { logger?: Config['logger'] } = config
|
|
48
|
+
if (
|
|
49
|
+
loggerConfig.logger &&
|
|
50
|
+
typeof loggerConfig.logger === 'object' &&
|
|
51
|
+
'options' in loggerConfig.logger
|
|
52
|
+
) {
|
|
53
|
+
loggerConfig.logger.destination = process.stderr
|
|
54
|
+
} else {
|
|
55
|
+
loggerConfig.logger = { destination: process.stderr, options: {} }
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const payload = await getPayload({ config, cron: false, disableOnInit: true })
|
|
59
|
+
|
|
52
60
|
let pluginConfig: SanitizedMCPPluginConfig
|
|
53
61
|
try {
|
|
54
62
|
pluginConfig = getPluginConfig({ config: payload.config })
|
|
55
63
|
} catch {
|
|
64
|
+
// The command also works when mcpPlugin() is not in the Payload config.
|
|
56
65
|
pluginConfig = sanitizeMCPConfig({ config: payload.config, pluginConfig: {} })
|
|
57
66
|
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
67
|
+
const fallbackPlugin: Plugin = (config) => config
|
|
68
|
+
Object.assign(fallbackPlugin, {
|
|
69
|
+
slug: '@payloadcms/plugin-mcp',
|
|
70
|
+
sanitizedOptions: pluginConfig,
|
|
71
|
+
})
|
|
72
|
+
payload.config.plugins ??= []
|
|
73
|
+
payload.config.plugins.push(fallbackPlugin)
|
|
65
74
|
}
|
|
66
75
|
|
|
67
76
|
const overrideAccessEnv = process.env.PAYLOAD_MCP_OVERRIDE_ACCESS
|
|
@@ -82,32 +91,41 @@ export const runMcpStdio = async (): Promise<void> => {
|
|
|
82
91
|
headers.set('Authorization', process.env.PAYLOAD_MCP_AUTHORIZATION)
|
|
83
92
|
}
|
|
84
93
|
|
|
85
|
-
const req = await
|
|
94
|
+
const req = await createPayloadRequest({ payload, req: { headers } })
|
|
86
95
|
req.payloadAPI = 'MCP' as const
|
|
87
96
|
const authorizedMCP = await getAuthorizedMCP({ overrideAccess, req })
|
|
88
97
|
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
98
|
+
const stdioServer = serveStdio(() => buildMcpServer({ authorizedMCP, pluginConfig, req }), {
|
|
99
|
+
onerror: (err) => {
|
|
100
|
+
// MCP messages use stdout, so write SDK errors to stderr.
|
|
101
|
+
console.error('[payload-mcp] error serving MCP over stdio:', err)
|
|
102
|
+
},
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
// Close the MCP server and Payload when the client disconnects or the process stops.
|
|
106
|
+
let isShuttingDown = false
|
|
107
|
+
const shutdown = async () => {
|
|
108
|
+
if (isShuttingDown) {
|
|
109
|
+
return
|
|
110
|
+
}
|
|
111
|
+
isShuttingDown = true
|
|
93
112
|
|
|
94
|
-
// Process now lives until stdin closes. Wire graceful shutdown so DB
|
|
95
|
-
// connections (and any other Payload-managed resources) get released.
|
|
96
|
-
const shutdown = async (code = 0) => {
|
|
97
113
|
try {
|
|
98
|
-
await
|
|
114
|
+
await stdioServer.close()
|
|
99
115
|
} catch (err) {
|
|
100
116
|
console.error('[payload-mcp] error closing server:', err)
|
|
101
117
|
}
|
|
118
|
+
|
|
102
119
|
try {
|
|
103
120
|
await payload.destroy()
|
|
104
121
|
} catch (err) {
|
|
105
122
|
console.error('[payload-mcp] error destroying payload:', err)
|
|
106
123
|
}
|
|
107
|
-
|
|
124
|
+
|
|
125
|
+
process.exit(0)
|
|
108
126
|
}
|
|
109
127
|
|
|
110
|
-
process.
|
|
111
|
-
process.
|
|
112
|
-
process.stdin.
|
|
128
|
+
process.once('SIGINT', () => void shutdown())
|
|
129
|
+
process.once('SIGTERM', () => void shutdown())
|
|
130
|
+
process.stdin.once('close', () => void shutdown())
|
|
113
131
|
}
|