davinci-resolve-mcp 2.35.1 → 2.35.2
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 +13 -0
- package/README.md +1 -1
- package/docs/SKILL.md +2 -0
- package/install.py +1 -1
- package/package.json +1 -1
- package/src/granular/common.py +1 -1
- package/src/server.py +17 -7
- package/src/utils/readback.py +21 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,19 @@
|
|
|
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.35.2
|
|
6
|
+
|
|
7
|
+
Verification observability and a validator consolidation.
|
|
8
|
+
|
|
9
|
+
- **Added** `resolve_control(action="verification_stats")` returns a
|
|
10
|
+
process-level tally of readback-verification outcomes
|
|
11
|
+
(verified / contradicted / unverified) since server start. A rising
|
|
12
|
+
`contradicted` count means the Resolve API reported success but a readback
|
|
13
|
+
disagreed. No connection required.
|
|
14
|
+
- **Changed** `open_page` now validates its `page` argument through the declarative
|
|
15
|
+
contract layer (`contracts.validate`) instead of a hand-written enum check —
|
|
16
|
+
behavior unchanged; part of folding scattered validation into one place.
|
|
17
|
+
|
|
5
18
|
## What's New in v2.35.1
|
|
6
19
|
|
|
7
20
|
- **Added** `media_pool_item(action="extract_frames", clip_id, timestamps, output_dir?)`
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# DaVinci Resolve MCP Server
|
|
2
2
|
|
|
3
|
-
[](https://github.com/samuelgursky/davinci-resolve-mcp/releases)
|
|
4
4
|
[](https://www.npmjs.com/package/davinci-resolve-mcp)
|
|
5
5
|
[](docs/reference/api-coverage.md)
|
|
6
6
|
[-blue.svg)](#server-modes)
|
package/docs/SKILL.md
CHANGED
|
@@ -320,6 +320,8 @@ Key actions:
|
|
|
320
320
|
- `get_version` — returns `{product, version, version_string}`
|
|
321
321
|
- `api_truth(query?)` — look up behaviorally-verified facts about quirky/unreliable
|
|
322
322
|
Resolve API behavior (no connection needed); filter by substring
|
|
323
|
+
- `verification_stats` — readback-verification tally (verified/contradicted/
|
|
324
|
+
unverified) since server start (no connection needed)
|
|
323
325
|
- `get_page` / `open_page(page)` — read or switch the active page
|
|
324
326
|
- `get_keyframe_mode` / `set_keyframe_mode(mode)`
|
|
325
327
|
- `get_fairlight_presets` — Resolve 20.2.2+; returns available Fairlight
|
package/install.py
CHANGED
|
@@ -35,7 +35,7 @@ from src.utils.update_check import (
|
|
|
35
35
|
|
|
36
36
|
# ─── Version ──────────────────────────────────────────────────────────────────
|
|
37
37
|
|
|
38
|
-
VERSION = "2.35.
|
|
38
|
+
VERSION = "2.35.2"
|
|
39
39
|
# Only hard floor: mcp[cli] requires Python 3.10+. There is no upper bound —
|
|
40
40
|
# Resolve's scripting bridge loads into newer interpreters on recent builds
|
|
41
41
|
# (Python 3.14 verified against Resolve Studio 20.3.2). Older Resolve builds
|
package/package.json
CHANGED
package/src/granular/common.py
CHANGED
|
@@ -80,7 +80,7 @@ if not logging.getLogger().handlers:
|
|
|
80
80
|
handlers=[logging.StreamHandler()],
|
|
81
81
|
)
|
|
82
82
|
|
|
83
|
-
VERSION = "2.35.
|
|
83
|
+
VERSION = "2.35.2"
|
|
84
84
|
logger = logging.getLogger("davinci-resolve-mcp")
|
|
85
85
|
logger.info(f"Starting DaVinci Resolve MCP Server v{VERSION}")
|
|
86
86
|
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 341-tool granular server instead
|
|
12
12
|
"""
|
|
13
13
|
|
|
14
|
-
VERSION = "2.35.
|
|
14
|
+
VERSION = "2.35.2"
|
|
15
15
|
|
|
16
16
|
import base64
|
|
17
17
|
import os
|
|
@@ -48,7 +48,7 @@ from src.utils.contracts import validate as _validate_params
|
|
|
48
48
|
from src.utils.cut_ir import build_cut_list as _build_cut_list
|
|
49
49
|
from src.utils.page_lock import open_page_serialized as _open_page_serialized
|
|
50
50
|
from src.utils.proc import safe_run
|
|
51
|
-
from src.utils.readback import verify_by_readback
|
|
51
|
+
from src.utils.readback import verify_by_readback, verification_stats as _verification_stats
|
|
52
52
|
from src.utils.update_check import (
|
|
53
53
|
check_for_updates,
|
|
54
54
|
clear_update_prompt_preferences,
|
|
@@ -10632,6 +10632,8 @@ def resolve_control(action: str, params: Optional[Dict[str, Any]] = None) -> Dic
|
|
|
10632
10632
|
clear_mcp_update_preferences() -> {success, version, update, decision}
|
|
10633
10633
|
api_truth(query?) -> {verified_on, count, facts} — look up behaviorally-verified
|
|
10634
10634
|
facts about quirky/unreliable Resolve API behavior (no connection needed).
|
|
10635
|
+
verification_stats() -> {stats} — readback-verification tally
|
|
10636
|
+
(verified/contradicted/unverified) since server start (no connection needed).
|
|
10635
10637
|
get_page() -> {page}
|
|
10636
10638
|
open_page(page) -> {success} — page: edit, cut, color, fusion, fairlight, deliver
|
|
10637
10639
|
get_keyframe_mode() -> {mode}
|
|
@@ -10656,6 +10658,11 @@ def resolve_control(action: str, params: Optional[Dict[str, Any]] = None) -> Dic
|
|
|
10656
10658
|
if action == "api_truth":
|
|
10657
10659
|
facts = lookup_api_truth(p.get("query"))
|
|
10658
10660
|
return {"verified_on": _API_TRUTH_VERIFIED_ON, "count": len(facts), "facts": facts}
|
|
10661
|
+
if action == "verification_stats":
|
|
10662
|
+
# Process-level readback-verification tally — no connection needed.
|
|
10663
|
+
stats = _verification_stats()
|
|
10664
|
+
return {"stats": stats, "note": "Counts since server start. A rising "
|
|
10665
|
+
"'contradicted' count means the API reported success but a readback disagreed."}
|
|
10659
10666
|
|
|
10660
10667
|
# Control-panel actions don't require Resolve to be running.
|
|
10661
10668
|
if action == "open_control_panel":
|
|
@@ -10720,12 +10727,15 @@ def resolve_control(action: str, params: Optional[Dict[str, Any]] = None) -> Dic
|
|
|
10720
10727
|
elif action == "get_page":
|
|
10721
10728
|
return {"page": r.GetCurrentPage()}
|
|
10722
10729
|
elif action == "open_page":
|
|
10723
|
-
|
|
10724
|
-
|
|
10725
|
-
|
|
10730
|
+
err, clean = _validate_params(p, {
|
|
10731
|
+
"page": {"enum": ["media", "cut", "edit", "color", "fusion", "fairlight", "deliver"],
|
|
10732
|
+
"required": True},
|
|
10733
|
+
})
|
|
10734
|
+
if err:
|
|
10735
|
+
return _err(err)
|
|
10726
10736
|
# Serialize page switches so concurrent agents can't flip the single
|
|
10727
10737
|
# globally-active page underneath each other.
|
|
10728
|
-
return {"success": bool(_open_page_serialized(r,
|
|
10738
|
+
return {"success": bool(_open_page_serialized(r, clean["page"]))}
|
|
10729
10739
|
elif action == "get_keyframe_mode":
|
|
10730
10740
|
return {"mode": r.GetKeyframeMode()}
|
|
10731
10741
|
elif action == "set_keyframe_mode":
|
|
@@ -10746,7 +10756,7 @@ def resolve_control(action: str, params: Optional[Dict[str, Any]] = None) -> Dic
|
|
|
10746
10756
|
return missing
|
|
10747
10757
|
r.DisableBackgroundTasksForCurrentResolveSession()
|
|
10748
10758
|
return _ok()
|
|
10749
|
-
return _unknown(action, ["launch","get_version","api_truth","mcp_update_status","set_mcp_update_policy","ignore_mcp_update","snooze_mcp_update","clear_mcp_update_preferences","get_page","open_page","get_keyframe_mode","set_keyframe_mode","quit","get_fairlight_presets","set_high_priority","disable_background_tasks_for_current_session","open_control_panel","control_panel_status","close_control_panel","save_state","restore_state"])
|
|
10759
|
+
return _unknown(action, ["launch","get_version","api_truth","verification_stats","mcp_update_status","set_mcp_update_policy","ignore_mcp_update","snooze_mcp_update","clear_mcp_update_preferences","get_page","open_page","get_keyframe_mode","set_keyframe_mode","quit","get_fairlight_presets","set_high_priority","disable_background_tasks_for_current_session","open_control_panel","control_panel_status","close_control_panel","save_state","restore_state"])
|
|
10750
10760
|
|
|
10751
10761
|
|
|
10752
10762
|
# ─── V2 C4: Per-field corrections with provenance + changelog ────────────────
|
package/src/utils/readback.py
CHANGED
|
@@ -16,6 +16,21 @@ from typing import Any, Callable, Dict, Optional
|
|
|
16
16
|
|
|
17
17
|
logger = logging.getLogger("davinci-resolve-mcp")
|
|
18
18
|
|
|
19
|
+
# Process-level tally of verification outcomes — lightweight observability into
|
|
20
|
+
# how often the Resolve API's self-reported success matches reality. A rising
|
|
21
|
+
# `contradicted` count is the signal worth watching.
|
|
22
|
+
_STATS = {"total": 0, "verified": 0, "contradicted": 0, "unverified": 0}
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def verification_stats():
|
|
26
|
+
"""Return a copy of the process-level verification tally."""
|
|
27
|
+
return dict(_STATS)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def reset_verification_stats():
|
|
31
|
+
for k in _STATS:
|
|
32
|
+
_STATS[k] = 0
|
|
33
|
+
|
|
19
34
|
|
|
20
35
|
def verify_by_readback(
|
|
21
36
|
mutate: Callable[[], Any],
|
|
@@ -56,6 +71,7 @@ def verify_by_readback(
|
|
|
56
71
|
|
|
57
72
|
# A contradiction — reported success but the readback disagrees — is the
|
|
58
73
|
# signal worth surfacing loudly.
|
|
74
|
+
_STATS["total"] += 1
|
|
59
75
|
if result.get("success_raw") and not result.get("verified"):
|
|
60
76
|
logger.warning(
|
|
61
77
|
"readback contradiction%s: API reported success but post-state "
|
|
@@ -64,7 +80,12 @@ def verify_by_readback(
|
|
|
64
80
|
f" (intent={intent})" if intent else "",
|
|
65
81
|
)
|
|
66
82
|
result["contradiction"] = True
|
|
83
|
+
_STATS["contradicted"] += 1
|
|
67
84
|
else:
|
|
68
85
|
result["contradiction"] = False
|
|
86
|
+
if result.get("verified"):
|
|
87
|
+
_STATS["verified"] += 1
|
|
88
|
+
else:
|
|
89
|
+
_STATS["unverified"] += 1
|
|
69
90
|
|
|
70
91
|
return result
|