premiere-pro-mcp 1.7.0 → 1.8.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/CHANGELOG.md CHANGED
@@ -6,6 +6,27 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [1.8.0] - 2026-08-01
10
+
11
+ ### Added
12
+
13
+ - Added three read-only, capability-gated UXP transcript tools: native transcript
14
+ export, native transcript search, and revision-locked transcript edit previews.
15
+ - Added a deterministic SHA-256 transcript revision and confirmation token so a
16
+ proposed edit cannot be confused with a regenerated transcript.
17
+
18
+ ### Changed
19
+
20
+ - Expanded the connected UXP surface from 16 to 19 tools while keeping automatic
21
+ transcript-to-timeline application unavailable pending real-host validation.
22
+ - Added repository Copilot instructions and a deterministic Node 24 setup workflow.
23
+
24
+ ### Validation
25
+
26
+ - Automated tests cover transcript range validation, revision locking, capability
27
+ registration, and the MCP catalog. A real Premiere 25.6 or 26.3 host still must
28
+ validate transcript semantics before any apply operation is introduced.
29
+
9
30
  ## [1.7.0] - 2026-08-01
10
31
 
11
32
  ### Added
package/README.md CHANGED
@@ -6,7 +6,7 @@
6
6
 
7
7
  **Give AI full control over Adobe Premiere Pro.**
8
8
 
9
- 279 core tools across 31 modules, 3 resources, and 4 guided workflows. A connected UXP host adds 16 capability-gated tools.
9
+ 279 core tools across 31 modules, 3 resources, and 4 guided workflows. A connected UXP host adds 19 capability-gated tools.
10
10
 
11
11
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
12
12
  [![Node.js](https://img.shields.io/badge/Node.js-20.19%2B-green.svg)](https://nodejs.org)
@@ -27,9 +27,20 @@ An [MCP (Model Context Protocol)](https://modelcontextprotocol.io) server that l
27
27
  "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."
28
28
  ```
29
29
 
30
- The AI handles the entire workflow through 279 core tools spanning the supported ExtendScript, QE DOM, local media analysis, and safe edit-planning surfaces. A compatible, authenticated UXP panel adds 16 documented, capability-gated workflows without replacing the production CEP bridge.
30
+ The AI handles the entire workflow through 279 core tools spanning the supported ExtendScript, QE DOM, local media analysis, and safe edit-planning surfaces. A compatible, authenticated UXP panel adds 19 documented, capability-gated workflows without replacing the production CEP bridge.
31
31
 
32
- ### What's new in 1.7.0
32
+ ### What's new in 1.8.0
33
+
34
+ - **Native transcript planning:** compatible UXP hosts can export and search the
35
+ transcript Premiere generated for a clip, then preview a revision-locked set of
36
+ source-time deletion ranges.
37
+ - **No false edit promise:** previews return a deterministic confirmation token and
38
+ never modify a clip or timeline. Automated application remains withheld until the
39
+ documented source-to-sequence reconstruction path passes real-host validation.
40
+ - **19 connected UXP tools:** the capability-gated UXP surface grows from 16 to 19
41
+ without changing the 279 core-tool surface.
42
+
43
+ ### Previous release: 1.7.0
33
44
 
34
45
  - **Six documented workflows:** compatible 26.3+ hosts can expose UXP track renaming, subclip creation, stable marker IDs, Source Monitor seeking, transcript presence checks, and AAF export.
35
46
  - **Capability first:** a tool is discoverable only with the authenticated local panel; the panel's live `capabilities.get` response—not package metadata—decides whether the current host supports it.
@@ -248,11 +259,11 @@ From a clone of this repository:
248
259
  ```bash
249
260
  codex plugin marketplace add .
250
261
  codex plugin add premiere-pro@premiere-pro-mcp
251
- npx -y premiere-pro-mcp@1.7.0 --install-cep
262
+ npx -y premiere-pro-mcp@1.8.0 --install-cep
252
263
  ```
253
264
 
254
265
  Restart Premiere Pro and start a new Codex session after installation. The plugin
255
- launches `premiere-pro-mcp@1.7.0` through `npx`; the separate CEP installation is
266
+ launches `premiere-pro-mcp@1.8.0` through `npx`; the separate CEP installation is
256
267
  required because the MCP server communicates with the running Premiere host through
257
268
  the local bridge.
258
269
 
@@ -272,7 +283,7 @@ For Claude Code, add this repository as a marketplace and install the plugin:
272
283
  Then install the Premiere bridge and start a new Claude Code session:
273
284
 
274
285
  ```bash
275
- npx -y premiere-pro-mcp@1.7.0 --install-cep
286
+ npx -y premiere-pro-mcp@1.8.0 --install-cep
276
287
  ```
277
288
 
278
289
  The Claude Code package lives in
@@ -362,7 +373,17 @@ PREMIERE_UXP_TOKEN="replace-with-a-long-random-secret" premiere-pro-mcp
362
373
 
363
374
  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.
364
375
 
365
- When enabled, MCP discovery includes `get_uxp_capabilities`, `get_uxp_state`, `inspect_project_uxp`, `save_project_uxp`, `create_sequence_with_preset_uxp`, `export_interchange_uxp`, `get_transcript_languages_uxp`, `detect_object_masks_uxp`, `configure_encoder_uxp`, `export_frame_uxp`, `rename_track_uxp`, `create_subclip_uxp`, `list_markers_uxp`, `set_source_monitor_position_uxp`, `has_transcript_uxp`, and `export_aaf_uxp`. 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.
376
+ When enabled, MCP discovery includes `get_uxp_capabilities`, `get_uxp_state`, `inspect_project_uxp`, `save_project_uxp`, `create_sequence_with_preset_uxp`, `export_interchange_uxp`, `get_transcript_languages_uxp`, `get_clip_transcript_uxp`, `search_clip_transcript_uxp`, `preview_transcript_edit_uxp`, `detect_object_masks_uxp`, `configure_encoder_uxp`, `export_frame_uxp`, `rename_track_uxp`, `create_subclip_uxp`, `list_markers_uxp`, `set_source_monitor_position_uxp`, `has_transcript_uxp`, and `export_aaf_uxp`. 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.
377
+
378
+ Native transcript editing starts with a read-only, revision-locked planning flow. Use
379
+ `get_clip_transcript_uxp` to export the transcript Premiere generated for a source
380
+ clip, select source-time ranges from that JSON, and pass its SHA-256 revision to
381
+ `preview_transcript_edit_uxp`. The preview sorts and merges ranges and returns a
382
+ confirmation token without changing the timeline. Premiere does not expose a
383
+ documented operation that directly turns deleted transcript text into timeline cuts,
384
+ so automatic application remains withheld until the source-to-sequence mapping and
385
+ documented reconstruction path pass live-host validation. `search_clip_transcript_uxp`
386
+ provides read-only discovery without substituting an external transcription engine.
366
387
 
367
388
  Premiere 26.2-26.3 hosts also expose documented UXP workflows for revisioned project
368
389
  inspection, verified project saves, preset-based sequence creation, OTIO/FCP XML
@@ -416,7 +437,7 @@ The file-based IPC bridge is simple, reliable, and works across macOS and Window
416
437
 
417
438
  ---
418
439
 
419
- ## Tools (279 core total; 277 under the default profile; 293 with a connected UXP bridge)
440
+ ## Tools (279 core total; 277 under the default profile; 296 with a connected UXP bridge)
420
441
 
421
442
  ### Discovery & Inspection (10 + 10)
422
443
 
@@ -659,7 +680,7 @@ premiere-pro-mcp/
659
680
  ├── src/
660
681
  │ ├── index.ts # Entry point — stdio transport setup
661
682
  │ ├── http-server.ts # Entry point — HTTP/SSE transport (Fly.io / remote)
662
- │ ├── server.ts # MCP server — registers 279 tools, filtered by authority profile
683
+ │ ├── server.ts # MCP server — registers 279 core tools, filtered by authority profile
663
684
  │ ├── bridge/
664
685
  │ │ ├── file-bridge.ts # File-based IPC (write .jsx, poll .json)
665
686
  │ │ └── 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.7.0" ExtensionBundleName="MCP Bridge">
2
+ <ExtensionManifest Version="7.0" ExtensionBundleId="com.mcp.premiere.bridge" ExtensionBundleVersion="1.8.0" ExtensionBundleName="MCP Bridge">
3
3
  <ExtensionList>
4
- <Extension Id="com.mcp.premiere.bridge.panel" Version="1.7.0"/>
5
- <Extension Id="com.mcp.premiere.bridge.headless" Version="1.7.0"/>
4
+ <Extension Id="com.mcp.premiere.bridge.panel" Version="1.8.0"/>
5
+ <Extension Id="com.mcp.premiere.bridge.headless" Version="1.8.0"/>
6
6
  </ExtensionList>
7
7
  <ExecutionEnvironment>
8
8
  <HostList>
@@ -65,7 +65,7 @@
65
65
  <section class="update-section" aria-live="polite">
66
66
  <div class="update-copy">
67
67
  <span class="section-label">Connector updates</span>
68
- <strong id="updateTitle">Version 1.7.0</strong>
68
+ <strong id="updateTitle">Version 1.8.0</strong>
69
69
  <span id="updateDetail">Checking for updates…</span>
70
70
  </div>
71
71
  <button id="btnUpdate" class="button button-update" onclick="handleUpdateClick()" type="button" disabled>
@@ -7,7 +7,7 @@
7
7
  })(this, function () {
8
8
  "use strict";
9
9
 
10
- var CURRENT_VERSION = "1.7.0";
10
+ var CURRENT_VERSION = "1.8.0";
11
11
  var LATEST_RELEASE_API =
12
12
  "https://api.github.com/repos/leancoderkavy/premiere-pro-mcp/releases/latest";
13
13
  var RELEASES_URL =
@@ -38,7 +38,12 @@ export function requireCapability(config, capability, operationId) {
38
38
  }
39
39
  }
40
40
  export const UNSAFE_TOOL_NAMES = new Set(["execute_extendscript", "send_raw_script", "evaluate_expression"]);
41
- const INSPECT_TOOL_NAMES = new Set(["ping", "get_capabilities", "preview_edit_plan"]);
41
+ const INSPECT_TOOL_NAMES = new Set([
42
+ "ping",
43
+ "get_capabilities",
44
+ "preview_edit_plan",
45
+ "preview_transcript_edit_uxp",
46
+ ]);
42
47
  // detect_silence reads a media file from disk and shells out to ffmpeg. It
43
48
  // changes nothing in Premiere, so classifying it as "edit" would overstate what
44
49
  // it does; filesystem is the authority it actually needs.
@@ -0,0 +1,15 @@
1
+ export interface TranscriptDeletionRange {
2
+ start_seconds: number;
3
+ end_seconds: number;
4
+ }
5
+ export interface TranscriptEditPreview {
6
+ transcriptRevision: string;
7
+ deletionRanges: TranscriptDeletionRange[];
8
+ deletedSeconds: number;
9
+ confirmationToken: string;
10
+ applied: false;
11
+ }
12
+ export declare function transcriptRevision(json: string): string;
13
+ export declare function normalizeTranscriptDeletionRanges(value: unknown, handleSeconds?: number): TranscriptDeletionRange[];
14
+ export declare function previewTranscriptEdit(json: string, requestedRevision: string, deletions: unknown, handleSeconds?: number): TranscriptEditPreview;
15
+ //# sourceMappingURL=transcript-edits.d.ts.map
@@ -0,0 +1,64 @@
1
+ import { createHash } from "node:crypto";
2
+ const MAX_DELETION_RANGES = 100;
3
+ export function transcriptRevision(json) {
4
+ return `sha256:${createHash("sha256").update(json).digest("hex")}`;
5
+ }
6
+ function roundSeconds(value) {
7
+ return Number(value.toFixed(6));
8
+ }
9
+ export function normalizeTranscriptDeletionRanges(value, handleSeconds = 0) {
10
+ if (!Array.isArray(value) || value.length === 0) {
11
+ throw new Error("deletions must contain at least one transcript time range");
12
+ }
13
+ if (value.length > MAX_DELETION_RANGES) {
14
+ throw new Error(`transcript edits are limited to ${MAX_DELETION_RANGES} deletion ranges`);
15
+ }
16
+ if (!Number.isFinite(handleSeconds) || handleSeconds < 0 || handleSeconds > 10) {
17
+ throw new Error("handle_seconds must be between 0 and 10");
18
+ }
19
+ const ranges = value.map((entry, index) => {
20
+ if (!entry || typeof entry !== "object") {
21
+ throw new Error(`deletion ${index} must be an object`);
22
+ }
23
+ const range = entry;
24
+ if (!Number.isFinite(range.start_seconds) || Number(range.start_seconds) < 0) {
25
+ throw new Error(`deletion ${index} start_seconds must be a non-negative number`);
26
+ }
27
+ if (!Number.isFinite(range.end_seconds) || Number(range.end_seconds) <= Number(range.start_seconds)) {
28
+ throw new Error(`deletion ${index} end_seconds must be greater than start_seconds`);
29
+ }
30
+ return {
31
+ start_seconds: roundSeconds(Math.max(0, Number(range.start_seconds) - handleSeconds)),
32
+ end_seconds: roundSeconds(Number(range.end_seconds) + handleSeconds),
33
+ };
34
+ }).sort((left, right) => left.start_seconds - right.start_seconds || left.end_seconds - right.end_seconds);
35
+ const merged = [];
36
+ for (const range of ranges) {
37
+ const previous = merged.at(-1);
38
+ if (previous && range.start_seconds <= previous.end_seconds) {
39
+ previous.end_seconds = roundSeconds(Math.max(previous.end_seconds, range.end_seconds));
40
+ }
41
+ else {
42
+ merged.push({ ...range });
43
+ }
44
+ }
45
+ return merged;
46
+ }
47
+ export function previewTranscriptEdit(json, requestedRevision, deletions, handleSeconds = 0) {
48
+ if (typeof json !== "string" || !json)
49
+ throw new Error("Premiere returned an empty transcript");
50
+ const revision = transcriptRevision(json);
51
+ if (requestedRevision !== revision) {
52
+ throw new Error("Transcript revision does not match the current Premiere transcript; export it again before planning edits");
53
+ }
54
+ const deletionRanges = normalizeTranscriptDeletionRanges(deletions, handleSeconds);
55
+ const canonical = JSON.stringify({ transcriptRevision: revision, deletionRanges });
56
+ return {
57
+ transcriptRevision: revision,
58
+ deletionRanges,
59
+ deletedSeconds: roundSeconds(deletionRanges.reduce((total, range) => total + range.end_seconds - range.start_seconds, 0)),
60
+ confirmationToken: createHash("sha256").update(canonical).digest("hex"),
61
+ applied: false,
62
+ };
63
+ }
64
+ //# sourceMappingURL=transcript-edits.js.map
@@ -150,6 +150,170 @@ export declare function getUxpTools(bridge: UxpWebSocketBridge): {
150
150
  error: string;
151
151
  }>;
152
152
  };
153
+ get_clip_transcript_uxp: {
154
+ description: string;
155
+ parameters: {
156
+ type: "object";
157
+ properties: {
158
+ project_item_id: {
159
+ type: string;
160
+ maxLength: number;
161
+ description: string;
162
+ };
163
+ project_item_name: {
164
+ type: string;
165
+ maxLength: number;
166
+ description: string;
167
+ };
168
+ };
169
+ };
170
+ handler: (args: {
171
+ project_item_id?: string;
172
+ project_item_name?: string;
173
+ }) => Promise<{
174
+ success: boolean;
175
+ data: {
176
+ backend: string;
177
+ result: {
178
+ transcriptRevision: string;
179
+ json?: unknown;
180
+ };
181
+ };
182
+ error?: undefined;
183
+ } | {
184
+ success: boolean;
185
+ error: string;
186
+ data?: undefined;
187
+ }>;
188
+ };
189
+ search_clip_transcript_uxp: {
190
+ description: string;
191
+ parameters: {
192
+ type: "object";
193
+ properties: {
194
+ project_item_id: {
195
+ type: string;
196
+ maxLength: number;
197
+ description: string;
198
+ };
199
+ project_item_name: {
200
+ type: string;
201
+ maxLength: number;
202
+ description: string;
203
+ };
204
+ query: {
205
+ type: string;
206
+ minLength: number;
207
+ maxLength: number;
208
+ description: string;
209
+ };
210
+ case_sensitive: {
211
+ type: string;
212
+ description: string;
213
+ };
214
+ max_results: {
215
+ type: string;
216
+ minimum: number;
217
+ maximum: number;
218
+ description: string;
219
+ };
220
+ };
221
+ required: string[];
222
+ };
223
+ handler: (args: {
224
+ project_item_id?: string;
225
+ project_item_name?: string;
226
+ query: string;
227
+ case_sensitive?: boolean;
228
+ max_results?: number;
229
+ }) => Promise<{
230
+ success: boolean;
231
+ data: {
232
+ backend: string;
233
+ result: unknown;
234
+ };
235
+ } | {
236
+ success: boolean;
237
+ error: string;
238
+ }>;
239
+ };
240
+ preview_transcript_edit_uxp: {
241
+ description: string;
242
+ parameters: {
243
+ type: "object";
244
+ properties: {
245
+ project_item_id: {
246
+ type: string;
247
+ maxLength: number;
248
+ description: string;
249
+ };
250
+ project_item_name: {
251
+ type: string;
252
+ maxLength: number;
253
+ description: string;
254
+ };
255
+ transcript_revision: {
256
+ type: string;
257
+ pattern: string;
258
+ description: string;
259
+ };
260
+ deletions: {
261
+ type: string;
262
+ minItems: number;
263
+ maxItems: number;
264
+ items: {
265
+ type: string;
266
+ additionalProperties: boolean;
267
+ properties: {
268
+ start_seconds: {
269
+ type: string;
270
+ minimum: number;
271
+ };
272
+ end_seconds: {
273
+ type: string;
274
+ exclusiveMinimum: number;
275
+ };
276
+ };
277
+ required: string[];
278
+ };
279
+ description: string;
280
+ };
281
+ handle_seconds: {
282
+ type: string;
283
+ minimum: number;
284
+ maximum: number;
285
+ description: string;
286
+ };
287
+ };
288
+ required: string[];
289
+ };
290
+ handler: (args: {
291
+ project_item_id?: string;
292
+ project_item_name?: string;
293
+ transcript_revision: string;
294
+ deletions: unknown;
295
+ handle_seconds?: number;
296
+ }) => Promise<{
297
+ success: boolean;
298
+ data: {
299
+ backend: string;
300
+ result: {
301
+ transcriptRevision: string;
302
+ deletionRanges: import("./transcript-edits.js").TranscriptDeletionRange[];
303
+ deletedSeconds: number;
304
+ confirmationToken: string;
305
+ applied: false;
306
+ projectItemId: unknown;
307
+ projectItemName: unknown;
308
+ };
309
+ };
310
+ error?: undefined;
311
+ } | {
312
+ success: boolean;
313
+ error: string;
314
+ data?: undefined;
315
+ }>;
316
+ };
153
317
  detect_object_masks_uxp: {
154
318
  description: string;
155
319
  parameters: {
package/dist/tools/uxp.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { previewTranscriptEdit, transcriptRevision } from "./transcript-edits.js";
1
2
  function invoke(bridge, command, args = {}) {
2
3
  return bridge.request(command, args)
3
4
  .then((result) => ({ success: true, data: { backend: "uxp", result } }))
@@ -76,6 +77,95 @@ export function getUxpTools(bridge) {
76
77
  parameters: {},
77
78
  handler: async () => invoke(bridge, "transcript.languages"),
78
79
  },
80
+ get_clip_transcript_uxp: {
81
+ description: "Export Premiere's native transcript JSON for one source media clip. Returns a revision hash that must be used when previewing transcript edits. This is read-only and does not run Speech-to-Text.",
82
+ parameters: {
83
+ type: "object",
84
+ properties: {
85
+ project_item_id: { type: "string", maxLength: 512, description: "Source project-item ID. Omit with project_item_name to use exactly one Project panel selection." },
86
+ project_item_name: { type: "string", maxLength: 255, description: "Unique source media-clip name. Not allowed together with project_item_id." },
87
+ },
88
+ },
89
+ handler: async (args) => {
90
+ try {
91
+ const result = await bridge.request("transcript.export", {
92
+ ...(args.project_item_id ? { projectItemId: args.project_item_id } : {}),
93
+ ...(args.project_item_name ? { projectItemName: args.project_item_name } : {}),
94
+ });
95
+ if (typeof result?.json !== "string" || !result.json)
96
+ throw new Error("Premiere returned an empty transcript");
97
+ return { success: true, data: { backend: "uxp", result: { ...result, transcriptRevision: transcriptRevision(result.json) } } };
98
+ }
99
+ catch (error) {
100
+ return { success: false, error: error instanceof Error ? error.message : String(error) };
101
+ }
102
+ },
103
+ },
104
+ search_clip_transcript_uxp: {
105
+ description: "Search Premiere's native transcript JSON without modifying the clip or timeline.",
106
+ parameters: {
107
+ type: "object",
108
+ properties: {
109
+ project_item_id: { type: "string", maxLength: 512, description: "Source project-item ID." },
110
+ project_item_name: { type: "string", maxLength: 255, description: "Unique source media-clip name." },
111
+ query: { type: "string", minLength: 1, maxLength: 1000, description: "Transcript text to find." },
112
+ case_sensitive: { type: "boolean", description: "Use case-sensitive matching; defaults to false." },
113
+ max_results: { type: "integer", minimum: 1, maximum: 500, description: "Maximum matches; defaults to 50." },
114
+ },
115
+ required: ["query"],
116
+ },
117
+ handler: async (args) => invoke(bridge, "transcript.search", {
118
+ ...(args.project_item_id ? { projectItemId: args.project_item_id } : {}),
119
+ ...(args.project_item_name ? { projectItemName: args.project_item_name } : {}),
120
+ query: args.query,
121
+ ...(args.case_sensitive === undefined ? {} : { caseSensitive: args.case_sensitive }),
122
+ ...(args.max_results === undefined ? {} : { maxResults: args.max_results }),
123
+ }),
124
+ },
125
+ preview_transcript_edit_uxp: {
126
+ description: "Validate and merge source-time ranges selected from Premiere's native transcript. Returns a confirmation token and never changes the timeline. Automatic timeline application remains withheld until the source-to-sequence mapping is live-host verified.",
127
+ parameters: {
128
+ type: "object",
129
+ properties: {
130
+ project_item_id: { type: "string", maxLength: 512, description: "Source project-item ID used for the transcript export." },
131
+ project_item_name: { type: "string", maxLength: 255, description: "Unique source media-clip name." },
132
+ transcript_revision: { type: "string", pattern: "^sha256:[a-f0-9]{64}$", description: "Revision returned by get_clip_transcript_uxp." },
133
+ deletions: {
134
+ type: "array", minItems: 1, maxItems: 100,
135
+ items: {
136
+ type: "object", additionalProperties: false,
137
+ properties: {
138
+ start_seconds: { type: "number", minimum: 0 },
139
+ end_seconds: { type: "number", exclusiveMinimum: 0 },
140
+ },
141
+ required: ["start_seconds", "end_seconds"],
142
+ },
143
+ description: "Source-media time ranges corresponding to transcript words or segments to remove.",
144
+ },
145
+ handle_seconds: { type: "number", minimum: 0, maximum: 10, description: "Optional context added to both sides before overlapping ranges are merged." },
146
+ },
147
+ required: ["transcript_revision", "deletions"],
148
+ },
149
+ handler: async (args) => {
150
+ try {
151
+ const exported = await bridge.request("transcript.export", {
152
+ ...(args.project_item_id ? { projectItemId: args.project_item_id } : {}),
153
+ ...(args.project_item_name ? { projectItemName: args.project_item_name } : {}),
154
+ });
155
+ if (typeof exported?.json !== "string")
156
+ throw new Error("Premiere returned an empty transcript");
157
+ const preview = previewTranscriptEdit(exported.json, args.transcript_revision, args.deletions, args.handle_seconds);
158
+ return { success: true, data: { backend: "uxp", result: {
159
+ projectItemId: exported.projectItemId,
160
+ projectItemName: exported.projectItemName,
161
+ ...preview,
162
+ } } };
163
+ }
164
+ catch (error) {
165
+ return { success: false, error: error instanceof Error ? error.message : String(error) };
166
+ }
167
+ },
168
+ },
79
169
  detect_object_masks_uxp: {
80
170
  description: "Detect whether the active project or sequence contains an Object Mask using Premiere 26.3+.",
81
171
  parameters: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "premiere-pro-mcp",
3
- "version": "1.7.0",
3
+ "version": "1.8.0",
4
4
  "description": "Adobe Premiere Pro MCP server with 279 core AI video editing tools and a capability-aware UXP bridge for supported Premiere workflows.",
5
5
  "main": "dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -12,6 +12,13 @@ It also exposes documented Premiere 25.6+ video-transition and transcript workfl
12
12
 
13
13
  Transition names must come from `transition.video.list`. Transcript targets can be selected in the Project panel or addressed by project-item ID/name. Caption creation, text/timing mutation, and deletion remain explicitly unsupported because Premiere does not document those UXP APIs.
14
14
 
15
+ The MCP adapter exposes `transcript.export` as `get_clip_transcript_uxp` and adds a
16
+ SHA-256 revision to the result. `search_clip_transcript_uxp` maps to the existing
17
+ read-only search command. `preview_transcript_edit_uxp` re-exports the transcript,
18
+ rejects stale revisions, validates and merges selected source-time deletion ranges,
19
+ and returns a confirmation token. It never changes the transcript or timeline;
20
+ automatic transcript-to-timeline application remains a live-host validation gate.
21
+
15
22
  ## Premiere 26.3 commands
16
23
 
17
24
  The following commands use APIs Adobe introduced in Premiere 26.3. They are
@@ -2,7 +2,7 @@
2
2
  "manifestVersion": 5,
3
3
  "id": "com.ppmcp.premiere.uxp",
4
4
  "name": "Premiere Pro MCP Bridge",
5
- "version": "1.7.0",
5
+ "version": "1.8.0",
6
6
  "main": "index.html",
7
7
  "host": { "app": "premierepro", "minVersion": "25.6.0" },
8
8
  "entrypoints": [