@vibeframe/mcp-server 0.109.1 → 0.110.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 +15 -0
- package/dist/index.js +134 -16
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -125,6 +125,21 @@ Claude Code drives `vibe` natively via shell + the scaffolded `AGENTS.md` / `CLA
|
|
|
125
125
|
claude mcp add vibeframe --scope project -- npx -y @vibeframe/mcp-server
|
|
126
126
|
```
|
|
127
127
|
|
|
128
|
+
## Human-in-the-Loop Choices
|
|
129
|
+
|
|
130
|
+
The server prefers asking over silently picking defaults:
|
|
131
|
+
|
|
132
|
+
- On hosts that support **MCP elicitation** (Claude Code 2.1.76+), the `build`
|
|
133
|
+
tool opens a native form before the build starts for any choice the call
|
|
134
|
+
left unspecified: narration provider (Kokoro free/local vs ElevenLabs),
|
|
135
|
+
backdrop image generation (skip vs paid OpenAI), and a max cost cap.
|
|
136
|
+
Declining cancels the build before any provider spend. Set
|
|
137
|
+
`VIBE_MCP_ELICIT=off` in the server env to disable the form (headless and
|
|
138
|
+
automation setups).
|
|
139
|
+
- On hosts without elicitation (Claude Desktop today), the server
|
|
140
|
+
instructions tell the agent to present the same choices in chat and wait
|
|
141
|
+
for your answer.
|
|
142
|
+
|
|
128
143
|
## What You Can Do
|
|
129
144
|
|
|
130
145
|
Once connected, your MCP host can resolve prompts like these into typed tool calls:
|
package/dist/index.js
CHANGED
|
@@ -469537,6 +469537,7 @@ function isComposerProvider(value) {
|
|
|
469537
469537
|
return value === "claude" || value === "openai" || value === "gemini";
|
|
469538
469538
|
}
|
|
469539
469539
|
function resolveComposer(explicit) {
|
|
469540
|
+
loadEnv();
|
|
469540
469541
|
if (explicit) {
|
|
469541
469542
|
const key2 = readKey(explicit);
|
|
469542
469543
|
if (!key2) {
|
|
@@ -469561,6 +469562,7 @@ var ENV_VAR, PROVIDER_LABEL, ComposerResolveError;
|
|
|
469561
469562
|
var init_composer_resolve = __esm({
|
|
469562
469563
|
"../cli/src/commands/_shared/composer-resolve.ts"() {
|
|
469563
469564
|
"use strict";
|
|
469565
|
+
init_api_key();
|
|
469564
469566
|
ENV_VAR = {
|
|
469565
469567
|
claude: "ANTHROPIC_API_KEY",
|
|
469566
469568
|
openai: "OPENAI_API_KEY",
|
|
@@ -486484,6 +486486,76 @@ function pickOutputPath(data) {
|
|
|
486484
486486
|
return typeof candidate === "string" ? candidate : void 0;
|
|
486485
486487
|
}
|
|
486486
486488
|
|
|
486489
|
+
// ../cli/src/tools/_shared/elicit.ts
|
|
486490
|
+
var NARRATION_CHOICES = ["kokoro", "elevenlabs"];
|
|
486491
|
+
var BACKDROP_CHOICES = ["skip", "openai"];
|
|
486492
|
+
function planBuildElicitation(args) {
|
|
486493
|
+
const assetsWillRun = args.stage === void 0 || args.stage === "all" || args.stage === "assets";
|
|
486494
|
+
if (!assetsWillRun) return null;
|
|
486495
|
+
const properties = {};
|
|
486496
|
+
const required = [];
|
|
486497
|
+
const narrationUndecided = !args.skipNarration && (args.ttsProvider === void 0 || args.ttsProvider === "auto");
|
|
486498
|
+
if (narrationUndecided) {
|
|
486499
|
+
properties.narration = {
|
|
486500
|
+
type: "string",
|
|
486501
|
+
title: "Narration voice-over",
|
|
486502
|
+
description: "Which TTS engine narrates the video?",
|
|
486503
|
+
enum: [...NARRATION_CHOICES],
|
|
486504
|
+
enumNames: [
|
|
486505
|
+
"Kokoro \u2014 free, runs locally on this machine",
|
|
486506
|
+
"ElevenLabs \u2014 cloud TTS, uses your ElevenLabs credits"
|
|
486507
|
+
]
|
|
486508
|
+
};
|
|
486509
|
+
required.push("narration");
|
|
486510
|
+
}
|
|
486511
|
+
if (args.skipBackdrop === void 0 && args.imageProvider === void 0) {
|
|
486512
|
+
properties.backdrop_images = {
|
|
486513
|
+
type: "string",
|
|
486514
|
+
title: "Backdrop images",
|
|
486515
|
+
description: "Generate AI background images for each scene?",
|
|
486516
|
+
enum: [...BACKDROP_CHOICES],
|
|
486517
|
+
enumNames: [
|
|
486518
|
+
"Skip \u2014 free, pure typographic scenes",
|
|
486519
|
+
"OpenAI \u2014 paid image generation (roughly $1-3 per video)"
|
|
486520
|
+
]
|
|
486521
|
+
};
|
|
486522
|
+
required.push("backdrop_images");
|
|
486523
|
+
}
|
|
486524
|
+
if (args.maxCostUsd === void 0) {
|
|
486525
|
+
properties.max_cost_usd = {
|
|
486526
|
+
type: "number",
|
|
486527
|
+
title: "Max provider spend (USD)",
|
|
486528
|
+
description: "Abort before any paid provider call when the estimate exceeds this cap. Leave empty for no cap.",
|
|
486529
|
+
minimum: 0
|
|
486530
|
+
};
|
|
486531
|
+
}
|
|
486532
|
+
if (Object.keys(properties).length === 0) return null;
|
|
486533
|
+
return {
|
|
486534
|
+
message: "VibeFrame is about to build this video. Choose how the assets are generated:",
|
|
486535
|
+
requestedSchema: { type: "object", properties, required }
|
|
486536
|
+
};
|
|
486537
|
+
}
|
|
486538
|
+
function applyElicitationAnswers(args, content) {
|
|
486539
|
+
if (!content) return args;
|
|
486540
|
+
const next = { ...args };
|
|
486541
|
+
const narration = content.narration;
|
|
486542
|
+
if (typeof narration === "string" && NARRATION_CHOICES.includes(narration)) {
|
|
486543
|
+
next.ttsProvider = narration;
|
|
486544
|
+
}
|
|
486545
|
+
const backdrop = content.backdrop_images;
|
|
486546
|
+
if (backdrop === "skip") {
|
|
486547
|
+
next.skipBackdrop = true;
|
|
486548
|
+
} else if (backdrop === "openai") {
|
|
486549
|
+
next.skipBackdrop = false;
|
|
486550
|
+
next.imageProvider = "openai";
|
|
486551
|
+
}
|
|
486552
|
+
const cap = content.max_cost_usd;
|
|
486553
|
+
if (typeof cap === "number" && Number.isFinite(cap) && cap >= 0) {
|
|
486554
|
+
next.maxCostUsd = cap;
|
|
486555
|
+
}
|
|
486556
|
+
return next;
|
|
486557
|
+
}
|
|
486558
|
+
|
|
486487
486559
|
// ../cli/src/commands/_shared/visual-styles.ts
|
|
486488
486560
|
var STYLES = [
|
|
486489
486561
|
{
|
|
@@ -488722,9 +488794,32 @@ var sceneBuildTool = defineTool({
|
|
|
488722
488794
|
name: "build",
|
|
488723
488795
|
category: "scene",
|
|
488724
488796
|
cost: "high",
|
|
488725
|
-
description: "v0.60 one-shot orchestrator: read STORYBOARD.md per-beat YAML cues (narration / backdrop / duration), dispatch TTS + image generation per beat, compose scene HTML via the compose-scenes-with-skills pipeline, then render to MP4. Use this instead of chaining init + scene_add + render manually. Caches by SHA256 of (DESIGN.md + cue body) so re-runs are idempotent and cheap. Long runs: over MCP, calls exceeding ~45s return immediately with { promoted: true, jobId, status: 'running' } \u2014 poll status_job every 15-30s until completed/failed instead of re-invoking build. Emits MCP progress notifications when the client supplies a progressToken.",
|
|
488797
|
+
description: "v0.60 one-shot orchestrator: read STORYBOARD.md per-beat YAML cues (narration / backdrop / duration), dispatch TTS + image generation per beat, compose scene HTML via the compose-scenes-with-skills pipeline, then render to MP4. Use this instead of chaining init + scene_add + render manually. Caches by SHA256 of (DESIGN.md + cue body) so re-runs are idempotent and cheap. Long runs: over MCP, calls exceeding ~45s return immediately with { promoted: true, jobId, status: 'running' } \u2014 poll status_job every 15-30s until completed/failed instead of re-invoking build. Emits MCP progress notifications when the client supplies a progressToken. When the MCP host supports elicitation, unspecified asset choices (narration provider, backdrop images, cost cap) are confirmed with the user via a form before the build starts.",
|
|
488726
488798
|
schema: sceneBuildSchema,
|
|
488727
488799
|
async execute(args, ctx) {
|
|
488800
|
+
let warnings;
|
|
488801
|
+
if (ctx.surface === "mcp" && ctx.elicit) {
|
|
488802
|
+
const form = planBuildElicitation(args);
|
|
488803
|
+
if (form) {
|
|
488804
|
+
const outcome = await ctx.elicit(form).catch(() => null);
|
|
488805
|
+
if (outcome === null) {
|
|
488806
|
+
warnings = ["Asset-choice elicitation failed or timed out; proceeding with defaults."];
|
|
488807
|
+
} else if (outcome.action === "accept") {
|
|
488808
|
+
args = applyElicitationAnswers(args, outcome.content);
|
|
488809
|
+
} else {
|
|
488810
|
+
return {
|
|
488811
|
+
success: false,
|
|
488812
|
+
error: "Build cancelled \u2014 the user declined the asset choices.",
|
|
488813
|
+
data: {
|
|
488814
|
+
cancelled: true,
|
|
488815
|
+
retryWith: [
|
|
488816
|
+
`build { projectDir: "${args.projectDir ?? "."}", ttsProvider: "kokoro", skipBackdrop: true }`
|
|
488817
|
+
]
|
|
488818
|
+
}
|
|
488819
|
+
};
|
|
488820
|
+
}
|
|
488821
|
+
}
|
|
488822
|
+
}
|
|
488728
488823
|
const projectDir = args.projectDir ? resolve34(ctx.workingDirectory, args.projectDir) : ctx.workingDirectory;
|
|
488729
488824
|
const runBuild = (report) => executeSceneBuild({
|
|
488730
488825
|
projectDir,
|
|
@@ -488752,7 +488847,9 @@ var sceneBuildTool = defineTool({
|
|
|
488752
488847
|
ctx.onProgress?.({ message: update2.message ?? update2.stage });
|
|
488753
488848
|
report(update2);
|
|
488754
488849
|
}
|
|
488755
|
-
}).then(mapBuildResultToToolResult)
|
|
488850
|
+
}).then(mapBuildResultToToolResult).then(
|
|
488851
|
+
(result) => warnings === void 0 ? result : { ...result, data: { ...result.data, elicitationWarnings: warnings } }
|
|
488852
|
+
);
|
|
488756
488853
|
if (ctx.surface !== "mcp") {
|
|
488757
488854
|
return runBuild(() => void 0);
|
|
488758
488855
|
}
|
|
@@ -497250,7 +497347,8 @@ function buildMcpDispatcher(manifest2) {
|
|
|
497250
497347
|
() => tool.execute(parsed.data, {
|
|
497251
497348
|
workingDirectory: process.cwd(),
|
|
497252
497349
|
surface: "mcp",
|
|
497253
|
-
...extra?.onProgress ? { onProgress: sink.send } : {}
|
|
497350
|
+
...extra?.onProgress ? { onProgress: sink.send } : {},
|
|
497351
|
+
...extra?.elicit ? { elicit: extra.elicit } : {}
|
|
497254
497352
|
})
|
|
497255
497353
|
);
|
|
497256
497354
|
const text = result.success ? JSON.stringify({ success: true, ...result.data }) : result.data ? JSON.stringify({
|
|
@@ -497745,10 +497843,22 @@ function buildServerInstructions(cwd = resolveServerWorkspaceRoot()) {
|
|
|
497745
497843
|
"For args named dir, projectDir, output, videoPath, or source, prefer workspace-relative paths unless the user explicitly provides an absolute path.",
|
|
497746
497844
|
"When creating projects with init, use a project name or workspace-relative path under the workspace root.",
|
|
497747
497845
|
"Do not create projects in /tmp, /home/claude, /workspace, or other synthetic roots unless the user explicitly asks.",
|
|
497748
|
-
"Before high or very-high cost provider work, run a dry-run or plan when available and ask the user to confirm provider spend."
|
|
497846
|
+
"Before high or very-high cost provider work, run a dry-run or plan when available and ask the user to confirm provider spend.",
|
|
497847
|
+
"When the user's request leaves them unspecified, ask the user before building instead of silently picking defaults: narration provider (kokoro = free local, elevenlabs = cloud credits), backdrop image generation (paid; skipping is free), and visual style (list options via scene_list_styles). Present the choices and wait for the answer."
|
|
497749
497848
|
].join("\n");
|
|
497750
497849
|
}
|
|
497751
497850
|
|
|
497851
|
+
// src/elicit.ts
|
|
497852
|
+
var ELICIT_TIMEOUT_MS = 6e5;
|
|
497853
|
+
function makeElicitFn(server3, env4 = process.env) {
|
|
497854
|
+
if ((env4.VIBE_MCP_ELICIT ?? "").toLowerCase() === "off") return void 0;
|
|
497855
|
+
if (!server3.getClientCapabilities()?.elicitation) return void 0;
|
|
497856
|
+
return (form) => server3.elicitInput(
|
|
497857
|
+
{ mode: "form", message: form.message, requestedSchema: form.requestedSchema },
|
|
497858
|
+
{ timeout: ELICIT_TIMEOUT_MS }
|
|
497859
|
+
);
|
|
497860
|
+
}
|
|
497861
|
+
|
|
497752
497862
|
// src/index.ts
|
|
497753
497863
|
console.log = (...args) => console.error(...args);
|
|
497754
497864
|
console.info = (...args) => console.error(...args);
|
|
@@ -497759,7 +497869,7 @@ var server2 = new Server(
|
|
|
497759
497869
|
{
|
|
497760
497870
|
name: "vibeframe",
|
|
497761
497871
|
// Stamped with the package version by build.js at bundle time.
|
|
497762
|
-
version: "0.
|
|
497872
|
+
version: "0.110.0"
|
|
497763
497873
|
},
|
|
497764
497874
|
{
|
|
497765
497875
|
capabilities: {
|
|
@@ -497776,20 +497886,28 @@ server2.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
497776
497886
|
server2.setRequestHandler(CallToolRequestSchema, async (request5, extra) => {
|
|
497777
497887
|
const { name, arguments: args } = request5.params;
|
|
497778
497888
|
const progressToken = request5.params._meta?.progressToken;
|
|
497889
|
+
const elicit = makeElicitFn(server2);
|
|
497779
497890
|
return handleToolCall(
|
|
497780
497891
|
name,
|
|
497781
497892
|
args || {},
|
|
497782
|
-
progressToken === void 0 ? void 0 : {
|
|
497783
|
-
|
|
497784
|
-
|
|
497785
|
-
|
|
497786
|
-
|
|
497787
|
-
|
|
497788
|
-
|
|
497789
|
-
|
|
497790
|
-
|
|
497791
|
-
|
|
497792
|
-
|
|
497893
|
+
progressToken === void 0 && elicit === void 0 ? void 0 : {
|
|
497894
|
+
...elicit ? { elicit } : {},
|
|
497895
|
+
...progressToken === void 0 ? {} : {
|
|
497896
|
+
onProgress: ({
|
|
497897
|
+
progress,
|
|
497898
|
+
total,
|
|
497899
|
+
message
|
|
497900
|
+
}) => {
|
|
497901
|
+
void extra.sendNotification({
|
|
497902
|
+
method: "notifications/progress",
|
|
497903
|
+
params: {
|
|
497904
|
+
progressToken,
|
|
497905
|
+
progress: progress ?? 0,
|
|
497906
|
+
...total !== void 0 ? { total } : {},
|
|
497907
|
+
...message ? { message } : {}
|
|
497908
|
+
}
|
|
497909
|
+
}).catch(() => void 0);
|
|
497910
|
+
}
|
|
497793
497911
|
}
|
|
497794
497912
|
}
|
|
497795
497913
|
);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vibeframe/mcp-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.110.0",
|
|
4
4
|
"description": "VibeFrame MCP Server - AI-native video editing via Model Context Protocol",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -60,8 +60,8 @@
|
|
|
60
60
|
"tsx": "^4.21.0",
|
|
61
61
|
"typescript": "^5.3.3",
|
|
62
62
|
"vitest": "^1.2.2",
|
|
63
|
-
"@vibeframe/
|
|
64
|
-
"@vibeframe/
|
|
63
|
+
"@vibeframe/core": "0.110.0",
|
|
64
|
+
"@vibeframe/cli": "0.110.0"
|
|
65
65
|
},
|
|
66
66
|
"engines": {
|
|
67
67
|
"node": ">=20"
|