@writepanda/mcp 1.109.0 → 1.116.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.
Files changed (3) hide show
  1. package/README.md +60 -55
  2. package/bin/server.mjs +161 -1
  3. package/package.json +3 -4
package/README.md CHANGED
@@ -1,18 +1,29 @@
1
- # @writepanda/mcp
1
+ # PandaStudio MCP Server
2
2
 
3
- [Model Context Protocol](https://modelcontextprotocol.io) server for [PandaStudio](https://www.writepanda.ai) — a desktop video editor for YouTube creators. Lets AI agents edit videos like a human does: transcribe, delete filler words, drop motion graphics / FX / lower-thirds, generate captions, render the final MP4 — all without the user leaving their chat.
3
+ [![npm](https://img.shields.io/npm/v/@writepanda/mcp)](https://www.npmjs.com/package/@writepanda/mcp)
4
+ [![license](https://img.shields.io/badge/license-MIT-blue)](./LICENSE)
4
5
 
5
- Works with **Claude Desktop, Cursor, Continue.dev, Cline, and any MCP-compliant client**.
6
+ [Model Context Protocol](https://modelcontextprotocol.io) server for **[PandaStudio](https://www.writepanda.ai)** — a local-first desktop video editor. It exposes the editor's full automation surface (**148 tools**) to Claude, ChatGPT/Codex, Cursor, Cline, Continue, and any MCP-compliant client.
6
7
 
7
- > **You also need PandaStudio installed.** The MCP server is a thin translator between MCP and PandaStudio's localhost-only automation API. Get the desktop app at [writepanda.ai](https://www.writepanda.ai).
8
+ Most video MCP servers wrap FFmpeg or call a cloud rendering API. This one drives a **real desktop editor** running on your machine: transcript-based cutting, filler-word removal, motion graphics, captions, background removal, thumbnails, and publishing to YouTube/Instagram. Your footage never leaves your computer.
8
9
 
9
- ## Install
10
+ ```
11
+ "Transcribe the recording, cut the filler words and dead air, add captions,
12
+ punch in a zoom whenever I click something, and export it."
13
+ ```
14
+
15
+ …and the agent actually does it, end to end.
10
16
 
11
- The MCP server runs on demand via `npx` — no global install needed. Add to your client config:
17
+ ## Requirements
12
18
 
13
- ### Claude Desktop
19
+ - **[PandaStudio](https://www.writepanda.ai)** installed (macOS or Windows). This server is a thin translator between MCP and PandaStudio's loopback automation API — it needs the app.
20
+ - Node.js ≥ 18.
14
21
 
15
- `~/Library/Application Support/Claude/claude_desktop_config.json` (Mac) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows):
22
+ ## Install
23
+
24
+ Runs on demand via `npx`; no global install.
25
+
26
+ **Claude Desktop** — `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows):
16
27
 
17
28
  ```json
18
29
  {
@@ -25,9 +36,7 @@ The MCP server runs on demand via `npx` — no global install needed. Add to you
25
36
  }
26
37
  ```
27
38
 
28
- ### Cursor
29
-
30
- `.cursor/mcp.json` in your workspace:
39
+ **Cursor** — `.cursor/mcp.json`:
31
40
 
32
41
  ```json
33
42
  {
@@ -40,74 +49,70 @@ The MCP server runs on demand via `npx` — no global install needed. Add to you
40
49
  }
41
50
  ```
42
51
 
43
- ### Continue.dev / Cline
52
+ **Cline / Continue / Codex / others** — same shape in their MCP config.
44
53
 
45
- Same shape, in their respective MCP config files.
46
-
47
- After adding, restart your client. The MCP server auto-launches PandaStudio if it isn't running and waits for the localhost HTTP server to come up (~5s).
54
+ Restart the client afterwards. The server auto-launches PandaStudio if it isn't running and waits for its local API (~5s).
48
55
 
49
56
  ## What the agent gets
50
57
 
51
- 55 tools covering the full PandaStudio editorial surface — complete UI parity:
52
-
53
- | Category | Tools |
54
- |---|---|
55
- | Discovery | `system_status`, `system_list_commands` |
56
- | Project lifecycle | `project_list`, `project_show`, `project_read`, `project_new`, `project_open`, `project_save`, `project_delete` |
57
- | Clips | `project_add_clip`, `project_remove_clip`, `project_split_clip` |
58
- | Composition | `project_add_motion_graphic`, `project_add_fx`, `project_add_lower_third`, `project_add_zoom`, `project_add_trim`, `project_add_speed`, `project_add_annotation` |
59
- | Region editing | `project_remove_region`, `project_update_region` |
60
- | Canvas & style | `project_set_aspect_ratio`, `project_set_wallpaper`, `project_set_style`, `project_set_crop`, `project_set_webcam_layout`, `project_set_export_settings` |
61
- | Transcript editing | `transcript_transcribe`, `transcript_get`, `transcript_delete_words`, `transcript_remove_fillers`, `transcript_search`, `transcript_find_replace`, `transcript_remove_silences` |
62
- | Audio | `audio_clean` (DeepFilter denoising) |
63
- | Captions | `caption_toggle`, `caption_set_template`, `caption_set_style` |
64
- | Motion graphics | `motion_list`, `motion_themes`, `motion_generate`, `motion_render_html` |
65
- | Assets | `asset_list_sounds`, `asset_list_fx` |
66
- | AI metadata | `llm_generate_title`, `llm_generate_description`, `llm_generate_timestamps` |
67
- | Export | `export_start`, `export_list` |
68
- | Preview overlay | `preview_show`, `preview_seek`, `preview_hide` |
69
- | Async jobs | `job_wait`, `job_get` |
70
- | Escape hatch | `pandastudio_call` (raw verb.noun dispatch for anything not in the static list) |
71
-
72
- ## Idiomatic agent prompt
58
+ **148 tools**, full parity with the desktop UI — anything you can do by clicking, an agent can do by asking.
73
59
 
74
- ```
75
- Edit the two videos in /Users/me/Downloads/raw-clips/ — transcribe them,
76
- remove filler words, add a "How I Built This" intro card, enable bold-yellow
77
- captions, and export the final MP4. Show me the preview overlay so I can
78
- watch as you work.
79
- ```
60
+ | Category | Tools | What it covers |
61
+ |---|--:|---|
62
+ | `project_*` | 60 | Project lifecycle, clips, trims, zooms, speed, motion graphics, FX, lower thirds, background removal, spotlight, crop, layouts, aspect ratio, wallpaper, focal point, shorts layouts, podcast composites |
63
+ | `export_*` | 13 | Render to MP4, export library, AI thumbnails (generate/edit/revert), publish to YouTube + Instagram, find shots for shorts |
64
+ | `workspace_*` | 11 | Multi-client workspaces, brand kit, per-workspace project defaults |
65
+ | `transcript_*` | 10 | Transcribe (local, word-level), edit by transcript, remove fillers, remove silences, find bad takes, find/replace, insert/restore words |
66
+ | `system_*` | 9 | Status, command discovery, transcription language, local model management |
67
+ | `motion_*` | 8 | Motion-graphic templates, multi-scene storyboards, custom HTML compositions, frame verification |
68
+ | `youtube_*` / `instagram_*` | 9 | Account connection, channel listing, publishing |
69
+ | `asset_*` | 5 | Bundled music, sound effects, LUTs, transitions, FX |
70
+ | `llm_*` | 4 | Generate titles, descriptions, chapter timestamps from the transcript |
71
+ | `caption_*` | 3 | Toggle, templates, per-style overrides |
72
+ | `media_*` | 3 | Generate images, music, narration |
73
+ | `preview_*` / `job_*` / `agent_*` / `audio_*` / `timeline_*` | 14 | Live preview overlay, async job polling, agent sessions, audio cleanup, time-base conversion |
74
+
75
+ Plus `pandastudio_call` — a raw `verb.noun` escape hatch for anything not yet a first-class tool.
80
76
 
81
- The agent calls `project_new`, `transcript_transcribe`, `transcript_remove_fillers`, `motion_generate`, `project_add_motion_graphic`, `caption_toggle`, `caption_set_template`, `preview_show`, then `export_start`. ~12 tool calls, fully unattended.
77
+ ## Example
78
+
79
+ > Edit the two clips in `~/Downloads/raw/` — transcribe them, remove filler words,
80
+ > add a "How I Built This" intro card, turn on bold captions, and export the MP4.
81
+
82
+ The agent chains `project_new` → `transcript_transcribe` → `transcript_remove_fillers` → `motion_generate` → `project_add_motion_graphic` → `caption_toggle` → `caption_set_template` → `export_start`. Roughly a dozen tool calls, unattended.
82
83
 
83
84
  ## How it works
84
85
 
85
86
  ```
86
- MCP client (Cursor / Continue / Cline / Claude Desktop)
87
+ MCP client (Claude Desktop / Cursor / Cline / Codex)
87
88
  ↓ JSON-RPC over stdio
88
- @writepanda/mcp (this server)
89
+ @writepanda/mcp (this server)
89
90
  ↓ HTTP POST 127.0.0.1:7878/v1/call
90
91
  PandaStudio desktop app
91
- ↓ in-process function calls
92
- Editorial primitives (transcript, motion graphics, export, ...)
92
+ ↓ in-process calls
93
+ Editorial engine (transcript, motion graphics, render, publish)
93
94
  ```
94
95
 
95
- Every call is bearer-authenticated against the per-launch token PandaStudio writes to `~/.config/pandastudio/token` (Mac/Linux) or `%APPDATA%\pandastudio\token` (Windows). Loopback-only — nothing leaves your machine.
96
+ Every call is bearer-authenticated against the per-launch token PandaStudio writes to `~/.config/pandastudio/token` (macOS/Linux) or `%APPDATA%\pandastudio\token` (Windows). **Loopback only — nothing leaves your machine.** Credentials are discovered automatically from your local install; there is no token to paste.
96
97
 
97
98
  ## Licensing
98
99
 
99
- The MCP server honours the same license gate the desktop app does. With an expired trial and no license, only diagnostic tools work and every editorial tool returns `{ ok: false, details: { code: "trial_expired" } }`. Activate a license in the desktop app's Settings → License panel.
100
+ The server honours the same license gate as the desktop app. With an expired trial and no license, diagnostic tools still work and editorial tools return `{ ok: false, details: { code: "trial_expired" } }`. Activate in the app under **Settings → License**.
100
101
 
101
102
  ## Companions
102
103
 
103
- - **[`@writepanda/cli`](https://www.npmjs.com/package/@writepanda/cli)** — same surface as a shell command (`pandastudio system.status`). Use this when scripting from bash / CI.
104
- - **Bundled Claude Skill** — auto-loaded markdown instructions for Claude Code / Claude Desktop. Install via PandaStudio Settings → Local automation → Install Skill (drops into `~/.claude/skills/pandastudio/`).
104
+ - **[`@writepanda/cli`](https://www.npmjs.com/package/@writepanda/cli)** — the same surface as a shell command (`pandastudio system.status`). Better for bash/CI scripting, and cheaper on context than 148 tool schemas.
105
+ - **[PandaStudio Agent Skill](https://github.com/kamskans/pandastudio-skills)** — `npx skills add kamskans/pandastudio-skills`. The authoritative playbook: which verbs to call, in what order, with what defaults per destination.
105
106
 
106
107
  ## Documentation
107
108
 
108
- - Full surface + recipes: [writepanda.ai/cli](https://www.writepanda.ai/cli)
109
- - Source: [github.com/kamskans/openscreen](https://github.com/kamskans/openscreen)
109
+ - Full surface + recipes: **[writepanda.ai/cli](https://www.writepanda.ai/cli)**
110
+ - Desktop app: **[writepanda.ai](https://www.writepanda.ai)**
111
+
112
+ ## Note on this repository
113
+
114
+ This repo mirrors the published `@writepanda/mcp` package (the server, its README, and license) so the package has a public home for issues and MCP registries. The desktop app's source is private; the MCP server is MIT and published in full here and on npm.
110
115
 
111
116
  ## License
112
117
 
113
- MIT.
118
+ MIT
package/bin/server.mjs CHANGED
@@ -1221,6 +1221,72 @@ const TOOLS = [
1221
1221
  },
1222
1222
  command: "project.add-zoom",
1223
1223
  },
1224
+ {
1225
+ name: "project_add_caption_region",
1226
+ description:
1227
+ "Hide captions for a stretch of the timeline. Captions show everywhere by default when enabled, so this carves out an exception — use it when subtitles would cover something on screen, such as during a UI demo. Times are edited-timeline ms. Overlapping regions are fine.",
1228
+ inputSchema: {
1229
+ type: "object",
1230
+ properties: {
1231
+ id: { type: "string" },
1232
+ path: { type: "string" },
1233
+ atMs: { type: "number", description: "Edited-time start (ms)." },
1234
+ durationMs: { type: "number", description: "How long captions stay hidden (ms)." },
1235
+ expectedRevision: { type: "number" },
1236
+ },
1237
+ required: ["atMs", "durationMs"],
1238
+ },
1239
+ command: "project.add-caption-region",
1240
+ },
1241
+ {
1242
+ name: "project_remove_caption_region",
1243
+ description:
1244
+ "Remove a caption-suppression region so captions show there again. Find ids in project_read under editor.captionRegions[].id.",
1245
+ inputSchema: {
1246
+ type: "object",
1247
+ properties: {
1248
+ id: { type: "string" },
1249
+ path: { type: "string" },
1250
+ regionId: { type: "string", description: "Caption region id." },
1251
+ expectedRevision: { type: "number" },
1252
+ },
1253
+ required: ["regionId"],
1254
+ },
1255
+ command: "project.remove-caption-region",
1256
+ },
1257
+ {
1258
+ name: "project_add_mute_region",
1259
+ description:
1260
+ "Silence the video's own audio for a stretch of the timeline (the main voice/screen track). Background music and SFX overlays keep playing — mute touches only the main track, same as the editor. Times are edited-timeline ms; durationMs controls how much is muted. Overlapping regions are fine. Use to drop a cough, a name, or dead air without deleting the footage. Remove with project_remove_mute_region.",
1261
+ inputSchema: {
1262
+ type: "object",
1263
+ properties: {
1264
+ id: { type: "string" },
1265
+ path: { type: "string" },
1266
+ atMs: { type: "number", description: "Edited-time start (ms)." },
1267
+ durationMs: { type: "number", description: "How long the main audio stays silent (ms)." },
1268
+ expectedRevision: { type: "number" },
1269
+ },
1270
+ required: ["atMs", "durationMs"],
1271
+ },
1272
+ command: "project.add-mute-region",
1273
+ },
1274
+ {
1275
+ name: "project_remove_mute_region",
1276
+ description:
1277
+ "Remove a mute region so the main audio is audible there again. Find ids in project_read under editor.muteRegions[].id.",
1278
+ inputSchema: {
1279
+ type: "object",
1280
+ properties: {
1281
+ id: { type: "string" },
1282
+ path: { type: "string" },
1283
+ regionId: { type: "string", description: "Mute region id." },
1284
+ expectedRevision: { type: "number" },
1285
+ },
1286
+ required: ["regionId"],
1287
+ },
1288
+ command: "project.remove-mute-region",
1289
+ },
1224
1290
  {
1225
1291
  name: "project_add_spotlight",
1226
1292
  description:
@@ -1830,6 +1896,44 @@ const TOOLS = [
1830
1896
  },
1831
1897
  command: "project.set-webcam-layout",
1832
1898
  },
1899
+ {
1900
+ name: "project_set_webcam_style",
1901
+ description:
1902
+ "Set the camera tile's APPEARANCE (project-level): shape, border ring, drop shadow. Complements project_set_webcam_layout (position/size/crop). shape: auto (preset's responsive radius — default) | rectangle (square corners) | rounded (use cornerRadius) | circle (circular camera bubble). borderWidth 0-40 px at a 1080p reference (0 removes) + borderColor (CSS color). shadow 0-1 intensity (0 = none; omit = preset default). Fields merge into the current style; reset=true returns to preset defaults. Applies to the camera tile in picture-in-picture / side-by-side / vertical-stack (podcast grids keep co-equal tiles). Preview and export honor it identically.",
1903
+ inputSchema: {
1904
+ type: "object",
1905
+ properties: {
1906
+ id: { type: "string" },
1907
+ path: { type: "string" },
1908
+ shape: {
1909
+ type: "string",
1910
+ description: "auto | rectangle | rounded | circle",
1911
+ },
1912
+ cornerRadius: {
1913
+ type: "number",
1914
+ description: "Corner radius for shape=rounded, px at 1080p reference (0-200).",
1915
+ },
1916
+ borderWidth: {
1917
+ type: "number",
1918
+ description: "Border ring width, px at 1080p reference (0-40). 0 removes the border.",
1919
+ },
1920
+ borderColor: {
1921
+ type: "string",
1922
+ description: 'Border ring CSS color, e.g. "#ffffff".',
1923
+ },
1924
+ shadow: {
1925
+ type: "number",
1926
+ description: "Drop-shadow intensity 0-1. 0 = none. Omit to keep the preset default.",
1927
+ },
1928
+ reset: {
1929
+ type: "boolean",
1930
+ description: "true clears all camera-appearance overrides.",
1931
+ },
1932
+ expectedRevision: { type: "number" },
1933
+ },
1934
+ },
1935
+ command: "project.set-webcam-style",
1936
+ },
1833
1937
  {
1834
1938
  name: "project_set_crop",
1835
1939
  description:
@@ -2116,6 +2220,11 @@ const TOOLS = [
2116
2220
  description:
2117
2221
  "Optional anchor end (source ms). When set, the overlay's edited duration tracks the source-time span between anchorSourceMs and anchorSourceEndMs.",
2118
2222
  },
2223
+ transcribe: {
2224
+ type: "boolean",
2225
+ description:
2226
+ "Transcribe this audio and merge its words into the project transcript at the overlay's position. Use for VOICEOVER / narration so captions and transcript-driven edits work — audio overlays are otherwise never transcribed (only main-track clips are). Do NOT pass for music. Async: response includes transcribeJobId, poll job_get / job_wait.",
2227
+ },
2119
2228
  expectedRevision: { type: "number" },
2120
2229
  },
2121
2230
  required: ["audioPath"],
@@ -2203,6 +2312,30 @@ const TOOLS = [
2203
2312
  },
2204
2313
  command: "project.set-webcam-offset",
2205
2314
  },
2315
+ {
2316
+ name: "project_set_clip_volume",
2317
+ description:
2318
+ "Set a main-track clip's audio VOLUME (linear gain). volume=1 is the original level, 0 silences the clip, 2 is +6 dB (clamped 0-2). volume=1 clears the override. Identify the clip by clipId OR clipIndex (0-based, matching the order clipStates are returned by project_read). Applied in preview AND both export paths — no re-render of the audio file needed. Use to balance loudness across clips (e.g. boost a quiet second recording); for a hard mute pass volume=0.",
2319
+ inputSchema: {
2320
+ type: "object",
2321
+ properties: {
2322
+ id: { type: "string" },
2323
+ path: { type: "string" },
2324
+ clipId: { type: "string", description: "Clip id (or use clipIndex)" },
2325
+ clipIndex: {
2326
+ type: "number",
2327
+ description: "0-based clip position in the main track (alternative to clipId)",
2328
+ },
2329
+ volume: {
2330
+ type: "number",
2331
+ description: "Linear gain 0-2. 1 = original, 0 = silent, 2 = +6 dB.",
2332
+ },
2333
+ expectedRevision: { type: "number" },
2334
+ },
2335
+ required: ["volume"],
2336
+ },
2337
+ command: "project.set-clip-volume",
2338
+ },
2206
2339
  {
2207
2340
  name: "project_set_clip_layout",
2208
2341
  description:
@@ -2433,7 +2566,7 @@ const TOOLS = [
2433
2566
  thresholdMs: {
2434
2567
  type: "number",
2435
2568
  description:
2436
- "Gaps longer than this are trimmed. Default 500ms — same threshold as the UI Remove Silences button, so the agent removes the same silences a manual click would.",
2569
+ "Gaps longer than this are trimmed. Default 600ms — same threshold as the UI Remove Silences button, so the agent removes the same silences a manual click would.",
2437
2570
  },
2438
2571
  expectedRevision: { type: "number" },
2439
2572
  },
@@ -3004,6 +3137,33 @@ const TOOLS = [
3004
3137
  inputSchema: { type: "object", properties: {} },
3005
3138
  command: "export.list",
3006
3139
  },
3140
+ {
3141
+ name: "export_set_details",
3142
+ description:
3143
+ "Set an export's YouTube-facing details — title, description, and/or chapter timestamps (the fields in the export's Content tab). Pass only what you want to change. Call this when the user asks to update the title/description of an export. `id` is the export-library entry id; when the user is on the export page it is available to the agent as exportPage.entryId in the editor context (else call export_list to find it).",
3144
+ inputSchema: {
3145
+ type: "object",
3146
+ properties: {
3147
+ id: { type: "string", description: "Export-library entry id." },
3148
+ title: { type: "string", description: "New video title." },
3149
+ description: { type: "string", description: "New video description." },
3150
+ timestamps: {
3151
+ type: "array",
3152
+ description:
3153
+ "Chapter timestamps as an array of { timeMs, label } objects, sorted ascending. Omit to leave unchanged.",
3154
+ items: {
3155
+ type: "object",
3156
+ properties: {
3157
+ timeMs: { type: "number" },
3158
+ label: { type: "string" },
3159
+ },
3160
+ },
3161
+ },
3162
+ },
3163
+ required: ["id"],
3164
+ },
3165
+ command: "export.set-details",
3166
+ },
3007
3167
  {
3008
3168
  name: "export_generate_thumbnail",
3009
3169
  description:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@writepanda/mcp",
3
- "version": "1.109.0",
3
+ "version": "1.116.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",
@@ -18,11 +18,10 @@
18
18
  "homepage": "https://www.writepanda.ai/cli",
19
19
  "repository": {
20
20
  "type": "git",
21
- "url": "git+https://github.com/kamskans/openscreen.git",
22
- "directory": "packages/mcp"
21
+ "url": "git+https://github.com/kamskans/pandastudio-mcp.git"
23
22
  },
24
23
  "bugs": {
25
- "url": "https://github.com/kamskans/openscreen/issues"
24
+ "url": "https://github.com/kamskans/pandastudio-mcp/issues"
26
25
  },
27
26
  "type": "module",
28
27
  "engines": {