@strapi/upload 5.52.3 → 5.54.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 (220) hide show
  1. package/dist/admin/future/components/Drawer.js +6 -3
  2. package/dist/admin/future/components/Drawer.js.map +1 -1
  3. package/dist/admin/future/components/Drawer.mjs +6 -3
  4. package/dist/admin/future/components/Drawer.mjs.map +1 -1
  5. package/dist/admin/future/components/UploadProgressDialog.js +9 -8
  6. package/dist/admin/future/components/UploadProgressDialog.js.map +1 -1
  7. package/dist/admin/future/components/UploadProgressDialog.mjs +9 -8
  8. package/dist/admin/future/components/UploadProgressDialog.mjs.map +1 -1
  9. package/dist/admin/future/pages/Assets/AssetsPage.js +16 -4
  10. package/dist/admin/future/pages/Assets/AssetsPage.js.map +1 -1
  11. package/dist/admin/future/pages/Assets/AssetsPage.mjs +16 -4
  12. package/dist/admin/future/pages/Assets/AssetsPage.mjs.map +1 -1
  13. package/dist/admin/future/pages/Assets/components/AssetActionsMenu.js +5 -0
  14. package/dist/admin/future/pages/Assets/components/AssetActionsMenu.js.map +1 -1
  15. package/dist/admin/future/pages/Assets/components/AssetActionsMenu.mjs +5 -0
  16. package/dist/admin/future/pages/Assets/components/AssetActionsMenu.mjs.map +1 -1
  17. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetCropEditor.js +19 -4
  18. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetCropEditor.js.map +1 -1
  19. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetCropEditor.mjs +19 -4
  20. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetCropEditor.mjs.map +1 -1
  21. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.js +35 -1
  22. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.js.map +1 -1
  23. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.mjs +35 -1
  24. package/dist/admin/future/pages/Assets/components/AssetDetails/AssetDetailsDrawer.mjs.map +1 -1
  25. package/dist/admin/future/pages/Assets/components/AssetsGrid.js +10 -0
  26. package/dist/admin/future/pages/Assets/components/AssetsGrid.js.map +1 -1
  27. package/dist/admin/future/pages/Assets/components/AssetsGrid.mjs +10 -0
  28. package/dist/admin/future/pages/Assets/components/AssetsGrid.mjs.map +1 -1
  29. package/dist/admin/future/pages/Assets/components/AssetsTable.js +9 -0
  30. package/dist/admin/future/pages/Assets/components/AssetsTable.js.map +1 -1
  31. package/dist/admin/future/pages/Assets/components/AssetsTable.mjs +10 -1
  32. package/dist/admin/future/pages/Assets/components/AssetsTable.mjs.map +1 -1
  33. package/dist/admin/future/pages/Assets/components/BulkActionsBar.js +132 -88
  34. package/dist/admin/future/pages/Assets/components/BulkActionsBar.js.map +1 -1
  35. package/dist/admin/future/pages/Assets/components/BulkActionsBar.mjs +135 -91
  36. package/dist/admin/future/pages/Assets/components/BulkActionsBar.mjs.map +1 -1
  37. package/dist/admin/future/pages/Assets/components/Dnd/AssetsDndProvider.js +7 -0
  38. package/dist/admin/future/pages/Assets/components/Dnd/AssetsDndProvider.js.map +1 -1
  39. package/dist/admin/future/pages/Assets/components/Dnd/AssetsDndProvider.mjs +7 -0
  40. package/dist/admin/future/pages/Assets/components/Dnd/AssetsDndProvider.mjs.map +1 -1
  41. package/dist/admin/future/pages/Assets/components/Dnd/DragOverlayChip.js +4 -1
  42. package/dist/admin/future/pages/Assets/components/Dnd/DragOverlayChip.js.map +1 -1
  43. package/dist/admin/future/pages/Assets/components/Dnd/DragOverlayChip.mjs +4 -1
  44. package/dist/admin/future/pages/Assets/components/Dnd/DragOverlayChip.mjs.map +1 -1
  45. package/dist/admin/future/pages/Assets/components/MainAreaContextMenu.js +181 -0
  46. package/dist/admin/future/pages/Assets/components/MainAreaContextMenu.js.map +1 -0
  47. package/dist/admin/future/pages/Assets/components/MainAreaContextMenu.mjs +179 -0
  48. package/dist/admin/future/pages/Assets/components/MainAreaContextMenu.mjs.map +1 -0
  49. package/dist/admin/future/pages/Assets/constants.js +22 -0
  50. package/dist/admin/future/pages/Assets/constants.js.map +1 -1
  51. package/dist/admin/future/pages/Assets/constants.mjs +19 -1
  52. package/dist/admin/future/pages/Assets/constants.mjs.map +1 -1
  53. package/dist/admin/future/pages/Assets/hooks/useInfiniteAssets.js +65 -10
  54. package/dist/admin/future/pages/Assets/hooks/useInfiniteAssets.js.map +1 -1
  55. package/dist/admin/future/pages/Assets/hooks/useInfiniteAssets.mjs +66 -11
  56. package/dist/admin/future/pages/Assets/hooks/useInfiniteAssets.mjs.map +1 -1
  57. package/dist/admin/future/pages/Assets/hooks/useListScrollRestoration.js +111 -0
  58. package/dist/admin/future/pages/Assets/hooks/useListScrollRestoration.js.map +1 -0
  59. package/dist/admin/future/pages/Assets/hooks/useListScrollRestoration.mjs +109 -0
  60. package/dist/admin/future/pages/Assets/hooks/useListScrollRestoration.mjs.map +1 -0
  61. package/dist/admin/future/services/api.js +17 -0
  62. package/dist/admin/future/services/api.js.map +1 -1
  63. package/dist/admin/future/services/api.mjs +18 -1
  64. package/dist/admin/future/services/api.mjs.map +1 -1
  65. package/dist/admin/future/store/uploadProgress.js +31 -22
  66. package/dist/admin/future/store/uploadProgress.js.map +1 -1
  67. package/dist/admin/future/store/uploadProgress.mjs +31 -22
  68. package/dist/admin/future/store/uploadProgress.mjs.map +1 -1
  69. package/dist/admin/index.js +11 -10
  70. package/dist/admin/index.js.map +1 -1
  71. package/dist/admin/index.mjs +11 -10
  72. package/dist/admin/index.mjs.map +1 -1
  73. package/dist/admin/src/future/components/Drawer.d.ts +10 -0
  74. package/dist/admin/src/future/pages/Assets/components/MainAreaContextMenu.d.ts +28 -0
  75. package/dist/admin/src/future/pages/Assets/constants.d.ts +20 -0
  76. package/dist/admin/src/future/pages/Assets/hooks/useInfiniteAssets.d.ts +4 -0
  77. package/dist/admin/src/future/pages/Assets/hooks/useListScrollRestoration.d.ts +15 -0
  78. package/dist/admin/src/future/store/uploadProgress.d.ts +14 -20
  79. package/dist/admin/translations/en.json.js +1 -3
  80. package/dist/admin/translations/en.json.js.map +1 -1
  81. package/dist/admin/translations/en.json.mjs +1 -3
  82. package/dist/admin/translations/en.json.mjs.map +1 -1
  83. package/dist/server/bootstrap.js +11 -0
  84. package/dist/server/bootstrap.js.map +1 -1
  85. package/dist/server/bootstrap.mjs +11 -0
  86. package/dist/server/bootstrap.mjs.map +1 -1
  87. package/dist/server/controllers/admin-upload.js +31 -1
  88. package/dist/server/controllers/admin-upload.js.map +1 -1
  89. package/dist/server/controllers/admin-upload.mjs +31 -1
  90. package/dist/server/controllers/admin-upload.mjs.map +1 -1
  91. package/dist/server/controllers/utils/find-entity-and-check-permissions.js +15 -4
  92. package/dist/server/controllers/utils/find-entity-and-check-permissions.js.map +1 -1
  93. package/dist/server/controllers/utils/find-entity-and-check-permissions.mjs +15 -4
  94. package/dist/server/controllers/utils/find-entity-and-check-permissions.mjs.map +1 -1
  95. package/dist/server/controllers/utils/folders.js +1 -1
  96. package/dist/server/controllers/utils/folders.js.map +1 -1
  97. package/dist/server/controllers/utils/folders.mjs +1 -1
  98. package/dist/server/controllers/utils/folders.mjs.map +1 -1
  99. package/dist/server/mcp/ambient-instance.js +46 -0
  100. package/dist/server/mcp/ambient-instance.js.map +1 -0
  101. package/dist/server/mcp/ambient-instance.mjs +43 -0
  102. package/dist/server/mcp/ambient-instance.mjs.map +1 -0
  103. package/dist/server/mcp/handlers/constants.js +60 -0
  104. package/dist/server/mcp/handlers/constants.js.map +1 -0
  105. package/dist/server/mcp/handlers/constants.mjs +45 -0
  106. package/dist/server/mcp/handlers/constants.mjs.map +1 -0
  107. package/dist/server/mcp/handlers/folder-handlers.js +308 -0
  108. package/dist/server/mcp/handlers/folder-handlers.js.map +1 -0
  109. package/dist/server/mcp/handlers/folder-handlers.mjs +303 -0
  110. package/dist/server/mcp/handlers/folder-handlers.mjs.map +1 -0
  111. package/dist/server/mcp/handlers/read-handlers.js +134 -0
  112. package/dist/server/mcp/handlers/read-handlers.js.map +1 -0
  113. package/dist/server/mcp/handlers/read-handlers.mjs +130 -0
  114. package/dist/server/mcp/handlers/read-handlers.mjs.map +1 -0
  115. package/dist/server/mcp/handlers/write-handlers.js +315 -0
  116. package/dist/server/mcp/handlers/write-handlers.js.map +1 -0
  117. package/dist/server/mcp/handlers/write-handlers.mjs +311 -0
  118. package/dist/server/mcp/handlers/write-handlers.mjs.map +1 -0
  119. package/dist/server/mcp/permissions.js +36 -0
  120. package/dist/server/mcp/permissions.js.map +1 -0
  121. package/dist/server/mcp/permissions.mjs +33 -0
  122. package/dist/server/mcp/permissions.mjs.map +1 -0
  123. package/dist/server/mcp/register-upload-mcp-tools.js +235 -0
  124. package/dist/server/mcp/register-upload-mcp-tools.js.map +1 -0
  125. package/dist/server/mcp/register-upload-mcp-tools.mjs +232 -0
  126. package/dist/server/mcp/register-upload-mcp-tools.mjs.map +1 -0
  127. package/dist/server/mcp/sanitizers/sanitize-media.js +97 -0
  128. package/dist/server/mcp/sanitizers/sanitize-media.js.map +1 -0
  129. package/dist/server/mcp/sanitizers/sanitize-media.mjs +93 -0
  130. package/dist/server/mcp/sanitizers/sanitize-media.mjs.map +1 -0
  131. package/dist/server/mcp/schemas/input-schemas.js +206 -0
  132. package/dist/server/mcp/schemas/input-schemas.js.map +1 -0
  133. package/dist/server/mcp/schemas/input-schemas.mjs +190 -0
  134. package/dist/server/mcp/schemas/input-schemas.mjs.map +1 -0
  135. package/dist/server/mcp/schemas/output-schemas.js +158 -0
  136. package/dist/server/mcp/schemas/output-schemas.js.map +1 -0
  137. package/dist/server/mcp/schemas/output-schemas.mjs +142 -0
  138. package/dist/server/mcp/schemas/output-schemas.mjs.map +1 -0
  139. package/dist/server/mcp/utils.js +14 -0
  140. package/dist/server/mcp/utils.js.map +1 -0
  141. package/dist/server/mcp/utils.mjs +12 -0
  142. package/dist/server/mcp/utils.mjs.map +1 -0
  143. package/dist/server/media-library-default-notice.js +42 -0
  144. package/dist/server/media-library-default-notice.js.map +1 -0
  145. package/dist/server/media-library-default-notice.mjs +40 -0
  146. package/dist/server/media-library-default-notice.mjs.map +1 -0
  147. package/dist/server/register.js +5 -0
  148. package/dist/server/register.js.map +1 -1
  149. package/dist/server/register.mjs +5 -0
  150. package/dist/server/register.mjs.map +1 -1
  151. package/dist/server/services/folder.js.map +1 -1
  152. package/dist/server/services/folder.mjs.map +1 -1
  153. package/dist/server/services/upload.js +34 -10
  154. package/dist/server/services/upload.js.map +1 -1
  155. package/dist/server/services/upload.mjs +34 -10
  156. package/dist/server/services/upload.mjs.map +1 -1
  157. package/dist/server/src/bootstrap.d.ts.map +1 -1
  158. package/dist/server/src/controllers/admin-upload.d.ts +1 -0
  159. package/dist/server/src/controllers/admin-upload.d.ts.map +1 -1
  160. package/dist/server/src/controllers/utils/find-entity-and-check-permissions.d.ts +14 -1
  161. package/dist/server/src/controllers/utils/find-entity-and-check-permissions.d.ts.map +1 -1
  162. package/dist/server/src/controllers/utils/folders.d.ts +2 -1
  163. package/dist/server/src/controllers/utils/folders.d.ts.map +1 -1
  164. package/dist/server/src/index.d.ts +10 -2
  165. package/dist/server/src/index.d.ts.map +1 -1
  166. package/dist/server/src/mcp/ambient-instance.d.ts +65 -0
  167. package/dist/server/src/mcp/ambient-instance.d.ts.map +1 -0
  168. package/dist/server/src/mcp/handlers/constants.d.ts +48 -0
  169. package/dist/server/src/mcp/handlers/constants.d.ts.map +1 -0
  170. package/dist/server/src/mcp/handlers/folder-handlers.d.ts +49 -0
  171. package/dist/server/src/mcp/handlers/folder-handlers.d.ts.map +1 -0
  172. package/dist/server/src/mcp/handlers/index.d.ts +5 -0
  173. package/dist/server/src/mcp/handlers/index.d.ts.map +1 -0
  174. package/dist/server/src/mcp/handlers/read-handlers.d.ts +35 -0
  175. package/dist/server/src/mcp/handlers/read-handlers.d.ts.map +1 -0
  176. package/dist/server/src/mcp/handlers/write-handlers.d.ts +66 -0
  177. package/dist/server/src/mcp/handlers/write-handlers.d.ts.map +1 -0
  178. package/dist/server/src/mcp/index.d.ts +3 -0
  179. package/dist/server/src/mcp/index.d.ts.map +1 -0
  180. package/dist/server/src/mcp/permissions.d.ts +22 -0
  181. package/dist/server/src/mcp/permissions.d.ts.map +1 -0
  182. package/dist/server/src/mcp/register-upload-mcp-tools.d.ts +29 -0
  183. package/dist/server/src/mcp/register-upload-mcp-tools.d.ts.map +1 -0
  184. package/dist/server/src/mcp/sanitizers/sanitize-media.d.ts +63 -0
  185. package/dist/server/src/mcp/sanitizers/sanitize-media.d.ts.map +1 -0
  186. package/dist/server/src/mcp/schemas/index.d.ts +3 -0
  187. package/dist/server/src/mcp/schemas/index.d.ts.map +1 -0
  188. package/dist/server/src/mcp/schemas/input-schemas.d.ts +148 -0
  189. package/dist/server/src/mcp/schemas/input-schemas.d.ts.map +1 -0
  190. package/dist/server/src/mcp/schemas/output-schemas.d.ts +276 -0
  191. package/dist/server/src/mcp/schemas/output-schemas.d.ts.map +1 -0
  192. package/dist/server/src/mcp/types.d.ts +19 -0
  193. package/dist/server/src/mcp/types.d.ts.map +1 -0
  194. package/dist/server/src/mcp/utils.d.ts +4 -0
  195. package/dist/server/src/mcp/utils.d.ts.map +1 -0
  196. package/dist/server/src/media-library-default-notice.d.ts +19 -0
  197. package/dist/server/src/media-library-default-notice.d.ts.map +1 -0
  198. package/dist/server/src/register.d.ts.map +1 -1
  199. package/dist/server/src/services/folder.d.ts +6 -2
  200. package/dist/server/src/services/folder.d.ts.map +1 -1
  201. package/dist/server/src/services/index.d.ts +10 -2
  202. package/dist/server/src/services/index.d.ts.map +1 -1
  203. package/dist/server/src/services/upload.d.ts +10 -1
  204. package/dist/server/src/services/upload.d.ts.map +1 -1
  205. package/dist/server/src/types.d.ts +2 -2
  206. package/dist/server/src/types.d.ts.map +1 -1
  207. package/dist/server/src/utils/index.d.ts +2 -1
  208. package/dist/server/src/utils/index.d.ts.map +1 -1
  209. package/dist/server/utils/index.js +2 -2
  210. package/dist/server/utils/index.js.map +1 -1
  211. package/dist/server/utils/index.mjs +2 -2
  212. package/dist/server/utils/index.mjs.map +1 -1
  213. package/dist/shared/contracts/files.d.ts +22 -0
  214. package/dist/shared/contracts/files.d.ts.map +1 -1
  215. package/package.json +7 -6
  216. package/dist/admin/future/components/BetaNotice.js +0 -72
  217. package/dist/admin/future/components/BetaNotice.js.map +0 -1
  218. package/dist/admin/future/components/BetaNotice.mjs +0 -70
  219. package/dist/admin/future/components/BetaNotice.mjs.map +0 -1
  220. package/dist/admin/src/future/components/BetaNotice.d.ts +0 -11
@@ -0,0 +1,235 @@
1
+ 'use strict';
2
+
3
+ var constants = require('../constants.js');
4
+ var inputSchemas = require('./schemas/input-schemas.js');
5
+ var outputSchemas = require('./schemas/output-schemas.js');
6
+ var readHandlers = require('./handlers/read-handlers.js');
7
+ var writeHandlers = require('./handlers/write-handlers.js');
8
+ var folderHandlers = require('./handlers/folder-handlers.js');
9
+
10
+ /**
11
+ * The Media Library MCP tools.
12
+ *
13
+ * Folder writes inherit the same `plugin::upload.assets.update` action rather than introducing a
14
+ * folder-specific one, matching what the admin UI enforces today. MCP-specific folder RBAC is
15
+ * out of scope.
16
+ *
17
+ * Renaming and moving are separate tools for both objects — rename/update changes attributes,
18
+ * move changes location — so an agent selects by intent instead of assembling a combined patch.
19
+ *
20
+ * The asset and folder tools stay separate for both move and delete, even though
21
+ * `/actions/bulk-move` accepts both id lists at once and `/actions/bulk-delete` accepts `fileIds`
22
+ * and `folderIds` together. Asset ids and folder ids are indistinguishable integers from separate
23
+ * namespaces, and both `media_list_assets` and `media_list_folders` return a plain `id`, so a
24
+ * combined tool would let an agent pass folder ids where assets were meant with nothing to
25
+ * object. On the delete side that mistake is unrecoverable, and two tools also let each
26
+ * 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
+ ];
221
+ /**
222
+ * Registers the Media Library MCP tools via `strapi.ai.mcp.registerTool()`.
223
+ * Must be called from the plugin register phase, before the MCP HTTP server starts.
224
+ */ const registerUploadMcpTools = ({ strapi })=>{
225
+ // 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
227
+ // definitions are static, so there is no derivation cost worth guarding either.
228
+ for (const tool of buildUploadMcpToolDefinitions()){
229
+ strapi.ai?.mcp?.registerTool(tool);
230
+ }
231
+ };
232
+
233
+ exports.buildUploadMcpToolDefinitions = buildUploadMcpToolDefinitions;
234
+ exports.registerUploadMcpTools = registerUploadMcpTools;
235
+ //# sourceMappingURL=register-upload-mcp-tools.js.map
@@ -0,0 +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":"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"}
@@ -0,0 +1,232 @@
1
+ import { ACTIONS } from '../constants.mjs';
2
+ import { mediaListAssetsInputSchema, mediaGetAssetInputSchema, mediaUpdateAssetInputSchema, mediaMoveAssetsInputSchema, mediaDeleteAssetsInputSchema, mediaCreateFolderInputSchema, mediaRenameFolderInputSchema, mediaMoveFolderInputSchema, mediaDeleteFolderInputSchema } from './schemas/input-schemas.mjs';
3
+ import { mediaListAssetsOutputSchema, mediaGetAssetOutputSchema, mediaListFoldersOutputSchema, mediaUpdateAssetOutputSchema, mediaMoveAssetsOutputSchema, mediaDeleteAssetsOutputSchema, mediaCreateFolderOutputSchema, mediaRenameFolderOutputSchema, mediaMoveFolderOutputSchema, mediaDeleteFolderOutputSchema } from './schemas/output-schemas.mjs';
4
+ import { createMediaListAssetsHandler, createMediaGetAssetHandler, createMediaListFoldersHandler } from './handlers/read-handlers.mjs';
5
+ import { createMediaUpdateAssetHandler, createMediaMoveAssetsHandler, createMediaDeleteAssetsHandler } from './handlers/write-handlers.mjs';
6
+ import { createMediaCreateFolderHandler, createMediaRenameFolderHandler, createMediaMoveFolderHandler, createMediaDeleteFolderHandler } from './handlers/folder-handlers.mjs';
7
+
8
+ /**
9
+ * The Media Library MCP tools.
10
+ *
11
+ * Folder writes inherit the same `plugin::upload.assets.update` action rather than introducing a
12
+ * folder-specific one, matching what the admin UI enforces today. MCP-specific folder RBAC is
13
+ * out of scope.
14
+ *
15
+ * Renaming and moving are separate tools for both objects — rename/update changes attributes,
16
+ * move changes location — so an agent selects by intent instead of assembling a combined patch.
17
+ *
18
+ * The asset and folder tools stay separate for both move and delete, even though
19
+ * `/actions/bulk-move` accepts both id lists at once and `/actions/bulk-delete` accepts `fileIds`
20
+ * and `folderIds` together. Asset ids and folder ids are indistinguishable integers from separate
21
+ * namespaces, and both `media_list_assets` and `media_list_folders` return a plain `id`, so a
22
+ * combined tool would let an agent pass folder ids where assets were meant with nothing to
23
+ * object. On the delete side that mistake is unrecoverable, and two tools also let each
24
+ * description carry the warning matched to its own blast radius.
25
+ */ const buildUploadMcpToolDefinitions = ()=>[
26
+ {
27
+ name: 'media_list_assets',
28
+ title: 'Media: list assets',
29
+ 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.',
30
+ telemetry: {
31
+ source: 'upload',
32
+ name: 'list'
33
+ },
34
+ auth: {
35
+ policies: [
36
+ {
37
+ action: ACTIONS.read
38
+ }
39
+ ]
40
+ },
41
+ resolveInputSchema: ()=>mediaListAssetsInputSchema,
42
+ resolveOutputSchema: ()=>mediaListAssetsOutputSchema,
43
+ createHandler: createMediaListAssetsHandler
44
+ },
45
+ {
46
+ name: 'media_get_asset',
47
+ title: 'Media: get asset',
48
+ description: 'Get a single Media Library asset by its numeric id. Media files are not documents: use the numeric id, not a documentId.',
49
+ telemetry: {
50
+ source: 'upload',
51
+ name: 'get'
52
+ },
53
+ auth: {
54
+ policies: [
55
+ {
56
+ action: ACTIONS.read
57
+ }
58
+ ]
59
+ },
60
+ resolveInputSchema: ()=>mediaGetAssetInputSchema,
61
+ resolveOutputSchema: ()=>mediaGetAssetOutputSchema,
62
+ createHandler: createMediaGetAssetHandler
63
+ },
64
+ {
65
+ name: 'media_list_folders',
66
+ title: 'Media: list folders',
67
+ 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.',
68
+ telemetry: {
69
+ source: 'upload',
70
+ name: 'list_folders'
71
+ },
72
+ auth: {
73
+ policies: [
74
+ {
75
+ action: ACTIONS.read
76
+ }
77
+ ]
78
+ },
79
+ resolveOutputSchema: ()=>mediaListFoldersOutputSchema,
80
+ createHandler: createMediaListFoldersHandler
81
+ },
82
+ {
83
+ name: 'media_update_asset',
84
+ title: 'Media: update asset metadata',
85
+ 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.",
86
+ telemetry: {
87
+ source: 'upload',
88
+ name: 'update'
89
+ },
90
+ auth: {
91
+ policies: [
92
+ {
93
+ action: ACTIONS.update
94
+ }
95
+ ]
96
+ },
97
+ resolveInputSchema: ()=>mediaUpdateAssetInputSchema,
98
+ resolveOutputSchema: ()=>mediaUpdateAssetOutputSchema,
99
+ createHandler: createMediaUpdateAssetHandler
100
+ },
101
+ {
102
+ name: 'media_move_assets',
103
+ title: 'Media: move assets between folders',
104
+ 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.",
105
+ telemetry: {
106
+ source: 'upload',
107
+ name: 'move'
108
+ },
109
+ auth: {
110
+ policies: [
111
+ {
112
+ action: ACTIONS.update
113
+ }
114
+ ]
115
+ },
116
+ resolveInputSchema: ()=>mediaMoveAssetsInputSchema,
117
+ resolveOutputSchema: ()=>mediaMoveAssetsOutputSchema,
118
+ createHandler: createMediaMoveAssetsHandler
119
+ },
120
+ {
121
+ name: 'media_delete_assets',
122
+ title: 'Media: delete assets (destructive)',
123
+ 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.',
124
+ telemetry: {
125
+ source: 'upload',
126
+ name: 'delete'
127
+ },
128
+ auth: {
129
+ policies: [
130
+ {
131
+ action: ACTIONS.update
132
+ }
133
+ ]
134
+ },
135
+ resolveInputSchema: ()=>mediaDeleteAssetsInputSchema,
136
+ resolveOutputSchema: ()=>mediaDeleteAssetsOutputSchema,
137
+ createHandler: createMediaDeleteAssetsHandler
138
+ },
139
+ {
140
+ name: 'media_create_folder',
141
+ title: 'Media: create folder',
142
+ 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.',
143
+ telemetry: {
144
+ source: 'upload',
145
+ name: 'create_folder'
146
+ },
147
+ // `create`, not `update`, to match `POST /upload/folders` — the admin route for the same
148
+ // operation gates on `assets.create`. The other folder tools use `update` because their
149
+ // admin counterparts (`PUT /folders/:id` and both bulk actions) do.
150
+ auth: {
151
+ policies: [
152
+ {
153
+ action: ACTIONS.create
154
+ }
155
+ ]
156
+ },
157
+ resolveInputSchema: ()=>mediaCreateFolderInputSchema,
158
+ resolveOutputSchema: ()=>mediaCreateFolderOutputSchema,
159
+ createHandler: createMediaCreateFolderHandler
160
+ },
161
+ {
162
+ name: 'media_rename_folder',
163
+ title: 'Media: rename folder',
164
+ 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.",
165
+ telemetry: {
166
+ source: 'upload',
167
+ name: 'rename_folder'
168
+ },
169
+ auth: {
170
+ policies: [
171
+ {
172
+ action: ACTIONS.update
173
+ }
174
+ ]
175
+ },
176
+ resolveInputSchema: ()=>mediaRenameFolderInputSchema,
177
+ resolveOutputSchema: ()=>mediaRenameFolderOutputSchema,
178
+ createHandler: createMediaRenameFolderHandler
179
+ },
180
+ {
181
+ name: 'media_move_folder',
182
+ title: 'Media: move folder',
183
+ 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.',
184
+ telemetry: {
185
+ source: 'upload',
186
+ name: 'move_folder'
187
+ },
188
+ auth: {
189
+ policies: [
190
+ {
191
+ action: ACTIONS.update
192
+ }
193
+ ]
194
+ },
195
+ resolveInputSchema: ()=>mediaMoveFolderInputSchema,
196
+ resolveOutputSchema: ()=>mediaMoveFolderOutputSchema,
197
+ createHandler: createMediaMoveFolderHandler
198
+ },
199
+ {
200
+ name: 'media_delete_folder',
201
+ title: 'Media: delete folder (destructive)',
202
+ 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.',
203
+ telemetry: {
204
+ source: 'upload',
205
+ name: 'delete_folder'
206
+ },
207
+ auth: {
208
+ policies: [
209
+ {
210
+ action: ACTIONS.update
211
+ }
212
+ ]
213
+ },
214
+ resolveInputSchema: ()=>mediaDeleteFolderInputSchema,
215
+ resolveOutputSchema: ()=>mediaDeleteFolderOutputSchema,
216
+ createHandler: createMediaDeleteFolderHandler
217
+ }
218
+ ];
219
+ /**
220
+ * Registers the Media Library MCP tools via `strapi.ai.mcp.registerTool()`.
221
+ * Must be called from the plugin register phase, before the MCP HTTP server starts.
222
+ */ const registerUploadMcpTools = ({ strapi })=>{
223
+ // No `isEnabled()` gate: registerTool() only stores the definition, and the MCP server never
224
+ // exposes it when disabled, so registering unconditionally is a no-op there. The three
225
+ // definitions are static, so there is no derivation cost worth guarding either.
226
+ for (const tool of buildUploadMcpToolDefinitions()){
227
+ strapi.ai?.mcp?.registerTool(tool);
228
+ }
229
+ };
230
+
231
+ export { buildUploadMcpToolDefinitions, registerUploadMcpTools };
232
+ //# sourceMappingURL=register-upload-mcp-tools.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register-upload-mcp-tools.mjs","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":"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"}