@writepanda/mcp 1.265.0 → 1.269.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/bin/server.mjs +88 -9
- package/package.json +1 -1
package/bin/server.mjs
CHANGED
|
@@ -1739,7 +1739,7 @@ const TOOLS = [
|
|
|
1739
1739
|
{
|
|
1740
1740
|
name: "project_edit_summary",
|
|
1741
1741
|
description:
|
|
1742
|
-
"What the edit contains now: lengths (editedDurationMs, sourceDurationMs, removedMs cut or sped up), counts (cuts, zooms, motionElements, graphics, transitions, brollBeats, mediaOverlays, captions { on, template }, audio { narration, music, soundEffects }, ...) and highlights[] (plain lines). Cheap; use it to report an editing pass instead of project_read.",
|
|
1742
|
+
"What the edit contains now: lengths (editedDurationMs, sourceDurationMs, removedMs cut or sped up), counts (cuts, zooms, motionElements, graphics, transitions, brollBeats, mediaOverlays, captions { on, template }, audio { narration, music, soundEffects }, voiceEnhancedClips vs loudnessNormalizedClips, ...) and highlights[] (plain lines). Each recording counts once, so splits change neither source length nor cuts. Cheap; use it to report an editing pass instead of project_read.",
|
|
1743
1743
|
inputSchema: {
|
|
1744
1744
|
type: "object",
|
|
1745
1745
|
properties: {
|
|
@@ -3576,6 +3576,35 @@ const TOOLS = [
|
|
|
3576
3576
|
},
|
|
3577
3577
|
command: "project.add-spotlight",
|
|
3578
3578
|
},
|
|
3579
|
+
{
|
|
3580
|
+
name: "project_set_speaker_background",
|
|
3581
|
+
description:
|
|
3582
|
+
"The speaker's background for the WHOLE video as one look: blur, remove (wallpaper shows; outline on by default), image (studio plate) or none. Replaces the previous whole-video background instead of stacking; partial background-effect regions stay. Camera footage. For one stretch use project_add_background_effect.",
|
|
3583
|
+
inputSchema: {
|
|
3584
|
+
type: "object",
|
|
3585
|
+
properties: {
|
|
3586
|
+
id: { type: "string" },
|
|
3587
|
+
path: { type: "string" },
|
|
3588
|
+
mode: { type: "string", enum: ["none", "blur", "remove", "image"] },
|
|
3589
|
+
strength: { type: "number", description: "blur: 1-120, default 18." },
|
|
3590
|
+
backgroundImage: {
|
|
3591
|
+
type: "string",
|
|
3592
|
+
description:
|
|
3593
|
+
"image: warm-creator, tech-rgb, neutral-grey, podcast-warm, daylight-airy, gradient-gel, cinematic-dark, or an image path.",
|
|
3594
|
+
},
|
|
3595
|
+
outline: {
|
|
3596
|
+
type: "boolean",
|
|
3597
|
+
description: "Keyline around the cutout (on by default for remove).",
|
|
3598
|
+
},
|
|
3599
|
+
outlineWidth: { type: "number" },
|
|
3600
|
+
outlineColor: { type: "string" },
|
|
3601
|
+
outlineShadow: { type: "boolean" },
|
|
3602
|
+
expectedRevision: { type: "number" },
|
|
3603
|
+
},
|
|
3604
|
+
required: ["mode"],
|
|
3605
|
+
},
|
|
3606
|
+
command: "project.set-speaker-background",
|
|
3607
|
+
},
|
|
3579
3608
|
{
|
|
3580
3609
|
name: "project_add_background_effect",
|
|
3581
3610
|
description:
|
|
@@ -4475,7 +4504,7 @@ const TOOLS = [
|
|
|
4475
4504
|
{
|
|
4476
4505
|
name: "project_center_camera_on_face",
|
|
4477
4506
|
description:
|
|
4478
|
-
"Keep the presenter's face centred in
|
|
4507
|
+
"Keep the presenter's face centred in a SEPARATE camera card by tracking it (can take a minute). Not for the main video: face-tracked zooms on the main video are project_auto_reframe. On a podcast clip it tracks every participant's camera so their tiles (pair, grid, screen-share strip) centre on each face (the editor also does this in the background when a podcast opens; a set-podcast-source-crop framing wins). clear: true turns it off. Concurrent saves are merged and retried (three attempts). Exhausted conflicts report code revision_conflict / status 409 (job.errorDetails for async jobs).",
|
|
4479
4508
|
inputSchema: {
|
|
4480
4509
|
type: "object",
|
|
4481
4510
|
properties: {
|
|
@@ -4714,7 +4743,7 @@ const TOOLS = [
|
|
|
4714
4743
|
{
|
|
4715
4744
|
name: "project_auto_reframe",
|
|
4716
4745
|
description:
|
|
4717
|
-
"Active-speaker auto-reframe
|
|
4746
|
+
"Active-speaker auto-reframe: frames whoever talks, shot by shot (face tracking, no speaker IDs needed). Landscape footage on a vertical / square canvas gets a crop that follows the speaker; footage that already has the canvas shape (a 16:9 wide of two hosts in a 16:9 video) gets a punch-in on the speaker inside the frame, which is also how to get face-tracked zooms on the main video. zoom = fixed punch-in. split=true stacks two people (podcast / interview wide) one above the other on a 9:16 canvas. Slow (minutes). clear reverts. Concurrent saves are merged and retried (three attempts). Exhausted conflicts report code revision_conflict / status 409 (job.errorDetails for async jobs).",
|
|
4718
4747
|
inputSchema: {
|
|
4719
4748
|
type: "object",
|
|
4720
4749
|
properties: {
|
|
@@ -5964,6 +5993,30 @@ const TOOLS = [
|
|
|
5964
5993
|
},
|
|
5965
5994
|
command: "caption.set-style",
|
|
5966
5995
|
},
|
|
5996
|
+
{
|
|
5997
|
+
name: "caption_set_look",
|
|
5998
|
+
description:
|
|
5999
|
+
"Set a COMPLETE caption look in one call, replacing the current one: on/off, template, words per line, position and every override (in style). What the look leaves out goes back to the template's own, never what an earlier style left. How a recipe's captions are applied; use it to copy a look exactly. For one tweak use caption_set_style.",
|
|
6000
|
+
inputSchema: {
|
|
6001
|
+
type: "object",
|
|
6002
|
+
properties: {
|
|
6003
|
+
id: { type: "string" },
|
|
6004
|
+
path: { type: "string" },
|
|
6005
|
+
enabled: { type: "boolean" },
|
|
6006
|
+
templateId: { type: "string", description: "A caption_set_template id." },
|
|
6007
|
+
wordsPerLine: { type: "number", description: "1-10. Default the template's own." },
|
|
6008
|
+
positionY: { type: "number", description: "% from the top. Default the project's." },
|
|
6009
|
+
style: {
|
|
6010
|
+
type: "object",
|
|
6011
|
+
description:
|
|
6012
|
+
"caption_set_style's look fields: fontFamily, fontSize, color, backgroundColor, highlightColor, highlightBackgroundColor, strokeColor, strokeWidth, uppercase, highlightMode, emphasisColor, emphasisBackgroundColor, emphasisScale, emphasisItalic, emphasisFontFamily, boxRotation.",
|
|
6013
|
+
},
|
|
6014
|
+
expectedRevision: { type: "number" },
|
|
6015
|
+
},
|
|
6016
|
+
required: ["enabled"],
|
|
6017
|
+
},
|
|
6018
|
+
command: "caption.set-look",
|
|
6019
|
+
},
|
|
5967
6020
|
{
|
|
5968
6021
|
name: "caption_mark_emphasis",
|
|
5969
6022
|
description:
|
|
@@ -6157,17 +6210,20 @@ const TOOLS = [
|
|
|
6157
6210
|
properties: {
|
|
6158
6211
|
script: {
|
|
6159
6212
|
type: "string",
|
|
6160
|
-
description:
|
|
6213
|
+
description:
|
|
6214
|
+
"What the user will read, plain text (no markdown or stage directions), up to 20,000 characters.",
|
|
6161
6215
|
},
|
|
6162
6216
|
mode: {
|
|
6163
6217
|
type: "string",
|
|
6164
6218
|
enum: ["camera", "screen", "both"],
|
|
6165
|
-
description:
|
|
6219
|
+
description:
|
|
6220
|
+
"camera (solo; default with a script), screen (screen only), or both (screen + camera bubble; default without a script).",
|
|
6166
6221
|
},
|
|
6167
6222
|
orientation: {
|
|
6168
6223
|
type: "string",
|
|
6169
6224
|
enum: ["landscape", "portrait"],
|
|
6170
|
-
description:
|
|
6225
|
+
description:
|
|
6226
|
+
"landscape 16:9 (YouTube) or portrait 9:16 (Shorts, Reels, TikTok): the camera shape for a camera take; a screen take's final shape is set while editing.",
|
|
6171
6227
|
},
|
|
6172
6228
|
speed: { type: "number", description: "Teleprompter scroll speed 0.25-3." },
|
|
6173
6229
|
fontSize: { type: "number", description: "Teleprompter text size in px, 16-72." },
|
|
@@ -7439,7 +7495,7 @@ const TOOLS = [
|
|
|
7439
7495
|
{
|
|
7440
7496
|
name: "recipe_apply_style",
|
|
7441
7497
|
description:
|
|
7442
|
-
"Apply a recipe's fixed style to a project, before recipe_render's content work. Returns { applied, failed, pending, notes }: applied / failed are read back from the project, notes = parts left to you. Fails, changing nothing, when the recipe needs footage the project lacks (a camera recipe on an audio-only project).",
|
|
7498
|
+
"Apply a recipe's fixed style to a project, before recipe_render's content work: aspect, the full caption look, speaker background, vertical framing, grade, camera layout. It REPLACES an earlier recipe's look. Returns { applied, failed, pending, notes }: applied / failed are read back from the project, notes = parts left to you. Fails, changing nothing, when the recipe needs footage the project lacks (a camera recipe on an audio-only project).",
|
|
7443
7499
|
inputSchema: {
|
|
7444
7500
|
type: "object",
|
|
7445
7501
|
properties: {
|
|
@@ -7452,6 +7508,17 @@ const TOOLS = [
|
|
|
7452
7508
|
},
|
|
7453
7509
|
command: "recipe.apply-style",
|
|
7454
7510
|
},
|
|
7511
|
+
{
|
|
7512
|
+
name: "recipe_look_frames",
|
|
7513
|
+
description:
|
|
7514
|
+
"The recipe's target look as images (attached): stills of its finished edit at key moments, each with what it shows. Look before editing with a recipe; compare project_render_frame at the matching beats before saying done. Match the look, never the content.",
|
|
7515
|
+
inputSchema: {
|
|
7516
|
+
type: "object",
|
|
7517
|
+
properties: { id: { type: "string", description: "Recipe id." } },
|
|
7518
|
+
required: ["id"],
|
|
7519
|
+
},
|
|
7520
|
+
command: "recipe.look-frames",
|
|
7521
|
+
},
|
|
7455
7522
|
{
|
|
7456
7523
|
name: "recipe_save",
|
|
7457
7524
|
description:
|
|
@@ -7462,7 +7529,7 @@ const TOOLS = [
|
|
|
7462
7529
|
recipe: {
|
|
7463
7530
|
type: "object",
|
|
7464
7531
|
description:
|
|
7465
|
-
"{ id?, title, description, category, footage?, aspectRatio?, fields: [{ key, label, type: text|longtext|select|color|images, default?, options?, required?, help?, minCount?, maxCount?, optional? }], prompt, style?: { aspectRatio?, colorCorrection?, lut?: { preset, intensity? },
|
|
7532
|
+
"{ id?, title, description, category, footage?, aspectRatio?, fields: [{ key, label, type: text|longtext|select|color|images, default?, options?, required?, help?, minCount?, maxCount?, optional? }], prompt, lookFrames?: [{ src: absolute image path, shows: what it shows (position, size, colours), atMs? }] (up to 8 stills of the target look; copied into the recipe), style?: { aspectRatio?, colorCorrection?, lut?: { preset, intensity? }, speakerBackground?: { mode: none|blur|remove|image, image?, strength?, outline?: { enabled, width?, color?, shadow? } }, framing?: { shortsLayout: full|camera-corner }, cameraLayout?, captions?: { enabled, templateId?, wordsPerLine?, positionY?, style?: caption_set_look's style }, broll?: { use: none|ask|generate|user-images, layout?: full|split|card, notes? }, graphics?: { family?, titleFont?, bodyFont?, accentColor?, textColor?, surfaceColor?, notes? }, wallpaper? }, checklist: string[] }. Put the WHOLE look in style (every caption value, the background, framing, B-roll rule, title fonts and colours): it is applied exactly, the prompt only covers what depends on the footage.",
|
|
7466
7533
|
},
|
|
7467
7534
|
},
|
|
7468
7535
|
required: ["recipe"],
|
|
@@ -9049,10 +9116,16 @@ server.setRequestHandler(CallToolRequestSchema, async (request, extra) => {
|
|
|
9049
9116
|
for (const previewPath of previews) {
|
|
9050
9117
|
const fs = await import("node:fs/promises");
|
|
9051
9118
|
const buf = await fs.readFile(previewPath);
|
|
9119
|
+
const ext = previewPath.toLowerCase().split(".").pop();
|
|
9052
9120
|
content.push({
|
|
9053
9121
|
type: "image",
|
|
9054
9122
|
data: buf.toString("base64"),
|
|
9055
|
-
mimeType:
|
|
9123
|
+
mimeType:
|
|
9124
|
+
ext === "jpg" || ext === "jpeg"
|
|
9125
|
+
? "image/jpeg"
|
|
9126
|
+
: ext === "webp"
|
|
9127
|
+
? "image/webp"
|
|
9128
|
+
: "image/png",
|
|
9056
9129
|
});
|
|
9057
9130
|
}
|
|
9058
9131
|
} catch (imgErr) {
|
|
@@ -9113,6 +9186,12 @@ function collectInlinePreviewPaths(command, data) {
|
|
|
9113
9186
|
if (command === "motion.screenshot") {
|
|
9114
9187
|
return typeof data.previewPath === "string" ? [data.previewPath] : [];
|
|
9115
9188
|
}
|
|
9189
|
+
if (command === "recipe.look-frames") {
|
|
9190
|
+
const frames = Array.isArray(data.frames) ? data.frames : [];
|
|
9191
|
+
return frames
|
|
9192
|
+
.map((f) => (f && typeof f.path === "string" ? f.path : null))
|
|
9193
|
+
.filter((p) => p !== null);
|
|
9194
|
+
}
|
|
9116
9195
|
if (command === "motion.verify-frames") {
|
|
9117
9196
|
const frames = Array.isArray(data.frames) ? data.frames : [];
|
|
9118
9197
|
return frames
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@writepanda/mcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.269.0",
|
|
4
4
|
"description": "Model Context Protocol server for PandaStudio. Exposes the desktop video editor's automation surface to Cursor, Continue, Cline, Claude Desktop, and any MCP-compliant client.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pandastudio",
|