davinci-resolve-mcp 2.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/AGENTS.md +85 -0
  2. package/CHANGELOG.md +802 -0
  3. package/CLAUDE.md +15 -0
  4. package/LICENSE +21 -0
  5. package/README.md +159 -0
  6. package/SECURITY.md +53 -0
  7. package/bin/davinci-resolve-mcp.mjs +376 -0
  8. package/docs/README.md +56 -0
  9. package/docs/SKILL.md +1145 -0
  10. package/docs/authoring/fuse-dctl-authoring.md +242 -0
  11. package/docs/authoring/script-plugin-authoring.md +195 -0
  12. package/docs/contributing.md +82 -0
  13. package/docs/guides/color-decision-guide.md +387 -0
  14. package/docs/guides/editorial-decision-guide.md +136 -0
  15. package/docs/guides/media-analysis-guide.md +615 -0
  16. package/docs/guides/multicam-setup-guide.md +138 -0
  17. package/docs/install.md +198 -0
  18. package/docs/integrations/workflow-integrations.md +120 -0
  19. package/docs/kernels/README.md +28 -0
  20. package/docs/kernels/audio-fairlight-kernel.md +86 -0
  21. package/docs/kernels/color-grade-kernel.md +103 -0
  22. package/docs/kernels/extension-authoring-kernel.md +101 -0
  23. package/docs/kernels/fusion-composition-kernel.md +91 -0
  24. package/docs/kernels/media-pool-ingest-kernel.md +147 -0
  25. package/docs/kernels/project-lifecycle-kernel.md +120 -0
  26. package/docs/kernels/render-deliver-kernel.md +92 -0
  27. package/docs/kernels/review-annotation-kernel.md +110 -0
  28. package/docs/kernels/timeline-conform-interchange-kernel.md +99 -0
  29. package/docs/kernels/timeline-edit-kernel.md +189 -0
  30. package/docs/notes/codec-plugin-notes.md +136 -0
  31. package/docs/notes/dctl-notes.md +234 -0
  32. package/docs/notes/fusion-template-notes.md +136 -0
  33. package/docs/notes/lut-notes.md +136 -0
  34. package/docs/notes/openfx-notes.md +120 -0
  35. package/docs/process/release-process.md +152 -0
  36. package/docs/reference/api-coverage.md +488 -0
  37. package/docs/reference/resolve_scripting_api.txt +1012 -0
  38. package/examples/README.md +53 -0
  39. package/examples/markers/README.md +81 -0
  40. package/examples/media/README.md +94 -0
  41. package/examples/timeline/README.md +98 -0
  42. package/install.py +1196 -0
  43. package/package.json +52 -0
  44. package/scripts/audit_api_parity.py +275 -0
  45. package/scripts/live_media_analysis_polish_probe.py +65 -0
  46. package/src/__init__.py +3 -0
  47. package/src/analysis_dashboard.py +4936 -0
  48. package/src/control_panel.py +13 -0
  49. package/src/granular/__init__.py +17 -0
  50. package/src/granular/common.py +727 -0
  51. package/src/granular/folder.py +287 -0
  52. package/src/granular/gallery.py +306 -0
  53. package/src/granular/graph.py +309 -0
  54. package/src/granular/media_pool.py +679 -0
  55. package/src/granular/media_pool_item.py +852 -0
  56. package/src/granular/media_storage.py +179 -0
  57. package/src/granular/project.py +1594 -0
  58. package/src/granular/resolve_control.py +521 -0
  59. package/src/granular/timeline.py +1074 -0
  60. package/src/granular/timeline_item.py +2251 -0
  61. package/src/resolve_mcp_server.py +43 -0
  62. package/src/server.py +15691 -0
  63. package/src/utils/__init__.py +3 -0
  64. package/src/utils/app_control.py +319 -0
  65. package/src/utils/audio_fairlight_live_probe.py +263 -0
  66. package/src/utils/cdl.py +20 -0
  67. package/src/utils/cloud_operations.py +192 -0
  68. package/src/utils/color_grade_live_probe.py +444 -0
  69. package/src/utils/dctl_templates.py +368 -0
  70. package/src/utils/extension_authoring_live_probe.py +292 -0
  71. package/src/utils/fuse_templates.py +1968 -0
  72. package/src/utils/fusion_composition_live_probe.py +284 -0
  73. package/src/utils/layout_presets.py +333 -0
  74. package/src/utils/mcp_stdio.py +32 -0
  75. package/src/utils/media_analysis.py +3618 -0
  76. package/src/utils/media_analysis_jobs.py +796 -0
  77. package/src/utils/media_pool_ingest_live_probe.py +592 -0
  78. package/src/utils/multicam.py +393 -0
  79. package/src/utils/object_inspection.py +287 -0
  80. package/src/utils/platform.py +157 -0
  81. package/src/utils/project_lifecycle_live_probe.py +376 -0
  82. package/src/utils/project_properties.py +601 -0
  83. package/src/utils/render_deliver_live_probe.py +384 -0
  84. package/src/utils/resolve_connection.py +77 -0
  85. package/src/utils/review_annotation_live_probe.py +352 -0
  86. package/src/utils/script_templates.py +1193 -0
  87. package/src/utils/sync_detection.py +887 -0
  88. package/src/utils/timeline_conform_live_probe.py +280 -0
  89. package/src/utils/timeline_kernel_live_probe.py +1091 -0
  90. package/src/utils/timeline_kernel_probe.py +185 -0
  91. package/src/utils/timeline_title_text.py +87 -0
  92. package/src/utils/update_check.py +610 -0
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
+ [![Version](https://img.shields.io/badge/version-2.23.0-blue.svg)](https://github.com/samuelgursky/davinci-resolve-mcp/releases)
4
+ [![API Coverage](https://img.shields.io/badge/API%20Coverage-100%25-brightgreen.svg)](docs/reference/api-coverage.md)
5
+ [![Tools](https://img.shields.io/badge/MCP%20Tools-32%20(329%20full)-blue.svg)](#server-modes)
6
+ [![Tested](https://img.shields.io/badge/Live%20Tested-98.5%25-green.svg)](docs/reference/api-coverage.md#test-results)
7
+ [![DaVinci Resolve](https://img.shields.io/badge/DaVinci%20Resolve-18.5+-darkred.svg)](https://www.blackmagicdesign.com/products/davinciresolve)
8
+ [![Python](https://img.shields.io/badge/python-3.10--3.12-green.svg)](https://www.python.org/downloads/)
9
+ [![License](https://img.shields.io/badge/license-MIT-blue.svg)](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)