@writepanda/mcp 1.269.0 → 1.271.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 (2) hide show
  1. package/bin/server.mjs +284 -6
  2. package/package.json +1 -1
package/bin/server.mjs CHANGED
@@ -2020,11 +2020,11 @@ const TOOLS = [
2020
2020
  ...[
2021
2021
  [
2022
2022
  "status",
2023
- "Read the live podcast session code, guest link, recording and sharing state, the host's micMuted / cameraOff / devices, and each guest's name, role, state, micMuted, cameraOff and sharing.",
2023
+ "Read the live podcast session code, mode (hosting / producing), links (guest, call-in, host, producer), recording and sharing state, the desktop's micMuted / cameraOff / devices, each guest's name, role, state, micMuted, cameraOff and sharing, and people: everyone's role, stage (on / back), upNext, talkingPrivately and (while recording) whether they're recorded. While recording, takeStage is who was on stage when.",
2024
2024
  ],
2025
2025
  [
2026
2026
  "start-recording",
2027
- "Start recording the host and signal connected guests to record. Returns once recording has really started; fails with the reason otherwise.",
2027
+ "Start the take: everyone on stage records now, everyone else from their first time on stage (a producer backstage is never recorded). Returns once recording has really started; fails with the reason otherwise.",
2028
2028
  ],
2029
2029
  [
2030
2030
  "stop-recording",
@@ -2149,19 +2149,67 @@ const TOOLS = [
2149
2149
  {
2150
2150
  name: "podcast_set_stage",
2151
2151
  description:
2152
- "Put a participant (host | guest | guest-2 | guest-3) on air or backstage (onAir), or mute them in the stream only (muted). The recording is never affected.",
2152
+ "Put someone on stage or backstage (stage on|back, live or recording or before the show), queue them up next (upNext: they hear the show and get a cue), or mute them in the stream only (muted). Only on-stage people are in the stream, the recording and the edit; backstage they're recorded as silence. Ids: host (the show's host), producer (the desktop when a producer runs the show), cohost, guest, guest-2, guest-3, caller-N, producer-web-N (browser producers can't go on stage). See podcast_status.",
2153
2153
  inputSchema: {
2154
2154
  type: "object",
2155
2155
  properties: {
2156
2156
  waitSec: PODCAST_WAIT,
2157
2157
  participant: { type: "string" },
2158
- onAir: { type: "boolean" },
2158
+ stage: { type: "string", enum: ["on", "back"] },
2159
+ onAir: { type: "boolean", description: "Same as stage on (true) / back (false)." },
2160
+ upNext: { type: "boolean" },
2159
2161
  muted: { type: "boolean" },
2160
2162
  },
2161
2163
  required: ["participant"],
2162
2164
  },
2163
2165
  command: "podcast.set-stage",
2164
2166
  },
2167
+ {
2168
+ name: "podcast_talkback",
2169
+ description:
2170
+ 'Talk privately from the studio desktop (a producer running the show): its mic reaches only `to` (participant ids, or "stage" for everyone on stage), never the stream or the recording, until you call it with active false.',
2171
+ inputSchema: {
2172
+ type: "object",
2173
+ properties: {
2174
+ to: { type: "array", items: { type: "string" } },
2175
+ active: { type: "boolean", description: "false stops (default true)." },
2176
+ },
2177
+ },
2178
+ command: "podcast.talkback",
2179
+ },
2180
+ {
2181
+ name: "podcast_set_mode",
2182
+ description:
2183
+ "Who runs the show from this desktop: hosting (its operator hosts, on camera; default) or producing (a producer runs the studio backstage, never recorded unless they step on stage; the host joins by the host link from podcast_invite as host). Not while recording.",
2184
+ inputSchema: {
2185
+ type: "object",
2186
+ properties: { mode: { type: "string", enum: ["hosting", "producing"] } },
2187
+ required: ["mode"],
2188
+ },
2189
+ command: "podcast.set-mode",
2190
+ },
2191
+ {
2192
+ name: "podcast_host_control",
2193
+ description:
2194
+ "Give the host (host link) control on their page, or take it back: Record, bring people on or backstage, next segment. Graphics and going live stay with the producer. Off by default.",
2195
+ inputSchema: {
2196
+ type: "object",
2197
+ properties: { on: { type: "boolean" } },
2198
+ required: ["on"],
2199
+ },
2200
+ command: "podcast.host-control",
2201
+ },
2202
+ {
2203
+ name: "podcast_cue_host",
2204
+ description:
2205
+ 'Show the host a cue card on their page ("Wrap up in 2", "Ask about pricing"). Never on air. Needs the host connected by the host link.',
2206
+ inputSchema: {
2207
+ type: "object",
2208
+ properties: { text: { type: "string", description: "Up to 280 characters." } },
2209
+ required: ["text"],
2210
+ },
2211
+ command: "podcast.cue-host",
2212
+ },
2165
2213
  {
2166
2214
  name: "podcast_show_overlay",
2167
2215
  description:
@@ -2290,10 +2338,214 @@ const TOOLS = [
2290
2338
  "YouTube title when it should differ from the episode title; empty = follow it.",
2291
2339
  },
2292
2340
  draftRundown: { type: "boolean" },
2341
+ mode: {
2342
+ type: "string",
2343
+ enum: ["hosting", "producing"],
2344
+ description:
2345
+ "producing: a producer runs the studio, the host joins by the host link (podcast_invite as host).",
2346
+ },
2347
+ host: {
2348
+ type: "object",
2349
+ description: "Producing: the show's host (their lower third).",
2350
+ properties: {
2351
+ name: { type: "string" },
2352
+ email: { type: "string" },
2353
+ role: { type: "string" },
2354
+ },
2355
+ required: ["name"],
2356
+ },
2357
+ crew: {
2358
+ type: "array",
2359
+ description: "The production side: producers, editor, client.",
2360
+ items: {
2361
+ type: "object",
2362
+ properties: {
2363
+ name: { type: "string" },
2364
+ email: { type: "string" },
2365
+ role: { type: "string" },
2366
+ },
2367
+ required: ["name"],
2368
+ },
2369
+ },
2370
+ hostControl: {
2371
+ type: "boolean",
2372
+ description: "Producing: the host gets Record, stage and next segment on their page.",
2373
+ },
2374
+ showId: { type: "string", description: "The show (series) it belongs to." },
2293
2375
  },
2294
2376
  },
2295
2377
  command: "podcast.schedule",
2296
2378
  },
2379
+ {
2380
+ name: "show_list",
2381
+ description:
2382
+ "Podcast shows (series) in the current workspace. A workspace is the client; a show is one of its series, with defaults for new episodes and a delivery after each recording.",
2383
+ inputSchema: { type: "object", properties: {} },
2384
+ command: "show.list",
2385
+ },
2386
+ {
2387
+ name: "show_create",
2388
+ description:
2389
+ "Create a podcast show in the current workspace. Episodes scheduled with its showId (podcast_schedule) start from its mode (hosting / producing), host, crew, host control, run-of-show template, recipe and destinations. A delivery with edit / MP3 / Shorts / upload proposes a delivery routine the user turns on.",
2390
+ inputSchema: {
2391
+ type: "object",
2392
+ properties: {
2393
+ name: { type: "string" },
2394
+ description: { type: "string" },
2395
+ mode: { type: "string", enum: ["hosting", "producing"] },
2396
+ host: {
2397
+ type: "object",
2398
+ properties: {
2399
+ name: { type: "string" },
2400
+ email: { type: "string" },
2401
+ role: { type: "string" },
2402
+ },
2403
+ required: ["name"],
2404
+ },
2405
+ crew: {
2406
+ type: "array",
2407
+ items: {
2408
+ type: "object",
2409
+ properties: {
2410
+ name: { type: "string" },
2411
+ email: { type: "string" },
2412
+ role: { type: "string" },
2413
+ },
2414
+ required: ["name"],
2415
+ },
2416
+ },
2417
+ hostControl: { type: "boolean" },
2418
+ recipeId: { type: "string", description: "The edit's recipe (recipe_list); empty clears." },
2419
+ rundownTemplate: { type: "object", description: "Run of show new episodes start from." },
2420
+ destinationIds: { type: "array", items: { type: "string" } },
2421
+ delivery: {
2422
+ type: "object",
2423
+ description:
2424
+ "After each recorded episode: folder (absolute) gets rawFiles (each person's own recording + the live program); edit, audioMaster (MP3), shorts (0-10) and youtube {accountId, privacy} run as a delivery routine the user turns on. null clears.",
2425
+ properties: {
2426
+ folder: { type: "string" },
2427
+ rawFiles: { type: "boolean" },
2428
+ edit: { type: "boolean" },
2429
+ audioMaster: { type: "boolean" },
2430
+ shorts: { type: "number" },
2431
+ youtube: {
2432
+ type: "object",
2433
+ properties: {
2434
+ accountId: { type: "string" },
2435
+ privacy: { type: "string", enum: ["private", "unlisted", "public"] },
2436
+ },
2437
+ required: ["accountId"],
2438
+ },
2439
+ notes: { type: "string" },
2440
+ },
2441
+ },
2442
+ },
2443
+ required: ["name"],
2444
+ },
2445
+ command: "show.create",
2446
+ },
2447
+ {
2448
+ name: "show_update",
2449
+ description: "Change a show's name, defaults or delivery (only the fields given).",
2450
+ inputSchema: {
2451
+ type: "object",
2452
+ properties: {
2453
+ id: { type: "string" },
2454
+ name: { type: "string" },
2455
+ description: { type: "string" },
2456
+ mode: { type: "string", enum: ["hosting", "producing"] },
2457
+ host: {
2458
+ type: "object",
2459
+ properties: {
2460
+ name: { type: "string" },
2461
+ email: { type: "string" },
2462
+ role: { type: "string" },
2463
+ },
2464
+ required: ["name"],
2465
+ },
2466
+ crew: {
2467
+ type: "array",
2468
+ items: {
2469
+ type: "object",
2470
+ properties: {
2471
+ name: { type: "string" },
2472
+ email: { type: "string" },
2473
+ role: { type: "string" },
2474
+ },
2475
+ required: ["name"],
2476
+ },
2477
+ },
2478
+ hostControl: { type: "boolean" },
2479
+ recipeId: { type: "string", description: "The edit's recipe (recipe_list); empty clears." },
2480
+ rundownTemplate: { type: "object", description: "Run of show new episodes start from." },
2481
+ destinationIds: { type: "array", items: { type: "string" } },
2482
+ delivery: {
2483
+ type: "object",
2484
+ description:
2485
+ "After each recorded episode: folder (absolute) gets rawFiles (each person's own recording + the live program); edit, audioMaster (MP3), shorts (0-10) and youtube {accountId, privacy} run as a delivery routine the user turns on. null clears.",
2486
+ properties: {
2487
+ folder: { type: "string" },
2488
+ rawFiles: { type: "boolean" },
2489
+ edit: { type: "boolean" },
2490
+ audioMaster: { type: "boolean" },
2491
+ shorts: { type: "number" },
2492
+ youtube: {
2493
+ type: "object",
2494
+ properties: {
2495
+ accountId: { type: "string" },
2496
+ privacy: { type: "string", enum: ["private", "unlisted", "public"] },
2497
+ },
2498
+ required: ["accountId"],
2499
+ },
2500
+ notes: { type: "string" },
2501
+ },
2502
+ },
2503
+ },
2504
+ required: ["id"],
2505
+ },
2506
+ command: "show.update",
2507
+ },
2508
+ {
2509
+ name: "show_set_delivery",
2510
+ description:
2511
+ "What to hand over after each recorded episode of a show: raw files to a folder (copied right after recording), plus the edit, MP3, Shorts and YouTube upload as a delivery routine the user turns on.",
2512
+ inputSchema: {
2513
+ type: "object",
2514
+ properties: {
2515
+ id: { type: "string" },
2516
+ delivery: {
2517
+ type: "object",
2518
+ description:
2519
+ "After each recorded episode: folder (absolute) gets rawFiles (each person's own recording + the live program); edit, audioMaster (MP3), shorts (0-10) and youtube {accountId, privacy} run as a delivery routine the user turns on. null clears.",
2520
+ properties: {
2521
+ folder: { type: "string" },
2522
+ rawFiles: { type: "boolean" },
2523
+ edit: { type: "boolean" },
2524
+ audioMaster: { type: "boolean" },
2525
+ shorts: { type: "number" },
2526
+ youtube: {
2527
+ type: "object",
2528
+ properties: {
2529
+ accountId: { type: "string" },
2530
+ privacy: { type: "string", enum: ["private", "unlisted", "public"] },
2531
+ },
2532
+ required: ["accountId"],
2533
+ },
2534
+ notes: { type: "string" },
2535
+ },
2536
+ },
2537
+ },
2538
+ required: ["id", "delivery"],
2539
+ },
2540
+ command: "show.set-delivery",
2541
+ },
2542
+ {
2543
+ name: "show_delete",
2544
+ description:
2545
+ "Delete a show (ask the user first). Its episodes and files stay; its delivery routine is removed.",
2546
+ inputSchema: { type: "object", properties: { id: { type: "string" } }, required: ["id"] },
2547
+ command: "show.delete",
2548
+ },
2297
2549
  {
2298
2550
  name: "podcast_list_upcoming",
2299
2551
  description:
@@ -2324,13 +2576,14 @@ const TOOLS = [
2324
2576
  {
2325
2577
  name: "podcast_invite",
2326
2578
  description:
2327
- "An episode's guest invite: join link, invite text and a calendar invite (.ics, needs a date). out writes the .ics there. Don't send it yourself unless the user asks.",
2579
+ "An episode's invite: the link, invite text and a calendar invite (.ics, needs a date). as: guest (default), host (the host link, when a producer runs the studio) or producer (a browser producer link: watch, talk privately, approve the AI producer). out writes the .ics there. Don't send it yourself unless the user asks.",
2328
2580
  inputSchema: {
2329
2581
  type: "object",
2330
2582
  properties: {
2331
2583
  path: { type: "string" },
2332
2584
  id: { type: "string" },
2333
2585
  sessionCode: { type: "string" },
2586
+ as: { type: "string", enum: ["guest", "host", "producer"] },
2334
2587
  out: { type: "string", description: "Absolute path ending in .ics." },
2335
2588
  hostName: { type: "string" },
2336
2589
  },
@@ -5140,6 +5393,24 @@ const TOOLS = [
5140
5393
  },
5141
5394
  command: "project.set-clip-chroma-key",
5142
5395
  },
5396
+ {
5397
+ name: "project_set_clip_flip",
5398
+ description:
5399
+ "Flip a main-track clip's picture: fixes a recording that came out upside down (horizontal + vertical = turned 180 degrees, e.g. a monitor mounted upside down) or mirrored (horizontal). Corrects the source: crops, cursor and zoom focus read the flipped picture. Omitted axes keep their value; both false removes it. Check with project_render_frame.",
5400
+ inputSchema: {
5401
+ type: "object",
5402
+ properties: {
5403
+ id: { type: "string" },
5404
+ path: { type: "string" },
5405
+ clipId: { type: "string" },
5406
+ horizontal: { type: "boolean", description: "Mirror left to right." },
5407
+ vertical: { type: "boolean", description: "Mirror top to bottom." },
5408
+ expectedRevision: { type: "number" },
5409
+ },
5410
+ required: ["clipId"],
5411
+ },
5412
+ command: "project.set-clip-flip",
5413
+ },
5143
5414
  {
5144
5415
  name: "project_set_clip_kind",
5145
5416
  description:
@@ -5459,7 +5730,7 @@ const TOOLS = [
5459
5730
  {
5460
5731
  name: "transcript_transcribe",
5461
5732
  description:
5462
- "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[]). 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).",
5733
+ "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. 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).",
5463
5734
  inputSchema: {
5464
5735
  type: "object",
5465
5736
  properties: {
@@ -7531,6 +7802,13 @@ const TOOLS = [
7531
7802
  description:
7532
7803
  "{ 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.",
7533
7804
  },
7805
+ id: {
7806
+ type: "string",
7807
+ description:
7808
+ "Project the edit was made in (default: the one open in the editor). Without lookFrames, three stills of it become the recipe's cover on Home and the look the next run matches.",
7809
+ },
7810
+ path: { type: "string", description: "Same as id, by project file path." },
7811
+ stills: { type: "boolean", description: "false = save without stills of the edit." },
7534
7812
  },
7535
7813
  required: ["recipe"],
7536
7814
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@writepanda/mcp",
3
- "version": "1.269.0",
3
+ "version": "1.271.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",