davinci-resolve-mcp 2.23.0
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/AGENTS.md +85 -0
- package/CHANGELOG.md +802 -0
- package/CLAUDE.md +15 -0
- package/LICENSE +21 -0
- package/README.md +159 -0
- package/SECURITY.md +53 -0
- package/bin/davinci-resolve-mcp.mjs +376 -0
- package/docs/README.md +56 -0
- package/docs/SKILL.md +1145 -0
- package/docs/authoring/fuse-dctl-authoring.md +242 -0
- package/docs/authoring/script-plugin-authoring.md +195 -0
- package/docs/contributing.md +82 -0
- package/docs/guides/color-decision-guide.md +387 -0
- package/docs/guides/editorial-decision-guide.md +136 -0
- package/docs/guides/media-analysis-guide.md +615 -0
- package/docs/guides/multicam-setup-guide.md +138 -0
- package/docs/install.md +198 -0
- package/docs/integrations/workflow-integrations.md +120 -0
- package/docs/kernels/README.md +28 -0
- package/docs/kernels/audio-fairlight-kernel.md +86 -0
- package/docs/kernels/color-grade-kernel.md +103 -0
- package/docs/kernels/extension-authoring-kernel.md +101 -0
- package/docs/kernels/fusion-composition-kernel.md +91 -0
- package/docs/kernels/media-pool-ingest-kernel.md +147 -0
- package/docs/kernels/project-lifecycle-kernel.md +120 -0
- package/docs/kernels/render-deliver-kernel.md +92 -0
- package/docs/kernels/review-annotation-kernel.md +110 -0
- package/docs/kernels/timeline-conform-interchange-kernel.md +99 -0
- package/docs/kernels/timeline-edit-kernel.md +189 -0
- package/docs/notes/codec-plugin-notes.md +136 -0
- package/docs/notes/dctl-notes.md +234 -0
- package/docs/notes/fusion-template-notes.md +136 -0
- package/docs/notes/lut-notes.md +136 -0
- package/docs/notes/openfx-notes.md +120 -0
- package/docs/process/release-process.md +152 -0
- package/docs/reference/api-coverage.md +488 -0
- package/docs/reference/resolve_scripting_api.txt +1012 -0
- package/examples/README.md +53 -0
- package/examples/markers/README.md +81 -0
- package/examples/media/README.md +94 -0
- package/examples/timeline/README.md +98 -0
- package/install.py +1196 -0
- package/package.json +52 -0
- package/scripts/audit_api_parity.py +275 -0
- package/scripts/live_media_analysis_polish_probe.py +65 -0
- package/src/__init__.py +3 -0
- package/src/analysis_dashboard.py +4936 -0
- package/src/control_panel.py +13 -0
- package/src/granular/__init__.py +17 -0
- package/src/granular/common.py +727 -0
- package/src/granular/folder.py +287 -0
- package/src/granular/gallery.py +306 -0
- package/src/granular/graph.py +309 -0
- package/src/granular/media_pool.py +679 -0
- package/src/granular/media_pool_item.py +852 -0
- package/src/granular/media_storage.py +179 -0
- package/src/granular/project.py +1594 -0
- package/src/granular/resolve_control.py +521 -0
- package/src/granular/timeline.py +1074 -0
- package/src/granular/timeline_item.py +2251 -0
- package/src/resolve_mcp_server.py +43 -0
- package/src/server.py +15691 -0
- package/src/utils/__init__.py +3 -0
- package/src/utils/app_control.py +319 -0
- package/src/utils/audio_fairlight_live_probe.py +263 -0
- package/src/utils/cdl.py +20 -0
- package/src/utils/cloud_operations.py +192 -0
- package/src/utils/color_grade_live_probe.py +444 -0
- package/src/utils/dctl_templates.py +368 -0
- package/src/utils/extension_authoring_live_probe.py +292 -0
- package/src/utils/fuse_templates.py +1968 -0
- package/src/utils/fusion_composition_live_probe.py +284 -0
- package/src/utils/layout_presets.py +333 -0
- package/src/utils/mcp_stdio.py +32 -0
- package/src/utils/media_analysis.py +3618 -0
- package/src/utils/media_analysis_jobs.py +796 -0
- package/src/utils/media_pool_ingest_live_probe.py +592 -0
- package/src/utils/multicam.py +393 -0
- package/src/utils/object_inspection.py +287 -0
- package/src/utils/platform.py +157 -0
- package/src/utils/project_lifecycle_live_probe.py +376 -0
- package/src/utils/project_properties.py +601 -0
- package/src/utils/render_deliver_live_probe.py +384 -0
- package/src/utils/resolve_connection.py +77 -0
- package/src/utils/review_annotation_live_probe.py +352 -0
- package/src/utils/script_templates.py +1193 -0
- package/src/utils/sync_detection.py +887 -0
- package/src/utils/timeline_conform_live_probe.py +280 -0
- package/src/utils/timeline_kernel_live_probe.py +1091 -0
- package/src/utils/timeline_kernel_probe.py +185 -0
- package/src/utils/timeline_title_text.py +87 -0
- package/src/utils/update_check.py +610 -0
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
# Fuse and DCTL Authoring Tools (Experimental)
|
|
2
|
+
|
|
3
|
+
The `fuse_plugin` and `dctl` compound tools (introduced in v2.5.0) generate and
|
|
4
|
+
install Fusion Fuse plugins and DCTL color-transform files. They are the first
|
|
5
|
+
*authoring* tools in this MCP — every other tool wraps Resolve's scripting API,
|
|
6
|
+
while these two write source files into Resolve's plugin/LUT directories.
|
|
7
|
+
|
|
8
|
+
**Status: lifecycle-tested, runtime rendering still experimental.** The v2.16.0
|
|
9
|
+
Extension Authoring kernel live-tested template generation, validation,
|
|
10
|
+
install/read/list/remove, LUT refresh for regular DCTLs, and restart-required
|
|
11
|
+
classification for Fuse and ACES DCTL surfaces. It does not prove every Fuse
|
|
12
|
+
renders correctly after a restart or that every DCTL compiles on every GPU
|
|
13
|
+
backend. Community feedback on runtime behavior is still welcome — please open
|
|
14
|
+
an issue with the template kind, your Resolve version and platform, and any
|
|
15
|
+
console output from Resolve's Workspace → Console.
|
|
16
|
+
|
|
17
|
+
## What's covered
|
|
18
|
+
|
|
19
|
+
### `fuse_plugin` — Fusion Fuse plugins
|
|
20
|
+
|
|
21
|
+
Fuses are Lua plugins (or GLSL view-LUT shaders) that Fusion loads at startup.
|
|
22
|
+
A new Fuse requires a Resolve restart to register; existing Fuses can be
|
|
23
|
+
edited and reloaded from the Inspector's Edit/Reload buttons without a
|
|
24
|
+
restart. The MCP cannot trigger reload — that's a UI-only action.
|
|
25
|
+
|
|
26
|
+
Actions: `path`, `list`, `install`, `remove`, `read`, `validate`, `template`,
|
|
27
|
+
`list_templates`.
|
|
28
|
+
|
|
29
|
+
**18 template kinds**, grouped by purpose:
|
|
30
|
+
|
|
31
|
+
| Group | Kind | Type | Lang | Risk |
|
|
32
|
+
|-----------------|-----------------------|----------------|-------------|-------|
|
|
33
|
+
| Color | `color_matrix` | `CT_Tool` | Lua | Low |
|
|
34
|
+
| | `per_pixel` | `CT_Tool` | Lua | Low |
|
|
35
|
+
| | `channel_op` | `CT_Tool` | Lua | Low |
|
|
36
|
+
| Geometric | `transform` | `CT_Tool` | Lua | Low |
|
|
37
|
+
| | `spatial_warp` | `CT_Tool` | Lua | Med |
|
|
38
|
+
| Text & shapes | `text_overlay` | `CT_Tool` | Lua | Med |
|
|
39
|
+
| | `shape_generator` | `CT_Tool` | Lua | Med |
|
|
40
|
+
| Source/temporal | `source_generator` | `CT_Tool` (source) | Lua | Med |
|
|
41
|
+
| | `time_displace` | `CT_Tool` | Lua | Low |
|
|
42
|
+
| Filters | `builtin_blur` | `CT_Tool` | Lua | Low |
|
|
43
|
+
| | `builtin_resize` | `CT_Tool` | Lua | Low |
|
|
44
|
+
| | `variable_blur` | `CT_Tool` | Lua (SAT) | Med |
|
|
45
|
+
| Modifiers | `modifier` | `CT_Modifier` | Lua | High |
|
|
46
|
+
| | `point_modifier` | `CT_Modifier` | Lua | High |
|
|
47
|
+
| Display/shaders | `view_lut` | `CT_ViewLUTPlugin` | Lua + GLSL | Med |
|
|
48
|
+
| | `dctl_kernel` | `CT_Tool` | Lua + DCTL | High |
|
|
49
|
+
| Reference | `controls_demo` | `CT_Tool` | Lua | Low |
|
|
50
|
+
| | `notifychanged_demo` | `CT_Tool` | Lua | Low |
|
|
51
|
+
|
|
52
|
+
Risk levels reflect how confident we are the template is correct based on the
|
|
53
|
+
SDK reference and parser-level checks:
|
|
54
|
+
|
|
55
|
+
- **Low** — directly mirrors a documented SDK example, simple Lua, no aux paths.
|
|
56
|
+
- **Medium** — uses several documented APIs together (Shape system, sampling,
|
|
57
|
+
source-tool registration, GLSL parameter passing). Each API is documented
|
|
58
|
+
but the combination has more surface area to misalign on.
|
|
59
|
+
- **High** — `CT_Modifier` is barely covered in the SDK; `dctl_kernel` exercises
|
|
60
|
+
GPU-compute integration (`DVIPComputeNode`, parameter blocks, samplers) that
|
|
61
|
+
isn't reachable by static checks.
|
|
62
|
+
|
|
63
|
+
Install location:
|
|
64
|
+
|
|
65
|
+
| Platform | Path |
|
|
66
|
+
|---|---|
|
|
67
|
+
| macOS | `~/Library/Application Support/Blackmagic Design/DaVinci Resolve/Support/Fusion/Fuses` |
|
|
68
|
+
| Windows | `%PROGRAMDATA%\Blackmagic Design\DaVinci Resolve\Support\Fusion\Fuses` |
|
|
69
|
+
| Linux | `~/.local/share/DaVinciResolve/Fusion/Fuses` |
|
|
70
|
+
|
|
71
|
+
### `dctl` — DCTL color-transform files
|
|
72
|
+
|
|
73
|
+
Regular DCTLs live under Resolve's LUT directory and appear as LUT-style entries
|
|
74
|
+
in the LUT browser, the Clip/Node LUT picker, and the ResolveFX DCTL plugin.
|
|
75
|
+
After install, call `project_settings(action='refresh_luts')` to make Resolve
|
|
76
|
+
discover the new file.
|
|
77
|
+
|
|
78
|
+
ACES DCTLs (IDT/ODT) install to a separate ACES Transforms directory and are
|
|
79
|
+
scanned **only at Resolve startup**. Install requires a Resolve restart.
|
|
80
|
+
|
|
81
|
+
Actions: `path`, `list`, `install`, `remove`, `read`, `validate`, `template`,
|
|
82
|
+
`list_templates`.
|
|
83
|
+
|
|
84
|
+
**8 template kinds**:
|
|
85
|
+
|
|
86
|
+
| Kind | Entry point | Category | Notes |
|
|
87
|
+
|---------------------|----------------------------|----------------|--------------------------------|
|
|
88
|
+
| `transform` | `__DEVICE__ float3 transform()` | `lut` | Per-pixel, no alpha |
|
|
89
|
+
| `transform_alpha` | `__DEVICE__ float4 transform()` | `lut` | Resolve 19.1+; alpha mode tag |
|
|
90
|
+
| `transition` | `__DEVICE__ float4 transition()` | `lut` | Reads `TRANSITION_PROGRESS` |
|
|
91
|
+
| `matrix` | `__DEVICE__ float3 transform()` | `lut` | 3x3 color matrix as constants |
|
|
92
|
+
| `kernel` | `__DEVICE__ float3 transform()` | `lut` | Bare TODO stub |
|
|
93
|
+
| `lut_apply` | `__DEVICE__ float3 transform()` | `lut` | Wraps an external `.cube` LUT |
|
|
94
|
+
| `aces_idt` | `__DEVICE__ float3 transform()` | `aces_idt` | ACES Input Device Transform |
|
|
95
|
+
| `aces_odt` | `__DEVICE__ float3 transform()` | `aces_odt` | ACES Output Device Transform |
|
|
96
|
+
|
|
97
|
+
The `template` action returns `suggested_category` so callers know which install
|
|
98
|
+
path to use:
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
gen = dctl('template', {'kind': 'aces_idt', 'name': 'MyIDT'})
|
|
102
|
+
dctl('install', {'name': 'MyIDT', 'source': gen['source'],
|
|
103
|
+
'category': gen['suggested_category']})
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Install locations:
|
|
107
|
+
|
|
108
|
+
| Category | macOS | Windows | Linux |
|
|
109
|
+
|---|---|---|---|
|
|
110
|
+
| `lut` | `~/Library/Application Support/Blackmagic Design/DaVinci Resolve/LUT` | `%APPDATA%\Blackmagic Design\DaVinci Resolve\Support\LUT` | `~/.local/share/DaVinciResolve/LUT` |
|
|
111
|
+
| `aces_idt` | `~/Library/Application Support/Blackmagic Design/DaVinci Resolve/ACES Transforms/IDT` | `%APPDATA%\…\ACES Transforms\IDT` | `~/.local/share/DaVinciResolve/ACES Transforms/IDT` |
|
|
112
|
+
| `aces_odt` | …`/ACES Transforms/ODT` | …`\ACES Transforms\ODT` | …`/ACES Transforms/ODT` |
|
|
113
|
+
|
|
114
|
+
Subdir support is available within any category for organization (e.g.
|
|
115
|
+
`subdir='MCP'` puts a generated DCTL under `LUT/MCP/`).
|
|
116
|
+
|
|
117
|
+
See `docs/notes/dctl-notes.md` for the full DCTL language reference, custom UI
|
|
118
|
+
parameter syntax (`DCTLUI_SLIDER_FLOAT`, `DCTLUI_COLOR_PICKER`, etc.), and
|
|
119
|
+
ACES parametric V1/V2 details.
|
|
120
|
+
|
|
121
|
+
## What's been tested vs. what hasn't
|
|
122
|
+
|
|
123
|
+
**Tested:**
|
|
124
|
+
- All 18 Fuse templates pass `luac -p` (Lua 5.5) with default *and* varied
|
|
125
|
+
options
|
|
126
|
+
- All 8 DCTL templates produce a valid entry-point signature
|
|
127
|
+
- Filesystem round-trip (install → list → read → remove) for both tools across
|
|
128
|
+
all install categories (LUT, ACES IDT, ACES ODT)
|
|
129
|
+
- Live v2.16.0 lifecycle probe confirmed generated Fuse install/read/list/remove,
|
|
130
|
+
regular DCTL install/read/list/refresh/remove, and ACES IDT
|
|
131
|
+
install/read/list/remove on Resolve Studio 20.3.2.9
|
|
132
|
+
- `list_templates` enumeration for both tools
|
|
133
|
+
- Path-traversal and name-regex rejection paths
|
|
134
|
+
- Subdir handling with traversal guards (no `..`, no hidden dirs)
|
|
135
|
+
- `view_lut` parameter types: `float`, `vec2`, `vec3_rgb`, `vec4_rgba`
|
|
136
|
+
|
|
137
|
+
**Still not fully proven:**
|
|
138
|
+
- Restarting Resolve and confirming every generated Fuse appears in the Fusion
|
|
139
|
+
tool list
|
|
140
|
+
- Confirming every template renders correctly at runtime (e.g. does
|
|
141
|
+
`color_matrix` brightness actually shift values? does `text_overlay` draw
|
|
142
|
+
glyphs? does `point_modifier` drive a Merge Center input?)
|
|
143
|
+
- The Modifier templates — `CT_Modifier` is barely covered in the Fuse SDK
|
|
144
|
+
- The `dctl_kernel` Fuse — `DVIPComputeNode` runtime, sampler setup,
|
|
145
|
+
parameter struct memory layout
|
|
146
|
+
- GLSL `view_lut` shader compilation (we only check braces and the
|
|
147
|
+
`ShadePixel` substring; `glslangValidator` would be needed for full GLSL
|
|
148
|
+
parsing)
|
|
149
|
+
- Every DCTL template compiling on every Resolve GPU backend (Metal/CUDA/OpenCL
|
|
150
|
+
each have edge cases)
|
|
151
|
+
- `variable_blur` SAT-based pattern — `UseSAT()`/`SampleAreaW()`/`RecycleSAT()`
|
|
152
|
+
are documented but unverified in this combination
|
|
153
|
+
- `source_generator` `CT_SourceTool` registration — the `REG_Source_*Ctrls`
|
|
154
|
+
attributes mirror the SDK example but the global `Width`/`Height`/`Scale`/
|
|
155
|
+
`XAspect`/`YAspect` variables we reference are inferred, not documented
|
|
156
|
+
- `controls_demo` and `notifychanged_demo` — Inspector layout and dynamic
|
|
157
|
+
show/hide behavior
|
|
158
|
+
|
|
159
|
+
## Reporting feedback
|
|
160
|
+
|
|
161
|
+
If a template fails to load, render incorrectly, or produces a Resolve
|
|
162
|
+
console error, please open an issue at
|
|
163
|
+
<https://github.com/samuelgursky/davinci-resolve-mcp/issues> with:
|
|
164
|
+
|
|
165
|
+
- Template kind (e.g. `text_overlay`, `dctl_kernel`)
|
|
166
|
+
- DaVinci Resolve version and platform
|
|
167
|
+
- The exact MCP call you made (action, name, options)
|
|
168
|
+
- Any console output from Workspace → Console (for Fuses) or the build-error
|
|
169
|
+
dialog (for DCTLs)
|
|
170
|
+
- Whether the bug reproduces with default options or only with custom ones
|
|
171
|
+
|
|
172
|
+
A short manual-smoke-test recipe for the highest-risk templates lives at the
|
|
173
|
+
end of this document.
|
|
174
|
+
|
|
175
|
+
## Manual smoke test
|
|
176
|
+
|
|
177
|
+
For maintainers who want to live-test before merging template changes.
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
# Install the highest-risk Fuses
|
|
181
|
+
venv/bin/python <<'EOF'
|
|
182
|
+
import sys
|
|
183
|
+
sys.modules['DaVinciResolveScript'] = type(sys)('DaVinciResolveScript')
|
|
184
|
+
from src.server import fuse_plugin
|
|
185
|
+
for kind in ('text_overlay', 'dctl_kernel', 'point_modifier', 'variable_blur'):
|
|
186
|
+
name = 'McpSmoke' + kind.replace('_', '').title()
|
|
187
|
+
src = fuse_plugin('template', {'kind': kind, 'name': name})['source']
|
|
188
|
+
print(fuse_plugin('install', {'name': name, 'source': src, 'overwrite': True}))
|
|
189
|
+
EOF
|
|
190
|
+
|
|
191
|
+
# Quit and relaunch Resolve, then in the Fusion page:
|
|
192
|
+
# Effects Library → Tools → Fuses → MCP → McpSmokeTextoverlay
|
|
193
|
+
# Effects Library → Tools → Fuses → MCP → McpSmokeDctlkernel
|
|
194
|
+
# Effects Library → Tools → Fuses → MCP → McpSmokeVariableblur
|
|
195
|
+
# Drop each onto a node graph between MediaIn1 and MediaOut1.
|
|
196
|
+
# For McpSmokePointmodifier: right-click any Point input (e.g. Merge Center)
|
|
197
|
+
# in any tool → Modify with → MCP → McpSmokePointmodifier.
|
|
198
|
+
# Verify Inspector controls work and the image responds.
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
For the DCTL side:
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
venv/bin/python <<'EOF'
|
|
205
|
+
import sys
|
|
206
|
+
sys.modules['DaVinciResolveScript'] = type(sys)('DaVinciResolveScript')
|
|
207
|
+
from src.server import dctl
|
|
208
|
+
# Regular DCTL — refresh-luts to pick up
|
|
209
|
+
gen = dctl('template', {'kind': 'lut_apply', 'name': 'McpSmokeLut'})
|
|
210
|
+
dctl('install', {'name': 'McpSmokeLut', 'source': gen['source'],
|
|
211
|
+
'subdir': 'MCP', 'overwrite': True})
|
|
212
|
+
# ACES IDT — restart Resolve to pick up
|
|
213
|
+
gen = dctl('template', {'kind': 'aces_idt', 'name': 'McpSmokeIdt'})
|
|
214
|
+
dctl('install', {'name': 'McpSmokeIdt', 'source': gen['source'],
|
|
215
|
+
'category': gen['suggested_category'], 'overwrite': True})
|
|
216
|
+
EOF
|
|
217
|
+
# Then: project_settings(action='refresh_luts') in your MCP client for the
|
|
218
|
+
# regular one; restart Resolve for the ACES IDT.
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
Cleanup:
|
|
222
|
+
|
|
223
|
+
```bash
|
|
224
|
+
venv/bin/python -c "
|
|
225
|
+
import sys
|
|
226
|
+
sys.modules['DaVinciResolveScript'] = type(sys)('DaVinciResolveScript')
|
|
227
|
+
from src.server import fuse_plugin, dctl
|
|
228
|
+
for n in ('McpSmokeTextoverlay', 'McpSmokeDctlkernel',
|
|
229
|
+
'McpSmokePointmodifier', 'McpSmokeVariableblur'):
|
|
230
|
+
print(fuse_plugin('remove', {'name': n}))
|
|
231
|
+
print(dctl('remove', {'name': 'McpSmokeLut', 'subdir': 'MCP'}))
|
|
232
|
+
print(dctl('remove', {'name': 'McpSmokeIdt', 'category': 'aces_idt'}))
|
|
233
|
+
"
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
## Source media integrity
|
|
237
|
+
|
|
238
|
+
These tools write into Resolve's plugin and LUT directories. They do not
|
|
239
|
+
touch source media. Effects authored with these tools modify Resolve's
|
|
240
|
+
grade/render pipeline, not the original camera files. Do not bake template
|
|
241
|
+
effects into source media, create rendered derivatives, or export/reimport
|
|
242
|
+
processed media unless the user explicitly asks for that workflow.
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
# Script Plugin Authoring & Conversational Resolve Scripting
|
|
2
|
+
|
|
3
|
+
The `script_plugin` compound tool (introduced in v2.5.0) generates, installs,
|
|
4
|
+
and **executes** Resolve-page Lua/Python scripts. It closes the conversational
|
|
5
|
+
loop: an LLM with access to the MCP can describe a workflow, generate the
|
|
6
|
+
script, install it as a Resolve menu item, and execute it — all in one turn —
|
|
7
|
+
with the script's stdout streamed back into the conversation.
|
|
8
|
+
|
|
9
|
+
Unlike `fuse_plugin` (which authors Fusion image-processing tools) and `dctl`
|
|
10
|
+
(which authors color-page shaders), `script_plugin` targets the
|
|
11
|
+
**Workspace → Scripts** menu — the user-facing surface for general Resolve
|
|
12
|
+
automation.
|
|
13
|
+
|
|
14
|
+
## When to use what
|
|
15
|
+
|
|
16
|
+
| Goal | Use |
|
|
17
|
+
|---|---|
|
|
18
|
+
| One-off conversational query against Resolve | `script_plugin('run_inline', ...)` |
|
|
19
|
+
| Custom workflow you want as a permanent menu item | `script_plugin('install', ...)` then `('execute', ...)` |
|
|
20
|
+
| Image-processing node for the Fusion page | `fuse_plugin` |
|
|
21
|
+
| Color-page programmable transform | `dctl` |
|
|
22
|
+
| Anything the existing 28 wrapped Resolve API tools already cover | The wrapped tool — no scripting needed |
|
|
23
|
+
|
|
24
|
+
## Two template kinds
|
|
25
|
+
|
|
26
|
+
### `scaffold`
|
|
27
|
+
Minimal stub. Connects to Resolve, gets `resolve` / `project` / `mp` /
|
|
28
|
+
`timeline` handles, defines an empty `main()`. For when the LLM wants to
|
|
29
|
+
write everything from scratch.
|
|
30
|
+
|
|
31
|
+
### `media_rules`
|
|
32
|
+
The rules-and-variables DSL. Generates a self-contained script with three
|
|
33
|
+
top sections (VARIABLES, ENGINE GLOBALS, RULES) followed by an embedded
|
|
34
|
+
~300-line engine that interprets the rules. The LLM (or user) edits the
|
|
35
|
+
RULES table; the engine handles execution.
|
|
36
|
+
|
|
37
|
+
**Rules** are dicts with shape:
|
|
38
|
+
```lua
|
|
39
|
+
{
|
|
40
|
+
name = "rule description",
|
|
41
|
+
target = "media_pool_clips", -- scope
|
|
42
|
+
extract = { -- pull values from each item
|
|
43
|
+
{ source = "file_path", pattern = "DATE_PATTERN",
|
|
44
|
+
into = {"yr", "mo", "dy"} },
|
|
45
|
+
},
|
|
46
|
+
apply = { -- side effects driven by the captures
|
|
47
|
+
{ type = "set_metadata", field = "Shoot Date",
|
|
48
|
+
value = "{yr}-{mo}-{dy}" },
|
|
49
|
+
},
|
|
50
|
+
condition = function(vars) return ... end, -- optional
|
|
51
|
+
enabled = true, -- optional
|
|
52
|
+
stop_on_match = false, -- optional
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## DSL coverage
|
|
57
|
+
|
|
58
|
+
### Sources (where data comes from)
|
|
59
|
+
`file_path`, `filename`, `dirname`, `parent_dir`, `grandparent_dir`,
|
|
60
|
+
`file_extension`, `path_segment:N`, `clip_property:<Field>`,
|
|
61
|
+
`metadata:<Field>`, `embedded_metadata:<Field>`, `camera_metadata:<Field>`,
|
|
62
|
+
`previous_capture:<rule_id>`, `static_value`, `bin_name`, `media_pool_path`,
|
|
63
|
+
`clip_duration`, `clip_resolution`, `frame_rate`, `codec`, `audio_channels`,
|
|
64
|
+
`audio_format`, `start_tc`, `end_tc`, `creation_time`, `modification_time`,
|
|
65
|
+
`external_data:<column>` (loaded from CSV/JSON).
|
|
66
|
+
|
|
67
|
+
### Actions (what to do)
|
|
68
|
+
`set_metadata`, `set_clip_property`, `rename_clip`, `move_to_bin`,
|
|
69
|
+
`set_clip_color`, `flag_clip`, `add_keyword`, `add_marker`, `apply_lut`,
|
|
70
|
+
`set_in_out`, `tag_for_review`, `notify` / `print`.
|
|
71
|
+
|
|
72
|
+
### Targets (scope)
|
|
73
|
+
`media_pool_clips`, `current_bin_clips`, `bin_path:<path>`,
|
|
74
|
+
`selected_clips`, `timeline_items`, `selected_timeline_items`,
|
|
75
|
+
`unmatched_clips`, `clips_matching:<predicate>`, `timeline_items_in_track:N`.
|
|
76
|
+
|
|
77
|
+
### Transforms (variable pipes)
|
|
78
|
+
Plain substitution `{var}`, plus pipes: `upper`, `lower`, `title`, `slug`,
|
|
79
|
+
`pad(n, char)`, `lookup(table_name)`, `add(n)`, `sub(n)`, `mul(n)`, `div(n)`,
|
|
80
|
+
`date(format)`. Chainable: `{var | upper | slug}`.
|
|
81
|
+
|
|
82
|
+
### Engine globals
|
|
83
|
+
`DRY_RUN`, `LOG_LEVEL`, `LIMIT_TO_FIRST_N`, `EXTERNAL_DATA`,
|
|
84
|
+
`BACKUP_BEFORE_RUN`.
|
|
85
|
+
|
|
86
|
+
### External data (the killer feature)
|
|
87
|
+
`EXTERNAL_DATA = { csv = "/path/to/sheet.csv", match_on = {...} }` lets
|
|
88
|
+
rules reference any column in a spreadsheet via `external_data:<column>`.
|
|
89
|
+
Match strategies: `exact`, `regex`, `fuzzy` (Levenshtein nearest match —
|
|
90
|
+
useful for filename variations).
|
|
91
|
+
|
|
92
|
+
Real-world example: a script supervisor's CSV with Filename, Scene, Take,
|
|
93
|
+
Camera, Lens columns. Single rule maps each clip to its row and populates
|
|
94
|
+
all metadata fields plus organizes into Scene bins. Six lines of RULES.
|
|
95
|
+
|
|
96
|
+
## Conversational execution: `run_inline` and `execute`
|
|
97
|
+
|
|
98
|
+
The two actions that close the loop:
|
|
99
|
+
|
|
100
|
+
### `run_inline(source, language, timeout?)`
|
|
101
|
+
Run an ad-hoc Lua or Python snippet inside Resolve, get stdout + return
|
|
102
|
+
value back. No file persistence.
|
|
103
|
+
|
|
104
|
+
**Python**: writes source to a temp file with `resolve`/`project`/`mp`/
|
|
105
|
+
`timeline` pre-bound, runs as subprocess, captures stdout/stderr.
|
|
106
|
+
|
|
107
|
+
**Lua**: wraps source so `print()` is intercepted into a buffer, runs via
|
|
108
|
+
`fusion.RunScript()`, polls a completion sentinel, reads stdout + return
|
|
109
|
+
value back via `app:SetData()`/`fusion.GetData()`. (Note: `fusion.Execute()`
|
|
110
|
+
from the Python bridge is a no-op in Resolve 20.x — `RunScript()` against a
|
|
111
|
+
file is the only working path. The implementation handles this.)
|
|
112
|
+
|
|
113
|
+
Example:
|
|
114
|
+
```python
|
|
115
|
+
script_plugin('run_inline', {
|
|
116
|
+
'source': '''
|
|
117
|
+
print(f"Project: {project.GetName()}")
|
|
118
|
+
print(f"Bins: {len(mp.GetRootFolder().GetSubFolderList() or [])}")
|
|
119
|
+
''',
|
|
120
|
+
'language': 'py',
|
|
121
|
+
})
|
|
122
|
+
# → {success: True, stdout: "Project: My Show\nBins: 12\n", exit_code: 0}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### `execute(name, category, language, args?, timeout?)`
|
|
126
|
+
Run an installed script. Same return shape as `run_inline`.
|
|
127
|
+
|
|
128
|
+
**Python**: subprocess captures full stdout/stderr.
|
|
129
|
+
**Lua**: `fusion.RunScript()`; print() output goes to Resolve Console
|
|
130
|
+
(can't capture). For Lua scripts that need to return data, have them write
|
|
131
|
+
to `app:SetData()` and the caller reads via the existing `fusion_comp`
|
|
132
|
+
tooling.
|
|
133
|
+
|
|
134
|
+
## Install paths
|
|
135
|
+
|
|
136
|
+
Resolve scans these subdirs for the **Workspace → Scripts → \<category\>** menu:
|
|
137
|
+
|
|
138
|
+
| Platform | Root |
|
|
139
|
+
|---|---|
|
|
140
|
+
| macOS | `~/Library/Application Support/Blackmagic Design/DaVinci Resolve/Fusion/Scripts/<category>/` |
|
|
141
|
+
| Windows | `%APPDATA%\Blackmagic Design\DaVinci Resolve\Support\Fusion\Scripts\<category>\` |
|
|
142
|
+
| Linux | `~/.local/share/DaVinciResolve/Fusion/Scripts/<category>/` |
|
|
143
|
+
|
|
144
|
+
Categories: `Edit`, `Color`, `Deliver`, `Comp`, `Tool`, `Utility`, `Views`.
|
|
145
|
+
`Utility` shows up everywhere; the others only on the matching page.
|
|
146
|
+
|
|
147
|
+
Resolve picks up new scripts **without a restart** — the menu refreshes each
|
|
148
|
+
time it's opened.
|
|
149
|
+
|
|
150
|
+
## Languages
|
|
151
|
+
|
|
152
|
+
Both Lua and Python are first-class. Lua is Fusion-native; Python is more
|
|
153
|
+
familiar for data-heavy workflows. The same RULES table syntax works in both
|
|
154
|
+
(Lua tables vs. Python dicts).
|
|
155
|
+
|
|
156
|
+
## Live verification
|
|
157
|
+
|
|
158
|
+
Verified on DaVinci Resolve Studio 20.3.2.9, macOS:
|
|
159
|
+
|
|
160
|
+
- ✅ Scripts appear in Workspace → Scripts → \<category\> after install (no restart needed)
|
|
161
|
+
- ⚠️ Installed Lua script execution via `fusion.RunScript(path)` can return
|
|
162
|
+
`False` from the Python bridge even when install/read/list/remove work. Use
|
|
163
|
+
`run_inline(language="lua")` when captured output or return values matter.
|
|
164
|
+
- ✅ Python scripts execute via subprocess with full stdout/stderr capture
|
|
165
|
+
- ✅ `run_inline` Lua: stdout captured (with tabs), return value captured, errors trapped with line numbers
|
|
166
|
+
- ✅ `run_inline` Python: full Resolve API access, project + media-pool + timeline pre-bound
|
|
167
|
+
- ✅ Both engines (Lua and Python) compile without errors
|
|
168
|
+
- ✅ DSL coverage tests confirm every documented source/action/target/transform/strategy is present in both engines
|
|
169
|
+
|
|
170
|
+
## Implementation notes (for maintainers)
|
|
171
|
+
|
|
172
|
+
Two non-obvious behaviors of Resolve's Lua bridge surfaced during live
|
|
173
|
+
testing and are encoded in the implementation:
|
|
174
|
+
|
|
175
|
+
1. **`fusion.Execute(luaSource)` is a no-op** when called from the Python
|
|
176
|
+
`DaVinciResolveScript` bridge in Resolve 20.x. It returns `None` and has
|
|
177
|
+
no observable side effects. Don't use it. Use `fusion.RunScript(filepath)`
|
|
178
|
+
against a temp file instead.
|
|
179
|
+
|
|
180
|
+
2. **`fusion.RunScript()` is asynchronous.** It returns before the script
|
|
181
|
+
finishes. Reading `fusion.GetData()` immediately gives stale values. The
|
|
182
|
+
implementation polls a completion-sentinel slot (`__mcp_done__`) until
|
|
183
|
+
the wrapped Lua sets it to `"1"`, then reads results.
|
|
184
|
+
|
|
185
|
+
These constraints are unique to the Lua side; Python's subprocess approach
|
|
186
|
+
is straightforwardly synchronous.
|
|
187
|
+
|
|
188
|
+
## Source media integrity
|
|
189
|
+
|
|
190
|
+
These tools generate workflows that READ Resolve's media-pool and timeline
|
|
191
|
+
state and WRITE metadata, bin organization, markers, and similar
|
|
192
|
+
non-destructive properties. The DSL's actions do not modify source files
|
|
193
|
+
on disk. If you build a custom action that exports media, transcodes, or
|
|
194
|
+
otherwise creates derivatives, that's outside the engine's defaults — be
|
|
195
|
+
explicit when authoring such rules.
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Contributing and Project Layout
|
|
2
|
+
|
|
3
|
+
Contributor workflow, platform support, security considerations, and the repository layout.
|
|
4
|
+
|
|
5
|
+
## Contributing
|
|
6
|
+
|
|
7
|
+
We welcome contributions! The following areas especially need help:
|
|
8
|
+
|
|
9
|
+
### Help Wanted: Untested API Methods
|
|
10
|
+
|
|
11
|
+
**5 methods** (1.5%) remain untested against a live DaVinci Resolve instance. If you have access to the required infrastructure or content, we'd love a PR with test confirmation:
|
|
12
|
+
|
|
13
|
+
1. **Cloud Project Methods** (4 methods) — Need DaVinci Resolve cloud infrastructure:
|
|
14
|
+
- `ProjectManager.CreateCloudProject`
|
|
15
|
+
- `ProjectManager.LoadCloudProject`
|
|
16
|
+
- `ProjectManager.ImportCloudProject`
|
|
17
|
+
- `ProjectManager.RestoreCloudProject`
|
|
18
|
+
|
|
19
|
+
2. **HDR Analysis** (1 method) — Needs specific content:
|
|
20
|
+
- `Timeline.AnalyzeDolbyVision` — needs HDR/Dolby Vision content
|
|
21
|
+
|
|
22
|
+
### How to Contribute
|
|
23
|
+
|
|
24
|
+
1. Fork the repository
|
|
25
|
+
2. Create a feature branch (`git checkout -b feature/my-contribution`)
|
|
26
|
+
3. Run the existing test suite to ensure nothing breaks
|
|
27
|
+
4. Add your test results or fixes
|
|
28
|
+
5. Submit a pull request
|
|
29
|
+
|
|
30
|
+
### Other Contribution Ideas
|
|
31
|
+
|
|
32
|
+
- **Windows testing** — All tests were run on macOS; Windows verification welcome
|
|
33
|
+
- **Linux testing** — DaVinci Resolve supports Linux; test coverage needed
|
|
34
|
+
- **Resolve version compatibility** — Test against Resolve 18.x, 19.0, or newer versions
|
|
35
|
+
- **Bug reports** — If a tool returns unexpected results on your setup, file an issue
|
|
36
|
+
- **Documentation** — Improve examples, add tutorials, translate docs
|
|
37
|
+
|
|
38
|
+
## Platform Support
|
|
39
|
+
|
|
40
|
+
| Platform | Status | Resolve Paths Auto-Detected | Notes |
|
|
41
|
+
|----------|--------|----------------------------|-------|
|
|
42
|
+
| macOS | ✅ Tested | `/Library/Application Support/Blackmagic Design/...` | Primary development and test platform |
|
|
43
|
+
| Windows | ✅ Supported | `C:\ProgramData\Blackmagic Design\...` | Community-tested; installer now emits env + `PYTHONHOME` for Resolve 20.3 multi-Python setups |
|
|
44
|
+
| Linux | ⚠️ Experimental | `/opt/resolve/...` | Should work — testing and feedback welcome |
|
|
45
|
+
|
|
46
|
+
## Security Considerations
|
|
47
|
+
|
|
48
|
+
This MCP server controls DaVinci Resolve via its Scripting API. Some tools perform actions that are destructive or interact with the host filesystem:
|
|
49
|
+
|
|
50
|
+
| Tool | Risk | Mitigation |
|
|
51
|
+
|------|------|------------|
|
|
52
|
+
| `quit_app` / `restart_app` | Terminates the Resolve process — can cause data loss if unsaved changes exist or a render is in progress | MCP clients should require explicit user confirmation before calling these tools. Subprocess calls use hardcoded command lists (no shell injection possible). |
|
|
53
|
+
| `export_layout_preset` / `import_layout_preset` / `delete_layout_preset` | Read/write/delete files in the Resolve layout presets directory | Path traversal protection validates all resolved paths stay within the expected presets directory (v2.0.7+). |
|
|
54
|
+
| `save_project` | Creates and removes a temporary `.drp` file in the system temp directory | Path is constructed server-side with no LLM-controlled input. |
|
|
55
|
+
|
|
56
|
+
**Recommendations for MCP client developers:**
|
|
57
|
+
- Enable tool-call confirmation prompts for destructive tools (`quit_app`, `restart_app`, `delete_layout_preset`)
|
|
58
|
+
- Do not grant blanket auto-approval to all tools in this server
|
|
59
|
+
|
|
60
|
+
## Project Structure
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
davinci-resolve-mcp/
|
|
64
|
+
├── install.py # Universal installer (macOS/Windows/Linux)
|
|
65
|
+
├── src/
|
|
66
|
+
│ ├── server.py # Compound MCP server — 32 tools (default)
|
|
67
|
+
│ ├── resolve_mcp_server.py # Thin full-server entrypoint — 329 tools
|
|
68
|
+
│ ├── granular/ # Modular full-server implementation
|
|
69
|
+
│ └── utils/ # Platform detection, Resolve connection helpers
|
|
70
|
+
├── tests/ # 5-phase live API test suite + Resolve 20 delta (331/331 pass)
|
|
71
|
+
├── docs/
|
|
72
|
+
│ ├── README.md # Documentation index
|
|
73
|
+
│ ├── SKILL.md # AI assistant operating reference
|
|
74
|
+
│ ├── guides/ # Media analysis and decision guides
|
|
75
|
+
│ ├── process/ # Release and maintenance process docs
|
|
76
|
+
│ ├── reference/ # Resolve scripting API reference
|
|
77
|
+
│ ├── kernels/ # Maintained workflow support maps
|
|
78
|
+
│ ├── authoring/ # Fuse/DCTL and script authoring references
|
|
79
|
+
│ ├── integrations/ # Resolve-hosted integration references
|
|
80
|
+
│ └── notes/ # Resolve developer-package notes
|
|
81
|
+
└── examples/ # MCP prompt recipes for markers, media, and timeline workflows
|
|
82
|
+
```
|