@payloadcms/plugin-mcp 4.0.0-canary.2 → 4.0.0-internal.011fd46

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 (209) hide show
  1. package/dist/components/APIKeyField/index.client.d.ts.map +1 -1
  2. package/dist/components/APIKeyField/index.client.js.map +1 -1
  3. package/dist/components/APIKeysEmptyState/index.client.d.ts.map +1 -1
  4. package/dist/components/APIKeysEmptyState/index.client.js.map +1 -1
  5. package/dist/components/AccessField/index.client.d.ts.map +1 -1
  6. package/dist/components/AccessField/index.client.js.map +1 -1
  7. package/dist/components/SettingsMenu/index.client.d.ts.map +1 -1
  8. package/dist/components/SettingsMenu/index.client.js +8 -13
  9. package/dist/components/SettingsMenu/index.client.js.map +1 -1
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +6 -1
  12. package/dist/index.js.map +1 -1
  13. package/dist/mcp/buildMcpServer.d.ts.map +1 -1
  14. package/dist/mcp/buildMcpServer.js +2 -0
  15. package/dist/mcp/buildMcpServer.js.map +1 -1
  16. package/dist/mcp/builtin/collections/authTools.d.ts.map +1 -1
  17. package/dist/mcp/builtin/collections/authTools.js +44 -6
  18. package/dist/mcp/builtin/collections/authTools.js.map +1 -1
  19. package/dist/mcp/builtin/collections/createTool.d.ts.map +1 -1
  20. package/dist/mcp/builtin/collections/createTool.js +10 -19
  21. package/dist/mcp/builtin/collections/createTool.js.map +1 -1
  22. package/dist/mcp/builtin/collections/deleteTool.d.ts.map +1 -1
  23. package/dist/mcp/builtin/collections/deleteTool.js +7 -0
  24. package/dist/mcp/builtin/collections/deleteTool.js.map +1 -1
  25. package/dist/mcp/builtin/collections/findTool.d.ts.map +1 -1
  26. package/dist/mcp/builtin/collections/findTool.js +41 -22
  27. package/dist/mcp/builtin/collections/findTool.js.map +1 -1
  28. package/dist/mcp/builtin/collections/getCollectionSchemaTool.d.ts.map +1 -1
  29. package/dist/mcp/builtin/collections/getCollectionSchemaTool.js +7 -0
  30. package/dist/mcp/builtin/collections/getCollectionSchemaTool.js.map +1 -1
  31. package/dist/mcp/builtin/collections/updateTool.d.ts.map +1 -1
  32. package/dist/mcp/builtin/collections/updateTool.js +12 -21
  33. package/dist/mcp/builtin/collections/updateTool.js.map +1 -1
  34. package/dist/mcp/builtin/getConfigInfoTool.d.ts.map +1 -1
  35. package/dist/mcp/builtin/getConfigInfoTool.js +7 -0
  36. package/dist/mcp/builtin/getConfigInfoTool.js.map +1 -1
  37. package/dist/mcp/builtin/globals/findTool.d.ts.map +1 -1
  38. package/dist/mcp/builtin/globals/findTool.js +15 -20
  39. package/dist/mcp/builtin/globals/findTool.js.map +1 -1
  40. package/dist/mcp/builtin/globals/getGlobalSchemaTool.d.ts.map +1 -1
  41. package/dist/mcp/builtin/globals/getGlobalSchemaTool.js +7 -0
  42. package/dist/mcp/builtin/globals/getGlobalSchemaTool.js.map +1 -1
  43. package/dist/mcp/builtin/globals/updateTool.d.ts.map +1 -1
  44. package/dist/mcp/builtin/globals/updateTool.js +10 -19
  45. package/dist/mcp/builtin/globals/updateTool.js.map +1 -1
  46. package/dist/mcp/builtinTools.d.ts +2 -10
  47. package/dist/mcp/builtinTools.d.ts.map +1 -1
  48. package/dist/mcp/builtinTools.js +2 -10
  49. package/dist/mcp/builtinTools.js.map +1 -1
  50. package/dist/mcp/sanitizeMCPConfig.js +24 -10
  51. package/dist/mcp/sanitizeMCPConfig.js.map +1 -1
  52. package/dist/translations/index.d.ts.map +1 -1
  53. package/dist/translations/index.js.map +1 -1
  54. package/dist/translations/languages/ar.d.ts.map +1 -1
  55. package/dist/translations/languages/ar.js.map +1 -1
  56. package/dist/translations/languages/az.d.ts.map +1 -1
  57. package/dist/translations/languages/az.js.map +1 -1
  58. package/dist/translations/languages/bg.d.ts.map +1 -1
  59. package/dist/translations/languages/bg.js.map +1 -1
  60. package/dist/translations/languages/bnBd.d.ts.map +1 -1
  61. package/dist/translations/languages/bnBd.js.map +1 -1
  62. package/dist/translations/languages/bnIn.d.ts.map +1 -1
  63. package/dist/translations/languages/bnIn.js.map +1 -1
  64. package/dist/translations/languages/ca.d.ts.map +1 -1
  65. package/dist/translations/languages/ca.js.map +1 -1
  66. package/dist/translations/languages/cs.d.ts.map +1 -1
  67. package/dist/translations/languages/cs.js.map +1 -1
  68. package/dist/translations/languages/da.d.ts.map +1 -1
  69. package/dist/translations/languages/da.js.map +1 -1
  70. package/dist/translations/languages/de.d.ts.map +1 -1
  71. package/dist/translations/languages/de.js.map +1 -1
  72. package/dist/translations/languages/en.d.ts.map +1 -1
  73. package/dist/translations/languages/en.js.map +1 -1
  74. package/dist/translations/languages/es.d.ts.map +1 -1
  75. package/dist/translations/languages/es.js.map +1 -1
  76. package/dist/translations/languages/et.d.ts.map +1 -1
  77. package/dist/translations/languages/et.js.map +1 -1
  78. package/dist/translations/languages/fa.d.ts.map +1 -1
  79. package/dist/translations/languages/fa.js.map +1 -1
  80. package/dist/translations/languages/fr.d.ts.map +1 -1
  81. package/dist/translations/languages/fr.js.map +1 -1
  82. package/dist/translations/languages/he.d.ts.map +1 -1
  83. package/dist/translations/languages/he.js.map +1 -1
  84. package/dist/translations/languages/hr.d.ts.map +1 -1
  85. package/dist/translations/languages/hr.js.map +1 -1
  86. package/dist/translations/languages/hu.d.ts.map +1 -1
  87. package/dist/translations/languages/hu.js.map +1 -1
  88. package/dist/translations/languages/hy.d.ts.map +1 -1
  89. package/dist/translations/languages/hy.js.map +1 -1
  90. package/dist/translations/languages/id.d.ts.map +1 -1
  91. package/dist/translations/languages/id.js.map +1 -1
  92. package/dist/translations/languages/is.d.ts.map +1 -1
  93. package/dist/translations/languages/is.js.map +1 -1
  94. package/dist/translations/languages/it.d.ts.map +1 -1
  95. package/dist/translations/languages/it.js.map +1 -1
  96. package/dist/translations/languages/ja.d.ts.map +1 -1
  97. package/dist/translations/languages/ja.js.map +1 -1
  98. package/dist/translations/languages/ko.d.ts.map +1 -1
  99. package/dist/translations/languages/ko.js.map +1 -1
  100. package/dist/translations/languages/lt.d.ts.map +1 -1
  101. package/dist/translations/languages/lt.js.map +1 -1
  102. package/dist/translations/languages/lv.d.ts.map +1 -1
  103. package/dist/translations/languages/lv.js.map +1 -1
  104. package/dist/translations/languages/my.d.ts.map +1 -1
  105. package/dist/translations/languages/my.js.map +1 -1
  106. package/dist/translations/languages/nb.d.ts.map +1 -1
  107. package/dist/translations/languages/nb.js.map +1 -1
  108. package/dist/translations/languages/nl.d.ts.map +1 -1
  109. package/dist/translations/languages/nl.js.map +1 -1
  110. package/dist/translations/languages/pl.d.ts.map +1 -1
  111. package/dist/translations/languages/pl.js.map +1 -1
  112. package/dist/translations/languages/pt.d.ts.map +1 -1
  113. package/dist/translations/languages/pt.js.map +1 -1
  114. package/dist/translations/languages/ro.d.ts.map +1 -1
  115. package/dist/translations/languages/ro.js.map +1 -1
  116. package/dist/translations/languages/rs.d.ts.map +1 -1
  117. package/dist/translations/languages/rs.js.map +1 -1
  118. package/dist/translations/languages/rsLatin.d.ts.map +1 -1
  119. package/dist/translations/languages/rsLatin.js.map +1 -1
  120. package/dist/translations/languages/ru.d.ts.map +1 -1
  121. package/dist/translations/languages/ru.js.map +1 -1
  122. package/dist/translations/languages/sk.d.ts.map +1 -1
  123. package/dist/translations/languages/sk.js.map +1 -1
  124. package/dist/translations/languages/sl.d.ts.map +1 -1
  125. package/dist/translations/languages/sl.js.map +1 -1
  126. package/dist/translations/languages/sv.d.ts.map +1 -1
  127. package/dist/translations/languages/sv.js.map +1 -1
  128. package/dist/translations/languages/ta.d.ts.map +1 -1
  129. package/dist/translations/languages/ta.js.map +1 -1
  130. package/dist/translations/languages/th.d.ts.map +1 -1
  131. package/dist/translations/languages/th.js.map +1 -1
  132. package/dist/translations/languages/tr.d.ts.map +1 -1
  133. package/dist/translations/languages/tr.js.map +1 -1
  134. package/dist/translations/languages/uk.d.ts.map +1 -1
  135. package/dist/translations/languages/uk.js.map +1 -1
  136. package/dist/translations/languages/vi.d.ts.map +1 -1
  137. package/dist/translations/languages/vi.js.map +1 -1
  138. package/dist/translations/languages/zh.d.ts.map +1 -1
  139. package/dist/translations/languages/zh.js.map +1 -1
  140. package/dist/translations/languages/zhTw.d.ts.map +1 -1
  141. package/dist/translations/languages/zhTw.js.map +1 -1
  142. package/dist/types.d.ts +7 -5
  143. package/dist/types.d.ts.map +1 -1
  144. package/dist/types.js.map +1 -1
  145. package/package.json +7 -7
  146. package/src/components/APIKeyField/index.client.tsx +2 -7
  147. package/src/components/APIKeysEmptyState/index.client.tsx +1 -4
  148. package/src/components/AccessField/index.client.tsx +1 -4
  149. package/src/components/SettingsMenu/index.client.tsx +1 -5
  150. package/src/index.ts +4 -1
  151. package/src/mcp/buildMcpServer.ts +2 -0
  152. package/src/mcp/builtin/collections/authTools.ts +45 -9
  153. package/src/mcp/builtin/collections/createTool.ts +10 -13
  154. package/src/mcp/builtin/collections/deleteTool.ts +7 -0
  155. package/src/mcp/builtin/collections/findTool.ts +53 -16
  156. package/src/mcp/builtin/collections/getCollectionSchemaTool.ts +7 -0
  157. package/src/mcp/builtin/collections/updateTool.ts +11 -14
  158. package/src/mcp/builtin/getConfigInfoTool.ts +7 -0
  159. package/src/mcp/builtin/globals/findTool.ts +22 -16
  160. package/src/mcp/builtin/globals/getGlobalSchemaTool.ts +7 -0
  161. package/src/mcp/builtin/globals/updateTool.ts +11 -14
  162. package/src/mcp/builtinTools.ts +9 -12
  163. package/src/mcp/sanitizeMCPConfig.ts +15 -11
  164. package/src/translations/index.ts +1 -4
  165. package/src/translations/languages/ar.ts +6 -3
  166. package/src/translations/languages/az.ts +6 -3
  167. package/src/translations/languages/bg.ts +8 -4
  168. package/src/translations/languages/bnBd.ts +8 -4
  169. package/src/translations/languages/bnIn.ts +8 -4
  170. package/src/translations/languages/ca.ts +8 -4
  171. package/src/translations/languages/cs.ts +8 -4
  172. package/src/translations/languages/da.ts +6 -3
  173. package/src/translations/languages/de.ts +8 -4
  174. package/src/translations/languages/en.ts +8 -4
  175. package/src/translations/languages/es.ts +8 -4
  176. package/src/translations/languages/et.ts +6 -3
  177. package/src/translations/languages/fa.ts +8 -4
  178. package/src/translations/languages/fr.ts +8 -4
  179. package/src/translations/languages/he.ts +4 -2
  180. package/src/translations/languages/hr.ts +8 -4
  181. package/src/translations/languages/hu.ts +8 -4
  182. package/src/translations/languages/hy.ts +8 -4
  183. package/src/translations/languages/id.ts +8 -4
  184. package/src/translations/languages/is.ts +8 -4
  185. package/src/translations/languages/it.ts +8 -4
  186. package/src/translations/languages/ja.ts +8 -4
  187. package/src/translations/languages/ko.ts +8 -4
  188. package/src/translations/languages/lt.ts +8 -4
  189. package/src/translations/languages/lv.ts +6 -3
  190. package/src/translations/languages/my.ts +8 -4
  191. package/src/translations/languages/nb.ts +8 -4
  192. package/src/translations/languages/nl.ts +8 -4
  193. package/src/translations/languages/pl.ts +6 -3
  194. package/src/translations/languages/pt.ts +8 -4
  195. package/src/translations/languages/ro.ts +8 -4
  196. package/src/translations/languages/rs.ts +6 -3
  197. package/src/translations/languages/rsLatin.ts +6 -3
  198. package/src/translations/languages/ru.ts +8 -4
  199. package/src/translations/languages/sk.ts +8 -4
  200. package/src/translations/languages/sl.ts +6 -3
  201. package/src/translations/languages/sv.ts +8 -4
  202. package/src/translations/languages/ta.ts +8 -4
  203. package/src/translations/languages/th.ts +6 -3
  204. package/src/translations/languages/tr.ts +6 -3
  205. package/src/translations/languages/uk.ts +8 -4
  206. package/src/translations/languages/vi.ts +8 -4
  207. package/src/translations/languages/zh.ts +2 -1
  208. package/src/translations/languages/zhTw.ts +2 -1
  209. package/src/types.ts +7 -4
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@payloadcms/plugin-mcp",
3
- "version": "4.0.0-canary.2",
3
+ "version": "4.0.0-internal.011fd46",
4
4
  "description": "MCP (Model Context Protocol) capabilities with Payload",
5
5
  "keywords": [
6
6
  "plugin",
@@ -57,19 +57,19 @@
57
57
  "@modelcontextprotocol/server": "2.0.0-alpha.2",
58
58
  "tsx": "4.22.4",
59
59
  "zod": "^4.0.0",
60
- "@payloadcms/translations": "4.0.0-canary.2"
60
+ "@payloadcms/translations": "4.0.0-internal.011fd46"
61
61
  },
62
62
  "devDependencies": {
63
63
  "@types/react": "19.2.14",
64
64
  "react": "^19.0.1 || ^19.1.2 || ^19.2.1",
65
- "@payloadcms/eslint-config": "3.28.0",
66
- "payload": "4.0.0-canary.2",
67
- "@payloadcms/ui": "4.0.0-canary.2"
65
+ "@payloadcms/ui": "4.0.0-internal.011fd46",
66
+ "payload": "4.0.0-internal.011fd46",
67
+ "@payloadcms/eslint-config": "3.28.0"
68
68
  },
69
69
  "peerDependencies": {
70
70
  "react": "^19.0.1 || ^19.1.2 || ^19.2.1",
71
- "@payloadcms/ui": "4.0.0-canary.2",
72
- "payload": "4.0.0-canary.2"
71
+ "@payloadcms/ui": "4.0.0-internal.011fd46",
72
+ "payload": "4.0.0-internal.011fd46"
73
73
  },
74
74
  "//deps_notes": {
75
75
  "zod": "zod is a hard dependency of @modelcontextprotocol/server, thus we can safely use it without it impacting bundle size. Make extra sure the zod version here matches exactly what's defined in the dependencies of @modelcontextprotocol/server to avoid duplicate versions being installed.",
@@ -3,10 +3,7 @@
3
3
  import { APIKeyInput, Button, useField, useTranslation, WarningTriangleIcon } from '@payloadcms/ui'
4
4
  import React, { useState } from 'react'
5
5
 
6
- import type {
7
- PluginMCPTranslationKeys,
8
- PluginMCPTranslations,
9
- } from '../../translations/index.js'
6
+ import type { PluginMCPTranslationKeys, PluginMCPTranslations } from '../../translations/index.js'
10
7
 
11
8
  import './index.css'
12
9
 
@@ -29,9 +26,7 @@ export const APIKeyField: React.FC = () => {
29
26
 
30
27
  return (
31
28
  <div className={baseClass}>
32
- <p className={`${baseClass}__description`}>
33
- {t('plugin-mcp:apiKeyDescription')}
34
- </p>
29
+ <p className={`${baseClass}__description`}>{t('plugin-mcp:apiKeyDescription')}</p>
35
30
  <div className={`${baseClass}__panel`}>
36
31
  <div className={`${baseClass}__header`}>
37
32
  <span className={`${baseClass}__title`}>{t('authentication:apiKey')}</span>
@@ -5,10 +5,7 @@ import type { NoResultsClientProps } from 'payload'
5
5
  import { Button, NoListResults, useTranslation } from '@payloadcms/ui'
6
6
  import React from 'react'
7
7
 
8
- import type {
9
- PluginMCPTranslationKeys,
10
- PluginMCPTranslations,
11
- } from '../../translations/index.js'
8
+ import type { PluginMCPTranslationKeys, PluginMCPTranslations } from '../../translations/index.js'
12
9
 
13
10
  export const APIKeysEmptyState: React.FC<NoResultsClientProps> = ({
14
11
  hasCreatePermission,
@@ -5,10 +5,7 @@ import type { JSONFieldClientProps } from 'payload'
5
5
  import { CheckboxInput, Collapsible, Tabs, useField, useTranslation } from '@payloadcms/ui'
6
6
  import React, { useState } from 'react'
7
7
 
8
- import type {
9
- PluginMCPTranslationKeys,
10
- PluginMCPTranslations,
11
- } from '../../translations/index.js'
8
+ import type { PluginMCPTranslationKeys, PluginMCPTranslations } from '../../translations/index.js'
12
9
  import type { ClientMCPPluginConfig, MCPAPIKeysDocAccessTree } from '../../types.js'
13
10
 
14
11
  import './index.css'
@@ -4,10 +4,7 @@ import { PopupList, useConfig, useTranslation } from '@payloadcms/ui'
4
4
  import { formatAdminURL } from 'payload/shared'
5
5
  import React from 'react'
6
6
 
7
- import type {
8
- PluginMCPTranslationKeys,
9
- PluginMCPTranslations,
10
- } from '../../translations/index.js'
7
+ import type { PluginMCPTranslationKeys, PluginMCPTranslations } from '../../translations/index.js'
11
8
 
12
9
  /**
13
10
  * Entry in the user menu's Settings sub-popup linking to the API keys
@@ -20,7 +17,6 @@ export const MCPSettingsMenu: React.FC = () => {
20
17
 
21
18
  return (
22
19
  <PopupList.MenuItem>
23
- <PopupList.GroupLabel label={t('plugin-mcp:mcp')} />
24
20
  <PopupList.Button
25
21
  href={formatAdminURL({
26
22
  adminRoute: config.routes.admin,
package/src/index.ts CHANGED
@@ -88,7 +88,10 @@ export const mcpPlugin = definePlugin<MCPPluginConfig>({
88
88
  ...config.admin?.components,
89
89
  userMenuSettingsItems: [
90
90
  ...(config.admin?.components?.userMenuSettingsItems ?? []),
91
- '@payloadcms/plugin-mcp/client#MCPSettingsMenu',
91
+ {
92
+ group: 'MCP',
93
+ items: ['@payloadcms/plugin-mcp/client#MCPSettingsMenu'],
94
+ },
92
95
  ],
93
96
  },
94
97
  },
@@ -137,6 +137,7 @@ export const buildMcpServer = ({
137
137
  server.registerTool(
138
138
  item.mcpName,
139
139
  {
140
+ annotations: item.tool.annotations,
140
141
  description: item.tool.description,
141
142
  inputSchema: toStandardSchema(inputSchema),
142
143
  },
@@ -193,6 +194,7 @@ export const buildMcpServer = ({
193
194
  server.registerTool(
194
195
  item.mcpName,
195
196
  {
197
+ annotations: tool.annotations,
196
198
  description: tool.description,
197
199
  inputSchema: tool.input ? toStandardSchema(tool.input) : undefined,
198
200
  },
@@ -32,13 +32,18 @@ const wrapError =
32
32
  }
33
33
 
34
34
  export const authCollectionTool = defineCollectionTool({
35
+ annotations: {
36
+ destructiveHint: false,
37
+ idempotentHint: true,
38
+ openWorldHint: false,
39
+ readOnlyHint: true,
40
+ title: 'Check Auth Status',
41
+ },
35
42
  description: 'Checks authentication status for the current user.',
36
43
  input: z.object({
37
44
  headers: z
38
- .string()
39
- .describe(
40
- 'Optional JSON string containing custom headers to send with the authentication request',
41
- )
45
+ .record(z.string(), z.string())
46
+ .describe('Optional custom headers to send with the authentication request')
42
47
  .optional(),
43
48
  }),
44
49
  }).handler(async ({ collectionSlug, input, req }) => {
@@ -46,11 +51,7 @@ export const authCollectionTool = defineCollectionTool({
46
51
  try {
47
52
  let authHeaders = new Headers()
48
53
  if (input.headers) {
49
- try {
50
- authHeaders = new Headers(JSON.parse(input.headers) as Record<string, string>)
51
- } catch {
52
- logger.warn(`Invalid headers JSON for auth: ${input.headers}, using empty headers`)
53
- }
54
+ authHeaders = new Headers(input.headers)
54
55
  }
55
56
  const result = await req.payload.auth({ headers: authHeaders })
56
57
  return {
@@ -70,6 +71,13 @@ export const authCollectionTool = defineCollectionTool({
70
71
  })
71
72
 
72
73
  export const forgotPasswordCollectionTool = defineCollectionTool({
74
+ annotations: {
75
+ destructiveHint: false,
76
+ idempotentHint: false,
77
+ openWorldHint: true,
78
+ readOnlyHint: false,
79
+ title: 'Forgot Password',
80
+ },
73
81
  description: 'Sends a password reset email to a user.',
74
82
  input: z.object({
75
83
  disableEmail: z
@@ -104,6 +112,13 @@ export const forgotPasswordCollectionTool = defineCollectionTool({
104
112
  })
105
113
 
106
114
  export const loginCollectionTool = defineCollectionTool({
115
+ annotations: {
116
+ destructiveHint: false,
117
+ idempotentHint: false,
118
+ openWorldHint: false,
119
+ readOnlyHint: false,
120
+ title: 'User Login',
121
+ },
107
122
  description: 'Authenticates a user with email and password.',
108
123
  input: z.object({
109
124
  depth: z
@@ -148,6 +163,13 @@ export const loginCollectionTool = defineCollectionTool({
148
163
  })
149
164
 
150
165
  export const resetPasswordCollectionTool = defineCollectionTool({
166
+ annotations: {
167
+ destructiveHint: false,
168
+ idempotentHint: false,
169
+ openWorldHint: false,
170
+ readOnlyHint: false,
171
+ title: 'Reset Password',
172
+ },
151
173
  description: 'Resets a user password with a reset token.',
152
174
  input: z.object({
153
175
  password: z.string().describe('The new password for the user'),
@@ -178,6 +200,13 @@ export const resetPasswordCollectionTool = defineCollectionTool({
178
200
  })
179
201
 
180
202
  export const unlockCollectionTool = defineCollectionTool({
203
+ annotations: {
204
+ destructiveHint: false,
205
+ idempotentHint: true,
206
+ openWorldHint: false,
207
+ readOnlyHint: false,
208
+ title: 'Unlock Account',
209
+ },
181
210
  description: 'Unlocks a user account that has been locked due to failed login attempts.',
182
211
  input: z.object({ email: emailSchema }),
183
212
  }).handler(async ({ collectionSlug, input, req }) => {
@@ -205,6 +234,13 @@ export const unlockCollectionTool = defineCollectionTool({
205
234
  })
206
235
 
207
236
  export const verifyCollectionTool = defineCollectionTool({
237
+ annotations: {
238
+ destructiveHint: false,
239
+ idempotentHint: false,
240
+ openWorldHint: false,
241
+ readOnlyHint: false,
242
+ title: 'Email Verification',
243
+ },
208
244
  description: 'Verifies a user email with a verification token.',
209
245
  input: z.object({
210
246
  token: z.string().describe('The verification token sent to the user email'),
@@ -17,6 +17,13 @@ const DEFAULT_DESCRIPTION =
17
17
  'Create a document in any collection by passing the collection slug and data.'
18
18
 
19
19
  export const createDocumentTool = defineCollectionTool({
20
+ annotations: {
21
+ destructiveHint: false,
22
+ idempotentHint: false,
23
+ openWorldHint: false,
24
+ readOnlyHint: false,
25
+ title: 'Create Document',
26
+ },
20
27
  description: DEFAULT_DESCRIPTION,
21
28
  input: z.object({
22
29
  data: z.record(z.string(), z.unknown()).describe('The document fields to create'),
@@ -44,9 +51,9 @@ export const createDocumentTool = defineCollectionTool({
44
51
  )
45
52
  .optional(),
46
53
  select: z
47
- .string()
54
+ .record(z.string(), z.unknown())
48
55
  .describe(
49
- "Optional: define exactly which fields you'd like to return (JSON), e.g., '{\"title\": true}'",
56
+ 'Optional: define exactly which fields you\'d like to return, e.g., {"title": true}',
50
57
  )
51
58
  .optional(),
52
59
  }),
@@ -71,16 +78,6 @@ export const createDocumentTool = defineCollectionTool({
71
78
 
72
79
  const parsedData = transformPointDataToPayload(inputData)
73
80
 
74
- let selectClause: SelectType | undefined
75
- if (select) {
76
- try {
77
- selectClause = JSON.parse(select) as SelectType
78
- } catch {
79
- logger.warn(`Invalid select clause JSON: ${select}`)
80
- return { content: [{ type: 'text', text: 'Error: Invalid JSON in select clause' }] }
81
- }
82
- }
83
-
84
81
  const result = await payload.create({
85
82
  collection: collectionSlug,
86
83
  data: parsedData,
@@ -90,7 +87,7 @@ export const createDocumentTool = defineCollectionTool({
90
87
  ...localAPIDefaults(authorizedMCP),
91
88
  ...(locale ? { locale } : {}),
92
89
  ...(fallbackLocale ? { fallbackLocale } : {}),
93
- ...(selectClause ? { select: selectClause } : {}),
90
+ ...(select ? { select: select as SelectType } : {}),
94
91
  })
95
92
 
96
93
  logger.info(`Successfully created document in ${collectionSlug} with ID: ${result.id}`)
@@ -9,6 +9,13 @@ const DEFAULT_DESCRIPTION =
9
9
  'Delete documents in any collection by passing the collection slug and ID or where clause.'
10
10
 
11
11
  export const deleteDocumentsTool = defineCollectionTool({
12
+ annotations: {
13
+ destructiveHint: true,
14
+ idempotentHint: false,
15
+ openWorldHint: false,
16
+ readOnlyHint: false,
17
+ title: 'Delete Documents',
18
+ },
12
19
  description: DEFAULT_DESCRIPTION,
13
20
  input: z.object({
14
21
  id: z
@@ -1,4 +1,4 @@
1
- import type { SelectType } from 'payload'
1
+ import type { JoinQuery, PopulateType, SelectType } from 'payload'
2
2
 
3
3
  import { z } from 'zod'
4
4
 
@@ -11,6 +11,13 @@ const DEFAULT_DESCRIPTION =
11
11
  'Find documents in any collection by passing the collection slug and optional ID or where clause.'
12
12
 
13
13
  export const findDocumentsTool = defineCollectionTool({
14
+ annotations: {
15
+ destructiveHint: false,
16
+ idempotentHint: true,
17
+ openWorldHint: false,
18
+ readOnlyHint: true,
19
+ title: 'Find Documents',
20
+ },
14
21
  description: DEFAULT_DESCRIPTION,
15
22
  input: z.object({
16
23
  id: z
@@ -37,6 +44,10 @@ export const findDocumentsTool = defineCollectionTool({
37
44
  .string()
38
45
  .describe('Optional: fallback locale code to use when requested locale is not available')
39
46
  .optional(),
47
+ joins: z
48
+ .union([z.record(z.string(), z.unknown()), z.literal(false)])
49
+ .describe('Optional: configure join field queries, or pass false to disable all join fields.')
50
+ .optional(),
40
51
  limit: z
41
52
  .number()
42
53
  .int()
@@ -58,16 +69,30 @@ export const findDocumentsTool = defineCollectionTool({
58
69
  .describe('Page number for pagination (default: 1)')
59
70
  .optional()
60
71
  .default(1),
72
+ pagination: z
73
+ .boolean()
74
+ .describe('Optional: set to false to skip the count query overhead')
75
+ .optional(),
76
+ populate: z
77
+ .record(z.string(), z.unknown())
78
+ .describe(
79
+ 'Optional: control which fields to include from populated relationship or upload documents.',
80
+ )
81
+ .optional(),
61
82
  select: z
62
- .string()
83
+ .record(z.string(), z.unknown())
63
84
  .describe(
64
- "Optional: define exactly which fields you'd like to return in the response (JSON), e.g., '{\"title\": true}'",
85
+ 'Optional: define exactly which fields you\'d like to return in the response, e.g., {"title": true}',
65
86
  )
66
87
  .optional(),
67
88
  sort: z
68
89
  .string()
69
90
  .describe('Field to sort by (e.g., "createdAt", "-updatedAt" for descending)')
70
91
  .optional(),
92
+ trash: z
93
+ .boolean()
94
+ .describe('Optional: include soft-deleted documents when trash is enabled on the collection')
95
+ .optional(),
71
96
  where: whereSchema
72
97
  .describe(
73
98
  'Optional: where clause for filtering. Use field names with Payload operators, and/or arrays for grouping. Example: {"title":{"contains":"test"}}',
@@ -78,23 +103,28 @@ export const findDocumentsTool = defineCollectionTool({
78
103
  const payload = req.payload
79
104
  const logger = getLogger({ payload })
80
105
 
81
- const { id, depth, draft, fallbackLocale, limit, locale, page, select, sort, where } = input
106
+ const {
107
+ id,
108
+ depth,
109
+ draft,
110
+ fallbackLocale,
111
+ joins,
112
+ limit,
113
+ locale,
114
+ page,
115
+ pagination,
116
+ populate,
117
+ select,
118
+ sort,
119
+ trash,
120
+ where,
121
+ } = input
82
122
 
83
123
  logger.info(
84
124
  `Reading document from collection: ${collectionSlug}${id ? ` with ID: ${id}` : ''}, limit: ${limit}, page: ${page}${locale ? `, locale: ${locale}` : ''}`,
85
125
  )
86
126
 
87
127
  try {
88
- let selectClause: SelectType | undefined
89
- if (select) {
90
- try {
91
- selectClause = JSON.parse(select) as SelectType
92
- } catch {
93
- logger.warn(`Invalid select clause JSON: ${select}`)
94
- return { content: [{ type: 'text', text: 'Error: Invalid JSON in select clause' }] }
95
- }
96
- }
97
-
98
128
  if (id) {
99
129
  try {
100
130
  const doc = await payload.findByID({
@@ -103,10 +133,13 @@ export const findDocumentsTool = defineCollectionTool({
103
133
  depth,
104
134
  req,
105
135
  ...localAPIDefaults(authorizedMCP),
106
- ...(selectClause && { select: selectClause }),
136
+ ...(select && { select: select as SelectType }),
137
+ ...(populate && { populate: populate as PopulateType }),
138
+ ...(joins !== undefined && { joins: joins as JoinQuery }),
107
139
  ...(locale && { locale }),
108
140
  ...(fallbackLocale && { fallbackLocale }),
109
141
  ...(draft !== undefined && { draft }),
142
+ ...(trash !== undefined && { trash }),
110
143
  })
111
144
 
112
145
  return {
@@ -138,10 +171,14 @@ export const findDocumentsTool = defineCollectionTool({
138
171
  page,
139
172
  req,
140
173
  ...localAPIDefaults(authorizedMCP),
141
- ...(selectClause && { select: selectClause }),
174
+ ...(select && { select: select as SelectType }),
175
+ ...(populate && { populate: populate as PopulateType }),
176
+ ...(joins !== undefined && { joins: joins as JoinQuery }),
142
177
  ...(locale && { locale }),
143
178
  ...(fallbackLocale && { fallbackLocale }),
144
179
  ...(draft !== undefined && { draft }),
180
+ ...(pagination !== undefined && { pagination }),
181
+ ...(trash !== undefined && { trash }),
145
182
  }
146
183
 
147
184
  if (sort) {
@@ -2,6 +2,13 @@ import { defineCollectionTool } from '../../../defineTool.js'
2
2
  import { getCollectionInputSchema } from '../../../utils/schemaConversion/getEntityInputSchema.js'
3
3
 
4
4
  export const getCollectionSchemaTool = defineCollectionTool({
5
+ annotations: {
6
+ destructiveHint: false,
7
+ idempotentHint: true,
8
+ openWorldHint: false,
9
+ readOnlyHint: true,
10
+ title: 'Get Collection Schema',
11
+ },
5
12
  description: 'Get the input schema for creating or updating documents in a collection.',
6
13
  }).handler(({ collectionSlug, req }) => {
7
14
  const inputSchema = getCollectionInputSchema({ collectionSlug, req })
@@ -19,6 +19,13 @@ const DEFAULT_DESCRIPTION =
19
19
  'Update documents in any collection by passing the collection slug and data.'
20
20
 
21
21
  export const updateDocumentTool = defineCollectionTool({
22
+ annotations: {
23
+ destructiveHint: true,
24
+ idempotentHint: false,
25
+ openWorldHint: false,
26
+ readOnlyHint: false,
27
+ title: 'Update Document',
28
+ },
22
29
  description: DEFAULT_DESCRIPTION,
23
30
  input: z.object({
24
31
  id: z.union([z.string(), z.number()]).describe('The ID of the document to update').optional(),
@@ -55,9 +62,9 @@ export const updateDocumentTool = defineCollectionTool({
55
62
  .optional()
56
63
  .default(false),
57
64
  select: z
58
- .string()
65
+ .record(z.string(), z.unknown())
59
66
  .describe(
60
- "Optional: define exactly which fields you'd like to return in the response (JSON), e.g., '{\"title\": true}'",
67
+ 'Optional: define exactly which fields you\'d like to return in the response, e.g., {"title": true}',
61
68
  )
62
69
  .optional(),
63
70
  where: whereSchema
@@ -112,16 +119,6 @@ export const updateDocumentTool = defineCollectionTool({
112
119
 
113
120
  const whereClause: Where = where ?? {}
114
121
 
115
- let selectClause: SelectType | undefined
116
- if (select) {
117
- try {
118
- selectClause = JSON.parse(select) as SelectType
119
- } catch {
120
- logger.warn(`Invalid select clause JSON: ${select}`)
121
- return { content: [{ type: 'text', text: 'Error: Invalid JSON in select clause' }] }
122
- }
123
- }
124
-
125
122
  if (id) {
126
123
  const result = await payload.update({
127
124
  id,
@@ -136,7 +133,7 @@ export const updateDocumentTool = defineCollectionTool({
136
133
  ...(overwriteExistingFiles ? { overwriteExistingFiles } : {}),
137
134
  ...(locale ? { locale } : {}),
138
135
  ...(fallbackLocale ? { fallbackLocale } : {}),
139
- ...(selectClause ? { select: selectClause } : {}),
136
+ ...(select ? { select: select as SelectType } : {}),
140
137
  })
141
138
 
142
139
  return {
@@ -163,7 +160,7 @@ export const updateDocumentTool = defineCollectionTool({
163
160
  ...(overwriteExistingFiles ? { overwriteExistingFiles } : {}),
164
161
  ...(locale ? { locale } : {}),
165
162
  ...(fallbackLocale ? { fallbackLocale } : {}),
166
- ...(selectClause ? { select: selectClause } : {}),
163
+ ...(select ? { select: select as SelectType } : {}),
167
164
  })
168
165
 
169
166
  const docs = result.docs || []
@@ -3,6 +3,13 @@ import { getAccessResults, isEntityHidden } from 'payload'
3
3
  import { defineTool } from '../../defineTool.js'
4
4
 
5
5
  export const getConfigInfoTool = defineTool({
6
+ annotations: {
7
+ destructiveHint: false,
8
+ idempotentHint: true,
9
+ openWorldHint: false,
10
+ readOnlyHint: true,
11
+ title: 'Config Info',
12
+ },
6
13
  description: 'List the Payload collection and global slugs visible to this MCP client.',
7
14
  }).handler(async ({ authorizedMCP, req }) => {
8
15
  const user = authorizedMCP.user ?? req.user ?? null
@@ -1,4 +1,4 @@
1
- import type { SelectType } from 'payload'
1
+ import type { PopulateType, SelectType } from 'payload'
2
2
 
3
3
  import { z } from 'zod'
4
4
 
@@ -9,6 +9,13 @@ import { localAPIDefaults } from '../../../utils/localAPIDefaults.js'
9
9
  const DEFAULT_DESCRIPTION = 'Find any Payload global by passing the global slug.'
10
10
 
11
11
  export const findGlobalTool = defineGlobalTool({
12
+ annotations: {
13
+ destructiveHint: false,
14
+ idempotentHint: true,
15
+ openWorldHint: false,
16
+ readOnlyHint: true,
17
+ title: 'Find Global',
18
+ },
12
19
  description: DEFAULT_DESCRIPTION,
13
20
  input: z.object({
14
21
  depth: z
@@ -29,10 +36,16 @@ export const findGlobalTool = defineGlobalTool({
29
36
  'Optional: locale code to retrieve data in (e.g., "en", "es"). Use "all" to retrieve all locales for localized fields',
30
37
  )
31
38
  .optional(),
39
+ populate: z
40
+ .record(z.string(), z.unknown())
41
+ .describe(
42
+ 'Optional: control which fields to include from populated relationship or upload documents.',
43
+ )
44
+ .optional(),
32
45
  select: z
33
- .string()
46
+ .record(z.string(), z.unknown())
34
47
  .describe(
35
- "Optional: define exactly which fields you'd like to return in the response (JSON), e.g., '{\"title\": true}'",
48
+ 'Optional: define exactly which fields you\'d like to return in the response, e.g., {"title": true}',
36
49
  )
37
50
  .optional(),
38
51
  }),
@@ -40,7 +53,7 @@ export const findGlobalTool = defineGlobalTool({
40
53
  const payload = req.payload
41
54
  const logger = getLogger({ payload })
42
55
 
43
- const { depth, fallbackLocale, locale, select } = input
56
+ const { depth, fallbackLocale, locale, populate, select } = input
44
57
 
45
58
  logger.info(
46
59
  `Reading global: ${globalSlug}, depth: ${depth}${locale ? `, locale: ${locale}` : ''}`,
@@ -53,24 +66,17 @@ export const findGlobalTool = defineGlobalTool({
53
66
  ...localAPIDefaults(authorizedMCP),
54
67
  }
55
68
 
56
- let selectClause: SelectType | undefined
57
- if (select) {
58
- try {
59
- selectClause = JSON.parse(select) as SelectType
60
- } catch {
61
- logger.warn(`Invalid select clause JSON for global: ${select}`)
62
- return { content: [{ type: 'text', text: 'Error: Invalid JSON in select clause' }] }
63
- }
64
- }
65
-
66
69
  if (locale) {
67
70
  findOptions.locale = locale
68
71
  }
69
72
  if (fallbackLocale) {
70
73
  findOptions.fallbackLocale = fallbackLocale
71
74
  }
72
- if (selectClause) {
73
- findOptions.select = selectClause
75
+ if (select) {
76
+ findOptions.select = select as SelectType
77
+ }
78
+ if (populate) {
79
+ findOptions.populate = populate as PopulateType
74
80
  }
75
81
 
76
82
  const result = await payload.findGlobal(findOptions)
@@ -2,6 +2,13 @@ import { defineGlobalTool } from '../../../defineTool.js'
2
2
  import { getGlobalInputSchema } from '../../../utils/schemaConversion/getEntityInputSchema.js'
3
3
 
4
4
  export const getGlobalSchemaTool = defineGlobalTool({
5
+ annotations: {
6
+ destructiveHint: false,
7
+ idempotentHint: true,
8
+ openWorldHint: false,
9
+ readOnlyHint: true,
10
+ title: 'Get Global Schema',
11
+ },
5
12
  description: 'Get the input schema for updating a global.',
6
13
  }).handler(({ globalSlug, req }) => {
7
14
  const inputSchema = getGlobalInputSchema({ globalSlug, req })
@@ -15,6 +15,13 @@ import { validateGlobalData } from '../validateEntityData.js'
15
15
  const DEFAULT_DESCRIPTION = 'Update any Payload global by passing the global slug and data.'
16
16
 
17
17
  export const updateGlobalTool = defineGlobalTool({
18
+ annotations: {
19
+ destructiveHint: true,
20
+ idempotentHint: false,
21
+ openWorldHint: false,
22
+ readOnlyHint: false,
23
+ title: 'Update Global',
24
+ },
18
25
  description: DEFAULT_DESCRIPTION,
19
26
  input: z.object({
20
27
  data: z.record(z.string(), z.unknown()).describe('The global fields to update'),
@@ -39,9 +46,9 @@ export const updateGlobalTool = defineGlobalTool({
39
46
  )
40
47
  .optional(),
41
48
  select: z
42
- .string()
49
+ .record(z.string(), z.unknown())
43
50
  .describe(
44
- "Optional: define exactly which fields you'd like to return in the response (JSON), e.g., '{\"siteName\": true}'",
51
+ 'Optional: define exactly which fields you\'d like to return in the response, e.g., {"siteName": true}',
45
52
  )
46
53
  .optional(),
47
54
  }),
@@ -66,16 +73,6 @@ export const updateGlobalTool = defineGlobalTool({
66
73
 
67
74
  const parsedData = transformPointDataToPayload(inputData)
68
75
 
69
- let selectClause: SelectType | undefined
70
- if (select) {
71
- try {
72
- selectClause = JSON.parse(select) as SelectType
73
- } catch {
74
- logger.warn(`Invalid select clause JSON for global: ${select}`)
75
- return { content: [{ type: 'text', text: 'Error: Invalid JSON in select clause' }] }
76
- }
77
- }
78
-
79
76
  const updateOptions: Parameters<typeof payload.updateGlobal>[0] = {
80
77
  slug: globalSlug,
81
78
  data: parsedData,
@@ -90,8 +87,8 @@ export const updateGlobalTool = defineGlobalTool({
90
87
  if (fallbackLocale) {
91
88
  updateOptions.fallbackLocale = fallbackLocale
92
89
  }
93
- if (selectClause) {
94
- updateOptions.select = selectClause
90
+ if (select) {
91
+ updateOptions.select = select as SelectType
95
92
  }
96
93
 
97
94
  const result = await payload.updateGlobal(updateOptions)