davinci-resolve-mcp 2.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/AGENTS.md +85 -0
  2. package/CHANGELOG.md +802 -0
  3. package/CLAUDE.md +15 -0
  4. package/LICENSE +21 -0
  5. package/README.md +159 -0
  6. package/SECURITY.md +53 -0
  7. package/bin/davinci-resolve-mcp.mjs +376 -0
  8. package/docs/README.md +56 -0
  9. package/docs/SKILL.md +1145 -0
  10. package/docs/authoring/fuse-dctl-authoring.md +242 -0
  11. package/docs/authoring/script-plugin-authoring.md +195 -0
  12. package/docs/contributing.md +82 -0
  13. package/docs/guides/color-decision-guide.md +387 -0
  14. package/docs/guides/editorial-decision-guide.md +136 -0
  15. package/docs/guides/media-analysis-guide.md +615 -0
  16. package/docs/guides/multicam-setup-guide.md +138 -0
  17. package/docs/install.md +198 -0
  18. package/docs/integrations/workflow-integrations.md +120 -0
  19. package/docs/kernels/README.md +28 -0
  20. package/docs/kernels/audio-fairlight-kernel.md +86 -0
  21. package/docs/kernels/color-grade-kernel.md +103 -0
  22. package/docs/kernels/extension-authoring-kernel.md +101 -0
  23. package/docs/kernels/fusion-composition-kernel.md +91 -0
  24. package/docs/kernels/media-pool-ingest-kernel.md +147 -0
  25. package/docs/kernels/project-lifecycle-kernel.md +120 -0
  26. package/docs/kernels/render-deliver-kernel.md +92 -0
  27. package/docs/kernels/review-annotation-kernel.md +110 -0
  28. package/docs/kernels/timeline-conform-interchange-kernel.md +99 -0
  29. package/docs/kernels/timeline-edit-kernel.md +189 -0
  30. package/docs/notes/codec-plugin-notes.md +136 -0
  31. package/docs/notes/dctl-notes.md +234 -0
  32. package/docs/notes/fusion-template-notes.md +136 -0
  33. package/docs/notes/lut-notes.md +136 -0
  34. package/docs/notes/openfx-notes.md +120 -0
  35. package/docs/process/release-process.md +152 -0
  36. package/docs/reference/api-coverage.md +488 -0
  37. package/docs/reference/resolve_scripting_api.txt +1012 -0
  38. package/examples/README.md +53 -0
  39. package/examples/markers/README.md +81 -0
  40. package/examples/media/README.md +94 -0
  41. package/examples/timeline/README.md +98 -0
  42. package/install.py +1196 -0
  43. package/package.json +52 -0
  44. package/scripts/audit_api_parity.py +275 -0
  45. package/scripts/live_media_analysis_polish_probe.py +65 -0
  46. package/src/__init__.py +3 -0
  47. package/src/analysis_dashboard.py +4936 -0
  48. package/src/control_panel.py +13 -0
  49. package/src/granular/__init__.py +17 -0
  50. package/src/granular/common.py +727 -0
  51. package/src/granular/folder.py +287 -0
  52. package/src/granular/gallery.py +306 -0
  53. package/src/granular/graph.py +309 -0
  54. package/src/granular/media_pool.py +679 -0
  55. package/src/granular/media_pool_item.py +852 -0
  56. package/src/granular/media_storage.py +179 -0
  57. package/src/granular/project.py +1594 -0
  58. package/src/granular/resolve_control.py +521 -0
  59. package/src/granular/timeline.py +1074 -0
  60. package/src/granular/timeline_item.py +2251 -0
  61. package/src/resolve_mcp_server.py +43 -0
  62. package/src/server.py +15691 -0
  63. package/src/utils/__init__.py +3 -0
  64. package/src/utils/app_control.py +319 -0
  65. package/src/utils/audio_fairlight_live_probe.py +263 -0
  66. package/src/utils/cdl.py +20 -0
  67. package/src/utils/cloud_operations.py +192 -0
  68. package/src/utils/color_grade_live_probe.py +444 -0
  69. package/src/utils/dctl_templates.py +368 -0
  70. package/src/utils/extension_authoring_live_probe.py +292 -0
  71. package/src/utils/fuse_templates.py +1968 -0
  72. package/src/utils/fusion_composition_live_probe.py +284 -0
  73. package/src/utils/layout_presets.py +333 -0
  74. package/src/utils/mcp_stdio.py +32 -0
  75. package/src/utils/media_analysis.py +3618 -0
  76. package/src/utils/media_analysis_jobs.py +796 -0
  77. package/src/utils/media_pool_ingest_live_probe.py +592 -0
  78. package/src/utils/multicam.py +393 -0
  79. package/src/utils/object_inspection.py +287 -0
  80. package/src/utils/platform.py +157 -0
  81. package/src/utils/project_lifecycle_live_probe.py +376 -0
  82. package/src/utils/project_properties.py +601 -0
  83. package/src/utils/render_deliver_live_probe.py +384 -0
  84. package/src/utils/resolve_connection.py +77 -0
  85. package/src/utils/review_annotation_live_probe.py +352 -0
  86. package/src/utils/script_templates.py +1193 -0
  87. package/src/utils/sync_detection.py +887 -0
  88. package/src/utils/timeline_conform_live_probe.py +280 -0
  89. package/src/utils/timeline_kernel_live_probe.py +1091 -0
  90. package/src/utils/timeline_kernel_probe.py +185 -0
  91. package/src/utils/timeline_title_text.py +87 -0
  92. package/src/utils/update_check.py +610 -0
@@ -0,0 +1,179 @@
1
+ """MediaStorage tools."""
2
+
3
+ from src.granular.common import * # noqa: F401,F403
4
+
5
+ resolve = ResolveProxy()
6
+
7
+ @mcp.tool()
8
+ def get_mounted_volumes() -> Dict[str, Any]:
9
+ """Get list of mounted volumes displayed in Resolve's Media Storage."""
10
+ resolve = get_resolve()
11
+ if resolve is None:
12
+ return {"error": "Not connected to DaVinci Resolve"}
13
+ ms = resolve.GetMediaStorage()
14
+ if not ms:
15
+ return {"error": "Failed to get MediaStorage"}
16
+ volumes = ms.GetMountedVolumeList()
17
+ return {"volumes": volumes if volumes else []}
18
+
19
+
20
+ @mcp.tool()
21
+ def get_media_storage_subfolders(folder_path: str) -> Dict[str, Any]:
22
+ """Get subfolders in a given absolute folder path from Media Storage.
23
+
24
+ Args:
25
+ folder_path: Absolute path to the folder to list subfolders for.
26
+ """
27
+ resolve = get_resolve()
28
+ if resolve is None:
29
+ return {"error": "Not connected to DaVinci Resolve"}
30
+ ms = resolve.GetMediaStorage()
31
+ if not ms:
32
+ return {"error": "Failed to get MediaStorage"}
33
+ subfolders = ms.GetSubFolderList(folder_path)
34
+ return {"folder_path": folder_path, "subfolders": subfolders if subfolders else []}
35
+
36
+
37
+ @mcp.tool()
38
+ def get_media_storage_files(folder_path: str) -> Dict[str, Any]:
39
+ """Get media and file listings in a given absolute folder path from Media Storage.
40
+
41
+ Args:
42
+ folder_path: Absolute path to the folder to list files for.
43
+ """
44
+ resolve = get_resolve()
45
+ if resolve is None:
46
+ return {"error": "Not connected to DaVinci Resolve"}
47
+ ms = resolve.GetMediaStorage()
48
+ if not ms:
49
+ return {"error": "Failed to get MediaStorage"}
50
+ files = ms.GetFileList(folder_path)
51
+ return {"folder_path": folder_path, "files": files if files else []}
52
+
53
+
54
+ @mcp.tool()
55
+ def reveal_in_media_storage(file_path: str) -> Dict[str, Any]:
56
+ """Reveal a file path in Resolve's Media Storage browser.
57
+
58
+ Args:
59
+ file_path: Absolute path to the file to reveal.
60
+ """
61
+ resolve = get_resolve()
62
+ if resolve is None:
63
+ return {"error": "Not connected to DaVinci Resolve"}
64
+ ms = resolve.GetMediaStorage()
65
+ if not ms:
66
+ return {"error": "Failed to get MediaStorage"}
67
+ result = ms.RevealInStorage(file_path)
68
+ return {"success": bool(result), "file_path": file_path}
69
+
70
+
71
+ @mcp.tool()
72
+ def add_items_to_media_pool_from_storage(
73
+ file_paths: Optional[List[str]] = None,
74
+ item_infos: Optional[List[Dict[str, Any]]] = None,
75
+ ) -> Dict[str, Any]:
76
+ """Add specified file/folder paths from Media Storage into current Media Pool folder.
77
+
78
+ Args:
79
+ file_paths: Simple form — list of absolute file/folder paths.
80
+ item_infos: Positioned form — list of dicts with keys media (required),
81
+ startFrame, endFrame. Mirrors
82
+ MediaStorage.AddItemListToMediaPool([{itemInfo}, ...]) per docs line 210.
83
+ """
84
+ resolve = get_resolve()
85
+ if resolve is None:
86
+ return {"error": "Not connected to DaVinci Resolve"}
87
+ ms = resolve.GetMediaStorage()
88
+ if not ms:
89
+ return {"error": "Failed to get MediaStorage"}
90
+ if item_infos is not None:
91
+ if not isinstance(item_infos, list) or not item_infos:
92
+ return {"error": "item_infos must be a non-empty list"}
93
+ for i, info in enumerate(item_infos):
94
+ if not isinstance(info, dict):
95
+ return {"error": f"item_infos[{i}] must be an object"}
96
+ if not info.get("media"):
97
+ return {"error": f"item_infos[{i}] requires media (file path)"}
98
+ clips = ms.AddItemListToMediaPool(item_infos)
99
+ else:
100
+ if not file_paths:
101
+ return {"error": "Provide file_paths (simple) or item_infos (positioned)"}
102
+ clips = ms.AddItemListToMediaPool(file_paths)
103
+ if clips:
104
+ return {"success": True, "clips_added": len(clips)}
105
+ return {"success": False, "error": "Failed to add items to Media Pool"}
106
+
107
+
108
+ @mcp.tool()
109
+ def add_clip_mattes_to_media_pool(media_pool_item_id: str, matte_paths: List[str]) -> Dict[str, Any]:
110
+ """Add clip mattes from Media Storage to a MediaPoolItem.
111
+
112
+ Args:
113
+ media_pool_item_id: The unique ID of the MediaPoolItem.
114
+ matte_paths: List of absolute file paths for the matte files.
115
+ """
116
+ resolve = get_resolve()
117
+ if resolve is None:
118
+ return {"error": "Not connected to DaVinci Resolve"}
119
+ ms = resolve.GetMediaStorage()
120
+ if not ms:
121
+ return {"error": "Failed to get MediaStorage"}
122
+
123
+ # Find the media pool item by ID
124
+ project = resolve.GetProjectManager().GetCurrentProject()
125
+ if not project:
126
+ return {"error": "No project currently open"}
127
+ mp = project.GetMediaPool()
128
+ root = mp.GetRootFolder()
129
+
130
+ # Search for clip by ID
131
+ def find_clip_by_id(folder, target_id):
132
+ for clip in (folder.GetClipList() or []):
133
+ if clip.GetUniqueId() == target_id:
134
+ return clip
135
+ for sub in (folder.GetSubFolderList() or []):
136
+ found = find_clip_by_id(sub, target_id)
137
+ if found:
138
+ return found
139
+ return None
140
+
141
+ clip = find_clip_by_id(root, media_pool_item_id)
142
+ if not clip:
143
+ return {"error": f"MediaPoolItem with ID {media_pool_item_id} not found"}
144
+
145
+ result = ms.AddClipMattesToMediaPool(clip, matte_paths, root)
146
+ return {"success": bool(result)}
147
+
148
+
149
+ @mcp.tool()
150
+ def add_timeline_mattes_to_media_pool(timeline_item_index: int, matte_paths: List[str], track_type: str = "video", track_index: int = 1) -> Dict[str, Any]:
151
+ """Add timeline mattes from Media Storage to a timeline item.
152
+
153
+ Args:
154
+ timeline_item_index: 0-based index of the item in the track.
155
+ matte_paths: List of absolute file paths for the matte files.
156
+ track_type: Track type ('video' or 'audio'). Default: 'video'.
157
+ track_index: 1-based track index. Default: 1.
158
+ """
159
+ resolve = get_resolve()
160
+ if resolve is None:
161
+ return {"error": "Not connected to DaVinci Resolve"}
162
+ ms = resolve.GetMediaStorage()
163
+ if not ms:
164
+ return {"error": "Failed to get MediaStorage"}
165
+
166
+ project = resolve.GetProjectManager().GetCurrentProject()
167
+ if not project:
168
+ return {"error": "No project currently open"}
169
+ timeline = project.GetCurrentTimeline()
170
+ if not timeline:
171
+ return {"error": "No current timeline"}
172
+
173
+ items = timeline.GetItemListInTrack(track_type, track_index)
174
+ if not items or timeline_item_index >= len(items):
175
+ return {"error": f"Timeline item at index {timeline_item_index} not found"}
176
+
177
+ item = items[timeline_item_index]
178
+ result = ms.AddTimelineMattesToMediaPool(item, matte_paths)
179
+ return {"success": bool(result)}