@collage-dam/mcp-server 0.1.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 (306) hide show
  1. package/.env.example +56 -0
  2. package/CHANGELOG.md +90 -0
  3. package/LICENSE +21 -0
  4. package/README.md +512 -0
  5. package/dist/client.d.ts +497 -0
  6. package/dist/client.d.ts.map +1 -0
  7. package/dist/client.js +1162 -0
  8. package/dist/client.js.map +1 -0
  9. package/dist/conventions/confirmation.d.ts +89 -0
  10. package/dist/conventions/confirmation.d.ts.map +1 -0
  11. package/dist/conventions/confirmation.js +132 -0
  12. package/dist/conventions/confirmation.js.map +1 -0
  13. package/dist/conventions/dry-run/batch-executor.d.ts +36 -0
  14. package/dist/conventions/dry-run/batch-executor.d.ts.map +1 -0
  15. package/dist/conventions/dry-run/batch-executor.js +89 -0
  16. package/dist/conventions/dry-run/batch-executor.js.map +1 -0
  17. package/dist/conventions/dry-run/diff-renderer.d.ts +34 -0
  18. package/dist/conventions/dry-run/diff-renderer.d.ts.map +1 -0
  19. package/dist/conventions/dry-run/diff-renderer.js +158 -0
  20. package/dist/conventions/dry-run/diff-renderer.js.map +1 -0
  21. package/dist/conventions/dry-run/index.d.ts +13 -0
  22. package/dist/conventions/dry-run/index.d.ts.map +1 -0
  23. package/dist/conventions/dry-run/index.js +10 -0
  24. package/dist/conventions/dry-run/index.js.map +1 -0
  25. package/dist/conventions/dry-run/mutating-tool.d.ts +64 -0
  26. package/dist/conventions/dry-run/mutating-tool.d.ts.map +1 -0
  27. package/dist/conventions/dry-run/mutating-tool.js +88 -0
  28. package/dist/conventions/dry-run/mutating-tool.js.map +1 -0
  29. package/dist/conventions/dry-run/summary.d.ts +66 -0
  30. package/dist/conventions/dry-run/summary.d.ts.map +1 -0
  31. package/dist/conventions/dry-run/summary.js +185 -0
  32. package/dist/conventions/dry-run/summary.js.map +1 -0
  33. package/dist/conventions/dry-run/types.d.ts +597 -0
  34. package/dist/conventions/dry-run/types.d.ts.map +1 -0
  35. package/dist/conventions/dry-run/types.js +108 -0
  36. package/dist/conventions/dry-run/types.js.map +1 -0
  37. package/dist/conventions/dry-run/with-dry-run.d.ts +66 -0
  38. package/dist/conventions/dry-run/with-dry-run.d.ts.map +1 -0
  39. package/dist/conventions/dry-run/with-dry-run.js +219 -0
  40. package/dist/conventions/dry-run/with-dry-run.js.map +1 -0
  41. package/dist/conventions/env.d.ts +49 -0
  42. package/dist/conventions/env.d.ts.map +1 -0
  43. package/dist/conventions/env.js +84 -0
  44. package/dist/conventions/env.js.map +1 -0
  45. package/dist/conventions/errors.d.ts +68 -0
  46. package/dist/conventions/errors.d.ts.map +1 -0
  47. package/dist/conventions/errors.js +81 -0
  48. package/dist/conventions/errors.js.map +1 -0
  49. package/dist/conventions/logger.d.ts +28 -0
  50. package/dist/conventions/logger.d.ts.map +1 -0
  51. package/dist/conventions/logger.js +105 -0
  52. package/dist/conventions/logger.js.map +1 -0
  53. package/dist/conventions/pagination.d.ts +37 -0
  54. package/dist/conventions/pagination.d.ts.map +1 -0
  55. package/dist/conventions/pagination.js +53 -0
  56. package/dist/conventions/pagination.js.map +1 -0
  57. package/dist/conventions/rate-limiter.d.ts +54 -0
  58. package/dist/conventions/rate-limiter.d.ts.map +1 -0
  59. package/dist/conventions/rate-limiter.js +143 -0
  60. package/dist/conventions/rate-limiter.js.map +1 -0
  61. package/dist/conventions/response-budget.d.ts +66 -0
  62. package/dist/conventions/response-budget.d.ts.map +1 -0
  63. package/dist/conventions/response-budget.js +89 -0
  64. package/dist/conventions/response-budget.js.map +1 -0
  65. package/dist/conventions/schema-version.d.ts +27 -0
  66. package/dist/conventions/schema-version.d.ts.map +1 -0
  67. package/dist/conventions/schema-version.js +29 -0
  68. package/dist/conventions/schema-version.js.map +1 -0
  69. package/dist/conventions/state-store-redis.d.ts +32 -0
  70. package/dist/conventions/state-store-redis.d.ts.map +1 -0
  71. package/dist/conventions/state-store-redis.js +77 -0
  72. package/dist/conventions/state-store-redis.js.map +1 -0
  73. package/dist/conventions/state-store.d.ts +46 -0
  74. package/dist/conventions/state-store.d.ts.map +1 -0
  75. package/dist/conventions/state-store.js +105 -0
  76. package/dist/conventions/state-store.js.map +1 -0
  77. package/dist/index.d.ts +5 -0
  78. package/dist/index.d.ts.map +1 -0
  79. package/dist/index.js +421 -0
  80. package/dist/index.js.map +1 -0
  81. package/dist/prompts/collection-audit.d.ts +13 -0
  82. package/dist/prompts/collection-audit.d.ts.map +1 -0
  83. package/dist/prompts/collection-audit.js +168 -0
  84. package/dist/prompts/collection-audit.js.map +1 -0
  85. package/dist/prompts/create-distribution.d.ts +15 -0
  86. package/dist/prompts/create-distribution.d.ts.map +1 -0
  87. package/dist/prompts/create-distribution.js +111 -0
  88. package/dist/prompts/create-distribution.js.map +1 -0
  89. package/dist/prompts/helpers.d.ts +20 -0
  90. package/dist/prompts/helpers.d.ts.map +1 -0
  91. package/dist/prompts/helpers.js +53 -0
  92. package/dist/prompts/helpers.js.map +1 -0
  93. package/dist/prompts/library-health-audit.d.ts +13 -0
  94. package/dist/prompts/library-health-audit.d.ts.map +1 -0
  95. package/dist/prompts/library-health-audit.js +131 -0
  96. package/dist/prompts/library-health-audit.js.map +1 -0
  97. package/dist/prompts/usage-insights.d.ts +13 -0
  98. package/dist/prompts/usage-insights.d.ts.map +1 -0
  99. package/dist/prompts/usage-insights.js +98 -0
  100. package/dist/prompts/usage-insights.js.map +1 -0
  101. package/dist/prompts/wrap-prompt-as-tool.d.ts +48 -0
  102. package/dist/prompts/wrap-prompt-as-tool.d.ts.map +1 -0
  103. package/dist/prompts/wrap-prompt-as-tool.js +61 -0
  104. package/dist/prompts/wrap-prompt-as-tool.js.map +1 -0
  105. package/dist/resources/asset-by-id.d.ts +4 -0
  106. package/dist/resources/asset-by-id.d.ts.map +1 -0
  107. package/dist/resources/asset-by-id.js +27 -0
  108. package/dist/resources/asset-by-id.js.map +1 -0
  109. package/dist/resources/collections.d.ts +5 -0
  110. package/dist/resources/collections.d.ts.map +1 -0
  111. package/dist/resources/collections.js +48 -0
  112. package/dist/resources/collections.js.map +1 -0
  113. package/dist/resources/custom-fields.d.ts +4 -0
  114. package/dist/resources/custom-fields.d.ts.map +1 -0
  115. package/dist/resources/custom-fields.js +30 -0
  116. package/dist/resources/custom-fields.js.map +1 -0
  117. package/dist/resources/folders.d.ts +5 -0
  118. package/dist/resources/folders.d.ts.map +1 -0
  119. package/dist/resources/folders.js +73 -0
  120. package/dist/resources/folders.js.map +1 -0
  121. package/dist/resources/helpers.d.ts +17 -0
  122. package/dist/resources/helpers.d.ts.map +1 -0
  123. package/dist/resources/helpers.js +59 -0
  124. package/dist/resources/helpers.js.map +1 -0
  125. package/dist/resources/portals.d.ts +5 -0
  126. package/dist/resources/portals.d.ts.map +1 -0
  127. package/dist/resources/portals.js +81 -0
  128. package/dist/resources/portals.js.map +1 -0
  129. package/dist/resources/recent-and-dashboard.d.ts +5 -0
  130. package/dist/resources/recent-and-dashboard.d.ts.map +1 -0
  131. package/dist/resources/recent-and-dashboard.js +42 -0
  132. package/dist/resources/recent-and-dashboard.js.map +1 -0
  133. package/dist/tools/asset-selection.d.ts +102 -0
  134. package/dist/tools/asset-selection.d.ts.map +1 -0
  135. package/dist/tools/asset-selection.js +133 -0
  136. package/dist/tools/asset-selection.js.map +1 -0
  137. package/dist/tools/audit/audit-folder-structure.d.ts +108 -0
  138. package/dist/tools/audit/audit-folder-structure.d.ts.map +1 -0
  139. package/dist/tools/audit/audit-folder-structure.js +260 -0
  140. package/dist/tools/audit/audit-folder-structure.js.map +1 -0
  141. package/dist/tools/audit/audit-naming-conventions.d.ts +83 -0
  142. package/dist/tools/audit/audit-naming-conventions.d.ts.map +1 -0
  143. package/dist/tools/audit/audit-naming-conventions.js +238 -0
  144. package/dist/tools/audit/audit-naming-conventions.js.map +1 -0
  145. package/dist/tools/audit/audit-tagging-hygiene.d.ts +77 -0
  146. package/dist/tools/audit/audit-tagging-hygiene.d.ts.map +1 -0
  147. package/dist/tools/audit/audit-tagging-hygiene.js +402 -0
  148. package/dist/tools/audit/audit-tagging-hygiene.js.map +1 -0
  149. package/dist/tools/audit/detect-duplicates.d.ts +62 -0
  150. package/dist/tools/audit/detect-duplicates.d.ts.map +1 -0
  151. package/dist/tools/audit/detect-duplicates.js +0 -0
  152. package/dist/tools/audit/detect-duplicates.js.map +1 -0
  153. package/dist/tools/audit/types.d.ts +526 -0
  154. package/dist/tools/audit/types.d.ts.map +1 -0
  155. package/dist/tools/audit/types.js +188 -0
  156. package/dist/tools/audit/types.js.map +1 -0
  157. package/dist/tools/bulk-move-assets.d.ts +78 -0
  158. package/dist/tools/bulk-move-assets.d.ts.map +1 -0
  159. package/dist/tools/bulk-move-assets.js +122 -0
  160. package/dist/tools/bulk-move-assets.js.map +1 -0
  161. package/dist/tools/bulk-normalize-filenames.d.ts +62 -0
  162. package/dist/tools/bulk-normalize-filenames.d.ts.map +1 -0
  163. package/dist/tools/bulk-normalize-filenames.js +237 -0
  164. package/dist/tools/bulk-normalize-filenames.js.map +1 -0
  165. package/dist/tools/bulk-rename-assets.d.ts +79 -0
  166. package/dist/tools/bulk-rename-assets.d.ts.map +1 -0
  167. package/dist/tools/bulk-rename-assets.js +139 -0
  168. package/dist/tools/bulk-rename-assets.js.map +1 -0
  169. package/dist/tools/bulk-tags.d.ts +107 -0
  170. package/dist/tools/bulk-tags.d.ts.map +1 -0
  171. package/dist/tools/bulk-tags.js +220 -0
  172. package/dist/tools/bulk-tags.js.map +1 -0
  173. package/dist/tools/client-adapters.d.ts +76 -0
  174. package/dist/tools/client-adapters.d.ts.map +1 -0
  175. package/dist/tools/client-adapters.js +648 -0
  176. package/dist/tools/client-adapters.js.map +1 -0
  177. package/dist/tools/collection-membership.d.ts +90 -0
  178. package/dist/tools/collection-membership.d.ts.map +1 -0
  179. package/dist/tools/collection-membership.js +195 -0
  180. package/dist/tools/collection-membership.js.map +1 -0
  181. package/dist/tools/create-collection.d.ts +63 -0
  182. package/dist/tools/create-collection.d.ts.map +1 -0
  183. package/dist/tools/create-collection.js +151 -0
  184. package/dist/tools/create-collection.js.map +1 -0
  185. package/dist/tools/create-folder.d.ts +46 -0
  186. package/dist/tools/create-folder.d.ts.map +1 -0
  187. package/dist/tools/create-folder.js +83 -0
  188. package/dist/tools/create-folder.js.map +1 -0
  189. package/dist/tools/create-share-link.d.ts +107 -0
  190. package/dist/tools/create-share-link.d.ts.map +1 -0
  191. package/dist/tools/create-share-link.js +239 -0
  192. package/dist/tools/create-share-link.js.map +1 -0
  193. package/dist/tools/get-asset-details.d.ts +401 -0
  194. package/dist/tools/get-asset-details.d.ts.map +1 -0
  195. package/dist/tools/get-asset-details.js +56 -0
  196. package/dist/tools/get-asset-details.js.map +1 -0
  197. package/dist/tools/get-collection.d.ts +126 -0
  198. package/dist/tools/get-collection.d.ts.map +1 -0
  199. package/dist/tools/get-collection.js +52 -0
  200. package/dist/tools/get-collection.js.map +1 -0
  201. package/dist/tools/get-embed-code.d.ts +195 -0
  202. package/dist/tools/get-embed-code.d.ts.map +1 -0
  203. package/dist/tools/get-embed-code.js +214 -0
  204. package/dist/tools/get-embed-code.js.map +1 -0
  205. package/dist/tools/insights/analyze-share-links.d.ts +159 -0
  206. package/dist/tools/insights/analyze-share-links.d.ts.map +1 -0
  207. package/dist/tools/insights/analyze-share-links.js +314 -0
  208. package/dist/tools/insights/analyze-share-links.js.map +1 -0
  209. package/dist/tools/insights/insight-cache.d.ts +36 -0
  210. package/dist/tools/insights/insight-cache.d.ts.map +1 -0
  211. package/dist/tools/insights/insight-cache.js +98 -0
  212. package/dist/tools/insights/insight-cache.js.map +1 -0
  213. package/dist/tools/insights/report-asset-activation.d.ts +149 -0
  214. package/dist/tools/insights/report-asset-activation.d.ts.map +1 -0
  215. package/dist/tools/insights/report-asset-activation.js +380 -0
  216. package/dist/tools/insights/report-asset-activation.js.map +1 -0
  217. package/dist/tools/insights/report-stale-assets.d.ts +120 -0
  218. package/dist/tools/insights/report-stale-assets.d.ts.map +1 -0
  219. package/dist/tools/insights/report-stale-assets.js +281 -0
  220. package/dist/tools/insights/report-stale-assets.js.map +1 -0
  221. package/dist/tools/insights/report-top-assets.d.ts +139 -0
  222. package/dist/tools/insights/report-top-assets.d.ts.map +1 -0
  223. package/dist/tools/insights/report-top-assets.js +407 -0
  224. package/dist/tools/insights/report-top-assets.js.map +1 -0
  225. package/dist/tools/list-categories.d.ts +127 -0
  226. package/dist/tools/list-categories.d.ts.map +1 -0
  227. package/dist/tools/list-categories.js +68 -0
  228. package/dist/tools/list-categories.js.map +1 -0
  229. package/dist/tools/list-collections.d.ts +127 -0
  230. package/dist/tools/list-collections.d.ts.map +1 -0
  231. package/dist/tools/list-collections.js +53 -0
  232. package/dist/tools/list-collections.js.map +1 -0
  233. package/dist/tools/list-custom-fields.d.ts +125 -0
  234. package/dist/tools/list-custom-fields.d.ts.map +1 -0
  235. package/dist/tools/list-custom-fields.js +51 -0
  236. package/dist/tools/list-custom-fields.js.map +1 -0
  237. package/dist/tools/list-share-links.d.ts +192 -0
  238. package/dist/tools/list-share-links.d.ts.map +1 -0
  239. package/dist/tools/list-share-links.js +92 -0
  240. package/dist/tools/list-share-links.js.map +1 -0
  241. package/dist/tools/list-workspaces.d.ts +88 -0
  242. package/dist/tools/list-workspaces.d.ts.map +1 -0
  243. package/dist/tools/list-workspaces.js +71 -0
  244. package/dist/tools/list-workspaces.js.map +1 -0
  245. package/dist/tools/move-asset.d.ts +48 -0
  246. package/dist/tools/move-asset.d.ts.map +1 -0
  247. package/dist/tools/move-asset.js +85 -0
  248. package/dist/tools/move-asset.js.map +1 -0
  249. package/dist/tools/rename-asset.d.ts +88 -0
  250. package/dist/tools/rename-asset.d.ts.map +1 -0
  251. package/dist/tools/rename-asset.js +100 -0
  252. package/dist/tools/rename-asset.js.map +1 -0
  253. package/dist/tools/rename-folder.d.ts +55 -0
  254. package/dist/tools/rename-folder.d.ts.map +1 -0
  255. package/dist/tools/rename-folder.js +101 -0
  256. package/dist/tools/rename-folder.js.map +1 -0
  257. package/dist/tools/revoke-share-link.d.ts +55 -0
  258. package/dist/tools/revoke-share-link.d.ts.map +1 -0
  259. package/dist/tools/revoke-share-link.js +77 -0
  260. package/dist/tools/revoke-share-link.js.map +1 -0
  261. package/dist/tools/search/facets.d.ts +34 -0
  262. package/dist/tools/search/facets.d.ts.map +1 -0
  263. package/dist/tools/search/facets.js +147 -0
  264. package/dist/tools/search/facets.js.map +1 -0
  265. package/dist/tools/search/filter-builder.d.ts +33 -0
  266. package/dist/tools/search/filter-builder.d.ts.map +1 -0
  267. package/dist/tools/search/filter-builder.js +111 -0
  268. package/dist/tools/search/filter-builder.js.map +1 -0
  269. package/dist/tools/search/search-assets.d.ts +41 -0
  270. package/dist/tools/search/search-assets.d.ts.map +1 -0
  271. package/dist/tools/search/search-assets.js +162 -0
  272. package/dist/tools/search/search-assets.js.map +1 -0
  273. package/dist/tools/search/search-collections.d.ts +35 -0
  274. package/dist/tools/search/search-collections.d.ts.map +1 -0
  275. package/dist/tools/search/search-collections.js +103 -0
  276. package/dist/tools/search/search-collections.js.map +1 -0
  277. package/dist/tools/search/types.d.ts +1047 -0
  278. package/dist/tools/search/types.d.ts.map +1 -0
  279. package/dist/tools/search/types.js +216 -0
  280. package/dist/tools/search/types.js.map +1 -0
  281. package/dist/tools/update-asset-metadata.d.ts +78 -0
  282. package/dist/tools/update-asset-metadata.d.ts.map +1 -0
  283. package/dist/tools/update-asset-metadata.js +203 -0
  284. package/dist/tools/update-asset-metadata.js.map +1 -0
  285. package/dist/tools/update-collection.d.ts +69 -0
  286. package/dist/tools/update-collection.d.ts.map +1 -0
  287. package/dist/tools/update-collection.js +142 -0
  288. package/dist/tools/update-collection.js.map +1 -0
  289. package/dist/tools/view-category-contents.d.ts +231 -0
  290. package/dist/tools/view-category-contents.d.ts.map +1 -0
  291. package/dist/tools/view-category-contents.js +97 -0
  292. package/dist/tools/view-category-contents.js.map +1 -0
  293. package/dist/types.d.ts +1326 -0
  294. package/dist/types.d.ts.map +1 -0
  295. package/dist/types.js +288 -0
  296. package/dist/types.js.map +1 -0
  297. package/dist/typesense.d.ts +84 -0
  298. package/dist/typesense.d.ts.map +1 -0
  299. package/dist/typesense.js +243 -0
  300. package/dist/typesense.js.map +1 -0
  301. package/docs/api-field-verification.md +244 -0
  302. package/docs/deployment-runbook.md +446 -0
  303. package/docs/security-review.md +195 -0
  304. package/docs/typesense-filter-schema.md +262 -0
  305. package/docs/verified-endpoints.md +38 -0
  306. package/package.json +72 -0
@@ -0,0 +1,262 @@
1
+ # Typesense Filter Schema (reverse-engineered)
2
+
3
+ This document captures the filter, query, sort, and result shapes that
4
+ Collage's Admin-Frontend issues against its Typesense Cloud cluster. The
5
+ MCP `search_assets` and `search_collections` tools mirror this contract
6
+ verbatim. **There is no upstream documentation** — every clause below
7
+ was reverse-engineered from live frontend code. As field names or
8
+ operators drift, the contract test harness in `tests/contract/` is the
9
+ tripwire.
10
+
11
+ Source files cited inline use repo-relative paths against the cloned
12
+ Admin-Frontend tree at `/Users/justin/Sites/southleft/collage/Admin-Frontend/`.
13
+
14
+ ## Collections
15
+
16
+ Three Typesense collections are searchable:
17
+
18
+ | Collection | Domain |
19
+ | ----------------------------- | ------------------------------- |
20
+ | `digital_assets` | Asset rows (file metadata) |
21
+ | `dam_collections` | Curated asset collections |
22
+ | `digital_assets_categories` | Folders (the category tree) |
23
+
24
+ Reference: `Admin-Frontend/mixins/search-common-functions.js:355-395`.
25
+
26
+ ## Workspace scoping (mandatory)
27
+
28
+ Every query is rewritten upstream to append the workspace clause:
29
+
30
+ ```
31
+ filter = filter.length
32
+ ? `${filter} && workspace_id: ${workspace_unique_id}`
33
+ : `workspace_id: ${workspace_unique_id}`
34
+ ```
35
+
36
+ Source: `Admin-Frontend/api/typesense.js:212-215` (also lines 420-422
37
+ on the `search-ids` route). On the MCP side this is enforced at the
38
+ `searchWorkspaceScoped` wrapper in `src/typesense.ts` — tool authors
39
+ cannot omit it by construction.
40
+
41
+ ## Common search params
42
+
43
+ From `Admin-Frontend/api/typesense.js:252-269`:
44
+
45
+ ```js
46
+ {
47
+ q: adjustedQuery, // q.toLowerCase() unless '*'
48
+ filter_by: filter,
49
+ sort_by: collectionSortBy,
50
+ infix: 'always', // substring matching enabled
51
+ prefix: true,
52
+ num_typos: 2,
53
+ typo_tokens_threshold: 1,
54
+ // optional: include_fields, group_by, group_limit, ...
55
+ }
56
+ ```
57
+
58
+ `commonSearchParams.query_by` defaults to `'search_name'` on the
59
+ results page (`pages/_workspace_id/dam/search.vue:1418`) and the
60
+ search bar (`components/dam/SearchBarTypeSense.vue:898`). The MCP
61
+ contract widens this to `display_file_name,search_name,description,tags,custom_fields`
62
+ to match the spec's stated query target set.
63
+
64
+ ## Sort schema
65
+
66
+ `sort_by` is a comma-separated list of `field:direction` pairs, where
67
+ direction is `asc` or `desc`. Validation regex (server-side):
68
+
69
+ ```
70
+ /^[a-zA-Z0-9_]+:(asc|desc)$/
71
+ ```
72
+
73
+ Source: `Admin-Frontend/api/typesense.js:160-189`.
74
+
75
+ Default sort:
76
+
77
+ ```
78
+ _text_match:desc,modified_at:desc
79
+ ```
80
+
81
+ Source: `pages/_workspace_id/dam/search.vue:1442` and
82
+ `components/dam/SearchBarTypeSense.vue:902`.
83
+
84
+ `sort_by` may also be a per-collection object — keys are collection
85
+ names, values are sort strings. For `dam_collections` and
86
+ `digital_assets_categories`, the upstream remaps `display_file_name:`
87
+ to `collection_name:` / `folder_name:` and falls back to
88
+ `modified_at:` when sorting by `file_size:` or `file_type:` (which
89
+ those collections lack). See `api/typesense.js:223-249`.
90
+
91
+ ## Filter clauses (`filter_by` syntax)
92
+
93
+ All filter clauses are joined with ` && ` (Typesense AND). Each
94
+ clause is wrapped in parentheses by the frontend builders — they
95
+ nest naturally because parens are part of the frontend's clause
96
+ emission, not a wrapper added later. The server-side `/search`
97
+ endpoint strips a *single* outer pair of balanced parens
98
+ (`api/typesense.js:194-212`) before appending the workspace clause.
99
+
100
+ ### 1. Tag filter
101
+
102
+ Source: `mixins/search-common-functions.js:194-224`.
103
+
104
+ | Operator | Generated clause |
105
+ | --------------- | ------------------------------------------------------------------ |
106
+ | include-all-of | `tags:[\tag1\] && tags:[\tag2\]` (per-tag clauses joined by `&&`) |
107
+ | include-any-of | `tags:[\tag1\] \|\| tags:[\tag2\]` (joined by `\|\|`) |
108
+ | exclude-all-of | `tags:!=[name1] && tags:!=[name2]` |
109
+ | exclude-any-of | `tags:!=[name1] \|\| tags:!=[name2]` |
110
+ | contains | `tags:*<substring>*` |
111
+
112
+ The MCP contract exposes a simplified `tags: string[]` filter that
113
+ emits the `include-any-of` shape (`tags:=[name1, name2]` per
114
+ spec.md §Filter schema). Advanced operator selection is deferred to
115
+ Phase 2.
116
+
117
+ ### 2. File-type filter
118
+
119
+ Source: `mixins/search-common-functions.js:225-239`.
120
+
121
+ | Operator | Clause |
122
+ | -------- | ------------------------------------------------------- |
123
+ | is | `file_type:=image \|\| file_type:=video` (OR-joined) |
124
+ | is not | `file_type:!=image && file_type:!=video` (AND-joined) |
125
+
126
+ MCP contract: `file_type: string[]` → `file_type:=[image,video]`
127
+ (Typesense array shorthand for OR-joined `:=`).
128
+
129
+ ### 3. Visibility / permission filter
130
+
131
+ Source: `mixins/search-common-functions.js:85-89`.
132
+
133
+ ```js
134
+ return ` (visibility${isCondition === isPublic ? ':=' : ':!='}0) `
135
+ ```
136
+
137
+ Visibility is **numeric**: `0` = public, `1` = private. Per spec
138
+ §Filter schema this was confirmed against Phase 2.5 testing.
139
+
140
+ MCP contract: `visibility: 'public' | 'private' | number` →
141
+ `visibility:=0` / `visibility:=1`.
142
+
143
+ ### 4. Date-range filters
144
+
145
+ Source: `mixins/search-common-functions.js:148-193`. All upstream
146
+ date filtering is **unix-second** based.
147
+
148
+ | Field key in request | Typesense field |
149
+ | ------------------------ | --------------- |
150
+ | `date-added` | `created_at` |
151
+ | `last-modified-date` | `modified_at` |
152
+
153
+ Operators emitted:
154
+
155
+ - `after` → `created_at:>=<unix>`
156
+ - `before` → `created_at:<=<unix>`
157
+ - `between` (custom range) →
158
+ `created_at:>=<startUnix> && created_at:<=<endUnix>`
159
+
160
+ Pre-canned slugs: `30-mins-ago`, `1-day-ago`, `3-days-ago`,
161
+ `1-week-ago`, `1-month-ago`, `custom`.
162
+
163
+ MCP contract: `created_after`, `created_before`, `modified_after`,
164
+ `modified_before` — each accepts unix-seconds (number) or ISO-8601
165
+ string (coerced to unix).
166
+
167
+ ### 5. Collection-scoped filter (`collage` in frontend)
168
+
169
+ Source: `mixins/search-common-functions.js:240-249`.
170
+
171
+ ```
172
+ collection_ids:=[<slug>] && is_collection:=1
173
+ ```
174
+
175
+ Multiple collections are joined by `||` (is) or `&&` (is-not). Note
176
+ the `is_collection:=1` companion clause — the upstream filters the
177
+ `digital_assets` index for rows that *are* collection-bearing.
178
+
179
+ MCP contract: `collection_ids: (string|number)[]` →
180
+ `collection_ids:=[id1,id2]` (single clause; the `is_collection:=1`
181
+ side-clause is omitted in the MCP surface — we surface raw
182
+ membership).
183
+
184
+ ### 6. Category / folder-scoped filter
185
+
186
+ Source: `pages/_workspace_id/dam/folders/_id/index.vue:2920`:
187
+
188
+ ```js
189
+ const folderFilter = `category_id:=[${folderId}]`
190
+ ```
191
+
192
+ MCP contract: `category_id: string|number` → `category_id:=<id>`.
193
+
194
+ ### 7. Uploaded-by filter
195
+
196
+ Source: `mixins/search-common-functions.js:318-353`. Emits
197
+ `created_by_id:=<id>` (or `:!=`) per user, joined by `||` for "is"
198
+ and `&&` for "is not", with optional `is_external_upload:=true|false`
199
+ companion clause.
200
+
201
+ Out of scope for the MCP `search_assets` v1 surface — covered by the
202
+ audit/distribution tooling in Phase 2.
203
+
204
+ ### 8. Custom-field filter
205
+
206
+ Source: `mixins/search-common-functions.js:255-316`. Emits literal
207
+ clauses like `` custom_fields:=`<field_label>:<value>` `` (note the
208
+ backticks — they are part of the Typesense filter syntax). The MCP
209
+ exposes raw passthrough for now (`custom_fields: string[]`),
210
+ defer-validating the inner shape to the consumer.
211
+
212
+ ## Indexed fields (per `digital_assets`)
213
+
214
+ From spec.md §Indexed fields and live frontend usage:
215
+
216
+ ```
217
+ id, workspace_id, instances_id, display_file_name, search_name,
218
+ description, file_type, type, thumbnail_file, compress_file,
219
+ video_preview, display_file, file_size, height, width,
220
+ orientation, is_external_upload, visibility, category_id,
221
+ is_collection, collection_ids, created_by, created_by_id,
222
+ created_at, modified_at, tags, custom_fields, breadcrumb
223
+ ```
224
+
225
+ ## Surprises worth surfacing
226
+
227
+ 1. **`workspace_id` matched against `workspace_unique_id`, not the
228
+ workspace database id.** The frontend resolves
229
+ `workspace_unique_id` via the `/user` endpoint
230
+ (`api/typesense.js:122-132`). For the MCP we treat
231
+ `COLLAGE_WORKSPACE_ID` env as the raw id used in the filter —
232
+ if it turns out Collage's Typesense indexes `workspace_unique_id`
233
+ rather than the workspace db id, we will need to plumb a
234
+ one-time resolution at startup. T1 (Tarang) is the trigger to
235
+ confirm this.
236
+
237
+ 2. **`tags:[\tag\]`** uses an *escaped backslash* before the bracket
238
+ when matching exact tag names. Frontend sources show `\\\\` in
239
+ template-literal form which renders to a single backslash in the
240
+ emitted filter. The MCP avoids this escape entirely by using the
241
+ array form `tags:=[name1,name2]` which Typesense interprets
242
+ identically for the include-any-of shape used in the contract.
243
+
244
+ 3. **Visibility is numeric** (not the string `"public"`/`"private"`).
245
+ Frontend treats `0` = public, `1` = private. Documented in
246
+ spec.md but worth the second mention because it is easy to get
247
+ wrong.
248
+
249
+ 4. **`infix: 'always'`** is enabled by default at the upstream
250
+ middleware. This means a query for "cal" matches "calvin",
251
+ "local", and "optical". Spec callers should set
252
+ `infix: 'off'` if they want strict prefix matching.
253
+
254
+ 5. **The frontend sometimes blanks the filter for non-asset
255
+ collections.** When `tags`, `file-type`, `collage`, or
256
+ `uploaded-by` filters are present, the frontend skips the
257
+ `dam_collections` and `digital_assets_categories` searches
258
+ (`mixins/search-common-functions.js:131-141, 396-413`). The
259
+ MCP `search_collections` tool deliberately does NOT carry that
260
+ short-circuit — collection search runs independently of asset
261
+ filters. If a downstream caller needs the frontend's exact
262
+ behaviour, they compose the two tool calls themselves.
@@ -0,0 +1,38 @@
1
+ # Verified Collage API endpoints (historical)
2
+
3
+ > **Superseded 2026-05-04.** This file is the original Phase-2.5 stub
4
+ > that captured the first 5 endpoints we verified against BREZ. It has
5
+ > been superseded by [`api-field-verification.md`](./api-field-verification.md),
6
+ > which now covers ~22 endpoints across asset, tag, folder, collection,
7
+ > share-link, embed, and search surfaces with full Admin-Frontend
8
+ > citations and per-endpoint contract-test references.
9
+ >
10
+ > Kept for git history continuity. Don't update — extend
11
+ > `api-field-verification.md` instead.
12
+
13
+ ---
14
+
15
+ ## Original Phase-1 surface (kept for reference)
16
+
17
+ The endpoints below were the first 5 verified against a live workspace
18
+ (BREZ, `workspace_id=1927483178`). All have since been re-verified by
19
+ contract tests in `tests/contract/`:
20
+
21
+ 1. `check-workspace-access` — auth + scoping smoke. Verified by
22
+ `check-workspace-access.contract.test.ts`.
23
+ 2. `digital-assets/category/all-category-list` — folder roots.
24
+ Originally 402-blocked; resolved 2026-05-01 (missing `workspace_id`
25
+ query param). Verified by `list-categories.contract.test.ts`. Now
26
+ walked recursively via `listAllCategoriesRecursive()` to recover
27
+ the full tree (the upstream returns roots only by design).
28
+ 3. `digital-assets/collection/get-all` — collections list. Verified
29
+ by `list-collections.contract.test.ts`.
30
+ 4. `digital-assets/embed-code-list` — embed-code paginator. Verified
31
+ by `list-embed-codes.contract.test.ts`.
32
+ 5. `digital-assets/view-detail` — single-asset full metadata. Body
33
+ param is `digital_assets_id` (NOT `asset_id`). Verified by
34
+ `get-asset-details.contract.test.ts`.
35
+
36
+ For the full current state of every endpoint the MCP server uses —
37
+ including share-link, write-side, and search-proxy endpoints — see
38
+ [`api-field-verification.md`](./api-field-verification.md).
package/package.json ADDED
@@ -0,0 +1,72 @@
1
+ {
2
+ "name": "@collage-dam/mcp-server",
3
+ "version": "0.1.0",
4
+ "description": "Model Context Protocol (MCP) server for the Collage Digital Asset Management platform. Exposes Collage workspaces — assets, folders, collections, share links, audit prompts — to AI clients (Claude Desktop, Cursor, ChatGPT) through a typed tool surface.",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "bin": {
9
+ "collage-mcp": "dist/index.js"
10
+ },
11
+ "files": [
12
+ "dist",
13
+ "README.md",
14
+ "CHANGELOG.md",
15
+ "LICENSE",
16
+ ".env.example",
17
+ "docs"
18
+ ],
19
+ "scripts": {
20
+ "build": "tsc",
21
+ "postbuild": "chmod +x dist/index.js",
22
+ "dev": "tsx watch src/index.ts",
23
+ "start": "node dist/index.js",
24
+ "test": "vitest run --exclude 'tests/contract/**' --exclude 'tests/integration/**'",
25
+ "test:watch": "vitest",
26
+ "test:integration": "INTEGRATION=1 vitest run tests/contract tests/integration",
27
+ "smoke": "tsx scripts/smoke-stdio.ts",
28
+ "prompt": "tsx scripts/dump-prompt.ts",
29
+ "lint": "tsc --noEmit",
30
+ "prepublishOnly": "npm run lint && npm test && npm run build"
31
+ },
32
+ "keywords": [
33
+ "mcp",
34
+ "model-context-protocol",
35
+ "collage",
36
+ "dam",
37
+ "digital-asset-management",
38
+ "claude",
39
+ "ai-tools"
40
+ ],
41
+ "author": "Southleft <hello@southleft.com>",
42
+ "license": "MIT",
43
+ "homepage": "https://github.com/southleft/collage-mcp#readme",
44
+ "repository": {
45
+ "type": "git",
46
+ "url": "git+https://github.com/southleft/collage-mcp.git"
47
+ },
48
+ "bugs": {
49
+ "url": "https://github.com/southleft/collage-mcp/issues"
50
+ },
51
+ "engines": {
52
+ "node": ">=20"
53
+ },
54
+ "publishConfig": {
55
+ "access": "public",
56
+ "registry": "https://registry.npmjs.org/"
57
+ },
58
+ "dependencies": {
59
+ "@modelcontextprotocol/sdk": "1.12.1",
60
+ "ioredis": "^5.10.1",
61
+ "pino": "^9.6.0",
62
+ "ulid": "^2.3.0",
63
+ "zod": "^3.24.0"
64
+ },
65
+ "devDependencies": {
66
+ "@types/ioredis": "^4.28.10",
67
+ "@types/node": "^22.0.0",
68
+ "tsx": "^4.19.0",
69
+ "typescript": "^5.7.0",
70
+ "vitest": "^3.1.0"
71
+ }
72
+ }