@strapi/upload 5.57.0 → 5.59.0

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 (253) hide show
  1. package/dist/admin/components/MediaLibraryInput/AddAssetMenu.js +141 -0
  2. package/dist/admin/components/MediaLibraryInput/AddAssetMenu.js.map +1 -0
  3. package/dist/admin/components/MediaLibraryInput/AddAssetMenu.mjs +139 -0
  4. package/dist/admin/components/MediaLibraryInput/AddAssetMenu.mjs.map +1 -0
  5. package/dist/admin/components/MediaLibraryInput/AssetDropZone.js +129 -0
  6. package/dist/admin/components/MediaLibraryInput/AssetDropZone.js.map +1 -0
  7. package/dist/admin/components/MediaLibraryInput/AssetDropZone.mjs +127 -0
  8. package/dist/admin/components/MediaLibraryInput/AssetDropZone.mjs.map +1 -0
  9. package/dist/admin/components/MediaLibraryInput/AssetRow.js +144 -0
  10. package/dist/admin/components/MediaLibraryInput/AssetRow.js.map +1 -0
  11. package/dist/admin/components/MediaLibraryInput/AssetRow.mjs +142 -0
  12. package/dist/admin/components/MediaLibraryInput/AssetRow.mjs.map +1 -0
  13. package/dist/admin/components/MediaLibraryInput/MediaLibraryInput.js +397 -0
  14. package/dist/admin/components/MediaLibraryInput/MediaLibraryInput.js.map +1 -0
  15. package/dist/admin/components/MediaLibraryInput/MediaLibraryInput.mjs +395 -0
  16. package/dist/admin/components/MediaLibraryInput/MediaLibraryInput.mjs.map +1 -0
  17. package/dist/admin/components/MediaLibraryInput/NoLibraryAccessDialog.js +45 -0
  18. package/dist/admin/components/MediaLibraryInput/NoLibraryAccessDialog.js.map +1 -0
  19. package/dist/admin/components/MediaLibraryInput/NoLibraryAccessDialog.mjs +43 -0
  20. package/dist/admin/components/MediaLibraryInput/NoLibraryAccessDialog.mjs.map +1 -0
  21. package/dist/admin/hooks/useAIMetadataAvailability.js +5 -1
  22. package/dist/admin/hooks/useAIMetadataAvailability.js.map +1 -1
  23. package/dist/admin/hooks/useAIMetadataAvailability.mjs +5 -1
  24. package/dist/admin/hooks/useAIMetadataAvailability.mjs.map +1 -1
  25. package/dist/admin/hooks/useAIMetadataEnabled.js +7 -1
  26. package/dist/admin/hooks/useAIMetadataEnabled.js.map +1 -1
  27. package/dist/admin/hooks/useAIMetadataEnabled.mjs +7 -1
  28. package/dist/admin/hooks/useAIMetadataEnabled.mjs.map +1 -1
  29. package/dist/admin/hooks/useMediaLibraryPermissions.js +4 -0
  30. package/dist/admin/hooks/useMediaLibraryPermissions.js.map +1 -1
  31. package/dist/admin/hooks/useMediaLibraryPermissions.mjs +4 -0
  32. package/dist/admin/hooks/useMediaLibraryPermissions.mjs.map +1 -1
  33. package/dist/admin/hooks/useTracking.js +5 -1
  34. package/dist/admin/hooks/useTracking.js.map +1 -1
  35. package/dist/admin/hooks/useTracking.mjs +5 -1
  36. package/dist/admin/hooks/useTracking.mjs.map +1 -1
  37. package/dist/admin/index.js +7 -2
  38. package/dist/admin/index.js.map +1 -1
  39. package/dist/admin/index.mjs +7 -2
  40. package/dist/admin/index.mjs.map +1 -1
  41. package/dist/admin/legacy/components/AssetCard/AssetCardBase.js.map +1 -1
  42. package/dist/admin/legacy/components/AssetCard/AssetCardBase.mjs.map +1 -1
  43. package/dist/admin/legacy/components/AssetCard/UploadingAssetCard.js +9 -1
  44. package/dist/admin/legacy/components/AssetCard/UploadingAssetCard.js.map +1 -1
  45. package/dist/admin/legacy/components/AssetCard/UploadingAssetCard.mjs +9 -1
  46. package/dist/admin/legacy/components/AssetCard/UploadingAssetCard.mjs.map +1 -1
  47. package/dist/admin/legacy/components/AssetCard/VideoPreview.js +2 -1
  48. package/dist/admin/legacy/components/AssetCard/VideoPreview.js.map +1 -1
  49. package/dist/admin/legacy/components/AssetCard/VideoPreview.mjs +2 -1
  50. package/dist/admin/legacy/components/AssetCard/VideoPreview.mjs.map +1 -1
  51. package/dist/admin/legacy/components/AssetDialog/AssetDialog.js +3 -1
  52. package/dist/admin/legacy/components/AssetDialog/AssetDialog.js.map +1 -1
  53. package/dist/admin/legacy/components/AssetDialog/AssetDialog.mjs +3 -1
  54. package/dist/admin/legacy/components/AssetDialog/AssetDialog.mjs.map +1 -1
  55. package/dist/admin/legacy/components/AssetDialog/BrowseStep/BrowseStep.js +3 -1
  56. package/dist/admin/legacy/components/AssetDialog/BrowseStep/BrowseStep.js.map +1 -1
  57. package/dist/admin/legacy/components/AssetDialog/BrowseStep/BrowseStep.mjs +3 -1
  58. package/dist/admin/legacy/components/AssetDialog/BrowseStep/BrowseStep.mjs.map +1 -1
  59. package/dist/admin/legacy/components/AssetDialog/BrowseStep/Filters.js.map +1 -1
  60. package/dist/admin/legacy/components/AssetDialog/BrowseStep/Filters.mjs.map +1 -1
  61. package/dist/admin/legacy/components/AssetGridList/AssetGridList.js +7 -6
  62. package/dist/admin/legacy/components/AssetGridList/AssetGridList.js.map +1 -1
  63. package/dist/admin/legacy/components/AssetGridList/AssetGridList.mjs +7 -6
  64. package/dist/admin/legacy/components/AssetGridList/AssetGridList.mjs.map +1 -1
  65. package/dist/admin/legacy/components/Breadcrumbs/CrumbSimpleMenuAsync.js +2 -1
  66. package/dist/admin/legacy/components/Breadcrumbs/CrumbSimpleMenuAsync.js.map +1 -1
  67. package/dist/admin/legacy/components/Breadcrumbs/CrumbSimpleMenuAsync.mjs +2 -1
  68. package/dist/admin/legacy/components/Breadcrumbs/CrumbSimpleMenuAsync.mjs.map +1 -1
  69. package/dist/admin/legacy/components/BulkMoveDialog/BulkMoveDialog.js +2 -1
  70. package/dist/admin/legacy/components/BulkMoveDialog/BulkMoveDialog.js.map +1 -1
  71. package/dist/admin/legacy/components/BulkMoveDialog/BulkMoveDialog.mjs +2 -1
  72. package/dist/admin/legacy/components/BulkMoveDialog/BulkMoveDialog.mjs.map +1 -1
  73. package/dist/admin/legacy/components/EditAssetDialog/EditAssetContent.js +3 -1
  74. package/dist/admin/legacy/components/EditAssetDialog/EditAssetContent.js.map +1 -1
  75. package/dist/admin/legacy/components/EditAssetDialog/EditAssetContent.mjs +3 -1
  76. package/dist/admin/legacy/components/EditAssetDialog/EditAssetContent.mjs.map +1 -1
  77. package/dist/admin/legacy/components/EditAssetDialog/PreviewBox/PreviewBox.js +20 -6
  78. package/dist/admin/legacy/components/EditAssetDialog/PreviewBox/PreviewBox.js.map +1 -1
  79. package/dist/admin/legacy/components/EditAssetDialog/PreviewBox/PreviewBox.mjs +20 -6
  80. package/dist/admin/legacy/components/EditAssetDialog/PreviewBox/PreviewBox.mjs.map +1 -1
  81. package/dist/admin/legacy/components/FilterList/FilterList.js.map +1 -1
  82. package/dist/admin/legacy/components/FilterList/FilterList.mjs.map +1 -1
  83. package/dist/admin/legacy/components/FilterPopover/FilterPopover.js.map +1 -1
  84. package/dist/admin/legacy/components/FilterPopover/FilterPopover.mjs.map +1 -1
  85. package/dist/admin/legacy/components/FilterPopover/FilterValueInput.js +2 -1
  86. package/dist/admin/legacy/components/FilterPopover/FilterValueInput.js.map +1 -1
  87. package/dist/admin/legacy/components/FilterPopover/FilterValueInput.mjs +2 -1
  88. package/dist/admin/legacy/components/FilterPopover/FilterValueInput.mjs.map +1 -1
  89. package/dist/admin/legacy/components/MediaLibraryDialog/MediaLibraryDialog.js +4 -2
  90. package/dist/admin/legacy/components/MediaLibraryDialog/MediaLibraryDialog.js.map +1 -1
  91. package/dist/admin/legacy/components/MediaLibraryDialog/MediaLibraryDialog.mjs +4 -2
  92. package/dist/admin/legacy/components/MediaLibraryDialog/MediaLibraryDialog.mjs.map +1 -1
  93. package/dist/admin/legacy/components/MediaLibraryInput/MediaLibraryInput.js +2 -1
  94. package/dist/admin/legacy/components/MediaLibraryInput/MediaLibraryInput.js.map +1 -1
  95. package/dist/admin/legacy/components/MediaLibraryInput/MediaLibraryInput.mjs +2 -1
  96. package/dist/admin/legacy/components/MediaLibraryInput/MediaLibraryInput.mjs.map +1 -1
  97. package/dist/admin/legacy/components/SelectTree/SelectTree.js +3 -1
  98. package/dist/admin/legacy/components/SelectTree/SelectTree.js.map +1 -1
  99. package/dist/admin/legacy/components/SelectTree/SelectTree.mjs +3 -1
  100. package/dist/admin/legacy/components/SelectTree/SelectTree.mjs.map +1 -1
  101. package/dist/admin/legacy/components/TableList/TableList.js +3 -1
  102. package/dist/admin/legacy/components/TableList/TableList.js.map +1 -1
  103. package/dist/admin/legacy/components/TableList/TableList.mjs +3 -1
  104. package/dist/admin/legacy/components/TableList/TableList.mjs.map +1 -1
  105. package/dist/admin/legacy/components/TableList/TableRows.js +3 -1
  106. package/dist/admin/legacy/components/TableList/TableRows.js.map +1 -1
  107. package/dist/admin/legacy/components/TableList/TableRows.mjs +3 -1
  108. package/dist/admin/legacy/components/TableList/TableRows.mjs.map +1 -1
  109. package/dist/admin/legacy/components/UploadAssetDialog/UploadAssetDialog.js +3 -1
  110. package/dist/admin/legacy/components/UploadAssetDialog/UploadAssetDialog.js.map +1 -1
  111. package/dist/admin/legacy/components/UploadAssetDialog/UploadAssetDialog.mjs +3 -1
  112. package/dist/admin/legacy/components/UploadAssetDialog/UploadAssetDialog.mjs.map +1 -1
  113. package/dist/admin/legacy/hooks/useEditAsset.js +11 -6
  114. package/dist/admin/legacy/hooks/useEditAsset.js.map +1 -1
  115. package/dist/admin/legacy/hooks/useEditAsset.mjs +12 -7
  116. package/dist/admin/legacy/hooks/useEditAsset.mjs.map +1 -1
  117. package/dist/admin/legacy/hooks/useUpload.js +6 -4
  118. package/dist/admin/legacy/hooks/useUpload.js.map +1 -1
  119. package/dist/admin/legacy/hooks/useUpload.mjs +6 -4
  120. package/dist/admin/legacy/hooks/useUpload.mjs.map +1 -1
  121. package/dist/admin/legacy/pages/App/ConfigureTheView/ConfigureTheView.js.map +1 -1
  122. package/dist/admin/legacy/pages/App/ConfigureTheView/ConfigureTheView.mjs.map +1 -1
  123. package/dist/admin/legacy/pages/App/components/BulkActions.js +2 -1
  124. package/dist/admin/legacy/pages/App/components/BulkActions.js.map +1 -1
  125. package/dist/admin/legacy/pages/App/components/BulkActions.mjs +2 -1
  126. package/dist/admin/legacy/pages/App/components/BulkActions.mjs.map +1 -1
  127. package/dist/admin/legacy/pages/App/components/BulkMoveButton.js +2 -1
  128. package/dist/admin/legacy/pages/App/components/BulkMoveButton.js.map +1 -1
  129. package/dist/admin/legacy/pages/App/components/BulkMoveButton.mjs +2 -1
  130. package/dist/admin/legacy/pages/App/components/BulkMoveButton.mjs.map +1 -1
  131. package/dist/admin/pages/Assets/components/AssetsGrid.js +2 -1
  132. package/dist/admin/pages/Assets/components/AssetsGrid.js.map +1 -1
  133. package/dist/admin/pages/Assets/components/AssetsGrid.mjs +2 -1
  134. package/dist/admin/pages/Assets/components/AssetsGrid.mjs.map +1 -1
  135. package/dist/admin/pages/Assets/components/AssetsTable.js +2 -1
  136. package/dist/admin/pages/Assets/components/AssetsTable.js.map +1 -1
  137. package/dist/admin/pages/Assets/components/AssetsTable.mjs +2 -1
  138. package/dist/admin/pages/Assets/components/AssetsTable.mjs.map +1 -1
  139. package/dist/admin/pages/Assets/components/BulkActionsBar.js +3 -1
  140. package/dist/admin/pages/Assets/components/BulkActionsBar.js.map +1 -1
  141. package/dist/admin/pages/Assets/components/BulkActionsBar.mjs +3 -1
  142. package/dist/admin/pages/Assets/components/BulkActionsBar.mjs.map +1 -1
  143. package/dist/admin/pages/Assets/components/DateRangeCalendar.js +10 -7
  144. package/dist/admin/pages/Assets/components/DateRangeCalendar.js.map +1 -1
  145. package/dist/admin/pages/Assets/components/DateRangeCalendar.mjs +10 -7
  146. package/dist/admin/pages/Assets/components/DateRangeCalendar.mjs.map +1 -1
  147. package/dist/admin/pages/Assets/components/DropZone/UploadDropZoneContext.js +4 -2
  148. package/dist/admin/pages/Assets/components/DropZone/UploadDropZoneContext.js.map +1 -1
  149. package/dist/admin/pages/Assets/components/DropZone/UploadDropZoneContext.mjs +5 -3
  150. package/dist/admin/pages/Assets/components/DropZone/UploadDropZoneContext.mjs.map +1 -1
  151. package/dist/admin/pages/Assets/components/FilterBadges.js +32 -3
  152. package/dist/admin/pages/Assets/components/FilterBadges.js.map +1 -1
  153. package/dist/admin/pages/Assets/components/FilterBadges.mjs +33 -4
  154. package/dist/admin/pages/Assets/components/FilterBadges.mjs.map +1 -1
  155. package/dist/admin/services/api.js +15 -5
  156. package/dist/admin/services/api.js.map +1 -1
  157. package/dist/admin/services/api.mjs +15 -5
  158. package/dist/admin/services/api.mjs.map +1 -1
  159. package/dist/admin/src/components/MediaLibraryInput/AddAssetMenu.d.ts +19 -0
  160. package/dist/admin/src/components/MediaLibraryInput/AssetDropZone.d.ts +13 -0
  161. package/dist/admin/src/components/MediaLibraryInput/AssetRow.d.ts +15 -0
  162. package/dist/admin/src/components/MediaLibraryInput/MediaLibraryInput.d.ts +26 -0
  163. package/dist/admin/src/components/MediaLibraryInput/NoLibraryAccessDialog.d.ts +10 -0
  164. package/dist/admin/src/hooks/useMediaLibraryPermissions.d.ts +1 -0
  165. package/dist/admin/src/legacy/components/BulkMoveDialog/BulkMoveDialog.d.ts +1 -1
  166. package/dist/admin/src/legacy/hooks/useEditAsset.d.ts +13 -22
  167. package/dist/admin/src/legacy/hooks/useUpload.d.ts +1 -1
  168. package/dist/admin/src/legacy/pages/App/components/BulkActions.d.ts +1 -1
  169. package/dist/admin/src/services/api.d.ts +6 -0
  170. package/dist/admin/src/utils/allowedMediaTypes.d.ts +16 -0
  171. package/dist/admin/translations/ca.json.js +3 -3
  172. package/dist/admin/translations/ca.json.mjs +3 -3
  173. package/dist/admin/translations/da.json.js +1 -1
  174. package/dist/admin/translations/da.json.mjs +1 -1
  175. package/dist/admin/translations/de.json.js +1 -1
  176. package/dist/admin/translations/de.json.mjs +1 -1
  177. package/dist/admin/translations/en.json.js +9 -0
  178. package/dist/admin/translations/en.json.js.map +1 -1
  179. package/dist/admin/translations/en.json.mjs +9 -0
  180. package/dist/admin/translations/en.json.mjs.map +1 -1
  181. package/dist/admin/translations/es.json.js +1 -1
  182. package/dist/admin/translations/es.json.mjs +1 -1
  183. package/dist/admin/translations/sk.json.js +2 -2
  184. package/dist/admin/translations/sk.json.mjs +2 -2
  185. package/dist/admin/translations/tr.json.js +2 -2
  186. package/dist/admin/translations/tr.json.mjs +2 -2
  187. package/dist/admin/translations/zh-Hans.json.js +1 -1
  188. package/dist/admin/translations/zh-Hans.json.mjs +1 -1
  189. package/dist/admin/translations/zh.json.js +2 -2
  190. package/dist/admin/translations/zh.json.mjs +2 -2
  191. package/dist/admin/utils/allowedMediaTypes.js +42 -0
  192. package/dist/admin/utils/allowedMediaTypes.js.map +1 -0
  193. package/dist/admin/utils/allowedMediaTypes.mjs +39 -0
  194. package/dist/admin/utils/allowedMediaTypes.mjs.map +1 -0
  195. package/dist/server/config.js +6 -0
  196. package/dist/server/config.js.map +1 -1
  197. package/dist/server/config.mjs +6 -0
  198. package/dist/server/config.mjs.map +1 -1
  199. package/dist/server/controllers/validation/admin/upload.js.map +1 -1
  200. package/dist/server/controllers/validation/admin/upload.mjs.map +1 -1
  201. package/dist/server/controllers/validation/content-api/upload.js.map +1 -1
  202. package/dist/server/controllers/validation/content-api/upload.mjs.map +1 -1
  203. package/dist/server/mcp/ambient-instance.js +7 -5
  204. package/dist/server/mcp/ambient-instance.js.map +1 -1
  205. package/dist/server/mcp/ambient-instance.mjs +7 -5
  206. package/dist/server/mcp/ambient-instance.mjs.map +1 -1
  207. package/dist/server/mcp/handlers/folder-handlers.js +4 -16
  208. package/dist/server/mcp/handlers/folder-handlers.js.map +1 -1
  209. package/dist/server/mcp/handlers/folder-handlers.mjs +5 -17
  210. package/dist/server/mcp/handlers/folder-handlers.mjs.map +1 -1
  211. package/dist/server/mcp/handlers/read-handlers.js +6 -14
  212. package/dist/server/mcp/handlers/read-handlers.js.map +1 -1
  213. package/dist/server/mcp/handlers/read-handlers.mjs +7 -15
  214. package/dist/server/mcp/handlers/read-handlers.mjs.map +1 -1
  215. package/dist/server/mcp/handlers/write-handlers.js +3 -13
  216. package/dist/server/mcp/handlers/write-handlers.js.map +1 -1
  217. package/dist/server/mcp/handlers/write-handlers.mjs +3 -13
  218. package/dist/server/mcp/handlers/write-handlers.mjs.map +1 -1
  219. package/dist/server/mcp/register-upload-mcp-tools.js +215 -195
  220. package/dist/server/mcp/register-upload-mcp-tools.js.map +1 -1
  221. package/dist/server/mcp/register-upload-mcp-tools.mjs +215 -195
  222. package/dist/server/mcp/register-upload-mcp-tools.mjs.map +1 -1
  223. package/dist/server/services/extensions/utils.js +1 -1
  224. package/dist/server/services/extensions/utils.js.map +1 -1
  225. package/dist/server/services/extensions/utils.mjs +1 -1
  226. package/dist/server/services/extensions/utils.mjs.map +1 -1
  227. package/dist/server/services/image-manipulation.js +33 -14
  228. package/dist/server/services/image-manipulation.js.map +1 -1
  229. package/dist/server/services/image-manipulation.mjs +33 -14
  230. package/dist/server/services/image-manipulation.mjs.map +1 -1
  231. package/dist/server/src/config.d.ts +3 -0
  232. package/dist/server/src/config.d.ts.map +1 -1
  233. package/dist/server/src/controllers/validation/admin/upload.d.ts.map +1 -1
  234. package/dist/server/src/controllers/validation/content-api/upload.d.ts.map +1 -1
  235. package/dist/server/src/index.d.ts +3 -0
  236. package/dist/server/src/index.d.ts.map +1 -1
  237. package/dist/server/src/mcp/ambient-instance.d.ts +7 -5
  238. package/dist/server/src/mcp/ambient-instance.d.ts.map +1 -1
  239. package/dist/server/src/mcp/handlers/folder-handlers.d.ts.map +1 -1
  240. package/dist/server/src/mcp/handlers/read-handlers.d.ts +3 -2
  241. package/dist/server/src/mcp/handlers/read-handlers.d.ts.map +1 -1
  242. package/dist/server/src/mcp/handlers/write-handlers.d.ts.map +1 -1
  243. package/dist/server/src/mcp/register-upload-mcp-tools.d.ts +9 -14
  244. package/dist/server/src/mcp/register-upload-mcp-tools.d.ts.map +1 -1
  245. package/dist/server/src/services/extensions/utils.d.ts +1 -1
  246. package/dist/server/src/services/image-manipulation.d.ts.map +1 -1
  247. package/dist/server/src/types.d.ts +1 -0
  248. package/dist/server/src/types.d.ts.map +1 -1
  249. package/dist/server/utils/mime-validation.js +1 -1
  250. package/dist/server/utils/mime-validation.js.map +1 -1
  251. package/dist/server/utils/mime-validation.mjs +1 -1
  252. package/dist/server/utils/mime-validation.mjs.map +1 -1
  253. package/package.json +7 -7
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var constants = require('../constants.js');
4
+ var ambientInstance = require('./ambient-instance.js');
4
5
  var inputSchemas = require('./schemas/input-schemas.js');
5
6
  var outputSchemas = require('./schemas/output-schemas.js');
6
7
  var readHandlers = require('./handlers/read-handlers.js');
@@ -24,206 +25,225 @@ var folderHandlers = require('./handlers/folder-handlers.js');
24
25
  * combined tool would let an agent pass folder ids where assets were meant with nothing to
25
26
  * object. On the delete side that mistake is unrecoverable, and two tools also let each
26
27
  * description carry the warning matched to its own blast radius.
27
- */ const buildUploadMcpToolDefinitions = ()=>[
28
- {
29
- name: 'media_list_assets',
30
- title: 'Media: list assets',
31
- description: 'List Media Library assets with pagination, folder / mime type / name filters and sorting. Assets are identified by a numeric id — media files are not documents and have no documentId.',
32
- telemetry: {
33
- source: 'upload',
34
- name: 'list'
35
- },
36
- auth: {
37
- policies: [
38
- {
39
- action: constants.ACTIONS.read
40
- }
41
- ]
42
- },
43
- resolveInputSchema: ()=>inputSchemas.mediaListAssetsInputSchema,
44
- resolveOutputSchema: ()=>outputSchemas.mediaListAssetsOutputSchema,
45
- createHandler: readHandlers.createMediaListAssetsHandler
46
- },
47
- {
48
- name: 'media_get_asset',
49
- title: 'Media: get asset',
50
- description: 'Get a single Media Library asset by its numeric id. Media files are not documents: use the numeric id, not a documentId.',
51
- telemetry: {
52
- source: 'upload',
53
- name: 'get'
54
- },
55
- auth: {
56
- policies: [
57
- {
58
- action: constants.ACTIONS.read
59
- }
60
- ]
61
- },
62
- resolveInputSchema: ()=>inputSchemas.mediaGetAssetInputSchema,
63
- resolveOutputSchema: ()=>outputSchemas.mediaGetAssetOutputSchema,
64
- createHandler: readHandlers.createMediaGetAssetHandler
65
- },
66
- {
67
- name: 'media_list_folders',
68
- title: 'Media: list folders',
69
- description: 'List the Media Library folder structure as a nested tree. Folders are identified by a numeric id; pass one as `folderId` to media_list_assets to list its contents.',
70
- telemetry: {
71
- source: 'upload',
72
- name: 'list_folders'
73
- },
74
- auth: {
75
- policies: [
76
- {
77
- action: constants.ACTIONS.read
78
- }
79
- ]
80
- },
81
- resolveOutputSchema: ()=>outputSchemas.mediaListFoldersOutputSchema,
82
- createHandler: readHandlers.createMediaListFoldersHandler
83
- },
84
- {
85
- name: 'media_update_asset',
86
- title: 'Media: update asset metadata',
87
- description: "Update the editable metadata of a Media Library asset, identified by its numeric id. Only name, alternativeText and caption can be written: use media_move_assets to change an asset's folder, and note that url, mime, size and the file contents are owned by the upload provider and cannot be edited over MCP.",
88
- telemetry: {
89
- source: 'upload',
90
- name: 'update'
91
- },
92
- auth: {
93
- policies: [
94
- {
95
- action: constants.ACTIONS.update
96
- }
97
- ]
98
- },
99
- resolveInputSchema: ()=>inputSchemas.mediaUpdateAssetInputSchema,
100
- resolveOutputSchema: ()=>outputSchemas.mediaUpdateAssetOutputSchema,
101
- createHandler: writeHandlers.createMediaUpdateAssetHandler
102
- },
103
- {
104
- name: 'media_move_assets',
105
- title: 'Media: move assets between folders',
106
- description: "Move Media Library assets into a different folder, in bulk. Takes `ids` — an array of numeric ASSET ids — and `folder`, the numeric id of the destination; pass `folder: null` to move them to the media library root. Both are required: use an array of one to move a single asset, and say null explicitly for the root.\n\nTakes ASSET ids only. Media files are not documents: use numeric ids, not documentIds.\n\nNEVER PASS A FOLDER ID. Asset ids and folder ids are separate, independently numbered namespaces, and the SAME NUMBER OFTEN NAMES BOTH an asset and a folder. This tool always reads the number as an ASSET id: hand it a folder id and it will move whichever unrelated asset happens to share that number, reporting that move as a success, while leaving the folder exactly where it was. Nothing in the request can express which one you meant, so the server cannot catch this for you — only an id matching no asset at all is reported as failed. Take ids only from media_list_assets or media_get_asset, never from media_list_folders, and use media_move_folder to move a folder (which carries its whole subtree).\n\nMoving changes the folder only. Names, alt text, captions and the assets' public URLs are unaffected, so nothing referencing them breaks — use media_update_asset to edit metadata.\n\nPARTIAL SUCCESS IS POSSIBLE: a bad id among good ones does NOT roll the valid moves back. The response always reports `moved` (the assets that were moved) and `failed` (each remaining id with a reason), which together account for every id you passed — so retry only the ids in `failed`, and treat `moved` as done. This holds even when nothing moved at all: `moved` is then empty and every id is in `failed`. The one error that rejects the whole call is a destination folder that does not exist, which is checked before anything is moved.",
107
- telemetry: {
108
- source: 'upload',
109
- name: 'move'
110
- },
111
- auth: {
112
- policies: [
113
- {
114
- action: constants.ACTIONS.update
115
- }
116
- ]
117
- },
118
- resolveInputSchema: ()=>inputSchemas.mediaMoveAssetsInputSchema,
119
- resolveOutputSchema: ()=>outputSchemas.mediaMoveAssetsOutputSchema,
120
- createHandler: writeHandlers.createMediaMoveAssetsHandler
121
- },
122
- {
123
- name: 'media_delete_assets',
124
- title: 'Media: delete assets (destructive)',
125
- description: 'DESTRUCTIVE AND IRREVERSIBLE. Permanently deletes Media Library assets by numeric id, in bulk — from the database AND from the storage provider, along with every generated thumbnail and size variant. There is no undo, no trash and no recycle bin. The deleted files stop being served immediately, so any live entry, page or export still referencing one will break.\n\nWHETHER AN ASSET IS USED IN PUBLISHED CONTENT CANNOT BE CHECKED: Strapi does not expose "used in" information over this API, so this tool cannot tell you whether an asset is referenced by any entry, and a successful delete is NOT evidence that nothing was using it. Confirm with the user before deleting.\n\nCall it first WITHOUT `dryRun` (or with `dryRun: true`) to preview: nothing is deleted and the response lists exactly which assets WOULD be removed, and how many. Report those to the user, and only then call it again with `dryRun: false` to actually delete.\n\nTakes `ids`, an array of numeric ASSET ids — use an array of one to delete a single asset. Media files are not documents: use numeric ids, not documentIds.\n\nNEVER PASS A FOLDER ID. Asset ids and folder ids are separate, independently numbered namespaces, and the SAME NUMBER OFTEN NAMES BOTH an asset and a folder. This tool always reads the number as an ASSET id: hand it a folder id and it will silently delete whichever unrelated asset happens to share that number, while leaving the folder untouched. Nothing in the request can express which one you meant, so the server cannot catch this for you — only an id matching no asset at all is reported as failed. Take ids only from media_list_assets or media_get_asset, never from media_list_folders, and use media_delete_folder to delete a folder. If you are not certain an id came from media_list_assets, run the dry run and check the returned name and folder before deleting.\n\nPARTIAL SUCCESS IS POSSIBLE: a bad id among good ones does NOT roll the completed deletions back, and those cannot be undone. The response always reports `deleted` (the assets removed, described in full because they can no longer be read back) and `failed` (each remaining id with a reason), which together account for every id you passed — so retry only the ids in `failed`. This holds on the dry run too, which reports the same split before anything is destroyed.',
126
- telemetry: {
127
- source: 'upload',
128
- name: 'delete'
129
- },
130
- auth: {
131
- policies: [
132
- {
133
- action: constants.ACTIONS.update
134
- }
135
- ]
136
- },
137
- resolveInputSchema: ()=>inputSchemas.mediaDeleteAssetsInputSchema,
138
- resolveOutputSchema: ()=>outputSchemas.mediaDeleteAssetsOutputSchema,
139
- createHandler: writeHandlers.createMediaDeleteAssetsHandler
140
- },
141
- {
142
- name: 'media_create_folder',
143
- title: 'Media: create folder',
144
- description: 'Create a Media Library folder, optionally inside an existing one. Folders are identified by a numeric id: pass `parent` to nest the new folder, or omit it to create the folder at the media library root. The name must be unique among its siblings and cannot contain slashes.',
145
- telemetry: {
146
- source: 'upload',
147
- name: 'create_folder'
148
- },
149
- // `create`, not `update`, to match `POST /upload/folders` — the admin route for the same
150
- // operation gates on `assets.create`. The other folder tools use `update` because their
151
- // admin counterparts (`PUT /folders/:id` and both bulk actions) do.
152
- auth: {
153
- policies: [
154
- {
155
- action: constants.ACTIONS.create
156
- }
157
- ]
158
- },
159
- resolveInputSchema: ()=>inputSchemas.mediaCreateFolderInputSchema,
160
- resolveOutputSchema: ()=>outputSchemas.mediaCreateFolderOutputSchema,
161
- createHandler: folderHandlers.createMediaCreateFolderHandler
162
- },
163
- {
164
- name: 'media_rename_folder',
165
- title: 'Media: rename folder',
166
- description: "Rename a Media Library folder, identified by its numeric id. Changes the folder name only and leaves its location, its contents and their URLs untouched — use media_move_folder to change which folder it sits in. The new name must be unique among the folder's siblings.",
167
- telemetry: {
168
- source: 'upload',
169
- name: 'rename_folder'
170
- },
171
- auth: {
172
- policies: [
173
- {
174
- action: constants.ACTIONS.update
175
- }
176
- ]
177
- },
178
- resolveInputSchema: ()=>inputSchemas.mediaRenameFolderInputSchema,
179
- resolveOutputSchema: ()=>outputSchemas.mediaRenameFolderOutputSchema,
180
- createHandler: folderHandlers.createMediaRenameFolderHandler
181
- },
182
- {
183
- name: 'media_move_folder',
184
- title: 'Media: move folder',
185
- description: 'Move a Media Library folder into a different parent folder, identified by numeric ids. The folder keeps its name and carries all of its subfolders and files with it; pass `parent: null` to move it to the media library root. A folder cannot be moved into itself or into one of its own descendants. Use media_rename_folder to change the name instead.',
186
- telemetry: {
187
- source: 'upload',
188
- name: 'move_folder'
189
- },
190
- auth: {
191
- policies: [
192
- {
193
- action: constants.ACTIONS.update
194
- }
195
- ]
196
- },
197
- resolveInputSchema: ()=>inputSchemas.mediaMoveFolderInputSchema,
198
- resolveOutputSchema: ()=>outputSchemas.mediaMoveFolderOutputSchema,
199
- createHandler: folderHandlers.createMediaMoveFolderHandler
200
- },
201
- {
202
- name: 'media_delete_folder',
203
- title: 'Media: delete folder (destructive)',
204
- description: 'DESTRUCTIVE AND IRREVERSIBLE. Deletes Media Library folders by numeric id and CASCADES: every subfolder and every file inside them is permanently deleted from the database and from the storage provider. There is no undo, no trash and no recycle bin, and the deleted files stop being served — any live entry or page still referencing one will break.\n\nWHETHER THE CONTAINED ASSETS ARE USED IN PUBLISHED CONTENT CANNOT BE CHECKED: Strapi does not expose "used in" information over this API, so this tool cannot tell you whether a file is referenced by an entry. Confirm with the user before deleting.\n\nCall it first WITHOUT `dryRun` (or with `dryRun: true`) to preview: nothing is deleted and the response reports how many folders and files WOULD be removed. Only after reporting those counts should you call it again with `dryRun: false` to actually delete. Takes FOLDER ids only — asset ids are a separate namespace of integers; use media_delete_assets for individual assets. All or nothing: if ANY id does not resolve to a folder the whole call is rejected and nothing is deleted, so a list mixing folder and asset ids never deletes half of what it names.',
205
- telemetry: {
206
- source: 'upload',
207
- name: 'delete_folder'
208
- },
209
- auth: {
210
- policies: [
211
- {
212
- action: constants.ACTIONS.update
213
- }
214
- ]
215
- },
216
- resolveInputSchema: ()=>inputSchemas.mediaDeleteFolderInputSchema,
217
- resolveOutputSchema: ()=>outputSchemas.mediaDeleteFolderOutputSchema,
218
- createHandler: folderHandlers.createMediaDeleteFolderHandler
219
- }
220
- ];
28
+ */ const UPLOAD_MCP_TOOLS = [
29
+ {
30
+ name: 'media_list_assets',
31
+ title: 'Media: list assets',
32
+ description: 'List Media Library assets with pagination, folder / mime type / name filters and sorting. Assets are identified by a numeric id — media files are not documents and have no documentId.',
33
+ telemetry: {
34
+ source: 'upload',
35
+ name: 'list'
36
+ },
37
+ auth: {
38
+ policies: [
39
+ {
40
+ action: constants.ACTIONS.read
41
+ }
42
+ ]
43
+ },
44
+ resolveInputSchema: ()=>inputSchemas.mediaListAssetsInputSchema,
45
+ resolveOutputSchema: ()=>outputSchemas.mediaListAssetsOutputSchema,
46
+ createHandler: readHandlers.createMediaListAssetsHandler
47
+ },
48
+ {
49
+ name: 'media_get_asset',
50
+ title: 'Media: get asset',
51
+ description: 'Get a single Media Library asset by its numeric id. Media files are not documents: use the numeric id, not a documentId.',
52
+ telemetry: {
53
+ source: 'upload',
54
+ name: 'get'
55
+ },
56
+ auth: {
57
+ policies: [
58
+ {
59
+ action: constants.ACTIONS.read
60
+ }
61
+ ]
62
+ },
63
+ resolveInputSchema: ()=>inputSchemas.mediaGetAssetInputSchema,
64
+ resolveOutputSchema: ()=>outputSchemas.mediaGetAssetOutputSchema,
65
+ createHandler: readHandlers.createMediaGetAssetHandler
66
+ },
67
+ {
68
+ name: 'media_list_folders',
69
+ title: 'Media: list folders',
70
+ description: 'List the Media Library folder structure as a nested tree. Folders are identified by a numeric id; pass one as `folderId` to media_list_assets to list its contents.',
71
+ telemetry: {
72
+ source: 'upload',
73
+ name: 'list_folders'
74
+ },
75
+ auth: {
76
+ policies: [
77
+ {
78
+ action: constants.ACTIONS.read
79
+ }
80
+ ]
81
+ },
82
+ resolveOutputSchema: ()=>outputSchemas.mediaListFoldersOutputSchema,
83
+ createHandler: readHandlers.createMediaListFoldersHandler
84
+ },
85
+ {
86
+ name: 'media_update_asset',
87
+ title: 'Media: update asset metadata',
88
+ description: "Update the editable metadata of a Media Library asset, identified by its numeric id. Only name, alternativeText and caption can be written: use media_move_assets to change an asset's folder, and note that url, mime, size and the file contents are owned by the upload provider and cannot be edited over MCP.",
89
+ telemetry: {
90
+ source: 'upload',
91
+ name: 'update'
92
+ },
93
+ auth: {
94
+ policies: [
95
+ {
96
+ action: constants.ACTIONS.update
97
+ }
98
+ ]
99
+ },
100
+ resolveInputSchema: ()=>inputSchemas.mediaUpdateAssetInputSchema,
101
+ resolveOutputSchema: ()=>outputSchemas.mediaUpdateAssetOutputSchema,
102
+ createHandler: writeHandlers.createMediaUpdateAssetHandler
103
+ },
104
+ {
105
+ name: 'media_move_assets',
106
+ title: 'Media: move assets between folders',
107
+ description: "Move Media Library assets into a different folder, in bulk. Takes `ids` — an array of numeric ASSET ids — and `folder`, the numeric id of the destination; pass `folder: null` to move them to the media library root. Both are required: use an array of one to move a single asset, and say null explicitly for the root.\n\nTakes ASSET ids only. Media files are not documents: use numeric ids, not documentIds.\n\nNEVER PASS A FOLDER ID. Asset ids and folder ids are separate, independently numbered namespaces, and the SAME NUMBER OFTEN NAMES BOTH an asset and a folder. This tool always reads the number as an ASSET id: hand it a folder id and it will move whichever unrelated asset happens to share that number, reporting that move as a success, while leaving the folder exactly where it was. Nothing in the request can express which one you meant, so the server cannot catch this for you — only an id matching no asset at all is reported as failed. Take ids only from media_list_assets or media_get_asset, never from media_list_folders, and use media_move_folder to move a folder (which carries its whole subtree).\n\nMoving changes the folder only. Names, alt text, captions and the assets' public URLs are unaffected, so nothing referencing them breaks — use media_update_asset to edit metadata.\n\nPARTIAL SUCCESS IS POSSIBLE: a bad id among good ones does NOT roll the valid moves back. The response always reports `moved` (the assets that were moved) and `failed` (each remaining id with a reason), which together account for every id you passed — so retry only the ids in `failed`, and treat `moved` as done. This holds even when nothing moved at all: `moved` is then empty and every id is in `failed`. The one error that rejects the whole call is a destination folder that does not exist, which is checked before anything is moved.",
108
+ telemetry: {
109
+ source: 'upload',
110
+ name: 'move'
111
+ },
112
+ auth: {
113
+ policies: [
114
+ {
115
+ action: constants.ACTIONS.update
116
+ }
117
+ ]
118
+ },
119
+ resolveInputSchema: ()=>inputSchemas.mediaMoveAssetsInputSchema,
120
+ resolveOutputSchema: ()=>outputSchemas.mediaMoveAssetsOutputSchema,
121
+ createHandler: writeHandlers.createMediaMoveAssetsHandler
122
+ },
123
+ {
124
+ name: 'media_delete_assets',
125
+ title: 'Media: delete assets (destructive)',
126
+ description: 'DESTRUCTIVE AND IRREVERSIBLE. Permanently deletes Media Library assets by numeric id, in bulk — from the database AND from the storage provider, along with every generated thumbnail and size variant. There is no undo, no trash and no recycle bin. The deleted files stop being served immediately, so any live entry, page or export still referencing one will break.\n\nWHETHER AN ASSET IS USED IN PUBLISHED CONTENT CANNOT BE CHECKED: Strapi does not expose "used in" information over this API, so this tool cannot tell you whether an asset is referenced by any entry, and a successful delete is NOT evidence that nothing was using it. Confirm with the user before deleting.\n\nCall it first WITHOUT `dryRun` (or with `dryRun: true`) to preview: nothing is deleted and the response lists exactly which assets WOULD be removed, and how many. Report those to the user, and only then call it again with `dryRun: false` to actually delete.\n\nTakes `ids`, an array of numeric ASSET ids — use an array of one to delete a single asset. Media files are not documents: use numeric ids, not documentIds.\n\nNEVER PASS A FOLDER ID. Asset ids and folder ids are separate, independently numbered namespaces, and the SAME NUMBER OFTEN NAMES BOTH an asset and a folder. This tool always reads the number as an ASSET id: hand it a folder id and it will silently delete whichever unrelated asset happens to share that number, while leaving the folder untouched. Nothing in the request can express which one you meant, so the server cannot catch this for you — only an id matching no asset at all is reported as failed. Take ids only from media_list_assets or media_get_asset, never from media_list_folders, and use media_delete_folder to delete a folder. If you are not certain an id came from media_list_assets, run the dry run and check the returned name and folder before deleting.\n\nPARTIAL SUCCESS IS POSSIBLE: a bad id among good ones does NOT roll the completed deletions back, and those cannot be undone. The response always reports `deleted` (the assets removed, described in full because they can no longer be read back) and `failed` (each remaining id with a reason), which together account for every id you passed — so retry only the ids in `failed`. This holds on the dry run too, which reports the same split before anything is destroyed.',
127
+ telemetry: {
128
+ source: 'upload',
129
+ name: 'delete'
130
+ },
131
+ auth: {
132
+ policies: [
133
+ {
134
+ action: constants.ACTIONS.update
135
+ }
136
+ ]
137
+ },
138
+ resolveInputSchema: ()=>inputSchemas.mediaDeleteAssetsInputSchema,
139
+ resolveOutputSchema: ()=>outputSchemas.mediaDeleteAssetsOutputSchema,
140
+ createHandler: writeHandlers.createMediaDeleteAssetsHandler
141
+ },
142
+ {
143
+ name: 'media_create_folder',
144
+ title: 'Media: create folder',
145
+ description: 'Create a Media Library folder, optionally inside an existing one. Folders are identified by a numeric id: pass `parent` to nest the new folder, or omit it to create the folder at the media library root. The name must be unique among its siblings and cannot contain slashes.',
146
+ telemetry: {
147
+ source: 'upload',
148
+ name: 'create_folder'
149
+ },
150
+ // `create`, not `update`, to match `POST /upload/folders` — the admin route for the same
151
+ // operation gates on `assets.create`. The other folder tools use `update` because their
152
+ // admin counterparts (`PUT /folders/:id` and both bulk actions) do.
153
+ auth: {
154
+ policies: [
155
+ {
156
+ action: constants.ACTIONS.create
157
+ }
158
+ ]
159
+ },
160
+ resolveInputSchema: ()=>inputSchemas.mediaCreateFolderInputSchema,
161
+ resolveOutputSchema: ()=>outputSchemas.mediaCreateFolderOutputSchema,
162
+ createHandler: folderHandlers.createMediaCreateFolderHandler
163
+ },
164
+ {
165
+ name: 'media_rename_folder',
166
+ title: 'Media: rename folder',
167
+ description: "Rename a Media Library folder, identified by its numeric id. Changes the folder name only and leaves its location, its contents and their URLs untouched — use media_move_folder to change which folder it sits in. The new name must be unique among the folder's siblings.",
168
+ telemetry: {
169
+ source: 'upload',
170
+ name: 'rename_folder'
171
+ },
172
+ auth: {
173
+ policies: [
174
+ {
175
+ action: constants.ACTIONS.update
176
+ }
177
+ ]
178
+ },
179
+ resolveInputSchema: ()=>inputSchemas.mediaRenameFolderInputSchema,
180
+ resolveOutputSchema: ()=>outputSchemas.mediaRenameFolderOutputSchema,
181
+ createHandler: folderHandlers.createMediaRenameFolderHandler
182
+ },
183
+ {
184
+ name: 'media_move_folder',
185
+ title: 'Media: move folder',
186
+ description: 'Move a Media Library folder into a different parent folder, identified by numeric ids. The folder keeps its name and carries all of its subfolders and files with it; pass `parent: null` to move it to the media library root. A folder cannot be moved into itself or into one of its own descendants. Use media_rename_folder to change the name instead.',
187
+ telemetry: {
188
+ source: 'upload',
189
+ name: 'move_folder'
190
+ },
191
+ auth: {
192
+ policies: [
193
+ {
194
+ action: constants.ACTIONS.update
195
+ }
196
+ ]
197
+ },
198
+ resolveInputSchema: ()=>inputSchemas.mediaMoveFolderInputSchema,
199
+ resolveOutputSchema: ()=>outputSchemas.mediaMoveFolderOutputSchema,
200
+ createHandler: folderHandlers.createMediaMoveFolderHandler
201
+ },
202
+ {
203
+ name: 'media_delete_folder',
204
+ title: 'Media: delete folder (destructive)',
205
+ description: 'DESTRUCTIVE AND IRREVERSIBLE. Deletes Media Library folders by numeric id and CASCADES: every subfolder and every file inside them is permanently deleted from the database and from the storage provider. There is no undo, no trash and no recycle bin, and the deleted files stop being served — any live entry or page still referencing one will break.\n\nWHETHER THE CONTAINED ASSETS ARE USED IN PUBLISHED CONTENT CANNOT BE CHECKED: Strapi does not expose "used in" information over this API, so this tool cannot tell you whether a file is referenced by an entry. Confirm with the user before deleting.\n\nCall it first WITHOUT `dryRun` (or with `dryRun: true`) to preview: nothing is deleted and the response reports how many folders and files WOULD be removed. Only after reporting those counts should you call it again with `dryRun: false` to actually delete. Takes FOLDER ids only — asset ids are a separate namespace of integers; use media_delete_assets for individual assets. All or nothing: if ANY id does not resolve to a folder the whole call is rejected and nothing is deleted, so a list mixing folder and asset ids never deletes half of what it names.',
206
+ telemetry: {
207
+ source: 'upload',
208
+ name: 'delete_folder'
209
+ },
210
+ auth: {
211
+ policies: [
212
+ {
213
+ action: constants.ACTIONS.update
214
+ }
215
+ ]
216
+ },
217
+ resolveInputSchema: ()=>inputSchemas.mediaDeleteFolderInputSchema,
218
+ resolveOutputSchema: ()=>outputSchemas.mediaDeleteFolderOutputSchema,
219
+ createHandler: folderHandlers.createMediaDeleteFolderHandler
220
+ }
221
+ ];
222
+ /**
223
+ * The Media Library MCP tools, every handler factory wrapped in the ambient-instance guard.
224
+ *
225
+ * The guard is applied here rather than left to each factory so it is structural: a tool added
226
+ * to the array above cannot forget it. See `assertAmbientInstance` for what it defends against
227
+ * — the `folder` and `file` services query `global.strapi` regardless of the instance passed to
228
+ * `getService`, so a handler acting on any other instance would read or write the wrong app's
229
+ * media library.
230
+ *
231
+ * Wrapping the factory, not the handler, keeps the failure at handler construction: the MCP
232
+ * registry catches a factory throw, logs it and substitutes a fallback handler, so the invariant
233
+ * reaches the operator's log instead of an agent's tool output.
234
+ */ const buildUploadMcpToolDefinitions = ()=>UPLOAD_MCP_TOOLS.map((tool)=>({
235
+ ...tool,
236
+ createHandler (strapi, context) {
237
+ ambientInstance.assertAmbientInstance(strapi);
238
+ return tool.createHandler(strapi, context);
239
+ }
240
+ }));
221
241
  /**
222
242
  * Registers the Media Library MCP tools via `strapi.ai.mcp.registerTool()`.
223
243
  * Must be called from the plugin register phase, before the MCP HTTP server starts.
224
244
  */ const registerUploadMcpTools = ({ strapi })=>{
225
245
  // No `isEnabled()` gate: registerTool() only stores the definition, and the MCP server never
226
- // exposes it when disabled, so registering unconditionally is a no-op there. The three
246
+ // exposes it when disabled, so registering unconditionally is a no-op there. The
227
247
  // definitions are static, so there is no derivation cost worth guarding either.
228
248
  for (const tool of buildUploadMcpToolDefinitions()){
229
249
  strapi.ai?.mcp?.registerTool(tool);
@@ -1 +1 @@
1
- {"version":3,"file":"register-upload-mcp-tools.js","sources":["../../../server/src/mcp/register-upload-mcp-tools.ts"],"sourcesContent":["import type { Core } from '@strapi/types';\n\nimport { ACTIONS } from '../constants';\nimport type { UploadMcpTool } from './types';\nimport {\n mediaListAssetsInputSchema,\n mediaGetAssetInputSchema,\n mediaListAssetsOutputSchema,\n mediaGetAssetOutputSchema,\n mediaListFoldersOutputSchema,\n mediaUpdateAssetInputSchema,\n mediaUpdateAssetOutputSchema,\n mediaCreateFolderInputSchema,\n mediaCreateFolderOutputSchema,\n mediaRenameFolderInputSchema,\n mediaRenameFolderOutputSchema,\n mediaMoveFolderInputSchema,\n mediaMoveFolderOutputSchema,\n mediaDeleteFolderInputSchema,\n mediaDeleteFolderOutputSchema,\n mediaMoveAssetsInputSchema,\n mediaMoveAssetsOutputSchema,\n mediaDeleteAssetsInputSchema,\n mediaDeleteAssetsOutputSchema,\n} from './schemas';\nimport {\n createMediaListAssetsHandler,\n createMediaGetAssetHandler,\n createMediaListFoldersHandler,\n createMediaUpdateAssetHandler,\n createMediaCreateFolderHandler,\n createMediaRenameFolderHandler,\n createMediaMoveFolderHandler,\n createMediaDeleteFolderHandler,\n createMediaMoveAssetsHandler,\n createMediaDeleteAssetsHandler,\n} from './handlers';\n\n/**\n * The Media Library MCP tools.\n *\n * Folder writes inherit the same `plugin::upload.assets.update` action rather than introducing a\n * folder-specific one, matching what the admin UI enforces today. MCP-specific folder RBAC is\n * out of scope.\n *\n * Renaming and moving are separate tools for both objects — rename/update changes attributes,\n * move changes location — so an agent selects by intent instead of assembling a combined patch.\n *\n * The asset and folder tools stay separate for both move and delete, even though\n * `/actions/bulk-move` accepts both id lists at once and `/actions/bulk-delete` accepts `fileIds`\n * and `folderIds` together. Asset ids and folder ids are indistinguishable integers from separate\n * namespaces, and both `media_list_assets` and `media_list_folders` return a plain `id`, so a\n * combined tool would let an agent pass folder ids where assets were meant with nothing to\n * object. On the delete side that mistake is unrecoverable, and two tools also let each\n * description carry the warning matched to its own blast radius.\n */\nexport const buildUploadMcpToolDefinitions = (): UploadMcpTool[] => [\n {\n name: 'media_list_assets',\n title: 'Media: list assets',\n description:\n 'List Media Library assets with pagination, folder / mime type / name filters and sorting. Assets are identified by a numeric id — media files are not documents and have no documentId.',\n telemetry: { source: 'upload', name: 'list' },\n auth: { policies: [{ action: ACTIONS.read }] },\n resolveInputSchema: () => mediaListAssetsInputSchema,\n resolveOutputSchema: () => mediaListAssetsOutputSchema,\n createHandler: createMediaListAssetsHandler,\n },\n {\n name: 'media_get_asset',\n title: 'Media: get asset',\n description:\n 'Get a single Media Library asset by its numeric id. Media files are not documents: use the numeric id, not a documentId.',\n telemetry: { source: 'upload', name: 'get' },\n auth: { policies: [{ action: ACTIONS.read }] },\n resolveInputSchema: () => mediaGetAssetInputSchema,\n resolveOutputSchema: () => mediaGetAssetOutputSchema,\n createHandler: createMediaGetAssetHandler,\n },\n {\n name: 'media_list_folders',\n title: 'Media: list folders',\n description:\n 'List the Media Library folder structure as a nested tree. Folders are identified by a numeric id; pass one as `folderId` to media_list_assets to list its contents.',\n telemetry: { source: 'upload', name: 'list_folders' },\n auth: { policies: [{ action: ACTIONS.read }] },\n resolveOutputSchema: () => mediaListFoldersOutputSchema,\n createHandler: createMediaListFoldersHandler,\n },\n {\n name: 'media_update_asset',\n title: 'Media: update asset metadata',\n description:\n \"Update the editable metadata of a Media Library asset, identified by its numeric id. Only name, alternativeText and caption can be written: use media_move_assets to change an asset's folder, and note that url, mime, size and the file contents are owned by the upload provider and cannot be edited over MCP.\",\n telemetry: { source: 'upload', name: 'update' },\n auth: { policies: [{ action: ACTIONS.update }] },\n resolveInputSchema: () => mediaUpdateAssetInputSchema,\n resolveOutputSchema: () => mediaUpdateAssetOutputSchema,\n createHandler: createMediaUpdateAssetHandler,\n },\n {\n name: 'media_move_assets',\n title: 'Media: move assets between folders',\n description:\n \"Move Media Library assets into a different folder, in bulk. Takes `ids` — an array of numeric ASSET ids — and `folder`, the numeric id of the destination; pass `folder: null` to move them to the media library root. Both are required: use an array of one to move a single asset, and say null explicitly for the root.\\n\\nTakes ASSET ids only. Media files are not documents: use numeric ids, not documentIds.\\n\\nNEVER PASS A FOLDER ID. Asset ids and folder ids are separate, independently numbered namespaces, and the SAME NUMBER OFTEN NAMES BOTH an asset and a folder. This tool always reads the number as an ASSET id: hand it a folder id and it will move whichever unrelated asset happens to share that number, reporting that move as a success, while leaving the folder exactly where it was. Nothing in the request can express which one you meant, so the server cannot catch this for you — only an id matching no asset at all is reported as failed. Take ids only from media_list_assets or media_get_asset, never from media_list_folders, and use media_move_folder to move a folder (which carries its whole subtree).\\n\\nMoving changes the folder only. Names, alt text, captions and the assets' public URLs are unaffected, so nothing referencing them breaks — use media_update_asset to edit metadata.\\n\\nPARTIAL SUCCESS IS POSSIBLE: a bad id among good ones does NOT roll the valid moves back. The response always reports `moved` (the assets that were moved) and `failed` (each remaining id with a reason), which together account for every id you passed — so retry only the ids in `failed`, and treat `moved` as done. This holds even when nothing moved at all: `moved` is then empty and every id is in `failed`. The one error that rejects the whole call is a destination folder that does not exist, which is checked before anything is moved.\",\n telemetry: { source: 'upload', name: 'move' },\n auth: { policies: [{ action: ACTIONS.update }] },\n resolveInputSchema: () => mediaMoveAssetsInputSchema,\n resolveOutputSchema: () => mediaMoveAssetsOutputSchema,\n createHandler: createMediaMoveAssetsHandler,\n },\n {\n name: 'media_delete_assets',\n title: 'Media: delete assets (destructive)',\n description:\n 'DESTRUCTIVE AND IRREVERSIBLE. Permanently deletes Media Library assets by numeric id, in bulk — from the database AND from the storage provider, along with every generated thumbnail and size variant. There is no undo, no trash and no recycle bin. The deleted files stop being served immediately, so any live entry, page or export still referencing one will break.\\n\\nWHETHER AN ASSET IS USED IN PUBLISHED CONTENT CANNOT BE CHECKED: Strapi does not expose \"used in\" information over this API, so this tool cannot tell you whether an asset is referenced by any entry, and a successful delete is NOT evidence that nothing was using it. Confirm with the user before deleting.\\n\\nCall it first WITHOUT `dryRun` (or with `dryRun: true`) to preview: nothing is deleted and the response lists exactly which assets WOULD be removed, and how many. Report those to the user, and only then call it again with `dryRun: false` to actually delete.\\n\\nTakes `ids`, an array of numeric ASSET ids — use an array of one to delete a single asset. Media files are not documents: use numeric ids, not documentIds.\\n\\nNEVER PASS A FOLDER ID. Asset ids and folder ids are separate, independently numbered namespaces, and the SAME NUMBER OFTEN NAMES BOTH an asset and a folder. This tool always reads the number as an ASSET id: hand it a folder id and it will silently delete whichever unrelated asset happens to share that number, while leaving the folder untouched. Nothing in the request can express which one you meant, so the server cannot catch this for you — only an id matching no asset at all is reported as failed. Take ids only from media_list_assets or media_get_asset, never from media_list_folders, and use media_delete_folder to delete a folder. If you are not certain an id came from media_list_assets, run the dry run and check the returned name and folder before deleting.\\n\\nPARTIAL SUCCESS IS POSSIBLE: a bad id among good ones does NOT roll the completed deletions back, and those cannot be undone. The response always reports `deleted` (the assets removed, described in full because they can no longer be read back) and `failed` (each remaining id with a reason), which together account for every id you passed — so retry only the ids in `failed`. This holds on the dry run too, which reports the same split before anything is destroyed.',\n telemetry: { source: 'upload', name: 'delete' },\n auth: { policies: [{ action: ACTIONS.update }] },\n resolveInputSchema: () => mediaDeleteAssetsInputSchema,\n resolveOutputSchema: () => mediaDeleteAssetsOutputSchema,\n createHandler: createMediaDeleteAssetsHandler,\n },\n {\n name: 'media_create_folder',\n title: 'Media: create folder',\n description:\n 'Create a Media Library folder, optionally inside an existing one. Folders are identified by a numeric id: pass `parent` to nest the new folder, or omit it to create the folder at the media library root. The name must be unique among its siblings and cannot contain slashes.',\n telemetry: { source: 'upload', name: 'create_folder' },\n // `create`, not `update`, to match `POST /upload/folders` — the admin route for the same\n // operation gates on `assets.create`. The other folder tools use `update` because their\n // admin counterparts (`PUT /folders/:id` and both bulk actions) do.\n auth: { policies: [{ action: ACTIONS.create }] },\n resolveInputSchema: () => mediaCreateFolderInputSchema,\n resolveOutputSchema: () => mediaCreateFolderOutputSchema,\n createHandler: createMediaCreateFolderHandler,\n },\n {\n name: 'media_rename_folder',\n title: 'Media: rename folder',\n description:\n \"Rename a Media Library folder, identified by its numeric id. Changes the folder name only and leaves its location, its contents and their URLs untouched — use media_move_folder to change which folder it sits in. The new name must be unique among the folder's siblings.\",\n telemetry: { source: 'upload', name: 'rename_folder' },\n auth: { policies: [{ action: ACTIONS.update }] },\n resolveInputSchema: () => mediaRenameFolderInputSchema,\n resolveOutputSchema: () => mediaRenameFolderOutputSchema,\n createHandler: createMediaRenameFolderHandler,\n },\n {\n name: 'media_move_folder',\n title: 'Media: move folder',\n description:\n 'Move a Media Library folder into a different parent folder, identified by numeric ids. The folder keeps its name and carries all of its subfolders and files with it; pass `parent: null` to move it to the media library root. A folder cannot be moved into itself or into one of its own descendants. Use media_rename_folder to change the name instead.',\n telemetry: { source: 'upload', name: 'move_folder' },\n auth: { policies: [{ action: ACTIONS.update }] },\n resolveInputSchema: () => mediaMoveFolderInputSchema,\n resolveOutputSchema: () => mediaMoveFolderOutputSchema,\n createHandler: createMediaMoveFolderHandler,\n },\n {\n name: 'media_delete_folder',\n title: 'Media: delete folder (destructive)',\n description:\n 'DESTRUCTIVE AND IRREVERSIBLE. Deletes Media Library folders by numeric id and CASCADES: every subfolder and every file inside them is permanently deleted from the database and from the storage provider. There is no undo, no trash and no recycle bin, and the deleted files stop being served — any live entry or page still referencing one will break.\\n\\nWHETHER THE CONTAINED ASSETS ARE USED IN PUBLISHED CONTENT CANNOT BE CHECKED: Strapi does not expose \"used in\" information over this API, so this tool cannot tell you whether a file is referenced by an entry. Confirm with the user before deleting.\\n\\nCall it first WITHOUT `dryRun` (or with `dryRun: true`) to preview: nothing is deleted and the response reports how many folders and files WOULD be removed. Only after reporting those counts should you call it again with `dryRun: false` to actually delete. Takes FOLDER ids only — asset ids are a separate namespace of integers; use media_delete_assets for individual assets. All or nothing: if ANY id does not resolve to a folder the whole call is rejected and nothing is deleted, so a list mixing folder and asset ids never deletes half of what it names.',\n telemetry: { source: 'upload', name: 'delete_folder' },\n auth: { policies: [{ action: ACTIONS.update }] },\n resolveInputSchema: () => mediaDeleteFolderInputSchema,\n resolveOutputSchema: () => mediaDeleteFolderOutputSchema,\n createHandler: createMediaDeleteFolderHandler,\n },\n];\n\n/**\n * Registers the Media Library MCP tools via `strapi.ai.mcp.registerTool()`.\n * Must be called from the plugin register phase, before the MCP HTTP server starts.\n */\nexport const registerUploadMcpTools = ({ strapi }: { strapi: Core.Strapi }): void => {\n // No `isEnabled()` gate: registerTool() only stores the definition, and the MCP server never\n // exposes it when disabled, so registering unconditionally is a no-op there. The three\n // definitions are static, so there is no derivation cost worth guarding either.\n for (const tool of buildUploadMcpToolDefinitions()) {\n strapi.ai?.mcp?.registerTool(tool);\n }\n};\n"],"names":["buildUploadMcpToolDefinitions","name","title","description","telemetry","source","auth","policies","action","ACTIONS","read","resolveInputSchema","mediaListAssetsInputSchema","resolveOutputSchema","mediaListAssetsOutputSchema","createHandler","createMediaListAssetsHandler","mediaGetAssetInputSchema","mediaGetAssetOutputSchema","createMediaGetAssetHandler","mediaListFoldersOutputSchema","createMediaListFoldersHandler","update","mediaUpdateAssetInputSchema","mediaUpdateAssetOutputSchema","createMediaUpdateAssetHandler","mediaMoveAssetsInputSchema","mediaMoveAssetsOutputSchema","createMediaMoveAssetsHandler","mediaDeleteAssetsInputSchema","mediaDeleteAssetsOutputSchema","createMediaDeleteAssetsHandler","create","mediaCreateFolderInputSchema","mediaCreateFolderOutputSchema","createMediaCreateFolderHandler","mediaRenameFolderInputSchema","mediaRenameFolderOutputSchema","createMediaRenameFolderHandler","mediaMoveFolderInputSchema","mediaMoveFolderOutputSchema","createMediaMoveFolderHandler","mediaDeleteFolderInputSchema","mediaDeleteFolderOutputSchema","createMediaDeleteFolderHandler","registerUploadMcpTools","strapi","tool","ai","mcp","registerTool"],"mappings":";;;;;;;;;AAsCA;;;;;;;;;;;;;;;;;IAkBO,MAAMA,6BAAAA,GAAgC,IAAuB;AAClE,QAAA;YACEC,IAAAA,EAAM,mBAAA;YACNC,KAAAA,EAAO,oBAAA;YACPC,WAAAA,EACE,yLAAA;YACFC,SAAAA,EAAW;gBAAEC,MAAAA,EAAQ,QAAA;gBAAUJ,IAAAA,EAAM;AAAO,aAAA;YAC5CK,IAAAA,EAAM;gBAAEC,QAAAA,EAAU;AAAC,oBAAA;AAAEC,wBAAAA,MAAAA,EAAQC,kBAAQC;AAAK;AAAE;AAAC,aAAA;AAC7CC,YAAAA,kBAAAA,EAAoB,IAAMC,uCAAAA;AAC1BC,YAAAA,mBAAAA,EAAqB,IAAMC,yCAAAA;YAC3BC,aAAAA,EAAeC;AACjB,SAAA;AACA,QAAA;YACEf,IAAAA,EAAM,iBAAA;YACNC,KAAAA,EAAO,kBAAA;YACPC,WAAAA,EACE,0HAAA;YACFC,SAAAA,EAAW;gBAAEC,MAAAA,EAAQ,QAAA;gBAAUJ,IAAAA,EAAM;AAAM,aAAA;YAC3CK,IAAAA,EAAM;gBAAEC,QAAAA,EAAU;AAAC,oBAAA;AAAEC,wBAAAA,MAAAA,EAAQC,kBAAQC;AAAK;AAAE;AAAC,aAAA;AAC7CC,YAAAA,kBAAAA,EAAoB,IAAMM,qCAAAA;AAC1BJ,YAAAA,mBAAAA,EAAqB,IAAMK,uCAAAA;YAC3BH,aAAAA,EAAeI;AACjB,SAAA;AACA,QAAA;YACElB,IAAAA,EAAM,oBAAA;YACNC,KAAAA,EAAO,qBAAA;YACPC,WAAAA,EACE,qKAAA;YACFC,SAAAA,EAAW;gBAAEC,MAAAA,EAAQ,QAAA;gBAAUJ,IAAAA,EAAM;AAAe,aAAA;YACpDK,IAAAA,EAAM;gBAAEC,QAAAA,EAAU;AAAC,oBAAA;AAAEC,wBAAAA,MAAAA,EAAQC,kBAAQC;AAAK;AAAE;AAAC,aAAA;AAC7CG,YAAAA,mBAAAA,EAAqB,IAAMO,0CAAAA;YAC3BL,aAAAA,EAAeM;AACjB,SAAA;AACA,QAAA;YACEpB,IAAAA,EAAM,oBAAA;YACNC,KAAAA,EAAO,8BAAA;YACPC,WAAAA,EACE,oTAAA;YACFC,SAAAA,EAAW;gBAAEC,MAAAA,EAAQ,QAAA;gBAAUJ,IAAAA,EAAM;AAAS,aAAA;YAC9CK,IAAAA,EAAM;gBAAEC,QAAAA,EAAU;AAAC,oBAAA;AAAEC,wBAAAA,MAAAA,EAAQC,kBAAQa;AAAO;AAAE;AAAC,aAAA;AAC/CX,YAAAA,kBAAAA,EAAoB,IAAMY,wCAAAA;AAC1BV,YAAAA,mBAAAA,EAAqB,IAAMW,0CAAAA;YAC3BT,aAAAA,EAAeU;AACjB,SAAA;AACA,QAAA;YACExB,IAAAA,EAAM,mBAAA;YACNC,KAAAA,EAAO,oCAAA;YACPC,WAAAA,EACE,+yDAAA;YACFC,SAAAA,EAAW;gBAAEC,MAAAA,EAAQ,QAAA;gBAAUJ,IAAAA,EAAM;AAAO,aAAA;YAC5CK,IAAAA,EAAM;gBAAEC,QAAAA,EAAU;AAAC,oBAAA;AAAEC,wBAAAA,MAAAA,EAAQC,kBAAQa;AAAO;AAAE;AAAC,aAAA;AAC/CX,YAAAA,kBAAAA,EAAoB,IAAMe,uCAAAA;AAC1Bb,YAAAA,mBAAAA,EAAqB,IAAMc,yCAAAA;YAC3BZ,aAAAA,EAAea;AACjB,SAAA;AACA,QAAA;YACE3B,IAAAA,EAAM,qBAAA;YACNC,KAAAA,EAAO,oCAAA;YACPC,WAAAA,EACE,gyEAAA;YACFC,SAAAA,EAAW;gBAAEC,MAAAA,EAAQ,QAAA;gBAAUJ,IAAAA,EAAM;AAAS,aAAA;YAC9CK,IAAAA,EAAM;gBAAEC,QAAAA,EAAU;AAAC,oBAAA;AAAEC,wBAAAA,MAAAA,EAAQC,kBAAQa;AAAO;AAAE;AAAC,aAAA;AAC/CX,YAAAA,kBAAAA,EAAoB,IAAMkB,yCAAAA;AAC1BhB,YAAAA,mBAAAA,EAAqB,IAAMiB,2CAAAA;YAC3Bf,aAAAA,EAAegB;AACjB,SAAA;AACA,QAAA;YACE9B,IAAAA,EAAM,qBAAA;YACNC,KAAAA,EAAO,sBAAA;YACPC,WAAAA,EACE,mRAAA;YACFC,SAAAA,EAAW;gBAAEC,MAAAA,EAAQ,QAAA;gBAAUJ,IAAAA,EAAM;AAAgB,aAAA;;;;YAIrDK,IAAAA,EAAM;gBAAEC,QAAAA,EAAU;AAAC,oBAAA;AAAEC,wBAAAA,MAAAA,EAAQC,kBAAQuB;AAAO;AAAE;AAAC,aAAA;AAC/CrB,YAAAA,kBAAAA,EAAoB,IAAMsB,yCAAAA;AAC1BpB,YAAAA,mBAAAA,EAAqB,IAAMqB,2CAAAA;YAC3BnB,aAAAA,EAAeoB;AACjB,SAAA;AACA,QAAA;YACElC,IAAAA,EAAM,qBAAA;YACNC,KAAAA,EAAO,sBAAA;YACPC,WAAAA,EACE,8QAAA;YACFC,SAAAA,EAAW;gBAAEC,MAAAA,EAAQ,QAAA;gBAAUJ,IAAAA,EAAM;AAAgB,aAAA;YACrDK,IAAAA,EAAM;gBAAEC,QAAAA,EAAU;AAAC,oBAAA;AAAEC,wBAAAA,MAAAA,EAAQC,kBAAQa;AAAO;AAAE;AAAC,aAAA;AAC/CX,YAAAA,kBAAAA,EAAoB,IAAMyB,yCAAAA;AAC1BvB,YAAAA,mBAAAA,EAAqB,IAAMwB,2CAAAA;YAC3BtB,aAAAA,EAAeuB;AACjB,SAAA;AACA,QAAA;YACErC,IAAAA,EAAM,mBAAA;YACNC,KAAAA,EAAO,oBAAA;YACPC,WAAAA,EACE,8VAAA;YACFC,SAAAA,EAAW;gBAAEC,MAAAA,EAAQ,QAAA;gBAAUJ,IAAAA,EAAM;AAAc,aAAA;YACnDK,IAAAA,EAAM;gBAAEC,QAAAA,EAAU;AAAC,oBAAA;AAAEC,wBAAAA,MAAAA,EAAQC,kBAAQa;AAAO;AAAE;AAAC,aAAA;AAC/CX,YAAAA,kBAAAA,EAAoB,IAAM4B,uCAAAA;AAC1B1B,YAAAA,mBAAAA,EAAqB,IAAM2B,yCAAAA;YAC3BzB,aAAAA,EAAe0B;AACjB,SAAA;AACA,QAAA;YACExC,IAAAA,EAAM,qBAAA;YACNC,KAAAA,EAAO,oCAAA;YACPC,WAAAA,EACE,yoCAAA;YACFC,SAAAA,EAAW;gBAAEC,MAAAA,EAAQ,QAAA;gBAAUJ,IAAAA,EAAM;AAAgB,aAAA;YACrDK,IAAAA,EAAM;gBAAEC,QAAAA,EAAU;AAAC,oBAAA;AAAEC,wBAAAA,MAAAA,EAAQC,kBAAQa;AAAO;AAAE;AAAC,aAAA;AAC/CX,YAAAA,kBAAAA,EAAoB,IAAM+B,yCAAAA;AAC1B7B,YAAAA,mBAAAA,EAAqB,IAAM8B,2CAAAA;YAC3B5B,aAAAA,EAAe6B;AACjB;;AAGF;;;AAGC,IACM,MAAMC,sBAAAA,GAAyB,CAAC,EAAEC,MAAM,EAA2B,GAAA;;;;IAIxE,KAAK,MAAMC,QAAQ/C,6BAAAA,EAAAA,CAAiC;QAClD8C,MAAAA,CAAOE,EAAE,EAAEC,GAAAA,EAAKC,YAAAA,CAAaH,IAAAA,CAAAA;AAC/B,IAAA;AACF;;;;;"}
1
+ {"version":3,"file":"register-upload-mcp-tools.js","sources":["../../../server/src/mcp/register-upload-mcp-tools.ts"],"sourcesContent":["import type { Core } from '@strapi/types';\n\nimport { ACTIONS } from '../constants';\nimport { assertAmbientInstance } from './ambient-instance';\nimport type { UploadMcpTool } from './types';\nimport {\n mediaListAssetsInputSchema,\n mediaGetAssetInputSchema,\n mediaListAssetsOutputSchema,\n mediaGetAssetOutputSchema,\n mediaListFoldersOutputSchema,\n mediaUpdateAssetInputSchema,\n mediaUpdateAssetOutputSchema,\n mediaCreateFolderInputSchema,\n mediaCreateFolderOutputSchema,\n mediaRenameFolderInputSchema,\n mediaRenameFolderOutputSchema,\n mediaMoveFolderInputSchema,\n mediaMoveFolderOutputSchema,\n mediaDeleteFolderInputSchema,\n mediaDeleteFolderOutputSchema,\n mediaMoveAssetsInputSchema,\n mediaMoveAssetsOutputSchema,\n mediaDeleteAssetsInputSchema,\n mediaDeleteAssetsOutputSchema,\n} from './schemas';\nimport {\n createMediaListAssetsHandler,\n createMediaGetAssetHandler,\n createMediaListFoldersHandler,\n createMediaUpdateAssetHandler,\n createMediaCreateFolderHandler,\n createMediaRenameFolderHandler,\n createMediaMoveFolderHandler,\n createMediaDeleteFolderHandler,\n createMediaMoveAssetsHandler,\n createMediaDeleteAssetsHandler,\n} from './handlers';\n\n/**\n * The Media Library MCP tools.\n *\n * Folder writes inherit the same `plugin::upload.assets.update` action rather than introducing a\n * folder-specific one, matching what the admin UI enforces today. MCP-specific folder RBAC is\n * out of scope.\n *\n * Renaming and moving are separate tools for both objects — rename/update changes attributes,\n * move changes location — so an agent selects by intent instead of assembling a combined patch.\n *\n * The asset and folder tools stay separate for both move and delete, even though\n * `/actions/bulk-move` accepts both id lists at once and `/actions/bulk-delete` accepts `fileIds`\n * and `folderIds` together. Asset ids and folder ids are indistinguishable integers from separate\n * namespaces, and both `media_list_assets` and `media_list_folders` return a plain `id`, so a\n * combined tool would let an agent pass folder ids where assets were meant with nothing to\n * object. On the delete side that mistake is unrecoverable, and two tools also let each\n * description carry the warning matched to its own blast radius.\n */\nconst UPLOAD_MCP_TOOLS: UploadMcpTool[] = [\n {\n name: 'media_list_assets',\n title: 'Media: list assets',\n description:\n 'List Media Library assets with pagination, folder / mime type / name filters and sorting. Assets are identified by a numeric id — media files are not documents and have no documentId.',\n telemetry: { source: 'upload', name: 'list' },\n auth: { policies: [{ action: ACTIONS.read }] },\n resolveInputSchema: () => mediaListAssetsInputSchema,\n resolveOutputSchema: () => mediaListAssetsOutputSchema,\n createHandler: createMediaListAssetsHandler,\n },\n {\n name: 'media_get_asset',\n title: 'Media: get asset',\n description:\n 'Get a single Media Library asset by its numeric id. Media files are not documents: use the numeric id, not a documentId.',\n telemetry: { source: 'upload', name: 'get' },\n auth: { policies: [{ action: ACTIONS.read }] },\n resolveInputSchema: () => mediaGetAssetInputSchema,\n resolveOutputSchema: () => mediaGetAssetOutputSchema,\n createHandler: createMediaGetAssetHandler,\n },\n {\n name: 'media_list_folders',\n title: 'Media: list folders',\n description:\n 'List the Media Library folder structure as a nested tree. Folders are identified by a numeric id; pass one as `folderId` to media_list_assets to list its contents.',\n telemetry: { source: 'upload', name: 'list_folders' },\n auth: { policies: [{ action: ACTIONS.read }] },\n resolveOutputSchema: () => mediaListFoldersOutputSchema,\n createHandler: createMediaListFoldersHandler,\n },\n {\n name: 'media_update_asset',\n title: 'Media: update asset metadata',\n description:\n \"Update the editable metadata of a Media Library asset, identified by its numeric id. Only name, alternativeText and caption can be written: use media_move_assets to change an asset's folder, and note that url, mime, size and the file contents are owned by the upload provider and cannot be edited over MCP.\",\n telemetry: { source: 'upload', name: 'update' },\n auth: { policies: [{ action: ACTIONS.update }] },\n resolveInputSchema: () => mediaUpdateAssetInputSchema,\n resolveOutputSchema: () => mediaUpdateAssetOutputSchema,\n createHandler: createMediaUpdateAssetHandler,\n },\n {\n name: 'media_move_assets',\n title: 'Media: move assets between folders',\n description:\n \"Move Media Library assets into a different folder, in bulk. Takes `ids` — an array of numeric ASSET ids — and `folder`, the numeric id of the destination; pass `folder: null` to move them to the media library root. Both are required: use an array of one to move a single asset, and say null explicitly for the root.\\n\\nTakes ASSET ids only. Media files are not documents: use numeric ids, not documentIds.\\n\\nNEVER PASS A FOLDER ID. Asset ids and folder ids are separate, independently numbered namespaces, and the SAME NUMBER OFTEN NAMES BOTH an asset and a folder. This tool always reads the number as an ASSET id: hand it a folder id and it will move whichever unrelated asset happens to share that number, reporting that move as a success, while leaving the folder exactly where it was. Nothing in the request can express which one you meant, so the server cannot catch this for you — only an id matching no asset at all is reported as failed. Take ids only from media_list_assets or media_get_asset, never from media_list_folders, and use media_move_folder to move a folder (which carries its whole subtree).\\n\\nMoving changes the folder only. Names, alt text, captions and the assets' public URLs are unaffected, so nothing referencing them breaks — use media_update_asset to edit metadata.\\n\\nPARTIAL SUCCESS IS POSSIBLE: a bad id among good ones does NOT roll the valid moves back. The response always reports `moved` (the assets that were moved) and `failed` (each remaining id with a reason), which together account for every id you passed — so retry only the ids in `failed`, and treat `moved` as done. This holds even when nothing moved at all: `moved` is then empty and every id is in `failed`. The one error that rejects the whole call is a destination folder that does not exist, which is checked before anything is moved.\",\n telemetry: { source: 'upload', name: 'move' },\n auth: { policies: [{ action: ACTIONS.update }] },\n resolveInputSchema: () => mediaMoveAssetsInputSchema,\n resolveOutputSchema: () => mediaMoveAssetsOutputSchema,\n createHandler: createMediaMoveAssetsHandler,\n },\n {\n name: 'media_delete_assets',\n title: 'Media: delete assets (destructive)',\n description:\n 'DESTRUCTIVE AND IRREVERSIBLE. Permanently deletes Media Library assets by numeric id, in bulk — from the database AND from the storage provider, along with every generated thumbnail and size variant. There is no undo, no trash and no recycle bin. The deleted files stop being served immediately, so any live entry, page or export still referencing one will break.\\n\\nWHETHER AN ASSET IS USED IN PUBLISHED CONTENT CANNOT BE CHECKED: Strapi does not expose \"used in\" information over this API, so this tool cannot tell you whether an asset is referenced by any entry, and a successful delete is NOT evidence that nothing was using it. Confirm with the user before deleting.\\n\\nCall it first WITHOUT `dryRun` (or with `dryRun: true`) to preview: nothing is deleted and the response lists exactly which assets WOULD be removed, and how many. Report those to the user, and only then call it again with `dryRun: false` to actually delete.\\n\\nTakes `ids`, an array of numeric ASSET ids — use an array of one to delete a single asset. Media files are not documents: use numeric ids, not documentIds.\\n\\nNEVER PASS A FOLDER ID. Asset ids and folder ids are separate, independently numbered namespaces, and the SAME NUMBER OFTEN NAMES BOTH an asset and a folder. This tool always reads the number as an ASSET id: hand it a folder id and it will silently delete whichever unrelated asset happens to share that number, while leaving the folder untouched. Nothing in the request can express which one you meant, so the server cannot catch this for you — only an id matching no asset at all is reported as failed. Take ids only from media_list_assets or media_get_asset, never from media_list_folders, and use media_delete_folder to delete a folder. If you are not certain an id came from media_list_assets, run the dry run and check the returned name and folder before deleting.\\n\\nPARTIAL SUCCESS IS POSSIBLE: a bad id among good ones does NOT roll the completed deletions back, and those cannot be undone. The response always reports `deleted` (the assets removed, described in full because they can no longer be read back) and `failed` (each remaining id with a reason), which together account for every id you passed — so retry only the ids in `failed`. This holds on the dry run too, which reports the same split before anything is destroyed.',\n telemetry: { source: 'upload', name: 'delete' },\n auth: { policies: [{ action: ACTIONS.update }] },\n resolveInputSchema: () => mediaDeleteAssetsInputSchema,\n resolveOutputSchema: () => mediaDeleteAssetsOutputSchema,\n createHandler: createMediaDeleteAssetsHandler,\n },\n {\n name: 'media_create_folder',\n title: 'Media: create folder',\n description:\n 'Create a Media Library folder, optionally inside an existing one. Folders are identified by a numeric id: pass `parent` to nest the new folder, or omit it to create the folder at the media library root. The name must be unique among its siblings and cannot contain slashes.',\n telemetry: { source: 'upload', name: 'create_folder' },\n // `create`, not `update`, to match `POST /upload/folders` — the admin route for the same\n // operation gates on `assets.create`. The other folder tools use `update` because their\n // admin counterparts (`PUT /folders/:id` and both bulk actions) do.\n auth: { policies: [{ action: ACTIONS.create }] },\n resolveInputSchema: () => mediaCreateFolderInputSchema,\n resolveOutputSchema: () => mediaCreateFolderOutputSchema,\n createHandler: createMediaCreateFolderHandler,\n },\n {\n name: 'media_rename_folder',\n title: 'Media: rename folder',\n description:\n \"Rename a Media Library folder, identified by its numeric id. Changes the folder name only and leaves its location, its contents and their URLs untouched — use media_move_folder to change which folder it sits in. The new name must be unique among the folder's siblings.\",\n telemetry: { source: 'upload', name: 'rename_folder' },\n auth: { policies: [{ action: ACTIONS.update }] },\n resolveInputSchema: () => mediaRenameFolderInputSchema,\n resolveOutputSchema: () => mediaRenameFolderOutputSchema,\n createHandler: createMediaRenameFolderHandler,\n },\n {\n name: 'media_move_folder',\n title: 'Media: move folder',\n description:\n 'Move a Media Library folder into a different parent folder, identified by numeric ids. The folder keeps its name and carries all of its subfolders and files with it; pass `parent: null` to move it to the media library root. A folder cannot be moved into itself or into one of its own descendants. Use media_rename_folder to change the name instead.',\n telemetry: { source: 'upload', name: 'move_folder' },\n auth: { policies: [{ action: ACTIONS.update }] },\n resolveInputSchema: () => mediaMoveFolderInputSchema,\n resolveOutputSchema: () => mediaMoveFolderOutputSchema,\n createHandler: createMediaMoveFolderHandler,\n },\n {\n name: 'media_delete_folder',\n title: 'Media: delete folder (destructive)',\n description:\n 'DESTRUCTIVE AND IRREVERSIBLE. Deletes Media Library folders by numeric id and CASCADES: every subfolder and every file inside them is permanently deleted from the database and from the storage provider. There is no undo, no trash and no recycle bin, and the deleted files stop being served — any live entry or page still referencing one will break.\\n\\nWHETHER THE CONTAINED ASSETS ARE USED IN PUBLISHED CONTENT CANNOT BE CHECKED: Strapi does not expose \"used in\" information over this API, so this tool cannot tell you whether a file is referenced by an entry. Confirm with the user before deleting.\\n\\nCall it first WITHOUT `dryRun` (or with `dryRun: true`) to preview: nothing is deleted and the response reports how many folders and files WOULD be removed. Only after reporting those counts should you call it again with `dryRun: false` to actually delete. Takes FOLDER ids only — asset ids are a separate namespace of integers; use media_delete_assets for individual assets. All or nothing: if ANY id does not resolve to a folder the whole call is rejected and nothing is deleted, so a list mixing folder and asset ids never deletes half of what it names.',\n telemetry: { source: 'upload', name: 'delete_folder' },\n auth: { policies: [{ action: ACTIONS.update }] },\n resolveInputSchema: () => mediaDeleteFolderInputSchema,\n resolveOutputSchema: () => mediaDeleteFolderOutputSchema,\n createHandler: createMediaDeleteFolderHandler,\n },\n];\n\n/**\n * The Media Library MCP tools, every handler factory wrapped in the ambient-instance guard.\n *\n * The guard is applied here rather than left to each factory so it is structural: a tool added\n * to the array above cannot forget it. See `assertAmbientInstance` for what it defends against\n * — the `folder` and `file` services query `global.strapi` regardless of the instance passed to\n * `getService`, so a handler acting on any other instance would read or write the wrong app's\n * media library.\n *\n * Wrapping the factory, not the handler, keeps the failure at handler construction: the MCP\n * registry catches a factory throw, logs it and substitutes a fallback handler, so the invariant\n * reaches the operator's log instead of an agent's tool output.\n */\nexport const buildUploadMcpToolDefinitions = (): UploadMcpTool[] =>\n UPLOAD_MCP_TOOLS.map((tool) => ({\n ...tool,\n createHandler(strapi, context) {\n assertAmbientInstance(strapi);\n\n return tool.createHandler(strapi, context);\n },\n }));\n\n/**\n * Registers the Media Library MCP tools via `strapi.ai.mcp.registerTool()`.\n * Must be called from the plugin register phase, before the MCP HTTP server starts.\n */\nexport const registerUploadMcpTools = ({ strapi }: { strapi: Core.Strapi }): void => {\n // No `isEnabled()` gate: registerTool() only stores the definition, and the MCP server never\n // exposes it when disabled, so registering unconditionally is a no-op there. The\n // definitions are static, so there is no derivation cost worth guarding either.\n for (const tool of buildUploadMcpToolDefinitions()) {\n strapi.ai?.mcp?.registerTool(tool);\n }\n};\n"],"names":["UPLOAD_MCP_TOOLS","name","title","description","telemetry","source","auth","policies","action","ACTIONS","read","resolveInputSchema","mediaListAssetsInputSchema","resolveOutputSchema","mediaListAssetsOutputSchema","createHandler","createMediaListAssetsHandler","mediaGetAssetInputSchema","mediaGetAssetOutputSchema","createMediaGetAssetHandler","mediaListFoldersOutputSchema","createMediaListFoldersHandler","update","mediaUpdateAssetInputSchema","mediaUpdateAssetOutputSchema","createMediaUpdateAssetHandler","mediaMoveAssetsInputSchema","mediaMoveAssetsOutputSchema","createMediaMoveAssetsHandler","mediaDeleteAssetsInputSchema","mediaDeleteAssetsOutputSchema","createMediaDeleteAssetsHandler","create","mediaCreateFolderInputSchema","mediaCreateFolderOutputSchema","createMediaCreateFolderHandler","mediaRenameFolderInputSchema","mediaRenameFolderOutputSchema","createMediaRenameFolderHandler","mediaMoveFolderInputSchema","mediaMoveFolderOutputSchema","createMediaMoveFolderHandler","mediaDeleteFolderInputSchema","mediaDeleteFolderOutputSchema","createMediaDeleteFolderHandler","buildUploadMcpToolDefinitions","map","tool","strapi","context","assertAmbientInstance","registerUploadMcpTools","ai","mcp","registerTool"],"mappings":"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"}