@synthetic-ai/premiere-mcp 2.3.6 → 3.0.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 (126) hide show
  1. package/LICENSE +5 -21
  2. package/README.md +10 -242
  3. package/launcher.mjs +111 -0
  4. package/package.json +10 -54
  5. package/CHANGELOG.md +0 -186
  6. package/cep-plugin/.debug +0 -8
  7. package/cep-plugin/CSInterface.js +0 -92
  8. package/cep-plugin/CSXS/manifest.xml +0 -49
  9. package/cep-plugin/host.jsx +0 -7
  10. package/cep-plugin/i18n-core.cjs +0 -224
  11. package/cep-plugin/i18n-locales.js +0 -3
  12. package/cep-plugin/i18n-panel.cjs +0 -178
  13. package/cep-plugin/index.html +0 -507
  14. package/cep-plugin/main.js +0 -793
  15. package/cep-plugin/premiere.jsx +0 -24947
  16. package/cep-plugin/synthetic-logo.png +0 -0
  17. package/dist/bridge/file-bridge.d.ts +0 -29
  18. package/dist/bridge/file-bridge.js +0 -146
  19. package/dist/bridge/script-builder.d.ts +0 -19
  20. package/dist/bridge/script-builder.js +0 -408
  21. package/dist/http-server.d.ts +0 -22
  22. package/dist/http-server.js +0 -143
  23. package/dist/i18n.d.ts +0 -42
  24. package/dist/i18n.js +0 -69
  25. package/dist/index.d.ts +0 -3
  26. package/dist/index.js +0 -179
  27. package/dist/license.d.ts +0 -22
  28. package/dist/license.js +0 -133
  29. package/dist/resources/extendscript-reference.d.ts +0 -2
  30. package/dist/resources/extendscript-reference.js +0 -219
  31. package/dist/server.d.ts +0 -4
  32. package/dist/server.js +0 -292
  33. package/dist/tools/advanced.d.ts +0 -530
  34. package/dist/tools/advanced.js +0 -923
  35. package/dist/tools/audio-advanced.d.ts +0 -847
  36. package/dist/tools/audio-advanced.js +0 -1653
  37. package/dist/tools/audio.d.ts +0 -84
  38. package/dist/tools/audio.js +0 -123
  39. package/dist/tools/captions.d.ts +0 -30
  40. package/dist/tools/captions.js +0 -73
  41. package/dist/tools/clipboard.d.ts +0 -153
  42. package/dist/tools/clipboard.js +0 -381
  43. package/dist/tools/color-advanced.d.ts +0 -821
  44. package/dist/tools/color-advanced.js +0 -772
  45. package/dist/tools/discovery.d.ts +0 -128
  46. package/dist/tools/discovery.js +0 -445
  47. package/dist/tools/effects.d.ts +0 -211
  48. package/dist/tools/effects.js +0 -555
  49. package/dist/tools/export-presets.d.ts +0 -333
  50. package/dist/tools/export-presets.js +0 -490
  51. package/dist/tools/export.d.ts +0 -320
  52. package/dist/tools/export.js +0 -619
  53. package/dist/tools/health.d.ts +0 -9
  54. package/dist/tools/health.js +0 -25
  55. package/dist/tools/inspection.d.ts +0 -179
  56. package/dist/tools/inspection.js +0 -1089
  57. package/dist/tools/keyframes.d.ts +0 -253
  58. package/dist/tools/keyframes.js +0 -611
  59. package/dist/tools/markers.d.ts +0 -117
  60. package/dist/tools/markers.js +0 -206
  61. package/dist/tools/media.d.ts +0 -297
  62. package/dist/tools/media.js +0 -493
  63. package/dist/tools/metadata.d.ts +0 -178
  64. package/dist/tools/metadata.js +0 -278
  65. package/dist/tools/multicam.d.ts +0 -199
  66. package/dist/tools/multicam.js +0 -212
  67. package/dist/tools/playback.d.ts +0 -34
  68. package/dist/tools/playback.js +0 -63
  69. package/dist/tools/playhead.d.ts +0 -77
  70. package/dist/tools/playhead.js +0 -185
  71. package/dist/tools/project-manager.d.ts +0 -65
  72. package/dist/tools/project-manager.js +0 -81
  73. package/dist/tools/project.d.ts +0 -390
  74. package/dist/tools/project.js +0 -596
  75. package/dist/tools/scripting.d.ts +0 -98
  76. package/dist/tools/scripting.js +0 -434
  77. package/dist/tools/selection.d.ts +0 -120
  78. package/dist/tools/selection.js +0 -334
  79. package/dist/tools/sequence-advanced.d.ts +0 -84
  80. package/dist/tools/sequence-advanced.js +0 -476
  81. package/dist/tools/sequence-settings.d.ts +0 -397
  82. package/dist/tools/sequence-settings.js +0 -975
  83. package/dist/tools/sequence.d.ts +0 -211
  84. package/dist/tools/sequence.js +0 -400
  85. package/dist/tools/source-monitor.d.ts +0 -95
  86. package/dist/tools/source-monitor.js +0 -180
  87. package/dist/tools/text.d.ts +0 -97
  88. package/dist/tools/text.js +0 -159
  89. package/dist/tools/timeline.d.ts +0 -265
  90. package/dist/tools/timeline.js +0 -575
  91. package/dist/tools/track-management.d.ts +0 -482
  92. package/dist/tools/track-management.js +0 -787
  93. package/dist/tools/track-targeting.d.ts +0 -666
  94. package/dist/tools/track-targeting.js +0 -1318
  95. package/dist/tools/tracks.d.ts +0 -90
  96. package/dist/tools/tracks.js +0 -183
  97. package/dist/tools/transitions-motion.d.ts +0 -788
  98. package/dist/tools/transitions-motion.js +0 -680
  99. package/dist/tools/transitions.d.ts +0 -124
  100. package/dist/tools/transitions.js +0 -268
  101. package/dist/tools/utility.d.ts +0 -469
  102. package/dist/tools/utility.js +0 -1118
  103. package/dist/tools/workspace.d.ts +0 -25
  104. package/dist/tools/workspace.js +0 -61
  105. package/i18n/i18n-core.cjs +0 -224
  106. package/i18n/locales/de.json +0 -1488
  107. package/i18n/locales/en.json +0 -1488
  108. package/i18n/locales/es.json +0 -1488
  109. package/i18n/locales/fr.json +0 -1488
  110. package/i18n/locales/hashes/de.json +0 -1488
  111. package/i18n/locales/hashes/es.json +0 -1488
  112. package/i18n/locales/hashes/fr.json +0 -1488
  113. package/i18n/locales/hashes/ja.json +0 -1488
  114. package/i18n/locales/hashes/pt-BR.json +0 -1488
  115. package/i18n/locales/ja.json +0 -1488
  116. package/i18n/locales/pt-BR.json +0 -1488
  117. package/i18n/node.cjs +0 -124
  118. package/scripts/build-chat-dmg.sh +0 -210
  119. package/scripts/build-chat-zip.sh +0 -291
  120. package/scripts/install-cep-windows.ps1 +0 -99
  121. package/scripts/install-cep.sh +0 -66
  122. package/scripts/install-chat-plugin.bat +0 -67
  123. package/scripts/install-chat-plugin.sh +0 -85
  124. package/scripts/install-windows.bat +0 -95
  125. package/scripts/package.mjs +0 -270
  126. package/scripts/sync-i18n.mjs +0 -117
package/LICENSE CHANGED
@@ -1,21 +1,5 @@
1
- MIT License
2
-
3
- Copyright (c) 2025 Premiere Pro MCP Contributors
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ Copyright (c) 2026 Synthetic. All rights reserved.
2
+
3
+ This package contains only a small launcher. The Synthetic MCP software it starts is NOT part of this package: it is downloaded from synthetic.com.ar
4
+ and can only be used with a valid Synthetic license (https://synthetic.com.ar). Using the launcher does not grant any right to the downloaded software
5
+ beyond what your license gives you.
package/README.md CHANGED
@@ -1,242 +1,10 @@
1
- # Premiere Pro MCP
2
-
3
- **Control Adobe Premiere Pro with natural language through Claude (or any MCP-compatible LLM).**
4
-
5
- [![Premiere Pro 2026](https://img.shields.io/badge/Premiere%20Pro-2026-blueviolet)](https://www.adobe.com/products/premiere.html)
6
- [![MCP](https://img.shields.io/badge/MCP-compatible-green)](https://modelcontextprotocol.io)
7
- [![License](https://img.shields.io/badge/license-MIT-blue)](LICENSE)
8
-
9
- ---
10
-
11
- ## What it does
12
-
13
- ```
14
- You: "Apply a cinematic look to all clips on V1, ducking the music
15
- when there's voice, and export to YouTube 1080p."
16
-
17
- Claude: ✓ Applied Lumetri (-15K temperature, +10 contrast) to 4 clips
18
- ✓ Added voiceover ducking on A2 (-12dB during A1 voice)
19
- ✓ Queued H.264 1080p export to ~/Videos/final.mp4
20
- ```
21
-
22
- 437 tools exposed via MCP to drive Premiere Pro 2026 from any LLM agent.
23
- Tested in runtime against PP 2026.2.2 on Spanish-localized Windows install.
24
-
25
- ---
26
-
27
- ## Highlights
28
-
29
- - **Locale-resilient**: works on Premiere Pro in Spanish, German, French, etc.
30
- (most competitors hardcode English component names and silently fail)
31
- - **Honest errors**: when a Premiere host API genuinely doesn't expose
32
- something (PP 2026 has known limitations), you get a clear error with
33
- the recommended workaround — not a silent no-op
34
- - **Battle-tested**: 137 tools validated in live runtime against PP 2026 with
35
- detailed bug fixes (see [CHANGELOG.md](CHANGELOG.md))
36
- - **AI-first**: built for LLM-driven workflows. Pair it with Whisper for
37
- speech-to-text, ComfyUI for thumbnails, FFmpeg for analysis — chain MCPs
38
-
39
- ---
40
-
41
- ## Quick start
42
-
43
- ### 1. Install the CEP plugin
44
-
45
- Copy `cep-plugin/` to your Adobe CEP extensions folder:
46
-
47
- - **Windows**: `%APPDATA%\Adobe\CEP\extensions\MCPBridgeCEP\`
48
- - **macOS**: `~/Library/Application Support/Adobe/CEP/extensions/MCPBridgeCEP/`
49
-
50
- Enable CEP debugging:
51
- ```powershell
52
- # Windows
53
- reg add HKCU\Software\Adobe\CSXS.11 /v PlayerDebugMode /t REG_SZ /d 1 /f
54
- ```
55
-
56
- ### 2. Build the MCP server
57
-
58
- ```bash
59
- cd premiere-pro-mcp
60
- npm install
61
- npm run build
62
- ```
63
-
64
- ### 3. Register with Claude Desktop
65
-
66
- Add to `%APPDATA%\Claude\claude_desktop_config.json`:
67
-
68
- ```json
69
- {
70
- "mcpServers": {
71
- "premiere-pro": {
72
- "command": "node",
73
- "args": ["C:/path/to/premiere-pro-mcp/dist/index.js"]
74
- }
75
- }
76
- }
77
- ```
78
-
79
- ### 4. Open Premiere Pro
80
-
81
- - Launch Premiere Pro 2026
82
- - `Window > Extensions > MCPBridgeCEP` (the bridge panel)
83
- - Click "Start Bridge"
84
-
85
- ### 5. Talk to Claude
86
-
87
- ```
88
- "Show me the active sequence structure."
89
- "Add a 1-second fade-in to the audio clip on A2."
90
- "Apply Cross Dissolve at every cut on V1, 0.5 seconds each."
91
- ```
92
-
93
- ---
94
-
95
- ## What works (validated runtime, PP 2026 es-ES)
96
-
97
- ### Project & Inspection
98
- - Full project / sequence / clip overviews
99
- - Bins, markers, metadata (XMP), color labels
100
- - Effect properties with all values, keyframes, source media details
101
- - Find/search project items, list sequences
102
-
103
- ### Timeline editing
104
- - Add/remove/move/duplicate clips, split, trim
105
- - Set in/out points, playhead, work area
106
- - Selection by name/range/color, invert, deselect
107
- - Enable/disable clips, link/unlink
108
-
109
- ### Transform & Motion
110
- - Position, scale, rotation, opacity (locale-resilient)
111
- - Anchor point, blend mode
112
- - Position/scale keyframes via `add_keyframe`
113
-
114
- ### Color
115
- - Lumetri full parameter control: exposure, contrast, highlights/shadows,
116
- whites/blacks, temperature/tint, saturation, vibrance, sharpen, vignette,
117
- faded film
118
- - LUTs apply
119
- - Copy/paste color grade across clips
120
- - ⚠️ See limitations: applying Lumetri *for the first time* requires manual UI
121
-
122
- ### Audio
123
- - Per-clip volume, fade in/out (locale-resilient)
124
- - Volume/panning keyframes
125
- - Audio FX pipeline: Compressor, EQ, De-Esser, De-Hum, De-Reverb, Limiter,
126
- Noise Reduction
127
- - Voiceover ducking
128
- - Normalize, detect clipping
129
-
130
- ### Effects & Transitions
131
- - 60+ video effects (Gaussian/Directional Blur, Sharpen, Warp Stabilizer,
132
- Noise Reduction, Mirror, Spherize, Corner Pin, Lens Distortion, etc.)
133
- - Transitions with locale-aware name lookup (Cross Dissolve works on any
134
- language install)
135
- - Batch apply across cuts
136
-
137
- ### Captions
138
- - Import SRT files as caption tracks
139
- - Pipeline integration: Whisper-transcribe → SRT → MCP creates captions
140
-
141
- ### Export
142
- - Single sequence + batch export via Adobe Media Encoder
143
- - Match Source presets, YouTube/Vimeo/Twitter/Facebook presets
144
- - Encode arbitrary files via AME
145
- - AAF, OMF, FCPXML export
146
-
147
- ### Multicam
148
- - Create multicam sequences, switch angles, flatten
149
-
150
- ### Markers
151
- - Add/update/delete on sequence or clip
152
- - Color labels, comments, in/out range
153
- - Import/export CSV
154
-
155
- ---
156
-
157
- ## Known limitations (PP 2026 host)
158
-
159
- These are not bugs in this MCP — they're verified limitations of Premiere Pro
160
- 2026's ExtendScript/QE-DOM surface. Each tool returns a clear actionable error
161
- with the recommended workaround.
162
-
163
- | Feature | Status | Workaround |
164
- |---------|--------|------------|
165
- | `capture_frame` programmatic | ❌ `qeSeq.exportFramePNG` reports success but never writes file | UI: File > Export > Media > Single Frame |
166
- | `set_track_volume` | ❌ Audio track DOM no longer exposes `.components` or `.volume`; QE has no `setVolume` | Use `add_audio_keyframes` per-clip, or Audio Track Mixer |
167
- | `speed_change` programmatic | ❌ `qeClip.setSpeed` signature changed in PP 2026 (rejects all known forms) | UI: Clip > Speed/Duration, or change duration with `trim_clip` |
168
- | Apply Lumetri for the first time | ❌ `addVideoEffect` reports success but doesn't add component | Apply Lumetri manually once; afterwards all 28 setters work perfectly |
169
- | LUFS integrated measurement | ❌ Not scriptable | Export and measure with ffmpeg-loudnorm |
170
- | Native PP Speech-to-Text | ❌ Adobe AI STT not exposed | Use Whisper + `create_caption_track` (works great) |
171
- | Adobe Libraries MOGRT | ❌ Adobe Libraries not scriptable | Use local `.mogrt` files via `import_mogrt` |
172
- | Dynamic Link with AE | ❌ `import_ae_comps` not implemented | Render from AE and import as video |
173
- | Async export completion | ⚠️ AME runs async, no callback | Poll `get_render_queue_status` |
174
-
175
- ---
176
-
177
- ## Architecture
178
-
179
- ```
180
- ┌─────────────┐ ┌──────────────┐ ┌─────────────┐
181
- │ Claude │ │ Node.js │ │ Premiere │
182
- │ (or LLM) │◄───────►│ MCP server │◄───────►│ Pro CEP │
183
- └─────────────┘ stdio └──────────────┘ files │ plugin │
184
- │ (panel) │
185
- └─────────────┘
186
- │
187
- ▼
188
- ┌──────────────┐
189
- │ ExtendScript │
190
- │ DOM + QE │
191
- └──────────────┘
192
- ```
193
-
194
- The bridge automatically prepends locale-resilient helpers to every script:
195
-
196
- ```javascript
197
- __findIntrinsic(clip, "motion" | "opacity" | "volume" | "lumetri" | "timeRemap")
198
- // tries matchName ("AE.ADBE Motion") first — locale-INDEPENDENT —
199
- // then localized displayName ("Movimiento", "Bewegung", "Mouvement", etc.)
200
-
201
- __findProp(component, ["Position", "Posición", "Position", "Position"])
202
- // also descends one level into nested groups (needed for Lumetri's
203
- // grouped parameters like Exposure inside Basic Correction)
204
-
205
- __readMaybe(obj, "isMuted", false)
206
- // reads members that are property in some PP versions, method in others
207
-
208
- __findTransition(name, "video")
209
- // resolves transition names across locales:
210
- // "Cross Dissolve" matches "Disolvencia cruzada" / "Fondu enchaîné"
211
- ```
212
-
213
- ---
214
-
215
- ## Development
216
-
217
- ```bash
218
- npm run dev # Watch mode
219
- npm run build # Build dist/
220
- npx tsc --noEmit # Type-check only
221
- ```
222
-
223
- When adding a tool, prefer:
224
- - `__findIntrinsic` / `__findComponent` over hardcoded `displayName === "Motion"`
225
- - `__readMaybe` for any `isSomething()` / `isSomething` property
226
- - Pass `.ticks` strings (not Time objects) to `insertClip`/`setInPoint`/etc.
227
-
228
- ---
229
-
230
- ## Credits
231
-
232
- Built on top of work from
233
- [`AdobePremiereProMCP`](https://github.com/bdenney99/AdobePremiereProMCP)
234
- with extensive fixes for PP 2026 compatibility, locale resilience, and
235
- runtime-validated behavior. See [CHANGELOG.md](CHANGELOG.md) for the full
236
- fix log.
237
-
238
- ---
239
-
240
- ## License
241
-
242
- MIT
1
+ # @synthetic-ai/premiere-mcp
2
+
3
+ Synthetic MCP launcher. Set your license in your MCP client's configuration and keep using `npx -y @synthetic-ai/premiere-mcp`:
4
+
5
+ ```json
6
+ { "mcpServers": { "premiere-mcp": { "command": "npx", "args": ["-y", "@synthetic-ai/premiere-mcp"], "env": { "PREMIERE_PRO_MCP_LICENSE": "<your license key>" } } } }
7
+ ```
8
+
9
+ On start it checks your license with synthetic.com.ar, downloads the current server (verified with a sha256) and runs it. Without a connection it runs the last
10
+ downloaded copy. Your key is in https://synthetic.com.ar/dashboard.
package/launcher.mjs ADDED
@@ -0,0 +1,111 @@
1
+ #!/usr/bin/env node
2
+ // Synthetic MCP launcher — ZERO dependencies (Node >= 18). This is the only thing that goes on npm; the real server is downloaded with the
3
+ // customer's license from synthetic.com.ar, verified (sha256), cached under ~/.synthetic/mcp/<product>/ and run. See docs/MCP_DISTRIBUTION_PLAN.md.
4
+ //
5
+ // 1. reads the license from the product's environment variable (the same one the customer already has in their MCP config)
6
+ // 2. asks POST /api/v1/mcp/bundle for the current version; the server validates the license and registers the device
7
+ // 3. downloads the bundle (short-lived signed URL), checks its sha256, unpacks it atomically
8
+ // 4. runs `node server.mjs` with the same stdio, so the MCP client talks to the real server
9
+ // Offline / server down: runs the last cached version. Invalid or revoked license: it does NOT run, and says why.
10
+ import fs from "node:fs";
11
+ import os from "node:os";
12
+ import path from "node:path";
13
+ import zlib from "node:zlib";
14
+ import crypto from "node:crypto";
15
+ import { spawn } from "node:child_process";
16
+ import { fileURLToPath } from "node:url";
17
+
18
+ export const DEFAULTS = {
19
+ product: "premiere-mcp", // set per package by the publisher
20
+ licenseEnv: "PREMIERE_PRO_MCP_LICENSE",
21
+ api: process.env.SYNTHETIC_API_URL || "https://synthetic.com.ar", // the override is for tests against a local/dev site
22
+ };
23
+
24
+ const say = (m) => process.stderr.write(`[synthetic] ${m}\n`);
25
+
26
+ /** ~/.synthetic/device-id: the SAME file the servers and panels use, so launcher + server + panel count as one device. */
27
+ function deviceId(home) {
28
+ const dir = path.join(home, ".synthetic"), file = path.join(dir, "device-id");
29
+ try { const v = fs.readFileSync(file, "utf8").trim(); if (v) return v; } catch { /* first run */ }
30
+ const id = crypto.randomUUID();
31
+ try { fs.mkdirSync(dir, { recursive: true }); fs.writeFileSync(file, id, "utf8"); } catch { /* read-only home: the id just won't persist */ }
32
+ return id;
33
+ }
34
+
35
+ /** Unpacks a container {files:{path:{enc,data}}} into dir. Refuses any path that would escape it. */
36
+ export function unpackContainer(buf, dir) {
37
+ const json = JSON.parse(zlib.gunzipSync(buf).toString("utf8"));
38
+ const root = path.resolve(dir);
39
+ for (const [rel, f] of Object.entries(json.files)) {
40
+ const target = path.resolve(root, rel);
41
+ if (target !== root && !target.startsWith(root + path.sep)) throw new Error(`ruta no permitida en el paquete: ${rel}`);
42
+ fs.mkdirSync(path.dirname(target), { recursive: true });
43
+ fs.writeFileSync(target, f.enc === "b64" ? Buffer.from(f.data, "base64") : f.data, f.enc === "b64" ? undefined : "utf8");
44
+ }
45
+ return json;
46
+ }
47
+
48
+ const readJson = (p) => { try { return JSON.parse(fs.readFileSync(p, "utf8")); } catch { return null; } };
49
+ /** The file to run inside an unpacked bundle: launch.json says (AE keeps dist/server.mjs); older bundles have server.mjs at the root. */
50
+ export const entryOf = (dir) => readJson(path.join(dir, "launch.json"))?.entry || "server.mjs";
51
+
52
+ /** Makes sure a runnable server is in the cache and returns its folder. Throws {kind:"license"|"network"|"other"}. */
53
+ export async function ensureBundle(opts = {}) {
54
+ const o = { ...DEFAULTS, home: os.homedir(), env: process.env, fetchImpl: globalThis.fetch, ...opts };
55
+ const license = (o.env[o.licenseEnv] ?? "").trim();
56
+ if (!license) throw Object.assign(new Error(`Falta la licencia: configurá ${o.licenseEnv} en tu cliente MCP (tu clave está en synthetic.com.ar/dashboard).`), { kind: "license" });
57
+ const cacheDir = path.join(o.home, ".synthetic", "mcp", o.product);
58
+ const current = readJson(path.join(cacheDir, "current.json")); // {version, sha256}
59
+ const have = current && fs.existsSync(path.join(cacheDir, current.version, entryOf(path.join(cacheDir, current.version)))) ? current : null;
60
+
61
+ let answer;
62
+ try {
63
+ const res = await o.fetchImpl(`${o.api}/api/v1/mcp/bundle`, {
64
+ method: "POST", headers: { "Content-Type": "application/json" },
65
+ body: JSON.stringify({ product: o.product, licenseKey: license, machineId: deviceId(o.home), deviceLabel: `${os.hostname()} (${process.platform})`, have: have?.version ?? null }),
66
+ signal: AbortSignal.timeout(15_000),
67
+ });
68
+ const body = await res.json().catch(() => ({}));
69
+ if (res.status === 401 || res.status === 403) throw Object.assign(new Error(body.error || "Licencia no válida."), { kind: "license" });
70
+ if (!res.ok) throw Object.assign(new Error(`El servidor respondió ${res.status}`), { kind: "network" });
71
+ answer = body;
72
+ } catch (e) {
73
+ if (e.kind === "license") throw e;
74
+ if (have) { say(`Sin conexión con synthetic.com.ar: uso la versión ${have.version} guardada.`); return { dir: path.join(cacheDir, have.version), version: have.version, offline: true }; }
75
+ throw Object.assign(new Error(`No pude conectar con synthetic.com.ar para descargar el servidor (${e.message}).`), { kind: "network" });
76
+ }
77
+
78
+ if (answer.upToDate && have) return { dir: path.join(cacheDir, have.version), version: have.version };
79
+ if (!answer.url || !answer.sha256 || !answer.version) throw Object.assign(new Error("Respuesta inesperada del servidor."), { kind: "other" });
80
+
81
+ const dl = await o.fetchImpl(answer.url, { signal: AbortSignal.timeout(60_000) });
82
+ if (!dl.ok) throw Object.assign(new Error(`No pude descargar el servidor (${dl.status}).`), { kind: "network" });
83
+ const buf = Buffer.from(await dl.arrayBuffer());
84
+ const got = crypto.createHash("sha256").update(buf).digest("hex");
85
+ if (got !== answer.sha256) throw Object.assign(new Error("El archivo descargado no coincide con su firma (sha256): no se ejecuta."), { kind: "other" });
86
+
87
+ const finalDir = path.join(cacheDir, answer.version), tmp = `${finalDir}.tmp-${process.pid}`;
88
+ fs.rmSync(tmp, { recursive: true, force: true });
89
+ fs.mkdirSync(tmp, { recursive: true });
90
+ unpackContainer(buf, tmp);
91
+ fs.rmSync(finalDir, { recursive: true, force: true });
92
+ fs.renameSync(tmp, finalDir);
93
+ fs.writeFileSync(path.join(cacheDir, "current.json"), JSON.stringify({ version: answer.version, sha256: answer.sha256 }));
94
+ for (const d of fs.readdirSync(cacheDir)) { // keep this version and the previous one only
95
+ if (d !== answer.version && d !== have?.version && fs.statSync(path.join(cacheDir, d)).isDirectory()) fs.rmSync(path.join(cacheDir, d), { recursive: true, force: true });
96
+ }
97
+ return { dir: finalDir, version: answer.version, downloaded: true };
98
+ }
99
+
100
+ export async function main(opts = {}) {
101
+ let r;
102
+ try { r = await ensureBundle(opts); }
103
+ // No process.exit() here: on Windows it can abort with a native crash code while the download's socket is still closing.
104
+ // Setting exitCode lets Node leave on its own once the connection is released.
105
+ catch (e) { say(e.message); process.exitCode = e.kind === "license" ? 2 : 1; return; }
106
+ const child = spawn(process.execPath, [path.join(r.dir, entryOf(r.dir)), ...process.argv.slice(2)], { stdio: "inherit", env: process.env });
107
+ for (const sig of ["SIGINT", "SIGTERM"]) process.on(sig, () => child.kill(sig));
108
+ child.on("exit", (code, signal) => process.exit(code ?? (signal ? 1 : 0)));
109
+ }
110
+
111
+ if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) await main();
package/package.json CHANGED
@@ -1,68 +1,24 @@
1
1
  {
2
2
  "name": "@synthetic-ai/premiere-mcp",
3
- "version": "2.3.6",
4
- "description": "MCP server for controlling Adobe Premiere Pro via CEP/ExtendScript — 437 tools for AI-driven video editing",
5
- "main": "dist/index.js",
3
+ "version": "3.0.0",
4
+ "description": "Launcher for the Synthetic premiere-mcp MCP server. Requires a license from https://synthetic.com.ar",
6
5
  "type": "module",
7
6
  "bin": {
8
- "premiere-mcp": "dist/index.js"
7
+ "premiere-mcp": "launcher.mjs"
9
8
  },
10
9
  "files": [
11
- "dist/**/*.js",
12
- "dist/**/*.d.ts",
13
- "i18n",
14
- "cep-plugin",
15
- "scripts",
10
+ "launcher.mjs",
16
11
  "README.md",
17
- "LICENSE",
18
- "CHANGELOG.md"
12
+ "LICENSE"
19
13
  ],
20
- "scripts": {
21
- "build": "tsc",
22
- "dev": "tsc --watch",
23
- "start": "node dist/index.js",
24
- "start:http": "node dist/http-server.js",
25
- "test": "vitest run",
26
- "test:watch": "vitest",
27
- "test:coverage": "vitest run --coverage",
28
- "install-cep": "bash scripts/install-cep.sh",
29
- "sync-i18n": "node scripts/sync-i18n.mjs"
30
- },
31
- "repository": {
32
- "type": "git",
33
- "url": "git+https://github.com/SyntheticArtOk/premiere-pro-mcp.git"
14
+ "engines": {
15
+ "node": ">=18"
34
16
  },
17
+ "license": "SEE LICENSE IN LICENSE",
35
18
  "homepage": "https://synthetic.com.ar",
36
- "bugs": {
37
- "url": "https://synthetic.com.ar"
38
- },
39
- "author": "Synthetic",
40
19
  "keywords": [
41
20
  "mcp",
42
- "model-context-protocol",
43
21
  "adobe",
44
- "premiere-pro",
45
- "video-editing",
46
- "ai",
47
- "extendscript",
48
- "cep",
49
- "claude",
50
- "windsurf",
51
- "cursor",
52
- "automation"
53
- ],
54
- "license": "MIT",
55
- "engines": {
56
- "node": ">=18.0.0"
57
- },
58
- "dependencies": {
59
- "@modelcontextprotocol/sdk": "^1.12.1",
60
- "zod": "^3.23.0"
61
- },
62
- "devDependencies": {
63
- "@types/node": "^22.10.0",
64
- "javascript-obfuscator": "^4.2.2",
65
- "typescript": "^5.7.0",
66
- "vitest": "^4.0.18"
67
- }
22
+ "synthetic"
23
+ ]
68
24
  }
package/CHANGELOG.md DELETED
@@ -1,186 +0,0 @@
1
- # Changelog
2
-
3
- ## [v2.3.6] — License check no longer locks the MCP out for an hour
4
-
5
- A failed license check (slow server answer, hiccup) is now remembered for 30 seconds instead of an hour, and the validation
6
- timeout went from 5 s to 15 s. Before, one slow answer left every tool answering "License server unreachable" until the MCP
7
- was restarted, even after the server was back.
8
-
9
- ## [v2.3.4] — The "Reload panel" button no longer reloads in place
10
-
11
- v2.3.3's `stopBridge()`-before-`location.reload()` fix wasn't enough —
12
- confirmed live, twice, on a clean install + full Premiere Pro restart, that
13
- `location.reload()` doesn't reliably re-run `init()` in this CEP host. Root
14
- cause found: each reload leaks the old page's `CEPHtmlEngine` subprocesses
15
- instead of terminating them — 37 orphaned processes were found accumulated
16
- from repeated testing today, versus ~6 for one cleanly opened panel. Rather
17
- than keep guessing at ways to make an in-place reload work, the ⟳ button no
18
- longer calls `location.reload()` at all — it stops the bridge and tells the
19
- user to restart Premiere Pro, the one path confirmed to always leave the
20
- panel correct.
21
-
22
- ## [v2.3.3] — Fixed the "Reload panel" button
23
-
24
- It called a bare `location.reload()`, which could leave the old poll
25
- interval running underneath the fresh page and race with `init()`
26
- re-running — the panel could get stuck showing the raw HTML placeholder
27
- badge, an empty temp dir field, and a spurious "Please set a temp
28
- directory" error, all while the actually-installed files were fine. Now
29
- stops the bridge (clearing the interval) before reloading, same fix class
30
- as Photoshop MCP's `wss.close()`-before-reload.
31
-
32
- ## [v2.3.2] — Reverted the license.json USER_DATA change
33
-
34
- v2.3.1 (panel side, unreleased separately from the npm tag) moved
35
- `getLicensePath()` from `SystemPath.EXTENSION` to `SystemPath.USER_DATA` to
36
- fix license saves failing with EPERM under a system-wide install. Live
37
- testing found a deeper issue: the CEP panel's embedded Node
38
- `fs.writeFileSync` can report success without the write actually landing on
39
- disk on this Premiere Pro version — confirmed by writing the target file
40
- directly and watching Premiere's own "successful" save leave it untouched.
41
- Reverted back to `SystemPath.EXTENSION` (pre-fix behavior) until this CEP
42
- Node.js reliability issue is understood; the original EPERM bug is still
43
- open, to be investigated outside production.
44
-
45
- ## [v2.3.1] — macOS example paths in tool descriptions
46
-
47
- `create_sequence`'s description and example calls only showed Windows
48
- `C:\Program Files\...` preset paths, even though the actual runtime preset
49
- lookup already searched macOS `/Applications/...` locations too — now the
50
- description and both examples (Windows + macOS) match what the code
51
- actually does, so the LLM doesn't suggest a Windows-only path to a Mac
52
- user. No runtime/behavior change.
53
-
54
- ## [v2.2.0] — `--doctor` diagnostic command
55
-
56
- `premiere-pro-mcp --doctor` runs a standalone setup check — no MCP client or
57
- Premiere Pro needs to be running: Node version, Premiere Pro install
58
- detected on disk, license key present + live-validated against
59
- synthetic.com.ar, and the CEP bridge temp directory is writable. Prints a
60
- pass/warn/fail summary and exits 1 if anything failed, so it's scriptable.
61
- Fixed a real crash found while building this: forcing `process.exit()`
62
- right after the live license check's `fetch()` call could crash with a
63
- libuv assertion on Windows (`UV_HANDLE_CLOSING`, src/win/async.c) — now
64
- sets `process.exitCode` and lets the event loop drain naturally instead.
65
-
66
- ## [v2.1.0] — CRITICAL: correct the version line, ship everything since 2.0.0
67
-
68
- `@synthetic-ai/premiere-mcp@2.0.0` (published 2026-06-10, the npm rename
69
- from unscoped `premiere-pro-mcp`) has been the only version ever actually
70
- published to the registry — `npm view` confirms `dist-tags.latest` and the
71
- full `versions` list both show only `2.0.0`, right up until this release.
72
- Six commits after the rename (v1.1.2 through v1.1.8, including v1.1.7's
73
- **server-side license enforcement**) bumped `package.json`'s version
74
- *backward* into a stale pre-rename 1.1.x line instead of continuing from
75
- 2.0.0, and were committed/tested but never `npm publish`ed under that
76
- wrong version number. Net effect: every customer running
77
- `npx @synthetic-ai/premiere-mcp` has been getting the unmodified 2.0.0
78
- tarball — with **zero license checking on any of the 437 tools** — for
79
- over three months, discovered 2026-09-23 while shipping the macOS preset
80
- fix below. This release corrects the version line (2.0.0 → 2.1.0, a real
81
- semver increase) and ships every accumulated fix at once:
82
- - License enforcement (was v1.1.7): every tool except `ping` /
83
- `get_version_info` now validates `PREMIERE_PRO_MCP_LICENSE`.
84
- - In-panel auto-update + local license storage (was v1.1.2).
85
- - ExtendScript obfuscation breaking `evalFile()` (was v1.1.4).
86
- - Bridge could wedge forever after a single failed command read (was v1.1.5).
87
- - macOS default sequence-preset paths (was v1.1.8, see below).
88
-
89
- ## [v1.1.8] — macOS default preset paths (superseded by v2.1.0, never actually reached "latest" — see above)
90
-
91
- `create_sequence`, `create_sequence_from_clip`, and `get_default_sequence_presets`
92
- only ever probed Windows install paths for the default `.sqpreset` (and, for
93
- `create_sequence`, only a single hardcoded PP 2026 path with no probing at
94
- all). All three now check both Windows and macOS locations across PP
95
- 2026/2025/2024/CC 2023, matching the pattern `export_sequence` already used
96
- for AME presets. When nothing is found, the tools return a clear error
97
- asking for an explicit `preset_path` instead of silently using a
98
- definitely-wrong fallback. Found via a site-wide macOS-compatibility audit
99
- of every Synthetic product (2026-09-23) — this was the one confirmed gap in
100
- an otherwise genuinely cross-platform architecture (no launch step to
101
- break, unlike ae-mcp). Unverified on real macOS hardware — no Mac available
102
- to test against yet.
103
-
104
- ## [v1.1.7] — License enforcement
105
-
106
- The MCP server itself (all 437 tools) never actually validated
107
- `PREMIERE_PRO_MCP_LICENSE` — the CEP panel had a license field for its own
108
- auto-update, but the server side was wide open. Added the same
109
- `checkLicense()` gate ae-mcp and photoshop-mcp already have: every tool
110
- except `ping` / `get_version_info` now requires a valid license, validated
111
- against `https://synthetic.com.ar/api/v1/license/validate` and cached for an
112
- hour.
113
-
114
- ---
115
-
116
- All notable changes to this MCP server. Every fix below was discovered via
117
- **static audit + live runtime testing against Premiere Pro 2026.2.2 on
118
- Spanish-localized Windows**.
119
-
120
- The audit started at **31/100 sellability score** (22% green tools) and
121
- finished at **~78/100** (~75% green) after the rounds below.
122
-
123
- ---
124
-
125
- ## [v1.2.0] — PP 2026 compatibility + locale resilience
126
-
127
- ### Round 6 — Live runtime validation
128
- - `6f20892` capture_frame: honest error for PP 2026 host limitation
129
- - `8152021` bridge: sanitize NaN and Infinity to null
130
- - `a74ce33` Round 5: 8 more fixes from full smoke test (137 tools tested)
131
- - `45fdaba` track-targeting: locale-resilient set_clip_position/scale/rotation
132
- - `f9589cb` premiere.jsx: locale-resilient fadeIn/fadeOut/crossFadeClips
133
- - `29e941d` graceful fallbacks for setSpeed signature + track volume
134
- - `0533162` Live-test fixes: setSpeed signature, locale prop names, audio clip volume
135
- - `084ef49` Live-test fixes: set_clip_opacity locale, color_correct Lumetri name
136
-
137
- ### Round 5 — Bridge JSON sanitization
138
- - `f3d83d7` Fix bridge JSON: ExtendScript ignores replacer; sanitize tree pre-stringify
139
-
140
- ### Round 4 — premiere.jsx loading (single highest-impact fix)
141
- - `366f325` Fix premiere.jsx SyntaxError that broke ALL JSX helpers
142
- - **1-char fix, ~30+ tools unblocked**
143
- - `premiere.jsx` (22k lines) had `package:` as bare property name at line
144
- 22006. ExtendScript is strict ES3 where `package` is reserved → entire
145
- file fails to parse → every JSX-helper-backed tool returns
146
- `ReferenceError: <fn> is not a function`. Quoting fixes everything.
147
- - `b12a0d8` Round 4: bridge JSON-parse failure + locale-resilient transition lookup
148
-
149
- ### Round 3 — Concrete code bugs from re-audit
150
- - `21bf821` Round 3 part 2: fix remaining 9 files
151
- - `e4534d5` Round 3: fix 32 concrete code bugs from re-audit
152
- - ticks/Time correctness (markers, source-monitor, scripting, clipboard, audio)
153
- - property-vs-method (media.check_offline_media)
154
- - QE-only methods routed correctly (timeline.move_clip/speed_change, transitions)
155
- - missing `app.enableQE()` guards
156
- - nested Lumetri prop lookup via `__findProp`
157
-
158
- ### Round 2 — Locale-resilient helpers
159
- - `bdaebaa` Round 2: guard QE multicam enumeration and proxy detach
160
- - `48d3648` Round 2 part 2: fix remaining 8 files
161
- - `2b718b3` Round 2 part 1: locale-resilient helpers + fix 13 tool files
162
- - Added `__findIntrinsic(clip, key)` with matchName-first lookup
163
- - Added `__findComponent`, `__findProp`, `__readMaybe`, `__findTransition`
164
-
165
- ### Round 1 — Property-vs-method bugs
166
- - `ffe6931` Fix 21 red tools: property-vs-method bugs, missing APIs, stub handlers
167
- - `35ecbfa` Fix PP 2026 compatibility: sequence creation, tracks, audio, effects, export
168
-
169
- ---
170
-
171
- ## Validated tool inventory
172
-
173
- ### ✅ 66 tools confirmed working in runtime (PP 2026.2.2 es-ES)
174
- Inspection, transform, audio/video FX, timeline editing, selection, markers,
175
- sequence ops, project/bins, captions, source monitor, track management,
176
- metadata, scripting, export. Full list in [README.md](README.md).
177
-
178
- ### ⚠️ Honest errors (PP 2026 host limitations, not bugs)
179
- - `set_track_volume`, `speed_change`, `capture_frame`, Lumetri-when-not-applied
180
- - All return clear errors with the recommended UI workaround
181
-
182
- ### Validated against
183
- - Premiere Pro 2026.2.2 on Windows
184
- - Spanish (es-ES) locale — names like "Opacidad", "Movimiento", "Escala",
185
- "Posición", "Disolvencia cruzada" all handled
186
- - 15-item test project with multi-track timeline, transitions, fades, Lumetri
package/cep-plugin/.debug DELETED
@@ -1,8 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <ExtensionList>
3
- <Extension Id="com.mcp.premiere.bridge.panel">
4
- <HostList>
5
- <Host Name="PPRO" Port="8088"/>
6
- </HostList>
7
- </Extension>
8
- </ExtensionList>