@payloadcms/plugin-mcp 4.0.0-canary.0 → 4.0.0-canary.2

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 (381) hide show
  1. package/dist/collection/getAccessField.d.ts.map +1 -1
  2. package/dist/collection/getAccessField.js +25 -10
  3. package/dist/collection/getAccessField.js.map +1 -1
  4. package/dist/collection/index.d.ts.map +1 -1
  5. package/dist/collection/index.js +73 -27
  6. package/dist/collection/index.js.map +1 -1
  7. package/dist/components/APIKeyField/index.client.d.ts +9 -0
  8. package/dist/components/APIKeyField/index.client.d.ts.map +1 -0
  9. package/dist/components/APIKeyField/index.client.js +85 -0
  10. package/dist/components/APIKeyField/index.client.js.map +1 -0
  11. package/dist/components/APIKeyField/index.css +105 -0
  12. package/dist/components/APIKeysEmptyState/index.client.d.ts +4 -0
  13. package/dist/components/APIKeysEmptyState/index.client.d.ts.map +1 -0
  14. package/dist/components/APIKeysEmptyState/index.client.js +21 -0
  15. package/dist/components/APIKeysEmptyState/index.client.js.map +1 -0
  16. package/dist/components/AccessField/index.client.d.ts.map +1 -1
  17. package/dist/components/AccessField/index.client.js +149 -207
  18. package/dist/components/AccessField/index.client.js.map +1 -1
  19. package/dist/components/AccessField/index.css +50 -44
  20. package/dist/components/SettingsMenu/index.client.d.ts +8 -0
  21. package/dist/components/SettingsMenu/index.client.d.ts.map +1 -0
  22. package/dist/components/SettingsMenu/index.client.js +29 -0
  23. package/dist/components/SettingsMenu/index.client.js.map +1 -0
  24. package/dist/endpoint/access.js +21 -5
  25. package/dist/endpoint/access.js.map +1 -1
  26. package/dist/exports/client.d.ts +3 -0
  27. package/dist/exports/client.d.ts.map +1 -1
  28. package/dist/exports/client.js +3 -0
  29. package/dist/exports/client.js.map +1 -1
  30. package/dist/index.d.ts.map +1 -1
  31. package/dist/index.js +46 -3
  32. package/dist/index.js.map +1 -1
  33. package/dist/mcp/buildMcpServer.d.ts.map +1 -1
  34. package/dist/mcp/buildMcpServer.js +100 -64
  35. package/dist/mcp/buildMcpServer.js.map +1 -1
  36. package/dist/mcp/builtin/collections/createTool.d.ts +1 -1
  37. package/dist/mcp/builtin/collections/createTool.d.ts.map +1 -1
  38. package/dist/mcp/builtin/collections/createTool.js +28 -21
  39. package/dist/mcp/builtin/collections/createTool.js.map +1 -1
  40. package/dist/mcp/builtin/collections/deleteTool.d.ts +1 -1
  41. package/dist/mcp/builtin/collections/deleteTool.d.ts.map +1 -1
  42. package/dist/mcp/builtin/collections/deleteTool.js +5 -20
  43. package/dist/mcp/builtin/collections/deleteTool.js.map +1 -1
  44. package/dist/mcp/builtin/collections/findTool.d.ts +1 -1
  45. package/dist/mcp/builtin/collections/findTool.d.ts.map +1 -1
  46. package/dist/mcp/builtin/collections/findTool.js +6 -21
  47. package/dist/mcp/builtin/collections/findTool.js.map +1 -1
  48. package/dist/mcp/builtin/collections/formatCollectionError.d.ts +9 -0
  49. package/dist/mcp/builtin/collections/formatCollectionError.d.ts.map +1 -0
  50. package/dist/mcp/builtin/collections/formatCollectionError.js +60 -0
  51. package/dist/mcp/builtin/collections/formatCollectionError.js.map +1 -0
  52. package/dist/mcp/builtin/collections/getCollectionSchemaTool.d.ts +2 -0
  53. package/dist/mcp/builtin/collections/getCollectionSchemaTool.d.ts.map +1 -0
  54. package/dist/mcp/builtin/collections/getCollectionSchemaTool.js +35 -0
  55. package/dist/mcp/builtin/collections/getCollectionSchemaTool.js.map +1 -0
  56. package/dist/mcp/builtin/collections/updateTool.d.ts +1 -1
  57. package/dist/mcp/builtin/collections/updateTool.d.ts.map +1 -1
  58. package/dist/mcp/builtin/collections/updateTool.js +74 -62
  59. package/dist/mcp/builtin/collections/updateTool.js.map +1 -1
  60. package/dist/mcp/builtin/getConfigInfoTool.d.ts +2 -0
  61. package/dist/mcp/builtin/getConfigInfoTool.d.ts.map +1 -0
  62. package/dist/mcp/builtin/getConfigInfoTool.js +49 -0
  63. package/dist/mcp/builtin/getConfigInfoTool.js.map +1 -0
  64. package/dist/mcp/builtin/globals/findTool.js +1 -1
  65. package/dist/mcp/builtin/globals/findTool.js.map +1 -1
  66. package/dist/mcp/builtin/globals/getGlobalSchemaTool.d.ts +2 -0
  67. package/dist/mcp/builtin/globals/getGlobalSchemaTool.d.ts.map +1 -0
  68. package/dist/mcp/builtin/globals/getGlobalSchemaTool.js +35 -0
  69. package/dist/mcp/builtin/globals/getGlobalSchemaTool.js.map +1 -0
  70. package/dist/mcp/builtin/globals/updateTool.d.ts.map +1 -1
  71. package/dist/mcp/builtin/globals/updateTool.js +21 -19
  72. package/dist/mcp/builtin/globals/updateTool.js.map +1 -1
  73. package/dist/mcp/builtin/validateEntityData.d.ts +14 -0
  74. package/dist/mcp/builtin/validateEntityData.d.ts.map +1 -0
  75. package/dist/mcp/builtin/validateEntityData.js +82 -0
  76. package/dist/mcp/builtin/validateEntityData.js.map +1 -0
  77. package/dist/mcp/builtinTools.d.ts +84 -16
  78. package/dist/mcp/builtinTools.d.ts.map +1 -1
  79. package/dist/mcp/builtinTools.js +54 -11
  80. package/dist/mcp/builtinTools.js.map +1 -1
  81. package/dist/mcp/sanitizeMCPConfig.d.ts.map +1 -1
  82. package/dist/mcp/sanitizeMCPConfig.js +61 -40
  83. package/dist/mcp/sanitizeMCPConfig.js.map +1 -1
  84. package/dist/translations/index.d.ts +11 -0
  85. package/dist/translations/index.d.ts.map +1 -0
  86. package/dist/translations/index.js +92 -0
  87. package/dist/translations/index.js.map +1 -0
  88. package/dist/translations/languages/ar.d.ts +31 -0
  89. package/dist/translations/languages/ar.d.ts.map +1 -0
  90. package/dist/translations/languages/ar.js +34 -0
  91. package/dist/translations/languages/ar.js.map +1 -0
  92. package/dist/translations/languages/az.d.ts +31 -0
  93. package/dist/translations/languages/az.d.ts.map +1 -0
  94. package/dist/translations/languages/az.js +34 -0
  95. package/dist/translations/languages/az.js.map +1 -0
  96. package/dist/translations/languages/bg.d.ts +31 -0
  97. package/dist/translations/languages/bg.d.ts.map +1 -0
  98. package/dist/translations/languages/bg.js +34 -0
  99. package/dist/translations/languages/bg.js.map +1 -0
  100. package/dist/translations/languages/bnBd.d.ts +31 -0
  101. package/dist/translations/languages/bnBd.d.ts.map +1 -0
  102. package/dist/translations/languages/bnBd.js +34 -0
  103. package/dist/translations/languages/bnBd.js.map +1 -0
  104. package/dist/translations/languages/bnIn.d.ts +31 -0
  105. package/dist/translations/languages/bnIn.d.ts.map +1 -0
  106. package/dist/translations/languages/bnIn.js +34 -0
  107. package/dist/translations/languages/bnIn.js.map +1 -0
  108. package/dist/translations/languages/ca.d.ts +31 -0
  109. package/dist/translations/languages/ca.d.ts.map +1 -0
  110. package/dist/translations/languages/ca.js +34 -0
  111. package/dist/translations/languages/ca.js.map +1 -0
  112. package/dist/translations/languages/cs.d.ts +31 -0
  113. package/dist/translations/languages/cs.d.ts.map +1 -0
  114. package/dist/translations/languages/cs.js +34 -0
  115. package/dist/translations/languages/cs.js.map +1 -0
  116. package/dist/translations/languages/da.d.ts +31 -0
  117. package/dist/translations/languages/da.d.ts.map +1 -0
  118. package/dist/translations/languages/da.js +34 -0
  119. package/dist/translations/languages/da.js.map +1 -0
  120. package/dist/translations/languages/de.d.ts +31 -0
  121. package/dist/translations/languages/de.d.ts.map +1 -0
  122. package/dist/translations/languages/de.js +34 -0
  123. package/dist/translations/languages/de.js.map +1 -0
  124. package/dist/translations/languages/en.d.ts +31 -0
  125. package/dist/translations/languages/en.d.ts.map +1 -0
  126. package/dist/translations/languages/en.js +34 -0
  127. package/dist/translations/languages/en.js.map +1 -0
  128. package/dist/translations/languages/es.d.ts +31 -0
  129. package/dist/translations/languages/es.d.ts.map +1 -0
  130. package/dist/translations/languages/es.js +34 -0
  131. package/dist/translations/languages/es.js.map +1 -0
  132. package/dist/translations/languages/et.d.ts +31 -0
  133. package/dist/translations/languages/et.d.ts.map +1 -0
  134. package/dist/translations/languages/et.js +34 -0
  135. package/dist/translations/languages/et.js.map +1 -0
  136. package/dist/translations/languages/fa.d.ts +31 -0
  137. package/dist/translations/languages/fa.d.ts.map +1 -0
  138. package/dist/translations/languages/fa.js +34 -0
  139. package/dist/translations/languages/fa.js.map +1 -0
  140. package/dist/translations/languages/fr.d.ts +31 -0
  141. package/dist/translations/languages/fr.d.ts.map +1 -0
  142. package/dist/translations/languages/fr.js +34 -0
  143. package/dist/translations/languages/fr.js.map +1 -0
  144. package/dist/translations/languages/he.d.ts +31 -0
  145. package/dist/translations/languages/he.d.ts.map +1 -0
  146. package/dist/translations/languages/he.js +34 -0
  147. package/dist/translations/languages/he.js.map +1 -0
  148. package/dist/translations/languages/hr.d.ts +31 -0
  149. package/dist/translations/languages/hr.d.ts.map +1 -0
  150. package/dist/translations/languages/hr.js +34 -0
  151. package/dist/translations/languages/hr.js.map +1 -0
  152. package/dist/translations/languages/hu.d.ts +31 -0
  153. package/dist/translations/languages/hu.d.ts.map +1 -0
  154. package/dist/translations/languages/hu.js +34 -0
  155. package/dist/translations/languages/hu.js.map +1 -0
  156. package/dist/translations/languages/hy.d.ts +31 -0
  157. package/dist/translations/languages/hy.d.ts.map +1 -0
  158. package/dist/translations/languages/hy.js +34 -0
  159. package/dist/translations/languages/hy.js.map +1 -0
  160. package/dist/translations/languages/id.d.ts +31 -0
  161. package/dist/translations/languages/id.d.ts.map +1 -0
  162. package/dist/translations/languages/id.js +34 -0
  163. package/dist/translations/languages/id.js.map +1 -0
  164. package/dist/translations/languages/is.d.ts +31 -0
  165. package/dist/translations/languages/is.d.ts.map +1 -0
  166. package/dist/translations/languages/is.js +34 -0
  167. package/dist/translations/languages/is.js.map +1 -0
  168. package/dist/translations/languages/it.d.ts +31 -0
  169. package/dist/translations/languages/it.d.ts.map +1 -0
  170. package/dist/translations/languages/it.js +34 -0
  171. package/dist/translations/languages/it.js.map +1 -0
  172. package/dist/translations/languages/ja.d.ts +31 -0
  173. package/dist/translations/languages/ja.d.ts.map +1 -0
  174. package/dist/translations/languages/ja.js +34 -0
  175. package/dist/translations/languages/ja.js.map +1 -0
  176. package/dist/translations/languages/ko.d.ts +31 -0
  177. package/dist/translations/languages/ko.d.ts.map +1 -0
  178. package/dist/translations/languages/ko.js +34 -0
  179. package/dist/translations/languages/ko.js.map +1 -0
  180. package/dist/translations/languages/lt.d.ts +31 -0
  181. package/dist/translations/languages/lt.d.ts.map +1 -0
  182. package/dist/translations/languages/lt.js +34 -0
  183. package/dist/translations/languages/lt.js.map +1 -0
  184. package/dist/translations/languages/lv.d.ts +31 -0
  185. package/dist/translations/languages/lv.d.ts.map +1 -0
  186. package/dist/translations/languages/lv.js +34 -0
  187. package/dist/translations/languages/lv.js.map +1 -0
  188. package/dist/translations/languages/my.d.ts +31 -0
  189. package/dist/translations/languages/my.d.ts.map +1 -0
  190. package/dist/translations/languages/my.js +34 -0
  191. package/dist/translations/languages/my.js.map +1 -0
  192. package/dist/translations/languages/nb.d.ts +31 -0
  193. package/dist/translations/languages/nb.d.ts.map +1 -0
  194. package/dist/translations/languages/nb.js +34 -0
  195. package/dist/translations/languages/nb.js.map +1 -0
  196. package/dist/translations/languages/nl.d.ts +31 -0
  197. package/dist/translations/languages/nl.d.ts.map +1 -0
  198. package/dist/translations/languages/nl.js +34 -0
  199. package/dist/translations/languages/nl.js.map +1 -0
  200. package/dist/translations/languages/pl.d.ts +31 -0
  201. package/dist/translations/languages/pl.d.ts.map +1 -0
  202. package/dist/translations/languages/pl.js +34 -0
  203. package/dist/translations/languages/pl.js.map +1 -0
  204. package/dist/translations/languages/pt.d.ts +31 -0
  205. package/dist/translations/languages/pt.d.ts.map +1 -0
  206. package/dist/translations/languages/pt.js +34 -0
  207. package/dist/translations/languages/pt.js.map +1 -0
  208. package/dist/translations/languages/ro.d.ts +31 -0
  209. package/dist/translations/languages/ro.d.ts.map +1 -0
  210. package/dist/translations/languages/ro.js +34 -0
  211. package/dist/translations/languages/ro.js.map +1 -0
  212. package/dist/translations/languages/rs.d.ts +31 -0
  213. package/dist/translations/languages/rs.d.ts.map +1 -0
  214. package/dist/translations/languages/rs.js +34 -0
  215. package/dist/translations/languages/rs.js.map +1 -0
  216. package/dist/translations/languages/rsLatin.d.ts +31 -0
  217. package/dist/translations/languages/rsLatin.d.ts.map +1 -0
  218. package/dist/translations/languages/rsLatin.js +34 -0
  219. package/dist/translations/languages/rsLatin.js.map +1 -0
  220. package/dist/translations/languages/ru.d.ts +31 -0
  221. package/dist/translations/languages/ru.d.ts.map +1 -0
  222. package/dist/translations/languages/ru.js +34 -0
  223. package/dist/translations/languages/ru.js.map +1 -0
  224. package/dist/translations/languages/sk.d.ts +31 -0
  225. package/dist/translations/languages/sk.d.ts.map +1 -0
  226. package/dist/translations/languages/sk.js +34 -0
  227. package/dist/translations/languages/sk.js.map +1 -0
  228. package/dist/translations/languages/sl.d.ts +31 -0
  229. package/dist/translations/languages/sl.d.ts.map +1 -0
  230. package/dist/translations/languages/sl.js +34 -0
  231. package/dist/translations/languages/sl.js.map +1 -0
  232. package/dist/translations/languages/sv.d.ts +31 -0
  233. package/dist/translations/languages/sv.d.ts.map +1 -0
  234. package/dist/translations/languages/sv.js +34 -0
  235. package/dist/translations/languages/sv.js.map +1 -0
  236. package/dist/translations/languages/ta.d.ts +31 -0
  237. package/dist/translations/languages/ta.d.ts.map +1 -0
  238. package/dist/translations/languages/ta.js +34 -0
  239. package/dist/translations/languages/ta.js.map +1 -0
  240. package/dist/translations/languages/th.d.ts +31 -0
  241. package/dist/translations/languages/th.d.ts.map +1 -0
  242. package/dist/translations/languages/th.js +34 -0
  243. package/dist/translations/languages/th.js.map +1 -0
  244. package/dist/translations/languages/tr.d.ts +31 -0
  245. package/dist/translations/languages/tr.d.ts.map +1 -0
  246. package/dist/translations/languages/tr.js +34 -0
  247. package/dist/translations/languages/tr.js.map +1 -0
  248. package/dist/translations/languages/uk.d.ts +31 -0
  249. package/dist/translations/languages/uk.d.ts.map +1 -0
  250. package/dist/translations/languages/uk.js +34 -0
  251. package/dist/translations/languages/uk.js.map +1 -0
  252. package/dist/translations/languages/vi.d.ts +31 -0
  253. package/dist/translations/languages/vi.d.ts.map +1 -0
  254. package/dist/translations/languages/vi.js +34 -0
  255. package/dist/translations/languages/vi.js.map +1 -0
  256. package/dist/translations/languages/zh.d.ts +31 -0
  257. package/dist/translations/languages/zh.d.ts.map +1 -0
  258. package/dist/translations/languages/zh.js +34 -0
  259. package/dist/translations/languages/zh.js.map +1 -0
  260. package/dist/translations/languages/zhTw.d.ts +31 -0
  261. package/dist/translations/languages/zhTw.d.ts.map +1 -0
  262. package/dist/translations/languages/zhTw.js +34 -0
  263. package/dist/translations/languages/zhTw.js.map +1 -0
  264. package/dist/translations/types.d.ts +32 -0
  265. package/dist/translations/types.d.ts.map +1 -0
  266. package/dist/translations/types.js +3 -0
  267. package/dist/translations/types.js.map +1 -0
  268. package/dist/types.d.ts +22 -28
  269. package/dist/types.d.ts.map +1 -1
  270. package/dist/types.js.map +1 -1
  271. package/dist/utils/schemaConversion/getEntityInputSchema.d.ts +11 -0
  272. package/dist/utils/schemaConversion/getEntityInputSchema.d.ts.map +1 -0
  273. package/dist/utils/schemaConversion/getEntityInputSchema.js +34 -0
  274. package/dist/utils/schemaConversion/getEntityInputSchema.js.map +1 -0
  275. package/dist/utils/schemaConversion/sanitizeEntitySchema.d.ts +15 -0
  276. package/dist/utils/schemaConversion/sanitizeEntitySchema.d.ts.map +1 -0
  277. package/dist/utils/schemaConversion/sanitizeEntitySchema.js +464 -0
  278. package/dist/utils/schemaConversion/sanitizeEntitySchema.js.map +1 -0
  279. package/dist/utils/schemaConversion/sanitizeEntitySchema.spec.js +158 -0
  280. package/dist/utils/schemaConversion/sanitizeEntitySchema.spec.js.map +1 -0
  281. package/dist/utils/whereSchema.d.ts +9 -0
  282. package/dist/utils/whereSchema.d.ts.map +1 -0
  283. package/dist/utils/whereSchema.js +13 -0
  284. package/dist/utils/whereSchema.js.map +1 -0
  285. package/package.json +7 -6
  286. package/src/collection/getAccessField.ts +33 -13
  287. package/src/collection/index.ts +64 -22
  288. package/src/components/APIKeyField/index.client.tsx +73 -0
  289. package/src/components/APIKeyField/index.css +105 -0
  290. package/src/components/APIKeysEmptyState/index.client.tsx +36 -0
  291. package/src/components/AccessField/index.client.tsx +175 -220
  292. package/src/components/AccessField/index.css +50 -44
  293. package/src/components/SettingsMenu/index.client.tsx +34 -0
  294. package/src/endpoint/access.ts +17 -5
  295. package/src/exports/client.ts +3 -0
  296. package/src/index.ts +49 -3
  297. package/src/mcp/buildMcpServer.ts +123 -90
  298. package/src/mcp/builtin/collections/createTool.ts +46 -50
  299. package/src/mcp/builtin/collections/deleteTool.ts +9 -16
  300. package/src/mcp/builtin/collections/findTool.ts +7 -17
  301. package/src/mcp/builtin/collections/formatCollectionError.ts +84 -0
  302. package/src/mcp/builtin/collections/getCollectionSchemaTool.ts +28 -0
  303. package/src/mcp/builtin/collections/updateTool.ts +97 -91
  304. package/src/mcp/builtin/getConfigInfoTool.ts +44 -0
  305. package/src/mcp/builtin/globals/findTool.ts +1 -1
  306. package/src/mcp/builtin/globals/getGlobalSchemaTool.ts +28 -0
  307. package/src/mcp/builtin/globals/updateTool.ts +40 -43
  308. package/src/mcp/builtin/validateEntityData.ts +132 -0
  309. package/src/mcp/builtinTools.ts +52 -38
  310. package/src/mcp/sanitizeMCPConfig.ts +78 -57
  311. package/src/translations/index.ts +108 -0
  312. package/src/translations/languages/ar.ts +35 -0
  313. package/src/translations/languages/az.ts +35 -0
  314. package/src/translations/languages/bg.ts +35 -0
  315. package/src/translations/languages/bnBd.ts +35 -0
  316. package/src/translations/languages/bnIn.ts +35 -0
  317. package/src/translations/languages/ca.ts +35 -0
  318. package/src/translations/languages/cs.ts +35 -0
  319. package/src/translations/languages/da.ts +35 -0
  320. package/src/translations/languages/de.ts +35 -0
  321. package/src/translations/languages/en.ts +35 -0
  322. package/src/translations/languages/es.ts +35 -0
  323. package/src/translations/languages/et.ts +35 -0
  324. package/src/translations/languages/fa.ts +35 -0
  325. package/src/translations/languages/fr.ts +35 -0
  326. package/src/translations/languages/he.ts +35 -0
  327. package/src/translations/languages/hr.ts +35 -0
  328. package/src/translations/languages/hu.ts +35 -0
  329. package/src/translations/languages/hy.ts +35 -0
  330. package/src/translations/languages/id.ts +35 -0
  331. package/src/translations/languages/is.ts +35 -0
  332. package/src/translations/languages/it.ts +35 -0
  333. package/src/translations/languages/ja.ts +35 -0
  334. package/src/translations/languages/ko.ts +35 -0
  335. package/src/translations/languages/lt.ts +35 -0
  336. package/src/translations/languages/lv.ts +35 -0
  337. package/src/translations/languages/my.ts +35 -0
  338. package/src/translations/languages/nb.ts +35 -0
  339. package/src/translations/languages/nl.ts +35 -0
  340. package/src/translations/languages/pl.ts +35 -0
  341. package/src/translations/languages/pt.ts +35 -0
  342. package/src/translations/languages/ro.ts +35 -0
  343. package/src/translations/languages/rs.ts +35 -0
  344. package/src/translations/languages/rsLatin.ts +35 -0
  345. package/src/translations/languages/ru.ts +35 -0
  346. package/src/translations/languages/sk.ts +35 -0
  347. package/src/translations/languages/sl.ts +35 -0
  348. package/src/translations/languages/sv.ts +35 -0
  349. package/src/translations/languages/ta.ts +35 -0
  350. package/src/translations/languages/th.ts +35 -0
  351. package/src/translations/languages/tr.ts +35 -0
  352. package/src/translations/languages/uk.ts +35 -0
  353. package/src/translations/languages/vi.ts +35 -0
  354. package/src/translations/languages/zh.ts +35 -0
  355. package/src/translations/languages/zhTw.ts +35 -0
  356. package/src/translations/types.ts +34 -0
  357. package/src/types.ts +30 -30
  358. package/src/utils/schemaConversion/getEntityInputSchema.ts +78 -0
  359. package/src/utils/schemaConversion/sanitizeEntitySchema.spec.ts +103 -0
  360. package/src/utils/schemaConversion/sanitizeEntitySchema.ts +529 -0
  361. package/src/utils/whereSchema.ts +24 -0
  362. package/dist/utils/schemaConversion/prepareCollectionSchema.d.ts +0 -7
  363. package/dist/utils/schemaConversion/prepareCollectionSchema.d.ts.map +0 -1
  364. package/dist/utils/schemaConversion/prepareCollectionSchema.js +0 -37
  365. package/dist/utils/schemaConversion/prepareCollectionSchema.js.map +0 -1
  366. package/dist/utils/schemaConversion/sanitizeJsonSchema.d.ts +0 -13
  367. package/dist/utils/schemaConversion/sanitizeJsonSchema.d.ts.map +0 -1
  368. package/dist/utils/schemaConversion/sanitizeJsonSchema.js +0 -56
  369. package/dist/utils/schemaConversion/sanitizeJsonSchema.js.map +0 -1
  370. package/dist/utils/schemaConversion/simplifyRelationshipFields.d.ts +0 -20
  371. package/dist/utils/schemaConversion/simplifyRelationshipFields.d.ts.map +0 -1
  372. package/dist/utils/schemaConversion/simplifyRelationshipFields.js +0 -56
  373. package/dist/utils/schemaConversion/simplifyRelationshipFields.js.map +0 -1
  374. package/dist/utils/schemaConversion/transformPointFields.d.ts +0 -3
  375. package/dist/utils/schemaConversion/transformPointFields.d.ts.map +0 -1
  376. package/dist/utils/schemaConversion/transformPointFields.js +0 -57
  377. package/dist/utils/schemaConversion/transformPointFields.js.map +0 -1
  378. package/src/utils/schemaConversion/prepareCollectionSchema.ts +0 -39
  379. package/src/utils/schemaConversion/sanitizeJsonSchema.ts +0 -62
  380. package/src/utils/schemaConversion/simplifyRelationshipFields.ts +0 -70
  381. package/src/utils/schemaConversion/transformPointFields.ts +0 -56
@@ -3,32 +3,22 @@
3
3
  display: flex;
4
4
  flex-direction: column;
5
5
  gap: var(--base);
6
+ /* Breathing room below the API-key section's divider - the fields
7
+ container itself adds no gap between these two fields. */
8
+ padding-block-start: var(--spacer-4);
9
+ /* This custom field renders straight into `render-fields` (no `.field-type`
10
+ wrapper), so it must carry the standard inter-field margin itself -
11
+ otherwise the next field (e.g. an overrideApiKeyCollection field) butts
12
+ against the last card. */
13
+ margin-block-end: var(--spacer-3);
6
14
  }
7
15
 
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 {
16
+ .mcp-access-field__header {
27
17
  display: flex;
28
18
  flex-direction: column;
29
19
  }
30
20
 
31
- .mcp-access-field__section-header h4 {
21
+ .mcp-access-field__header h4 {
32
22
  margin: 0;
33
23
  color: var(--color-text);
34
24
  font-family: var(--text-heading-small-font-family);
@@ -38,7 +28,7 @@
38
28
  letter-spacing: var(--text-heading-small-letter-spacing);
39
29
  }
40
30
 
41
- .mcp-access-field__section-header p {
31
+ .mcp-access-field__header p {
42
32
  margin: 0;
43
33
  color: var(--color-text-secondary);
44
34
  font-family: var(--text-body-medium-font-family);
@@ -48,38 +38,46 @@
48
38
  letter-spacing: var(--text-body-medium-letter-spacing);
49
39
  }
50
40
 
51
- .mcp-access-field__group {
52
- margin-block-end: calc(var(--base) / 2);
41
+ .mcp-access-field__tabbed-content {
42
+ display: flex;
43
+ flex-direction: column;
53
44
  }
54
45
 
55
- .mcp-access-field__group-label {
56
- font-weight: 600;
46
+ .mcp-access-field__cards {
47
+ display: flex;
48
+ flex-direction: column;
49
+ gap: calc(var(--base) / 2);
57
50
  }
58
51
 
59
- .mcp-access-field__group-actions {
60
- display: flex;
61
- align-items: center;
62
- gap: calc(var(--base) / 6);
52
+ /* The collapsible header is pointer-events: none so clicks reach the toggle
53
+ overlay; re-enable events on the checkbox and lift it above the toggle. */
54
+ .mcp-access-field__card-checkbox {
55
+ position: relative;
56
+ z-index: 1;
57
+ display: inline-flex;
58
+ pointer-events: auto;
63
59
  }
64
60
 
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;
61
+ .mcp-access-field__leaf-group {
62
+ padding-block: calc(var(--base) / 2);
63
+ border-block-end: 1px solid var(--theme-elevation-100);
64
+ }
65
+
66
+ .mcp-access-field__leaf-group:first-child {
67
+ padding-block-start: 0;
73
68
  }
74
69
 
75
- .mcp-access-field__action:hover {
76
- color: var(--theme-text);
77
- text-decoration: underline;
70
+ .mcp-access-field__leaf-group:last-child {
71
+ border-block-end: none;
72
+ padding-block-end: 0;
78
73
  }
79
74
 
80
- .mcp-access-field__action-sep {
81
- color: var(--theme-elevation-300);
82
- font-size: 0.75rem;
75
+ .mcp-access-field__leaf-group-label {
76
+ margin: 0 0 calc(var(--base) / 2);
77
+ color: var(--color-text-secondary);
78
+ font-family: var(--text-body-medium-font-family);
79
+ font-size: var(--text-body-medium-font-size);
80
+ line-height: var(--text-body-medium-line-height);
83
81
  }
84
82
 
85
83
  .mcp-access-field__list {
@@ -88,6 +86,14 @@
88
86
  padding: 0;
89
87
  display: flex;
90
88
  flex-direction: column;
91
- gap: calc(var(--base) / 3);
89
+ gap: calc(var(--base) / 2);
90
+ }
91
+
92
+ .mcp-access-field__leaf-description {
93
+ margin: calc(var(--base) / 6) 0 0;
94
+ color: var(--color-text-secondary);
95
+ font-family: var(--text-body-medium-font-family);
96
+ font-size: var(--text-body-medium-font-size);
97
+ line-height: var(--text-body-medium-line-height);
92
98
  }
93
99
  }
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ /**
3
+ * Entry in the user menu's Settings sub-popup linking to the API keys
4
+ * collection. The collection is excluded from the main nav
5
+ * (`admin.group: false`) and managed from here instead.
6
+ */
7
+ export declare const MCPSettingsMenu: React.FC;
8
+ //# sourceMappingURL=index.client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.client.d.ts","sourceRoot":"","sources":["../../../src/components/SettingsMenu/index.client.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,MAAM,OAAO,CAAA;AAOzB;;;;GAIG;AACH,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAiBnC,CAAA"}
@@ -0,0 +1,29 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { PopupList, useConfig, useTranslation } from '@payloadcms/ui';
4
+ import { formatAdminURL } from 'payload/shared';
5
+ import React from 'react';
6
+ /**
7
+ * Entry in the user menu's Settings sub-popup linking to the API keys
8
+ * collection. The collection is excluded from the main nav
9
+ * (`admin.group: false`) and managed from here instead.
10
+ */ export const MCPSettingsMenu = ()=>{
11
+ const { config } = useConfig();
12
+ const { t } = useTranslation();
13
+ return /*#__PURE__*/ _jsxs(PopupList.MenuItem, {
14
+ children: [
15
+ /*#__PURE__*/ _jsx(PopupList.GroupLabel, {
16
+ label: t('plugin-mcp:mcp')
17
+ }),
18
+ /*#__PURE__*/ _jsx(PopupList.Button, {
19
+ href: formatAdminURL({
20
+ adminRoute: config.routes.admin,
21
+ path: '/collections/payload-mcp-api-keys'
22
+ }),
23
+ children: t('plugin-mcp:manageAPIKeys')
24
+ })
25
+ ]
26
+ });
27
+ };
28
+
29
+ //# sourceMappingURL=index.client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/SettingsMenu/index.client.tsx"],"sourcesContent":["'use client'\n\nimport { PopupList, useConfig, useTranslation } from '@payloadcms/ui'\nimport { formatAdminURL } from 'payload/shared'\nimport React from 'react'\n\nimport type {\n PluginMCPTranslationKeys,\n PluginMCPTranslations,\n} from '../../translations/index.js'\n\n/**\n * Entry in the user menu's Settings sub-popup linking to the API keys\n * collection. The collection is excluded from the main nav\n * (`admin.group: false`) and managed from here instead.\n */\nexport const MCPSettingsMenu: React.FC = () => {\n const { config } = useConfig()\n const { t } = useTranslation<PluginMCPTranslations, PluginMCPTranslationKeys>()\n\n return (\n <PopupList.MenuItem>\n <PopupList.GroupLabel label={t('plugin-mcp:mcp')} />\n <PopupList.Button\n href={formatAdminURL({\n adminRoute: config.routes.admin,\n path: '/collections/payload-mcp-api-keys',\n })}\n >\n {t('plugin-mcp:manageAPIKeys')}\n </PopupList.Button>\n </PopupList.MenuItem>\n )\n}\n"],"names":["PopupList","useConfig","useTranslation","formatAdminURL","React","MCPSettingsMenu","config","t","MenuItem","GroupLabel","label","Button","href","adminRoute","routes","admin","path"],"mappings":"AAAA;;AAEA,SAASA,SAAS,EAAEC,SAAS,EAAEC,cAAc,QAAQ,iBAAgB;AACrE,SAASC,cAAc,QAAQ,iBAAgB;AAC/C,OAAOC,WAAW,QAAO;AAOzB;;;;CAIC,GACD,OAAO,MAAMC,kBAA4B;IACvC,MAAM,EAAEC,MAAM,EAAE,GAAGL;IACnB,MAAM,EAAEM,CAAC,EAAE,GAAGL;IAEd,qBACE,MAACF,UAAUQ,QAAQ;;0BACjB,KAACR,UAAUS,UAAU;gBAACC,OAAOH,EAAE;;0BAC/B,KAACP,UAAUW,MAAM;gBACfC,MAAMT,eAAe;oBACnBU,YAAYP,OAAOQ,MAAM,CAACC,KAAK;oBAC/BC,MAAM;gBACR;0BAECT,EAAE;;;;AAIX,EAAC"}
@@ -18,15 +18,15 @@ import { getPluginConfig } from '../utils/getPluginConfig.js';
18
18
  items: pluginConfig.items.filter((item)=>{
19
19
  switch(item.type){
20
20
  case 'collectionTool':
21
- return apiKeyDoc.access.collections?.[item.collectionSlug]?.[item.key] !== false;
21
+ return apiKeyDoc.access.collections?.[item.collectionSlug]?.[item.configKey] !== false;
22
22
  case 'globalTool':
23
- return apiKeyDoc.access.globals?.[item.globalSlug]?.[item.key] !== false;
23
+ return apiKeyDoc.access.globals?.[item.globalSlug]?.[item.configKey] !== false;
24
24
  case 'prompt':
25
- return apiKeyDoc.access.prompts?.[item.key] !== false;
25
+ return apiKeyDoc.access.prompts?.[item.configKey] !== false;
26
26
  case 'resource':
27
- return apiKeyDoc.access.resources?.[item.key] !== false;
27
+ return apiKeyDoc.access.resources?.[item.configKey] !== false;
28
28
  case 'tool':
29
- return apiKeyDoc.access.tools?.[item.key] !== false;
29
+ return apiKeyDoc.access.tools?.[item.configKey] !== false;
30
30
  }
31
31
  }),
32
32
  overrideAccess: typeof apiKeyDoc.overrideAccess === 'boolean' ? apiKeyDoc.overrideAccess : false,
@@ -93,6 +93,22 @@ const getAPIKeyDoc = async ({ logger, overrideApiKey, pluginConfig, req })=>{
93
93
  if (!user) {
94
94
  throw new UnauthorizedError();
95
95
  }
96
+ try {
97
+ await req.payload.db.updateOne({
98
+ id: doc.id,
99
+ collection: 'payload-mcp-api-keys',
100
+ data: {
101
+ lastUsed: new Date().toISOString()
102
+ },
103
+ req,
104
+ returning: false
105
+ });
106
+ } catch (err) {
107
+ logger.warn({
108
+ err,
109
+ msg: 'Failed to update MCP API key last-used timestamp'
110
+ });
111
+ }
96
112
  return {
97
113
  ...doc,
98
114
  user: {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/endpoint/access.ts"],"sourcesContent":["import type { DefaultDocumentIDType, PayloadRequest, TypedUser } from 'payload'\n\nimport crypto from 'crypto'\nimport { UnauthorizedError } from 'payload'\n\nimport type { AuthorizedMCP, MCPAPIKeysDoc } from '../types.js'\n\nimport { getLogger } from '../utils/getLogger.js'\nimport { getPluginConfig } from '../utils/getPluginConfig.js'\n\n/**\n * Resolves the API key (or dev-mode session) and returns the items the caller\n * may use. Denied items are dropped from the array.\n */\nexport const getAuthorizedMCP: (args: { req: PayloadRequest }) => Promise<AuthorizedMCP> = async ({\n req,\n}) => {\n const logger = getLogger({ payload: req.payload })\n const pluginConfig = getPluginConfig({ config: req.payload.config })\n\n const authHeader = req.headers.get('Authorization')\n const hasBearerToken = authHeader?.startsWith('Bearer ')\n\n const buildAuthorized = (apiKeyDoc: MCPAPIKeysDoc): AuthorizedMCP => ({\n items: pluginConfig.items.filter((item) => {\n switch (item.type) {\n case 'collectionTool':\n return apiKeyDoc.access.collections?.[item.collectionSlug]?.[item.key] !== false\n case 'globalTool':\n return apiKeyDoc.access.globals?.[item.globalSlug]?.[item.key] !== false\n case 'prompt':\n return apiKeyDoc.access.prompts?.[item.key] !== false\n case 'resource':\n return apiKeyDoc.access.resources?.[item.key] !== false\n case 'tool':\n return apiKeyDoc.access.tools?.[item.key] !== false\n }\n }),\n overrideAccess:\n typeof apiKeyDoc.overrideAccess === 'boolean' ? apiKeyDoc.overrideAccess : false,\n user: apiKeyDoc.user,\n })\n\n if (pluginConfig.overrideAuth) {\n return await pluginConfig.overrideAuth({\n getAPIKeyDoc: (overrideApiKey) => getAPIKeyDoc({ logger, overrideApiKey, pluginConfig, req }),\n getAuthorizedMCP: ({ apiKeyDoc }) => buildAuthorized(apiKeyDoc),\n pluginConfig,\n req,\n })\n }\n\n if (process.env.NODE_ENV === 'development' && !hasBearerToken) {\n logger.info('Dev mode: skipping API key check, using session user')\n return buildAuthorized({\n id: -1,\n access: {},\n overrideAccess: true,\n user: req.user ?? null,\n })\n }\n\n return buildAuthorized(await getAPIKeyDoc({ logger, pluginConfig, req }))\n}\n\nconst getAPIKeyDoc = async ({\n logger,\n overrideApiKey,\n pluginConfig,\n req,\n}: {\n logger: ReturnType<typeof getLogger>\n overrideApiKey?: string\n pluginConfig: ReturnType<typeof getPluginConfig>\n req: PayloadRequest\n}): Promise<MCPAPIKeysDoc> => {\n const authHeader = req.headers.get('Authorization')\n const hasBearerToken = authHeader?.startsWith('Bearer ')\n\n const apiKey =\n overrideApiKey ?? (hasBearerToken ? authHeader?.replace('Bearer ', '').trim() || null : null)\n\n if (!apiKey) {\n throw new UnauthorizedError()\n }\n\n const sha256APIKeyIndex = crypto\n .createHmac('sha256', req.payload.secret)\n .update(apiKey)\n .digest('hex')\n\n const doc = await req.payload.db.findOne<MCPAPIKeysDoc>({\n collection: 'payload-mcp-api-keys',\n req,\n where: {\n apiKeyIndex: { equals: sha256APIKeyIndex },\n },\n })\n\n if (!doc || !doc.user) {\n throw new UnauthorizedError()\n }\n\n logger.info('API Key is valid')\n\n const userRef = doc.user\n const userID =\n typeof userRef === 'object' && userRef !== null && 'id' in userRef\n ? userRef.id\n : (userRef as unknown as DefaultDocumentIDType)\n\n const user = (await req.payload.findByID({\n id: userID,\n collection: pluginConfig.userCollection,\n depth: 0,\n disableErrors: true,\n req,\n })) as null | TypedUser\n\n if (!user) {\n throw new UnauthorizedError()\n }\n\n return {\n ...doc,\n user: {\n ...user,\n _strategy: 'mcp-api-key' as const,\n collection: pluginConfig.userCollection,\n },\n }\n}\n"],"names":["crypto","UnauthorizedError","getLogger","getPluginConfig","getAuthorizedMCP","req","logger","payload","pluginConfig","config","authHeader","headers","get","hasBearerToken","startsWith","buildAuthorized","apiKeyDoc","items","filter","item","type","access","collections","collectionSlug","key","globals","globalSlug","prompts","resources","tools","overrideAccess","user","overrideAuth","getAPIKeyDoc","overrideApiKey","process","env","NODE_ENV","info","id","apiKey","replace","trim","sha256APIKeyIndex","createHmac","secret","update","digest","doc","db","findOne","collection","where","apiKeyIndex","equals","userRef","userID","findByID","userCollection","depth","disableErrors","_strategy"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/endpoint/access.ts"],"sourcesContent":["import type { DefaultDocumentIDType, PayloadRequest, TypedUser } from 'payload'\n\nimport crypto from 'crypto'\nimport { UnauthorizedError } from 'payload'\n\nimport type { AuthorizedMCP, MCPAPIKeysDoc } from '../types.js'\n\nimport { getLogger } from '../utils/getLogger.js'\nimport { getPluginConfig } from '../utils/getPluginConfig.js'\n\n/**\n * Resolves the API key (or dev-mode session) and returns the items the caller\n * may use. Denied items are dropped from the array.\n */\nexport const getAuthorizedMCP: (args: { req: PayloadRequest }) => Promise<AuthorizedMCP> = async ({\n req,\n}) => {\n const logger = getLogger({ payload: req.payload })\n const pluginConfig = getPluginConfig({ config: req.payload.config })\n\n const authHeader = req.headers.get('Authorization')\n const hasBearerToken = authHeader?.startsWith('Bearer ')\n\n const buildAuthorized = (apiKeyDoc: MCPAPIKeysDoc): AuthorizedMCP => ({\n items: pluginConfig.items.filter((item) => {\n switch (item.type) {\n case 'collectionTool':\n return apiKeyDoc.access.collections?.[item.collectionSlug]?.[item.configKey] !== false\n case 'globalTool':\n return apiKeyDoc.access.globals?.[item.globalSlug]?.[item.configKey] !== false\n case 'prompt':\n return apiKeyDoc.access.prompts?.[item.configKey] !== false\n case 'resource':\n return apiKeyDoc.access.resources?.[item.configKey] !== false\n case 'tool':\n return apiKeyDoc.access.tools?.[item.configKey] !== false\n }\n }),\n overrideAccess:\n typeof apiKeyDoc.overrideAccess === 'boolean' ? apiKeyDoc.overrideAccess : false,\n user: apiKeyDoc.user,\n })\n\n if (pluginConfig.overrideAuth) {\n return await pluginConfig.overrideAuth({\n getAPIKeyDoc: (overrideApiKey) => getAPIKeyDoc({ logger, overrideApiKey, pluginConfig, req }),\n getAuthorizedMCP: ({ apiKeyDoc }) => buildAuthorized(apiKeyDoc),\n pluginConfig,\n req,\n })\n }\n\n if (process.env.NODE_ENV === 'development' && !hasBearerToken) {\n logger.info('Dev mode: skipping API key check, using session user')\n return buildAuthorized({\n id: -1,\n access: {},\n overrideAccess: true,\n user: req.user ?? null,\n })\n }\n\n return buildAuthorized(await getAPIKeyDoc({ logger, pluginConfig, req }))\n}\n\nconst getAPIKeyDoc = async ({\n logger,\n overrideApiKey,\n pluginConfig,\n req,\n}: {\n logger: ReturnType<typeof getLogger>\n overrideApiKey?: string\n pluginConfig: ReturnType<typeof getPluginConfig>\n req: PayloadRequest\n}): Promise<MCPAPIKeysDoc> => {\n const authHeader = req.headers.get('Authorization')\n const hasBearerToken = authHeader?.startsWith('Bearer ')\n\n const apiKey =\n overrideApiKey ?? (hasBearerToken ? authHeader?.replace('Bearer ', '').trim() || null : null)\n\n if (!apiKey) {\n throw new UnauthorizedError()\n }\n\n const sha256APIKeyIndex = crypto\n .createHmac('sha256', req.payload.secret)\n .update(apiKey)\n .digest('hex')\n\n const doc = await req.payload.db.findOne<MCPAPIKeysDoc>({\n collection: 'payload-mcp-api-keys',\n req,\n where: {\n apiKeyIndex: { equals: sha256APIKeyIndex },\n },\n })\n\n if (!doc || !doc.user) {\n throw new UnauthorizedError()\n }\n\n logger.info('API Key is valid')\n\n const userRef = doc.user\n const userID =\n typeof userRef === 'object' && userRef !== null && 'id' in userRef\n ? userRef.id\n : (userRef as unknown as DefaultDocumentIDType)\n\n const user = (await req.payload.findByID({\n id: userID,\n collection: pluginConfig.userCollection,\n depth: 0,\n disableErrors: true,\n req,\n })) as null | TypedUser\n\n if (!user) {\n throw new UnauthorizedError()\n }\n\n try {\n await req.payload.db.updateOne({\n id: doc.id,\n collection: 'payload-mcp-api-keys',\n data: { lastUsed: new Date().toISOString() },\n req,\n returning: false,\n })\n } catch (err) {\n logger.warn({ err, msg: 'Failed to update MCP API key last-used timestamp' })\n }\n\n return {\n ...doc,\n user: {\n ...user,\n _strategy: 'mcp-api-key' as const,\n collection: pluginConfig.userCollection,\n },\n }\n}\n"],"names":["crypto","UnauthorizedError","getLogger","getPluginConfig","getAuthorizedMCP","req","logger","payload","pluginConfig","config","authHeader","headers","get","hasBearerToken","startsWith","buildAuthorized","apiKeyDoc","items","filter","item","type","access","collections","collectionSlug","configKey","globals","globalSlug","prompts","resources","tools","overrideAccess","user","overrideAuth","getAPIKeyDoc","overrideApiKey","process","env","NODE_ENV","info","id","apiKey","replace","trim","sha256APIKeyIndex","createHmac","secret","update","digest","doc","db","findOne","collection","where","apiKeyIndex","equals","userRef","userID","findByID","userCollection","depth","disableErrors","updateOne","data","lastUsed","Date","toISOString","returning","err","warn","msg","_strategy"],"mappings":"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"}
@@ -1,2 +1,5 @@
1
1
  export { AccessField } from '../components/AccessField/index.client.js';
2
+ export { APIKeyField } from '../components/APIKeyField/index.client.js';
3
+ export { APIKeysEmptyState } from '../components/APIKeysEmptyState/index.client.js';
4
+ export { MCPSettingsMenu } from '../components/SettingsMenu/index.client.js';
2
5
  //# sourceMappingURL=client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/exports/client.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,2CAA2C,CAAA"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/exports/client.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,2CAA2C,CAAA;AACvE,OAAO,EAAE,WAAW,EAAE,MAAM,2CAA2C,CAAA;AACvE,OAAO,EAAE,iBAAiB,EAAE,MAAM,iDAAiD,CAAA;AACnF,OAAO,EAAE,eAAe,EAAE,MAAM,4CAA4C,CAAA"}
@@ -1,4 +1,7 @@
1
1
  'use client';
2
2
  export { AccessField } from '../components/AccessField/index.client.js';
3
+ export { APIKeyField } from '../components/APIKeyField/index.client.js';
4
+ export { APIKeysEmptyState } from '../components/APIKeysEmptyState/index.client.js';
5
+ export { MCPSettingsMenu } from '../components/SettingsMenu/index.client.js';
3
6
 
4
7
  //# sourceMappingURL=client.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/exports/client.ts"],"sourcesContent":["'use client'\nexport { AccessField } from '../components/AccessField/index.client.js'\n"],"names":["AccessField"],"mappings":"AAAA;AACA,SAASA,WAAW,QAAQ,4CAA2C"}
1
+ {"version":3,"sources":["../../src/exports/client.ts"],"sourcesContent":["'use client'\nexport { AccessField } from '../components/AccessField/index.client.js'\nexport { APIKeyField } from '../components/APIKeyField/index.client.js'\nexport { APIKeysEmptyState } from '../components/APIKeysEmptyState/index.client.js'\nexport { MCPSettingsMenu } from '../components/SettingsMenu/index.client.js'\n"],"names":["AccessField","APIKeyField","APIKeysEmptyState","MCPSettingsMenu"],"mappings":"AAAA;AACA,SAASA,WAAW,QAAQ,4CAA2C;AACvE,SAASC,WAAW,QAAQ,4CAA2C;AACvE,SAASC,iBAAiB,QAAQ,kDAAiD;AACnF,SAASC,eAAe,QAAQ,6CAA4C"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAA;AAM1F,OAAO,QAAQ,SAAS,CAAC;IACvB,UAAiB,cAAc;QAC7B,UAAU,EAAE,SAAS,GAAG,OAAO,GAAG,KAAK,GAAG,MAAM,CAAA;KACjD;IACD,UAAU,iBAAiB;QACzB,uFAAuF;QACvF,wBAAwB,EAAE,eAAe,CAAA;KAC1C;CACF;AAED,YAAY,EAAE,aAAa,EAAE,eAAe,EAAE,wBAAwB,EAAE,CAAA;AAExE,OAAO,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAElG,eAAO,MAAM,SAAS,wDAwCpB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAA;AAO1F,OAAO,QAAQ,SAAS,CAAC;IACvB,UAAiB,cAAc;QAC7B,UAAU,EAAE,SAAS,GAAG,OAAO,GAAG,KAAK,GAAG,MAAM,CAAA;KACjD;IACD,UAAU,iBAAiB;QACzB,uFAAuF;QACvF,wBAAwB,EAAE,eAAe,CAAA;KAC1C;CACF;AAED,YAAY,EAAE,aAAa,EAAE,eAAe,EAAE,wBAAwB,EAAE,CAAA;AAExE,OAAO,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAElG,eAAO,MAAM,SAAS,wDAkFpB,CAAA"}
package/dist/index.js CHANGED
@@ -2,14 +2,14 @@ import { defaultUserCollection, definePlugin } from 'payload';
2
2
  import { getAPIKeysCollection } from './collection/index.js';
3
3
  import { mcpEndpoint } from './endpoint/index.js';
4
4
  import { sanitizeMCPConfig } from './mcp/sanitizeMCPConfig.js';
5
+ import { translations } from './translations/index.js';
5
6
  export { defineCollectionTool, defineGlobalTool, definePrompt, defineTool } from './defineTool.js';
6
7
  export const mcpPlugin = definePlugin({
7
8
  slug: '@payloadcms/plugin-mcp',
8
9
  order: 10,
9
10
  plugin: ({ config, plugins, ...rawConfig })=>{
10
- // Our `payload-mcp-api-keys` is auth-enabled; if it'd be the only auth
11
- // collection, Payload's later sanitize would pick it as `admin.user`.
12
- // Pre-seed the default user collection to prevent that.
11
+ // If a project has no auth collection yet, add the default users collection
12
+ // so the relationship target and default `userCollection` exist.
13
13
  if (!config.admin?.user) {
14
14
  const firstCollectionWithAuth = (config.collections ?? []).find(({ auth })=>Boolean(auth));
15
15
  if (!firstCollectionWithAuth) {
@@ -31,6 +31,27 @@ export const mcpPlugin = definePlugin({
31
31
  (config.collections ??= []).push(getAPIKeysCollection({
32
32
  pluginConfig
33
33
  }));
34
+ if (!config.i18n) {
35
+ config.i18n = {};
36
+ }
37
+ if (!config.i18n.translations) {
38
+ config.i18n.translations = {};
39
+ }
40
+ const supportedLanguageKeys = config.i18n.supportedLanguages ? Object.keys(config.i18n.supportedLanguages) : [
41
+ 'en'
42
+ ];
43
+ for (const lang of supportedLanguageKeys){
44
+ const pluginEntry = translations[lang];
45
+ if (!pluginEntry) {
46
+ continue;
47
+ }
48
+ const typedLocale = lang;
49
+ const existing = config.i18n.translations[typedLocale] ?? {};
50
+ config.i18n.translations[typedLocale] = {
51
+ ...existing,
52
+ 'plugin-mcp': pluginEntry.translations['plugin-mcp']
53
+ };
54
+ }
34
55
  // Keep the API-keys collection registered even when disabled, so DB schema
35
56
  // and generated types don't drift between enabled/disabled environments.
36
57
  if (pluginConfig.disabled) {
@@ -38,6 +59,16 @@ export const mcpPlugin = definePlugin({
38
59
  }
39
60
  return {
40
61
  ...config,
62
+ admin: {
63
+ ...config.admin,
64
+ components: {
65
+ ...config.admin?.components,
66
+ userMenuSettingsItems: [
67
+ ...config.admin?.components?.userMenuSettingsItems ?? [],
68
+ '@payloadcms/plugin-mcp/client#MCPSettingsMenu'
69
+ ]
70
+ }
71
+ },
41
72
  endpoints: [
42
73
  ...config.endpoints ?? [],
43
74
  // Payload prefixes /api, so the full path is /api/mcp.
@@ -45,6 +76,18 @@ export const mcpPlugin = definePlugin({
45
76
  handler: mcpEndpoint,
46
77
  method: 'post',
47
78
  path: '/mcp'
79
+ },
80
+ // Streamable HTTP's optional server=>client GET stream. We don't offer
81
+ // one, so answer 405 per spec-— clients then skip it cleanly
82
+ {
83
+ handler: ()=>new Response(null, {
84
+ headers: {
85
+ Allow: 'POST'
86
+ },
87
+ status: 405
88
+ }),
89
+ method: 'get',
90
+ path: '/mcp'
48
91
  }
49
92
  ]
50
93
  };
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { defaultUserCollection, definePlugin } from 'payload'\n\nimport type { AuthorizedMCP, MCPPluginConfig, SanitizedMCPPluginConfig } from './types.js'\n\nimport { getAPIKeysCollection } from './collection/index.js'\nimport { mcpEndpoint } from './endpoint/index.js'\nimport { sanitizeMCPConfig } from './mcp/sanitizeMCPConfig.js'\n\ndeclare module 'payload' {\n export interface PayloadRequest {\n payloadAPI: 'GraphQL' | 'local' | 'MCP' | 'REST'\n }\n interface RegisteredPlugins {\n /** After the plugin's `plugin` callback runs, `options` holds the sanitized config. */\n '@payloadcms/plugin-mcp': MCPPluginConfig\n }\n}\n\nexport type { AuthorizedMCP, MCPPluginConfig, SanitizedMCPPluginConfig }\n\nexport { defineCollectionTool, defineGlobalTool, definePrompt, defineTool } from './defineTool.js'\n\nexport const mcpPlugin = definePlugin<MCPPluginConfig>({\n slug: '@payloadcms/plugin-mcp',\n order: 10,\n plugin: ({ config, plugins, ...rawConfig }) => {\n // Our `payload-mcp-api-keys` is auth-enabled; if it'd be the only auth\n // collection, Payload's later sanitize would pick it as `admin.user`.\n // Pre-seed the default user collection to prevent that.\n if (!config.admin?.user) {\n const firstCollectionWithAuth = (config.collections ?? []).find(({ auth }) => Boolean(auth))\n if (!firstCollectionWithAuth) {\n ;(config.collections ??= []).push(defaultUserCollection)\n }\n }\n\n const pluginConfig = sanitizeMCPConfig({ config, pluginConfig: rawConfig })\n\n // Stash the sanitized config on plugin options so `getPluginConfig()` reads it.\n const registered = plugins['@payloadcms/plugin-mcp']\n if (registered) {\n // @ts-expect-error\n registered.sanitizedOptions = pluginConfig as unknown as typeof registered.options\n }\n\n ;(config.collections ??= []).push(getAPIKeysCollection({ pluginConfig }))\n\n // Keep the API-keys collection registered even when disabled, so DB schema\n // and generated types don't drift between enabled/disabled environments.\n if (pluginConfig.disabled) {\n return config\n }\n\n return {\n ...config,\n endpoints: [\n ...(config.endpoints ?? []),\n // Payload prefixes /api, so the full path is /api/mcp.\n { handler: mcpEndpoint, method: 'post', path: '/mcp' },\n ],\n }\n },\n})\n"],"names":["defaultUserCollection","definePlugin","getAPIKeysCollection","mcpEndpoint","sanitizeMCPConfig","defineCollectionTool","defineGlobalTool","definePrompt","defineTool","mcpPlugin","slug","order","plugin","config","plugins","rawConfig","admin","user","firstCollectionWithAuth","collections","find","auth","Boolean","push","pluginConfig","registered","sanitizedOptions","disabled","endpoints","handler","method","path"],"mappings":"AAAA,SAASA,qBAAqB,EAAEC,YAAY,QAAQ,UAAS;AAI7D,SAASC,oBAAoB,QAAQ,wBAAuB;AAC5D,SAASC,WAAW,QAAQ,sBAAqB;AACjD,SAASC,iBAAiB,QAAQ,6BAA4B;AAc9D,SAASC,oBAAoB,EAAEC,gBAAgB,EAAEC,YAAY,EAAEC,UAAU,QAAQ,kBAAiB;AAElG,OAAO,MAAMC,YAAYR,aAA8B;IACrDS,MAAM;IACNC,OAAO;IACPC,QAAQ,CAAC,EAAEC,MAAM,EAAEC,OAAO,EAAE,GAAGC,WAAW;QACxC,uEAAuE;QACvE,sEAAsE;QACtE,wDAAwD;QACxD,IAAI,CAACF,OAAOG,KAAK,EAAEC,MAAM;YACvB,MAAMC,0BAA0B,AAACL,CAAAA,OAAOM,WAAW,IAAI,EAAE,AAAD,EAAGC,IAAI,CAAC,CAAC,EAAEC,IAAI,EAAE,GAAKC,QAAQD;YACtF,IAAI,CAACH,yBAAyB;;gBAC1BL,CAAAA,OAAOM,WAAW,KAAK,EAAE,AAAD,EAAGI,IAAI,CAACvB;YACpC;QACF;QAEA,MAAMwB,eAAepB,kBAAkB;YAAES;YAAQW,cAAcT;QAAU;QAEzE,gFAAgF;QAChF,MAAMU,aAAaX,OAAO,CAAC,yBAAyB;QACpD,IAAIW,YAAY;YACd,mBAAmB;YACnBA,WAAWC,gBAAgB,GAAGF;QAChC;;QAEEX,CAAAA,OAAOM,WAAW,KAAK,EAAE,AAAD,EAAGI,IAAI,CAACrB,qBAAqB;YAAEsB;QAAa;QAEtE,2EAA2E;QAC3E,yEAAyE;QACzE,IAAIA,aAAaG,QAAQ,EAAE;YACzB,OAAOd;QACT;QAEA,OAAO;YACL,GAAGA,MAAM;YACTe,WAAW;mBACLf,OAAOe,SAAS,IAAI,EAAE;gBAC1B,uDAAuD;gBACvD;oBAAEC,SAAS1B;oBAAa2B,QAAQ;oBAAQC,MAAM;gBAAO;aACtD;QACH;IACF;AACF,GAAE"}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { AcceptedLanguages } from '@payloadcms/translations'\n\nimport { defaultUserCollection, definePlugin } from 'payload'\n\nimport type { PluginDefaultTranslationsObject } from './translations/types.js'\nimport type { AuthorizedMCP, MCPPluginConfig, SanitizedMCPPluginConfig } from './types.js'\n\nimport { getAPIKeysCollection } from './collection/index.js'\nimport { mcpEndpoint } from './endpoint/index.js'\nimport { sanitizeMCPConfig } from './mcp/sanitizeMCPConfig.js'\nimport { translations } from './translations/index.js'\n\ndeclare module 'payload' {\n export interface PayloadRequest {\n payloadAPI: 'GraphQL' | 'local' | 'MCP' | 'REST'\n }\n interface RegisteredPlugins {\n /** After the plugin's `plugin` callback runs, `options` holds the sanitized config. */\n '@payloadcms/plugin-mcp': MCPPluginConfig\n }\n}\n\nexport type { AuthorizedMCP, MCPPluginConfig, SanitizedMCPPluginConfig }\n\nexport { defineCollectionTool, defineGlobalTool, definePrompt, defineTool } from './defineTool.js'\n\nexport const mcpPlugin = definePlugin<MCPPluginConfig>({\n slug: '@payloadcms/plugin-mcp',\n order: 10,\n plugin: ({ config, plugins, ...rawConfig }) => {\n // If a project has no auth collection yet, add the default users collection\n // so the relationship target and default `userCollection` exist.\n if (!config.admin?.user) {\n const firstCollectionWithAuth = (config.collections ?? []).find(({ auth }) => Boolean(auth))\n if (!firstCollectionWithAuth) {\n ;(config.collections ??= []).push(defaultUserCollection)\n }\n }\n\n const pluginConfig = sanitizeMCPConfig({ config, pluginConfig: rawConfig })\n\n // Stash the sanitized config on plugin options so `getPluginConfig()` reads it.\n const registered = plugins['@payloadcms/plugin-mcp']\n if (registered) {\n // @ts-expect-error\n registered.sanitizedOptions = pluginConfig as unknown as typeof registered.options\n }\n\n ;(config.collections ??= []).push(getAPIKeysCollection({ pluginConfig }))\n\n if (!config.i18n) {\n config.i18n = {}\n }\n\n if (!config.i18n.translations) {\n config.i18n.translations = {}\n }\n\n const supportedLanguageKeys = config.i18n.supportedLanguages\n ? Object.keys(config.i18n.supportedLanguages)\n : ['en']\n\n for (const lang of supportedLanguageKeys) {\n const pluginEntry = translations[lang as keyof typeof translations]\n if (!pluginEntry) {\n continue\n }\n\n const typedLocale = lang as AcceptedLanguages\n const existing = (config.i18n.translations[typedLocale] ?? {}) as Record<string, unknown>\n config.i18n.translations[typedLocale] = {\n ...existing,\n 'plugin-mcp': pluginEntry.translations['plugin-mcp'],\n } as PluginDefaultTranslationsObject\n }\n\n // Keep the API-keys collection registered even when disabled, so DB schema\n // and generated types don't drift between enabled/disabled environments.\n if (pluginConfig.disabled) {\n return config\n }\n\n return {\n ...config,\n admin: {\n ...config.admin,\n components: {\n ...config.admin?.components,\n userMenuSettingsItems: [\n ...(config.admin?.components?.userMenuSettingsItems ?? []),\n '@payloadcms/plugin-mcp/client#MCPSettingsMenu',\n ],\n },\n },\n endpoints: [\n ...(config.endpoints ?? []),\n // Payload prefixes /api, so the full path is /api/mcp.\n { handler: mcpEndpoint, method: 'post', path: '/mcp' },\n // Streamable HTTP's optional server=>client GET stream. We don't offer\n // one, so answer 405 per spec-— clients then skip it cleanly\n {\n handler: () => new Response(null, { headers: { Allow: 'POST' }, status: 405 }),\n method: 'get',\n path: '/mcp',\n },\n ],\n }\n },\n})\n"],"names":["defaultUserCollection","definePlugin","getAPIKeysCollection","mcpEndpoint","sanitizeMCPConfig","translations","defineCollectionTool","defineGlobalTool","definePrompt","defineTool","mcpPlugin","slug","order","plugin","config","plugins","rawConfig","admin","user","firstCollectionWithAuth","collections","find","auth","Boolean","push","pluginConfig","registered","sanitizedOptions","i18n","supportedLanguageKeys","supportedLanguages","Object","keys","lang","pluginEntry","typedLocale","existing","disabled","components","userMenuSettingsItems","endpoints","handler","method","path","Response","headers","Allow","status"],"mappings":"AAEA,SAASA,qBAAqB,EAAEC,YAAY,QAAQ,UAAS;AAK7D,SAASC,oBAAoB,QAAQ,wBAAuB;AAC5D,SAASC,WAAW,QAAQ,sBAAqB;AACjD,SAASC,iBAAiB,QAAQ,6BAA4B;AAC9D,SAASC,YAAY,QAAQ,0BAAyB;AActD,SAASC,oBAAoB,EAAEC,gBAAgB,EAAEC,YAAY,EAAEC,UAAU,QAAQ,kBAAiB;AAElG,OAAO,MAAMC,YAAYT,aAA8B;IACrDU,MAAM;IACNC,OAAO;IACPC,QAAQ,CAAC,EAAEC,MAAM,EAAEC,OAAO,EAAE,GAAGC,WAAW;QACxC,4EAA4E;QAC5E,iEAAiE;QACjE,IAAI,CAACF,OAAOG,KAAK,EAAEC,MAAM;YACvB,MAAMC,0BAA0B,AAACL,CAAAA,OAAOM,WAAW,IAAI,EAAE,AAAD,EAAGC,IAAI,CAAC,CAAC,EAAEC,IAAI,EAAE,GAAKC,QAAQD;YACtF,IAAI,CAACH,yBAAyB;;gBAC1BL,CAAAA,OAAOM,WAAW,KAAK,EAAE,AAAD,EAAGI,IAAI,CAACxB;YACpC;QACF;QAEA,MAAMyB,eAAerB,kBAAkB;YAAEU;YAAQW,cAAcT;QAAU;QAEzE,gFAAgF;QAChF,MAAMU,aAAaX,OAAO,CAAC,yBAAyB;QACpD,IAAIW,YAAY;YACd,mBAAmB;YACnBA,WAAWC,gBAAgB,GAAGF;QAChC;;QAEEX,CAAAA,OAAOM,WAAW,KAAK,EAAE,AAAD,EAAGI,IAAI,CAACtB,qBAAqB;YAAEuB;QAAa;QAEtE,IAAI,CAACX,OAAOc,IAAI,EAAE;YAChBd,OAAOc,IAAI,GAAG,CAAC;QACjB;QAEA,IAAI,CAACd,OAAOc,IAAI,CAACvB,YAAY,EAAE;YAC7BS,OAAOc,IAAI,CAACvB,YAAY,GAAG,CAAC;QAC9B;QAEA,MAAMwB,wBAAwBf,OAAOc,IAAI,CAACE,kBAAkB,GACxDC,OAAOC,IAAI,CAAClB,OAAOc,IAAI,CAACE,kBAAkB,IAC1C;YAAC;SAAK;QAEV,KAAK,MAAMG,QAAQJ,sBAAuB;YACxC,MAAMK,cAAc7B,YAAY,CAAC4B,KAAkC;YACnE,IAAI,CAACC,aAAa;gBAChB;YACF;YAEA,MAAMC,cAAcF;YACpB,MAAMG,WAAYtB,OAAOc,IAAI,CAACvB,YAAY,CAAC8B,YAAY,IAAI,CAAC;YAC5DrB,OAAOc,IAAI,CAACvB,YAAY,CAAC8B,YAAY,GAAG;gBACtC,GAAGC,QAAQ;gBACX,cAAcF,YAAY7B,YAAY,CAAC,aAAa;YACtD;QACF;QAEA,2EAA2E;QAC3E,yEAAyE;QACzE,IAAIoB,aAAaY,QAAQ,EAAE;YACzB,OAAOvB;QACT;QAEA,OAAO;YACL,GAAGA,MAAM;YACTG,OAAO;gBACL,GAAGH,OAAOG,KAAK;gBACfqB,YAAY;oBACV,GAAGxB,OAAOG,KAAK,EAAEqB,UAAU;oBAC3BC,uBAAuB;2BACjBzB,OAAOG,KAAK,EAAEqB,YAAYC,yBAAyB,EAAE;wBACzD;qBACD;gBACH;YACF;YACAC,WAAW;mBACL1B,OAAO0B,SAAS,IAAI,EAAE;gBAC1B,uDAAuD;gBACvD;oBAAEC,SAAStC;oBAAauC,QAAQ;oBAAQC,MAAM;gBAAO;gBACrD,uEAAuE;gBACvE,6DAA6D;gBAC7D;oBACEF,SAAS,IAAM,IAAIG,SAAS,MAAM;4BAAEC,SAAS;gCAAEC,OAAO;4BAAO;4BAAGC,QAAQ;wBAAI;oBAC5EL,QAAQ;oBACRC,MAAM;gBACR;aACD;QACH;IACF;AACF,GAAE"}
@@ -1 +1 @@
1
- {"version":3,"file":"buildMcpServer.d.ts","sourceRoot":"","sources":["../../src/mcp/buildMcpServer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAsB,MAAM,8BAA8B,CAAA;AAC5E,OAAO,EAAgC,KAAK,cAAc,EAAE,MAAM,SAAS,CAAA;AAE3E,OAAO,KAAK,EACV,aAAa,EAIb,wBAAwB,EACzB,MAAM,aAAa,CAAA;AAiBpB;;;;;;;;;GASG;AACH,eAAO,MAAM,cAAc,GAAI,uCAI5B;IACD,aAAa,EAAE,aAAa,CAAA;IAC5B,YAAY,EAAE,wBAAwB,CAAA;IACtC,GAAG,EAAE,cAAc,CAAA;CACpB,KAAG,SAmLH,CAAA"}
1
+ {"version":3,"file":"buildMcpServer.d.ts","sourceRoot":"","sources":["../../src/mcp/buildMcpServer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAsB,MAAM,8BAA8B,CAAA;AAC5E,OAAO,EAAY,KAAK,cAAc,EAAE,MAAM,SAAS,CAAA;AAGvD,OAAO,KAAK,EACV,aAAa,EAMb,wBAAwB,EAEzB,MAAM,aAAa,CAAA;AAKpB;;;;;;;;;GASG;AACH,eAAO,MAAM,cAAc,GAAI,uCAI5B;IACD,aAAa,EAAE,aAAa,CAAA;IAC5B,YAAY,EAAE,wBAAwB,CAAA;IACtC,GAAG,EAAE,cAAc,CAAA;CACpB,KAAG,SAuLH,CAAA"}
@@ -1,14 +1,8 @@
1
1
  import { McpServer } from '@modelcontextprotocol/server';
2
- import { APIError, configToJSONSchema } from 'payload';
3
- import { toCamelCase } from '../utils/camelCase.js';
2
+ import { APIError } from 'payload';
3
+ import { z } from 'zod';
4
4
  import { getLogger } from '../utils/getLogger.js';
5
- import { getCollectionVirtualFieldNames, getGlobalVirtualFieldNames } from '../utils/getVirtualFieldNames.js';
6
- import { removeVirtualFieldsFromSchema } from '../utils/schemaConversion/removeVirtualFieldsFromSchema.js';
7
5
  import { toStandardSchema } from '../utils/toStandardSchema.js';
8
- /** `findPosts`, `updateSiteSettings` — auto-prefixed wire name for collection/global tools. */ const wireName = (key, slug)=>{
9
- const camel = toCamelCase(slug);
10
- return `${key}${camel.charAt(0).toUpperCase()}${camel.slice(1)}`;
11
- };
12
6
  /**
13
7
  * Transport-agnostic core: registers every authorized MCP item onto a fresh
14
8
  * `McpServer` and returns it. The caller is responsible for picking a transport
@@ -36,72 +30,84 @@ import { toStandardSchema } from '../utils/toStandardSchema.js';
36
30
  const { doc: _doc, ...rest } = overridden;
37
31
  return rest;
38
32
  };
39
- const configSchema = configToJSONSchema(req.payload.config, req.payload.db.defaultIDType, req.i18n, {
40
- forceInlineBlocks: true
41
- });
33
+ /**
34
+ * Runs a collection/global tool call:
35
+ * - reads `collectionSlug` / `globalSlug` from the input
36
+ * - runs access control: errors if `authorizedMCP.items` has no entry for this tool + slug
37
+ * - runs the tool handler and finalizes its response
38
+ */ const callEntityTool = async ({ input, item, serverContext })=>{
39
+ const entity = item.type === 'collectionTool' ? 'collection' : 'global';
40
+ const slugKey = item.type === 'collectionTool' ? 'collectionSlug' : 'globalSlug';
41
+ const toolInput = input ?? {};
42
+ const slug = toolInput[slugKey];
43
+ if (!slug) {
44
+ return {
45
+ content: [
46
+ {
47
+ type: 'text',
48
+ text: `Error: "${item.mcpName}" requires ${slugKey}. Use getConfigInfo to inspect ${entity} slugs.`
49
+ }
50
+ ],
51
+ isError: true
52
+ };
53
+ }
54
+ const match = authorizedMCP.items.find((candidate)=>candidate.type === item.type && candidate.mcpName === item.mcpName && (candidate.type === 'collectionTool' ? candidate.collectionSlug === slug : candidate.type === 'globalTool' && candidate.globalSlug === slug));
55
+ if (!match) {
56
+ return {
57
+ content: [
58
+ {
59
+ type: 'text',
60
+ text: `Error: MCP access to "${item.mcpName}" is not enabled for ${entity} "${slug}"`
61
+ }
62
+ ],
63
+ isError: true
64
+ };
65
+ }
66
+ const handlerArgs = {
67
+ authorizedMCP,
68
+ input: toolInput,
69
+ req,
70
+ serverContext
71
+ };
72
+ const response = await (match.type === 'collectionTool' ? match.tool.handler({
73
+ ...handlerArgs,
74
+ collectionSlug: slug
75
+ }) : match.tool.handler({
76
+ ...handlerArgs,
77
+ globalSlug: slug
78
+ }));
79
+ return finalizeToolResponse(response, match.tool.overrideResponse);
80
+ };
42
81
  try {
82
+ const registeredEntityTools = new Set();
43
83
  for (const item of authorizedMCP.items){
44
84
  switch(item.type){
45
85
  case 'collectionTool':
46
- {
47
- const tool = item.tool;
48
- const name = wireName(item.key, item.collectionSlug);
49
- let inputSchema = tool.input;
50
- if (typeof inputSchema === 'function') {
51
- const raw = configSchema.$defs?.[item.collectionSlug];
52
- if (!raw) {
53
- throw new APIError(`Collection schema not found for slug: ${item.collectionSlug}`, 500);
54
- }
55
- const collectionSchema = removeVirtualFieldsFromSchema(JSON.parse(JSON.stringify(raw)), getCollectionVirtualFieldNames(req.payload.config, item.collectionSlug));
56
- inputSchema = inputSchema({
57
- collectionSchema
58
- });
59
- }
60
- server.registerTool(name, {
61
- description: tool.description,
62
- inputSchema: inputSchema ? toStandardSchema(inputSchema) : undefined
63
- }, async (input, ctx)=>finalizeToolResponse(await tool.handler({
64
- authorizedMCP,
65
- collectionSlug: item.collectionSlug,
66
- input: input ?? {},
67
- req,
68
- serverContext: ctx
69
- }), tool.overrideResponse));
70
- logger.info(`✅ Tool: ${name} Registered.`);
71
- break;
72
- }
73
86
  case 'globalTool':
74
87
  {
75
- const tool = item.tool;
76
- const name = wireName(item.key, item.globalSlug);
77
- let inputSchema = tool.input;
78
- if (typeof inputSchema === 'function') {
79
- const raw = configSchema.$defs?.[item.globalSlug];
80
- if (!raw) {
81
- throw new APIError(`Global schema not found for slug: ${item.globalSlug}`, 500);
82
- }
83
- const globalSchema = removeVirtualFieldsFromSchema(JSON.parse(JSON.stringify(raw)), getGlobalVirtualFieldNames(req.payload.config, item.globalSlug));
84
- inputSchema = inputSchema({
85
- globalSchema
86
- });
88
+ if (registeredEntityTools.has(item.mcpName)) {
89
+ break;
87
90
  }
88
- server.registerTool(name, {
89
- description: tool.description,
90
- inputSchema: inputSchema ? toStandardSchema(inputSchema) : undefined
91
- }, async (input, ctx)=>finalizeToolResponse(await tool.handler({
92
- authorizedMCP,
93
- globalSlug: item.globalSlug,
94
- input: input ?? {},
95
- req,
91
+ registeredEntityTools.add(item.mcpName);
92
+ const inputSchema = withSlugInput({
93
+ name: item.type === 'collectionTool' ? 'collectionSlug' : 'globalSlug',
94
+ input: item.tool.input
95
+ });
96
+ server.registerTool(item.mcpName, {
97
+ description: item.tool.description,
98
+ inputSchema: toStandardSchema(inputSchema)
99
+ }, async (input, ctx)=>callEntityTool({
100
+ input,
101
+ item,
96
102
  serverContext: ctx
97
- }), tool.overrideResponse));
98
- logger.info(`✅ Tool: ${name} Registered.`);
103
+ }));
104
+ logger.info(`✅ Tool: ${item.mcpName} Registered.`);
99
105
  break;
100
106
  }
101
107
  case 'prompt':
102
108
  {
103
109
  const prompt = item.prompt;
104
- server.registerPrompt(item.key, {
110
+ server.registerPrompt(item.mcpName, {
105
111
  argsSchema: prompt.argsSchema ? toStandardSchema(prompt.argsSchema) : undefined,
106
112
  description: prompt.description,
107
113
  title: prompt.title
@@ -116,7 +122,7 @@ import { toStandardSchema } from '../utils/toStandardSchema.js';
116
122
  case 'resource':
117
123
  {
118
124
  const resource = item.resource;
119
- server.registerResource(item.key, // @ts-expect-error - Overload type ambiguity (string OR ResourceTemplate is valid)
125
+ server.registerResource(item.mcpName, // @ts-expect-error - Overload type ambiguity (string OR ResourceTemplate is valid)
120
126
  resource.uri, {
121
127
  description: resource.description,
122
128
  mimeType: resource.mimeType,
@@ -140,7 +146,7 @@ import { toStandardSchema } from '../utils/toStandardSchema.js';
140
146
  case 'tool':
141
147
  {
142
148
  const tool = item.tool;
143
- server.registerTool(item.key, {
149
+ server.registerTool(item.mcpName, {
144
150
  description: tool.description,
145
151
  inputSchema: tool.input ? toStandardSchema(tool.input) : undefined
146
152
  }, async (input, ctx)=>finalizeToolResponse(await tool.handler({
@@ -149,7 +155,7 @@ import { toStandardSchema } from '../utils/toStandardSchema.js';
149
155
  req,
150
156
  serverContext: ctx
151
157
  }), tool.overrideResponse));
152
- logger.info(`✅ Tool: ${item.key} Registered.`);
158
+ logger.info(`✅ Tool: ${item.mcpName} Registered.`);
153
159
  break;
154
160
  }
155
161
  }
@@ -159,5 +165,35 @@ import { toStandardSchema } from '../utils/toStandardSchema.js';
159
165
  }
160
166
  return server;
161
167
  };
168
+ const withSlugInput = ({ name, input })=>{
169
+ const description = name === 'collectionSlug' ? 'The collection slug' : 'The global slug';
170
+ const slugSchema = z.string().describe(description);
171
+ if (!input) {
172
+ return z.object({
173
+ [name]: slugSchema
174
+ });
175
+ }
176
+ if (input instanceof z.ZodObject) {
177
+ return input.extend({
178
+ [name]: slugSchema
179
+ });
180
+ }
181
+ const schema = input;
182
+ return {
183
+ ...schema,
184
+ type: 'object',
185
+ properties: {
186
+ ...schema.properties,
187
+ [name]: {
188
+ type: 'string',
189
+ description
190
+ }
191
+ },
192
+ required: Array.from(new Set([
193
+ name,
194
+ ...schema.required ?? []
195
+ ]))
196
+ };
197
+ };
162
198
 
163
199
  //# sourceMappingURL=buildMcpServer.js.map