@payloadcms/plugin-mcp 4.0.0-internal.41055b1 → 4.0.0-internal.435b2d6

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 (58) hide show
  1. package/bin.js +6 -8
  2. package/dist/defaultAccess.d.ts.map +1 -1
  3. package/dist/defineTool.d.ts +8 -8
  4. package/dist/defineTool.d.ts.map +1 -1
  5. package/dist/endpoint/access.d.ts.map +1 -1
  6. package/dist/mcp/buildMcpServer.d.ts.map +1 -1
  7. package/dist/mcp/builtin/collections/createTool.d.ts.map +1 -1
  8. package/dist/mcp/builtin/collections/createTool.js +11 -1
  9. package/dist/mcp/builtin/collections/createTool.js.map +1 -1
  10. package/dist/mcp/builtin/collections/fileInput.d.ts +20 -0
  11. package/dist/mcp/builtin/collections/fileInput.d.ts.map +1 -0
  12. package/dist/mcp/builtin/collections/fileInput.js +100 -0
  13. package/dist/mcp/builtin/collections/fileInput.js.map +1 -0
  14. package/dist/mcp/builtin/collections/fileInput.spec.js +72 -0
  15. package/dist/mcp/builtin/collections/fileInput.spec.js.map +1 -0
  16. package/dist/mcp/builtin/collections/formatCollectionError.d.ts +1 -1
  17. package/dist/mcp/builtin/collections/formatCollectionError.d.ts.map +1 -1
  18. package/dist/mcp/builtin/collections/getCollectionSchemaTool.d.ts.map +1 -1
  19. package/dist/mcp/builtin/collections/getCollectionSchemaTool.js +23 -2
  20. package/dist/mcp/builtin/collections/getCollectionSchemaTool.js.map +1 -1
  21. package/dist/mcp/builtin/collections/updateTool.d.ts.map +1 -1
  22. package/dist/mcp/builtin/collections/updateTool.js +12 -6
  23. package/dist/mcp/builtin/collections/updateTool.js.map +1 -1
  24. package/dist/mcp/builtin/validateEntityData.d.ts.map +1 -1
  25. package/dist/mcp/builtinTools.d.ts.map +1 -1
  26. package/dist/mcp/sanitizeMCPConfig.d.ts.map +1 -1
  27. package/dist/stdio.d.ts +1 -2
  28. package/dist/stdio.d.ts.map +1 -1
  29. package/dist/stdio.js +4 -6
  30. package/dist/stdio.js.map +1 -1
  31. package/dist/utils/camelCase.d.ts.map +1 -1
  32. package/dist/utils/resolveProjectRoot.d.ts.map +1 -1
  33. package/dist/utils/schemaConversion/filterFieldsByAccess.d.ts.map +1 -1
  34. package/dist/utils/schemaConversion/getEntityInputSchema.d.ts.map +1 -1
  35. package/dist/utils/schemaConversion/sanitizeEntitySchema.d.ts.map +1 -1
  36. package/dist/utils/toStandardSchema.d.ts.map +1 -1
  37. package/package.json +5 -18
  38. package/src/mcp/builtin/collections/createTool.ts +5 -1
  39. package/src/mcp/builtin/collections/fileInput.spec.ts +79 -0
  40. package/src/mcp/builtin/collections/fileInput.ts +139 -0
  41. package/src/mcp/builtin/collections/getCollectionSchemaTool.ts +14 -1
  42. package/src/mcp/builtin/collections/updateTool.ts +6 -4
  43. package/src/stdio.ts +4 -6
  44. package/dist/bin/index.d.ts +0 -2
  45. package/dist/bin/index.d.ts.map +0 -1
  46. package/dist/bin/index.js +0 -12
  47. package/dist/bin/index.js.map +0 -1
  48. package/dist/bin/initializeViteHMR.d.ts +0 -8
  49. package/dist/bin/initializeViteHMR.d.ts.map +0 -1
  50. package/dist/bin/initializeViteHMR.js +0 -75
  51. package/dist/bin/initializeViteHMR.js.map +0 -1
  52. package/dist/bin/viteConfigBoundary.d.ts +0 -6
  53. package/dist/bin/viteConfigBoundary.d.ts.map +0 -1
  54. package/dist/bin/viteConfigBoundary.js +0 -25
  55. package/dist/bin/viteConfigBoundary.js.map +0 -1
  56. package/src/bin/index.ts +0 -16
  57. package/src/bin/initializeViteHMR.ts +0 -76
  58. package/src/bin/viteConfigBoundary.ts +0 -39
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/mcp/builtin/collections/updateTool.ts"],"sourcesContent":["import type { SelectType, Where } from 'payload'\n\nimport { z } from 'zod'\n\nimport { defaultAccess } from '../../../defaultAccess.js'\nimport { defineCollectionTool } from '../../../defineTool.js'\nimport { getLogger } from '../../../utils/getLogger.js'\nimport {\n getCollectionVirtualFieldNames,\n stripVirtualFields,\n} from '../../../utils/getVirtualFieldNames.js'\nimport { getCollectionInputSchema } from '../../../utils/schemaConversion/getEntityInputSchema.js'\nimport { transformPointDataToPayload } from '../../../utils/transformPointDataToPayload.js'\nimport { whereSchema } from '../../../utils/whereSchema.js'\nimport { validateCollectionData } from '../validateEntityData.js'\nimport { formatCollectionError } from './formatCollectionError.js'\n\nconst DEFAULT_DESCRIPTION =\n 'Update documents in any collection by passing the collection slug and data.'\n\nexport const updateDocumentTool = defineCollectionTool({\n access: (args) =>\n defaultAccess(args) && Boolean(args.permissions?.collections?.[args.collectionSlug]?.update),\n annotations: {\n destructiveHint: true,\n idempotentHint: false,\n openWorldHint: false,\n readOnlyHint: false,\n title: 'Update Document',\n },\n description: DEFAULT_DESCRIPTION,\n input: z.object({\n id: z.union([z.string(), z.number()]).describe('The ID of the document to update').optional(),\n data: z\n .record(z.string(), z.unknown())\n .describe(\n 'The fields to update. Only include fields permitted by the schema returned by getCollectionSchema.',\n ),\n depth: z\n .number()\n .describe('How many levels deep to populate relationships')\n .optional()\n .default(0),\n draft: z\n .boolean()\n .describe(\n 'Only if getCollectionSchema includes _status; otherwise _status does not exist. true saves only a draft version; false updates main and versions. data._status: \"published\" overrides true.',\n )\n .optional()\n .default(false),\n fallbackLocale: z\n .string()\n .describe('Optional: fallback locale code to use when requested locale is not available')\n .optional(),\n filePath: z.string().describe('File path for file uploads').optional(),\n locale: z\n .string()\n .describe(\n 'Optional: locale code to update the document in (e.g., \"en\", \"es\"). Defaults to the default locale',\n )\n .optional(),\n overrideLock: z\n .boolean()\n .describe('Whether to override document locks')\n .optional()\n .default(true),\n overwriteExistingFiles: z\n .boolean()\n .describe('Whether to overwrite existing files')\n .optional()\n .default(false),\n publishAllLocales: z\n .boolean()\n .describe(\n 'For collections with localized publishing status, whether publishing should affect every locale. Set false with locale to publish only that locale.',\n )\n .optional(),\n select: z\n .record(z.string(), z.unknown())\n .describe(\n 'Optional: define exactly which fields you\\'d like to return in the response, e.g., {\"title\": true}',\n )\n .optional(),\n where: whereSchema\n .describe(\n 'Where clause to update multiple documents. Use field names with Payload operators, and/or arrays for grouping. Example: {\"title\":{\"contains\":\"test\"}}',\n )\n .optional(),\n }),\n}).handler(async ({ authorizedMCP, collectionSlug, input, req }) => {\n const payload = req.payload\n const logger = getLogger({ payload })\n\n const {\n id,\n data,\n depth,\n draft,\n fallbackLocale,\n filePath,\n locale,\n overrideLock,\n overwriteExistingFiles,\n publishAllLocales,\n select,\n where,\n } = input\n\n logger.info(\n `Updating document in collection: ${collectionSlug}${id ? ` with ID: ${id}` : ' with where clause'}, draft: ${draft}${locale ? `, locale: ${locale}` : ''}`,\n )\n\n try {\n if (!id && !where) {\n return {\n content: [{ type: 'text', text: 'Error: Either id or where clause must be provided' }],\n }\n }\n\n const virtualFieldNames = getCollectionVirtualFieldNames(payload.config, collectionSlug)\n const inputData = stripVirtualFields(data, virtualFieldNames)\n const validationError = validateCollectionData({\n collectionSlug,\n data: inputData,\n partial: true,\n req,\n })\n\n if (validationError) {\n return validationError\n }\n\n const parsedData = transformPointDataToPayload(inputData)\n\n const whereClause: Where = where ?? {}\n\n if (id) {\n const result = await payload.update({\n id,\n collection: collectionSlug,\n data: parsedData,\n depth,\n draft,\n overrideAccess: authorizedMCP.overrideAccess,\n overrideLock,\n req,\n ...(filePath ? { filePath } : {}),\n ...(overwriteExistingFiles ? { overwriteExistingFiles } : {}),\n ...(publishAllLocales !== undefined ? { publishAllLocales } : {}),\n ...(locale ? { locale } : {}),\n ...(fallbackLocale ? { fallbackLocale } : {}),\n ...(select ? { select: select as SelectType } : {}),\n })\n\n return {\n content: [\n {\n type: 'text',\n text: `Document updated successfully in collection \"${collectionSlug}\"!\\nUpdated document:\\n\\`\\`\\`json\\n${JSON.stringify(result)}\\n\\`\\`\\``,\n },\n ],\n doc: result as Record<string, unknown>,\n }\n }\n\n const result = await payload.update({\n collection: collectionSlug,\n data: parsedData,\n depth,\n draft,\n overrideAccess: authorizedMCP.overrideAccess,\n overrideLock,\n req,\n where: whereClause,\n ...(filePath ? { filePath } : {}),\n ...(overwriteExistingFiles ? { overwriteExistingFiles } : {}),\n ...(publishAllLocales !== undefined ? { publishAllLocales } : {}),\n ...(locale ? { locale } : {}),\n ...(fallbackLocale ? { fallbackLocale } : {}),\n ...(select ? { select: select as SelectType } : {}),\n })\n\n const docs = result.docs || []\n const errors = result.errors || []\n\n let responseText = `Multiple documents updated in collection \"${collectionSlug}\"!\\nUpdated: ${docs.length} documents\\nErrors: ${errors.length}\\n---`\n if (docs.length > 0) {\n responseText += `\\n\\nUpdated documents:\\n\\`\\`\\`json\\n${JSON.stringify(docs)}\\n\\`\\`\\``\n }\n if (errors.length > 0) {\n responseText += `\\n\\nErrors:\\n\\`\\`\\`json\\n${JSON.stringify(errors)}\\n\\`\\`\\``\n\n const errorSchema = getCollectionInputSchema({ collectionSlug, req })\n\n if (errorSchema) {\n responseText += `\\n\\nUse this schema for data:\\n\\`\\`\\`json\\n${JSON.stringify(errorSchema)}\\n\\`\\`\\``\n }\n\n return {\n content: [{ type: 'text', text: responseText }],\n doc: { docs, errors } as unknown as Record<string, unknown>,\n isError: true,\n ...(errorSchema\n ? {\n structuredContent: {\n collectionSlug,\n docs,\n errors,\n schema: errorSchema,\n },\n }\n : {}),\n }\n }\n\n return {\n content: [{ type: 'text', text: responseText }],\n doc: { docs, errors } as unknown as Record<string, unknown>,\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : 'Unknown error'\n logger.error(`Error updating document in ${collectionSlug}: ${errorMessage}`)\n return formatCollectionError({ action: 'updating', collectionSlug, error, req })\n }\n})\n"],"names":["z","defaultAccess","defineCollectionTool","getLogger","getCollectionVirtualFieldNames","stripVirtualFields","getCollectionInputSchema","transformPointDataToPayload","whereSchema","validateCollectionData","formatCollectionError","DEFAULT_DESCRIPTION","updateDocumentTool","access","args","Boolean","permissions","collections","collectionSlug","update","annotations","destructiveHint","idempotentHint","openWorldHint","readOnlyHint","title","description","input","object","id","union","string","number","describe","optional","data","record","unknown","depth","default","draft","boolean","fallbackLocale","filePath","locale","overrideLock","overwriteExistingFiles","publishAllLocales","select","where","handler","authorizedMCP","req","payload","logger","info","content","type","text","virtualFieldNames","config","inputData","validationError","partial","parsedData","whereClause","result","collection","overrideAccess","undefined","JSON","stringify","doc","docs","errors","responseText","length","errorSchema","isError","structuredContent","schema","error","errorMessage","Error","message","action"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../src/mcp/builtin/collections/updateTool.ts"],"sourcesContent":["import type { SelectType, Where } from 'payload'\n\nimport { z } from 'zod'\n\nimport { defaultAccess } from '../../../defaultAccess.js'\nimport { defineCollectionTool } from '../../../defineTool.js'\nimport { getLogger } from '../../../utils/getLogger.js'\nimport {\n getCollectionVirtualFieldNames,\n stripVirtualFields,\n} from '../../../utils/getVirtualFieldNames.js'\nimport { getCollectionInputSchema } from '../../../utils/schemaConversion/getEntityInputSchema.js'\nimport { transformPointDataToPayload } from '../../../utils/transformPointDataToPayload.js'\nimport { whereSchema } from '../../../utils/whereSchema.js'\nimport { validateCollectionData } from '../validateEntityData.js'\nimport { fileInputSchema, resolveFileInput } from './fileInput.js'\nimport { formatCollectionError } from './formatCollectionError.js'\n\nconst DEFAULT_DESCRIPTION =\n 'Update documents in any collection by passing the collection slug and data.'\n\nexport const updateDocumentTool = defineCollectionTool({\n access: (args) =>\n defaultAccess(args) && Boolean(args.permissions?.collections?.[args.collectionSlug]?.update),\n annotations: {\n destructiveHint: true,\n idempotentHint: false,\n openWorldHint: false,\n readOnlyHint: false,\n title: 'Update Document',\n },\n description: DEFAULT_DESCRIPTION,\n input: z.object({\n id: z.union([z.string(), z.number()]).describe('The ID of the document to update').optional(),\n data: z\n .record(z.string(), z.unknown())\n .describe(\n 'The fields to update. Only include fields permitted by the schema returned by getCollectionSchema.',\n ),\n depth: z\n .number()\n .describe('How many levels deep to populate relationships')\n .optional()\n .default(0),\n draft: z\n .boolean()\n .describe(\n 'Only if getCollectionSchema includes _status; otherwise _status does not exist. true saves only a draft version; false updates main and versions. data._status: \"published\" overrides true.',\n )\n .optional()\n .default(false),\n fallbackLocale: z\n .string()\n .describe('Optional: fallback locale code to use when requested locale is not available')\n .optional(),\n file: fileInputSchema.optional(),\n locale: z\n .string()\n .describe(\n 'Optional: locale code to update the document in (e.g., \"en\", \"es\"). Defaults to the default locale',\n )\n .optional(),\n overrideLock: z\n .boolean()\n .describe('Whether to override document locks')\n .optional()\n .default(true),\n overwriteExistingFiles: z\n .boolean()\n .describe('Whether to overwrite existing files')\n .optional()\n .default(false),\n publishAllLocales: z\n .boolean()\n .describe(\n 'For collections with localized publishing status, whether publishing should affect every locale. Set false with locale to publish only that locale.',\n )\n .optional(),\n select: z\n .record(z.string(), z.unknown())\n .describe(\n 'Optional: define exactly which fields you\\'d like to return in the response, e.g., {\"title\": true}',\n )\n .optional(),\n where: whereSchema\n .describe(\n 'Where clause to update multiple documents. Use field names with Payload operators, and/or arrays for grouping. Example: {\"title\":{\"contains\":\"test\"}}',\n )\n .optional(),\n }),\n}).handler(async ({ authorizedMCP, collectionSlug, input, req }) => {\n const payload = req.payload\n const logger = getLogger({ payload })\n\n const {\n id,\n data,\n depth,\n draft,\n fallbackLocale,\n file: fileInput,\n locale,\n overrideLock,\n overwriteExistingFiles,\n publishAllLocales,\n select,\n where,\n } = input\n\n logger.info(\n `Updating document in collection: ${collectionSlug}${id ? ` with ID: ${id}` : ' with where clause'}, draft: ${draft}${locale ? `, locale: ${locale}` : ''}`,\n )\n\n try {\n if (!id && !where) {\n return {\n content: [{ type: 'text', text: 'Error: Either id or where clause must be provided' }],\n }\n }\n\n const virtualFieldNames = getCollectionVirtualFieldNames(payload.config, collectionSlug)\n const inputData = stripVirtualFields(data, virtualFieldNames)\n const validationError = validateCollectionData({\n collectionSlug,\n data: inputData,\n partial: true,\n req,\n })\n\n if (validationError) {\n return validationError\n }\n\n const parsedData = transformPointDataToPayload(inputData)\n const file = await resolveFileInput({ collectionSlug, input: fileInput, req })\n\n const whereClause: Where = where ?? {}\n\n if (id) {\n const result = await payload.update({\n id,\n collection: collectionSlug,\n data: parsedData,\n depth,\n draft,\n overrideAccess: authorizedMCP.overrideAccess,\n overrideLock,\n req,\n ...(file ? { file } : {}),\n ...(overwriteExistingFiles ? { overwriteExistingFiles } : {}),\n ...(publishAllLocales !== undefined ? { publishAllLocales } : {}),\n ...(locale ? { locale } : {}),\n ...(fallbackLocale ? { fallbackLocale } : {}),\n ...(select ? { select: select as SelectType } : {}),\n })\n\n return {\n content: [\n {\n type: 'text',\n text: `Document updated successfully in collection \"${collectionSlug}\"!\\nUpdated document:\\n\\`\\`\\`json\\n${JSON.stringify(result)}\\n\\`\\`\\``,\n },\n ],\n doc: result as Record<string, unknown>,\n }\n }\n\n const result = await payload.update({\n collection: collectionSlug,\n data: parsedData,\n depth,\n draft,\n overrideAccess: authorizedMCP.overrideAccess,\n overrideLock,\n req,\n where: whereClause,\n ...(file ? { file } : {}),\n ...(overwriteExistingFiles ? { overwriteExistingFiles } : {}),\n ...(publishAllLocales !== undefined ? { publishAllLocales } : {}),\n ...(locale ? { locale } : {}),\n ...(fallbackLocale ? { fallbackLocale } : {}),\n ...(select ? { select: select as SelectType } : {}),\n })\n\n const docs = result.docs || []\n const errors = result.errors || []\n\n let responseText = `Multiple documents updated in collection \"${collectionSlug}\"!\\nUpdated: ${docs.length} documents\\nErrors: ${errors.length}\\n---`\n if (docs.length > 0) {\n responseText += `\\n\\nUpdated documents:\\n\\`\\`\\`json\\n${JSON.stringify(docs)}\\n\\`\\`\\``\n }\n if (errors.length > 0) {\n responseText += `\\n\\nErrors:\\n\\`\\`\\`json\\n${JSON.stringify(errors)}\\n\\`\\`\\``\n\n const errorSchema = getCollectionInputSchema({ collectionSlug, req })\n\n if (errorSchema) {\n responseText += `\\n\\nUse this schema for data:\\n\\`\\`\\`json\\n${JSON.stringify(errorSchema)}\\n\\`\\`\\``\n }\n\n return {\n content: [{ type: 'text', text: responseText }],\n doc: { docs, errors } as unknown as Record<string, unknown>,\n isError: true,\n ...(errorSchema\n ? {\n structuredContent: {\n collectionSlug,\n docs,\n errors,\n schema: errorSchema,\n },\n }\n : {}),\n }\n }\n\n return {\n content: [{ type: 'text', text: responseText }],\n doc: { docs, errors } as unknown as Record<string, unknown>,\n }\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : 'Unknown error'\n logger.error(`Error updating document in ${collectionSlug}: ${errorMessage}`)\n return formatCollectionError({ action: 'updating', collectionSlug, error, req })\n }\n})\n"],"names":["z","defaultAccess","defineCollectionTool","getLogger","getCollectionVirtualFieldNames","stripVirtualFields","getCollectionInputSchema","transformPointDataToPayload","whereSchema","validateCollectionData","fileInputSchema","resolveFileInput","formatCollectionError","DEFAULT_DESCRIPTION","updateDocumentTool","access","args","Boolean","permissions","collections","collectionSlug","update","annotations","destructiveHint","idempotentHint","openWorldHint","readOnlyHint","title","description","input","object","id","union","string","number","describe","optional","data","record","unknown","depth","default","draft","boolean","fallbackLocale","file","locale","overrideLock","overwriteExistingFiles","publishAllLocales","select","where","handler","authorizedMCP","req","payload","logger","fileInput","info","content","type","text","virtualFieldNames","config","inputData","validationError","partial","parsedData","whereClause","result","collection","overrideAccess","undefined","JSON","stringify","doc","docs","errors","responseText","length","errorSchema","isError","structuredContent","schema","error","errorMessage","Error","message","action"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"validateEntityData.d.ts","sourceRoot":"","sources":["../../../src/mcp/builtin/validateEntityData.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,cAAc,EAAmB,MAAM,SAAS,CAAA;AAI1F,OAAO,KAAK,EAAkB,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAuBrE,eAAO,MAAM,sBAAsB,GAAI,yCAKpC;IACD,cAAc,EAAE,cAAc,CAAA;IAC9B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC7B,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,GAAG,EAAE,cAAc,CAAA;CACpB,KAAG,eAAe,GAAG,IAQlB,CAAA;AAEJ,eAAO,MAAM,kBAAkB,GAAI,4BAIhC;IACD,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC7B,UAAU,EAAE,UAAU,CAAA;IACtB,GAAG,EAAE,cAAc,CAAA;CACpB,KAAG,eAAe,GAAG,IAQlB,CAAA"}
1
+ {"version":3,"file":"validateEntityData.d.ts","sourceRoot":"","sources":["../../../src/mcp/builtin/validateEntityData.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,cAAc,EAAmB,MAAM,SAAS,CAAA;AAI1F,OAAO,KAAK,EAAkB,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAuBrE,eAAO,MAAM,sBAAsB,4CAKhC;IACD,cAAc,EAAE,cAAc,CAAA;IAC9B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC7B,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,GAAG,EAAE,cAAc,CAAA;CACpB,KAAG,eAAe,GAAG,IAQlB,CAAA;AAEJ,eAAO,MAAM,kBAAkB,+BAI5B;IACD,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC7B,UAAU,EAAE,UAAU,CAAA;IACtB,GAAG,EAAE,cAAc,CAAA;CACpB,KAAG,eAAe,GAAG,IAQlB,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"builtinTools.d.ts","sourceRoot":"","sources":["../../src/mcp/builtinTools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AA+BnE,KAAK,iBAAiB,GAAG;IACvB,OAAO,EAAE,MAAM,CAAA;IACf,wBAAwB,CAAC,EAAE,OAAO,CAAA;IAClC,gBAAgB,CAAC,EAAE,OAAO,CAAA;IAC1B,IAAI,EAAE,cAAc,CAAA;CACrB,CAAA;AAED,KAAK,aAAa,GAAG;IACnB,OAAO,EAAE,MAAM,CAAA;IACf,gBAAgB,CAAC,EAAE,OAAO,CAAA;IAC1B,IAAI,EAAE,UAAU,CAAA;CACjB,CAAA;AAED,eAAO,MAAM,aAAa;;;;;CAEiC,CAAA;AAE3D;;;;GAIG;AACH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqBa,CAAA;AAE7C;;;GAGG;AACH,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;CAagC,CAAA;AAErE;;;GAGG;AACH,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwBa,CAAA;AAEzC,MAAM,MAAM,wBAAwB,GAAG,MAAM,OAAO,mBAAmB,CAAA;AAEvE,MAAM,MAAM,yBAAyB,GAAG,MAAM,OAAO,wBAAwB,CAAA;AAE7E,MAAM,MAAM,oBAAoB,GAAG,MAAM,OAAO,eAAe,CAAA;AAE/D,MAAM,MAAM,sBAAsB,GAAG,MAAM,OAAO,aAAa,CAAA;AAE/D;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,EAAoC,KAAK,CACxE,CAAC,sBAAsB,EAAE,CAAC,OAAO,aAAa,EAAE,sBAAsB,CAAC,CAAC,CACzE,CAAA;AAED,eAAO,MAAM,0BAA0B,EAA0C,KAAK,CACpF,CAAC,wBAAwB,EAAE,iBAAiB,CAAC,CAC9C,CAAA;AAED,eAAO,MAAM,+BAA+B,EAA+C,KAAK,CAC9F,CAAC,yBAAyB,EAAE,CAAC,OAAO,wBAAwB,EAAE,yBAAyB,CAAC,CAAC,CAC1F,CAAA;AAED,eAAO,MAAM,sBAAsB,EAAsC,KAAK,CAC5E,CAAC,oBAAoB,EAAE,aAAa,CAAC,CACtC,CAAA"}
1
+ {"version":3,"file":"builtinTools.d.ts","sourceRoot":"","sources":["../../src/mcp/builtinTools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AA+BnE,KAAK,iBAAiB,GAAG;IACvB,OAAO,EAAE,MAAM,CAAA;IACf,wBAAwB,CAAC,EAAE,OAAO,CAAA;IAClC,gBAAgB,CAAC,EAAE,OAAO,CAAA;IAC1B,IAAI,EAAE,cAAc,CAAA;CACrB,CAAA;AAED,KAAK,aAAa,GAAG;IACnB,OAAO,EAAE,MAAM,CAAA;IACf,gBAAgB,CAAC,EAAE,OAAO,CAAA;IAC1B,IAAI,EAAE,UAAU,CAAA;CACjB,CAAA;AAED,eAAO,MAAM,aAAa;;QACP,OAAO;QAAmB,IAAI;;CACU,CAAA;AAE3D;;;;GAIG;AACH,eAAO,MAAM,mBAAmB;;QACrB,OAAO;QAAoB,IAAI;;;;;;;;QAE9B,OAAO;QAAoB,IAAI;;;QAC/B,OAAO;QAAqB,IAAI;;;;;;;;QAMlC,OAAO;QAAmB,IAAI;;;QACtB,OAAO;QAAkB,IAAI;;;;;;;;;;;;;QAOtB,OAAO;QAAyB,IAAI;;;;;;;;QAEjD,OAAO;QAAoB,IAAI;;CACE,CAAA;AAE7C;;;GAGG;AACH,eAAO,MAAM,wBAAwB;;QAC3B,OAAO;QAAU,IAAI;;;QAE3B,OAAO;QACP,IAAI;;;QAEG,OAAO;QAAW,IAAI;;;QAE7B,OAAO;QACP,IAAI;;;QAEI,OAAO;QAAY,IAAI;;;QACvB,OAAO;QAAY,IAAI;;CACkC,CAAA;AAErE;;;GAGG;AACH,eAAO,MAAM,eAAe;;;;;;;QAMlB,OAAO;QAAgB,IAAI;;;;;;;;;;;;;QAWhB,OAAO;QAAqB,IAAI;;;;;;;;QAMzC,OAAO;QAAkB,IAAI;;CACA,CAAA;AAEzC,MAAM,MAAM,wBAAwB,GAAG,MAAM,OAAO,mBAAmB,CAAA;AAEvE,MAAM,MAAM,yBAAyB,GAAG,MAAM,OAAO,wBAAwB,CAAA;AAE7E,MAAM,MAAM,oBAAoB,GAAG,MAAM,OAAO,eAAe,CAAA;AAE/D,MAAM,MAAM,sBAAsB,GAAG,MAAM,OAAO,aAAa,CAAA;AAE/D;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,EAAoC,KAAK,CACxE,CAAC,sBAAsB,EAAE,CAAC,OAAO,aAAa,CAAC,CAAC,sBAAsB,CAAC,CAAC,CACzE,CAAA;AAED,eAAO,MAAM,0BAA0B,EAA0C,KAAK,CACpF,CAAC,wBAAwB,EAAE,iBAAiB,CAAC,CAC9C,CAAA;AAED,eAAO,MAAM,+BAA+B,EAA+C,KAAK,CAC9F,CAAC,yBAAyB,EAAE,CAAC,OAAO,wBAAwB,CAAC,CAAC,yBAAyB,CAAC,CAAC,CAC1F,CAAA;AAED,eAAO,MAAM,sBAAsB,EAAsC,KAAK,CAC5E,CAAC,oBAAoB,EAAE,aAAa,CAAC,CACtC,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"sanitizeMCPConfig.d.ts","sourceRoot":"","sources":["../../src/mcp/sanitizeMCPConfig.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,MAAM,EAGN,eAAe,EAEhB,MAAM,SAAS,CAAA;AAEhB,OAAO,KAAK,EAMV,eAAe,EACf,wBAAwB,EACzB,MAAM,aAAa,CAAA;AAcpB;;;;;;;;GAQG;AACH,eAAO,MAAM,iBAAiB,GAAI,2BAG/B;IACD,MAAM,EAAE,MAAM,GAAG,eAAe,CAAA;IAChC,YAAY,EAAE,eAAe,CAAA;CAC9B,KAAG,wBA6DH,CAAA"}
1
+ {"version":3,"file":"sanitizeMCPConfig.d.ts","sourceRoot":"","sources":["../../src/mcp/sanitizeMCPConfig.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,MAAM,EAGN,eAAe,EAEhB,MAAM,SAAS,CAAA;AAEhB,OAAO,KAAK,EAMV,eAAe,EACf,wBAAwB,EACzB,MAAM,aAAa,CAAA;AAcpB;;;;;;;;GAQG;AACH,eAAO,MAAM,iBAAiB,8BAG3B;IACD,MAAM,EAAE,MAAM,GAAG,eAAe,CAAA;IAChC,YAAY,EAAE,eAAe,CAAA;CAC9B,KAAG,wBA6DH,CAAA"}
package/dist/stdio.d.ts CHANGED
@@ -1,9 +1,8 @@
1
- import type { SanitizedConfig } from 'payload';
2
1
  /**
3
2
  * Starts Payload's MCP server over stdin and stdout.
4
3
  *
5
4
  * Set `PAYLOAD_MCP_AUTHORIZATION` to authenticate. In development,
6
5
  * `PAYLOAD_MCP_OVERRIDE_ACCESS=true` skips access checks.
7
6
  */
8
- export declare const runMcpStdio: (configOverride?: SanitizedConfig) => Promise<void>;
7
+ export declare const runMcpStdio: () => Promise<void>;
9
8
  //# sourceMappingURL=stdio.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"stdio.d.ts","sourceRoot":"","sources":["../src/stdio.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAkB,eAAe,EAAE,MAAM,SAAS,CAAA;AAgB9D;;;;;GAKG;AACH,eAAO,MAAM,WAAW,GAAU,iBAAiB,eAAe,KAAG,OAAO,CAAC,IAAI,CA6GhF,CAAA"}
1
+ {"version":3,"file":"stdio.d.ts","sourceRoot":"","sources":["../src/stdio.ts"],"names":[],"mappings":"AAgBA;;;;;GAKG;AACH,eAAO,MAAM,WAAW,QAAa,OAAO,CAAC,IAAI,CA2GhD,CAAA"}
package/dist/stdio.js CHANGED
@@ -1,7 +1,7 @@
1
1
  /* eslint-disable no-console */ import { serveStdio } from '@modelcontextprotocol/server/stdio';
2
2
  import { fileURLToPath, pathToFileURL } from 'node:url';
3
3
  import { createLocalReq, getPayload } from 'payload';
4
- import { findConfig, loadEnv } from 'payload/node';
4
+ import { findConfig } from 'payload/node';
5
5
  import { getAuthorizedMCP } from './endpoint/access.js';
6
6
  import { buildMcpServer } from './mcp/buildMcpServer.js';
7
7
  import { sanitizeMCPConfig } from './mcp/sanitizeMCPConfig.js';
@@ -12,18 +12,16 @@ import { resolveProjectRoot } from './utils/resolveProjectRoot.js';
12
12
  *
13
13
  * Set `PAYLOAD_MCP_AUTHORIZATION` to authenticate. In development,
14
14
  * `PAYLOAD_MCP_OVERRIDE_ACCESS=true` skips access checks.
15
- */ export const runMcpStdio = async (configOverride)=>{
15
+ */ export const runMcpStdio = async ()=>{
16
16
  // MCP clients may start this command from another folder. Move to the Payload
17
17
  // project so findConfig() can find the config.
18
18
  const projectRoot = resolveProjectRoot(fileURLToPath(import.meta.url));
19
19
  if (projectRoot) {
20
20
  process.chdir(projectRoot);
21
21
  }
22
- loadEnv();
23
22
  const configPath = findConfig();
24
- const configURL = pathToFileURL(configPath).href;
25
- const configModule = configOverride ? undefined : await import(configURL);
26
- const config = configOverride ?? await (configModule?.default ?? configModule);
23
+ const configModule = await import(pathToFileURL(configPath).toString());
24
+ const config = await (configModule.default ?? configModule);
27
25
  /**
28
26
  * stdout is only for MCP messages. The spec says the server must not write
29
27
  * logs there and may write them to stderr instead.
package/dist/stdio.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/stdio.ts"],"sourcesContent":["import type { Config, Plugin, SanitizedConfig } from 'payload'\n\n/* eslint-disable no-console */\nimport { serveStdio } from '@modelcontextprotocol/server/stdio'\nimport { fileURLToPath, pathToFileURL } from 'node:url'\nimport { createLocalReq, getPayload } from 'payload'\nimport { findConfig, loadEnv } from 'payload/node'\n\nimport type { SanitizedMCPPluginConfig } from './types.js'\n\nimport { getAuthorizedMCP } from './endpoint/access.js'\nimport { buildMcpServer } from './mcp/buildMcpServer.js'\nimport { sanitizeMCPConfig } from './mcp/sanitizeMCPConfig.js'\nimport { getPluginConfig } from './utils/getPluginConfig.js'\nimport { resolveProjectRoot } from './utils/resolveProjectRoot.js'\n\n/**\n * Starts Payload's MCP server over stdin and stdout.\n *\n * Set `PAYLOAD_MCP_AUTHORIZATION` to authenticate. In development,\n * `PAYLOAD_MCP_OVERRIDE_ACCESS=true` skips access checks.\n */\nexport const runMcpStdio = async (configOverride?: SanitizedConfig): Promise<void> => {\n // MCP clients may start this command from another folder. Move to the Payload\n // project so findConfig() can find the config.\n const projectRoot = resolveProjectRoot(fileURLToPath(import.meta.url))\n if (projectRoot) {\n process.chdir(projectRoot)\n }\n\n loadEnv()\n const configPath = findConfig()\n const configURL = pathToFileURL(configPath).href\n const configModule = configOverride ? undefined : await import(configURL)\n const config: SanitizedConfig = configOverride ?? (await (configModule?.default ?? configModule))\n\n /**\n * stdout is only for MCP messages. The spec says the server must not write\n * logs there and may write them to stderr instead.\n *\n * The 2.0 client library recovers from stray stdout logs, but that behavior is not\n * guaranteed. Move Payload logs to stderr so Payload does not add invalid data\n * to stdout. Keep options from configurable loggers. Replace pre-built loggers\n * because their output cannot be redirected.\n *\n * @see https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#stdio\n */\n const loggerConfig: { logger?: Config['logger'] } = config\n if (\n loggerConfig.logger &&\n typeof loggerConfig.logger === 'object' &&\n 'options' in loggerConfig.logger\n ) {\n loggerConfig.logger.destination = process.stderr\n } else {\n loggerConfig.logger = { destination: process.stderr, options: {} }\n }\n\n const payload = await getPayload({ config, cron: false, disableOnInit: true })\n\n let pluginConfig: SanitizedMCPPluginConfig\n try {\n pluginConfig = getPluginConfig({ config: payload.config })\n } catch {\n // The command also works when mcpPlugin() is not in the Payload config.\n pluginConfig = sanitizeMCPConfig({ config: payload.config, pluginConfig: {} })\n\n const fallbackPlugin: Plugin = (config) => config\n Object.assign(fallbackPlugin, {\n slug: '@payloadcms/plugin-mcp',\n sanitizedOptions: pluginConfig,\n })\n payload.config.plugins ??= []\n payload.config.plugins.push(fallbackPlugin)\n }\n\n const overrideAccessEnv = process.env.PAYLOAD_MCP_OVERRIDE_ACCESS\n let overrideAccess = false\n\n if (overrideAccessEnv === 'true') {\n overrideAccess = true\n } else if (overrideAccessEnv && overrideAccessEnv !== 'false') {\n throw new Error('PAYLOAD_MCP_OVERRIDE_ACCESS must be \"true\" or \"false\".')\n }\n\n if (overrideAccess && process.env.NODE_ENV !== 'development') {\n throw new Error('PAYLOAD_MCP_OVERRIDE_ACCESS is only available in development.')\n }\n\n const headers = new Headers()\n if (process.env.PAYLOAD_MCP_AUTHORIZATION) {\n headers.set('Authorization', process.env.PAYLOAD_MCP_AUTHORIZATION)\n }\n\n const req = await createLocalReq({ req: { headers } }, payload)\n req.payloadAPI = 'MCP' as const\n const authorizedMCP = await getAuthorizedMCP({ overrideAccess, req })\n\n const stdioServer = serveStdio(() => buildMcpServer({ authorizedMCP, pluginConfig, req }), {\n onerror: (err) => {\n // MCP messages use stdout, so write SDK errors to stderr.\n console.error('[payload-mcp] error serving MCP over stdio:', err)\n },\n })\n\n // Close the MCP server and Payload when the client disconnects or the process stops.\n let isShuttingDown = false\n const shutdown = async () => {\n if (isShuttingDown) {\n return\n }\n isShuttingDown = true\n\n try {\n await stdioServer.close()\n } catch (err) {\n console.error('[payload-mcp] error closing server:', err)\n }\n\n try {\n await payload.destroy()\n } catch (err) {\n console.error('[payload-mcp] error destroying payload:', err)\n }\n\n process.exit(0)\n }\n\n process.once('SIGINT', () => void shutdown())\n process.once('SIGTERM', () => void shutdown())\n process.stdin.once('close', () => void shutdown())\n}\n"],"names":["serveStdio","fileURLToPath","pathToFileURL","createLocalReq","getPayload","findConfig","loadEnv","getAuthorizedMCP","buildMcpServer","sanitizeMCPConfig","getPluginConfig","resolveProjectRoot","runMcpStdio","configOverride","projectRoot","url","process","chdir","configPath","configURL","href","configModule","undefined","config","default","loggerConfig","logger","destination","stderr","options","payload","cron","disableOnInit","pluginConfig","fallbackPlugin","Object","assign","slug","sanitizedOptions","plugins","push","overrideAccessEnv","env","PAYLOAD_MCP_OVERRIDE_ACCESS","overrideAccess","Error","NODE_ENV","headers","Headers","PAYLOAD_MCP_AUTHORIZATION","set","req","payloadAPI","authorizedMCP","stdioServer","onerror","err","console","error","isShuttingDown","shutdown","close","destroy","exit","once","stdin"],"mappings":"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"}
1
+ {"version":3,"sources":["../src/stdio.ts"],"sourcesContent":["import type { Config, Plugin, SanitizedConfig } from 'payload'\n\n/* eslint-disable no-console */\nimport { serveStdio } from '@modelcontextprotocol/server/stdio'\nimport { fileURLToPath, pathToFileURL } from 'node:url'\nimport { createLocalReq, getPayload } from 'payload'\nimport { findConfig } from 'payload/node'\n\nimport type { SanitizedMCPPluginConfig } from './types.js'\n\nimport { getAuthorizedMCP } from './endpoint/access.js'\nimport { buildMcpServer } from './mcp/buildMcpServer.js'\nimport { sanitizeMCPConfig } from './mcp/sanitizeMCPConfig.js'\nimport { getPluginConfig } from './utils/getPluginConfig.js'\nimport { resolveProjectRoot } from './utils/resolveProjectRoot.js'\n\n/**\n * Starts Payload's MCP server over stdin and stdout.\n *\n * Set `PAYLOAD_MCP_AUTHORIZATION` to authenticate. In development,\n * `PAYLOAD_MCP_OVERRIDE_ACCESS=true` skips access checks.\n */\nexport const runMcpStdio = async (): Promise<void> => {\n // MCP clients may start this command from another folder. Move to the Payload\n // project so findConfig() can find the config.\n const projectRoot = resolveProjectRoot(fileURLToPath(import.meta.url))\n if (projectRoot) {\n process.chdir(projectRoot)\n }\n\n const configPath = findConfig()\n const configModule = await import(pathToFileURL(configPath).toString())\n const config = (await (configModule.default ?? configModule)) as SanitizedConfig\n\n /**\n * stdout is only for MCP messages. The spec says the server must not write\n * logs there and may write them to stderr instead.\n *\n * The 2.0 client library recovers from stray stdout logs, but that behavior is not\n * guaranteed. Move Payload logs to stderr so Payload does not add invalid data\n * to stdout. Keep options from configurable loggers. Replace pre-built loggers\n * because their output cannot be redirected.\n *\n * @see https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#stdio\n */\n const loggerConfig: { logger?: Config['logger'] } = config\n if (\n loggerConfig.logger &&\n typeof loggerConfig.logger === 'object' &&\n 'options' in loggerConfig.logger\n ) {\n loggerConfig.logger.destination = process.stderr\n } else {\n loggerConfig.logger = { destination: process.stderr, options: {} }\n }\n\n const payload = await getPayload({ config, cron: false, disableOnInit: true })\n\n let pluginConfig: SanitizedMCPPluginConfig\n try {\n pluginConfig = getPluginConfig({ config: payload.config })\n } catch {\n // The command also works when mcpPlugin() is not in the Payload config.\n pluginConfig = sanitizeMCPConfig({ config: payload.config, pluginConfig: {} })\n\n const fallbackPlugin: Plugin = (config) => config\n Object.assign(fallbackPlugin, {\n slug: '@payloadcms/plugin-mcp',\n sanitizedOptions: pluginConfig,\n })\n payload.config.plugins ??= []\n payload.config.plugins.push(fallbackPlugin)\n }\n\n const overrideAccessEnv = process.env.PAYLOAD_MCP_OVERRIDE_ACCESS\n let overrideAccess = false\n\n if (overrideAccessEnv === 'true') {\n overrideAccess = true\n } else if (overrideAccessEnv && overrideAccessEnv !== 'false') {\n throw new Error('PAYLOAD_MCP_OVERRIDE_ACCESS must be \"true\" or \"false\".')\n }\n\n if (overrideAccess && process.env.NODE_ENV !== 'development') {\n throw new Error('PAYLOAD_MCP_OVERRIDE_ACCESS is only available in development.')\n }\n\n const headers = new Headers()\n if (process.env.PAYLOAD_MCP_AUTHORIZATION) {\n headers.set('Authorization', process.env.PAYLOAD_MCP_AUTHORIZATION)\n }\n\n const req = await createLocalReq({ req: { headers } }, payload)\n req.payloadAPI = 'MCP' as const\n const authorizedMCP = await getAuthorizedMCP({ overrideAccess, req })\n\n const stdioServer = serveStdio(() => buildMcpServer({ authorizedMCP, pluginConfig, req }), {\n onerror: (err) => {\n // MCP messages use stdout, so write SDK errors to stderr.\n console.error('[payload-mcp] error serving MCP over stdio:', err)\n },\n })\n\n // Close the MCP server and Payload when the client disconnects or the process stops.\n let isShuttingDown = false\n const shutdown = async () => {\n if (isShuttingDown) {\n return\n }\n isShuttingDown = true\n\n try {\n await stdioServer.close()\n } catch (err) {\n console.error('[payload-mcp] error closing server:', err)\n }\n\n try {\n await payload.destroy()\n } catch (err) {\n console.error('[payload-mcp] error destroying payload:', err)\n }\n\n process.exit(0)\n }\n\n process.once('SIGINT', () => void shutdown())\n process.once('SIGTERM', () => void shutdown())\n process.stdin.once('close', () => void shutdown())\n}\n"],"names":["serveStdio","fileURLToPath","pathToFileURL","createLocalReq","getPayload","findConfig","getAuthorizedMCP","buildMcpServer","sanitizeMCPConfig","getPluginConfig","resolveProjectRoot","runMcpStdio","projectRoot","url","process","chdir","configPath","configModule","toString","config","default","loggerConfig","logger","destination","stderr","options","payload","cron","disableOnInit","pluginConfig","fallbackPlugin","Object","assign","slug","sanitizedOptions","plugins","push","overrideAccessEnv","env","PAYLOAD_MCP_OVERRIDE_ACCESS","overrideAccess","Error","NODE_ENV","headers","Headers","PAYLOAD_MCP_AUTHORIZATION","set","req","payloadAPI","authorizedMCP","stdioServer","onerror","err","console","error","isShuttingDown","shutdown","close","destroy","exit","once","stdin"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"camelCase.d.ts","sourceRoot":"","sources":["../../src/utils/camelCase.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,eAAO,MAAM,WAAW,GAAI,KAAK,MAAM,KAAG,MAIzC,CAAA"}
1
+ {"version":3,"file":"camelCase.d.ts","sourceRoot":"","sources":["../../src/utils/camelCase.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,eAAO,MAAM,WAAW,QAAS,MAAM,KAAG,MAIzC,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"resolveProjectRoot.d.ts","sourceRoot":"","sources":["../../src/utils/resolveProjectRoot.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,GAAI,UAAU,MAAM,KAAG,IAAI,GAAG,MAS5D,CAAA"}
1
+ {"version":3,"file":"resolveProjectRoot.d.ts","sourceRoot":"","sources":["../../src/utils/resolveProjectRoot.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,aAAc,MAAM,KAAG,IAAI,GAAG,MAS5D,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"filterFieldsByAccess.d.ts","sourceRoot":"","sources":["../../../src/utils/schemaConversion/filterFieldsByAccess.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,cAAc,EACd,SAAS,EACT,4BAA4B,EAE7B,MAAM,SAAS,CAAA;AAEhB,KAAK,cAAc,GAAG,OAAO,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAA;AAClD,KAAK,sBAAsB,GAAG,MAAM,CAAC,cAAc,EAAE,OAAO,CAAC,CAAA;AAE7D;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,oBAAoB,GAAI,sDAKlC;IACD,MAAM,CAAC,EAAE,cAAc,EAAE,CAAA;IACzB,MAAM,EAAE,cAAc,EAAE,CAAA;IACxB,WAAW,EAAE,4BAA4B,CAAA;IACzC,kBAAkB,EAAE,CAAC,iBAAiB,EAAE,sBAAsB,KAAK,OAAO,CAAA;CAC3E,KAAG,cAAc,EAoFjB,CAAA"}
1
+ {"version":3,"file":"filterFieldsByAccess.d.ts","sourceRoot":"","sources":["../../../src/utils/schemaConversion/filterFieldsByAccess.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,cAAc,EACd,SAAS,EACT,4BAA4B,EAE7B,MAAM,SAAS,CAAA;AAEhB,KAAK,cAAc,GAAG,OAAO,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAA;AAClD,KAAK,sBAAsB,GAAG,MAAM,CAAC,cAAc,EAAE,OAAO,CAAC,CAAA;AAE7D;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,oBAAoB,yDAK9B;IACD,MAAM,CAAC,EAAE,cAAc,EAAE,CAAA;IACzB,MAAM,EAAE,cAAc,EAAE,CAAA;IACxB,WAAW,EAAE,4BAA4B,CAAA;IACzC,kBAAkB,EAAE,CAAC,iBAAiB,EAAE,sBAAsB,KAAK,OAAO,CAAA;CAC3E,KAAG,cAAc,EAoFjB,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"getEntityInputSchema.d.ts","sourceRoot":"","sources":["../../../src/utils/schemaConversion/getEntityInputSchema.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,cAAc,EAGnB,KAAK,UAAU,EACf,KAAK,cAAc,EAEnB,KAAK,6BAA6B,EAElC,KAAK,yBAAyB,EAC/B,MAAM,SAAS,CAAA;AAEhB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAKpD,eAAO,MAAM,wBAAwB,GAAI,uCAItC;IACD,cAAc,EAAE,cAAc,CAAA;IAC9B,WAAW,CAAC,EAAE,6BAA6B,CAAA;IAC3C,GAAG,EAAE,cAAc,CAAA;CACpB,KAAG,cAAc,GAAG,IAmBpB,CAAA;AAED,eAAO,MAAM,oBAAoB,GAAI,mCAIlC;IACD,UAAU,EAAE,UAAU,CAAA;IACtB,WAAW,CAAC,EAAE,yBAAyB,CAAA;IACvC,GAAG,EAAE,cAAc,CAAA;CACpB,KAAG,cAAc,GAAG,IAmBpB,CAAA"}
1
+ {"version":3,"file":"getEntityInputSchema.d.ts","sourceRoot":"","sources":["../../../src/utils/schemaConversion/getEntityInputSchema.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,cAAc,EAGnB,KAAK,UAAU,EACf,KAAK,cAAc,EAEnB,KAAK,6BAA6B,EAElC,KAAK,yBAAyB,EAC/B,MAAM,SAAS,CAAA;AAEhB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAKpD,eAAO,MAAM,wBAAwB,0CAIlC;IACD,cAAc,EAAE,cAAc,CAAA;IAC9B,WAAW,CAAC,EAAE,6BAA6B,CAAA;IAC3C,GAAG,EAAE,cAAc,CAAA;CACpB,KAAG,cAAc,GAAG,IAmBpB,CAAA;AAED,eAAO,MAAM,oBAAoB,sCAI9B;IACD,UAAU,EAAE,UAAU,CAAA;IACtB,WAAW,CAAC,EAAE,yBAAyB,CAAA;IACvC,GAAG,EAAE,cAAc,CAAA;CACpB,KAAG,cAAc,GAAG,IAmBpB,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"sanitizeEntitySchema.d.ts","sourceRoot":"","sources":["../../../src/utils/schemaConversion/sanitizeEntitySchema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAEpD;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB,GAAI,QAAQ,cAAc,KAAG,cA0B7D,CAAA"}
1
+ {"version":3,"file":"sanitizeEntitySchema.d.ts","sourceRoot":"","sources":["../../../src/utils/schemaConversion/sanitizeEntitySchema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAEpD;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB,WAAY,cAAc,KAAG,cA0B7D,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"toStandardSchema.d.ts","sourceRoot":"","sources":["../../src/utils/toStandardSchema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,sBAAsB,EAAE,MAAM,8BAA8B,CAAA;AAE1F,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAElD,gIAAgI;AAChI,eAAO,MAAM,gBAAgB,GAAI,QAAQ,eAAe,KAAG,sBAG/B,CAAA"}
1
+ {"version":3,"file":"toStandardSchema.d.ts","sourceRoot":"","sources":["../../src/utils/toStandardSchema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,KAAK,sBAAsB,EAAE,MAAM,8BAA8B,CAAA;AAE1F,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAElD,gIAAgI;AAChI,eAAO,MAAM,gBAAgB,WAAY,eAAe,KAAG,sBAG/B,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@payloadcms/plugin-mcp",
3
- "version": "4.0.0-internal.41055b1",
3
+ "version": "4.0.0-internal.435b2d6",
4
4
  "description": "MCP (Model Context Protocol) capabilities with Payload",
5
5
  "keywords": [
6
6
  "plugin",
@@ -28,11 +28,6 @@
28
28
  "types": "./dist/index.d.ts",
29
29
  "default": "./dist/index.js"
30
30
  },
31
- "./bin": {
32
- "import": "./dist/bin/index.js",
33
- "types": "./dist/bin/index.d.ts",
34
- "default": "./dist/bin/index.js"
35
- },
36
31
  "./client": {
37
32
  "import": "./dist/exports/client.js",
38
33
  "types": "./dist/exports/client.d.ts",
@@ -65,23 +60,15 @@
65
60
  "zod": "^4.2.0"
66
61
  },
67
62
  "devDependencies": {
68
- "vite": "~8.1.4",
69
- "payload": "4.0.0-internal.41055b1",
70
- "@payloadcms/eslint-config": "3.28.0"
63
+ "@payloadcms/eslint-config": "3.28.0",
64
+ "payload": "4.0.0-internal.435b2d6"
71
65
  },
72
66
  "peerDependencies": {
73
- "vite": "~8.1.4",
74
- "payload": "4.0.0-internal.41055b1"
75
- },
76
- "peerDependenciesMeta": {
77
- "vite": {
78
- "optional": true
79
- }
67
+ "payload": "4.0.0-internal.435b2d6"
80
68
  },
81
69
  "//deps_notes": {
82
70
  "zod": "zod is a hard dependency of @modelcontextprotocol/server, thus we can safely use it without it impacting bundle size. Make extra sure the zod version here matches exactly what's defined in the dependencies of @modelcontextprotocol/server to avoid duplicate versions being installed.",
83
- "tsx": "Required by the `bin.js` stdio mcp. Keep the version pinned to whatever `payload` ships to avoid duplicate installs.",
84
- "vite": "Vite is an optional peer used by stdio development HMR and duplicated in devDependencies for this package's build and tests. Keep the Vite minor pinned while its server module runner API is experimental."
71
+ "tsx": "Required by the `bin.js` stdio mcp. Keep the version pinned to whatever `payload` ships to avoid duplicate installs."
85
72
  },
86
73
  "homepage:": "https://payloadcms.com",
87
74
  "scripts": {
@@ -11,6 +11,7 @@ import {
11
11
  } from '../../../utils/getVirtualFieldNames.js'
12
12
  import { transformPointDataToPayload } from '../../../utils/transformPointDataToPayload.js'
13
13
  import { validateCollectionData } from '../validateEntityData.js'
14
+ import { fileInputSchema, resolveFileInput } from './fileInput.js'
14
15
  import { formatCollectionError } from './formatCollectionError.js'
15
16
 
16
17
  const DEFAULT_DESCRIPTION =
@@ -52,6 +53,7 @@ export const createDocumentTool = defineCollectionTool({
52
53
  .string()
53
54
  .describe('Optional: fallback locale code to use when requested locale is not available')
54
55
  .optional(),
56
+ file: fileInputSchema.optional(),
55
57
  locale: z
56
58
  .string()
57
59
  .describe(
@@ -69,7 +71,7 @@ export const createDocumentTool = defineCollectionTool({
69
71
  const payload = req.payload
70
72
  const logger = getLogger({ payload })
71
73
 
72
- const { data, depth, draft, fallbackLocale, locale, select } = input
74
+ const { data, depth, draft, fallbackLocale, file: fileInput, locale, select } = input
73
75
 
74
76
  logger.info(
75
77
  `Creating document in collection: ${collectionSlug}${locale ? ` with locale: ${locale}` : ''}`,
@@ -85,6 +87,7 @@ export const createDocumentTool = defineCollectionTool({
85
87
  }
86
88
 
87
89
  const parsedData = transformPointDataToPayload(inputData)
90
+ const file = await resolveFileInput({ collectionSlug, input: fileInput, req })
88
91
 
89
92
  const result = await payload.create({
90
93
  collection: collectionSlug,
@@ -93,6 +96,7 @@ export const createDocumentTool = defineCollectionTool({
93
96
  draft,
94
97
  overrideAccess: authorizedMCP.overrideAccess,
95
98
  req,
99
+ ...(file ? { file } : {}),
96
100
  ...(locale ? { locale } : {}),
97
101
  ...(fallbackLocale ? { fallbackLocale } : {}),
98
102
  ...(select ? { select: select as SelectType } : {}),
@@ -0,0 +1,79 @@
1
+ import type { PayloadRequest } from 'payload'
2
+
3
+ import { describe, expect, it } from 'vitest'
4
+
5
+ import { fileInputSchema, resolveFileInput } from './fileInput.js'
6
+
7
+ describe('MCP file input', () => {
8
+ it('should reject malformed MIME types', () => {
9
+ const result = fileInputSchema.safeParse({
10
+ data: 'aGVsbG8=',
11
+ mimeType: 'text/plain\r\nx-test: value',
12
+ name: 'hello.txt',
13
+ source: 'base64',
14
+ })
15
+
16
+ expect(result.success).toBe(false)
17
+ })
18
+
19
+ it('should reject oversized base64 files', async () => {
20
+ const req = createRequest({ maxFileSize: 4 })
21
+
22
+ await expect(
23
+ resolveFileInput({
24
+ collectionSlug: 'media',
25
+ input: {
26
+ data: Buffer.from('hello').toString('base64'),
27
+ mimeType: 'text/plain',
28
+ name: 'hello.txt',
29
+ source: 'base64',
30
+ },
31
+ req,
32
+ }),
33
+ ).rejects.toThrow('File exceeds the 4 byte upload limit.')
34
+ })
35
+
36
+ it('should reject URLs outside the collection allowlist', async () => {
37
+ const req = createRequest({
38
+ allowList: [{ hostname: 'assets.example.com', protocol: 'https' }],
39
+ })
40
+
41
+ await expect(
42
+ resolveFileInput({
43
+ collectionSlug: 'media',
44
+ input: {
45
+ source: 'url',
46
+ url: 'https://example.com/image.png',
47
+ },
48
+ req,
49
+ }),
50
+ ).rejects.toThrow('The provided file URL is not allowed.')
51
+ })
52
+ })
53
+
54
+ function createRequest({
55
+ allowList,
56
+ maxFileSize,
57
+ }: {
58
+ allowList?: Array<{ hostname: string; protocol: 'http' | 'https' }>
59
+ maxFileSize?: number
60
+ }): PayloadRequest {
61
+ return {
62
+ payload: {
63
+ collections: {
64
+ media: {
65
+ config: {
66
+ upload: allowList ? { pasteURL: { allowList } } : {},
67
+ },
68
+ },
69
+ },
70
+ config: {
71
+ upload: {
72
+ limits: {
73
+ fileSize: maxFileSize,
74
+ },
75
+ },
76
+ },
77
+ },
78
+ } as unknown as PayloadRequest
79
+ }
@@ -0,0 +1,139 @@
1
+ import type { CollectionSlug, File, FileData, PayloadRequest } from 'payload'
2
+
3
+ import { APIError } from 'payload'
4
+ import { getExternalFile, isURLAllowed } from 'payload/internal'
5
+ import { sanitizeFilename } from 'payload/shared'
6
+ import { z } from 'zod'
7
+
8
+ const mimeTypeSchema = z
9
+ .string()
10
+ .regex(/^[!#$%&'*+.^`|~\w-]+\/[!#$%&'*+.^`|~\w-]+$/, 'MIME type must use the type/subtype format')
11
+
12
+ export const fileInputSchema = z
13
+ .discriminatedUnion('source', [
14
+ z.object({
15
+ name: z.string().min(1).describe('The file name, including its extension'),
16
+ data: z.string().describe('The base64-encoded file bytes, without a data URL prefix'),
17
+ mimeType: mimeTypeSchema.describe('The file MIME type, for example image/png'),
18
+ source: z.literal('base64'),
19
+ }),
20
+ z.object({
21
+ name: z.string().min(1).describe('Optional file name override').optional(),
22
+ source: z.literal('url'),
23
+ url: z.url().describe('The http or https URL to download'),
24
+ }),
25
+ ])
26
+ .describe(
27
+ 'A file for an upload collection. Use only a source listed by getCollectionSchema: url for an online file or base64 for a local file.',
28
+ )
29
+
30
+ type FileInput = z.infer<typeof fileInputSchema>
31
+
32
+ export async function resolveFileInput({
33
+ collectionSlug,
34
+ input,
35
+ req,
36
+ }: {
37
+ collectionSlug: CollectionSlug
38
+ input?: FileInput
39
+ req: PayloadRequest
40
+ }): Promise<File | undefined> {
41
+ if (!input) {
42
+ return undefined
43
+ }
44
+
45
+ const uploadConfig = req.payload.collections[collectionSlug]?.config.upload
46
+
47
+ if (!uploadConfig) {
48
+ throw new APIError(`Collection "${collectionSlug}" does not support file uploads.`, 400)
49
+ }
50
+
51
+ const maxFileSize = req.payload.config.upload.limits?.fileSize
52
+ let file: File
53
+
54
+ if (input.source === 'base64') {
55
+ const data = decodeBase64({ maxFileSize, value: input.data })
56
+
57
+ file = {
58
+ name: sanitizeFilename(input.name),
59
+ data,
60
+ mimetype: input.mimeType,
61
+ size: data.length,
62
+ }
63
+ } else {
64
+ if (uploadConfig.pasteURL === false) {
65
+ throw new APIError(
66
+ `Uploading files from URLs is disabled for collection "${collectionSlug}".`,
67
+ 400,
68
+ )
69
+ }
70
+
71
+ const url = new URL(input.url)
72
+
73
+ if (!['http:', 'https:'].includes(url.protocol)) {
74
+ throw new APIError('File URLs must use http or https.', 400)
75
+ }
76
+
77
+ if (
78
+ typeof uploadConfig.pasteURL === 'object' &&
79
+ !isURLAllowed(input.url, uploadConfig.pasteURL.allowList)
80
+ ) {
81
+ throw new APIError('The provided file URL is not allowed.', 400)
82
+ }
83
+
84
+ file = await getExternalFile({
85
+ data: {
86
+ filename: sanitizeFilename(input.name || getURLFilename(url)),
87
+ url: input.url,
88
+ } as FileData,
89
+ req,
90
+ uploadConfig: {
91
+ ...uploadConfig,
92
+ externalFileHeaderFilter: uploadConfig.externalFileHeaderFilter ?? (() => ({})),
93
+ },
94
+ })
95
+ file.mimetype = file.mimetype?.split(';')[0] || 'application/octet-stream'
96
+ file.size = file.data.length
97
+ }
98
+
99
+ if (maxFileSize !== undefined && Number.isFinite(maxFileSize) && file.size > maxFileSize) {
100
+ throw new APIError(`File exceeds the ${maxFileSize} byte upload limit.`, 400)
101
+ }
102
+
103
+ return file
104
+ }
105
+
106
+ function decodeBase64({ maxFileSize, value }: { maxFileSize?: number; value: string }): Buffer {
107
+ const normalized = value.replace(/\s/g, '')
108
+
109
+ if (!/^[a-z0-9+/]*={0,2}$/i.test(normalized) || normalized.length % 4 === 1) {
110
+ throw new APIError('File data must be valid base64.', 400)
111
+ }
112
+
113
+ if (maxFileSize !== undefined && Number.isFinite(maxFileSize)) {
114
+ const paddingLength = normalized.endsWith('==') ? 2 : normalized.endsWith('=') ? 1 : 0
115
+ const decodedSize = Math.floor((normalized.length * 3) / 4) - paddingLength
116
+
117
+ if (decodedSize > maxFileSize) {
118
+ throw new APIError(`File exceeds the ${maxFileSize} byte upload limit.`, 400)
119
+ }
120
+ }
121
+
122
+ const data = Buffer.from(normalized, 'base64')
123
+
124
+ if (data.toString('base64').replace(/=+$/, '') !== normalized.replace(/=+$/, '')) {
125
+ throw new APIError('File data must be valid base64.', 400)
126
+ }
127
+
128
+ return data
129
+ }
130
+
131
+ function getURLFilename(url: URL): string {
132
+ const pathSegment = url.pathname.split('/').pop() || 'upload'
133
+
134
+ try {
135
+ return decodeURIComponent(pathSegment)
136
+ } catch {
137
+ return pathSegment
138
+ }
139
+ }
@@ -48,16 +48,29 @@ export const getCollectionSchemaTool = defineCollectionTool({
48
48
  }
49
49
  }
50
50
 
51
+ const uploadConfig = req.payload.collections[collectionSlug]?.config.upload
52
+ const maxFileSize = req.payload.config.upload.limits?.fileSize
53
+ const upload = uploadConfig
54
+ ? {
55
+ enabled: true,
56
+ filesRequiredOnCreate: uploadConfig.filesRequiredOnCreate !== false,
57
+ mimeTypes: uploadConfig.mimeTypes ?? ['*/*'],
58
+ sources: [...(uploadConfig.pasteURL !== false ? ['url'] : []), 'base64'],
59
+ ...(typeof maxFileSize === 'number' && Number.isFinite(maxFileSize) ? { maxFileSize } : {}),
60
+ }
61
+ : { enabled: false }
62
+
51
63
  return {
52
64
  content: [
53
65
  {
54
66
  type: 'text',
55
- text: `Schema for collection "${collectionSlug}":\n\`\`\`json\n${JSON.stringify(inputSchema)}\n\`\`\``,
67
+ text: `Schema for collection "${collectionSlug}":\n\`\`\`json\n${JSON.stringify(inputSchema)}\n\`\`\`\nUpload configuration:\n\`\`\`json\n${JSON.stringify(upload)}\n\`\`\``,
56
68
  },
57
69
  ],
58
70
  structuredContent: {
59
71
  collectionSlug,
60
72
  schema: inputSchema,
73
+ upload,
61
74
  },
62
75
  }
63
76
  })
@@ -13,6 +13,7 @@ import { getCollectionInputSchema } from '../../../utils/schemaConversion/getEnt
13
13
  import { transformPointDataToPayload } from '../../../utils/transformPointDataToPayload.js'
14
14
  import { whereSchema } from '../../../utils/whereSchema.js'
15
15
  import { validateCollectionData } from '../validateEntityData.js'
16
+ import { fileInputSchema, resolveFileInput } from './fileInput.js'
16
17
  import { formatCollectionError } from './formatCollectionError.js'
17
18
 
18
19
  const DEFAULT_DESCRIPTION =
@@ -52,7 +53,7 @@ export const updateDocumentTool = defineCollectionTool({
52
53
  .string()
53
54
  .describe('Optional: fallback locale code to use when requested locale is not available')
54
55
  .optional(),
55
- filePath: z.string().describe('File path for file uploads').optional(),
56
+ file: fileInputSchema.optional(),
56
57
  locale: z
57
58
  .string()
58
59
  .describe(
@@ -97,7 +98,7 @@ export const updateDocumentTool = defineCollectionTool({
97
98
  depth,
98
99
  draft,
99
100
  fallbackLocale,
100
- filePath,
101
+ file: fileInput,
101
102
  locale,
102
103
  overrideLock,
103
104
  overwriteExistingFiles,
@@ -131,6 +132,7 @@ export const updateDocumentTool = defineCollectionTool({
131
132
  }
132
133
 
133
134
  const parsedData = transformPointDataToPayload(inputData)
135
+ const file = await resolveFileInput({ collectionSlug, input: fileInput, req })
134
136
 
135
137
  const whereClause: Where = where ?? {}
136
138
 
@@ -144,7 +146,7 @@ export const updateDocumentTool = defineCollectionTool({
144
146
  overrideAccess: authorizedMCP.overrideAccess,
145
147
  overrideLock,
146
148
  req,
147
- ...(filePath ? { filePath } : {}),
149
+ ...(file ? { file } : {}),
148
150
  ...(overwriteExistingFiles ? { overwriteExistingFiles } : {}),
149
151
  ...(publishAllLocales !== undefined ? { publishAllLocales } : {}),
150
152
  ...(locale ? { locale } : {}),
@@ -172,7 +174,7 @@ export const updateDocumentTool = defineCollectionTool({
172
174
  overrideLock,
173
175
  req,
174
176
  where: whereClause,
175
- ...(filePath ? { filePath } : {}),
177
+ ...(file ? { file } : {}),
176
178
  ...(overwriteExistingFiles ? { overwriteExistingFiles } : {}),
177
179
  ...(publishAllLocales !== undefined ? { publishAllLocales } : {}),
178
180
  ...(locale ? { locale } : {}),