@cloudinary/asset-management-mcp 0.9.1 → 0.9.3

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 (47) hide show
  1. package/README.md +12 -15
  2. package/bin/mcp-server.js +288 -369
  3. package/bin/mcp-server.js.map +13 -13
  4. package/esm/landing-page.d.ts.map +1 -1
  5. package/esm/landing-page.js +9 -3
  6. package/esm/landing-page.js.map +1 -1
  7. package/esm/lib/config.d.ts +3 -3
  8. package/esm/lib/config.js +3 -3
  9. package/esm/mcp-server/apps/app-shared.d.ts +6 -5
  10. package/esm/mcp-server/apps/app-shared.d.ts.map +1 -1
  11. package/esm/mcp-server/apps/app-shared.js +134 -14
  12. package/esm/mcp-server/apps/app-shared.js.map +1 -1
  13. package/esm/mcp-server/apps/asset-details-app.d.ts.map +1 -1
  14. package/esm/mcp-server/apps/asset-details-app.js +7 -14
  15. package/esm/mcp-server/apps/asset-details-app.js.map +1 -1
  16. package/esm/mcp-server/apps/asset-gallery-app.d.ts.map +1 -1
  17. package/esm/mcp-server/apps/asset-gallery-app.js +99 -306
  18. package/esm/mcp-server/apps/asset-gallery-app.js.map +1 -1
  19. package/esm/mcp-server/apps/asset-upload-app.d.ts.map +1 -1
  20. package/esm/mcp-server/apps/asset-upload-app.js +29 -24
  21. package/esm/mcp-server/apps/asset-upload-app.js.map +1 -1
  22. package/esm/mcp-server/apps/config.d.ts.map +1 -1
  23. package/esm/mcp-server/apps/config.js +1 -2
  24. package/esm/mcp-server/apps/config.js.map +1 -1
  25. package/esm/mcp-server/apps/extensions.d.ts.map +1 -1
  26. package/esm/mcp-server/apps/extensions.js +6 -1
  27. package/esm/mcp-server/apps/extensions.js.map +1 -1
  28. package/esm/mcp-server/cli/serve/impl.js +1 -1
  29. package/esm/mcp-server/cli/serve/impl.js.map +1 -1
  30. package/esm/mcp-server/mcp-server.js +1 -1
  31. package/esm/mcp-server/server.js +1 -1
  32. package/esm/types/bigint.d.ts.map +1 -1
  33. package/esm/types/bigint.js +4 -3
  34. package/esm/types/bigint.js.map +1 -1
  35. package/package.json +1 -1
  36. package/src/landing-page.ts +9 -3
  37. package/src/lib/config.ts +3 -3
  38. package/src/mcp-server/apps/app-shared.ts +135 -14
  39. package/src/mcp-server/apps/asset-details-app.ts +7 -13
  40. package/src/mcp-server/apps/asset-gallery-app.ts +99 -305
  41. package/src/mcp-server/apps/asset-upload-app.ts +29 -23
  42. package/src/mcp-server/apps/config.ts +1 -2
  43. package/src/mcp-server/apps/extensions.ts +6 -1
  44. package/src/mcp-server/cli/serve/impl.ts +1 -1
  45. package/src/mcp-server/mcp-server.ts +1 -1
  46. package/src/mcp-server/server.ts +1 -1
  47. package/src/types/bigint.ts +18 -17
@@ -18,6 +18,7 @@ import { toJSONSchema } from "zod";
18
18
  import {
19
19
  SHARED_CSS_TOKENS,
20
20
  SHARED_CSS_COMPONENTS,
21
+ SHARED_JS_ICONS,
21
22
  SHARED_JS_MCP_CLIENT,
22
23
  SHARED_JS_HELPERS,
23
24
  SHARED_JS_TOOLTIPS,
@@ -61,15 +62,8 @@ const UPLOAD_CSS = /* css */ `
61
62
  .upload-header h1 {
62
63
  font-size: var(--cld-font-sm); font-weight: 600; color: var(--cld-text);
63
64
  }
64
- .upload-header-icon { font-size: 20px; }
65
- .upload-header { position: relative; }
66
- .back-link {
67
- position: absolute; top: -2px; right: 0;
68
- background: none; border: none; cursor: pointer;
69
- color: var(--cld-accent); font-size: var(--cld-font-xs);
70
- padding: 2px 6px; border-radius: 4px;
71
- }
72
- .back-link:hover { text-decoration: underline; background: var(--cld-accent-bg); }
65
+ .upload-header-icon { display: flex; align-items: center; justify-content: center; }
66
+ .upload-header-icon svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
73
67
 
74
68
  .upload-result .detail-section { padding: 14px 16px; }
75
69
  .upload-result .detail-section:first-child { padding-top: 0; }
@@ -508,16 +502,18 @@ function renderPicker() {
508
502
  var h = "";
509
503
 
510
504
  h += '<div class="upload-header">';
505
+ h += '<span class="upload-header-icon icon-accent">' + IC.uploadCloud + '</span>';
506
+ h += "<h1>Upload to Cloudinary</h1>";
507
+ h += '<div id="header-actions" style="display:flex;align-items:center;gap:6px;margin-left:auto">';
511
508
  if (lastResult) {
512
- h += '<button class="back-link" id="back-to-result-btn">\\u2190 Back to Result</button>';
509
+ h += '<button class="icon-btn" id="back-to-result-btn">' + IC.chevronLeft + ' Back</button>';
513
510
  }
514
- h += '<span class="upload-header-icon">\\u2B06\\uFE0F</span>';
515
- h += "<h1>Upload to Cloudinary</h1>";
511
+ h += '</div>';
516
512
  h += "</div>";
517
513
 
518
514
  if (stagedFile) {
519
515
  h += '<div class="upload-staged">';
520
- h += '<div class="upload-staged-icon">\\u{1F4C4}</div>';
516
+ h += '<div class="upload-staged-icon">' + IC.file + '</div>';
521
517
  h += '<div class="upload-staged-info">';
522
518
  h += '<div class="upload-staged-name">' + esc(stagedFile.name) + "</div>";
523
519
  if (stagedFile.size) {
@@ -528,11 +524,11 @@ function renderPicker() {
528
524
  h += '<div class="upload-staged-meta">Remote URL</div>';
529
525
  }
530
526
  h += "</div>";
531
- h += '<button class="upload-staged-clear" id="clear-staged-btn" title="Remove">\\u2715</button>';
527
+ h += '<button class="upload-staged-clear icon-btn icon-only" id="clear-staged-btn" title="Remove">' + IC.x + '</button>';
532
528
  h += "</div>";
533
529
  } else {
534
530
  h += '<div class="upload-zone" id="drop-zone">';
535
- h += '<div class="upload-zone-icon">\\u{1F4C1}</div>';
531
+ h += '<div class="upload-zone-icon">' + IC.folderOpen + '</div>';
536
532
  h += '<div class="upload-zone-text">Drag & drop a file here</div>';
537
533
  h += '<div class="upload-zone-hint">Images, videos, PDFs, and other files up to 60 MB</div>';
538
534
  h += '<button class="upload-zone-btn" id="browse-btn">Browse Files</button>';
@@ -556,6 +552,7 @@ function renderPicker() {
556
552
  }
557
553
 
558
554
  root.innerHTML = h;
555
+ renderThemeToggle();
559
556
 
560
557
  var backBtn = document.getElementById("back-to-result-btn");
561
558
  if (backBtn && lastResult) {
@@ -635,12 +632,13 @@ function renderUploading(name, meta) {
635
632
  var h = "";
636
633
 
637
634
  h += '<div class="upload-header">';
638
- h += '<span class="upload-header-icon">\\u2B06\\uFE0F</span>';
639
- h += "<h1>Uploading\\u2026</h1>";
635
+ h += '<span class="upload-header-icon icon-accent">' + IC.uploadCloud + '</span>';
636
+ h += '<h1>Uploading…</h1>';
637
+ h += '<div id="header-actions" style="display:flex;align-items:center;gap:6px;margin-left:auto"></div>';
640
638
  h += "</div>";
641
639
 
642
640
  h += '<div class="upload-preview">';
643
- h += '<div class="upload-preview-icon">\\u{1F4C4}</div>';
641
+ h += '<div class="upload-preview-icon">' + IC.file + '</div>';
644
642
  h += '<div class="upload-preview-info">';
645
643
  h += '<div class="upload-preview-name">' + esc(name) + "</div>";
646
644
  h += '<div class="upload-preview-meta">' + esc(meta) + "</div>";
@@ -652,6 +650,7 @@ function renderUploading(name, meta) {
652
650
  h += "</div>";
653
651
 
654
652
  root.innerHTML = h;
653
+ renderThemeToggle();
655
654
  animateProgress();
656
655
  }
657
656
 
@@ -705,7 +704,7 @@ function renderUploadError(title, msg) {
705
704
  var header = document.querySelector(".upload-header h1");
706
705
  if (header) header.textContent = title;
707
706
  var icon = document.querySelector(".upload-header-icon");
708
- if (icon) icon.textContent = "\\u26A0\\uFE0F";
707
+ if (icon) { icon.innerHTML = IC.alertTriangle; icon.className = "upload-header-icon icon-warning"; }
709
708
 
710
709
  var safeMsg = esc(msg).replace(/\\n/g, "<br>");
711
710
  var h = '<div class="upload-error-msg">' + safeMsg + "</div>";
@@ -717,14 +716,16 @@ function renderUploadError(title, msg) {
717
716
  var root = document.getElementById("app");
718
717
  var safeMsg = esc(msg).replace(/\\n/g, "<br>");
719
718
  var h = '<div class="upload-header">';
720
- h += '<span class="upload-header-icon">\\u26A0\\uFE0F</span>';
719
+ h += '<span class="upload-header-icon icon-warning">' + IC.alertTriangle + '</span>';
721
720
  h += "<h1>" + esc(title) + "</h1>";
721
+ h += '<div id="header-actions" style="display:flex;align-items:center;gap:6px;margin-left:auto"></div>';
722
722
  h += "</div>";
723
723
  h += '<div class="upload-error-msg">' + safeMsg + "</div>";
724
724
  h += '<div class="upload-another" style="margin-top:14px;text-align:center">';
725
725
  h += '<button class="prompt-btn prompt-btn-primary" id="retry-upload-btn">Try from App</button>';
726
726
  h += "</div>";
727
727
  root.innerHTML = h;
728
+ renderThemeToggle();
728
729
  }
729
730
 
730
731
  var btn = document.getElementById("retry-upload-btn");
@@ -769,8 +770,9 @@ function renderLocalFileNeeded(expectedName, errMsg) {
769
770
  var classified = classifyFileError(errMsg);
770
771
  var root = document.getElementById("app");
771
772
  var h = '<div class="upload-header">';
772
- h += '<span class="upload-header-icon">\\u{1F4C1}</span>';
773
+ h += '<span class="upload-header-icon icon-accent">' + IC.folderOpen + '</span>';
773
774
  h += "<h1>" + esc(classified.title) + "</h1>";
775
+ h += '<div id="header-actions" style="display:flex;align-items:center;gap:6px;margin-left:auto"></div>';
774
776
  h += "</div>";
775
777
  h += '<div class="prompt" style="margin-bottom:16px">';
776
778
  h += '<div class="prompt-desc">The file <strong>' + esc(expectedName)
@@ -785,13 +787,14 @@ function renderLocalFileNeeded(expectedName, errMsg) {
785
787
  }
786
788
  h += "</div>";
787
789
  h += '<div class="upload-zone" id="drop-zone">';
788
- h += '<div class="upload-zone-icon">\\u{1F4C1}</div>';
790
+ h += '<div class="upload-zone-icon">' + IC.folderOpen + '</div>';
789
791
  h += '<div class="upload-zone-text">Drop <strong>' + esc(expectedName) + "</strong> here</div>";
790
792
  h += '<div class="upload-zone-hint">Or click to browse your files</div>';
791
793
  h += '<button class="upload-zone-btn" id="browse-btn">Browse Files</button>';
792
794
  h += '<input type="file" id="file-input" style="display:none">';
793
795
  h += "</div>";
794
796
  root.innerHTML = h;
797
+ renderThemeToggle();
795
798
 
796
799
  function onFileSelected(file) {
797
800
  var reader = new FileReader();
@@ -904,8 +907,9 @@ function renderResult(r) {
904
907
  var h = "";
905
908
 
906
909
  h += '<div class="upload-header">';
907
- h += '<span class="upload-header-icon">' + (isPending ? "\\u23F3" : "\\u2705") + '</span>';
910
+ h += '<span class="upload-header-icon ' + (isPending ? "icon-accent" : "icon-success") + '">' + (isPending ? IC.clock : IC.checkCircle) + '</span>';
908
911
  h += "<h1>" + (isPending ? "Upload Queued" : "Upload Complete") + "</h1>";
912
+ h += '<div id="header-actions" style="display:flex;align-items:center;gap:6px;margin-left:auto"></div>';
909
913
  h += "</div>";
910
914
 
911
915
  h += '<div class="upload-result">';
@@ -966,6 +970,7 @@ function renderResult(r) {
966
970
  h += "</div></div>";
967
971
 
968
972
  root.innerHTML = h;
973
+ renderThemeToggle();
969
974
 
970
975
  root.addEventListener("click", function handler(e) {
971
976
  var el = e.target;
@@ -1102,6 +1107,7 @@ ${UPLOAD_CSS}
1102
1107
  <div id="app"><div class="status">Preparing upload&hellip;</div></div>
1103
1108
 
1104
1109
  <script>
1110
+ ${SHARED_JS_ICONS}
1105
1111
  ${SHARED_JS_MCP_CLIENT}
1106
1112
  ${SHARED_JS_HELPERS}
1107
1113
  ${SHARED_JS_TOOLTIPS}
@@ -12,8 +12,7 @@ export const MCP_APPS: readonly McpApp[] = [
12
12
  "asset-upload",
13
13
  ];
14
14
 
15
- // Flip to [...MCP_APPS] to enable MCP Apps by default.
16
- export const DEFAULT_MCP_APPS: readonly McpApp[] = [];
15
+ export const DEFAULT_MCP_APPS: readonly McpApp[] = [...MCP_APPS];
17
16
 
18
17
  export function parseMcpAppsList(value: string): McpApp[] {
19
18
  const parts = value.split(",").map((s) => s.trim()).filter(Boolean);
@@ -66,7 +66,12 @@ function appResourceContent(uri: URL, html: string) {
66
66
  uri: uri.toString(),
67
67
  mimeType: MCP_APP_MIME_TYPE,
68
68
  text: html,
69
- _meta: { ui: { csp: { resourceDomains: CSP_RESOURCE_DOMAINS } } },
69
+ _meta: {
70
+ ui: {
71
+ csp: { resourceDomains: CSP_RESOURCE_DOMAINS },
72
+ permissions: { clipboardWrite: {} },
73
+ },
74
+ },
70
75
  // deno-lint-ignore no-explicit-any
71
76
  } as any],
72
77
  };
@@ -42,7 +42,7 @@ async function startStreamableHTTP(cliFlags: ServeCommandFlags) {
42
42
  app.use((req, res, next) => {
43
43
  res.header("Access-Control-Allow-Origin", "*");
44
44
  res.header("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
45
- res.header("Access-Control-Allow-Headers", "Content-Type, *");
45
+ res.header("Access-Control-Allow-Headers", "*");
46
46
  if (req.method === "OPTIONS") {
47
47
  res.sendStatus(204);
48
48
  return;
@@ -22,7 +22,7 @@ const routes = buildRouteMap({
22
22
  export const app = buildApplication(routes, {
23
23
  name: "mcp",
24
24
  versionInfo: {
25
- currentVersion: "0.9.1",
25
+ currentVersion: "0.9.3",
26
26
  },
27
27
  });
28
28
 
@@ -60,7 +60,7 @@ export function createMCPServer(deps: {
60
60
  }) {
61
61
  const server = new McpServer({
62
62
  name: "CloudinaryAssetMgmt",
63
- version: "0.9.1",
63
+ version: "0.9.3",
64
64
  });
65
65
 
66
66
  const getClient = deps.getSDK || (() =>
@@ -25,23 +25,24 @@ export function bigint(): z.ZodType<bigint | string> {
25
25
  }
26
26
 
27
27
  export function bigintOptional(): z.ZodType<bigint | string | undefined> {
28
- return z.union([
29
- z.bigint().transform((v) => String(v)),
30
- z.string().transform((v, ctx) => {
31
- try {
32
- return BigInt(v);
33
- } catch {
34
- ctx.addIssue({
35
- code: z.ZodIssueCode.custom,
36
- message: "Invalid bigint value",
37
- });
38
- return z.NEVER;
39
- }
40
- }),
41
- z.number().transform((v) => BigInt(Math.trunc(v))),
42
- z.undefined(),
43
- z.null().transform(() => undefined),
44
- ]);
28
+ return z
29
+ .union([
30
+ z.bigint().transform((v) => String(v)),
31
+ z.string().transform((v, ctx) => {
32
+ try {
33
+ return BigInt(v);
34
+ } catch {
35
+ ctx.addIssue({
36
+ code: z.ZodIssueCode.custom,
37
+ message: "Invalid bigint value",
38
+ });
39
+ return z.NEVER;
40
+ }
41
+ }),
42
+ z.number().transform((v) => BigInt(Math.trunc(v))),
43
+ z.null().transform(() => undefined),
44
+ ])
45
+ .optional();
45
46
  }
46
47
 
47
48
  export function bigintNullable(): z.ZodType<bigint | string | null> {