davinci-resolve-mcp 2.98.5 → 2.98.6

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
@@ -2,6 +2,69 @@
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.98.6
6
+
7
+ **Correcting the scope of the v2.98.5 Fusion fix, and covering all six paths
8
+ with a render.** v2.98.5 removed a `Comp.Lock()` from six Fusion value writes and
9
+ described all six as the same bug. Only two of them were proven with a render at
10
+ the time; the other four were changed by inference. Extending the live harness to
11
+ cover the remaining four showed that inference was too broad.
12
+
13
+ Every site was mutation-checked by reintroducing the lock and re-rendering on
14
+ Studio 19.1.3.7:
15
+
16
+ | call path | with the lock back |
17
+ | --- | --- |
18
+ | `set_input` | **PSNR inf — suppressed** |
19
+ | `safe_set_inputs` | **PSNR inf — suppressed** |
20
+ | `bulk_set_inputs` | unchanged, still rendered |
21
+ | `bulk_set_expressions` | unchanged, still rendered |
22
+ | `add_fusion_mask` | unchanged, still rendered |
23
+ | `set_text_plus` | unchanged, still rendered |
24
+
25
+ The two that break are the two where the locked write is the only thing the call
26
+ does. The four that survive each do something else in the same call that appears
27
+ to invalidate the graph anyway — `bulk_set_inputs` and `bulk_set_expressions`
28
+ wrap the write in `StartUndo`/`EndUndo`, `add_fusion_mask` performs an `AddTool`,
29
+ and `set_text_plus` writes a string rather than a number. **Which of those is the
30
+ rescuing mechanism is not established** — only that the four do not reproduce.
31
+
32
+ No code changed back. Removing the lock from a single write buys nothing and
33
+ costs nothing, and treating the four as merely unexplained rather than proven
34
+ safe is the conservative reading. What changed is the claim: `api_truth`,
35
+ `docs/SKILL.md` and the AST guard's failure message now state the measured scope
36
+ instead of "any value write".
37
+
38
+ If you read the v2.98.5 notes and concluded every Fusion parameter this server
39
+ ever wrote was ignored at render, that was overstated — it was true for
40
+ `set_input` and `safe_set_inputs`.
41
+
42
+ ### Tests
43
+
44
+ `tests/live_fusion_value_write_validation.py` grows from two cases to six,
45
+ covering every site the fix touched:
46
+
47
+ ```
48
+ set_input: PSNR 24.375987 -> APPLIED at render
49
+ safe_set_inputs: PSNR 24.375987 -> APPLIED at render
50
+ set_text_plus: PSNR 13.33844 -> APPLIED at render
51
+ bulk_set_expressions: PSNR 24.375987 -> APPLIED at render
52
+ bulk_set_inputs: PSNR 24.375987 -> APPLIED at render
53
+ add_fusion_mask: PSNR 30.369794 -> APPLIED at render
54
+ ```
55
+
56
+ The `set_text_plus` case builds a rooted `MediaIn -> Merge -> MediaOut` graph
57
+ with the Text+ in the foreground — a comp whose MediaOut is fed only by a Text+
58
+ is bypassed at render for an unrelated reason and would have failed for the
59
+ wrong cause. The `add_fusion_mask` case cannot use a baseline/after comparison,
60
+ because a default-sized mask still changes the render; it builds the same graph
61
+ twice, once with a default mask and once with an explicitly tiny one, and
62
+ requires the two renders to differ.
63
+
64
+ Four of the six cases do not discriminate the lock. They are kept because they
65
+ still prove the write reaches the render — the property that matters, and the
66
+ one no readback can check.
67
+
5
68
  ## What's New in v2.98.5
6
69
 
7
70
  **Every Fusion parameter this server wrote was ignored at render.** A value
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  English | [简体中文](README.zh-CN.md)
4
4
 
5
- [![Version](https://img.shields.io/badge/version-2.98.5-blue.svg)](https://github.com/samuelgursky/davinci-resolve-mcp/releases)
5
+ [![Version](https://img.shields.io/badge/version-2.98.6-blue.svg)](https://github.com/samuelgursky/davinci-resolve-mcp/releases)
6
6
  [![npm](https://img.shields.io/npm/v/davinci-resolve-mcp.svg?label=npm&color=CB3837)](https://www.npmjs.com/package/davinci-resolve-mcp)
7
7
  [![API Coverage](https://img.shields.io/badge/API%20Coverage-100%25-brightgreen.svg)](docs/reference/api-coverage.md)
8
8
  [![Tools](https://img.shields.io/badge/MCP%20Tools-35%20(353%20full)-blue.svg)](#server-modes)
package/README.zh-CN.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [English](README.md) | 简体中文
4
4
 
5
- [![Version](https://img.shields.io/badge/version-2.98.5-blue.svg)](https://github.com/samuelgursky/davinci-resolve-mcp/releases)
5
+ [![Version](https://img.shields.io/badge/version-2.98.6-blue.svg)](https://github.com/samuelgursky/davinci-resolve-mcp/releases)
6
6
  [![npm](https://img.shields.io/npm/v/davinci-resolve-mcp.svg?label=npm&color=CB3837)](https://www.npmjs.com/package/davinci-resolve-mcp)
7
7
  [![API Coverage](https://img.shields.io/badge/API%20Coverage-100%25-brightgreen.svg)](docs/reference/api-coverage.md)
8
8
  [![Tools](https://img.shields.io/badge/MCP%20Tools-35%20(353%20full)-blue.svg)](#服务器模式)
@@ -12,7 +12,7 @@
12
12
  [![Python](https://img.shields.io/badge/python-3.10+-green.svg)](https://www.python.org/downloads/)
13
13
  [![License](https://img.shields.io/badge/license-MIT-blue.svg)](https://opensource.org/licenses/MIT)
14
14
 
15
- > 本翻译对应 v2.98.5 版 README。如与英文原版有出入,以 [英文原版](README.md) 为准。
15
+ > 本翻译对应 v2.98.6 版 README。如与英文原版有出入,以 [英文原版](README.md) 为准。
16
16
 
17
17
  一个 Model Context Protocol (MCP) 服务器,让 AI 助手通过官方脚本 API 控制 DaVinci Resolve Studio(达芬奇)。它提供完整的 API 覆盖,外加带护栏的工作流助手,涵盖剪辑、媒体池整理、渲染设置、审阅标记、调色、Fusion、Fairlight、项目生命周期任务、扩展开发,以及不碰源媒体的媒体分析。
18
18
 
package/docs/SKILL.md CHANGED
@@ -1691,10 +1691,13 @@ Target a comp either from a timeline item (pass `clip_id`, `timeline_item_id`, o
1691
1691
  page comp (omit timeline scope).
1692
1692
 
1693
1693
  READBACK IS NOT PROOF FOR FUSION PARAMETERS. Up to v2.98.4 every value write
1694
- here ran inside a `Comp.Lock()`, and a value written under a comp lock is stored
1695
- in the graph and returned by `get_input` while the RENDER ignores it entirely
1696
- (Studio 19.1.3.7: PSNR inf vs the no-comp baseline — the delivered file was
1697
- bit-identical to no comp at all). Fixed in v2.98.5, and guarded by
1694
+ here ran inside a `Comp.Lock()`. For `set_input` and `safe_set_inputs` that was
1695
+ load-bearing: the value is stored in the graph and returned by `get_input` while
1696
+ the RENDER ignores it entirely (Studio 19.1.3.7: PSNR inf vs the no-comp
1697
+ baseline — the delivered file was bit-identical to no comp at all). The other
1698
+ four locked paths did not reproduce it, so the blast radius was narrower than
1699
+ first reported; the locks came off all six regardless. Fixed in v2.98.5
1700
+ (measurement corrected in v2.98.6), and guarded by
1698
1701
  `tests/test_fusion_value_write_lock.py` plus the rendered-frame harness
1699
1702
  `tests/live_fusion_value_write_validation.py`. The lesson outlives the bug: a
1700
1703
  Fusion parameter that reads back correctly has proven nothing about the output,
@@ -343,7 +343,7 @@ values, or automation-hostile modal prompts.
343
343
 
344
344
  - **Object:** `Composition (Fusion, via TimelineItem comps)`
345
345
  - **Signature:** `Lock() / Unlock()`
346
- - **Behavior:** A value write performed between Comp.Lock() and Comp.Unlock() SetInput(), or Input.SetExpression() is stored in the graph and reads back correctly from GetInput(), but is NOT applied when the timeline is rendered. Measured live on Studio 19.1.3.7 (2026-08-21) with MediaIn -> Blur(XBlurSize 20) -> MediaOut on a media-backed clip: written under the lock the delivered H.264 render is bit-identical to the no-comp baseline (ffmpeg PSNR inf); the identical write with the lock removed renders at PSNR 24.38 dB and the file shrinks 2.0 MB -> 727 KB, as a blur should. The variable was isolated against the comp handle (AddFusionComp, GetFusionCompByIndex and GetFusionCompByName all render), the node name, and the write form (attribute assignment and SetInput both render unlocked). STRUCTURAL edits are unaffected: AddTool and ConnectInput inside a lock render normally, so the lock is not broadly unsafe — it suppresses the parameter-change invalidation that a value write depends on. Lock() is widely recommended for batching Fusion edits, which is how this reaches production code.
346
+ - **Behavior:** A numeric tool.SetInput() performed between Comp.Lock() and Comp.Unlock(), when that write is the only thing the call does, is stored in the graph and reads back correctly from GetInput() but is NOT applied when the timeline is rendered. Measured live on Studio 19.1.3.7 (2026-08-21) with MediaIn -> Blur(XBlurSize 20) -> MediaOut on a media-backed clip: written under the lock the delivered H.264 render is bit-identical to the no-comp baseline (ffmpeg PSNR inf); the identical write with the lock removed renders at PSNR 24.38 dB and the file shrinks 2.0 MB -> 727 KB, as a blur should. The variable was isolated against the comp handle (AddFusionComp, GetFusionCompByIndex and GetFusionCompByName all render), the node name, and the write form (attribute assignment and SetInput both render unlocked). STRUCTURAL edits are unaffected: AddTool and ConnectInput inside a lock render normally, so the lock is not broadly unsafe — it suppresses the parameter-change invalidation that a value write depends on. Lock() is widely recommended for batching Fusion edits, which is how this reaches production code. SCOPE, measured by reintroducing the lock at each site and re-rendering: it reproduces for a bare numeric SetInput (2 of 6 call paths tested) and does NOT reproduce when the same call also wraps the write in StartUndo/EndUndo, performs an AddTool, or writes a string to StyledText (4 of 6). Which of those rescues the write is not established — only that they do. Treat the safe cases as unexplained rather than proven safe, and keep value writes outside the lock everywhere.
347
347
  - **Workaround / current handling:** Never hold a comp lock across a value write. Lock only structural work (AddTool/ConnectInput) and set inputs outside it. Because every readback the API offers agrees with the value that was written, this failure is invisible without a render — prove Fusion parameter changes with a delivered frame or gallery_stills grab_and_export, never with GetInput.
348
348
  - **Tags:** fusion, silent-failure, render, readback
349
349
 
package/install.py CHANGED
@@ -37,7 +37,7 @@ from src.utils.update_check import (
37
37
 
38
38
  # ─── Version ──────────────────────────────────────────────────────────────────
39
39
 
40
- VERSION = "2.98.5"
40
+ VERSION = "2.98.6"
41
41
  # Only hard floor: mcp[cli] requires Python 3.10+. There is no upper bound —
42
42
  # Resolve's scripting bridge loads into newer interpreters on recent builds
43
43
  # (Python 3.14 verified against Resolve Studio 20.3.2). Older Resolve builds
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "davinci-resolve-mcp",
3
- "version": "2.98.5",
3
+ "version": "2.98.6",
4
4
  "description": "NPM bootstrapper for the DaVinci Resolve MCP Server.",
5
5
  "license": "MIT",
6
6
  "author": "Samuel Gursky <samgursky@gmail.com>",
@@ -87,7 +87,7 @@ if not logging.getLogger().handlers:
87
87
  handlers=[logging.StreamHandler()],
88
88
  )
89
89
 
90
- VERSION = "2.98.5"
90
+ VERSION = "2.98.6"
91
91
  logger = logging.getLogger("davinci-resolve-mcp")
92
92
  logger.info(f"Starting DaVinci Resolve MCP Server v{VERSION}")
93
93
  logger.info(f"Detected platform: {get_platform()}")
package/src/server.py CHANGED
@@ -11,7 +11,7 @@ Usage:
11
11
  python src/server.py --full # Start the 353-tool granular server instead
12
12
  """
13
13
 
14
- VERSION = "2.98.5"
14
+ VERSION = "2.98.6"
15
15
 
16
16
  import base64
17
17
  import os
@@ -407,10 +407,10 @@ API_TRUTH: List[Dict[str, Any]] = [
407
407
  "symbol": "Composition.Lock (suppresses render invalidation for value writes)",
408
408
  "object": "Composition (Fusion, via TimelineItem comps)",
409
409
  "signature": "Lock() / Unlock()",
410
- "reality": "A value write performed between Comp.Lock() and "
411
- "Comp.Unlock() — SetInput(), or Input.SetExpression() is "
412
- "stored in the graph and reads back correctly from "
413
- "GetInput(), but is NOT applied when the timeline is "
410
+ "reality": "A numeric tool.SetInput() performed between Comp.Lock() "
411
+ "and Comp.Unlock(), when that write is the only thing the "
412
+ "call does, is stored in the graph and reads back correctly "
413
+ "from GetInput() but is NOT applied when the timeline is "
414
414
  "rendered. Measured live on Studio 19.1.3.7 (2026-08-21) "
415
415
  "with MediaIn -> Blur(XBlurSize 20) -> MediaOut on a "
416
416
  "media-backed clip: written under the lock the delivered "
@@ -427,7 +427,15 @@ API_TRUTH: List[Dict[str, Any]] = [
427
427
  "suppresses the parameter-change invalidation that a value "
428
428
  "write depends on. Lock() is widely recommended for "
429
429
  "batching Fusion edits, which is how this reaches "
430
- "production code.",
430
+ "production code. SCOPE, measured by reintroducing the lock "
431
+ "at each site and re-rendering: it reproduces for a bare "
432
+ "numeric SetInput (2 of 6 call paths tested) and does NOT "
433
+ "reproduce when the same call also wraps the write in "
434
+ "StartUndo/EndUndo, performs an AddTool, or writes a string "
435
+ "to StyledText (4 of 6). Which of those rescues the write is "
436
+ "not established — only that they do. Treat the safe cases as "
437
+ "unexplained rather than proven safe, and keep value writes "
438
+ "outside the lock everywhere.",
431
439
  "recommended": "Never hold a comp lock across a value write. Lock only "
432
440
  "structural work (AddTool/ConnectInput) and set inputs "
433
441
  "outside it. Because every readback the API offers "