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,615 @@
1
+ # Media Analysis Guide for DaVinci Resolve MCP
2
+
3
+ This guide teaches AI coding assistants how to use FFprobe, FFmpeg, and Whisper to understand source media files — so the DaVinci Resolve MCP can operate with full context of what the footage actually is.
4
+
5
+ This guide is tool-agnostic. It works with any AI assistant that can run shell commands alongside the MCP server.
6
+
7
+ ---
8
+
9
+ ## The First Rule: Never Touch the Source
10
+
11
+ **This is the foundational, non-negotiable principle.**
12
+
13
+ Your relationship to source media is **READ-ONLY**. Every department in a post-production pipeline depends on an unbroken chain from the camera original files (OCFs) through to final delivery.
14
+
15
+ ### NEVER do any of the following unless the user explicitly requests it:
16
+ - Transcode, convert, or re-encode any media file
17
+ - Create proxies, mezzanines, or lower-resolution copies
18
+ - Export media from Resolve and reimport it
19
+ - Apply LUTs, color transforms, or any processing to files on disk
20
+ - Create rendered versions of timeline segments
21
+ - Modify, rename, move, or reorganize source media files
22
+ - Strip, modify, or rewrite metadata in source files
23
+ - Change timecode in source files
24
+ - Create "optimized" or "analysis-friendly" copies
25
+
26
+ ### ALWAYS limit yourself to:
27
+ - Reading files with FFprobe (metadata extraction — zero disk writes)
28
+ - Analyzing files with FFmpeg using `-f null -` output (read-through analysis — zero disk writes)
29
+ - Writing analysis results to separate sidecar JSON files only
30
+ - Running Whisper transcription that writes only to an analysis directory
31
+ - Creating sampled frames/contact sheets only for visual analysis workflows, only
32
+ in a designated analysis directory. The `analyze_media` prompt defaults
33
+ visual analysis on when chat-context vision is supported; pass
34
+ `include_visuals=false` to opt out.
35
+
36
+ ### Why This Matters
37
+
38
+ - **Assistant Editor:** Every transcode introduces a generation loss. Every conversion makes assumptions about color space, bit depth, and timecode that may be wrong. An unauthorized proxy that doesn't match source timecode breaks the online conform.
39
+ - **Editor:** The edit is discovered from the real footage. Analysis informs creative decisions without creating derivatives that confuse the media pool or timeline.
40
+ - **Colorist:** The grade starts with every bit of dynamic range the camera captured. A transcode bakes in assumptions about color space and gamma. Once latitude is lost, it's gone forever.
41
+ - **Online Editor:** The entire conform workflow traces back to OCFs. Exported-and-reimported media looks like the original but breaks the file path, media hash, and metadata chain.
42
+ - **Producer:** Distributors trace chain of custody back to camera originals. Unauthorized derivatives risk QC failure, E&O issues, and delivery rejection.
43
+
44
+ ### The Only Exception
45
+
46
+ If the user explicitly requests a derivative ("make me a proxy," "transcode this to ProRes"), then:
47
+ - Confirm the request before executing
48
+ - Clearly label the output as a derivative
49
+ - Never overwrite or replace the original
50
+ - Document what was created and where
51
+ - Preserve all metadata including timecode
52
+
53
+ ---
54
+
55
+ ## Setup: First Interaction
56
+
57
+ On first use, determine:
58
+
59
+ ### 1. Where should analysis files be saved?
60
+ - **alongside** — Sidecar files next to each media file (e.g., `clip.mov` -> `clip.mov.analysis.json`)
61
+ - **directory** — A central analysis directory (default: `~/resolve-media-analysis/`)
62
+ - **project** — Inside a `.analysis/` folder within the Resolve project's media folder
63
+
64
+ If source media is on read-only storage (camera cards, SAN volumes), use `directory` or `project`.
65
+
66
+ ### 2. What tools are available?
67
+
68
+ Check automatically:
69
+ ```bash
70
+ # Required
71
+ which ffprobe && ffprobe -version 2>&1 | head -1
72
+
73
+ # Optional — enhanced analysis
74
+ which ffmpeg && ffmpeg -version 2>&1 | head -1
75
+
76
+ # Optional — transcription
77
+ which whisper 2>/dev/null || which whisper-cpp 2>/dev/null || python3 -c "import whisper" 2>/dev/null
78
+ ```
79
+
80
+ FFprobe is required. If missing:
81
+ - macOS: `brew install ffmpeg`
82
+ - Linux: `sudo apt install ffmpeg` or `sudo dnf install ffmpeg`
83
+ - Windows: Download from https://ffmpeg.org
84
+
85
+ ### 3. Analysis depth preference
86
+ - **quick** — FFprobe metadata only (~1 second per file)
87
+ - **standard** — Metadata, loudness, full-stream scene detection, cut-boundary
88
+ analysis, flash-frame candidates, motion/variance scoring, and analysis
89
+ keyframes (~30-60 seconds per file)
90
+ - **deep** — Standard analysis plus transcription and expanded visual sampling
91
+ when chat-context vision is available (~2-5 minutes per file)
92
+
93
+ ---
94
+
95
+ ## Analysis Commands
96
+
97
+ Every command below is read-only. None write to the source file.
98
+
99
+ ### FFprobe: Technical Metadata (Required)
100
+
101
+ ```bash
102
+ ffprobe -v quiet -print_format json -show_format -show_streams -show_chapters "INPUT_FILE"
103
+ ```
104
+
105
+ Extract and structure:
106
+ - **Video**: codec, profile, level, pixel format, bit depth, resolution, frame rate, scan type (progressive/interlaced), color primaries, transfer characteristics, matrix coefficients, HDR metadata
107
+ - **Audio**: codec, sample rate, channels, channel layout, bit depth
108
+ - **Container**: format, duration, overall bitrate, timecode (if present)
109
+ - **Chapters**: timestamps and titles
110
+
111
+ For frame rate, distinguish between `r_frame_rate` (container) and `avg_frame_rate` (actual). Flag VFR if they differ significantly.
112
+
113
+ ### FFmpeg: Content Analysis (Optional)
114
+
115
+ All commands use `-f null -` as output — read-through analysis, zero disk writes.
116
+
117
+ **Loudness (EBU R128):**
118
+ ```bash
119
+ ffmpeg -i "INPUT_FILE" -af ebur128=peak=true -f null - 2>&1 | tail -30
120
+ ```
121
+
122
+ **Scene Detection:**
123
+ ```bash
124
+ ffmpeg -i "INPUT_FILE" -filter:v "select='gt(scene,0.3)',showinfo" -f null - 2>&1 | grep "showinfo"
125
+ ```
126
+
127
+ Scene detection is a full-stream read. Standard/deep analysis turns the detected
128
+ times into cut-boundary evidence: one frame before and one frame after each
129
+ candidate cut, first/last usable clip frames, and short adjacent scene ranges
130
+ that may be flash frames. Those candidates are advisory until visual review
131
+ checks whether the boundary is a true edit, a flash/title/black insertion, or a
132
+ high-motion moment inside one continuous shot.
133
+
134
+ **Black Frame Detection:**
135
+ ```bash
136
+ ffmpeg -i "INPUT_FILE" -vf blackdetect=d=0.5:pix_th=0.10 -f null - 2>&1 | grep "blackdetect"
137
+ ```
138
+
139
+ **Silence Detection:**
140
+ ```bash
141
+ ffmpeg -i "INPUT_FILE" -af silencedetect=noise=-50dB:d=1 -f null - 2>&1 | grep "silence"
142
+ ```
143
+
144
+ ### Sync Event Detection
145
+
146
+ Use `media_analysis(action="detect_sync_events")` when the task is to find
147
+ advisory sync points in deliverables, single-camera footage, dual-system sound,
148
+ or multicam source clips.
149
+
150
+ The detector is source-safe:
151
+
152
+ - It uses FFprobe for metadata and FFmpeg to decode source audio to in-memory
153
+ mono samples.
154
+ - It writes no media files, proxies, renders, or derivatives.
155
+ - It returns likely 1 kHz 2-pops, slate-clap transients, frame/timecode
156
+ positions when frame rate/timecode are known, and per-file record-offset
157
+ suggestions.
158
+ - It returns marker suggestions for Media Pool clips, but never writes markers
159
+ during detection.
160
+ - It does not install FFmpeg automatically. If `ffmpeg` or `ffprobe` is missing,
161
+ report the missing optional dependency and suggest installing FFmpeg.
162
+
163
+ Analyze explicit files:
164
+
165
+ ```json
166
+ {
167
+ "action": "detect_sync_events",
168
+ "params": {
169
+ "paths": ["/path/to/camera_a.mov", "/path/to/camera_b.mov"],
170
+ "fps": 24,
171
+ "event_types": ["two_pop", "slate_clap"],
172
+ "scan_start_seconds": 30,
173
+ "scan_tail_seconds": 30,
174
+ "prefer_event_type": "slate_clap"
175
+ }
176
+ }
177
+ ```
178
+
179
+ Analyze selected Media Pool clips:
180
+
181
+ ```json
182
+ {
183
+ "action": "detect_sync_events",
184
+ "params": {
185
+ "target": "selected",
186
+ "prefer_event_type": "slate_clap"
187
+ }
188
+ }
189
+ ```
190
+
191
+ For multicam prep, use `alignment.suggestions[].suggested_record_offset_frames`
192
+ as per-angle `record_offset` values with
193
+ `media_pool(action="setup_multicam_timeline", sync_mode="record_frame")`, then
194
+ verify sync in Resolve before converting the setup timeline to a native multicam
195
+ clip.
196
+
197
+ To add source-frame Media Pool markers from detected sync events, first show the
198
+ user the marker suggestions. Only after the user approves, call:
199
+
200
+ ```json
201
+ {
202
+ "action": "add_sync_event_markers",
203
+ "params": {
204
+ "target": "selected",
205
+ "prefer_event_type": "slate_clap",
206
+ "confirm": true
207
+ }
208
+ }
209
+ ```
210
+
211
+ If you already have a detection result, pass it back as `detection` with
212
+ `confirm=true`. Raw file-path detections cannot be marked in Resolve unless
213
+ they are tied to Media Pool clips.
214
+
215
+ ### Publishing Analysis Back To Resolve Metadata
216
+
217
+ Use `media_analysis(action="publish_clip_metadata")` when analysis should become
218
+ searchable and usable inside Resolve's own Media Pool metadata views, smart bins,
219
+ and filters.
220
+
221
+ The publish step is a separate Resolve-project mutation. It does not modify
222
+ source media, but it does write to the Resolve project database, so it defaults
223
+ to `dry_run=true` and requires `confirm=true` before writing.
224
+
225
+ Recommended dry-run:
226
+
227
+ ```json
228
+ {
229
+ "action": "publish_clip_metadata",
230
+ "params": {
231
+ "target": "selected",
232
+ "fields": ["Description", "Comments", "Keywords", "People"],
233
+ "merge_policy": "append_relevant",
234
+ "vision": {"enabled": true, "provider": "chat_context"},
235
+ "slate_detection": {"enabled": true, "use_vision": true},
236
+ "dry_run": true
237
+ }
238
+ }
239
+ ```
240
+
241
+ After reviewing the proposed field changes, confirm only if the target clips and
242
+ merge results are correct:
243
+
244
+ ```json
245
+ {
246
+ "action": "publish_clip_metadata",
247
+ "params": {
248
+ "target": "selected",
249
+ "fields": ["Description", "Comments", "Keywords", "People", "Scene", "Shot", "Take", "Camera #"],
250
+ "merge_policy": "append_relevant",
251
+ "slate_detection": {"enabled": true, "use_vision": true},
252
+ "dry_run": false,
253
+ "confirm": true
254
+ }
255
+ }
256
+ ```
257
+
258
+ Field policies are conservative by default:
259
+
260
+ - `Description` and `Comments` preserve existing text and update an MCP-owned
261
+ analysis block.
262
+ - `Keywords` and `People` are list-merged with case-insensitive de-duplication.
263
+ - `Scene`, `Shot`, `Take`, `Camera #`, and roll/card fields are fill-empty fields
264
+ unless the caller explicitly requests overwrite behavior.
265
+ - Machine provenance is written to third-party metadata using
266
+ `davinci_resolve_mcp.*` keys so future runs can check report path, signature,
267
+ publish timestamp, publisher version, and changed fields.
268
+ - Source-time observations can optionally be written as Media Pool clip markers
269
+ by calling `publish_clip_metadata` with `write_markers=true`. This is off by
270
+ default; without that flag, best moments, sync events, and warnings remain in
271
+ the analysis JSON and metadata text rather than becoming Resolve markers.
272
+ - If no timed-marker choice or saved default exists, `publish_clip_metadata`
273
+ returns a `timed_marker_prompt` with four choices: `yes`, `no`,
274
+ `default_yes`, and `default_no`. The default choices persist locally for
275
+ future publishes; actual Resolve writes still require `confirm=true`.
276
+ - Conversation-level defaults can also be managed through
277
+ `setup(action="get_defaults")` and `setup(action="set_defaults")`. For
278
+ example, pass
279
+ `{"defaults":{"media_analysis":{"timed_markers_default":"default_no"}}}` to
280
+ make timed markers opt-in without waiting for the next publish prompt.
281
+ The setup tool also stores defaults for slate detection, chat-context vision,
282
+ transcription, session-only vs persisted reports, metadata field lists,
283
+ metadata overwrite policy, timed-marker types/colors/counts, confidence/time
284
+ note reporting, summary style, report format, preferred analysis roots,
285
+ generated-media folders, post-operation page preference, marker custom-data
286
+ style, and dry-run-first behavior. These defaults shape future analysis calls
287
+ but do not remove the `confirm=true` requirement for Resolve project writes.
288
+
289
+ When slate detection is enabled, the helper first looks for likely audio clap
290
+ cues with the source-safe sync detector, then checks temporary frames around the
291
+ cue before publishing slate-specific metadata or markers. Audio-only detections
292
+ remain sync evidence; they do not become slate keywords, slate comments, slate
293
+ fields, or slate markers unless visual review confirms that a slate or clapper
294
+ is actually present. Only high-confidence visual slate reads are proposed for
295
+ structured fields; lower-confidence reads stay out of structured writeback.
296
+
297
+ When visual analysis is requested for metadata publishing, `Description` and
298
+ editorial `Comments` are generated from successful visual analysis rather than
299
+ falling back to filename/duration/motion summaries. If the MCP client cannot
300
+ provide chat-context vision for that request, the publish result reports the
301
+ visual skip and leaves those descriptive fields unchanged.
302
+
303
+ ### Clip Marker JSON And Sequence Analysis
304
+
305
+ Executed media analysis writes `clip_analysis_markers.json` beside each
306
+ `analysis.json` report under the project analysis root. This JSON is the durable
307
+ edit-intelligence layer: shot ranges, black/title/QC ranges, best moments, visual
308
+ descriptions, sound notes, transcript excerpts, word-timestamp availability,
309
+ color intent, and timeline occurrences when the clip came from a sequence.
310
+
311
+ Resolve Media Pool clip markers are optional writeback, not the source of truth.
312
+ Only `publish_clip_metadata` with marker writeback enabled and confirmed should
313
+ add markers to the Resolve project. Analysis itself should produce JSON marker
314
+ plans without mutating the project.
315
+
316
+ Use `media_analysis(action="analyze_bin")` for a bin of source clips. Use
317
+ `media_analysis(action="analyze_sequence")` or target `"sequence"`/`"timeline"`
318
+ when the task is to understand an existing edit; the sequence target analyzes
319
+ the distinct Media Pool assets used on the timeline and records each timeline
320
+ occurrence as structured data for later cutdown, adjustment, or recommendation
321
+ work.
322
+
323
+ ### Local SQLite Analysis Index
324
+
325
+ For large single-user projects, the derived SQLite index is built automatically
326
+ after persisted analysis reports are written. Durable batch jobs refresh the
327
+ index after each successful slice, so search becomes useful as soon as the first
328
+ clip is analyzed instead of waiting for a long job to finish.
329
+
330
+ Use the explicit build action when you want to repair or fully rebuild the cache
331
+ from existing reports:
332
+
333
+ ```json
334
+ {"action": "build_index", "params": {"analysis_root": "/path/to/analysis-root"}}
335
+ ```
336
+
337
+ The database is stored as `index.sqlite` beside `manifest.json` and
338
+ `project_summary.json` under the project analysis root. The JSON reports remain
339
+ the source of truth; the SQLite index is a rebuildable cache for searching clips,
340
+ markers, transcript segments, visual tags, timeline occurrences, warnings, and
341
+ computed keyframe metrics.
342
+
343
+ Use `media_analysis(action="index_status")` to inspect row counts and size. Use
344
+ `media_analysis(action="query_index", params={"query": "quiet reflective b-roll"})`
345
+ to search indexed clip summaries, marker descriptions, and transcript text.
346
+
347
+ Do not store sampled frames or contact sheets in SQLite. The index stores
348
+ text/metadata only; generated frame files remain disposable artifacts under the
349
+ analysis root and can be removed with `cleanup_artifacts(frames_only=true)`.
350
+
351
+ ### Batch Jobs And Local Dashboard
352
+
353
+ For long runs, prefer durable batch jobs over one large analysis call. A job
354
+ stores operational state in `jobs.sqlite` under the same project analysis root
355
+ as the reports and index. Each slice processes a bounded number of clips, exits
356
+ cleanly, and can be resumed by a later agent or dashboard action.
357
+
358
+ Resolve-aware MCP workflow:
359
+
360
+ ```json
361
+ {"action": "start_batch_job", "params": {"target": {"type": "bin", "path": "Master/Day 01"}, "depth": "standard"}}
362
+ ```
363
+
364
+ ```json
365
+ {"action": "run_batch_job_slice", "params": {"job_id": "job-...", "max_clips": 1}}
366
+ ```
367
+
368
+ ```json
369
+ {"action": "batch_job_status", "params": {"job_id": "job-..."}}
370
+ ```
371
+
372
+ Use `list_batch_jobs`, `cancel_batch_job`, and `resume_batch_job` for operations
373
+ around the same project analysis root. Jobs refresh the SQLite search index
374
+ after each successful analyzed or reused clip, and completed jobs do a final
375
+ rebuild if needed. Pass `auto_build_index=false` when creating the job to disable
376
+ that behavior.
377
+
378
+ Standalone local dashboard:
379
+
380
+ ```bash
381
+ venv/bin/python -m src.analysis_dashboard --analysis-root ~/Documents/davinci-resolve-mcp-analysis --open
382
+ ```
383
+
384
+ The dashboard can create file/folder jobs without Resolve open, run one clip
385
+ slice at a time or auto-run slices, inspect recent events, build the local
386
+ index, and query completed analysis. Chat-context visual analysis still requires
387
+ the MCP request path because the standalone dashboard cannot call the host
388
+ chat/sampling model. It is intentionally single-user and local; it does not
389
+ provide authentication, multi-user locking, media playback, or image storage in
390
+ SQLite.
391
+
392
+ ### Mapping Resolve Metadata Fields
393
+
394
+ Use `media_pool(action="metadata_field_inventory")` before expanding metadata
395
+ writeback beyond the default analysis fields. The probe is read-only and reports
396
+ three distinct surfaces for selected or explicit Media Pool clips:
397
+
398
+ - `GetMetadata("")`: project metadata values that have been explicitly written
399
+ or are otherwise exposed through Resolve's metadata API.
400
+ - `GetClipProperty("")`: the larger clip-property map that usually mirrors the
401
+ fields visible in Resolve's Metadata panel.
402
+ - Inferred Metadata-panel groups such as `Shot & Scene`, `Camera`, `Audio`,
403
+ `Production`, and `Reviewed By`.
404
+
405
+ Resolve does not expose a guaranteed public schema for the Metadata panel group
406
+ layout, and field names can differ subtly between the UI and scripting surfaces.
407
+ For example, the UI may show `Keywords` while `GetClipProperty("")` exposes
408
+ `Keyword`; live validation on Resolve Studio 20.3 showed that writeback should
409
+ still call `SetMetadata("Keywords", value)`. Likewise, slate roll/card values
410
+ should write to `Roll Card #` even when older helper code or UI/property maps use
411
+ `Roll/Card`. The probe reports aliases and marks this group map as best-effort.
412
+
413
+ For live validation against a disposable synthetic project, run:
414
+
415
+ ```bash
416
+ venv/bin/python tests/live_metadata_field_inventory_validation.py --output-dir /tmp/resolve-metadata-field-probe
417
+ ```
418
+
419
+ That harness compares `metadata_field_inventory`, `MediaPool.ExportMetadata()`,
420
+ and `SetMetadata()` readback without touching user source media. Use a Resolve
421
+ scripting-compatible Python 3.10-3.12 environment for the live run.
422
+
423
+ **Interlace Detection:**
424
+ ```bash
425
+ ffmpeg -i "INPUT_FILE" -vf idet -frames:v 500 -f null - 2>&1 | grep "idet"
426
+ ```
427
+
428
+ **Thumbnail Extraction (explicit user approval required; writes to analysis directory ONLY):**
429
+ ```bash
430
+ ffmpeg -i "INPUT_FILE" -vf "select=eq(n\,FRAME_NUM)" -frames:v 1 -q:v 2 "ANALYSIS_DIR/thumbnail.jpg"
431
+ ffmpeg -i "INPUT_FILE" -vf "fps=1/INTERVAL,scale=320:-1,tile=4x4" -frames:v 1 "ANALYSIS_DIR/contact_sheet.jpg"
432
+ ```
433
+
434
+ ### Whisper: Transcription (Optional)
435
+
436
+ ```bash
437
+ # OpenAI Whisper CLI
438
+ whisper "INPUT_FILE" --model base --output_format json --output_dir "ANALYSIS_DIR"
439
+
440
+ # Or whisper-cpp
441
+ whisper-cpp -m /path/to/model -f "INPUT_FILE" --output-json
442
+
443
+ # Or Python whisper
444
+ python3 -c "
445
+ import whisper, json, sys
446
+ model = whisper.load_model('base')
447
+ result = model.transcribe(sys.argv[1])
448
+ print(json.dumps(result, indent=2))
449
+ " "INPUT_FILE"
450
+ ```
451
+
452
+ ---
453
+
454
+ ## Analysis Output Format
455
+
456
+ Save as JSON sidecar files:
457
+
458
+ ```json
459
+ {
460
+ "analysis_version": "1.0",
461
+ "analyzed_at": "2026-03-09T12:00:00Z",
462
+ "source_file": "/path/to/clip.mov",
463
+ "source_file_size_bytes": 1234567890,
464
+ "source_file_modified": "2026-03-01T10:30:00Z",
465
+
466
+ "video": {
467
+ "codec": "prores",
468
+ "codec_long": "Apple ProRes 422 HQ",
469
+ "profile": "3",
470
+ "pixel_format": "yuv422p10le",
471
+ "bit_depth": 10,
472
+ "width": 3840,
473
+ "height": 2160,
474
+ "display_aspect_ratio": "16:9",
475
+ "frame_rate": "23.976",
476
+ "frame_rate_exact": "24000/1001",
477
+ "is_vfr": false,
478
+ "scan_type": "progressive",
479
+ "color_primaries": "bt709",
480
+ "transfer_characteristics": "bt709",
481
+ "matrix_coefficients": "bt709",
482
+ "hdr": null,
483
+ "duration_seconds": 125.5,
484
+ "frame_count": 3010,
485
+ "bitrate_mbps": 220.5
486
+ },
487
+
488
+ "audio": [
489
+ {
490
+ "stream_index": 1,
491
+ "codec": "pcm_s24le",
492
+ "sample_rate": 48000,
493
+ "channels": 2,
494
+ "channel_layout": "stereo",
495
+ "bit_depth": 24,
496
+ "duration_seconds": 125.5
497
+ }
498
+ ],
499
+
500
+ "container": {
501
+ "format": "mov",
502
+ "duration_seconds": 125.5,
503
+ "overall_bitrate_mbps": 225.3,
504
+ "timecode_start": "01:00:00:00",
505
+ "creation_time": "2026-03-01T10:30:00Z"
506
+ },
507
+
508
+ "loudness": {
509
+ "integrated_lufs": -23.1,
510
+ "loudness_range_lu": 12.5,
511
+ "true_peak_dbtp": -1.2
512
+ },
513
+
514
+ "scenes": [
515
+ {"time": 0.0, "score": 0.95},
516
+ {"time": 5.2, "score": 0.45},
517
+ {"time": 12.8, "score": 0.72}
518
+ ],
519
+
520
+ "transcription": {
521
+ "language": "en",
522
+ "text": "Full transcription text...",
523
+ "segments": [
524
+ {"start": 1.2, "end": 3.5, "text": "Hello and welcome..."}
525
+ ]
526
+ }
527
+ }
528
+ ```
529
+
530
+ ---
531
+
532
+ ## Connecting Analysis to the MCP
533
+
534
+ ### Getting File Paths from Resolve
535
+
536
+ Use MCP tools to get file paths from the current project, then analyze them externally:
537
+
538
+ 1. **From media pool clips:** `media_pool_item` -> `get_clip_property(clip_id)` returns `"File Path"`
539
+ 2. **From timeline items:** `timeline_item` -> `get_media_pool_item(item_id)` -> then get clip properties
540
+ 3. **From media storage:** `media_storage` -> `get_files(path)` lists files in a directory
541
+
542
+ ### Workflow: Analyze Before Acting
543
+
544
+ 1. **Identify the media** — Use MCP to get clip IDs and file paths
545
+ 2. **Check for existing analysis** — Look for sidecar JSON files
546
+ 3. **Analyze if needed** — Run FFprobe (+ optional tools) on the files
547
+ 4. **Act with context** — Use MCP tools with full knowledge of what the media is
548
+
549
+ Analysis informs Resolve actions. At no point do we create intermediate files that enter the media pipeline.
550
+
551
+ ### Examples
552
+
553
+ **"Set up my timeline for this footage"**
554
+ - FFprobe reveals 4K ProRes 422 HQ, 23.976fps, Rec.709
555
+ - Use `project_settings` to set timeline resolution, frame rate, and color science
556
+ - Original files stay untouched
557
+
558
+ **"Create markers at scene changes"**
559
+ - Run FFmpeg scene detection (`-f null -` — no output file)
560
+ - Use `timeline_markers` or `media_pool_item_markers` to add markers
561
+ - Analysis writes nothing to source; markers live in Resolve's database
562
+
563
+ **"What are my audio levels?"**
564
+ - Run EBU R128 loudness analysis (`-f null -`)
565
+ - Report current levels vs target (-24 LUFS broadcast, -14 LUFS streaming)
566
+ - Suggest adjustments in Resolve's Fairlight page
567
+
568
+ **"Help me set up color management"**
569
+ - FFprobe reveals ARRI LogC3, wide gamut, 12-bit
570
+ - Recommend ACES IDT or DaVinci Wide Gamut
571
+ - Camera original retains full latitude
572
+
573
+ ---
574
+
575
+ ## What Analysis Enables
576
+
577
+ | Task | Without Analysis | With Analysis |
578
+ |------|-----------------|---------------|
579
+ | Set timeline settings | Guess or ask user | Auto-detect from footage |
580
+ | Color space setup | Default to Rec.709 | Match source (ARRI LogC, S-Log3, etc.) |
581
+ | Audio normalization | Manual measurement | Report LUFS, suggest Fairlight adjustments |
582
+ | Scene-based editing | Manual review | Auto-mark scene changes via MCP markers |
583
+ | Subtitle creation | Use Resolve's built-in | Whisper transcription -> import via MCP |
584
+ | QC checks | Visual inspection | Automated codec/bitrate/level verification |
585
+ | Render settings | Generic defaults | Match source codec/colorspace for delivery |
586
+ | Timecode sync | Manual entry | Extract embedded timecode for reference |
587
+ | VFR detection | Unknown issues | Flag before problems occur in timeline |
588
+ | Mixed-camera projects | Manual identification | Auto-detect cameras, suggest per-clip IDTs |
589
+
590
+ ---
591
+
592
+ ## Proactive Warnings
593
+
594
+ When analysis reveals potential issues, always alert the user:
595
+
596
+ - **VFR** — Variable frame rate detected; Resolve may interpret differently than expected
597
+ - **Mismatched sample rates** — 44.1kHz audio in a 48kHz timeline causes drift
598
+ - **HDR metadata** — HDR10/HLG/Dolby Vision present; color management must account for it
599
+ - **Color space flags** — ARRI LogC3 / S-Log3 / V-Log etc. requires appropriate IDT
600
+ - **Timecode discontinuity** — Multiple clips share starting TC; conform conflicts possible
601
+ - **Interlaced content** — Set deinterlacing mode before editing
602
+ - **Missing audio** — No audio streams detected
603
+ - **Extremely high bitrate** — Verify storage can sustain real-time playback
604
+
605
+ ---
606
+
607
+ ## Key Principles
608
+
609
+ - **The source is sacred.** Read from source files, write only to analysis sidecars unless a visual analysis workflow needs sampled frames/contact sheets in a separate analysis directory. Confirmed metadata publishing writes to Resolve's project database, not source media. `analyze_media` can opt out with `include_visuals=false`.
610
+ - **Respect file paths.** Use exact paths from Resolve or the filesystem.
611
+ - **Cache analysis.** Skip re-analysis if the sidecar is newer than the source.
612
+ - **Report clearly.** Present analysis to inform the user's next action within Resolve.
613
+ - **Timecode matters.** Always extract and report TC — it's the foundation of conform, sync, and delivery.
614
+ - **Handle errors gracefully.** If a file can't be analyzed, report and move on.
615
+ - **Chain of custody is real.** This tool provides intelligence about the source — never creates alternatives to it.