loading…
Search for a command to run...
loading…
MCP server integration for DaVinci Resolve providing powerful tools for video editing, color grading, media management, and project control
MCP server integration for DaVinci Resolve providing powerful tools for video editing, color grading, media management, and project control
Version API Coverage Tools Tested DaVinci Resolve Python License
A Model Context Protocol (MCP) server providing complete coverage of the DaVinci Resolve Scripting API. Connect AI assistants (Claude, Cursor, Windsurf) to DaVinci Resolve and control every aspect of your post-production workflow through natural language.
fusion_comp tool — 20-action tool exposing the full Fusion composition node graph API. Add/delete/find nodes, wire connections, set/get parameters, manage keyframes, control undo grouping, set render ranges, and trigger renders — all on the currently active Fusion page compositiontimeline_item_fusion cache actions — added get_cache_enabled and set_cache actions for Fusion output cache control directly on timeline items_resolve_safe_dir() now handles macOS (/var/folders, /private/var), Linux (/tmp, /var/tmp), and Windows (AppData\Local\Temp) sandbox paths that Resolve can't write to. Redirects to ~/Documents/resolve-stills instead of Desktopgrab_and_export — exported files are read into the response (DRX as inline text, images as base64) then deleted from disk automatically. Zero file accumulation. Pass cleanup: false to keep files on diskserver.py and resolve_mcp_server.py now share the same version and both use _resolve_safe_dir() for all Resolve-facing temp paths (project export, LUT export, still export)grab_and_export action on gallery_stills — combines GrabStill() + ExportStills() in a single atomic call, keeping the live GalleryStill reference for reliable export. Returns a file manifest with exported image + companion .drx grade file/var/folders and /private/var paths are redirected to ~/Desktop/resolve-stills since Resolve's process can't write to sandboxed temp directoriesExportStills requires the Gallery panel to be visible on the Color page. All 9 supported formats (dpx, cin, tif, jpg, png, ppm, bmp, xpm, drx) produce a companion .drx grade file alongside the imageexport_layout_preset, import_layout_preset, and delete_layout_preset now validate that resolved file paths stay within the expected Resolve presets directory, preventing path traversal via crafted preset namesquit_app/restart_app tools can terminate Resolve; MCP clients should require user confirmation before invokingtimeline_item_color unpacked _check() as (proj, _, _) but _check() returns (pm, proj, err), so proj got the ProjectManager instead of the Project, crashing assign_color_group and remove_from_color_group--full mode) now auto-reconnects and auto-launches Resolve, matching the compound server behaviorGetProjectManager(), GetCurrentProject(), GetCurrentTimeline() failures now return clear errors instead of NoneType crashesget_resolve(), get_project_manager(), get_current_project() replace 178 boilerplate blocksmode to grade_mode to match Resolve API; corrected documentation from replace/append to actual keyframe alignment modes (0=No keyframes, 1=Source Timecode aligned, 2=Start Frames aligned)mode for existing clients, grade_mode takes precedenceGetNodeGraph(0) returns False in Resolve; now calls without args unless layer_index is explicitly providednot g instead of g is None to catch False returnspython install.py for macOS/Windows/Linux, 10 MCP clients| Metric | Value |
|---|---|
| MCP Tools | 26 compound (default) / 342 granular |
| API Methods Covered | 324/324 (100%) |
| Methods Live Tested | 319/324 (98.5%) |
| Live Test Pass Rate | 319/319 (100%) |
| API Object Classes | 13 |
| Tested Against | DaVinci Resolve 19.1.3 Studio |
Every non-deprecated method in the DaVinci Resolve Scripting API is covered. The default compound server exposes 27 tools that group related operations by action parameter, keeping LLM context windows lean. The full granular server provides 342 individual tools for power users. Both modes cover all 13 API object classes:
| Class | Methods | Tools | Description |
|---|---|---|---|
| Resolve | 21 | 21 | App control, pages, layout presets, render/burn-in presets, keyframe mode |
| ProjectManager | 25 | 25 | Project CRUD, folders, databases, cloud projects, archive/restore |
| Project | 42 | 42 | Timelines, render pipeline, settings, LUTs, color groups |
| MediaStorage | 9 | 9 | Volumes, file browsing, media import, mattes |
| MediaPool | 27 | 27 | Folders, clips, timelines, metadata, stereo, sync |
| Folder | 8 | 8 | Clip listing, export, transcription |
| MediaPoolItem | 32 | 32 | Metadata, markers, flags, properties, proxy, transcription |
| Timeline | 56 | 56 | Tracks, markers, items, export, generators, titles, stills, stereo |
| TimelineItem | 76 | 76 | Properties, markers, Fusion comps, versions, takes, CDL, AI tools |
| Gallery | 8 | 8 | Albums, stills, power grades |
| GalleryStillAlbum | 6 | 6 | Stills management, import/export, labels |
| Graph | 11 | 22 | Node operations, LUTs, cache, grades (timeline + clip graph variants) |
| ColorGroup | 5 | 10 | Group management, pre/post clip node graphs |
# Clone the repository
git clone https://github.com/samuelgursky/davinci-resolve-mcp.git
cd davinci-resolve-mcp
# Make sure DaVinci Resolve is running, then:
python install.py
The universal installer auto-detects your platform, finds your DaVinci Resolve installation, creates a virtual environment, and configures your MCP client — all in one step.
The installer can automatically configure any of these clients:
| Client | Config Written To |
|---|---|
| Claude Desktop | ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) |
| Claude Code | .mcp.json (project root) |
| Cursor | ~/.cursor/mcp.json |
| VS Code (Copilot) | .vscode/mcp.json (workspace) |
| Windsurf | ~/.codeium/windsurf/mcp_config.json |
| Cline | VS Code global storage |
| Roo Code | VS Code global storage |
| Zed | ~/.config/zed/settings.json |
| Continue | ~/.continue/config.json |
| JetBrains IDEs | Manual (Settings > Tools > AI Assistant > MCP) |
You can configure multiple clients at once, or use --clients manual to get copy-paste config snippets.
python install.py # Interactive mode
python install.py --clients all # Configure all clients
python install.py --clients cursor,claude-desktop # Specific clients
python install.py --clients manual # Just print the config
python install.py --dry-run --clients all # Preview without writing
python install.py --no-venv --clients cursor # Skip venv creation
The MCP server comes in two modes:
| Mode | File | Tools | Best For |
|---|---|---|---|
| Compound (default) | src/server.py |
26 | Most users — fast, clean, low context usage |
| Full | src/resolve_mcp_server.py |
342 | Power users who want one tool per API method |
The compound server's timeline_item tool includes dedicated actions for common workflows:
| Category | Actions | Parameters |
|---|---|---|
| Retime | get_retime, set_retime |
process (nearest, frame_blend, optical_flow), motion_estimation (0-6) |
| Transform | get_transform, set_transform |
Pan, Tilt, ZoomX/Y, RotationAngle, AnchorPointX/Y, Pitch, Yaw, FlipX/Y |
| Crop | get_crop, set_crop |
CropLeft, CropRight, CropTop, CropBottom, CropSoftness, CropRetain |
| Composite | get_composite, set_composite |
Opacity, CompositeMode |
| Audio | get_audio, set_audio |
Volume, Pan, AudioSyncOffset |
| Keyframes | get_keyframes, add_keyframe, modify_keyframe, delete_keyframe, set_keyframe_interpolation |
property, frame, value, interpolation (Linear, Bezier, EaseIn, EaseOut, EaseInOut) |
The installer uses the compound server by default. To use the full server:
python src/server.py --full # Launch full 342-tool server
# Or point your MCP config directly at src/resolve_mcp_server.py
If you prefer to set things up yourself, add to your MCP client config:
{
"mcpServers": {
"davinci-resolve": {
"command": "/path/to/venv/bin/python",
"args": ["/path/to/davinci-resolve-mcp/src/server.py"]
}
}
}
Platform-specific paths:
| Platform | API Path | Library Path |
|---|---|---|
| macOS | /Library/Application Support/Blackmagic Design/DaVinci Resolve/Developer/Scripting |
fusionscript.so in DaVinci Resolve.app |
| Windows | C:\ProgramData\Blackmagic Design\DaVinci Resolve\Support\Developer\Scripting |
fusionscript.dll in Resolve install dir |
| Linux | /opt/resolve/Developer/Scripting |
/opt/resolve/libs/Fusion/fusionscript.so |
Once connected, you can control DaVinci Resolve through natural language:
"What version of DaVinci Resolve is running?"
"List all projects and open the one called 'My Film'"
"Create a new timeline called 'Assembly Cut' and add all clips from the media pool"
"Add a blue marker at the current playhead position with note 'Review this'"
"Set up a ProRes 422 HQ render for the current timeline"
"Export the timeline as an EDL"
"Switch to the Color page and grab a still"
"Create a Fusion composition on the selected clip"
All testing performed against DaVinci Resolve 19.1.3 Studio on macOS with live API calls (no mocks).
| Phase | Tests | Pass Rate | Scope |
|---|---|---|---|
| Phase 1 | 204/204 | 100% | Safe read-only operations across all classes |
| Phase 2 | 79/79 | 100% | Destructive operations with create-test-cleanup patterns |
| Phase 3 | 20/20 | 100% | Real media import, sync, transcription, database switching, Resolve.Quit |
| Phase 4 | 10/10 | 100% | AI/ML methods, Fusion clips, stereo, gallery stills |
| Phase 5 | 6/6 | 100% | Scene cuts, subtitles from audio, graph node cache/tools/enable |
| Total | 319/319 | 100% | 98.5% of all API methods tested live |
| Method | Reason | Help Wanted |
|---|---|---|
PM.CreateCloudProject |
Requires DaVinci Resolve cloud infrastructure | Yes |
PM.LoadCloudProject |
Requires DaVinci Resolve cloud infrastructure | Yes |
PM.ImportCloudProject |
Requires DaVinci Resolve cloud infrastructure | Yes |
PM.RestoreCloudProject |
Requires DaVinci Resolve cloud infrastructure | Yes |
TL.AnalyzeDolbyVision |
Requires HDR/Dolby Vision content | Yes |
Every method in the DaVinci Resolve Scripting API and its test status. Methods are listed by object class.
Status Key:
False — needs specific context to fully execute)| # | Method | Status | Test Result / Notes |
|---|---|---|---|
| 1 | Fusion() |
✅ | Returns Fusion object |
| 2 | GetMediaStorage() |
✅ | Returns MediaStorage object |
| 3 | GetProjectManager() |
✅ | Returns ProjectManager object |
| 4 | OpenPage(pageName) |
✅ | Switches Resolve page |
| 5 | GetCurrentPage() |
✅ | Returns current page name (e.g. "edit") |
| 6 | GetProductName() |
✅ | Returns "DaVinci Resolve Studio" |
| 7 | GetVersion() |
✅ | Returns [19, 1, 3, 7, ''] |
| 8 | GetVersionString() |
✅ | Returns "19.1.3.7" |
| 9 | LoadLayoutPreset(presetName) |
✅ | Loads saved layout |
| 10 | UpdateLayoutPreset(presetName) |
✅ | Updates existing preset |
| 11 | ExportLayoutPreset(presetName, presetFilePath) |
✅ | Exports preset to file |
| 12 | DeleteLayoutPreset(presetName) |
✅ | Deletes preset |
| 13 | SaveLayoutPreset(presetName) |
⚠️ | API accepts; returns False when preset name conflicts |
| 14 | ImportLayoutPreset(presetFilePath, presetName) |
✅ | Imports preset from file |
| 15 | Quit() |
✅ | Quits DaVinci Resolve |
| 16 | ImportRenderPreset(presetPath) |
⚠️ | API accepts; needs valid preset file |
| 17 | ExportRenderPreset(presetName, exportPath) |
⚠️ | API accepts; needs valid preset name |
| 18 | ImportBurnInPreset(presetPath) |
⚠️ | API accepts; needs valid preset file |
| 19 | ExportBurnInPreset(presetName, exportPath) |
⚠️ | API accepts; needs valid preset name |
| 20 | GetKeyframeMode() |
✅ | Returns keyframe mode |
| 21 | SetKeyframeMode(keyframeMode) |
⚠️ | API accepts; mode must match valid enum |
| # | Method | Status | Test Result / Notes |
|---|---|---|---|
| 1 | ArchiveProject(projectName, filePath, ...) |
⚠️ | API accepts; archiving is slow |
| 2 | CreateProject(projectName) |
✅ | Creates new project |
| 3 | DeleteProject(projectName) |
⚠️ | Returns False if project is open |
| 4 | LoadProject(projectName) |
✅ | Returns Project object |
| 5 | GetCurrentProject() |
✅ | Returns current Project |
| 6 | SaveProject() |
✅ | Saves current project |
| 7 | CloseProject(project) |
✅ | Closes project |
| 8 | CreateFolder(folderName) |
✅ | Creates project folder |
| 9 | DeleteFolder(folderName) |
✅ | Deletes project folder |
| 10 | GetProjectListInCurrentFolder() |
✅ | Returns project name list |
| 11 | GetFolderListInCurrentFolder() |
✅ | Returns folder name list |
| 12 | GotoRootFolder() |
✅ | Navigates to root |
| 13 | GotoParentFolder() |
✅ | Returns False at root (expected) |
| 14 | GetCurrentFolder() |
✅ | Returns current folder name |
| 15 | OpenFolder(folderName) |
✅ | Opens folder |
| 16 | ImportProject(filePath, projectName) |
✅ | Imports .drp file |
| 17 | ExportProject(projectName, filePath, ...) |
✅ | Exports .drp file |
| 18 | RestoreProject(filePath, projectName) |
⚠️ | API accepts; needs backup archive |
| 19 | GetCurrentDatabase() |
✅ | Returns {DbType, DbName} |
| 20 | GetDatabaseList() |
✅ | Returns list of databases |
| 21 | SetCurrentDatabase({dbInfo}) |
✅ | Switches database |
| 22 | CreateCloudProject({cloudSettings}) |
☁️ | Requires cloud infrastructure |
| 23 | LoadCloudProject({cloudSettings}) |
☁️ | Requires cloud infrastructure |
| 24 | ImportCloudProject(filePath, {cloudSettings}) |
☁️ | Requires cloud infrastructure |
| 25 | RestoreCloudProject(folderPath, {cloudSettings}) |
☁️ | Requires cloud infrastructure |
| # | Method | Status | Test Result / Notes |
|---|---|---|---|
| 1 | GetMediaPool() |
✅ | Returns MediaPool object |
| 2 | GetTimelineCount() |
✅ | Returns integer count |
| 3 | GetTimelineByIndex(idx) |
✅ | Returns Timeline object |
| 4 | GetCurrentTimeline() |
✅ | Returns current Timeline |
| 5 | SetCurrentTimeline(timeline) |
✅ | Sets active timeline |
| 6 | GetGallery() |
✅ | Returns Gallery object |
| 7 | GetName() |
✅ | Returns project name |
| 8 | SetName(projectName) |
⚠️ | Returns False on open project |
| 9 | GetPresetList() |
✅ | Returns preset list with dimensions |
| 10 | SetPreset(presetName) |
⚠️ | API accepts; preset must exist |
| 11 | AddRenderJob() |
✅ | Returns job ID string |
| 12 | DeleteRenderJob(jobId) |
✅ | Deletes render job |
| 13 | DeleteAllRenderJobs() |
✅ | Clears render queue |
| 14 | GetRenderJobList() |
✅ | Returns job list |
| 15 | GetRenderPresetList() |
✅ | Returns preset names |
| 16 | StartRendering(...) |
✅ | Starts render |
| 17 | StopRendering() |
✅ | Stops render |
| 18 | IsRenderingInProgress() |
✅ | Returns False when idle |
| 19 | LoadRenderPreset(presetName) |
✅ | Loads render preset |
| 20 | SaveAsNewRenderPreset(presetName) |
✅ | Creates render preset |
| 21 | DeleteRenderPreset(presetName) |
✅ | Deletes render preset |
| 22 | SetRenderSettings({settings}) |
✅ | Applies render settings |
| 23 | GetRenderJobStatus(jobId) |
✅ | Returns {JobStatus, CompletionPercentage} |
| 24 | GetQuickExportRenderPresets() |
✅ | Returns preset names |
| 25 | RenderWithQuickExport(preset, {params}) |
✅ | Initiates quick export |
| 26 | GetSetting(settingName) |
✅ | Returns project settings dict |
| 27 | SetSetting(settingName, settingValue) |
✅ | Sets project setting |
| 28 | GetRenderFormats() |
✅ | Returns format map |
| 29 | GetRenderCodecs(renderFormat) |
✅ | Returns codec map |
| 30 | GetCurrentRenderFormatAndCodec() |
✅ | Returns {format, codec} |
| 31 | SetCurrentRenderFormatAndCodec(format, codec) |
✅ | Sets format and codec |
| 32 | GetCurrentRenderMode() |
✅ | Returns mode integer |
| 33 | SetCurrentRenderMode(renderMode) |
✅ | Sets render mode |
| 34 | GetRenderResolutions(format, codec) |
✅ | Returns resolution list |
| 35 | RefreshLUTList() |
✅ | Refreshes LUT list |
| 36 | GetUniqueId() |
✅ | Returns UUID string |
| 37 | InsertAudioToCurrentTrackAtPlayhead(...) |
⚠️ | Tested; needs Fairlight page context |
| 38 | LoadBurnInPreset(presetName) |
⚠️ | API accepts; preset must exist |
| 39 | ExportCurrentFrameAsStill(filePath) |
⚠️ | API accepts; needs valid playhead position |
| 40 | GetColorGroupsList() |
✅ | Returns color group list |
| 41 | AddColorGroup(groupName) |
✅ | Returns ColorGroup object |
| 42 | DeleteColorGroup(colorGroup) |
✅ | Deletes color group |
| # | Method | Status | Test Result / Notes |
|---|---|---|---|
| 1 | GetMountedVolumeList() |
✅ | Returns mounted volume paths |
| 2 | GetSubFolderList(folderPath) |
✅ | Returns subfolder paths |
| 3 | GetFileList(folderPath) |
✅ | Returns file paths |
| 4 | RevealInStorage(path) |
✅ | Reveals path in Media Storage |
| 5 | AddItemListToMediaPool(...) |
✅ | Imports media, returns clips |
| 6 | AddClipMattesToMediaPool(item, [paths], eye) |
✅ | Adds clip mattes |
| 7 | AddTimelineMattesToMediaPool([paths]) |
✅ | Returns MediaPoolItem list |
| # | Method | Status | Test Result / Notes |
|---|---|---|---|
| 1 | GetRootFolder() |
✅ | Returns root Folder |
| 2 | AddSubFolder(folder, name) |
✅ | Creates subfolder |
| 3 | RefreshFolders() |
✅ | Refreshes folder list |
| 4 | CreateEmptyTimeline(name) |
✅ | Creates timeline |
| 5 | AppendToTimeline(...) |
✅ | Appends clips, returns TimelineItems |
| 6 | CreateTimelineFromClips(name, ...) |
✅ | Creates timeline from clips |
| 7 | ImportTimelineFromFile(filePath, {options}) |
✅ | Imports AAF/EDL/XML |
| 8 | DeleteTimelines([timeline]) |
✅ | Deletes timelines |
| 9 | GetCurrentFolder() |
✅ | Returns current Folder |
| 10 | SetCurrentFolder(folder) |
✅ | Sets current folder |
| 11 | DeleteClips([clips]) |
✅ | Deletes clips |
| 12 | ImportFolderFromFile(filePath) |
✅ | Imports DRB folder |
| 13 | DeleteFolders([subfolders]) |
✅ | Deletes folders |
| 14 | MoveClips([clips], targetFolder) |
✅ | Moves clips |
| 15 | MoveFolders([folders], targetFolder) |
✅ | Moves folders |
| 16 | GetClipMatteList(item) |
✅ | Returns matte paths |
| 17 | GetTimelineMatteList(folder) |
✅ | Returns matte items |
| 18 | DeleteClipMattes(item, [paths]) |
✅ | Deletes clip mattes |
| 19 | RelinkClips([items], folderPath) |
⚠️ | API accepts; needs offline clips |
| 20 | UnlinkClips([items]) |
✅ | Unlinks clips |
| 21 | ImportMedia([items]) |
✅ | Imports media files |
| 22 | ExportMetadata(fileName, [clips]) |
✅ | Exports metadata CSV |
| 23 | GetUniqueId() |
✅ | Returns UUID string |
| 24 | CreateStereoClip(left, right) |
✅ | Creates stereo pair |
| 25 | AutoSyncAudio([items], {settings}) |
⚠️ | Tested; needs matching A/V clips |
| 26 | GetSelectedClips() |
✅ | Returns selected clips |
| 27 | SetSelectedClip(item) |
✅ | Selects clip |
| # | Method | Status | Test Result / Notes |
|---|---|---|---|
| 1 | GetClipList() |
✅ | Returns clip list |
| 2 | GetName() |
✅ | Returns folder name |
| 3 | GetSubFolderList() |
✅ | Returns subfolder list |
| 4 | GetIsFolderStale() |
✅ | Returns False |
| 5 | GetUniqueId() |
✅ | Returns UUID string |
| 6 | Export(filePath) |
✅ | Exports DRB file |
| 7 | TranscribeAudio() |
✅ | Starts audio transcription |
| 8 | ClearTranscription() |
✅ | Clears transcription |
| # | Method | Status | Test Result / Notes |
|---|---|---|---|
| 1 | GetName() |
✅ | Returns clip name |
| 2 | GetMetadata(metadataType) |
✅ | Returns metadata dict |
| 3 | SetMetadata(type, value) |
✅ | Sets metadata |
| 4 | GetThirdPartyMetadata(type) |
✅ | Returns third-party metadata |
| 5 | SetThirdPartyMetadata(type, value) |
✅ | Sets third-party metadata |
| 6 | GetMediaId() |
✅ | Returns media UUID |
| 7 | AddMarker(frameId, color, name, note, duration, customData) |
✅ | Adds marker |
| 8 | GetMarkers() |
✅ | Returns marker dict |
| 9 | GetMarkerByCustomData(customData) |
✅ | Finds marker by data |
| 10 | UpdateMarkerCustomData(frameId, customData) |
✅ | Updates marker data |
| 11 | GetMarkerCustomData(frameId) |
✅ | Returns custom data string |
| 12 | DeleteMarkersByColor(color) |
✅ | Deletes markers by color |
| 13 | DeleteMarkerAtFrame(frameNum) |
⚠️ | Returns False if no marker at frame |
| 14 | DeleteMarkerByCustomData(customData) |
⚠️ | Returns False if no match |
| 15 | AddFlag(color) |
✅ | Adds flag |
| 16 | GetFlagList() |
✅ | Returns flag colors |
| 17 | ClearFlags(color) |
✅ | Clears flags |
| 18 | GetClipColor() |
✅ | Returns clip color |
| 19 | SetClipColor(colorName) |
✅ | Sets clip color |
| 20 | ClearClipColor() |
✅ | Clears clip color |
| 21 | GetClipProperty(propertyName) |
✅ | Returns property dict |
| 22 | SetClipProperty(propertyName, value) |
⚠️ | API accepts; some properties read-only |
| 23 | LinkProxyMedia(proxyMediaFilePath) |
✅ | Links proxy media |
| 24 | UnlinkProxyMedia() |
✅ | Unlinks proxy media |
| 25 | ReplaceClip(filePath) |
✅ | Replaces clip source |
| 26 | GetUniqueId() |
✅ | Returns UUID string |
| 27 | TranscribeAudio() |
✅ | Starts audio transcription |
| 28 | ClearTranscription() |
✅ | Clears transcription |
| 29 | GetAudioMapping() |
✅ | Returns JSON audio mapping |
| 30 | GetMarkInOut() |
✅ | Returns mark in/out dict |
| 31 | SetMarkInOut(in, out, type) |
✅ | Sets mark in/out |
| 32 | ClearMarkInOut(type) |
✅ | Clears mark in/out |
| # | Method | Status | Test Result / Notes |
|---|---|---|---|
| 1 | GetName() |
✅ | Returns timeline name |
| 2 | SetName(timelineName) |
⚠️ | Returns False on active timeline |
| 3 | GetStartFrame() |
✅ | Returns start frame |
| 4 | GetEndFrame() |
✅ | Returns end frame |
| 5 | SetStartTimecode(timecode) |
✅ | Sets start timecode |
| 6 | GetStartTimecode() |
✅ | Returns "01:00:00:00" |
| 7 | GetTrackCount(trackType) |
✅ | Returns track count |
| 8 | AddTrack(trackType, subTrackType) |
✅ | Adds track |
| 9 | DeleteTrack(trackType, trackIndex) |
✅ | Deletes track |
| 10 | GetTrackSubType(trackType, trackIndex) |
✅ | Returns sub-type (e.g. "stereo") |
| 11 | SetTrackEnable(trackType, trackIndex, enabled) |
✅ | Enables/disables track |
| 12 | GetIsTrackEnabled(trackType, trackIndex) |
✅ | Returns enabled state |
| 13 | SetTrackLock(trackType, trackIndex, locked) |
✅ | Locks/unlocks track |
| 14 | GetIsTrackLocked(trackType, trackIndex) |
✅ | Returns lock state |
| 15 | DeleteClips([timelineItems], ripple) |
✅ | Deletes clips from timeline |
| 16 | SetClipsLinked([timelineItems], linked) |
✅ | Links/unlinks clips |
| 17 | GetItemListInTrack(trackType, index) |
✅ | Returns items on track |
| 18 | AddMarker(frameId, color, name, note, duration, customData) |
✅ | Adds timeline marker |
| 19 | GetMarkers() |
✅ | Returns marker dict |
| 20 | GetMarkerByCustomData(customData) |
✅ | Finds marker by data |
| 21 | UpdateMarkerCustomData(frameId, customData) |
✅ | Updates marker data |
| 22 | GetMarkerCustomData(frameId) |
✅ | Returns custom data |
| 23 | DeleteMarkersByColor(color) |
✅ | Deletes markers by color |
| 24 | DeleteMarkerAtFrame(frameNum) |
⚠️ | Returns False if no marker at frame |
| 25 | DeleteMarkerByCustomData(customData) |
⚠️ | Returns False if no match |
| 26 | GetCurrentTimecode() |
✅ | Returns timecode string |
| 27 | SetCurrentTimecode(timecode) |
⚠️ | Returns False if playback not active |
| 28 | GetCurrentVideoItem() |
✅ | Returns item at playhead |
| 29 | GetCurrentClipThumbnailImage() |
✅ | Returns thumbnail data |
| 30 | GetTrackName(trackType, trackIndex) |
✅ | Returns track name |
| 31 | SetTrackName(trackType, trackIndex, name) |
✅ | Sets track name |
| 32 | DuplicateTimeline(timelineName) |
✅ | Duplicates timeline |
| 33 | CreateCompoundClip([items], {clipInfo}) |
✅ | Returns compound clip item |
| 34 | CreateFusionClip([timelineItems]) |
✅ | Returns Fusion clip item |
| 35 | ImportIntoTimeline(filePath, {options}) |
⚠️ | Tested; result depends on file format |
| 36 | Export(fileName, exportType, exportSubtype) |
✅ | Exports EDL/XML/AAF |
| 37 | GetSetting(settingName) |
✅ | Returns settings dict |
| 38 | SetSetting(settingName, settingValue) |
⚠️ | API accepts; some settings read-only |
| 39 | InsertGeneratorIntoTimeline(name) |
✅ | Inserts generator |
| 40 | InsertFusionGeneratorIntoTimeline(name) |
✅ | Inserts Fusion generator |
| 41 | InsertFusionCompositionIntoTimeline() |
✅ | Inserts Fusion composition |
| 42 | InsertOFXGeneratorIntoTimeline(name) |
⚠️ | API accepts; needs valid OFX plugin |
| 43 | InsertTitleIntoTimeline(name) |
✅ | Inserts title |
| 44 | InsertFusionTitleIntoTimeline(name) |
✅ | Inserts Fusion title |
| 45 | GrabStill() |
✅ | Returns GalleryStill object |
| 46 | GrabAllStills(stillFrameSource) |
✅ | Returns list of GalleryStill objects |
| 47 | GetUniqueId() |
✅ | Returns UUID string |
| 48 | CreateSubtitlesFromAudio({settings}) |
✅ | Returns True — creates subtitles from audio |
| 49 | DetectSceneCuts() |
✅ | Returns True — detects scene cuts in timeline |
| 50 | ConvertTimelineToStereo() |
✅ | Converts timeline to stereo 3D |
| 51 | GetNodeGraph() |
✅ | Returns Graph object |
| 52 | AnalyzeDolbyVision([items], analysisType) |
🔬 | Requires HDR/Dolby Vision content |
| 53 | GetMediaPoolItem() |
✅ | Returns MediaPoolItem for timeline |
| 54 | GetMarkInOut() |
✅ | Returns mark in/out dict |
| 55 | SetMarkInOut(in, out, type) |
✅ | Sets mark in/out |
| 56 | ClearMarkInOut(type) |
✅ | Clears mark in/out |
| # | Method | Status | Test Result / Notes |
|---|---|---|---|
| 1 | GetName() |
✅ | Returns item name |
| 2 | GetDuration(subframe_precision) |
✅ | Returns duration |
| 3 | GetEnd(subframe_precision) |
✅ | Returns end frame |
| 4 | GetSourceEndFrame() |
✅ | Returns source end frame |
| 5 | GetSourceEndTime() |
✅ | Returns source end time |
| 6 | GetFusionCompCount() |
✅ | Returns comp count |
| 7 | GetFusionCompByIndex(compIndex) |
✅ | Returns Fusion composition |
| 8 | GetFusionCompNameList() |
✅ | Returns comp names |
| 9 | GetFusionCompByName(compName) |
✅ | Returns Fusion composition |
| 10 | GetLeftOffset(subframe_precision) |
✅ | Returns left offset |
| 11 | GetRightOffset(subframe_precision) |
✅ | Returns right offset |
| 12 | GetStart(subframe_precision) |
✅ | Returns start frame |
| 13 | GetSourceStartFrame() |
✅ | Returns source start |
| 14 | GetSourceStartTime() |
✅ | Returns source start time |
| 15 | SetProperty(propertyKey, propertyValue) |
✅ | Sets item property |
| 16 | GetProperty(propertyKey) |
✅ | Returns property dict |
| 17 | AddMarker(frameId, color, name, note, duration, customData) |
✅ | Adds marker to item |
| 18 | GetMarkers() |
✅ | Returns marker dict |
| 19 | GetMarkerByCustomData(customData) |
✅ | Finds marker by data |
| 20 | UpdateMarkerCustomData(frameId, customData) |
✅ | Updates marker data |
| 21 | GetMarkerCustomData(frameId) |
✅ | Returns custom data |
| 22 | DeleteMarkersByColor(color) |
✅ | Deletes markers by color |
| 23 | DeleteMarkerAtFrame(frameNum) |
⚠️ | Returns False if no marker at frame |
| 24 | DeleteMarkerByCustomData(customData) |
⚠️ | Returns False if no match |
| 25 | AddFlag(color) |
✅ | Adds flag |
| 26 | GetFlagList() |
✅ | Returns flag colors |
| 27 | ClearFlags(color) |
✅ | Clears flags |
| 28 | GetClipColor() |
✅ | Returns clip color |
| 29 | SetClipColor(colorName) |
✅ | Sets clip color |
| 30 | ClearClipColor() |
✅ | Clears clip color |
| 31 | AddFusionComp() |
✅ | Creates Fusion composition |
| 32 | ImportFusionComp(path) |
✅ | Imports .comp file |
| 33 | ExportFusionComp(path, compIndex) |
✅ | Exports .comp file |
| 34 | DeleteFusionCompByName(compName) |
⚠️ | Returns False if comp not found |
| 35 | LoadFusionCompByName(compName) |
✅ | Loads composition |
| 36 | RenameFusionCompByName(oldName, newName) |
✅ | Renames composition |
| 37 | AddVersion(versionName, versionType) |
✅ | Adds grade version |
| 38 | GetCurrentVersion() |
✅ | Returns version info |
| 39 | DeleteVersionByName(versionName, versionType) |
⚠️ | Returns False if version not found |
| 40 | LoadVersionByName(versionName, versionType) |
✅ | Loads grade version |
| 41 | RenameVersionByName(oldName, newName, type) |
✅ | Renames version |
| 42 | GetVersionNameList(versionType) |
✅ | Returns version names |
| 43 | GetMediaPoolItem() |
✅ | Returns source MediaPoolItem |
| 44 | GetStereoConvergenceValues() |
✅ | Returns stereo keyframes |
| 45 | GetStereoLeftFloatingWindowParams() |
✅ | Returns stereo params |
| 46 | GetStereoRightFloatingWindowParams() |
✅ | Returns stereo params |
| 47 | SetCDL([CDL map]) |
✅ | Sets CDL values |
| 48 | AddTake(mediaPoolItem, startFrame, endFrame) |
✅ | Adds take |
| 49 | GetSelectedTakeIndex() |
✅ | Returns selected take index |
| 50 | GetTakesCount() |
✅ | Returns take count |
| 51 | GetTakeByIndex(idx) |
✅ | Returns take info |
| 52 | DeleteTakeByIndex(idx) |
✅ | Deletes take |
| 53 | SelectTakeByIndex(idx) |
✅ | Selects take |
| 54 | FinalizeTake() |
⚠️ | Returns False when no take selected |
| 55 | CopyGrades([tgtTimelineItems]) |
⚠️ | API accepts; needs matching items |
| 56 | SetClipEnabled(enabled) |
✅ | Enables/disables clip |
| 57 | GetClipEnabled() |
✅ | Returns enabled state |
| 58 | UpdateSidecar() |
⚠️ | Returns False for non-BRAW clips |
| 59 | GetUniqueId() |
✅ | Returns UUID string |
| 60 | LoadBurnInPreset(presetName) |
⚠️ | API accepts; preset must exist |
| 61 | CreateMagicMask(mode) |
⚠️ | Tested; needs DaVinci Neural Engine + Color page context |
| 62 | RegenerateMagicMask() |
⚠️ | Tested; needs existing mask |
| 63 | Stabilize() |
✅ | Returns True on supported clips |
| 64 | SmartReframe() |
⚠️ | Tested; needs specific aspect ratio setup |
| 65 | GetNodeGraph(layerIdx) |
✅ | Returns Graph object |
| 66 | GetColorGroup() |
✅ | Returns ColorGroup |
| 67 | AssignToColorGroup(colorGroup) |
✅ | Assigns to group |
| 68 | RemoveFromColorGroup() |
⚠️ | Returns False if not in group |
| 69 | ExportLUT(exportType, path) |
✅ | Exports LUT file |
| 70 | GetLinkedItems() |
✅ | Returns linked items |
| 71 | GetTrackTypeAndIndex() |
✅ | Returns [trackType, trackIndex] |
| 72 | GetSourceAudioChannelMapping() |
✅ | Returns audio mapping |
| 73 | GetIsColorOutputCacheEnabled() |
✅ | Returns cache state |
| 74 | GetIsFusionOutputCacheEnabled() |
✅ | Returns cache state |
| 75 | SetColorOutputCache(cache_value) |
⚠️ | Tested; needs active color pipeline |
| 76 | SetFusionOutputCache(cache_value) |
⚠️ | Tested; needs active Fusion pipeline |
| # | Method | Status | Test Result / Notes |
|---|---|---|---|
| 1 | GetAlbumName(galleryStillAlbum) |
✅ | Returns album name |
| 2 | SetAlbumName(galleryStillAlbum, albumName) |
✅ | Sets album name |
| 3 | GetCurrentStillAlbum() |
✅ | Returns GalleryStillAlbum |
| 4 | SetCurrentStillAlbum(galleryStillAlbum) |
✅ | Sets current album |
| 5 | GetGalleryStillAlbums() |
✅ | Returns album list |
| 6 | GetGalleryPowerGradeAlbums() |
✅ | Returns power grade albums |
| 7 | CreateGalleryStillAlbum() |
✅ | Creates still album |
| 8 | CreateGalleryPowerGradeAlbum() |
✅ | Creates power grade album |
| # | Method | Status | Test Result / Notes |
|---|---|---|---|
| 1 | GetStills() |
✅ | Returns list of GalleryStill objects |
| 2 | GetLabel(galleryStill) |
✅ | Returns label string |
| 3 | SetLabel(galleryStill, label) |
⚠️ | API accepts; may not persist in all versions |
| 4 | ImportStills([filePaths]) |
✅ | Imports DRX still files (requires Color page) |
| 5 | ExportStills([stills], folderPath, prefix, format) |
✅ | Exports stills as image + companion .drx grade file. Requires Color page with Gallery panel visible. Supported formats: dpx, cin, tif, jpg, png, ppm, bmp, xpm, drx. |
| 6 | DeleteStills([galleryStill]) |
✅ | Deletes stills from album |
Note (v2.0.8+): The compound server's
gallery_stillstool includes agrab_and_exportaction that combinesGrabStill()+ExportStills()in a single call — more reliable than calling them separately since it keeps the live GalleryStill reference. Returns the list of exported files (image + .drx grade data). Requires the Color page with the Gallery panel open.
| # | Method | Status | Test Result / Notes |
|---|---|---|---|
| 1 | GetNumNodes() |
✅ | Returns node count (via ColorGroup pre/post graphs) |
| 2 | SetLUT(nodeIndex, lutPath) |
✅ | Sets LUT on node |
| 3 | GetLUT(nodeIndex) |
✅ | Returns LUT path |
| 4 | SetNodeCacheMode(nodeIndex, cache_value) |
✅ | Returns True |
| 5 | GetNodeCacheMode(nodeIndex) |
✅ | Returns -1 (no cache mode set) |
| 6 | GetNodeLabel(nodeIndex) |
✅ | Returns node label string |
| 7 | GetToolsInNode(nodeIndex) |
✅ | Returns None (no OFX tools in node) |
| 8 | SetNodeEnabled(nodeIndex, isEnabled) |
✅ | Returns True |
| 9 | ApplyGradeFromDRX(path, gradeMode) |
✅ | Applies grade from DRX file |
| 10 | ApplyArriCdlLut() |
✅ | Applies ARRI CDL LUT |
| 11 | ResetAllGrades() |
✅ | Resets all grades |
| # | Method | Status | Test Result / Notes |
|---|---|---|---|
| 1 | GetName() |
✅ | Returns group name |
| 2 | SetName(groupName) |
✅ | Sets group name |
| 3 | GetClipsInTimeline(timeline) |
✅ | Returns clips in group |
| 4 | GetPreClipNodeGraph() |
✅ | Returns Graph object |
| 5 | GetPostClipNodeGraph() |
✅ | Returns Graph object |
We welcome contributions! The following areas especially need help:
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:
Cloud Project Methods (4 methods) — Need DaVinci Resolve cloud infrastructure:
ProjectManager.CreateCloudProjectProjectManager.LoadCloudProjectProjectManager.ImportCloudProjectProjectManager.RestoreCloudProjectHDR Analysis (1 method) — Needs specific content:
Timeline.AnalyzeDolbyVision — needs HDR/Dolby Vision contentgit checkout -b feature/my-contribution)| Platform | Status | Resolve Paths Auto-Detected | Notes |
|---|---|---|---|
| macOS | ✅ Tested | /Library/Application Support/Blackmagic Design/... |
Primary development and test platform |
| Windows | ✅ Supported | C:\ProgramData\Blackmagic Design\... |
Community-tested; PRs welcome |
| Linux | ⚠️ Experimental | /opt/resolve/... |
Should work — testing and feedback welcome |
This MCP server controls DaVinci Resolve via its Scripting API. Some tools perform actions that are destructive or interact with the host filesystem:
| Tool | Risk | Mitigation |
|---|---|---|
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). |
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+). |
save_project |
Creates and removes a temporary .drp file in the system temp directory |
Path is constructed server-side with no LLM-controlled input. |
Recommendations for MCP client developers:
quit_app, restart_app, delete_layout_preset)davinci-resolve-mcp/
├── install.py # Universal installer (macOS/Windows/Linux)
├── src/
│ ├── server.py # Compound MCP server — 27 tools (default)
│ ├── resolve_mcp_server.py # Full MCP server — 342 tools (power users)
│ └── utils/ # Platform detection, Resolve connection helpers
├── tests/ # 5-phase live API test suite (319/319 pass)
├── docs/
│ └── resolve_scripting_api.txt # Official Resolve Scripting API reference
└── examples/ # Getting started, markers, media, timeline examples
MIT
Samuel Gursky ([email protected])
Add this to claude_desktop_config.json and restart Claude Desktop.
{
"mcpServers": {
"samuelgursky-davinci-resolve-mcp": {
"command": "npx",
"args": []
}
}
}