@payloadcms/plugin-mcp 3.86.0-internal.ac46214 → 4.0.0-internal.1f9ae9a

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 (329) hide show
  1. package/README.md +2 -2
  2. package/bin.js +39 -0
  3. package/dist/collection/getAccessField.d.ts +12 -0
  4. package/dist/collection/getAccessField.d.ts.map +1 -0
  5. package/dist/collection/getAccessField.js +57 -0
  6. package/dist/collection/getAccessField.js.map +1 -0
  7. package/dist/collection/index.d.ts +6 -0
  8. package/dist/collection/index.d.ts.map +1 -0
  9. package/dist/collection/index.js +59 -0
  10. package/dist/collection/index.js.map +1 -0
  11. package/dist/components/AccessField/index.client.d.ts +10 -0
  12. package/dist/components/AccessField/index.client.d.ts.map +1 -0
  13. package/dist/components/AccessField/index.client.js +305 -0
  14. package/dist/components/AccessField/index.client.js.map +1 -0
  15. package/dist/components/AccessField/index.css +93 -0
  16. package/dist/defineTool.d.ts +26 -0
  17. package/dist/defineTool.d.ts.map +1 -0
  18. package/dist/defineTool.js +37 -0
  19. package/dist/defineTool.js.map +1 -0
  20. package/dist/endpoint/access.d.ts +10 -0
  21. package/dist/endpoint/access.d.ts.map +1 -0
  22. package/dist/endpoint/access.js +106 -0
  23. package/dist/endpoint/access.js.map +1 -0
  24. package/dist/endpoint/index.d.ts +3 -0
  25. package/dist/endpoint/index.d.ts.map +1 -0
  26. package/dist/endpoint/index.js +36 -0
  27. package/dist/endpoint/index.js.map +1 -0
  28. package/dist/exports/client.d.ts +2 -0
  29. package/dist/exports/client.d.ts.map +1 -0
  30. package/dist/exports/client.js +4 -0
  31. package/dist/exports/client.js.map +1 -0
  32. package/dist/index.d.ts +4 -7
  33. package/dist/index.d.ts.map +1 -1
  34. package/dist/index.js +44 -67
  35. package/dist/index.js.map +1 -1
  36. package/dist/mcp/buildMcpServer.d.ts +19 -0
  37. package/dist/mcp/buildMcpServer.d.ts.map +1 -0
  38. package/dist/mcp/buildMcpServer.js +163 -0
  39. package/dist/mcp/buildMcpServer.js.map +1 -0
  40. package/dist/mcp/builtin/collections/authTools.d.ts +7 -0
  41. package/dist/mcp/builtin/collections/authTools.d.ts.map +1 -0
  42. package/dist/mcp/builtin/collections/authTools.js +250 -0
  43. package/dist/mcp/builtin/collections/authTools.js.map +1 -0
  44. package/dist/mcp/builtin/collections/createTool.d.ts +2 -0
  45. package/dist/mcp/builtin/collections/createTool.d.ts.map +1 -0
  46. package/dist/mcp/builtin/collections/createTool.js +87 -0
  47. package/dist/mcp/builtin/collections/createTool.js.map +1 -0
  48. package/dist/mcp/builtin/collections/deleteTool.d.ts +2 -0
  49. package/dist/mcp/builtin/collections/deleteTool.d.ts.map +1 -0
  50. package/dist/mcp/builtin/collections/deleteTool.js +117 -0
  51. package/dist/mcp/builtin/collections/deleteTool.js.map +1 -0
  52. package/dist/mcp/builtin/collections/findTool.d.ts +2 -0
  53. package/dist/mcp/builtin/collections/findTool.d.ts.map +1 -0
  54. package/dist/mcp/builtin/collections/findTool.js +159 -0
  55. package/dist/mcp/builtin/collections/findTool.js.map +1 -0
  56. package/dist/mcp/builtin/collections/updateTool.d.ts +2 -0
  57. package/dist/mcp/builtin/collections/updateTool.d.ts.map +1 -0
  58. package/dist/mcp/builtin/collections/updateTool.js +187 -0
  59. package/dist/mcp/builtin/collections/updateTool.js.map +1 -0
  60. package/dist/mcp/builtin/globals/findTool.d.ts +2 -0
  61. package/dist/mcp/builtin/globals/findTool.d.ts.map +1 -0
  62. package/dist/mcp/builtin/globals/findTool.js +76 -0
  63. package/dist/mcp/builtin/globals/findTool.js.map +1 -0
  64. package/dist/mcp/builtin/globals/updateTool.d.ts +2 -0
  65. package/dist/mcp/builtin/globals/updateTool.d.ts.map +1 -0
  66. package/dist/mcp/builtin/globals/updateTool.js +92 -0
  67. package/dist/mcp/builtin/globals/updateTool.js.map +1 -0
  68. package/dist/mcp/builtinTools.d.ts +37 -0
  69. package/dist/mcp/builtinTools.d.ts.map +1 -0
  70. package/dist/mcp/builtinTools.js +64 -0
  71. package/dist/mcp/builtinTools.js.map +1 -0
  72. package/dist/mcp/sanitizeMCPConfig.d.ts +17 -0
  73. package/dist/mcp/sanitizeMCPConfig.d.ts.map +1 -0
  74. package/dist/mcp/sanitizeMCPConfig.js +167 -0
  75. package/dist/mcp/sanitizeMCPConfig.js.map +1 -0
  76. package/dist/stdio.d.ts +8 -0
  77. package/dist/stdio.d.ts.map +1 -0
  78. package/dist/stdio.js +89 -0
  79. package/dist/stdio.js.map +1 -0
  80. package/dist/types.d.ts +262 -455
  81. package/dist/types.d.ts.map +1 -1
  82. package/dist/types.js +6 -1
  83. package/dist/types.js.map +1 -1
  84. package/dist/utils/camelCase.d.ts.map +1 -1
  85. package/dist/utils/getLogger.d.ts +10 -0
  86. package/dist/utils/getLogger.d.ts.map +1 -0
  87. package/dist/utils/getLogger.js +22 -0
  88. package/dist/utils/getLogger.js.map +1 -0
  89. package/dist/utils/getPluginConfig.d.ts +12 -0
  90. package/dist/utils/getPluginConfig.d.ts.map +1 -0
  91. package/dist/utils/getPluginConfig.js +15 -0
  92. package/dist/utils/getPluginConfig.js.map +1 -0
  93. package/dist/utils/localAPIDefaults.d.ts +20 -0
  94. package/dist/utils/localAPIDefaults.d.ts.map +1 -0
  95. package/dist/utils/localAPIDefaults.js +19 -0
  96. package/dist/utils/localAPIDefaults.js.map +1 -0
  97. package/dist/utils/resolveProjectRoot.d.ts +7 -0
  98. package/dist/utils/resolveProjectRoot.d.ts.map +1 -0
  99. package/dist/utils/resolveProjectRoot.js +15 -0
  100. package/dist/utils/resolveProjectRoot.js.map +1 -0
  101. package/dist/utils/schemaConversion/prepareCollectionSchema.d.ts +7 -0
  102. package/dist/utils/schemaConversion/prepareCollectionSchema.d.ts.map +1 -0
  103. package/dist/utils/schemaConversion/prepareCollectionSchema.js +37 -0
  104. package/dist/utils/schemaConversion/prepareCollectionSchema.js.map +1 -0
  105. package/dist/utils/schemaConversion/removeVirtualFieldsFromSchema.d.ts +2 -2
  106. package/dist/utils/schemaConversion/removeVirtualFieldsFromSchema.d.ts.map +1 -1
  107. package/dist/utils/schemaConversion/removeVirtualFieldsFromSchema.js.map +1 -1
  108. package/dist/utils/schemaConversion/sanitizeJsonSchema.d.ts +2 -2
  109. package/dist/utils/schemaConversion/sanitizeJsonSchema.d.ts.map +1 -1
  110. package/dist/utils/schemaConversion/sanitizeJsonSchema.js.map +1 -1
  111. package/dist/utils/schemaConversion/simplifyRelationshipFields.d.ts +2 -2
  112. package/dist/utils/schemaConversion/simplifyRelationshipFields.d.ts.map +1 -1
  113. package/dist/utils/schemaConversion/simplifyRelationshipFields.js +7 -4
  114. package/dist/utils/schemaConversion/simplifyRelationshipFields.js.map +1 -1
  115. package/dist/utils/schemaConversion/transformPointFields.d.ts +2 -2
  116. package/dist/utils/schemaConversion/transformPointFields.d.ts.map +1 -1
  117. package/dist/utils/schemaConversion/transformPointFields.js +7 -1
  118. package/dist/utils/schemaConversion/transformPointFields.js.map +1 -1
  119. package/dist/utils/toStandardSchema.d.ts +5 -0
  120. package/dist/utils/toStandardSchema.d.ts.map +1 -0
  121. package/dist/utils/toStandardSchema.js +4 -0
  122. package/dist/utils/toStandardSchema.js.map +1 -0
  123. package/package.json +35 -10
  124. package/src/collection/getAccessField.ts +64 -0
  125. package/src/collection/index.ts +63 -0
  126. package/src/components/AccessField/index.client.tsx +344 -0
  127. package/src/components/AccessField/index.css +93 -0
  128. package/src/defineTool.ts +44 -0
  129. package/src/endpoint/access.ts +132 -0
  130. package/src/endpoint/index.ts +35 -0
  131. package/src/exports/client.ts +2 -0
  132. package/src/index.ts +35 -85
  133. package/src/mcp/buildMcpServer.ts +224 -0
  134. package/src/mcp/builtin/collections/authTools.ts +233 -0
  135. package/src/mcp/builtin/collections/createTool.ts +116 -0
  136. package/src/mcp/builtin/collections/deleteTool.ts +123 -0
  137. package/src/mcp/builtin/collections/findTool.ts +187 -0
  138. package/src/mcp/builtin/collections/updateTool.ts +205 -0
  139. package/src/mcp/builtin/globals/findTool.ts +96 -0
  140. package/src/mcp/builtin/globals/updateTool.ts +118 -0
  141. package/src/mcp/builtinTools.ts +84 -0
  142. package/src/mcp/sanitizeMCPConfig.ts +239 -0
  143. package/src/stdio.ts +98 -0
  144. package/src/types.ts +295 -490
  145. package/src/utils/getLogger.ts +22 -0
  146. package/src/utils/getPluginConfig.ts +24 -0
  147. package/src/utils/localAPIDefaults.ts +22 -0
  148. package/src/utils/resolveProjectRoot.ts +17 -0
  149. package/src/utils/schemaConversion/prepareCollectionSchema.ts +39 -0
  150. package/src/utils/schemaConversion/removeVirtualFieldsFromSchema.ts +3 -3
  151. package/src/utils/schemaConversion/sanitizeJsonSchema.ts +4 -4
  152. package/src/utils/schemaConversion/simplifyRelationshipFields.ts +11 -6
  153. package/src/utils/schemaConversion/transformPointFields.ts +6 -5
  154. package/src/utils/toStandardSchema.ts +9 -0
  155. package/dist/collections/createApiKeysCollection.d.ts +0 -7
  156. package/dist/collections/createApiKeysCollection.d.ts.map +0 -1
  157. package/dist/collections/createApiKeysCollection.js +0 -317
  158. package/dist/collections/createApiKeysCollection.js.map +0 -1
  159. package/dist/defaults.d.ts +0 -4
  160. package/dist/defaults.d.ts.map +0 -1
  161. package/dist/defaults.js +0 -5
  162. package/dist/defaults.js.map +0 -1
  163. package/dist/endpoints/mcp.d.ts +0 -4
  164. package/dist/endpoints/mcp.d.ts.map +0 -1
  165. package/dist/endpoints/mcp.js +0 -71
  166. package/dist/endpoints/mcp.js.map +0 -1
  167. package/dist/mcp/createRequest.d.ts +0 -3
  168. package/dist/mcp/createRequest.d.ts.map +0 -1
  169. package/dist/mcp/createRequest.js +0 -14
  170. package/dist/mcp/createRequest.js.map +0 -1
  171. package/dist/mcp/getMcpHandler.d.ts +0 -4
  172. package/dist/mcp/getMcpHandler.d.ts.map +0 -1
  173. package/dist/mcp/getMcpHandler.js +0 -231
  174. package/dist/mcp/getMcpHandler.js.map +0 -1
  175. package/dist/mcp/helpers/config.d.ts +0 -22
  176. package/dist/mcp/helpers/config.d.ts.map +0 -1
  177. package/dist/mcp/helpers/config.js +0 -153
  178. package/dist/mcp/helpers/config.js.map +0 -1
  179. package/dist/mcp/helpers/fields.d.ts +0 -19
  180. package/dist/mcp/helpers/fields.d.ts.map +0 -1
  181. package/dist/mcp/helpers/fields.js +0 -102
  182. package/dist/mcp/helpers/fields.js.map +0 -1
  183. package/dist/mcp/helpers/fileValidation.d.ts +0 -67
  184. package/dist/mcp/helpers/fileValidation.d.ts.map +0 -1
  185. package/dist/mcp/helpers/fileValidation.js +0 -267
  186. package/dist/mcp/helpers/fileValidation.js.map +0 -1
  187. package/dist/mcp/registerTool.d.ts +0 -6
  188. package/dist/mcp/registerTool.d.ts.map +0 -1
  189. package/dist/mcp/registerTool.js +0 -18
  190. package/dist/mcp/registerTool.js.map +0 -1
  191. package/dist/mcp/tools/auth/auth.d.ts +0 -4
  192. package/dist/mcp/tools/auth/auth.d.ts.map +0 -1
  193. package/dist/mcp/tools/auth/auth.js +0 -57
  194. package/dist/mcp/tools/auth/auth.js.map +0 -1
  195. package/dist/mcp/tools/auth/forgotPassword.d.ts +0 -4
  196. package/dist/mcp/tools/auth/forgotPassword.d.ts.map +0 -1
  197. package/dist/mcp/tools/auth/forgotPassword.js +0 -48
  198. package/dist/mcp/tools/auth/forgotPassword.js.map +0 -1
  199. package/dist/mcp/tools/auth/login.d.ts +0 -4
  200. package/dist/mcp/tools/auth/login.d.ts.map +0 -1
  201. package/dist/mcp/tools/auth/login.js +0 -51
  202. package/dist/mcp/tools/auth/login.js.map +0 -1
  203. package/dist/mcp/tools/auth/resetPassword.d.ts +0 -4
  204. package/dist/mcp/tools/auth/resetPassword.d.ts.map +0 -1
  205. package/dist/mcp/tools/auth/resetPassword.js +0 -49
  206. package/dist/mcp/tools/auth/resetPassword.js.map +0 -1
  207. package/dist/mcp/tools/auth/unlock.d.ts +0 -4
  208. package/dist/mcp/tools/auth/unlock.d.ts.map +0 -1
  209. package/dist/mcp/tools/auth/unlock.js +0 -48
  210. package/dist/mcp/tools/auth/unlock.js.map +0 -1
  211. package/dist/mcp/tools/auth/verify.d.ts +0 -4
  212. package/dist/mcp/tools/auth/verify.d.ts.map +0 -1
  213. package/dist/mcp/tools/auth/verify.js +0 -45
  214. package/dist/mcp/tools/auth/verify.js.map +0 -1
  215. package/dist/mcp/tools/collection/create.d.ts +0 -10
  216. package/dist/mcp/tools/collection/create.d.ts.map +0 -1
  217. package/dist/mcp/tools/collection/create.js +0 -139
  218. package/dist/mcp/tools/collection/create.js.map +0 -1
  219. package/dist/mcp/tools/collection/delete.d.ts +0 -10
  220. package/dist/mcp/tools/collection/delete.d.ts.map +0 -1
  221. package/dist/mcp/tools/collection/delete.js +0 -154
  222. package/dist/mcp/tools/collection/delete.js.map +0 -1
  223. package/dist/mcp/tools/collection/find.d.ts +0 -10
  224. package/dist/mcp/tools/collection/find.d.ts.map +0 -1
  225. package/dist/mcp/tools/collection/find.js +0 -165
  226. package/dist/mcp/tools/collection/find.js.map +0 -1
  227. package/dist/mcp/tools/collection/update.d.ts +0 -10
  228. package/dist/mcp/tools/collection/update.d.ts.map +0 -1
  229. package/dist/mcp/tools/collection/update.js +0 -209
  230. package/dist/mcp/tools/collection/update.js.map +0 -1
  231. package/dist/mcp/tools/config/find.d.ts +0 -10
  232. package/dist/mcp/tools/config/find.d.ts.map +0 -1
  233. package/dist/mcp/tools/config/find.js +0 -97
  234. package/dist/mcp/tools/config/find.js.map +0 -1
  235. package/dist/mcp/tools/config/update.d.ts +0 -10
  236. package/dist/mcp/tools/config/update.d.ts.map +0 -1
  237. package/dist/mcp/tools/config/update.js +0 -215
  238. package/dist/mcp/tools/config/update.js.map +0 -1
  239. package/dist/mcp/tools/global/find.d.ts +0 -5
  240. package/dist/mcp/tools/global/find.d.ts.map +0 -1
  241. package/dist/mcp/tools/global/find.js +0 -82
  242. package/dist/mcp/tools/global/find.js.map +0 -1
  243. package/dist/mcp/tools/global/update.d.ts +0 -6
  244. package/dist/mcp/tools/global/update.d.ts.map +0 -1
  245. package/dist/mcp/tools/global/update.js +0 -124
  246. package/dist/mcp/tools/global/update.js.map +0 -1
  247. package/dist/mcp/tools/job/create.d.ts +0 -10
  248. package/dist/mcp/tools/job/create.d.ts.map +0 -1
  249. package/dist/mcp/tools/job/create.js +0 -293
  250. package/dist/mcp/tools/job/create.js.map +0 -1
  251. package/dist/mcp/tools/job/run.d.ts +0 -10
  252. package/dist/mcp/tools/job/run.d.ts.map +0 -1
  253. package/dist/mcp/tools/job/run.js +0 -129
  254. package/dist/mcp/tools/job/run.js.map +0 -1
  255. package/dist/mcp/tools/job/update.d.ts +0 -11
  256. package/dist/mcp/tools/job/update.d.ts.map +0 -1
  257. package/dist/mcp/tools/job/update.js +0 -186
  258. package/dist/mcp/tools/job/update.js.map +0 -1
  259. package/dist/mcp/tools/resource/create.d.ts +0 -6
  260. package/dist/mcp/tools/resource/create.d.ts.map +0 -1
  261. package/dist/mcp/tools/resource/create.js +0 -124
  262. package/dist/mcp/tools/resource/create.js.map +0 -1
  263. package/dist/mcp/tools/resource/delete.d.ts +0 -5
  264. package/dist/mcp/tools/resource/delete.d.ts.map +0 -1
  265. package/dist/mcp/tools/resource/delete.js +0 -151
  266. package/dist/mcp/tools/resource/delete.js.map +0 -1
  267. package/dist/mcp/tools/resource/find.d.ts +0 -5
  268. package/dist/mcp/tools/resource/find.d.ts.map +0 -1
  269. package/dist/mcp/tools/resource/find.js +0 -170
  270. package/dist/mcp/tools/resource/find.js.map +0 -1
  271. package/dist/mcp/tools/resource/update.d.ts +0 -6
  272. package/dist/mcp/tools/resource/update.d.ts.map +0 -1
  273. package/dist/mcp/tools/resource/update.js +0 -256
  274. package/dist/mcp/tools/resource/update.js.map +0 -1
  275. package/dist/mcp/tools/schemas.d.ts +0 -457
  276. package/dist/mcp/tools/schemas.d.ts.map +0 -1
  277. package/dist/mcp/tools/schemas.js +0 -243
  278. package/dist/mcp/tools/schemas.js.map +0 -1
  279. package/dist/utils/adminEntitySettings.d.ts +0 -17
  280. package/dist/utils/adminEntitySettings.d.ts.map +0 -1
  281. package/dist/utils/adminEntitySettings.js +0 -41
  282. package/dist/utils/adminEntitySettings.js.map +0 -1
  283. package/dist/utils/createApiKeyFields.d.ts +0 -15
  284. package/dist/utils/createApiKeyFields.d.ts.map +0 -1
  285. package/dist/utils/createApiKeyFields.js +0 -57
  286. package/dist/utils/createApiKeyFields.js.map +0 -1
  287. package/dist/utils/getEnabledSlugs.d.ts +0 -13
  288. package/dist/utils/getEnabledSlugs.d.ts.map +0 -1
  289. package/dist/utils/getEnabledSlugs.js +0 -32
  290. package/dist/utils/getEnabledSlugs.js.map +0 -1
  291. package/dist/utils/schemaConversion/convertCollectionSchemaToZod.d.ts +0 -3
  292. package/dist/utils/schemaConversion/convertCollectionSchemaToZod.d.ts.map +0 -1
  293. package/dist/utils/schemaConversion/convertCollectionSchemaToZod.js +0 -43
  294. package/dist/utils/schemaConversion/convertCollectionSchemaToZod.js.map +0 -1
  295. package/src/collections/createApiKeysCollection.ts +0 -373
  296. package/src/defaults.ts +0 -3
  297. package/src/endpoints/mcp.ts +0 -91
  298. package/src/mcp/createRequest.ts +0 -13
  299. package/src/mcp/getMcpHandler.ts +0 -545
  300. package/src/mcp/helpers/config.ts +0 -213
  301. package/src/mcp/helpers/fields.ts +0 -154
  302. package/src/mcp/helpers/fileValidation.ts +0 -362
  303. package/src/mcp/registerTool.ts +0 -22
  304. package/src/mcp/tools/auth/auth.ts +0 -71
  305. package/src/mcp/tools/auth/forgotPassword.ts +0 -70
  306. package/src/mcp/tools/auth/login.ts +0 -72
  307. package/src/mcp/tools/auth/resetPassword.ts +0 -61
  308. package/src/mcp/tools/auth/unlock.ts +0 -64
  309. package/src/mcp/tools/auth/verify.ts +0 -57
  310. package/src/mcp/tools/collection/create.ts +0 -210
  311. package/src/mcp/tools/collection/delete.ts +0 -211
  312. package/src/mcp/tools/collection/find.ts +0 -224
  313. package/src/mcp/tools/collection/update.ts +0 -290
  314. package/src/mcp/tools/config/find.ts +0 -128
  315. package/src/mcp/tools/config/update.ts +0 -280
  316. package/src/mcp/tools/global/find.ts +0 -128
  317. package/src/mcp/tools/global/update.ts +0 -207
  318. package/src/mcp/tools/job/create.ts +0 -416
  319. package/src/mcp/tools/job/run.ts +0 -167
  320. package/src/mcp/tools/job/update.ts +0 -274
  321. package/src/mcp/tools/resource/create.ts +0 -211
  322. package/src/mcp/tools/resource/delete.ts +0 -218
  323. package/src/mcp/tools/resource/find.ts +0 -246
  324. package/src/mcp/tools/resource/update.ts +0 -383
  325. package/src/mcp/tools/schemas.ts +0 -520
  326. package/src/utils/adminEntitySettings.ts +0 -40
  327. package/src/utils/createApiKeyFields.ts +0 -72
  328. package/src/utils/getEnabledSlugs.ts +0 -42
  329. package/src/utils/schemaConversion/convertCollectionSchemaToZod.ts +0 -52
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/utils/schemaConversion/transformPointFields.ts"],"sourcesContent":["import type { JSONSchema4 } from 'json-schema'\n\nexport function transformPointFieldsForMCP(schema: JSONSchema4): JSONSchema4 {\n if (!schema || typeof schema !== 'object') {\n return schema\n }\n\n const transformed = { ...schema }\n\n if (transformed.properties && typeof transformed.properties === 'object') {\n transformed.properties = Object.fromEntries(\n Object.entries(transformed.properties).map(([key, value]) => {\n const isArrayType =\n value.type === 'array' || (Array.isArray(value.type) && value.type.includes('array'))\n\n if (\n value &&\n typeof value === 'object' &&\n isArrayType &&\n Array.isArray(value.items) &&\n value.items.length === 2 &&\n value.items.every((item: JSONSchema4) => item?.type === 'number')\n ) {\n // Transform to object format\n const isNullable = Array.isArray(value.type) && value.type.includes('null')\n\n return [\n key,\n {\n type: isNullable ? ['object', 'null'] : 'object',\n description: value.description || 'Geographic coordinates (longitude, latitude)',\n properties: {\n latitude: { type: 'number', description: 'Latitude coordinate' },\n longitude: { type: 'number', description: 'Longitude coordinate' },\n },\n required: ['longitude', 'latitude'],\n },\n ]\n }\n\n return [key, transformPointFieldsForMCP(value)]\n }),\n )\n }\n\n if (\n transformed.items &&\n typeof transformed.items === 'object' &&\n !Array.isArray(transformed.items)\n ) {\n transformed.items = transformPointFieldsForMCP(transformed.items)\n }\n\n return transformed\n}\n"],"names":["transformPointFieldsForMCP","schema","transformed","properties","Object","fromEntries","entries","map","key","value","isArrayType","type","Array","isArray","includes","items","length","every","item","isNullable","description","latitude","longitude","required"],"mappings":"AAEA,OAAO,SAASA,2BAA2BC,MAAmB;IAC5D,IAAI,CAACA,UAAU,OAAOA,WAAW,UAAU;QACzC,OAAOA;IACT;IAEA,MAAMC,cAAc;QAAE,GAAGD,MAAM;IAAC;IAEhC,IAAIC,YAAYC,UAAU,IAAI,OAAOD,YAAYC,UAAU,KAAK,UAAU;QACxED,YAAYC,UAAU,GAAGC,OAAOC,WAAW,CACzCD,OAAOE,OAAO,CAACJ,YAAYC,UAAU,EAAEI,GAAG,CAAC,CAAC,CAACC,KAAKC,MAAM;YACtD,MAAMC,cACJD,MAAME,IAAI,KAAK,WAAYC,MAAMC,OAAO,CAACJ,MAAME,IAAI,KAAKF,MAAME,IAAI,CAACG,QAAQ,CAAC;YAE9E,IACEL,SACA,OAAOA,UAAU,YACjBC,eACAE,MAAMC,OAAO,CAACJ,MAAMM,KAAK,KACzBN,MAAMM,KAAK,CAACC,MAAM,KAAK,KACvBP,MAAMM,KAAK,CAACE,KAAK,CAAC,CAACC,OAAsBA,MAAMP,SAAS,WACxD;gBACA,6BAA6B;gBAC7B,MAAMQ,aAAaP,MAAMC,OAAO,CAACJ,MAAME,IAAI,KAAKF,MAAME,IAAI,CAACG,QAAQ,CAAC;gBAEpE,OAAO;oBACLN;oBACA;wBACEG,MAAMQ,aAAa;4BAAC;4BAAU;yBAAO,GAAG;wBACxCC,aAAaX,MAAMW,WAAW,IAAI;wBAClCjB,YAAY;4BACVkB,UAAU;gCAAEV,MAAM;gCAAUS,aAAa;4BAAsB;4BAC/DE,WAAW;gCAAEX,MAAM;gCAAUS,aAAa;4BAAuB;wBACnE;wBACAG,UAAU;4BAAC;4BAAa;yBAAW;oBACrC;iBACD;YACH;YAEA,OAAO;gBAACf;gBAAKR,2BAA2BS;aAAO;QACjD;IAEJ;IAEA,IACEP,YAAYa,KAAK,IACjB,OAAOb,YAAYa,KAAK,KAAK,YAC7B,CAACH,MAAMC,OAAO,CAACX,YAAYa,KAAK,GAChC;QACAb,YAAYa,KAAK,GAAGf,2BAA2BE,YAAYa,KAAK;IAClE;IAEA,OAAOb;AACT"}
1
+ {"version":3,"sources":["../../../src/utils/schemaConversion/transformPointFields.ts"],"sourcesContent":["import type { JsonSchemaType } from '../../types.js'\n\nexport function transformPointFieldsForMCP(schema: JsonSchemaType): JsonSchemaType {\n if (!schema || typeof schema !== 'object') {\n return schema\n }\n\n const transformed = { ...schema }\n\n if (transformed.properties && typeof transformed.properties === 'object') {\n transformed.properties = Object.fromEntries(\n Object.entries(transformed.properties).map(([key, value]) => {\n if (!value || typeof value !== 'object') {\n return [key, value]\n }\n const isArrayType =\n value.type === 'array' || (Array.isArray(value.type) && value.type.includes('array'))\n\n if (\n isArrayType &&\n Array.isArray(value.items) &&\n value.items.length === 2 &&\n value.items.every((item) => item && typeof item === 'object' && item.type === 'number')\n ) {\n // Transform to object format\n const isNullable = Array.isArray(value.type) && value.type.includes('null')\n\n return [\n key,\n {\n type: isNullable ? ['object', 'null'] : 'object',\n description: value.description || 'Geographic coordinates (longitude, latitude)',\n properties: {\n latitude: { type: 'number', description: 'Latitude coordinate' },\n longitude: { type: 'number', description: 'Longitude coordinate' },\n },\n required: ['longitude', 'latitude'],\n },\n ]\n }\n\n return [key, transformPointFieldsForMCP(value)]\n }),\n )\n }\n\n if (\n transformed.items &&\n typeof transformed.items === 'object' &&\n !Array.isArray(transformed.items)\n ) {\n transformed.items = transformPointFieldsForMCP(transformed.items)\n }\n\n return transformed\n}\n"],"names":["transformPointFieldsForMCP","schema","transformed","properties","Object","fromEntries","entries","map","key","value","isArrayType","type","Array","isArray","includes","items","length","every","item","isNullable","description","latitude","longitude","required"],"mappings":"AAEA,OAAO,SAASA,2BAA2BC,MAAsB;IAC/D,IAAI,CAACA,UAAU,OAAOA,WAAW,UAAU;QACzC,OAAOA;IACT;IAEA,MAAMC,cAAc;QAAE,GAAGD,MAAM;IAAC;IAEhC,IAAIC,YAAYC,UAAU,IAAI,OAAOD,YAAYC,UAAU,KAAK,UAAU;QACxED,YAAYC,UAAU,GAAGC,OAAOC,WAAW,CACzCD,OAAOE,OAAO,CAACJ,YAAYC,UAAU,EAAEI,GAAG,CAAC,CAAC,CAACC,KAAKC,MAAM;YACtD,IAAI,CAACA,SAAS,OAAOA,UAAU,UAAU;gBACvC,OAAO;oBAACD;oBAAKC;iBAAM;YACrB;YACA,MAAMC,cACJD,MAAME,IAAI,KAAK,WAAYC,MAAMC,OAAO,CAACJ,MAAME,IAAI,KAAKF,MAAME,IAAI,CAACG,QAAQ,CAAC;YAE9E,IACEJ,eACAE,MAAMC,OAAO,CAACJ,MAAMM,KAAK,KACzBN,MAAMM,KAAK,CAACC,MAAM,KAAK,KACvBP,MAAMM,KAAK,CAACE,KAAK,CAAC,CAACC,OAASA,QAAQ,OAAOA,SAAS,YAAYA,KAAKP,IAAI,KAAK,WAC9E;gBACA,6BAA6B;gBAC7B,MAAMQ,aAAaP,MAAMC,OAAO,CAACJ,MAAME,IAAI,KAAKF,MAAME,IAAI,CAACG,QAAQ,CAAC;gBAEpE,OAAO;oBACLN;oBACA;wBACEG,MAAMQ,aAAa;4BAAC;4BAAU;yBAAO,GAAG;wBACxCC,aAAaX,MAAMW,WAAW,IAAI;wBAClCjB,YAAY;4BACVkB,UAAU;gCAAEV,MAAM;gCAAUS,aAAa;4BAAsB;4BAC/DE,WAAW;gCAAEX,MAAM;gCAAUS,aAAa;4BAAuB;wBACnE;wBACAG,UAAU;4BAAC;4BAAa;yBAAW;oBACrC;iBACD;YACH;YAEA,OAAO;gBAACf;gBAAKR,2BAA2BS;aAAO;QACjD;IAEJ;IAEA,IACEP,YAAYa,KAAK,IACjB,OAAOb,YAAYa,KAAK,KAAK,YAC7B,CAACH,MAAMC,OAAO,CAACX,YAAYa,KAAK,GAChC;QACAb,YAAYa,KAAK,GAAGf,2BAA2BE,YAAYa,KAAK;IAClE;IAEA,OAAOb;AACT"}
@@ -0,0 +1,5 @@
1
+ import { type StandardSchemaWithJSON } from '@modelcontextprotocol/server';
2
+ import type { ToolInputSchema } from '../types.js';
3
+ /** Normalize a tool/prompt input to a Standard Schema. Raw JSON Schema gets wrapped; Standard Schema instances pass through. */
4
+ export declare const toStandardSchema: (schema: ToolInputSchema) => StandardSchemaWithJSON;
5
+ //# sourceMappingURL=toStandardSchema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toStandardSchema.d.ts","sourceRoot":"","sources":["../../src/utils/toStandardSchema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,sBAAsB,EAAE,MAAM,8BAA8B,CAAA;AAE1F,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAElD,gIAAgI;AAChI,eAAO,MAAM,gBAAgB,GAAI,QAAQ,eAAe,KAAG,sBAG/B,CAAA"}
@@ -0,0 +1,4 @@
1
+ import { fromJsonSchema } from '@modelcontextprotocol/server';
2
+ /** Normalize a tool/prompt input to a Standard Schema. Raw JSON Schema gets wrapped; Standard Schema instances pass through. */ export const toStandardSchema = (schema)=>typeof schema === 'object' && schema !== null && '~standard' in schema ? schema : fromJsonSchema(schema);
3
+
4
+ //# sourceMappingURL=toStandardSchema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/utils/toStandardSchema.ts"],"sourcesContent":["import { fromJsonSchema, type StandardSchemaWithJSON } from '@modelcontextprotocol/server'\n\nimport type { ToolInputSchema } from '../types.js'\n\n/** Normalize a tool/prompt input to a Standard Schema. Raw JSON Schema gets wrapped; Standard Schema instances pass through. */\nexport const toStandardSchema = (schema: ToolInputSchema): StandardSchemaWithJSON =>\n typeof schema === 'object' && schema !== null && '~standard' in schema\n ? (schema as StandardSchemaWithJSON)\n : fromJsonSchema(schema)\n"],"names":["fromJsonSchema","toStandardSchema","schema"],"mappings":"AAAA,SAASA,cAAc,QAAqC,+BAA8B;AAI1F,8HAA8H,GAC9H,OAAO,MAAMC,mBAAmB,CAACC,SAC/B,OAAOA,WAAW,YAAYA,WAAW,QAAQ,eAAeA,SAC3DA,SACDF,eAAeE,QAAO"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@payloadcms/plugin-mcp",
3
- "version": "3.86.0-internal.ac46214",
3
+ "version": "4.0.0-internal.1f9ae9a",
4
4
  "description": "MCP (Model Context Protocol) capabilities with Payload",
5
5
  "keywords": [
6
6
  "plugin",
@@ -21,34 +21,59 @@
21
21
  "url": "https://payloadcms.com"
22
22
  }
23
23
  ],
24
- "sideEffects": false,
24
+ "sideEffects": [
25
+ "*.css"
26
+ ],
25
27
  "type": "module",
26
28
  "exports": {
27
29
  ".": {
28
30
  "import": "./dist/index.js",
29
31
  "types": "./dist/index.d.ts",
30
32
  "default": "./dist/index.js"
33
+ },
34
+ "./client": {
35
+ "import": "./dist/exports/client.js",
36
+ "types": "./dist/exports/client.d.ts",
37
+ "default": "./dist/exports/client.js"
38
+ },
39
+ "./stdio": {
40
+ "import": "./dist/stdio.js",
41
+ "types": "./dist/stdio.d.ts",
42
+ "default": "./dist/stdio.js"
31
43
  }
32
44
  },
33
45
  "main": "./dist/index.js",
34
46
  "types": "./dist/index.d.ts",
47
+ "bin": {
48
+ "payload-mcp": "./bin.js"
49
+ },
35
50
  "files": [
36
51
  "src",
37
- "dist"
52
+ "dist",
53
+ "bin.js"
38
54
  ],
39
55
  "dependencies": {
40
- "@modelcontextprotocol/sdk": "1.27.1",
41
- "@types/json-schema": "7.0.15",
42
- "json-schema-to-zod": "2.6.1",
43
- "mcp-handler": "^1.0.7",
44
- "zod": "^3.25.50"
56
+ "@cfworker/json-schema": "^4.1.1",
57
+ "@modelcontextprotocol/server": "2.0.0-alpha.2",
58
+ "tsx": "4.22.4",
59
+ "zod": "^4.0.0"
45
60
  },
46
61
  "devDependencies": {
62
+ "@types/react": "19.2.14",
63
+ "react": "^19.0.1 || ^19.1.2 || ^19.2.1",
47
64
  "@payloadcms/eslint-config": "3.28.0",
48
- "payload": "3.86.0-internal.ac46214"
65
+ "payload": "4.0.0-internal.1f9ae9a",
66
+ "@payloadcms/ui": "4.0.0-internal.1f9ae9a"
49
67
  },
50
68
  "peerDependencies": {
51
- "payload": "3.86.0-internal.ac46214"
69
+ "react": "^19.0.1 || ^19.1.2 || ^19.2.1",
70
+ "@payloadcms/ui": "4.0.0-internal.1f9ae9a",
71
+ "payload": "4.0.0-internal.1f9ae9a"
72
+ },
73
+ "//deps_notes": {
74
+ "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.",
75
+ "@cfworker/json-schema": "Should be able to remove in next @modelcontextprotocol/server alpha release. Marked as an optional peer of @modelcontextprotocol/server, but its bundle does an eager top-level `import { Validator } from '@cfworker/json-schema'`, so it must be installed even when only zod-registered tools are used. Drop once upstream lazy-loads the validator. See: https://github.com/modelcontextprotocol/typescript-sdk",
76
+ "tsx": "Required by the `bin.js` stdio mcp. Keep the version pinned to whatever `payload` ships to avoid duplicate installs."
52
77
  },
53
78
  "homepage:": "https://payloadcms.com",
54
79
  "scripts": {
@@ -0,0 +1,64 @@
1
+ import type { JSONField } from 'payload'
2
+
3
+ import type { ClientMCPPluginConfig, MCPItem, SanitizedMCPPluginConfig } from '../types.js'
4
+
5
+ /**
6
+ * Returns the API key collection's `access` field — a JSON field whose value
7
+ * is the `MCPAPIKeysDocAccessTree` the endpoint consults. The actual UI is
8
+ * a custom client component (`AccessField`) which renders a permissions
9
+ * matrix; the field's stored shape is just the runtime access tree.
10
+ */
11
+ export const getAccessField = ({
12
+ pluginConfig,
13
+ }: {
14
+ pluginConfig: SanitizedMCPPluginConfig
15
+ }): JSONField => {
16
+ const clientPluginConfig = sanitizeClientPluginConfig(pluginConfig)
17
+
18
+ return {
19
+ name: 'access',
20
+ type: 'json',
21
+ admin: {
22
+ components: {
23
+ Field: {
24
+ clientProps: { pluginConfig: clientPluginConfig },
25
+ path: '@payloadcms/plugin-mcp/client#AccessField',
26
+ },
27
+ },
28
+ // TODO: needs i18n once design is finalized
29
+ description: 'Access for this API key — uncheck to revoke individual tools.',
30
+ position: 'sidebar',
31
+ },
32
+ defaultValue: {},
33
+ // TODO: needs i18n once design is finalized
34
+ label: 'Access',
35
+ }
36
+ }
37
+
38
+ /**
39
+ * Strips the non-serializable parts of `SanitizedMCPPluginConfig` (handlers,
40
+ * input/argsSchema functions, etc.) so the result is safe to thread to a
41
+ * client component via `clientProps`.
42
+ */
43
+ const sanitizeClientPluginConfig = (
44
+ pluginConfig: SanitizedMCPPluginConfig,
45
+ ): ClientMCPPluginConfig => ({
46
+ items: pluginConfig.items.map((item) => ({
47
+ ...(item.type === 'collectionTool' ? { collectionSlug: item.collectionSlug } : {}),
48
+ ...(item.type === 'globalTool' ? { globalSlug: item.globalSlug } : {}),
49
+ type: item.type,
50
+ description: itemDescription(item),
51
+ key: item.key,
52
+ label: item.label,
53
+ })),
54
+ })
55
+
56
+ const itemDescription = (item: MCPItem): string => {
57
+ if (item.type === 'prompt') {
58
+ return item.prompt.description
59
+ }
60
+ if (item.type === 'resource') {
61
+ return item.resource.description
62
+ }
63
+ return item.tool.description
64
+ }
@@ -0,0 +1,63 @@
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
+ }
59
+
60
+ return pluginConfig.overrideApiKeyCollection
61
+ ? pluginConfig.overrideApiKeyCollection(collection)
62
+ : collection
63
+ }
@@ -0,0 +1,344 @@
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
+ )
@@ -0,0 +1,93 @@
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
+ }