davinci-resolve-mcp 2.93.3 → 2.94.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/CHANGELOG.md CHANGED
@@ -2,6 +2,79 @@
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.94.1
6
+
7
+ Removes the `hls_h264` target added in v2.94.0 — it could never work — and fixes
8
+ a QC note that told the truth only for image sequences.
9
+
10
+ ### Fixed
11
+
12
+ - **`hls_h264` is withdrawn.** It resolved cleanly against the format/codec
13
+ matrix, which is why it shipped, but it can never render: on Studio 21.0.4.5
14
+ `GetRenderCodecs('m3u8')` returns `{'H.264': 'H264'}` and
15
+ `GetRenderResolutions('m3u8', 'H264')` returns real rasters, yet
16
+ `SetCurrentRenderFormatAndCodec('m3u8', ...)` is False for every value tried
17
+ (`'H264'`, `'H.264'`, `'h264'`, `''`) while `('mp4', 'H264')` succeeds. Caught
18
+ by queuing an actual job rather than by resolving a name. A target that always
19
+ fails is worse than no target, so it is gone along with its `hls` and
20
+ `streaming` aliases.
21
+ - **`qc_note` reported every target's missing QC projection as an image
22
+ sequence.** It was hard-coded, so `webp_animated` — which declines QC because
23
+ its ffprobe values are unmeasured — told callers its output was a many-file
24
+ sequence. It now surfaces the target's own `qc_skip_reason`.
25
+
26
+ ### Notes
27
+
28
+ - New API-truth finding, folded into the existing `Project.GetRenderCodecs`
29
+ entry: **the format/codec matrix is not a capability contract.** A format can
30
+ advertise a codec, and rasters for it, and still refuse to be selected. That is
31
+ worse than the zero-codec formats, which at least advertise nothing. Presence
32
+ in the matrix proves a pair is *listed*, never that it is usable — the
33
+ authoritative test is setting it and reading the boolean back, which
34
+ `prepare_render_job` and `prepare_delivery_job` already do.
35
+ - 31 targets, all verified end to end on Studio 21.0.4.5: resolved, queued as a
36
+ real render job, then deleted.
37
+
38
+ ## What's New in v2.94.0
39
+
40
+ Adds four delivery targets for deliverable classes the table did not cover:
41
+ image sequences for web/graphics, animated web assets, and an HTTP Live
42
+ Streaming package. All 32 targets resolve live on Studio 21.0.4.5.
43
+
44
+ ### Added
45
+
46
+ - **`png_sequence`** — PNG frames for web and motion-graphics handoff. Resolve
47
+ exposes **RGB only** (no alpha codec), so the target says so and points at
48
+ `dpx_sequence` (`RGBA 8 bits`) or `prores4444_master` when transparency is
49
+ actually needed. Alias: `png`.
50
+ - **`gif_animated`** — looping animated GIF. No audio track at all, so
51
+ `ExportAudio` is False rather than merely unpinned. Its QC projection uses
52
+ ffprobe values measured on a generated file (`container: gif`, `codec: gif`).
53
+ Alias: `gif`.
54
+ - **`webp_animated`** — looping animated WebP. Ships with **no QC projection**:
55
+ the reference machine's ffmpeg has only the `webp_pipe` still-image demuxer, so
56
+ a rendered animated WebP could not be probed and the ffprobe values are
57
+ unmeasured. `qc_skip_reason` says exactly that. Guessing `webp`/`webp` would
58
+ have produced QC failures about vocabulary rather than about the deliverable —
59
+ the same trap as mp4 reporting its container as `mov`. Alias: `webp`.
60
+ - **`hls_h264`** — HTTP Live Streaming package (`.m3u8` playlist plus segments),
61
+ in the `package` tier alongside IMF and DCP. Bitrate ladders, variant playlists
62
+ and encryption keys are not expressible as a render target. Aliases: `hls`,
63
+ `streaming`.
64
+
65
+ ### Notes
66
+
67
+ - PNG, WebP and HLS are **not render formats on Resolve 19.x**. These targets
68
+ resolve on 21.x and fail loudly with the machine's available list on older
69
+ builds, which is the designed behavior rather than a regression.
70
+ - Deliberately **not** added, having checked the full 21.0.4.5 matrix: container
71
+ swaps that duplicate existing capability (MKV carries the same ProRes and
72
+ H.264/H.265 codecs already covered), standalone JPEG 2000 (the same essence the
73
+ IMF/DCP targets reach), and legacy formats (AVI, Cineon, MJ2, Panasonic AVC
74
+ 8K). All remain reachable via a `format_candidates` override or a user target.
75
+ - `braw`, `mts` and `wav` expose zero codecs and reject every codec value, so no
76
+ target is possible for them at all.
77
+
5
78
  ## What's New in v2.93.3
6
79
 
7
80
  Re-verifies the delivery-target table and the two recorded render API
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.93.3-blue.svg)](https://github.com/samuelgursky/davinci-resolve-mcp/releases)
5
+ [![Version](https://img.shields.io/badge/version-2.94.1-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-34%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.93.3-blue.svg)](https://github.com/samuelgursky/davinci-resolve-mcp/releases)
5
+ [![Version](https://img.shields.io/badge/version-2.94.1-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-34%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.93.3 版 README。如与英文原版有出入,以 [英文原版](README.md) 为准。
15
+ > 本翻译对应 v2.94.1 版 README。如与英文原版有出入,以 [英文原版](README.md) 为准。
16
16
 
17
17
  一个 Model Context Protocol (MCP) 服务器,让 AI 助手通过官方脚本 API 控制 DaVinci Resolve Studio(达芬奇)。它提供完整的 API 覆盖,外加带护栏的工作流助手,涵盖剪辑、媒体池整理、渲染设置、审阅标记、调色、Fusion、Fairlight、项目生命周期任务、扩展开发,以及不碰源媒体的媒体分析。
18
18
 
@@ -470,8 +470,8 @@ values, or automation-hostile modal prompts.
470
470
 
471
471
  - **Object:** `Project`
472
472
  - **Signature:** `(renderFormat) -> {codec description: codec name}`
473
- - **Behavior:** Returns {description: id} — the human-readable description is the KEY and the id Resolve actually accepts is the VALUE. SetCurrentRenderFormatAndCodec, GetRenderCodecs and GetRenderResolutions all require the id, so passing the description a user sees in the Deliver page is rejected. Verified live on Studio 19.1.3.7 and re-confirmed unchanged on 21.0.4.5: ('mov', 'Apple ProRes 422 HQ') -> False while ('mov', 'ProRes422HQ') -> True, and ('mp4', 'H.264') -> False while ('mp4', 'H264') -> True. It affects every family, not only the ones whose id differs obviously. Mirrors the same trap in GetRenderFormats, which returns {format: extension}. Descriptions also DRIFT between majors while ids do not — every DNx description gained an 'Avid ' prefix in 21.x ('DNxHR HQ' -> 'Avid DNxHR HQ 12-bit') while the ids (DNxHRHQ, DNxHRLB, DNxHRHQX_10) were unchanged. Key on ids.
474
- - **Workaround / current handling:** Normalize both arguments through the live maps before calling: src.utils.render_ids.render_format_id_from_formats and render_codec_id_from_codecs accept a description or an id and return the id.
473
+ - **Behavior:** Returns {description: id} — the human-readable description is the KEY and the id Resolve actually accepts is the VALUE. SetCurrentRenderFormatAndCodec, GetRenderCodecs and GetRenderResolutions all require the id, so passing the description a user sees in the Deliver page is rejected. Verified live on Studio 19.1.3.7 and re-confirmed unchanged on 21.0.4.5: ('mov', 'Apple ProRes 422 HQ') -> False while ('mov', 'ProRes422HQ') -> True, and ('mp4', 'H.264') -> False while ('mp4', 'H264') -> True. It affects every family, not only the ones whose id differs obviously. Mirrors the same trap in GetRenderFormats, which returns {format: extension}. Descriptions also DRIFT between majors while ids do not — every DNx description gained an 'Avid ' prefix in 21.x ('DNxHR HQ' -> 'Avid DNxHR HQ 12-bit') while the ids (DNxHRHQ, DNxHRLB, DNxHRHQX_10) were unchanged. Key on ids. SEPARATELY, the returned map is not a capability contract: a format can ADVERTISE a codec it will not accept. On 21.0.4.5 GetRenderCodecs('m3u8') returns {'H.264': 'H264'} and GetRenderResolutions('m3u8','H264') returns real rasters, yet SetCurrentRenderFormatAndCodec('m3u8', ...) is False for every value tried ('H264', 'H.264', 'h264', '') while ('mp4','H264') succeeds. That is worse than the zero-codec formats, which at least advertise nothing.
474
+ - **Workaround / current handling:** Never treat presence in the matrix as proof a pair is usable — set it and read the boolean back (prepare_render_job / prepare_delivery_job do this and refuse to queue on False). Normalize both arguments through the live maps before calling: src.utils.render_ids.render_format_id_from_formats and render_codec_id_from_codecs accept a description or an id and return the id.
475
475
  - **Reference:** [issue #59](https://github.com/samuelgursky/davinci-resolve-mcp/issues/59)
476
476
  - **Tags:** render, deliver, silent-failure, id-vs-label
477
477
 
package/install.py CHANGED
@@ -36,7 +36,7 @@ from src.utils.update_check import (
36
36
 
37
37
  # ─── Version ──────────────────────────────────────────────────────────────────
38
38
 
39
- VERSION = "2.93.3"
39
+ VERSION = "2.94.1"
40
40
  # Only hard floor: mcp[cli] requires Python 3.10+. There is no upper bound —
41
41
  # Resolve's scripting bridge loads into newer interpreters on recent builds
42
42
  # (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.93.3",
3
+ "version": "2.94.1",
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.93.3"
90
+ VERSION = "2.94.1"
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.93.3"
14
+ VERSION = "2.94.1"
15
15
 
16
16
  import base64
17
17
  import os
@@ -17007,10 +17007,16 @@ def _resolve_delivery_target_live(proj, p: Dict[str, Any]):
17007
17007
  "timeline_fps": fps,
17008
17008
  "settings": _delivery_targets.to_render_settings(target, timeline_fps=fps),
17009
17009
  "qc_spec": qc_spec,
17010
+ # Surface the target's OWN reason. This used to hard-code an
17011
+ # image-sequence message, which was simply false for any other kind
17012
+ # of target that declines a QC projection.
17010
17013
  "qc_note": (
17011
17014
  None
17012
17015
  if qc_spec
17013
- else "This target renders an image sequence; deliverable_qc probes a single file, so it has no QC spec."
17016
+ else (
17017
+ target.qc_skip_reason
17018
+ or "This target has no single-file QC projection."
17019
+ )
17014
17020
  ),
17015
17021
  "loudness_target": loudness,
17016
17022
  "loudness_note": (
@@ -1689,8 +1689,20 @@ API_TRUTH: List[Dict[str, Any]] = [
1689
1689
  "Descriptions also DRIFT between majors while ids do not — "
1690
1690
  "every DNx description gained an 'Avid ' prefix in 21.x "
1691
1691
  "('DNxHR HQ' -> 'Avid DNxHR HQ 12-bit') while the ids "
1692
- "(DNxHRHQ, DNxHRLB, DNxHRHQX_10) were unchanged. Key on ids.",
1693
- "recommended": "Normalize both arguments through the live maps before "
1692
+ "(DNxHRHQ, DNxHRLB, DNxHRHQX_10) were unchanged. Key on ids. "
1693
+ "SEPARATELY, the returned map is not a capability contract: a "
1694
+ "format can ADVERTISE a codec it will not accept. On 21.0.4.5 "
1695
+ "GetRenderCodecs('m3u8') returns {'H.264': 'H264'} and "
1696
+ "GetRenderResolutions('m3u8','H264') returns real rasters, yet "
1697
+ "SetCurrentRenderFormatAndCodec('m3u8', ...) is False for every "
1698
+ "value tried ('H264', 'H.264', 'h264', '') while ('mp4','H264') "
1699
+ "succeeds. That is worse than the zero-codec formats, which at "
1700
+ "least advertise nothing.",
1701
+ "recommended": "Never treat presence in the matrix as proof a pair is "
1702
+ "usable — set it and read the boolean back "
1703
+ "(prepare_render_job / prepare_delivery_job do this and "
1704
+ "refuse to queue on False). Normalize both arguments "
1705
+ "through the live maps before "
1694
1706
  "calling: src.utils.render_ids.render_format_id_from_formats "
1695
1707
  "and render_codec_id_from_codecs accept a description or an "
1696
1708
  "id and return the id.",
@@ -110,9 +110,15 @@ major-version upgrade.
110
110
 
111
111
  Two findings changed between the builds and should not be treated as fixed facts:
112
112
 
113
- - **PNG.** Not a render format on 19.1.3.7; it *is* one on 21.0.4.5 (along with
114
- `jpg` and `webp`). There is still no `png_sequence` target, but the reason is
115
- now "not added", not "impossible".
113
+ - **PNG and WebP.** Not render formats on 19.1.3.7; they *are* on 21.0.4.5, so
114
+ `png_sequence` and `webp_animated` resolve on 21.x and fail loudly on 19.x,
115
+ which is correct behavior rather than a regression. PNG exposes RGB only — no
116
+ alpha codec — so it does not replace `dpx_sequence` for transparency.
117
+ - **A format can advertise a codec it will not accept.** `HLS` (m3u8) returns a
118
+ codec from `GetRenderCodecs` and real rasters from `GetRenderResolutions`, yet
119
+ `SetCurrentRenderFormatAndCodec` rejects every value. Resolving a target proves
120
+ only that the pair is *listed*; the authoritative test is queuing a job, which
121
+ is why `prepare_delivery_job` refuses to queue on a rejected pair.
116
122
  - **Zero-codec formats.** `wav` and `gif` on 19.x; `braw`, `mts` and `wav` on
117
123
  21.x — `gif` gained codecs, BRAW and MTS lost them. `wav` is the constant, so
118
124
  an audio-only WAV target remains inexpressible through
@@ -578,6 +584,63 @@ DELIVERY_TARGETS: Dict[str, DeliveryTarget] = {
578
584
  ("RGB 16 bits", "RGB16", "RGB 8 bits"),
579
585
  "TIFF frames for stills-oriented or archival handoff.",
580
586
  ),
587
+ "png_sequence": _sequence(
588
+ "png_sequence", "PNG image sequence", ("PNG", "png"),
589
+ ("RGB16", "RGB 16 bits", "RGB8", "RGB 8 bits"),
590
+ "PNG frames for web and motion-graphics handoff.",
591
+ notes=(
592
+ "RGB ONLY — Resolve exposes no alpha PNG codec (21.0.4.5 offers just "
593
+ "'RGB 16 bits' / 'RGB 8 bits'). For transparency use dpx_sequence "
594
+ "('RGBA 8 bits') or prores4444_master.",
595
+ "PNG is not a render format on Resolve 19.x; this target resolves on 21.x+.",
596
+ ),
597
+ ),
598
+ # ── Animated web assets ─────────────────────────────────────────────────
599
+ # Not _web(): that helper pins mp4 and requires a raster. These carry no
600
+ # audio track at all, so export_audio is False rather than merely unpinned.
601
+ "gif_animated": DeliveryTarget(
602
+ id="gif_animated",
603
+ label="Animated GIF",
604
+ describe="Looping animated GIF for web/social placement. No audio.",
605
+ tier="web",
606
+ format_candidates=("GIF", "gif"),
607
+ codec_candidates=("Animated_GIF", "Animated GIF"),
608
+ qc_container="gif",
609
+ qc_codec="gif",
610
+ export_audio=False,
611
+ verified=_VERIFIED,
612
+ source="Live matrix: GIF render format; ffprobe values measured on a generated .gif.",
613
+ notes=(
614
+ "GIF carries no audio and is palette-limited to 256 colours; prefer "
615
+ "webp_animated where the destination supports it.",
616
+ "Raster and rate inherit the timeline — set them explicitly for a "
617
+ "placement with a fixed spec.",
618
+ ),
619
+ ),
620
+ "webp_animated": DeliveryTarget(
621
+ id="webp_animated",
622
+ label="Animated WebP",
623
+ describe="Looping animated WebP for web placement. No audio.",
624
+ tier="web",
625
+ format_candidates=("WebP", "webp"),
626
+ codec_candidates=("Animated_WEBP", "Animated WebP"),
627
+ export_audio=False,
628
+ # No QC projection on purpose — see qc_skip_reason. Guessing "webp"/"webp"
629
+ # would produce failures that say nothing about the deliverable, which is
630
+ # the exact trap the mp4-reports-as-mov case taught.
631
+ qc_skip_reason=(
632
+ "ffprobe container/codec values for animated WebP are unverified: the "
633
+ "reference machine's ffmpeg has only the webp_pipe still-image demuxer, "
634
+ "so a rendered animated WebP could not be probed. Measure and fill in "
635
+ "qc_container/qc_codec on a build with full WebP support."
636
+ ),
637
+ verified=_VERIFIED,
638
+ source="Live matrix: WebP render format (ffprobe side unmeasured).",
639
+ notes=(
640
+ "WebP carries no audio track.",
641
+ "WebP is not a render format on Resolve 19.x; this target resolves on 21.x+.",
642
+ ),
643
+ ),
581
644
  # ── Broadcast / Avid handoff ────────────────────────────────────────────
582
645
  "dnxhr_hq_mxf_opatom": DeliveryTarget(
583
646
  id="dnxhr_hq_mxf_opatom",
@@ -644,6 +707,13 @@ DELIVERY_TARGETS: Dict[str, DeliveryTarget] = {
644
707
  "need a human. easyDCP variants exist on this install too.",
645
708
  ),
646
709
  ),
710
+ # No HLS target. `HLS` (m3u8) looks fully supported through the query APIs on
711
+ # 21.0.4.5 — GetRenderCodecs returns {'H.264': 'H264'} and GetRenderResolutions
712
+ # returns real rasters — but SetCurrentRenderFormatAndCodec('m3u8', ...) is
713
+ # rejected for every value tried ('H264', 'H.264', 'h264', ''), while the same
714
+ # call for mp4/H264 succeeds. The matrix advertises a pair that cannot be
715
+ # selected, so a target for it would fail 100% of the time.
716
+ # Verified on Studio 21.0.4.5, 2026-08-12. See api_truth.py.
647
717
  }
648
718
 
649
719
  VALID_TARGETS = frozenset(DELIVERY_TARGETS)
@@ -676,6 +746,9 @@ TARGET_ALIASES: Dict[str, str] = {
676
746
  "dnx_master": "dnxhr_hqx_master",
677
747
  "avid": "dnxhr_hq_mxf_opatom",
678
748
  "vfx": "exr_sequence",
749
+ "png": "png_sequence",
750
+ "gif": "gif_animated",
751
+ "webp": "webp_animated",
679
752
  }
680
753
 
681
754
  #: Fields a caller may override per call. Deliberately excludes id/label/tier/