@kolbo/mcp 1.79.3 → 1.79.4

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kolbo/mcp",
3
- "version": "1.79.3",
3
+ "version": "1.79.4",
4
4
  "description": "Kolbo AI MCP Server - Generate images, videos, music, speech, and sound effects from Claude Code",
5
5
  "main": "src/index.js",
6
6
  "bin": {
package/src/cdn.js ADDED
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Rewrite Kolbo Spaces origin URLs to the custom-domain CDN.
3
+ *
4
+ * Origin (`*.digitaloceanspaces.com`) is uncached and makes every MCP image
5
+ * / video / Visual DNA sheet crawl. Custom hosts:
6
+ * production → media.kolbo.ai
7
+ * development → media-dev.kolbo.ai
8
+ * staging → media-staging.kolbo.ai
9
+ * sapir → media-sapir.kolbo.ai
10
+ */
11
+
12
+ const HOST_MAP = [
13
+ ['kolboai-production.ams3.cdn.digitaloceanspaces.com', 'media.kolbo.ai'],
14
+ ['kolboai-production.ams3.digitaloceanspaces.com', 'media.kolbo.ai'],
15
+ ['kolboai-development.ams3.cdn.digitaloceanspaces.com', 'media-dev.kolbo.ai'],
16
+ ['kolboai-development.ams3.digitaloceanspaces.com', 'media-dev.kolbo.ai'],
17
+ ['kolboai-staging.ams3.cdn.digitaloceanspaces.com', 'media-staging.kolbo.ai'],
18
+ ['kolboai-staging.ams3.digitaloceanspaces.com', 'media-staging.kolbo.ai'],
19
+ ['kolboai-sapir.ams3.cdn.digitaloceanspaces.com', 'media-sapir.kolbo.ai'],
20
+ ['kolboai-sapir.ams3.digitaloceanspaces.com', 'media-sapir.kolbo.ai'],
21
+ ];
22
+
23
+ const URL_IN_TEXT = /https?:\/\/[^\s"'<>\\]+/gi;
24
+ const SKIP_KEYS = /^(upload_url|uploadUrl|signed_url|signedUrl|presigned_url|presignedUrl|put_url|putUrl)$/;
25
+
26
+ function rewriteUrl(url) {
27
+ if (!url || typeof url !== 'string') return url;
28
+ if (/[?&](X-Amz-Algorithm|AWSAccessKeyId|Signature=)/i.test(url)) return url;
29
+ let out = url;
30
+ for (const [from, to] of HOST_MAP) {
31
+ if (out.includes(from)) out = out.split(from).join(to);
32
+ }
33
+ return out;
34
+ }
35
+
36
+ function rewriteTree(value, seen) {
37
+ const visited = seen || new WeakSet();
38
+ if (typeof value === 'string') {
39
+ if (!value.includes('digitaloceanspaces.com')) return value;
40
+ if (/^https?:\/\//i.test(value) && !/\s/.test(value)) return rewriteUrl(value);
41
+ return value.replace(URL_IN_TEXT, rewriteUrl);
42
+ }
43
+ if (!value || typeof value !== 'object') return value;
44
+ if (visited.has(value)) return value;
45
+ visited.add(value);
46
+ if (Array.isArray(value)) return value.map((item) => rewriteTree(item, visited));
47
+ const out = {};
48
+ for (const [key, item] of Object.entries(value)) {
49
+ out[key] = SKIP_KEYS.test(key) ? item : rewriteTree(item, visited);
50
+ }
51
+ return out;
52
+ }
53
+
54
+ module.exports = { rewriteUrl, rewriteTree, HOST_MAP };
package/src/client.js CHANGED
@@ -2,6 +2,7 @@ const fs = require('fs');
2
2
  const path = require('path');
3
3
  const os = require('os');
4
4
  const progress = require('./progress');
5
+ const { rewriteTree } = require('./cdn');
5
6
 
6
7
  /**
7
8
  * Kolbo API HTTP client wrapper
@@ -402,7 +403,7 @@ class KolboClient {
402
403
  progress.trackGeneration(generationId, () => this._cancelAfterCallerAbort(generationId));
403
404
  }
404
405
  }
405
- return data;
406
+ return rewriteTree(data);
406
407
  }
407
408
 
408
409
  async _cancelAfterCallerAbort(generationId) {
@@ -543,7 +544,7 @@ class KolboClient {
543
544
  await progress.generation(generationId);
544
545
  progress.trackGeneration(generationId, () => this._cancelAfterCallerAbort(generationId));
545
546
  }
546
- return data;
547
+ return rewriteTree(data);
547
548
  }
548
549
  }
549
550
 
@@ -135,7 +135,7 @@ function registerVisualDnaTools(server, client, options = {}) {
135
135
  // such a DNA brings its own voice as reference audio on models with audio slots. Without
136
136
  // it the model has to fetch each DNA in full just to find out.
137
137
  const text = compactList(dnas, {
138
- fields: ['id', 'name', 'type', 'folder_id', 'tags', 'thumbnail', 'has_voice_reference'],
138
+ fields: ['id', 'name', 'type', 'dna_type', 'folder_id', 'tags', 'thumbnail', 'description', 'sheet_url', 'has_voice_reference'],
139
139
  cap: 60,
140
140
  total,
141
141
  note: 'Narrow with `search`, `tags`, or `collection`, or pass `page`/`limit` for the rest; get_visual_dna returns one in full.',