davinci-resolve-mcp 2.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +85 -0
- package/CHANGELOG.md +802 -0
- package/CLAUDE.md +15 -0
- package/LICENSE +21 -0
- package/README.md +159 -0
- package/SECURITY.md +53 -0
- package/bin/davinci-resolve-mcp.mjs +376 -0
- package/docs/README.md +56 -0
- package/docs/SKILL.md +1145 -0
- package/docs/authoring/fuse-dctl-authoring.md +242 -0
- package/docs/authoring/script-plugin-authoring.md +195 -0
- package/docs/contributing.md +82 -0
- package/docs/guides/color-decision-guide.md +387 -0
- package/docs/guides/editorial-decision-guide.md +136 -0
- package/docs/guides/media-analysis-guide.md +615 -0
- package/docs/guides/multicam-setup-guide.md +138 -0
- package/docs/install.md +198 -0
- package/docs/integrations/workflow-integrations.md +120 -0
- package/docs/kernels/README.md +28 -0
- package/docs/kernels/audio-fairlight-kernel.md +86 -0
- package/docs/kernels/color-grade-kernel.md +103 -0
- package/docs/kernels/extension-authoring-kernel.md +101 -0
- package/docs/kernels/fusion-composition-kernel.md +91 -0
- package/docs/kernels/media-pool-ingest-kernel.md +147 -0
- package/docs/kernels/project-lifecycle-kernel.md +120 -0
- package/docs/kernels/render-deliver-kernel.md +92 -0
- package/docs/kernels/review-annotation-kernel.md +110 -0
- package/docs/kernels/timeline-conform-interchange-kernel.md +99 -0
- package/docs/kernels/timeline-edit-kernel.md +189 -0
- package/docs/notes/codec-plugin-notes.md +136 -0
- package/docs/notes/dctl-notes.md +234 -0
- package/docs/notes/fusion-template-notes.md +136 -0
- package/docs/notes/lut-notes.md +136 -0
- package/docs/notes/openfx-notes.md +120 -0
- package/docs/process/release-process.md +152 -0
- package/docs/reference/api-coverage.md +488 -0
- package/docs/reference/resolve_scripting_api.txt +1012 -0
- package/examples/README.md +53 -0
- package/examples/markers/README.md +81 -0
- package/examples/media/README.md +94 -0
- package/examples/timeline/README.md +98 -0
- package/install.py +1196 -0
- package/package.json +52 -0
- package/scripts/audit_api_parity.py +275 -0
- package/scripts/live_media_analysis_polish_probe.py +65 -0
- package/src/__init__.py +3 -0
- package/src/analysis_dashboard.py +4936 -0
- package/src/control_panel.py +13 -0
- package/src/granular/__init__.py +17 -0
- package/src/granular/common.py +727 -0
- package/src/granular/folder.py +287 -0
- package/src/granular/gallery.py +306 -0
- package/src/granular/graph.py +309 -0
- package/src/granular/media_pool.py +679 -0
- package/src/granular/media_pool_item.py +852 -0
- package/src/granular/media_storage.py +179 -0
- package/src/granular/project.py +1594 -0
- package/src/granular/resolve_control.py +521 -0
- package/src/granular/timeline.py +1074 -0
- package/src/granular/timeline_item.py +2251 -0
- package/src/resolve_mcp_server.py +43 -0
- package/src/server.py +15691 -0
- package/src/utils/__init__.py +3 -0
- package/src/utils/app_control.py +319 -0
- package/src/utils/audio_fairlight_live_probe.py +263 -0
- package/src/utils/cdl.py +20 -0
- package/src/utils/cloud_operations.py +192 -0
- package/src/utils/color_grade_live_probe.py +444 -0
- package/src/utils/dctl_templates.py +368 -0
- package/src/utils/extension_authoring_live_probe.py +292 -0
- package/src/utils/fuse_templates.py +1968 -0
- package/src/utils/fusion_composition_live_probe.py +284 -0
- package/src/utils/layout_presets.py +333 -0
- package/src/utils/mcp_stdio.py +32 -0
- package/src/utils/media_analysis.py +3618 -0
- package/src/utils/media_analysis_jobs.py +796 -0
- package/src/utils/media_pool_ingest_live_probe.py +592 -0
- package/src/utils/multicam.py +393 -0
- package/src/utils/object_inspection.py +287 -0
- package/src/utils/platform.py +157 -0
- package/src/utils/project_lifecycle_live_probe.py +376 -0
- package/src/utils/project_properties.py +601 -0
- package/src/utils/render_deliver_live_probe.py +384 -0
- package/src/utils/resolve_connection.py +77 -0
- package/src/utils/review_annotation_live_probe.py +352 -0
- package/src/utils/script_templates.py +1193 -0
- package/src/utils/sync_detection.py +887 -0
- package/src/utils/timeline_conform_live_probe.py +280 -0
- package/src/utils/timeline_kernel_live_probe.py +1091 -0
- package/src/utils/timeline_kernel_probe.py +185 -0
- package/src/utils/timeline_title_text.py +87 -0
- package/src/utils/update_check.py +610 -0
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Claude Code Instructions
|
|
2
|
+
|
|
3
|
+
This file is intentionally short. The canonical AI-agent instructions for this
|
|
4
|
+
repository live in `AGENTS.md`.
|
|
5
|
+
|
|
6
|
+
Claude Code users should follow:
|
|
7
|
+
|
|
8
|
+
- `AGENTS.md` for repository rules and source media safety
|
|
9
|
+
- `docs/SKILL.md` for DaVinci Resolve MCP operating guidance
|
|
10
|
+
- `docs/process/release-process.md` for version bumps, validation, tags, and
|
|
11
|
+
GitHub Releases
|
|
12
|
+
- `docs/guides/media-analysis-guide.md` for source-safe media analysis
|
|
13
|
+
|
|
14
|
+
Do not maintain a separate release checklist, tool-count summary, or changelog
|
|
15
|
+
here. Those details drift; use the docs above as the source of truth.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025-2026 DaVinci Resolve MCP Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
# DaVinci Resolve MCP Server
|
|
2
|
+
|
|
3
|
+
[](https://github.com/samuelgursky/davinci-resolve-mcp/releases)
|
|
4
|
+
[](docs/reference/api-coverage.md)
|
|
5
|
+
[-blue.svg)](#server-modes)
|
|
6
|
+
[](docs/reference/api-coverage.md#test-results)
|
|
7
|
+
[](https://www.blackmagicdesign.com/products/davinciresolve)
|
|
8
|
+
[](https://www.python.org/downloads/)
|
|
9
|
+
[](https://opensource.org/licenses/MIT)
|
|
10
|
+
|
|
11
|
+
A Model Context Protocol (MCP) server that lets AI assistants control DaVinci Resolve Studio through the official Scripting API. It provides full API coverage plus guarded workflow helpers for editing, media pool organization, render setup, review markers, grading, Fusion, Fairlight, project lifecycle tasks, extension authoring, and source-safe media analysis.
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npx davinci-resolve-mcp setup
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Before connecting, open DaVinci Resolve Studio and set **Preferences > General > External scripting using** to **Local**. The npm launcher installs a managed copy under your user application-data directory, then runs the universal Python installer. The installer creates a virtual environment, detects Resolve paths, and can configure Claude Desktop, Claude Code, Cursor, VS Code, Windsurf, Zed, Continue, Cline, Roo Code, and JetBrains IDEs.
|
|
20
|
+
|
|
21
|
+
For source installs:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
git clone https://github.com/samuelgursky/davinci-resolve-mcp.git
|
|
25
|
+
cd davinci-resolve-mcp
|
|
26
|
+
python install.py
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
For platform paths, client-specific config, and manual setup, see [Installation and Configuration](docs/install.md).
|
|
30
|
+
|
|
31
|
+
The installer and server check the latest GitHub release for MCP updates. Checks are best-effort and throttled; the server never blocks MCP startup for a prompt. The installer can prompt, snooze, ignore a release, disable checks, or apply an opt-in safe auto-update for clean git checkouts.
|
|
32
|
+
|
|
33
|
+
## Local Control Panel
|
|
34
|
+
|
|
35
|
+
Launch the single-user local control panel from the repository root:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
venv/bin/python -m src.control_panel
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
The command starts a localhost server and opens the control panel in your browser. To have an AI coding agent do this, ask: **"Open the Resolve MCP control panel for this repo."** Agents should use `venv/bin/python -m src.control_panel` unless your Python environment is already active. Persisted analysis jobs refresh the local search index automatically after successful slices; the manual Build Index action is for rebuilding from existing reports.
|
|
42
|
+
|
|
43
|
+
## Server Modes
|
|
44
|
+
|
|
45
|
+
| Mode | Entry point | Tools | Best for |
|
|
46
|
+
|------|-------------|-------|----------|
|
|
47
|
+
| Compound | `src/server.py` | 32 | Default mode for most assistants. Related Resolve operations are grouped behind action parameters to keep context usage low. |
|
|
48
|
+
| Full / granular | `src/server.py --full` or `src/resolve_mcp_server.py` | 329 | Power users who want one MCP tool per Resolve API method. |
|
|
49
|
+
|
|
50
|
+
The compound server is recommended unless you specifically need the granular one-tool-per-method surface.
|
|
51
|
+
|
|
52
|
+
## What You Can Do
|
|
53
|
+
|
|
54
|
+
```text
|
|
55
|
+
"List all projects and open the one called 'My Film'"
|
|
56
|
+
"Create a timeline called 'Assembly Cut' from all clips in the current bin"
|
|
57
|
+
"Build a multicam prep timeline from selected camera angles and preserve source media"
|
|
58
|
+
"Detect 2-pops or slate claps and suggest record offsets for sync prep"
|
|
59
|
+
"Publish analysis summaries, keywords, people, and slate hints into Resolve clip metadata"
|
|
60
|
+
"Probe this timeline for gaps, overlaps, missing media, and source frame ranges"
|
|
61
|
+
"Safely import this image sequence, organize it into bins, and normalize clip metadata"
|
|
62
|
+
"Build a ProRes 422 HQ render plan, validate the settings, and queue the job"
|
|
63
|
+
"Copy review markers from the timeline to the selected clip and export a review report"
|
|
64
|
+
"Snapshot this clip's grade, validate a CDL update, and export a temp LUT"
|
|
65
|
+
"Create a Fusion TextPlus overlay on the selected clip and verify graph connections"
|
|
66
|
+
"Report audio channel mappings, voice isolation availability, and subtitle support"
|
|
67
|
+
"Install this MCP-marked DCTL or script, classify refresh/restart needs, then remove it"
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Core Capabilities
|
|
71
|
+
|
|
72
|
+
| Area | What the compound server supports |
|
|
73
|
+
|------|-----------------------------------|
|
|
74
|
+
| App and project control | Launch/reconnect, page switching, project CRUD, project folders, databases, cloud project wrappers, settings, presets, archives |
|
|
75
|
+
| Media pool and ingest | Safe import, image sequences, multicam prep timelines, bin organization, metadata normalization, metadata field inventory, marks, annotations, relink/proxy/full-resolution guards |
|
|
76
|
+
| Media analysis | Source-safe file/clip/bin/project analysis, 2-pop/slate-clap sync-event detection, confirmed Resolve metadata publishing, session-only defaults, existing-report reuse, chat-context visual analysis by default in `analyze_media` with opt-out, optional transcription |
|
|
77
|
+
| Timeline editing and conform | Track/item probing, title text key scans/writes, copy/move/duplicate helpers, range operations, gaps/overlaps, source ranges, checked interchange exports/imports |
|
|
78
|
+
| Review annotations | Timeline/item/clip markers, custom data, flags, clip color, copy/move/sync cleanup, review reports, marker thumbnail review |
|
|
79
|
+
| Color and grading | Node graph probing, CDL validation, grade copy, DRX/LUT helpers, versions, Gallery stills, color groups |
|
|
80
|
+
| Fusion | Timeline-item comps, safe tool creation, input writes, port inspection, validated connections, scoped bulk writes |
|
|
81
|
+
| Audio and Fairlight | Track/item probes, source mapping, guarded audio property writes, voice isolation, auto-sync planning, transcription/subtitle probes |
|
|
82
|
+
| Render and deliver | Format/codec matrix probing, render settings validation, queued job lifecycle checks, guarded Quick Export |
|
|
83
|
+
| Extension authoring | Fuse, DCTL, ACES DCTL, and Resolve-page Lua/Python script lifecycle helpers with safe MCP-marked install/remove |
|
|
84
|
+
|
|
85
|
+
## Source Media Safety
|
|
86
|
+
|
|
87
|
+
This project treats camera originals and source media as immutable. Analysis tools read source files and write reports only to sidecar, scratch, or project analysis directories; confirmed metadata publishing writes only to Resolve's project database. The server must not modify, transcode, proxy, or create derivatives of source media unless the user explicitly asks for that. See [Media Analysis Guide](docs/guides/media-analysis-guide.md) for the detailed source-safe workflow.
|
|
88
|
+
|
|
89
|
+
## Security Posture
|
|
90
|
+
|
|
91
|
+
The default server is a local stdio process launched by your MCP client; it does not expose a network listener or built-in multi-user auth surface. Tool metadata includes MCP client-safety hints for read-only, destructive, idempotent, and external-resource operations. See [Security Policy](SECURITY.md) for operational boundaries, confirmation guidance, and vulnerability reporting.
|
|
92
|
+
|
|
93
|
+
## Key Stats
|
|
94
|
+
|
|
95
|
+
| Metric | Value |
|
|
96
|
+
|--------|-------|
|
|
97
|
+
| MCP Tools | **32** compound / **329** granular |
|
|
98
|
+
| Kernel Actions | **136** guarded workflow actions across 9 compound tools |
|
|
99
|
+
| API Methods Covered | **336/336** (100%) |
|
|
100
|
+
| Methods Live Tested | **331/336** (98.5%) |
|
|
101
|
+
| Live Test Pass Rate | **331/331** (100%) |
|
|
102
|
+
| Tested Against | DaVinci Resolve 19.1.3 Studio + Resolve 20.3.2 Studio |
|
|
103
|
+
|
|
104
|
+
For method-by-method status, see [API Coverage and Test Results](docs/reference/api-coverage.md). For current workflow support, see [Kernel Action Coverage](docs/kernels/README.md).
|
|
105
|
+
|
|
106
|
+
`analyze_media` uses in-chat visual analysis by default when the MCP client supports sampling/image messages. Pass `include_visuals=false` for technical-only or privacy-sensitive runs. If in-chat vision is unavailable, analysis continues with local technical/motion evidence and reports the skipped visual layer. `media_analysis.publish_clip_metadata` can publish confirmed analysis summaries, comments, keywords, people, and high-confidence slate fields back to Resolve clip metadata while preserving existing human-entered fields by default.
|
|
107
|
+
|
|
108
|
+
## Documentation
|
|
109
|
+
|
|
110
|
+
| Document | Use it for |
|
|
111
|
+
|----------|------------|
|
|
112
|
+
| [Installation and Configuration](docs/install.md) | Requirements, installer options, supported clients, server modes, manual config |
|
|
113
|
+
| [API Coverage and Test Results](docs/reference/api-coverage.md) | Key stats, API coverage table, live-test status, full method reference |
|
|
114
|
+
| [Kernel Action Coverage](docs/kernels/README.md) | Current guarded workflow action map |
|
|
115
|
+
| [AI Skill Reference](docs/SKILL.md) | Operational context for AI assistants using the compound server |
|
|
116
|
+
| [Media Analysis Guide](docs/guides/media-analysis-guide.md) | Source-safe FFprobe, FFmpeg, Whisper, sidecar, and analysis-root workflows |
|
|
117
|
+
| [Multicam Setup Helper Guide](docs/guides/multicam-setup-guide.md) | Stacked timeline prep, helper/API boundary, and Resolve UI conversion steps |
|
|
118
|
+
| [Editorial Decision Guide](docs/guides/editorial-decision-guide.md) | Project-owned editorial craft guidance for analysis and timeline decisions |
|
|
119
|
+
| [Color Decision Guide](docs/guides/color-decision-guide.md) | Project-owned color correction guidance and Resolve color API boundaries |
|
|
120
|
+
| [Contributing and Project Layout](docs/contributing.md) | Contribution workflow, platform support, security notes, repository structure |
|
|
121
|
+
| [Security Policy](SECURITY.md) | Local stdio trust boundary, tool metadata, confirmation guidance, reporting |
|
|
122
|
+
| [Release Process](docs/process/release-process.md) | Maintainer release checklist, version surfaces, validation, tags, and release notes |
|
|
123
|
+
| [Changelog](CHANGELOG.md) | Historical release notes |
|
|
124
|
+
|
|
125
|
+
Extension authoring references live in [docs/authoring](docs/authoring/). Resolve developer-package notes live in [docs/notes](docs/notes/) and [docs/integrations](docs/integrations/). Prompt recipes live in [examples](examples/).
|
|
126
|
+
|
|
127
|
+
## Requirements
|
|
128
|
+
|
|
129
|
+
- DaVinci Resolve Studio 18.5+ on macOS, Windows, or Linux. The free edition does not support external scripting.
|
|
130
|
+
- Python 3.10-3.12 recommended. Python 3.13+ may have ABI incompatibilities with Resolve's scripting library.
|
|
131
|
+
- Resolve external scripting set to **Local**.
|
|
132
|
+
|
|
133
|
+
Resolve 19.1.3 remains the compatibility baseline. Resolve 20.x scripting calls are additive, version-guarded, and live-tested on 20.3.2. Resolve 21 beta APIs are intentionally deferred until stable.
|
|
134
|
+
|
|
135
|
+
## Development
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
python src/server.py # Compound server
|
|
139
|
+
python src/server.py --full # Granular server
|
|
140
|
+
venv/bin/python tests/test_import.py
|
|
141
|
+
venv/bin/python scripts/audit_api_parity.py
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Release and validation rules are in [docs/process/release-process.md](docs/process/release-process.md). AI agents working in this repository should start with [AGENTS.md](AGENTS.md); Claude Code users can also read [CLAUDE.md](CLAUDE.md), which points to the same canonical instructions.
|
|
145
|
+
|
|
146
|
+
## License
|
|
147
|
+
|
|
148
|
+
MIT
|
|
149
|
+
|
|
150
|
+
## Author
|
|
151
|
+
|
|
152
|
+
Samuel Gursky (samgursky@gmail.com)
|
|
153
|
+
- GitHub: [github.com/samuelgursky](https://github.com/samuelgursky)
|
|
154
|
+
|
|
155
|
+
## Acknowledgments
|
|
156
|
+
|
|
157
|
+
- Blackmagic Design for DaVinci Resolve and its scripting API
|
|
158
|
+
- The Model Context Protocol team for enabling AI assistant integration
|
|
159
|
+
- Anthropic for Claude Code, used extensively in development and testing
|
package/SECURITY.md
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Security Policy
|
|
2
|
+
|
|
3
|
+
## Supported Use
|
|
4
|
+
|
|
5
|
+
`davinci-resolve-mcp` is a local stdio MCP server for controlling DaVinci
|
|
6
|
+
Resolve Studio through the official Resolve Scripting API. It is intended to run
|
|
7
|
+
under the same local user account that operates Resolve.
|
|
8
|
+
|
|
9
|
+
The default server does not expose a network listener, HTTP API, remote shell, or
|
|
10
|
+
multi-user authentication surface. Access control is delegated to the MCP client
|
|
11
|
+
that launches the stdio process and to the local operating-system user session.
|
|
12
|
+
|
|
13
|
+
## Operational Boundaries
|
|
14
|
+
|
|
15
|
+
- Keep Resolve external scripting set to **Local** unless you have a separate,
|
|
16
|
+
intentional remote-control deployment plan.
|
|
17
|
+
- Treat the MCP client as the user-confirmation boundary. Clients should ask for
|
|
18
|
+
confirmation before destructive or high-impact actions such as quitting
|
|
19
|
+
Resolve, deleting projects, replacing clips, relinking media, deleting markers,
|
|
20
|
+
changing render/project settings, or installing/removing scripts, Fuses, DCTLs,
|
|
21
|
+
and presets.
|
|
22
|
+
- Source media is immutable by default. This server must not modify, transcode,
|
|
23
|
+
proxy, relink, replace, or create derivatives of source media unless the user
|
|
24
|
+
explicitly asks for that exact operation.
|
|
25
|
+
- Analysis outputs belong in sidecar files, session scratch space, or the
|
|
26
|
+
configured `davinci-resolve-mcp-analysis` project root.
|
|
27
|
+
|
|
28
|
+
## Tool Metadata
|
|
29
|
+
|
|
30
|
+
Tools use MCP `ToolAnnotations` where supported:
|
|
31
|
+
|
|
32
|
+
- `readOnlyHint` for probe/list/get operations.
|
|
33
|
+
- `destructiveHint` for operations that overwrite, delete, relink, replace,
|
|
34
|
+
change project state, or can otherwise cause meaningful workflow impact.
|
|
35
|
+
- `idempotentHint` for repeatable state changes such as page switching.
|
|
36
|
+
- `openWorldHint` for operations that touch filesystem paths, media, render
|
|
37
|
+
output, scripts, Fuses, DCTLs, presets, or other external resources.
|
|
38
|
+
|
|
39
|
+
Compound tools group multiple actions behind an `action` parameter, so their
|
|
40
|
+
annotation is conservative when any action in the group can mutate state.
|
|
41
|
+
|
|
42
|
+
## Reporting Vulnerabilities
|
|
43
|
+
|
|
44
|
+
Please report security issues privately by opening a GitHub security advisory or
|
|
45
|
+
emailing the maintainer listed in the README. Include:
|
|
46
|
+
|
|
47
|
+
- Affected version or commit.
|
|
48
|
+
- MCP client and operating system.
|
|
49
|
+
- Minimal reproduction steps.
|
|
50
|
+
- Expected and actual impact.
|
|
51
|
+
|
|
52
|
+
Please do not publish exploit details until there is a coordinated fix or a
|
|
53
|
+
reasonable disclosure window has passed.
|
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { spawn, spawnSync } from "node:child_process";
|
|
4
|
+
import fs from "node:fs";
|
|
5
|
+
import os from "node:os";
|
|
6
|
+
import path from "node:path";
|
|
7
|
+
import { fileURLToPath } from "node:url";
|
|
8
|
+
|
|
9
|
+
const APP_NAME = "davinci-resolve-mcp";
|
|
10
|
+
const PACKAGE_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
11
|
+
const VERSION = readPackageVersion();
|
|
12
|
+
const MANAGED_MARKER = ".davinci-resolve-mcp-managed.json";
|
|
13
|
+
|
|
14
|
+
const SYNC_ITEMS = [
|
|
15
|
+
"bin",
|
|
16
|
+
"src",
|
|
17
|
+
"docs",
|
|
18
|
+
"examples",
|
|
19
|
+
"scripts",
|
|
20
|
+
"install.py",
|
|
21
|
+
"README.md",
|
|
22
|
+
"CHANGELOG.md",
|
|
23
|
+
"LICENSE",
|
|
24
|
+
"SECURITY.md",
|
|
25
|
+
"AGENTS.md",
|
|
26
|
+
"CLAUDE.md",
|
|
27
|
+
"package.json",
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
function readPackageVersion() {
|
|
31
|
+
const packageJsonPath = path.join(PACKAGE_ROOT, "package.json");
|
|
32
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
|
|
33
|
+
return packageJson.version;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function usage() {
|
|
37
|
+
return `DaVinci Resolve MCP ${VERSION}
|
|
38
|
+
|
|
39
|
+
Usage:
|
|
40
|
+
davinci-resolve-mcp setup [install.py options]
|
|
41
|
+
davinci-resolve-mcp doctor [install.py options]
|
|
42
|
+
davinci-resolve-mcp server [server.py options]
|
|
43
|
+
davinci-resolve-mcp control-panel [control panel options]
|
|
44
|
+
davinci-resolve-mcp --version
|
|
45
|
+
davinci-resolve-mcp --help
|
|
46
|
+
|
|
47
|
+
Examples:
|
|
48
|
+
npx davinci-resolve-mcp setup
|
|
49
|
+
npx davinci-resolve-mcp setup --clients cursor,claude-desktop
|
|
50
|
+
npx davinci-resolve-mcp doctor
|
|
51
|
+
|
|
52
|
+
Environment:
|
|
53
|
+
DAVINCI_RESOLVE_MCP_INSTALL_ROOT Override the managed install directory.
|
|
54
|
+
DAVINCI_RESOLVE_MCP_PYTHON Python executable to use.
|
|
55
|
+
PYTHON Fallback Python executable to use.
|
|
56
|
+
`;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function defaultInstallRoot() {
|
|
60
|
+
if (process.platform === "darwin") {
|
|
61
|
+
return path.join(os.homedir(), "Library", "Application Support", APP_NAME);
|
|
62
|
+
}
|
|
63
|
+
if (process.platform === "win32") {
|
|
64
|
+
const localAppData = process.env.LOCALAPPDATA || path.join(os.homedir(), "AppData", "Local");
|
|
65
|
+
return path.join(localAppData, APP_NAME);
|
|
66
|
+
}
|
|
67
|
+
const dataHome = process.env.XDG_DATA_HOME || path.join(os.homedir(), ".local", "share");
|
|
68
|
+
return path.join(dataHome, APP_NAME);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function installRoot() {
|
|
72
|
+
return path.resolve(process.env.DAVINCI_RESOLVE_MCP_INSTALL_ROOT || defaultInstallRoot());
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function realPathIfExists(target) {
|
|
76
|
+
try {
|
|
77
|
+
return fs.realpathSync(target);
|
|
78
|
+
} catch {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function samePath(left, right) {
|
|
84
|
+
const leftReal = realPathIfExists(left);
|
|
85
|
+
const rightReal = realPathIfExists(right);
|
|
86
|
+
return Boolean(leftReal && rightReal && leftReal === rightReal);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function isRootOrHome(target) {
|
|
90
|
+
const resolved = path.resolve(target);
|
|
91
|
+
const parsed = path.parse(resolved);
|
|
92
|
+
return resolved === parsed.root || resolved === path.resolve(os.homedir());
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function validateManagedRoot(root) {
|
|
96
|
+
if (isRootOrHome(root)) {
|
|
97
|
+
throw new Error(`Refusing to use unsafe install root: ${root}`);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (!fs.existsSync(root)) {
|
|
101
|
+
fs.mkdirSync(root, { recursive: true });
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const entries = fs.readdirSync(root).filter((entry) => entry !== ".DS_Store");
|
|
106
|
+
if (entries.length === 0) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const marker = path.join(root, MANAGED_MARKER);
|
|
111
|
+
const knownInstall = fs.existsSync(path.join(root, "install.py")) &&
|
|
112
|
+
fs.existsSync(path.join(root, "src", "server.py"));
|
|
113
|
+
if (!fs.existsSync(marker) && !knownInstall) {
|
|
114
|
+
throw new Error(
|
|
115
|
+
`Refusing to update non-managed directory: ${root}\n` +
|
|
116
|
+
`Set DAVINCI_RESOLVE_MCP_INSTALL_ROOT to an empty directory or an existing ${APP_NAME} install.`
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function copyItem(name, destinationRoot) {
|
|
122
|
+
const source = path.join(PACKAGE_ROOT, name);
|
|
123
|
+
if (!fs.existsSync(source)) {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const destination = path.join(destinationRoot, name);
|
|
128
|
+
fs.rmSync(destination, { recursive: true, force: true });
|
|
129
|
+
fs.cpSync(source, destination, {
|
|
130
|
+
recursive: true,
|
|
131
|
+
errorOnExist: false,
|
|
132
|
+
force: true,
|
|
133
|
+
preserveTimestamps: true,
|
|
134
|
+
filter: (sourcePath) => shouldSyncPath(sourcePath),
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function shouldSyncPath(sourcePath) {
|
|
139
|
+
const basename = path.basename(sourcePath);
|
|
140
|
+
if (basename === "__pycache__" || basename === ".DS_Store") {
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
if (basename.endsWith(".pyc") || basename.endsWith(".pyo")) {
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function syncManagedInstall(root) {
|
|
150
|
+
validateManagedRoot(root);
|
|
151
|
+
if (samePath(PACKAGE_ROOT, root)) {
|
|
152
|
+
return root;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
for (const item of SYNC_ITEMS) {
|
|
156
|
+
copyItem(item, root);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const markerPath = path.join(root, MANAGED_MARKER);
|
|
160
|
+
fs.writeFileSync(
|
|
161
|
+
markerPath,
|
|
162
|
+
`${JSON.stringify({ name: APP_NAME, version: VERSION, managed: true, updatedAt: new Date().toISOString() }, null, 2)}\n`,
|
|
163
|
+
"utf8"
|
|
164
|
+
);
|
|
165
|
+
return root;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function commandExists(command, args = []) {
|
|
169
|
+
const result = spawnSync(command, [...args, "--version"], {
|
|
170
|
+
encoding: "utf8",
|
|
171
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
172
|
+
});
|
|
173
|
+
return result.status === 0;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function parseExecutable(value) {
|
|
177
|
+
if (!value) {
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
const trimmed = value.trim();
|
|
181
|
+
if (!trimmed) {
|
|
182
|
+
return null;
|
|
183
|
+
}
|
|
184
|
+
return { command: trimmed, args: [] };
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function pythonCandidates() {
|
|
188
|
+
const explicit = parseExecutable(process.env.DAVINCI_RESOLVE_MCP_PYTHON || process.env.PYTHON);
|
|
189
|
+
const candidates = [];
|
|
190
|
+
if (explicit) {
|
|
191
|
+
candidates.push(explicit);
|
|
192
|
+
}
|
|
193
|
+
if (process.platform === "win32" && commandExists("py")) {
|
|
194
|
+
candidates.push(
|
|
195
|
+
{ command: "py", args: ["-3.12"] },
|
|
196
|
+
{ command: "py", args: ["-3.11"] },
|
|
197
|
+
{ command: "py", args: ["-3.10"] }
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
candidates.push(
|
|
201
|
+
{ command: "python3.12", args: [] },
|
|
202
|
+
{ command: "python3.11", args: [] },
|
|
203
|
+
{ command: "python3.10", args: [] },
|
|
204
|
+
{ command: "python3", args: [] },
|
|
205
|
+
{ command: "python", args: [] }
|
|
206
|
+
);
|
|
207
|
+
return candidates;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function checkPython(candidate) {
|
|
211
|
+
const script = [
|
|
212
|
+
"import json, sys",
|
|
213
|
+
"print(json.dumps({'major': sys.version_info.major, 'minor': sys.version_info.minor, 'micro': sys.version_info.micro, 'executable': sys.executable}))",
|
|
214
|
+
].join("; ");
|
|
215
|
+
const result = spawnSync(candidate.command, [...candidate.args, "-c", script], {
|
|
216
|
+
encoding: "utf8",
|
|
217
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
218
|
+
});
|
|
219
|
+
if (result.status !== 0) {
|
|
220
|
+
return null;
|
|
221
|
+
}
|
|
222
|
+
try {
|
|
223
|
+
const info = JSON.parse(result.stdout.trim());
|
|
224
|
+
const supported = info.major === 3 && info.minor >= 10 && info.minor <= 12;
|
|
225
|
+
return { ...candidate, ...info, supported };
|
|
226
|
+
} catch {
|
|
227
|
+
return null;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function findSupportedPython() {
|
|
232
|
+
const checked = [];
|
|
233
|
+
for (const candidate of pythonCandidates()) {
|
|
234
|
+
const info = checkPython(candidate);
|
|
235
|
+
if (!info) {
|
|
236
|
+
continue;
|
|
237
|
+
}
|
|
238
|
+
checked.push(`${candidate.command}${candidate.args.length ? ` ${candidate.args.join(" ")}` : ""} (${info.major}.${info.minor}.${info.micro})`);
|
|
239
|
+
if (info.supported) {
|
|
240
|
+
return info;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
const suffix = checked.length ? ` Found: ${checked.join(", ")}.` : "";
|
|
245
|
+
throw new Error(`Python 3.10-3.12 is required for Resolve scripting compatibility.${suffix}`);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function venvPython(root) {
|
|
249
|
+
const relative = process.platform === "win32"
|
|
250
|
+
? path.join("venv", "Scripts", "python.exe")
|
|
251
|
+
: path.join("venv", "bin", "python");
|
|
252
|
+
const executable = path.join(root, relative);
|
|
253
|
+
if (!fs.existsSync(executable)) {
|
|
254
|
+
return null;
|
|
255
|
+
}
|
|
256
|
+
const info = checkPython({ command: executable, args: [] });
|
|
257
|
+
if (!info || !info.supported) {
|
|
258
|
+
throw new Error(`Managed venv Python must be 3.10-3.12. Re-run setup to recreate it: ${executable}`);
|
|
259
|
+
}
|
|
260
|
+
return info;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
function run(command, args, options = {}) {
|
|
264
|
+
const child = spawn(command, args, {
|
|
265
|
+
cwd: options.cwd,
|
|
266
|
+
env: options.env || process.env,
|
|
267
|
+
stdio: "inherit",
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
child.on("exit", (code, signal) => {
|
|
271
|
+
if (signal) {
|
|
272
|
+
process.kill(process.pid, signal);
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
process.exit(code ?? 1);
|
|
276
|
+
});
|
|
277
|
+
child.on("error", (error) => {
|
|
278
|
+
console.error(error.message);
|
|
279
|
+
process.exit(1);
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
function pythonCommandLine(python, rest) {
|
|
284
|
+
return [python.command, ...python.args, ...rest];
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
function hasOption(args, name) {
|
|
288
|
+
return args.some((arg) => arg === name || arg.startsWith(`${name}=`));
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
function commandSetup(args) {
|
|
292
|
+
const root = syncManagedInstall(installRoot());
|
|
293
|
+
const python = findSupportedPython();
|
|
294
|
+
const installScript = path.join(root, "install.py");
|
|
295
|
+
const [command, ...commandArgs] = pythonCommandLine(python, [installScript, ...args]);
|
|
296
|
+
|
|
297
|
+
console.log(`DaVinci Resolve MCP managed install: ${root}`);
|
|
298
|
+
console.log(`Python: ${python.executable} (${python.major}.${python.minor}.${python.micro})`);
|
|
299
|
+
run(command, commandArgs, { cwd: root });
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
function commandDoctor(args) {
|
|
303
|
+
const root = syncManagedInstall(installRoot());
|
|
304
|
+
const python = findSupportedPython();
|
|
305
|
+
const doctorArgs = [...args];
|
|
306
|
+
if (!hasOption(doctorArgs, "--dry-run")) {
|
|
307
|
+
doctorArgs.unshift("--dry-run");
|
|
308
|
+
}
|
|
309
|
+
if (!hasOption(doctorArgs, "--no-venv")) {
|
|
310
|
+
doctorArgs.unshift("--no-venv");
|
|
311
|
+
}
|
|
312
|
+
if (!hasOption(doctorArgs, "--clients")) {
|
|
313
|
+
doctorArgs.push("--clients", "manual");
|
|
314
|
+
}
|
|
315
|
+
const installScript = path.join(root, "install.py");
|
|
316
|
+
const [command, ...commandArgs] = pythonCommandLine(python, [installScript, ...doctorArgs]);
|
|
317
|
+
|
|
318
|
+
console.log(`DaVinci Resolve MCP managed install: ${root}`);
|
|
319
|
+
console.log(`Python: ${python.executable} (${python.major}.${python.minor}.${python.micro})`);
|
|
320
|
+
run(command, commandArgs, { cwd: root });
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
function commandServer(args) {
|
|
324
|
+
const root = syncManagedInstall(installRoot());
|
|
325
|
+
const python = venvPython(root) || findSupportedPython();
|
|
326
|
+
const serverScript = path.join(root, "src", "server.py");
|
|
327
|
+
const [command, ...commandArgs] = pythonCommandLine(python, [serverScript, ...args]);
|
|
328
|
+
run(command, commandArgs, { cwd: root });
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
function commandControlPanel(args) {
|
|
332
|
+
const root = syncManagedInstall(installRoot());
|
|
333
|
+
const python = venvPython(root) || findSupportedPython();
|
|
334
|
+
const [command, ...commandArgs] = pythonCommandLine(python, ["-m", "src.control_panel", ...args]);
|
|
335
|
+
run(command, commandArgs, { cwd: root });
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
function main() {
|
|
339
|
+
const [command = "--help", ...args] = process.argv.slice(2);
|
|
340
|
+
|
|
341
|
+
try {
|
|
342
|
+
if (command === "--help" || command === "-h" || command === "help") {
|
|
343
|
+
console.log(usage());
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
if (command === "--version" || command === "-v" || command === "version") {
|
|
347
|
+
console.log(VERSION);
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
if (command === "setup") {
|
|
351
|
+
commandSetup(args);
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
if (command === "doctor") {
|
|
355
|
+
commandDoctor(args);
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
if (command === "server") {
|
|
359
|
+
commandServer(args);
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
if (command === "control-panel" || command === "control_panel") {
|
|
363
|
+
commandControlPanel(args);
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
console.error(`Unknown command: ${command}\n`);
|
|
368
|
+
console.error(usage());
|
|
369
|
+
process.exit(2);
|
|
370
|
+
} catch (error) {
|
|
371
|
+
console.error(error.message);
|
|
372
|
+
process.exit(1);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
main();
|
package/docs/README.md
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# DaVinci Resolve MCP Documentation
|
|
2
|
+
|
|
3
|
+
This folder keeps durable project documentation. Temporary research notes,
|
|
4
|
+
session logs, and build gameplans should live outside this folder or under
|
|
5
|
+
ignored scratch folders such as `docs/_scratch/`.
|
|
6
|
+
|
|
7
|
+
## Operating References
|
|
8
|
+
|
|
9
|
+
- [Installation and Configuration](install.md) — requirements, supported MCP
|
|
10
|
+
clients, installer options, server modes, and manual configuration.
|
|
11
|
+
- [API Coverage and Test Results](reference/api-coverage.md) — current stats,
|
|
12
|
+
live-test status, and the method-by-method Resolve API reference.
|
|
13
|
+
- [AI Skill Reference](SKILL.md) — operational context for AI assistants using
|
|
14
|
+
the compound MCP server.
|
|
15
|
+
- [Media Analysis Guide](guides/media-analysis-guide.md) — source-safe FFprobe, FFmpeg,
|
|
16
|
+
Whisper, sidecar, and analysis-root workflows.
|
|
17
|
+
- [Multicam Setup Helper Guide](guides/multicam-setup-guide.md) — source-safe
|
|
18
|
+
stacked timeline prep, helper/API boundary, and Resolve UI conversion steps.
|
|
19
|
+
- [Editorial Decision Guide](guides/editorial-decision-guide.md) — project-owned
|
|
20
|
+
editorial craft guidance for analysis and edit decisions.
|
|
21
|
+
- [Color Decision Guide](guides/color-decision-guide.md) — project-owned color
|
|
22
|
+
correction guidance and Resolve color API boundaries.
|
|
23
|
+
- [Resolve Scripting API Reference](reference/resolve_scripting_api.txt) — bundled
|
|
24
|
+
Resolve scripting API text used for parity checks.
|
|
25
|
+
- [Contributing and Project Layout](contributing.md) — contribution workflow,
|
|
26
|
+
platform support, security notes, and repository structure.
|
|
27
|
+
- [Release Process](process/release-process.md) — maintainer release checklist.
|
|
28
|
+
- [Changelog](../CHANGELOG.md) — historical release notes.
|
|
29
|
+
|
|
30
|
+
## Kernel Support Maps
|
|
31
|
+
|
|
32
|
+
- [Kernel Action Coverage](kernels/README.md)
|
|
33
|
+
- [Timeline Edit](kernels/timeline-edit-kernel.md)
|
|
34
|
+
- [Media Pool / Ingest](kernels/media-pool-ingest-kernel.md)
|
|
35
|
+
- [Render / Deliver](kernels/render-deliver-kernel.md)
|
|
36
|
+
- [Review Annotation](kernels/review-annotation-kernel.md)
|
|
37
|
+
- [Color / Grade](kernels/color-grade-kernel.md)
|
|
38
|
+
- [Fusion Composition](kernels/fusion-composition-kernel.md)
|
|
39
|
+
- [Timeline Conform / Interchange](kernels/timeline-conform-interchange-kernel.md)
|
|
40
|
+
- [Audio / Fairlight](kernels/audio-fairlight-kernel.md)
|
|
41
|
+
- [Project Lifecycle](kernels/project-lifecycle-kernel.md)
|
|
42
|
+
- [Extension Authoring](kernels/extension-authoring-kernel.md)
|
|
43
|
+
|
|
44
|
+
## Authoring References
|
|
45
|
+
|
|
46
|
+
- [Fuse + DCTL Authoring](authoring/fuse-dctl-authoring.md)
|
|
47
|
+
- [Script Plugin Authoring + Conversational Lua/Python](authoring/script-plugin-authoring.md)
|
|
48
|
+
|
|
49
|
+
## Resolve Developer-Package References
|
|
50
|
+
|
|
51
|
+
- [Workflow Integrations](integrations/workflow-integrations.md)
|
|
52
|
+
- [OpenFX](notes/openfx-notes.md)
|
|
53
|
+
- [LUTs](notes/lut-notes.md)
|
|
54
|
+
- [Fusion Templates](notes/fusion-template-notes.md)
|
|
55
|
+
- [DCTL](notes/dctl-notes.md)
|
|
56
|
+
- [Codec Plugins](notes/codec-plugin-notes.md)
|