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.
Files changed (92) hide show
  1. package/AGENTS.md +85 -0
  2. package/CHANGELOG.md +802 -0
  3. package/CLAUDE.md +15 -0
  4. package/LICENSE +21 -0
  5. package/README.md +159 -0
  6. package/SECURITY.md +53 -0
  7. package/bin/davinci-resolve-mcp.mjs +376 -0
  8. package/docs/README.md +56 -0
  9. package/docs/SKILL.md +1145 -0
  10. package/docs/authoring/fuse-dctl-authoring.md +242 -0
  11. package/docs/authoring/script-plugin-authoring.md +195 -0
  12. package/docs/contributing.md +82 -0
  13. package/docs/guides/color-decision-guide.md +387 -0
  14. package/docs/guides/editorial-decision-guide.md +136 -0
  15. package/docs/guides/media-analysis-guide.md +615 -0
  16. package/docs/guides/multicam-setup-guide.md +138 -0
  17. package/docs/install.md +198 -0
  18. package/docs/integrations/workflow-integrations.md +120 -0
  19. package/docs/kernels/README.md +28 -0
  20. package/docs/kernels/audio-fairlight-kernel.md +86 -0
  21. package/docs/kernels/color-grade-kernel.md +103 -0
  22. package/docs/kernels/extension-authoring-kernel.md +101 -0
  23. package/docs/kernels/fusion-composition-kernel.md +91 -0
  24. package/docs/kernels/media-pool-ingest-kernel.md +147 -0
  25. package/docs/kernels/project-lifecycle-kernel.md +120 -0
  26. package/docs/kernels/render-deliver-kernel.md +92 -0
  27. package/docs/kernels/review-annotation-kernel.md +110 -0
  28. package/docs/kernels/timeline-conform-interchange-kernel.md +99 -0
  29. package/docs/kernels/timeline-edit-kernel.md +189 -0
  30. package/docs/notes/codec-plugin-notes.md +136 -0
  31. package/docs/notes/dctl-notes.md +234 -0
  32. package/docs/notes/fusion-template-notes.md +136 -0
  33. package/docs/notes/lut-notes.md +136 -0
  34. package/docs/notes/openfx-notes.md +120 -0
  35. package/docs/process/release-process.md +152 -0
  36. package/docs/reference/api-coverage.md +488 -0
  37. package/docs/reference/resolve_scripting_api.txt +1012 -0
  38. package/examples/README.md +53 -0
  39. package/examples/markers/README.md +81 -0
  40. package/examples/media/README.md +94 -0
  41. package/examples/timeline/README.md +98 -0
  42. package/install.py +1196 -0
  43. package/package.json +52 -0
  44. package/scripts/audit_api_parity.py +275 -0
  45. package/scripts/live_media_analysis_polish_probe.py +65 -0
  46. package/src/__init__.py +3 -0
  47. package/src/analysis_dashboard.py +4936 -0
  48. package/src/control_panel.py +13 -0
  49. package/src/granular/__init__.py +17 -0
  50. package/src/granular/common.py +727 -0
  51. package/src/granular/folder.py +287 -0
  52. package/src/granular/gallery.py +306 -0
  53. package/src/granular/graph.py +309 -0
  54. package/src/granular/media_pool.py +679 -0
  55. package/src/granular/media_pool_item.py +852 -0
  56. package/src/granular/media_storage.py +179 -0
  57. package/src/granular/project.py +1594 -0
  58. package/src/granular/resolve_control.py +521 -0
  59. package/src/granular/timeline.py +1074 -0
  60. package/src/granular/timeline_item.py +2251 -0
  61. package/src/resolve_mcp_server.py +43 -0
  62. package/src/server.py +15691 -0
  63. package/src/utils/__init__.py +3 -0
  64. package/src/utils/app_control.py +319 -0
  65. package/src/utils/audio_fairlight_live_probe.py +263 -0
  66. package/src/utils/cdl.py +20 -0
  67. package/src/utils/cloud_operations.py +192 -0
  68. package/src/utils/color_grade_live_probe.py +444 -0
  69. package/src/utils/dctl_templates.py +368 -0
  70. package/src/utils/extension_authoring_live_probe.py +292 -0
  71. package/src/utils/fuse_templates.py +1968 -0
  72. package/src/utils/fusion_composition_live_probe.py +284 -0
  73. package/src/utils/layout_presets.py +333 -0
  74. package/src/utils/mcp_stdio.py +32 -0
  75. package/src/utils/media_analysis.py +3618 -0
  76. package/src/utils/media_analysis_jobs.py +796 -0
  77. package/src/utils/media_pool_ingest_live_probe.py +592 -0
  78. package/src/utils/multicam.py +393 -0
  79. package/src/utils/object_inspection.py +287 -0
  80. package/src/utils/platform.py +157 -0
  81. package/src/utils/project_lifecycle_live_probe.py +376 -0
  82. package/src/utils/project_properties.py +601 -0
  83. package/src/utils/render_deliver_live_probe.py +384 -0
  84. package/src/utils/resolve_connection.py +77 -0
  85. package/src/utils/review_annotation_live_probe.py +352 -0
  86. package/src/utils/script_templates.py +1193 -0
  87. package/src/utils/sync_detection.py +887 -0
  88. package/src/utils/timeline_conform_live_probe.py +280 -0
  89. package/src/utils/timeline_kernel_live_probe.py +1091 -0
  90. package/src/utils/timeline_kernel_probe.py +185 -0
  91. package/src/utils/timeline_title_text.py +87 -0
  92. 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
+ ```