Imported from samuelgursky/davinci-resolve-mcp (
docs/SKILL.md). Install upstream withnpx skills add samuelgursky/davinci-resolve-mcp --skill docs. Copyright stays with the author.
DaVinci Resolve MCP Server — AI Skill Reference
This document gives AI assistants the context needed to use the DaVinci Resolve MCP server effectively. It covers the tool landscape, page prerequisites, common workflow patterns, error recovery, and known gotchas.
What This Server Does
The DaVinci Resolve MCP server bridges AI assistants to DaVinci Resolve Studio via its official Scripting API. You can control every aspect of a post-production session — projects, timelines, clips, color grading, Fusion compositions, audio, render queues, and more — through natural language.
DaVinci Resolve must be running with Preferences > General > "External scripting
using" set to Local, or set to Network with RESOLVE_SCRIPT_HOST
configured to the Resolve host IP (use 127.0.0.1 on the same machine). The
server auto-launches Resolve if it is not running, but that first connection can
take up to 60 seconds.
Free edition. Both of those preferences are Studio features; on the free
edition scriptapp("Resolve") refuses a foreign process regardless. A third
transport reaches it — a script run from Workspace ▸ Scripts is handed the
live resolve object (measured on free 21.0.3.7) and re-exports it over an
authenticated loopback listener. Resolve 21.1 moved Python scripting to Studio:
on free 21.1 the Scripts menu no longer lists .py files (#203), so on that
build expect the bridge to have no launch path until the Console is checked. Install with python scripts/install_resolve_bridge.py and
start it from that menu; once running it is used automatically when external
scripting is unavailable, with no environment variable needed.
DAVINCI_RESOLVE_BRIDGE=1 forces it — the bridge becomes the only transport
tried, so its faults surface directly instead of degrading to another path.
Existing tool call sites work unchanged. Two things to know when diagnosing it:
- On macOS, Resolve finds Python 3 through
PYTHON3HOME, then/usr/local/bin/python3— and nowhere else, so Homebrew/pyenv/uv/conda interpreters simply never appear, with no error. python.org installs work because that installer creates/usr/local/bin/python3; framework-ness itself is not the variable (#143). The sudo-free fix islaunchctl setenv PYTHON3HOME "$(python3 -c 'import sys; print(sys.prefix)')"—launchctl, notexport, because Resolve is GUI-launched and inherits launchd's environment. The installer preflights both routes and ships a Lua canary, which always lists, so "Python not detected" is distinguishable from "wrong folder". The preflight is macOS-only — off macOS Resolve finds Python by other means, and running the check there was a false alarm (#106). Two follow-ups from #182 worth having in hand when a user says the menu is empty despite a setPYTHON3HOME: the prefix needs bothlib/libpython3.X.dylibandbin/python3under that unversioned name (Homebrew framework builds often ship onlypython3.X, so half the check passes on the very interpreter people reach for), andlaunchctl setenvdoes not survive a reboot — a bridge that listed for weeks and then stopped, with no error anywhere, is usually that.sudo ln -s "$(command -v python3)" /usr/local/bin/python3is the persistent alternative. - Windows: both script folders confirmed.
%PROGRAMDATA%(#109) and%APPDATA%(#112) have each been shown serving the bridge on Windows 11 free builds. If a user reports the menu entry missing on Windows, ask whether the Lua canary lists — that separates "wrong folder" from "Python not detected". - A bridge that stops answering while its socket is
LISTENINGis a stale process, not a modal dialog. Before v2.70.3 the Windows bridge could never detect Resolve exiting (os.getppid()does not change there), so it outlived Resolve holding the port and answering with a dead handle — and thebridge_timeoutmessage blamed a modal dialog. On any build, the way out is theshutdownoperation (BridgeClient.bridge_shutdown()); killing the process is the fallback, not the first move. - The control panel connects over the bridge too (fixed in v2.70.2). It runs as a separate process with its own connector, so a panel that reports "Resolve unavailable" while tool calls work is a panel-side bug, not a broken bridge.
- The in-Resolve runtime is a copy taken at install time. After changing the repository, re-run the installer and then ask the running bridge to reload — it re-imports from disk in place, so Resolve does not need restarting.
The bridge is a documented in-app path rather than a licence circumvention, but Blackmagic could close it; treat it as a supported-until-it-is-not tier.
Network scripting permits remote control of Resolve. Use Local mode when remote access is unnecessary; otherwise restrict access with host firewall and network controls.
Session-start update note. The first resolve_control(action="get_version")
of a session returns an mcp block with the cached update check
(mcp.update + mcp.update_decision). If update_decision.action is
"notify" or "prompt", tell the user ONCE that a newer MCP release is
available (version + one-line pointer). Do not repeat it, do not auto-apply,
and do not treat it as an error — updates are applied by the user via
python install.py or the control panel's Settings page. If the user asks to
check on demand, use resolve_control(action="mcp_update_status", params={"force_check": true}).
Workflow Integration plugins/scripts are a separate Resolve-hosted UI mechanism.
They are not required for this MCP server, but docs/integrations/workflow-integrations.md
summarizes when they are useful for optional in-Resolve panels, UIManager
scripts, and render callback companions.
OpenFX plugins are native C++ image-effect plugins, not an MCP control surface.
Use docs/notes/openfx-notes.md when diagnosing insert_ofx_generator failures or
discussing optional OFX plugin development.
LUT files are directly relevant to Color-page graph actions. Use
docs/notes/lut-notes.md when diagnosing graph.set_lut failures, validating .cube
files, or explaining project_settings.refresh_luts.
Fusion templates are relevant to Edit/Cut page insertion actions. Use
docs/notes/fusion-template-notes.md when diagnosing insert_fusion_generator or
insert_fusion_title failures, template paths, .setting files, or .drfx
bundles.
DCTL files are programmable color transforms/effects adjacent to LUT and OpenFX
workflows. Use docs/notes/dctl-notes.md when diagnosing .dctl/.dctle discovery,
ResolveFX DCTL plugin behavior, ACES DCTL IDT/ODT setup, or DCTL-as-LUT usage.
Codec plugins are native IO encode plugins that extend Deliver-page render
formats/codecs. Use docs/notes/codec-plugin-notes.md when diagnosing missing custom
render formats/codecs, .dvcp.bundle packaging, or IOPlugins install paths.
The fuse_plugin, dctl, and script_plugin compound tools (v2.5.0+) write
Fuse plugin source, DCTL files, and Lua/Python scripts into Resolve's install
directories. They are authoring tools — every other tool in this server wraps
Resolve's scripting API, while these three emit and install plugin/script
source. Status: lifecycle-verified in DaVinci Resolve Studio 20.3.2.9 for
MCP-marked install/read/list/remove, regular DCTL refresh_luts, ACES/Fuse
restart-required classification. Script execution — execute and run_inline —
was removed in v3.0.0: this server does not run caller-supplied code. Use
docs/kernels/extension-authoring-kernel.md for the
kernel boundary map, docs/authoring/fuse-dctl-authoring.md for the Fuse + DCTL coverage
matrix, and docs/authoring/script-plugin-authoring.md for the script DSL spec and the
install paths. For hand-authoring .setting template files
(Edit effects/transitions/titles/generators and Fusion macros) — the format,
control catalog, thumbnail conventions, install paths, and gotchas, plus copyable
starter templates — see docs/authoring/setting-files/.
Plugin writes are gated like every other write. install and remove on all
three tools, and script_plugin's safe_install_extension / safe_remove_extension,
are registered destructive actions. An explicit dry_run=true on install or
remove is refused with DRY_RUN_UNAVAILABLE rather than executed — for a real
preview use safe_install_extension / safe_remove_extension, which honour
dry_run themselves. remove is rated HIGH and is blocked while safe mode is on
(allow_risky_operation: true overrides a single call); install is MEDIUM.
Every call is recorded in the security audit log, and none of them archives the
timeline — they write plugin folders, not the project. The probe_*_lifecycle
actions route their installs and cleanup deletes through the same gate.
Extension Authoring kernel actions (v2.16.0+) are exposed through
script_plugin:
extension_capabilitiesprobe_fuse_lifecycle(name?, kind?, install?, cleanup?)probe_dctl_lifecycle(name?, kind?, category?, install?, refresh_luts?, cleanup?)probe_script_lifecycle(name?, language?, category?, install?, cleanup?)safe_install_extension(extension_type, name, source?|kind?, dry_run?)safe_remove_extension(extension_type, name, dry_run?)refresh_or_restart_required(extension_type, category?)extension_boundary_report(include_template_matrix?)
Key behavioral notes for script_plugin:
- No script execution.
run_inlineandexecutewere removed in v3.0.0: this server does not run caller-supplied code, in any form.installputs a script in Resolve's Workspace › Scripts menu; running it is the user's action inside Resolve. For conversational queries against the Resolve API, use the typed tools rather than a script. languageacceptslua,py, or the human-facing aliasespythonandpython3.- Fuse install path on macOS is
…/DaVinci Resolve/Fusion/Fuses/(NOTSupport/Fusion/Fuses/as the SDK doc lists). The MCP path helpers handle this; if you're staging files manually, use the path the implementation emits. - Resolve picks up new scripts without a restart; new Fuses need a restart
to register; new DCTLs need
project_settings(action='refresh_luts')(regular LUT category) or a restart (ACES IDT/ODT category).
Tool metadata (v2.17.1+) includes MCP ToolAnnotations for read-only,
destructive, idempotent, and external-resource hints. Treat compound tool
annotations as conservative because a single compound tool may expose both probe
and mutation actions behind its action parameter. Continue to prefer
safe_*, dry_run, probe_*, capabilities, and boundary_report actions
before mutating Resolve state.
Reading A Result: The Operation Envelope
Every compound tool return carries an _operation block alongside its normal
payload. It answers the three questions that otherwise need a different key per
tool — did it happen, was it verified, what changed:
{
"success": true,
"insert_frame_absolute": 86400,
"shift_frames": 48,
"_operation": {
"status": "success",
"operation": "timeline.ripple_insert",
"execution_id": "exec_d2c123817bee",
"verification": {
"status": "passed",
"checks": [{"check": "readback_verification", "passed": true, "missing_items": 0}],
"contradiction": false
},
"changes": {"items_added": 3, "items_moved": 17, "items_deleted": 0}
}
}
status—success|partial|blocked|failed.blockedmeans a confirm gate is waiting; the payload still carries theconfirm_tokenandpreviewto act on.verification.status—passed|failed|partial|contradiction|unverified.contradictionis the one to stop on: Resolve reported success and the readback disagrees.unverifiedmeans no evidence was reported, not that the operation was checked and found clean — if you need certainty there, go and read the state back.changes— the semantic delta, present only when the action declared or reported one. Absent means "not reported", never "nothing changed", so do not read a missingchangesas a no-op.warnings— present only when there are any.execution_id— correlates one call across logs and transcripts.
The envelope is namespaced under _operation rather than merged into the top
level because status, operation, warnings, result and changes are all
already domain keys on this server (a background job's status is "done", a
confirm gate's is "confirmation_required"). The payload is passed through
untouched; read domain values where you always read them.
Change the shape with setup(action="set_defaults", params={"result_envelope": "pure" | "legacy" | "dual"}),
per call with params={"envelope": "pure"}, or per process with
RESOLVE_MCP_RESULT_ENVELOPE. pure returns only the envelope with the payload
nested under result; legacy adds nothing.
Agent Observability: Execution Traces ("Why did the editor do this?")
Multi-step AI operations (such as detecting pauses, deleting multiple timeline items, and verifying the result) correlate across calls into unified execution traces. Each trace captures the user request or prompt, tool execution timing, cumulative semantic deltas, and verification outcomes.
Example trace shape returned by resolve_control(action="get_execution_trace"):
{
"execution_id": "exec_8f91c7a210bc",
"request": "Remove all pauses longer than 800ms",
"status": "success",
"started_at": "2026-09-04T07:30:00Z",
"ended_at": "2026-09-04T07:30:02Z",
"duration_ms": 2845,
"tools": [
{
"tool": "media_analysis.analyze_timeline",
"count": 1,
"duration_ms": 821
},
{
"tool": "timeline.delete_item",
"count": 17,
"duration_ms": 1420
}
],
"changes": {
"items_deleted": 17
},
"verification": {
"status": "passed",
"passed": true,
"checks": [{"check": "readback_verification", "passed": true}]
},
"warnings": []
}
Trace Actions on resolve_control
-
begin_execution(request?, execution_id?, initiator?): Opens a scoped multi-step execution. Subsequent tool calls in the session automatically thread under thisexecution_iduntil ended. -
end_execution(execution_id?, verification?, status?, notes?): Closes the active execution, finalizes timestamps and aggregated metrics. -
get_execution_trace(execution_id?)/get_execution(execution_id): Fetches the trace for a specific ID, or the most recent execution if omitted. -
list_recent_executions(limit?): Returns the recent execution traces (newest first, default limit 20). -
export_execution_report(execution_id?, format?, path?, overwrite?, include_steps?): Writes a Markdown or JSON audit report for a trace. The default destination islogs/execution-reports/<execution_id>.md; passformat: "json"for structured output,include_steps: falsefor a shorter summary, oroverwrite: trueto replace an existing report. -
clear_executions(dry_run?): Clears the in-memory execution trace buffer. -
inspect_operation(tool?, target_action?, target_params?): Evaluates operation risk level (low,medium,high,critical), destructive potential, confirmation requirements, and blast radius scope before executing an action.It is a heuristic over action names, not a simulation. It does not touch the project, does not validate your parameters, and cannot tell you whether the clip ids you are holding exist. Read three fields before trusting it:
recognised: falsemeans no rule matched and the levels are name-based defaults rather than a finding;snapshot_available: nullmeans rollback availability was not determined, never that there is none; andpre_state_availableseparates "no project open" from "state never read". For an actual preview, use the action's owndry_runwhere it has one. Where it has none, an explicitdry_run=trueon a registered destructive action is refused withDRY_RUN_UNAVAILABLE(status: dry_run_unavailable,simulated: false,executed: false, plus the same static risk block) before any archive, state lookup, or handler execution. Until v2.211.0 the flag was silently ignored on those actions and the mutation ran; the actions that do honour it are listed inNATIVE_DRY_RUN_ACTIONS(src/utils/destructive_hook.py) and pinned to the handlers by a test. -
list_lifecycle_hooks(): Returns active execution lifecycle pipeline hooks (risk_classification,resolve_state_inspection,readback_verification,drift_detection,provenance_trace). All of them observe; none replaces a tool result.dry_runis therefore never answered on a handler's behalf: an action with a native dry-run path runs it, and every other registered destructive action refuses the flag instead of either simulating or executing.
Explicit correlation is also supported per-call: pass params={"execution_id": ...}
or params={"trace_id": ...} in any tool call to associate it with a specific trace.
Two things to know when a trace is not where you expect it. The buffer holds the
100 most recent executions and is in memory only — a server restart empties
it, and the on-disk logs/execution-traces.jsonl is the durable record.
list_recent_executions returns a persistence block naming that file and
whether it is writable; check it before concluding that nothing was traced,
since the append is best-effort and will never fail a real edit to report a
logging problem.
Recorded per step: tool, action, duration_ms, status, semantic deltas and
verification. Not recorded: parameters, file paths, clip or project names.
The only free text is the request string passed to begin_execution.
The file rotates at 8 MB, keeping one previous generation as
execution-traces.jsonl.1. Both are gitignored along with the rest of logs/.
Audit reports are separate point-in-time exports; RESOLVE_MCP_TRACE_REPORT_DIR
moves their default directory without moving the append-only trace log.
path is honoured as given — the report can be written anywhere, and the
directories are created to reach it. That is deliberate (a conform's paperwork
belongs beside the conform, not in logs/), so treat it the way you would any
other export destination and do not invent a path near source media. The
execution_id route cannot escape the report directory: it is sanitised to a
filename.
A report whose run recorded no verification checks renders "not established
— no checks recorded" in the Passed row, never "yes" — the same rule as
verification.status: "unverified" in the envelope. Do not report such a run
to the user as verified.
Two Server Modes
| Mode | Entry point | Tool count | Use when |
|---|---|---|---|
| Compound (default) | src/server.py |
37 tools | Most workflows — keeps context lean |
| Granular (full) | src/server.py --full |
387 tools | Power users needing one tool per API method |
Resolve 21.1 adds twelve read-only discovery controls for edition, presets, audio formats/codecs, normalization modes, speed, fades and blanking in both server interfaces. These readers do not invoke setters.
This skill document covers the compound server (the default). Each compound
tool accepts an action string and an optional params object.
Granular writes are enforced, not archived. Every destructive-hinted granular
tool (deletes, clears, resets, replaces, sets, loads — 132 of the 387) runs
through granular_destructive_op: while destructive.safe_mode is on, a
HIGH-risk call is refused unless that call passes allow_risky_operation: true
(a parameter the hook adds to each hooked tool's schema), and every call writes
a row to the security audit log. Risk is read from the verb — delete/remove/
clear/reset/replace/unlink/quit/restart are HIGH, set/load/
switch/close/stop are MEDIUM — except that a tool reaching a symbol the
api_truth ledger marks destroys_prior_work is HIGH from the ledger
(ti_copy_grades), and those tools also keep their acknowledge_trap +
confirm-token gate. What the granular hook does not do is duplicate the
timeline into an Archive bin first, as the compound hook does: a granular write
has no recovery version, and a refused-or-audited call is the whole of its
safety. Use the compound server when you want the archive.
The advanced server (davinci-resolve-advanced-mcp)
The same package ships an optional third surface: an offline Node server (18
tools, typically registered as davinci-resolve-advanced) that edits Resolve
files (.drp/.drt/.drx) and patches the project DB — no running Resolve
required. Rule of thumb: drive a live session with the Python server; compute
grades, QC, conform math, and file-level edits with the advanced server, then
apply results through the live server. Full catalog: resolve-advanced/README.md.
Operating rules an agent must know:
- Grade value space.
drxgenerate/mergedefault tospace:'ui'— params are Resolve PANEL units (lift/gamma/gain/offset panel numbers, saturation 0–100 neutral 50). Passspace:'drx'only for raw internal floats (e.g. re-encoding decoded values). Decoded values are ground truth only for the calibrated native set — check thevalueFidelitymarker onparseresults; per-control status isresolve-advanced/vendor/drx-parameters/CALIBRATION-STATUS.md. - Hue-axis curves. Naive
[0,1]point lists are canonicalized into the verified bezier cage automatically. Pre-wrapped lists (x outside[0,1]) are REFUSED unlessallowWrappedHueCage:true(malformed cages can crash Resolve 19). If agenerate/mergeresult carries awarningsarray, the curve was passed through raw and will render FLAT — tell the user, don't ship it silently. - Node-graph relayout (programmatic "Cleanup Node Graph"; the UI command
has no API). Single clip, live:
gallery_stills.grab_and_export→ advanceddrx(action="relayout")→graph.reset_all_grades→safe_apply_drxwith EXPLICIT item indices (the reset is required — a same-structure apply keeps the old layout). Whole project, offline:project_db(action="relayout_node_graphs"). - project_db patches require the project CLOSED in Resolve plus
iConfirmProjectClosed:true; every write auto-backs-up and read-back verifies. Resolve caches open projects in memory: after patching, fully QUIT and relaunch Resolve or the patch will not be visible. - Guards are load-bearing. Advanced tools refuse rather than fabricate
(silent-lie guards): a thrown "refused" error usually means wrong input space,
log-encoded frames, or missing media — read the message before retrying.
Optional native deps (
better-sqlite3,sharp, ffmpeg) gate some actions; call the advancedcapabilitiestool for live status and install hints.
Per-domain depth for both servers lives in the kernels (docs/kernels/), each of
which carries an "Advanced (offline) server" section where an offline counterpart
exists. Portable skills in .agents/skills/ (resolve-color, resolve-edit,
resolve-conform, resolve-delivery, resolve-media-analysis) route
craft ↔ live ↔ offline automatically when working in that domain.
The compound server also registers MCP prompts. Use davinci_resolve_workflow
as the compact operating brief, and use analyze_media as a slash-command style
entry point for source-safe project, selected-clip, bin, file, or sequence
analysis. The Analyze Media prompt executes directly by default, persists
inspectable reports/artifacts under the project analysis root, requests
host_chat_paths visual analysis (frames are extracted to disk and the host
chat finalizes each clip via media_analysis(action="commit_vision", ...)),
runs local transcription through the configured backend, and writes metadata
plus source-time Media Pool markers back to the Resolve project unless the
user opts out.
Anti-regression rule: do not silently downgrade media analysis. Source-safe
means source media stays untouched; it does not mean no visuals, no transcript,
no persisted report, no metadata writeback, or no Media Pool markers. Do not
add include_visuals=false, include_transcription=false,
publish_metadata=false, timed_markers=no, session_only=true, or
dry_run=true unless the user explicitly asks for that opt-out, the target is a
raw file path that cannot receive Resolve project writeback. The host_chat_paths
vision protocol is: analyze_* returns a deferred payload with absolute
frame_paths and a JSON schema; you must read those frames as images (Claude
Code's Read tool handles JPG/PNG natively), produce the JSON, and call
commit_vision for each clip. Skipping commit_vision leaves the run in
pending_host_vision_analysis — surface that explicitly; do not call the
analysis complete.
The deferred payload also includes a host_tool_choice_hint block. Hosts that
respect this hint pass it as tool_choice={type:"tool", name:"media_analysis"}
on the next API turn, hard-locking the agent into the correct next call. Hosts
that don't recognize the field ignore it — the flow is unchanged for them.
Headless Resolve (-nogui)
Resolve runs without a UI, and it is capability-identical to a GUI session.
Measured across 238 paired observations on Studio 19.1.3.7 (see
docs/reference/headless-cli.md and the regenerable
docs/reference/headless-capability-matrix.md): zero capabilities work with
a UI and fail without one. Pages, render-to-disk, AAF/EDL/XML/DRT/OTIO export,
ExportCurrentFrameAsStill, Fusion comps, colour groups, layout presets and all
ordinary editorial behave identically.
Capability is not stability, but stability is now partly measured too. Ten consecutive ProRes 422 HQ renders in one headless session, from a JPEG 2000 / MXF OP1A source, completed with no crash, no death and no leak — marginally faster and ~95 MB lighter than the same ten renders with a UI. What remains untested is sustained encode over hours and the operator's own footage and codec settings. Use headless freely for orchestration, edit, conform, analysis and renders of that scale; qualify it on real footage before promising a long-form or professional-container delivery, and keep a GUI fallback there.
Headless is NOT immune to modal dialogs — it is worse. It cannot display a dialog, but Resolve still tries to raise one, and the call then never returns.
The canonical case, measured on a cold -nogui boot:
ProjectManager.SaveProject() on the default never-saved project named
Untitled Project blocks forever headless (no return after 45s, client
parked in Fusion::RemoteApp::WaitPkt), where the GUI merely returns False.
The project has no location and there is no SaveProjectAs, so Resolve wants a
Save-As dialog and waits for an answer that can never arrive. In the GUI a human
clears it in one click; headless nothing can.
Never call SaveProject() without checking the project name first:
project = pm.GetCurrentProject()
if project is not None and project.GetName() != "Untitled Project":
pm.SaveProject() # safe: it has a location
# else: nothing to save, and headless this call blocks forever
src/utils/project_cleanup.py:save_project_if_safe(pm) does exactly this — use
it rather than calling SaveProject directly. And do not reach for headless
to dodge the GUI's save dialog; that trade makes a one-click interruption into a
dead session.
Rules:
- Check the mode before any project switch.
resolve_control(action="runtime_mode")→{running, headless, instances, database_attached, guidance}. It needs no connection. database_attached: falsemeans the instance is WEDGED — stop and restart it. Resolve can come up with no project database attached. It accepts connections and answers product, version, page and current-project queries normally, so every ordinary liveness check passes, whileCreateProject/LoadProjectreturn False forever,SaveProjectreturns None, and some calls never return at all. It does not recover on its own. Do not retry; quit and relaunch.headlessmay benull. That means "cannot be determined", not "has a UI". Treatnulllikefalse— take the careful path — but do not report it as fact.- There is no API tell. A headless instance returns a real page from
GetCurrentPage()and identical product/version strings. Anything that inspects theresolvehandle to guess the mode is guessing.runtime_modereads the process argv, which is the only place-noguiappears. - Launching:
resolve_control(action="launch", params={"headless": true}), or setDAVINCI_RESOLVE_HEADLESS=1to make auto-launch headless. Launching the other mode while an instance is already running returnsRESOLVE_MODE_CONFLICTrather than starting a second one — two Resolves fight the singleton and have been observed to crash-loop rather than fail cleanly. instances> 1 is a fault to report, not a state to work around. Check for a render node before starting anything.- Teardown is
resolve_control(action="quit"); it discards the open project without prompting, which is what a batch process wants.
The one thing headless genuinely cannot do is anything that needs a visible
panel — ExportStills being the known case, and it fails in a panel-closed GUI
too.
Local Control Panel
If the user asks to open, launch, or inspect the Resolve MCP control panel, run this from the repository root:
venv/bin/python -m src.control_panel
The command starts the local control panel and opens the default browser. Use
--no-open when running in a headless context, then give the user the printed
localhost URL exactly as printed — it carries a per-launch bearer token in
its fragment (#token=…) and the panel refuses every request without it. The
panel binds loopback only (a non-loopback host is refused, no override) and is
single-user; it is an operational surface
for server status, Resolve clips, source-safe analysis jobs, preferences, and
diagnostics as those sections are added.
The Review tab → History button opens the timeline-history surface:
per-timeline version chain, brain-edit deltas, manual archive, and rollback.
Backed by timeline_versioning MCP actions; see that tool's section below for
the underlying primitives.
Editorial Memory And Decision-Making
When the user asks for cutting, pacing, story shape, suspense, comedy timing, or
tonal reframing, operate like an editor, not just a metadata scanner. Use
docs/guides/editorial-decision-guide.md as the project-owned craft reference. The
short version: emotion and story come first, then clarity, rhythm, eye trace,
screen geography, continuity, and coverage variety.
Before analyzing or rebuilding anything, check whether the active project already contains useful evidence:
media_analysis(action="coverage_report", params={"target": {...}})— the pre-flight contract. Pure read; never triggers analysis. Returns per-clip state (analyzed / stale / missing / reuse_blocked / superseded_by_relink), layer presence,source_trusttier, and arecommended_action. The response carries anevidence_basesummary string — lead any editorial or color recommendation with that line, before the creative answer.media_analysis(action="summarize")for project-wide rollup of warnings, motion distribution, and signed-report counts.media_analysis(action="get_report")when a manifest or report path is known.timeline(action="list")timeline(action="get_current")timeline(action="probe_timeline_structure")timeline(action="source_range_report")timeline_markers(action="get_all")media_analysis(action="review_timeline_markers")when marker imagery matters
Reuse prior analysis unless it is stale, incomplete, missing a modality, or
flagged superseded_by_relink because Resolve's source clip was replaced after
analysis ran. Coverage_report surfaces all of these in one read. Do not re-run
visual analysis just because the edit task is new if a current report already
has keyframes, motion variance, and usable visual descriptions. Add
transcription, host_chat_paths vision (followed by commit_vision), marker
review, or source range checks only when that missing evidence changes the
decision. Use force_refresh=true only when the user asks for a fresh read or
when cache signatures show the source, prompt, depth, or requested modality has
changed.
Source-trust filtering: coverage_report accepts min_source_trust (one of
auto, filename, low, medium, high). Clips below the threshold appear
in summary.clips_needs_higher_trust and are reported with
below_min_source_trust=true. Use medium for routine work, high for
shot-matching or look-development passes where confident scene/identity reads
matter.
For finished-video editorial work, scene detection and motion variance are guardrails, not story. Use them to avoid black frames, flash frames, corrupt ranges, and accidental cut points. Let transcript, sound events, complete thoughts, reactions, and decisive visual frames drive the actual edit.
After creating or modifying a timeline variant, do a second pass before calling the work done:
timeline(action="detect_gaps_overlaps")timeline(action="source_range_report")timeline_frame(action="capture")at important markers and cuts- Compare each marker name against the Resolve-rendered frame; revise the marker or edit if the image contradicts the plan.
Do not depend on personal, external, or workstation-specific editorial context.
For this project, keep the editorial craft reference self-contained in
docs/guides/editorial-decision-guide.md and keep this SKILL.md focused on
operational use of the MCP.
Color Memory And Decision-Making
When the user asks for color correction, shot matching, look development, LUTs,
DCTLs, DRX grades, Gallery stills, or color-group workflows, use
docs/guides/color-decision-guide.md as the project-owned color reference.
Be explicit about the API boundary:
- Directly creatable/control surfaces: CDL values on an existing node, grade versions, color-group assignment, LUT assignment on existing nodes, node enable/cache state, LUT/DCTL assets, Gallery still import/export, and grade copy/export helpers.
- Opaque full-grade surfaces: copied grades, imported/exported
.drxstills, and manually built Resolve node graphs. These can carry full grades, but the MCP applies or copies them as packages. - Not directly creatable from structured params: new node trees, Lift/Gamma/Gain wheel values, log/HDR palette values, curves, qualifiers, power windows, tracking, Color Warper, and detailed ResolveFX/OFX parameter edits.
Before any color recommendation, run
media_analysis(action="coverage_report", params={"target": {...}, "min_source_trust": "medium"}) (use "high" for shot-matching or
look-development passes). Lead the response with the returned evidence_base
line before the grade plan. Coverage_report surfaces relink-superseded clips
that must be re-analyzed before being graded from prior visual descriptions.
For safe color work, start with timeline_item_color(action="grade_boundary_report"),
timeline_item_color(action="grade_version_snapshot"),
timeline_item_color(action="probe_node_graph"), and a Resolve-rendered frame
reference for the target shot or shots. Use thumbnails, contact sheets, Gallery
stills, marker frames, or existing visual analysis reports before writing a
grade, and cite the inspected frames in the response. When the API can safely
provide them, compare matched untreated/bypass, current, and after frames at the
same timecodes, then restore the previous active version or node-enabled state
after any temporary bypass capture. Treat untreated frames as diagnostic
evidence, not as permission to discard an existing creative grade.
Prefer safe_set_cdl for small reversible primary corrections. SetCDL's
NodeIndex is 1-BASED (scripting README line 6) and there is no GetCDL
readback — safe_set_cdl and apply_look_to_items now read the node graph's
GetNumNodes first and return a structured reason/diagnosis on a false
SetCDL instead of a bare boolean. Use DRX/stills
or grade copy only when the user accepts whole-grade replacement/transfer
semantics. Use DCTL/LUT authoring only for reusable mathematical transforms, not
as a substitute for hand-built windows, qualifiers, or tracked secondaries. Do
not apply blind/global grades unless the user explicitly asks for that. When the
user asks to build on or adjust an existing grade, preserve the current
grade/version as the starting point, create or switch to a recoverable
adjustment version, and apply only incremental changes through supported
controls. Do not reset grades, replace graphs, or apply DRX/copy-grade
whole-grade artifacts unless replacement or transfer semantics are explicitly
accepted. Distinguish Resolve's default one-node graph from an existing creative
grade; only describe a creative grade when active tools, LUTs, or other grade
state are present.
For sequence-wide looks, prefer a duplicated timeline, batch creation of reference/current/look versions across all target clips, and one bulk Resolve script for repeated version, group, or CDL operations. Use color groups for shared scene-level intent only when they fit the work: group pre-clip for shared normalization, clip versions for shot-specific matching, and group post-clip for the creative look. Sampling can guide a first pass, but final handoff should state the reviewed scope; short sequences should be checked shot by shot.
Page Context Requirements
DaVinci Resolve is a page-based application. Certain operations only work on specific pages. Always confirm or switch pages before calling page-sensitive tools.
| Operation category | Required page | How to switch |
|---|---|---|
| Color grading, node graphs, CDL | Color | resolve_control(action="open_page", params={"page": "color"}) |
LUT export (export_lut, safe_export_lut) |
Color — measured False from media, edit, fusion, fairlight and deliver |
resolve_control(action="open_page", params={"page": "color"}) |
Gallery stills export, grab_and_export |
Color, Gallery panel open | resolve_control + open Gallery panel in Workspace menu |
| Fusion compositions (page comp) | Fusion | resolve_control(action="open_page", params={"page": "fusion"}) |
| Timeline editing, track operations | Edit or Cut | resolve_control(action="open_page", params={"page": "edit"}) |
| Fairlight audio | Fairlight | resolve_control(action="open_page", params={"page": "fairlight"}) |
| Render / deliver | Deliver | resolve_control(action="open_page", params={"page": "deliver"}) |
| Media import, storage browsing | Media | resolve_control(action="open_page", params={"page": "media"}) |
When a tool returns an unexpected False or an error about context, check whether
you are on the correct page first.
Tool Map
Craft Guidance
knowledge — The editorial, colour, audio, and workflow guidance bundled with
this server, served as prose. No Resolve connection required.
Read a topic before a creative or destructive operation, not after. The tools will happily execute an editorially wrong decision; this is where the reasoning lives — measured numbers, known traps, and what each move costs to undo.
Key actions:
topics(category?)— the index: topic id, one-line summary, size, sections, and related topics. Categories:workflow(task playbooks: tighten a recording, build a rough cut, match a grade),guide,kernel(per-surface tool maps),reference(exhaustive ledgers including this document),repo(contributing here)get(topic, section?, inline?)— the resolved prose. Natural aliases work ("tighten","dead air","grading","conform"). Referenced guides and kernels arrive inlined, so a client with no checkout of this repository still gets the manual, not a path to it.sectionreturns one heading's subtreesearch(query, limit?)— ranked topics with excerptscapabilities()— topic count by category, and the corpus directories
The same index is published as the knowledge://topics MCP resource, so hosts that
consume resources can see what guidance exists without spending a turn.
App Control
resolve_control — App-level operations.
Key actions:
launch— connect to or start Resolve; call this first if any tool returns a "Not connected" errorget_version— returns{product, version, version_string, build, mcp}.build.unavailable_on_this_buildlists every recorded API surface this build does not have; read it before offering anything version-gated. An absence from that list is not a promise a method exists — most of the API has never been version-bisected, socheck_version_supportanswersunknownfor it, andunknownmeans probe withname in dir(obj), never barehasattr(constantTrueon Resolve objects)check_version_support(symbol?, resolve_version?)— is one named symbol on this build? Withoutsymbol, the same missing-surface listget_versioncarries. No connection needed whenresolve_versionis passedapi_truth(query?)— look up behaviorally-verified facts about quirky/unreliable Resolve API behavior (no connection needed); filter by substringverification_stats— readback-verification tally (verified/contradicted/ unverified) since server start (no connection needed)report_issue(kind, title, summary, …)— when the user says "send this as a bug" or "…as a feature request", draft a GitHub issue for this server. Fill it from the conversation (the failing tool/action and its error verbatim, expected vs actual, steps). Server version, Resolve build, connection mode and OS are attached; paths, usernames, e-mails and secrets are redacted. It files nothing: show the user the draft, then hand them the returnedurlto review and submit on GitHub. Redaction cannot catch client or project names written as prose, so ask the user to check. Never call it unprompted; offering once after a failure that looks like a server defect is fine. No connection needed, and it never launches Resolveget_page/open_page(page)— read or switch the active pageget_keyframe_mode/set_keyframe_mode(mode)get_fairlight_presets— Resolve 20.2.2+; returns available Fairlight preset nameslist/save/load/delete/import/export_user_preferences_preset— Resolve 21.0.4+; user-preferences presets.load_...is SESSION-WIDE: it swaps the user's global Resolve preferences, so only call it when the user asked for the switch.import_...does not activate the imported preset — follow withload_user_preferences_presetquit— terminates Resolve (destructive; confirm with user first)
Offline timeline authoring on timeline — served above the connection check:
author_offline writes an importable .drt / .otio / .edl from a clip plan when
Resolve is unreachable, and offline_fallback_capabilities reports whether it can. Every
not-connected error carries an offline_alternative block naming it. Authoring a file
does not complete a failed live operation — the timeline is not in a project until it is
imported. See docs/kernels/timeline-conform-interchange-kernel.md.
Offline audio and image QC on media_analysis — no Resolve connection required:
measure_loudness, mix_plan / mix_plan_capabilities (dialogue-anchored rough mix
with dialogue-following ducking, rendered and re-measured), and assess_grade /
grade_loop / grade_loop_capabilities (numeric grade-damage QC and the retry ladder
that backs a look off until it stops damaging the picture). See
docs/kernels/audio-fairlight-kernel.md and docs/kernels/color-grade-kernel.md.
layout_presets — Save, load, export, import, delete UI layout presets.
list (Resolve 21.0.4+) enumerates the saved preset names the other actions
take.
render_presets — Import and export render and burn-in presets.
list_burnin / delete_burnin (Resolve 21.0.4+) enumerate and remove burn-in
presets — list_burnin is the only way to discover the names the DataBurnIn
render setting and the load_burnin_preset actions expect.
Project Management
project_manager — CRUD on projects.
Key actions: list, list_attributes, get_current,
create(name, media_location_path?),
load(name), save, close,
delete(name), import_project(path), export_project(name, path), archive,
restore
list_attributes (Resolve 21.0.4+) returns lastModifiedDate, creationDate,
notes, and liveCollaborationMode per project in the current folder without
loading any of them.
Project / Database / Archive kernel actions (v2.15.0+) add guarded project lifecycle, settings, database, preset, and archive boundary helpers:
project_capabilitiesprobe_project_lifecycleprobe_project_settings(keys?, try_write?, dry_run?)safe_project_create(name, media_location_path?, dry_run?)safe_project_export(name, path, with_stills_and_luts?, dry_run?)safe_project_import(path, name, dry_run?)safe_project_archive(name, path, src_media=false, render_cache=false, proxy_media=false, dry_run?)safe_project_restore(path, name, dry_run?)safe_project_delete(name, close_current?, dry_run?)safe_set_project_settings(settings, restore?, dry_run?)project_settings_snapshot(name?)database_capabilitiessafe_set_current_database(db_info, dry_run?, allow_switch?)preset_lifecycle_probeproject_boundary_report
Health check and declarative spec (v2.28.0+):
lint— graded project health pre-flight returning{ok, counts, issues}. Issues (error / warning / info) cover: no project, no current timeline, mixed frame rates across timelines, empty timeline, render format unset, color science unmanaged, offline media, and unanalyzed clips. Composed from existing probes; safe read-only.diff_to_spec(spec_path | spec)— preview drift between a declarative spec and the live project WITHOUT mutating. Returns{actions, diff, change_count}.plan_spec(spec_path | spec)— the ordered action list as a dry run.apply_spec(spec_path | spec, dry_run?, run_hooks?, continue_on_error?)— reconcile the project toward the spec. Idempotent (re-runs are no-ops); color/ HDR settings apply in dependency order; markers added only when absent; explicitsettingsoverride a namedcolor_preset; before/after shell hooks run only withrun_hooks=true. The spec is YAML or JSON:{project, color_preset?, settings?, timelines:[{name, fps?, settings?, markers?}], hooks?}. Note:apply_specreconciles the currently open or already-existing project; creating a brand-new project from a spec depends on Resolve'sCreateProjectsucceeding (it can return None when an unsaved project blocks the switch).
Safe project actions require _mcp_ names and temp paths by default. Database
switching dry-runs by default because Resolve closes open projects when
switching databases. Archive source media/cache/proxy flags are rejected unless
explicitly opted in.
project_manager_folders — Navigate project folders.
Key actions: list, get_current, create(name), open(name), goto_root,
goto_parent
project_manager_database — Switch databases.
Key actions: get_current, list, set_current(db_info)
project_manager_cloud — Cloud projects (requires Resolve cloud
infrastructure; most users will not have this).
project_settings — Project metadata, settings, color groups, and misc
operations on the open project.
Key actions: get_name, set_name(name), get_setting(name?),
set_setting(name, value), get_color_groups, add_color_group(name),
delete_color_group(name), export_frame_as_still(path),
load_burnin_preset(name), insert_audio(media_path, ...),
apply_fairlight_preset(preset_name),
project_summary(include_clips?, clip_limit?) — live structural readout
(current page, timeline count, media-pool inventory by type)
Media
media_storage — Browse mounted volumes and import files.
Key actions: get_volumes, get_subfolders(path), get_files(path),
import_to_pool(items) — items is a list of file path strings
media_pool — Full Media Pool management.
Key actions: get_root_folder, get_current_folder, set_current_folder(path),
add_subfolder(name), create_timeline(name), import_timeline(path, options?),
import_media(paths), delete_clips(clip_ids), move_clips(clip_ids, target_path),
setup_multicam_timeline(name, clip_ids|angles, sync_mode?, include_audio?, dry_run?),
get_selected, set_selected(clip_id), export_metadata(path, clip_ids?)
Media Pool / Ingest kernel actions (v2.8.0+) add safer agent-facing workflows:
ingest_capabilities, probe_media_pool, probe_ingest_item,
safe_import_media, safe_import_sequence, safe_import_folder,
organize_clips, copy_metadata, normalize_metadata,
probe_clip_properties, metadata_field_inventory, safe_relink,
safe_unlink, link_proxy_checked, link_full_resolution_checked,
set_clip_marks, clear_clip_marks, copy_clip_annotations,
setup_multicam_timeline, and
media_pool_boundary_report. See
docs/kernels/media-pool-ingest-kernel.md for the live-tested support map.
setup_multicam_timeline is a helper, not a native multicam API wrapper. It
creates a source-safe stacked prep timeline with one angle per video track,
optional matching audio tracks, and stack_start, source_timecode, or
explicit record_frame placement. Native multicam clip creation, angle
switching, and flattening remain Resolve UI workflows; see
docs/guides/multicam-setup-guide.md.
Note: folder path arguments use slash notation like "Master/SubFolder".
"Master" or "/" refers to the root folder.
Address a folder either by path or by folder_id — the id get_subfolders
returns for each entry (v2.77.0+; the same pair works for media_pool add_subfolder via parent_path/folder_id and for media_pool get_timeline_mattes via folder_path/folder_id). Omit both to get the
action's default: the current folder for the folder tool, the root folder for
those two media_pool actions. An address that is supplied but does not resolve
is a FOLDER_NOT_FOUND / invalid_input error — it never quietly falls back to
the current bin.
That fallback is what these tools used to do, so treat a pre-v2.77.0 server as
unable to tell you when it answered about the wrong folder. Note also that only
path/folder_path/folderPath and folder_id/folderId are recognised as
addresses: any other key you invent (id, bin, folderName) is still
silently dropped, and the action still answers about its default folder with
success. Use the documented names.
folder — Operations on a specific Media Pool folder.
Key actions: get_clips(path?|folder_id?), get_subfolders(path?|folder_id?), export(path?, export_path),
transcribe_audio(path?, use_speaker_detection?), clear_transcription(path?),
perform_audio_classification(path?), analyze_for_intellisearch(path?, identify_faces?, is_better_mode?),
analyze_for_slate(path?, marker_color?), remove_motion_blur(path?, deblur_option?) (Resolve 21+;
the last three need AI Extras, and remove_motion_blur is confirm-token gated)
media_pool_item — Read/write clip metadata and properties. All actions
require a clip_id (the UUID returned by GetUniqueId()).
Key actions: get_name, get_metadata(key?), set_metadata(key, value),
get_clip_property(key?), set_clip_property(key, value), get_clip_color,
set_clip_color(color), link_proxy(proxy_path), replace_clip(path),
set_name(name), link_full_resolution_media(path),
replace_clip_preserve_sub_clip(path), monitor_growing_file,
transcribe_audio(use_speaker_detection?), clear_transcription,
get_transcription(include_words?, use_nested_clip_transcription?) (read back
{text, segments, language, source, truncated, status, has_transcription}; on
Resolve 21.1+ it uses MediaPoolItem.GetTranscription, so segments carries
{start, end, text, speaker} in SOURCE timecode and nothing is truncated, and
on 21.0.x it falls back to the Transcription clip property, where truncated
flags a cut-off preview — source says which route ran),
perform_audio_classification,
analyze_for_intellisearch(identify_faces?, is_better_mode?), analyze_for_slate(marker_color?),
remove_motion_blur(deblur_option?) (Resolve 21+; AI Extras / confirm-token gated as noted above),
get_audio_mapping, get_mark_in_out, set_mark_in_out
media_pool_item_markers — Markers and flags on clips in the Media Pool.
All actions require a clip_id.
Key actions: add(frame, color, name, note, duration), get_all, delete_by_color(color),
delete_at_frame(frame), add_flag(color), get_flags, set_name(name)
media_analysis — Project-scoped media intelligence and guarded metadata publishing.
Media Analysis and editorial-assist actions (v2.17.0+) add source-safe planning,
report reuse, persisted analysis execution, host_chat_paths visual review
(finalized per clip via commit_vision), transcription, default Resolve
metadata/marker writeback, and timeline-level editorial helpers.
Key actions: capabilities, install_guidance, resolve_output_root, plan,
coverage_report, analyze_file, analyze_clip, analyze_bin,
analyze_project, detect_sync_events, add_sync_event_markers,
publish_clip_metadata, commit_vision, summarize, get_report,
build_index, index_status, query_index, start_batch_job,
run_batch_job_slice, batch_job_status, list_batch_jobs,
cancel_batch_job, resume_batch_job, review_timeline_markers,
cleanup_artifacts, db_status, db_ingest, get_panel_state,
set_panel_state, session_start_context, update_clip_field,
update_shot_field, get_field_history, revert_field,
list_corrections, deepen, commit_shot_vision, vision_pending_sweep,
build_embeddings, find_similar, detect_entities, commit_entities,
list_entities, prepare_bin_briefing, commit_bin_summary,
detect_shot_relationships, commit_shot_relationships,
list_shot_relationships, strata_status, backfill_words, strata_run,
take_diff, cut_candidates, strata_query, timeline_strata,
plan_story_beats, commit_story_beats, and list_story_beats.
Cross-clip entities + bin briefing v2 (v2.44.0+). Recurring people/places/props across a project's media, found cheaply and confirmed with ONE vision call per cluster:
detect_entities(threshold?, min_cluster_size?)clusters the v10 CLIP frame vectors (build visual embeddings first), writes provisional entity rows + appearances, and returns a deferred payload with one representative frame per cluster (caps pre-checked, estimate inlined). The host chat reads those frames and callscommit_entities(entities=[{entity_index, kind, label, description, confidence, merge_with?}], vision_token)— conservative labels only (describe what's visible; never guess names).merge_withcollapses clusters that show the same entity.list_entitiesreturns labeled entities with per-clip/shot appearances; the panel's Review page shows a "Recurring across this bin" card.prepare_bin_briefingreturns entities + per-clip summaries (text-only, no vision cost); the host writes a colleague-style markdown briefing and callscommit_bin_summary(briefing, briefing_token), which lands inmemory/bin_summary.mdabove the v2.0 aggregate.
Cross-shot relationships (v2.49.0+). Pattern recognition only (spec §4 —
no editorial suggestions): same_setup_as / alt_take_of (symmetric) and
continues_from (directional; the source shot continues from the target).
detect_shot_relationships(setup_threshold?, alt_take_threshold?, continues_band?, max_candidates?)— pairwise cosine over the per-shot visual vectors (build visual embeddings first; raisemax_frames_per_clipif shot coverage is partial), plus transcript continuity as a second signal forcontinues_from. Returns a deferred payload with a representative frame PAIR per candidate (caps pre-checked, two frames per candidate). Candidates live only in the detection-state stash until committed — re-detect replaces them.- The host chat reads BOTH frames of each pair and calls
commit_shot_relationships(relationships=[{candidate_index, verdict: confirm|reject, relationship_type?, confidence?}], vision_token). Confirm only what the frames show; reject lookalikes. Overriding the suggested type is allowed. Committed rows supersede prior machine rows for the same pair. list_shot_relationships(clip_id?, shot_uuid?, relationship_type?)— current rows with clip/shot context on both ends. The shot page's Relationships group fills from these rows, andplan_swapprefers confirmedalt_take_ofalternates over raw cosine (the rationale states which basis ranked each alternate).
Perception strata (v2.61.0+, schema v13/v14). A timecoded track model over each analyzed clip — events (pause/breath/hesitation/blink/beat/downbeat/…), sampled curves (pitch/vocal_energy/speech_rate/motion_energy/face curves), per-word transcript rows, and story beats. Local compute only (ffmpeg + numpy; face tier needs opencv + mediapipe); machine re-runs replace their own rows, human rows are append-only and always win. These measure and rank — they never decide; the editor picks.
strata_status(clip_id?)— project or per-clip track inventory plus what this machine can run (analyzer_capabilities).strata_run(clip_id, analyzers?)— run prosody / beat_grid / motion_energy / face on one clip (default: whatever is available locally).backfill_words()— promote word timestamps already inside stored report blobs into queryabletranscript_wordsrows; idempotent, no re-analysis.take_diff(clip_a, clip_b, text?)— align two takes on transcript words and diff their delivery (pace, pauses, pitch, energy). Deltas only, no winner.cut_candidates(clip_id, time_seconds, window_seconds?, fps?, limit?)— rank cut frames around an intended joint with human-readable reasons (blink / word-gap / pause / breath / beat / motion); missing tracks are reported, never treated as "no signal".strata_query(clip_id?, start_seconds?, end_seconds?, match_word?, …)— one queryable surface: a windowed cross-track bundle for a clip, or a project-wide word find with a joined ±context bundle per hit.timeline_strata(timeline_name, timeline_version?, …)— project clip strata through a versioned timeline's recorded placements. Snapshot frames are absolute record frames (start-timecode-inclusive); snapshots from schema v14+ carry the timeline's fps/start frame so placements also get timeline-relative frames a
Truncated - read the full file at https://github.com/samuelgursky/davinci-resolve-mcp/blob/ce3362a1a38ba6ea4e91bd08c61d306109258d17/docs/SKILL.md.