@kolbo/mcp 1.6.8 → 1.6.9
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 +1 -1
- package/src/client.js +18 -4
- package/src/tools/_shared.js +32 -1
- package/src/tools/chat.js +2 -0
- package/src/tools/generate.js +17 -1
- package/src/tools/models.js +32 -0
package/package.json
CHANGED
package/src/client.js
CHANGED
|
@@ -198,12 +198,21 @@ class KolboClient {
|
|
|
198
198
|
|
|
199
199
|
async _doRequest(method, reqPath, body = null) {
|
|
200
200
|
const url = `${this.baseUrl}${reqPath}`;
|
|
201
|
+
const headers = {
|
|
202
|
+
'X-API-Key': this.apiKey,
|
|
203
|
+
'Content-Type': 'application/json'
|
|
204
|
+
};
|
|
205
|
+
// Stable per-app-launch identifier from the parent process (Kolbo Code
|
|
206
|
+
// sets this in the MCP env when spawning us). kolbo-api tags every
|
|
207
|
+
// CreditUsage record with it so the desktop UI and the get_session_usage
|
|
208
|
+
// tool can aggregate spend without enumerating individual generations.
|
|
209
|
+
const callerSessionId = process.env.KOLBO_CALLER_SESSION_ID;
|
|
210
|
+
if (callerSessionId) {
|
|
211
|
+
headers['X-Kolbo-Caller-Session-Id'] = callerSessionId;
|
|
212
|
+
}
|
|
201
213
|
const options = {
|
|
202
214
|
method,
|
|
203
|
-
headers
|
|
204
|
-
'X-API-Key': this.apiKey,
|
|
205
|
-
'Content-Type': 'application/json'
|
|
206
|
-
}
|
|
215
|
+
headers,
|
|
207
216
|
};
|
|
208
217
|
|
|
209
218
|
if (body) {
|
|
@@ -270,6 +279,11 @@ class KolboClient {
|
|
|
270
279
|
'X-API-Key': this.apiKey,
|
|
271
280
|
...formData.getHeaders()
|
|
272
281
|
};
|
|
282
|
+
// Same caller-session header as JSON requests — see _doRequest.
|
|
283
|
+
const callerSessionId = process.env.KOLBO_CALLER_SESSION_ID;
|
|
284
|
+
if (callerSessionId) {
|
|
285
|
+
headers['X-Kolbo-Caller-Session-Id'] = callerSessionId;
|
|
286
|
+
}
|
|
273
287
|
|
|
274
288
|
// Serialize form-data to a Buffer before passing to fetch(). Node's
|
|
275
289
|
// built-in fetch (undici) can't consume legacy Node.js streams from
|
package/src/tools/_shared.js
CHANGED
|
@@ -200,6 +200,36 @@ async function resolveToBuffer(source, kind, opts = {}) {
|
|
|
200
200
|
};
|
|
201
201
|
}
|
|
202
202
|
|
|
203
|
+
/**
|
|
204
|
+
* Extract real, multiplier-adjusted credit cost from a polled getStatus
|
|
205
|
+
* response. kolbo-api returns `credits_used` (final number deducted) and
|
|
206
|
+
* `credits_breakdown` (per-CreditUsage detail) when the generation is
|
|
207
|
+
* complete. Returns `{}` when the API didn't include them so spreading
|
|
208
|
+
* the result into a tool's response object is a no-op (forward-compatible
|
|
209
|
+
* with old kolbo-api versions).
|
|
210
|
+
*
|
|
211
|
+
* Usage in every generation tool:
|
|
212
|
+
* return {
|
|
213
|
+
* content: [{ type: 'text', text: JSON.stringify({
|
|
214
|
+
* urls: result.result.urls,
|
|
215
|
+
* model: result.result.model,
|
|
216
|
+
* ...creditFields(result), // adds credits_used + credits_breakdown
|
|
217
|
+
* _followup_hint: '...',
|
|
218
|
+
* }, null, 2) }]
|
|
219
|
+
* };
|
|
220
|
+
*/
|
|
221
|
+
function creditFields(polledResult) {
|
|
222
|
+
if (!polledResult) return {};
|
|
223
|
+
const out = {};
|
|
224
|
+
if (typeof polledResult.credits_used === 'number') {
|
|
225
|
+
out.credits_used = polledResult.credits_used;
|
|
226
|
+
}
|
|
227
|
+
if (Array.isArray(polledResult.credits_breakdown) && polledResult.credits_breakdown.length) {
|
|
228
|
+
out.credits_breakdown = polledResult.credits_breakdown;
|
|
229
|
+
}
|
|
230
|
+
return out;
|
|
231
|
+
}
|
|
232
|
+
|
|
203
233
|
module.exports = {
|
|
204
234
|
MAX_FILE_BYTES,
|
|
205
235
|
VISUAL_DNA_MAX_BYTES,
|
|
@@ -208,5 +238,6 @@ module.exports = {
|
|
|
208
238
|
safeFetch,
|
|
209
239
|
guessFilename,
|
|
210
240
|
guessContentType,
|
|
211
|
-
resolveToBuffer
|
|
241
|
+
resolveToBuffer,
|
|
242
|
+
creditFields,
|
|
212
243
|
};
|
package/src/tools/chat.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
const { z } = require('zod');
|
|
7
7
|
const { pollUntilDone } = require('../polling');
|
|
8
|
+
const { creditFields } = require('./_shared');
|
|
8
9
|
|
|
9
10
|
function registerChatTools(server, client) {
|
|
10
11
|
// ─── chat_send_message ─────────────────────────────────────
|
|
@@ -49,6 +50,7 @@ function registerChatTools(server, client) {
|
|
|
49
50
|
content: [{
|
|
50
51
|
type: 'text',
|
|
51
52
|
text: JSON.stringify({
|
|
53
|
+
...creditFields(result),
|
|
52
54
|
session_id: gen.session_id,
|
|
53
55
|
message_id: gen.message_id,
|
|
54
56
|
model: r.model || gen.model,
|
package/src/tools/generate.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
const { z } = require('zod');
|
|
7
7
|
const FormData = require('form-data');
|
|
8
8
|
const { pollUntilDone } = require('../polling');
|
|
9
|
-
const { resolveToBuffer } = require('./_shared');
|
|
9
|
+
const { resolveToBuffer, creditFields } = require('./_shared');
|
|
10
10
|
|
|
11
11
|
function registerGenerateTools(server, client) {
|
|
12
12
|
// ─── generate_image ────────────────────────────────────────
|
|
@@ -41,6 +41,7 @@ function registerGenerateTools(server, client) {
|
|
|
41
41
|
content: [{
|
|
42
42
|
type: 'text',
|
|
43
43
|
text: JSON.stringify({
|
|
44
|
+
...creditFields(result),
|
|
44
45
|
urls: result.result.urls,
|
|
45
46
|
model: result.result.model,
|
|
46
47
|
prompt_used: result.result.prompt_used,
|
|
@@ -86,6 +87,7 @@ function registerGenerateTools(server, client) {
|
|
|
86
87
|
content: [{
|
|
87
88
|
type: 'text',
|
|
88
89
|
text: JSON.stringify({
|
|
90
|
+
...creditFields(result),
|
|
89
91
|
urls: result.result.urls,
|
|
90
92
|
model: result.result.model,
|
|
91
93
|
prompt_used: result.result.prompt_used,
|
|
@@ -139,6 +141,7 @@ function registerGenerateTools(server, client) {
|
|
|
139
141
|
content: [{
|
|
140
142
|
type: 'text',
|
|
141
143
|
text: JSON.stringify({
|
|
144
|
+
...creditFields(result),
|
|
142
145
|
scenes,
|
|
143
146
|
total_scenes: result.scenes?.length || 0,
|
|
144
147
|
completed_scenes: scenes.length,
|
|
@@ -181,6 +184,7 @@ function registerGenerateTools(server, client) {
|
|
|
181
184
|
content: [{
|
|
182
185
|
type: 'text',
|
|
183
186
|
text: JSON.stringify({
|
|
187
|
+
...creditFields(result),
|
|
184
188
|
urls: result.result.urls,
|
|
185
189
|
model: result.result.model,
|
|
186
190
|
duration: result.result.duration,
|
|
@@ -221,6 +225,7 @@ function registerGenerateTools(server, client) {
|
|
|
221
225
|
content: [{
|
|
222
226
|
type: 'text',
|
|
223
227
|
text: JSON.stringify({
|
|
228
|
+
...creditFields(result),
|
|
224
229
|
urls: result.result.urls,
|
|
225
230
|
model: result.result.model,
|
|
226
231
|
duration: result.result.duration,
|
|
@@ -260,6 +265,7 @@ function registerGenerateTools(server, client) {
|
|
|
260
265
|
content: [{
|
|
261
266
|
type: 'text',
|
|
262
267
|
text: JSON.stringify({
|
|
268
|
+
...creditFields(result),
|
|
263
269
|
urls: result.result.urls,
|
|
264
270
|
title: result.result.title,
|
|
265
271
|
duration: result.result.duration,
|
|
@@ -294,6 +300,7 @@ function registerGenerateTools(server, client) {
|
|
|
294
300
|
content: [{
|
|
295
301
|
type: 'text',
|
|
296
302
|
text: JSON.stringify({
|
|
303
|
+
...creditFields(result),
|
|
297
304
|
urls: result.result.urls,
|
|
298
305
|
voice: result.result.voice,
|
|
299
306
|
duration: result.result.duration
|
|
@@ -327,6 +334,7 @@ function registerGenerateTools(server, client) {
|
|
|
327
334
|
content: [{
|
|
328
335
|
type: 'text',
|
|
329
336
|
text: JSON.stringify({
|
|
337
|
+
...creditFields(result),
|
|
330
338
|
urls: result.result.urls,
|
|
331
339
|
duration: result.result.duration
|
|
332
340
|
}, null, 2)
|
|
@@ -454,6 +462,7 @@ function registerGenerateTools(server, client) {
|
|
|
454
462
|
content: [{
|
|
455
463
|
type: 'text',
|
|
456
464
|
text: JSON.stringify({
|
|
465
|
+
...creditFields(result),
|
|
457
466
|
urls: result.result?.urls || [],
|
|
458
467
|
thumbnail_url: result.result?.thumbnail_url || null,
|
|
459
468
|
duration: result.result?.duration || null,
|
|
@@ -523,6 +532,7 @@ function registerGenerateTools(server, client) {
|
|
|
523
532
|
content: [{
|
|
524
533
|
type: 'text',
|
|
525
534
|
text: JSON.stringify({
|
|
535
|
+
...creditFields(result),
|
|
526
536
|
urls: result.result?.urls || [],
|
|
527
537
|
thumbnail_url: result.result?.thumbnail_url || null,
|
|
528
538
|
duration: result.result?.duration || null,
|
|
@@ -593,6 +603,7 @@ function registerGenerateTools(server, client) {
|
|
|
593
603
|
content: [{
|
|
594
604
|
type: 'text',
|
|
595
605
|
text: JSON.stringify({
|
|
606
|
+
...creditFields(result),
|
|
596
607
|
urls: result.result?.urls || [],
|
|
597
608
|
thumbnail_url: result.result?.thumbnail_url || null,
|
|
598
609
|
duration: result.result?.duration || null,
|
|
@@ -657,6 +668,7 @@ function registerGenerateTools(server, client) {
|
|
|
657
668
|
content: [{
|
|
658
669
|
type: 'text',
|
|
659
670
|
text: JSON.stringify({
|
|
671
|
+
...creditFields(result),
|
|
660
672
|
urls: result.result?.urls || [],
|
|
661
673
|
thumbnail_url: result.result?.thumbnail_url || null,
|
|
662
674
|
duration: result.result?.duration || null,
|
|
@@ -697,6 +709,7 @@ function registerGenerateTools(server, client) {
|
|
|
697
709
|
content: [{
|
|
698
710
|
type: 'text',
|
|
699
711
|
text: JSON.stringify({
|
|
712
|
+
...creditFields(result),
|
|
700
713
|
text: result.result?.text || '',
|
|
701
714
|
srt_url: result.result?.srt_url || null,
|
|
702
715
|
word_by_word_srt_url: result.result?.word_by_word_srt_url || null,
|
|
@@ -749,6 +762,7 @@ function registerGenerateTools(server, client) {
|
|
|
749
762
|
content: [{
|
|
750
763
|
type: 'text',
|
|
751
764
|
text: JSON.stringify({
|
|
765
|
+
...creditFields(result),
|
|
752
766
|
urls: result.result?.urls || [],
|
|
753
767
|
thumbnail_url: result.result?.thumbnail_url || null,
|
|
754
768
|
mode: result.result?.mode || null,
|
|
@@ -790,6 +804,7 @@ function registerGenerateTools(server, client) {
|
|
|
790
804
|
content: [{
|
|
791
805
|
type: 'text',
|
|
792
806
|
text: JSON.stringify({
|
|
807
|
+
...creditFields(result),
|
|
793
808
|
urls: result.result?.urls || [],
|
|
794
809
|
edit_type: result.result?.edit_type || null,
|
|
795
810
|
model: result.result?.model || null
|
|
@@ -838,6 +853,7 @@ function registerGenerateTools(server, client) {
|
|
|
838
853
|
content: [{
|
|
839
854
|
type: 'text',
|
|
840
855
|
text: JSON.stringify({
|
|
856
|
+
...creditFields(result),
|
|
841
857
|
urls: result.result?.urls || [],
|
|
842
858
|
download_url: result.result?.download_url || null,
|
|
843
859
|
edit_type: result.result?.edit_type || null,
|
package/src/tools/models.js
CHANGED
|
@@ -113,6 +113,38 @@ function registerModelTools(server, client) {
|
|
|
113
113
|
};
|
|
114
114
|
}
|
|
115
115
|
);
|
|
116
|
+
|
|
117
|
+
// ─── get_session_usage ─────────────────────────────────────
|
|
118
|
+
// Real, multiplier-adjusted credit spend tagged with the caller's
|
|
119
|
+
// X-Kolbo-Caller-Session-Id (set automatically by the parent process —
|
|
120
|
+
// no need to pass it). Use this to give the user an honest "you've spent
|
|
121
|
+
// X credits in this app session" instead of estimating from base credits.
|
|
122
|
+
server.tool(
|
|
123
|
+
'get_session_usage',
|
|
124
|
+
'Fetch real, multiplier-adjusted credit spend for the current Kolbo Code app session. Use when the user asks "how much did I spend?" or before/after a large bulk job so you can quote actual cost (not an estimate from base credits). Returns total + per-tool breakdown + per-model breakdown + a recent list. The caller-session-id is forwarded automatically by the MCP HTTP client.',
|
|
125
|
+
{},
|
|
126
|
+
async () => {
|
|
127
|
+
try {
|
|
128
|
+
const r = await client.get('/credit-usage/by-caller-session');
|
|
129
|
+
// The endpoint returns { message, data: { total, count, by_tool, by_model, recent[] } }
|
|
130
|
+
return {
|
|
131
|
+
content: [{
|
|
132
|
+
type: 'text',
|
|
133
|
+
text: JSON.stringify(r.data || r, null, 2)
|
|
134
|
+
}]
|
|
135
|
+
};
|
|
136
|
+
} catch (err) {
|
|
137
|
+
// 400 from the endpoint means no caller-session-id was forwarded —
|
|
138
|
+
// surface a clear hint instead of a generic API error.
|
|
139
|
+
const hint = err?.status === 400
|
|
140
|
+
? 'No caller-session-id was forwarded. Ensure the parent process (Kolbo Code / desktop sidecar) sets KOLBO_CALLER_SESSION_ID in this MCP\'s env, or call again after at least one media generation has fired.'
|
|
141
|
+
: err?.message || 'Failed to fetch session usage';
|
|
142
|
+
return {
|
|
143
|
+
content: [{ type: 'text', text: JSON.stringify({ error: hint }, null, 2) }]
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
);
|
|
116
148
|
}
|
|
117
149
|
|
|
118
150
|
module.exports = { registerModelTools };
|