@payloadcms/plugin-mcp 4.0.0-internal.4cbdd50 → 4.0.0-internal.4e1f822

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 (202) hide show
  1. package/LICENSE.md +1 -1
  2. package/bin.js +7 -0
  3. package/dist/defaultAccess.d.ts.map +1 -1
  4. package/dist/defineTool.d.ts +8 -8
  5. package/dist/defineTool.d.ts.map +1 -1
  6. package/dist/endpoint/access.d.ts +2 -7
  7. package/dist/endpoint/access.d.ts.map +1 -1
  8. package/dist/endpoint/access.js +6 -13
  9. package/dist/endpoint/access.js.map +1 -1
  10. package/dist/endpoint/index.d.ts +1 -1
  11. package/dist/endpoint/index.d.ts.map +1 -1
  12. package/dist/endpoint/index.js +57 -17
  13. package/dist/endpoint/index.js.map +1 -1
  14. package/dist/index.d.ts +2 -2
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +2 -2
  17. package/dist/index.js.map +1 -1
  18. package/dist/mcp/buildMcpServer.d.ts +5 -5
  19. package/dist/mcp/buildMcpServer.d.ts.map +1 -1
  20. package/dist/mcp/buildMcpServer.js +67 -33
  21. package/dist/mcp/buildMcpServer.js.map +1 -1
  22. package/dist/mcp/builtin/collections/authTools.d.ts.map +1 -1
  23. package/dist/mcp/builtin/collections/authTools.js +79 -56
  24. package/dist/mcp/builtin/collections/authTools.js.map +1 -1
  25. package/dist/mcp/builtin/collections/countTool.d.ts.map +1 -1
  26. package/dist/mcp/builtin/collections/countTool.js +10 -16
  27. package/dist/mcp/builtin/collections/countTool.js.map +1 -1
  28. package/dist/mcp/builtin/collections/countVersionsTool.d.ts.map +1 -1
  29. package/dist/mcp/builtin/collections/countVersionsTool.js +10 -15
  30. package/dist/mcp/builtin/collections/countVersionsTool.js.map +1 -1
  31. package/dist/mcp/builtin/collections/createTool.d.ts +1 -1
  32. package/dist/mcp/builtin/collections/createTool.d.ts.map +1 -1
  33. package/dist/mcp/builtin/collections/createTool.js +104 -54
  34. package/dist/mcp/builtin/collections/createTool.js.map +1 -1
  35. package/dist/mcp/builtin/collections/deleteTool.d.ts.map +1 -1
  36. package/dist/mcp/builtin/collections/deleteTool.js +41 -45
  37. package/dist/mcp/builtin/collections/deleteTool.js.map +1 -1
  38. package/dist/mcp/builtin/collections/duplicateTool.d.ts.map +1 -1
  39. package/dist/mcp/builtin/collections/duplicateTool.js +27 -38
  40. package/dist/mcp/builtin/collections/duplicateTool.js.map +1 -1
  41. package/dist/mcp/builtin/collections/fileInput.d.ts +28 -0
  42. package/dist/mcp/builtin/collections/fileInput.d.ts.map +1 -0
  43. package/dist/mcp/builtin/collections/fileInput.js +123 -0
  44. package/dist/mcp/builtin/collections/fileInput.js.map +1 -0
  45. package/dist/mcp/builtin/collections/fileInput.spec.js +86 -0
  46. package/dist/mcp/builtin/collections/fileInput.spec.js.map +1 -0
  47. package/dist/mcp/builtin/collections/findDistinctTool.d.ts.map +1 -1
  48. package/dist/mcp/builtin/collections/findDistinctTool.js +12 -28
  49. package/dist/mcp/builtin/collections/findDistinctTool.js.map +1 -1
  50. package/dist/mcp/builtin/collections/findTool.d.ts.map +1 -1
  51. package/dist/mcp/builtin/collections/findTool.js +23 -46
  52. package/dist/mcp/builtin/collections/findTool.js.map +1 -1
  53. package/dist/mcp/builtin/collections/findVersionByIDTool.d.ts.map +1 -1
  54. package/dist/mcp/builtin/collections/findVersionByIDTool.js +18 -28
  55. package/dist/mcp/builtin/collections/findVersionByIDTool.js.map +1 -1
  56. package/dist/mcp/builtin/collections/findVersionsTool.d.ts.map +1 -1
  57. package/dist/mcp/builtin/collections/findVersionsTool.js +17 -32
  58. package/dist/mcp/builtin/collections/findVersionsTool.js.map +1 -1
  59. package/dist/mcp/builtin/collections/getCollectionSchemaTool.d.ts.map +1 -1
  60. package/dist/mcp/builtin/collections/getCollectionSchemaTool.js +51 -11
  61. package/dist/mcp/builtin/collections/getCollectionSchemaTool.js.map +1 -1
  62. package/dist/mcp/builtin/collections/restoreVersionTool.d.ts.map +1 -1
  63. package/dist/mcp/builtin/collections/restoreVersionTool.js +15 -28
  64. package/dist/mcp/builtin/collections/restoreVersionTool.js.map +1 -1
  65. package/dist/mcp/builtin/collections/updateTool.d.ts.map +1 -1
  66. package/dist/mcp/builtin/collections/updateTool.js +62 -86
  67. package/dist/mcp/builtin/collections/updateTool.js.map +1 -1
  68. package/dist/mcp/builtin/collections/uploadInstructionsTool.d.ts +2 -0
  69. package/dist/mcp/builtin/collections/uploadInstructionsTool.d.ts.map +1 -0
  70. package/dist/mcp/builtin/collections/uploadInstructionsTool.js +55 -0
  71. package/dist/mcp/builtin/collections/uploadInstructionsTool.js.map +1 -0
  72. package/dist/mcp/builtin/formatEntityError.d.ts +16 -0
  73. package/dist/mcp/builtin/formatEntityError.d.ts.map +1 -0
  74. package/dist/mcp/builtin/formatEntityError.js +55 -0
  75. package/dist/mcp/builtin/formatEntityError.js.map +1 -0
  76. package/dist/mcp/builtin/getConfigInfoTool.d.ts.map +1 -1
  77. package/dist/mcp/builtin/getConfigInfoTool.js +5 -7
  78. package/dist/mcp/builtin/getConfigInfoTool.js.map +1 -1
  79. package/dist/mcp/builtin/globals/countVersionsTool.d.ts.map +1 -1
  80. package/dist/mcp/builtin/globals/countVersionsTool.js +10 -15
  81. package/dist/mcp/builtin/globals/countVersionsTool.js.map +1 -1
  82. package/dist/mcp/builtin/globals/findTool.d.ts.map +1 -1
  83. package/dist/mcp/builtin/globals/findTool.js +12 -18
  84. package/dist/mcp/builtin/globals/findTool.js.map +1 -1
  85. package/dist/mcp/builtin/globals/findVersionByIDTool.d.ts.map +1 -1
  86. package/dist/mcp/builtin/globals/findVersionByIDTool.js +14 -26
  87. package/dist/mcp/builtin/globals/findVersionByIDTool.js.map +1 -1
  88. package/dist/mcp/builtin/globals/findVersionsTool.d.ts.map +1 -1
  89. package/dist/mcp/builtin/globals/findVersionsTool.js +14 -31
  90. package/dist/mcp/builtin/globals/findVersionsTool.js.map +1 -1
  91. package/dist/mcp/builtin/globals/getGlobalSchemaTool.d.ts.map +1 -1
  92. package/dist/mcp/builtin/globals/getGlobalSchemaTool.js +28 -10
  93. package/dist/mcp/builtin/globals/getGlobalSchemaTool.js.map +1 -1
  94. package/dist/mcp/builtin/globals/restoreVersionTool.d.ts.map +1 -1
  95. package/dist/mcp/builtin/globals/restoreVersionTool.js +16 -24
  96. package/dist/mcp/builtin/globals/restoreVersionTool.js.map +1 -1
  97. package/dist/mcp/builtin/globals/updateTool.d.ts.map +1 -1
  98. package/dist/mcp/builtin/globals/updateTool.js +28 -37
  99. package/dist/mcp/builtin/globals/updateTool.js.map +1 -1
  100. package/dist/mcp/builtinTools.d.ts +6 -0
  101. package/dist/mcp/builtinTools.d.ts.map +1 -1
  102. package/dist/mcp/builtinTools.js +9 -3
  103. package/dist/mcp/builtinTools.js.map +1 -1
  104. package/dist/mcp/sanitizeMCPConfig.d.ts.map +1 -1
  105. package/dist/mcp/sanitizeMCPConfig.js +5 -1
  106. package/dist/mcp/sanitizeMCPConfig.js.map +1 -1
  107. package/dist/stdio.d.ts +3 -4
  108. package/dist/stdio.d.ts.map +1 -1
  109. package/dist/stdio.js +61 -42
  110. package/dist/stdio.js.map +1 -1
  111. package/dist/types.d.ts +61 -13
  112. package/dist/types.d.ts.map +1 -1
  113. package/dist/types.js +2 -4
  114. package/dist/types.js.map +1 -1
  115. package/dist/utils/camelCase.d.ts.map +1 -1
  116. package/dist/utils/resolveProjectRoot.d.ts.map +1 -1
  117. package/dist/utils/toStandardSchema.d.ts.map +1 -1
  118. package/package.json +8 -12
  119. package/src/endpoint/access.ts +5 -13
  120. package/src/endpoint/index.ts +45 -16
  121. package/src/index.ts +4 -4
  122. package/src/mcp/buildMcpServer.ts +79 -49
  123. package/src/mcp/builtin/collections/authTools.ts +77 -69
  124. package/src/mcp/builtin/collections/countTool.ts +10 -23
  125. package/src/mcp/builtin/collections/countVersionsTool.ts +10 -20
  126. package/src/mcp/builtin/collections/createTool.ts +110 -77
  127. package/src/mcp/builtin/collections/deleteTool.ts +36 -65
  128. package/src/mcp/builtin/collections/duplicateTool.ts +34 -86
  129. package/src/mcp/builtin/collections/fileInput.spec.ts +93 -0
  130. package/src/mcp/builtin/collections/fileInput.ts +169 -0
  131. package/src/mcp/builtin/collections/findDistinctTool.ts +12 -65
  132. package/src/mcp/builtin/collections/findTool.ts +23 -106
  133. package/src/mcp/builtin/collections/findVersionByIDTool.ts +16 -60
  134. package/src/mcp/builtin/collections/findVersionsTool.ts +15 -87
  135. package/src/mcp/builtin/collections/getCollectionSchemaTool.ts +48 -14
  136. package/src/mcp/builtin/collections/restoreVersionTool.ts +15 -58
  137. package/src/mcp/builtin/collections/updateTool.ts +61 -100
  138. package/src/mcp/builtin/collections/uploadInstructionsTool.ts +64 -0
  139. package/src/mcp/builtin/formatEntityError.ts +77 -0
  140. package/src/mcp/builtin/getConfigInfoTool.ts +4 -5
  141. package/src/mcp/builtin/globals/countVersionsTool.ts +10 -19
  142. package/src/mcp/builtin/globals/findTool.ts +14 -53
  143. package/src/mcp/builtin/globals/findVersionByIDTool.ts +14 -54
  144. package/src/mcp/builtin/globals/findVersionsTool.ts +15 -94
  145. package/src/mcp/builtin/globals/getGlobalSchemaTool.ts +30 -8
  146. package/src/mcp/builtin/globals/restoreVersionTool.ts +15 -47
  147. package/src/mcp/builtin/globals/updateTool.ts +39 -62
  148. package/src/mcp/builtinTools.ts +9 -2
  149. package/src/mcp/sanitizeMCPConfig.ts +5 -1
  150. package/src/stdio.ts +61 -43
  151. package/src/types.ts +61 -13
  152. package/dist/@types/assets.d.js +0 -2
  153. package/dist/@types/assets.d.js.map +0 -1
  154. package/dist/mcp/builtin/collections/formatCollectionError.d.ts +0 -9
  155. package/dist/mcp/builtin/collections/formatCollectionError.d.ts.map +0 -1
  156. package/dist/mcp/builtin/collections/formatCollectionError.js +0 -60
  157. package/dist/mcp/builtin/collections/formatCollectionError.js.map +0 -1
  158. package/dist/mcp/builtin/validateEntityData.d.ts +0 -14
  159. package/dist/mcp/builtin/validateEntityData.d.ts.map +0 -1
  160. package/dist/mcp/builtin/validateEntityData.js +0 -82
  161. package/dist/mcp/builtin/validateEntityData.js.map +0 -1
  162. package/dist/utils/getVirtualFieldNames.d.ts +0 -14
  163. package/dist/utils/getVirtualFieldNames.d.ts.map +0 -1
  164. package/dist/utils/getVirtualFieldNames.js +0 -35
  165. package/dist/utils/getVirtualFieldNames.js.map +0 -1
  166. package/dist/utils/localAPIDefaults.d.ts +0 -20
  167. package/dist/utils/localAPIDefaults.d.ts.map +0 -1
  168. package/dist/utils/localAPIDefaults.js +0 -19
  169. package/dist/utils/localAPIDefaults.js.map +0 -1
  170. package/dist/utils/schemaConversion/getEntityInputSchema.d.ts +0 -11
  171. package/dist/utils/schemaConversion/getEntityInputSchema.d.ts.map +0 -1
  172. package/dist/utils/schemaConversion/getEntityInputSchema.js +0 -34
  173. package/dist/utils/schemaConversion/getEntityInputSchema.js.map +0 -1
  174. package/dist/utils/schemaConversion/removeVirtualFieldsFromSchema.d.ts +0 -7
  175. package/dist/utils/schemaConversion/removeVirtualFieldsFromSchema.d.ts.map +0 -1
  176. package/dist/utils/schemaConversion/removeVirtualFieldsFromSchema.js +0 -20
  177. package/dist/utils/schemaConversion/removeVirtualFieldsFromSchema.js.map +0 -1
  178. package/dist/utils/schemaConversion/sanitizeEntitySchema.d.ts +0 -15
  179. package/dist/utils/schemaConversion/sanitizeEntitySchema.d.ts.map +0 -1
  180. package/dist/utils/schemaConversion/sanitizeEntitySchema.js +0 -464
  181. package/dist/utils/schemaConversion/sanitizeEntitySchema.js.map +0 -1
  182. package/dist/utils/schemaConversion/sanitizeEntitySchema.spec.js +0 -158
  183. package/dist/utils/schemaConversion/sanitizeEntitySchema.spec.js.map +0 -1
  184. package/dist/utils/transformPointDataToPayload.d.ts +0 -7
  185. package/dist/utils/transformPointDataToPayload.d.ts.map +0 -1
  186. package/dist/utils/transformPointDataToPayload.js +0 -28
  187. package/dist/utils/transformPointDataToPayload.js.map +0 -1
  188. package/dist/utils/whereSchema.d.ts +0 -9
  189. package/dist/utils/whereSchema.d.ts.map +0 -1
  190. package/dist/utils/whereSchema.js +0 -13
  191. package/dist/utils/whereSchema.js.map +0 -1
  192. package/src/@types/assets.d.ts +0 -3
  193. package/src/mcp/builtin/collections/formatCollectionError.ts +0 -84
  194. package/src/mcp/builtin/validateEntityData.ts +0 -132
  195. package/src/utils/getVirtualFieldNames.ts +0 -53
  196. package/src/utils/localAPIDefaults.ts +0 -22
  197. package/src/utils/schemaConversion/getEntityInputSchema.ts +0 -78
  198. package/src/utils/schemaConversion/removeVirtualFieldsFromSchema.ts +0 -27
  199. package/src/utils/schemaConversion/sanitizeEntitySchema.spec.ts +0 -103
  200. package/src/utils/schemaConversion/sanitizeEntitySchema.ts +0 -529
  201. package/src/utils/transformPointDataToPayload.ts +0 -40
  202. package/src/utils/whereSchema.ts +0 -24
package/LICENSE.md CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2018-2024 Payload CMS, Inc. <info@payloadcms.com>
3
+ Copyright (c) 2018-2026 Payload CMS, LLC <info@payloadcms.com>
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining
6
6
  a copy of this software and associated documentation files (the
package/bin.js CHANGED
@@ -27,6 +27,13 @@ const start = async () => {
27
27
  return
28
28
  }
29
29
 
30
+ // tsx 4.22.4's synchronous loader leaks its namespace query onto Node built-ins on Node 23.5+.
31
+ // Force the stable asynchronous loader path, matching payload/bin.js.
32
+ const nodeModule = await import('node:module')
33
+ if (typeof nodeModule.default.registerHooks === 'function') {
34
+ nodeModule.default.registerHooks = undefined
35
+ }
36
+
30
37
  const { tsImport } = await import('tsx/esm/api')
31
38
  const { runMcpStdio } = await tsImport('./dist/stdio.js', baseURL)
32
39
  await runMcpStdio()
@@ -1 +1 @@
1
- {"version":3,"file":"defaultAccess.d.ts","sourceRoot":"","sources":["../src/defaultAccess.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAE/C,eAAO,MAAM,aAAa,GAAI,SAAS,aAAa,KAAG,OAA4B,CAAA"}
1
+ {"version":3,"file":"defaultAccess.d.ts","sourceRoot":"","sources":["../src/defaultAccess.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAE/C,eAAO,MAAM,aAAa,YAAa,aAAa,KAAG,OAA4B,CAAA"}
@@ -11,16 +11,16 @@ import type { CollectionTool, GlobalTool, Prompt, Tool, ToolInputSchema } from '
11
11
  * Config and handler signatures are derived from `Tool` / `CollectionTool` / `GlobalTool` /
12
12
  * `Prompt` via `Omit` + indexed access so there's no duplication with `types.ts`.
13
13
  */
14
- export declare const defineTool: <TSchema extends ToolInputSchema | undefined = ToolInputSchema | undefined>(args: Omit<Tool<TSchema>, "handler">) => {
15
- handler: (fn: Tool<TSchema>["handler"]) => Tool;
14
+ export declare const defineTool: <TSchema extends ToolInputSchema | undefined = ToolInputSchema | undefined>(args: Omit<Tool<TSchema>, 'handler'>) => {
15
+ handler: (fn: Tool<TSchema>['handler']) => Tool;
16
16
  };
17
- export declare const defineCollectionTool: <TSchema extends ToolInputSchema | undefined = ToolInputSchema | undefined>(args: Omit<CollectionTool<TSchema>, "handler">) => {
18
- handler: (fn: CollectionTool<TSchema>["handler"]) => CollectionTool;
17
+ export declare const defineCollectionTool: <TSchema extends ToolInputSchema | undefined = ToolInputSchema | undefined>(args: Omit<CollectionTool<TSchema>, 'handler'>) => {
18
+ handler: (fn: CollectionTool<TSchema>['handler']) => CollectionTool;
19
19
  };
20
- export declare const defineGlobalTool: <TSchema extends ToolInputSchema | undefined = ToolInputSchema | undefined>(args: Omit<GlobalTool<TSchema>, "handler">) => {
21
- handler: (fn: GlobalTool<TSchema>["handler"]) => GlobalTool;
20
+ export declare const defineGlobalTool: <TSchema extends ToolInputSchema | undefined = ToolInputSchema | undefined>(args: Omit<GlobalTool<TSchema>, 'handler'>) => {
21
+ handler: (fn: GlobalTool<TSchema>['handler']) => GlobalTool;
22
22
  };
23
- export declare const definePrompt: <TSchema extends ToolInputSchema = ToolInputSchema>(args: Omit<Prompt<TSchema>, "handler">) => {
24
- handler: (fn: Prompt<TSchema>["handler"]) => Prompt;
23
+ export declare const definePrompt: <TSchema extends ToolInputSchema = ToolInputSchema>(args: Omit<Prompt<TSchema>, 'handler'>) => {
24
+ handler: (fn: Prompt<TSchema>['handler']) => Prompt;
25
25
  };
26
26
  //# sourceMappingURL=defineTool.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"defineTool.d.ts","sourceRoot":"","sources":["../src/defineTool.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAE3F;;;;;;;;;;;GAWG;AAEH,eAAO,MAAM,UAAU,GACrB,OAAO,SAAS,eAAe,GAAG,SAAS,GAAG,eAAe,GAAG,SAAS,EAEzE,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC,KACnC;IAAE,OAAO,EAAE,CAAC,EAAE,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,KAAK,IAAI,CAAA;CAElD,CAAA;AAEF,eAAO,MAAM,oBAAoB,GAC/B,OAAO,SAAS,eAAe,GAAG,SAAS,GAAG,eAAe,GAAG,SAAS,EAEzE,MAAM,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC,KAC7C;IAAE,OAAO,EAAE,CAAC,EAAE,EAAE,cAAc,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,KAAK,cAAc,CAAA;CAEtE,CAAA;AAEF,eAAO,MAAM,gBAAgB,GAC3B,OAAO,SAAS,eAAe,GAAG,SAAS,GAAG,eAAe,GAAG,SAAS,EAEzE,MAAM,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC,KACzC;IAAE,OAAO,EAAE,CAAC,EAAE,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,KAAK,UAAU,CAAA;CAE9D,CAAA;AAEF,eAAO,MAAM,YAAY,GAAI,OAAO,SAAS,eAAe,GAAG,eAAe,EAC5E,MAAM,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC,KACrC;IAAE,OAAO,EAAE,CAAC,EAAE,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,KAAK,MAAM,CAAA;CAEtD,CAAA"}
1
+ {"version":3,"file":"defineTool.d.ts","sourceRoot":"","sources":["../src/defineTool.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,eAAe,EAAE,MAAM,YAAY,CAAA;AAE3F;;;;;;;;;;;GAWG;AAEH,eAAO,MAAM,UAAU,GACrB,OAAO,SAAS,eAAe,GAAG,SAAS,GAAG,eAAe,GAAG,SAAS,QAEnE,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC,KACnC;IAAE,OAAO,EAAE,CAAC,EAAE,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,KAAK,IAAI,CAAA;CAElD,CAAA;AAEF,eAAO,MAAM,oBAAoB,GAC/B,OAAO,SAAS,eAAe,GAAG,SAAS,GAAG,eAAe,GAAG,SAAS,QAEnE,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC,KAC7C;IAAE,OAAO,EAAE,CAAC,EAAE,EAAE,cAAc,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,KAAK,cAAc,CAAA;CAEtE,CAAA;AAEF,eAAO,MAAM,gBAAgB,GAC3B,OAAO,SAAS,eAAe,GAAG,SAAS,GAAG,eAAe,GAAG,SAAS,QAEnE,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC,KACzC;IAAE,OAAO,EAAE,CAAC,EAAE,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,KAAK,UAAU,CAAA;CAE9D,CAAA;AAEF,eAAO,MAAM,YAAY,GAAI,OAAO,SAAS,eAAe,GAAG,eAAe,QACtE,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC,KACrC;IAAE,OAAO,EAAE,CAAC,EAAE,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,KAAK,MAAM,CAAA;CAEtD,CAAA"}
@@ -5,13 +5,8 @@ export type GetAuthorizedMCPArgs = {
5
5
  req: PayloadRequest;
6
6
  };
7
7
  /**
8
- * Resolves the MCP caller and returns the MCP surface authorized for that request.
9
- *
10
- * Authorization has two layers:
11
- * 1. Payload collection/global permissions determine whether built-in operation tools are shown.
12
- * 2. MCP `access` callbacks can further hide any configured tool, prompt, or resource.
13
- *
14
- * Like Payload core operations, `overrideAccess` skips both layers.
8
+ * Authenticates an MCP request and removes items the user cannot access.
9
+ * `overrideAccess` skips Payload and MCP item access checks.
15
10
  */
16
11
  export declare const getAuthorizedMCP: (args: GetAuthorizedMCPArgs) => Promise<AuthorizedMCP>;
17
12
  export declare const filterMCPItems: ({ items, overrideAccess, req, }: {
@@ -1 +1 @@
1
- {"version":3,"file":"access.d.ts","sourceRoot":"","sources":["../../src/endpoint/access.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAwB,MAAM,SAAS,CAAA;AAInE,OAAO,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AAIzD,MAAM,MAAM,oBAAoB,GAAG;IACjC,cAAc,EAAE,OAAO,CAAA;IACvB,GAAG,EAAE,cAAc,CAAA;CACpB,CAAA;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,gBAAgB,EAAE,CAAC,IAAI,EAAE,oBAAoB,KAAK,OAAO,CAAC,aAAa,CAmCnF,CAAA;AAED,eAAO,MAAM,cAAc,GAAU,iCAIlC;IACD,KAAK,EAAE,OAAO,EAAE,CAAA;IAChB,cAAc,EAAE,OAAO,CAAA;IACvB,GAAG,EAAE,cAAc,CAAA;CACpB,KAAG,OAAO,CAAC,OAAO,EAAE,CAmBpB,CAAA"}
1
+ {"version":3,"file":"access.d.ts","sourceRoot":"","sources":["../../src/endpoint/access.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAwB,MAAM,SAAS,CAAA;AAInE,OAAO,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AAIzD,MAAM,MAAM,oBAAoB,GAAG;IACjC,cAAc,EAAE,OAAO,CAAA;IACvB,GAAG,EAAE,cAAc,CAAA;CACpB,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,gBAAgB,EAAE,CAAC,IAAI,EAAE,oBAAoB,KAAK,OAAO,CAAC,aAAa,CAkCnF,CAAA;AAED,eAAO,MAAM,cAAc,oCAIxB;IACD,KAAK,EAAE,OAAO,EAAE,CAAA;IAChB,cAAc,EAAE,OAAO,CAAA;IACvB,GAAG,EAAE,cAAc,CAAA;CACpB,KAAG,OAAO,CAAC,OAAO,EAAE,CAkBpB,CAAA"}
@@ -1,13 +1,8 @@
1
1
  import { getAccessResults, UnauthorizedError } from 'payload';
2
2
  import { getPluginConfig } from '../utils/getPluginConfig.js';
3
3
  /**
4
- * Resolves the MCP caller and returns the MCP surface authorized for that request.
5
- *
6
- * Authorization has two layers:
7
- * 1. Payload collection/global permissions determine whether built-in operation tools are shown.
8
- * 2. MCP `access` callbacks can further hide any configured tool, prompt, or resource.
9
- *
10
- * Like Payload core operations, `overrideAccess` skips both layers.
4
+ * Authenticates an MCP request and removes items the user cannot access.
5
+ * `overrideAccess` skips Payload and MCP item access checks.
11
6
  */ export const getAuthorizedMCP = async ({ overrideAccess, req })=>{
12
7
  const pluginConfig = getPluginConfig({
13
8
  config: req.payload.config
@@ -37,13 +32,11 @@ import { getPluginConfig } from '../utils/getPluginConfig.js';
37
32
  overrideAccess,
38
33
  req
39
34
  }),
40
- overrideAccess,
41
- user: req.user
35
+ overrideAccess
42
36
  };
43
37
  };
44
38
  export const filterMCPItems = async ({ items, overrideAccess, req })=>{
45
- // Match Payload core: overrideAccess bypasses access evaluation instead of
46
- // forcing each access function to return true.
39
+ // Match Payload core: overrideAccess bypasses access evaluation
47
40
  if (overrideAccess) {
48
41
  return items;
49
42
  }
@@ -69,13 +62,13 @@ export const filterMCPItems = async ({ items, overrideAccess, req })=>{
69
62
  switch(item.type){
70
63
  case 'collectionTool':
71
64
  return !item.tool.access || await item.tool.access({
72
- collectionSlug: item.collectionSlug,
65
+ slug: item.collectionSlug,
73
66
  permissions,
74
67
  req
75
68
  });
76
69
  case 'globalTool':
77
70
  return !item.tool.access || await item.tool.access({
78
- globalSlug: item.globalSlug,
71
+ slug: item.globalSlug,
79
72
  permissions,
80
73
  req
81
74
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/endpoint/access.ts"],"sourcesContent":["import type { PayloadRequest, SanitizedPermissions } from 'payload'\n\nimport { getAccessResults, UnauthorizedError } from 'payload'\n\nimport type { AuthorizedMCP, MCPItem } from '../types.js'\n\nimport { getPluginConfig } from '../utils/getPluginConfig.js'\n\nexport type GetAuthorizedMCPArgs = {\n overrideAccess: boolean\n req: PayloadRequest\n}\n\n/**\n * Resolves the MCP caller and returns the MCP surface authorized for that request.\n *\n * Authorization has two layers:\n * 1. Payload collection/global permissions determine whether built-in operation tools are shown.\n * 2. MCP `access` callbacks can further hide any configured tool, prompt, or resource.\n *\n * Like Payload core operations, `overrideAccess` skips both layers.\n */\nexport const getAuthorizedMCP: (args: GetAuthorizedMCPArgs) => Promise<AuthorizedMCP> = async ({\n overrideAccess,\n req,\n}) => {\n const pluginConfig = getPluginConfig({ config: req.payload.config })\n\n if (pluginConfig.overrideGetAuthorizedMCP) {\n return await pluginConfig.overrideGetAuthorizedMCP({\n overrideAccess,\n pluginConfig,\n req,\n })\n }\n\n if (req.headers) {\n const headers = new Headers(req.headers)\n const hasAuthorization = headers.has('Authorization')\n\n headers.set('DisableAutologin', 'true')\n req.user = (await req.payload.auth({ headers, req })).user\n\n if (hasAuthorization && !req.user) {\n throw new UnauthorizedError(req.t)\n }\n }\n\n return {\n items: await filterMCPItems({\n items: pluginConfig.items,\n overrideAccess,\n req,\n }),\n overrideAccess,\n user: req.user,\n }\n}\n\nexport const filterMCPItems = async ({\n items,\n overrideAccess,\n req,\n}: {\n items: MCPItem[]\n overrideAccess: boolean\n req: PayloadRequest\n}): Promise<MCPItem[]> => {\n // Match Payload core: overrideAccess bypasses access evaluation instead of\n // forcing each access function to return true.\n if (overrideAccess) {\n return items\n }\n\n const authorizedItems: MCPItem[] = []\n\n const permissions = await getAccessResults({ req })\n\n for (const item of items) {\n if (!(await checkItemAccess({ item, permissions, req }))) {\n continue\n }\n authorizedItems.push(item)\n }\n\n return authorizedItems\n}\n\n/**\n * Runs MCP item access callbacks\n */\nconst checkItemAccess = async ({\n item,\n permissions,\n req,\n}: {\n item: MCPItem\n permissions?: SanitizedPermissions\n req: PayloadRequest\n}): Promise<boolean> => {\n switch (item.type) {\n case 'collectionTool':\n return (\n !item.tool.access ||\n (await item.tool.access({ collectionSlug: item.collectionSlug, permissions, req }))\n )\n case 'globalTool':\n return (\n !item.tool.access ||\n (await item.tool.access({ globalSlug: item.globalSlug, permissions, req }))\n )\n case 'prompt':\n return !item.prompt.access || (await item.prompt.access({ permissions, req }))\n case 'resource':\n return !item.resource.access || (await item.resource.access({ permissions, req }))\n case 'tool':\n return !item.tool.access || (await item.tool.access({ permissions, req }))\n }\n}\n"],"names":["getAccessResults","UnauthorizedError","getPluginConfig","getAuthorizedMCP","overrideAccess","req","pluginConfig","config","payload","overrideGetAuthorizedMCP","headers","Headers","hasAuthorization","has","set","user","auth","t","items","filterMCPItems","authorizedItems","permissions","item","checkItemAccess","push","type","tool","access","collectionSlug","globalSlug","prompt","resource"],"mappings":"AAEA,SAASA,gBAAgB,EAAEC,iBAAiB,QAAQ,UAAS;AAI7D,SAASC,eAAe,QAAQ,8BAA6B;AAO7D;;;;;;;;CAQC,GACD,OAAO,MAAMC,mBAA2E,OAAO,EAC7FC,cAAc,EACdC,GAAG,EACJ;IACC,MAAMC,eAAeJ,gBAAgB;QAAEK,QAAQF,IAAIG,OAAO,CAACD,MAAM;IAAC;IAElE,IAAID,aAAaG,wBAAwB,EAAE;QACzC,OAAO,MAAMH,aAAaG,wBAAwB,CAAC;YACjDL;YACAE;YACAD;QACF;IACF;IAEA,IAAIA,IAAIK,OAAO,EAAE;QACf,MAAMA,UAAU,IAAIC,QAAQN,IAAIK,OAAO;QACvC,MAAME,mBAAmBF,QAAQG,GAAG,CAAC;QAErCH,QAAQI,GAAG,CAAC,oBAAoB;QAChCT,IAAIU,IAAI,GAAG,AAAC,CAAA,MAAMV,IAAIG,OAAO,CAACQ,IAAI,CAAC;YAAEN;YAASL;QAAI,EAAC,EAAGU,IAAI;QAE1D,IAAIH,oBAAoB,CAACP,IAAIU,IAAI,EAAE;YACjC,MAAM,IAAId,kBAAkBI,IAAIY,CAAC;QACnC;IACF;IAEA,OAAO;QACLC,OAAO,MAAMC,eAAe;YAC1BD,OAAOZ,aAAaY,KAAK;YACzBd;YACAC;QACF;QACAD;QACAW,MAAMV,IAAIU,IAAI;IAChB;AACF,EAAC;AAED,OAAO,MAAMI,iBAAiB,OAAO,EACnCD,KAAK,EACLd,cAAc,EACdC,GAAG,EAKJ;IACC,2EAA2E;IAC3E,+CAA+C;IAC/C,IAAID,gBAAgB;QAClB,OAAOc;IACT;IAEA,MAAME,kBAA6B,EAAE;IAErC,MAAMC,cAAc,MAAMrB,iBAAiB;QAAEK;IAAI;IAEjD,KAAK,MAAMiB,QAAQJ,MAAO;QACxB,IAAI,CAAE,MAAMK,gBAAgB;YAAED;YAAMD;YAAahB;QAAI,IAAK;YACxD;QACF;QACAe,gBAAgBI,IAAI,CAACF;IACvB;IAEA,OAAOF;AACT,EAAC;AAED;;CAEC,GACD,MAAMG,kBAAkB,OAAO,EAC7BD,IAAI,EACJD,WAAW,EACXhB,GAAG,EAKJ;IACC,OAAQiB,KAAKG,IAAI;QACf,KAAK;YACH,OACE,CAACH,KAAKI,IAAI,CAACC,MAAM,IAChB,MAAML,KAAKI,IAAI,CAACC,MAAM,CAAC;gBAAEC,gBAAgBN,KAAKM,cAAc;gBAAEP;gBAAahB;YAAI;QAEpF,KAAK;YACH,OACE,CAACiB,KAAKI,IAAI,CAACC,MAAM,IAChB,MAAML,KAAKI,IAAI,CAACC,MAAM,CAAC;gBAAEE,YAAYP,KAAKO,UAAU;gBAAER;gBAAahB;YAAI;QAE5E,KAAK;YACH,OAAO,CAACiB,KAAKQ,MAAM,CAACH,MAAM,IAAK,MAAML,KAAKQ,MAAM,CAACH,MAAM,CAAC;gBAAEN;gBAAahB;YAAI;QAC7E,KAAK;YACH,OAAO,CAACiB,KAAKS,QAAQ,CAACJ,MAAM,IAAK,MAAML,KAAKS,QAAQ,CAACJ,MAAM,CAAC;gBAAEN;gBAAahB;YAAI;QACjF,KAAK;YACH,OAAO,CAACiB,KAAKI,IAAI,CAACC,MAAM,IAAK,MAAML,KAAKI,IAAI,CAACC,MAAM,CAAC;gBAAEN;gBAAahB;YAAI;IAC3E;AACF"}
1
+ {"version":3,"sources":["../../src/endpoint/access.ts"],"sourcesContent":["import type { PayloadRequest, SanitizedPermissions } from 'payload'\n\nimport { getAccessResults, UnauthorizedError } from 'payload'\n\nimport type { AuthorizedMCP, MCPItem } from '../types.js'\n\nimport { getPluginConfig } from '../utils/getPluginConfig.js'\n\nexport type GetAuthorizedMCPArgs = {\n overrideAccess: boolean\n req: PayloadRequest\n}\n\n/**\n * Authenticates an MCP request and removes items the user cannot access.\n * `overrideAccess` skips Payload and MCP item access checks.\n */\nexport const getAuthorizedMCP: (args: GetAuthorizedMCPArgs) => Promise<AuthorizedMCP> = async ({\n overrideAccess,\n req,\n}) => {\n const pluginConfig = getPluginConfig({ config: req.payload.config })\n\n if (pluginConfig.overrideGetAuthorizedMCP) {\n return await pluginConfig.overrideGetAuthorizedMCP({\n overrideAccess,\n pluginConfig,\n req,\n })\n }\n\n if (req.headers) {\n const headers = new Headers(req.headers)\n const hasAuthorization = headers.has('Authorization')\n\n headers.set('DisableAutologin', 'true')\n req.user = (await req.payload.auth({ headers, req })).user\n\n if (hasAuthorization && !req.user) {\n throw new UnauthorizedError(req.t)\n }\n }\n\n return {\n items: await filterMCPItems({\n items: pluginConfig.items,\n overrideAccess,\n req,\n }),\n overrideAccess,\n }\n}\n\nexport const filterMCPItems = async ({\n items,\n overrideAccess,\n req,\n}: {\n items: MCPItem[]\n overrideAccess: boolean\n req: PayloadRequest\n}): Promise<MCPItem[]> => {\n // Match Payload core: overrideAccess bypasses access evaluation\n if (overrideAccess) {\n return items\n }\n\n const authorizedItems: MCPItem[] = []\n\n const permissions = await getAccessResults({ req })\n\n for (const item of items) {\n if (!(await checkItemAccess({ item, permissions, req }))) {\n continue\n }\n authorizedItems.push(item)\n }\n\n return authorizedItems\n}\n\n/**\n * Runs MCP item access callbacks\n */\nconst checkItemAccess = async ({\n item,\n permissions,\n req,\n}: {\n item: MCPItem\n permissions?: SanitizedPermissions\n req: PayloadRequest\n}): Promise<boolean> => {\n switch (item.type) {\n case 'collectionTool':\n return (\n !item.tool.access ||\n (await item.tool.access({ slug: item.collectionSlug, permissions, req }))\n )\n case 'globalTool':\n return (\n !item.tool.access || (await item.tool.access({ slug: item.globalSlug, permissions, req }))\n )\n case 'prompt':\n return !item.prompt.access || (await item.prompt.access({ permissions, req }))\n case 'resource':\n return !item.resource.access || (await item.resource.access({ permissions, req }))\n case 'tool':\n return !item.tool.access || (await item.tool.access({ permissions, req }))\n }\n}\n"],"names":["getAccessResults","UnauthorizedError","getPluginConfig","getAuthorizedMCP","overrideAccess","req","pluginConfig","config","payload","overrideGetAuthorizedMCP","headers","Headers","hasAuthorization","has","set","user","auth","t","items","filterMCPItems","authorizedItems","permissions","item","checkItemAccess","push","type","tool","access","slug","collectionSlug","globalSlug","prompt","resource"],"mappings":"AAEA,SAASA,gBAAgB,EAAEC,iBAAiB,QAAQ,UAAS;AAI7D,SAASC,eAAe,QAAQ,8BAA6B;AAO7D;;;CAGC,GACD,OAAO,MAAMC,mBAA2E,OAAO,EAC7FC,cAAc,EACdC,GAAG,EACJ;IACC,MAAMC,eAAeJ,gBAAgB;QAAEK,QAAQF,IAAIG,OAAO,CAACD,MAAM;IAAC;IAElE,IAAID,aAAaG,wBAAwB,EAAE;QACzC,OAAO,MAAMH,aAAaG,wBAAwB,CAAC;YACjDL;YACAE;YACAD;QACF;IACF;IAEA,IAAIA,IAAIK,OAAO,EAAE;QACf,MAAMA,UAAU,IAAIC,QAAQN,IAAIK,OAAO;QACvC,MAAME,mBAAmBF,QAAQG,GAAG,CAAC;QAErCH,QAAQI,GAAG,CAAC,oBAAoB;QAChCT,IAAIU,IAAI,GAAG,AAAC,CAAA,MAAMV,IAAIG,OAAO,CAACQ,IAAI,CAAC;YAAEN;YAASL;QAAI,EAAC,EAAGU,IAAI;QAE1D,IAAIH,oBAAoB,CAACP,IAAIU,IAAI,EAAE;YACjC,MAAM,IAAId,kBAAkBI,IAAIY,CAAC;QACnC;IACF;IAEA,OAAO;QACLC,OAAO,MAAMC,eAAe;YAC1BD,OAAOZ,aAAaY,KAAK;YACzBd;YACAC;QACF;QACAD;IACF;AACF,EAAC;AAED,OAAO,MAAMe,iBAAiB,OAAO,EACnCD,KAAK,EACLd,cAAc,EACdC,GAAG,EAKJ;IACC,gEAAgE;IAChE,IAAID,gBAAgB;QAClB,OAAOc;IACT;IAEA,MAAME,kBAA6B,EAAE;IAErC,MAAMC,cAAc,MAAMrB,iBAAiB;QAAEK;IAAI;IAEjD,KAAK,MAAMiB,QAAQJ,MAAO;QACxB,IAAI,CAAE,MAAMK,gBAAgB;YAAED;YAAMD;YAAahB;QAAI,IAAK;YACxD;QACF;QACAe,gBAAgBI,IAAI,CAACF;IACvB;IAEA,OAAOF;AACT,EAAC;AAED;;CAEC,GACD,MAAMG,kBAAkB,OAAO,EAC7BD,IAAI,EACJD,WAAW,EACXhB,GAAG,EAKJ;IACC,OAAQiB,KAAKG,IAAI;QACf,KAAK;YACH,OACE,CAACH,KAAKI,IAAI,CAACC,MAAM,IAChB,MAAML,KAAKI,IAAI,CAACC,MAAM,CAAC;gBAAEC,MAAMN,KAAKO,cAAc;gBAAER;gBAAahB;YAAI;QAE1E,KAAK;YACH,OACE,CAACiB,KAAKI,IAAI,CAACC,MAAM,IAAK,MAAML,KAAKI,IAAI,CAACC,MAAM,CAAC;gBAAEC,MAAMN,KAAKQ,UAAU;gBAAET;gBAAahB;YAAI;QAE3F,KAAK;YACH,OAAO,CAACiB,KAAKS,MAAM,CAACJ,MAAM,IAAK,MAAML,KAAKS,MAAM,CAACJ,MAAM,CAAC;gBAAEN;gBAAahB;YAAI;QAC7E,KAAK;YACH,OAAO,CAACiB,KAAKU,QAAQ,CAACL,MAAM,IAAK,MAAML,KAAKU,QAAQ,CAACL,MAAM,CAAC;gBAAEN;gBAAahB;YAAI;QACjF,KAAK;YACH,OAAO,CAACiB,KAAKI,IAAI,CAACC,MAAM,IAAK,MAAML,KAAKI,IAAI,CAACC,MAAM,CAAC;gBAAEN;gBAAahB;YAAI;IAC3E;AACF"}
@@ -1,3 +1,3 @@
1
- import { type PayloadHandler } from 'payload';
1
+ import type { PayloadHandler } from 'payload';
2
2
  export declare const mcpEndpoint: PayloadHandler;
3
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/endpoint/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAY,KAAK,cAAc,EAAE,MAAM,SAAS,CAAA;AAMvD,eAAO,MAAM,WAAW,EAAE,cAwCzB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/endpoint/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAkB,MAAM,SAAS,CAAA;AAa7D,eAAO,MAAM,WAAW,EAAE,cA+DzB,CAAA"}
@@ -1,4 +1,4 @@
1
- import { WebStandardStreamableHTTPServerTransport } from '@modelcontextprotocol/server';
1
+ import { createMcpHandler, isLegacyRequest, WebStandardStreamableHTTPServerTransport } from '@modelcontextprotocol/server';
2
2
  import { APIError } from 'payload';
3
3
  import { buildMcpServer } from '../mcp/buildMcpServer.js';
4
4
  import { getPluginConfig } from '../utils/getPluginConfig.js';
@@ -25,23 +25,63 @@ export const mcpEndpoint = async (req)=>{
25
25
  overrideAccess,
26
26
  req
27
27
  });
28
- const server = buildMcpServer({
29
- authorizedMCP,
30
- pluginConfig,
31
- req
32
- });
33
- const transport = new WebStandardStreamableHTTPServerTransport({
34
- enableJsonResponse: true,
35
- sessionIdGenerator: undefined
36
- });
37
- await server.connect(transport);
38
- const mcpRequest = new Request(req.url, {
39
- body: req.body,
40
- duplex: 'half',
41
- headers: req.headers,
42
- method: req.method
28
+ // Payload augments the original web-standard Request in place.
29
+ const mcpRequest = req;
30
+ // Keep the old JSON-only, stateless behavior because the SDK's 2025 fallback uses SSE.
31
+ if (await isLegacyRequest(mcpRequest)) {
32
+ const server = buildMcpServer({
33
+ authorizedMCP,
34
+ pluginConfig,
35
+ req
36
+ });
37
+ const transport = new WebStandardStreamableHTTPServerTransport({
38
+ enableJsonResponse: true,
39
+ sessionIdGenerator: undefined
40
+ });
41
+ transport.onerror = (err)=>{
42
+ req.payload.logger.error({
43
+ err,
44
+ msg: 'Error serving legacy MCP request'
45
+ });
46
+ };
47
+ try {
48
+ await server.connect(transport);
49
+ return await transport.handleRequest(mcpRequest);
50
+ } finally{
51
+ await server.close().catch((err)=>{
52
+ req.payload.logger.error({
53
+ err,
54
+ msg: 'Error closing MCP server'
55
+ });
56
+ });
57
+ }
58
+ }
59
+ const handler = createMcpHandler(()=>buildMcpServer({
60
+ authorizedMCP,
61
+ pluginConfig,
62
+ req
63
+ }), {
64
+ legacy: 'reject',
65
+ // SDK subscriptions always use SSE, so disable them to keep every response JSON-only.
66
+ maxSubscriptions: 0,
67
+ onerror: (err)=>{
68
+ req.payload.logger.error({
69
+ err,
70
+ msg: 'Error serving modern MCP request'
71
+ });
72
+ },
73
+ responseMode: 'json'
43
74
  });
44
- return await transport.handleRequest(mcpRequest);
75
+ try {
76
+ return await handler.fetch(mcpRequest);
77
+ } finally{
78
+ await handler.close().catch((err)=>{
79
+ req.payload.logger.error({
80
+ err,
81
+ msg: 'Error closing modern MCP handler'
82
+ });
83
+ });
84
+ }
45
85
  };
46
86
 
47
87
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/endpoint/index.ts"],"sourcesContent":["import { WebStandardStreamableHTTPServerTransport } from '@modelcontextprotocol/server'\nimport { APIError, type PayloadHandler } from 'payload'\n\nimport { buildMcpServer } from '../mcp/buildMcpServer.js'\nimport { getPluginConfig } from '../utils/getPluginConfig.js'\nimport { getAuthorizedMCP } from './access.js'\n\nexport const mcpEndpoint: PayloadHandler = async (req) => {\n if (!req.url) {\n throw new APIError('Missing request URL', 400)\n }\n\n req.payloadAPI = 'MCP' as const\n\n const pluginConfig = getPluginConfig({ config: req.payload.config })\n const overrideAccessParam = new URL(req.url).searchParams.get('overrideAccess')\n\n if (overrideAccessParam !== null && process.env.NODE_ENV !== 'development') {\n throw new APIError('MCP overrideAccess is only available in development.', 400)\n }\n\n let overrideAccess = false\n if (overrideAccessParam === 'true') {\n overrideAccess = true\n } else if (overrideAccessParam !== null && overrideAccessParam !== 'false') {\n throw new APIError('MCP overrideAccess must be \"true\" or \"false\".', 400)\n }\n\n const authorizedMCP = await getAuthorizedMCP({ overrideAccess, req })\n\n const server = buildMcpServer({ authorizedMCP, pluginConfig, req })\n\n const transport = new WebStandardStreamableHTTPServerTransport({\n enableJsonResponse: true,\n sessionIdGenerator: undefined, // stateless mode\n })\n\n await server.connect(transport)\n\n const mcpRequest = new Request(req.url, {\n body: req.body,\n duplex: 'half',\n headers: req.headers,\n method: req.method,\n } as { duplex: 'half' } & RequestInit)\n\n return await transport.handleRequest(mcpRequest)\n}\n"],"names":["WebStandardStreamableHTTPServerTransport","APIError","buildMcpServer","getPluginConfig","getAuthorizedMCP","mcpEndpoint","req","url","payloadAPI","pluginConfig","config","payload","overrideAccessParam","URL","searchParams","get","process","env","NODE_ENV","overrideAccess","authorizedMCP","server","transport","enableJsonResponse","sessionIdGenerator","undefined","connect","mcpRequest","Request","body","duplex","headers","method","handleRequest"],"mappings":"AAAA,SAASA,wCAAwC,QAAQ,+BAA8B;AACvF,SAASC,QAAQ,QAA6B,UAAS;AAEvD,SAASC,cAAc,QAAQ,2BAA0B;AACzD,SAASC,eAAe,QAAQ,8BAA6B;AAC7D,SAASC,gBAAgB,QAAQ,cAAa;AAE9C,OAAO,MAAMC,cAA8B,OAAOC;IAChD,IAAI,CAACA,IAAIC,GAAG,EAAE;QACZ,MAAM,IAAIN,SAAS,uBAAuB;IAC5C;IAEAK,IAAIE,UAAU,GAAG;IAEjB,MAAMC,eAAeN,gBAAgB;QAAEO,QAAQJ,IAAIK,OAAO,CAACD,MAAM;IAAC;IAClE,MAAME,sBAAsB,IAAIC,IAAIP,IAAIC,GAAG,EAAEO,YAAY,CAACC,GAAG,CAAC;IAE9D,IAAIH,wBAAwB,QAAQI,QAAQC,GAAG,CAACC,QAAQ,KAAK,eAAe;QAC1E,MAAM,IAAIjB,SAAS,wDAAwD;IAC7E;IAEA,IAAIkB,iBAAiB;IACrB,IAAIP,wBAAwB,QAAQ;QAClCO,iBAAiB;IACnB,OAAO,IAAIP,wBAAwB,QAAQA,wBAAwB,SAAS;QAC1E,MAAM,IAAIX,SAAS,iDAAiD;IACtE;IAEA,MAAMmB,gBAAgB,MAAMhB,iBAAiB;QAAEe;QAAgBb;IAAI;IAEnE,MAAMe,SAASnB,eAAe;QAAEkB;QAAeX;QAAcH;IAAI;IAEjE,MAAMgB,YAAY,IAAItB,yCAAyC;QAC7DuB,oBAAoB;QACpBC,oBAAoBC;IACtB;IAEA,MAAMJ,OAAOK,OAAO,CAACJ;IAErB,MAAMK,aAAa,IAAIC,QAAQtB,IAAIC,GAAG,EAAE;QACtCsB,MAAMvB,IAAIuB,IAAI;QACdC,QAAQ;QACRC,SAASzB,IAAIyB,OAAO;QACpBC,QAAQ1B,IAAI0B,MAAM;IACpB;IAEA,OAAO,MAAMV,UAAUW,aAAa,CAACN;AACvC,EAAC"}
1
+ {"version":3,"sources":["../../src/endpoint/index.ts"],"sourcesContent":["import type { PayloadHandler, PayloadRequest } from 'payload'\n\nimport {\n createMcpHandler,\n isLegacyRequest,\n WebStandardStreamableHTTPServerTransport,\n} from '@modelcontextprotocol/server'\nimport { APIError } from 'payload'\n\nimport { buildMcpServer } from '../mcp/buildMcpServer.js'\nimport { getPluginConfig } from '../utils/getPluginConfig.js'\nimport { getAuthorizedMCP } from './access.js'\n\nexport const mcpEndpoint: PayloadHandler = async (req) => {\n if (!req.url) {\n throw new APIError('Missing request URL', 400)\n }\n\n req.payloadAPI = 'MCP' as const\n\n const pluginConfig = getPluginConfig({ config: req.payload.config })\n const overrideAccessParam = new URL(req.url).searchParams.get('overrideAccess')\n\n if (overrideAccessParam !== null && process.env.NODE_ENV !== 'development') {\n throw new APIError('MCP overrideAccess is only available in development.', 400)\n }\n\n let overrideAccess = false\n if (overrideAccessParam === 'true') {\n overrideAccess = true\n } else if (overrideAccessParam !== null && overrideAccessParam !== 'false') {\n throw new APIError('MCP overrideAccess must be \"true\" or \"false\".', 400)\n }\n\n const authorizedMCP = await getAuthorizedMCP({ overrideAccess, req })\n // Payload augments the original web-standard Request in place.\n const mcpRequest = req as PayloadRequest & Request\n\n // Keep the old JSON-only, stateless behavior because the SDK's 2025 fallback uses SSE.\n if (await isLegacyRequest(mcpRequest)) {\n const server = buildMcpServer({ authorizedMCP, pluginConfig, req })\n const transport = new WebStandardStreamableHTTPServerTransport({\n enableJsonResponse: true,\n sessionIdGenerator: undefined, // stateless mode\n })\n transport.onerror = (err) => {\n req.payload.logger.error({ err, msg: 'Error serving legacy MCP request' })\n }\n\n try {\n await server.connect(transport)\n return await transport.handleRequest(mcpRequest)\n } finally {\n await server.close().catch((err) => {\n req.payload.logger.error({ err, msg: 'Error closing MCP server' })\n })\n }\n }\n\n const handler = createMcpHandler(() => buildMcpServer({ authorizedMCP, pluginConfig, req }), {\n legacy: 'reject',\n // SDK subscriptions always use SSE, so disable them to keep every response JSON-only.\n maxSubscriptions: 0,\n onerror: (err) => {\n req.payload.logger.error({ err, msg: 'Error serving modern MCP request' })\n },\n responseMode: 'json',\n })\n\n try {\n return await handler.fetch(mcpRequest)\n } finally {\n await handler.close().catch((err) => {\n req.payload.logger.error({ err, msg: 'Error closing modern MCP handler' })\n })\n }\n}\n"],"names":["createMcpHandler","isLegacyRequest","WebStandardStreamableHTTPServerTransport","APIError","buildMcpServer","getPluginConfig","getAuthorizedMCP","mcpEndpoint","req","url","payloadAPI","pluginConfig","config","payload","overrideAccessParam","URL","searchParams","get","process","env","NODE_ENV","overrideAccess","authorizedMCP","mcpRequest","server","transport","enableJsonResponse","sessionIdGenerator","undefined","onerror","err","logger","error","msg","connect","handleRequest","close","catch","handler","legacy","maxSubscriptions","responseMode","fetch"],"mappings":"AAEA,SACEA,gBAAgB,EAChBC,eAAe,EACfC,wCAAwC,QACnC,+BAA8B;AACrC,SAASC,QAAQ,QAAQ,UAAS;AAElC,SAASC,cAAc,QAAQ,2BAA0B;AACzD,SAASC,eAAe,QAAQ,8BAA6B;AAC7D,SAASC,gBAAgB,QAAQ,cAAa;AAE9C,OAAO,MAAMC,cAA8B,OAAOC;IAChD,IAAI,CAACA,IAAIC,GAAG,EAAE;QACZ,MAAM,IAAIN,SAAS,uBAAuB;IAC5C;IAEAK,IAAIE,UAAU,GAAG;IAEjB,MAAMC,eAAeN,gBAAgB;QAAEO,QAAQJ,IAAIK,OAAO,CAACD,MAAM;IAAC;IAClE,MAAME,sBAAsB,IAAIC,IAAIP,IAAIC,GAAG,EAAEO,YAAY,CAACC,GAAG,CAAC;IAE9D,IAAIH,wBAAwB,QAAQI,QAAQC,GAAG,CAACC,QAAQ,KAAK,eAAe;QAC1E,MAAM,IAAIjB,SAAS,wDAAwD;IAC7E;IAEA,IAAIkB,iBAAiB;IACrB,IAAIP,wBAAwB,QAAQ;QAClCO,iBAAiB;IACnB,OAAO,IAAIP,wBAAwB,QAAQA,wBAAwB,SAAS;QAC1E,MAAM,IAAIX,SAAS,iDAAiD;IACtE;IAEA,MAAMmB,gBAAgB,MAAMhB,iBAAiB;QAAEe;QAAgBb;IAAI;IACnE,+DAA+D;IAC/D,MAAMe,aAAaf;IAEnB,uFAAuF;IACvF,IAAI,MAAMP,gBAAgBsB,aAAa;QACrC,MAAMC,SAASpB,eAAe;YAAEkB;YAAeX;YAAcH;QAAI;QACjE,MAAMiB,YAAY,IAAIvB,yCAAyC;YAC7DwB,oBAAoB;YACpBC,oBAAoBC;QACtB;QACAH,UAAUI,OAAO,GAAG,CAACC;YACnBtB,IAAIK,OAAO,CAACkB,MAAM,CAACC,KAAK,CAAC;gBAAEF;gBAAKG,KAAK;YAAmC;QAC1E;QAEA,IAAI;YACF,MAAMT,OAAOU,OAAO,CAACT;YACrB,OAAO,MAAMA,UAAUU,aAAa,CAACZ;QACvC,SAAU;YACR,MAAMC,OAAOY,KAAK,GAAGC,KAAK,CAAC,CAACP;gBAC1BtB,IAAIK,OAAO,CAACkB,MAAM,CAACC,KAAK,CAAC;oBAAEF;oBAAKG,KAAK;gBAA2B;YAClE;QACF;IACF;IAEA,MAAMK,UAAUtC,iBAAiB,IAAMI,eAAe;YAAEkB;YAAeX;YAAcH;QAAI,IAAI;QAC3F+B,QAAQ;QACR,sFAAsF;QACtFC,kBAAkB;QAClBX,SAAS,CAACC;YACRtB,IAAIK,OAAO,CAACkB,MAAM,CAACC,KAAK,CAAC;gBAAEF;gBAAKG,KAAK;YAAmC;QAC1E;QACAQ,cAAc;IAChB;IAEA,IAAI;QACF,OAAO,MAAMH,QAAQI,KAAK,CAACnB;IAC7B,SAAU;QACR,MAAMe,QAAQF,KAAK,GAAGC,KAAK,CAAC,CAACP;YAC3BtB,IAAIK,OAAO,CAACkB,MAAM,CAACC,KAAK,CAAC;gBAAEF;gBAAKG,KAAK;YAAmC;QAC1E;IACF;AACF,EAAC"}
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import type { AuthorizedMCP, MCPPluginConfig, SanitizedMCPPluginConfig } from './types.js';
2
2
  declare module 'payload' {
3
- interface PayloadRequest {
4
- payloadAPI: 'GraphQL' | 'local' | 'MCP' | 'REST';
3
+ interface PayloadRequestAPI {
4
+ MCP: true;
5
5
  }
6
6
  interface RegisteredPlugins {
7
7
  /** After the plugin's `plugin` callback runs, `options` holds the sanitized config. */
@@ -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;AAK1F,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,wDAiCpB,CAAA"}
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;AAK1F,OAAO,QAAQ,SAAS,CAAC;IACvB,UAAiB,iBAAiB;QAChC,GAAG,EAAE,IAAI,CAAA;KACV;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,wDAiCpB,CAAA"}
package/dist/index.js CHANGED
@@ -5,10 +5,10 @@ export { defineCollectionTool, defineGlobalTool, definePrompt, defineTool } from
5
5
  export const mcpPlugin = definePlugin({
6
6
  slug: '@payloadcms/plugin-mcp',
7
7
  order: 10,
8
- plugin: ({ config, plugins, ...rawConfig })=>{
8
+ plugin: ({ config, options, plugins })=>{
9
9
  const pluginConfig = sanitizeMCPConfig({
10
10
  config,
11
- pluginConfig: rawConfig
11
+ pluginConfig: options
12
12
  });
13
13
  // Stash the sanitized config on plugin options so `getPluginConfig()` reads it.
14
14
  const registered = plugins['@payloadcms/plugin-mcp'];
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { definePlugin } from 'payload'\n\nimport type { AuthorizedMCP, MCPPluginConfig, SanitizedMCPPluginConfig } from './types.js'\n\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 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 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 // 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":["definePlugin","mcpEndpoint","sanitizeMCPConfig","defineCollectionTool","defineGlobalTool","definePrompt","defineTool","mcpPlugin","slug","order","plugin","config","plugins","rawConfig","pluginConfig","registered","sanitizedOptions","disabled","endpoints","handler","method","path","Response","headers","Allow","status"],"mappings":"AAAA,SAASA,YAAY,QAAQ,UAAS;AAItC,SAASC,WAAW,QAAQ,sBAAqB;AACjD,SAASC,iBAAiB,QAAQ,6BAA4B;AAc9D,SAASC,oBAAoB,EAAEC,gBAAgB,EAAEC,YAAY,EAAEC,UAAU,QAAQ,kBAAiB;AAElG,OAAO,MAAMC,YAAYP,aAA8B;IACrDQ,MAAM;IACNC,OAAO;IACPC,QAAQ,CAAC,EAAEC,MAAM,EAAEC,OAAO,EAAE,GAAGC,WAAW;QACxC,MAAMC,eAAeZ,kBAAkB;YAAES;YAAQG,cAAcD;QAAU;QAEzE,gFAAgF;QAChF,MAAME,aAAaH,OAAO,CAAC,yBAAyB;QACpD,IAAIG,YAAY;YACd,mBAAmB;YACnBA,WAAWC,gBAAgB,GAAGF;QAChC;QAEA,IAAIA,aAAaG,QAAQ,EAAE;YACzB,OAAON;QACT;QAEA,OAAO;YACL,GAAGA,MAAM;YACTO,WAAW;mBACLP,OAAOO,SAAS,IAAI,EAAE;gBAC1B,uDAAuD;gBACvD;oBAAEC,SAASlB;oBAAamB,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
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { definePlugin } from 'payload'\n\nimport type { AuthorizedMCP, MCPPluginConfig, SanitizedMCPPluginConfig } from './types.js'\n\nimport { mcpEndpoint } from './endpoint/index.js'\nimport { sanitizeMCPConfig } from './mcp/sanitizeMCPConfig.js'\n\ndeclare module 'payload' {\n export interface PayloadRequestAPI {\n MCP: true\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, options, plugins }) => {\n const pluginConfig = sanitizeMCPConfig({ config, pluginConfig: options })\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 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 // 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":["definePlugin","mcpEndpoint","sanitizeMCPConfig","defineCollectionTool","defineGlobalTool","definePrompt","defineTool","mcpPlugin","slug","order","plugin","config","options","plugins","pluginConfig","registered","sanitizedOptions","disabled","endpoints","handler","method","path","Response","headers","Allow","status"],"mappings":"AAAA,SAASA,YAAY,QAAQ,UAAS;AAItC,SAASC,WAAW,QAAQ,sBAAqB;AACjD,SAASC,iBAAiB,QAAQ,6BAA4B;AAc9D,SAASC,oBAAoB,EAAEC,gBAAgB,EAAEC,YAAY,EAAEC,UAAU,QAAQ,kBAAiB;AAElG,OAAO,MAAMC,YAAYP,aAA8B;IACrDQ,MAAM;IACNC,OAAO;IACPC,QAAQ,CAAC,EAAEC,MAAM,EAAEC,OAAO,EAAEC,OAAO,EAAE;QACnC,MAAMC,eAAeZ,kBAAkB;YAAES;YAAQG,cAAcF;QAAQ;QAEvE,gFAAgF;QAChF,MAAMG,aAAaF,OAAO,CAAC,yBAAyB;QACpD,IAAIE,YAAY;YACd,mBAAmB;YACnBA,WAAWC,gBAAgB,GAAGF;QAChC;QAEA,IAAIA,aAAaG,QAAQ,EAAE;YACzB,OAAON;QACT;QAEA,OAAO;YACL,GAAGA,MAAM;YACTO,WAAW;mBACLP,OAAOO,SAAS,IAAI,EAAE;gBAC1B,uDAAuD;gBACvD;oBAAEC,SAASlB;oBAAamB,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,11 +1,11 @@
1
+ import type { PayloadRequest } from 'payload';
1
2
  import { McpServer } from '@modelcontextprotocol/server';
2
- import { type PayloadRequest } from 'payload';
3
3
  import type { AuthorizedMCP, SanitizedMCPPluginConfig } from '../types.js';
4
4
  /**
5
- * Transport-agnostic core: registers every authorized MCP item onto a fresh
6
- * `McpServer` and returns it. The caller is responsible for picking a transport
7
- * (`WebStandardStreamableHTTPServerTransport`, `StdioServerTransport`, …) and
8
- * calling `server.connect(transport)`.
5
+ * Serving-entry-agnostic core: registers every authorized MCP item onto a fresh
6
+ * `McpServer` and returns it. The HTTP and stdio entry point callers provide fresh
7
+ * instances from this builder while they own the transport and protocol-era
8
+ * decision.
9
9
  *
10
10
  * `req` is the request context handlers see. For HTTP it's the live
11
11
  * `PayloadRequest` derived from the incoming HTTP request; for stdio it's a
@@ -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,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,SA8LH,CAAA"}
1
+ {"version":3,"file":"buildMcpServer.d.ts","sourceRoot":"","sources":["../../src/mcp/buildMcpServer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAE7C,OAAO,EAAE,SAAS,EAAsB,MAAM,8BAA8B,CAAA;AAG5E,OAAO,KAAK,EACV,aAAa,EAMb,wBAAwB,EAEzB,MAAM,aAAa,CAAA;AAOpB;;;;;;;;;GASG;AACH,eAAO,MAAM,cAAc,0CAIxB;IACD,aAAa,EAAE,aAAa,CAAA;IAC5B,YAAY,EAAE,wBAAwB,CAAA;IACtC,GAAG,EAAE,cAAc,CAAA;CACpB,KAAG,SA8MH,CAAA"}
@@ -1,13 +1,13 @@
1
1
  import { McpServer } from '@modelcontextprotocol/server';
2
- import { APIError } from 'payload';
3
- import { z } from 'zod';
2
+ import { APIError, strictObject, z } from 'payload';
4
3
  import { getLogger } from '../utils/getLogger.js';
5
4
  import { toStandardSchema } from '../utils/toStandardSchema.js';
5
+ z.config(z.locales.en());
6
6
  /**
7
- * Transport-agnostic core: registers every authorized MCP item onto a fresh
8
- * `McpServer` and returns it. The caller is responsible for picking a transport
9
- * (`WebStandardStreamableHTTPServerTransport`, `StdioServerTransport`, …) and
10
- * calling `server.connect(transport)`.
7
+ * Serving-entry-agnostic core: registers every authorized MCP item onto a fresh
8
+ * `McpServer` and returns it. The HTTP and stdio entry point callers provide fresh
9
+ * instances from this builder while they own the transport and protocol-era
10
+ * decision.
11
11
  *
12
12
  * `req` is the request context handlers see. For HTTP it's the live
13
13
  * `PayloadRequest` derived from the incoming HTTP request; for stdio it's a
@@ -25,27 +25,34 @@ import { toStandardSchema } from '../utils/toStandardSchema.js';
25
25
  /**
26
26
  * Wrap a tool handler's response with the tool's `overrideResponse`, then
27
27
  * strip the internal `doc` field so it doesn't leak onto the wire.
28
- */ const finalizeToolResponse = (response, overrideResponse)=>{
29
- const overridden = overrideResponse?.(response, response.doc ?? {}, req) ?? response;
28
+ */ const finalizeToolResponse = async ({ input, overrideResponse, response, toolName })=>{
29
+ let overridden = overrideResponse?.(response, response.doc ?? {}, req) ?? response;
30
+ for (const hook of pluginConfig.hooks?.afterToolCall ?? []){
31
+ overridden = await hook({
32
+ input,
33
+ req,
34
+ response: overridden,
35
+ toolName
36
+ });
37
+ }
30
38
  const { doc: _doc, ...rest } = overridden;
31
39
  return rest;
32
40
  };
33
41
  /**
34
42
  * Runs a collection/global tool call:
35
- * - reads `collectionSlug` / `globalSlug` from the input
43
+ * - reads `slug` from the input
36
44
  * - runs access control: errors if `authorizedMCP.items` has no entry for this tool + slug
37
45
  * - runs the tool handler and finalizes its response
38
46
  */ const callEntityTool = async ({ input, item, serverContext })=>{
39
47
  const entity = item.type === 'collectionTool' ? 'collection' : 'global';
40
- const slugKey = item.type === 'collectionTool' ? 'collectionSlug' : 'globalSlug';
41
48
  const toolInput = input ?? {};
42
- const slug = toolInput[slugKey];
49
+ const slug = toolInput.slug;
43
50
  if (!slug) {
44
51
  return {
45
52
  content: [
46
53
  {
47
54
  type: 'text',
48
- text: `Error: "${item.mcpName}" requires ${slugKey}. Use getConfigInfo to inspect ${entity} slugs.`
55
+ text: `Error: "${item.mcpName}" requires slug. Use getConfigInfo to inspect ${entity} slugs.`
49
56
  }
50
57
  ],
51
58
  isError: true
@@ -71,12 +78,17 @@ import { toStandardSchema } from '../utils/toStandardSchema.js';
71
78
  };
72
79
  const response = await (match.type === 'collectionTool' ? match.tool.handler({
73
80
  ...handlerArgs,
74
- collectionSlug: slug
81
+ slug
75
82
  }) : match.tool.handler({
76
83
  ...handlerArgs,
77
- globalSlug: slug
84
+ slug
78
85
  }));
79
- return finalizeToolResponse(response, match.tool.overrideResponse);
86
+ return finalizeToolResponse({
87
+ input: toolInput,
88
+ overrideResponse: match.tool.overrideResponse,
89
+ response,
90
+ toolName: match.mcpName
91
+ });
80
92
  };
81
93
  try {
82
94
  const registeredEntityTools = new Set();
@@ -90,7 +102,6 @@ import { toStandardSchema } from '../utils/toStandardSchema.js';
90
102
  }
91
103
  registeredEntityTools.add(item.mcpName);
92
104
  const inputSchema = withSlugInput({
93
- name: item.type === 'collectionTool' ? 'collectionSlug' : 'globalSlug',
94
105
  input: item.tool.input
95
106
  });
96
107
  server.registerTool(item.mcpName, {
@@ -151,12 +162,21 @@ import { toStandardSchema } from '../utils/toStandardSchema.js';
151
162
  annotations: tool.annotations,
152
163
  description: tool.description,
153
164
  inputSchema: tool.input ? toStandardSchema(tool.input) : undefined
154
- }, async (input, ctx)=>finalizeToolResponse(await tool.handler({
165
+ }, async (input, ctx)=>{
166
+ const toolInput = input ?? {};
167
+ const response = await tool.handler({
155
168
  authorizedMCP,
156
- input: input ?? {},
169
+ input: toolInput,
157
170
  req,
158
171
  serverContext: ctx
159
- }), tool.overrideResponse));
172
+ });
173
+ return finalizeToolResponse({
174
+ input: toolInput,
175
+ overrideResponse: tool.overrideResponse,
176
+ response,
177
+ toolName: item.mcpName
178
+ });
179
+ });
160
180
  logger.info(`✅ Tool: ${item.mcpName} Registered.`);
161
181
  break;
162
182
  }
@@ -167,33 +187,47 @@ import { toStandardSchema } from '../utils/toStandardSchema.js';
167
187
  }
168
188
  return server;
169
189
  };
170
- const withSlugInput = ({ name, input })=>{
171
- const description = name === 'collectionSlug' ? 'The collection slug' : 'The global slug';
172
- const slugSchema = z.string().describe(description);
190
+ const withSlugInput = ({ input })=>{
191
+ const description = 'The target slug.';
192
+ const slugSchema = z.string().check(z.describe(description));
173
193
  if (!input) {
174
- return z.object({
175
- [name]: slugSchema
194
+ return strictObject({
195
+ slug: slugSchema
176
196
  });
177
197
  }
178
- if (input instanceof z.ZodObject) {
179
- return input.extend({
180
- [name]: slugSchema
198
+ if (typeof input === 'object' && input !== null && '~standard' in input) {
199
+ const schema = input['~standard'].jsonSchema.input({
200
+ target: 'draft-2020-12'
201
+ });
202
+ const properties = schema.properties;
203
+ if (properties?.slug) {
204
+ return input;
205
+ }
206
+ return addSlugToJSONSchema({
207
+ description,
208
+ schema: schema
181
209
  });
182
210
  }
183
- const schema = input;
211
+ return addSlugToJSONSchema({
212
+ description,
213
+ schema: input
214
+ });
215
+ };
216
+ const addSlugToJSONSchema = ({ description, schema })=>{
217
+ const objectSchema = schema;
184
218
  return {
185
- ...schema,
219
+ ...objectSchema,
186
220
  type: 'object',
187
221
  properties: {
188
- ...schema.properties,
189
- [name]: {
222
+ ...objectSchema.properties,
223
+ slug: {
190
224
  type: 'string',
191
225
  description
192
226
  }
193
227
  },
194
228
  required: Array.from(new Set([
195
- name,
196
- ...schema.required ?? []
229
+ 'slug',
230
+ ...objectSchema.required ?? []
197
231
  ]))
198
232
  };
199
233
  };