@payloadcms/plugin-mcp 4.0.0-canary.1 → 4.0.0-canary.11

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 (222) hide show
  1. package/LICENSE.md +1 -1
  2. package/bin.js +7 -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/defineTool.d.ts +8 -8
  8. package/dist/defineTool.d.ts.map +1 -1
  9. package/dist/endpoint/access.d.ts +12 -5
  10. package/dist/endpoint/access.d.ts.map +1 -1
  11. package/dist/endpoint/access.js +75 -88
  12. package/dist/endpoint/access.js.map +1 -1
  13. package/dist/endpoint/index.d.ts +1 -1
  14. package/dist/endpoint/index.d.ts.map +1 -1
  15. package/dist/endpoint/index.js +68 -17
  16. package/dist/endpoint/index.js.map +1 -1
  17. package/dist/exports/client.d.ts +1 -1
  18. package/dist/exports/client.d.ts.map +1 -1
  19. package/dist/exports/client.js +1 -1
  20. package/dist/exports/client.js.map +1 -1
  21. package/dist/exports/internal.d.ts +2 -0
  22. package/dist/exports/internal.d.ts.map +1 -0
  23. package/dist/exports/internal.js +3 -0
  24. package/dist/exports/internal.js.map +1 -0
  25. package/dist/index.d.ts +2 -2
  26. package/dist/index.d.ts.map +1 -1
  27. package/dist/index.js +15 -20
  28. package/dist/index.js.map +1 -1
  29. package/dist/mcp/buildMcpServer.d.ts +4 -4
  30. package/dist/mcp/buildMcpServer.d.ts.map +1 -1
  31. package/dist/mcp/buildMcpServer.js +34 -10
  32. package/dist/mcp/buildMcpServer.js.map +1 -1
  33. package/dist/mcp/builtin/collections/authTools.d.ts.map +1 -1
  34. package/dist/mcp/builtin/collections/authTools.js +44 -6
  35. package/dist/mcp/builtin/collections/authTools.js.map +1 -1
  36. package/dist/mcp/builtin/collections/countTool.d.ts +2 -0
  37. package/dist/mcp/builtin/collections/countTool.d.ts.map +1 -0
  38. package/dist/mcp/builtin/collections/countTool.js +68 -0
  39. package/dist/mcp/builtin/collections/countTool.js.map +1 -0
  40. package/dist/mcp/builtin/collections/countVersionsTool.d.ts +2 -0
  41. package/dist/mcp/builtin/collections/countVersionsTool.d.ts.map +1 -0
  42. package/dist/mcp/builtin/collections/countVersionsTool.js +64 -0
  43. package/dist/mcp/builtin/collections/countVersionsTool.js.map +1 -0
  44. package/dist/mcp/builtin/collections/createTool.d.ts.map +1 -1
  45. package/dist/mcp/builtin/collections/createTool.js +26 -24
  46. package/dist/mcp/builtin/collections/createTool.js.map +1 -1
  47. package/dist/mcp/builtin/collections/deleteTool.d.ts.map +1 -1
  48. package/dist/mcp/builtin/collections/deleteTool.js +10 -2
  49. package/dist/mcp/builtin/collections/deleteTool.js.map +1 -1
  50. package/dist/mcp/builtin/collections/duplicateTool.d.ts +2 -0
  51. package/dist/mcp/builtin/collections/duplicateTool.d.ts.map +1 -0
  52. package/dist/mcp/builtin/collections/duplicateTool.js +96 -0
  53. package/dist/mcp/builtin/collections/duplicateTool.js.map +1 -0
  54. package/dist/mcp/builtin/collections/fileInput.d.ts +20 -0
  55. package/dist/mcp/builtin/collections/fileInput.d.ts.map +1 -0
  56. package/dist/mcp/builtin/collections/fileInput.js +100 -0
  57. package/dist/mcp/builtin/collections/fileInput.js.map +1 -0
  58. package/dist/mcp/builtin/collections/fileInput.spec.js +72 -0
  59. package/dist/mcp/builtin/collections/fileInput.spec.js.map +1 -0
  60. package/dist/mcp/builtin/collections/findDistinctTool.d.ts +2 -0
  61. package/dist/mcp/builtin/collections/findDistinctTool.d.ts.map +1 -0
  62. package/dist/mcp/builtin/collections/findDistinctTool.js +92 -0
  63. package/dist/mcp/builtin/collections/findDistinctTool.js.map +1 -0
  64. package/dist/mcp/builtin/collections/findTool.d.ts.map +1 -1
  65. package/dist/mcp/builtin/collections/findTool.js +46 -26
  66. package/dist/mcp/builtin/collections/findTool.js.map +1 -1
  67. package/dist/mcp/builtin/collections/findVersionByIDTool.d.ts +2 -0
  68. package/dist/mcp/builtin/collections/findVersionByIDTool.d.ts.map +1 -0
  69. package/dist/mcp/builtin/collections/findVersionByIDTool.js +83 -0
  70. package/dist/mcp/builtin/collections/findVersionByIDTool.js.map +1 -0
  71. package/dist/mcp/builtin/collections/findVersionsTool.d.ts +2 -0
  72. package/dist/mcp/builtin/collections/findVersionsTool.d.ts.map +1 -0
  73. package/dist/mcp/builtin/collections/findVersionsTool.js +98 -0
  74. package/dist/mcp/builtin/collections/findVersionsTool.js.map +1 -0
  75. package/dist/mcp/builtin/collections/formatCollectionError.d.ts +1 -1
  76. package/dist/mcp/builtin/collections/formatCollectionError.d.ts.map +1 -1
  77. package/dist/mcp/builtin/collections/formatCollectionError.js.map +1 -1
  78. package/dist/mcp/builtin/collections/getCollectionSchemaTool.d.ts.map +1 -1
  79. package/dist/mcp/builtin/collections/getCollectionSchemaTool.js +55 -4
  80. package/dist/mcp/builtin/collections/getCollectionSchemaTool.js.map +1 -1
  81. package/dist/mcp/builtin/collections/restoreVersionTool.d.ts +2 -0
  82. package/dist/mcp/builtin/collections/restoreVersionTool.d.ts.map +1 -0
  83. package/dist/mcp/builtin/collections/restoreVersionTool.js +81 -0
  84. package/dist/mcp/builtin/collections/restoreVersionTool.js.map +1 -0
  85. package/dist/mcp/builtin/collections/updateTool.d.ts.map +1 -1
  86. package/dist/mcp/builtin/collections/updateTool.js +37 -32
  87. package/dist/mcp/builtin/collections/updateTool.js.map +1 -1
  88. package/dist/mcp/builtin/getConfigInfoTool.d.ts.map +1 -1
  89. package/dist/mcp/builtin/getConfigInfoTool.js +27 -8
  90. package/dist/mcp/builtin/getConfigInfoTool.js.map +1 -1
  91. package/dist/mcp/builtin/globals/countVersionsTool.d.ts +2 -0
  92. package/dist/mcp/builtin/globals/countVersionsTool.d.ts.map +1 -0
  93. package/dist/mcp/builtin/globals/countVersionsTool.js +64 -0
  94. package/dist/mcp/builtin/globals/countVersionsTool.js.map +1 -0
  95. package/dist/mcp/builtin/globals/findTool.d.ts.map +1 -1
  96. package/dist/mcp/builtin/globals/findTool.js +19 -22
  97. package/dist/mcp/builtin/globals/findTool.js.map +1 -1
  98. package/dist/mcp/builtin/globals/findVersionByIDTool.d.ts +2 -0
  99. package/dist/mcp/builtin/globals/findVersionByIDTool.d.ts.map +1 -0
  100. package/dist/mcp/builtin/globals/findVersionByIDTool.js +79 -0
  101. package/dist/mcp/builtin/globals/findVersionByIDTool.js.map +1 -0
  102. package/dist/mcp/builtin/globals/findVersionsTool.d.ts +2 -0
  103. package/dist/mcp/builtin/globals/findVersionsTool.d.ts.map +1 -0
  104. package/dist/mcp/builtin/globals/findVersionsTool.js +94 -0
  105. package/dist/mcp/builtin/globals/findVersionsTool.js.map +1 -0
  106. package/dist/mcp/builtin/globals/getGlobalSchemaTool.d.ts.map +1 -1
  107. package/dist/mcp/builtin/globals/getGlobalSchemaTool.js +32 -2
  108. package/dist/mcp/builtin/globals/getGlobalSchemaTool.js.map +1 -1
  109. package/dist/mcp/builtin/globals/restoreVersionTool.d.ts +2 -0
  110. package/dist/mcp/builtin/globals/restoreVersionTool.d.ts.map +1 -0
  111. package/dist/mcp/builtin/globals/restoreVersionTool.js +77 -0
  112. package/dist/mcp/builtin/globals/restoreVersionTool.js.map +1 -0
  113. package/dist/mcp/builtin/globals/updateTool.js +14 -21
  114. package/dist/mcp/builtin/globals/updateTool.js.map +1 -1
  115. package/dist/mcp/builtin/validateEntityData.d.ts.map +1 -1
  116. package/dist/mcp/builtin/validateEntityData.js +1 -1
  117. package/dist/mcp/builtin/validateEntityData.js.map +1 -1
  118. package/dist/mcp/builtinTools.d.ts +69 -12
  119. package/dist/mcp/builtinTools.d.ts.map +1 -1
  120. package/dist/mcp/builtinTools.js +66 -10
  121. package/dist/mcp/builtinTools.js.map +1 -1
  122. package/dist/mcp/sanitizeMCPConfig.d.ts +0 -1
  123. package/dist/mcp/sanitizeMCPConfig.d.ts.map +1 -1
  124. package/dist/mcp/sanitizeMCPConfig.js +69 -27
  125. package/dist/mcp/sanitizeMCPConfig.js.map +1 -1
  126. package/dist/stdio.d.ts +3 -3
  127. package/dist/stdio.d.ts.map +1 -1
  128. package/dist/stdio.js +82 -45
  129. package/dist/stdio.js.map +1 -1
  130. package/dist/types.d.ts +100 -87
  131. package/dist/types.d.ts.map +1 -1
  132. package/dist/types.js +2 -4
  133. package/dist/types.js.map +1 -1
  134. package/dist/utils/camelCase.d.ts.map +1 -1
  135. package/dist/utils/getPluginConfig.d.ts +1 -1
  136. package/dist/utils/getPluginConfig.js +1 -1
  137. package/dist/utils/getPluginConfig.js.map +1 -1
  138. package/dist/utils/resolveProjectRoot.d.ts.map +1 -1
  139. package/dist/utils/schemaConversion/filterFieldsByAccess.d.ts +28 -0
  140. package/dist/utils/schemaConversion/filterFieldsByAccess.d.ts.map +1 -0
  141. package/dist/utils/schemaConversion/filterFieldsByAccess.js +71 -0
  142. package/dist/utils/schemaConversion/filterFieldsByAccess.js.map +1 -0
  143. package/dist/utils/schemaConversion/getEntityInputSchema.d.ts +5 -3
  144. package/dist/utils/schemaConversion/getEntityInputSchema.d.ts.map +1 -1
  145. package/dist/utils/schemaConversion/getEntityInputSchema.js +44 -12
  146. package/dist/utils/schemaConversion/getEntityInputSchema.js.map +1 -1
  147. package/dist/utils/schemaConversion/sanitizeEntitySchema.d.ts +5 -10
  148. package/dist/utils/schemaConversion/sanitizeEntitySchema.d.ts.map +1 -1
  149. package/dist/utils/schemaConversion/sanitizeEntitySchema.js +15 -95
  150. package/dist/utils/schemaConversion/sanitizeEntitySchema.js.map +1 -1
  151. package/dist/utils/schemaConversion/sanitizeEntitySchema.spec.js +15 -40
  152. package/dist/utils/schemaConversion/sanitizeEntitySchema.spec.js.map +1 -1
  153. package/dist/utils/toStandardSchema.d.ts.map +1 -1
  154. package/package.json +10 -15
  155. package/src/defaultAccess.ts +3 -0
  156. package/src/endpoint/access.ts +81 -101
  157. package/src/endpoint/index.ts +58 -16
  158. package/src/exports/client.ts +2 -1
  159. package/src/exports/internal.ts +1 -0
  160. package/src/index.ts +12 -20
  161. package/src/mcp/buildMcpServer.ts +48 -21
  162. package/src/mcp/builtin/collections/authTools.ts +45 -9
  163. package/src/mcp/builtin/collections/countTool.ts +73 -0
  164. package/src/mcp/builtin/collections/countVersionsTool.ts +69 -0
  165. package/src/mcp/builtin/collections/createTool.ts +27 -18
  166. package/src/mcp/builtin/collections/deleteTool.ts +11 -2
  167. package/src/mcp/builtin/collections/duplicateTool.ts +134 -0
  168. package/src/mcp/builtin/collections/fileInput.spec.ts +79 -0
  169. package/src/mcp/builtin/collections/fileInput.ts +139 -0
  170. package/src/mcp/builtin/collections/findDistinctTool.ts +119 -0
  171. package/src/mcp/builtin/collections/findTool.ts +59 -20
  172. package/src/mcp/builtin/collections/findVersionByIDTool.ts +109 -0
  173. package/src/mcp/builtin/collections/findVersionsTool.ts +154 -0
  174. package/src/mcp/builtin/collections/formatCollectionError.ts +1 -1
  175. package/src/mcp/builtin/collections/getCollectionSchemaTool.ts +51 -3
  176. package/src/mcp/builtin/collections/restoreVersionTool.ts +107 -0
  177. package/src/mcp/builtin/collections/updateTool.ts +39 -23
  178. package/src/mcp/builtin/getConfigInfoTool.ts +27 -4
  179. package/src/mcp/builtin/globals/countVersionsTool.ts +68 -0
  180. package/src/mcp/builtin/globals/findTool.ts +27 -18
  181. package/src/mcp/builtin/globals/findVersionByIDTool.ts +103 -0
  182. package/src/mcp/builtin/globals/findVersionsTool.ts +147 -0
  183. package/src/mcp/builtin/globals/getGlobalSchemaTool.ts +37 -2
  184. package/src/mcp/builtin/globals/restoreVersionTool.ts +99 -0
  185. package/src/mcp/builtin/globals/updateTool.ts +16 -16
  186. package/src/mcp/builtin/validateEntityData.ts +1 -1
  187. package/src/mcp/builtinTools.ts +72 -16
  188. package/src/mcp/sanitizeMCPConfig.ts +48 -30
  189. package/src/stdio.ts +77 -45
  190. package/src/types.ts +108 -90
  191. package/src/utils/getPluginConfig.ts +1 -1
  192. package/src/utils/schemaConversion/filterFieldsByAccess.ts +123 -0
  193. package/src/utils/schemaConversion/getEntityInputSchema.ts +45 -27
  194. package/src/utils/schemaConversion/sanitizeEntitySchema.spec.ts +12 -19
  195. package/src/utils/schemaConversion/sanitizeEntitySchema.ts +17 -114
  196. package/dist/collection/getAccessField.d.ts +0 -12
  197. package/dist/collection/getAccessField.d.ts.map +0 -1
  198. package/dist/collection/getAccessField.js +0 -57
  199. package/dist/collection/getAccessField.js.map +0 -1
  200. package/dist/collection/index.d.ts +0 -6
  201. package/dist/collection/index.d.ts.map +0 -1
  202. package/dist/collection/index.js +0 -60
  203. package/dist/collection/index.js.map +0 -1
  204. package/dist/components/AccessField/index.client.d.ts +0 -10
  205. package/dist/components/AccessField/index.client.d.ts.map +0 -1
  206. package/dist/components/AccessField/index.client.js +0 -305
  207. package/dist/components/AccessField/index.client.js.map +0 -1
  208. package/dist/components/AccessField/index.css +0 -93
  209. package/dist/utils/localAPIDefaults.d.ts +0 -20
  210. package/dist/utils/localAPIDefaults.d.ts.map +0 -1
  211. package/dist/utils/localAPIDefaults.js +0 -19
  212. package/dist/utils/localAPIDefaults.js.map +0 -1
  213. package/dist/utils/schemaConversion/removeVirtualFieldsFromSchema.d.ts +0 -7
  214. package/dist/utils/schemaConversion/removeVirtualFieldsFromSchema.d.ts.map +0 -1
  215. package/dist/utils/schemaConversion/removeVirtualFieldsFromSchema.js +0 -20
  216. package/dist/utils/schemaConversion/removeVirtualFieldsFromSchema.js.map +0 -1
  217. package/src/collection/getAccessField.ts +0 -64
  218. package/src/collection/index.ts +0 -64
  219. package/src/components/AccessField/index.client.tsx +0 -347
  220. package/src/components/AccessField/index.css +0 -93
  221. package/src/utils/localAPIDefaults.ts +0 -22
  222. package/src/utils/schemaConversion/removeVirtualFieldsFromSchema.ts +0 -27
@@ -1,64 +0,0 @@
1
- import type { CollectionConfig } from 'payload'
2
-
3
- import type { SanitizedMCPPluginConfig } from '../types.js'
4
-
5
- import { getAccessField } from './getAccessField.js'
6
-
7
- export const getAPIKeysCollection = ({
8
- pluginConfig,
9
- }: {
10
- pluginConfig: SanitizedMCPPluginConfig
11
- }): CollectionConfig => {
12
- const collection: CollectionConfig = {
13
- slug: 'payload-mcp-api-keys',
14
- admin: {
15
- description:
16
- 'API keys control which collections, resources, tools, and prompts MCP clients can access',
17
- group: 'MCP',
18
- useAsTitle: 'label',
19
- },
20
- auth: {
21
- disableLocalStrategy: true,
22
- useAPIKey: true,
23
- },
24
- fields: [
25
- {
26
- name: 'user',
27
- type: 'relationship',
28
- admin: { description: 'The user that the API key is associated with.' },
29
- relationTo: pluginConfig.userCollection,
30
- required: true,
31
- },
32
- {
33
- name: 'label',
34
- type: 'text',
35
- admin: { description: 'A useful label for the API key.' },
36
- },
37
- {
38
- name: 'description',
39
- type: 'text',
40
- admin: { description: 'The purpose of the API key.' },
41
- },
42
- {
43
- name: 'overrideAccess',
44
- type: 'checkbox',
45
- admin: {
46
- description:
47
- 'When checked, this key bypasses Payload access control on every operation it performs. Leave unchecked unless you have a specific reason.',
48
- },
49
- defaultValue: false,
50
- label: 'Override access control',
51
- },
52
- getAccessField({ pluginConfig }),
53
- ],
54
- labels: {
55
- plural: 'API Keys',
56
- singular: 'API Key',
57
- },
58
- versions: false,
59
- }
60
-
61
- return pluginConfig.overrideApiKeyCollection
62
- ? pluginConfig.overrideApiKeyCollection(collection)
63
- : collection
64
- }
@@ -1,347 +0,0 @@
1
- 'use client'
2
-
3
- import type { JSONFieldClientProps } from 'payload'
4
-
5
- import { CheckboxInput, Collapsible, useField } from '@payloadcms/ui'
6
- import React from 'react'
7
-
8
- import type { ClientMCPPluginConfig, MCPAPIKeysDocAccessTree } from '../../types.js'
9
-
10
- import './index.css'
11
-
12
- const baseClass = 'mcp-access-field'
13
-
14
- type ClientItem = ClientMCPPluginConfig['items'][number]
15
- type ScopeKey = 'collections' | 'globals'
16
- type FlatKey = 'prompts' | 'resources' | 'tools'
17
-
18
- type Props = {
19
- pluginConfig: ClientMCPPluginConfig
20
- } & JSONFieldClientProps
21
-
22
- /** Drop a key from an object and return a new object — or `undefined` if it'd be empty. */
23
- const without = <T extends Record<string, unknown>>(
24
- obj: T | undefined,
25
- key: string,
26
- ): T | undefined => {
27
- if (!obj || !(key in obj)) {
28
- return obj
29
- }
30
- const { [key]: _omitted, ...rest } = obj
31
- return Object.keys(rest).length === 0 ? undefined : (rest as T)
32
- }
33
-
34
- const setKey = <T extends Record<string, unknown>>(
35
- obj: T | undefined,
36
- key: string,
37
- value: unknown,
38
- ): T => ({ ...(obj ?? {}), [key]: value }) as T
39
-
40
- export const AccessField: React.FC<Props> = ({ path, pluginConfig }) => {
41
- const { setValue, value } = useField<MCPAPIKeysDocAccessTree>({ path })
42
- const access = value ?? {}
43
-
44
- // Bucket items for rendering. (Bucketing is cheap and runs once per render;
45
- // memoizing would mean managing inputs/refs for marginal benefit.)
46
- const collectionsBySlug: Record<string, ClientItem[]> = {}
47
- const globalsBySlug: Record<string, ClientItem[]> = {}
48
- const tools: ClientItem[] = []
49
- const prompts: ClientItem[] = []
50
- const resources: ClientItem[] = []
51
- for (const item of pluginConfig.items) {
52
- switch (item.type) {
53
- case 'collectionTool':
54
- ;(collectionsBySlug[item.collectionSlug!] ??= []).push(item)
55
- break
56
- case 'globalTool':
57
- ;(globalsBySlug[item.globalSlug!] ??= []).push(item)
58
- break
59
- case 'prompt':
60
- prompts.push(item)
61
- break
62
- case 'resource':
63
- resources.push(item)
64
- break
65
- case 'tool':
66
- tools.push(item)
67
- break
68
- }
69
- }
70
-
71
- const isScopedAllowed = (scope: ScopeKey, slug: string, configKey: string): boolean =>
72
- access[scope]?.[slug]?.[configKey] !== false
73
-
74
- const isFlatAllowed = (scope: FlatKey, configKey: string): boolean =>
75
- access[scope]?.[configKey] !== false
76
-
77
- const toggleScoped = (scope: ScopeKey, slug: string, configKey: string, allow: boolean) => {
78
- if (allow) {
79
- const slugBucket = without(access[scope]?.[slug], configKey)
80
- const scopeBucket = slugBucket
81
- ? setKey(access[scope], slug, slugBucket)
82
- : without(access[scope], slug)
83
- setValue(scopeBucket ? setKey(access, scope, scopeBucket) : (without(access, scope) ?? {}))
84
- } else {
85
- setValue(
86
- setKey(
87
- access,
88
- scope,
89
- setKey(access[scope], slug, setKey(access[scope]?.[slug], configKey, false)),
90
- ),
91
- )
92
- }
93
- }
94
-
95
- const toggleFlat = (scope: FlatKey, configKey: string, allow: boolean) => {
96
- if (allow) {
97
- const bucket = without(access[scope], configKey)
98
- setValue(bucket ? setKey(access, scope, bucket) : (without(access, scope) ?? {}))
99
- } else {
100
- setValue(setKey(access, scope, setKey(access[scope], configKey, false)))
101
- }
102
- }
103
-
104
- const setAllScoped = (scope: ScopeKey, slug: string, leaves: ClientItem[], allow: boolean) => {
105
- if (allow) {
106
- const scopeBucket = without(access[scope], slug)
107
- setValue(scopeBucket ? setKey(access, scope, scopeBucket) : (without(access, scope) ?? {}))
108
- } else {
109
- const slugBucket = leaves.reduce<Record<string, boolean>>(
110
- (acc, leaf) => ({ ...acc, [leaf.configKey]: false }),
111
- {},
112
- )
113
- setValue(setKey(access, scope, setKey(access[scope], slug, slugBucket)))
114
- }
115
- }
116
-
117
- const setAllFlat = (scope: FlatKey, leaves: ClientItem[], allow: boolean) => {
118
- if (allow) {
119
- setValue(without(access, scope) ?? {})
120
- } else {
121
- const bucket = leaves.reduce<Record<string, boolean>>(
122
- (acc, leaf) => ({ ...acc, [leaf.configKey]: false }),
123
- {},
124
- )
125
- setValue(setKey(access, scope, bucket))
126
- }
127
- }
128
-
129
- const collectionSlugs = Object.keys(collectionsBySlug)
130
- const globalSlugs = Object.keys(globalsBySlug)
131
-
132
- return (
133
- <div className={baseClass}>
134
- {collectionSlugs.length > 0 && (
135
- <section className={`${baseClass}__section`}>
136
- <header className={`${baseClass}__section-header`}>
137
- {/* TODO: needs i18n once design is finalized */}
138
- <h4>Collection-level permissions</h4>
139
- {/* TODO: needs i18n once design is finalized */}
140
- <p>Allow MCP clients to perform the following actions within these collections:</p>
141
- </header>
142
- {collectionSlugs.map((slug) => {
143
- const leaves = collectionsBySlug[slug]!
144
- return (
145
- <Collapsible
146
- actions={
147
- <GroupActions
148
- onSetAll={(allow) => setAllScoped('collections', slug, leaves, allow)}
149
- />
150
- }
151
- className={`${baseClass}__group`}
152
- header={<span className={`${baseClass}__group-label`}>{titleCase(slug)}</span>}
153
- initCollapsed
154
- key={`collection-${slug}`}
155
- >
156
- <ul className={`${baseClass}__list`}>
157
- {leaves.map((leaf) => (
158
- <li key={leaf.configKey}>
159
- <CheckboxInput
160
- checked={isScopedAllowed('collections', slug, leaf.configKey)}
161
- id={`${path}.collections.${slug}.${leaf.configKey}`}
162
- label={leaf.label}
163
- onToggle={(e) =>
164
- toggleScoped('collections', slug, leaf.configKey, e.target.checked)
165
- }
166
- tooltip={leaf.description}
167
- />
168
- </li>
169
- ))}
170
- </ul>
171
- </Collapsible>
172
- )
173
- })}
174
- </section>
175
- )}
176
-
177
- {globalSlugs.length > 0 && (
178
- <section className={`${baseClass}__section`}>
179
- <header className={`${baseClass}__section-header`}>
180
- {/* TODO: needs i18n once design is finalized */}
181
- <h4>Global-level permissions</h4>
182
- {/* TODO: needs i18n once design is finalized */}
183
- <p>Allow MCP clients to perform the following actions on these globals:</p>
184
- </header>
185
- {globalSlugs.map((slug) => {
186
- const leaves = globalsBySlug[slug]!
187
- return (
188
- <Collapsible
189
- actions={
190
- <GroupActions
191
- onSetAll={(allow) => setAllScoped('globals', slug, leaves, allow)}
192
- />
193
- }
194
- className={`${baseClass}__group`}
195
- header={<span className={`${baseClass}__group-label`}>{titleCase(slug)}</span>}
196
- initCollapsed
197
- key={`global-${slug}`}
198
- >
199
- <ul className={`${baseClass}__list`}>
200
- {leaves.map((leaf) => (
201
- <li key={leaf.configKey}>
202
- <CheckboxInput
203
- checked={isScopedAllowed('globals', slug, leaf.configKey)}
204
- id={`${path}.globals.${slug}.${leaf.configKey}`}
205
- label={leaf.label}
206
- onToggle={(e) =>
207
- toggleScoped('globals', slug, leaf.configKey, e.target.checked)
208
- }
209
- tooltip={leaf.description}
210
- />
211
- </li>
212
- ))}
213
- </ul>
214
- </Collapsible>
215
- )
216
- })}
217
- </section>
218
- )}
219
-
220
- {(tools.length > 0 || prompts.length > 0 || resources.length > 0) && (
221
- <section className={`${baseClass}__section`}>
222
- <header className={`${baseClass}__section-header`}>
223
- {/* TODO: needs i18n once design is finalized */}
224
- <h4>Project-level permissions</h4>
225
- {/* TODO: needs i18n once design is finalized */}
226
- <p>Cross-cutting tools, prompts, and resources not scoped to a single collection.</p>
227
- </header>
228
- {tools.length > 0 && (
229
- <Collapsible
230
- actions={<GroupActions onSetAll={(allow) => setAllFlat('tools', tools, allow)} />}
231
- className={`${baseClass}__group`}
232
- header={
233
- /* TODO: needs i18n once design is finalized */
234
- <span className={`${baseClass}__group-label`}>Tools</span>
235
- }
236
- initCollapsed
237
- >
238
- <ul className={`${baseClass}__list`}>
239
- {tools.map((leaf) => (
240
- <li key={leaf.configKey}>
241
- <CheckboxInput
242
- checked={isFlatAllowed('tools', leaf.configKey)}
243
- id={`${path}.tools.${leaf.configKey}`}
244
- label={leaf.label}
245
- onToggle={(e) => toggleFlat('tools', leaf.configKey, e.target.checked)}
246
- tooltip={leaf.description}
247
- />
248
- </li>
249
- ))}
250
- </ul>
251
- </Collapsible>
252
- )}
253
- {prompts.length > 0 && (
254
- <Collapsible
255
- actions={<GroupActions onSetAll={(allow) => setAllFlat('prompts', prompts, allow)} />}
256
- className={`${baseClass}__group`}
257
- header={
258
- /* TODO: needs i18n once design is finalized */
259
- <span className={`${baseClass}__group-label`}>Prompts</span>
260
- }
261
- initCollapsed
262
- >
263
- <ul className={`${baseClass}__list`}>
264
- {prompts.map((leaf) => (
265
- <li key={leaf.configKey}>
266
- <CheckboxInput
267
- checked={isFlatAllowed('prompts', leaf.configKey)}
268
- id={`${path}.prompts.${leaf.configKey}`}
269
- label={leaf.label}
270
- onToggle={(e) => toggleFlat('prompts', leaf.configKey, e.target.checked)}
271
- tooltip={leaf.description}
272
- />
273
- </li>
274
- ))}
275
- </ul>
276
- </Collapsible>
277
- )}
278
- {resources.length > 0 && (
279
- <Collapsible
280
- actions={
281
- <GroupActions onSetAll={(allow) => setAllFlat('resources', resources, allow)} />
282
- }
283
- className={`${baseClass}__group`}
284
- header={
285
- /* TODO: needs i18n once design is finalized */
286
- <span className={`${baseClass}__group-label`}>Resources</span>
287
- }
288
- initCollapsed
289
- >
290
- <ul className={`${baseClass}__list`}>
291
- {resources.map((leaf) => (
292
- <li key={leaf.configKey}>
293
- <CheckboxInput
294
- checked={isFlatAllowed('resources', leaf.configKey)}
295
- id={`${path}.resources.${leaf.configKey}`}
296
- label={leaf.label}
297
- onToggle={(e) => toggleFlat('resources', leaf.configKey, e.target.checked)}
298
- tooltip={leaf.description}
299
- />
300
- </li>
301
- ))}
302
- </ul>
303
- </Collapsible>
304
- )}
305
- </section>
306
- )}
307
- </div>
308
- )
309
- }
310
-
311
- const GroupActions: React.FC<{ onSetAll: (allow: boolean) => void }> = ({ onSetAll }) => (
312
- // TODO: button labels + aria-labels need i18n once design is finalized
313
- <div className={`${baseClass}__group-actions`}>
314
- <button
315
- aria-label="Select all"
316
- className={`${baseClass}__action`}
317
- onClick={(e) => {
318
- e.stopPropagation()
319
- onSetAll(true)
320
- }}
321
- title="Select all"
322
- type="button"
323
- >
324
- all
325
- </button>
326
- <span aria-hidden className={`${baseClass}__action-sep`}>
327
- /
328
- </span>
329
- <button
330
- aria-label="Clear all"
331
- className={`${baseClass}__action`}
332
- onClick={(e) => {
333
- e.stopPropagation()
334
- onSetAll(false)
335
- }}
336
- title="Clear all"
337
- type="button"
338
- >
339
- none
340
- </button>
341
- </div>
342
- )
343
-
344
- const titleCase = (slug: string): string =>
345
- slug.replace(/(^|[-_])(.)/g, (_, sep: string, ch: string) =>
346
- sep ? ` ${ch.toUpperCase()}` : ch.toUpperCase(),
347
- )
@@ -1,93 +0,0 @@
1
- @layer payload-default {
2
- .mcp-access-field {
3
- display: flex;
4
- flex-direction: column;
5
- gap: var(--base);
6
- }
7
-
8
- .mcp-access-field__section {
9
- display: flex;
10
- flex-direction: column;
11
- gap: calc(var(--base) / 2);
12
- padding-bottom: var(--base);
13
- /* Full-bleed separator: extend past the sidebar's horizontal gutter so the
14
- border-block-end spans the entire sidebar width. */
15
- margin-inline-start: calc(-1 * var(--sidebar-gutter-h-left, var(--gutter-h)));
16
- margin-inline-end: calc(-1 * var(--sidebar-gutter-h-right, var(--gutter-h)));
17
- padding-inline-start: var(--sidebar-gutter-h-left, var(--gutter-h));
18
- padding-inline-end: var(--sidebar-gutter-h-right, var(--gutter-h));
19
- border-block-end: 1px solid var(--theme-elevation-100);
20
- }
21
-
22
- .mcp-access-field__section:last-child {
23
- border-block-end: none;
24
- }
25
-
26
- .mcp-access-field__section-header {
27
- display: flex;
28
- flex-direction: column;
29
- }
30
-
31
- .mcp-access-field__section-header h4 {
32
- margin: 0;
33
- color: var(--color-text);
34
- font-family: var(--text-heading-small-font-family);
35
- font-size: var(--text-heading-small-font-size);
36
- font-weight: var(--text-heading-small-font-weight);
37
- line-height: var(--text-heading-small-line-height);
38
- letter-spacing: var(--text-heading-small-letter-spacing);
39
- }
40
-
41
- .mcp-access-field__section-header p {
42
- margin: 0;
43
- color: var(--color-text-secondary);
44
- font-family: var(--text-body-medium-font-family);
45
- font-size: var(--text-body-medium-font-size);
46
- font-weight: var(--text-body-medium-font-weight);
47
- line-height: var(--text-body-medium-line-height);
48
- letter-spacing: var(--text-body-medium-letter-spacing);
49
- }
50
-
51
- .mcp-access-field__group {
52
- margin-block-end: calc(var(--base) / 2);
53
- }
54
-
55
- .mcp-access-field__group-label {
56
- font-weight: 600;
57
- }
58
-
59
- .mcp-access-field__group-actions {
60
- display: flex;
61
- align-items: center;
62
- gap: calc(var(--base) / 6);
63
- }
64
-
65
- .mcp-access-field__action {
66
- appearance: none;
67
- background: none;
68
- border: none;
69
- color: var(--theme-elevation-500);
70
- cursor: pointer;
71
- font-size: 0.75rem;
72
- padding: 0;
73
- }
74
-
75
- .mcp-access-field__action:hover {
76
- color: var(--theme-text);
77
- text-decoration: underline;
78
- }
79
-
80
- .mcp-access-field__action-sep {
81
- color: var(--theme-elevation-300);
82
- font-size: 0.75rem;
83
- }
84
-
85
- .mcp-access-field__list {
86
- list-style: none;
87
- margin: 0;
88
- padding: 0;
89
- display: flex;
90
- flex-direction: column;
91
- gap: calc(var(--base) / 3);
92
- }
93
- }
@@ -1,22 +0,0 @@
1
- import type { AuthorizedMCP } from '../types.js'
2
-
3
- /**
4
- * Returns the `user` and `overrideAccess` arguments every Payload local API call
5
- * should receive when initiated from an MCP request. Spread the result into the
6
- * call's arg object so the two pieces of caller state can't drift apart.
7
- *
8
- * @example
9
- * ```ts
10
- * await req.payload.create({
11
- * collection: 'posts',
12
- * data,
13
- * ...localAPIDefaults(authorizedMCP),
14
- * })
15
- * ```
16
- */
17
- export const localAPIDefaults = (
18
- authorizedMCP: AuthorizedMCP,
19
- ): { overrideAccess: boolean; user: AuthorizedMCP['user'] } => ({
20
- overrideAccess: authorizedMCP.overrideAccess,
21
- user: authorizedMCP.user,
22
- })
@@ -1,27 +0,0 @@
1
- import type { JsonSchemaType } from '../../types.js'
2
-
3
- /**
4
- * Removes virtual fields from a JSON Schema by name so they don't appear
5
- * in the generated MCP tool input schema.
6
- */
7
- export function removeVirtualFieldsFromSchema(
8
- schema: JsonSchemaType,
9
- virtualFieldNames: string[],
10
- ): JsonSchemaType {
11
- if (virtualFieldNames.length === 0) {
12
- return schema
13
- }
14
-
15
- for (const name of virtualFieldNames) {
16
- delete schema?.properties?.[name]
17
- }
18
-
19
- if (Array.isArray(schema.required)) {
20
- schema.required = schema.required.filter((field) => !virtualFieldNames.includes(field))
21
- if (schema.required.length === 0) {
22
- delete schema.required
23
- }
24
- }
25
-
26
- return schema
27
- }