@kolbo/mcp 1.0.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.
package/README.md ADDED
@@ -0,0 +1,65 @@
1
+ # @kolbo/mcp
2
+
3
+ Use [Kolbo AI](https://kolbo.ai) as native tools in Claude Code and Claude Desktop via MCP (Model Context Protocol).
4
+
5
+ Generate images, videos, music, speech, and sound effects — all from natural language in your coding environment.
6
+
7
+ ## Quick Setup
8
+
9
+ ### 1. Get an API Key
10
+
11
+ Create a key at [app.kolbo.ai](https://app.kolbo.ai) or via the [API](https://docs.kolbo.ai/developer-api).
12
+
13
+ ### 2. Add to Claude Code
14
+
15
+ Add to `.claude/settings.json`:
16
+
17
+ ```json
18
+ {
19
+ "mcpServers": {
20
+ "kolbo": {
21
+ "command": "npx",
22
+ "args": ["-y", "@kolbo/mcp"],
23
+ "env": {
24
+ "KOLBO_API_KEY": "kolbo_live_..."
25
+ }
26
+ }
27
+ }
28
+ }
29
+ ```
30
+
31
+ ### 3. Use it
32
+
33
+ Just ask Claude naturally:
34
+
35
+ - *"Generate an image of a sunset over mountains"*
36
+ - *"Create a 5-second video of waves crashing"*
37
+ - *"Make a lo-fi hip hop beat"*
38
+ - *"Convert this text to speech: Hello world"*
39
+
40
+ ## Available Tools
41
+
42
+ | Tool | Description |
43
+ |------|-------------|
44
+ | `generate_image` | Generate images from text prompts |
45
+ | `generate_video` | Generate videos from text |
46
+ | `generate_video_from_image` | Animate an image into video |
47
+ | `generate_music` | Generate music from descriptions |
48
+ | `generate_speech` | Convert text to speech |
49
+ | `generate_sound` | Generate sound effects |
50
+ | `list_models` | Browse available AI models |
51
+ | `check_credits` | Check credit balance |
52
+ | `get_generation_status` | Check a generation's status |
53
+
54
+ ## Environment Variables
55
+
56
+ | Variable | Required | Description |
57
+ |----------|----------|-------------|
58
+ | `KOLBO_API_KEY` | Yes | Your Kolbo API key |
59
+ | `KOLBO_API_URL` | No | Custom API URL (default: `https://api.kolbo.ai/api`) |
60
+
61
+ ## Links
62
+
63
+ - [API Documentation](https://docs.kolbo.ai/developer-api)
64
+ - [Kolbo AI Platform](https://kolbo.ai)
65
+ - [Get API Key](https://app.kolbo.ai)
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ require('../src/index.js');
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@kolbo/mcp",
3
+ "version": "1.0.0",
4
+ "description": "Kolbo AI MCP Server - Generate images, videos, music, speech, and sound effects from Claude Code",
5
+ "main": "src/index.js",
6
+ "bin": {
7
+ "kolbo-mcp": "./bin/kolbo-mcp.js"
8
+ },
9
+ "scripts": {
10
+ "start": "node src/index.js"
11
+ },
12
+ "keywords": [
13
+ "kolbo",
14
+ "mcp",
15
+ "ai",
16
+ "image-generation",
17
+ "video-generation",
18
+ "music-generation",
19
+ "text-to-speech",
20
+ "claude-code",
21
+ "claude-desktop",
22
+ "model-context-protocol"
23
+ ],
24
+ "license": "MIT",
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "https://github.com/nicenathapong/kolbo-mcp"
28
+ },
29
+ "homepage": "https://docs.kolbo.ai/developer-api/claude-code-mcp",
30
+ "author": "Kolbo AI <support@kolbo.ai>",
31
+ "publishConfig": {
32
+ "access": "public"
33
+ },
34
+ "files": [
35
+ "src/",
36
+ "bin/",
37
+ "README.md"
38
+ ],
39
+ "dependencies": {
40
+ "@modelcontextprotocol/sdk": "^1.12.1"
41
+ },
42
+ "engines": {
43
+ "node": ">=18.0.0"
44
+ }
45
+ }
package/src/client.js ADDED
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Kolbo API HTTP client wrapper
3
+ */
4
+ class KolboClient {
5
+ constructor() {
6
+ this.apiKey = process.env.KOLBO_API_KEY;
7
+ this.baseUrl = (process.env.KOLBO_API_URL || 'https://api.kolbo.ai/api').replace(/\/$/, '');
8
+
9
+ if (!this.apiKey) {
10
+ throw new Error('KOLBO_API_KEY environment variable is required');
11
+ }
12
+ }
13
+
14
+ async request(method, path, body = null) {
15
+ const url = `${this.baseUrl}${path}`;
16
+ const options = {
17
+ method,
18
+ headers: {
19
+ 'X-API-Key': this.apiKey,
20
+ 'Content-Type': 'application/json'
21
+ }
22
+ };
23
+
24
+ if (body) {
25
+ options.body = JSON.stringify(body);
26
+ }
27
+
28
+ const response = await fetch(url, options);
29
+ const data = await response.json();
30
+
31
+ if (!response.ok || data.success === false) {
32
+ throw new Error(data.error || data.message || `API error: ${response.status}`);
33
+ }
34
+
35
+ return data;
36
+ }
37
+
38
+ async post(path, body) {
39
+ return this.request('POST', path, body);
40
+ }
41
+
42
+ async get(path) {
43
+ return this.request('GET', path);
44
+ }
45
+ }
46
+
47
+ module.exports = KolboClient;
package/src/index.js ADDED
@@ -0,0 +1,27 @@
1
+ const { McpServer } = require('@modelcontextprotocol/sdk/server/mcp.js');
2
+ const { StdioServerTransport } = require('@modelcontextprotocol/sdk/server/stdio.js');
3
+ const KolboClient = require('./client');
4
+ const { registerGenerateTools } = require('./tools/generate');
5
+ const { registerModelTools } = require('./tools/models');
6
+
7
+ async function main() {
8
+ const client = new KolboClient();
9
+
10
+ const server = new McpServer({
11
+ name: 'kolbo',
12
+ version: '1.0.0'
13
+ });
14
+
15
+ // Register all tools
16
+ registerGenerateTools(server, client);
17
+ registerModelTools(server, client);
18
+
19
+ // Start the server with stdio transport
20
+ const transport = new StdioServerTransport();
21
+ await server.connect(transport);
22
+ }
23
+
24
+ main().catch(err => {
25
+ console.error('Failed to start Kolbo MCP server:', err);
26
+ process.exit(1);
27
+ });
package/src/polling.js ADDED
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Poll a generation until it reaches a terminal state
3
+ */
4
+ async function pollUntilDone(client, generationId, options = {}) {
5
+ const {
6
+ interval = 5000,
7
+ timeout = 300000 // 5 minutes default
8
+ } = options;
9
+
10
+ const startTime = Date.now();
11
+
12
+ while (true) {
13
+ if (Date.now() - startTime > timeout) {
14
+ throw new Error(`Generation ${generationId} timed out after ${timeout / 1000}s`);
15
+ }
16
+
17
+ const result = await client.get(`/v1/generate/${generationId}/status`);
18
+
19
+ if (result.state === 'completed') {
20
+ return result;
21
+ }
22
+
23
+ if (result.state === 'failed') {
24
+ throw new Error(result.error || 'Generation failed');
25
+ }
26
+
27
+ if (result.state === 'cancelled') {
28
+ throw new Error('Generation was cancelled');
29
+ }
30
+
31
+ // Wait before next poll
32
+ await new Promise(resolve => setTimeout(resolve, interval));
33
+ }
34
+ }
35
+
36
+ module.exports = { pollUntilDone };
@@ -0,0 +1,224 @@
1
+ const { pollUntilDone } = require('../polling');
2
+
3
+ function registerGenerateTools(server, client) {
4
+ // ─── generate_image ────────────────────────────────────────
5
+ server.tool(
6
+ 'generate_image',
7
+ 'Generate image(s) from a text prompt using Kolbo AI. Returns the final image URL(s) when complete.',
8
+ {
9
+ prompt: { type: 'string', description: 'Text description of the image to generate' },
10
+ model: { type: 'string', description: 'Model identifier (e.g., "fal-ai/flux/schnell"). Use list_models to see available models. Omit for auto-selection.' },
11
+ aspect_ratio: { type: 'string', description: 'Aspect ratio (e.g., "1:1", "16:9", "9:16"). Default: "1:1"' },
12
+ enhance_prompt: { type: 'boolean', description: 'Enhance the prompt for better results. Default: true' }
13
+ },
14
+ async ({ prompt, model, aspect_ratio, enhance_prompt }) => {
15
+ const gen = await client.post('/v1/generate/image', {
16
+ prompt, model, aspect_ratio, enhance_prompt
17
+ });
18
+
19
+ const result = await pollUntilDone(client, gen.generation_id, {
20
+ interval: (gen.poll_interval_hint || 3) * 1000,
21
+ timeout: 120000
22
+ });
23
+
24
+ return {
25
+ content: [{
26
+ type: 'text',
27
+ text: JSON.stringify({
28
+ urls: result.result.urls,
29
+ model: result.result.model,
30
+ prompt_used: result.result.prompt_used
31
+ }, null, 2)
32
+ }]
33
+ };
34
+ }
35
+ );
36
+
37
+ // ─── generate_video ────────────────────────────────────────
38
+ server.tool(
39
+ 'generate_video',
40
+ 'Generate a video from a text prompt using Kolbo AI. Returns the final video URL when complete.',
41
+ {
42
+ prompt: { type: 'string', description: 'Text description of the video to generate' },
43
+ model: { type: 'string', description: 'Model identifier. Use list_models with type "video" to see options.' },
44
+ aspect_ratio: { type: 'string', description: 'Aspect ratio (e.g., "16:9", "9:16", "1:1"). Default: "16:9"' },
45
+ duration: { type: 'number', description: 'Duration in seconds (e.g., 5, 10). Default: 5' },
46
+ enhance_prompt: { type: 'boolean', description: 'Enhance the prompt for better results. Default: true' }
47
+ },
48
+ async ({ prompt, model, aspect_ratio, duration, enhance_prompt }) => {
49
+ const gen = await client.post('/v1/generate/video', {
50
+ prompt, model, aspect_ratio, duration, enhance_prompt
51
+ });
52
+
53
+ const result = await pollUntilDone(client, gen.generation_id, {
54
+ interval: (gen.poll_interval_hint || 8) * 1000,
55
+ timeout: 300000
56
+ });
57
+
58
+ return {
59
+ content: [{
60
+ type: 'text',
61
+ text: JSON.stringify({
62
+ urls: result.result.urls,
63
+ model: result.result.model,
64
+ duration: result.result.duration,
65
+ thumbnail_url: result.result.thumbnail_url,
66
+ prompt_used: result.result.prompt_used
67
+ }, null, 2)
68
+ }]
69
+ };
70
+ }
71
+ );
72
+
73
+ // ─── generate_video_from_image ─────────────────────────────
74
+ server.tool(
75
+ 'generate_video_from_image',
76
+ 'Animate an image into a video using Kolbo AI. Returns the final video URL when complete.',
77
+ {
78
+ image_url: { type: 'string', description: 'URL of the source image to animate' },
79
+ prompt: { type: 'string', description: 'Text description of the desired motion/animation' },
80
+ model: { type: 'string', description: 'Model identifier. Use list_models with type "video_from_image" to see options.' },
81
+ duration: { type: 'number', description: 'Duration in seconds (e.g., 5, 10). Default: 5' },
82
+ enhance_prompt: { type: 'boolean', description: 'Enhance the prompt. Default: true' }
83
+ },
84
+ async ({ image_url, prompt, model, duration, enhance_prompt }) => {
85
+ const gen = await client.post('/v1/generate/video/from-image', {
86
+ image_url, prompt, model, duration, enhance_prompt
87
+ });
88
+
89
+ const result = await pollUntilDone(client, gen.generation_id, {
90
+ interval: (gen.poll_interval_hint || 8) * 1000,
91
+ timeout: 300000
92
+ });
93
+
94
+ return {
95
+ content: [{
96
+ type: 'text',
97
+ text: JSON.stringify({
98
+ urls: result.result.urls,
99
+ model: result.result.model,
100
+ duration: result.result.duration,
101
+ thumbnail_url: result.result.thumbnail_url
102
+ }, null, 2)
103
+ }]
104
+ };
105
+ }
106
+ );
107
+
108
+ // ─── generate_music ────────────────────────────────────────
109
+ server.tool(
110
+ 'generate_music',
111
+ 'Generate music from a text description using Kolbo AI. Returns the final audio URL when complete.',
112
+ {
113
+ prompt: { type: 'string', description: 'Text description of the music to generate (e.g., "upbeat electronic dance track with synthesizers")' },
114
+ style: { type: 'string', description: 'Music style (e.g., "pop", "rock", "electronic", "jazz")' },
115
+ instrumental: { type: 'boolean', description: 'Generate instrumental only (no vocals). Default: false' },
116
+ lyrics: { type: 'string', description: 'Custom lyrics for the song' }
117
+ },
118
+ async ({ prompt, style, instrumental, lyrics }) => {
119
+ const gen = await client.post('/v1/generate/music', {
120
+ prompt, style, instrumental, lyrics
121
+ });
122
+
123
+ const result = await pollUntilDone(client, gen.generation_id, {
124
+ interval: (gen.poll_interval_hint || 8) * 1000,
125
+ timeout: 300000
126
+ });
127
+
128
+ return {
129
+ content: [{
130
+ type: 'text',
131
+ text: JSON.stringify({
132
+ urls: result.result.urls,
133
+ title: result.result.title,
134
+ duration: result.result.duration,
135
+ lyrics: result.result.lyrics
136
+ }, null, 2)
137
+ }]
138
+ };
139
+ }
140
+ );
141
+
142
+ // ─── generate_speech ───────────────────────────────────────
143
+ server.tool(
144
+ 'generate_speech',
145
+ 'Convert text to speech using Kolbo AI. Returns the final audio URL when complete.',
146
+ {
147
+ text: { type: 'string', description: 'The text to convert to speech' },
148
+ voice: { type: 'string', description: 'Voice ID or name (e.g., "Rachel", "Adam"). Default: "Rachel"' },
149
+ language: { type: 'string', description: 'Language code (e.g., "en-US", "he-IL"). Default: "en-US"' }
150
+ },
151
+ async ({ text, voice, language }) => {
152
+ const gen = await client.post('/v1/generate/speech', {
153
+ text, voice, language
154
+ });
155
+
156
+ const result = await pollUntilDone(client, gen.generation_id, {
157
+ interval: (gen.poll_interval_hint || 5) * 1000,
158
+ timeout: 120000
159
+ });
160
+
161
+ return {
162
+ content: [{
163
+ type: 'text',
164
+ text: JSON.stringify({
165
+ urls: result.result.urls,
166
+ voice: result.result.voice,
167
+ duration: result.result.duration
168
+ }, null, 2)
169
+ }]
170
+ };
171
+ }
172
+ );
173
+
174
+ // ─── generate_sound ────────────────────────────────────────
175
+ server.tool(
176
+ 'generate_sound',
177
+ 'Generate sound effects from a text description using Kolbo AI. Returns the final audio URL when complete.',
178
+ {
179
+ prompt: { type: 'string', description: 'Text description of the sound effect (e.g., "thunder clap with rain", "door creaking open")' },
180
+ duration: { type: 'number', description: 'Duration in seconds. Omit for auto duration.' }
181
+ },
182
+ async ({ prompt, duration }) => {
183
+ const gen = await client.post('/v1/generate/sound', {
184
+ prompt, duration
185
+ });
186
+
187
+ const result = await pollUntilDone(client, gen.generation_id, {
188
+ interval: (gen.poll_interval_hint || 5) * 1000,
189
+ timeout: 120000
190
+ });
191
+
192
+ return {
193
+ content: [{
194
+ type: 'text',
195
+ text: JSON.stringify({
196
+ urls: result.result.urls,
197
+ duration: result.result.duration
198
+ }, null, 2)
199
+ }]
200
+ };
201
+ }
202
+ );
203
+
204
+ // ─── get_generation_status ─────────────────────────────────
205
+ server.tool(
206
+ 'get_generation_status',
207
+ 'Check the status of a generation. Use this if a generation tool timed out or you need to check progress.',
208
+ {
209
+ generation_id: { type: 'string', description: 'The generation ID to check' }
210
+ },
211
+ async ({ generation_id }) => {
212
+ const result = await client.get(`/v1/generate/${generation_id}/status`);
213
+
214
+ return {
215
+ content: [{
216
+ type: 'text',
217
+ text: JSON.stringify(result, null, 2)
218
+ }]
219
+ };
220
+ }
221
+ );
222
+ }
223
+
224
+ module.exports = { registerGenerateTools };
@@ -0,0 +1,48 @@
1
+ function registerModelTools(server, client) {
2
+ // ─── list_models ───────────────────────────────────────────
3
+ server.tool(
4
+ 'list_models',
5
+ 'List available AI models on Kolbo. Filter by type to find models for a specific generation type.',
6
+ {
7
+ type: {
8
+ type: 'string',
9
+ description: 'Filter by type: "image", "video", "video_from_image", "music", "speech", "sound". Omit for all models.'
10
+ }
11
+ },
12
+ async ({ type }) => {
13
+ const path = type ? `/v1/models?type=${encodeURIComponent(type)}` : '/v1/models';
14
+ const result = await client.get(path);
15
+
16
+ // Format for readability
17
+ const summary = result.models.map(m =>
18
+ `${m.identifier} (${m.name}) - ${m.credit} credits${m.recommended ? ' [RECOMMENDED]' : ''}${m.new_model ? ' [NEW]' : ''}`
19
+ ).join('\n');
20
+
21
+ return {
22
+ content: [{
23
+ type: 'text',
24
+ text: `Available models (${result.count}):\n\n${summary}\n\nUse the "identifier" value as the "model" parameter in generate tools.`
25
+ }]
26
+ };
27
+ }
28
+ );
29
+
30
+ // ─── check_credits ─────────────────────────────────────────
31
+ server.tool(
32
+ 'check_credits',
33
+ 'Check your remaining Kolbo credit balance.',
34
+ {},
35
+ async () => {
36
+ const result = await client.get('/v1/account/credits');
37
+
38
+ return {
39
+ content: [{
40
+ type: 'text',
41
+ text: `Credit Balance:\n- Total: ${result.credits.total}\n- Plan credits: ${result.credits.plan_credits}\n- Credit pack: ${result.credits.credit_pack}\n- Redemption: ${result.credits.redemption}`
42
+ }]
43
+ };
44
+ }
45
+ );
46
+ }
47
+
48
+ module.exports = { registerModelTools };