@payloadcms/plugin-mcp 4.0.0-internal.c3ac604 → 4.0.0-internal.cb69780

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.
Files changed (159) hide show
  1. package/dist/endpoint/access.js +2 -2
  2. package/dist/endpoint/access.js.map +1 -1
  3. package/dist/mcp/buildMcpServer.d.ts +2 -2
  4. package/dist/mcp/buildMcpServer.d.ts.map +1 -1
  5. package/dist/mcp/buildMcpServer.js +36 -24
  6. package/dist/mcp/buildMcpServer.js.map +1 -1
  7. package/dist/mcp/builtin/collections/authTools.d.ts.map +1 -1
  8. package/dist/mcp/builtin/collections/authTools.js +80 -56
  9. package/dist/mcp/builtin/collections/authTools.js.map +1 -1
  10. package/dist/mcp/builtin/collections/countTool.d.ts.map +1 -1
  11. package/dist/mcp/builtin/collections/countTool.js +9 -14
  12. package/dist/mcp/builtin/collections/countTool.js.map +1 -1
  13. package/dist/mcp/builtin/collections/countVersionsTool.d.ts.map +1 -1
  14. package/dist/mcp/builtin/collections/countVersionsTool.js +9 -13
  15. package/dist/mcp/builtin/collections/countVersionsTool.js.map +1 -1
  16. package/dist/mcp/builtin/collections/createTool.d.ts.map +1 -1
  17. package/dist/mcp/builtin/collections/createTool.js +48 -49
  18. package/dist/mcp/builtin/collections/createTool.js.map +1 -1
  19. package/dist/mcp/builtin/collections/deleteTool.d.ts.map +1 -1
  20. package/dist/mcp/builtin/collections/deleteTool.js +44 -43
  21. package/dist/mcp/builtin/collections/deleteTool.js.map +1 -1
  22. package/dist/mcp/builtin/collections/duplicateTool.d.ts.map +1 -1
  23. package/dist/mcp/builtin/collections/duplicateTool.js +31 -37
  24. package/dist/mcp/builtin/collections/duplicateTool.js.map +1 -1
  25. package/dist/mcp/builtin/collections/fileInput.d.ts +21 -21
  26. package/dist/mcp/builtin/collections/fileInput.d.ts.map +1 -1
  27. package/dist/mcp/builtin/collections/fileInput.js +34 -70
  28. package/dist/mcp/builtin/collections/fileInput.js.map +1 -1
  29. package/dist/mcp/builtin/collections/findDistinctTool.d.ts.map +1 -1
  30. package/dist/mcp/builtin/collections/findDistinctTool.js +11 -26
  31. package/dist/mcp/builtin/collections/findDistinctTool.js.map +1 -1
  32. package/dist/mcp/builtin/collections/findTool.d.ts.map +1 -1
  33. package/dist/mcp/builtin/collections/findTool.js +27 -45
  34. package/dist/mcp/builtin/collections/findTool.js.map +1 -1
  35. package/dist/mcp/builtin/collections/findVersionByIDTool.d.ts.map +1 -1
  36. package/dist/mcp/builtin/collections/findVersionByIDTool.js +17 -26
  37. package/dist/mcp/builtin/collections/findVersionByIDTool.js.map +1 -1
  38. package/dist/mcp/builtin/collections/findVersionsTool.d.ts.map +1 -1
  39. package/dist/mcp/builtin/collections/findVersionsTool.js +16 -30
  40. package/dist/mcp/builtin/collections/findVersionsTool.js.map +1 -1
  41. package/dist/mcp/builtin/collections/getCollectionSchemaTool.d.ts.map +1 -1
  42. package/dist/mcp/builtin/collections/getCollectionSchemaTool.js +12 -12
  43. package/dist/mcp/builtin/collections/getCollectionSchemaTool.js.map +1 -1
  44. package/dist/mcp/builtin/collections/restoreVersionTool.d.ts.map +1 -1
  45. package/dist/mcp/builtin/collections/restoreVersionTool.js +14 -26
  46. package/dist/mcp/builtin/collections/restoreVersionTool.js.map +1 -1
  47. package/dist/mcp/builtin/collections/updateTool.d.ts.map +1 -1
  48. package/dist/mcp/builtin/collections/updateTool.js +55 -87
  49. package/dist/mcp/builtin/collections/updateTool.js.map +1 -1
  50. package/dist/mcp/builtin/collections/uploadInstructionsTool.js +11 -11
  51. package/dist/mcp/builtin/collections/uploadInstructionsTool.js.map +1 -1
  52. package/dist/mcp/builtin/formatEntityError.d.ts +16 -0
  53. package/dist/mcp/builtin/formatEntityError.d.ts.map +1 -0
  54. package/dist/mcp/builtin/formatEntityError.js +55 -0
  55. package/dist/mcp/builtin/formatEntityError.js.map +1 -0
  56. package/dist/mcp/builtin/getConfigInfoTool.d.ts.map +1 -1
  57. package/dist/mcp/builtin/getConfigInfoTool.js +3 -2
  58. package/dist/mcp/builtin/getConfigInfoTool.js.map +1 -1
  59. package/dist/mcp/builtin/globals/countVersionsTool.d.ts.map +1 -1
  60. package/dist/mcp/builtin/globals/countVersionsTool.js +9 -13
  61. package/dist/mcp/builtin/globals/countVersionsTool.js.map +1 -1
  62. package/dist/mcp/builtin/globals/findTool.d.ts.map +1 -1
  63. package/dist/mcp/builtin/globals/findTool.js +10 -16
  64. package/dist/mcp/builtin/globals/findTool.js.map +1 -1
  65. package/dist/mcp/builtin/globals/findVersionByIDTool.d.ts.map +1 -1
  66. package/dist/mcp/builtin/globals/findVersionByIDTool.js +13 -24
  67. package/dist/mcp/builtin/globals/findVersionByIDTool.js.map +1 -1
  68. package/dist/mcp/builtin/globals/findVersionsTool.d.ts.map +1 -1
  69. package/dist/mcp/builtin/globals/findVersionsTool.js +13 -29
  70. package/dist/mcp/builtin/globals/findVersionsTool.js.map +1 -1
  71. package/dist/mcp/builtin/globals/getGlobalSchemaTool.d.ts.map +1 -1
  72. package/dist/mcp/builtin/globals/getGlobalSchemaTool.js +11 -11
  73. package/dist/mcp/builtin/globals/getGlobalSchemaTool.js.map +1 -1
  74. package/dist/mcp/builtin/globals/restoreVersionTool.d.ts.map +1 -1
  75. package/dist/mcp/builtin/globals/restoreVersionTool.js +15 -22
  76. package/dist/mcp/builtin/globals/restoreVersionTool.js.map +1 -1
  77. package/dist/mcp/builtin/globals/updateTool.d.ts.map +1 -1
  78. package/dist/mcp/builtin/globals/updateTool.js +27 -36
  79. package/dist/mcp/builtin/globals/updateTool.js.map +1 -1
  80. package/dist/stdio.js +4 -3
  81. package/dist/stdio.js.map +1 -1
  82. package/dist/types.d.ts +4 -4
  83. package/dist/types.d.ts.map +1 -1
  84. package/dist/types.js.map +1 -1
  85. package/package.json +5 -7
  86. package/src/endpoint/access.ts +2 -3
  87. package/src/mcp/buildMcpServer.ts +40 -30
  88. package/src/mcp/builtin/collections/authTools.ts +80 -69
  89. package/src/mcp/builtin/collections/countTool.ts +9 -21
  90. package/src/mcp/builtin/collections/countVersionsTool.ts +9 -18
  91. package/src/mcp/builtin/collections/createTool.ts +73 -96
  92. package/src/mcp/builtin/collections/deleteTool.ts +36 -64
  93. package/src/mcp/builtin/collections/duplicateTool.ts +35 -85
  94. package/src/mcp/builtin/collections/fileInput.spec.ts +2 -2
  95. package/src/mcp/builtin/collections/fileInput.ts +44 -81
  96. package/src/mcp/builtin/collections/findDistinctTool.ts +11 -63
  97. package/src/mcp/builtin/collections/findTool.ts +23 -105
  98. package/src/mcp/builtin/collections/findVersionByIDTool.ts +15 -58
  99. package/src/mcp/builtin/collections/findVersionsTool.ts +14 -85
  100. package/src/mcp/builtin/collections/getCollectionSchemaTool.ts +11 -11
  101. package/src/mcp/builtin/collections/restoreVersionTool.ts +14 -56
  102. package/src/mcp/builtin/collections/updateTool.ts +55 -109
  103. package/src/mcp/builtin/collections/uploadInstructionsTool.ts +12 -12
  104. package/src/mcp/builtin/formatEntityError.ts +77 -0
  105. package/src/mcp/builtin/getConfigInfoTool.ts +2 -1
  106. package/src/mcp/builtin/globals/countVersionsTool.ts +9 -17
  107. package/src/mcp/builtin/globals/findTool.ts +12 -51
  108. package/src/mcp/builtin/globals/findVersionByIDTool.ts +13 -52
  109. package/src/mcp/builtin/globals/findVersionsTool.ts +14 -92
  110. package/src/mcp/builtin/globals/getGlobalSchemaTool.ts +10 -10
  111. package/src/mcp/builtin/globals/restoreVersionTool.ts +14 -45
  112. package/src/mcp/builtin/globals/updateTool.ts +37 -60
  113. package/src/stdio.ts +2 -2
  114. package/src/types.ts +4 -4
  115. package/dist/mcp/builtin/collections/fileInput.spec.js +0 -86
  116. package/dist/mcp/builtin/collections/fileInput.spec.js.map +0 -1
  117. package/dist/mcp/builtin/collections/formatCollectionError.d.ts +0 -9
  118. package/dist/mcp/builtin/collections/formatCollectionError.d.ts.map +0 -1
  119. package/dist/mcp/builtin/collections/formatCollectionError.js +0 -60
  120. package/dist/mcp/builtin/collections/formatCollectionError.js.map +0 -1
  121. package/dist/mcp/builtin/validateEntityData.d.ts +0 -14
  122. package/dist/mcp/builtin/validateEntityData.d.ts.map +0 -1
  123. package/dist/mcp/builtin/validateEntityData.js +0 -82
  124. package/dist/mcp/builtin/validateEntityData.js.map +0 -1
  125. package/dist/utils/getVirtualFieldNames.d.ts +0 -14
  126. package/dist/utils/getVirtualFieldNames.d.ts.map +0 -1
  127. package/dist/utils/getVirtualFieldNames.js +0 -35
  128. package/dist/utils/getVirtualFieldNames.js.map +0 -1
  129. package/dist/utils/schemaConversion/filterFieldsByAccess.d.ts +0 -28
  130. package/dist/utils/schemaConversion/filterFieldsByAccess.d.ts.map +0 -1
  131. package/dist/utils/schemaConversion/filterFieldsByAccess.js +0 -71
  132. package/dist/utils/schemaConversion/filterFieldsByAccess.js.map +0 -1
  133. package/dist/utils/schemaConversion/getEntityInputSchema.d.ts +0 -13
  134. package/dist/utils/schemaConversion/getEntityInputSchema.d.ts.map +0 -1
  135. package/dist/utils/schemaConversion/getEntityInputSchema.js +0 -66
  136. package/dist/utils/schemaConversion/getEntityInputSchema.js.map +0 -1
  137. package/dist/utils/schemaConversion/sanitizeEntitySchema.d.ts +0 -10
  138. package/dist/utils/schemaConversion/sanitizeEntitySchema.d.ts.map +0 -1
  139. package/dist/utils/schemaConversion/sanitizeEntitySchema.js +0 -384
  140. package/dist/utils/schemaConversion/sanitizeEntitySchema.js.map +0 -1
  141. package/dist/utils/schemaConversion/sanitizeEntitySchema.spec.js +0 -133
  142. package/dist/utils/schemaConversion/sanitizeEntitySchema.spec.js.map +0 -1
  143. package/dist/utils/transformPointDataToPayload.d.ts +0 -7
  144. package/dist/utils/transformPointDataToPayload.d.ts.map +0 -1
  145. package/dist/utils/transformPointDataToPayload.js +0 -28
  146. package/dist/utils/transformPointDataToPayload.js.map +0 -1
  147. package/dist/utils/whereSchema.d.ts +0 -9
  148. package/dist/utils/whereSchema.d.ts.map +0 -1
  149. package/dist/utils/whereSchema.js +0 -13
  150. package/dist/utils/whereSchema.js.map +0 -1
  151. package/src/mcp/builtin/collections/formatCollectionError.ts +0 -84
  152. package/src/mcp/builtin/validateEntityData.ts +0 -132
  153. package/src/utils/getVirtualFieldNames.ts +0 -53
  154. package/src/utils/schemaConversion/filterFieldsByAccess.ts +0 -123
  155. package/src/utils/schemaConversion/getEntityInputSchema.ts +0 -96
  156. package/src/utils/schemaConversion/sanitizeEntitySchema.spec.ts +0 -96
  157. package/src/utils/schemaConversion/sanitizeEntitySchema.ts +0 -432
  158. package/src/utils/transformPointDataToPayload.ts +0 -40
  159. package/src/utils/whereSchema.ts +0 -24
@@ -1,27 +1,27 @@
1
- import type { SelectType, Where } from 'payload'
1
+ import type { Where } from 'payload'
2
2
 
3
- import { z } from 'zod'
3
+ import {
4
+ getCollectionInputSchema,
5
+ getCollectionVirtualFieldNames,
6
+ parseDocumentID,
7
+ stripVirtualFields,
8
+ transformPointDataToPayload,
9
+ updateDocumentInputSchema,
10
+ validateCollectionData,
11
+ } from 'payload'
4
12
 
5
13
  import { defaultAccess } from '../../../defaultAccess.js'
6
14
  import { defineCollectionTool } from '../../../defineTool.js'
7
15
  import { getLogger } from '../../../utils/getLogger.js'
8
- import {
9
- getCollectionVirtualFieldNames,
10
- stripVirtualFields,
11
- } from '../../../utils/getVirtualFieldNames.js'
12
- import { getCollectionInputSchema } from '../../../utils/schemaConversion/getEntityInputSchema.js'
13
- import { transformPointDataToPayload } from '../../../utils/transformPointDataToPayload.js'
14
- import { whereSchema } from '../../../utils/whereSchema.js'
15
- import { validateCollectionData } from '../validateEntityData.js'
16
+ import { formatEntityError } from '../formatEntityError.js'
16
17
  import { fileInputSchema, resolveFile } from './fileInput.js'
17
- import { formatCollectionError } from './formatCollectionError.js'
18
18
 
19
19
  const DEFAULT_DESCRIPTION =
20
20
  'Update documents. Prefer uploadReference after upload, externalURL for URLs, or base64 for small local files.'
21
21
 
22
22
  export const updateDocumentTool = defineCollectionTool({
23
23
  access: (args) =>
24
- defaultAccess(args) && Boolean(args.permissions?.collections?.[args.collectionSlug]?.update),
24
+ defaultAccess(args) && Boolean(args.permissions?.collections?.[args.slug]?.update),
25
25
  annotations: {
26
26
  destructiveHint: true,
27
27
  idempotentHint: false,
@@ -30,65 +30,8 @@ export const updateDocumentTool = defineCollectionTool({
30
30
  title: 'Update Document',
31
31
  },
32
32
  description: DEFAULT_DESCRIPTION,
33
- input: z.object({
34
- id: z.union([z.string(), z.number()]).describe('The ID of the document to update').optional(),
35
- data: z
36
- .record(z.string(), z.unknown())
37
- .describe(
38
- 'The fields to update. Only include fields permitted by the schema returned by getCollectionSchema.',
39
- ),
40
- depth: z
41
- .number()
42
- .describe('How many levels deep to populate relationships')
43
- .optional()
44
- .default(0),
45
- draft: z
46
- .boolean()
47
- .describe(
48
- 'Only if getCollectionSchema includes _status; otherwise _status does not exist. true saves only a draft version; false updates main and versions. data._status: "published" overrides true.',
49
- )
50
- .optional()
51
- .default(false),
52
- fallbackLocale: z
53
- .string()
54
- .describe('Optional: fallback locale code to use when requested locale is not available')
55
- .optional(),
56
- file: fileInputSchema.optional(),
57
- locale: z
58
- .string()
59
- .describe(
60
- 'Optional: locale code to update the document in (e.g., "en", "es"). Defaults to the default locale',
61
- )
62
- .optional(),
63
- overrideLock: z
64
- .boolean()
65
- .describe('Whether to override document locks')
66
- .optional()
67
- .default(true),
68
- overwriteExistingFiles: z
69
- .boolean()
70
- .describe('Whether to overwrite existing files')
71
- .optional()
72
- .default(false),
73
- publishAllLocales: z
74
- .boolean()
75
- .describe(
76
- 'For collections with localized publishing status, whether publishing should affect every locale. Set false with locale to publish only that locale.',
77
- )
78
- .optional(),
79
- select: z
80
- .record(z.string(), z.unknown())
81
- .describe(
82
- 'Optional: define exactly which fields you\'d like to return in the response, e.g., {"title": true}',
83
- )
84
- .optional(),
85
- where: whereSchema
86
- .describe(
87
- 'Where clause to update multiple documents. Use field names with Payload operators, and/or arrays for grouping. Example: {"title":{"contains":"test"}}',
88
- )
89
- .optional(),
90
- }),
91
- }).handler(async ({ authorizedMCP, collectionSlug, input, req }) => {
33
+ input: updateDocumentInputSchema({ file: fileInputSchema }),
34
+ }).handler(async ({ slug, authorizedMCP, input, req }) => {
92
35
  const payload = req.payload
93
36
  const logger = getLogger({ payload })
94
37
 
@@ -99,100 +42,103 @@ export const updateDocumentTool = defineCollectionTool({
99
42
  draft,
100
43
  fallbackLocale,
101
44
  file: fileInput,
45
+ limit,
102
46
  locale,
103
47
  overrideLock,
104
- overwriteExistingFiles,
48
+ populate,
105
49
  publishAllLocales,
50
+ returning,
106
51
  select,
52
+ sort,
53
+ trash,
54
+ unpublishAllLocales,
107
55
  where,
108
56
  } = input
109
57
 
110
58
  logger.info(
111
- `Updating document in collection: ${collectionSlug}${id ? ` with ID: ${id}` : ' with where clause'}, draft: ${draft}${locale ? `, locale: ${locale}` : ''}`,
59
+ `Updating document in collection: ${slug}${id ? ` with ID: ${id}` : ' with where clause'}, draft: ${draft}${locale ? `, locale: ${locale}` : ''}`,
112
60
  )
113
61
 
114
62
  try {
115
- if (!id && !where) {
116
- return {
117
- content: [{ type: 'text', text: 'Error: Either id or where clause must be provided' }],
118
- }
119
- }
120
-
121
- const virtualFieldNames = getCollectionVirtualFieldNames(payload.config, collectionSlug)
63
+ const virtualFieldNames = getCollectionVirtualFieldNames(payload.config, slug)
122
64
  const inputData = stripVirtualFields(data, virtualFieldNames)
123
- const validationError = validateCollectionData({
124
- collectionSlug,
65
+ validateCollectionData({
66
+ slug,
125
67
  data: inputData,
126
68
  partial: true,
127
69
  req,
128
70
  })
129
71
 
130
- if (validationError) {
131
- return validationError
132
- }
133
-
134
72
  const parsedData = transformPointDataToPayload(inputData)
135
- const file = await resolveFile({ collectionSlug, input: fileInput, req })
73
+ const file = await resolveFile({ slug, input: fileInput, req })
136
74
 
137
75
  const whereClause: Where = where ?? {}
138
76
 
139
- if (id) {
77
+ if (id !== undefined) {
140
78
  const result = await payload.update({
141
- id,
142
- collection: collectionSlug,
79
+ id: parseDocumentID({ id, collectionSlug: slug, payload }),
80
+ collection: slug,
143
81
  data: parsedData,
144
82
  depth,
145
83
  draft,
84
+ fallbackLocale,
85
+ locale,
146
86
  overrideAccess: authorizedMCP.overrideAccess,
147
87
  overrideLock,
88
+ populate,
89
+ publishAllLocales,
148
90
  req,
91
+ select: returning ? select : { id: true },
92
+ trash,
93
+ unpublishAllLocales,
149
94
  ...(file ? { file } : {}),
150
- ...(overwriteExistingFiles ? { overwriteExistingFiles } : {}),
151
- ...(publishAllLocales !== undefined ? { publishAllLocales } : {}),
152
- ...(locale ? { locale } : {}),
153
- ...(fallbackLocale ? { fallbackLocale } : {}),
154
- ...(select ? { select: select as SelectType } : {}),
155
95
  })
156
96
 
97
+ const responseResult = returning ? result : { id: result.id }
98
+
157
99
  return {
158
100
  content: [
159
101
  {
160
102
  type: 'text',
161
- text: `Document updated successfully in collection "${collectionSlug}"!\nUpdated document:\n\`\`\`json\n${JSON.stringify(result)}\n\`\`\``,
103
+ text: `Document updated successfully in collection "${slug}"!\nResult:\n\`\`\`json\n${JSON.stringify(responseResult)}\n\`\`\``,
162
104
  },
163
105
  ],
164
- doc: result as Record<string, unknown>,
106
+ doc: responseResult as Record<string, unknown>,
165
107
  }
166
108
  }
167
109
 
168
110
  const result = await payload.update({
169
- collection: collectionSlug,
111
+ collection: slug,
170
112
  data: parsedData,
171
113
  depth,
172
114
  draft,
115
+ fallbackLocale,
116
+ limit,
117
+ locale,
173
118
  overrideAccess: authorizedMCP.overrideAccess,
174
119
  overrideLock,
120
+ populate,
121
+ publishAllLocales,
175
122
  req,
123
+ select: returning ? select : { id: true },
124
+ sort,
125
+ trash,
126
+ unpublishAllLocales,
176
127
  where: whereClause,
177
128
  ...(file ? { file } : {}),
178
- ...(overwriteExistingFiles ? { overwriteExistingFiles } : {}),
179
- ...(publishAllLocales !== undefined ? { publishAllLocales } : {}),
180
- ...(locale ? { locale } : {}),
181
- ...(fallbackLocale ? { fallbackLocale } : {}),
182
- ...(select ? { select: select as SelectType } : {}),
183
129
  })
184
130
 
185
- const docs = result.docs || []
131
+ const docs = returning ? result.docs : result.docs.map(({ id }) => ({ id }))
186
132
  const errors = result.errors || []
187
133
 
188
- let responseText = `Multiple documents updated in collection "${collectionSlug}"!\nUpdated: ${docs.length} documents\nErrors: ${errors.length}\n---`
134
+ let responseText = `Multiple documents updated in collection "${slug}"!\nUpdated: ${docs.length} documents\nErrors: ${errors.length}\n---`
189
135
  if (docs.length > 0) {
190
136
  responseText += `\n\nUpdated documents:\n\`\`\`json\n${JSON.stringify(docs)}\n\`\`\``
191
137
  }
192
138
  if (errors.length > 0) {
193
139
  responseText += `\n\nErrors:\n\`\`\`json\n${JSON.stringify(errors)}\n\`\`\``
194
140
 
195
- const errorSchema = getCollectionInputSchema({ collectionSlug, req })
141
+ const errorSchema = getCollectionInputSchema({ collectionSlug: slug, req })
196
142
 
197
143
  if (errorSchema) {
198
144
  responseText += `\n\nUse this schema for data:\n\`\`\`json\n${JSON.stringify(errorSchema)}\n\`\`\``
@@ -205,7 +151,7 @@ export const updateDocumentTool = defineCollectionTool({
205
151
  ...(errorSchema
206
152
  ? {
207
153
  structuredContent: {
208
- collectionSlug,
154
+ slug,
209
155
  docs,
210
156
  errors,
211
157
  schema: errorSchema,
@@ -221,7 +167,7 @@ export const updateDocumentTool = defineCollectionTool({
221
167
  }
222
168
  } catch (error) {
223
169
  const errorMessage = error instanceof Error ? error.message : 'Unknown error'
224
- logger.error(`Error updating document in ${collectionSlug}: ${errorMessage}`)
225
- return formatCollectionError({ action: 'updating', collectionSlug, error, req })
170
+ logger.error(`Error updating document in ${slug}: ${errorMessage}`)
171
+ return formatEntityError({ slug, action: 'updating', entity: 'collection', error, req })
226
172
  }
227
173
  })
@@ -1,5 +1,5 @@
1
+ import { strictObject, z } from 'payload'
1
2
  import { getUploadInstructions as getPayloadUploadInstructions } from 'payload/internal'
2
- import { z } from 'zod'
3
3
 
4
4
  import { defaultAccess } from '../../../defaultAccess.js'
5
5
  import { defineCollectionTool } from '../../../defineTool.js'
@@ -8,8 +8,8 @@ export const getUploadInstructionsTool = defineCollectionTool({
8
8
  access: (args) =>
9
9
  defaultAccess(args) &&
10
10
  Boolean(
11
- args.permissions?.collections?.[args.collectionSlug]?.create ||
12
- args.permissions?.collections?.[args.collectionSlug]?.update,
11
+ args.permissions?.collections?.[args.slug]?.create ||
12
+ args.permissions?.collections?.[args.slug]?.update,
13
13
  ),
14
14
  annotations: {
15
15
  destructiveHint: false,
@@ -20,17 +20,17 @@ export const getUploadInstructionsTool = defineCollectionTool({
20
20
  },
21
21
  description:
22
22
  'Prepare uploads for createDocuments or updateDocument. This does not upload bytes; finish the returned action before use.',
23
- input: z.object({
24
- docPrefix: z.string().describe('Optional document folder or prefix').optional(),
25
- filename: z.string().describe('The original file name'),
26
- filesize: z.number().int().nonnegative().describe('The file size in bytes'),
27
- mimeType: z.string().describe('The file MIME type'),
23
+ input: strictObject({
24
+ docPrefix: z.optional(z.string()).check(z.describe('Document folder or prefix.')),
25
+ filename: z.string().check(z.describe('The original file name.')),
26
+ filesize: z.int().check(z.nonnegative(), z.describe('The file size in bytes.')),
27
+ mimeType: z.string().check(z.describe('The file MIME type.')),
28
28
  }),
29
- }).handler(async ({ authorizedMCP, collectionSlug, input, req }) => {
29
+ }).handler(async ({ slug, authorizedMCP, input, req }) => {
30
30
  try {
31
31
  const instructions = await getPayloadUploadInstructions({
32
32
  ...input,
33
- collectionSlug,
33
+ collectionSlug: slug,
34
34
  overrideAccess: authorizedMCP.overrideAccess,
35
35
  req,
36
36
  })
@@ -44,7 +44,7 @@ export const getUploadInstructionsTool = defineCollectionTool({
44
44
  content: [
45
45
  {
46
46
  type: 'text',
47
- text: `Upload instructions for collection "${collectionSlug}":\n\`\`\`json\n${JSON.stringify(instructions)}\n\`\`\`\n${nextStep}`,
47
+ text: `Upload instructions for collection "${slug}":\n\`\`\`json\n${JSON.stringify(instructions)}\n\`\`\`\n${nextStep}`,
48
48
  },
49
49
  ],
50
50
  structuredContent: { instructions },
@@ -55,7 +55,7 @@ export const getUploadInstructionsTool = defineCollectionTool({
55
55
  content: [
56
56
  {
57
57
  type: 'text',
58
- text: `Error getting upload instructions for collection "${collectionSlug}": ${message}`,
58
+ text: `Error getting upload instructions for collection "${slug}": ${message}`,
59
59
  },
60
60
  ],
61
61
  isError: true,
@@ -0,0 +1,77 @@
1
+ import type { CollectionSlug, GlobalSlug, PayloadRequest } from 'payload'
2
+
3
+ import { getCollectionInputSchema, getGlobalInputSchema, ValidationError } from 'payload'
4
+
5
+ import type { MCPToolResponse } from '../../types.js'
6
+
7
+ export const formatEntityError = ({
8
+ slug,
9
+ action,
10
+ entity,
11
+ error,
12
+ req,
13
+ }:
14
+ | {
15
+ action: 'creating' | 'duplicating' | 'updating'
16
+ entity: 'collection'
17
+ error: unknown
18
+ req: PayloadRequest
19
+ slug: CollectionSlug
20
+ }
21
+ | {
22
+ action: 'updating'
23
+ entity: 'global'
24
+ error: unknown
25
+ req: PayloadRequest
26
+ slug: GlobalSlug
27
+ }): MCPToolResponse => {
28
+ const message = error instanceof Error ? error.message : 'Unknown error'
29
+ const target = entity === 'collection' ? `document in collection "${slug}"` : `global "${slug}"`
30
+
31
+ if (!isValidationError(error, message)) {
32
+ return {
33
+ content: [{ type: 'text', text: `Error ${action} ${target}: ${message}` }],
34
+ isError: true,
35
+ }
36
+ }
37
+
38
+ const schema =
39
+ entity === 'collection'
40
+ ? getCollectionInputSchema({ collectionSlug: slug, req })
41
+ : getGlobalInputSchema({ globalSlug: slug, req })
42
+ const errors = error instanceof ValidationError ? error.data.errors : [{ message }]
43
+ const validationMessage = errors
44
+ .map((issue) => `${'path' in issue ? `${issue.path}: ` : ''}${issue.message}`)
45
+ .join('\n')
46
+ const schemaText = schema
47
+ ? `\n\nUse this schema for data:\n\`\`\`json\n${JSON.stringify(schema)}\n\`\`\``
48
+ : ''
49
+
50
+ return {
51
+ content: [
52
+ { type: 'text', text: `Error ${action} ${target}: ${validationMessage}${schemaText}` },
53
+ ],
54
+ isError: true,
55
+ ...(schema
56
+ ? {
57
+ structuredContent: {
58
+ slug,
59
+ errors,
60
+ schema,
61
+ },
62
+ }
63
+ : {}),
64
+ }
65
+ }
66
+
67
+ const isValidationError = (error: unknown, message: string): boolean => {
68
+ if (error instanceof ValidationError) {
69
+ return true
70
+ }
71
+
72
+ const name = error && typeof error === 'object' && 'name' in error ? error.name : undefined
73
+
74
+ return (
75
+ name === 'CastError' || message.includes('Cast to ') || message.includes('validation failed')
76
+ )
77
+ }
@@ -1,4 +1,4 @@
1
- import { getAccessResults, isEntityHidden } from 'payload'
1
+ import { getAccessResults, getConfigInfoInputSchema, isEntityHidden } from 'payload'
2
2
 
3
3
  import { defineTool } from '../../defineTool.js'
4
4
 
@@ -11,6 +11,7 @@ export const getConfigInfoTool = defineTool({
11
11
  title: 'Config Info',
12
12
  },
13
13
  description: 'List the Payload collection and global slugs visible to this MCP client.',
14
+ input: getConfigInfoInputSchema,
14
15
  }).handler(async ({ authorizedMCP, req }) => {
15
16
  const user = req.user
16
17
  const permissions = authorizedMCP.overrideAccess ? null : await getAccessResults({ req })
@@ -1,16 +1,15 @@
1
- import { z } from 'zod'
1
+ import { countGlobalVersionsInputSchema } from 'payload'
2
2
 
3
3
  import { defaultAccess } from '../../../defaultAccess.js'
4
4
  import { defineGlobalTool } from '../../../defineTool.js'
5
5
  import { getLogger } from '../../../utils/getLogger.js'
6
- import { whereSchema } from '../../../utils/whereSchema.js'
7
6
 
8
7
  const DEFAULT_DESCRIPTION =
9
8
  'Count global versions in any version-enabled global by passing the global slug and optional where clause.'
10
9
 
11
10
  export const countGlobalVersionsTool = defineGlobalTool({
12
11
  access: (args) =>
13
- defaultAccess(args) && Boolean(args.permissions?.globals?.[args.globalSlug]?.readVersions),
12
+ defaultAccess(args) && Boolean(args.permissions?.globals?.[args.slug]?.readVersions),
14
13
  annotations: {
15
14
  destructiveHint: false,
16
15
  idempotentHint: true,
@@ -19,24 +18,17 @@ export const countGlobalVersionsTool = defineGlobalTool({
19
18
  title: 'Count Global Versions',
20
19
  },
21
20
  description: DEFAULT_DESCRIPTION,
22
- input: z.object({
23
- locale: z.string().describe('Optional: locale code to count versions in').optional(),
24
- where: whereSchema
25
- .describe(
26
- 'Optional: where clause for filtering versions. Version document fields are usually under "version". Example: {"version.siteName":{"contains":"test"}}',
27
- )
28
- .optional(),
29
- }),
30
- }).handler(async ({ authorizedMCP, globalSlug, input, req }) => {
21
+ input: countGlobalVersionsInputSchema,
22
+ }).handler(async ({ slug, authorizedMCP, input, req }) => {
31
23
  const payload = req.payload
32
24
  const logger = getLogger({ payload })
33
25
  const { locale, where } = input
34
26
 
35
- logger.info(`Counting versions for global: ${globalSlug}`)
27
+ logger.info(`Counting versions for global: ${slug}`)
36
28
 
37
29
  try {
38
30
  const result = await payload.countGlobalVersions({
39
- global: globalSlug,
31
+ global: slug,
40
32
  overrideAccess: authorizedMCP.overrideAccess,
41
33
  req,
42
34
  ...(locale ? { locale } : {}),
@@ -47,19 +39,19 @@ export const countGlobalVersionsTool = defineGlobalTool({
47
39
  content: [
48
40
  {
49
41
  type: 'text',
50
- text: `Global "${globalSlug}" contains ${result.totalDocs} matching versions.\n\`\`\`json\n${JSON.stringify(result)}\n\`\`\``,
42
+ text: `Global "${slug}" contains ${result.totalDocs} matching versions.\n\`\`\`json\n${JSON.stringify(result)}\n\`\`\``,
51
43
  },
52
44
  ],
53
45
  doc: result,
54
46
  }
55
47
  } catch (error) {
56
48
  const errorMessage = error instanceof Error ? error.message : 'Unknown error'
57
- logger.error(`Error counting versions for global ${globalSlug}: ${errorMessage}`)
49
+ logger.error(`Error counting versions for global ${slug}: ${errorMessage}`)
58
50
  return {
59
51
  content: [
60
52
  {
61
53
  type: 'text',
62
- text: `❌ **Error counting versions for global "${globalSlug}":** ${errorMessage}`,
54
+ text: `❌ **Error counting versions for global "${slug}":** ${errorMessage}`,
63
55
  },
64
56
  ],
65
57
  isError: true,
@@ -1,6 +1,4 @@
1
- import type { PopulateType, SelectType } from 'payload'
2
-
3
- import { z } from 'zod'
1
+ import { findGlobalInputSchema } from 'payload'
4
2
 
5
3
  import { defaultAccess } from '../../../defaultAccess.js'
6
4
  import { defineGlobalTool } from '../../../defineTool.js'
@@ -9,8 +7,7 @@ import { getLogger } from '../../../utils/getLogger.js'
9
7
  const DEFAULT_DESCRIPTION = 'Find any Payload global by passing the global slug.'
10
8
 
11
9
  export const findGlobalTool = defineGlobalTool({
12
- access: (args) =>
13
- defaultAccess(args) && Boolean(args.permissions?.globals?.[args.globalSlug]?.read),
10
+ access: (args) => defaultAccess(args) && Boolean(args.permissions?.globals?.[args.slug]?.read),
14
11
  annotations: {
15
12
  destructiveHint: false,
16
13
  idempotentHint: true,
@@ -19,51 +16,18 @@ export const findGlobalTool = defineGlobalTool({
19
16
  title: 'Find Global',
20
17
  },
21
18
  description: DEFAULT_DESCRIPTION,
22
- input: z.object({
23
- depth: z
24
- .number()
25
- .int()
26
- .min(0)
27
- .max(10)
28
- .describe('Depth of population for relationships')
29
- .optional()
30
- .default(0),
31
- fallbackLocale: z
32
- .string()
33
- .describe('Optional: fallback locale code to use when requested locale is not available')
34
- .optional(),
35
- locale: z
36
- .string()
37
- .describe(
38
- 'Optional: locale code to retrieve data in (e.g., "en", "es"). Use "all" to retrieve all locales for localized fields',
39
- )
40
- .optional(),
41
- populate: z
42
- .record(z.string(), z.unknown())
43
- .describe(
44
- 'Optional: control which fields to include from populated relationship or upload documents.',
45
- )
46
- .optional(),
47
- select: z
48
- .record(z.string(), z.unknown())
49
- .describe(
50
- 'Optional: define exactly which fields you\'d like to return in the response, e.g., {"title": true}',
51
- )
52
- .optional(),
53
- }),
54
- }).handler(async ({ authorizedMCP, globalSlug, input, req }) => {
19
+ input: findGlobalInputSchema,
20
+ }).handler(async ({ slug, authorizedMCP, input, req }) => {
55
21
  const payload = req.payload
56
22
  const logger = getLogger({ payload })
57
23
 
58
24
  const { depth, fallbackLocale, locale, populate, select } = input
59
25
 
60
- logger.info(
61
- `Reading global: ${globalSlug}, depth: ${depth}${locale ? `, locale: ${locale}` : ''}`,
62
- )
26
+ logger.info(`Reading global: ${slug}, depth: ${depth}${locale ? `, locale: ${locale}` : ''}`)
63
27
 
64
28
  try {
65
29
  const findOptions: Parameters<typeof payload.findGlobal>[0] = {
66
- slug: globalSlug,
30
+ slug,
67
31
  depth,
68
32
  overrideAccess: authorizedMCP.overrideAccess,
69
33
  req,
@@ -72,34 +36,31 @@ export const findGlobalTool = defineGlobalTool({
72
36
  if (locale) {
73
37
  findOptions.locale = locale
74
38
  }
75
- if (fallbackLocale) {
39
+ if (fallbackLocale !== undefined) {
76
40
  findOptions.fallbackLocale = fallbackLocale
77
41
  }
78
42
  if (select) {
79
- findOptions.select = select as SelectType
43
+ findOptions.select = select
80
44
  }
81
45
  if (populate) {
82
- findOptions.populate = populate as PopulateType
46
+ findOptions.populate = populate
83
47
  }
84
-
85
48
  const result = await payload.findGlobal(findOptions)
86
49
 
87
50
  return {
88
51
  content: [
89
52
  {
90
53
  type: 'text',
91
- text: `Global "${globalSlug}":\n\`\`\`json\n${JSON.stringify(result)}\n\`\`\``,
54
+ text: `Global "${slug}":\n\`\`\`json\n${JSON.stringify(result)}\n\`\`\``,
92
55
  },
93
56
  ],
94
57
  doc: result as Record<string, unknown>,
95
58
  }
96
59
  } catch (error) {
97
60
  const errorMessage = error instanceof Error ? error.message : 'Unknown error'
98
- logger.error(`Error reading global ${globalSlug}: ${errorMessage}`)
61
+ logger.error(`Error reading global ${slug}: ${errorMessage}`)
99
62
  return {
100
- content: [
101
- { type: 'text', text: `❌ **Error reading global "${globalSlug}":** ${errorMessage}` },
102
- ],
63
+ content: [{ type: 'text', text: `❌ **Error reading global "${slug}":** ${errorMessage}` }],
103
64
  }
104
65
  }
105
66
  })