davinci-resolve-mcp 2.205.0 → 2.205.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,47 @@
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.205.1 — #182: the bridge preflight checks both halves of Resolve's Python lookup
6
+
7
+ ### Fixed
8
+
9
+ - **A `PYTHON3HOME` prefix with a dylib but no `bin/python3` is no longer
10
+ reported as usable.** fusionscript.so does two things with the prefix — runs
11
+ `<prefix>/bin/python3` and dlopens `<prefix>/lib/libpython3.X.dylib`, whose
12
+ strings sit adjacent in the binary — and the preflight validated only the
13
+ second. It answered `python3_home.usable: true` and
14
+ `resolve_will_list_python_scripts: true` while Resolve listed **zero** Python
15
+ scripts and logged nothing, which is the worst shape this failure can take:
16
+ the user has been told the thing is configured correctly, so the real cause
17
+ is the last place they look. Reported in #182, with the root cause and the
18
+ fix both correct as filed.
19
+ - **The interpreter has to be there under the unversioned name.** `python3` is
20
+ the literal name in the binary, and that is what makes this trap easy to hit:
21
+ a Homebrew framework prefix carries a perfectly good
22
+ `lib/libpython3.13.dylib` next to a `bin/` that has `python3.13` and no
23
+ `python3`. It is formula-dependent — `python@3.14` ships one, `python@3.11`
24
+ and `python@3.13` do not — so the same "Homebrew Python" advice works on one
25
+ machine and silently fails on the next. `framework_pythons()` has always
26
+ required `bin/python3`; this is the same rule applied to the route that
27
+ skipped it.
28
+ - **A set-but-unusable `PYTHON3HOME` is now called out even when another
29
+ discovery route exists.** Resolve reads it first, and whether it falls back
30
+ after choosing a prefix it cannot use is inferred from string adjacency
31
+ rather than established — so resting a clean bill of health on a route
32
+ Resolve may never reach is the same false all-clear in a new place. The
33
+ preflight names the mismatch, prints the exact `ln -s` that repairs it, and
34
+ suggests `launchctl unsetenv` as the alternative.
35
+
36
+ ### Changed
37
+
38
+ - **The advice says that `launchctl setenv` does not survive a reboot.** A
39
+ bridge that listed for weeks and then stopped, with no error anywhere, is
40
+ usually that, and nobody connects it back to a step they ran a month
41
+ earlier. `sudo ln -s "$(command -v python3)" /usr/local/bin/python3` is
42
+ offered as the persistent alternative, with the `PATH` caveat — presented
43
+ alongside the sudo-free route rather than replacing it, since avoiding a
44
+ system-wide install is the whole point of the #143 fix.
45
+
5
46
  ## What's New in v2.205.0 — a standard operation envelope on every tool result
6
47
 
7
48
  Adapted from the design contributed in PR #181.
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.205.0-blue.svg)](https://github.com/samuelgursky/davinci-resolve-mcp/releases)
5
+ [![Version](https://img.shields.io/badge/version-2.205.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-36%20(353%20full)-blue.svg)](#server-modes)
@@ -80,6 +80,20 @@ never sees your shell's environment. Restart Resolve afterwards. A Lua canary is
80
80
  installed alongside so you can tell "Python not detected" apart from a wrong
81
81
  folder.
82
82
 
83
+ Two things that bite (#182). The prefix must contain **both**
84
+ `lib/libpython3.X.dylib` and `bin/python3` under that exact **unversioned**
85
+ name — Homebrew's framework builds often ship only `bin/python3.13`, which is
86
+ half a Python as far as Resolve is concerned, and the installer's preflight now
87
+ says so instead of reporting a usable prefix. And `launchctl setenv` **does not
88
+ survive a reboot**; if scripts stop listing weeks later with no error, that is
89
+ why. For something persistent, put an interpreter where Resolve already looks
90
+ (this one needs `sudo`, and check that `/usr/local/bin` does not precede your
91
+ normal Python on `PATH`):
92
+
93
+ ```bash
94
+ sudo ln -s "$(command -v python3)" /usr/local/bin/python3
95
+ ```
96
+
83
97
  Validated on free 21.0.3.7 and Studio 19.1.3.7, both macOS. The Windows paths
84
98
  added in v2.70.1 (issue #106) shipped unverified; reports on free 21.0.1.11
85
99
  (issue #109) and free 21.0.3.7 (issue #112) have since shown the bridge
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.205.0-blue.svg)](https://github.com/samuelgursky/davinci-resolve-mcp/releases)
5
+ [![Version](https://img.shields.io/badge/version-2.205.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-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.205.0 版 README。如与英文原版有出入,以 [英文原版](README.md) 为准。
15
+ > 本翻译对应 v2.205.1 版 README。如与英文原版有出入,以 [英文原版](README.md) 为准。
16
16
 
17
17
  一个 Model Context Protocol (MCP) 服务器,让 AI 助手通过官方脚本 API 控制 DaVinci Resolve Studio(达芬奇)。它提供完整的 API 覆盖,外加带护栏的工作流助手,涵盖剪辑、媒体池整理、渲染设置、审阅标记、调色、Fusion、Fairlight、项目生命周期任务、扩展开发,以及不碰源媒体的媒体分析。
18
18
 
@@ -61,6 +61,12 @@ launchctl setenv PYTHON3HOME "$(python3 -c 'import sys; print(sys.prefix)')"
61
61
 
62
62
  必须用 `launchctl setenv` 而不是 `export`——Resolve 从 Dock 启动,看不到你 shell 的环境变量。之后重启 Resolve。安装时会顺带装一个 Lua 金丝雀脚本,帮你区分"Python 未被检测到"和"目录放错"。
63
63
 
64
+ 有两个坑(#182)。前缀里必须**同时**有 `lib/libpython3.X.dylib` 和 `bin/python3`——而且是这个**不带版本号**的名字。Homebrew 的 framework 构建经常只提供 `bin/python3.13`,在 Resolve 眼里这只算半个 Python;安装器的预检现在会明说这一点,而不是报告前缀可用。另外,`launchctl setenv` **在重启后不会保留**;如果几周之后脚本又不列出来了且没有任何报错,通常就是这个原因。想要持久生效,就把解释器放到 Resolve 本来就会查的位置(这条需要 `sudo`,并且先确认 `/usr/local/bin` 没有排在你常用 Python 的 `PATH` 前面):
65
+
66
+ ```bash
67
+ sudo ln -s "$(command -v python3)" /usr/local/bin/python3
68
+ ```
69
+
64
70
  已在免费版 21.0.3.7 和 Studio 19.1.3.7 上验证(均为 macOS)。v2.70.1(issue #106)加入的 Windows 路径发布时未经验证;后续免费版 21.0.1.11(issue #109)和免费版 21.0.3.7(issue #112)的用户报告证实,Windows 11 上桥接在 `%PROGRAMDATA%` 和 `%APPDATA%` **两处**都能安装、列出并正常服务,这些路径现在是已证实而非假设。Linux 同样已获证实:免费版 20.3.2.9 的用户报告(issue #129,Fedora 43)显示桥接可安装到 `~/.local/share/DaVinciResolve/Fusion/Scripts/Utility`,用系统 Python 就能直接枚举脚本(Linux 完全没有这套查找问题),并能端到端正常服务。现在没有任何平台停留在假设上:macOS 为本项目直接验证,Windows 和 Linux 来自用户报告。
65
71
 
66
72
  注意:桥接在服务期间会一直占用端口。v2.70.3 之前,Windows 上的桥接可能在 Resolve 退出后存活,挡住下一个会话的监听器;如果你用的是旧版本且桥接不响应了,检查是否有残留的 `fuscript.exe` 还占着端口。
package/docs/SKILL.md CHANGED
@@ -41,6 +41,14 @@ Existing tool call sites work unchanged. Two things to know when diagnosing it:
41
41
  canary, which always lists, so "Python not detected" is distinguishable from
42
42
  "wrong folder". The preflight is macOS-only — off macOS Resolve finds Python
43
43
  by other means, and running the check there was a false alarm (#106).
44
+ Two follow-ups from #182 worth having in hand when a user says the menu is
45
+ empty despite a set `PYTHON3HOME`: the prefix needs **both**
46
+ `lib/libpython3.X.dylib` and `bin/python3` under that **unversioned** name
47
+ (Homebrew framework builds often ship only `python3.X`, so half the check
48
+ passes on the very interpreter people reach for), and `launchctl setenv` does
49
+ not survive a reboot — a bridge that listed for weeks and then stopped, with
50
+ no error anywhere, is usually that. `sudo ln -s "$(command -v python3)"
51
+ /usr/local/bin/python3` is the persistent alternative.
44
52
  - **Windows: both script folders confirmed.** `%PROGRAMDATA%` (#109) and
45
53
  `%APPDATA%` (#112) have each been shown serving the bridge on Windows 11 free
46
54
  builds. If a user reports the menu entry missing on Windows, ask whether the
package/install.py CHANGED
@@ -37,7 +37,7 @@ from src.utils.update_check import (
37
37
 
38
38
  # ─── Version ──────────────────────────────────────────────────────────────────
39
39
 
40
- VERSION = "2.205.0"
40
+ VERSION = "2.205.1"
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.205.0",
3
+ "version": "2.205.1",
4
4
  "description": "NPM bootstrapper for the DaVinci Resolve MCP Server.",
5
5
  "license": "MIT",
6
6
  "author": "Samuel Gursky <samgursky@gmail.com>",
@@ -286,10 +286,14 @@ _LUA_CANARY = """-- Installed by davinci-resolve-mcp as an enumeration canary.
286
286
  -- Resolve is listing Lua and silently skipping Python: it cannot find a Python 3.
287
287
  -- It looks at PYTHON3HOME, then /usr/local/bin/python3 -- and nowhere else, which
288
288
  -- is why Homebrew, pyenv, uv and conda interpreters go unseen. Either point it at
289
- -- the one you have (no sudo):
289
+ -- the one you have (no sudo, but does NOT survive a reboot):
290
290
  -- launchctl setenv PYTHON3HOME "$(python3 -c 'import sys; print(sys.prefix)')"
291
- -- (launchctl, not export -- Resolve never sees your shell), or install a
292
- -- python.org build, which creates /usr/local/bin/python3. Restart Resolve after.
291
+ -- (launchctl, not export -- Resolve never sees your shell; and the prefix needs
292
+ -- BOTH lib/libpython3.X.dylib and bin/python3 under that unversioned name --
293
+ -- Homebrew framework builds often ship only python3.X), or put one where Resolve
294
+ -- already looks, which persists:
295
+ -- sudo ln -s "$(command -v python3)" /usr/local/bin/python3
296
+ -- A python.org build creates that symlink for you. Restart Resolve after.
293
297
  print("Resolve is enumerating scripts. If the Python probe is missing, Resolve")
294
298
  print("cannot find a Python 3: set PYTHON3HOME with launchctl setenv, or install")
295
299
  print("a python.org build. Homebrew/pyenv/uv/conda are not looked at directly.")
@@ -335,12 +339,28 @@ def launchd_env(name: str) -> str | None:
335
339
 
336
340
 
337
341
  def python3_home_prefix() -> dict:
338
- """Is PYTHON3HOME set for Resolve, and does it point at a loadable Python 3?
342
+ """Is PYTHON3HOME set for Resolve, and does it point at a usable Python 3?
339
343
 
340
- "Loadable" means the `lib/libpython3.X.dylib` that fusionscript.so dlopens.
341
- An interpreter that cannot supply one is reported as set-but-unusable rather
342
- than counted, because the silent-non-enumeration symptom is identical and the
343
- remedy is not.
344
+ Usable means BOTH halves of what fusionscript.so does with the prefix, whose
345
+ strings sit adjacent in the binary:
346
+
347
+ python3 -c 'import sys; ...sys.prefix...' # run <prefix>/bin/python3
348
+ /libpython # dlopen <prefix>/lib/libpython3.X.dylib
349
+
350
+ Checking only the dylib reported `usable: true` for a prefix Resolve cannot
351
+ run, and then Resolve listed zero Python scripts — the exact false all-clear
352
+ this function's docstring already warned about, since "the silent
353
+ non-enumeration symptom is identical and the remedy is not" (issue #182).
354
+
355
+ The interpreter must be there under the **unversioned** name. That is the
356
+ literal name in the binary, and it is what makes this trap so easy to hit:
357
+ a Homebrew framework prefix has `bin/python3.13` but no `bin/python3`
358
+ (formula-dependent — python@3.14 ships one, python@3.11 and python@3.13 do
359
+ not), while carrying a perfectly good `lib/libpython3.13.dylib`. Half the
360
+ check passes on exactly the interpreter most likely to be tried.
361
+
362
+ `framework_pythons()` has always required `bin/python3`; this is the same
363
+ rule applied to the route that skipped it.
344
364
  """
345
365
  value = launchd_env("PYTHON3HOME")
346
366
  result = {
@@ -348,20 +368,70 @@ def python3_home_prefix() -> dict:
348
368
  "in_launchd": value is not None,
349
369
  "in_this_shell": os.environ.get("PYTHON3HOME") or None,
350
370
  "dylib": None,
371
+ "interpreter": None,
372
+ "reason": None,
351
373
  "usable": False,
352
374
  }
353
375
  if not value:
354
376
  return result
377
+
378
+ prefix = Path(value)
355
379
  try:
356
- dylibs = sorted(Path(value).glob("lib/libpython3.*.dylib"))
380
+ dylibs = sorted(prefix.glob("lib/libpython3.*.dylib"))
357
381
  except OSError:
358
382
  dylibs = []
383
+ interpreter = prefix / "bin" / "python3"
384
+ try:
385
+ # .exists() follows symlinks, so a dangling one reads as absent — which
386
+ # is what it is to a Resolve trying to execute it.
387
+ has_interpreter = interpreter.exists()
388
+ except OSError:
389
+ has_interpreter = False
390
+
359
391
  if dylibs:
360
392
  result["dylib"] = str(dylibs[0])
361
- result["usable"] = True
393
+ if has_interpreter:
394
+ result["interpreter"] = str(interpreter)
395
+ result["usable"] = bool(dylibs) and has_interpreter
396
+
397
+ if result["usable"]:
398
+ return result
399
+ if dylibs and not has_interpreter:
400
+ versioned = sorted(
401
+ child.name for child in _safe_iterdir(prefix / "bin")
402
+ if child.name.startswith("python3.")
403
+ and not child.name.endswith("-config")
404
+ )
405
+ result["reason"] = (
406
+ f"{prefix}/lib has a libpython dylib but {interpreter} does not "
407
+ f"exist. Resolve runs the UNVERSIONED name `python3`"
408
+ + (f"; this prefix ships only {', '.join(versioned)}. " if versioned else ". ")
409
+ + "Homebrew framework builds are the common case. Either symlink it "
410
+ f"inside the prefix (ln -s {versioned[0] if versioned else 'python3.X'} "
411
+ f"{prefix}/bin/python3), or point PYTHON3HOME at a prefix that has both."
412
+ )
413
+ elif has_interpreter and not dylibs:
414
+ result["reason"] = (
415
+ f"{interpreter} exists but {prefix}/lib has no libpython3.X.dylib "
416
+ "for Resolve to dlopen. A static or non-shared build cannot be "
417
+ "embedded; point PYTHON3HOME at a prefix built with a shared library."
418
+ )
419
+ else:
420
+ result["reason"] = (
421
+ f"{prefix} has neither bin/python3 nor lib/libpython3.X.dylib. "
422
+ "Check the path — it should be a Python `sys.prefix`, which "
423
+ "`python3 -c 'import sys; print(sys.prefix)'` prints."
424
+ )
362
425
  return result
363
426
 
364
427
 
428
+ def _safe_iterdir(directory: Path) -> list[Path]:
429
+ try:
430
+ return sorted(directory.iterdir())
431
+ except OSError:
432
+ return []
433
+
434
+
365
435
  def fallback_python3() -> dict:
366
436
  """`/usr/local/bin/python3` — the path baked into fusionscript.so.
367
437
 
@@ -414,7 +484,27 @@ def python_preflight() -> dict:
414
484
  # the order the binary's strings imply, and it is the one the user chose.
415
485
  found = home["usable"] or fallback["exists"] or bool(frameworks)
416
486
  advice = None
417
- if not found:
487
+ if home["in_launchd"] and not home["usable"]:
488
+ # A set-but-broken PYTHON3HOME has to be said out loud even when another
489
+ # route exists. PYTHON3HOME is read FIRST, and whether Resolve falls
490
+ # back after choosing a prefix it cannot use is not established — the
491
+ # ordering here is inferred from string adjacency in fusionscript.so,
492
+ # not from decompiled control flow. Reporting a clean bill of health on
493
+ # the strength of a route Resolve may never reach is the failure this
494
+ # whole check exists to prevent (issue #182).
495
+ advice = (
496
+ "PYTHON3HOME is set for Resolve but does not point at a Python 3 it "
497
+ f"can use.\n{home['reason']}\n"
498
+ + ("Another discovery route is present on this machine, but Resolve "
499
+ "reads PYTHON3HOME first and it is NOT established that it falls "
500
+ "back after picking a prefix it cannot use. Fix the prefix or "
501
+ "unset it (launchctl unsetenv PYTHON3HOME) rather than relying "
502
+ "on the fallback.\n" if found else "")
503
+ + "Restart Resolve after changing it. The Lua canary installed "
504
+ "alongside lists regardless, so 'Python not detected' stays "
505
+ "distinguishable from 'wrong folder'."
506
+ )
507
+ elif not found:
418
508
  advice = (
419
509
  "Resolve cannot find a Python 3, so it will silently ignore every "
420
510
  ".py script in its Scripts folders — they will simply not appear in "
@@ -428,8 +518,16 @@ def python_preflight() -> dict:
428
518
  "print(sys.prefix)')\"\n"
429
519
  " Use launchctl, NOT export — Resolve is launched from the Dock "
430
520
  "and never sees your shell's environment. The prefix must contain "
431
- "lib/libpython3.X.dylib.\n"
432
- " 2. Or install a python.org build, which creates "
521
+ "BOTH lib/libpython3.X.dylib and bin/python3 under that exact "
522
+ "unversioned name. Note that launchctl setenv does not survive a "
523
+ "reboot: if scripts stop listing weeks later with no error, this is "
524
+ "why.\n"
525
+ " 2. Or symlink an interpreter where Resolve already looks, which "
526
+ "is a file on disk and does persist (needs sudo):\n"
527
+ " sudo ln -s \"$(command -v python3)\" /usr/local/bin/python3\n"
528
+ " Check that /usr/local/bin does not precede your normal Python "
529
+ "on PATH before doing this.\n"
530
+ " 3. Or install a python.org build, which creates "
433
531
  "/usr/local/bin/python3 for you.\n"
434
532
  "Restart Resolve either way, then re-check. The Lua canary installed "
435
533
  "alongside will list regardless, so you can tell 'Python not "
@@ -87,7 +87,7 @@ if not logging.getLogger().handlers:
87
87
  handlers=[logging.StreamHandler()],
88
88
  )
89
89
 
90
- VERSION = "2.205.0"
90
+ VERSION = "2.205.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.205.0"
14
+ VERSION = "2.205.1"
15
15
 
16
16
  import base64
17
17
  import os