@writepanda/mcp 1.275.0 → 1.284.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 +161 -12
- package/package.json +1 -1
package/bin/server.mjs
CHANGED
|
@@ -53,7 +53,6 @@ import {
|
|
|
53
53
|
IN_APP_UNAVAILABLE,
|
|
54
54
|
isInAppCaller,
|
|
55
55
|
} from "./appConnection.mjs";
|
|
56
|
-
import { frameUntrusted } from "./untrusted.mjs";
|
|
57
56
|
import {
|
|
58
57
|
APP_TOOLS,
|
|
59
58
|
clientSupportsUi,
|
|
@@ -63,6 +62,7 @@ import {
|
|
|
63
62
|
toolUiMeta,
|
|
64
63
|
} from "./apps/index.mjs";
|
|
65
64
|
import { portableSchema } from "./portableSchema.mjs";
|
|
65
|
+
import { frameUntrusted } from "./untrusted.mjs";
|
|
66
66
|
|
|
67
67
|
// ── Credentials + transport ───────────────────────────────────────────
|
|
68
68
|
//
|
|
@@ -1032,7 +1032,7 @@ const TOOLS = [
|
|
|
1032
1032
|
{
|
|
1033
1033
|
name: "connector_list",
|
|
1034
1034
|
description:
|
|
1035
|
-
'List MCP connectors and their state. If the one needed isn\'t connected, tell the user its howToConnect line; you cannot connect connectors. status "connected, last check failed" (connected:false, lastCheck with reason, host and fix) means PandaStudio\'s own last use of it failed. needsReconnect:true (state needs_auth, status "needs sign-in again", HTTP 401) = the service refused its sign-in (e.g. a stale Replicate API token): nothing on it runs until the user presses Reconnect in Settings; relay howToConnect, don\'t retry. auth "api-key" + needsKey: the user must paste a key in Settings (never ask for it in chat).',
|
|
1035
|
+
'List MCP connectors and their state. If the one needed isn\'t connected, tell the user its howToConnect line; you cannot connect connectors. status "connected, last check failed" (connected:false, lastCheck with reason, host and fix) means PandaStudio\'s own last use of it failed. needsReconnect:true (state needs_auth, status "needs sign-in again", HTTP 401) = the service refused its sign-in (e.g. a stale Replicate API token): nothing on it runs until the user presses Reconnect in Settings; relay howToConnect, don\'t retry. auth "api-key" + needsKey: the user must paste a key in Settings (never ask for it in chat). native:true (fal): no connector_tools/connector_call; use its usedThrough tools (fal: media_generate_video).',
|
|
1036
1036
|
inputSchema: {
|
|
1037
1037
|
type: "object",
|
|
1038
1038
|
properties: {
|
|
@@ -1648,6 +1648,34 @@ const TOOLS = [
|
|
|
1648
1648
|
},
|
|
1649
1649
|
command: "project.duplicate",
|
|
1650
1650
|
},
|
|
1651
|
+
{
|
|
1652
|
+
name: "project_versions",
|
|
1653
|
+
description:
|
|
1654
|
+
"A project's earlier versions, newest first (a snapshot about every 10 min of editing, kept up to 30 days). For lost edits or 'go back to how it was'. Then project_open_version.",
|
|
1655
|
+
inputSchema: {
|
|
1656
|
+
type: "object",
|
|
1657
|
+
properties: {
|
|
1658
|
+
id: { type: "string" },
|
|
1659
|
+
path: { type: "string" },
|
|
1660
|
+
},
|
|
1661
|
+
},
|
|
1662
|
+
command: "project.versions",
|
|
1663
|
+
},
|
|
1664
|
+
{
|
|
1665
|
+
name: "project_open_version",
|
|
1666
|
+
description:
|
|
1667
|
+
"Bring back an earlier version (from project_versions) as a NEW project beside the original, named '<name> (<date, time>)'. Never changes the original. Returns { id, path, name, savedAt }.",
|
|
1668
|
+
inputSchema: {
|
|
1669
|
+
type: "object",
|
|
1670
|
+
properties: {
|
|
1671
|
+
id: { type: "string" },
|
|
1672
|
+
path: { type: "string" },
|
|
1673
|
+
versionId: { type: "string", description: "From project_versions" },
|
|
1674
|
+
},
|
|
1675
|
+
required: ["versionId"],
|
|
1676
|
+
},
|
|
1677
|
+
command: "project.open-version",
|
|
1678
|
+
},
|
|
1651
1679
|
{
|
|
1652
1680
|
name: "project_locate",
|
|
1653
1681
|
description:
|
|
@@ -3005,6 +3033,11 @@ const TOOLS = [
|
|
|
3005
3033
|
inputSchema: {
|
|
3006
3034
|
type: "object",
|
|
3007
3035
|
properties: {
|
|
3036
|
+
still: {
|
|
3037
|
+
type: "boolean",
|
|
3038
|
+
description:
|
|
3039
|
+
"The graphic is MEANT to hold still (no entrance, no motion): skip the frozen-render check, kept for re-renders. Never fake a slow drift instead.",
|
|
3040
|
+
},
|
|
3008
3041
|
id: { type: "string" },
|
|
3009
3042
|
path: { type: "string" },
|
|
3010
3043
|
overlayId: { type: "string" },
|
|
@@ -4107,10 +4140,31 @@ const TOOLS = [
|
|
|
4107
4140
|
},
|
|
4108
4141
|
command: "project.detect-face",
|
|
4109
4142
|
},
|
|
4143
|
+
{
|
|
4144
|
+
name: "project_review_moment",
|
|
4145
|
+
description:
|
|
4146
|
+
"LOOK AND LISTEN to a moment of the edit as the viewer gets it: a contact sheet of the frames around atMs (edited ms) or wordId, the EXPORTED mix of that stretch transcribed and compared with what the edit should play (extra = leftover of a cut word or line, missing = clipped word), whether each cut lands in quiet or speech, nearby edits and stutters, plus a plain verdict. Use after every cut / pause / insert fix BEFORE telling the user it's fixed, and when the user names a moment ('at 16 seconds'). ASYNC: { jobId }; job_wait.",
|
|
4147
|
+
inputSchema: {
|
|
4148
|
+
type: "object",
|
|
4149
|
+
properties: {
|
|
4150
|
+
id: { type: "string" },
|
|
4151
|
+
path: { type: "string" },
|
|
4152
|
+
atMs: { type: "number", description: "Edited ms at the centre. Or wordId." },
|
|
4153
|
+
wordId: { type: "string", description: "Centre on this word (transcript id or prefix)." },
|
|
4154
|
+
spanMs: {
|
|
4155
|
+
type: "number",
|
|
4156
|
+
description: "Each side of the centre, ms. Default 1500, max 5000.",
|
|
4157
|
+
},
|
|
4158
|
+
frames: { type: "number", description: "Frames on the sheet. Default 12, max 24." },
|
|
4159
|
+
listen: { type: "boolean", description: "Default true; false = frames and edits only." },
|
|
4160
|
+
},
|
|
4161
|
+
},
|
|
4162
|
+
command: "project.review-moment",
|
|
4163
|
+
},
|
|
4110
4164
|
{
|
|
4111
4165
|
name: "project_render_sheet",
|
|
4112
4166
|
description:
|
|
4113
|
-
"Render N frames across an edited-time range into one contact-sheet PNG (row-major). Returns { sheetPath, frames[{atMs, path}] }; sheetPath null = read frames[].path.",
|
|
4167
|
+
"Render N frames across an edited-time range into one contact-sheet PNG (row-major). Returns { sheetPath, frames[{atMs, path}] }; sheetPath null (see sheetWarning) = read frames[].path.",
|
|
4114
4168
|
inputSchema: {
|
|
4115
4169
|
type: "object",
|
|
4116
4170
|
properties: {
|
|
@@ -4128,7 +4182,7 @@ const TOOLS = [
|
|
|
4128
4182
|
{
|
|
4129
4183
|
name: "project_apply_edit_plan",
|
|
4130
4184
|
description:
|
|
4131
|
-
'Apply many trim / zoom / speed ops atomically (any invalid op aborts). Ops: {"op":"add-trim",startMs,endMs} | {"op":"add-zoom",atMs,durationMs,depth?,focusX?,focusY?,soundUrl?,anchorSourceMs?} | {"op":"add-speed",startMs,endMs,speed}.',
|
|
4185
|
+
'Apply many trim / zoom / speed ops atomically (any invalid op aborts). Ops: {"op":"add-trim",startMs,endMs} (SOURCE ms) or by word {"op":"add-trim",afterWordId|fromWordId,beforeWordId|throughWordId}, edges snapped to the audio like project_add_trim | {"op":"add-zoom",atMs,durationMs,depth?,focusX?,focusY?,soundUrl?,anchorSourceMs?} | {"op":"add-speed",startMs,endMs,speed}.',
|
|
4132
4186
|
inputSchema: {
|
|
4133
4187
|
type: "object",
|
|
4134
4188
|
properties: {
|
|
@@ -4348,17 +4402,32 @@ const TOOLS = [
|
|
|
4348
4402
|
},
|
|
4349
4403
|
{
|
|
4350
4404
|
name: "project_add_trim",
|
|
4351
|
-
description:
|
|
4405
|
+
description:
|
|
4406
|
+
"Cut a span the exporter skips. Name the edges by WORD (afterWordId / fromWordId for the start, beforeWordId / throughWordId for the end): no ms maths, no clock mix-ups. Or startMs/endMs in SOURCE ms (a transcript word's sourceStartMs). Every edge snaps to the quietest point nearby without clipping a kept word; result.edges says where each landed and notes say when an edge inside a word cut it. Check the spot with project_review_moment before telling the user it's fixed.",
|
|
4352
4407
|
inputSchema: {
|
|
4353
4408
|
type: "object",
|
|
4354
4409
|
properties: {
|
|
4355
4410
|
id: { type: "string" },
|
|
4356
4411
|
path: { type: "string" },
|
|
4357
|
-
startMs: { type: "number" },
|
|
4358
|
-
endMs: { type: "number" },
|
|
4412
|
+
startMs: { type: "number", description: "SOURCE ms. Or afterWordId / fromWordId." },
|
|
4413
|
+
endMs: { type: "number", description: "SOURCE ms. Or beforeWordId / throughWordId." },
|
|
4414
|
+
afterWordId: {
|
|
4415
|
+
type: "string",
|
|
4416
|
+
description: "Cut STARTS right after this word (kept). Instead of startMs.",
|
|
4417
|
+
},
|
|
4418
|
+
fromWordId: { type: "string", description: "Cut STARTS at this word (cut too)." },
|
|
4419
|
+
beforeWordId: {
|
|
4420
|
+
type: "string",
|
|
4421
|
+
description: "Cut ENDS right before this word (kept). Instead of endMs.",
|
|
4422
|
+
},
|
|
4423
|
+
throughWordId: { type: "string", description: "Cut ENDS after this word (cut too)." },
|
|
4424
|
+
snapToAudio: {
|
|
4425
|
+
type: "boolean",
|
|
4426
|
+
description:
|
|
4427
|
+
"Default true: edges snap to the quietest point nearby without clipping a kept word. false = exact ms.",
|
|
4428
|
+
},
|
|
4359
4429
|
expectedRevision: { type: "number" },
|
|
4360
4430
|
},
|
|
4361
|
-
required: ["startMs", "endMs"],
|
|
4362
4431
|
},
|
|
4363
4432
|
command: "project.add-trim",
|
|
4364
4433
|
},
|
|
@@ -4407,6 +4476,11 @@ const TOOLS = [
|
|
|
4407
4476
|
inputSchema: {
|
|
4408
4477
|
type: "object",
|
|
4409
4478
|
properties: {
|
|
4479
|
+
snapToAudio: {
|
|
4480
|
+
type: "boolean",
|
|
4481
|
+
description:
|
|
4482
|
+
"lane main: default true, each edge snaps to the quietest point nearby without clipping a kept word (result.edges). false = exact.",
|
|
4483
|
+
},
|
|
4410
4484
|
id: { type: "string", description: "Project id (or pass path)." },
|
|
4411
4485
|
path: { type: "string", description: "Project file path (or pass id)." },
|
|
4412
4486
|
startMs: { type: "number", description: "Gap start, edited ms." },
|
|
@@ -4838,10 +4912,25 @@ const TOOLS = [
|
|
|
4838
4912
|
{
|
|
4839
4913
|
name: "project_update_region",
|
|
4840
4914
|
description:
|
|
4841
|
-
"Patch a region; unspecified fields are kept. Put the fields in patch. Every type takes startMs, endMs (edited ms; trim and speed are source ms); a retimed region is re-anchored at its new place, so later cuts and editor reloads keep it there. Patchable: zoom (depth, focusX, focusY, followCursor, focusMode static|auto), trim (startMs, endMs), speed (speed, rampIn, rampOut, preservePitch, freezeMs, holdMs, reverse, reverseAudio), fx (opacity, blendMode, speed, zIndex), annotation (text = the words shown, content, textContent, x, y, width, height, fontSize, fontFamily, textColor, color, backgroundColor, fontWeight, fontStyle, textDecoration, textAlign, style, zIndex), overlay (x, y, width, height in canvas %, layer, opacity, blendMode, muted, volume, loop, motionBlur, zIndex), adjustment (blendMode, fadeIn, fadeOut), motion (motionBlur), clip-transform (preset, transitionMs, easing, bezier, cameraFit, backgroundColor), background-effect (mode, strength, backgroundImage, backgroundFit, outline, outlineWidth, outlineColor, outlineShadow, matteContract, matteFeather), audio-overlay (sourceStartMs, volume 0-2, fadeIn, fadeOut in ms, 0 or null removes; fadeInMs, fadeOutMs are aliases). A key the region type doesn't have is not applied: the result lists it in ignoredKeys with a warning, and the call fails when nothing in the patch applies.",
|
|
4915
|
+
"Patch a region; unspecified fields are kept. Put the fields in patch. Every type takes startMs, endMs (edited ms; trim and speed are source ms); a retimed region is re-anchored at its new place, so later cuts and editor reloads keep it there. Patchable: zoom (depth, focusX, focusY, followCursor, focusMode static|auto), trim (startMs, endMs, afterWordId, fromWordId, beforeWordId, throughWordId), speed (speed, rampIn, rampOut, preservePitch, freezeMs, holdMs, reverse, reverseAudio), fx (opacity, blendMode, speed, zIndex), annotation (text = the words shown, content, textContent, x, y, width, height, fontSize, fontFamily, textColor, color, backgroundColor, fontWeight, fontStyle, textDecoration, textAlign, style, zIndex), overlay (x, y, width, height in canvas %, layer, opacity, blendMode, muted, volume, loop, motionBlur, zIndex), adjustment (blendMode, fadeIn, fadeOut), motion (motionBlur), clip-transform (preset, transitionMs, easing, bezier, cameraFit, backgroundColor), background-effect (mode, strength, backgroundImage, backgroundFit, outline, outlineWidth, outlineColor, outlineShadow, matteContract, matteFeather), audio-overlay (sourceStartMs, volume 0-2, fadeIn, fadeOut in ms, 0 or null removes; fadeInMs, fadeOutMs are aliases). A key the region type doesn't have is not applied: the result lists it in ignoredKeys with a warning, and the call fails when nothing in the patch applies.",
|
|
4842
4916
|
inputSchema: {
|
|
4843
4917
|
type: "object",
|
|
4844
4918
|
properties: {
|
|
4919
|
+
afterWordId: {
|
|
4920
|
+
type: "string",
|
|
4921
|
+
description: "Cut STARTS right after this word (kept). Instead of startMs.",
|
|
4922
|
+
},
|
|
4923
|
+
fromWordId: { type: "string", description: "Cut STARTS at this word (cut too)." },
|
|
4924
|
+
beforeWordId: {
|
|
4925
|
+
type: "string",
|
|
4926
|
+
description: "Cut ENDS right before this word (kept). Instead of endMs.",
|
|
4927
|
+
},
|
|
4928
|
+
throughWordId: { type: "string", description: "Cut ENDS after this word (cut too)." },
|
|
4929
|
+
snapToAudio: {
|
|
4930
|
+
type: "boolean",
|
|
4931
|
+
description:
|
|
4932
|
+
"Default true: edges snap to the quietest point nearby without clipping a kept word. false = exact ms.",
|
|
4933
|
+
},
|
|
4845
4934
|
id: { type: "string" },
|
|
4846
4935
|
loop: { type: "boolean", description: "overlay: loop, or hold the last frame." },
|
|
4847
4936
|
path: { type: "string" },
|
|
@@ -5821,7 +5910,7 @@ const TOOLS = [
|
|
|
5821
5910
|
{
|
|
5822
5911
|
name: "transcript_transcribe",
|
|
5823
5912
|
description:
|
|
5824
|
-
"Transcribe clips with word timestamps (default: only clips without words). Engine: language auto/english = Parakeet; any other named language = local Whisper LOCKED to it (engine override). Returns { jobId, plan } (plan = engine + reason, ranges, totalAudioMs: the audio that will be processed, estimate/estimatedMs: how long on this computer, advice: faster options for a long Whisper run; tell the user for long jobs). Long Whisper runs are saved chunk by chunk: stalls restart from the last chunk automatically; after job_cancel, a crash or an app restart, transcribing again resumes there. Progress is real (audio decoded); time left in progress.message and progress.data.etaMs. To REDO a transcript (wrong language, bad run) confirm language, pass per-run language and provider overrides, then force: true (all clips) or clipId. Word fixes are re-applied; tell the user about result droppedWordEdits[] (fixes that may need redoing). Each clip is transcribed only over the part it plays (head trim to tail trim, e.g. one half of a split; only the kept parts when cuts hide most of a long recording; result transcribedRanges[]). Clips with no audio track are skipped (result noAudioClips), not failed. Result warnings[] flags words that can't cover the audio (sound with no words, too few words: music, noise, another language) and a re-run with the same words as before: surface it, and get a second reading with engine whisper or a cloud provider (Parakeet isn't locked by language english, so retrying the same way repeats it). ASYNC: { jobId }, job_wait. Concurrent saves are merged and retried (three attempts). Exhausted conflicts report code revision_conflict / status 409 (job.errorDetails for async jobs).",
|
|
5913
|
+
"Transcribe clips with word timestamps (default: only clips without words). Asking again while the same transcription is still running returns that job (alreadyRunning: true), never a second run: keep waiting on it. Engine: language auto/english = Parakeet; any other named language = local Whisper LOCKED to it (engine override). Returns { jobId, plan } (plan = engine + reason, ranges, totalAudioMs: the audio that will be processed, estimate/estimatedMs: how long on this computer, advice: faster options for a long Whisper run; tell the user for long jobs). Long Whisper runs are saved chunk by chunk: stalls restart from the last chunk automatically; after job_cancel, a crash or an app restart, transcribing again resumes there. Progress is real (audio decoded); time left in progress.message and progress.data.etaMs. To REDO a transcript (wrong language, bad run) confirm language, pass per-run language and provider overrides, then force: true (all clips) or clipId. Word fixes are re-applied; tell the user about result droppedWordEdits[] (fixes that may need redoing). Each clip is transcribed only over the part it plays (head trim to tail trim, e.g. one half of a split; only the kept parts when cuts hide most of a long recording; result transcribedRanges[]). Clips with no audio track are skipped (result noAudioClips), not failed. Result warnings[] flags words that can't cover the audio (sound with no words, too few words: music, noise, another language) and a re-run with the same words as before: surface it, and get a second reading with engine whisper or a cloud provider (Parakeet isn't locked by language english, so retrying the same way repeats it). ASYNC: { jobId }, job_wait. Concurrent saves are merged and retried (three attempts). Exhausted conflicts report code revision_conflict / status 409 (job.errorDetails for async jobs).",
|
|
5825
5914
|
inputSchema: {
|
|
5826
5915
|
type: "object",
|
|
5827
5916
|
properties: {
|
|
@@ -5921,7 +6010,7 @@ const TOOLS = [
|
|
|
5921
6010
|
{
|
|
5922
6011
|
name: "transcript_get",
|
|
5923
6012
|
description:
|
|
5924
|
-
"Transcript (default: open project). compact: segments of [id, text,
|
|
6013
|
+
"Transcript (default: open project). compact: segments of [id, text, editedStartMs, editedEndMs, sourceStartMs] (edited = as it plays, the playhead's clock, null = cut; sourceStartMs for anchorSourceMs; cut by word id, not ms); ids are unique prefixes, accepted wherever word ids are. text: '[m:ss.s] line' per segment, cheapest to read. words: full ids, end times, speaker. full: legacy.",
|
|
5925
6014
|
inputSchema: {
|
|
5926
6015
|
type: "object",
|
|
5927
6016
|
properties: {
|
|
@@ -6906,6 +6995,54 @@ const TOOLS = [
|
|
|
6906
6995
|
},
|
|
6907
6996
|
command: "media.generate-presenter",
|
|
6908
6997
|
},
|
|
6998
|
+
{
|
|
6999
|
+
name: "media_generate_video",
|
|
7000
|
+
description:
|
|
7001
|
+
"Generate an AI video clip with MiniMax H3 on the user's OWN fal account (connect fal in Settings > Connectors; their credits). Text to video, or image to video from a first frame (image) and optional last frame (endImage). PAID: only after the user agreed; never retry a failed job yourself. ASYNC: { jobId, estimatedCostUsd }; job_wait timeoutMs 600000 for { videoPath, durationMs, width, height, model, requestId }. Place with project_add_motion_graphic (overlay, moving B-roll) or project_add_clip (main track). FAL_NOT_CONNECTED: ask the user to connect fal (never ask for the key in chat).",
|
|
7002
|
+
inputSchema: {
|
|
7003
|
+
type: "object",
|
|
7004
|
+
properties: {
|
|
7005
|
+
prompt: {
|
|
7006
|
+
type: "string",
|
|
7007
|
+
description:
|
|
7008
|
+
"The shot: subject, action, camera, light, mood. With an image, describe the motion.",
|
|
7009
|
+
},
|
|
7010
|
+
image: {
|
|
7011
|
+
type: "string",
|
|
7012
|
+
description: "First frame: absolute path (PNG/JPEG/WebP) or https URL.",
|
|
7013
|
+
},
|
|
7014
|
+
endImage: { type: "string", description: "Last frame, same forms. Image to video only." },
|
|
7015
|
+
model: {
|
|
7016
|
+
type: "string",
|
|
7017
|
+
enum: ["h3", "h3-max", "h3-max-turbo"],
|
|
7018
|
+
description: "Default h3. h3-max for 1080P; h3-max-turbo is faster and cheaper.",
|
|
7019
|
+
},
|
|
7020
|
+
durationSec: {
|
|
7021
|
+
type: "number",
|
|
7022
|
+
description: "Default 5. h3: whole seconds 5-15; h3-max/turbo: 0.92-15.",
|
|
7023
|
+
},
|
|
7024
|
+
resolution: {
|
|
7025
|
+
type: "string",
|
|
7026
|
+
enum: ["480P", "768P", "1080P", "2K", "4K"],
|
|
7027
|
+
description: "Default 768P. h3: 480P/768P/2K/4K; h3-max/turbo: 480P/768P/1080P.",
|
|
7028
|
+
},
|
|
7029
|
+
aspectRatio: {
|
|
7030
|
+
type: "string",
|
|
7031
|
+
enum: ["16:9", "9:16", "1:1", "4:3", "3:4", "21:9"],
|
|
7032
|
+
description: "Text to video only (default 16:9); image to video follows the image.",
|
|
7033
|
+
},
|
|
7034
|
+
promptExpansion: {
|
|
7035
|
+
type: "string",
|
|
7036
|
+
enum: ["balanced", "fast", "quality", "disabled"],
|
|
7037
|
+
description: "fal's prompt rewriting. Default balanced; disabled = word for word.",
|
|
7038
|
+
},
|
|
7039
|
+
seed: { type: "number" },
|
|
7040
|
+
outputDir: { type: "string", description: "Default <userData>/generated-videos." },
|
|
7041
|
+
},
|
|
7042
|
+
required: ["prompt"],
|
|
7043
|
+
},
|
|
7044
|
+
command: "media.generate-video",
|
|
7045
|
+
},
|
|
6909
7046
|
{
|
|
6910
7047
|
name: "project_inspect_footage",
|
|
6911
7048
|
description:
|
|
@@ -8179,6 +8316,11 @@ const TOOLS = [
|
|
|
8179
8316
|
inputSchema: {
|
|
8180
8317
|
type: "object",
|
|
8181
8318
|
properties: {
|
|
8319
|
+
still: {
|
|
8320
|
+
type: "boolean",
|
|
8321
|
+
description:
|
|
8322
|
+
"The graphic is MEANT to hold still (no entrance, no motion): skip the frozen-render check, kept for re-renders. Never fake a slow drift instead.",
|
|
8323
|
+
},
|
|
8182
8324
|
templateId: { type: "string" },
|
|
8183
8325
|
slots: { type: "object", description: "By key; image slots take a file path." },
|
|
8184
8326
|
variables: {
|
|
@@ -8328,6 +8470,11 @@ const TOOLS = [
|
|
|
8328
8470
|
inputSchema: {
|
|
8329
8471
|
type: "object",
|
|
8330
8472
|
properties: {
|
|
8473
|
+
still: {
|
|
8474
|
+
type: "boolean",
|
|
8475
|
+
description:
|
|
8476
|
+
"The graphic is MEANT to hold still (no entrance, no motion): skip the frozen-render check, kept for re-renders. Never fake a slow drift instead.",
|
|
8477
|
+
},
|
|
8331
8478
|
html: { type: "string", description: "Or htmlPath." },
|
|
8332
8479
|
htmlPath: { type: "string" },
|
|
8333
8480
|
aspectRatio: { type: "string", enum: ["16:9", "9:16", "1:1"] },
|
|
@@ -8484,7 +8631,8 @@ const TOOLS = [
|
|
|
8484
8631
|
},
|
|
8485
8632
|
{
|
|
8486
8633
|
name: "asset_list_music",
|
|
8487
|
-
description:
|
|
8634
|
+
description:
|
|
8635
|
+
"List bundled music (pick by intents; add absolutePath with project_add_audio). Cleared for commercial use in the user's videos, paid ads included (see `license` in the reply): don't flag it as a licensing risk.",
|
|
8488
8636
|
inputSchema: { type: "object", properties: {} },
|
|
8489
8637
|
command: "asset.list-music",
|
|
8490
8638
|
},
|
|
@@ -9707,6 +9855,7 @@ Publishing has daily limits (YouTube uploads and updates per license, social pos
|
|
|
9707
9855
|
|
|
9708
9856
|
PandaStudio problems (a capability gap like an imported font the export can't draw, a command failing unexpectedly, a render not matching the project): call system_report_issue yourself, then tell the user you reported it. Not for user mistakes, missing keys or taste.
|
|
9709
9857
|
|
|
9858
|
+
Fixing a cut, pause or insert the user points at ("at 16 s it's sloppy"): look and listen with project_review_moment (frames + the exported mix transcribed + whether each cut lands in quiet), fix by WORD (project_add_trim / project_update_region with afterWordId / beforeWordId, never ms worked out by hand; edges snap to the audio), then review again before saying it's fixed. A few frames off is quicker for the user to drag in the timeline: tell them. A stutter in a result's warnings (picture changes a few frames apart) means put them on one frame or keep one.
|
|
9710
9859
|
Views: in chat apps that show MCP views, preview_show, project_render_frame / _render_sheet and project_edit_summary also show the frames and what the edit contains, and clips_get / clips_make show the clips as cards the user can open, export or remove. Summarise in a line instead of describing each frame or clip; what the user does in a view arrives as context, don't redo it.
|
|
9711
9860
|
|
|
9712
9861
|
Share links: when the user asks to send a video for feedback, share_status then share_create on a finished export gives a link anyone can watch and comment on (async, job_wait; storage is capped per plan, quota_exceeded means ask which link to delete). share_comments brings viewer comments into the project as review pins: apply each, review_resolve it, and it shows as Done to viewers. Never share, delete a link or reply to viewers without the user asking.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@writepanda/mcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.284.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",
|