davinci-resolve-mcp 2.25.0 → 2.26.1
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/AGENTS.md +3 -1
- package/CHANGELOG.md +52 -0
- package/README.md +3 -3
- package/bin/davinci-resolve-mcp.mjs +78 -7
- package/docs/SKILL.md +19 -3
- package/docs/install.md +10 -1
- package/docs/kernels/fusion-composition-kernel.md +30 -0
- package/install.py +73 -8
- package/package.json +1 -1
- package/src/batch_cli.py +456 -0
- package/src/granular/common.py +1 -1
- package/src/server.py +331 -4
- package/src/utils/fusion_group_settings.py +323 -0
package/AGENTS.md
CHANGED
|
@@ -93,7 +93,9 @@ venv/bin/python tests/test_import.py
|
|
|
93
93
|
venv/bin/python scripts/audit_api_parity.py
|
|
94
94
|
```
|
|
95
95
|
|
|
96
|
-
Python 3.10-3.12 is
|
|
96
|
+
Python 3.10+ is required (the MCP SDK floor). 3.10-3.12 is the lowest-risk range
|
|
97
|
+
for Resolve scripting; 3.13/3.14 are accepted and verified on Resolve Studio
|
|
98
|
+
20.3.2, but older Resolve builds may fail to connect on 3.13+.
|
|
97
99
|
|
|
98
100
|
## Development Notes
|
|
99
101
|
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,58 @@
|
|
|
2
2
|
|
|
3
3
|
Release history for the DaVinci Resolve MCP Server. The latest release is summarized in the root README; older entries live here to keep the README focused.
|
|
4
4
|
|
|
5
|
+
## What's New in v2.26.1
|
|
6
|
+
|
|
7
|
+
**Python 3.13 / 3.14 support (issue #45)** — `npx davinci-resolve-mcp setup`
|
|
8
|
+
previously hard-refused any interpreter outside 3.10–3.12, so it failed outright
|
|
9
|
+
on Python 3.14. The 3.12 ceiling was based on a stale assumption that Resolve's
|
|
10
|
+
scripting bridge has ABI incompatibilities on 3.13+. Verified empirically against
|
|
11
|
+
DaVinci Resolve Studio 20.3.2.9: Python 3.14.4 connects and exercises the
|
|
12
|
+
dict/list marshalling paths cleanly. The launcher and installer now enforce only
|
|
13
|
+
the 3.10 floor (the `mcp[cli]` SDK requirement) with no upper cap. Python 3.13/3.14
|
|
14
|
+
are accepted with a soft heads-up; `setup`/`doctor` surface a precise,
|
|
15
|
+
connection-aware hint only when Resolve is running but the bridge returns no
|
|
16
|
+
connection on 3.13+. Sub-3.10 interpreters get an actionable error instead of a
|
|
17
|
+
dead end. `server.py` warns (never exits) on 3.13+. Adds 6 version-gate unit tests.
|
|
18
|
+
|
|
19
|
+
## What's New in v2.26.0
|
|
20
|
+
|
|
21
|
+
**Fusion group-settings helpers** — Three new `fusion_comp` actions for
|
|
22
|
+
authoring and patching `GroupOperator` macros without leaving the kernel.
|
|
23
|
+
`group_settings_export` writes a live group to a `.setting` file and returns a
|
|
24
|
+
parsed `published_inputs` summary using a balanced-brace walker so nested
|
|
25
|
+
`UserControls` / `ControlGroup` tables are bounded correctly (the original
|
|
26
|
+
flat-regex parser truncated `InstanceInput` bodies at the first inner `}`).
|
|
27
|
+
`group_settings_splice_inputs` replaces the `Inputs = ordered() { ... }` block
|
|
28
|
+
of one `.setting` with the matching block from another, preserving the source's
|
|
29
|
+
outer structure and inner `Tools`. `group_settings_load` applies a `.setting`
|
|
30
|
+
to a live group with an automatic timestamped backup, wrapped in
|
|
31
|
+
`StartUndo`/`Lock`/`LoadSettings`/`Unlock`/`EndUndo(True)` so Fusion's Ctrl+Z
|
|
32
|
+
reverses the change — verified live via direct BMD API.
|
|
33
|
+
|
|
34
|
+
**bulk_set_expressions** — Companion to the existing `bulk_set_inputs`. Batch
|
|
35
|
+
attach Fusion expressions across many timeline-item comps in one call. Each op
|
|
36
|
+
requires timeline scope plus `tool_name`, `input_name`, `expression`. Returns
|
|
37
|
+
per-op `success`/`error` rows + `op_count`, matching the bulk-inputs contract.
|
|
38
|
+
Useful for animating many controls at once (`time/30`, etc.) under a single
|
|
39
|
+
chat turn.
|
|
40
|
+
|
|
41
|
+
**Headless batch-runner CLI** — New
|
|
42
|
+
`davinci-resolve-mcp batch <plan|run|status|list|resume|cancel>` subcommand
|
|
43
|
+
drives `src/utils/media_analysis_jobs` from outside an MCP/chat client so long
|
|
44
|
+
analysis batches can run via cron, CI, or terminal without holding a chat turn
|
|
45
|
+
open. The orchestration loop and durable state stay in the existing jobs
|
|
46
|
+
engine; the CLI only handles argv, progress streaming, and exit codes
|
|
47
|
+
(`0` ok / `2` partial / `3` fatal / `130` Ctrl+C). JSON mode (`--json`)
|
|
48
|
+
emits one record per progress event for log scraping. Closes #42.
|
|
49
|
+
|
|
50
|
+
**Adapted from PR #40** — Group-settings work originated as a contribution
|
|
51
|
+
from @RaincloudTheDragon; PR #43 retains the keepable parts (parser, exporter,
|
|
52
|
+
splicer, loader, `bulk_set_expressions`) with a balanced-brace fix on the
|
|
53
|
+
parser and an undo+lock wrap on `group_settings_load`. The two AMZ-specific
|
|
54
|
+
templates and the static checklist from #40 were dropped as out-of-scope for a
|
|
55
|
+
general kernel.
|
|
56
|
+
|
|
5
57
|
## What's New in v2.25.0
|
|
6
58
|
|
|
7
59
|
**Agentic flow improvements** — A second-pass review against the Claude
|
package/README.md
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# DaVinci Resolve MCP Server
|
|
2
2
|
|
|
3
|
-
[](https://github.com/samuelgursky/davinci-resolve-mcp/releases)
|
|
4
4
|
[](https://www.npmjs.com/package/davinci-resolve-mcp)
|
|
5
5
|
[](docs/reference/api-coverage.md)
|
|
6
6
|
[-blue.svg)](#server-modes)
|
|
7
7
|
[](docs/reference/api-coverage.md#test-results)
|
|
8
8
|
[](https://www.blackmagicdesign.com/products/davinciresolve)
|
|
9
|
-
[](https://www.python.org/downloads/)
|
|
10
10
|
[](https://opensource.org/licenses/MIT)
|
|
11
11
|
|
|
12
12
|
A Model Context Protocol (MCP) server that lets AI assistants control DaVinci Resolve Studio through the official Scripting API. It provides full API coverage plus guarded workflow helpers for editing, media pool organization, render setup, review markers, grading, Fusion, Fairlight, project lifecycle tasks, extension authoring, and source-safe media analysis.
|
|
@@ -133,7 +133,7 @@ Extension authoring references live in [docs/authoring](docs/authoring/). Resolv
|
|
|
133
133
|
## Requirements
|
|
134
134
|
|
|
135
135
|
- DaVinci Resolve Studio 18.5+ on macOS, Windows, or Linux. The free edition does not support external scripting.
|
|
136
|
-
- Python 3.10-3.12
|
|
136
|
+
- Python 3.10+ (3.10-3.12 is the lowest-risk range). Python 3.13/3.14 also work on recent Resolve builds (verified on Studio 20.3.2); older builds may fail to connect on 3.13+, in which case use 3.10-3.12.
|
|
137
137
|
- Resolve external scripting set to **Local**.
|
|
138
138
|
|
|
139
139
|
Resolve 19.1.3 remains the compatibility baseline. Resolve 20.x scripting calls are additive, version-guarded, and live-tested on 20.3.2. Resolve 21 beta APIs are intentionally deferred until stable.
|
|
@@ -11,6 +11,16 @@ const PACKAGE_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)),
|
|
|
11
11
|
const VERSION = readPackageVersion();
|
|
12
12
|
const MANAGED_MARKER = ".davinci-resolve-mcp-managed.json";
|
|
13
13
|
|
|
14
|
+
// The only hard Python floor is the MCP SDK: mcp[cli] requires 3.10+.
|
|
15
|
+
// We do NOT cap the upper bound. Resolve's scripting bridge (fusionscript)
|
|
16
|
+
// loads cleanly into newer interpreters on recent builds — Python 3.14 is
|
|
17
|
+
// verified working against Resolve Studio 20.3.2. Older Resolve builds may
|
|
18
|
+
// fail to connect on 3.13+, but the version number is a poor proxy for that;
|
|
19
|
+
// the connection check in `setup`/`doctor` is the real signal, so we proceed
|
|
20
|
+
// with a soft heads-up rather than refusing to run.
|
|
21
|
+
const PY_MIN_MINOR = 10;
|
|
22
|
+
const PY_ABI_RISK_MINOR = 13;
|
|
23
|
+
|
|
14
24
|
const SYNC_ITEMS = [
|
|
15
25
|
"bin",
|
|
16
26
|
"src",
|
|
@@ -41,6 +51,7 @@ Usage:
|
|
|
41
51
|
davinci-resolve-mcp doctor [install.py options]
|
|
42
52
|
davinci-resolve-mcp server [server.py options]
|
|
43
53
|
davinci-resolve-mcp control-panel [control panel options]
|
|
54
|
+
davinci-resolve-mcp batch <plan|run|status|list|resume|cancel> [options]
|
|
44
55
|
davinci-resolve-mcp --version
|
|
45
56
|
davinci-resolve-mcp --help
|
|
46
57
|
|
|
@@ -48,10 +59,13 @@ Examples:
|
|
|
48
59
|
npx davinci-resolve-mcp setup
|
|
49
60
|
npx davinci-resolve-mcp setup --clients cursor,claude-desktop
|
|
50
61
|
npx davinci-resolve-mcp doctor
|
|
62
|
+
npx davinci-resolve-mcp batch run /path/to/footage --depth standard
|
|
63
|
+
npx davinci-resolve-mcp batch run /path/to/footage --json > progress.log
|
|
51
64
|
|
|
52
65
|
Environment:
|
|
53
66
|
DAVINCI_RESOLVE_MCP_INSTALL_ROOT Override the managed install directory.
|
|
54
|
-
DAVINCI_RESOLVE_MCP_PYTHON Python executable to use.
|
|
67
|
+
DAVINCI_RESOLVE_MCP_PYTHON Python executable to use (3.10+). Set this to
|
|
68
|
+
pin a specific interpreter, e.g. python3.12.
|
|
55
69
|
PYTHON Fallback Python executable to use.
|
|
56
70
|
`;
|
|
57
71
|
}
|
|
@@ -190,17 +204,24 @@ function pythonCandidates() {
|
|
|
190
204
|
if (explicit) {
|
|
191
205
|
candidates.push(explicit);
|
|
192
206
|
}
|
|
207
|
+
// Prefer the lowest-ABI-risk interpreters first, then newer ones, then the
|
|
208
|
+
// generic launchers. All 3.10+ are accepted; ordering just picks the safest
|
|
209
|
+
// when several are installed.
|
|
193
210
|
if (process.platform === "win32" && commandExists("py")) {
|
|
194
211
|
candidates.push(
|
|
195
212
|
{ command: "py", args: ["-3.12"] },
|
|
196
213
|
{ command: "py", args: ["-3.11"] },
|
|
197
|
-
{ command: "py", args: ["-3.10"] }
|
|
214
|
+
{ command: "py", args: ["-3.10"] },
|
|
215
|
+
{ command: "py", args: ["-3.13"] },
|
|
216
|
+
{ command: "py", args: ["-3.14"] }
|
|
198
217
|
);
|
|
199
218
|
}
|
|
200
219
|
candidates.push(
|
|
201
220
|
{ command: "python3.12", args: [] },
|
|
202
221
|
{ command: "python3.11", args: [] },
|
|
203
222
|
{ command: "python3.10", args: [] },
|
|
223
|
+
{ command: "python3.13", args: [] },
|
|
224
|
+
{ command: "python3.14", args: [] },
|
|
204
225
|
{ command: "python3", args: [] },
|
|
205
226
|
{ command: "python", args: [] }
|
|
206
227
|
);
|
|
@@ -221,8 +242,9 @@ function checkPython(candidate) {
|
|
|
221
242
|
}
|
|
222
243
|
try {
|
|
223
244
|
const info = JSON.parse(result.stdout.trim());
|
|
224
|
-
const supported = info.major === 3 && info.minor >=
|
|
225
|
-
|
|
245
|
+
const supported = info.major === 3 && info.minor >= PY_MIN_MINOR;
|
|
246
|
+
const abiRisk = info.major === 3 && info.minor >= PY_ABI_RISK_MINOR;
|
|
247
|
+
return { ...candidate, ...info, supported, abiRisk };
|
|
226
248
|
} catch {
|
|
227
249
|
return null;
|
|
228
250
|
}
|
|
@@ -241,8 +263,40 @@ function findSupportedPython() {
|
|
|
241
263
|
}
|
|
242
264
|
}
|
|
243
265
|
|
|
244
|
-
|
|
245
|
-
|
|
266
|
+
throw new Error(unsupportedPythonMessage(checked));
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// Print the 3.13+ heads-up for run modes that never invoke install.py
|
|
270
|
+
// (server/control-panel/batch). setup/doctor stay quiet here because
|
|
271
|
+
// install.py emits a richer, connection-aware note of its own.
|
|
272
|
+
function maybeWarnAbiRisk(info) {
|
|
273
|
+
if (info && info.abiRisk) {
|
|
274
|
+
console.warn(abiRiskNote(info));
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
function abiRiskNote(info) {
|
|
279
|
+
return (
|
|
280
|
+
`Note: using Python ${info.major}.${info.minor}.${info.micro}. ` +
|
|
281
|
+
`This is verified working on recent Resolve builds (Studio 20.3.2). ` +
|
|
282
|
+
`If Resolve fails to connect (scriptapp("Resolve") returns None), install ` +
|
|
283
|
+
`Python 3.10-3.12 and pin it with DAVINCI_RESOLVE_MCP_PYTHON=/path/to/python3.12.`
|
|
284
|
+
);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
function unsupportedPythonMessage(checked) {
|
|
288
|
+
const found = checked.length ? ` Found: ${checked.join(", ")}.` : "";
|
|
289
|
+
const lines = [
|
|
290
|
+
`Python 3.${PY_MIN_MINOR} or newer is required (the MCP SDK needs Python 3.${PY_MIN_MINOR}+).${found}`,
|
|
291
|
+
"",
|
|
292
|
+
"How to fix:",
|
|
293
|
+
" - Install Python 3.12 (the lowest-risk version for Resolve), e.g.:",
|
|
294
|
+
" macOS: brew install python@3.12 (or: pyenv install 3.12)",
|
|
295
|
+
" Linux: pyenv install 3.12 (or your distro's python3.12 package)",
|
|
296
|
+
" Windows: install Python 3.12 from python.org",
|
|
297
|
+
` - Point the launcher at it: DAVINCI_RESOLVE_MCP_PYTHON=/path/to/python3.12 npx ${APP_NAME} setup`,
|
|
298
|
+
];
|
|
299
|
+
return lines.join("\n");
|
|
246
300
|
}
|
|
247
301
|
|
|
248
302
|
function venvPython(root) {
|
|
@@ -255,7 +309,10 @@ function venvPython(root) {
|
|
|
255
309
|
}
|
|
256
310
|
const info = checkPython({ command: executable, args: [] });
|
|
257
311
|
if (!info || !info.supported) {
|
|
258
|
-
throw new Error(
|
|
312
|
+
throw new Error(
|
|
313
|
+
`Managed venv Python must be 3.${PY_MIN_MINOR} or newer. ` +
|
|
314
|
+
`Re-run setup to recreate it: ${executable}`
|
|
315
|
+
);
|
|
259
316
|
}
|
|
260
317
|
return info;
|
|
261
318
|
}
|
|
@@ -323,6 +380,7 @@ function commandDoctor(args) {
|
|
|
323
380
|
function commandServer(args) {
|
|
324
381
|
const root = syncManagedInstall(installRoot());
|
|
325
382
|
const python = venvPython(root) || findSupportedPython();
|
|
383
|
+
maybeWarnAbiRisk(python);
|
|
326
384
|
const serverScript = path.join(root, "src", "server.py");
|
|
327
385
|
const [command, ...commandArgs] = pythonCommandLine(python, [serverScript, ...args]);
|
|
328
386
|
run(command, commandArgs, { cwd: root });
|
|
@@ -331,10 +389,19 @@ function commandServer(args) {
|
|
|
331
389
|
function commandControlPanel(args) {
|
|
332
390
|
const root = syncManagedInstall(installRoot());
|
|
333
391
|
const python = venvPython(root) || findSupportedPython();
|
|
392
|
+
maybeWarnAbiRisk(python);
|
|
334
393
|
const [command, ...commandArgs] = pythonCommandLine(python, ["-m", "src.control_panel", ...args]);
|
|
335
394
|
run(command, commandArgs, { cwd: root });
|
|
336
395
|
}
|
|
337
396
|
|
|
397
|
+
function commandBatch(args) {
|
|
398
|
+
const root = syncManagedInstall(installRoot());
|
|
399
|
+
const python = venvPython(root) || findSupportedPython();
|
|
400
|
+
maybeWarnAbiRisk(python);
|
|
401
|
+
const [command, ...commandArgs] = pythonCommandLine(python, ["-m", "src.batch_cli", ...args]);
|
|
402
|
+
run(command, commandArgs, { cwd: root });
|
|
403
|
+
}
|
|
404
|
+
|
|
338
405
|
function main() {
|
|
339
406
|
const argv = process.argv.slice(2);
|
|
340
407
|
// No args → run the MCP stdio server. Anything printed to stdout would
|
|
@@ -366,6 +433,10 @@ function main() {
|
|
|
366
433
|
commandControlPanel(args);
|
|
367
434
|
return;
|
|
368
435
|
}
|
|
436
|
+
if (command === "batch") {
|
|
437
|
+
commandBatch(args);
|
|
438
|
+
return;
|
|
439
|
+
}
|
|
369
440
|
|
|
370
441
|
console.error(`Unknown command: ${command}\n`);
|
|
371
442
|
console.error(usage());
|
package/docs/SKILL.md
CHANGED
|
@@ -923,6 +923,18 @@ Key actions:
|
|
|
923
923
|
- `start_undo(name?)` / `end_undo(keep?)`
|
|
924
924
|
- `bulk_set_inputs(ops)` — batch set inputs across multiple timeline item comps in
|
|
925
925
|
one call; each op requires timeline scope plus `tool_name`, `input_name`, `value`
|
|
926
|
+
- `bulk_set_expressions(ops)` — batch attach expressions across multiple timeline
|
|
927
|
+
item comps in one call; each op requires timeline scope plus `tool_name`,
|
|
928
|
+
`input_name`, `expression`
|
|
929
|
+
- `group_settings_export(group_name, path, include_advisory?)` — write a
|
|
930
|
+
`GroupOperator` to disk and return a parsed published-input summary
|
|
931
|
+
- `group_settings_splice_inputs(source_path, template_path, dest_path?, source_group_name?, template_group_name?)` —
|
|
932
|
+
replace one `.setting` file's `Inputs = ordered() { ... }` block with the
|
|
933
|
+
matching block from another, preserving inner tools and outer structure;
|
|
934
|
+
balanced-brace parser handles nested `UserControls`
|
|
935
|
+
- `group_settings_load(group_name, settings_path, backup_path?, undo_name?)` —
|
|
936
|
+
apply a `.setting` to a live group with an auto backup and an undo wrap so
|
|
937
|
+
Ctrl+Z reverses the change
|
|
926
938
|
|
|
927
939
|
Fusion Composition kernel actions (v2.12.0+) add safer graph inspection and
|
|
928
940
|
mutation wrappers around the raw Fusion API:
|
|
@@ -1235,9 +1247,13 @@ timeline item returns `False` in Resolve. Use `get_node_graph` without a
|
|
|
1235
1247
|
if the Gallery panel is open in the Resolve UI on the Color page. Instruct the
|
|
1236
1248
|
user to open it via Workspace menu if export fails.
|
|
1237
1249
|
|
|
1238
|
-
**Python version** —
|
|
1239
|
-
|
|
1240
|
-
|
|
1250
|
+
**Python version** — the only hard requirement is Python **3.10+** (the MCP SDK
|
|
1251
|
+
floor). There is no upper cap: 3.13/3.14 are accepted, and Python 3.14 is verified
|
|
1252
|
+
working against Resolve Studio 20.3.2. On *older* Resolve builds the scripting
|
|
1253
|
+
bridge may still fail to load on 3.13+ (`scriptapp("Resolve")` returns `None`);
|
|
1254
|
+
`setup`/`doctor` warn on 3.13+ and their connection check surfaces a real failure.
|
|
1255
|
+
If that happens, recreate the venv with Python 3.10–3.12 (the lowest-risk range).
|
|
1256
|
+
The running server only warns on 3.13+ rather than exiting.
|
|
1241
1257
|
|
|
1242
1258
|
**Resolve version guards** — Resolve 20-specific actions return a clear
|
|
1243
1259
|
`requires DaVinci Resolve 20.x+` error when called against older builds. Resolve
|
package/docs/install.md
CHANGED
|
@@ -5,9 +5,18 @@ This guide covers Resolve requirements, the universal installer, supported MCP c
|
|
|
5
5
|
## Requirements
|
|
6
6
|
|
|
7
7
|
- **DaVinci Resolve Studio** 18.5+ (macOS, Windows, or Linux) — the free edition does not support external scripting
|
|
8
|
-
- **Python 3.10
|
|
8
|
+
- **Python 3.10+** (the MCP SDK requires 3.10). **3.10–3.12 is the lowest-risk
|
|
9
|
+
choice**; 3.13/3.14 also work on recent Resolve builds — see below
|
|
9
10
|
- DaVinci Resolve running with **Preferences > General > "External scripting using"** set to **Local**
|
|
10
11
|
|
|
12
|
+
> **Python 3.13 / 3.14:** these are **allowed** — setup will use them and warn.
|
|
13
|
+
> Python 3.14 is verified working against DaVinci Resolve Studio 20.3.2. On
|
|
14
|
+
> *older* Resolve builds the scripting bridge may fail to load on 3.13+
|
|
15
|
+
> (`scriptapp("Resolve")` returns `None`); setup's connection check will tell you
|
|
16
|
+
> if that happens. If it does, install a 3.10–3.12 interpreter
|
|
17
|
+
> (`brew install python@3.12`, `pyenv install 3.12`, or python.org on Windows) and
|
|
18
|
+
> point the launcher at it with `DAVINCI_RESOLVE_MCP_PYTHON=/path/to/python3.12`.
|
|
19
|
+
|
|
11
20
|
Validated live coverage is based on **DaVinci Resolve 19.1.3 Studio** for the original API surface, plus **DaVinci Resolve 20.3.2 Studio** for the Resolve 20.0-20.2.2 scripting additions. Resolve 21 beta APIs are intentionally deferred until a stable release.
|
|
12
21
|
|
|
13
22
|
## Quick Start
|
|
@@ -30,10 +30,40 @@ All actions are exposed through `fusion_comp`.
|
|
|
30
30
|
| `safe_set_inputs` | Batch write inputs on one tool with optional readback classification. |
|
|
31
31
|
| `safe_connect_tools` | Validate source/target tools before connecting a source output to a target input. |
|
|
32
32
|
| `fusion_boundary_report` | Return graph capabilities plus a composition snapshot for the selected comp scope. |
|
|
33
|
+
| `bulk_set_expressions` | Batch `SetExpression` across scoped timeline-item Fusion comps. Each op needs `tool_name`, `input_name`, `expression`, plus a timeline scope. Wraps each op in `StartUndo`/`EndUndo` + `comp.Lock`. |
|
|
34
|
+
| `group_settings_export` | Save a named `GroupOperator`'s settings to a `.setting` file via `SaveSettings`, returning a parsed published-input summary. |
|
|
35
|
+
| `group_settings_splice_inputs` | Replace the `Inputs = ordered() { ... }` block of `source_path` with the matching block from `template_path` and write `dest_path`. Read-only against Resolve; pure file operation. |
|
|
36
|
+
| `group_settings_load` | Backup the current group state, then `LoadSettings` from a `.setting` file. Wrapped in `StartUndo`/`EndUndo` + `comp.Lock` so Fusion's Ctrl+Z can reverse it. Backup path is returned alongside any error. |
|
|
37
|
+
| `probe_group_published_inputs` | Read live published `Input1..InputN` slots off a `GroupOperator`, optionally cross-referenced with a `.setting` file summary. |
|
|
33
38
|
|
|
34
39
|
The pre-existing `bulk_set_inputs` action remains the batch path for applying
|
|
35
40
|
input writes across multiple explicitly scoped timeline-item Fusion comps.
|
|
36
41
|
|
|
42
|
+
### `group_settings_splice_inputs` notes
|
|
43
|
+
|
|
44
|
+
The Fusion `.setting` format is a Lua-like nested structure: an InstanceInput
|
|
45
|
+
commonly contains `UserControls = ordered() { Custom = { ... } }` tables, so any
|
|
46
|
+
parsing that uses a flat regex will truncate bodies at the first inner `}`. This
|
|
47
|
+
kernel uses balanced-brace scanning end-to-end. Practical implications:
|
|
48
|
+
|
|
49
|
+
- The action only swaps the published `Inputs = ordered() { ... }` block. The
|
|
50
|
+
group's outer name, inner `Tools = ordered() { ... }` section, and surrounding
|
|
51
|
+
structure are preserved byte-for-byte.
|
|
52
|
+
- You must provide the *new* layout as a real `.setting` file (typically
|
|
53
|
+
exported from a known-good group via `group_settings_export`). The kernel does
|
|
54
|
+
not ship hardcoded templates.
|
|
55
|
+
- `template_group_name` is optional when the template file contains a single
|
|
56
|
+
`GroupOperator`; pass it when the template file contains multiple groups and
|
|
57
|
+
you want a specific one.
|
|
58
|
+
|
|
59
|
+
### `group_settings_load` Edit-page caveat
|
|
60
|
+
|
|
61
|
+
`LoadSettings` may update inner tool wiring but not refresh Edit-page
|
|
62
|
+
`InstanceInput` order until the group is selected in Fusion and reloaded via UI.
|
|
63
|
+
This is a Resolve quirk, not a kernel bug. The action always backs up the group
|
|
64
|
+
to a timestamped sibling of `settings_path` first; the backup path is returned
|
|
65
|
+
in success and in error responses.
|
|
66
|
+
|
|
37
67
|
## Scope Matrix
|
|
38
68
|
|
|
39
69
|
| Scope | Probe Support | Mutation Support | Notes |
|
package/install.py
CHANGED
|
@@ -35,9 +35,14 @@ from src.utils.update_check import (
|
|
|
35
35
|
|
|
36
36
|
# ─── Version ──────────────────────────────────────────────────────────────────
|
|
37
37
|
|
|
38
|
-
VERSION = "2.
|
|
38
|
+
VERSION = "2.26.1"
|
|
39
|
+
# Only hard floor: mcp[cli] requires Python 3.10+. There is no upper bound —
|
|
40
|
+
# Resolve's scripting bridge loads into newer interpreters on recent builds
|
|
41
|
+
# (Python 3.14 verified against Resolve Studio 20.3.2). Older Resolve builds
|
|
42
|
+
# may fail to connect on 3.13+, but the connection check is the real signal,
|
|
43
|
+
# so we proceed with a heads-up rather than refusing to run.
|
|
39
44
|
SUPPORTED_PYTHON_MIN = (3, 10)
|
|
40
|
-
|
|
45
|
+
PYTHON_ABI_RISK_MIN = (3, 13)
|
|
41
46
|
|
|
42
47
|
# ─── Colors (disabled on Windows cmd without ANSI support) ────────────────────
|
|
43
48
|
|
|
@@ -77,7 +82,12 @@ def platform_name():
|
|
|
77
82
|
|
|
78
83
|
def is_supported_python_version(version):
|
|
79
84
|
major, minor = version[:2]
|
|
80
|
-
return major == 3 and
|
|
85
|
+
return major == 3 and minor >= SUPPORTED_PYTHON_MIN[1]
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def is_abi_risk_python_version(version):
|
|
89
|
+
major, minor = version[:2]
|
|
90
|
+
return major == 3 and minor >= PYTHON_ABI_RISK_MIN[1]
|
|
81
91
|
|
|
82
92
|
|
|
83
93
|
def format_python_version(version):
|
|
@@ -85,9 +95,38 @@ def format_python_version(version):
|
|
|
85
95
|
|
|
86
96
|
|
|
87
97
|
def python_requirement_text():
|
|
98
|
+
return f"Python {SUPPORTED_PYTHON_MIN[0]}.{SUPPORTED_PYTHON_MIN[1]} or newer"
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
_ABI_NOTE_PRINTED = False
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def print_abi_risk_note_once(version, label="Python"):
|
|
105
|
+
"""Emit the 3.13+ heads-up at most once per installer run."""
|
|
106
|
+
global _ABI_NOTE_PRINTED
|
|
107
|
+
if _ABI_NOTE_PRINTED:
|
|
108
|
+
return
|
|
109
|
+
_ABI_NOTE_PRINTED = True
|
|
110
|
+
print(f" {yellow(label + ':')} {python_abi_risk_note(version)}")
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def python_abi_risk_note(version):
|
|
114
|
+
return (
|
|
115
|
+
f"Using Python {format_python_version(version)}. Verified working on recent "
|
|
116
|
+
f"Resolve builds (Studio 20.3.2). If Resolve fails to connect "
|
|
117
|
+
f"(scriptapp(\"Resolve\") returns None), install Python 3.10-3.12 and re-run "
|
|
118
|
+
f"with it, e.g.: python3.12 install.py"
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def python_fix_hint():
|
|
88
123
|
return (
|
|
89
|
-
|
|
90
|
-
|
|
124
|
+
" How to fix:\n"
|
|
125
|
+
" - Install Python 3.12 (the lowest-risk version for Resolve), e.g.:\n"
|
|
126
|
+
" macOS: brew install python@3.12 (or: pyenv install 3.12)\n"
|
|
127
|
+
" Linux: pyenv install 3.12 (or your distro's python3.12 package)\n"
|
|
128
|
+
" Windows: install Python 3.12 from python.org\n"
|
|
129
|
+
" - Re-run with that interpreter, e.g.: python3.12 install.py"
|
|
91
130
|
)
|
|
92
131
|
|
|
93
132
|
|
|
@@ -120,10 +159,13 @@ def require_supported_python(python_path, label="Python"):
|
|
|
120
159
|
if not is_supported_python_version(version):
|
|
121
160
|
print(
|
|
122
161
|
f" {red(label + ':')} {python_requirement_text()} is required "
|
|
123
|
-
f"
|
|
162
|
+
f"(the MCP SDK needs 3.10+); found {format_python_version(version)} "
|
|
124
163
|
f"at {python_path}"
|
|
125
164
|
)
|
|
165
|
+
print(python_fix_hint())
|
|
126
166
|
sys.exit(1)
|
|
167
|
+
if is_abi_risk_python_version(version):
|
|
168
|
+
print_abi_risk_note_once(version, label)
|
|
127
169
|
return version
|
|
128
170
|
|
|
129
171
|
|
|
@@ -132,10 +174,13 @@ def require_current_python(label="Python"):
|
|
|
132
174
|
if not is_supported_python_version(version):
|
|
133
175
|
print(
|
|
134
176
|
f" {red(label + ':')} {python_requirement_text()} is required "
|
|
135
|
-
f"
|
|
177
|
+
f"(the MCP SDK needs 3.10+); current interpreter is "
|
|
136
178
|
f"{format_python_version(version)} at {sys.executable}"
|
|
137
179
|
)
|
|
180
|
+
print(python_fix_hint())
|
|
138
181
|
sys.exit(1)
|
|
182
|
+
if is_abi_risk_python_version(version):
|
|
183
|
+
print_abi_risk_note_once(version, label)
|
|
139
184
|
return version
|
|
140
185
|
|
|
141
186
|
# ─── Resolve Path Detection ──────────────────────────────────────────────────
|
|
@@ -1411,14 +1456,34 @@ def main():
|
|
|
1411
1456
|
|
|
1412
1457
|
if api_path:
|
|
1413
1458
|
success, message = verify_resolve_connection(python_path, api_path, lib_path)
|
|
1459
|
+
try:
|
|
1460
|
+
py_abi_risk = is_abi_risk_python_version(_version_for_python(python_path))
|
|
1461
|
+
except Exception:
|
|
1462
|
+
py_abi_risk = False
|
|
1414
1463
|
if success:
|
|
1415
1464
|
if "not running" in message.lower():
|
|
1416
1465
|
print(f" API: {green('Module loads OK')}")
|
|
1417
|
-
|
|
1466
|
+
# If Resolve IS running but the bridge still reported no connection
|
|
1467
|
+
# on a 3.13+ interpreter, that is the ABI-mismatch signature.
|
|
1468
|
+
if resolve_running and py_abi_risk:
|
|
1469
|
+
print(
|
|
1470
|
+
f" Resolve: {yellow('Running, but the scripting bridge returned no connection')}"
|
|
1471
|
+
)
|
|
1472
|
+
print(
|
|
1473
|
+
f" This can happen on Python 3.13+ with older Resolve builds. "
|
|
1474
|
+
f"If MCP tools fail, recreate the venv with Python 3.10-3.12."
|
|
1475
|
+
)
|
|
1476
|
+
else:
|
|
1477
|
+
print(f" Resolve: {yellow('Not running')} — start Resolve to use MCP tools")
|
|
1418
1478
|
else:
|
|
1419
1479
|
print(f" Connected: {green(message)}")
|
|
1420
1480
|
else:
|
|
1421
1481
|
print(f" Verify: {yellow(message)}")
|
|
1482
|
+
if py_abi_risk:
|
|
1483
|
+
print(
|
|
1484
|
+
f" On Python 3.13+ this may be an ABI mismatch with Resolve's "
|
|
1485
|
+
f"scripting library — try Python 3.10-3.12 if it persists."
|
|
1486
|
+
)
|
|
1422
1487
|
else:
|
|
1423
1488
|
print(f" {yellow('Skipped')} — Resolve API path not detected")
|
|
1424
1489
|
|