davinci-resolve-mcp 2.99.2 → 2.99.3

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,60 @@
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.99.3
6
+
7
+ **Fusion authoring now works on the free edition.** v2.99.2 documented that
8
+ `fusion_comp add_tool` could not run there, because the in-app bridge reported
9
+ `GetAttrs`/`SetAttrs` as absent on a Fusion tool and `add_tool` calls `GetAttrs`
10
+ to build its return value — which took every server-authored Fusion graph with
11
+ it. Investigating the fallback found the premise was wrong: **those methods are
12
+ present and work.** Invoked directly on free 21.0.3.7, `GetAttrs` returned
13
+ `{TOOLS_Name: "Blur1", TOOLS_RegID: "Blur"}` and `SetAttrs` renamed the tool.
14
+
15
+ The fault was our capability check.
16
+
17
+ ### The API truth underneath
18
+
19
+ `dir()` on a live Fusion Tool returns 38 names — with `Composition` listed
20
+ **twice** — and omits `GetAttrs`/`SetAttrs`. Resolve fabricates a callable for
21
+ *any* attribute name, so `dir()` is the only evidence of absence that exists,
22
+ which makes an omitted name unrecoverable by probing. The bridge's strict proxy
23
+ took that omission as authoritative and answered "has no attribute 'GetAttrs' in
24
+ this Resolve build" for a method that was right there.
25
+
26
+ Resolve's own API objects enumerate correctly — Timeline 60, TimelineItem 88,
27
+ Composition 92 — so this is specific to Fusion Tools.
28
+
29
+ ### Fixed
30
+
31
+ - The bridge client now carries a **curated exception**: names that are
32
+ documented Fusion methods but absent from the enumeration resolve normally,
33
+ and only on an object whose own method list positively identifies it as a
34
+ Fusion object (`ConnectInput`/`FindMainInput`/`GetControlPageNames` on a Tool,
35
+ `AddTool`/`FindTool`/`GetToolList` on a Composition).
36
+
37
+ This is deliberately not a global relaxation. Dropping the scoping fails five
38
+ existing tests, including the ones that keep
39
+ `getattr(item, "CreateMagicMask", None)` honest — capability detection on
40
+ Resolve API objects answers exactly as before.
41
+
42
+ - `fusion_comp add_tool` needed **no change**. The fallback proposed in v2.99.2
43
+ would have papered over a client bug while leaving every other unenumerated
44
+ Fusion method broken.
45
+
46
+ ### Live validation
47
+
48
+ Free DaVinci Resolve 21.0.3.7, whole graph through the server including a custom
49
+ tool name (which requires `SetAttrs`):
50
+
51
+ ```
52
+ add_tool -> {'tool_name': 'FreeBlur', 'tool_type': 'Blur'}
53
+ connect -> {'success': True}
54
+ connect -> {'success': True}
55
+ set_input -> {'success': True}
56
+ render -> PSNR 23.32 dB vs baseline — RENDERED
57
+ ```
58
+
5
59
  ## What's New in v2.99.2
6
60
 
7
61
  **The Fusion comp-lock question is closed on Resolve 21.** The v2.98.5–v2.98.8
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.99.2-blue.svg)](https://github.com/samuelgursky/davinci-resolve-mcp/releases)
5
+ [![Version](https://img.shields.io/badge/version-2.99.3-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.99.2-blue.svg)](https://github.com/samuelgursky/davinci-resolve-mcp/releases)
5
+ [![Version](https://img.shields.io/badge/version-2.99.3-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.99.2 版 README。如与英文原版有出入,以 [英文原版](README.md) 为准。
15
+ > 本翻译对应 v2.99.3 版 README。如与英文原版有出入,以 [英文原版](README.md) 为准。
16
16
 
17
17
  一个 Model Context Protocol (MCP) 服务器,让 AI 助手通过官方脚本 API 控制 DaVinci Resolve Studio(达芬奇)。它提供完整的 API 覆盖,外加带护栏的工作流助手,涵盖剪辑、媒体池整理、渲染设置、审阅标记、调色、Fusion、Fairlight、项目生命周期任务、扩展开发,以及不碰源媒体的媒体分析。
18
18
 
@@ -355,13 +355,13 @@ values, or automation-hostile modal prompts.
355
355
  - **Workaround / current handling:** Author OTIO for Resolve by mirroring what Resolve itself exports, and give every event its media timecode origin. editorial.convert_to_interchange (target 'otio') does this and reports any event whose origin had to be assumed in `mediaOriginAssumed` — a non-empty list means the file will only import if that media really starts at 00:00:00:00. To debug a refusal, export any timeline with EXPORT_OTIO and diff your document against it; do NOT chase missing media or reach for sanitize_media, which cannot even parse a .otio (it is JSON, not XML).
356
356
  - **Tags:** timeline, import, interchange, otio, silent-failure, conform
357
357
 
358
- ### Fusion tool GetAttrs / SetAttrs (unreachable over the in-app bridge)
358
+ ### Fusion object dir() omits real methods (GetAttrs / SetAttrs)
359
359
 
360
- - **Object:** `Fusion Tool (via the free-edition bridge)`
361
- - **Signature:** `GetAttrs() -> dict / SetAttrs(dict) -> None`
362
- - **Behavior:** The in-app bridge's transparent proxy exposes SetInput, GetInput, ConnectInput and FindMainInput on a Fusion tool, but NOT GetAttrs or SetAttrs - the client raises AttributeError('... has no attribute SetAttrs in this Resolve build'). Measured 2026-08-22 on free 21.0.3.7. Because fusion_comp's add_tool calls tool.GetAttrs() unconditionally to build its return value, and SetAttrs whenever a name is passed, `fusion_comp add_tool` cannot run at all on the free edition, which takes connect/set_input with it for any graph the caller wanted to build through the server. Comp-level calls (AddFusionComp, GetFusionCompByIndex, FindTool, AddTool) work, so the graph can still be wired with raw proxy calls.
363
- - **Workaround / current handling:** On the free edition, wire Fusion graphs with raw comp.AddTool/ConnectInput and use fusion_comp only for value writes. Making add_tool tolerate a missing GetAttrs (fall back to the requested tool_type and a FindTool-based name) would restore the action there.
364
- - **Tags:** fusion, bridge, free-edition
360
+ - **Object:** `Fusion Tool / Composition`
361
+ - **Signature:** `dir(tool) -> incomplete list`
362
+ - **Behavior:** `dir()` on a live Fusion Tool returns 38 names with 'Composition' listed TWICE and omits GetAttrs and SetAttrs, which are documented Fusion Tool methods that work perfectly when called. Measured on free 21.0.3.7 over the in-app bridge: invoking GetAttrs directly returned {TOOLS_Name: 'Blur1', TOOLS_RegID: 'Blur'} and SetAttrs renamed the tool. This matters because Resolve fabricates a callable for ANY attribute name, so `dir()` is the only evidence of absence that exists which makes an omitted name unrecoverable by probing. Any capability detection built on dir()/hasattr will therefore report a real Fusion method as missing. Resolve's own API objects do not have this problem: Timeline (60), TimelineItem (88) and Composition (92) all enumerate correctly.
363
+ - **Workaround / current handling:** Do not treat dir()/hasattr as authoritative for Fusion Tool objects. Keep a curated set of documented Fusion methods that the enumeration omits, and identify a Fusion object positively (ConnectInput / FindMainInput / GetControlPageNames on a Tool, AddTool / FindTool / GetToolList on a Composition) rather than relaxing the check globally, which would silently re-open capability detection on Resolve API objects.
364
+ - **Tags:** fusion, introspection, bridge, free-edition
365
365
 
366
366
  ### Composition.Lock (suppresses render invalidation for value writes)
367
367
 
package/install.py CHANGED
@@ -37,7 +37,7 @@ from src.utils.update_check import (
37
37
 
38
38
  # ─── Version ──────────────────────────────────────────────────────────────────
39
39
 
40
- VERSION = "2.99.2"
40
+ VERSION = "2.99.3"
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.99.2",
3
+ "version": "2.99.3",
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.99.2"
90
+ VERSION = "2.99.3"
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.99.2"
14
+ VERSION = "2.99.3"
15
15
 
16
16
  import base64
17
17
  import os
@@ -404,29 +404,34 @@ API_TRUTH: List[Dict[str, Any]] = [
404
404
  "submit": "bug",
405
405
  },
406
406
  {
407
- "symbol": "Fusion tool GetAttrs / SetAttrs (unreachable over the in-app bridge)",
408
- "object": "Fusion Tool (via the free-edition bridge)",
409
- "signature": "GetAttrs() -> dict / SetAttrs(dict) -> None",
410
- "reality": "The in-app bridge's transparent proxy exposes SetInput, "
411
- "GetInput, ConnectInput and FindMainInput on a Fusion tool, "
412
- "but NOT GetAttrs or SetAttrs - the client raises "
413
- "AttributeError('... has no attribute SetAttrs in this "
414
- "Resolve build'). Measured 2026-08-22 on free 21.0.3.7. "
415
- "Because fusion_comp's add_tool calls tool.GetAttrs() "
416
- "unconditionally to build its return value, and SetAttrs "
417
- "whenever a name is passed, `fusion_comp add_tool` cannot "
418
- "run at all on the free edition, which takes "
419
- "connect/set_input with it for any graph the caller wanted "
420
- "to build through the server. Comp-level calls "
421
- "(AddFusionComp, GetFusionCompByIndex, FindTool, AddTool) "
422
- "work, so the graph can still be wired with raw proxy calls.",
423
- "recommended": "On the free edition, wire Fusion graphs with raw "
424
- "comp.AddTool/ConnectInput and use fusion_comp only for "
425
- "value writes. Making add_tool tolerate a missing "
426
- "GetAttrs (fall back to the requested tool_type and a "
427
- "FindTool-based name) would restore the action there.",
428
- "tags": ["fusion", "bridge", "free-edition"],
407
+ "symbol": "Fusion object dir() omits real methods (GetAttrs / SetAttrs)",
408
+ "object": "Fusion Tool / Composition",
409
+ "signature": "dir(tool) -> incomplete list",
410
+ "reality": "`dir()` on a live Fusion Tool returns 38 names — with "
411
+ "'Composition' listed TWICE and omits GetAttrs and "
412
+ "SetAttrs, which are documented Fusion Tool methods that "
413
+ "work perfectly when called. Measured on free 21.0.3.7 over "
414
+ "the in-app bridge: invoking GetAttrs directly returned "
415
+ "{TOOLS_Name: 'Blur1', TOOLS_RegID: 'Blur'} and SetAttrs "
416
+ "renamed the tool. This matters because Resolve fabricates a "
417
+ "callable for ANY attribute name, so `dir()` is the only "
418
+ "evidence of absence that exists which makes an omitted "
419
+ "name unrecoverable by probing. Any capability detection "
420
+ "built on dir()/hasattr will therefore report a real Fusion "
421
+ "method as missing. Resolve's own API objects do not have "
422
+ "this problem: Timeline (60), TimelineItem (88) and "
423
+ "Composition (92) all enumerate correctly.",
424
+ "recommended": "Do not treat dir()/hasattr as authoritative for Fusion "
425
+ "Tool objects. Keep a curated set of documented Fusion "
426
+ "methods that the enumeration omits, and identify a "
427
+ "Fusion object positively (ConnectInput / FindMainInput "
428
+ "/ GetControlPageNames on a Tool, AddTool / FindTool / "
429
+ "GetToolList on a Composition) rather than relaxing the "
430
+ "check globally, which would silently re-open capability "
431
+ "detection on Resolve API objects.",
432
+ "tags": ["fusion", "introspection", "bridge", "free-edition"],
429
433
  "submit": "bug",
434
+ "mitigation": ["_FUSION_UNENUMERATED_METHODS", "_FUSION_OBJECT_MARKERS"],
430
435
  },
431
436
  {
432
437
  "symbol": "Composition.Lock (suppresses render invalidation for value writes)",
@@ -198,6 +198,34 @@ def _decode_value(transport: BridgeTransport, value: Any) -> Any:
198
198
  return value
199
199
 
200
200
 
201
+ # Fusion's own objects under-report themselves, and unlike Resolve's they cannot
202
+ # be probed. `dir()` on a Fusion Tool lists 38 names — with "Composition"
203
+ # appearing twice — and omits GetAttrs/SetAttrs, which are documented Fusion Tool
204
+ # methods that work perfectly when called: measured on free 21.0.3.7 over this
205
+ # bridge, GetAttrs returned {TOOLS_Name: "Blur1", TOOLS_RegID: "Blur"} and
206
+ # SetAttrs renamed the tool. Resolve fabricates a callable for ANY name, so
207
+ # `dir()` is the only evidence of absence that exists — which means a name it
208
+ # omits cannot be recovered by probing, only by knowing.
209
+ #
210
+ # This is a curated exception, not a relaxation of the strict proxy. It applies
211
+ # only to names that are documented Fusion methods, and only on an object whose
212
+ # own method list identifies it as a Fusion object. Resolve API capability
213
+ # detection — `getattr(item, "CreateMagicMask", None)` — answers exactly as
214
+ # before, which is what the strict proxy exists to protect.
215
+ #
216
+ # Symptom when this is missing: `fusion_comp add_tool` calls tool.GetAttrs() to
217
+ # build its return value, so the action died with "has no attribute 'GetAttrs'
218
+ # in this Resolve build" and took every server-authored Fusion graph with it.
219
+ _FUSION_UNENUMERATED_METHODS = frozenset({"GetAttrs", "SetAttrs"})
220
+
221
+ #: Names that positively identify a Fusion Tool or Composition, as opposed to a
222
+ #: Resolve API object. Drawn from what `dir()` DOES report on each.
223
+ _FUSION_OBJECT_MARKERS = frozenset({
224
+ "ConnectInput", "FindMainInput", "GetControlPageNames", # Tool
225
+ "AddTool", "FindTool", "GetToolList", # Composition
226
+ })
227
+
228
+
201
229
  class _BoundMethod:
202
230
  """One callable method on a proxied object."""
203
231
 
@@ -309,6 +337,11 @@ class BridgeProxy:
309
337
  {"target": self._handle, "name": name}) or {}
310
338
  if probe.get("kind") == "value":
311
339
  return _decode_value(self._transport, probe.get("value"))
340
+ if (name in _FUSION_UNENUMERATED_METHODS
341
+ and self._methods() & _FUSION_OBJECT_MARKERS):
342
+ # A Fusion object omitting one of its own documented
343
+ # methods — see _FUSION_UNENUMERATED_METHODS.
344
+ return _BoundMethod(self._transport, self._handle, name)
312
345
  # Matches native semantics: hasattr() is False, getattr(..., None)
313
346
  # is None, and a capability check refuses instead of guessing.
314
347
  # A `callable` answer lands here too — Resolve fabricates one for