@kolbo/mcp 1.123.1 → 1.124.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 +2 -0
- package/package.json +1 -1
- package/src/toolAnnotations.js +4 -0
- package/src/tools/projects.js +64 -6
package/README.md
CHANGED
|
@@ -322,6 +322,8 @@ Requires DaVinci Resolve Studio with the Kolbo plugin open (Workspace → Workfl
|
|
|
322
322
|
| `list_visual_dna_folders` / `create_visual_dna_folder` / `update_visual_dna_folder` / `delete_visual_dna_folder` / `move_visual_dna_to_folder` | Organize Visual DNA characters into user folders (create/rename/recolor/delete + move DNAs in/out) |
|
|
323
323
|
| `create_project` / `update_project` / `archive_project` / `unarchive_project` | Project lifecycle (create/rename/describe/archive; deletion stays in-app) |
|
|
324
324
|
| `publish_project` / `get_project_publication` / `unpublish_project` / `submit_project_to_catalog` / `remove_project_hero_video` | Publish a project as a public showcase link, with write-up and final video as hero |
|
|
325
|
+
| `get_project_page_insights` | Visitor analytics for a published project page: visitors, active time, scroll depth, story reach, clicks, copies, sources, countries, most-opened media |
|
|
326
|
+
| `get_project_story` / `update_project_story` / `draft_project_story` | Write the published page as a post: headings, text, media, workflow steps (real prompt + model), before/after. AI draft from the project's own media |
|
|
325
327
|
| `transfer_visual_dna` / `list_visual_dna_transfers` / `respond_visual_dna_transfer` | Send Visual DNAs you own to another Kolbo account (they accept a copy with new ids; optionally move instead of copy) |
|
|
326
328
|
| `transfer_project` / `list_project_transfers` / `respond_project_transfer` | Hand a project you own to another Kolbo account (they accept; same ids; cast assets copied; payer history unchanged) |
|
|
327
329
|
| `list_skills` / `create_skill` / `update_skill` / `delete_skill` | Skills — reusable named personas for the chat tool; `description` is the system instruction |
|
package/package.json
CHANGED
package/src/toolAnnotations.js
CHANGED
|
@@ -26,6 +26,8 @@ const READ_ONLY = [
|
|
|
26
26
|
'list_media', 'list_media_folders', 'get_media', 'get_media_stats',
|
|
27
27
|
'list_presets', 'list_cinematic_presets',
|
|
28
28
|
'list_projects', 'get_project', 'get_project_publication', 'list_sessions', 'list_project_context', 'get_project_profile',
|
|
29
|
+
// Returns a draft without saving it.
|
|
30
|
+
'get_project_story', 'draft_project_story', 'get_project_page_insights',
|
|
29
31
|
'list_project_assets',
|
|
30
32
|
'list_project_transfers', 'list_visual_dna_transfers',
|
|
31
33
|
'list_session_generations',
|
|
@@ -140,6 +142,8 @@ const OPEN_WORLD_WRITE = [
|
|
|
140
142
|
|
|
141
143
|
const OPEN_WORLD_DESTRUCTIVE = [
|
|
142
144
|
'share_doc', 'revoke_review_share_link', 'unpublish_project',
|
|
145
|
+
// Replaces the whole story; live on the public page when the project is published.
|
|
146
|
+
'update_project_story',
|
|
143
147
|
'blender_apply_operations', 'blender_import_media', 'blender_render',
|
|
144
148
|
'blender_undo', 'blender_file_operation', 'blender_execute_python',
|
|
145
149
|
// Can delete layers; approved once per batch in the Kolbo panel.
|
package/src/tools/projects.js
CHANGED
|
@@ -320,28 +320,30 @@ function registerProjectTools(server, client) {
|
|
|
320
320
|
|
|
321
321
|
server.tool(
|
|
322
322
|
'publish_project',
|
|
323
|
-
'PUBLISH one of YOUR OWN projects as a public showcase page with a shareable link (the same as the app\'s Publish tab) and return the public `url`. Safe to call again: it never changes the URL, it only updates what you pass. In one call you can also set `allow_fork` (let viewers copy the project into their account), the public write-up `showcase_about`, and the project\'s FINAL VIDEO as the page hero. HERO VIDEO: the video must already be in THIS project — a generated video made with `project_id`, or a file you put there with `upload_media` (pass `project_id`; a local file is uploaded from disk). Then pass its media id as `hero_video_media_id` (or its Kolbo URL as `hero_video_url`). Anyone with the link can see the project\'s media, so ALWAYS confirm with the user before publishing, and consider `duplicate_project` first to publish a clean copy. Undo with `unpublish_project`.',
|
|
323
|
+
'PUBLISH one of YOUR OWN projects as a public showcase page with a shareable link (the same as the app\'s Publish tab) and return the public `url`. Safe to call again: it never changes the URL, it only updates what you pass. In one call you can also set `allow_fork` (let viewers copy the project into their account), `story_only` (publish a blog-style post without sharing the project: see below), the public write-up `showcase_about`, and the project\'s FINAL VIDEO as the page hero. HERO VIDEO: the video must already be in THIS project — a generated video made with `project_id`, or a file you put there with `upload_media` (pass `project_id`; a local file is uploaded from disk). Then pass its media id as `hero_video_media_id` (or its Kolbo URL as `hero_video_url`). Anyone with the link can see the project\'s media, so ALWAYS confirm with the user before publishing, and consider `duplicate_project` first to publish a clean copy. STORY ONLY: with `story_only: true` the page shows only the story (get_project_story / update_project_story) and the media inside it; the media library, sessions, chats/docs/flows, cast and credits are not served, and copying is refused whatever `allow_fork` says. Use it when the user wants a post about the work without sharing the project. Undo with `unpublish_project`.',
|
|
324
324
|
{
|
|
325
325
|
project_id: z.string().describe('ObjectId of a project you OWN (from list_projects).'),
|
|
326
|
-
allow_fork: z.boolean().optional().describe('Let viewers copy the project into their own account. Default true on first publish; omit to keep the current setting.'),
|
|
326
|
+
allow_fork: z.boolean().optional().describe('Let viewers copy the project into their own account. Default true on first publish; omit to keep the current setting. Has no effect while story_only is true.'),
|
|
327
|
+
story_only: z.boolean().optional().describe('true = the page shows only its story and the media in it (no library, sessions, chats, cast, credits, no copying). Default false on first publish; omit to keep the current setting.'),
|
|
327
328
|
showcase_about: z.string().optional().describe('Public "About" write-up shown on the page (max 10000 chars, plain text). Omit on first publish and Kolbo drafts one for you; pass "" to clear.'),
|
|
328
329
|
hero_video_media_id: z.string().optional().describe('Media id (from upload_media / list_media) of a VIDEO already in this project, shown as the full-bleed hero of the public page.'),
|
|
329
330
|
hero_video_url: z.string().optional().describe('Alternative to hero_video_media_id: the Kolbo CDN URL of a video already in this project.')
|
|
330
331
|
},
|
|
331
|
-
async ({ project_id, allow_fork, showcase_about, hero_video_media_id, hero_video_url }) => {
|
|
332
|
+
async ({ project_id, allow_fork, story_only, showcase_about, hero_video_media_id, hero_video_url }) => {
|
|
332
333
|
const body = {};
|
|
333
334
|
if (allow_fork !== undefined) body.allow_fork = allow_fork;
|
|
335
|
+
if (story_only !== undefined) body.story_only = story_only;
|
|
334
336
|
if (showcase_about !== undefined) body.showcase_about = showcase_about;
|
|
335
337
|
if (hero_video_media_id) body.hero_video_media_id = hero_video_media_id;
|
|
336
338
|
if (hero_video_url) body.hero_video_url = hero_video_url;
|
|
337
339
|
const result = await client.post(`/v1/projects/${encodeURIComponent(project_id)}/publish`, body);
|
|
338
|
-
return pubText(result, 'Share `url` with the user — it is live now. To list it in the public catalog call `submit_project_to_catalog` (review is manual).');
|
|
340
|
+
return pubText(result, 'Share `url` with the user — it is live now. Kolbo drafts the page\'s story on first publish; read or rewrite it with get_project_story / update_project_story. To list it in the public catalog (and Google) call `submit_project_to_catalog` (review is manual).');
|
|
339
341
|
}
|
|
340
342
|
);
|
|
341
343
|
|
|
342
344
|
server.tool(
|
|
343
345
|
'get_project_publication',
|
|
344
|
-
'Check whether a project is published and read its public `url`, allow_fork, showcase_about, hero video, catalog listing status (none / pending / approved / rejected) and fork count. Returns `{ published: false }` when it is not published.',
|
|
346
|
+
'Check whether a project is published and read its public `url`, allow_fork, story_only, showcase_about, hero video, catalog listing status (none / pending / approved / rejected) and fork count. Returns `{ published: false }` when it is not published.',
|
|
345
347
|
{ project_id: z.string().describe('ObjectId of a project you OWN.') },
|
|
346
348
|
async ({ project_id }) => pubText(await client.get(`/v1/projects/${encodeURIComponent(project_id)}/publish`))
|
|
347
349
|
);
|
|
@@ -355,7 +357,7 @@ function registerProjectTools(server, client) {
|
|
|
355
357
|
|
|
356
358
|
server.tool(
|
|
357
359
|
'submit_project_to_catalog',
|
|
358
|
-
'Submit a PUBLISHED project to Kolbo\'s public catalog (status becomes `pending`; a Kolbo admin approves it — you cannot approve your own). Pass `submit: false` to withdraw. Fails with NOT_PUBLISHED if `publish_project` has not been called.',
|
|
360
|
+
'Submit a PUBLISHED project to Kolbo\'s public catalog (status becomes `pending`; a Kolbo admin approves it — you cannot approve your own). Only approved projects are listed and may appear in Google search; until then the page is reachable by link but not indexed. Pass `submit: false` to withdraw. Fails with NOT_PUBLISHED if `publish_project` has not been called.',
|
|
359
361
|
{
|
|
360
362
|
project_id: z.string().describe('ObjectId of a project you OWN.'),
|
|
361
363
|
submit: z.boolean().optional().describe('true (default) = submit for review, false = withdraw.')
|
|
@@ -363,6 +365,62 @@ function registerProjectTools(server, client) {
|
|
|
363
365
|
async ({ project_id, submit }) => pubText(await client.post(`/v1/projects/${encodeURIComponent(project_id)}/publish/listing`, { submit: submit !== false }))
|
|
364
366
|
);
|
|
365
367
|
|
|
368
|
+
// ─── project story (the public page as a post) ─────────────
|
|
369
|
+
const storyBlock = z.object({
|
|
370
|
+
type: z.enum(['heading', 'text', 'media', 'step', 'before_after']).describe('heading = section title, text = paragraph, media = an image/video with a caption, step = a generated result shown WITH its real prompt and model (how it was made), before_after = two items side by side.'),
|
|
371
|
+
text: z.string().optional().describe('heading (max 160 chars) / text (max 5000 chars). Plain text; blank lines separate paragraphs.'),
|
|
372
|
+
media_id: z.string().optional().describe('media / step: a media_id from get_project_story `available_media`. A step must be a GENERATED result.'),
|
|
373
|
+
media_url: z.string().optional().describe('Alternative to media_id: the Kolbo URL of media already in this project.'),
|
|
374
|
+
before_media_id: z.string().optional().describe('before_after: the "before" item (often an upload, e.g. a sketch or source photo).'),
|
|
375
|
+
after_media_id: z.string().optional().describe('before_after: the "after" item (the result).'),
|
|
376
|
+
caption: z.string().optional().describe('media / before_after: one line on what it shows (max 300 chars).'),
|
|
377
|
+
note: z.string().optional().describe('step: one or two sentences on what this step did and why (max 1000 chars).')
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
server.tool(
|
|
381
|
+
'get_project_story',
|
|
382
|
+
'Read the STORY of a project you own — its public page written as an ordered post (headings, text, media, workflow steps with their real prompts, before/after pairs) — plus `available_media`: every item the story may use (this project\'s generated results and the owner\'s own uploads), with media_id, type, prompt and model. Call this FIRST before writing or editing a story: you need the `version` (pass it back as `base_version`) and the media ids. Also returns whether the project is published and its listing status.',
|
|
383
|
+
{ project_id: z.string().describe('ObjectId of a project you OWN.') },
|
|
384
|
+
async ({ project_id }) => pubText(await client.get(`/v1/projects/${encodeURIComponent(project_id)}/publish/story`))
|
|
385
|
+
);
|
|
386
|
+
|
|
387
|
+
server.tool(
|
|
388
|
+
'update_project_story',
|
|
389
|
+
'REPLACE the story of a project you own (the public page\'s post) with the blocks you pass, in order. Read `get_project_story` first and pass its `version` as `base_version`: if the owner (or another agent) saved in between you get STORY_VERSION_CONFLICT — read again and re-apply. Blocks reference media by media_id from `available_media`; to use a NEW image or video, put it in the project first (`upload_media` with `project_id`, or generate with `project_id`). A `step` shows the generation\'s real prompt and model automatically — never retype them. Invalid blocks come back as `errors` with the block `index`; nothing is saved until all are valid. `warnings` are advice (missing captions, no steps). Good structure: hero media → short intro → "How it was made" heading → 3-8 steps in order → before/after where an upload became a result → one closing line. If the project is published the change is live at once, so confirm with the user before replacing a story they wrote.',
|
|
390
|
+
{
|
|
391
|
+
project_id: z.string().describe('ObjectId of a project you OWN.'),
|
|
392
|
+
blocks: z.array(storyBlock).describe('The whole story, in order (max 60 blocks). An empty array clears it.'),
|
|
393
|
+
base_version: z.number().optional().describe('The `version` from get_project_story. Strongly recommended — without it you overwrite whatever is there.')
|
|
394
|
+
},
|
|
395
|
+
async ({ project_id, blocks, base_version }) => pubText(await client.put(
|
|
396
|
+
`/v1/projects/${encodeURIComponent(project_id)}/publish/story`,
|
|
397
|
+
{ blocks, ...(base_version !== undefined ? { base_version } : {}) }
|
|
398
|
+
), 'Saved. The project page shows it now if the project is published (get_project_publication for the url).')
|
|
399
|
+
);
|
|
400
|
+
|
|
401
|
+
server.tool(
|
|
402
|
+
'draft_project_story',
|
|
403
|
+
'Ask Kolbo to DRAFT a story for a project you own, by analysing the project\'s own media (prompts, models, sessions, which generation used which upload). Takes up to about a minute. Returns the draft `blocks` WITHOUT saving them — review or edit them, then save with `update_project_story`. Fails with STORY_DRAFT_UNAVAILABLE when the project has no generated media yet.',
|
|
404
|
+
{ project_id: z.string().describe('ObjectId of a project you OWN.') },
|
|
405
|
+
async ({ project_id }) => pubText(
|
|
406
|
+
await client.post(`/v1/projects/${encodeURIComponent(project_id)}/publish/story/draft`, {}),
|
|
407
|
+
'Not saved yet. Edit if needed, then call update_project_story with these blocks and the version from get_project_story.'
|
|
408
|
+
)
|
|
409
|
+
);
|
|
410
|
+
|
|
411
|
+
server.tool(
|
|
412
|
+
'get_project_page_insights',
|
|
413
|
+
'Visitor analytics for the PUBLIC PAGE of a project you own (its "Page insights"): visitors, visits, average ACTIVE time (tab visible and in use), how many reached the story, scroll depth, clicks (media opened, recipes opened, project video played, "Use this project"), copies made, SIGN-UPS (new Kolbo accounts whose first visit was this page) with conversion rates, where visitors came from, countries, devices, a per-day series and the most-opened media. Anonymous first-party counts: no personal data, bots and the owner\'s own visits excluded, visitors deduped per day. Use it to tell the owner what works on their page (e.g. which step gets opened most) before editing the story.',
|
|
414
|
+
{
|
|
415
|
+
project_id: z.string().describe('ObjectId of a project you OWN.'),
|
|
416
|
+
days: z.union([z.literal(7), z.literal(30), z.literal(90)]).optional().describe('Window in days: 7, 30 (default) or 90.')
|
|
417
|
+
},
|
|
418
|
+
async ({ project_id, days }) => {
|
|
419
|
+
const qs = days ? `days=${days}` : '';
|
|
420
|
+
return pubText(await client.get(`/v1/projects/${encodeURIComponent(project_id)}/publish/insights${qs ? '?' + qs : ''}`));
|
|
421
|
+
}
|
|
422
|
+
);
|
|
423
|
+
|
|
366
424
|
server.tool(
|
|
367
425
|
'remove_project_hero_video',
|
|
368
426
|
'Clear the hero video of a published project (the page falls back to a mosaic of the project\'s stills). The video file itself stays in the project\'s media.',
|