@kolbo/mcp 1.26.0 → 1.28.1
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/README.md +10 -0
- package/package.json +1 -1
- package/src/index.js +2 -0
- package/src/tools/stock_library.js +143 -0
package/README.md
CHANGED
|
@@ -201,6 +201,16 @@ Every generation tool also accepts an optional `project_id` arg that routes the
|
|
|
201
201
|
| `get_music_track_related` | Get stems + alternate versions of a track. |
|
|
202
202
|
| `get_music_track_lyrics` | Get lyrics text, theme, and explicit flag for a track. |
|
|
203
203
|
|
|
204
|
+
**Stock Library** (multi-source stock media: Pexels, Pixabay, Sketchfab 3D, Music)
|
|
205
|
+
| Tool | Description |
|
|
206
|
+
|------|-------------|
|
|
207
|
+
| `search_stock_media` | Search photos/videos/illustrations/vectors/3D/music across providers. `source="all"` returns one interleaved feed. Find ready-made assets / b-roll (distinct from `generate_image`/`generate_video`). |
|
|
208
|
+
| `get_stock_sources` | List enabled sources + which media types/filters each supports. |
|
|
209
|
+
| `get_stock_categories` | List dynamic category/topic chips (pass `providerParam` as the `category` filter). |
|
|
210
|
+
| `get_stock_asset` | Get one asset with all download variants, author, license, and attribution. |
|
|
211
|
+
| `analyze_script_for_stock` | AI: turn a script into b-roll search terms (`queries[]`, `mediaType`, `keywords`). |
|
|
212
|
+
| `import_stock_asset` | Copy a stock asset into the media library (CDN copy, stable URL). Free. |
|
|
213
|
+
|
|
204
214
|
**Discovery & Account**
|
|
205
215
|
| Tool | Description |
|
|
206
216
|
|------|-------------|
|
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -71,6 +71,7 @@ const { registerArtifactTools } = require('./tools/artifacts');
|
|
|
71
71
|
const { registerProjectTools } = require('./tools/projects');
|
|
72
72
|
const { registerVoiceTools } = require('./tools/voices');
|
|
73
73
|
const { registerMusicLibraryTools } = require('./tools/music_library');
|
|
74
|
+
const { registerStockLibraryTools } = require('./tools/stock_library');
|
|
74
75
|
|
|
75
76
|
/**
|
|
76
77
|
* Build a fully-configured Kolbo MCP server (all tool groups registered)
|
|
@@ -107,6 +108,7 @@ function createServer(opts = {}) {
|
|
|
107
108
|
registerArtifactTools(server, client);
|
|
108
109
|
registerProjectTools(server, client);
|
|
109
110
|
registerMusicLibraryTools(server, client);
|
|
111
|
+
registerStockLibraryTools(server, client);
|
|
110
112
|
|
|
111
113
|
return server;
|
|
112
114
|
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/* ⛔ BACKWARD COMPATIBILITY: Tool names and arg names below are a PUBLIC
|
|
2
|
+
* CONTRACT. Never rename, remove, or break an existing tool/arg. Full rules: ../index.js top-of-file. */
|
|
3
|
+
|
|
4
|
+
const { z } = require('zod');
|
|
5
|
+
|
|
6
|
+
// Compact one-line render of a normalized stock asset.
|
|
7
|
+
function assetLine(a) {
|
|
8
|
+
const dims = a.width && a.height ? `${a.width}x${a.height}` : null;
|
|
9
|
+
const dur = a.durationSeconds != null ? `${Math.round(a.durationSeconds)}s` : null;
|
|
10
|
+
const meta = [a.mediaType, dims, dur].filter(Boolean).join(' · ');
|
|
11
|
+
const by = a.author?.name ? ` by ${a.author.name}` : '';
|
|
12
|
+
const variants = Array.isArray(a.downloadVariants) ? a.downloadVariants.map((v) => v.label).join('/') : '';
|
|
13
|
+
return `[${a.source}:${a.sourceId}] ${a.title || '(untitled)'}${by}\n ${meta}${variants ? ` variants: ${variants}` : ''}${a.thumbnailUrl ? `\n thumb: ${a.thumbnailUrl}` : ''}`;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Returns the raw querystring (no leading '?'). Callers inline it as
|
|
17
|
+
// `${q ? '?' + q : ''}` so the parity checker recognizes it as a querystring.
|
|
18
|
+
function buildQuery(obj) {
|
|
19
|
+
const p = new URLSearchParams();
|
|
20
|
+
for (const [k, v] of Object.entries(obj)) if (v != null && v !== '') p.set(k, String(v));
|
|
21
|
+
return p.toString();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function registerStockLibraryTools(server, client) {
|
|
25
|
+
// ─── search_stock_media ───────────────────────────────────────
|
|
26
|
+
server.tool(
|
|
27
|
+
'search_stock_media',
|
|
28
|
+
'Search the Kolbo unified stock media library and return matching assets. Covers external providers (Pexels photos/videos, Pixabay, Sketchfab 3D, licensed Music) AND Kolbo\'s OWN AI-generated library: thousands of SOUND EFFECTS (mediaType="sfx") and MUSIC tracks (source="kolbo-ai"). Use this to FIND ready-made photos, videos, 3D models, music, or sound effects as b-roll/references/project assets — distinct from generate_* tools which create new content.\n\nFor SOUND EFFECTS or MUSIC, Kolbo supports SEMANTIC "VIBE" SEARCH: pass a natural-language description of the feeling/use ("tense ominous build-up for a horror reveal", "uplifting hopeful corporate background", "retro arcade coin pickup") with source="kolbo-ai" and mediaType="sfx" (or "music") — it matches by meaning, not just keywords. For external visual providers, use concrete keywords.\n\nsource="all" interleaves providers for the requested media type; or pick a single source. Returns assets with source, sourceId, mediaType, dimensions, author, attribution, thumbnail, and downloadable variants. To turn a script into queries first, call analyze_script_for_stock.',
|
|
29
|
+
{
|
|
30
|
+
query: z.string().max(200).optional().describe('For visual providers: concrete keywords ("city skyline sunset"). For Kolbo SFX/music (source="kolbo-ai"): a natural-language VIBE works great ("eerie suspenseful drone", "emotional sad piano"). Omit to browse.'),
|
|
31
|
+
source: z.enum(['all', 'kolbo-ai', 'pexels', 'pixabay', 'sketchfab', 'music', 'freesound']).optional().describe('Provider. "all" (default) interleaves. "kolbo-ai" = Kolbo\'s own AI SFX + music (best for vibe search). "freesound" = external CC sound effects.'),
|
|
32
|
+
mediaType: z.enum(['image', 'illustration', 'vector', 'video', '3d', 'music', 'sfx']).optional().describe('Asset type (default "image"). "sfx" = sound effects, "music" = music tracks. Not every source supports every type — call get_stock_sources.'),
|
|
33
|
+
category: z.string().optional().describe('Category/group chip value (providerParam) from get_stock_categories. For Kolbo SFX these are 77 Soundly-style top-level groups (e.g. Ambience, Animals, Vehicles, Weapons, Water, Designed, Magic, UI) — call get_stock_categories to list them all.'),
|
|
34
|
+
subcategory: z.string().optional().describe('Kolbo SFX sub-filter within a group (providerParam from get_stock_categories, e.g. Weapons>sword, Water>splash, Footsteps>concrete, Designed>riser). 623 sub-filters across the 77 groups.'),
|
|
35
|
+
packId: z.string().optional().describe('Filter to one Kolbo themed pack id (from get_stock_collections, kind="pack").'),
|
|
36
|
+
collectionId: z.string().optional().describe('Filter to one Kolbo collection id (from get_stock_collections).'),
|
|
37
|
+
orientation: z.enum(['horizontal', 'vertical', 'landscape', 'portrait', 'square']).optional().describe('Orientation filter (provider-dependent).'),
|
|
38
|
+
color: z.string().optional().describe('Color filter (Pixabay named color, or Pexels named/hex color).'),
|
|
39
|
+
order: z.enum(['popular', 'latest']).optional().describe('Sort order (Pixabay).'),
|
|
40
|
+
cursor: z.string().optional().describe('Opaque pagination cursor for Sketchfab single-source browse (from a previous response).'),
|
|
41
|
+
page: z.number().int().min(1).optional().describe('1-based page number (default 1).'),
|
|
42
|
+
perPage: z.number().int().min(1).max(80).optional().describe('Results per page (default 24, max 80).')
|
|
43
|
+
},
|
|
44
|
+
async (args) => {
|
|
45
|
+
const q = buildQuery(args);
|
|
46
|
+
const result = await client.get(`/v1/stock/search${q ? '?' + q : ''}`);
|
|
47
|
+
const assets = result.assets || [];
|
|
48
|
+
if (!assets.length) return { content: [{ type: 'text', text: 'No assets found. Try a broader query, a different source/mediaType, or call get_stock_sources.' }] };
|
|
49
|
+
const head = `Found ${assets.length} asset${assets.length === 1 ? '' : 's'}${result.total ? ` (≈${result.total} total)` : ''}${result.hasMore ? ' — more available (increment page)' : ''}:`;
|
|
50
|
+
return { content: [{ type: 'text', text: `${head}\n\n${assets.map(assetLine).join('\n\n')}\n\nUse [source:sourceId] with get_stock_asset for full variants, or import_stock_asset to copy it into the media library.` }] };
|
|
51
|
+
}
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
// ─── get_stock_sources ────────────────────────────────────────
|
|
55
|
+
server.tool(
|
|
56
|
+
'get_stock_sources',
|
|
57
|
+
'List the enabled stock providers and which media types + filters each supports. Call this to know whether a source supports image/video/illustration/vector/3d/music before searching.',
|
|
58
|
+
{},
|
|
59
|
+
async () => {
|
|
60
|
+
const result = await client.get('/v1/stock/sources');
|
|
61
|
+
return { content: [{ type: 'text', text: JSON.stringify({ mediaTypes: result.mediaTypes, sources: result.sources }, null, 2) }] };
|
|
62
|
+
}
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
// ─── get_stock_categories ─────────────────────────────────────
|
|
66
|
+
server.tool(
|
|
67
|
+
'get_stock_categories',
|
|
68
|
+
'List the dynamic category chips for stock sources. For external providers: Pixabay/Sketchfab categories + curated Pexels topics. For Kolbo SFX (source="kolbo-ai", mediaType="sfx"): the 77 Soundly-style top-level groups (group=null) AND their 623 sub-filters (each has a `group` pointing to its parent). Pass a row\'s `providerParam` as `category` (groups) or `subcategory` (sub-filters) to search_stock_media.',
|
|
69
|
+
{
|
|
70
|
+
source: z.enum(['kolbo-ai', 'pexels', 'pixabay', 'sketchfab']).optional().describe('Restrict to one source. Use "kolbo-ai" to list the SFX groups + sub-filters.'),
|
|
71
|
+
mediaType: z.string().optional().describe('Restrict to one media type (e.g. "image", "video", "3d", "sfx").')
|
|
72
|
+
},
|
|
73
|
+
async (args) => {
|
|
74
|
+
const q = buildQuery(args);
|
|
75
|
+
const result = await client.get(`/v1/stock/categories${q ? '?' + q : ''}`);
|
|
76
|
+
return { content: [{ type: 'text', text: JSON.stringify({ count: result.count, categories: result.categories }, null, 2) }] };
|
|
77
|
+
}
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
// ─── get_stock_collections ────────────────────────────────────
|
|
81
|
+
server.tool(
|
|
82
|
+
'get_stock_collections',
|
|
83
|
+
'List Kolbo\'s own SFX collections — the category collections AND the curated themed packs (kind="pack": e.g. Trailer Hits, Horror & Tension, Gaming FX, Foley Essentials). Use the returned `id` as `packId` or `collectionId` in search_stock_media to browse one pack/collection. Each has a cover image.',
|
|
84
|
+
{
|
|
85
|
+
mediaType: z.string().optional().describe('Media type (default "sfx").'),
|
|
86
|
+
kind: z.enum(['category', 'pack']).optional().describe('Filter to category collections or themed packs only.')
|
|
87
|
+
},
|
|
88
|
+
async (args) => {
|
|
89
|
+
const q = buildQuery(args);
|
|
90
|
+
const result = await client.get(`/v1/stock/collections${q ? '?' + q : ''}`);
|
|
91
|
+
return { content: [{ type: 'text', text: JSON.stringify({ count: result.count, collections: result.collections }, null, 2) }] };
|
|
92
|
+
}
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
// ─── get_stock_asset ──────────────────────────────────────────
|
|
96
|
+
server.tool(
|
|
97
|
+
'get_stock_asset',
|
|
98
|
+
'Get a single normalized stock asset with all downloadable variants, author, license, and attribution, by source + id. Call after search_stock_media to resolve the exact download URLs (incl. WAV master + MP3 for Kolbo SFX/music).',
|
|
99
|
+
{
|
|
100
|
+
source: z.enum(['kolbo-ai', 'pexels', 'pixabay', 'sketchfab', 'music', 'freesound']).describe('The asset source.'),
|
|
101
|
+
id: z.string().describe('The provider asset id (sourceId).'),
|
|
102
|
+
mediaType: z.string().optional().describe('Media type hint (e.g. "video") — needed for sources that share ids across types.')
|
|
103
|
+
},
|
|
104
|
+
async ({ source, id, mediaType }) => {
|
|
105
|
+
const q = buildQuery({ mediaType });
|
|
106
|
+
const result = await client.get(`/v1/stock/asset/${encodeURIComponent(source)}/${encodeURIComponent(id)}${q ? '?' + q : ''}`);
|
|
107
|
+
return { content: [{ type: 'text', text: JSON.stringify(result.asset, null, 2) }] };
|
|
108
|
+
}
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
// ─── analyze_script_for_stock ─────────────────────────────────
|
|
112
|
+
server.tool(
|
|
113
|
+
'analyze_script_for_stock',
|
|
114
|
+
'AI helper that turns a video/voiceover script into stock b-roll search terms. Returns { queries[], mediaType, keywords } you can feed into search_stock_media to auto-source matching footage/photos. Use this first when the user gives you a script rather than explicit search keywords.',
|
|
115
|
+
{
|
|
116
|
+
script: z.string().min(1).describe('The video/voiceover script or scene description to analyze (up to ~8000 chars).')
|
|
117
|
+
},
|
|
118
|
+
async ({ script }) => {
|
|
119
|
+
const result = await client.post('/v1/stock/analyze-script', { script });
|
|
120
|
+
return { content: [{ type: 'text', text: JSON.stringify({ queries: result.queries, mediaType: result.mediaType, keywords: result.keywords, _followup_hint: 'Run each query through search_stock_media (source="all", mediaType=result.mediaType).' }, null, 2) }] };
|
|
121
|
+
}
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
// ─── import_stock_asset ───────────────────────────────────────
|
|
125
|
+
server.tool(
|
|
126
|
+
'import_stock_asset',
|
|
127
|
+
"Copy a stock asset into the account's Kolbo media library (downloaded to Kolbo's CDN with a stable URL) so it can be used in projects/generations. Free. Returns the created media library item. Works for Kolbo SFX (source='kolbo-ai', mediaType='sfx') and external visual/audio sources. Licensed Music (source='music') is not importable here (use the music-library tools).",
|
|
128
|
+
{
|
|
129
|
+
source: z.enum(['kolbo-ai', 'pexels', 'pixabay', 'sketchfab', 'freesound']).describe('The asset source.'),
|
|
130
|
+
id: z.string().describe('The provider asset id (sourceId).'),
|
|
131
|
+
mediaType: z.string().optional().describe('Media type hint (e.g. "video", "image", "vector", "3d").'),
|
|
132
|
+
variant: z.string().optional().describe('Which download variant label to import (from get_stock_asset). Defaults to the best/largest available.'),
|
|
133
|
+
project_id: z.string().optional().describe('Optional project id to associate the imported item with.')
|
|
134
|
+
},
|
|
135
|
+
async (args) => {
|
|
136
|
+
const result = await client.post('/v1/stock/import', args);
|
|
137
|
+
const it = result.libraryItem || {};
|
|
138
|
+
return { content: [{ type: 'text', text: `${result.alreadyImported ? 'Already in library' : 'Imported'}: ${it.url || '(no url)'}\n${JSON.stringify({ id: it._id, mediaType: it.mediaType, filename: it.filename, url: it.url }, null, 2)}` }] };
|
|
139
|
+
}
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
module.exports = { registerStockLibraryTools };
|