@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
@@ -1,344 +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, key: string): boolean =>
72
- access[scope]?.[slug]?.[key] !== false
73
-
74
- const isFlatAllowed = (scope: FlatKey, key: string): boolean => access[scope]?.[key] !== false
75
-
76
- const toggleScoped = (scope: ScopeKey, slug: string, key: string, allow: boolean) => {
77
- if (allow) {
78
- const slugBucket = without(access[scope]?.[slug], key)
79
- const scopeBucket = slugBucket
80
- ? setKey(access[scope], slug, slugBucket)
81
- : without(access[scope], slug)
82
- setValue(scopeBucket ? setKey(access, scope, scopeBucket) : (without(access, scope) ?? {}))
83
- } else {
84
- setValue(
85
- setKey(
86
- access,
87
- scope,
88
- setKey(access[scope], slug, setKey(access[scope]?.[slug], key, false)),
89
- ),
90
- )
91
- }
92
- }
93
-
94
- const toggleFlat = (scope: FlatKey, key: string, allow: boolean) => {
95
- if (allow) {
96
- const bucket = without(access[scope], key)
97
- setValue(bucket ? setKey(access, scope, bucket) : (without(access, scope) ?? {}))
98
- } else {
99
- setValue(setKey(access, scope, setKey(access[scope], key, false)))
100
- }
101
- }
102
-
103
- const setAllScoped = (scope: ScopeKey, slug: string, leaves: ClientItem[], allow: boolean) => {
104
- if (allow) {
105
- const scopeBucket = without(access[scope], slug)
106
- setValue(scopeBucket ? setKey(access, scope, scopeBucket) : (without(access, scope) ?? {}))
107
- } else {
108
- const slugBucket = leaves.reduce<Record<string, boolean>>(
109
- (acc, leaf) => ({ ...acc, [leaf.key]: false }),
110
- {},
111
- )
112
- setValue(setKey(access, scope, setKey(access[scope], slug, slugBucket)))
113
- }
114
- }
115
-
116
- const setAllFlat = (scope: FlatKey, leaves: ClientItem[], allow: boolean) => {
117
- if (allow) {
118
- setValue(without(access, scope) ?? {})
119
- } else {
120
- const bucket = leaves.reduce<Record<string, boolean>>(
121
- (acc, leaf) => ({ ...acc, [leaf.key]: false }),
122
- {},
123
- )
124
- setValue(setKey(access, scope, bucket))
125
- }
126
- }
127
-
128
- const collectionSlugs = Object.keys(collectionsBySlug)
129
- const globalSlugs = Object.keys(globalsBySlug)
130
-
131
- return (
132
- <div className={baseClass}>
133
- {collectionSlugs.length > 0 && (
134
- <section className={`${baseClass}__section`}>
135
- <header className={`${baseClass}__section-header`}>
136
- {/* TODO: needs i18n once design is finalized */}
137
- <h4>Collection-level permissions</h4>
138
- {/* TODO: needs i18n once design is finalized */}
139
- <p>Allow MCP clients to perform the following actions within these collections:</p>
140
- </header>
141
- {collectionSlugs.map((slug) => {
142
- const leaves = collectionsBySlug[slug]!
143
- return (
144
- <Collapsible
145
- actions={
146
- <GroupActions
147
- onSetAll={(allow) => setAllScoped('collections', slug, leaves, allow)}
148
- />
149
- }
150
- className={`${baseClass}__group`}
151
- header={<span className={`${baseClass}__group-label`}>{titleCase(slug)}</span>}
152
- initCollapsed
153
- key={`collection-${slug}`}
154
- >
155
- <ul className={`${baseClass}__list`}>
156
- {leaves.map((leaf) => (
157
- <li key={leaf.key}>
158
- <CheckboxInput
159
- checked={isScopedAllowed('collections', slug, leaf.key)}
160
- id={`${path}.collections.${slug}.${leaf.key}`}
161
- label={leaf.label}
162
- onToggle={(e) =>
163
- toggleScoped('collections', slug, leaf.key, e.target.checked)
164
- }
165
- tooltip={leaf.description}
166
- />
167
- </li>
168
- ))}
169
- </ul>
170
- </Collapsible>
171
- )
172
- })}
173
- </section>
174
- )}
175
-
176
- {globalSlugs.length > 0 && (
177
- <section className={`${baseClass}__section`}>
178
- <header className={`${baseClass}__section-header`}>
179
- {/* TODO: needs i18n once design is finalized */}
180
- <h4>Global-level permissions</h4>
181
- {/* TODO: needs i18n once design is finalized */}
182
- <p>Allow MCP clients to perform the following actions on these globals:</p>
183
- </header>
184
- {globalSlugs.map((slug) => {
185
- const leaves = globalsBySlug[slug]!
186
- return (
187
- <Collapsible
188
- actions={
189
- <GroupActions
190
- onSetAll={(allow) => setAllScoped('globals', slug, leaves, allow)}
191
- />
192
- }
193
- className={`${baseClass}__group`}
194
- header={<span className={`${baseClass}__group-label`}>{titleCase(slug)}</span>}
195
- initCollapsed
196
- key={`global-${slug}`}
197
- >
198
- <ul className={`${baseClass}__list`}>
199
- {leaves.map((leaf) => (
200
- <li key={leaf.key}>
201
- <CheckboxInput
202
- checked={isScopedAllowed('globals', slug, leaf.key)}
203
- id={`${path}.globals.${slug}.${leaf.key}`}
204
- label={leaf.label}
205
- onToggle={(e) => toggleScoped('globals', slug, leaf.key, e.target.checked)}
206
- tooltip={leaf.description}
207
- />
208
- </li>
209
- ))}
210
- </ul>
211
- </Collapsible>
212
- )
213
- })}
214
- </section>
215
- )}
216
-
217
- {(tools.length > 0 || prompts.length > 0 || resources.length > 0) && (
218
- <section className={`${baseClass}__section`}>
219
- <header className={`${baseClass}__section-header`}>
220
- {/* TODO: needs i18n once design is finalized */}
221
- <h4>Project-level permissions</h4>
222
- {/* TODO: needs i18n once design is finalized */}
223
- <p>Cross-cutting tools, prompts, and resources not scoped to a single collection.</p>
224
- </header>
225
- {tools.length > 0 && (
226
- <Collapsible
227
- actions={<GroupActions onSetAll={(allow) => setAllFlat('tools', tools, allow)} />}
228
- className={`${baseClass}__group`}
229
- header={
230
- /* TODO: needs i18n once design is finalized */
231
- <span className={`${baseClass}__group-label`}>Tools</span>
232
- }
233
- initCollapsed
234
- >
235
- <ul className={`${baseClass}__list`}>
236
- {tools.map((leaf) => (
237
- <li key={leaf.key}>
238
- <CheckboxInput
239
- checked={isFlatAllowed('tools', leaf.key)}
240
- id={`${path}.tools.${leaf.key}`}
241
- label={leaf.label}
242
- onToggle={(e) => toggleFlat('tools', leaf.key, e.target.checked)}
243
- tooltip={leaf.description}
244
- />
245
- </li>
246
- ))}
247
- </ul>
248
- </Collapsible>
249
- )}
250
- {prompts.length > 0 && (
251
- <Collapsible
252
- actions={<GroupActions onSetAll={(allow) => setAllFlat('prompts', prompts, allow)} />}
253
- className={`${baseClass}__group`}
254
- header={
255
- /* TODO: needs i18n once design is finalized */
256
- <span className={`${baseClass}__group-label`}>Prompts</span>
257
- }
258
- initCollapsed
259
- >
260
- <ul className={`${baseClass}__list`}>
261
- {prompts.map((leaf) => (
262
- <li key={leaf.key}>
263
- <CheckboxInput
264
- checked={isFlatAllowed('prompts', leaf.key)}
265
- id={`${path}.prompts.${leaf.key}`}
266
- label={leaf.label}
267
- onToggle={(e) => toggleFlat('prompts', leaf.key, e.target.checked)}
268
- tooltip={leaf.description}
269
- />
270
- </li>
271
- ))}
272
- </ul>
273
- </Collapsible>
274
- )}
275
- {resources.length > 0 && (
276
- <Collapsible
277
- actions={
278
- <GroupActions onSetAll={(allow) => setAllFlat('resources', resources, allow)} />
279
- }
280
- className={`${baseClass}__group`}
281
- header={
282
- /* TODO: needs i18n once design is finalized */
283
- <span className={`${baseClass}__group-label`}>Resources</span>
284
- }
285
- initCollapsed
286
- >
287
- <ul className={`${baseClass}__list`}>
288
- {resources.map((leaf) => (
289
- <li key={leaf.key}>
290
- <CheckboxInput
291
- checked={isFlatAllowed('resources', leaf.key)}
292
- id={`${path}.resources.${leaf.key}`}
293
- label={leaf.label}
294
- onToggle={(e) => toggleFlat('resources', leaf.key, e.target.checked)}
295
- tooltip={leaf.description}
296
- />
297
- </li>
298
- ))}
299
- </ul>
300
- </Collapsible>
301
- )}
302
- </section>
303
- )}
304
- </div>
305
- )
306
- }
307
-
308
- const GroupActions: React.FC<{ onSetAll: (allow: boolean) => void }> = ({ onSetAll }) => (
309
- // TODO: button labels + aria-labels need i18n once design is finalized
310
- <div className={`${baseClass}__group-actions`}>
311
- <button
312
- aria-label="Select all"
313
- className={`${baseClass}__action`}
314
- onClick={(e) => {
315
- e.stopPropagation()
316
- onSetAll(true)
317
- }}
318
- title="Select all"
319
- type="button"
320
- >
321
- all
322
- </button>
323
- <span aria-hidden className={`${baseClass}__action-sep`}>
324
- /
325
- </span>
326
- <button
327
- aria-label="Clear all"
328
- className={`${baseClass}__action`}
329
- onClick={(e) => {
330
- e.stopPropagation()
331
- onSetAll(false)
332
- }}
333
- title="Clear all"
334
- type="button"
335
- >
336
- none
337
- </button>
338
- </div>
339
- )
340
-
341
- const titleCase = (slug: string): string =>
342
- slug.replace(/(^|[-_])(.)/g, (_, sep: string, ch: string) =>
343
- sep ? ` ${ch.toUpperCase()}` : ch.toUpperCase(),
344
- )
@@ -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,39 +0,0 @@
1
- import type { JsonSchemaType } from '../../types.js'
2
-
3
- import { sanitizeJsonSchema } from './sanitizeJsonSchema.js'
4
- import { simplifyRelationshipFields } from './simplifyRelationshipFields.js'
5
- import { transformPointFieldsForMCP } from './transformPointFields.js'
6
-
7
- /**
8
- * Fields Payload manages automatically — clients should never be required to provide
9
- * them. Stripped from `required` and `properties` so they don't appear in tool
10
- * inputs.
11
- */
12
- const PAYLOAD_MANAGED_FIELDS = new Set(['_status', 'createdAt', 'id', 'updatedAt'])
13
-
14
- /**
15
- * Sanitizes Payload's auto-generated collection JSON Schema so it can be safely
16
- * fed into the MCP server's `fromJsonSchema()` adapter (no zod intermediate step).
17
- */
18
- export const prepareCollectionSchema = (schema: JsonSchemaType): JsonSchemaType => {
19
- // Clone to avoid mutating the original schema (used elsewhere for tool listing)
20
- const schemaClone = JSON.parse(JSON.stringify(schema)) as JsonSchemaType
21
-
22
- const sanitized = sanitizeJsonSchema(schemaClone)
23
- const pointTransformed = transformPointFieldsForMCP(sanitized)
24
- const simplified = simplifyRelationshipFields(pointTransformed)
25
-
26
- if (simplified.properties) {
27
- for (const field of PAYLOAD_MANAGED_FIELDS) {
28
- delete simplified.properties[field]
29
- }
30
- }
31
- if (Array.isArray(simplified.required)) {
32
- simplified.required = simplified.required.filter((name) => !PAYLOAD_MANAGED_FIELDS.has(name))
33
- if (simplified.required.length === 0) {
34
- delete simplified.required
35
- }
36
- }
37
-
38
- return simplified
39
- }
@@ -1,62 +0,0 @@
1
- import type { JsonSchemaType } from '../../types.js'
2
-
3
- /**
4
- * Removes internal Payload properties (id, createdAt, updatedAt) from a
5
- * JSON Schema so they don't appear in the generated Zod validation schema.
6
- * Also strips `id` from the `required` array when present.
7
- *
8
- * Additionally normalizes nullable type arrays (e.g. `['array', 'null']` →
9
- * `'array'`) throughout the schema tree. Without this, `json-schema-to-zod`
10
- * emits a Zod union which the MCP SDK serialises back as `anyOf`, stripping
11
- * the concrete `type` from the output and breaking schema introspection.
12
- */
13
- export function sanitizeJsonSchema(schema: JsonSchemaType): JsonSchemaType {
14
- delete schema?.properties?.id
15
- delete schema?.properties?.createdAt
16
- delete schema?.properties?.updatedAt
17
-
18
- if (Array.isArray(schema.required)) {
19
- schema.required = schema.required.filter((field) => field !== 'id')
20
- if (schema.required.length === 0) {
21
- delete schema.required
22
- }
23
- }
24
-
25
- if (schema.properties && typeof schema.properties === 'object') {
26
- for (const key of Object.keys(schema.properties)) {
27
- const prop = schema.properties[key] as JsonSchemaType
28
- if (!prop || typeof prop !== 'object') {
29
- continue
30
- }
31
- normalizeNullableType(prop)
32
- if (prop.properties) {
33
- sanitizeJsonSchema(prop)
34
- }
35
- if (prop.items && typeof prop.items === 'object' && !Array.isArray(prop.items)) {
36
- sanitizeJsonSchema(prop.items)
37
- }
38
- }
39
- }
40
-
41
- return schema
42
- }
43
-
44
- /**
45
- * Strips `'null'` from a `type` array only when the remaining type is a
46
- * complex structural type (`array` or `object`).
47
- *
48
- * Simple scalar types (`string`, `number`, `boolean`) are intentionally
49
- * preserved as `['string', 'null']` so that the MCP SDK serialises them as a
50
- * compact inline `type` array. Complex types however cause `zodToJsonSchema`
51
- * to emit `anyOf: [{ type: 'array', items: ... }, { type: 'null' }]`, which
52
- * has no top-level `type` property and breaks schema introspection by clients.
53
- */
54
- function normalizeNullableType(schema: JsonSchemaType): void {
55
- if (!Array.isArray(schema.type)) {
56
- return
57
- }
58
- const nonNullTypes = schema.type.filter((t) => t !== 'null')
59
- if (nonNullTypes.length === 1 && (nonNullTypes[0] === 'array' || nonNullTypes[0] === 'object')) {
60
- schema.type = nonNullTypes[0]
61
- }
62
- }
@@ -1,70 +0,0 @@
1
- import type { JsonSchemaType } from '../../types.js'
2
-
3
- /**
4
- * Recursively processes JSON schema properties to simplify relationship fields
5
- * and convert `oneOf` constructs into MCP-friendly schemas.
6
- *
7
- * For create/update validation we only need to accept IDs (string/number),
8
- * not populated objects. `$ref` options pointing to full entity definitions
9
- * are removed entirely from `oneOf` unions. When a single option remains the
10
- * `oneOf` is unwrapped; otherwise it is converted to `anyOf`.
11
- *
12
- * This matters because `json-schema-to-zod` converts `oneOf` into a strict
13
- * `z.any().superRefine(...)` validator whose base type is `z.any()`, causing
14
- * `zodToJsonSchema` to emit `{}` and losing all type information in the MCP
15
- * tool input schema. `anyOf` instead produces a clean `z.union([...])`.
16
- *
17
- * NOTE: This function must operate on a cloned schema to avoid mutating
18
- * the original JSON schema used for tool listing.
19
- */
20
- export function simplifyRelationshipFields(schema: JsonSchemaType): JsonSchemaType {
21
- if (!schema || typeof schema !== 'object') {
22
- return schema
23
- }
24
-
25
- const processed = { ...schema }
26
-
27
- if (Array.isArray(processed.oneOf)) {
28
- const hasRef = processed.oneOf.some(
29
- (option) => option && typeof option === 'object' && '$ref' in option,
30
- )
31
-
32
- const recurse = (option: boolean | JsonSchemaType): boolean | JsonSchemaType =>
33
- typeof option === 'object' ? simplifyRelationshipFields(option) : option
34
-
35
- if (hasRef) {
36
- const nonRefOptions = processed.oneOf
37
- .filter((option) => !(option && typeof option === 'object' && '$ref' in option))
38
- .map(recurse)
39
-
40
- if (nonRefOptions.length === 1) {
41
- const single = nonRefOptions[0]!
42
- delete processed.oneOf
43
- if (typeof single === 'object') {
44
- Object.assign(processed, single)
45
- }
46
- } else if (nonRefOptions.length > 1) {
47
- delete processed.oneOf
48
- processed.anyOf = nonRefOptions
49
- }
50
- } else {
51
- processed.anyOf = processed.oneOf.map(recurse)
52
- delete processed.oneOf
53
- }
54
- }
55
-
56
- if (processed.properties && typeof processed.properties === 'object') {
57
- processed.properties = Object.fromEntries(
58
- Object.entries(processed.properties).map(([key, value]) => [
59
- key,
60
- typeof value === 'object' ? simplifyRelationshipFields(value) : value,
61
- ]),
62
- )
63
- }
64
-
65
- if (processed.items && typeof processed.items === 'object' && !Array.isArray(processed.items)) {
66
- processed.items = simplifyRelationshipFields(processed.items)
67
- }
68
-
69
- return processed
70
- }
@@ -1,56 +0,0 @@
1
- import type { JsonSchemaType } from '../../types.js'
2
-
3
- export function transformPointFieldsForMCP(schema: JsonSchemaType): JsonSchemaType {
4
- if (!schema || typeof schema !== 'object') {
5
- return schema
6
- }
7
-
8
- const transformed = { ...schema }
9
-
10
- if (transformed.properties && typeof transformed.properties === 'object') {
11
- transformed.properties = Object.fromEntries(
12
- Object.entries(transformed.properties).map(([key, value]) => {
13
- if (!value || typeof value !== 'object') {
14
- return [key, value]
15
- }
16
- const isArrayType =
17
- value.type === 'array' || (Array.isArray(value.type) && value.type.includes('array'))
18
-
19
- if (
20
- isArrayType &&
21
- Array.isArray(value.items) &&
22
- value.items.length === 2 &&
23
- value.items.every((item) => item && typeof item === 'object' && item.type === 'number')
24
- ) {
25
- // Transform to object format
26
- const isNullable = Array.isArray(value.type) && value.type.includes('null')
27
-
28
- return [
29
- key,
30
- {
31
- type: isNullable ? ['object', 'null'] : 'object',
32
- description: value.description || 'Geographic coordinates (longitude, latitude)',
33
- properties: {
34
- latitude: { type: 'number', description: 'Latitude coordinate' },
35
- longitude: { type: 'number', description: 'Longitude coordinate' },
36
- },
37
- required: ['longitude', 'latitude'],
38
- },
39
- ]
40
- }
41
-
42
- return [key, transformPointFieldsForMCP(value)]
43
- }),
44
- )
45
- }
46
-
47
- if (
48
- transformed.items &&
49
- typeof transformed.items === 'object' &&
50
- !Array.isArray(transformed.items)
51
- ) {
52
- transformed.items = transformPointFieldsForMCP(transformed.items)
53
- }
54
-
55
- return transformed
56
- }