premiere-pro-mcp 1.14.1 → 1.14.2

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 (56) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/README.md +32 -20
  3. package/artifacts/MCPBridgeCEP.zxp +0 -0
  4. package/cep-plugin/CSXS/manifest.xml +3 -3
  5. package/cep-plugin/index.html +1 -1
  6. package/cep-plugin/main.js +36 -0
  7. package/cep-plugin/updater.cjs +1 -1
  8. package/dist/bridge/file-bridge.d.ts +20 -0
  9. package/dist/bridge/file-bridge.js +53 -0
  10. package/dist/bridge/script-builder.js +30 -4
  11. package/dist/http-server.js +10 -9
  12. package/dist/index.js +6 -6
  13. package/dist/platform-capabilities.d.ts +54 -0
  14. package/dist/platform-capabilities.js +47 -0
  15. package/dist/security/capabilities.js +1 -0
  16. package/dist/server.d.ts +1 -1
  17. package/dist/server.js +29 -11
  18. package/dist/tools/advanced.d.ts +28 -3
  19. package/dist/tools/advanced.js +166 -71
  20. package/dist/tools/audio.d.ts +118 -1
  21. package/dist/tools/audio.js +208 -54
  22. package/dist/tools/clipboard.js +28 -4
  23. package/dist/tools/discovery.js +3 -3
  24. package/dist/tools/export.d.ts +5 -0
  25. package/dist/tools/export.js +70 -22
  26. package/dist/tools/health.d.ts +54 -0
  27. package/dist/tools/health.js +13 -4
  28. package/dist/tools/media.d.ts +5 -0
  29. package/dist/tools/media.js +16 -3
  30. package/dist/tools/metadata.d.ts +16 -2
  31. package/dist/tools/metadata.js +81 -13
  32. package/dist/tools/playhead.js +4 -3
  33. package/dist/tools/project.d.ts +16 -1
  34. package/dist/tools/project.js +169 -33
  35. package/dist/tools/recovery.d.ts +2 -0
  36. package/dist/tools/recovery.js +4 -2
  37. package/dist/tools/sequence.js +113 -43
  38. package/dist/tools/text.d.ts +5 -0
  39. package/dist/tools/text.js +21 -4
  40. package/dist/tools/track-targeting.js +81 -14
  41. package/dist/tools/utility.d.ts +6 -3
  42. package/dist/tools/utility.js +132 -43
  43. package/dist/tools/uxp.d.ts +153 -0
  44. package/dist/tools/uxp.js +69 -0
  45. package/dist/workflows/tool-metadata.d.ts +1 -1
  46. package/dist/workflows/tool-metadata.js +1 -0
  47. package/dist/workflows/tool-packs.js +2 -0
  48. package/docs/mcp-2026-07-28-capabilities.md +87 -0
  49. package/docs/supported-actions.md +25 -20
  50. package/package.json +11 -8
  51. package/scripts/generate-supported-actions.mjs +1 -2
  52. package/uxp-plugin/README.md +2 -1
  53. package/uxp-plugin/commands.cjs +49 -1
  54. package/uxp-plugin/index.cjs +3 -1
  55. package/uxp-plugin/manifest.json +1 -1
  56. package/uxp-plugin/protocol.cjs +5 -0
package/CHANGELOG.md CHANGED
@@ -6,6 +6,44 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [1.14.2] - 2026-08-28
10
+
11
+ ### Added
12
+
13
+ - Added dual-era MCP serving with the stable TypeScript SDK v2: modern
14
+ `2026-07-28` discovery and stateless request handling over HTTP and stdio,
15
+ with legacy protocol compatibility through `2025-11-25`.
16
+ - Added validated modern routing headers, cache hints, subscription-listen
17
+ support, a formal Premiere extension capability, and a machine-readable MCP
18
+ protocol report in `get_capabilities`.
19
+ - Added an evidence-backed capability matrix covering implemented, SDK-ready,
20
+ external-boundary, deprecated, and intentionally unsupported MCP surfaces.
21
+
22
+ ### Changed
23
+
24
+ - Migrated tool, resource, prompt, client, stdio, and Node HTTP integrations
25
+ from `@modelcontextprotocol/sdk` v1 to the split v2 packages and Standard
26
+ Schema registration APIs.
27
+
28
+ ### Fixed
29
+
30
+ - Restored strict JSON Schema 2020-12 tool compatibility and corrected legacy
31
+ CEP argument contracts, Premiere Time units, Adobe Media Encoder output
32
+ paths, active-sequence verification, metadata readback, XMP patch merging,
33
+ and single-extension UXP frame exports.
34
+ - Replaced false-success responses for structural edits, duplicate
35
+ consolidation, effect copying, nesting, deletion, and other host mutations
36
+ with verified outcomes or explicit fail-closed errors.
37
+ - Added bounded UXP selection lift and native transition adapters while keeping
38
+ unavailable track-management and global-redo capabilities explicit.
39
+
40
+ ### Safety
41
+
42
+ - Live Premiere resources remain private and uncached, and tool discovery is
43
+ private-cache scoped. The tasks extension and OAuth discovery are not
44
+ advertised without the durable storage and authorization infrastructure they
45
+ require.
46
+
9
47
  ## [1.14.1] - 2026-08-27
10
48
 
11
49
  ### Fixed
package/README.md CHANGED
@@ -8,11 +8,11 @@
8
8
 
9
9
  **Give compatible AI assistants structured control over supported Adobe Premiere Pro workflows.**
10
10
 
11
- 319 core tools across 37 modules, 14 resources, and 11 guided workflows. A connected UXP host adds 50 capability-gated tools.
11
+ 320 core tools across 37 modules, 14 resources, and 11 guided workflows. A connected UXP host adds 54 capability-gated tools.
12
12
 
13
13
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
14
14
  [![Node.js](https://img.shields.io/badge/Node.js-20.19%2B-green.svg)](https://nodejs.org)
15
- [![MCP](https://img.shields.io/badge/MCP-1.29-purple.svg)](https://modelcontextprotocol.io)
15
+ [![MCP](https://img.shields.io/badge/MCP-2026--07--28-purple.svg)](https://modelcontextprotocol.io/specification/2026-07-28)
16
16
  [![npm](https://img.shields.io/npm/v/premiere-pro-mcp.svg)](https://www.npmjs.com/package/premiere-pro-mcp)
17
17
  [![Fly.io](https://img.shields.io/badge/Fly.io-deployed-7C3AED.svg)](https://premiere-pro-mcp.fly.dev)
18
18
  [![Premiere Pro](https://img.shields.io/badge/Premiere%20Pro-2020--2026-9999FF.svg)](https://www.adobe.com/products/premiere.html)
@@ -31,9 +31,9 @@ An [MCP (Model Context Protocol)](https://modelcontextprotocol.io) server that l
31
31
  "Add the B-roll clips to V2, apply a cross dissolve between each, color correct them to match the A-roll, and export a 1080p ProRes."
32
32
  ```
33
33
 
34
- The AI handles the entire workflow through 319 core tools spanning the supported ExtendScript, QE DOM, local media and interchange analysis, revisioned project-context retrieval, safe edit-planning, project-intake preview, review handoff, and connection-verification surfaces. A compatible, authenticated UXP panel adds 50 documented, capability-gated tools without replacing the production CEP bridge.
34
+ The AI handles the entire workflow through 320 core tools spanning the supported ExtendScript, QE DOM, local media and interchange analysis, revisioned project-context retrieval, safe edit-planning, project-intake preview, review handoff, and connection-verification surfaces. A compatible, authenticated UXP panel adds 54 documented, capability-gated tools without replacing the production CEP bridge.
35
35
 
36
- ### Latest release: 1.14.1
36
+ ### Latest release: 1.14.2
37
37
 
38
38
  - **Focused discovery:** compatible MCP clients can select essential,
39
39
  inspection, delivery, or captions tool packs instead of beginning with the
@@ -47,9 +47,17 @@ The AI handles the entire workflow through 319 core tools spanning the supported
47
47
  tarball, keeping the validated distribution path compatible with the current
48
48
  npm CLI.
49
49
 
50
- See the [v1.14.1 release notes](https://github.com/leancoderkavy/premiere-pro-mcp/releases/tag/v1.14.1)
50
+ See the [v1.14.2 release notes](https://github.com/leancoderkavy/premiere-pro-mcp/releases/tag/v1.14.2)
51
51
  for complete details. Live installation in Premiere Pro still requires host verification.
52
52
 
53
+ ### Current MCP protocol support
54
+
55
+ The server uses the stable TypeScript SDK v2 and serves the `2026-07-28`
56
+ stateless protocol over HTTP and stdio, while retaining legacy MCP compatibility
57
+ through `2025-11-25`. Modern clients receive discovery, validated routing headers,
58
+ cache hints, subscription-stream support, and the formal Premiere extension
59
+ capability. See the [complete MCP capability and boundary report](docs/mcp-2026-07-28-capabilities.md).
60
+
53
61
  ---
54
62
 
55
63
  ## For editors evaluating an AI workflow
@@ -70,15 +78,20 @@ guide](https://premiere-pro-mcp.com/premiere-pro-collaboration-workflow/) before
70
78
  you evaluate an MCP path. It links the relevant Adobe guidance, makes no project
71
79
  inspection request, and ends with the same read-only connection check.
72
80
 
81
+ For a concrete first Project Intake preview, choose one of the three
82
+ [schema-checked, no-sensitive-data starter templates](https://premiere-pro-mcp.com/project-intake/#starter-template).
83
+ They are evaluation samples only: a human policy owner must review and replace
84
+ their bins, media rules, and organization rules before a facility uses one.
85
+
73
86
  ---
74
87
 
75
88
  ## Quick Start
76
89
 
77
90
  ### Easiest supported path: Claude Desktop
78
91
 
79
- 1. Download the current [Claude Desktop bundle (`.mcpb`)](https://github.com/leancoderkavy/premiere-pro-mcp/releases/download/v1.14.1/premiere-pro-mcp-1.14.1.mcpb).
92
+ 1. Download the current [Claude Desktop bundle (`.mcpb`)](https://github.com/leancoderkavy/premiere-pro-mcp/releases/download/v1.14.2/premiere-pro-mcp-1.14.2.mcpb).
80
93
  2. In Claude Desktop, open **Settings > Extensions > Advanced settings > Install Extension**, select the downloaded bundle, and restart Claude Desktop.
81
- 3. Download the separate [signed Premiere connector (`.zxp`)](https://github.com/leancoderkavy/premiere-pro-mcp/releases/download/v1.14.1/MCPBridgeCEP.zxp). Open it with your trusted ZXP installer. If your computer has no ZXP installer, use the npm connector installer in **Advanced setup** below.
94
+ 3. Download the separate [signed Premiere connector (`.zxp`)](https://github.com/leancoderkavy/premiere-pro-mcp/releases/download/v1.14.2/MCPBridgeCEP.zxp). Open it with your trusted ZXP installer. If your computer has no ZXP installer, use the npm connector installer in **Advanced setup** below.
82
95
  4. Restart Premiere, open a project, then open **Window > Extensions > MCP for Adobe Premiere Pro**.
83
96
  5. In Claude, enter: `Safely check my Premiere connection with verify_premiere_connection. Make no changes.`
84
97
 
@@ -325,11 +338,11 @@ From a clone of this repository:
325
338
  ```bash
326
339
  codex plugin marketplace add .
327
340
  codex plugin add premiere-pro@premiere-pro-mcp
328
- npx -y premiere-pro-mcp@1.14.1 --install-cep
341
+ npx -y premiere-pro-mcp@1.14.2 --install-cep
329
342
  ```
330
343
 
331
344
  Restart Premiere Pro and start a new Codex session after installation. The plugin
332
- launches `premiere-pro-mcp@1.14.1` through `npx`; the separate CEP installation is
345
+ launches `premiere-pro-mcp@1.14.2` through `npx`; the separate CEP installation is
333
346
  required because the MCP server communicates with the running Premiere host through
334
347
  the local bridge.
335
348
 
@@ -349,7 +362,7 @@ For Claude Code, add this repository as a marketplace and install the plugin:
349
362
  Then install the Premiere bridge and start a new Claude Code session:
350
363
 
351
364
  ```bash
352
- npx -y premiere-pro-mcp@1.14.1 --install-cep
365
+ npx -y premiere-pro-mcp@1.14.2 --install-cep
353
366
  ```
354
367
 
355
368
  The Claude Code package lives in
@@ -388,7 +401,7 @@ installed separately.
388
401
  QE-backed tools are reported as `experimental` because QE is undocumented and can vary between Premiere builds. Authority availability is reported separately from implementation support, so disabling `edit`, for example, does not incorrectly label editing tools as unsupported. Static metadata never claims that a Premiere operation succeeded; use `ping` and inspect each tool result for runtime evidence.
389
402
 
390
403
  MCP `tools/list` is filtered to the active authority profile. The default
391
- `inspect,edit,export,filesystem` profile advertises 317 of the 319 registered
404
+ `inspect,edit,export,filesystem` profile advertises 318 of the 320 registered
392
405
  tools and omits `execute_extendscript` and `evaluate_expression`, which require
393
406
  explicit `unsafe-script` authority. `ping` and `get_capabilities` remain visible
394
407
  under every profile so a restricted or misconfigured server can still explain
@@ -491,7 +504,7 @@ PREMIERE_UXP_TOKEN="replace-with-a-long-random-secret" premiere-pro-mcp
491
504
 
492
505
  Enter the same token in the UXP panel. The listener binds only to `127.0.0.1:7777`, authenticates the WebSocket upgrade, requires a versioned capability handshake, correlates concurrent requests, and fails pending work on timeout or disconnect. Set `PREMIERE_UXP_PORT` to use another loopback port.
493
506
 
494
- When enabled, MCP discovery includes the original 19 UXP tools, 21 consolidated stable workflows, and eight third-wave tools. The first expansion covers effects, deterministic timeline selection, selection batches, scene detection, proxy/ingest, relink, metadata, color conformance, Source Monitor audition, storage, and least-privilege workspace access. The second adds Project-panel selection, marker CRUD, bin organization, sequence settings, imports, typed effect parameters/keyframes, track-item transforms, SequenceEditor timeline edits, sequence lifecycle, and AME encoding. The third wave begins with a redacted event journal, conservative AME terminal receipts, explicit host-readiness gates, safe multi-project sessions, lease-based growing-media control, namespaced workflow checkpoints, bounded media-health maintenance, caption-aware track mute state, and transactional source trim/framing documented in [the third-wave workflow matrix](docs/third-wave-uxp-workflows.md). A separate [hybrid benchmark gate](docs/uxp-hybrid-benchmark.md) keeps native acceleration disabled until reproducible cross-platform evidence exists. See also [the first stable workflow matrix](docs/uxp-stable-workflows.md) and [the next-ten workflow matrix](docs/uxp-next-ten-workflows.md). Commands are advertised only while the authenticated local UXP bridge is connected; the host capability handshake remains the authority for support in the running Premiere build. A failed UXP command is never silently retried through CEP because the first operation may have partially succeeded.
507
+ When enabled, MCP discovery includes 54 capability-gated UXP additions. The first expansion covers effects, deterministic timeline selection, selection batches, scene detection, proxy/ingest, relink, metadata, color conformance, Source Monitor audition, storage, and least-privilege workspace access. The second adds Project-panel selection, marker CRUD, bin organization, sequence settings, imports, typed effect parameters/keyframes, track-item transforms, SequenceEditor timeline edits, sequence lifecycle, and AME encoding. The third wave begins with a redacted event journal, conservative AME terminal receipts, explicit host-readiness gates, safe multi-project sessions, lease-based growing-media control, namespaced workflow checkpoints, bounded media-health maintenance, caption-aware track mute state, and transactional source trim/framing documented in [the third-wave workflow matrix](docs/third-wave-uxp-workflows.md). The bounded migration surface also includes a non-ripple selected-item lift plus native video-transition listing and transactions; it does not claim direct empty-track create/delete or global redo support. A separate [hybrid benchmark gate](docs/uxp-hybrid-benchmark.md) keeps native acceleration disabled until reproducible cross-platform evidence exists. See also [the first stable workflow matrix](docs/uxp-stable-workflows.md) and [the next-ten workflow matrix](docs/uxp-next-ten-workflows.md). Commands are advertised only while the authenticated local UXP bridge is connected; the host capability handshake remains the authority for support in the running Premiere build. A failed UXP command is never silently retried through CEP because the first operation may have partially succeeded.
495
508
 
496
509
  The panel now requests access to one operator-selected workspace instead of declaring full filesystem access. Choose the folder in the panel before invoking a path-based UXP workflow. Media, relink, preset, export, and Source Monitor file paths must remain inside it; the persistent capability token and native root path are never returned over MCP. Lexical containment alone cannot exclude symlink, junction, or reparse-point escapes, and Adobe's request-scoped UXP filesystem API does not document canonical-path resolution. Builds without a host-supplied canonical resolver therefore advertise path-based UXP commands as unsupported and fail closed at invocation; use the existing CEP fallback for those operations.
497
510
 
@@ -566,11 +579,11 @@ The file-based IPC bridge is simple, reliable, and works across macOS and Window
566
579
 
567
580
  ---
568
581
 
569
- ## Tools (319 core total; 317 under the default profile; 367 with a connected UXP bridge)
582
+ ## Tools (320 core total; 318 under the default profile; 372 with a connected UXP bridge)
570
583
 
571
584
  The [complete supported-actions catalog](docs/supported-actions.md) lists every
572
585
  registered core tool, the two tools restricted behind explicit `unsafe-script`
573
- authority, and all 50 authenticated UXP additions with their current action or mode
586
+ authority, and all 54 authenticated UXP additions with their current action or mode
574
587
  values. It is generated from the same MCP registration surface returned to clients;
575
588
  the tables below are a shorter workflow-oriented overview.
576
589
 
@@ -614,8 +627,7 @@ the tables below are a shorter workflow-oriented overview.
614
627
  | `ripple_delete` | Remove clip and close gap (QE) |
615
628
  | `roll_edit` / `slide_edit` / `slip_edit` | Professional trim modes (QE) |
616
629
  | `move_clip_to_track` | Move between tracks (QE) |
617
- | `reverse_clip` | Reverse direction (QE, host-dependent) |
618
- | `speed_change` / `set_clip_speed_qe` | Unavailable: Premiere has no supported scripting API for changing clip speed |
630
+ | `reverse_clip` / `speed_change` / `set_clip_speed_qe` | Unavailable: Premiere has no supported scripting API for changing a timeline clip's speed or direction |
619
631
  | `split_clip` / `trim_clip` / `move_clip` | Basic edits; trim verifies source points and visible timeline edges |
620
632
  | `set_clip_properties` | Opacity, scale, rotation, position (speed requests fail before mutation) |
621
633
  | `link_selection` / `unlink_selection` | Link/unlink A/V |
@@ -629,8 +641,8 @@ the tables below are a shorter workflow-oriented overview.
629
641
  > to blend adjacent source frames. See [issue #21](https://github.com/leancoderkavy/premiere-pro-mcp/issues/21).
630
642
 
631
643
  > **Speed, caption, and visual-keyframe boundaries:** Premiere Pro 26.3 exposes no supported
632
- > scripting setter or Time Remapping component for timeline-clip speed. `speed_change`,
633
- > `set_clip_speed_qe`, and `set_clip_properties` with `speed` now stop before host mutation;
644
+ > scripting setter or Time Remapping component for timeline-clip speed or direction. `reverse_clip`,
645
+ > `speed_change`, `set_clip_speed_qe`, and `set_clip_properties` with `speed` now stop before host mutation;
634
646
  > use the Speed/Duration UI or pre-render retimed media. `add_text_overlay` likewise stops
635
647
  > before mutation because a raw-text-to-caption API is not exposed; import an `.srt`/`.vtt`
636
648
  > and use `create_caption_track`, or use a MOGRT/PNG overlay. Keyframe and caption-track
@@ -731,7 +743,7 @@ than presenting UI-only operations as available tools.
731
743
  | `set_offline` / `has_proxy` / `detach_proxy` | Offline/proxy management |
732
744
  | `set_override_frame_rate` | Override FPS |
733
745
  | `set_scale_to_frame_size` | Auto-scale to sequence frame |
734
- | `get_xmp_metadata` / `set_xmp_metadata` | Raw XMP access |
746
+ | `get_xmp_metadata` / `set_xmp_metadata` | Raw XMP access; writes merge a well-formed patch without removing unrelated fields |
735
747
  | `get_color_space` | Color space info |
736
748
 
737
749
  ### Sequence Management (11)
@@ -895,7 +907,7 @@ premiere-pro-mcp/
895
907
  ├── src/
896
908
  │ ├── index.ts # Entry point — stdio transport setup
897
909
  │ ├── http-server.ts # Entry point — HTTP/SSE transport (Fly.io / remote)
898
- │ ├── server.ts # MCP server — registers 319 tools, filtered by authority profile
910
+ │ ├── server.ts # MCP server — registers 320 tools, filtered by authority profile
899
911
  │ ├── bridge/
900
912
  │ │ ├── file-bridge.ts # File-based IPC (write .jsx, poll .json)
901
913
  │ │ └── script-builder.ts # ExtendScript generator with ES3 helpers
Binary file
@@ -1,8 +1,8 @@
1
1
  <?xml version="1.0" encoding="UTF-8"?>
2
- <ExtensionManifest Version="7.0" ExtensionBundleId="com.mcp.premiere.bridge" ExtensionBundleVersion="1.14.1" ExtensionBundleName="MCP for Adobe Premiere Pro">
2
+ <ExtensionManifest Version="7.0" ExtensionBundleId="com.mcp.premiere.bridge" ExtensionBundleVersion="1.14.2" ExtensionBundleName="MCP for Adobe Premiere Pro">
3
3
  <ExtensionList>
4
- <Extension Id="com.mcp.premiere.bridge.panel" Version="1.14.1"/>
5
- <Extension Id="com.mcp.premiere.bridge.headless" Version="1.14.1"/>
4
+ <Extension Id="com.mcp.premiere.bridge.panel" Version="1.14.2"/>
5
+ <Extension Id="com.mcp.premiere.bridge.headless" Version="1.14.2"/>
6
6
  </ExtensionList>
7
7
  <ExecutionEnvironment>
8
8
  <HostList>
@@ -81,7 +81,7 @@
81
81
  <section class="update-section" aria-live="polite">
82
82
  <div class="update-copy">
83
83
  <span class="section-label">Connector updates</span>
84
- <strong id="updateTitle">Version 1.14.1</strong>
84
+ <strong id="updateTitle">Version 1.14.2</strong>
85
85
  <span id="updateDetail">Checking for updates…</span>
86
86
  </div>
87
87
  <button id="btnUpdate" class="button button-update" onclick="handleUpdateClick()" type="button" disabled>
@@ -8,6 +8,8 @@ var pollInterval = null;
8
8
  var commandCount = 0;
9
9
  var tempDir = "";
10
10
  var POLL_MS = 200;
11
+ var HEARTBEAT_MS = 1000;
12
+ var heartbeatInterval = null;
11
13
 
12
14
  // ---- Logging ----
13
15
  function log(msg, cls) {
@@ -157,6 +159,36 @@ function deleteFile(filePath) {
157
159
  } catch (e) {}
158
160
  }
159
161
 
162
+ // The heartbeat carries only protocol state. It is published by rename so a
163
+ // server never observes partial JSON, and an older server can ignore it.
164
+ function writeBridgeHeartbeat() {
165
+ if (!tempDir) return;
166
+ var heartbeatPath = path.join(tempDir, "bridge-heartbeat.json");
167
+ var stagedPath = heartbeatPath + "." + ENGINE_ID + ".staged";
168
+ try {
169
+ fs.writeFileSync(stagedPath, JSON.stringify({
170
+ protocolVersion: 1,
171
+ state: bridgeRunning ? "running" : "waiting"
172
+ }), "utf-8");
173
+ fs.renameSync(stagedPath, heartbeatPath);
174
+ } catch (e) {
175
+ deleteFile(stagedPath);
176
+ }
177
+ }
178
+
179
+ function startBridgeHeartbeat() {
180
+ if (heartbeatInterval) clearInterval(heartbeatInterval);
181
+ writeBridgeHeartbeat();
182
+ heartbeatInterval = setInterval(writeBridgeHeartbeat, HEARTBEAT_MS);
183
+ }
184
+
185
+ function stopBridgeHeartbeat() {
186
+ if (heartbeatInterval) clearInterval(heartbeatInterval);
187
+ heartbeatInterval = null;
188
+ // Keep the last heartbeat in place. Its age lets newer servers diagnose a
189
+ // stopped connector, while concurrent visible/headless panels stay isolated.
190
+ }
191
+
160
192
  // ---- Script Execution ----
161
193
  function executeScript(script, callback) {
162
194
  // Script is already wrapped in an IIFE by the MCP server's buildScript(),
@@ -264,6 +296,7 @@ function startBridge() {
264
296
 
265
297
  ensureDir(tempDir);
266
298
  bridgeRunning = true;
299
+ startBridgeHeartbeat();
267
300
  setStatus("waiting", "Connector running");
268
301
  log("Connector started and ready for safe checks.", "ok");
269
302
 
@@ -279,6 +312,8 @@ function startBridge() {
279
312
 
280
313
  function stopBridge() {
281
314
  bridgeRunning = false;
315
+ writeBridgeHeartbeat();
316
+ stopBridgeHeartbeat();
282
317
  if (pollInterval) clearInterval(pollInterval);
283
318
  pollInterval = null;
284
319
 
@@ -438,6 +473,7 @@ function handleUpdateClick() {
438
473
  // one to click Start, and macOS periodically purges the temp dir — so create it
439
474
  // rather than gating auto-start on its existence.
440
475
  ensureDir(tempDir);
476
+ startBridgeHeartbeat();
441
477
  log("Auto-starting bridge...");
442
478
  setTimeout(startBridge, 500);
443
479
  setTimeout(checkForUpdates, 1200);
@@ -7,7 +7,7 @@
7
7
  })(this, function () {
8
8
  "use strict";
9
9
 
10
- var CURRENT_VERSION = "1.14.1";
10
+ var CURRENT_VERSION = "1.14.2";
11
11
  var LATEST_RELEASE_API =
12
12
  "https://api.github.com/repos/leancoderkavy/premiere-pro-mcp/releases/latest";
13
13
  var RELEASES_URL =
@@ -1,13 +1,33 @@
1
+ export declare const BRIDGE_HEARTBEAT_FILE = "bridge-heartbeat.json";
2
+ export declare const BRIDGE_HEARTBEAT_STALE_MS = 3000;
1
3
  export interface BridgeOptions {
2
4
  tempDir?: string;
3
5
  timeoutMs?: number;
6
+ /**
7
+ * Reject a health-style command without publishing it when a current CEP
8
+ * connector explicitly reports that it is waiting or its heartbeat is stale.
9
+ * A missing heartbeat remains compatible with older installed connectors.
10
+ */
11
+ failFastOnUnreadyHeartbeat?: boolean;
4
12
  }
5
13
  export interface CommandResult {
6
14
  success: boolean;
7
15
  data?: unknown;
8
16
  error?: string;
9
17
  }
18
+ export type BridgeLivenessState = "running" | "waiting" | "stale" | "unknown";
19
+ export interface BridgeLiveness {
20
+ state: BridgeLivenessState;
21
+ ageMs: number | null;
22
+ }
10
23
  export declare function getTempDir(options?: BridgeOptions): string;
24
+ /**
25
+ * Inspect the CEP panel's small, content-free heartbeat. This never creates a
26
+ * directory or reads command, response, project, or media data. Unknown is
27
+ * intentionally non-fatal so a server upgrade stays compatible with older CEP
28
+ * panels that do not publish a heartbeat yet.
29
+ */
30
+ export declare function getBridgeLiveness(options?: BridgeOptions, nowMs?: number): BridgeLiveness;
11
31
  /**
12
32
  * Send a command (ExtendScript) to the CEP plugin and wait for a response.
13
33
  *
@@ -6,6 +6,8 @@ import { getHelpersSource, helpersFileName, buildBootstrap } from "./script-buil
6
6
  const DEFAULT_TEMP_DIR = join(tmpdir(), "premiere-mcp-bridge");
7
7
  const POLL_FALLBACK_MS = 250;
8
8
  const DEFAULT_TIMEOUT_MS = 30000;
9
+ export const BRIDGE_HEARTBEAT_FILE = "bridge-heartbeat.json";
10
+ export const BRIDGE_HEARTBEAT_STALE_MS = 3_000;
9
11
  /**
10
12
  * Create the bridge temp dir private to this user, and — critically — refuse to trust
11
13
  * one we didn't create.
@@ -44,6 +46,47 @@ function ensureDir(dir) {
44
46
  export function getTempDir(options) {
45
47
  return options?.tempDir || process.env.PREMIERE_TEMP_DIR || DEFAULT_TEMP_DIR;
46
48
  }
49
+ /**
50
+ * Inspect the CEP panel's small, content-free heartbeat. This never creates a
51
+ * directory or reads command, response, project, or media data. Unknown is
52
+ * intentionally non-fatal so a server upgrade stays compatible with older CEP
53
+ * panels that do not publish a heartbeat yet.
54
+ */
55
+ export function getBridgeLiveness(options, nowMs = Date.now()) {
56
+ const heartbeatPath = join(getTempDir(options), BRIDGE_HEARTBEAT_FILE);
57
+ try {
58
+ if (!existsSync(heartbeatPath))
59
+ return { state: "unknown", ageMs: null };
60
+ const raw = readFileSync(heartbeatPath, "utf-8");
61
+ const heartbeat = JSON.parse(raw);
62
+ if (heartbeat.protocolVersion !== 1 ||
63
+ (heartbeat.state !== "running" && heartbeat.state !== "waiting")) {
64
+ return { state: "unknown", ageMs: null };
65
+ }
66
+ const ageMs = Math.max(0, nowMs - statSync(heartbeatPath).mtimeMs);
67
+ return ageMs > BRIDGE_HEARTBEAT_STALE_MS
68
+ ? { state: "stale", ageMs }
69
+ : { state: heartbeat.state, ageMs };
70
+ }
71
+ catch {
72
+ return { state: "unknown", ageMs: null };
73
+ }
74
+ }
75
+ function heartbeatFailure(liveness) {
76
+ if (liveness.state === "waiting") {
77
+ return {
78
+ success: false,
79
+ error: "The CEP connector is open but not running. In Premiere Pro, open Window > Extensions > MCP Bridge, wait for it to finish starting, then retry once.",
80
+ };
81
+ }
82
+ if (liveness.state === "stale") {
83
+ return {
84
+ success: false,
85
+ error: "The CEP connector heartbeat is stale. Reopen Window > Extensions > MCP Bridge in Premiere Pro, dismiss any blocking dialog, and retry once after it reports running.",
86
+ };
87
+ }
88
+ return null;
89
+ }
47
90
  /**
48
91
  * Make sure this server version's helpers file exists in the temp dir, and return
49
92
  * the bootstrap line each command must carry so the CEP-side engine loads it once.
@@ -68,6 +111,11 @@ export async function sendCommand(script, options) {
68
111
  const tempDir = getTempDir(options);
69
112
  const timeoutMs = options?.timeoutMs || DEFAULT_TIMEOUT_MS;
70
113
  ensureDir(tempDir);
114
+ if (options?.failFastOnUnreadyHeartbeat) {
115
+ const failure = heartbeatFailure(getBridgeLiveness(options));
116
+ if (failure)
117
+ return failure;
118
+ }
71
119
  const id = randomUUID();
72
120
  const cmdFile = join(tempDir, `cmd_${id}.jsx`);
73
121
  const stagedCmdFile = `${cmdFile}.staged`;
@@ -118,6 +166,11 @@ export async function sendRawCommand(script, options) {
118
166
  const tempDir = getTempDir(options);
119
167
  const timeoutMs = options?.timeoutMs || DEFAULT_TIMEOUT_MS;
120
168
  ensureDir(tempDir);
169
+ if (options?.failFastOnUnreadyHeartbeat) {
170
+ const failure = heartbeatFailure(getBridgeLiveness(options));
171
+ if (failure)
172
+ return failure;
173
+ }
121
174
  const id = randomUUID();
122
175
  const cmdFile = join(tempDir, `cmd_${id}.jsx`);
123
176
  const stagedCmdFile = `${cmdFile}.staged`;
@@ -62,20 +62,45 @@ function __pad(n) {
62
62
 
63
63
  function __findSequence(idOrName) {
64
64
  var project = app.project;
65
+ var wantedId = String(idOrName);
65
66
  for (var i = 0; i < project.sequences.numSequences; i++) {
66
67
  var seq = project.sequences[i];
67
- if (seq.sequenceID === idOrName || seq.name === idOrName) {
68
+ if (String(seq.sequenceID) === wantedId || seq.name === idOrName) {
68
69
  return seq;
69
70
  }
70
71
  }
71
72
  return null;
72
73
  }
73
74
 
75
+ // Premiere can retain a reference to the last active sequence immediately after
76
+ // app.newProject() switches to a new, empty project. Never expose or mutate
77
+ // through that stale object: only a sequence currently enumerated by this
78
+ // project's SequenceCollection is a valid active sequence for this command.
79
+ function __isCurrentProjectSequence(sequence) {
80
+ if (!sequence || !app || !app.project || !app.project.sequences) return false;
81
+ var wantedId = "";
82
+ try { wantedId = String(sequence.sequenceID); } catch (e) { return false; }
83
+ for (var i = 0; i < app.project.sequences.numSequences; i++) {
84
+ var candidate = app.project.sequences[i];
85
+ try {
86
+ if (candidate === sequence || String(candidate.sequenceID) === wantedId) return true;
87
+ } catch (e) {}
88
+ }
89
+ return false;
90
+ }
91
+
92
+ function __getCurrentActiveSequence() {
93
+ var sequence = null;
94
+ try { sequence = app.project.activeSequence; } catch (e) { return null; }
95
+ return __isCurrentProjectSequence(sequence) ? sequence : null;
96
+ }
97
+
74
98
  function __findProjectItem(nodeIdOrName, rootItem) {
75
99
  if (!rootItem) rootItem = app.project.rootItem;
100
+ var wantedId = String(nodeIdOrName);
76
101
  for (var i = 0; i < rootItem.children.numItems; i++) {
77
102
  var item = rootItem.children[i];
78
- if (item.nodeId === nodeIdOrName || item.name === nodeIdOrName) {
103
+ if (String(item.nodeId) === wantedId || item.name === nodeIdOrName) {
79
104
  return item;
80
105
  }
81
106
  if (item.type === 2) { // Bin
@@ -89,13 +114,14 @@ function __findProjectItem(nodeIdOrName, rootItem) {
89
114
  function __findClip(nodeId) {
90
115
  var seq = app.project.activeSequence;
91
116
  if (!seq) return null;
117
+ var wantedId = String(nodeId);
92
118
 
93
119
  // Search video tracks
94
120
  for (var t = 0; t < seq.videoTracks.numTracks; t++) {
95
121
  var track = seq.videoTracks[t];
96
122
  for (var c = 0; c < track.clips.numItems; c++) {
97
123
  var clip = track.clips[c];
98
- if (clip.nodeId === nodeId) {
124
+ if (String(clip.nodeId) === wantedId) {
99
125
  return { clip: clip, trackIndex: t, clipIndex: c, trackType: "video" };
100
126
  }
101
127
  }
@@ -106,7 +132,7 @@ function __findClip(nodeId) {
106
132
  var track = seq.audioTracks[t];
107
133
  for (var c = 0; c < track.clips.numItems; c++) {
108
134
  var clip = track.clips[c];
109
- if (clip.nodeId === nodeId) {
135
+ if (String(clip.nodeId) === wantedId) {
110
136
  return { clip: clip, trackIndex: t, clipIndex: c, trackType: "audio" };
111
137
  }
112
138
  }
@@ -26,7 +26,8 @@ import fs from "node:fs";
26
26
  import path from "node:path";
27
27
  import { randomBytes } from "node:crypto";
28
28
  import { fileURLToPath } from "node:url";
29
- import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
29
+ import { toNodeHandler } from "@modelcontextprotocol/node";
30
+ import { createMcpHandler } from "@modelcontextprotocol/server";
30
31
  import { createServer } from "./server.js";
31
32
  import { cleanupTempDir, getTempDir } from "./bridge/file-bridge.js";
32
33
  import { getTelemetry } from "./telemetry.js";
@@ -187,6 +188,12 @@ const bridgeOptions = {
187
188
  process.env.PREMIERE_MCP_TRANSPORT = "http";
188
189
  const telemetry = getTelemetry();
189
190
  const admission = new HttpAdmissionController(admissionSettings);
191
+ const mcpHandler = createMcpHandler(() => createServer(bridgeOptions, { telemetry }), {
192
+ onerror: (error) => console.error("[premiere-pro-mcp] MCP handler error:", error),
193
+ });
194
+ const handleMcpRequest = toNodeHandler(mcpHandler, {
195
+ onerror: (error) => console.error("[premiere-pro-mcp] MCP Node adapter error:", error),
196
+ });
190
197
  const tempDir = getTempDir(bridgeOptions);
191
198
  console.error(`[premiere-pro-mcp] Starting HTTP server on port ${PORT}...`);
192
199
  console.error(`[premiere-pro-mcp] Temp directory: ${tempDir}`);
@@ -282,18 +289,11 @@ const httpServer = http.createServer(async (req, res) => {
282
289
  outcome: "authorized",
283
290
  method: req.method ?? "unknown",
284
291
  });
285
- const mcpServer = createServer(bridgeOptions, { telemetry });
286
- const transport = new StreamableHTTPServerTransport({
287
- sessionIdGenerator: undefined, // stateless
288
- });
289
292
  res.on("close", () => {
290
293
  admissionDecision.release();
291
- transport.close().catch(() => { });
292
- mcpServer.close().catch(() => { });
293
294
  });
294
295
  try {
295
- await mcpServer.connect(transport);
296
- await transport.handleRequest(req, res, parsedBody);
296
+ await handleMcpRequest(req, res, parsedBody);
297
297
  telemetry.capture("mcp_request", {
298
298
  outcome: res.statusCode >= 400 ? "failed" : "succeeded",
299
299
  method: req.method ?? "unknown",
@@ -333,6 +333,7 @@ httpServer.listen(PORT, "0.0.0.0", () => {
333
333
  async function shutdown(signal) {
334
334
  console.error(`[premiere-pro-mcp] ${signal} received, shutting down...`);
335
335
  httpServer.close();
336
+ await mcpHandler.close();
336
337
  await telemetry.shutdown();
337
338
  process.exit(0);
338
339
  }
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
2
+ import { serveStdio } from "@modelcontextprotocol/server/stdio";
3
3
  import { createServer } from "./server.js";
4
4
  import { cleanupTempDir, getTempDir } from "./bridge/file-bridge.js";
5
5
  import { getTelemetry } from "./telemetry.js";
@@ -21,7 +21,7 @@ function debugLog(message) {
21
21
  const args = process.argv.slice(2);
22
22
  if (args.includes("--help") || args.includes("-h")) {
23
23
  console.log(`
24
- premiere-pro-mcp — MCP server for Adobe Premiere Pro (317 default-profile tools)
24
+ premiere-pro-mcp — MCP server for Adobe Premiere Pro (318 default-profile tools)
25
25
 
26
26
  Usage:
27
27
  premiere-pro-mcp Start the MCP server (stdio transport)
@@ -143,14 +143,14 @@ async function main() {
143
143
  const address = uxpBridge.address();
144
144
  debugLog(`UXP bridge listening on ws://${address.host}:${address.port}${address.path}`);
145
145
  }
146
- const server = createServer(bridgeOptions, { uxpBridge, telemetry });
147
- const transport = new StdioServerTransport();
148
- await server.connect(transport);
146
+ const serverHandle = serveStdio(() => createServer(bridgeOptions, { uxpBridge, telemetry }), {
147
+ onerror: (error) => console.error("[premiere-pro-mcp] MCP stdio error:", error),
148
+ });
149
149
  debugLog("Server connected and ready");
150
150
  const shutdown = async () => {
151
151
  if (uxpBridge)
152
152
  await uxpBridge.stop();
153
- await server.close();
153
+ await serverHandle.close();
154
154
  await telemetry.shutdown();
155
155
  };
156
156
  process.once("SIGINT", () => void shutdown().finally(() => process.exit(0)));
@@ -57,6 +57,60 @@ export declare function buildPlatformCapabilityReport(capabilities: CapabilityCo
57
57
  };
58
58
  toolPacks?: ToolPackReport | undefined;
59
59
  schemaVersion: number;
60
+ mcp: {
61
+ sdk: {
62
+ generation: number;
63
+ packages: string[];
64
+ };
65
+ protocol: {
66
+ modernRevision: string;
67
+ legacyRevisions: string;
68
+ dualEra: boolean;
69
+ };
70
+ features: {
71
+ statelessRequests: string;
72
+ serverDiscovery: string;
73
+ requestMetadataEnvelope: string;
74
+ headerBasedRouting: string;
75
+ deterministicCacheableLists: string;
76
+ resultTypeDiscriminator: string;
77
+ cancellation: string;
78
+ progressNotifications: string;
79
+ traceContext: string;
80
+ jsonSchema202012: string;
81
+ cursorPagination: string;
82
+ resourceTemplates: string;
83
+ completions: string;
84
+ embeddedResourcesAndLinks: string;
85
+ multiRoundTripRequests: string;
86
+ subscriptionsListen: string;
87
+ extensionCapabilities: string;
88
+ tasksExtension: string;
89
+ mcpAppsExtension: string;
90
+ skillsOverMcp: string;
91
+ serverCard: string;
92
+ oauthClientMetadataDocuments: string;
93
+ deprecatedSamplingRootsLogging: string;
94
+ };
95
+ cachePolicy: {
96
+ toolsList: {
97
+ ttlMs: number;
98
+ cacheScope: string;
99
+ };
100
+ promptsList: {
101
+ ttlMs: number;
102
+ cacheScope: string;
103
+ };
104
+ resourcesList: {
105
+ ttlMs: number;
106
+ cacheScope: string;
107
+ };
108
+ resourcesRead: {
109
+ ttlMs: number;
110
+ cacheScope: string;
111
+ };
112
+ };
113
+ };
60
114
  runtime: {
61
115
  platform: NodeJS.Platform;
62
116
  platformName: string;