@writepanda/mcp 1.207.0 → 1.211.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 +195 -29
- package/package.json +1 -1
package/bin/server.mjs
CHANGED
|
@@ -212,6 +212,7 @@ async function callPandastudio(command, args = {}) {
|
|
|
212
212
|
} catch {
|
|
213
213
|
body = { raw: text };
|
|
214
214
|
}
|
|
215
|
+
if (res.status === 409 && body?.details?.code === "revision_conflict") return body;
|
|
215
216
|
if (res.status >= 400) {
|
|
216
217
|
throw new Error(`HTTP ${res.status}: ${body?.error ?? text.slice(0, 200)}`);
|
|
217
218
|
}
|
|
@@ -627,7 +628,11 @@ const MOTION_ELEMENT_PROPS = {
|
|
|
627
628
|
enum: ["auto", "none", "pop", "whoosh", "hit", "tick", "bell"],
|
|
628
629
|
description: "Role for project_compose_soundtrack.",
|
|
629
630
|
},
|
|
630
|
-
zIndex: {
|
|
631
|
+
zIndex: {
|
|
632
|
+
type: "number",
|
|
633
|
+
description:
|
|
634
|
+
"Stack order, higher on top (default 0). Front elements share one stack with media overlays and annotations at group base + zIndex (B-roll 0, overlays 1000, annotations 2000, front elements 3000), so by default they draw over both; -2500 drops one under the default overlays.",
|
|
635
|
+
},
|
|
631
636
|
anchor: { type: "string", enum: ["auto", "free"] },
|
|
632
637
|
};
|
|
633
638
|
const TOOLS = [
|
|
@@ -635,7 +640,7 @@ const TOOLS = [
|
|
|
635
640
|
{
|
|
636
641
|
name: "system_status",
|
|
637
642
|
description:
|
|
638
|
-
"App version and license; automationGated true = trial expired, or the Solo plan (license.agentEditing.allowed false: no agent editing, relay license.agentEditing.message to the user), and every other tool fails; license.socialPublishing.allowed false = the plan has no Instagram/TikTok/social publishing (Creator, Team, Pro only). Call first.",
|
|
643
|
+
"App version and license; automationGated true = trial expired, or the Solo plan (license.agentEditing.allowed false: no agent editing, relay license.agentEditing.message to the user), and every other tool fails; license.socialPublishing.allowed false = the plan has no Instagram/TikTok/social publishing (Creator, Team, Pro only); license.exportQuality.allowed = the export_start qualities that work (free trial: draft 720p only; standard/high/ultra need a license). Call first.",
|
|
639
644
|
inputSchema: { type: "object", properties: {} },
|
|
640
645
|
command: "system.status",
|
|
641
646
|
},
|
|
@@ -725,7 +730,7 @@ const TOOLS = [
|
|
|
725
730
|
{
|
|
726
731
|
name: "system_get_transcription_language",
|
|
727
732
|
description:
|
|
728
|
-
"Workspace transcription language
|
|
733
|
+
"Workspace transcription language. auto = Parakeet TDT v3, which detects the language itself across 25 languages, English included: Bulgarian, Croatian, Czech, Danish, Dutch, English, Estonian, Finnish, French, German, Greek, Hungarian, Italian, Latvian, Lithuanian, Maltese, Polish, Portuguese, Romanian, Russian, Slovak, Slovenian, Spanish, Swedish, Ukrainian. Anything else names a Whisper language.",
|
|
729
734
|
inputSchema: { type: "object", properties: {} },
|
|
730
735
|
command: "system.get-transcription-language",
|
|
731
736
|
},
|
|
@@ -752,7 +757,7 @@ const TOOLS = [
|
|
|
752
757
|
{
|
|
753
758
|
name: "system_set_transcription_language",
|
|
754
759
|
description:
|
|
755
|
-
"Set the workspace transcription language.
|
|
760
|
+
"Set the workspace transcription language. auto = Parakeet TDT v3, which detects the language itself across 25 languages, English included: Bulgarian, Croatian, Czech, Danish, Dutch, English, Estonian, Finnish, French, German, Greek, Hungarian, Italian, Latvian, Lithuanian, Maltese, Polish, Portuguese, Romanian, Russian, Slovak, Slovenian, Spanish, Swedish, Ukrainian. For any of those (e.g. Romanian) use auto; their names are accepted and saved as auto. The other values use Whisper, a ~1.1 GB download: tell the user first (system.is-whisper-model-downloaded via pandastudio_call).",
|
|
756
761
|
inputSchema: {
|
|
757
762
|
type: "object",
|
|
758
763
|
properties: {
|
|
@@ -762,6 +767,30 @@ const TOOLS = [
|
|
|
762
767
|
"auto",
|
|
763
768
|
"english",
|
|
764
769
|
"en",
|
|
770
|
+
"bulgarian",
|
|
771
|
+
"croatian",
|
|
772
|
+
"czech",
|
|
773
|
+
"danish",
|
|
774
|
+
"dutch",
|
|
775
|
+
"estonian",
|
|
776
|
+
"finnish",
|
|
777
|
+
"french",
|
|
778
|
+
"german",
|
|
779
|
+
"greek",
|
|
780
|
+
"hungarian",
|
|
781
|
+
"italian",
|
|
782
|
+
"latvian",
|
|
783
|
+
"lithuanian",
|
|
784
|
+
"maltese",
|
|
785
|
+
"polish",
|
|
786
|
+
"portuguese",
|
|
787
|
+
"romanian",
|
|
788
|
+
"russian",
|
|
789
|
+
"slovak",
|
|
790
|
+
"slovenian",
|
|
791
|
+
"spanish",
|
|
792
|
+
"swedish",
|
|
793
|
+
"ukrainian",
|
|
765
794
|
"chinese",
|
|
766
795
|
"japanese",
|
|
767
796
|
"korean",
|
|
@@ -1048,8 +1077,14 @@ const TOOLS = [
|
|
|
1048
1077
|
},
|
|
1049
1078
|
{
|
|
1050
1079
|
name: "youtube_connect",
|
|
1051
|
-
description:
|
|
1052
|
-
|
|
1080
|
+
description:
|
|
1081
|
+
"Connect a YouTube account via browser sign-in (only when the user asks). Pass email to reconnect an existing account. permissionIssue set = the user unticked a Google permission: relay its message.",
|
|
1082
|
+
inputSchema: {
|
|
1083
|
+
type: "object",
|
|
1084
|
+
properties: {
|
|
1085
|
+
email: { type: "string", description: "Reconnect: that account's email." },
|
|
1086
|
+
},
|
|
1087
|
+
},
|
|
1053
1088
|
command: "youtube.connect",
|
|
1054
1089
|
},
|
|
1055
1090
|
{
|
|
@@ -1065,13 +1100,15 @@ const TOOLS = [
|
|
|
1065
1100
|
},
|
|
1066
1101
|
{
|
|
1067
1102
|
name: "youtube_list_accounts",
|
|
1068
|
-
description:
|
|
1103
|
+
description:
|
|
1104
|
+
"Connected YouTube accounts and channels (pick before export_publish_youtube). issues[] = accounts missing a Google permission (code youtube_permission_missing): relay message, follow howToFix (the user reconnects in Settings > YouTube, leaving every box ticked; you can't do the sign-in).",
|
|
1069
1105
|
inputSchema: { type: "object", properties: {} },
|
|
1070
1106
|
command: "youtube.list-accounts",
|
|
1071
1107
|
},
|
|
1072
1108
|
{
|
|
1073
1109
|
name: "youtube_list_channels",
|
|
1074
|
-
description:
|
|
1110
|
+
description:
|
|
1111
|
+
"Refresh an account's channel list from YouTube (bypasses cache). Error code youtube_permission_missing = channel permission unticked on Google's screen: relay message, follow howToFix; canStillPublish true = publish without channelId.",
|
|
1075
1112
|
inputSchema: {
|
|
1076
1113
|
type: "object",
|
|
1077
1114
|
properties: { accountId: { type: "string" } },
|
|
@@ -1082,7 +1119,7 @@ const TOOLS = [
|
|
|
1082
1119
|
{
|
|
1083
1120
|
name: "export_publish_youtube",
|
|
1084
1121
|
description:
|
|
1085
|
-
"Publish an export entry to YouTube. Slow. Check the entry's youtubeVideoId before republishing. Returns { videoUrl }.",
|
|
1122
|
+
"Publish an export entry to YouTube. Slow. Check the entry's youtubeVideoId before republishing. channelId optional (uploads go to the account's own channel; omit when channels can't be listed). Error code youtube_permission_missing: relay message, follow howToFix. Returns { videoUrl, channelId }.",
|
|
1086
1123
|
inputSchema: {
|
|
1087
1124
|
type: "object",
|
|
1088
1125
|
properties: {
|
|
@@ -1096,7 +1133,7 @@ const TOOLS = [
|
|
|
1096
1133
|
privacyStatus: { type: "string", enum: ["public", "unlisted", "private"] },
|
|
1097
1134
|
setThumbnail: { type: "boolean" },
|
|
1098
1135
|
},
|
|
1099
|
-
required: ["id", "accountId", "
|
|
1136
|
+
required: ["id", "accountId", "title"],
|
|
1100
1137
|
},
|
|
1101
1138
|
command: "export.publish-youtube",
|
|
1102
1139
|
},
|
|
@@ -1380,7 +1417,7 @@ const TOOLS = [
|
|
|
1380
1417
|
{
|
|
1381
1418
|
name: "project_add_clip",
|
|
1382
1419
|
description:
|
|
1383
|
-
"Append or insert a video clip, or a still image shown for durationMs, on the main track (later content moves with it).
|
|
1420
|
+
"Append or insert a video clip, or a still image shown for durationMs, on the main track (later content moves with it). atMs (edited time) inserts at that moment, splitting the clip under it; add replaceToMs to replace [atMs, replaceToMs) with the clip (e.g. a re-recorded take).",
|
|
1384
1421
|
inputSchema: {
|
|
1385
1422
|
type: "object",
|
|
1386
1423
|
properties: {
|
|
@@ -1391,6 +1428,14 @@ const TOOLS = [
|
|
|
1391
1428
|
fill: { type: "boolean", description: "Images: cover the frame (default true)." },
|
|
1392
1429
|
webcam: { type: "string", description: "Guest source: a two-speaker podcast clip." },
|
|
1393
1430
|
atIndex: { type: "number", description: "0-based; omit = append." },
|
|
1431
|
+
atMs: {
|
|
1432
|
+
type: "number",
|
|
1433
|
+
description: "Insert at this edited ms (splits the clip there; not with atIndex).",
|
|
1434
|
+
},
|
|
1435
|
+
replaceToMs: {
|
|
1436
|
+
type: "number",
|
|
1437
|
+
description: "With atMs: cut [atMs, replaceToMs) (a trim) and put the clip there.",
|
|
1438
|
+
},
|
|
1394
1439
|
expectedRevision: { type: "number" },
|
|
1395
1440
|
},
|
|
1396
1441
|
required: ["media"],
|
|
@@ -1433,6 +1478,79 @@ const TOOLS = [
|
|
|
1433
1478
|
},
|
|
1434
1479
|
command: "project.add-podcast-clip",
|
|
1435
1480
|
},
|
|
1481
|
+
{
|
|
1482
|
+
name: "podcast_open_host",
|
|
1483
|
+
description:
|
|
1484
|
+
"Open or focus the live podcast host window. Call podcast_status for the session code and guest link once it loads.",
|
|
1485
|
+
inputSchema: {
|
|
1486
|
+
type: "object",
|
|
1487
|
+
properties: {
|
|
1488
|
+
sessionCode: { type: "string", description: "Resume an existing session." },
|
|
1489
|
+
projectPath: { type: "string", description: "Matching podcast project when resuming." },
|
|
1490
|
+
},
|
|
1491
|
+
},
|
|
1492
|
+
command: "podcast.open-host",
|
|
1493
|
+
},
|
|
1494
|
+
...[
|
|
1495
|
+
[
|
|
1496
|
+
"status",
|
|
1497
|
+
"Read the live podcast session code, guest link, participants, recording, and sharing state.",
|
|
1498
|
+
],
|
|
1499
|
+
[
|
|
1500
|
+
"start-recording",
|
|
1501
|
+
"Start recording the host and signal connected guests to record. Returns once recording has really started; fails with the reason otherwise.",
|
|
1502
|
+
],
|
|
1503
|
+
[
|
|
1504
|
+
"stop-recording",
|
|
1505
|
+
"Stop recording and finalize podcast media. Check podcast_status for finalization and guest uploads.",
|
|
1506
|
+
],
|
|
1507
|
+
[
|
|
1508
|
+
"start-screen-share",
|
|
1509
|
+
"Open the desktop picker to share and record the host screen during a podcast. Waits for the host to choose; fails if the picker is cancelled or capture fails.",
|
|
1510
|
+
],
|
|
1511
|
+
["stop-screen-share", "Stop and finalize the host's podcast screen share."],
|
|
1512
|
+
["open-in-editor", "Open the finished podcast in the editor when guest media has arrived."],
|
|
1513
|
+
].map(([noun, description]) => ({
|
|
1514
|
+
name: `podcast_${noun.replaceAll("-", "_")}`,
|
|
1515
|
+
description,
|
|
1516
|
+
inputSchema: { type: "object", properties: {} },
|
|
1517
|
+
command: `podcast.${noun}`,
|
|
1518
|
+
})),
|
|
1519
|
+
{
|
|
1520
|
+
name: "project_set_podcast_source_crop",
|
|
1521
|
+
description:
|
|
1522
|
+
"Frame one podcast camera or screen-share source independently. Use source=host|guest|guest-2|guest-3|share:0; normalized x,y,width,height. 0,0,1,1 resets the crop. Preview and export use the same framing.",
|
|
1523
|
+
inputSchema: {
|
|
1524
|
+
type: "object",
|
|
1525
|
+
properties: {
|
|
1526
|
+
id: { type: "string" },
|
|
1527
|
+
path: { type: "string" },
|
|
1528
|
+
clipId: { type: "string" },
|
|
1529
|
+
source: { type: "string", description: "host, guest, guest-2, guest-3, or share:<index>." },
|
|
1530
|
+
x: { type: "number", description: "Left edge, 0-1." },
|
|
1531
|
+
y: { type: "number", description: "Top edge, 0-1." },
|
|
1532
|
+
width: { type: "number", description: "Crop width, >0 to 1." },
|
|
1533
|
+
height: { type: "number", description: "Crop height, >0 to 1." },
|
|
1534
|
+
expectedRevision: { type: "number" },
|
|
1535
|
+
},
|
|
1536
|
+
required: ["clipId", "source", "x", "y", "width", "height"],
|
|
1537
|
+
},
|
|
1538
|
+
command: "project.set-podcast-source-crop",
|
|
1539
|
+
},
|
|
1540
|
+
{
|
|
1541
|
+
name: "project_list_podcast_screen_shares",
|
|
1542
|
+
description:
|
|
1543
|
+
"List the screen-share intervals shown on the podcast editor timeline. Returns speaker, clip-local and merged-source timing, edited timing after trims/speed, and whether each interval is visible. Read-only.",
|
|
1544
|
+
inputSchema: {
|
|
1545
|
+
type: "object",
|
|
1546
|
+
properties: {
|
|
1547
|
+
id: { type: "string" },
|
|
1548
|
+
path: { type: "string" },
|
|
1549
|
+
clipId: { type: "string", description: "Optional podcast clip filter." },
|
|
1550
|
+
},
|
|
1551
|
+
},
|
|
1552
|
+
command: "project.list-podcast-screen-shares",
|
|
1553
|
+
},
|
|
1436
1554
|
{
|
|
1437
1555
|
name: "project_set_participant_offset",
|
|
1438
1556
|
description: "Nudge one guest's A/V sync on a podcast composite (host is the reference).",
|
|
@@ -1469,7 +1587,7 @@ const TOOLS = [
|
|
|
1469
1587
|
{
|
|
1470
1588
|
name: "project_update_motion_graphic",
|
|
1471
1589
|
description:
|
|
1472
|
-
"Edit a generated graphic (overlay with generatedFrom) and re-render it in place, keeping timing and position. ASYNC: { jobId }.",
|
|
1590
|
+
"Edit a generated graphic (overlay with generatedFrom) and re-render it in place, keeping timing and position. ASYNC: { jobId }. Concurrent saves are merged and retried (three attempts). Exhausted conflicts report code revision_conflict / status 409 (job.errorDetails for async jobs).",
|
|
1473
1591
|
inputSchema: {
|
|
1474
1592
|
type: "object",
|
|
1475
1593
|
properties: {
|
|
@@ -1493,7 +1611,7 @@ const TOOLS = [
|
|
|
1493
1611
|
{
|
|
1494
1612
|
name: "project_add_emoji",
|
|
1495
1613
|
description:
|
|
1496
|
-
"Place an animated emoji overlay. ASYNC: { jobId }; job_wait gives result.overlayId.",
|
|
1614
|
+
"Place an animated emoji overlay. ASYNC: { jobId }; job_wait gives result.overlayId. Concurrent saves are merged and retried (three attempts). Exhausted conflicts report code revision_conflict / status 409 (job.errorDetails for async jobs).",
|
|
1497
1615
|
inputSchema: {
|
|
1498
1616
|
type: "object",
|
|
1499
1617
|
properties: {
|
|
@@ -1699,7 +1817,7 @@ const TOOLS = [
|
|
|
1699
1817
|
{
|
|
1700
1818
|
name: "project_add_lower_third",
|
|
1701
1819
|
description:
|
|
1702
|
-
"Render a nameplate and place it at atMs in one call, laid out for the project's aspect. ASYNC: { jobId }; job_wait gives result.overlayId once placed.",
|
|
1820
|
+
"Render a nameplate and place it at atMs in one call, laid out for the project's aspect. ASYNC: { jobId }; job_wait gives result.overlayId once placed. Concurrent saves are merged and retried (three attempts). Exhausted conflicts report code revision_conflict / status 409 (job.errorDetails for async jobs).",
|
|
1703
1821
|
inputSchema: {
|
|
1704
1822
|
type: "object",
|
|
1705
1823
|
properties: {
|
|
@@ -1736,7 +1854,7 @@ const TOOLS = [
|
|
|
1736
1854
|
{
|
|
1737
1855
|
name: "project_add_title_behind",
|
|
1738
1856
|
description:
|
|
1739
|
-
"1-3 huge words at head height BEHIND the presenter. ASYNC: job_wait gives regionId, face.",
|
|
1857
|
+
"1-3 huge words at head height BEHIND the presenter. ASYNC: job_wait gives regionId, face. Concurrent saves are merged and retried (three attempts). Exhausted conflicts report code revision_conflict / status 409 (job.errorDetails for async jobs).",
|
|
1740
1858
|
inputSchema: {
|
|
1741
1859
|
type: "object",
|
|
1742
1860
|
properties: {
|
|
@@ -2483,7 +2601,7 @@ const TOOLS = [
|
|
|
2483
2601
|
{
|
|
2484
2602
|
name: "audio_probe",
|
|
2485
2603
|
description:
|
|
2486
|
-
"Per-clip audio stats: hasAudio, mean/max dB, silence spans (source time), plus audio overlays. A few seconds per clip.",
|
|
2604
|
+
"Per-clip audio stats: hasAudio, integratedLufs (null if unavailable/silent), tooQuiet (< -30 LUFS), mean/max dB, silence spans (source time), plus audio overlays. A few seconds per clip.",
|
|
2487
2605
|
inputSchema: {
|
|
2488
2606
|
type: "object",
|
|
2489
2607
|
properties: {
|
|
@@ -2883,7 +3001,7 @@ const TOOLS = [
|
|
|
2883
3001
|
{
|
|
2884
3002
|
name: "project_center_camera_on_face",
|
|
2885
3003
|
description:
|
|
2886
|
-
"Keep the presenter's face centred in the camera card by tracking it (can take a minute). clear: true turns it off.",
|
|
3004
|
+
"Keep the presenter's face centred in the camera card by tracking it (can take a minute). 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).",
|
|
2887
3005
|
inputSchema: {
|
|
2888
3006
|
type: "object",
|
|
2889
3007
|
properties: {
|
|
@@ -2900,7 +3018,7 @@ const TOOLS = [
|
|
|
2900
3018
|
{
|
|
2901
3019
|
name: "project_batch",
|
|
2902
3020
|
description:
|
|
2903
|
-
"Run up to 200 verb.noun commands on one project in order (id / path filled in; not atomic; stops at the first failure by default). Returns { ran, failed, results[] }.",
|
|
3021
|
+
"Run up to 200 verb.noun commands on one project in order (id / path filled in; not atomic; stops at the first failure by default). Returns { ran, failed, results[] }. Concurrent saves are merged and retried (three attempts). Exhausted conflicts report code revision_conflict / status 409 (job.errorDetails for async jobs).",
|
|
2904
3022
|
inputSchema: {
|
|
2905
3023
|
type: "object",
|
|
2906
3024
|
properties: {
|
|
@@ -2923,7 +3041,7 @@ const TOOLS = [
|
|
|
2923
3041
|
{
|
|
2924
3042
|
name: "project_update_region",
|
|
2925
3043
|
description:
|
|
2926
|
-
"Patch a region; unspecified fields are kept. Patchable: zoom (depth, focusX, focusY, focusMode static|auto), trim / speed (startMs, endMs, speed, rampIn, rampOut, preservePitch, freezeMs, reverse, reverseAudio), fx (atMs, durationMs, opacity, blendMode, speed), annotation, overlay (x, y, width, height in canvas %, layer, opacity, blendMode, muted, volume, loop, motionBlur), adjustment (startMs, endMs, blendMode), motion (motionBlur), clip-transform (startMs, endMs, preset, transitionMs, easing, bezier), background-effect (as project_add_background_effect), audio-overlay (startMs, endMs, sourceStartMs, volume 0-2, fadeIn, fadeOut).",
|
|
3044
|
+
"Patch a region; unspecified fields are kept. Patchable: zoom (depth, focusX, focusY, focusMode static|auto), trim / speed (startMs, endMs, speed, rampIn, rampOut, preservePitch, freezeMs, reverse, reverseAudio), fx (atMs, durationMs, opacity, blendMode, speed, zIndex), annotation (zIndex), overlay (x, y, width, height in canvas %, layer, opacity, blendMode, muted, volume, loop, motionBlur, zIndex), adjustment (startMs, endMs, blendMode), motion (motionBlur), clip-transform (startMs, endMs, preset, transitionMs, easing, bezier), background-effect (as project_add_background_effect), audio-overlay (startMs, endMs, sourceStartMs, volume 0-2, fadeIn, fadeOut).",
|
|
2927
3045
|
inputSchema: {
|
|
2928
3046
|
type: "object",
|
|
2929
3047
|
properties: {
|
|
@@ -2932,7 +3050,11 @@ const TOOLS = [
|
|
|
2932
3050
|
path: { type: "string" },
|
|
2933
3051
|
regionType: { type: "string", enum: REGION_TYPES },
|
|
2934
3052
|
regionId: { type: "string" },
|
|
2935
|
-
patch: {
|
|
3053
|
+
patch: {
|
|
3054
|
+
type: "object",
|
|
3055
|
+
description:
|
|
3056
|
+
"e.g. { depth: 4 }; null clears a value. zIndex (overlay / annotation / fx): stack order, higher on top; overlays, annotations and front motion elements share one stack at group base + zIndex (B-roll 0, overlays 1000, annotations 2000, motion elements 3000).",
|
|
3057
|
+
},
|
|
2936
3058
|
expectedRevision: { type: "number" },
|
|
2937
3059
|
},
|
|
2938
3060
|
required: ["regionType", "regionId", "patch"],
|
|
@@ -3117,7 +3239,7 @@ const TOOLS = [
|
|
|
3117
3239
|
{
|
|
3118
3240
|
name: "project_auto_reframe",
|
|
3119
3241
|
description:
|
|
3120
|
-
"Active-speaker auto-reframe of landscape multi-person footage for vertical / square: frames whoever talks, shot by shot. split=true stacks two people (podcast / interview wide) one above the other on a 9:16 canvas. Slow (minutes). clear reverts.",
|
|
3242
|
+
"Active-speaker auto-reframe of landscape multi-person footage for vertical / square: frames whoever talks, shot by shot. 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).",
|
|
3121
3243
|
inputSchema: {
|
|
3122
3244
|
type: "object",
|
|
3123
3245
|
properties: {
|
|
@@ -3141,13 +3263,19 @@ const TOOLS = [
|
|
|
3141
3263
|
},
|
|
3142
3264
|
{
|
|
3143
3265
|
name: "project_set_export_settings",
|
|
3144
|
-
description:
|
|
3266
|
+
description:
|
|
3267
|
+
"Project export defaults (Export dialog and export_start). quality good and source need a license: a free trial gets quality_requires_license, use medium.",
|
|
3145
3268
|
inputSchema: {
|
|
3146
3269
|
type: "object",
|
|
3147
3270
|
properties: {
|
|
3148
3271
|
id: { type: "string" },
|
|
3149
3272
|
path: { type: "string" },
|
|
3150
|
-
quality: {
|
|
3273
|
+
quality: {
|
|
3274
|
+
type: "string",
|
|
3275
|
+
enum: ["medium", "good", "source"],
|
|
3276
|
+
description:
|
|
3277
|
+
"medium 720p, good 1080p, source = source resolution (good/source license only).",
|
|
3278
|
+
},
|
|
3151
3279
|
format: { type: "string", enum: ["mp4"] },
|
|
3152
3280
|
normalizeLoudness: {
|
|
3153
3281
|
type: ["boolean", "string"],
|
|
@@ -3575,7 +3703,7 @@ const TOOLS = [
|
|
|
3575
3703
|
{
|
|
3576
3704
|
name: "transcript_transcribe",
|
|
3577
3705
|
description:
|
|
3578
|
-
"Transcribe clips with word timestamps (default: only clips without words). To REDO a transcript (wrong language, bad run) fix the language first, then force: true (all clips) or clipId. Word fixes are re-applied; tell the user about result droppedWordEdits[] (fixes that may need redoing). ASYNC: { jobId }, job_wait.",
|
|
3706
|
+
"Transcribe clips with word timestamps (default: only clips without words). To REDO a transcript (wrong language, bad run) fix the language first, 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 out-point, e.g. one half of a split; result transcribedRanges[]). 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).",
|
|
3579
3707
|
inputSchema: {
|
|
3580
3708
|
type: "object",
|
|
3581
3709
|
properties: {
|
|
@@ -3740,7 +3868,7 @@ const TOOLS = [
|
|
|
3740
3868
|
{
|
|
3741
3869
|
name: "audio_clean",
|
|
3742
3870
|
description:
|
|
3743
|
-
"Denoise each clip
|
|
3871
|
+
"Denoise each clip’s audio, optionally reducing room echo. Speech below -30 LUFS is boosted to -16 LUFS / -1.5 dBTP by default; warnings explain boosts. Original kept; audio_reset_clean restores it. ASYNC: { jobId }, job_wait. Concurrent saves are merged and retried (three attempts); exhausted conflicts report code revision_conflict / status 409.",
|
|
3744
3872
|
inputSchema: {
|
|
3745
3873
|
type: "object",
|
|
3746
3874
|
properties: {
|
|
@@ -3748,11 +3876,42 @@ const TOOLS = [
|
|
|
3748
3876
|
path: { type: "string" },
|
|
3749
3877
|
clipId: { type: "string" },
|
|
3750
3878
|
echo: { type: "boolean", description: "Only when the user mentions echo / reverb." },
|
|
3879
|
+
normalize: {
|
|
3880
|
+
type: "boolean",
|
|
3881
|
+
description: "Default true: boost very quiet speech. Set false to opt out.",
|
|
3882
|
+
},
|
|
3751
3883
|
},
|
|
3752
3884
|
},
|
|
3753
3885
|
command: "audio.clean",
|
|
3754
3886
|
},
|
|
3755
3887
|
|
|
3888
|
+
{
|
|
3889
|
+
name: "audio_normalize",
|
|
3890
|
+
description:
|
|
3891
|
+
"Normalize a clip’s active audio without denoising. Default -16 LUFS, -1.5 dBTP ceiling. Silent audio skipped with warnings. Original kept. ASYNC: job_wait.",
|
|
3892
|
+
inputSchema: {
|
|
3893
|
+
type: "object",
|
|
3894
|
+
properties: {
|
|
3895
|
+
id: { type: "string" },
|
|
3896
|
+
path: { type: "string" },
|
|
3897
|
+
clipId: { type: "string" },
|
|
3898
|
+
targetLufs: { type: "number", minimum: -70, maximum: -5, default: -16 },
|
|
3899
|
+
},
|
|
3900
|
+
required: ["clipId"],
|
|
3901
|
+
},
|
|
3902
|
+
command: "audio.normalize",
|
|
3903
|
+
},
|
|
3904
|
+
{
|
|
3905
|
+
name: "audio_reset_clean",
|
|
3906
|
+
description:
|
|
3907
|
+
"Restore original clip audio by clearing cleaned/normalized audio and echo metadata. Optional clipId; otherwise all clips. Keeps generated files. Synchronous.",
|
|
3908
|
+
inputSchema: {
|
|
3909
|
+
type: "object",
|
|
3910
|
+
properties: { id: { type: "string" }, path: { type: "string" }, clipId: { type: "string" } },
|
|
3911
|
+
},
|
|
3912
|
+
command: "audio.reset-clean",
|
|
3913
|
+
},
|
|
3914
|
+
|
|
3756
3915
|
// ── captions ────────────────────────────────────────────────────
|
|
3757
3916
|
{
|
|
3758
3917
|
name: "caption_toggle",
|
|
@@ -4459,7 +4618,7 @@ const TOOLS = [
|
|
|
4459
4618
|
{
|
|
4460
4619
|
name: "media_download_url",
|
|
4461
4620
|
description:
|
|
4462
|
-
"Download a video or its audio from a page link (YouTube, Vimeo...). Only content the user has rights to. ASYNC: job_wait gives { path, title, durationMs }.",
|
|
4621
|
+
"Download a video or its audio from a page link (YouTube, Vimeo...). Only content the user has rights to. ASYNC: job_wait gives { path, title, durationMs }. Project placement retries concurrent-save conflicts (three attempts); exhaustion is job.errorDetails with revision_conflict / status 409.",
|
|
4463
4622
|
inputSchema: {
|
|
4464
4623
|
type: "object",
|
|
4465
4624
|
properties: {
|
|
@@ -5043,14 +5202,19 @@ const TOOLS = [
|
|
|
5043
5202
|
{
|
|
5044
5203
|
name: "export_start",
|
|
5045
5204
|
description:
|
|
5046
|
-
"Render the project to MP4. ASYNC: { jobId, outputPath }; job_wait. Tell the user any warning and the result's loudness before / after.",
|
|
5205
|
+
"Render the project to MP4. ASYNC: { jobId, outputPath, quality }; job_wait. Tell the user any warning and the result's loudness before / after. Free trial: draft (720p) only (system_status license.exportQuality); standard/high/ultra fail with quality_requires_license.",
|
|
5047
5206
|
inputSchema: {
|
|
5048
5207
|
type: "object",
|
|
5049
5208
|
properties: {
|
|
5050
5209
|
id: { type: "string" },
|
|
5051
5210
|
path: { type: "string" },
|
|
5052
5211
|
outputPath: { type: "string" },
|
|
5053
|
-
quality: {
|
|
5212
|
+
quality: {
|
|
5213
|
+
type: "string",
|
|
5214
|
+
enum: ["draft", "standard", "high", "ultra"],
|
|
5215
|
+
description:
|
|
5216
|
+
"draft 720p, standard 1080p, high/ultra source resolution (standard and up: license only). Omit = high, or draft on a trial.",
|
|
5217
|
+
},
|
|
5054
5218
|
normalizeLoudness: {
|
|
5055
5219
|
type: ["boolean", "string"],
|
|
5056
5220
|
description: "streaming / podcast / off; omit = project setting.",
|
|
@@ -5165,7 +5329,7 @@ const TOOLS = [
|
|
|
5165
5329
|
{
|
|
5166
5330
|
name: "clips_export",
|
|
5167
5331
|
description:
|
|
5168
|
-
"Export a clip set's finished clips to MP4 (all, or clipIds) into Movies/PandaStudio Clips/<video
|
|
5332
|
+
"Export a clip set's finished clips to MP4 (all, or clipIds) into Movies/PandaStudio Clips/<video>/, at standard quality (1080p; 720p on a free trial). Async: returns { jobId, outputDir }; job_wait for { exported[] }.",
|
|
5169
5333
|
inputSchema: {
|
|
5170
5334
|
type: "object",
|
|
5171
5335
|
properties: {
|
|
@@ -5483,6 +5647,8 @@ const INSTRUCTIONS = `PandaStudio is a desktop video editor; these tools drive t
|
|
|
5483
5647
|
|
|
5484
5648
|
Start with system_status. Unknown arguments are rejected. Verbs without a tool of their own (system_list_commands) go through pandastudio_call.
|
|
5485
5649
|
|
|
5650
|
+
Read-only tools (project_read, transcript_get / _search / _find_issues, audio_probe, project_render_frame / _render_sheet, timeline_*, ...) use the project open in the editor when you pass no id or path; edits always need the id.
|
|
5651
|
+
|
|
5486
5652
|
Before an editing pass, read the skill's "Which tool for which moment" section (skill_read section="Which tool for which moment").
|
|
5487
5653
|
|
|
5488
5654
|
"Edit my video" / "make this a Short" with no specifics = this pipeline, in order. Confirm scope once ("full polish, or just part of it?"), then run it all:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@writepanda/mcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.211.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",
|