davinci-resolve-mcp 2.212.2 → 2.212.4

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,82 @@
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.212.4 — both dependency manifests move together again
6
+
7
+ ### Changed
8
+
9
+ - **The root `package.json` had lagged `resolve-advanced/package.json` since
10
+ July.** The advanced manifest was brought to zero advisories on 2026-08-30;
11
+ the root one still carried the SDK at 1.27, adm-zip 0.5, sharp 0.33, zod 3
12
+ and uuid 9, so `npm audit` on the root read nine advisories (five high)
13
+ while the advanced package read one. Both manifests now agree:
14
+ `@modelcontextprotocol/sdk` 1.30, `fast-xml-parser` 5.11, `adm-zip` 0.6,
15
+ `sharp` 0.35, `zod` 4, `js-yaml` 4.3, `pg` 8.23, `better-sqlite3` held on
16
+ the 11.x line. Contributed in #193 by @federicosada-pixel.
17
+ - **`uuid` is gone from the root manifest.** Nothing under `bin/`, `src/` or
18
+ `scripts/` imports it — the code uses `crypto.randomUUID` — so rather than
19
+ carry the bump to 14.x it was removed on landing.
20
+ - **Python floor for the MCP SDK is now `mcp[cli]>=1.30,<2`** in
21
+ `requirements.txt` and the installer; the `<2` pin stays because the 2.x
22
+ SDK dropped `mcp.server.fastmcp`. `pyaaf2` floor moves to 1.7.1.
23
+
24
+ ### What was checked
25
+
26
+ - **zod 3 → 4 is a major bump the advanced server takes directly.** Its two
27
+ single-argument `z.record()` sites (a documented zod 4 removal) were probed
28
+ on zod 4.5.4 for both parsing and JSON-schema conversion, and a real stdio
29
+ `tools/list` returns the same 18 tools before and after.
30
+ - **The five remaining root advisories are all transitive under the MCP
31
+ SDK** — hono, @hono/node-server, ajv → fast-uri, express-rate-limit →
32
+ ip-address, express → qs — and `npm audit fix --dry-run` reports the same
33
+ five, so they clear only when the SDK bumps its own dependencies.
34
+ - The Python suite was also run with the 1.30.0 SDK wheel shadowing the venv
35
+ before the venv itself was upgraded.
36
+
37
+ ### Validation
38
+
39
+ - Full offline Python suite, the drift guards (including the lockfile-sync
40
+ guard), `npm ci` from both lockfiles, the advanced Node suite, the CLI
41
+ smoke and pack checks, and pip-audit on the upgraded venv. No Resolve
42
+ behavior changed; live test not required.
43
+
44
+ ## What's New in v2.212.3 — a cached update prompt is re-judged against the version actually running
45
+
46
+ ### Fixed
47
+
48
+ - **A persisted "update available" outlived the upgrade it recommended.** The
49
+ update checker caches its last verdict (in memory and in
50
+ `logs/update-check.json`) and serves it without network for the throttle
51
+ interval. That verdict was stored as a *status*, not as a comparison, so
52
+ after upgrading from the version it was computed for — 2.135.0 → 2.210.0,
53
+ say — a server now running 2.212.1 kept prompting to update to 2.210.0.
54
+ Every cached path (in-memory, persisted, and the throttled branch of
55
+ `check_for_updates`) now re-compares the cached `latest_version` against
56
+ the running version and reclassifies to `update_available` /
57
+ `up_to_date` / `current_ahead`; `error` and `disabled` results are left
58
+ as they were. Contributed in #194 by @diesdaas.
59
+
60
+ ### Documentation
61
+
62
+ - **The READMEs said there was no beat detection; there has been for some
63
+ time.** Both the English and Simplified Chinese "not supported" tables
64
+ claimed "no beat or downbeat detection yet" — twenty lines below an
65
+ optional-extras table listing `pip install librosa` for exactly that. The
66
+ row now describes what actually exists: optional `librosa` beat detection
67
+ and beat / bar / phrase cut-point plans, downbeats inferred from the first
68
+ beat with `beat_offset` for pickups, and cut *points* rather than a finished
69
+ music edit. Speech-silence tools remain the wrong instrument for music.
70
+
71
+ ### Validation
72
+
73
+ - Four regression tests from the PR cover the persisted, in-memory and
74
+ throttled cache paths plus the preserved error/disabled states. On landing,
75
+ the update-check tests gained a `setUp` that resets the module-wide cache
76
+ around every test, so a seeded verdict cannot leak into another module's
77
+ cached-status read later in the run. Full offline suite, drift guards and
78
+ the advanced Node suite are green. No Resolve behavior changed; live test
79
+ not required.
80
+
5
81
  ## What's New in v2.212.2 — failed verification evidence survives the operation envelope
6
82
 
7
83
  ### Fixed
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.212.2-blue.svg)](https://github.com/samuelgursky/davinci-resolve-mcp/releases)
5
+ [![Version](https://img.shields.io/badge/version-2.212.4-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-36%20(353%20full)-blue.svg)](#server-modes)
@@ -339,7 +339,7 @@ cheaper to read it here than to discover it mid-project.
339
339
  | Not supported | Why, and what you get instead |
340
340
  |---|---|
341
341
  | **Choosing the best take** | Performance is most of what makes a take right, and none of it is measurable from a waveform or a transcript. `rank_takes` ranks *fluency* — fillers, restarts, script coverage — and says so in every response. The take that plays is regularly the least fluent one, because the hesitation is often the acting. Use it to find the clean safety take, not to choose the read. |
342
- | **Cutting to music** | No beat or downbeat detection yet. Speech-driven tools will read a music bed as one long region and are the wrong instrument for it. |
342
+ | **Automatic music editing** | Optional `librosa` support provides beat detection and beat/bar/phrase cut-point plans, not a finished assembly. Downbeats are inferred from the first beat; use `beat_offset` for pickups. Speech-silence tools are unsuitable for finding musical edit points. |
343
343
  | **Judging a cut** | Nothing here has an opinion about whether an edit is good. Every destructive action is plan → review → confirm for that reason. |
344
344
  | **Replacing an editor** | The output is a first-pass assembly, in the assistant-editor sense: ingest, sync, organize, string out, flag problems. It is a starting point you cut, not a finished cut. Defaults are deliberately **generous** — a first assembly is supposed to run long, because trimming is fast and visible while recovering discarded material is slow and invisible. |
345
345
  | **Modifying your source media** | By design and without exception — see below. |
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.212.2-blue.svg)](https://github.com/samuelgursky/davinci-resolve-mcp/releases)
5
+ [![Version](https://img.shields.io/badge/version-2.212.4-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-36%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.212.2 版 README。如与英文原版有出入,以 [英文原版](README.md) 为准。
15
+ > 本翻译对应 v2.212.4 版 README。如与英文原版有出入,以 [英文原版](README.md) 为准。
16
16
 
17
17
  一个 Model Context Protocol (MCP) 服务器,让 AI 助手通过官方脚本 API 控制 DaVinci Resolve Studio(达芬奇)。它提供完整的 API 覆盖,外加带护栏的工作流助手,涵盖剪辑、媒体池整理、渲染设置、审阅标记、调色、Fusion、Fairlight、项目生命周期任务、扩展开发,以及不碰源媒体的媒体分析。
18
18
 
@@ -207,7 +207,7 @@ DRX 调色写入**针对 Resolve Studio 做过实机校准**:调色参数默
207
207
  | 不支持 | 原因,以及你能得到什么 |
208
208
  |---|---|
209
209
  | **挑选最佳条次** | 表演是决定一条好坏的大头,而这些从波形或转写里都量不出来。`rank_takes` 排的是*流畅度*——填充词、重来、稿子覆盖率——并在每次响应里说明这一点。最终用的那条常常是最不流畅的一条,因为迟疑往往正是表演。用它找干净的保底条,别用它挑读法。 |
210
- | **跟音乐剪辑** | 还没有节拍/强拍检测。语音驱动的工具会把音乐床读成一整个长区域,用错了工具。 |
210
+ | **自动音乐剪辑** | 可选的 `librosa` 支持节拍检测和按节拍、小节、乐句规划剪切点,但不会生成完整剪辑。强拍从第一个节拍推断;遇到弱起时用 `beat_offset` 调整。语音静音检测工具不适合寻找音乐剪切点。 |
211
211
  | **评判剪辑好坏** | 这里没有任何东西对"这一刀剪得好不好"持有观点。正因如此,一切破坏性操作都走 计划 → 审阅 → 确认。 |
212
212
  | **取代剪辑师** | 输出是助理剪辑意义上的初剪:摄入、同步、整理、串片、标记问题。它是给你继续剪的起点,不是成片。默认参数刻意**宽松**——初剪本来就该偏长,因为往下修快且看得见,而找回已丢弃的素材慢且看不见。 |
213
213
  | **修改你的源媒体** | 设计如此,无例外——见下文。 |
package/install.py CHANGED
@@ -37,7 +37,7 @@ from src.utils.update_check import (
37
37
 
38
38
  # ─── Version ──────────────────────────────────────────────────────────────────
39
39
 
40
- VERSION = "2.212.2"
40
+ VERSION = "2.212.4"
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
@@ -1385,7 +1385,7 @@ def install_dependencies(venv_path, project_dir):
1385
1385
  # downgrade it, and the fix does not depend on install ordering. Lift both
1386
1386
  # together when server.py is ported to the 2.x layout.
1387
1387
  subprocess.run(
1388
- [str(pip), "install", "-q", "mcp[cli]>=1.29,<2"],
1388
+ [str(pip), "install", "-q", "mcp[cli]>=1.30,<2"],
1389
1389
  check=True, capture_output=True
1390
1390
  )
1391
1391
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "davinci-resolve-mcp",
3
- "version": "2.212.2",
3
+ "version": "2.212.4",
4
4
  "description": "NPM bootstrapper for the DaVinci Resolve MCP Server.",
5
5
  "license": "MIT",
6
6
  "author": "Samuel Gursky <samgursky@gmail.com>",
@@ -18,20 +18,19 @@
18
18
  "davinci-resolve-advanced-mcp": "./bin/davinci-resolve-advanced-mcp.mjs"
19
19
  },
20
20
  "dependencies": {
21
- "@modelcontextprotocol/sdk": "^1.27.1",
22
- "adm-zip": "^0.5.16",
23
- "fast-xml-parser": "^5.7.3",
21
+ "@modelcontextprotocol/sdk": "^1.30.0",
22
+ "adm-zip": "^0.6.0",
23
+ "fast-xml-parser": "^5.11.1",
24
24
  "fzstd": "^0.1.1",
25
25
  "jszip": "^3.10.1",
26
- "uuid": "^9.0.0",
27
- "zod": "^3.25.76",
26
+ "zod": "^4.5.4",
28
27
  "zstd-codec": "^0.1.5"
29
28
  },
30
29
  "optionalDependencies": {
31
- "better-sqlite3": "^11.0.0",
32
- "js-yaml": "^4.1.0",
33
- "pg": "^8.11.0",
34
- "sharp": "^0.33.0"
30
+ "better-sqlite3": "^11.10.0",
31
+ "js-yaml": "^4.3.2",
32
+ "pg": "^8.23.0",
33
+ "sharp": "^0.35.4"
35
34
  },
36
35
  "files": [
37
36
  "bin/",
@@ -19,18 +19,18 @@
19
19
  "LICENSE"
20
20
  ],
21
21
  "dependencies": {
22
- "@modelcontextprotocol/sdk": "^1.27.1",
22
+ "@modelcontextprotocol/sdk": "^1.30.0",
23
23
  "adm-zip": "^0.6.0",
24
- "fast-xml-parser": "^5.7.3",
24
+ "fast-xml-parser": "^5.11.1",
25
25
  "fzstd": "^0.1.1",
26
26
  "jszip": "^3.10.1",
27
- "zod": "^3.25.76",
27
+ "zod": "^4.5.4",
28
28
  "zstd-codec": "^0.1.5"
29
29
  },
30
30
  "optionalDependencies": {
31
31
  "better-sqlite3": "^11.10.0",
32
- "js-yaml": "^4.3.0",
33
- "pg": "^8.22.0",
32
+ "js-yaml": "^4.3.2",
33
+ "pg": "^8.23.0",
34
34
  "sharp": "^0.35.4"
35
35
  },
36
36
  "peerDependenciesMeta": {
@@ -87,7 +87,7 @@ if not logging.getLogger().handlers:
87
87
  handlers=[logging.StreamHandler()],
88
88
  )
89
89
 
90
- VERSION = "2.212.2"
90
+ VERSION = "2.212.4"
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.212.2"
14
+ VERSION = "2.212.4"
15
15
 
16
16
  import base64
17
17
  import os
@@ -135,14 +135,13 @@ def get_cached_update_status(
135
135
  with _cached_lock:
136
136
  cached = dict(_cached_status)
137
137
  if cached.get("status") != "unknown":
138
- if current_version and "current_version" not in cached:
139
- cached["current_version"] = current_version
138
+ cached = _reclassify_cached_status(cached, current_version)
139
+ _set_cached_status(cached)
140
140
  return cached
141
141
 
142
142
  state = _read_state(update_state_path(project_dir, env))
143
143
  if state:
144
- if current_version and "current_version" not in state:
145
- state["current_version"] = current_version
144
+ state = _reclassify_cached_status(state, current_version)
146
145
  if "update_mode" not in state:
147
146
  state["update_mode"] = get_update_mode(project_dir, env)
148
147
  return state
@@ -193,11 +192,12 @@ def check_for_updates(
193
192
  and previous
194
193
  and checked_at - float(previous.get("checked_at", 0)) < interval_seconds
195
194
  ):
196
- cached = dict(previous)
195
+ cached = _reclassify_cached_status(previous, current_version)
197
196
  cached["cached"] = True
198
197
  cached["update_mode"] = update_mode
199
198
  cached["next_check_at"] = float(previous.get("checked_at", 0)) + interval_seconds
200
199
  cached["next_check_at_iso"] = _format_timestamp(cached["next_check_at"])
200
+ _write_state(state_path, cached)
201
201
  _set_cached_status(cached)
202
202
  return cached
203
203
 
@@ -621,6 +621,27 @@ def _version_text(value: Any) -> str:
621
621
  return match.group(0) if match else str(value or "").strip()
622
622
 
623
623
 
624
+ def _reclassify_cached_status(
625
+ result: Mapping[str, Any], current_version: Optional[str]
626
+ ) -> Dict[str, Any]:
627
+ """Refresh cached status against the version of the running MCP."""
628
+ refreshed = dict(result)
629
+ if refreshed.get("status") not in _SUCCESS_STATUSES:
630
+ return refreshed
631
+ if current_version:
632
+ refreshed["current_version"] = current_version
633
+ comparison = compare_versions(current_version, refreshed.get("latest_version"))
634
+ if comparison is None:
635
+ return refreshed
636
+ if comparison < 0:
637
+ refreshed["status"] = "update_available"
638
+ elif comparison > 0:
639
+ refreshed["status"] = "current_ahead"
640
+ else:
641
+ refreshed["status"] = "up_to_date"
642
+ return refreshed
643
+
644
+
624
645
  def _read_state(path: Path) -> Dict[str, Any]:
625
646
  try:
626
647
  with path.open("r", encoding="utf-8") as handle: