@hybridlabor-api/aos 4.4.1 → 4.4.2-beta.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 (305) hide show
  1. package/.agents/skills/firecrawl/SKILL.md +149 -0
  2. package/.agents/skills/firecrawl/rules/install.md +82 -0
  3. package/.agents/skills/firecrawl/rules/security.md +26 -0
  4. package/.agents/skills/firecrawl-agent/SKILL.md +58 -0
  5. package/.agents/skills/firecrawl-build/SKILL.md +39 -0
  6. package/.agents/skills/firecrawl-build-interact/SKILL.md +68 -0
  7. package/.agents/skills/firecrawl-build-onboarding/SKILL.md +103 -0
  8. package/.agents/skills/firecrawl-build-onboarding/references/auth-flow.md +39 -0
  9. package/.agents/skills/firecrawl-build-onboarding/references/project-setup.md +20 -0
  10. package/.agents/skills/firecrawl-build-onboarding/references/sdk-installation.md +17 -0
  11. package/.agents/skills/firecrawl-build-scrape/SKILL.md +69 -0
  12. package/.agents/skills/firecrawl-build-search/SKILL.md +69 -0
  13. package/.agents/skills/firecrawl-crawl/SKILL.md +59 -0
  14. package/.agents/skills/firecrawl-download/SKILL.md +70 -0
  15. package/.agents/skills/firecrawl-interact/SKILL.md +84 -0
  16. package/.agents/skills/firecrawl-map/SKILL.md +51 -0
  17. package/.agents/skills/firecrawl-scrape/SKILL.md +69 -0
  18. package/.agents/skills/firecrawl-search/SKILL.md +60 -0
  19. package/CLAUDE.md +573 -0
  20. package/README.de.md +0 -8
  21. package/README.md +0 -8
  22. package/README.pt.md +0 -8
  23. package/assets/brand/ao-ant-mark.svg +91 -0
  24. package/assets/brand/bdb-core-mark.svg +34 -0
  25. package/assets/brand/heimdall-guardian-mark.svg +16 -0
  26. package/assets/brand/memb-crystal-mark.svg +18 -0
  27. package/bin/aos-config.mjs +89 -0
  28. package/bin/aos-dashboard.mjs +608 -0
  29. package/bin/aos-uninstall.mjs +227 -0
  30. package/docs/sessions/audit-2026-09-14-silent-failures.md +114 -0
  31. package/docs/skills_table.md +0 -3
  32. package/installer.js +387 -237
  33. package/mcps/RhinoMCP/cc-plugin/.claude/settings.json +10 -0
  34. package/mcps/after-effects-mcp/build/index.js +840 -0
  35. package/mcps/after-effects-mcp/build/scripts/applyEffect.jsx +153 -0
  36. package/mcps/after-effects-mcp/build/scripts/applyEffectTemplate.jsx +218 -0
  37. package/mcps/after-effects-mcp/build/scripts/createComposition.jsx +71 -0
  38. package/mcps/after-effects-mcp/build/scripts/createShapeLayer.jsx +147 -0
  39. package/mcps/after-effects-mcp/build/scripts/createSolidLayer.jsx +114 -0
  40. package/mcps/after-effects-mcp/build/scripts/createTextLayer.jsx +115 -0
  41. package/mcps/after-effects-mcp/build/scripts/getLayerInfo.jsx +192 -0
  42. package/mcps/after-effects-mcp/build/scripts/getProjectInfo.jsx +90 -0
  43. package/mcps/after-effects-mcp/build/scripts/listCompositions.jsx +50 -0
  44. package/mcps/after-effects-mcp/build/scripts/mcp-bridge-auto.jsx +1773 -0
  45. package/mcps/after-effects-mcp/build/scripts/setLayerProperties.jsx +160 -0
  46. package/mcps/computer-use-mcp/dist/client.d.ts +150 -0
  47. package/mcps/computer-use-mcp/dist/client.js +136 -0
  48. package/mcps/computer-use-mcp/dist/entrypoint.d.ts +16 -0
  49. package/mcps/computer-use-mcp/dist/entrypoint.js +26 -0
  50. package/mcps/computer-use-mcp/dist/native.d.ts +212 -0
  51. package/mcps/computer-use-mcp/dist/native.js +50 -0
  52. package/mcps/computer-use-mcp/dist/server.d.ts +32 -0
  53. package/mcps/computer-use-mcp/dist/server.js +342 -0
  54. package/mcps/computer-use-mcp/dist/session.d.ts +101 -0
  55. package/mcps/computer-use-mcp/dist/session.js +2372 -0
  56. package/package.json +13 -4
  57. package/skills/global_config/aos-project-init/SKILL.md +97 -130
  58. package/skills/global_config/aos-project-init/assets/openwikiignore.template +62 -0
  59. package/skills/global_config/aos-project-init/scripts/aos-project-doctor.mjs +38 -1
  60. package/skills/global_config/aos-setup/SKILL.md +98 -8
  61. package/skills/global_config/aos-setup/scripts/aos-doctor.mjs +21 -2
  62. package/skills/global_config/ask-tim/SKILL.md +2 -7
  63. package/skills/global_config/openwiki-skill/scripts/openwiki_daemon.py +65 -12
  64. package/bin/setup-saas.mjs +0 -792
  65. package/mcps/blender-mcp-server/.dockerignore +0 -19
  66. package/mcps/blender-mcp-server/.github/workflows/ci.yml +0 -67
  67. package/mcps/blender-mcp-server/.github/workflows/publish-pypi.yml +0 -54
  68. package/mcps/blender-mcp-server/CHANGELOG.md +0 -64
  69. package/mcps/blender-mcp-server/CONTRIBUTING.md +0 -107
  70. package/mcps/blender-mcp-server/Dockerfile +0 -19
  71. package/mcps/blender-mcp-server/LICENSE +0 -21
  72. package/mcps/blender-mcp-server/README.md +0 -409
  73. package/mcps/blender-mcp-server/addon/__init__.py +0 -1440
  74. package/mcps/blender-mcp-server/addon/models.py +0 -223
  75. package/mcps/blender-mcp-server/pyproject.toml +0 -120
  76. package/mcps/blender-mcp-server/scripts/blender_bridge_request.py +0 -71
  77. package/mcps/blender-mcp-server/scripts/blender_create_test_cube.py +0 -49
  78. package/mcps/blender-mcp-server/scripts/blender_scene_info.py +0 -38
  79. package/mcps/blender-mcp-server/scripts/build_addon_zip.sh +0 -29
  80. package/mcps/blender-mcp-server/scripts/demos/README.md +0 -186
  81. package/mcps/blender-mcp-server/scripts/demos/dam_break_scene.py +0 -276
  82. package/mcps/blender-mcp-server/scripts/demos/open_dam_break_gui.py +0 -33
  83. package/mcps/blender-mcp-server/scripts/demos/pipe_movement_study.py +0 -518
  84. package/mcps/blender-mcp-server/scripts/demos/pipe_pressure_failure_scene.py +0 -806
  85. package/mcps/blender-mcp-server/scripts/demos/procedural_dam_break_scene.py +0 -600
  86. package/mcps/blender-mcp-server/scripts/demos/run_dam_break.py +0 -510
  87. package/mcps/blender-mcp-server/scripts/launch_blender_gui.py +0 -41
  88. package/mcps/blender-mcp-server/scripts/library/README.md +0 -64
  89. package/mcps/blender-mcp-server/scripts/library/apply_transforms.py +0 -46
  90. package/mcps/blender-mcp-server/scripts/library/camera.py +0 -51
  91. package/mcps/blender-mcp-server/scripts/library/collections.py +0 -65
  92. package/mcps/blender-mcp-server/scripts/library/create_mesh.py +0 -41
  93. package/mcps/blender-mcp-server/scripts/library/effector.py +0 -48
  94. package/mcps/blender-mcp-server/scripts/library/fluid_domain.py +0 -80
  95. package/mcps/blender-mcp-server/scripts/library/fluid_inflow.py +0 -98
  96. package/mcps/blender-mcp-server/scripts/library/frame_range.py +0 -35
  97. package/mcps/blender-mcp-server/scripts/library/keyframes.py +0 -59
  98. package/mcps/blender-mcp-server/scripts/library/rigid_body.py +0 -52
  99. package/mcps/blender-mcp-server/scripts/library/save_blend.py +0 -40
  100. package/mcps/blender-mcp-server/scripts/server_start.sh +0 -26
  101. package/mcps/blender-mcp-server/src/blender_mcp_server/__init__.py +0 -3
  102. package/mcps/blender-mcp-server/src/blender_mcp_server/headless.py +0 -330
  103. package/mcps/blender-mcp-server/src/blender_mcp_server/server.py +0 -606
  104. package/mcps/davinci-mcp-professional/.bandit +0 -35
  105. package/mcps/davinci-mcp-professional/.claude/commands/security-review.md +0 -191
  106. package/mcps/davinci-mcp-professional/.claude/settings.json +0 -1
  107. package/mcps/davinci-mcp-professional/.editorconfig +0 -27
  108. package/mcps/davinci-mcp-professional/.gitattributes +0 -207
  109. package/mcps/davinci-mcp-professional/.github/CODEOWNERS +0 -2
  110. package/mcps/davinci-mcp-professional/.github/ISSUE_TEMPLATE/bug_report.md +0 -33
  111. package/mcps/davinci-mcp-professional/.github/ISSUE_TEMPLATE/feature_request.md +0 -19
  112. package/mcps/davinci-mcp-professional/.github/PULL_REQUEST_TEMPLATE.md +0 -20
  113. package/mcps/davinci-mcp-professional/.github/SECURITY.md +0 -97
  114. package/mcps/davinci-mcp-professional/.github/dependabot.yml +0 -27
  115. package/mcps/davinci-mcp-professional/.github/workflows/ci.yml +0 -39
  116. package/mcps/davinci-mcp-professional/ATTRIBUTION.md +0 -4
  117. package/mcps/davinci-mcp-professional/AUTHORS.md +0 -9
  118. package/mcps/davinci-mcp-professional/BUGS.md +0 -55
  119. package/mcps/davinci-mcp-professional/CLAUDE.md +0 -229
  120. package/mcps/davinci-mcp-professional/CONTRIBUTING.md +0 -51
  121. package/mcps/davinci-mcp-professional/COPYING.md +0 -228
  122. package/mcps/davinci-mcp-professional/Doxyfile +0 -379
  123. package/mcps/davinci-mcp-professional/README.md +0 -143
  124. package/mcps/davinci-mcp-professional/SECURITY.md +0 -40
  125. package/mcps/davinci-mcp-professional/USING.md +0 -301
  126. package/mcps/davinci-mcp-professional/VERSION.md +0 -13
  127. package/mcps/davinci-mcp-professional/build.py +0 -169
  128. package/mcps/davinci-mcp-professional/claude_desktop_config_template.json +0 -11
  129. package/mcps/davinci-mcp-professional/hooks/ci-check.sh +0 -29
  130. package/mcps/davinci-mcp-professional/hooks/pre-push +0 -46
  131. package/mcps/davinci-mcp-professional/main.py +0 -40
  132. package/mcps/davinci-mcp-professional/mcp_server.py +0 -30
  133. package/mcps/davinci-mcp-professional/pyproject.toml +0 -115
  134. package/mcps/davinci-mcp-professional/security_audit.py +0 -379
  135. package/mcps/davinci-mcp-professional/src/davinci_mcp/__init__.py +0 -19
  136. package/mcps/davinci-mcp-professional/src/davinci_mcp/cli.py +0 -138
  137. package/mcps/davinci-mcp-professional/src/davinci_mcp/resolve_client.py +0 -342
  138. package/mcps/davinci-mcp-professional/src/davinci_mcp/resources/__init__.py +0 -60
  139. package/mcps/davinci-mcp-professional/src/davinci_mcp/server.py +0 -185
  140. package/mcps/davinci-mcp-professional/src/davinci_mcp/tools/__init__.py +0 -146
  141. package/mcps/davinci-mcp-professional/src/davinci_mcp/types.py +0 -125
  142. package/mcps/davinci-mcp-professional/src/davinci_mcp/utils/__init__.py +0 -19
  143. package/mcps/davinci-mcp-professional/src/davinci_mcp/utils/platform.py +0 -239
  144. package/mcps/davinci-mcp-professional/test.py +0 -186
  145. package/mcps/davinci-mcp-professional/uv.lock +0 -2073
  146. package/mcps/davinci-resolve-mcp/.claude/skills/media-analysis.md +0 -44
  147. package/mcps/davinci-resolve-mcp/.clinerules +0 -17
  148. package/mcps/davinci-resolve-mcp/.cursorrules +0 -17
  149. package/mcps/davinci-resolve-mcp/.github/copilot-instructions.md +0 -17
  150. package/mcps/davinci-resolve-mcp/.github/workflows/npm-publish.yml +0 -109
  151. package/mcps/davinci-resolve-mcp/.windsurfrules +0 -17
  152. package/mcps/davinci-resolve-mcp/AGENTS.md +0 -114
  153. package/mcps/davinci-resolve-mcp/CHANGELOG.md +0 -2648
  154. package/mcps/davinci-resolve-mcp/CLAUDE.md +0 -15
  155. package/mcps/davinci-resolve-mcp/LICENSE +0 -21
  156. package/mcps/davinci-resolve-mcp/README.md +0 -173
  157. package/mcps/davinci-resolve-mcp/SECURITY.md +0 -53
  158. package/mcps/davinci-resolve-mcp/bin/davinci-resolve-mcp.mjs +0 -450
  159. package/mcps/davinci-resolve-mcp/examples/README.md +0 -53
  160. package/mcps/davinci-resolve-mcp/examples/markers/README.md +0 -81
  161. package/mcps/davinci-resolve-mcp/examples/media/README.md +0 -94
  162. package/mcps/davinci-resolve-mcp/examples/timeline/README.md +0 -98
  163. package/mcps/davinci-resolve-mcp/install.py +0 -1687
  164. package/mcps/davinci-resolve-mcp/package.json +0 -52
  165. package/mcps/davinci-resolve-mcp/release-notes/v2.22.0.md +0 -51
  166. package/mcps/davinci-resolve-mcp/release-notes/v2.23.0.md +0 -51
  167. package/mcps/davinci-resolve-mcp/release-notes/v2.23.1.md +0 -35
  168. package/mcps/davinci-resolve-mcp/release-notes/v2.24.1.md +0 -32
  169. package/mcps/davinci-resolve-mcp/scripts/audit_api_parity.py +0 -275
  170. package/mcps/davinci-resolve-mcp/scripts/audit_readwrite_symmetry.py +0 -80
  171. package/mcps/davinci-resolve-mcp/scripts/doctor.py +0 -227
  172. package/mcps/davinci-resolve-mcp/scripts/gen_api_limitations.py +0 -144
  173. package/mcps/davinci-resolve-mcp/scripts/live_media_analysis_polish_probe.py +0 -65
  174. package/mcps/davinci-resolve-mcp/scripts/measure_bridge_cost.py +0 -65
  175. package/mcps/davinci-resolve-mcp/scripts/regen_panel_screenshots.py +0 -76
  176. package/mcps/davinci-resolve-mcp/src/__init__.py +0 -3
  177. package/mcps/davinci-resolve-mcp/src/analysis_dashboard.py +0 -15505
  178. package/mcps/davinci-resolve-mcp/src/batch_cli.py +0 -540
  179. package/mcps/davinci-resolve-mcp/src/control_panel.py +0 -13
  180. package/mcps/davinci-resolve-mcp/src/granular/__init__.py +0 -17
  181. package/mcps/davinci-resolve-mcp/src/granular/common.py +0 -741
  182. package/mcps/davinci-resolve-mcp/src/granular/folder.py +0 -420
  183. package/mcps/davinci-resolve-mcp/src/granular/gallery.py +0 -306
  184. package/mcps/davinci-resolve-mcp/src/granular/graph.py +0 -309
  185. package/mcps/davinci-resolve-mcp/src/granular/media_pool.py +0 -679
  186. package/mcps/davinci-resolve-mcp/src/granular/media_pool_item.py +0 -1020
  187. package/mcps/davinci-resolve-mcp/src/granular/media_storage.py +0 -179
  188. package/mcps/davinci-resolve-mcp/src/granular/project.py +0 -1654
  189. package/mcps/davinci-resolve-mcp/src/granular/resolve_control.py +0 -538
  190. package/mcps/davinci-resolve-mcp/src/granular/timeline.py +0 -1075
  191. package/mcps/davinci-resolve-mcp/src/granular/timeline_item.py +0 -2251
  192. package/mcps/davinci-resolve-mcp/src/resolve_mcp_server.py +0 -43
  193. package/mcps/davinci-resolve-mcp/src/server.py +0 -24116
  194. package/mcps/davinci-resolve-mcp/src/utils/__init__.py +0 -3
  195. package/mcps/davinci-resolve-mcp/src/utils/actor_identity.py +0 -46
  196. package/mcps/davinci-resolve-mcp/src/utils/analysis_caps.py +0 -678
  197. package/mcps/davinci-resolve-mcp/src/utils/analysis_memory.py +0 -755
  198. package/mcps/davinci-resolve-mcp/src/utils/analysis_runs.py +0 -307
  199. package/mcps/davinci-resolve-mcp/src/utils/analysis_store.py +0 -945
  200. package/mcps/davinci-resolve-mcp/src/utils/api_truth.py +0 -525
  201. package/mcps/davinci-resolve-mcp/src/utils/app_control.py +0 -319
  202. package/mcps/davinci-resolve-mcp/src/utils/audio_fairlight_live_probe.py +0 -263
  203. package/mcps/davinci-resolve-mcp/src/utils/brain_edits.py +0 -387
  204. package/mcps/davinci-resolve-mcp/src/utils/bridge_metrics.py +0 -76
  205. package/mcps/davinci-resolve-mcp/src/utils/cdl.py +0 -20
  206. package/mcps/davinci-resolve-mcp/src/utils/clip_query.py +0 -85
  207. package/mcps/davinci-resolve-mcp/src/utils/cloud_operations.py +0 -192
  208. package/mcps/davinci-resolve-mcp/src/utils/color_grade_live_probe.py +0 -444
  209. package/mcps/davinci-resolve-mcp/src/utils/contracts.py +0 -102
  210. package/mcps/davinci-resolve-mcp/src/utils/cut_ir.py +0 -115
  211. package/mcps/davinci-resolve-mcp/src/utils/dctl_templates.py +0 -368
  212. package/mcps/davinci-resolve-mcp/src/utils/deep_vision.py +0 -643
  213. package/mcps/davinci-resolve-mcp/src/utils/destructive_hook.py +0 -606
  214. package/mcps/davinci-resolve-mcp/src/utils/edit_engine.py +0 -737
  215. package/mcps/davinci-resolve-mcp/src/utils/embeddings.py +0 -922
  216. package/mcps/davinci-resolve-mcp/src/utils/entities.py +0 -579
  217. package/mcps/davinci-resolve-mcp/src/utils/extension_authoring_live_probe.py +0 -292
  218. package/mcps/davinci-resolve-mcp/src/utils/failure_tracker.py +0 -119
  219. package/mcps/davinci-resolve-mcp/src/utils/fuse_templates.py +0 -1968
  220. package/mcps/davinci-resolve-mcp/src/utils/fusion_composition_live_probe.py +0 -284
  221. package/mcps/davinci-resolve-mcp/src/utils/fusion_group_settings.py +0 -334
  222. package/mcps/davinci-resolve-mcp/src/utils/layout_presets.py +0 -333
  223. package/mcps/davinci-resolve-mcp/src/utils/mcp_stdio.py +0 -32
  224. package/mcps/davinci-resolve-mcp/src/utils/mcp_transport.py +0 -128
  225. package/mcps/davinci-resolve-mcp/src/utils/media_analysis.py +0 -7690
  226. package/mcps/davinci-resolve-mcp/src/utils/media_analysis_jobs.py +0 -805
  227. package/mcps/davinci-resolve-mcp/src/utils/media_pool_changes.py +0 -121
  228. package/mcps/davinci-resolve-mcp/src/utils/media_pool_ingest_live_probe.py +0 -592
  229. package/mcps/davinci-resolve-mcp/src/utils/multicam.py +0 -393
  230. package/mcps/davinci-resolve-mcp/src/utils/object_inspection.py +0 -301
  231. package/mcps/davinci-resolve-mcp/src/utils/page_lock.py +0 -75
  232. package/mcps/davinci-resolve-mcp/src/utils/platform.py +0 -157
  233. package/mcps/davinci-resolve-mcp/src/utils/proc.py +0 -26
  234. package/mcps/davinci-resolve-mcp/src/utils/project_cleanup.py +0 -73
  235. package/mcps/davinci-resolve-mcp/src/utils/project_lifecycle_live_probe.py +0 -376
  236. package/mcps/davinci-resolve-mcp/src/utils/project_lint.py +0 -131
  237. package/mcps/davinci-resolve-mcp/src/utils/project_properties.py +0 -601
  238. package/mcps/davinci-resolve-mcp/src/utils/project_spec.py +0 -459
  239. package/mcps/davinci-resolve-mcp/src/utils/readback.py +0 -91
  240. package/mcps/davinci-resolve-mcp/src/utils/render_deliver_live_probe.py +0 -384
  241. package/mcps/davinci-resolve-mcp/src/utils/resolve_ai_governance.py +0 -214
  242. package/mcps/davinci-resolve-mcp/src/utils/resolve_ai_ledger.py +0 -244
  243. package/mcps/davinci-resolve-mcp/src/utils/resolve_busy.py +0 -171
  244. package/mcps/davinci-resolve-mcp/src/utils/resolve_connection.py +0 -77
  245. package/mcps/davinci-resolve-mcp/src/utils/review_annotation_live_probe.py +0 -352
  246. package/mcps/davinci-resolve-mcp/src/utils/script_templates.py +0 -1193
  247. package/mcps/davinci-resolve-mcp/src/utils/shot_relationships.py +0 -544
  248. package/mcps/davinci-resolve-mcp/src/utils/structural_diff.py +0 -175
  249. package/mcps/davinci-resolve-mcp/src/utils/sync_detection.py +0 -889
  250. package/mcps/davinci-resolve-mcp/src/utils/timeline_brain_db.py +0 -826
  251. package/mcps/davinci-resolve-mcp/src/utils/timeline_conform_live_probe.py +0 -280
  252. package/mcps/davinci-resolve-mcp/src/utils/timeline_kernel_live_probe.py +0 -1092
  253. package/mcps/davinci-resolve-mcp/src/utils/timeline_kernel_probe.py +0 -185
  254. package/mcps/davinci-resolve-mcp/src/utils/timeline_title_text.py +0 -87
  255. package/mcps/davinci-resolve-mcp/src/utils/timeline_versioning.py +0 -730
  256. package/mcps/davinci-resolve-mcp/src/utils/update_check.py +0 -685
  257. package/mcps/vectorworks-mcp/.dockerignore +0 -8
  258. package/mcps/vectorworks-mcp/Dockerfile +0 -28
  259. package/mcps/vectorworks-mcp/README.md +0 -156
  260. package/mcps/vectorworks-mcp/app/__init__.py +0 -2
  261. package/mcps/vectorworks-mcp/app/api.py +0 -52
  262. package/mcps/vectorworks-mcp/app/chunking.py +0 -56
  263. package/mcps/vectorworks-mcp/app/config.py +0 -29
  264. package/mcps/vectorworks-mcp/app/embeddings.py +0 -28
  265. package/mcps/vectorworks-mcp/app/indexer.py +0 -106
  266. package/mcps/vectorworks-mcp/app/main.py +0 -33
  267. package/mcps/vectorworks-mcp/app/mcp_server.py +0 -71
  268. package/mcps/vectorworks-mcp/app/search.py +0 -54
  269. package/mcps/vectorworks-mcp/app/utils.py +0 -14
  270. package/mcps/vectorworks-mcp/data/.gitkeep +0 -1
  271. package/mcps/vectorworks-mcp/data/vw-app-help/VW2022_PluginScript.htm +0 -95
  272. package/mcps/vectorworks-mcp/data/vw-app-help/VW2022_ScriptEditor.htm +0 -266
  273. package/mcps/vectorworks-mcp/data/vw-app-help/VW2022_Scripting.htm +0 -106
  274. package/mcps/vectorworks-mcp/data/vw-app-help/VW2023_CreatingScriptedPlugins.htm +0 -327
  275. package/mcps/vectorworks-mcp/data/vw-app-help/VW2024_RunningScripts.htm +0 -116
  276. package/mcps/vectorworks-mcp/data/vw-devwiki/VS_Function_Reference_category.html +0 -2129
  277. package/mcps/vectorworks-mcp/data/vw-jp-ref/ObjectsSymbols.html +0 -2035
  278. package/mcps/vectorworks-mcp/data/vw-jp-ref/ScriptFunctionReference.html +0 -29
  279. package/mcps/vectorworks-mcp/design.md +0 -57
  280. package/mcps/vectorworks-mcp/docker-compose.yml +0 -18
  281. package/mcps/vectorworks-mcp/index/.gitkeep +0 -1
  282. package/mcps/vectorworks-mcp/index/meta.jsonl +0 -3956
  283. package/mcps/vectorworks-mcp/index/vw.faiss +0 -0
  284. package/mcps/vectorworks-mcp/requirements.txt +0 -10
  285. package/mcps/vectorworks-mcp/scripts/fetch_docs_minimal.sh +0 -84
  286. package/mcps/vectorworks-mcp/scripts/fetch_github_vectorworks.sh +0 -85
  287. package/mcps/vectorworks-mcp/templates/index.html +0 -40
  288. package/scripts/ecosystem-health-audit.js +0 -257
  289. package/skills/bdb-dev-os-skill/SKILL.md +0 -49
  290. package/skills/bdb-dev-os-skill/package.json +0 -11
  291. package/skills/bdbsaastraining/SKILL.md +0 -316
  292. package/skills/bdbsaastraining/references/exam-pool.md +0 -313
  293. package/skills/bdbsaastraining/references/interaction-modes.md +0 -94
  294. package/skills/bdbsaastraining/references/track-a-ai-agent.md +0 -111
  295. package/skills/bdbsaastraining/references/track-b-wordpress.md +0 -111
  296. package/skills/bdbsaastraining/references/track-c-mailserver.md +0 -107
  297. package/skills/bdbsaastraining/references/track-d-debian.md +0 -109
  298. package/skills/bdbsaastraining/references/track-e-custom.md +0 -83
  299. package/skills/bdbsaastraining/scripts/build_profile.py +0 -529
  300. package/skills/bdbsaastraining/scripts/generate_certificate.py +0 -161
  301. package/skills/bdbsaastraining/scripts/preflight_check.sh +0 -150
  302. package/skills/bdbsaastraining/templates/certificate_template.html +0 -508
  303. package/skills/global_config/bdb-ecosystem-health/SKILL.md +0 -68
  304. package/skills/global_config/bdbsaas-ops/SKILL.md +0 -16
  305. package/skills/global_config/bdbsaashost/SKILL.md +0 -125
@@ -1,1654 +0,0 @@
1
- """Project, render, cache, cloud, and project-property tools."""
2
-
3
- from src.granular.common import * # noqa: F401,F403
4
-
5
- resolve = ResolveProxy()
6
-
7
- @mcp.resource("resolve://projects")
8
- def list_projects() -> List[str]:
9
- """List all available projects in the current database."""
10
- project_manager = get_project_manager()
11
- if not project_manager:
12
- return ["Error: Failed to get Project Manager"]
13
-
14
- projects = project_manager.GetProjectListInCurrentFolder()
15
-
16
- # Filter out any empty strings that might be in the list
17
- return [p for p in projects if p]
18
-
19
-
20
- @mcp.resource("resolve://current-project")
21
- def get_current_project_name() -> str:
22
- """Get the name of the currently open project."""
23
- pm, current_project = get_current_project()
24
- if not current_project:
25
- return "No project currently open"
26
-
27
- return current_project.GetName()
28
-
29
-
30
- @mcp.resource("resolve://project-settings")
31
- def get_project_settings() -> Dict[str, Any]:
32
- """Get all project settings from the current project."""
33
- pm, current_project = get_current_project()
34
- if not current_project:
35
- return {"error": "No project currently open"}
36
-
37
- try:
38
- # Get all settings
39
- return current_project.GetSetting('')
40
- except Exception as e:
41
- return {"error": f"Failed to get project settings: {str(e)}"}
42
-
43
-
44
- @mcp.resource("resolve://project-setting/{setting_name}")
45
- def get_project_setting(setting_name: str) -> Dict[str, Any]:
46
- """Get a specific project setting by name.
47
-
48
- Args:
49
- setting_name: The specific setting to retrieve.
50
- """
51
- pm, current_project = get_current_project()
52
- if not current_project:
53
- return {"error": "No project currently open"}
54
-
55
- try:
56
- # Get specific setting
57
- value = current_project.GetSetting(setting_name)
58
- return {setting_name: value}
59
- except Exception as e:
60
- return {"error": f"Failed to get project setting '{setting_name}': {str(e)}"}
61
-
62
-
63
- @mcp.tool(annotations=DESTRUCTIVE_TOOL)
64
- def set_project_setting(setting_name: str, setting_value: Any) -> str:
65
- """Set a project setting to the specified value.
66
-
67
- Args:
68
- setting_name: The name of the setting to change
69
- setting_value: The new value for the setting (can be string, integer, float, or boolean)
70
- """
71
- pm, current_project = get_current_project()
72
- if not current_project:
73
- return "Error: No project currently open"
74
-
75
- try:
76
- # Convert setting_value to string if it's not already
77
- if not isinstance(setting_value, str):
78
- setting_value = str(setting_value)
79
-
80
- # Try to determine if this should be a numeric value
81
- # DaVinci Resolve sometimes expects numeric values for certain settings
82
- try:
83
- # Check if it's a number in string form
84
- if setting_value.isdigit() or (setting_value.startswith('-') and setting_value[1:].isdigit()):
85
- # It's an integer
86
- numeric_value = int(setting_value)
87
- # Try with numeric value first
88
- if current_project.SetSetting(setting_name, numeric_value):
89
- return f"Successfully set project setting '{setting_name}' to numeric value {numeric_value}"
90
- elif '.' in setting_value and setting_value.replace('.', '', 1).replace('-', '', 1).isdigit():
91
- # It's a float
92
- numeric_value = float(setting_value)
93
- # Try with float value
94
- if current_project.SetSetting(setting_name, numeric_value):
95
- return f"Successfully set project setting '{setting_name}' to numeric value {numeric_value}"
96
- except (ValueError, TypeError):
97
- # Not a number or conversion failed, continue with string value
98
- pass
99
-
100
- # Fall back to string value if numeric didn't work or wasn't applicable
101
- result = current_project.SetSetting(setting_name, setting_value)
102
- if result:
103
- return f"Successfully set project setting '{setting_name}' to '{setting_value}'"
104
- else:
105
- return f"Failed to set project setting '{setting_name}'"
106
- except Exception as e:
107
- return f"Error setting project setting: {str(e)}"
108
-
109
-
110
- @mcp.tool()
111
- def open_project(name: str) -> str:
112
- """Open a project by name.
113
-
114
- Args:
115
- name: The name of the project to open
116
- """
117
- resolve = get_resolve()
118
- if resolve is None:
119
- return "Error: Not connected to DaVinci Resolve"
120
-
121
- if not name:
122
- return "Error: Project name cannot be empty"
123
-
124
- project_manager = resolve.GetProjectManager()
125
- if not project_manager:
126
- return "Error: Failed to get Project Manager"
127
-
128
- # Check if project exists
129
- projects = project_manager.GetProjectListInCurrentFolder()
130
- if name not in projects:
131
- return f"Error: Project '{name}' not found. Available projects: {', '.join(projects)}"
132
-
133
- result = project_manager.LoadProject(name)
134
- if result:
135
- return f"Successfully opened project '{name}'"
136
- else:
137
- return f"Failed to open project '{name}'"
138
-
139
-
140
- @mcp.tool()
141
- def create_project(name: str, media_location_path: str = None) -> str:
142
- """Create a new project with the given name.
143
-
144
- Args:
145
- name: The name for the new project
146
- media_location_path: Optional project media location path (Resolve 20.2.2+).
147
- """
148
- resolve = get_resolve()
149
- if resolve is None:
150
- return "Error: Not connected to DaVinci Resolve"
151
-
152
- if not name:
153
- return "Error: Project name cannot be empty"
154
-
155
- project_manager = resolve.GetProjectManager()
156
- if not project_manager:
157
- return "Error: Failed to get Project Manager"
158
-
159
- # Check if project already exists
160
- projects = project_manager.GetProjectListInCurrentFolder()
161
- if name in projects:
162
- return f"Error: Project '{name}' already exists"
163
-
164
- if media_location_path:
165
- version = resolve.GetVersion() or [0]
166
- if version[0] < 20 or (version[0] == 20 and len(version) > 2 and (version[1], version[2]) < (2, 2)):
167
- return "Error: ProjectManager.CreateProject media_location_path requires DaVinci Resolve 20.2.2+"
168
- result = project_manager.CreateProject(name, media_location_path)
169
- else:
170
- result = project_manager.CreateProject(name)
171
- if result:
172
- return f"Successfully created project '{name}'"
173
- else:
174
- return f"Failed to create project '{name}'"
175
-
176
-
177
- @mcp.tool()
178
- def save_project() -> str:
179
- """Save the current project.
180
-
181
- Note that DaVinci Resolve typically auto-saves projects, so this may not be necessary.
182
- """
183
- pm, current_project = get_current_project()
184
- if not current_project:
185
- return "Error: No project currently open"
186
-
187
- project_name = current_project.GetName()
188
- success = False
189
- error_message = None
190
-
191
- # Try multiple approaches to save the project
192
- try:
193
- # Method 1: Try direct save method if available
194
- try:
195
- if hasattr(current_project, "SaveProject"):
196
- result = current_project.SaveProject()
197
- if result:
198
- logger.info(f"Project '{project_name}' saved using SaveProject method")
199
- success = True
200
- except Exception as e:
201
- logger.error(f"Error in SaveProject method: {str(e)}")
202
- error_message = str(e)
203
-
204
- # Method 2: Try project manager save method
205
- if not success:
206
- try:
207
- if hasattr(project_manager, "SaveProject"):
208
- result = project_manager.SaveProject()
209
- if result:
210
- logger.info(f"Project '{project_name}' saved using ProjectManager.SaveProject method")
211
- success = True
212
- except Exception as e:
213
- logger.error(f"Error in ProjectManager.SaveProject method: {str(e)}")
214
- if not error_message:
215
- error_message = str(e)
216
-
217
- # Method 3: Try the export method as a backup approach
218
- if not success:
219
- try:
220
- # Get a temporary file path that Resolve can access
221
- temp_dir = _resolve_safe_dir(tempfile.gettempdir())
222
- os.makedirs(temp_dir, exist_ok=True)
223
- temp_file = os.path.join(temp_dir, f"{project_name}_temp.drp")
224
-
225
- # Try to export the project, which should trigger a save
226
- result = project_manager.ExportProject(project_name, temp_file)
227
- if result:
228
- logger.info(f"Project '{project_name}' saved via temporary export to {temp_file}")
229
- # Try to clean up temp file
230
- try:
231
- if os.path.exists(temp_file):
232
- os.remove(temp_file)
233
- except OSError:
234
- logger.debug("Could not remove temporary project export %s", temp_file, exc_info=True)
235
- success = True
236
- except Exception as e:
237
- logger.error(f"Error in export method: {str(e)}")
238
- if not error_message:
239
- error_message = str(e)
240
-
241
- # If all else fails, rely on auto-save
242
- if not success:
243
- return f"Automatic save likely in effect for project '{project_name}'. Manual save attempts failed: {error_message if error_message else 'Unknown error'}"
244
- else:
245
- return f"Successfully saved project '{project_name}'"
246
-
247
- except Exception as e:
248
- logger.error(f"Error saving project: {str(e)}")
249
- return f"Error saving project: {str(e)}"
250
-
251
-
252
- @mcp.tool()
253
- def close_project() -> str:
254
- """Close the current project.
255
-
256
- This closes the current project without saving. If you need to save, use the save_project function first.
257
- """
258
- pm, current_project = get_current_project()
259
- if not current_project:
260
- return "Error: No project currently open"
261
-
262
- project_name = current_project.GetName()
263
-
264
- # Close the project
265
- try:
266
- result = project_manager.CloseProject(current_project)
267
- if result:
268
- logger.info(f"Project '{project_name}' closed successfully")
269
- return f"Successfully closed project '{project_name}'"
270
- else:
271
- logger.error(f"Failed to close project '{project_name}'")
272
- return f"Failed to close project '{project_name}'"
273
- except Exception as e:
274
- logger.error(f"Error closing project: {str(e)}")
275
- return f"Error closing project: {str(e)}"
276
-
277
-
278
- @mcp.resource("resolve://cache/settings")
279
- def get_cache_settings() -> Dict[str, Any]:
280
- """Get current cache settings from the project."""
281
- pm, current_project = get_current_project()
282
- if not current_project:
283
- return {"error": "No project currently open"}
284
-
285
- try:
286
- # Get all cache-related settings
287
- settings = {}
288
- cache_keys = [
289
- "CacheMode",
290
- "CacheClipMode",
291
- "OptimizedMediaMode",
292
- "ProxyMode",
293
- "ProxyQuality",
294
- "TimelineCacheMode",
295
- "LocalCachePath",
296
- "NetworkCachePath"
297
- ]
298
-
299
- for key in cache_keys:
300
- value = current_project.GetSetting(key)
301
- settings[key] = value
302
-
303
- return settings
304
- except Exception as e:
305
- return {"error": f"Failed to get cache settings: {str(e)}"}
306
-
307
-
308
- @mcp.tool()
309
- def set_cache_mode(mode: str) -> str:
310
- """Set cache mode for the current project.
311
-
312
- Args:
313
- mode: Cache mode to set. Options: 'auto', 'on', 'off'
314
- """
315
- pm, current_project = get_current_project()
316
- if not current_project:
317
- return "Error: No project currently open"
318
-
319
- # Validate mode
320
- valid_modes = ["auto", "on", "off"]
321
- mode = mode.lower()
322
- if mode not in valid_modes:
323
- return f"Error: Invalid cache mode. Must be one of: {', '.join(valid_modes)}"
324
-
325
- # Convert mode to API value
326
- mode_map = {
327
- "auto": "0",
328
- "on": "1",
329
- "off": "2"
330
- }
331
-
332
- try:
333
- result = current_project.SetSetting("CacheMode", mode_map[mode])
334
- if result:
335
- return f"Successfully set cache mode to '{mode}'"
336
- else:
337
- return f"Failed to set cache mode to '{mode}'"
338
- except Exception as e:
339
- return f"Error setting cache mode: {str(e)}"
340
-
341
-
342
- @mcp.tool()
343
- def set_optimized_media_mode(mode: str) -> str:
344
- """Set optimized media mode for the current project.
345
-
346
- Args:
347
- mode: Optimized media mode to set. Options: 'auto', 'on', 'off'
348
- """
349
- pm, current_project = get_current_project()
350
- if not current_project:
351
- return "Error: No project currently open"
352
-
353
- # Validate mode
354
- valid_modes = ["auto", "on", "off"]
355
- mode = mode.lower()
356
- if mode not in valid_modes:
357
- return f"Error: Invalid optimized media mode. Must be one of: {', '.join(valid_modes)}"
358
-
359
- # Convert mode to API value
360
- mode_map = {
361
- "auto": "0",
362
- "on": "1",
363
- "off": "2"
364
- }
365
-
366
- try:
367
- result = current_project.SetSetting("OptimizedMediaMode", mode_map[mode])
368
- if result:
369
- return f"Successfully set optimized media mode to '{mode}'"
370
- else:
371
- return f"Failed to set optimized media mode to '{mode}'"
372
- except Exception as e:
373
- return f"Error setting optimized media mode: {str(e)}"
374
-
375
-
376
- @mcp.tool()
377
- def set_proxy_mode(mode: str) -> str:
378
- """Set proxy media mode for the current project.
379
-
380
- Args:
381
- mode: Proxy mode to set. Options: 'auto', 'on', 'off'
382
- """
383
- pm, current_project = get_current_project()
384
- if not current_project:
385
- return "Error: No project currently open"
386
-
387
- # Validate mode
388
- valid_modes = ["auto", "on", "off"]
389
- mode = mode.lower()
390
- if mode not in valid_modes:
391
- return f"Error: Invalid proxy mode. Must be one of: {', '.join(valid_modes)}"
392
-
393
- # Convert mode to API value
394
- mode_map = {
395
- "auto": "0",
396
- "on": "1",
397
- "off": "2"
398
- }
399
-
400
- try:
401
- result = current_project.SetSetting("ProxyMode", mode_map[mode])
402
- if result:
403
- return f"Successfully set proxy mode to '{mode}'"
404
- else:
405
- return f"Failed to set proxy mode to '{mode}'"
406
- except Exception as e:
407
- return f"Error setting proxy mode: {str(e)}"
408
-
409
-
410
- @mcp.tool()
411
- def set_proxy_quality(quality: str) -> str:
412
- """Set proxy media quality for the current project.
413
-
414
- Args:
415
- quality: Proxy quality to set. Options: 'quarter', 'half', 'threeQuarter', 'full'
416
- """
417
- pm, current_project = get_current_project()
418
- if not current_project:
419
- return "Error: No project currently open"
420
-
421
- # Validate quality
422
- valid_qualities = ["quarter", "half", "threeQuarter", "full"]
423
- if quality not in valid_qualities:
424
- return f"Error: Invalid proxy quality. Must be one of: {', '.join(valid_qualities)}"
425
-
426
- # Convert quality to API value
427
- quality_map = {
428
- "quarter": "0",
429
- "half": "1",
430
- "threeQuarter": "2",
431
- "full": "3"
432
- }
433
-
434
- try:
435
- result = current_project.SetSetting("ProxyQuality", quality_map[quality])
436
- if result:
437
- return f"Successfully set proxy quality to '{quality}'"
438
- else:
439
- return f"Failed to set proxy quality to '{quality}'"
440
- except Exception as e:
441
- return f"Error setting proxy quality: {str(e)}"
442
-
443
-
444
- @mcp.tool()
445
- def set_cache_path(path_type: str, path: str) -> str:
446
- """Set cache file path for the current project.
447
-
448
- Args:
449
- path_type: Type of cache path to set. Options: 'local', 'network'
450
- path: File system path for the cache
451
- """
452
- pm, current_project = get_current_project()
453
- if not current_project:
454
- return "Error: No project currently open"
455
-
456
- # Validate path_type
457
- valid_path_types = ["local", "network"]
458
- path_type = path_type.lower()
459
- if path_type not in valid_path_types:
460
- return f"Error: Invalid path type. Must be one of: {', '.join(valid_path_types)}"
461
-
462
- # Check if directory exists
463
- if not os.path.exists(path):
464
- return f"Error: Path '{path}' does not exist"
465
-
466
- setting_key = "LocalCachePath" if path_type == "local" else "NetworkCachePath"
467
-
468
- try:
469
- result = current_project.SetSetting(setting_key, path)
470
- if result:
471
- return f"Successfully set {path_type} cache path to '{path}'"
472
- else:
473
- return f"Failed to set {path_type} cache path to '{path}'"
474
- except Exception as e:
475
- return f"Error setting cache path: {str(e)}"
476
-
477
-
478
-
479
- @mcp.tool()
480
- def create_cloud_project_tool(
481
- project_name: Optional[str] = None,
482
- project_media_path: Optional[str] = None,
483
- is_collab: Optional[bool] = None,
484
- sync_mode: Optional[str] = None,
485
- is_camera_access: Optional[bool] = None,
486
- ) -> Dict[str, Any]:
487
- """Create a new cloud project.
488
-
489
- Mirrors ProjectManager.CreateCloudProject({cloudSettings}) per docs lines 138, 576-594.
490
-
491
- Args:
492
- project_name: maps to resolve.CLOUD_SETTING_PROJECT_NAME (required for create).
493
- project_media_path: maps to resolve.CLOUD_SETTING_PROJECT_MEDIA_PATH (required for create).
494
- is_collab: maps to resolve.CLOUD_SETTING_IS_COLLAB.
495
- sync_mode: 'none', 'proxy_only' (default), or 'proxy_and_orig' — maps to resolve.CLOUD_SYNC_*.
496
- is_camera_access: maps to resolve.CLOUD_SETTING_IS_CAMERA_ACCESS.
497
- """
498
- return create_cloud_project(get_resolve(), project_name=project_name,
499
- project_media_path=project_media_path, is_collab=is_collab,
500
- sync_mode=sync_mode, is_camera_access=is_camera_access)
501
-
502
-
503
- @mcp.tool()
504
- def load_cloud_project_tool(
505
- project_name: Optional[str] = None,
506
- project_media_path: Optional[str] = None,
507
- sync_mode: Optional[str] = None,
508
- ) -> Dict[str, Any]:
509
- """Load a cloud project.
510
-
511
- Mirrors ProjectManager.LoadCloudProject({cloudSettings}). Per docs line 585,
512
- only project_name, project_media_path, and sync_mode are honoured.
513
-
514
- Args:
515
- project_name: required.
516
- project_media_path: required.
517
- sync_mode: 'none', 'proxy_only', or 'proxy_and_orig'.
518
- """
519
- return load_cloud_project(get_resolve(), project_name=project_name,
520
- project_media_path=project_media_path, sync_mode=sync_mode)
521
-
522
-
523
- @mcp.tool()
524
- def import_cloud_project_tool(
525
- file_path: str,
526
- project_name: Optional[str] = None,
527
- project_media_path: Optional[str] = None,
528
- is_collab: Optional[bool] = None,
529
- sync_mode: Optional[str] = None,
530
- is_camera_access: Optional[bool] = None,
531
- ) -> Dict[str, Any]:
532
- """Import a cloud project from a file.
533
-
534
- Mirrors ProjectManager.ImportCloudProject(filePath, {cloudSettings}).
535
-
536
- Args:
537
- file_path: absolute path to the cloud project file (required).
538
- project_name, project_media_path, is_collab, sync_mode, is_camera_access:
539
- cloudSettings dict keys; same semantics as create_cloud_project_tool.
540
- """
541
- return import_cloud_project(get_resolve(), file_path=file_path,
542
- project_name=project_name, project_media_path=project_media_path,
543
- is_collab=is_collab, sync_mode=sync_mode,
544
- is_camera_access=is_camera_access)
545
-
546
-
547
- @mcp.tool()
548
- def restore_cloud_project_tool(
549
- folder_path: str,
550
- project_name: Optional[str] = None,
551
- project_media_path: Optional[str] = None,
552
- is_collab: Optional[bool] = None,
553
- sync_mode: Optional[str] = None,
554
- is_camera_access: Optional[bool] = None,
555
- ) -> Dict[str, Any]:
556
- """Restore a cloud project from a folder.
557
-
558
- Mirrors ProjectManager.RestoreCloudProject(folderPath, {cloudSettings}).
559
-
560
- Args:
561
- folder_path: absolute path to the cloud project folder (required).
562
- project_name, project_media_path, is_collab, sync_mode, is_camera_access:
563
- cloudSettings dict keys; same semantics as create_cloud_project_tool.
564
- """
565
- return restore_cloud_project(get_resolve(), folder_path=folder_path,
566
- project_name=project_name, project_media_path=project_media_path,
567
- is_collab=is_collab, sync_mode=sync_mode,
568
- is_camera_access=is_camera_access)
569
-
570
-
571
- @mcp.resource("resolve://project/properties")
572
- def get_project_properties_endpoint() -> Dict[str, Any]:
573
- """Get all project properties for the current project."""
574
- pm, current_project = get_current_project()
575
- if not current_project:
576
- return {"error": "No project currently open"}
577
-
578
- return get_all_project_properties(current_project)
579
-
580
-
581
- @mcp.resource("resolve://project/property/{property_name}")
582
- def get_project_property_endpoint(property_name: str) -> Dict[str, Any]:
583
- """Get a specific project property value.
584
-
585
- Args:
586
- property_name: Name of the property to get
587
- """
588
- pm, current_project = get_current_project()
589
- if not current_project:
590
- return {"error": "No project currently open"}
591
-
592
- value = get_project_property(current_project, property_name)
593
- return {property_name: value}
594
-
595
-
596
- @mcp.tool()
597
- def set_project_property_tool(property_name: str, property_value: Any) -> str:
598
- """Set a project property value.
599
-
600
- Args:
601
- property_name: Name of the property to set
602
- property_value: Value to set for the property
603
- """
604
- pm, current_project = get_current_project()
605
- if not current_project:
606
- return "Error: No project currently open"
607
-
608
- result = set_project_property(current_project, property_name, property_value)
609
-
610
- if result:
611
- return f"Successfully set project property '{property_name}' to '{property_value}'"
612
- else:
613
- return f"Failed to set project property '{property_name}'"
614
-
615
-
616
- @mcp.resource("resolve://project/timeline-format")
617
- def get_timeline_format() -> Dict[str, Any]:
618
- """Get timeline format settings for the current project."""
619
- pm, current_project = get_current_project()
620
- if not current_project:
621
- return {"error": "No project currently open"}
622
-
623
- return get_timeline_format_settings(current_project)
624
-
625
-
626
- @mcp.tool()
627
- def set_timeline_format_tool(width: int, height: int, frame_rate: float, interlaced: bool = False) -> str:
628
- """Set timeline format (resolution and frame rate).
629
-
630
- Args:
631
- width: Timeline width in pixels
632
- height: Timeline height in pixels
633
- frame_rate: Timeline frame rate
634
- interlaced: Whether the timeline should use interlaced processing
635
- """
636
- pm, current_project = get_current_project()
637
- if not current_project:
638
- return "Error: No project currently open"
639
-
640
- result = set_timeline_format(current_project, width, height, frame_rate, interlaced)
641
-
642
- if result:
643
- interlace_status = "interlaced" if interlaced else "progressive"
644
- return f"Successfully set timeline format to {width}x{height} at {frame_rate} fps ({interlace_status})"
645
- else:
646
- return "Failed to set timeline format"
647
-
648
-
649
- @mcp.resource("resolve://project/superscale")
650
- def get_superscale_settings_endpoint() -> Dict[str, Any]:
651
- """Get SuperScale settings for the current project."""
652
- pm, current_project = get_current_project()
653
- if not current_project:
654
- return {"error": "No project currently open"}
655
-
656
- return get_superscale_settings(current_project)
657
-
658
-
659
- @mcp.tool()
660
- def set_superscale_settings_tool(enabled: bool, quality: int = 0) -> str:
661
- """Set SuperScale settings for the current project.
662
-
663
- Args:
664
- enabled: Whether SuperScale is enabled
665
- quality: SuperScale quality (0=Auto, 1=Better Quality, 2=Smoother)
666
- """
667
- pm, current_project = get_current_project()
668
- if not current_project:
669
- return "Error: No project currently open"
670
-
671
- quality_names = {
672
- 0: "Auto",
673
- 1: "Better Quality",
674
- 2: "Smoother"
675
- }
676
-
677
- result = set_superscale_settings(current_project, enabled, quality)
678
-
679
- if result:
680
- status = "enabled" if enabled else "disabled"
681
- quality_name = quality_names.get(quality, "Unknown")
682
- return f"Successfully {status} SuperScale with quality set to {quality_name}"
683
- else:
684
- return "Failed to set SuperScale settings"
685
-
686
-
687
- @mcp.resource("resolve://project/color-settings")
688
- def get_color_settings_endpoint() -> Dict[str, Any]:
689
- """Get color science and color space settings for the current project."""
690
- pm, current_project = get_current_project()
691
- if not current_project:
692
- return {"error": "No project currently open"}
693
-
694
- return get_color_settings(current_project)
695
-
696
-
697
- @mcp.tool()
698
- def set_color_science_mode_tool(mode: str) -> str:
699
- """Set color science mode for the current project.
700
-
701
- Args:
702
- mode: Color science mode ('YRGB', 'YRGB Color Managed', 'ACEScct', or numeric value)
703
- """
704
- pm, current_project = get_current_project()
705
- if not current_project:
706
- return "Error: No project currently open"
707
-
708
- result = set_color_science_mode(current_project, mode)
709
-
710
- if result:
711
- return f"Successfully set color science mode to '{mode}'"
712
- else:
713
- return f"Failed to set color science mode to '{mode}'"
714
-
715
-
716
- @mcp.tool()
717
- def set_color_space_tool(color_space: str, gamma: str = None) -> str:
718
- """Set timeline color space and gamma.
719
-
720
- Args:
721
- color_space: Timeline color space (e.g., 'Rec.709', 'DCI-P3 D65', 'Rec.2020')
722
- gamma: Timeline gamma (e.g., 'Rec.709 Gamma', 'Gamma 2.4')
723
- """
724
- pm, current_project = get_current_project()
725
- if not current_project:
726
- return "Error: No project currently open"
727
-
728
- result = set_color_space(current_project, color_space, gamma)
729
-
730
- if result:
731
- if gamma:
732
- return f"Successfully set timeline color space to '{color_space}' with gamma '{gamma}'"
733
- else:
734
- return f"Successfully set timeline color space to '{color_space}'"
735
- else:
736
- return "Failed to set timeline color space"
737
-
738
-
739
- @mcp.resource("resolve://project/metadata")
740
- def get_project_metadata_endpoint() -> Dict[str, Any]:
741
- """Get metadata for the current project."""
742
- pm, current_project = get_current_project()
743
- if not current_project:
744
- return {"error": "No project currently open"}
745
-
746
- return get_project_metadata(current_project)
747
-
748
-
749
- @mcp.resource("resolve://project/info")
750
- def get_project_info_endpoint() -> Dict[str, Any]:
751
- """Get comprehensive information about the current project."""
752
- pm, current_project = get_current_project()
753
- if not current_project:
754
- return {"error": "No project currently open"}
755
-
756
- return get_project_info(current_project)
757
-
758
-
759
- @mcp.tool()
760
- def archive_project(project_name: str, archive_path: str, archive_src_media: bool = True, archive_render_cache: bool = True, archive_proxy_media: bool = False) -> Dict[str, Any]:
761
- """Archive a project to a file with optional media.
762
-
763
- Args:
764
- project_name: Name of the project to archive.
765
- archive_path: Absolute path for the archive file (.dra).
766
- archive_src_media: Include source media in archive. Default: True.
767
- archive_render_cache: Include render cache. Default: True.
768
- archive_proxy_media: Include proxy media. Default: False.
769
- """
770
- resolve = get_resolve()
771
- if resolve is None:
772
- return {"error": "Not connected to DaVinci Resolve"}
773
- pm = resolve.GetProjectManager()
774
- result = pm.ArchiveProject(project_name, archive_path, archive_src_media, archive_render_cache, archive_proxy_media)
775
- return {"success": bool(result), "project_name": project_name, "archive_path": archive_path}
776
-
777
-
778
- @mcp.tool()
779
- def delete_project(project_name: str) -> Dict[str, Any]:
780
- """Delete a project from the current database. WARNING: This is irreversible.
781
-
782
- Args:
783
- project_name: Name of the project to delete.
784
- """
785
- resolve = get_resolve()
786
- if resolve is None:
787
- return {"error": "Not connected to DaVinci Resolve"}
788
- pm = resolve.GetProjectManager()
789
- # DeleteProject is flaky (silently returns False when the target is/was
790
- # current, transient first-attempt failures); route through the retry+switch
791
- # guard (#19).
792
- from src.utils.project_cleanup import delete_project_safely
793
- deleted = delete_project_safely(pm, project_name)
794
- return {"success": bool(deleted.get("success")), "project_name": project_name, "delete_detail": deleted}
795
-
796
-
797
- @mcp.tool()
798
- def create_project_folder(folder_name: str) -> Dict[str, Any]:
799
- """Create a new folder in the current project folder location.
800
-
801
- Args:
802
- folder_name: Name of the folder to create.
803
- """
804
- resolve = get_resolve()
805
- if resolve is None:
806
- return {"error": "Not connected to DaVinci Resolve"}
807
- pm = resolve.GetProjectManager()
808
- result = pm.CreateFolder(folder_name)
809
- return {"success": bool(result), "folder_name": folder_name}
810
-
811
-
812
- @mcp.tool()
813
- def delete_project_folder(folder_name: str) -> Dict[str, Any]:
814
- """Delete a folder from the current project folder location.
815
-
816
- Args:
817
- folder_name: Name of the folder to delete.
818
- """
819
- resolve = get_resolve()
820
- if resolve is None:
821
- return {"error": "Not connected to DaVinci Resolve"}
822
- pm = resolve.GetProjectManager()
823
- result = pm.DeleteFolder(folder_name)
824
- return {"success": bool(result), "folder_name": folder_name}
825
-
826
-
827
- @mcp.tool()
828
- def get_project_folder_list() -> Dict[str, Any]:
829
- """Get list of folders in the current project folder location."""
830
- resolve = get_resolve()
831
- if resolve is None:
832
- return {"error": "Not connected to DaVinci Resolve"}
833
- pm = resolve.GetProjectManager()
834
- folders = pm.GetFolderListInCurrentFolder()
835
- return {"folders": folders if folders else []}
836
-
837
-
838
- @mcp.tool()
839
- def goto_root_project_folder() -> Dict[str, Any]:
840
- """Navigate to the root project folder."""
841
- resolve = get_resolve()
842
- if resolve is None:
843
- return {"error": "Not connected to DaVinci Resolve"}
844
- pm = resolve.GetProjectManager()
845
- result = pm.GotoRootFolder()
846
- return {"success": bool(result)}
847
-
848
-
849
- @mcp.tool()
850
- def goto_parent_project_folder() -> Dict[str, Any]:
851
- """Navigate up one level in the project folder hierarchy."""
852
- resolve = get_resolve()
853
- if resolve is None:
854
- return {"error": "Not connected to DaVinci Resolve"}
855
- pm = resolve.GetProjectManager()
856
- result = pm.GotoParentFolder()
857
- return {"success": bool(result)}
858
-
859
-
860
- @mcp.tool()
861
- def get_current_project_folder() -> Dict[str, Any]:
862
- """Get the name of the current project folder."""
863
- resolve = get_resolve()
864
- if resolve is None:
865
- return {"error": "Not connected to DaVinci Resolve"}
866
- pm = resolve.GetProjectManager()
867
- folder = pm.GetCurrentFolder()
868
- return {"current_folder": folder}
869
-
870
-
871
- @mcp.tool()
872
- def open_project_folder(folder_name: str) -> Dict[str, Any]:
873
- """Open/navigate into a project folder.
874
-
875
- Args:
876
- folder_name: Name of the folder to open.
877
- """
878
- resolve = get_resolve()
879
- if resolve is None:
880
- return {"error": "Not connected to DaVinci Resolve"}
881
- pm = resolve.GetProjectManager()
882
- result = pm.OpenFolder(folder_name)
883
- return {"success": bool(result), "folder_name": folder_name}
884
-
885
-
886
- @mcp.tool()
887
- def import_project_from_file(file_path: str) -> Dict[str, Any]:
888
- """Import a project from a .drp file.
889
-
890
- Args:
891
- file_path: Absolute path to the .drp project file.
892
- """
893
- resolve = get_resolve()
894
- if resolve is None:
895
- return {"error": "Not connected to DaVinci Resolve"}
896
- pm = resolve.GetProjectManager()
897
- result = pm.ImportProject(file_path)
898
- return {"success": bool(result), "file_path": file_path}
899
-
900
-
901
- @mcp.tool()
902
- def export_project_to_file(project_name: str, file_path: str, with_stills_and_luts: bool = True) -> Dict[str, Any]:
903
- """Export a project to a .drp file.
904
-
905
- Args:
906
- project_name: Name of the project to export.
907
- file_path: Absolute path for the exported .drp file.
908
- with_stills_and_luts: Include stills and LUTs in export. Default: True.
909
- """
910
- resolve = get_resolve()
911
- if resolve is None:
912
- return {"error": "Not connected to DaVinci Resolve"}
913
- pm = resolve.GetProjectManager()
914
- result = pm.ExportProject(project_name, file_path, with_stills_and_luts)
915
- return {"success": bool(result), "project_name": project_name, "file_path": file_path}
916
-
917
-
918
- @mcp.tool()
919
- def restore_project(file_path: str) -> Dict[str, Any]:
920
- """Restore a project from an archive (.dra) file.
921
-
922
- Args:
923
- file_path: Absolute path to the .dra archive file.
924
- """
925
- resolve = get_resolve()
926
- if resolve is None:
927
- return {"error": "Not connected to DaVinci Resolve"}
928
- pm = resolve.GetProjectManager()
929
- result = pm.RestoreProject(file_path)
930
- return {"success": bool(result), "file_path": file_path}
931
-
932
-
933
- @mcp.tool()
934
- def get_current_database() -> Dict[str, Any]:
935
- """Get information about the current database."""
936
- resolve = get_resolve()
937
- if resolve is None:
938
- return {"error": "Not connected to DaVinci Resolve"}
939
- pm = resolve.GetProjectManager()
940
- db = pm.GetCurrentDatabase()
941
- return db if db else {"error": "Failed to get current database"}
942
-
943
-
944
- @mcp.tool()
945
- def get_database_list() -> Dict[str, Any]:
946
- """Get list of all available databases."""
947
- resolve = get_resolve()
948
- if resolve is None:
949
- return {"error": "Not connected to DaVinci Resolve"}
950
- pm = resolve.GetProjectManager()
951
- dbs = pm.GetDatabaseList()
952
- return {"databases": dbs if dbs else []}
953
-
954
-
955
- @mcp.tool()
956
- def set_current_database(db_info: Dict[str, str]) -> Dict[str, Any]:
957
- """Switch to a different database.
958
-
959
- Args:
960
- db_info: Database info dict with keys 'DbType' and 'DbName'. Example: {"DbType": "Disk", "DbName": "Local Database"}
961
- """
962
- resolve = get_resolve()
963
- if resolve is None:
964
- return {"error": "Not connected to DaVinci Resolve"}
965
- pm = resolve.GetProjectManager()
966
- result = pm.SetCurrentDatabase(db_info)
967
- return {"success": bool(result), "database": db_info}
968
-
969
-
970
- @mcp.tool()
971
- def set_project_name(name: str) -> Dict[str, Any]:
972
- """Rename the current project.
973
-
974
- Args:
975
- name: New name for the project.
976
- """
977
- resolve = get_resolve()
978
- if resolve is None:
979
- return {"error": "Not connected to DaVinci Resolve"}
980
- project = resolve.GetProjectManager().GetCurrentProject()
981
- if not project:
982
- return {"error": "No project currently open"}
983
- result = project.SetName(name)
984
- return {"success": bool(result), "name": name}
985
-
986
-
987
- @mcp.tool()
988
- def get_timeline_by_index(index: int) -> Dict[str, Any]:
989
- """Get a timeline by its 1-based index.
990
-
991
- Args:
992
- index: 1-based timeline index.
993
- """
994
- resolve = get_resolve()
995
- if resolve is None:
996
- return {"error": "Not connected to DaVinci Resolve"}
997
- project = resolve.GetProjectManager().GetCurrentProject()
998
- if not project:
999
- return {"error": "No project currently open"}
1000
- tl = project.GetTimelineByIndex(index)
1001
- if tl:
1002
- return {"name": tl.GetName(), "start_frame": tl.GetStartFrame(), "end_frame": tl.GetEndFrame(), "unique_id": tl.GetUniqueId()}
1003
- return {"error": f"No timeline at index {index}"}
1004
-
1005
-
1006
- @mcp.tool()
1007
- def get_project_preset_list() -> Dict[str, Any]:
1008
- """Get list of available project presets."""
1009
- resolve = get_resolve()
1010
- if resolve is None:
1011
- return {"error": "Not connected to DaVinci Resolve"}
1012
- project = resolve.GetProjectManager().GetCurrentProject()
1013
- if not project:
1014
- return {"error": "No project currently open"}
1015
- presets = project.GetPresetList()
1016
- return {"presets": presets if presets else []}
1017
-
1018
-
1019
- @mcp.tool()
1020
- def set_project_preset(preset_name: str) -> Dict[str, Any]:
1021
- """Apply a project preset to the current project.
1022
-
1023
- Args:
1024
- preset_name: Name of the preset to apply.
1025
- """
1026
- resolve = get_resolve()
1027
- if resolve is None:
1028
- return {"error": "Not connected to DaVinci Resolve"}
1029
- project = resolve.GetProjectManager().GetCurrentProject()
1030
- if not project:
1031
- return {"error": "No project currently open"}
1032
- result = project.SetPreset(preset_name)
1033
- return {"success": bool(result), "preset_name": preset_name}
1034
-
1035
-
1036
- @mcp.tool()
1037
- def delete_render_job(job_id: str) -> Dict[str, Any]:
1038
- """Delete a specific render job by its ID.
1039
-
1040
- Args:
1041
- job_id: The unique ID of the render job to delete.
1042
- """
1043
- resolve = get_resolve()
1044
- if resolve is None:
1045
- return {"error": "Not connected to DaVinci Resolve"}
1046
- project = resolve.GetProjectManager().GetCurrentProject()
1047
- if not project:
1048
- return {"error": "No project currently open"}
1049
- result = project.DeleteRenderJob(job_id)
1050
- return {"success": bool(result), "job_id": job_id}
1051
-
1052
-
1053
- @mcp.tool()
1054
- def get_render_job_list() -> Dict[str, Any]:
1055
- """Get list of all render jobs in the queue."""
1056
- resolve = get_resolve()
1057
- if resolve is None:
1058
- return {"error": "Not connected to DaVinci Resolve"}
1059
- project = resolve.GetProjectManager().GetCurrentProject()
1060
- if not project:
1061
- return {"error": "No project currently open"}
1062
- jobs = project.GetRenderJobList()
1063
- return {"render_jobs": jobs if jobs else []}
1064
-
1065
-
1066
- @mcp.tool()
1067
- def start_rendering_jobs(job_ids: Optional[List[str]] = None, is_interactive_mode: bool = False) -> Dict[str, Any]:
1068
- """Start rendering jobs. If no job IDs specified, renders all queued jobs.
1069
-
1070
- Args:
1071
- job_ids: Optional list of job IDs to render. If None, renders all.
1072
- is_interactive_mode: If True, enables interactive rendering mode.
1073
- """
1074
- resolve = get_resolve()
1075
- if resolve is None:
1076
- return {"error": "Not connected to DaVinci Resolve"}
1077
- project = resolve.GetProjectManager().GetCurrentProject()
1078
- if not project:
1079
- return {"error": "No project currently open"}
1080
- if job_ids:
1081
- result = project.StartRendering(job_ids, is_interactive_mode)
1082
- else:
1083
- result = project.StartRendering(is_interactive_mode)
1084
- return {"success": bool(result)}
1085
-
1086
-
1087
- @mcp.tool()
1088
- def stop_rendering() -> Dict[str, Any]:
1089
- """Stop the current rendering process."""
1090
- resolve = get_resolve()
1091
- if resolve is None:
1092
- return {"error": "Not connected to DaVinci Resolve"}
1093
- project = resolve.GetProjectManager().GetCurrentProject()
1094
- if not project:
1095
- return {"error": "No project currently open"}
1096
- project.StopRendering()
1097
- return {"success": True}
1098
-
1099
-
1100
- @mcp.tool()
1101
- def is_rendering_in_progress() -> Dict[str, Any]:
1102
- """Check if rendering is currently in progress."""
1103
- resolve = get_resolve()
1104
- if resolve is None:
1105
- return {"error": "Not connected to DaVinci Resolve"}
1106
- project = resolve.GetProjectManager().GetCurrentProject()
1107
- if not project:
1108
- return {"error": "No project currently open"}
1109
- result = project.IsRenderingInProgress()
1110
- return {"is_rendering": bool(result)}
1111
-
1112
-
1113
- @mcp.tool()
1114
- def load_render_preset(preset_name: str) -> Dict[str, Any]:
1115
- """Load a render preset by name.
1116
-
1117
- Args:
1118
- preset_name: Name of the render preset to load.
1119
- """
1120
- resolve = get_resolve()
1121
- if resolve is None:
1122
- return {"error": "Not connected to DaVinci Resolve"}
1123
- project = resolve.GetProjectManager().GetCurrentProject()
1124
- if not project:
1125
- return {"error": "No project currently open"}
1126
- result = project.LoadRenderPreset(preset_name)
1127
- return {"success": bool(result), "preset_name": preset_name}
1128
-
1129
-
1130
- @mcp.tool()
1131
- def save_as_new_render_preset(preset_name: str) -> Dict[str, Any]:
1132
- """Save current render settings as a new preset.
1133
-
1134
- Args:
1135
- preset_name: Name for the new render preset.
1136
- """
1137
- resolve = get_resolve()
1138
- if resolve is None:
1139
- return {"error": "Not connected to DaVinci Resolve"}
1140
- project = resolve.GetProjectManager().GetCurrentProject()
1141
- if not project:
1142
- return {"error": "No project currently open"}
1143
- result = project.SaveAsNewRenderPreset(preset_name)
1144
- return {"success": bool(result), "preset_name": preset_name}
1145
-
1146
-
1147
- @mcp.tool()
1148
- def delete_render_preset(preset_name: str) -> Dict[str, Any]:
1149
- """Delete a render preset.
1150
-
1151
- Args:
1152
- preset_name: Name of the render preset to delete.
1153
- """
1154
- resolve = get_resolve()
1155
- if resolve is None:
1156
- return {"error": "Not connected to DaVinci Resolve"}
1157
- project = resolve.GetProjectManager().GetCurrentProject()
1158
- if not project:
1159
- return {"error": "No project currently open"}
1160
- result = project.DeleteRenderPreset(preset_name)
1161
- return {"success": bool(result), "preset_name": preset_name}
1162
-
1163
-
1164
- @mcp.tool()
1165
- def set_render_settings(settings: Dict[str, Any]) -> Dict[str, Any]:
1166
- """Set render settings for the current project.
1167
-
1168
- Mirrors Project.SetRenderSettings({settings}) per docs lines 765-799.
1169
-
1170
- Args:
1171
- settings: Dict of render settings. All documented keys are forwarded:
1172
- SelectAllFrames (bool), MarkIn (int), MarkOut (int),
1173
- TargetDir (str), CustomName (str), UniqueFilenameStyle (0=Prefix/1=Suffix),
1174
- ExportVideo (bool), ExportAudio (bool), FormatWidth (int),
1175
- FormatHeight (int), FrameRate (float), PixelAspectRatio (float),
1176
- VideoQuality (int/str), AudioCodec (str), AudioBitDepth (int),
1177
- AudioSampleRate (int), ColorSpaceTag (str), GammaTag (str),
1178
- ExportAlpha (bool), EncodingProfile (str), MultiPassEncode (bool),
1179
- AlphaMode (int), NetworkOptimization (bool), ClipStartFrame (int),
1180
- TimelineStartTimecode (str), ReplaceExistingFilesInPlace (bool),
1181
- ExportSubtitle (bool), SubtitleFormat ("BurnIn", "EmbeddedCaptions", "SeparateFile").
1182
- """
1183
- resolve = get_resolve()
1184
- if resolve is None:
1185
- return {"error": "Not connected to DaVinci Resolve"}
1186
- project = resolve.GetProjectManager().GetCurrentProject()
1187
- if not project:
1188
- return {"error": "No project currently open"}
1189
- result = project.SetRenderSettings(settings)
1190
- return {"success": bool(result)}
1191
-
1192
-
1193
- @mcp.tool()
1194
- def get_render_job_status(job_id: str) -> Dict[str, Any]:
1195
- """Get the status of a specific render job.
1196
-
1197
- Args:
1198
- job_id: The unique ID of the render job.
1199
- """
1200
- resolve = get_resolve()
1201
- if resolve is None:
1202
- return {"error": "Not connected to DaVinci Resolve"}
1203
- project = resolve.GetProjectManager().GetCurrentProject()
1204
- if not project:
1205
- return {"error": "No project currently open"}
1206
- status = project.GetRenderJobStatus(job_id)
1207
- return status if status else {"error": f"No render job with ID {job_id}"}
1208
-
1209
-
1210
- @mcp.tool()
1211
- def get_render_formats() -> Dict[str, Any]:
1212
- """Get all available render formats."""
1213
- resolve = get_resolve()
1214
- if resolve is None:
1215
- return {"error": "Not connected to DaVinci Resolve"}
1216
- project = resolve.GetProjectManager().GetCurrentProject()
1217
- if not project:
1218
- return {"error": "No project currently open"}
1219
- formats = project.GetRenderFormats()
1220
- return {"formats": formats if formats else {}}
1221
-
1222
-
1223
- @mcp.tool()
1224
- def get_render_codecs(format_name: str) -> Dict[str, Any]:
1225
- """Get available codecs for a given render format.
1226
-
1227
- Args:
1228
- format_name: Render format name (e.g. 'mp4', 'mov', 'avi').
1229
- """
1230
- resolve = get_resolve()
1231
- if resolve is None:
1232
- return {"error": "Not connected to DaVinci Resolve"}
1233
- project = resolve.GetProjectManager().GetCurrentProject()
1234
- if not project:
1235
- return {"error": "No project currently open"}
1236
- codecs = project.GetRenderCodecs(format_name)
1237
- return {"format": format_name, "codecs": codecs if codecs else {}}
1238
-
1239
-
1240
- @mcp.tool()
1241
- def get_current_render_format_and_codec() -> Dict[str, Any]:
1242
- """Get the current render format and codec setting."""
1243
- resolve = get_resolve()
1244
- if resolve is None:
1245
- return {"error": "Not connected to DaVinci Resolve"}
1246
- project = resolve.GetProjectManager().GetCurrentProject()
1247
- if not project:
1248
- return {"error": "No project currently open"}
1249
- result = project.GetCurrentRenderFormatAndCodec()
1250
- return result if result else {"error": "Failed to get render format and codec"}
1251
-
1252
-
1253
- @mcp.tool()
1254
- def set_current_render_format_and_codec(format_name: str, codec_name: str) -> Dict[str, Any]:
1255
- """Set the render format and codec.
1256
-
1257
- Args:
1258
- format_name: Render format (e.g. 'mp4', 'mov').
1259
- codec_name: Codec name (e.g. 'H264', 'H265', 'ProRes422HQ').
1260
- """
1261
- resolve = get_resolve()
1262
- if resolve is None:
1263
- return {"error": "Not connected to DaVinci Resolve"}
1264
- project = resolve.GetProjectManager().GetCurrentProject()
1265
- if not project:
1266
- return {"error": "No project currently open"}
1267
- result = project.SetCurrentRenderFormatAndCodec(format_name, codec_name)
1268
- return {"success": bool(result), "format": format_name, "codec": codec_name}
1269
-
1270
-
1271
- @mcp.tool()
1272
- def get_current_render_mode() -> Dict[str, Any]:
1273
- """Get the current render mode (0=Individual Clips, 1=Single Clip)."""
1274
- resolve = get_resolve()
1275
- if resolve is None:
1276
- return {"error": "Not connected to DaVinci Resolve"}
1277
- project = resolve.GetProjectManager().GetCurrentProject()
1278
- if not project:
1279
- return {"error": "No project currently open"}
1280
- mode = project.GetCurrentRenderMode()
1281
- return {"render_mode": mode, "mode_name": "Individual Clips" if mode == 0 else "Single Clip"}
1282
-
1283
-
1284
- @mcp.tool()
1285
- def set_current_render_mode(mode: int) -> Dict[str, Any]:
1286
- """Set the render mode.
1287
-
1288
- Args:
1289
- mode: 0 for Individual Clips, 1 for Single Clip.
1290
- """
1291
- resolve = get_resolve()
1292
- if resolve is None:
1293
- return {"error": "Not connected to DaVinci Resolve"}
1294
- project = resolve.GetProjectManager().GetCurrentProject()
1295
- if not project:
1296
- return {"error": "No project currently open"}
1297
- result = project.SetCurrentRenderMode(mode)
1298
- return {"success": bool(result), "render_mode": mode}
1299
-
1300
-
1301
- @mcp.tool()
1302
- def get_render_resolutions(format_name: str, codec_name: str) -> Dict[str, Any]:
1303
- """Get available render resolutions for a format/codec combination.
1304
-
1305
- Args:
1306
- format_name: Render format (e.g. 'mp4').
1307
- codec_name: Codec name (e.g. 'H264').
1308
- """
1309
- resolve = get_resolve()
1310
- if resolve is None:
1311
- return {"error": "Not connected to DaVinci Resolve"}
1312
- project = resolve.GetProjectManager().GetCurrentProject()
1313
- if not project:
1314
- return {"error": "No project currently open"}
1315
- resolutions = project.GetRenderResolutions(format_name, codec_name)
1316
- return {"format": format_name, "codec": codec_name, "resolutions": resolutions if resolutions else []}
1317
-
1318
-
1319
- @mcp.tool()
1320
- def refresh_lut_list() -> Dict[str, Any]:
1321
- """Refresh the LUT list in the project. Call after adding new LUT files."""
1322
- resolve = get_resolve()
1323
- if resolve is None:
1324
- return {"error": "Not connected to DaVinci Resolve"}
1325
- project = resolve.GetProjectManager().GetCurrentProject()
1326
- if not project:
1327
- return {"error": "No project currently open"}
1328
- result = project.RefreshLUTList()
1329
- return {"success": bool(result)}
1330
-
1331
-
1332
- @mcp.tool()
1333
- def get_project_unique_id() -> Dict[str, Any]:
1334
- """Get the unique ID of the current project."""
1335
- resolve = get_resolve()
1336
- if resolve is None:
1337
- return {"error": "Not connected to DaVinci Resolve"}
1338
- project = resolve.GetProjectManager().GetCurrentProject()
1339
- if not project:
1340
- return {"error": "No project currently open"}
1341
- uid = project.GetUniqueId()
1342
- return {"unique_id": uid}
1343
-
1344
-
1345
- @mcp.tool()
1346
- def insert_audio_to_current_track(file_path: str) -> Dict[str, Any]:
1347
- """Insert audio file to current track at playhead position.
1348
-
1349
- Args:
1350
- file_path: Absolute path to the audio file.
1351
- """
1352
- resolve = get_resolve()
1353
- if resolve is None:
1354
- return {"error": "Not connected to DaVinci Resolve"}
1355
- project = resolve.GetProjectManager().GetCurrentProject()
1356
- if not project:
1357
- return {"error": "No project currently open"}
1358
- result = project.InsertAudioToCurrentTrackAtPlayhead(file_path)
1359
- return {"success": bool(result), "file_path": file_path}
1360
-
1361
-
1362
- @mcp.tool()
1363
- def load_burn_in_preset(preset_name: str) -> Dict[str, Any]:
1364
- """Load a burn-in preset by name for the project.
1365
-
1366
- Args:
1367
- preset_name: Name of the burn-in preset to load.
1368
- """
1369
- resolve = get_resolve()
1370
- if resolve is None:
1371
- return {"error": "Not connected to DaVinci Resolve"}
1372
- project = resolve.GetProjectManager().GetCurrentProject()
1373
- if not project:
1374
- return {"error": "No project currently open"}
1375
- result = project.LoadBurnInPreset(preset_name)
1376
- return {"success": bool(result), "preset_name": preset_name}
1377
-
1378
-
1379
- @mcp.tool()
1380
- def export_current_frame_as_still(file_path: str) -> Dict[str, Any]:
1381
- """Export the current frame as a still image.
1382
-
1383
- Args:
1384
- file_path: Absolute path for the exported still image.
1385
- """
1386
- resolve = get_resolve()
1387
- if resolve is None:
1388
- return {"error": "Not connected to DaVinci Resolve"}
1389
- project = resolve.GetProjectManager().GetCurrentProject()
1390
- if not project:
1391
- return {"error": "No project currently open"}
1392
- result = project.ExportCurrentFrameAsStill(file_path)
1393
- return {"success": bool(result), "file_path": file_path}
1394
-
1395
-
1396
- @mcp.tool()
1397
- def get_color_groups_list() -> Dict[str, Any]:
1398
- """Get list of all color groups in the current project."""
1399
- resolve = get_resolve()
1400
- if resolve is None:
1401
- return {"error": "Not connected to DaVinci Resolve"}
1402
- project = resolve.GetProjectManager().GetCurrentProject()
1403
- if not project:
1404
- return {"error": "No project currently open"}
1405
- groups = project.GetColorGroupsList()
1406
- if groups:
1407
- return {"color_groups": [{"name": g.GetName()} for g in groups]}
1408
- return {"color_groups": []}
1409
-
1410
-
1411
- @mcp.tool()
1412
- def add_color_group(group_name: str) -> Dict[str, Any]:
1413
- """Create a new color group in the current project.
1414
-
1415
- Args:
1416
- group_name: Name for the new color group.
1417
- """
1418
- resolve = get_resolve()
1419
- if resolve is None:
1420
- return {"error": "Not connected to DaVinci Resolve"}
1421
- project = resolve.GetProjectManager().GetCurrentProject()
1422
- if not project:
1423
- return {"error": "No project currently open"}
1424
- result = project.AddColorGroup(group_name)
1425
- return {"success": bool(result), "group_name": group_name}
1426
-
1427
-
1428
- @mcp.tool()
1429
- def delete_color_group(group_name: str) -> Dict[str, Any]:
1430
- """Delete a color group from the current project.
1431
-
1432
- Args:
1433
- group_name: Name of the color group to delete.
1434
- """
1435
- resolve = get_resolve()
1436
- if resolve is None:
1437
- return {"error": "Not connected to DaVinci Resolve"}
1438
- project = resolve.GetProjectManager().GetCurrentProject()
1439
- if not project:
1440
- return {"error": "No project currently open"}
1441
- # Find the group by name
1442
- groups = project.GetColorGroupsList()
1443
- target = None
1444
- if groups:
1445
- for g in groups:
1446
- if g.GetName() == group_name:
1447
- target = g
1448
- break
1449
- if not target:
1450
- return {"error": f"Color group '{group_name}' not found"}
1451
- result = project.DeleteColorGroup(target)
1452
- return {"success": bool(result), "group_name": group_name}
1453
-
1454
-
1455
- @mcp.tool()
1456
- def rename_color_group(group_name: str, new_name: str) -> Dict[str, Any]:
1457
- """Rename a color group.
1458
-
1459
- Mirrors ColorGroup.SetName(groupName).
1460
-
1461
- Args:
1462
- group_name: Current name of the color group.
1463
- new_name: New name to assign.
1464
- """
1465
- resolve = get_resolve()
1466
- if resolve is None:
1467
- return {"error": "Not connected to DaVinci Resolve"}
1468
- project = resolve.GetProjectManager().GetCurrentProject()
1469
- if not project:
1470
- return {"error": "No project currently open"}
1471
- groups = project.GetColorGroupsList() or []
1472
- target = next((g for g in groups if g.GetName() == group_name), None)
1473
- if not target:
1474
- return {"error": f"Color group '{group_name}' not found"}
1475
- return {"success": bool(target.SetName(new_name)), "old_name": group_name, "new_name": new_name}
1476
-
1477
-
1478
- @mcp.tool()
1479
- def apply_fairlight_preset_to_current_timeline(preset_name: str) -> Dict[str, Any]:
1480
- """Apply a Fairlight preset to the current timeline.
1481
-
1482
- Args:
1483
- preset_name: Name of the Fairlight preset to apply.
1484
- """
1485
- resolve = get_resolve()
1486
- if resolve is None:
1487
- return {"error": "Not connected to DaVinci Resolve"}
1488
- project = resolve.GetProjectManager().GetCurrentProject()
1489
- if not project:
1490
- return {"error": "No project currently open"}
1491
- missing = _requires_method(project, "ApplyFairlightPresetToCurrentTimeline", "20.2.2")
1492
- if missing:
1493
- return missing
1494
- result = project.ApplyFairlightPresetToCurrentTimeline(preset_name)
1495
- return {"success": bool(result), "preset_name": preset_name}
1496
-
1497
-
1498
- @mcp.tool()
1499
- def get_quick_export_render_presets() -> Dict[str, Any]:
1500
- """Get list of available quick export render presets."""
1501
- resolve = get_resolve()
1502
- if resolve is None:
1503
- return {"error": "Not connected to DaVinci Resolve"}
1504
- project = resolve.GetProjectManager().GetCurrentProject()
1505
- if not project:
1506
- return {"error": "No project currently open"}
1507
- presets = project.GetQuickExportRenderPresets()
1508
- return {"presets": presets if presets else []}
1509
-
1510
-
1511
- @mcp.tool()
1512
- def render_with_quick_export(
1513
- preset_name: str,
1514
- target_dir: Optional[str] = None,
1515
- custom_name: Optional[str] = None,
1516
- video_quality: Optional[Any] = None,
1517
- enable_upload: Optional[bool] = None,
1518
- ) -> Dict[str, Any]:
1519
- """Render the current timeline using a Quick Export preset.
1520
-
1521
- Mirrors Project.RenderWithQuickExport(preset_name, {param_dict}) per docs line 179.
1522
-
1523
- Args:
1524
- preset_name: Name of the Quick Export preset (from get_quick_export_render_presets).
1525
- target_dir: Output directory; maps to TargetDir in param_dict.
1526
- custom_name: Output filename; maps to CustomName.
1527
- video_quality: Video quality setting (int or string per render-settings spec); maps to VideoQuality.
1528
- enable_upload: Enable direct upload for supported web presets; maps to EnableUpload.
1529
- """
1530
- resolve = get_resolve()
1531
- if resolve is None:
1532
- return {"error": "Not connected to DaVinci Resolve"}
1533
- project = resolve.GetProjectManager().GetCurrentProject()
1534
- if not project:
1535
- return {"error": "No project currently open"}
1536
- param_dict: Dict[str, Any] = {}
1537
- if target_dir is not None:
1538
- param_dict["TargetDir"] = target_dir
1539
- if custom_name is not None:
1540
- param_dict["CustomName"] = custom_name
1541
- if video_quality is not None:
1542
- param_dict["VideoQuality"] = video_quality
1543
- if enable_upload is not None:
1544
- param_dict["EnableUpload"] = bool(enable_upload)
1545
- if param_dict:
1546
- result = project.RenderWithQuickExport(preset_name, param_dict)
1547
- else:
1548
- result = project.RenderWithQuickExport(preset_name)
1549
- if not result:
1550
- return {"success": False, "preset_name": preset_name, "error": "RenderWithQuickExport returned no status"}
1551
- if isinstance(result, str):
1552
- return {"success": False, "preset_name": preset_name, "error": result}
1553
- return {"success": True, "preset_name": preset_name, "status": result}
1554
-
1555
-
1556
- @mcp.tool()
1557
- def add_render_job() -> Dict[str, Any]:
1558
- """Add a render job based on current render settings to the render queue.
1559
-
1560
- Returns the unique job ID string for the new render job.
1561
- Configure render settings first with set_render_settings, set_render_format_and_codec, etc.
1562
- """
1563
- resolve = get_resolve()
1564
- if resolve is None:
1565
- return {"error": "Not connected to DaVinci Resolve"}
1566
- project = resolve.GetProjectManager().GetCurrentProject()
1567
- if not project:
1568
- return {"error": "No project currently open"}
1569
- job_id = project.AddRenderJob()
1570
- if job_id:
1571
- return {"success": True, "job_id": job_id}
1572
- return {"success": False, "error": "Failed to add render job. Check render settings are configured."}
1573
-
1574
-
1575
- @mcp.tool()
1576
- def load_cloud_project(project_name: str, project_media_path: str, sync_mode: str = "proxy") -> Dict[str, Any]:
1577
- """Load a cloud project from DaVinci Resolve cloud.
1578
-
1579
- Args:
1580
- project_name: Name of the cloud project to load.
1581
- project_media_path: Local path for project media cache.
1582
- sync_mode: Sync mode - 'proxy' or 'full' (default: 'proxy').
1583
- """
1584
- resolve = get_resolve()
1585
- if resolve is None:
1586
- return {"error": "Not connected to DaVinci Resolve"}
1587
- pm = resolve.GetProjectManager()
1588
- if not pm:
1589
- return {"error": "Failed to get ProjectManager"}
1590
- cloud_settings = {
1591
- resolve.CLOUD_SETTING_PROJECT_NAME: project_name,
1592
- resolve.CLOUD_SETTING_PROJECT_MEDIA_PATH: project_media_path,
1593
- resolve.CLOUD_SETTING_SYNC_MODE: sync_mode,
1594
- }
1595
- project = pm.LoadCloudProject(cloud_settings)
1596
- if project:
1597
- return {"success": True, "project_name": project.GetName()}
1598
- return {"success": False, "error": "Failed to load cloud project. Check cloud settings and connectivity."}
1599
-
1600
-
1601
- @mcp.tool()
1602
- def generate_speech(text_input: str, voice_model: str = "", timecode: str = "",
1603
- add_to_timeline: bool = False, audio_track: Optional[int] = None,
1604
- custom_voice_file: str = "", speed: Optional[int] = None,
1605
- variation: Optional[int] = None, pitch: Optional[int] = None,
1606
- generation_id: Optional[int] = None, filename: str = "") -> Dict[str, Any]:
1607
- """Generate AI text-to-speech audio and add it to the media pool (Resolve 21+).
1608
-
1609
- Requires the AI Speech Generator Extra. Creates a NEW audio MediaPoolItem; if
1610
- add_to_timeline is True it is placed on the timeline at the given timecode.
1611
-
1612
- Args:
1613
- text_input: Text to synthesize (required).
1614
- voice_model: Voice model name (e.g. "Female 1", "Male 1", "Custom Voice").
1615
- timecode: Timeline timecode to place the clip at when add_to_timeline is True.
1616
- add_to_timeline: Whether to add the generated clip to the timeline.
1617
- audio_track: Audio track index for timeline placement.
1618
- custom_voice_file: Full path to a custom voice file (for "Custom Voice").
1619
- speed: Speech speed.
1620
- variation: Voice variation.
1621
- pitch: Voice pitch.
1622
- generation_id: Generation ID.
1623
- filename: Output filename.
1624
- """
1625
- pm, current_project = get_current_project()
1626
- if not current_project:
1627
- return {"error": "No project currently open"}
1628
- if not hasattr(current_project, "GenerateSpeech"):
1629
- return {"error": "GenerateSpeech requires DaVinci Resolve 21+ and the AI Speech Generator Extra"}
1630
- if not text_input:
1631
- return {"error": "text_input is required"}
1632
- settings: Dict[str, Any] = {"TextInput": text_input}
1633
- if voice_model:
1634
- settings["VoiceModel"] = voice_model
1635
- if custom_voice_file:
1636
- settings["CustomVoiceFile"] = custom_voice_file
1637
- if speed is not None:
1638
- settings["Speed"] = speed
1639
- if variation is not None:
1640
- settings["Variation"] = variation
1641
- if pitch is not None:
1642
- settings["Pitch"] = pitch
1643
- if generation_id is not None:
1644
- settings["GenerationID"] = generation_id
1645
- if filename:
1646
- settings["Filename"] = filename
1647
- if add_to_timeline:
1648
- settings["AddToTimeline"] = True
1649
- if audio_track is not None:
1650
- settings["AudioTrack"] = audio_track
1651
- new_item = current_project.GenerateSpeech(settings, timecode or "")
1652
- if not new_item:
1653
- return {"success": False, "error": "GenerateSpeech returned no media item"}
1654
- return {"success": True, "new": new_item.GetName(), "new_id": new_item.GetUniqueId()}