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 +54 -0
- package/README.md +1 -1
- package/README.zh-CN.md +2 -2
- package/docs/reference/api-limitations.md +6 -6
- package/install.py +1 -1
- package/package.json +1 -1
- package/src/granular/common.py +1 -1
- package/src/server.py +1 -1
- package/src/utils/api_truth.py +27 -22
- package/src/utils/resolve_bridge_client.py +33 -0
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
|
-
[](https://github.com/samuelgursky/davinci-resolve-mcp/releases)
|
|
6
6
|
[](https://www.npmjs.com/package/davinci-resolve-mcp)
|
|
7
7
|
[](docs/reference/api-coverage.md)
|
|
8
8
|
[-blue.svg)](#server-modes)
|
package/README.zh-CN.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[English](README.md) | 简体中文
|
|
4
4
|
|
|
5
|
-
[](https://github.com/samuelgursky/davinci-resolve-mcp/releases)
|
|
6
6
|
[](https://www.npmjs.com/package/davinci-resolve-mcp)
|
|
7
7
|
[](docs/reference/api-coverage.md)
|
|
8
8
|
[-blue.svg)](#服务器模式)
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
[](https://www.python.org/downloads/)
|
|
13
13
|
[](https://opensource.org/licenses/MIT)
|
|
14
14
|
|
|
15
|
-
> 本翻译对应 v2.99.
|
|
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
|
|
358
|
+
### Fusion object dir() omits real methods (GetAttrs / SetAttrs)
|
|
359
359
|
|
|
360
|
-
- **Object:** `Fusion Tool
|
|
361
|
-
- **Signature:** `
|
|
362
|
-
- **Behavior:**
|
|
363
|
-
- **Workaround / current handling:**
|
|
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.
|
|
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
package/src/granular/common.py
CHANGED
|
@@ -87,7 +87,7 @@ if not logging.getLogger().handlers:
|
|
|
87
87
|
handlers=[logging.StreamHandler()],
|
|
88
88
|
)
|
|
89
89
|
|
|
90
|
-
VERSION = "2.99.
|
|
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
package/src/utils/api_truth.py
CHANGED
|
@@ -404,29 +404,34 @@ API_TRUTH: List[Dict[str, Any]] = [
|
|
|
404
404
|
"submit": "bug",
|
|
405
405
|
},
|
|
406
406
|
{
|
|
407
|
-
"symbol": "Fusion
|
|
408
|
-
"object": "Fusion Tool
|
|
409
|
-
"signature": "
|
|
410
|
-
"reality": "
|
|
411
|
-
"
|
|
412
|
-
"
|
|
413
|
-
"
|
|
414
|
-
"
|
|
415
|
-
"
|
|
416
|
-
"
|
|
417
|
-
"
|
|
418
|
-
"
|
|
419
|
-
"
|
|
420
|
-
"
|
|
421
|
-
"
|
|
422
|
-
"
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
"
|
|
426
|
-
"
|
|
427
|
-
"
|
|
428
|
-
|
|
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
|