@payloadcms/plugin-mcp 4.0.0-internal.1f9ae9a → 4.0.0-internal.2fddfc0

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 (227) hide show
  1. package/dist/@types/assets.d.js +2 -0
  2. package/dist/@types/assets.d.js.map +1 -0
  3. package/dist/defaultAccess.d.ts +3 -0
  4. package/dist/defaultAccess.d.ts.map +1 -0
  5. package/dist/defaultAccess.js +3 -0
  6. package/dist/defaultAccess.js.map +1 -0
  7. package/dist/endpoint/access.d.ts +17 -5
  8. package/dist/endpoint/access.d.ts.map +1 -1
  9. package/dist/endpoint/access.js +82 -88
  10. package/dist/endpoint/access.js.map +1 -1
  11. package/dist/endpoint/index.d.ts.map +1 -1
  12. package/dist/endpoint/index.js +11 -0
  13. package/dist/endpoint/index.js.map +1 -1
  14. package/dist/exports/client.d.ts +1 -1
  15. package/dist/exports/client.d.ts.map +1 -1
  16. package/dist/exports/client.js +1 -1
  17. package/dist/exports/client.js.map +1 -1
  18. package/dist/exports/internal.d.ts +2 -0
  19. package/dist/exports/internal.d.ts.map +1 -0
  20. package/dist/exports/internal.js +3 -0
  21. package/dist/exports/internal.js.map +1 -0
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +13 -18
  24. package/dist/index.js.map +1 -1
  25. package/dist/mcp/buildMcpServer.d.ts.map +1 -1
  26. package/dist/mcp/buildMcpServer.js +102 -64
  27. package/dist/mcp/buildMcpServer.js.map +1 -1
  28. package/dist/mcp/builtin/collections/authTools.d.ts.map +1 -1
  29. package/dist/mcp/builtin/collections/authTools.js +44 -6
  30. package/dist/mcp/builtin/collections/authTools.js.map +1 -1
  31. package/dist/mcp/builtin/collections/countTool.d.ts +2 -0
  32. package/dist/mcp/builtin/collections/countTool.d.ts.map +1 -0
  33. package/dist/mcp/builtin/collections/countTool.js +69 -0
  34. package/dist/mcp/builtin/collections/countTool.js.map +1 -0
  35. package/dist/mcp/builtin/collections/countVersionsTool.d.ts +2 -0
  36. package/dist/mcp/builtin/collections/countVersionsTool.d.ts.map +1 -0
  37. package/dist/mcp/builtin/collections/countVersionsTool.js +65 -0
  38. package/dist/mcp/builtin/collections/countVersionsTool.js.map +1 -0
  39. package/dist/mcp/builtin/collections/createTool.d.ts +1 -1
  40. package/dist/mcp/builtin/collections/createTool.d.ts.map +1 -1
  41. package/dist/mcp/builtin/collections/createTool.js +38 -38
  42. package/dist/mcp/builtin/collections/createTool.js.map +1 -1
  43. package/dist/mcp/builtin/collections/deleteTool.d.ts +1 -1
  44. package/dist/mcp/builtin/collections/deleteTool.d.ts.map +1 -1
  45. package/dist/mcp/builtin/collections/deleteTool.js +14 -20
  46. package/dist/mcp/builtin/collections/deleteTool.js.map +1 -1
  47. package/dist/mcp/builtin/collections/duplicateTool.d.ts +2 -0
  48. package/dist/mcp/builtin/collections/duplicateTool.d.ts.map +1 -0
  49. package/dist/mcp/builtin/collections/duplicateTool.js +97 -0
  50. package/dist/mcp/builtin/collections/duplicateTool.js.map +1 -0
  51. package/dist/mcp/builtin/collections/findDistinctTool.d.ts +2 -0
  52. package/dist/mcp/builtin/collections/findDistinctTool.d.ts.map +1 -0
  53. package/dist/mcp/builtin/collections/findDistinctTool.js +93 -0
  54. package/dist/mcp/builtin/collections/findDistinctTool.js.map +1 -0
  55. package/dist/mcp/builtin/collections/findTool.d.ts +1 -1
  56. package/dist/mcp/builtin/collections/findTool.d.ts.map +1 -1
  57. package/dist/mcp/builtin/collections/findTool.js +49 -43
  58. package/dist/mcp/builtin/collections/findTool.js.map +1 -1
  59. package/dist/mcp/builtin/collections/findVersionByIDTool.d.ts +2 -0
  60. package/dist/mcp/builtin/collections/findVersionByIDTool.d.ts.map +1 -0
  61. package/dist/mcp/builtin/collections/findVersionByIDTool.js +84 -0
  62. package/dist/mcp/builtin/collections/findVersionByIDTool.js.map +1 -0
  63. package/dist/mcp/builtin/collections/findVersionsTool.d.ts +2 -0
  64. package/dist/mcp/builtin/collections/findVersionsTool.d.ts.map +1 -0
  65. package/dist/mcp/builtin/collections/findVersionsTool.js +99 -0
  66. package/dist/mcp/builtin/collections/findVersionsTool.js.map +1 -0
  67. package/dist/mcp/builtin/collections/formatCollectionError.d.ts +9 -0
  68. package/dist/mcp/builtin/collections/formatCollectionError.d.ts.map +1 -0
  69. package/dist/mcp/builtin/collections/formatCollectionError.js +60 -0
  70. package/dist/mcp/builtin/collections/formatCollectionError.js.map +1 -0
  71. package/dist/mcp/builtin/collections/getCollectionSchemaTool.d.ts +2 -0
  72. package/dist/mcp/builtin/collections/getCollectionSchemaTool.d.ts.map +1 -0
  73. package/dist/mcp/builtin/collections/getCollectionSchemaTool.js +47 -0
  74. package/dist/mcp/builtin/collections/getCollectionSchemaTool.js.map +1 -0
  75. package/dist/mcp/builtin/collections/restoreVersionTool.d.ts +2 -0
  76. package/dist/mcp/builtin/collections/restoreVersionTool.d.ts.map +1 -0
  77. package/dist/mcp/builtin/collections/restoreVersionTool.js +82 -0
  78. package/dist/mcp/builtin/collections/restoreVersionTool.js.map +1 -0
  79. package/dist/mcp/builtin/collections/updateTool.d.ts +1 -1
  80. package/dist/mcp/builtin/collections/updateTool.d.ts.map +1 -1
  81. package/dist/mcp/builtin/collections/updateTool.js +87 -82
  82. package/dist/mcp/builtin/collections/updateTool.js.map +1 -1
  83. package/dist/mcp/builtin/getConfigInfoTool.d.ts +2 -0
  84. package/dist/mcp/builtin/getConfigInfoTool.d.ts.map +1 -0
  85. package/dist/mcp/builtin/getConfigInfoTool.js +71 -0
  86. package/dist/mcp/builtin/getConfigInfoTool.js.map +1 -0
  87. package/dist/mcp/builtin/globals/countVersionsTool.d.ts +2 -0
  88. package/dist/mcp/builtin/globals/countVersionsTool.d.ts.map +1 -0
  89. package/dist/mcp/builtin/globals/countVersionsTool.js +65 -0
  90. package/dist/mcp/builtin/globals/countVersionsTool.js.map +1 -0
  91. package/dist/mcp/builtin/globals/findTool.d.ts.map +1 -1
  92. package/dist/mcp/builtin/globals/findTool.js +18 -21
  93. package/dist/mcp/builtin/globals/findTool.js.map +1 -1
  94. package/dist/mcp/builtin/globals/findVersionByIDTool.d.ts +2 -0
  95. package/dist/mcp/builtin/globals/findVersionByIDTool.d.ts.map +1 -0
  96. package/dist/mcp/builtin/globals/findVersionByIDTool.js +80 -0
  97. package/dist/mcp/builtin/globals/findVersionByIDTool.js.map +1 -0
  98. package/dist/mcp/builtin/globals/findVersionsTool.d.ts +2 -0
  99. package/dist/mcp/builtin/globals/findVersionsTool.d.ts.map +1 -0
  100. package/dist/mcp/builtin/globals/findVersionsTool.js +95 -0
  101. package/dist/mcp/builtin/globals/findVersionsTool.js.map +1 -0
  102. package/dist/mcp/builtin/globals/getGlobalSchemaTool.d.ts +2 -0
  103. package/dist/mcp/builtin/globals/getGlobalSchemaTool.d.ts.map +1 -0
  104. package/dist/mcp/builtin/globals/getGlobalSchemaTool.js +47 -0
  105. package/dist/mcp/builtin/globals/getGlobalSchemaTool.js.map +1 -0
  106. package/dist/mcp/builtin/globals/restoreVersionTool.d.ts +2 -0
  107. package/dist/mcp/builtin/globals/restoreVersionTool.d.ts.map +1 -0
  108. package/dist/mcp/builtin/globals/restoreVersionTool.js +78 -0
  109. package/dist/mcp/builtin/globals/restoreVersionTool.js.map +1 -0
  110. package/dist/mcp/builtin/globals/updateTool.d.ts.map +1 -1
  111. package/dist/mcp/builtin/globals/updateTool.js +31 -36
  112. package/dist/mcp/builtin/globals/updateTool.js.map +1 -1
  113. package/dist/mcp/builtin/validateEntityData.d.ts +14 -0
  114. package/dist/mcp/builtin/validateEntityData.d.ts.map +1 -0
  115. package/dist/mcp/builtin/validateEntityData.js +82 -0
  116. package/dist/mcp/builtin/validateEntityData.js.map +1 -0
  117. package/dist/mcp/builtinTools.d.ts +144 -19
  118. package/dist/mcp/builtinTools.d.ts.map +1 -1
  119. package/dist/mcp/builtinTools.js +119 -20
  120. package/dist/mcp/builtinTools.js.map +1 -1
  121. package/dist/mcp/sanitizeMCPConfig.d.ts +0 -1
  122. package/dist/mcp/sanitizeMCPConfig.d.ts.map +1 -1
  123. package/dist/mcp/sanitizeMCPConfig.js +120 -58
  124. package/dist/mcp/sanitizeMCPConfig.js.map +1 -1
  125. package/dist/stdio.d.ts +3 -2
  126. package/dist/stdio.d.ts.map +1 -1
  127. package/dist/stdio.js +27 -8
  128. package/dist/stdio.js.map +1 -1
  129. package/dist/types.d.ts +62 -108
  130. package/dist/types.d.ts.map +1 -1
  131. package/dist/types.js +4 -4
  132. package/dist/types.js.map +1 -1
  133. package/dist/utils/getPluginConfig.d.ts +1 -1
  134. package/dist/utils/getPluginConfig.js +1 -1
  135. package/dist/utils/getPluginConfig.js.map +1 -1
  136. package/dist/utils/schemaConversion/getEntityInputSchema.d.ts +11 -0
  137. package/dist/utils/schemaConversion/getEntityInputSchema.d.ts.map +1 -0
  138. package/dist/utils/schemaConversion/getEntityInputSchema.js +34 -0
  139. package/dist/utils/schemaConversion/getEntityInputSchema.js.map +1 -0
  140. package/dist/utils/schemaConversion/sanitizeEntitySchema.d.ts +15 -0
  141. package/dist/utils/schemaConversion/sanitizeEntitySchema.d.ts.map +1 -0
  142. package/dist/utils/schemaConversion/sanitizeEntitySchema.js +464 -0
  143. package/dist/utils/schemaConversion/sanitizeEntitySchema.js.map +1 -0
  144. package/dist/utils/schemaConversion/sanitizeEntitySchema.spec.js +158 -0
  145. package/dist/utils/schemaConversion/sanitizeEntitySchema.spec.js.map +1 -0
  146. package/dist/utils/whereSchema.d.ts +9 -0
  147. package/dist/utils/whereSchema.d.ts.map +1 -0
  148. package/dist/utils/whereSchema.js +13 -0
  149. package/dist/utils/whereSchema.js.map +1 -0
  150. package/package.json +8 -11
  151. package/src/@types/assets.d.ts +3 -0
  152. package/src/defaultAccess.ts +3 -0
  153. package/src/endpoint/access.ts +88 -101
  154. package/src/endpoint/index.ts +14 -1
  155. package/src/exports/client.ts +2 -1
  156. package/src/exports/internal.ts +1 -0
  157. package/src/index.ts +8 -16
  158. package/src/mcp/buildMcpServer.ts +130 -90
  159. package/src/mcp/builtin/collections/authTools.ts +45 -9
  160. package/src/mcp/builtin/collections/countTool.ts +74 -0
  161. package/src/mcp/builtin/collections/countVersionsTool.ts +70 -0
  162. package/src/mcp/builtin/collections/createTool.ts +55 -59
  163. package/src/mcp/builtin/collections/deleteTool.ts +19 -16
  164. package/src/mcp/builtin/collections/duplicateTool.ts +135 -0
  165. package/src/mcp/builtin/collections/findDistinctTool.ts +120 -0
  166. package/src/mcp/builtin/collections/findTool.ts +63 -33
  167. package/src/mcp/builtin/collections/findVersionByIDTool.ts +110 -0
  168. package/src/mcp/builtin/collections/findVersionsTool.ts +155 -0
  169. package/src/mcp/builtin/collections/formatCollectionError.ts +84 -0
  170. package/src/mcp/builtin/collections/getCollectionSchemaTool.ts +46 -0
  171. package/src/mcp/builtin/collections/restoreVersionTool.ts +108 -0
  172. package/src/mcp/builtin/collections/updateTool.ts +111 -105
  173. package/src/mcp/builtin/getConfigInfoTool.ts +69 -0
  174. package/src/mcp/builtin/globals/countVersionsTool.ts +69 -0
  175. package/src/mcp/builtin/globals/findTool.ts +26 -17
  176. package/src/mcp/builtin/globals/findVersionByIDTool.ts +104 -0
  177. package/src/mcp/builtin/globals/findVersionsTool.ts +148 -0
  178. package/src/mcp/builtin/globals/getGlobalSchemaTool.ts +41 -0
  179. package/src/mcp/builtin/globals/restoreVersionTool.ts +100 -0
  180. package/src/mcp/builtin/globals/updateTool.ts +50 -53
  181. package/src/mcp/builtin/validateEntityData.ts +132 -0
  182. package/src/mcp/builtinTools.ts +111 -41
  183. package/src/mcp/sanitizeMCPConfig.ts +116 -78
  184. package/src/stdio.ts +23 -8
  185. package/src/types.ts +77 -112
  186. package/src/utils/getPluginConfig.ts +1 -1
  187. package/src/utils/schemaConversion/getEntityInputSchema.ts +78 -0
  188. package/src/utils/schemaConversion/sanitizeEntitySchema.spec.ts +103 -0
  189. package/src/utils/schemaConversion/sanitizeEntitySchema.ts +529 -0
  190. package/src/utils/whereSchema.ts +24 -0
  191. package/dist/collection/getAccessField.d.ts +0 -12
  192. package/dist/collection/getAccessField.d.ts.map +0 -1
  193. package/dist/collection/getAccessField.js +0 -57
  194. package/dist/collection/getAccessField.js.map +0 -1
  195. package/dist/collection/index.d.ts +0 -6
  196. package/dist/collection/index.d.ts.map +0 -1
  197. package/dist/collection/index.js +0 -59
  198. package/dist/collection/index.js.map +0 -1
  199. package/dist/components/AccessField/index.client.d.ts +0 -10
  200. package/dist/components/AccessField/index.client.d.ts.map +0 -1
  201. package/dist/components/AccessField/index.client.js +0 -305
  202. package/dist/components/AccessField/index.client.js.map +0 -1
  203. package/dist/components/AccessField/index.css +0 -93
  204. package/dist/utils/schemaConversion/prepareCollectionSchema.d.ts +0 -7
  205. package/dist/utils/schemaConversion/prepareCollectionSchema.d.ts.map +0 -1
  206. package/dist/utils/schemaConversion/prepareCollectionSchema.js +0 -37
  207. package/dist/utils/schemaConversion/prepareCollectionSchema.js.map +0 -1
  208. package/dist/utils/schemaConversion/sanitizeJsonSchema.d.ts +0 -13
  209. package/dist/utils/schemaConversion/sanitizeJsonSchema.d.ts.map +0 -1
  210. package/dist/utils/schemaConversion/sanitizeJsonSchema.js +0 -56
  211. package/dist/utils/schemaConversion/sanitizeJsonSchema.js.map +0 -1
  212. package/dist/utils/schemaConversion/simplifyRelationshipFields.d.ts +0 -20
  213. package/dist/utils/schemaConversion/simplifyRelationshipFields.d.ts.map +0 -1
  214. package/dist/utils/schemaConversion/simplifyRelationshipFields.js +0 -56
  215. package/dist/utils/schemaConversion/simplifyRelationshipFields.js.map +0 -1
  216. package/dist/utils/schemaConversion/transformPointFields.d.ts +0 -3
  217. package/dist/utils/schemaConversion/transformPointFields.d.ts.map +0 -1
  218. package/dist/utils/schemaConversion/transformPointFields.js +0 -57
  219. package/dist/utils/schemaConversion/transformPointFields.js.map +0 -1
  220. package/src/collection/getAccessField.ts +0 -64
  221. package/src/collection/index.ts +0 -63
  222. package/src/components/AccessField/index.client.tsx +0 -344
  223. package/src/components/AccessField/index.css +0 -93
  224. package/src/utils/schemaConversion/prepareCollectionSchema.ts +0 -39
  225. package/src/utils/schemaConversion/sanitizeJsonSchema.ts +0 -62
  226. package/src/utils/schemaConversion/simplifyRelationshipFields.ts +0 -70
  227. package/src/utils/schemaConversion/transformPointFields.ts +0 -56
@@ -0,0 +1,155 @@
1
+ import type { PopulateType, SelectType } from 'payload'
2
+
3
+ import { z } from 'zod'
4
+
5
+ import { defaultAccess } from '../../../defaultAccess.js'
6
+ import { defineCollectionTool } from '../../../defineTool.js'
7
+ import { getLogger } from '../../../utils/getLogger.js'
8
+ import { localAPIDefaults } from '../../../utils/localAPIDefaults.js'
9
+ import { whereSchema } from '../../../utils/whereSchema.js'
10
+
11
+ const DEFAULT_DESCRIPTION =
12
+ 'Find document versions in any version-enabled collection by passing the collection slug and optional where clause.'
13
+
14
+ export const findVersionsTool = defineCollectionTool({
15
+ access: (args) =>
16
+ defaultAccess(args) &&
17
+ Boolean(args.permissions?.collections?.[args.collectionSlug]?.readVersions),
18
+ annotations: {
19
+ destructiveHint: false,
20
+ idempotentHint: true,
21
+ openWorldHint: false,
22
+ readOnlyHint: true,
23
+ title: 'Find Versions',
24
+ },
25
+ description: DEFAULT_DESCRIPTION,
26
+ input: z.object({
27
+ depth: z
28
+ .number()
29
+ .int()
30
+ .min(0)
31
+ .max(10)
32
+ .describe('How many levels deep to populate relationships in version documents')
33
+ .optional()
34
+ .default(0),
35
+ fallbackLocale: z
36
+ .string()
37
+ .describe('Optional: fallback locale code to use when requested locale is not available')
38
+ .optional(),
39
+ limit: z
40
+ .number()
41
+ .int()
42
+ .min(1)
43
+ .max(100)
44
+ .describe('Maximum number of versions to return (default: 10, max: 100)')
45
+ .optional()
46
+ .default(10),
47
+ locale: z
48
+ .string()
49
+ .describe(
50
+ 'Optional: locale code to retrieve data in (e.g., "en", "es"). Use "all" to retrieve all locales for localized fields',
51
+ )
52
+ .optional(),
53
+ page: z
54
+ .number()
55
+ .int()
56
+ .min(1)
57
+ .describe('Page number for pagination (default: 1)')
58
+ .optional()
59
+ .default(1),
60
+ pagination: z
61
+ .boolean()
62
+ .describe('Optional: set to false to skip the count query overhead')
63
+ .optional(),
64
+ populate: z
65
+ .record(z.string(), z.unknown())
66
+ .describe(
67
+ 'Optional: control which fields to include from populated relationship or upload documents.',
68
+ )
69
+ .optional(),
70
+ select: z
71
+ .record(z.string(), z.unknown())
72
+ .describe(
73
+ 'Optional: define exactly which fields you\'d like to return in the response, e.g., {"version.title": true}',
74
+ )
75
+ .optional(),
76
+ showHiddenFields: z
77
+ .boolean()
78
+ .describe('Optional: include hidden fields in returned version documents')
79
+ .optional(),
80
+ sort: z
81
+ .string()
82
+ .describe('Field to sort by (e.g., "-updatedAt", "-version.updatedAt" for descending)')
83
+ .optional(),
84
+ trash: z
85
+ .boolean()
86
+ .describe('Optional: include versions for soft-deleted documents when trash is enabled')
87
+ .optional(),
88
+ where: whereSchema
89
+ .describe(
90
+ 'Optional: where clause for filtering versions. Version document fields are usually under "version". Example: {"version.title":{"contains":"test"}}',
91
+ )
92
+ .optional(),
93
+ }),
94
+ }).handler(async ({ authorizedMCP, collectionSlug, input, req }) => {
95
+ const payload = req.payload
96
+ const logger = getLogger({ payload })
97
+ const {
98
+ depth,
99
+ fallbackLocale,
100
+ limit,
101
+ locale,
102
+ page,
103
+ pagination,
104
+ populate,
105
+ select,
106
+ showHiddenFields,
107
+ sort,
108
+ trash,
109
+ where,
110
+ } = input
111
+
112
+ logger.info(`Finding versions in collection: ${collectionSlug}, limit: ${limit}, page: ${page}`)
113
+
114
+ try {
115
+ const result = await payload.findVersions({
116
+ collection: collectionSlug,
117
+ depth,
118
+ limit,
119
+ page,
120
+ req,
121
+ ...localAPIDefaults(authorizedMCP),
122
+ ...(fallbackLocale ? { fallbackLocale } : {}),
123
+ ...(locale ? { locale } : {}),
124
+ ...(pagination !== undefined ? { pagination } : {}),
125
+ ...(populate ? { populate: populate as PopulateType } : {}),
126
+ ...(select ? { select: select as SelectType } : {}),
127
+ ...(showHiddenFields !== undefined ? { showHiddenFields } : {}),
128
+ ...(sort ? { sort } : {}),
129
+ ...(trash !== undefined ? { trash } : {}),
130
+ ...(where ? { where } : {}),
131
+ })
132
+
133
+ return {
134
+ content: [
135
+ {
136
+ type: 'text',
137
+ text: `Versions for collection "${collectionSlug}":\n\`\`\`json\n${JSON.stringify(result)}\n\`\`\``,
138
+ },
139
+ ],
140
+ doc: result as unknown as Record<string, unknown>,
141
+ }
142
+ } catch (error) {
143
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error'
144
+ logger.error(`Error finding versions in ${collectionSlug}: ${errorMessage}`)
145
+ return {
146
+ content: [
147
+ {
148
+ type: 'text',
149
+ text: `❌ **Error finding versions in collection "${collectionSlug}":** ${errorMessage}`,
150
+ },
151
+ ],
152
+ isError: true,
153
+ }
154
+ }
155
+ })
@@ -0,0 +1,84 @@
1
+ import type { CollectionSlug, PayloadRequest } from 'payload'
2
+
3
+ import type { MCPToolResponse } from '../../../types.js'
4
+
5
+ import { getCollectionInputSchema } from '../../../utils/schemaConversion/getEntityInputSchema.js'
6
+
7
+ const getValidationErrors = (error: unknown): undefined | unknown[] => {
8
+ if (!error || typeof error !== 'object') {
9
+ return undefined
10
+ }
11
+
12
+ const data = 'data' in error ? error.data : undefined
13
+ if (!data || typeof data !== 'object' || !('errors' in data) || !Array.isArray(data.errors)) {
14
+ return undefined
15
+ }
16
+
17
+ return data.errors
18
+ }
19
+
20
+ const isSchemaError = (error: unknown, message: string): boolean => {
21
+ if (getValidationErrors(error)) {
22
+ return true
23
+ }
24
+
25
+ const name = error && typeof error === 'object' && 'name' in error ? error.name : undefined
26
+
27
+ return (
28
+ name === 'CastError' ||
29
+ name === 'ValidationError' ||
30
+ message.includes('Cast to ') ||
31
+ message.includes('validation failed')
32
+ )
33
+ }
34
+
35
+ export const formatCollectionError = ({
36
+ action,
37
+ collectionSlug,
38
+ error,
39
+ req,
40
+ }: {
41
+ action: 'creating' | 'duplicating' | 'updating'
42
+ collectionSlug: CollectionSlug
43
+ error: unknown
44
+ req: PayloadRequest
45
+ }): MCPToolResponse => {
46
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error'
47
+ const errors = getValidationErrors(error) ?? [{ message: errorMessage }]
48
+
49
+ if (!isSchemaError(error, errorMessage)) {
50
+ return {
51
+ content: [
52
+ {
53
+ type: 'text',
54
+ text: `Error ${action} document in collection "${collectionSlug}": ${errorMessage}`,
55
+ },
56
+ ],
57
+ isError: true,
58
+ }
59
+ }
60
+
61
+ const schema = getCollectionInputSchema({ collectionSlug, req })
62
+ const schemaText = schema
63
+ ? `\n\nUse this schema for data:\n\`\`\`json\n${JSON.stringify(schema)}\n\`\`\``
64
+ : ''
65
+
66
+ return {
67
+ content: [
68
+ {
69
+ type: 'text',
70
+ text: `Error ${action} document in collection "${collectionSlug}": ${errorMessage}${schemaText}`,
71
+ },
72
+ ],
73
+ isError: true,
74
+ ...(schema
75
+ ? {
76
+ structuredContent: {
77
+ collectionSlug,
78
+ errors,
79
+ schema,
80
+ },
81
+ }
82
+ : {}),
83
+ }
84
+ }
@@ -0,0 +1,46 @@
1
+ import { defaultAccess } from '../../../defaultAccess.js'
2
+ import { defineCollectionTool } from '../../../defineTool.js'
3
+ import { getCollectionInputSchema } from '../../../utils/schemaConversion/getEntityInputSchema.js'
4
+
5
+ export const getCollectionSchemaTool = defineCollectionTool({
6
+ access: (args) => {
7
+ const permissions = args.permissions?.collections?.[args.collectionSlug]
8
+
9
+ return (
10
+ defaultAccess(args) &&
11
+ Boolean(
12
+ permissions?.create || permissions?.delete || permissions?.read || permissions?.update,
13
+ )
14
+ )
15
+ },
16
+ annotations: {
17
+ destructiveHint: false,
18
+ idempotentHint: true,
19
+ openWorldHint: false,
20
+ readOnlyHint: true,
21
+ title: 'Get Collection Schema',
22
+ },
23
+ description: 'Get the input schema for creating or updating documents in a collection.',
24
+ }).handler(({ collectionSlug, req }) => {
25
+ const inputSchema = getCollectionInputSchema({ collectionSlug, req })
26
+
27
+ if (!inputSchema) {
28
+ return {
29
+ content: [{ type: 'text', text: `Error: Collection "${collectionSlug}" not found` }],
30
+ isError: true,
31
+ }
32
+ }
33
+
34
+ return {
35
+ content: [
36
+ {
37
+ type: 'text',
38
+ text: `Schema for collection "${collectionSlug}":\n\`\`\`json\n${JSON.stringify(inputSchema)}\n\`\`\``,
39
+ },
40
+ ],
41
+ structuredContent: {
42
+ collectionSlug,
43
+ schema: inputSchema,
44
+ },
45
+ }
46
+ })
@@ -0,0 +1,108 @@
1
+ import type { PopulateType, SelectType } from 'payload'
2
+
3
+ import { z } from 'zod'
4
+
5
+ import { defaultAccess } from '../../../defaultAccess.js'
6
+ import { defineCollectionTool } from '../../../defineTool.js'
7
+ import { getLogger } from '../../../utils/getLogger.js'
8
+ import { localAPIDefaults } from '../../../utils/localAPIDefaults.js'
9
+
10
+ const DEFAULT_DESCRIPTION =
11
+ 'Restore a document from a previous version in any version-enabled collection.'
12
+
13
+ export const restoreVersionTool = defineCollectionTool({
14
+ access: (args) =>
15
+ defaultAccess(args) && Boolean(args.permissions?.collections?.[args.collectionSlug]?.update),
16
+ annotations: {
17
+ destructiveHint: true,
18
+ idempotentHint: false,
19
+ openWorldHint: false,
20
+ readOnlyHint: false,
21
+ title: 'Restore Version',
22
+ },
23
+ description: DEFAULT_DESCRIPTION,
24
+ input: z.object({
25
+ id: z.string().describe('The ID of the version to restore'),
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
+ draft: z
35
+ .boolean()
36
+ .describe('Whether to restore the version as a draft')
37
+ .optional()
38
+ .default(false),
39
+ fallbackLocale: z
40
+ .string()
41
+ .describe('Optional: fallback locale code to use when requested locale is not available')
42
+ .optional(),
43
+ locale: z
44
+ .string()
45
+ .describe('Optional: locale code to restore in (e.g., "en", "es")')
46
+ .optional(),
47
+ populate: z
48
+ .record(z.string(), z.unknown())
49
+ .describe(
50
+ 'Optional: control which fields to include from populated relationship or upload documents.',
51
+ )
52
+ .optional(),
53
+ select: z
54
+ .record(z.string(), z.unknown())
55
+ .describe(
56
+ 'Optional: define exactly which fields you\'d like to return in the response, e.g., {"title": true}',
57
+ )
58
+ .optional(),
59
+ showHiddenFields: z
60
+ .boolean()
61
+ .describe('Optional: include hidden fields in the restored document response')
62
+ .optional(),
63
+ }),
64
+ }).handler(async ({ authorizedMCP, collectionSlug, input, req }) => {
65
+ const payload = req.payload
66
+ const logger = getLogger({ payload })
67
+ const { id, depth, draft, fallbackLocale, locale, populate, select, showHiddenFields } = input
68
+
69
+ logger.info(`Restoring version in collection: ${collectionSlug} with ID: ${id}`)
70
+
71
+ try {
72
+ const result = await payload.restoreVersion({
73
+ id,
74
+ collection: collectionSlug,
75
+ depth,
76
+ draft,
77
+ req,
78
+ ...localAPIDefaults(authorizedMCP),
79
+ ...(fallbackLocale ? { fallbackLocale } : {}),
80
+ ...(locale ? { locale } : {}),
81
+ ...(populate ? { populate: populate as PopulateType } : {}),
82
+ ...(select ? { select: select as SelectType } : {}),
83
+ ...(showHiddenFields !== undefined ? { showHiddenFields } : {}),
84
+ })
85
+
86
+ return {
87
+ content: [
88
+ {
89
+ type: 'text',
90
+ text: `Version "${id}" restored successfully in collection "${collectionSlug}"!\nRestored document:\n\`\`\`json\n${JSON.stringify(result)}\n\`\`\``,
91
+ },
92
+ ],
93
+ doc: result as Record<string, unknown>,
94
+ }
95
+ } catch (error) {
96
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error'
97
+ logger.error(`Error restoring version ${id} in ${collectionSlug}: ${errorMessage}`)
98
+ return {
99
+ content: [
100
+ {
101
+ type: 'text',
102
+ text: `❌ **Error restoring version "${id}" in collection "${collectionSlug}":** ${errorMessage}`,
103
+ },
104
+ ],
105
+ isError: true,
106
+ }
107
+ }
108
+ })
@@ -1,7 +1,8 @@
1
- import type { SelectType } from 'payload'
1
+ import type { SelectType, Where } from 'payload'
2
2
 
3
3
  import { z } from 'zod'
4
4
 
5
+ import { defaultAccess } from '../../../defaultAccess.js'
5
6
  import { defineCollectionTool } from '../../../defineTool.js'
6
7
  import { getLogger } from '../../../utils/getLogger.js'
7
8
  import {
@@ -9,70 +10,72 @@ import {
9
10
  stripVirtualFields,
10
11
  } from '../../../utils/getVirtualFieldNames.js'
11
12
  import { localAPIDefaults } from '../../../utils/localAPIDefaults.js'
12
- import { prepareCollectionSchema } from '../../../utils/schemaConversion/prepareCollectionSchema.js'
13
+ import { getCollectionInputSchema } from '../../../utils/schemaConversion/getEntityInputSchema.js'
13
14
  import { transformPointDataToPayload } from '../../../utils/transformPointDataToPayload.js'
14
-
15
- const DEFAULT_DESCRIPTION = 'Update documents in a collection by ID or where clause.'
16
-
17
- export const updateCollectionTool = defineCollectionTool({
18
- description: DEFAULT_DESCRIPTION,
19
- input: ({ collectionSchema }) => {
20
- const partialSchema = prepareCollectionSchema(collectionSchema)
21
-
22
- // Collection updates do not require all required fields to be passed => delete .required.
23
- //
24
- // Local API equivalent: packages/payload/src/collections/operations/local/update.ts#BaseOptions#data:
25
- // data: DeepPartial<RequiredDataFromCollectionSlug<TSlug>>
26
- delete partialSchema.required
27
-
28
- return z.object({
29
- id: z.union([z.string(), z.number()]).describe('The ID of the document to update').optional(),
30
- data: z
31
- .fromJSONSchema(partialSchema as unknown as z.core.JSONSchema.JSONSchema)
32
- .describe('The fields to update'),
33
- depth: z
34
- .number()
35
- .describe('How many levels deep to populate relationships')
36
- .optional()
37
- .default(0),
38
- draft: z
39
- .boolean()
40
- .describe('Whether to update the document as a draft')
41
- .optional()
42
- .default(false),
43
- fallbackLocale: z
44
- .string()
45
- .describe('Optional: fallback locale code to use when requested locale is not available')
46
- .optional(),
47
- filePath: z.string().describe('File path for file uploads').optional(),
48
- locale: z
49
- .string()
50
- .describe(
51
- 'Optional: locale code to update the document in (e.g., "en", "es"). Defaults to the default locale',
52
- )
53
- .optional(),
54
- overrideLock: z
55
- .boolean()
56
- .describe('Whether to override document locks')
57
- .optional()
58
- .default(true),
59
- overwriteExistingFiles: z
60
- .boolean()
61
- .describe('Whether to overwrite existing files')
62
- .optional()
63
- .default(false),
64
- select: z
65
- .string()
66
- .describe(
67
- 'Optional: define exactly which fields you\'d like to return in the response (JSON), e.g., \'{"title": "My Post"}\'',
68
- )
69
- .optional(),
70
- where: z
71
- .string()
72
- .describe('JSON string for where clause to update multiple documents')
73
- .optional(),
74
- })
15
+ import { whereSchema } from '../../../utils/whereSchema.js'
16
+ import { validateCollectionData } from '../validateEntityData.js'
17
+ import { formatCollectionError } from './formatCollectionError.js'
18
+
19
+ const DEFAULT_DESCRIPTION =
20
+ 'Update documents in any collection by passing the collection slug and data.'
21
+
22
+ export const updateDocumentTool = defineCollectionTool({
23
+ access: (args) =>
24
+ defaultAccess(args) && Boolean(args.permissions?.collections?.[args.collectionSlug]?.update),
25
+ annotations: {
26
+ destructiveHint: true,
27
+ idempotentHint: false,
28
+ openWorldHint: false,
29
+ readOnlyHint: false,
30
+ title: 'Update Document',
75
31
  },
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.record(z.string(), z.unknown()).describe('The fields to update'),
36
+ depth: z
37
+ .number()
38
+ .describe('How many levels deep to populate relationships')
39
+ .optional()
40
+ .default(0),
41
+ draft: z
42
+ .boolean()
43
+ .describe('Whether to update the document as a draft')
44
+ .optional()
45
+ .default(false),
46
+ fallbackLocale: z
47
+ .string()
48
+ .describe('Optional: fallback locale code to use when requested locale is not available')
49
+ .optional(),
50
+ filePath: z.string().describe('File path for file uploads').optional(),
51
+ locale: z
52
+ .string()
53
+ .describe(
54
+ 'Optional: locale code to update the document in (e.g., "en", "es"). Defaults to the default locale',
55
+ )
56
+ .optional(),
57
+ overrideLock: z
58
+ .boolean()
59
+ .describe('Whether to override document locks')
60
+ .optional()
61
+ .default(true),
62
+ overwriteExistingFiles: z
63
+ .boolean()
64
+ .describe('Whether to overwrite existing files')
65
+ .optional()
66
+ .default(false),
67
+ select: z
68
+ .record(z.string(), z.unknown())
69
+ .describe(
70
+ 'Optional: define exactly which fields you\'d like to return in the response, e.g., {"title": true}',
71
+ )
72
+ .optional(),
73
+ where: whereSchema
74
+ .describe(
75
+ 'Where clause to update multiple documents. Use field names with Payload operators, and/or arrays for grouping. Example: {"title":{"contains":"test"}}',
76
+ )
77
+ .optional(),
78
+ }),
76
79
  }).handler(async ({ authorizedMCP, collectionSlug, input, req }) => {
77
80
  const payload = req.payload
78
81
  const logger = getLogger({ payload })
@@ -102,32 +105,25 @@ export const updateCollectionTool = defineCollectionTool({
102
105
  }
103
106
  }
104
107
 
105
- let parsedData = transformPointDataToPayload(data as Record<string, unknown>)
106
108
  const virtualFieldNames = getCollectionVirtualFieldNames(payload.config, collectionSlug)
107
- parsedData = stripVirtualFields(parsedData, virtualFieldNames)
108
-
109
- let whereClause: Record<string, unknown> = {}
110
- if (where) {
111
- try {
112
- whereClause = JSON.parse(where) as Record<string, unknown>
113
- } catch {
114
- logger.error(`Invalid where clause JSON: ${where}`)
115
- return { content: [{ type: 'text', text: 'Error: Invalid JSON in where clause' }] }
116
- }
117
- }
109
+ const inputData = stripVirtualFields(data, virtualFieldNames)
110
+ const validationError = validateCollectionData({
111
+ collectionSlug,
112
+ data: inputData,
113
+ partial: true,
114
+ req,
115
+ })
118
116
 
119
- let selectClause: SelectType | undefined
120
- if (select) {
121
- try {
122
- selectClause = JSON.parse(select) as SelectType
123
- } catch {
124
- logger.warn(`Invalid select clause JSON: ${select}`)
125
- return { content: [{ type: 'text', text: 'Error: Invalid JSON in select clause' }] }
126
- }
117
+ if (validationError) {
118
+ return validationError
127
119
  }
128
120
 
121
+ const parsedData = transformPointDataToPayload(inputData)
122
+
123
+ const whereClause: Where = where ?? {}
124
+
129
125
  if (id) {
130
- const updateOptions = {
126
+ const result = await payload.update({
131
127
  id,
132
128
  collection: collectionSlug,
133
129
  data: parsedData,
@@ -140,10 +136,8 @@ export const updateCollectionTool = defineCollectionTool({
140
136
  ...(overwriteExistingFiles ? { overwriteExistingFiles } : {}),
141
137
  ...(locale ? { locale } : {}),
142
138
  ...(fallbackLocale ? { fallbackLocale } : {}),
143
- ...(selectClause ? { select: selectClause } : {}),
144
- }
145
-
146
- const result = await payload.update(updateOptions as any)
139
+ ...(select ? { select: select as SelectType } : {}),
140
+ })
147
141
 
148
142
  return {
149
143
  content: [
@@ -156,27 +150,24 @@ export const updateCollectionTool = defineCollectionTool({
156
150
  }
157
151
  }
158
152
 
159
- const updateOptions = {
153
+ const result = await payload.update({
160
154
  collection: collectionSlug,
161
155
  data: parsedData,
162
156
  depth,
163
157
  draft,
164
158
  overrideLock,
165
159
  req,
166
- ...localAPIDefaults(authorizedMCP),
167
160
  where: whereClause,
161
+ ...localAPIDefaults(authorizedMCP),
168
162
  ...(filePath ? { filePath } : {}),
169
163
  ...(overwriteExistingFiles ? { overwriteExistingFiles } : {}),
170
164
  ...(locale ? { locale } : {}),
171
165
  ...(fallbackLocale ? { fallbackLocale } : {}),
172
- ...(selectClause ? { select: selectClause } : {}),
173
- }
174
-
175
- const result = await payload.update(updateOptions as any)
166
+ ...(select ? { select: select as SelectType } : {}),
167
+ })
176
168
 
177
- const bulkResult = result as { docs?: unknown[]; errors?: unknown[] }
178
- const docs = bulkResult.docs || []
179
- const errors = bulkResult.errors || []
169
+ const docs = result.docs || []
170
+ const errors = result.errors || []
180
171
 
181
172
  let responseText = `Multiple documents updated in collection "${collectionSlug}"!\nUpdated: ${docs.length} documents\nErrors: ${errors.length}\n---`
182
173
  if (docs.length > 0) {
@@ -184,6 +175,28 @@ export const updateCollectionTool = defineCollectionTool({
184
175
  }
185
176
  if (errors.length > 0) {
186
177
  responseText += `\n\nErrors:\n\`\`\`json\n${JSON.stringify(errors)}\n\`\`\``
178
+
179
+ const errorSchema = getCollectionInputSchema({ collectionSlug, req })
180
+
181
+ if (errorSchema) {
182
+ responseText += `\n\nUse this schema for data:\n\`\`\`json\n${JSON.stringify(errorSchema)}\n\`\`\``
183
+ }
184
+
185
+ return {
186
+ content: [{ type: 'text', text: responseText }],
187
+ doc: { docs, errors } as unknown as Record<string, unknown>,
188
+ isError: true,
189
+ ...(errorSchema
190
+ ? {
191
+ structuredContent: {
192
+ collectionSlug,
193
+ docs,
194
+ errors,
195
+ schema: errorSchema,
196
+ },
197
+ }
198
+ : {}),
199
+ }
187
200
  }
188
201
 
189
202
  return {
@@ -193,13 +206,6 @@ export const updateCollectionTool = defineCollectionTool({
193
206
  } catch (error) {
194
207
  const errorMessage = error instanceof Error ? error.message : 'Unknown error'
195
208
  logger.error(`Error updating document in ${collectionSlug}: ${errorMessage}`)
196
- return {
197
- content: [
198
- {
199
- type: 'text',
200
- text: `Error updating document in collection "${collectionSlug}": ${errorMessage}`,
201
- },
202
- ],
203
- }
209
+ return formatCollectionError({ action: 'updating', collectionSlug, error, req })
204
210
  }
205
211
  })