[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"similar-samuelgursky--davinci-resolve-mcp":3,"tool-samuelgursky--davinci-resolve-mcp":64},[4,17,27,35,48,56],{"id":5,"name":6,"github_repo":7,"description_zh":8,"stars":9,"difficulty_score":10,"last_commit_at":11,"category_tags":12,"status":16},3808,"stable-diffusion-webui","AUTOMATIC1111\u002Fstable-diffusion-webui","stable-diffusion-webui 是一个基于 Gradio 构建的网页版操作界面，旨在让用户能够轻松地在本地运行和使用强大的 Stable Diffusion 图像生成模型。它解决了原始模型依赖命令行、操作门槛高且功能分散的痛点，将复杂的 AI 绘图流程整合进一个直观易用的图形化平台。\n\n无论是希望快速上手的普通创作者、需要精细控制画面细节的设计师，还是想要深入探索模型潜力的开发者与研究人员，都能从中获益。其核心亮点在于极高的功能丰富度：不仅支持文生图、图生图、局部重绘（Inpainting）和外绘（Outpainting）等基础模式，还独创了注意力机制调整、提示词矩阵、负向提示词以及“高清修复”等高级功能。此外，它内置了 GFPGAN 和 CodeFormer 等人脸修复工具，支持多种神经网络放大算法，并允许用户通过插件系统无限扩展能力。即使是显存有限的设备，stable-diffusion-webui 也提供了相应的优化选项，让高质量的 AI 艺术创作变得触手可及。",162132,3,"2026-04-05T11:01:52",[13,14,15],"开发框架","图像","Agent","ready",{"id":18,"name":19,"github_repo":20,"description_zh":21,"stars":22,"difficulty_score":23,"last_commit_at":24,"category_tags":25,"status":16},1381,"everything-claude-code","affaan-m\u002Feverything-claude-code","everything-claude-code 是一套专为 AI 编程助手（如 Claude Code、Codex、Cursor 等）打造的高性能优化系统。它不仅仅是一组配置文件，而是一个经过长期实战打磨的完整框架，旨在解决 AI 代理在实际开发中面临的效率低下、记忆丢失、安全隐患及缺乏持续学习能力等核心痛点。\n\n通过引入技能模块化、直觉增强、记忆持久化机制以及内置的安全扫描功能，everything-claude-code 能显著提升 AI 在复杂任务中的表现，帮助开发者构建更稳定、更智能的生产级 AI 代理。其独特的“研究优先”开发理念和针对 Token 消耗的优化策略，使得模型响应更快、成本更低，同时有效防御潜在的攻击向量。\n\n这套工具特别适合软件开发者、AI 研究人员以及希望深度定制 AI 工作流的技术团队使用。无论您是在构建大型代码库，还是需要 AI 协助进行安全审计与自动化测试，everything-claude-code 都能提供强大的底层支持。作为一个曾荣获 Anthropic 黑客大奖的开源项目，它融合了多语言支持与丰富的实战钩子（hooks），让 AI 真正成长为懂上",138956,2,"2026-04-05T11:33:21",[13,15,26],"语言模型",{"id":28,"name":29,"github_repo":30,"description_zh":31,"stars":32,"difficulty_score":23,"last_commit_at":33,"category_tags":34,"status":16},2271,"ComfyUI","Comfy-Org\u002FComfyUI","ComfyUI 是一款功能强大且高度模块化的视觉 AI 引擎，专为设计和执行复杂的 Stable Diffusion 图像生成流程而打造。它摒弃了传统的代码编写模式，采用直观的节点式流程图界面，让用户通过连接不同的功能模块即可构建个性化的生成管线。\n\n这一设计巧妙解决了高级 AI 绘图工作流配置复杂、灵活性不足的痛点。用户无需具备编程背景，也能自由组合模型、调整参数并实时预览效果，轻松实现从基础文生图到多步骤高清修复等各类复杂任务。ComfyUI 拥有极佳的兼容性，不仅支持 Windows、macOS 和 Linux 全平台，还广泛适配 NVIDIA、AMD、Intel 及苹果 Silicon 等多种硬件架构，并率先支持 SDXL、Flux、SD3 等前沿模型。\n\n无论是希望深入探索算法潜力的研究人员和开发者，还是追求极致创作自由度的设计师与资深 AI 绘画爱好者，ComfyUI 都能提供强大的支持。其独特的模块化架构允许社区不断扩展新功能，使其成为当前最灵活、生态最丰富的开源扩散模型工具之一，帮助用户将创意高效转化为现实。",107662,"2026-04-03T11:11:01",[13,14,15],{"id":36,"name":37,"github_repo":38,"description_zh":39,"stars":40,"difficulty_score":23,"last_commit_at":41,"category_tags":42,"status":16},2268,"ML-For-Beginners","microsoft\u002FML-For-Beginners","ML-For-Beginners 是由微软推出的一套系统化机器学习入门课程，旨在帮助零基础用户轻松掌握经典机器学习知识。这套课程将学习路径规划为 12 周，包含 26 节精炼课程和 52 道配套测验，内容涵盖从基础概念到实际应用的完整流程，有效解决了初学者面对庞大知识体系时无从下手、缺乏结构化指导的痛点。\n\n无论是希望转型的开发者、需要补充算法背景的研究人员，还是对人工智能充满好奇的普通爱好者，都能从中受益。课程不仅提供了清晰的理论讲解，还强调动手实践，让用户在循序渐进中建立扎实的技能基础。其独特的亮点在于强大的多语言支持，通过自动化机制提供了包括简体中文在内的 50 多种语言版本，极大地降低了全球不同背景用户的学习门槛。此外，项目采用开源协作模式，社区活跃且内容持续更新，确保学习者能获取前沿且准确的技术资讯。如果你正寻找一条清晰、友好且专业的机器学习入门之路，ML-For-Beginners 将是理想的起点。",84991,"2026-04-05T10:45:23",[14,43,44,45,15,46,26,13,47],"数据工具","视频","插件","其他","音频",{"id":49,"name":50,"github_repo":51,"description_zh":52,"stars":53,"difficulty_score":10,"last_commit_at":54,"category_tags":55,"status":16},3128,"ragflow","infiniflow\u002Fragflow","RAGFlow 是一款领先的开源检索增强生成（RAG）引擎，旨在为大语言模型构建更精准、可靠的上下文层。它巧妙地将前沿的 RAG 技术与智能体（Agent）能力相结合，不仅支持从各类文档中高效提取知识，还能让模型基于这些知识进行逻辑推理和任务执行。\n\n在大模型应用中，幻觉问题和知识滞后是常见痛点。RAGFlow 通过深度解析复杂文档结构（如表格、图表及混合排版），显著提升了信息检索的准确度，从而有效减少模型“胡编乱造”的现象，确保回答既有据可依又具备时效性。其内置的智能体机制更进一步，使系统不仅能回答问题，还能自主规划步骤解决复杂问题。\n\n这款工具特别适合开发者、企业技术团队以及 AI 研究人员使用。无论是希望快速搭建私有知识库问答系统，还是致力于探索大模型在垂直领域落地的创新者，都能从中受益。RAGFlow 提供了可视化的工作流编排界面和灵活的 API 接口，既降低了非算法背景用户的上手门槛，也满足了专业开发者对系统深度定制的需求。作为基于 Apache 2.0 协议开源的项目，它正成为连接通用大模型与行业专有知识之间的重要桥梁。",77062,"2026-04-04T04:44:48",[15,14,13,26,46],{"id":57,"name":58,"github_repo":59,"description_zh":60,"stars":61,"difficulty_score":10,"last_commit_at":62,"category_tags":63,"status":16},2181,"OpenHands","OpenHands\u002FOpenHands","OpenHands 是一个专注于 AI 驱动开发的开源平台，旨在让智能体（Agent）像人类开发者一样理解、编写和调试代码。它解决了传统编程中重复性劳动多、环境配置复杂以及人机协作效率低等痛点，通过自动化流程显著提升开发速度。\n\n无论是希望提升编码效率的软件工程师、探索智能体技术的研究人员，还是需要快速原型验证的技术团队，都能从中受益。OpenHands 提供了灵活多样的使用方式：既可以通过命令行（CLI）或本地图形界面在个人电脑上轻松上手，体验类似 Devin 的流畅交互；也能利用其强大的 Python SDK 自定义智能体逻辑，甚至在云端大规模部署上千个智能体并行工作。\n\n其核心技术亮点在于模块化的软件智能体 SDK，这不仅构成了平台的引擎，还支持高度可组合的开发模式。此外，OpenHands 在 SWE-bench 基准测试中取得了 77.6% 的优异成绩，证明了其解决真实世界软件工程问题的能力。平台还具备完善的企业级功能，支持与 Slack、Jira 等工具集成，并提供细粒度的权限管理，适合从个人开发者到大型企业的各类用户场景。",70612,"2026-04-05T11:12:22",[26,15,13,45],{"id":65,"github_repo":66,"name":67,"description_en":68,"description_zh":69,"ai_summary_zh":69,"readme_en":70,"readme_zh":71,"quickstart_zh":72,"use_case_zh":73,"hero_image_url":74,"owner_login":75,"owner_name":76,"owner_avatar_url":77,"owner_bio":78,"owner_company":79,"owner_location":80,"owner_email":81,"owner_twitter":75,"owner_website":82,"owner_url":83,"languages":84,"stars":96,"forks":97,"last_commit_at":98,"license":99,"difficulty_score":100,"env_os":101,"env_gpu":102,"env_ram":103,"env_deps":104,"category_tags":109,"github_topics":110,"view_count":23,"oss_zip_url":81,"oss_zip_packed_at":81,"status":16,"created_at":118,"updated_at":119,"faqs":120,"releases":148},3673,"samuelgursky\u002Fdavinci-resolve-mcp","davinci-resolve-mcp","MCP server integration for DaVinci Resolve","davinci-resolve-mcp 是一款连接人工智能助手与达芬奇（DaVinci Resolve）剪辑软件的桥梁工具。它基于模型上下文协议（MCP）构建，能够完整覆盖达芬奇的脚本 API，让用户通过自然语言指令直接操控软件，从而将繁琐的后期制作流程转化为简单的对话交互。\n\n这款工具主要解决了传统视频编辑中重复性操作多、脚本编写门槛高的问题。用户无需手动编写复杂的 Python 代码或反复点击菜单，只需告诉 AI 助手想要执行的操作（如调整节点、导出素材或管理时间线），即可自动完成。它特别适合视频剪辑师、调色师以及希望利用 AI 提升工作效率的创意工作者，同时也为开发者提供了强大的自动化集成方案。\n\n其技术亮点在于对达芬奇 Fusion 合成模块的深度支持，新增的工具可全面操控节点图、关键帧及渲染流程。此外，它还具备智能的文件管理机制，能自动处理跨平台沙盒路径限制，并在导出任务完成后自动清理临时文件，确保系统整洁安全。从版本迭代中也能看出，开发团队高度重视安全性，特别增加了防止路径遍历的保护措施，让自动化操作更加可靠放心。","# DaVinci Resolve MCP Server\n\n[![Version](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Fversion-2.1.0-blue.svg)](https:\u002F\u002Fgithub.com\u002Fsamuelgursky\u002Fdavinci-resolve-mcp\u002Freleases)\n[![API Coverage](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FAPI%20Coverage-100%25-brightgreen.svg)](#api-coverage)\n[![Tools](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FMCP%20Tools-27%20(342%20full)-blue.svg)](#server-modes)\n[![Tested](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FLive%20Tested-98.5%25-green.svg)](#test-results)\n[![DaVinci Resolve](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FDaVinci%20Resolve-18.5+-darkred.svg)](https:\u002F\u002Fwww.blackmagicdesign.com\u002Fproducts\u002Fdavinciresolve)\n[![Python](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Fpython-3.10--3.12-green.svg)](https:\u002F\u002Fwww.python.org\u002Fdownloads\u002F)\n[![License](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Flicense-MIT-blue.svg)](https:\u002F\u002Fopensource.org\u002Flicenses\u002FMIT)\n\nA Model Context Protocol (MCP) server providing **complete coverage** of the DaVinci Resolve Scripting API. Connect AI assistants (Claude, Cursor, Windsurf) to DaVinci Resolve and control every aspect of your post-production workflow through natural language.\n\n### What's New in v2.1.0\n\n- **New `fusion_comp` tool** — 20-action tool exposing the full Fusion composition node graph API. Add\u002Fdelete\u002Ffind nodes, wire connections, set\u002Fget parameters, manage keyframes, control undo grouping, set render ranges, and trigger renders — all on the currently active Fusion page composition\n- **`timeline_item_fusion` cache actions** — added `get_cache_enabled` and `set_cache` actions for Fusion output cache control directly on timeline items\n- **Fusion node graph reference** — docstring includes common tool IDs (Merge, TextPlus, Background, Transform, ColorCorrector, DeltaKeyer, etc.) for discoverability\n\n### v2.0.9\n\n- **Cross-platform sandbox path redirect** — `_resolve_safe_dir()` now handles macOS (`\u002Fvar\u002Ffolders`, `\u002Fprivate\u002Fvar`), Linux (`\u002Ftmp`, `\u002Fvar\u002Ftmp`), and Windows (`AppData\\Local\\Temp`) sandbox paths that Resolve can't write to. Redirects to `~\u002FDocuments\u002Fresolve-stills` instead of Desktop\n- **Auto-cleanup for `grab_and_export`** — exported files are read into the response (DRX as inline text, images as base64) then deleted from disk automatically. Zero file accumulation. Pass `cleanup: false` to keep files on disk\n- **Both servers in sync** — `server.py` and `resolve_mcp_server.py` now share the same version and both use `_resolve_safe_dir()` for all Resolve-facing temp paths (project export, LUT export, still export)\n\n### v2.0.8\n\n- **New `grab_and_export` action on `gallery_stills`** — combines `GrabStill()` + `ExportStills()` in a single atomic call, keeping the live GalleryStill reference for reliable export. Returns a file manifest with exported image + companion `.drx` grade file\n- **Format fallback chain** — if the requested format fails, automatically retries with tif then dpx\n- **macOS sandbox path redirect** — `\u002Fvar\u002Ffolders` and `\u002Fprivate\u002Fvar` paths are redirected to `~\u002FDesktop\u002Fresolve-stills` since Resolve's process can't write to sandboxed temp directories\n- **Key finding documented** — `ExportStills` requires the Gallery panel to be visible on the Color page. All 9 supported formats (dpx, cin, tif, jpg, png, ppm, bmp, xpm, drx) produce a companion `.drx` grade file alongside the image\n\n### v2.0.7\n\n- **Security: path traversal protection for layout preset tools** — `export_layout_preset`, `import_layout_preset`, and `delete_layout_preset` now validate that resolved file paths stay within the expected Resolve presets directory, preventing path traversal via crafted preset names\n- **Security: document destructive tool risk** — added Security Considerations section noting that `quit_app`\u002F`restart_app` tools can terminate Resolve; MCP clients should require user confirmation before invoking\n\n### v2.0.6\n\n- **Fix color group operations crash** — `timeline_item_color` unpacked `_check()` as `(proj, _, _)` but `_check()` returns `(pm, proj, err)`, so `proj` got the ProjectManager instead of the Project, crashing `assign_color_group` and `remove_from_color_group`\n\n### v2.0.5\n\n- **Lazy connection recovery** — full server (`--full` mode) now auto-reconnects and auto-launches Resolve, matching the compound server behavior\n- **Null guards on all chained API calls** — `GetProjectManager()`, `GetCurrentProject()`, `GetCurrentTimeline()` failures now return clear errors instead of `NoneType` crashes\n- **Helper functions** — `get_resolve()`, `get_project_manager()`, `get_current_project()` replace 178 boilerplate blocks\n\n### v2.0.4\n\n- **Fix apply_grade_from_drx parameter** — renamed `mode` to `grade_mode` to match Resolve API; corrected documentation from replace\u002Fappend to actual keyframe alignment modes (0=No keyframes, 1=Source Timecode aligned, 2=Start Frames aligned)\n- **Backward compatible** — still accepts `mode` for existing clients, `grade_mode` takes precedence\n\n### v2.0.3\n\n- **Fix GetNodeGraph crash** — `GetNodeGraph(0)` returns `False` in Resolve; now calls without args unless `layer_index` is explicitly provided\n- **Falsy node graph check** — guard checks `not g` instead of `g is None` to catch `False` returns\n\n### v2.0.2\n\n- **Antigravity support** — Google's agentic AI coding assistant added as 10th MCP client\n- **Alphabetical client ordering** — MCP_CLIENTS list sorted for easier maintenance\n\n### v2.0.1\n\n- **26-tool compound server** — all 324 API methods grouped into 26 context-efficient tools (default)\n- **Universal installer** — single `python install.py` for macOS\u002FWindows\u002FLinux, 10 MCP clients\n- **Dedicated timeline_item actions** — retime\u002Fspeed, transform, crop, composite, audio, keyframes with validation\n- **Lazy Resolve connection** — server starts instantly, connects when first tool is called\n- **Bug fixes** — CreateMagicMask param type, GetCurrentClipThumbnailImage args, Python 3.13+ warning\n\n## Key Stats\n\n| Metric | Value |\n|--------|-------|\n| MCP Tools | **26** compound (default) \u002F **342** granular |\n| API Methods Covered | **324\u002F324** (100%) |\n| Methods Live Tested | **319\u002F324** (98.5%) |\n| Live Test Pass Rate | **319\u002F319** (100%) |\n| API Object Classes | 13 |\n| Tested Against | DaVinci Resolve 19.1.3 Studio |\n\n## API Coverage\n\nEvery non-deprecated method in the DaVinci Resolve Scripting API is covered. The default compound server exposes **27 tools** that group related operations by action parameter, keeping LLM context windows lean. The full granular server provides **342 individual tools** for power users. Both modes cover all 13 API object classes:\n\n| Class | Methods | Tools | Description |\n|-------|---------|-------|-------------|\n| Resolve | 21 | 21 | App control, pages, layout presets, render\u002Fburn-in presets, keyframe mode |\n| ProjectManager | 25 | 25 | Project CRUD, folders, databases, cloud projects, archive\u002Frestore |\n| Project | 42 | 42 | Timelines, render pipeline, settings, LUTs, color groups |\n| MediaStorage | 9 | 9 | Volumes, file browsing, media import, mattes |\n| MediaPool | 27 | 27 | Folders, clips, timelines, metadata, stereo, sync |\n| Folder | 8 | 8 | Clip listing, export, transcription |\n| MediaPoolItem | 32 | 32 | Metadata, markers, flags, properties, proxy, transcription |\n| Timeline | 56 | 56 | Tracks, markers, items, export, generators, titles, stills, stereo |\n| TimelineItem | 76 | 76 | Properties, markers, Fusion comps, versions, takes, CDL, AI tools |\n| Gallery | 8 | 8 | Albums, stills, power grades |\n| GalleryStillAlbum | 6 | 6 | Stills management, import\u002Fexport, labels |\n| Graph | 11 | 22 | Node operations, LUTs, cache, grades (timeline + clip graph variants) |\n| ColorGroup | 5 | 10 | Group management, pre\u002Fpost clip node graphs |\n\n## Requirements\n\n- **DaVinci Resolve Studio** 18.5+ (macOS, Windows, or Linux) — the free edition does not support external scripting\n- **Python 3.10–3.12** recommended (3.13+ may have ABI incompatibilities with Resolve's scripting library)\n- DaVinci Resolve running with **Preferences > General > \"External scripting using\"** set to **Local**\n\n## Quick Start\n\n```bash\n# Clone the repository\ngit clone https:\u002F\u002Fgithub.com\u002Fsamuelgursky\u002Fdavinci-resolve-mcp.git\ncd davinci-resolve-mcp\n\n# Make sure DaVinci Resolve is running, then:\npython install.py\n```\n\nThe universal installer auto-detects your platform, finds your DaVinci Resolve installation, creates a virtual environment, and configures your MCP client — all in one step.\n\n### Supported MCP Clients\n\nThe installer can automatically configure any of these clients:\n\n| Client | Config Written To |\n|--------|-------------------|\n| Claude Desktop | `~\u002FLibrary\u002FApplication Support\u002FClaude\u002Fclaude_desktop_config.json` (macOS) |\n| Claude Code | `.mcp.json` (project root) |\n| Cursor | `~\u002F.cursor\u002Fmcp.json` |\n| VS Code (Copilot) | `.vscode\u002Fmcp.json` (workspace) |\n| Windsurf | `~\u002F.codeium\u002Fwindsurf\u002Fmcp_config.json` |\n| Cline | VS Code global storage |\n| Roo Code | VS Code global storage |\n| Zed | `~\u002F.config\u002Fzed\u002Fsettings.json` |\n| Continue | `~\u002F.continue\u002Fconfig.json` |\n| JetBrains IDEs | Manual (Settings > Tools > AI Assistant > MCP) |\n\nYou can configure multiple clients at once, or use `--clients manual` to get copy-paste config snippets.\n\n### Installer Options\n\n```bash\npython install.py                              # Interactive mode\npython install.py --clients all                # Configure all clients\npython install.py --clients cursor,claude-desktop  # Specific clients\npython install.py --clients manual             # Just print the config\npython install.py --dry-run --clients all      # Preview without writing\npython install.py --no-venv --clients cursor   # Skip venv creation\n```\n\n### Server Modes\n\nThe MCP server comes in two modes:\n\n| Mode | File | Tools | Best For |\n|------|------|-------|----------|\n| **Compound** (default) | `src\u002Fserver.py` | 26 | Most users — fast, clean, low context usage |\n| **Full** | `src\u002Fresolve_mcp_server.py` | 342 | Power users who want one tool per API method |\n\nThe compound server's `timeline_item` tool includes dedicated actions for common workflows:\n\n| Category | Actions | Parameters |\n|----------|---------|------------|\n| **Retime** | `get_retime`, `set_retime` | process (nearest, frame_blend, optical_flow), motion_estimation (0-6) |\n| **Transform** | `get_transform`, `set_transform` | Pan, Tilt, ZoomX\u002FY, RotationAngle, AnchorPointX\u002FY, Pitch, Yaw, FlipX\u002FY |\n| **Crop** | `get_crop`, `set_crop` | CropLeft, CropRight, CropTop, CropBottom, CropSoftness, CropRetain |\n| **Composite** | `get_composite`, `set_composite` | Opacity, CompositeMode |\n| **Audio** | `get_audio`, `set_audio` | Volume, Pan, AudioSyncOffset |\n| **Keyframes** | `get_keyframes`, `add_keyframe`, `modify_keyframe`, `delete_keyframe`, `set_keyframe_interpolation` | property, frame, value, interpolation (Linear, Bezier, EaseIn, EaseOut, EaseInOut) |\n\nThe installer uses the compound server by default. To use the full server:\n```bash\npython src\u002Fserver.py --full    # Launch full 342-tool server\n# Or point your MCP config directly at src\u002Fresolve_mcp_server.py\n```\n\n### Manual Configuration\n\nIf you prefer to set things up yourself, add to your MCP client config:\n\n```json\n{\n  \"mcpServers\": {\n    \"davinci-resolve\": {\n      \"command\": \"\u002Fpath\u002Fto\u002Fvenv\u002Fbin\u002Fpython\",\n      \"args\": [\"\u002Fpath\u002Fto\u002Fdavinci-resolve-mcp\u002Fsrc\u002Fserver.py\"]\n    }\n  }\n}\n```\n\nPlatform-specific paths:\n\n| Platform | API Path | Library Path |\n|----------|----------|-------------|\n| macOS | `\u002FLibrary\u002FApplication Support\u002FBlackmagic Design\u002FDaVinci Resolve\u002FDeveloper\u002FScripting` | `fusionscript.so` in DaVinci Resolve.app |\n| Windows | `C:\\ProgramData\\Blackmagic Design\\DaVinci Resolve\\Support\\Developer\\Scripting` | `fusionscript.dll` in Resolve install dir |\n| Linux | `\u002Fopt\u002Fresolve\u002FDeveloper\u002FScripting` | `\u002Fopt\u002Fresolve\u002Flibs\u002FFusion\u002Ffusionscript.so` |\n\n## Usage Examples\n\nOnce connected, you can control DaVinci Resolve through natural language:\n\n```\n\"What version of DaVinci Resolve is running?\"\n\"List all projects and open the one called 'My Film'\"\n\"Create a new timeline called 'Assembly Cut' and add all clips from the media pool\"\n\"Add a blue marker at the current playhead position with note 'Review this'\"\n\"Set up a ProRes 422 HQ render for the current timeline\"\n\"Export the timeline as an EDL\"\n\"Switch to the Color page and grab a still\"\n\"Create a Fusion composition on the selected clip\"\n```\n\n## Test Results\n\nAll testing performed against **DaVinci Resolve 19.1.3 Studio** on macOS with live API calls (no mocks).\n\n| Phase | Tests | Pass Rate | Scope |\n|-------|-------|-----------|-------|\n| Phase 1 | 204\u002F204 | 100% | Safe read-only operations across all classes |\n| Phase 2 | 79\u002F79 | 100% | Destructive operations with create-test-cleanup patterns |\n| Phase 3 | 20\u002F20 | 100% | Real media import, sync, transcription, database switching, Resolve.Quit |\n| Phase 4 | 10\u002F10 | 100% | AI\u002FML methods, Fusion clips, stereo, gallery stills |\n| Phase 5 | 6\u002F6 | 100% | Scene cuts, subtitles from audio, graph node cache\u002Ftools\u002Fenable |\n| **Total** | **319\u002F319** | **100%** | **98.5% of all API methods tested live** |\n\n### Untested Methods (5 of 324)\n\n| Method | Reason | Help Wanted |\n|--------|--------|-------------|\n| `PM.CreateCloudProject` | Requires DaVinci Resolve cloud infrastructure | Yes |\n| `PM.LoadCloudProject` | Requires DaVinci Resolve cloud infrastructure | Yes |\n| `PM.ImportCloudProject` | Requires DaVinci Resolve cloud infrastructure | Yes |\n| `PM.RestoreCloudProject` | Requires DaVinci Resolve cloud infrastructure | Yes |\n| `TL.AnalyzeDolbyVision` | Requires HDR\u002FDolby Vision content | Yes |\n\n---\n\n## Complete API Reference\n\nEvery method in the DaVinci Resolve Scripting API and its test status. Methods are listed by object class.\n\n**Status Key:**\n- ✅ = Tested live, returned expected result\n- ⚠️ = Tested live, API accepted call (returned `False` — needs specific context to fully execute)\n- ☁️ = Requires cloud infrastructure (untested)\n- 🔬 = Requires specific content\u002Fhardware (untested — PRs welcome)\n\n### Resolve\n\n| # | Method | Status | Test Result \u002F Notes |\n|---|--------|--------|---------------------|\n| 1 | `Fusion()` | ✅ | Returns Fusion object |\n| 2 | `GetMediaStorage()` | ✅ | Returns MediaStorage object |\n| 3 | `GetProjectManager()` | ✅ | Returns ProjectManager object |\n| 4 | `OpenPage(pageName)` | ✅ | Switches Resolve page |\n| 5 | `GetCurrentPage()` | ✅ | Returns current page name (e.g. `\"edit\"`) |\n| 6 | `GetProductName()` | ✅ | Returns `\"DaVinci Resolve Studio\"` |\n| 7 | `GetVersion()` | ✅ | Returns `[19, 1, 3, 7, '']` |\n| 8 | `GetVersionString()` | ✅ | Returns `\"19.1.3.7\"` |\n| 9 | `LoadLayoutPreset(presetName)` | ✅ | Loads saved layout |\n| 10 | `UpdateLayoutPreset(presetName)` | ✅ | Updates existing preset |\n| 11 | `ExportLayoutPreset(presetName, presetFilePath)` | ✅ | Exports preset to file |\n| 12 | `DeleteLayoutPreset(presetName)` | ✅ | Deletes preset |\n| 13 | `SaveLayoutPreset(presetName)` | ⚠️ | API accepts; returns `False` when preset name conflicts |\n| 14 | `ImportLayoutPreset(presetFilePath, presetName)` | ✅ | Imports preset from file |\n| 15 | `Quit()` | ✅ | Quits DaVinci Resolve |\n| 16 | `ImportRenderPreset(presetPath)` | ⚠️ | API accepts; needs valid preset file |\n| 17 | `ExportRenderPreset(presetName, exportPath)` | ⚠️ | API accepts; needs valid preset name |\n| 18 | `ImportBurnInPreset(presetPath)` | ⚠️ | API accepts; needs valid preset file |\n| 19 | `ExportBurnInPreset(presetName, exportPath)` | ⚠️ | API accepts; needs valid preset name |\n| 20 | `GetKeyframeMode()` | ✅ | Returns keyframe mode |\n| 21 | `SetKeyframeMode(keyframeMode)` | ⚠️ | API accepts; mode must match valid enum |\n\n### ProjectManager\n\n| # | Method | Status | Test Result \u002F Notes |\n|---|--------|--------|---------------------|\n| 1 | `ArchiveProject(projectName, filePath, ...)` | ⚠️ | API accepts; archiving is slow |\n| 2 | `CreateProject(projectName)` | ✅ | Creates new project |\n| 3 | `DeleteProject(projectName)` | ⚠️ | Returns `False` if project is open |\n| 4 | `LoadProject(projectName)` | ✅ | Returns Project object |\n| 5 | `GetCurrentProject()` | ✅ | Returns current Project |\n| 6 | `SaveProject()` | ✅ | Saves current project |\n| 7 | `CloseProject(project)` | ✅ | Closes project |\n| 8 | `CreateFolder(folderName)` | ✅ | Creates project folder |\n| 9 | `DeleteFolder(folderName)` | ✅ | Deletes project folder |\n| 10 | `GetProjectListInCurrentFolder()` | ✅ | Returns project name list |\n| 11 | `GetFolderListInCurrentFolder()` | ✅ | Returns folder name list |\n| 12 | `GotoRootFolder()` | ✅ | Navigates to root |\n| 13 | `GotoParentFolder()` | ✅ | Returns `False` at root (expected) |\n| 14 | `GetCurrentFolder()` | ✅ | Returns current folder name |\n| 15 | `OpenFolder(folderName)` | ✅ | Opens folder |\n| 16 | `ImportProject(filePath, projectName)` | ✅ | Imports .drp file |\n| 17 | `ExportProject(projectName, filePath, ...)` | ✅ | Exports .drp file |\n| 18 | `RestoreProject(filePath, projectName)` | ⚠️ | API accepts; needs backup archive |\n| 19 | `GetCurrentDatabase()` | ✅ | Returns `{DbType, DbName}` |\n| 20 | `GetDatabaseList()` | ✅ | Returns list of databases |\n| 21 | `SetCurrentDatabase({dbInfo})` | ✅ | Switches database |\n| 22 | `CreateCloudProject({cloudSettings})` | ☁️ | Requires cloud infrastructure |\n| 23 | `LoadCloudProject({cloudSettings})` | ☁️ | Requires cloud infrastructure |\n| 24 | `ImportCloudProject(filePath, {cloudSettings})` | ☁️ | Requires cloud infrastructure |\n| 25 | `RestoreCloudProject(folderPath, {cloudSettings})` | ☁️ | Requires cloud infrastructure |\n\n### Project\n\n| # | Method | Status | Test Result \u002F Notes |\n|---|--------|--------|---------------------|\n| 1 | `GetMediaPool()` | ✅ | Returns MediaPool object |\n| 2 | `GetTimelineCount()` | ✅ | Returns integer count |\n| 3 | `GetTimelineByIndex(idx)` | ✅ | Returns Timeline object |\n| 4 | `GetCurrentTimeline()` | ✅ | Returns current Timeline |\n| 5 | `SetCurrentTimeline(timeline)` | ✅ | Sets active timeline |\n| 6 | `GetGallery()` | ✅ | Returns Gallery object |\n| 7 | `GetName()` | ✅ | Returns project name |\n| 8 | `SetName(projectName)` | ⚠️ | Returns `False` on open project |\n| 9 | `GetPresetList()` | ✅ | Returns preset list with dimensions |\n| 10 | `SetPreset(presetName)` | ⚠️ | API accepts; preset must exist |\n| 11 | `AddRenderJob()` | ✅ | Returns job ID string |\n| 12 | `DeleteRenderJob(jobId)` | ✅ | Deletes render job |\n| 13 | `DeleteAllRenderJobs()` | ✅ | Clears render queue |\n| 14 | `GetRenderJobList()` | ✅ | Returns job list |\n| 15 | `GetRenderPresetList()` | ✅ | Returns preset names |\n| 16 | `StartRendering(...)` | ✅ | Starts render |\n| 17 | `StopRendering()` | ✅ | Stops render |\n| 18 | `IsRenderingInProgress()` | ✅ | Returns `False` when idle |\n| 19 | `LoadRenderPreset(presetName)` | ✅ | Loads render preset |\n| 20 | `SaveAsNewRenderPreset(presetName)` | ✅ | Creates render preset |\n| 21 | `DeleteRenderPreset(presetName)` | ✅ | Deletes render preset |\n| 22 | `SetRenderSettings({settings})` | ✅ | Applies render settings |\n| 23 | `GetRenderJobStatus(jobId)` | ✅ | Returns `{JobStatus, CompletionPercentage}` |\n| 24 | `GetQuickExportRenderPresets()` | ✅ | Returns preset names |\n| 25 | `RenderWithQuickExport(preset, {params})` | ✅ | Initiates quick export |\n| 26 | `GetSetting(settingName)` | ✅ | Returns project settings dict |\n| 27 | `SetSetting(settingName, settingValue)` | ✅ | Sets project setting |\n| 28 | `GetRenderFormats()` | ✅ | Returns format map |\n| 29 | `GetRenderCodecs(renderFormat)` | ✅ | Returns codec map |\n| 30 | `GetCurrentRenderFormatAndCodec()` | ✅ | Returns `{format, codec}` |\n| 31 | `SetCurrentRenderFormatAndCodec(format, codec)` | ✅ | Sets format and codec |\n| 32 | `GetCurrentRenderMode()` | ✅ | Returns mode integer |\n| 33 | `SetCurrentRenderMode(renderMode)` | ✅ | Sets render mode |\n| 34 | `GetRenderResolutions(format, codec)` | ✅ | Returns resolution list |\n| 35 | `RefreshLUTList()` | ✅ | Refreshes LUT list |\n| 36 | `GetUniqueId()` | ✅ | Returns UUID string |\n| 37 | `InsertAudioToCurrentTrackAtPlayhead(...)` | ⚠️ | Tested; needs Fairlight page context |\n| 38 | `LoadBurnInPreset(presetName)` | ⚠️ | API accepts; preset must exist |\n| 39 | `ExportCurrentFrameAsStill(filePath)` | ⚠️ | API accepts; needs valid playhead position |\n| 40 | `GetColorGroupsList()` | ✅ | Returns color group list |\n| 41 | `AddColorGroup(groupName)` | ✅ | Returns ColorGroup object |\n| 42 | `DeleteColorGroup(colorGroup)` | ✅ | Deletes color group |\n\n### MediaStorage\n\n| # | Method | Status | Test Result \u002F Notes |\n|---|--------|--------|---------------------|\n| 1 | `GetMountedVolumeList()` | ✅ | Returns mounted volume paths |\n| 2 | `GetSubFolderList(folderPath)` | ✅ | Returns subfolder paths |\n| 3 | `GetFileList(folderPath)` | ✅ | Returns file paths |\n| 4 | `RevealInStorage(path)` | ✅ | Reveals path in Media Storage |\n| 5 | `AddItemListToMediaPool(...)` | ✅ | Imports media, returns clips |\n| 6 | `AddClipMattesToMediaPool(item, [paths], eye)` | ✅ | Adds clip mattes |\n| 7 | `AddTimelineMattesToMediaPool([paths])` | ✅ | Returns MediaPoolItem list |\n\n### MediaPool\n\n| # | Method | Status | Test Result \u002F Notes |\n|---|--------|--------|---------------------|\n| 1 | `GetRootFolder()` | ✅ | Returns root Folder |\n| 2 | `AddSubFolder(folder, name)` | ✅ | Creates subfolder |\n| 3 | `RefreshFolders()` | ✅ | Refreshes folder list |\n| 4 | `CreateEmptyTimeline(name)` | ✅ | Creates timeline |\n| 5 | `AppendToTimeline(...)` | ✅ | Appends clips, returns TimelineItems |\n| 6 | `CreateTimelineFromClips(name, ...)` | ✅ | Creates timeline from clips |\n| 7 | `ImportTimelineFromFile(filePath, {options})` | ✅ | Imports AAF\u002FEDL\u002FXML |\n| 8 | `DeleteTimelines([timeline])` | ✅ | Deletes timelines |\n| 9 | `GetCurrentFolder()` | ✅ | Returns current Folder |\n| 10 | `SetCurrentFolder(folder)` | ✅ | Sets current folder |\n| 11 | `DeleteClips([clips])` | ✅ | Deletes clips |\n| 12 | `ImportFolderFromFile(filePath)` | ✅ | Imports DRB folder |\n| 13 | `DeleteFolders([subfolders])` | ✅ | Deletes folders |\n| 14 | `MoveClips([clips], targetFolder)` | ✅ | Moves clips |\n| 15 | `MoveFolders([folders], targetFolder)` | ✅ | Moves folders |\n| 16 | `GetClipMatteList(item)` | ✅ | Returns matte paths |\n| 17 | `GetTimelineMatteList(folder)` | ✅ | Returns matte items |\n| 18 | `DeleteClipMattes(item, [paths])` | ✅ | Deletes clip mattes |\n| 19 | `RelinkClips([items], folderPath)` | ⚠️ | API accepts; needs offline clips |\n| 20 | `UnlinkClips([items])` | ✅ | Unlinks clips |\n| 21 | `ImportMedia([items])` | ✅ | Imports media files |\n| 22 | `ExportMetadata(fileName, [clips])` | ✅ | Exports metadata CSV |\n| 23 | `GetUniqueId()` | ✅ | Returns UUID string |\n| 24 | `CreateStereoClip(left, right)` | ✅ | Creates stereo pair |\n| 25 | `AutoSyncAudio([items], {settings})` | ⚠️ | Tested; needs matching A\u002FV clips |\n| 26 | `GetSelectedClips()` | ✅ | Returns selected clips |\n| 27 | `SetSelectedClip(item)` | ✅ | Selects clip |\n\n### Folder\n\n| # | Method | Status | Test Result \u002F Notes |\n|---|--------|--------|---------------------|\n| 1 | `GetClipList()` | ✅ | Returns clip list |\n| 2 | `GetName()` | ✅ | Returns folder name |\n| 3 | `GetSubFolderList()` | ✅ | Returns subfolder list |\n| 4 | `GetIsFolderStale()` | ✅ | Returns `False` |\n| 5 | `GetUniqueId()` | ✅ | Returns UUID string |\n| 6 | `Export(filePath)` | ✅ | Exports DRB file |\n| 7 | `TranscribeAudio()` | ✅ | Starts audio transcription |\n| 8 | `ClearTranscription()` | ✅ | Clears transcription |\n\n### MediaPoolItem\n\n| # | Method | Status | Test Result \u002F Notes |\n|---|--------|--------|---------------------|\n| 1 | `GetName()` | ✅ | Returns clip name |\n| 2 | `GetMetadata(metadataType)` | ✅ | Returns metadata dict |\n| 3 | `SetMetadata(type, value)` | ✅ | Sets metadata |\n| 4 | `GetThirdPartyMetadata(type)` | ✅ | Returns third-party metadata |\n| 5 | `SetThirdPartyMetadata(type, value)` | ✅ | Sets third-party metadata |\n| 6 | `GetMediaId()` | ✅ | Returns media UUID |\n| 7 | `AddMarker(frameId, color, name, note, duration, customData)` | ✅ | Adds marker |\n| 8 | `GetMarkers()` | ✅ | Returns marker dict |\n| 9 | `GetMarkerByCustomData(customData)` | ✅ | Finds marker by data |\n| 10 | `UpdateMarkerCustomData(frameId, customData)` | ✅ | Updates marker data |\n| 11 | `GetMarkerCustomData(frameId)` | ✅ | Returns custom data string |\n| 12 | `DeleteMarkersByColor(color)` | ✅ | Deletes markers by color |\n| 13 | `DeleteMarkerAtFrame(frameNum)` | ⚠️ | Returns `False` if no marker at frame |\n| 14 | `DeleteMarkerByCustomData(customData)` | ⚠️ | Returns `False` if no match |\n| 15 | `AddFlag(color)` | ✅ | Adds flag |\n| 16 | `GetFlagList()` | ✅ | Returns flag colors |\n| 17 | `ClearFlags(color)` | ✅ | Clears flags |\n| 18 | `GetClipColor()` | ✅ | Returns clip color |\n| 19 | `SetClipColor(colorName)` | ✅ | Sets clip color |\n| 20 | `ClearClipColor()` | ✅ | Clears clip color |\n| 21 | `GetClipProperty(propertyName)` | ✅ | Returns property dict |\n| 22 | `SetClipProperty(propertyName, value)` | ⚠️ | API accepts; some properties read-only |\n| 23 | `LinkProxyMedia(proxyMediaFilePath)` | ✅ | Links proxy media |\n| 24 | `UnlinkProxyMedia()` | ✅ | Unlinks proxy media |\n| 25 | `ReplaceClip(filePath)` | ✅ | Replaces clip source |\n| 26 | `GetUniqueId()` | ✅ | Returns UUID string |\n| 27 | `TranscribeAudio()` | ✅ | Starts audio transcription |\n| 28 | `ClearTranscription()` | ✅ | Clears transcription |\n| 29 | `GetAudioMapping()` | ✅ | Returns JSON audio mapping |\n| 30 | `GetMarkInOut()` | ✅ | Returns mark in\u002Fout dict |\n| 31 | `SetMarkInOut(in, out, type)` | ✅ | Sets mark in\u002Fout |\n| 32 | `ClearMarkInOut(type)` | ✅ | Clears mark in\u002Fout |\n\n### Timeline\n\n| # | Method | Status | Test Result \u002F Notes |\n|---|--------|--------|---------------------|\n| 1 | `GetName()` | ✅ | Returns timeline name |\n| 2 | `SetName(timelineName)` | ⚠️ | Returns `False` on active timeline |\n| 3 | `GetStartFrame()` | ✅ | Returns start frame |\n| 4 | `GetEndFrame()` | ✅ | Returns end frame |\n| 5 | `SetStartTimecode(timecode)` | ✅ | Sets start timecode |\n| 6 | `GetStartTimecode()` | ✅ | Returns `\"01:00:00:00\"` |\n| 7 | `GetTrackCount(trackType)` | ✅ | Returns track count |\n| 8 | `AddTrack(trackType, subTrackType)` | ✅ | Adds track |\n| 9 | `DeleteTrack(trackType, trackIndex)` | ✅ | Deletes track |\n| 10 | `GetTrackSubType(trackType, trackIndex)` | ✅ | Returns sub-type (e.g. `\"stereo\"`) |\n| 11 | `SetTrackEnable(trackType, trackIndex, enabled)` | ✅ | Enables\u002Fdisables track |\n| 12 | `GetIsTrackEnabled(trackType, trackIndex)` | ✅ | Returns enabled state |\n| 13 | `SetTrackLock(trackType, trackIndex, locked)` | ✅ | Locks\u002Funlocks track |\n| 14 | `GetIsTrackLocked(trackType, trackIndex)` | ✅ | Returns lock state |\n| 15 | `DeleteClips([timelineItems], ripple)` | ✅ | Deletes clips from timeline |\n| 16 | `SetClipsLinked([timelineItems], linked)` | ✅ | Links\u002Funlinks clips |\n| 17 | `GetItemListInTrack(trackType, index)` | ✅ | Returns items on track |\n| 18 | `AddMarker(frameId, color, name, note, duration, customData)` | ✅ | Adds timeline marker |\n| 19 | `GetMarkers()` | ✅ | Returns marker dict |\n| 20 | `GetMarkerByCustomData(customData)` | ✅ | Finds marker by data |\n| 21 | `UpdateMarkerCustomData(frameId, customData)` | ✅ | Updates marker data |\n| 22 | `GetMarkerCustomData(frameId)` | ✅ | Returns custom data |\n| 23 | `DeleteMarkersByColor(color)` | ✅ | Deletes markers by color |\n| 24 | `DeleteMarkerAtFrame(frameNum)` | ⚠️ | Returns `False` if no marker at frame |\n| 25 | `DeleteMarkerByCustomData(customData)` | ⚠️ | Returns `False` if no match |\n| 26 | `GetCurrentTimecode()` | ✅ | Returns timecode string |\n| 27 | `SetCurrentTimecode(timecode)` | ⚠️ | Returns `False` if playback not active |\n| 28 | `GetCurrentVideoItem()` | ✅ | Returns item at playhead |\n| 29 | `GetCurrentClipThumbnailImage()` | ✅ | Returns thumbnail data |\n| 30 | `GetTrackName(trackType, trackIndex)` | ✅ | Returns track name |\n| 31 | `SetTrackName(trackType, trackIndex, name)` | ✅ | Sets track name |\n| 32 | `DuplicateTimeline(timelineName)` | ✅ | Duplicates timeline |\n| 33 | `CreateCompoundClip([items], {clipInfo})` | ✅ | Returns compound clip item |\n| 34 | `CreateFusionClip([timelineItems])` | ✅ | Returns Fusion clip item |\n| 35 | `ImportIntoTimeline(filePath, {options})` | ⚠️ | Tested; result depends on file format |\n| 36 | `Export(fileName, exportType, exportSubtype)` | ✅ | Exports EDL\u002FXML\u002FAAF |\n| 37 | `GetSetting(settingName)` | ✅ | Returns settings dict |\n| 38 | `SetSetting(settingName, settingValue)` | ⚠️ | API accepts; some settings read-only |\n| 39 | `InsertGeneratorIntoTimeline(name)` | ✅ | Inserts generator |\n| 40 | `InsertFusionGeneratorIntoTimeline(name)` | ✅ | Inserts Fusion generator |\n| 41 | `InsertFusionCompositionIntoTimeline()` | ✅ | Inserts Fusion composition |\n| 42 | `InsertOFXGeneratorIntoTimeline(name)` | ⚠️ | API accepts; needs valid OFX plugin |\n| 43 | `InsertTitleIntoTimeline(name)` | ✅ | Inserts title |\n| 44 | `InsertFusionTitleIntoTimeline(name)` | ✅ | Inserts Fusion title |\n| 45 | `GrabStill()` | ✅ | Returns GalleryStill object |\n| 46 | `GrabAllStills(stillFrameSource)` | ✅ | Returns list of GalleryStill objects |\n| 47 | `GetUniqueId()` | ✅ | Returns UUID string |\n| 48 | `CreateSubtitlesFromAudio({settings})` | ✅ | Returns `True` — creates subtitles from audio |\n| 49 | `DetectSceneCuts()` | ✅ | Returns `True` — detects scene cuts in timeline |\n| 50 | `ConvertTimelineToStereo()` | ✅ | Converts timeline to stereo 3D |\n| 51 | `GetNodeGraph()` | ✅ | Returns Graph object |\n| 52 | `AnalyzeDolbyVision([items], analysisType)` | 🔬 | Requires HDR\u002FDolby Vision content |\n| 53 | `GetMediaPoolItem()` | ✅ | Returns MediaPoolItem for timeline |\n| 54 | `GetMarkInOut()` | ✅ | Returns mark in\u002Fout dict |\n| 55 | `SetMarkInOut(in, out, type)` | ✅ | Sets mark in\u002Fout |\n| 56 | `ClearMarkInOut(type)` | ✅ | Clears mark in\u002Fout |\n\n### TimelineItem\n\n| # | Method | Status | Test Result \u002F Notes |\n|---|--------|--------|---------------------|\n| 1 | `GetName()` | ✅ | Returns item name |\n| 2 | `GetDuration(subframe_precision)` | ✅ | Returns duration |\n| 3 | `GetEnd(subframe_precision)` | ✅ | Returns end frame |\n| 4 | `GetSourceEndFrame()` | ✅ | Returns source end frame |\n| 5 | `GetSourceEndTime()` | ✅ | Returns source end time |\n| 6 | `GetFusionCompCount()` | ✅ | Returns comp count |\n| 7 | `GetFusionCompByIndex(compIndex)` | ✅ | Returns Fusion composition |\n| 8 | `GetFusionCompNameList()` | ✅ | Returns comp names |\n| 9 | `GetFusionCompByName(compName)` | ✅ | Returns Fusion composition |\n| 10 | `GetLeftOffset(subframe_precision)` | ✅ | Returns left offset |\n| 11 | `GetRightOffset(subframe_precision)` | ✅ | Returns right offset |\n| 12 | `GetStart(subframe_precision)` | ✅ | Returns start frame |\n| 13 | `GetSourceStartFrame()` | ✅ | Returns source start |\n| 14 | `GetSourceStartTime()` | ✅ | Returns source start time |\n| 15 | `SetProperty(propertyKey, propertyValue)` | ✅ | Sets item property |\n| 16 | `GetProperty(propertyKey)` | ✅ | Returns property dict |\n| 17 | `AddMarker(frameId, color, name, note, duration, customData)` | ✅ | Adds marker to item |\n| 18 | `GetMarkers()` | ✅ | Returns marker dict |\n| 19 | `GetMarkerByCustomData(customData)` | ✅ | Finds marker by data |\n| 20 | `UpdateMarkerCustomData(frameId, customData)` | ✅ | Updates marker data |\n| 21 | `GetMarkerCustomData(frameId)` | ✅ | Returns custom data |\n| 22 | `DeleteMarkersByColor(color)` | ✅ | Deletes markers by color |\n| 23 | `DeleteMarkerAtFrame(frameNum)` | ⚠️ | Returns `False` if no marker at frame |\n| 24 | `DeleteMarkerByCustomData(customData)` | ⚠️ | Returns `False` if no match |\n| 25 | `AddFlag(color)` | ✅ | Adds flag |\n| 26 | `GetFlagList()` | ✅ | Returns flag colors |\n| 27 | `ClearFlags(color)` | ✅ | Clears flags |\n| 28 | `GetClipColor()` | ✅ | Returns clip color |\n| 29 | `SetClipColor(colorName)` | ✅ | Sets clip color |\n| 30 | `ClearClipColor()` | ✅ | Clears clip color |\n| 31 | `AddFusionComp()` | ✅ | Creates Fusion composition |\n| 32 | `ImportFusionComp(path)` | ✅ | Imports .comp file |\n| 33 | `ExportFusionComp(path, compIndex)` | ✅ | Exports .comp file |\n| 34 | `DeleteFusionCompByName(compName)` | ⚠️ | Returns `False` if comp not found |\n| 35 | `LoadFusionCompByName(compName)` | ✅ | Loads composition |\n| 36 | `RenameFusionCompByName(oldName, newName)` | ✅ | Renames composition |\n| 37 | `AddVersion(versionName, versionType)` | ✅ | Adds grade version |\n| 38 | `GetCurrentVersion()` | ✅ | Returns version info |\n| 39 | `DeleteVersionByName(versionName, versionType)` | ⚠️ | Returns `False` if version not found |\n| 40 | `LoadVersionByName(versionName, versionType)` | ✅ | Loads grade version |\n| 41 | `RenameVersionByName(oldName, newName, type)` | ✅ | Renames version |\n| 42 | `GetVersionNameList(versionType)` | ✅ | Returns version names |\n| 43 | `GetMediaPoolItem()` | ✅ | Returns source MediaPoolItem |\n| 44 | `GetStereoConvergenceValues()` | ✅ | Returns stereo keyframes |\n| 45 | `GetStereoLeftFloatingWindowParams()` | ✅ | Returns stereo params |\n| 46 | `GetStereoRightFloatingWindowParams()` | ✅ | Returns stereo params |\n| 47 | `SetCDL([CDL map])` | ✅ | Sets CDL values |\n| 48 | `AddTake(mediaPoolItem, startFrame, endFrame)` | ✅ | Adds take |\n| 49 | `GetSelectedTakeIndex()` | ✅ | Returns selected take index |\n| 50 | `GetTakesCount()` | ✅ | Returns take count |\n| 51 | `GetTakeByIndex(idx)` | ✅ | Returns take info |\n| 52 | `DeleteTakeByIndex(idx)` | ✅ | Deletes take |\n| 53 | `SelectTakeByIndex(idx)` | ✅ | Selects take |\n| 54 | `FinalizeTake()` | ⚠️ | Returns `False` when no take selected |\n| 55 | `CopyGrades([tgtTimelineItems])` | ⚠️ | API accepts; needs matching items |\n| 56 | `SetClipEnabled(enabled)` | ✅ | Enables\u002Fdisables clip |\n| 57 | `GetClipEnabled()` | ✅ | Returns enabled state |\n| 58 | `UpdateSidecar()` | ⚠️ | Returns `False` for non-BRAW clips |\n| 59 | `GetUniqueId()` | ✅ | Returns UUID string |\n| 60 | `LoadBurnInPreset(presetName)` | ⚠️ | API accepts; preset must exist |\n| 61 | `CreateMagicMask(mode)` | ⚠️ | Tested; needs DaVinci Neural Engine + Color page context |\n| 62 | `RegenerateMagicMask()` | ⚠️ | Tested; needs existing mask |\n| 63 | `Stabilize()` | ✅ | Returns `True` on supported clips |\n| 64 | `SmartReframe()` | ⚠️ | Tested; needs specific aspect ratio setup |\n| 65 | `GetNodeGraph(layerIdx)` | ✅ | Returns Graph object |\n| 66 | `GetColorGroup()` | ✅ | Returns ColorGroup |\n| 67 | `AssignToColorGroup(colorGroup)` | ✅ | Assigns to group |\n| 68 | `RemoveFromColorGroup()` | ⚠️ | Returns `False` if not in group |\n| 69 | `ExportLUT(exportType, path)` | ✅ | Exports LUT file |\n| 70 | `GetLinkedItems()` | ✅ | Returns linked items |\n| 71 | `GetTrackTypeAndIndex()` | ✅ | Returns `[trackType, trackIndex]` |\n| 72 | `GetSourceAudioChannelMapping()` | ✅ | Returns audio mapping |\n| 73 | `GetIsColorOutputCacheEnabled()` | ✅ | Returns cache state |\n| 74 | `GetIsFusionOutputCacheEnabled()` | ✅ | Returns cache state |\n| 75 | `SetColorOutputCache(cache_value)` | ⚠️ | Tested; needs active color pipeline |\n| 76 | `SetFusionOutputCache(cache_value)` | ⚠️ | Tested; needs active Fusion pipeline |\n\n### Gallery\n\n| # | Method | Status | Test Result \u002F Notes |\n|---|--------|--------|---------------------|\n| 1 | `GetAlbumName(galleryStillAlbum)` | ✅ | Returns album name |\n| 2 | `SetAlbumName(galleryStillAlbum, albumName)` | ✅ | Sets album name |\n| 3 | `GetCurrentStillAlbum()` | ✅ | Returns GalleryStillAlbum |\n| 4 | `SetCurrentStillAlbum(galleryStillAlbum)` | ✅ | Sets current album |\n| 5 | `GetGalleryStillAlbums()` | ✅ | Returns album list |\n| 6 | `GetGalleryPowerGradeAlbums()` | ✅ | Returns power grade albums |\n| 7 | `CreateGalleryStillAlbum()` | ✅ | Creates still album |\n| 8 | `CreateGalleryPowerGradeAlbum()` | ✅ | Creates power grade album |\n\n### GalleryStillAlbum\n\n| # | Method | Status | Test Result \u002F Notes |\n|---|--------|--------|---------------------|\n| 1 | `GetStills()` | ✅ | Returns list of GalleryStill objects |\n| 2 | `GetLabel(galleryStill)` | ✅ | Returns label string |\n| 3 | `SetLabel(galleryStill, label)` | ⚠️ | API accepts; may not persist in all versions |\n| 4 | `ImportStills([filePaths])` | ✅ | Imports DRX still files (requires Color page) |\n| 5 | `ExportStills([stills], folderPath, prefix, format)` | ✅ | Exports stills as image + companion .drx grade file. Requires Color page with Gallery panel visible. Supported formats: dpx, cin, tif, jpg, png, ppm, bmp, xpm, drx. |\n| 6 | `DeleteStills([galleryStill])` | ✅ | Deletes stills from album |\n\n> **Note (v2.0.8+):** The compound server's `gallery_stills` tool includes a `grab_and_export` action that combines `GrabStill()` + `ExportStills()` in a single call — more reliable than calling them separately since it keeps the live GalleryStill reference. Returns the list of exported files (image + .drx grade data). Requires the Color page with the Gallery panel open.\n\n### Graph\n\n| # | Method | Status | Test Result \u002F Notes |\n|---|--------|--------|---------------------|\n| 1 | `GetNumNodes()` | ✅ | Returns node count (via ColorGroup pre\u002Fpost graphs) |\n| 2 | `SetLUT(nodeIndex, lutPath)` | ✅ | Sets LUT on node |\n| 3 | `GetLUT(nodeIndex)` | ✅ | Returns LUT path |\n| 4 | `SetNodeCacheMode(nodeIndex, cache_value)` | ✅ | Returns `True` |\n| 5 | `GetNodeCacheMode(nodeIndex)` | ✅ | Returns `-1` (no cache mode set) |\n| 6 | `GetNodeLabel(nodeIndex)` | ✅ | Returns node label string |\n| 7 | `GetToolsInNode(nodeIndex)` | ✅ | Returns `None` (no OFX tools in node) |\n| 8 | `SetNodeEnabled(nodeIndex, isEnabled)` | ✅ | Returns `True` |\n| 9 | `ApplyGradeFromDRX(path, gradeMode)` | ✅ | Applies grade from DRX file |\n| 10 | `ApplyArriCdlLut()` | ✅ | Applies ARRI CDL LUT |\n| 11 | `ResetAllGrades()` | ✅ | Resets all grades |\n\n### ColorGroup\n\n| # | Method | Status | Test Result \u002F Notes |\n|---|--------|--------|---------------------|\n| 1 | `GetName()` | ✅ | Returns group name |\n| 2 | `SetName(groupName)` | ✅ | Sets group name |\n| 3 | `GetClipsInTimeline(timeline)` | ✅ | Returns clips in group |\n| 4 | `GetPreClipNodeGraph()` | ✅ | Returns Graph object |\n| 5 | `GetPostClipNodeGraph()` | ✅ | Returns Graph object |\n\n---\n\n## Contributing\n\nWe welcome contributions! The following areas especially need help:\n\n### Help Wanted: Untested API Methods\n\n**5 methods** (1.5%) remain untested against a live DaVinci Resolve instance. If you have access to the required infrastructure or content, we'd love a PR with test confirmation:\n\n1. **Cloud Project Methods** (4 methods) — Need DaVinci Resolve cloud infrastructure:\n   - `ProjectManager.CreateCloudProject`\n   - `ProjectManager.LoadCloudProject`\n   - `ProjectManager.ImportCloudProject`\n   - `ProjectManager.RestoreCloudProject`\n\n2. **HDR Analysis** (1 method) — Needs specific content:\n   - `Timeline.AnalyzeDolbyVision` — needs HDR\u002FDolby Vision content\n\n### How to Contribute\n\n1. Fork the repository\n2. Create a feature branch (`git checkout -b feature\u002Fmy-contribution`)\n3. Run the existing test suite to ensure nothing breaks\n4. Add your test results or fixes\n5. Submit a pull request\n\n### Other Contribution Ideas\n\n- **Windows testing** — All tests were run on macOS; Windows verification welcome\n- **Linux testing** — DaVinci Resolve supports Linux; test coverage needed\n- **Resolve version compatibility** — Test against Resolve 18.x, 19.0, or newer versions\n- **Bug reports** — If a tool returns unexpected results on your setup, file an issue\n- **Documentation** — Improve examples, add tutorials, translate docs\n\n## Platform Support\n\n| Platform | Status | Resolve Paths Auto-Detected | Notes |\n|----------|--------|----------------------------|-------|\n| macOS | ✅ Tested | `\u002FLibrary\u002FApplication Support\u002FBlackmagic Design\u002F...` | Primary development and test platform |\n| Windows | ✅ Supported | `C:\\ProgramData\\Blackmagic Design\\...` | Community-tested; PRs welcome |\n| Linux | ⚠️ Experimental | `\u002Fopt\u002Fresolve\u002F...` | Should work — testing and feedback welcome |\n\n## Security Considerations\n\nThis MCP server controls DaVinci Resolve via its Scripting API. Some tools perform actions that are destructive or interact with the host filesystem:\n\n| Tool | Risk | Mitigation |\n|------|------|------------|\n| `quit_app` \u002F `restart_app` | Terminates the Resolve process — can cause data loss if unsaved changes exist or a render is in progress | MCP clients should require explicit user confirmation before calling these tools. Subprocess calls use hardcoded command lists (no shell injection possible). |\n| `export_layout_preset` \u002F `import_layout_preset` \u002F `delete_layout_preset` | Read\u002Fwrite\u002Fdelete files in the Resolve layout presets directory | Path traversal protection validates all resolved paths stay within the expected presets directory (v2.0.7+). |\n| `save_project` | Creates and removes a temporary `.drp` file in the system temp directory | Path is constructed server-side with no LLM-controlled input. |\n\n**Recommendations for MCP client developers:**\n- Enable tool-call confirmation prompts for destructive tools (`quit_app`, `restart_app`, `delete_layout_preset`)\n- Do not grant blanket auto-approval to all tools in this server\n\n## Project Structure\n\n```\ndavinci-resolve-mcp\u002F\n├── install.py                    # Universal installer (macOS\u002FWindows\u002FLinux)\n├── src\u002F\n│   ├── server.py                # Compound MCP server — 27 tools (default)\n│   ├── resolve_mcp_server.py    # Full MCP server — 342 tools (power users)\n│   └── utils\u002F                   # Platform detection, Resolve connection helpers\n├── tests\u002F                       # 5-phase live API test suite (319\u002F319 pass)\n├── docs\u002F\n│   └── resolve_scripting_api.txt # Official Resolve Scripting API reference\n└── examples\u002F                    # Getting started, markers, media, timeline examples\n```\n\n## License\n\nMIT\n\n## Author\n\nSamuel Gursky (samgursky@gmail.com)\n- GitHub: [github.com\u002Fsamuelgursky](https:\u002F\u002Fgithub.com\u002Fsamuelgursky)\n\n## Acknowledgments\n\n- Blackmagic Design for DaVinci Resolve and its scripting API\n- The Model Context Protocol team for enabling AI assistant integration\n- Anthropic for Claude Code, used extensively in development and testing\n","# 达芬奇 Resolve MCP 服务器\n\n[![版本](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Fversion-2.1.0-blue.svg)](https:\u002F\u002Fgithub.com\u002Fsamuelgursky\u002Fdavinci-resolve-mcp\u002Freleases)\n[![API 覆盖率](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FAPI%20Coverage-100%25-brightgreen.svg)](#api-coverage)\n[![工具数量](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FMCP%20Tools-27%20(342%20full)-blue.svg)](#server-modes)\n[![测试通过率](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FLive%20Tested-98.5%25-green.svg)](#test-results)\n[![达芬奇 Resolve](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002FDaVinci%20Resolve-18.5+-darkred.svg)](https:\u002F\u002Fwww.blackmagicdesign.com\u002Fproducts\u002Fdavinciresolve)\n[![Python](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Fpython-3.10--3.12-green.svg)](https:\u002F\u002Fwww.python.org\u002Fdownloads\u002F)\n[![许可证](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Flicense-MIT-blue.svg)](https:\u002F\u002Fopensource.org\u002Flicenses\u002FMIT)\n\n一个模型上下文协议 (MCP) 服务器，提供对达芬奇 Resolve 脚本 API 的 **完全覆盖**。将 AI 助手（Claude、Cursor、Windsurf）连接到达芬奇 Resolve，并通过自然语言控制您的后期制作工作流程的各个方面。\n\n### v2.1.0 新特性\n\n- **新增 `fusion_comp` 工具** — 该工具包含 20 个操作，公开了完整的 Fusion 合成节点图 API。您可以在当前活动的 Fusion 页面合成上添加\u002F删除\u002F查找节点、连接线、设置\u002F获取参数、管理关键帧、控制撤销分组、设置渲染范围以及触发渲染。\n- **`timeline_item_fusion` 缓存操作** — 添加了 `get_cache_enabled` 和 `set_cache` 操作，用于直接在时间线项目上控制 Fusion 输出缓存。\n- **Fusion 节点图参考** — 文档字符串中包含了常见工具 ID（Merge、TextPlus、Background、Transform、ColorCorrector、DeltaKeyer 等），便于发现和使用。\n\n### v2.0.9\n\n- **跨平台沙盒路径重定向** — `_resolve_safe_dir()` 现在可以处理 macOS（`\u002Fvar\u002Ffolders`、`\u002Fprivate\u002Fvar`）、Linux（`\u002Ftmp`、`\u002Fvar\u002Ftmp`）和 Windows（`AppData\\Local\\Temp`）等 Resolve 无法写入的沙盒路径。这些路径将被重定向到 `~\u002FDocuments\u002Fresolve-stills`，而不是桌面。\n- **`grab_and_export` 自动清理** — 导出的文件会被读取到响应中（DRX 作为内联文本，图片为 base64 格式），然后自动从磁盘上删除。不会产生任何文件堆积。如果希望保留文件在磁盘上，可以传递 `cleanup: false` 参数。\n- **两台服务器同步** — `server.py` 和 `resolve_mcp_server.py` 现在共享相同版本，并且都使用 `_resolve_safe_dir()` 来处理所有面向 Resolve 的临时路径（项目导出、LUT 导出、静止图像导出）。\n\n### v2.0.8\n\n- **`gallery_stills` 上新增 `grab_and_export` 操作** — 将 `GrabStill()` 和 `ExportStills()` 合并为一个原子调用，同时保留 Live GalleryStill 引用以确保可靠导出。返回包含已导出图像及配套 `.drx` 调色文件的文件清单。\n- **格式回退链** — 如果请求的格式失败，将自动尝试 tif 格式，然后再是 dpx 格式。\n- **macOS 沙盒路径重定向** — `\u002Fvar\u002Ffolders` 和 `\u002Fprivate\u002Fvar` 路径将被重定向到 `~\u002FDesktop\u002Fresolve-stills` 目录，因为 Resolve 进程无法写入沙盒化的临时目录。\n- **关键发现记录在案** — `ExportStills` 需要 Color 页面上的 Gallery 面板处于可见状态。所有 9 种支持的格式（dpx、cin、tif、jpg、png、ppm、bmp、xpm、drx）都会在导出图像的同时生成配套的 `.drx` 调色文件。\n\n### v2.0.7\n\n- **安全性：布局预设工具的路径遍历防护** — `export_layout_preset`、`import_layout_preset` 和 `delete_layout_preset` 现在会验证解析后的文件路径是否位于预期的 Resolve 预设目录内，从而防止通过精心构造的预设名称进行路径遍历。\n- **安全性：破坏性工具风险说明** — 增加了“安全注意事项”章节，指出 `quit_app` 和 `restart_app` 工具可能会终止 Resolve 程序；因此，MCP 客户端在调用这些工具前应要求用户确认。\n\n### v2.0.6\n\n- **修复颜色组操作崩溃问题** — `timeline_item_color` 中的 `_check()` 被解包为 `(proj, _, _)`，但实际返回值为 `(pm, proj, err)`，导致 `proj` 接收到的是 ProjectManager 对象而非 Project 对象，从而引发 `assign_color_group` 和 `remove_from_color_group` 函数崩溃。\n\n### v2.0.5\n\n- **懒加载连接恢复** — 全功能服务器（`--full` 模式）现在会自动重新连接并启动 Resolve，与复合服务器的行为一致。\n- **所有链式 API 调用的空值保护** — 如果 `GetProjectManager()`、`GetCurrentProject()` 或 `GetCurrentTimeline()` 执行失败，现在会返回明确的错误信息，而不是抛出 `NoneType` 错误。\n- **辅助函数** — `get_resolve()`、`get_project_manager()` 和 `get_current_project()` 替代了 178 处重复代码块。\n\n### v2.0.4\n\n- **修复 `apply_grade_from_drx` 参数问题** — 将 `mode` 重命名为 `grade_mode`，以匹配 Resolve API；同时修正了文档中的描述，将其从“替换\u002F追加”更正为实际的关键帧对齐模式（0=无关键帧，1=源时间码对齐，2=起始帧对齐）。\n- **向后兼容** — 现在仍然接受 `mode` 参数以供现有客户端使用，但优先采用 `grade_mode` 参数。\n\n### v2.0.3\n\n- **修复 `GetNodeGraph` 崩溃问题** — 在 Resolve 中，`GetNodeGraph(0)` 会返回 `False`；现在除非显式提供 `layer_index` 参数，否则将不进行调用。\n- **假值节点图检查** — 使用 `not g` 而不是 `g is None` 来检查节点图，以捕获 `False` 返回值。\n\n### v2.0.2\n\n- **反重力支持** — Google 的代理型 AI 编程助手被添加为第 10 个 MCP 客户端。\n- **按字母顺序排列客户端** — MCP_CLIENTS 列表已排序，便于维护。\n\n### v2.0.1\n\n- **26 工具复合服务器** — 所有 324 个 API 方法被分组为 26 个上下文高效的工具（默认）。\n- **通用安装程序** — 单一的 `python install.py` 可用于 macOS\u002FWindows\u002FLinux，支持 10 个 MCP 客户端。\n- **专用的时间线项目操作** — 包括速度调整、变换、裁剪、合成、音频以及带验证的关键帧操作。\n- **懒加载 Resolve 连接** — 服务器会立即启动，直到首次调用工具时才连接 Resolve。\n- **Bug 修复** — 包括 CreateMagicMask 参数类型、GetCurrentClipThumbnailImage 参数以及 Python 3.13+ 警告。\n\n## 关键统计数据\n\n| 指标 | 数值 |\n|--------|-------|\n| MCP 工具 | **26** 个复合工具（默认） \u002F **342** 个细粒度工具 |\n| 覆盖的 API 方法 | **324\u002F324**（100%） |\n| 实际测试的 API 方法 | **319\u002F324**（98.5%） |\n| 实测通过率 | **319\u002F319**（100%） |\n| API 对象类 | 13 |\n| 测试版本 | DaVinci Resolve 19.1.3 Studio |\n\n## API 覆盖范围\n\nDaVinci Resolve 脚本 API 中所有未弃用的方法均已覆盖。默认的复合服务器公开了 **27 个工具**，这些工具按操作参数将相关功能分组，从而保持 LLM 上下文窗口的简洁。而完整细粒度服务器则为高级用户提供 **342 个独立工具**。两种模式均覆盖了全部 13 个 API 对象类：\n\n| 类别 | 方法数 | 工具数 | 描述 |\n|-------|---------|-------|-------------|\n| Resolve | 21 | 21 | 应用程序控制、页面、布局预设、渲染\u002F烧录预设、关键帧模式 |\n| ProjectManager | 25 | 25 | 项目增删改查、文件夹、数据库、云项目、归档与恢复 |\n| Project | 42 | 42 | 时间线、渲染流程、设置、LUT、颜色组 |\n| MediaStorage | 9 | 9 | 卷、文件浏览、媒体导入、遮罩 |\n| MediaPool | 27 | 27 | 文件夹、片段、时间线、元数据、立体声、同步 |\n| Folder | 8 | 8 | 片段列表、导出、转录 |\n| MediaPoolItem | 32 | 32 | 元数据、标记、标志、属性、代理、转录 |\n| Timeline | 56 | 56 | 轨道、标记、片段、导出、生成器、字幕、静止图像、立体声 |\n| TimelineItem | 76 | 76 | 属性、标记、Fusion 合成、版本、take、CDL、AI 工具 |\n| Gallery | 8 | 8 | 相册、静止图像、高级调色 |\n| GalleryStillAlbum | 6 | 6 | 静止图像管理、导入导出、标签 |\n| Graph | 11 | 22 | 节点操作、LUT、缓存、调色（时间线和片段图变体） |\n| ColorGroup | 5 | 10 | 组管理、片段前\u002F后节点图 |\n\n## 系统要求\n\n- **DaVinci Resolve Studio** 18.5+（macOS、Windows 或 Linux）——免费版不支持外部脚本\n- 推荐使用 **Python 3.10–3.12**（3.13+ 可能与 Resolve 的脚本库存在 ABI 不兼容问题）\n- DaVinci Resolve 需在 **偏好设置 > 常规 > “外部脚本”** 设置为 **本地** 的情况下运行\n\n## 快速入门\n\n```bash\n# 克隆仓库\ngit clone https:\u002F\u002Fgithub.com\u002Fsamuelgursky\u002Fdavinci-resolve-mcp.git\ncd davinci-resolve-mcp\n\n# 确保 DaVinci Resolve 已启动，然后：\npython install.py\n```\n\n通用安装程序会自动检测您的平台、查找 DaVinci Resolve 安装路径、创建虚拟环境并配置您的 MCP 客户端——所有步骤一步完成。\n\n### 支持的 MCP 客户端\n\n安装程序可自动配置以下任一客户端：\n\n| 客户端 | 配置写入位置 |\n|--------|-------------------|\n| Claude Desktop | `~\u002FLibrary\u002FApplication Support\u002FClaude\u002Fclaude_desktop_config.json` (macOS) |\n| Claude Code | `.mcp.json`（项目根目录） |\n| Cursor | `~\u002F.cursor\u002Fmcp.json` |\n| VS Code (Copilot) | `.vscode\u002Fmcp.json`（工作区） |\n| Windsurf | `~\u002F.codeium\u002Fwindsurf\u002Fmcp_config.json` |\n| Cline | VS Code 全局存储 |\n| Roo Code | VS Code 全局存储 |\n| Zed | `~\u002F.config\u002Fzed\u002Fsettings.json` |\n| Continue | `~\u002F.continue\u002Fconfig.json` |\n| JetBrains IDEs | 手动配置（设置 > 工具 > AI 助手 > MCP） |\n\n您可以同时配置多个客户端，或使用 `--clients manual` 来获取可复制粘贴的配置片段。\n\n### 安装选项\n\n```bash\npython install.py                              # 交互模式\npython install.py --clients all                # 配置所有客户端\npython install.py --clients cursor,claude-desktop  # 指定客户端\npython install.py --clients manual             # 仅输出配置\npython install.py --dry-run --clients all      # 预览而不写入\npython install.py --no-venv --clients cursor   # 跳过虚拟环境创建\n```\n\n### 服务器模式\n\nMCP 服务器有两种模式：\n\n| 模式 | 文件 | 工具数 | 适用人群 |\n|------|------|-------|----------|\n| **复合**（默认） | `src\u002Fserver.py` | 26 | 大多数用户——快速、简洁、低上下文占用 |\n| **完整** | `src\u002Fresolve_mcp_server.py` | 342 | 希望每个 API 方法对应一个工具的高级用户 |\n\n复合服务器的 `timeline_item` 工具包含针对常见工作流的专用操作：\n\n| 类别 | 操作 | 参数 |\n|----------|---------|------------|\n| **变速** | `get_retime`, `set_retime` | 处理方式（最近、帧混合、光流）、运动估计（0-6） |\n| **变换** | `get_transform`, `set_transform` | 平移、倾斜、缩放X\u002FY、旋转角度、锚点X\u002FY、俯仰、偏航、翻转X\u002FY |\n| **裁剪** | `get_crop`, `set_crop` | 左裁剪、右裁剪、上裁剪、下裁剪、裁剪柔化程度、是否保留裁剪区域 |\n| **合成** | `get_composite`, `set_composite` | 不透明度、合成模式 |\n| **音频** | `get_audio`, `set_audio` | 音量、声像、音频同步偏移 |\n| **关键帧** | `get_keyframes`, `add_keyframe`, `modify_keyframe`, `delete_keyframe`, `set_keyframe_interpolation` | 属性、帧、值、插值方式（线性、贝塞尔、缓入、缓出、缓入缓出） |\n\n安装程序默认使用复合服务器。如需使用完整服务器：\n```bash\npython src\u002Fserver.py --full    # 启动完整的 342 工具服务器\n# 或直接将您的 MCP 配置指向 src\u002Fresolve_mcp_server.py\n```\n\n### 手动配置\n\n如果您更倾向于自行设置，请在您的 MCP 客户端配置中添加以下内容：\n\n```json\n{\n  \"mcpServers\": {\n    \"davinci-resolve\": {\n      \"command\": \"\u002Fpath\u002Fto\u002Fvenv\u002Fbin\u002Fpython\",\n      \"args\": [\"\u002Fpath\u002Fto\u002Fdavinci-resolve-mcp\u002Fsrc\u002Fserver.py\"]\n    }\n  }\n}\n```\n\n各平台的具体路径如下：\n\n| 平台 | API 路径 | 库文件路径 |\n|----------|----------|-------------|\n| macOS | `\u002FLibrary\u002FApplication Support\u002FBlackmagic Design\u002FDaVinci Resolve\u002FDeveloper\u002FScripting` | `fusionscript.so` 在 DaVinci Resolve.app 中 |\n| Windows | `C:\\ProgramData\\Blackmagic Design\\DaVinci Resolve\\Support\\Developer\\Scripting` | `fusionscript.dll` 在 Resolve 安装目录中 |\n| Linux | `\u002Fopt\u002Fresolve\u002FDeveloper\u002FScripting` | `\u002Fopt\u002Fresolve\u002Flibs\u002FFusion\u002Ffusionscript.so` |\n\n## 使用示例\n\n连接成功后，您可以通过自然语言控制 DaVinci Resolve：\n\n```\n“当前运行的 DaVinci Resolve 是哪个版本？”\n“列出所有项目，并打开名为‘我的电影’的项目”\n“创建一个名为‘粗剪’的新时间线，并将媒体池中的所有片段添加进去”\n“在当前播放头位置添加一个蓝色标记，备注‘待审核’”\n“为当前时间线设置 ProRes 422 HQ 渲染”\n“将时间线导出为 EDL”\n“切换到调色页面，并截取一张静止图像”\n“在选中的片段上创建一个 Fusion 合成”\n```\n\n## 测试结果\n\n所有测试均基于 macOS 上的 **DaVinci Resolve 19.1.3 Studio** 进行，采用实时 API 调用（无模拟）。 \n\n| 阶段 | 测试数 | 通过率 | 范围 |\n|-------|-------|-----------|-------|\n| 第一阶段 | 204\u002F204 | 100% | 所有类别的安全只读操作 |\n| 第二阶段 | 79\u002F79 | 100% | 采用创建-测试-清理模式的破坏性操作 |\n| 第三阶段 | 20\u002F20 | 100% | 实际媒体导入、同步、转录、数据库切换、Resolve.Quit |\n| 第四阶段 | 10\u002F10 | 100% | AI\u002FML 方法、Fusion 片段、立体声、画廊静止图像 |\n| 第五阶段 | 6\u002F6 | 100% | 场景剪辑、从音频提取字幕、图表节点缓存\u002F工具\u002F启用 |\n| **总计** | **319\u002F319** | **100%** | **98.5% 的所有 API 方法均经过实时测试** |\n\n### 未测试的方法（5\u002F324）\n\n| 方法 | 原因 | 需要帮助 |\n|--------|--------|-------------|\n| `PM.CreateCloudProject` | 需要 DaVinci Resolve 云基础设施 | 是 |\n| `PM.LoadCloudProject` | 需要 DaVinci Resolve 云基础设施 | 是 |\n| `PM.ImportCloudProject` | 需要 DaVinci Resolve 云基础设施 | 是 |\n| `PM.RestoreCloudProject` | 需要 DaVinci Resolve 云基础设施 | 是 |\n| `TL.AnalyzeDolbyVision` | 需要 HDR\u002FDolby Vision 内容 | 是 |\n\n---\n\n## 完整 API 参考\n\nDaVinci Resolve 脚本 API 中的每个方法及其测试状态。方法按对象类列出。\n\n**状态说明：**\n- ✅ = 已现场测试，返回预期结果\n- ⚠️ = 已现场测试，API 接受调用（返回 `False` — 需要特定上下文才能完全执行）\n- ☁️ = 需要云基础设施（未测试）\n- 🔬 = 需要特定内容\u002F硬件（未测试 — 欢迎提交 PR）\n\n### Resolve\n\n| # | 方法 | 状态 | 测试结果 \u002F 备注 |\n|---|--------|--------|---------------------|\n| 1 | `Fusion()` | ✅ | 返回 Fusion 对象 |\n| 2 | `GetMediaStorage()` | ✅ | 返回 MediaStorage 对象 |\n| 3 | `GetProjectManager()` | ✅ | 返回 ProjectManager 对象 |\n| 4 | `OpenPage(pageName)` | ✅ | 切换 Resolve 页面 |\n| 5 | `GetCurrentPage()` | ✅ | 返回当前页面名称（例如 `\"edit\"`）|\n| 6 | `GetProductName()` | ✅ | 返回 `\"DaVinci Resolve Studio\"` |\n| 7 | `GetVersion()` | ✅ | 返回 `[19, 1, 3, 7, '']` |\n| 8 | `GetVersionString()` | ✅ | 返回 `\"19.1.3.7\"` |\n| 9 | `LoadLayoutPreset(presetName)` | ✅ | 加载已保存的布局 |\n| 10 | `UpdateLayoutPreset(presetName)` | ✅ | 更新现有预设 |\n| 11 | `ExportLayoutPreset(presetName, presetFilePath)` | ✅ | 将预设导出到文件 |\n| 12 | `DeleteLayoutPreset(presetName)` | ✅ | 删除预设 |\n| 13 | `SaveLayoutPreset(presetName)` | ⚠️ | API 接受；当预设名称冲突时返回 `False` |\n| 14 | `ImportLayoutPreset(presetFilePath, presetName)` | ✅ | 从文件导入预设 |\n| 15 | `Quit()` | ✅ | 退出 DaVinci Resolve |\n| 16 | `ImportRenderPreset(presetPath)` | ⚠️ | API 接受；需要有效的预设文件 |\n| 17 | `ExportRenderPreset(presetName, exportPath)` | ⚠️ | API 接受；需要有效的预设名称 |\n| 18 | `ImportBurnInPreset(presetPath)` | ⚠️ | API 接受；需要有效的预设文件 |\n| 19 | `ExportBurnInPreset(presetName, exportPath)` | ⚠️ | API 接受；需要有效的预设名称 |\n| 20 | `GetKeyframeMode()` | ✅ | 返回关键帧模式 |\n| 21 | `SetKeyframeMode(keyframeMode)` | ⚠️ | API 接受；模式必须匹配有效枚举 |\n\n### ProjectManager\n\n| # | 方法 | 状态 | 测试结果 \u002F 备注 |\n|---|--------|--------|---------------------|\n| 1 | `ArchiveProject(projectName, filePath, ...)` | ⚠️ | API 接受；归档过程较慢 |\n| 2 | `CreateProject(projectName)` | ✅ | 创建新项目 |\n| 3 | `DeleteProject(projectName)` | ⚠️ | 如果项目已打开，则返回 `False` |\n| 4 | `LoadProject(projectName)` | ✅ | 返回 Project 对象 |\n| 5 | `GetCurrentProject()` | ✅ | 返回当前项目 |\n| 6 | `SaveProject()` | ✅ | 保存当前项目 |\n| 7 | `CloseProject(project)` | ✅ | 关闭项目 |\n| 8 | `CreateFolder(folderName)` | ✅ | 创建项目文件夹 |\n| 9 | `DeleteFolder(folderName)` | ✅ | 删除项目文件夹 |\n| 10 | `GetProjectListInCurrentFolder()` | ✅ | 返回项目名称列表 |\n| 11 | `GetFolderListInCurrentFolder()` | ✅ | 返回文件夹名称列表 |\n| 12 | `GotoRootFolder()` | ✅ | 导航到根目录 |\n| 13 | `GotoParentFolder()` | ✅ | 在根目录时返回 `False`（符合预期）|\n| 14 | `GetCurrentFolder()` | ✅ | 返回当前文件夹名称 |\n| 15 | `OpenFolder(folderName)` | ✅ | 打开文件夹 |\n| 16 | `ImportProject(filePath, projectName)` | ✅ | 导入 .drp 文件 |\n| 17 | `ExportProject(projectName, filePath, ...)` | ✅ | 导出 .drp 文件 |\n| 18 | `RestoreProject(filePath, projectName)` | ⚠️ | API 接受；需要备份存档 |\n| 19 | `GetCurrentDatabase()` | ✅ | 返回 `{DbType, DbName}` |\n| 20 | `GetDatabaseList()` | ✅ | 返回数据库列表 |\n| 21 | `SetCurrentDatabase({dbInfo})` | ✅ | 切换数据库 |\n| 22 | `CreateCloudProject({cloudSettings})` | ☁️ | 需要云基础设施 |\n| 23 | `LoadCloudProject({cloudSettings})` | ☁️ | 需要云基础设施 |\n| 24 | `ImportCloudProject(filePath, {cloudSettings})` | ☁️ | 需要云基础设施 |\n| 25 | `RestoreCloudProject(folderPath, {cloudSettings})` | ☁️ | 需要云基础设施 |\n\n### 项目\n\n| 序号 | 方法 | 状态 | 测试结果\u002F备注 |\n|---|--------|--------|---------------------|\n| 1 | `GetMediaPool()` | ✅ | 返回 MediaPool 对象 |\n| 2 | `GetTimelineCount()` | ✅ | 返回整数计数 |\n| 3 | `GetTimelineByIndex(idx)` | ✅ | 返回 Timeline 对象 |\n| 4 | `GetCurrentTimeline()` | ✅ | 返回当前 Timeline |\n| 5 | `SetCurrentTimeline(timeline)` | ✅ | 设置活动 Timeline |\n| 6 | `GetGallery()` | ✅ | 返回 Gallery 对象 |\n| 7 | `GetName()` | ✅ | 返回项目名称 |\n| 8 | `SetName(projectName)` | ⚠️ | 在打开的项目中返回 `False` |\n| 9 | `GetPresetList()` | ✅ | 返回包含维度的预设列表 |\n| 10 | `SetPreset(presetName)` | ⚠️ | API 接受；预设必须存在 |\n| 11 | `AddRenderJob()` | ✅ | 返回作业 ID 字符串 |\n| 12 | `DeleteRenderJob(jobId)` | ✅ | 删除渲染作业 |\n| 13 | `DeleteAllRenderJobs()` | ✅ | 清空渲染队列 |\n| 14 | `GetRenderJobList()` | ✅ | 返回作业列表 |\n| 15 | `GetRenderPresetList()` | ✅ | 返回预设名称 |\n| 16 | `StartRendering(...)` | ✅ | 开始渲染 |\n| 17 | `StopRendering()` | ✅ | 停止渲染 |\n| 18 | `IsRenderingInProgress()` | ✅ | 空闲时返回 `False` |\n| 19 | `LoadRenderPreset(presetName)` | ✅ | 加载渲染预设 |\n| 20 | `SaveAsNewRenderPreset(presetName)` | ✅ | 创建渲染预设 |\n| 21 | `DeleteRenderPreset(presetName)` | ✅ | 删除渲染预设 |\n| 22 | `SetRenderSettings({settings})` | ✅ | 应用渲染设置 |\n| 23 | `GetRenderJobStatus(jobId)` | ✅ | 返回 `{JobStatus, CompletionPercentage}` |\n| 24 | `GetQuickExportRenderPresets()` | ✅ | 返回预设名称 |\n| 25 | `RenderWithQuickExport(preset, {params})` | ✅ | 启动快速导出 |\n| 26 | `GetSetting(settingName)` | ✅ | 返回项目设置字典 |\n| 27 | `SetSetting(settingName, settingValue)` | ✅ | 设置项目设置 |\n| 28 | `GetRenderFormats()` | ✅ | 返回格式映射 |\n| 29 | `GetRenderCodecs(renderFormat)` | ✅ | 返回编解码器映射 |\n| 30 | `GetCurrentRenderFormatAndCodec()` | ✅ | 返回 `{format, codec}` |\n| 31 | `SetCurrentRenderFormatAndCodec(format, codec)` | ✅ | 设置格式和编解码器 |\n| 32 | `GetCurrentRenderMode()` | ✅ | 返回模式整数 |\n| 33 | `SetCurrentRenderMode(renderMode)` | ✅ | 设置渲染模式 |\n| 34 | `GetRenderResolutions(format, codec)` | ✅ | 返回分辨率列表 |\n| 35 | `RefreshLUTList()` | ✅ | 刷新 LUT 列表 |\n| 36 | `GetUniqueId()` | ✅ | 返回 UUID 字符串 |\n| 37 | `InsertAudioToCurrentTrackAtPlayhead(...)` | ⚠️ | 已测试；需要 Fairlight 页面上下文 |\n| 38 | `LoadBurnInPreset(presetName)` | ⚠️ | API 接受；预设必须存在 |\n| 39 | `ExportCurrentFrameAsStill(filePath)` | ⚠️ | API 接受；需要有效的播放头位置 |\n| 40 | `GetColorGroupsList()` | ✅ | 返回颜色组列表 |\n| 41 | `AddColorGroup(groupName)` | ✅ | 返回 ColorGroup 对象 |\n| 42 | `DeleteColorGroup(colorGroup)` | ✅ | 删除颜色组 |\n\n### 媒体存储\n\n| 序号 | 方法 | 状态 | 测试结果\u002F备注 |\n|---|--------|--------|---------------------|\n| 1 | `GetMountedVolumeList()` | ✅ | 返回已挂载卷路径 |\n| 2 | `GetSubFolderList(folderPath)` | ✅ | 返回子文件夹路径 |\n| 3 | `GetFileList(folderPath)` | ✅ | 返回文件路径 |\n| 4 | `RevealInStorage(path)` | ✅ | 在媒体存储中显示路径 |\n| 5 | `AddItemListToMediaPool(...)` | ✅ | 导入媒体，返回片段 |\n| 6 | `AddClipMattesToMediaPool(item, [paths], eye)` | ✅ | 添加片段遮罩 |\n| 7 | `AddTimelineMattesToMediaPool([paths])` | ✅ | 返回 MediaPoolItem 列表 |\n\n### 媒体池\n\n| 序号 | 方法 | 状态 | 测试结果\u002F备注 |\n|---|--------|--------|---------------------|\n| 1 | `GetRootFolder()` | ✅ | 返回根文件夹 |\n| 2 | `AddSubFolder(folder, name)` | ✅ | 创建子文件夹 |\n| 3 | `RefreshFolders()` | ✅ | 刷新文件夹列表 |\n| 4 | `CreateEmptyTimeline(name)` | ✅ | 创建时间线 |\n| 5 | `AppendToTimeline(...)` | ✅ | 追加片段，返回 TimelineItems |\n| 6 | `CreateTimelineFromClips(name, ...)` | ✅ | 从片段创建时间线 |\n| 7 | `ImportTimelineFromFile(filePath, {options})` | ✅ | 导入 AAF\u002FEDL\u002FXML |\n| 8 | `DeleteTimelines([timeline])` | ✅ | 删除时间线 |\n| 9 | `GetCurrentFolder()` | ✅ | 返回当前文件夹 |\n| 10 | `SetCurrentFolder(folder)` | ✅ | 设置当前文件夹 |\n| 11 | `DeleteClips([clips])` | ✅ | 删除片段 |\n| 12 | `ImportFolderFromFile(filePath)` | ✅ | 导入 DRB 文件夹 |\n| 13 | `DeleteFolders([subfolders])` | ✅ | 删除文件夹 |\n| 14 | `MoveClips([clips], targetFolder)` | ✅ | 移动片段 |\n| 15 | `MoveFolders([folders], targetFolder)` | ✅ | 移动文件夹 |\n| 16 | `GetClipMatteList(item)` | ✅ | 返回遮罩路径 |\n| 17 | `GetTimelineMatteList(folder)` | ✅ | 返回遮罩项目 |\n| 18 | `DeleteClipMattes(item, [paths])` | ✅ | 删除片段遮罩 |\n| 19 | `RelinkClips([items], folderPath)` | ⚠️ | API 接受；需要离线片段 |\n| 20 | `UnlinkClips([items])` | ✅ | 解除片段链接 |\n| 21 | `ImportMedia([items])` | ✅ | 导入媒体文件 |\n| 22 | `ExportMetadata(fileName, [clips])` | ✅ | 导出元数据 CSV |\n| 23 | `GetUniqueId()` | ✅ | 返回 UUID 字符串 |\n| 24 | `CreateStereoClip(left, right)` | ✅ | 创建立体声对 |\n| 25 | `AutoSyncAudio([items], {settings})` | ⚠️ | 已测试；需要匹配的音视频片段 |\n| 26 | `GetSelectedClips()` | ✅ | 返回选定的片段 |\n| 27 | `SetSelectedClip(item)` | ✅ | 选择片段 |\n\n### 文件夹\n\n| 序号 | 方法 | 状态 | 测试结果\u002F备注 |\n|---|--------|--------|---------------------|\n| 1 | `GetClipList()` | ✅ | 返回片段列表 |\n| 2 | `GetName()` | ✅ | 返回文件夹名称 |\n| 3 | `GetSubFolderList()` | ✅ | 返回子文件夹列表 |\n| 4 | `GetIsFolderStale()` | ✅ | 返回 `False` |\n| 5 | `GetUniqueId()` | ✅ | 返回 UUID 字符串 |\n| 6 | `Export(filePath)` | ✅ | 导出 DRB 文件 |\n| 7 | `TranscribeAudio()` | ✅ | 开始音频转录 |\n| 8 | `ClearTranscription()` | ✅ | 清除转录内容 |\n\n### MediaPoolItem\n\n| 序号 | 方法 | 状态 | 测试结果\u002F备注 |\n|---|--------|--------|---------------------|\n| 1 | `GetName()` | ✅ | 返回片段名称 |\n| 2 | `GetMetadata(metadataType)` | ✅ | 返回元数据字典 |\n| 3 | `SetMetadata(type, value)` | ✅ | 设置元数据 |\n| 4 | `GetThirdPartyMetadata(type)` | ✅ | 返回第三方元数据 |\n| 5 | `SetThirdPartyMetadata(type, value)` | ✅ | 设置第三方元数据 |\n| 6 | `GetMediaId()` | ✅ | 返回媒体 UUID |\n| 7 | `AddMarker(frameId, color, name, note, duration, customData)` | ✅ | 添加标记 |\n| 8 | `GetMarkers()` | ✅ | 返回标记字典 |\n| 9 | `GetMarkerByCustomData(customData)` | ✅ | 根据数据查找标记 |\n| 10 | `UpdateMarkerCustomData(frameId, customData)` | ✅ | 更新标记数据 |\n| 11 | `GetMarkerCustomData(frameId)` | ✅ | 返回自定义数据字符串 |\n| 12 | `DeleteMarkersByColor(color)` | ✅ | 按颜色删除标记 |\n| 13 | `DeleteMarkerAtFrame(frameNum)` | ⚠️ | 如果该帧无标记，则返回 `False` |\n| 14 | `DeleteMarkerByCustomData(customData)` | ⚠️ | 如果没有匹配项，则返回 `False` |\n| 15 | `AddFlag(color)` | ✅ | 添加标志 |\n| 16 | `GetFlagList()` | ✅ | 返回标志颜色 |\n| 17 | `ClearFlags(color)` | ✅ | 清除标志 |\n| 18 | `GetClipColor()` | ✅ | 返回片段颜色 |\n| 19 | `SetClipColor(colorName)` | ✅ | 设置片段颜色 |\n| 20 | `ClearClipColor()` | ✅ | 清除片段颜色 |\n| 21 | `GetClipProperty(propertyName)` | ✅ | 返回属性字典 |\n| 22 | `SetClipProperty(propertyName, value)` | ⚠️ | API 接受；但部分属性只读 |\n| 23 | `LinkProxyMedia(proxyMediaFilePath)` | ✅ | 链接代理媒体 |\n| 24 | `UnlinkProxyMedia()` | ✅ | 取消链接代理媒体 |\n| 25 | `ReplaceClip(filePath)` | ✅ | 替换片段源文件 |\n| 26 | `GetUniqueId()` | ✅ | 返回 UUID 字符串 |\n| 27 | `TranscribeAudio()` | ✅ | 开始音频转录 |\n| 28 | `ClearTranscription()` | ✅ | 清除转录内容 |\n| 29 | `GetAudioMapping()` | ✅ | 返回 JSON 格式的音频映射 |\n| 30 | `GetMarkInOut()` | ✅ | 返回入点\u002F出点字典 |\n| 31 | `SetMarkInOut(in, out, type)` | ✅ | 设置入点\u002F出点 |\n| 32 | `ClearMarkInOut(type)` | ✅ | 清除入点\u002F出点 |\n\n### 时间线\n\n| 序号 | 方法 | 状态 | 测试结果\u002F备注 |\n|---|--------|--------|---------------------|\n| 1 | `GetName()` | ✅ | 返回时间线索引名称 |\n| 2 | `SetName(timelineName)` | ⚠️ | 在活动时间线上返回 `False` |\n| 3 | `GetStartFrame()` | ✅ | 返回起始帧 |\n| 4 | `GetEndFrame()` | ✅ | 返回结束帧 |\n| 5 | `SetStartTimecode(timecode)` | ✅ | 设置开始时间码 |\n| 6 | `GetStartTimecode()` | ✅ | 返回 `\"01:00:00:00\"` |\n| 7 | `GetTrackCount(trackType)` | ✅ | 返回轨道数量 |\n| 8 | `AddTrack(trackType, subTrackType)` | ✅ | 添加轨道 |\n| 9 | `DeleteTrack(trackType, trackIndex)` | ✅ | 删除轨道 |\n| 10 | `GetTrackSubType(trackType, trackIndex)` | ✅ | 返回子类型（例如 `\"stereo\"`） |\n| 11 | `SetTrackEnable(trackType, trackIndex, enabled)` | ✅ | 启用或禁用轨道 |\n| 12 | `GetIsTrackEnabled(trackType, trackIndex)` | ✅ | 返回启用状态 |\n| 13 | `SetTrackLock(trackType, trackIndex, locked)` | ✅ | 锁定或解锁轨道 |\n| 14 | `GetIsTrackLocked(trackType, trackIndex)` | ✅ | 返回锁定状态 |\n| 15 | `DeleteClips([timelineItems], ripple)` | ✅ | 从时间线删除片段 |\n| 16 | `SetClipsLinked([timelineItems], linked)` | ✅ | 链接或取消链接片段 |\n| 17 | `GetItemListInTrack(trackType, index)` | ✅ | 返回轨道上的项目列表 |\n| 18 | `AddMarker(frameId, color, name, note, duration, customData)` | ✅ | 添加时间线标记 |\n| 19 | `GetMarkers()` | ✅ | 返回标记字典 |\n| 20 | `GetMarkerByCustomData(customData)` | ✅ | 根据数据查找标记 |\n| 21 | `UpdateMarkerCustomData(frameId, customData)` | ✅ | 更新标记数据 |\n| 22 | `GetMarkerCustomData(frameId)` | ✅ | 返回自定义数据 |\n| 23 | `DeleteMarkersByColor(color)` | ✅ | 按颜色删除标记 |\n| 24 | `DeleteMarkerAtFrame(frameNum)` | ⚠️ | 如果该帧无标记，则返回 `False` |\n| 25 | `DeleteMarkerByCustomData(customData)` | ⚠️ | 如果没有匹配项，则返回 `False` |\n| 26 | `GetCurrentTimecode()` | ✅ | 返回时间码字符串 |\n| 27 | `SetCurrentTimecode(timecode)` | ⚠️ | 如果播放未激活，则返回 `False` |\n| 28 | `GetCurrentVideoItem()` | ✅ | 返回播放头处的项目 |\n| 29 | `GetCurrentClipThumbnailImage()` | ✅ | 返回缩略图数据 |\n| 30 | `GetTrackName(trackType, trackIndex)` | ✅ | 返回轨道名称 |\n| 31 | `SetTrackName(trackType, trackIndex, name)` | ✅ | 设置轨道名称 |\n| 32 | `DuplicateTimeline(timelineName)` | ✅ | 复制时间线 |\n| 33 | `CreateCompoundClip([items], {clipInfo})` | ✅ | 返回复合片段项目 |\n| 34 | `CreateFusionClip([timelineItems])` | ✅ | 返回 Fusion 片段项目 |\n| 35 | `ImportIntoTimeline(filePath, {options})` | ⚠️ | 已测试；结果取决于文件格式 |\n| 36 | `Export(fileName, exportType, exportSubtype)` | ✅ | 导出 EDL\u002FXML\u002FAAF 文件 |\n| 37 | `GetSetting(settingName)` | ✅ | 返回设置字典 |\n| 38 | `SetSetting(settingName, settingValue)` | ⚠️ | API 接受；但部分设置只读 |\n| 39 | `InsertGeneratorIntoTimeline(name)` | ✅ | 插入生成器 |\n| 40 | `InsertFusionGeneratorIntoTimeline(name)` | ✅ | 插入 Fusion 生成器 |\n| 41 | `InsertFusionCompositionIntoTimeline()` | ✅ | 插入 Fusion 合成 |\n| 42 | `InsertOFXGeneratorIntoTimeline(name)` | ⚠️ | API 接受；需要有效的 OFX 插件 |\n| 43 | `InsertTitleIntoTimeline(name)` | ✅ | 插入标题 |\n| 44 | `InsertFusionTitleIntoTimeline(name)` | ✅ | 插入 Fusion 标题 |\n| 45 | `GrabStill()` | ✅ | 返回 GalleryStill 对象 |\n| 46 | `GrabAllStills(stillFrameSource)` | ✅ | 返回 GalleryStill 对象列表 |\n| 47 | `GetUniqueId()` | ✅ | 返回 UUID 字符串 |\n| 48 | `CreateSubtitlesFromAudio({settings})` | ✅ | 返回 `True` — 从音频创建字幕 |\n| 49 | `DetectSceneCuts()` | ✅ | 返回 `True` — 检测时间线中的场景切换 |\n| 50 | `ConvertTimelineToStereo()` | ✅ | 将时间线转换为立体 3D |\n| 51 | `GetNodeGraph()` | ✅ | 返回 Graph 对象 |\n| 52 | `AnalyzeDolbyVision([items], analysisType)` | 🔬 | 需要 HDR\u002FDolby Vision 内容 |\n| 53 | `GetMediaPoolItem()` | ✅ | 返回时间线对应的 MediaPoolItem |\n| 54 | `GetMarkInOut()` | ✅ | 返回入点\u002F出点字典 |\n| 55 | `SetMarkInOut(in, out, type)` | ✅ | 设置入点\u002F出点 |\n| 56 | `ClearMarkInOut(type)` | ✅ | 清除入点\u002F出点 |\n\n### TimelineItem\n\n| 序号 | 方法 | 状态 | 测试结果\u002F备注 |\n|---|--------|--------|---------------------|\n| 1 | `GetName()` | ✅ | 返回项目名称 |\n| 2 | `GetDuration(subframe_precision)` | ✅ | 返回持续时间 |\n| 3 | `GetEnd(subframe_precision)` | ✅ | 返回结束帧 |\n| 4 | `GetSourceEndFrame()` | ✅ | 返回源素材的结束帧 |\n| 5 | `GetSourceEndTime()` | ✅ | 返回源素材的结束时间 |\n| 6 | `GetFusionCompCount()` | ✅ | 返回合成数量 |\n| 7 | `GetFusionCompByIndex(compIndex)` | ✅ | 返回 Fusion 合成 |\n| 8 | `GetFusionCompNameList()` | ✅ | 返回合成名称列表 |\n| 9 | `GetFusionCompByName(compName)` | ✅ | 返回 Fusion 合成 |\n| 10 | `GetLeftOffset(subframe_precision)` | ✅ | 返回左侧偏移量 |\n| 11 | `GetRightOffset(subframe_precision)` | ✅ | 返回右侧偏移量 |\n| 12 | `GetStart(subframe_precision)` | ✅ | 返回起始帧 |\n| 13 | `GetSourceStartFrame()` | ✅ | 返回源素材的起始帧 |\n| 14 | `GetSourceStartTime()` | ✅ | 返回源素材的开始时间 |\n| 15 | `SetProperty(propertyKey, propertyValue)` | ✅ | 设置项目属性 |\n| 16 | `GetProperty(propertyKey)` | ✅ | 返回属性字典 |\n| 17 | `AddMarker(frameId, color, name, note, duration, customData)` | ✅ | 向项目添加标记 |\n| 18 | `GetMarkers()` | ✅ | 返回标记字典 |\n| 19 | `GetMarkerByCustomData(customData)` | ✅ | 根据自定义数据查找标记 |\n| 20 | `UpdateMarkerCustomData(frameId, customData)` | ✅ | 更新标记的自定义数据 |\n| 21 | `GetMarkerCustomData(frameId)` | ✅ | 返回自定义数据 |\n| 22 | `DeleteMarkersByColor(color)` | ✅ | 按颜色删除标记 |\n| 23 | `DeleteMarkerAtFrame(frameNum)` | ⚠️ | 如果该帧没有标记，则返回 `False` |\n| 24 | `DeleteMarkerByCustomData(customData)` | ⚠️ | 如果没有匹配的标记，则返回 `False` |\n| 25 | `AddFlag(color)` | ✅ | 添加标志 |\n| 26 | `GetFlagList()` | ✅ | 返回标志颜色列表 |\n| 27 | `ClearFlags(color)` | ✅ | 清除标志 |\n| 28 | `GetClipColor()` | ✅ | 返回片段颜色 |\n| 29 | `SetClipColor(colorName)` | ✅ | 设置片段颜色 |\n| 30 | `ClearClipColor()` | ✅ | 清除片段颜色 |\n| 31 | `AddFusionComp()` | ✅ | 创建 Fusion 合成 |\n| 32 | `ImportFusionComp(path)` | ✅ | 导入 .comp 文件 |\n| 33 | `ExportFusionComp(path, compIndex)` | ✅ | 导出 .comp 文件 |\n| 34 | `DeleteFusionCompByName(compName)` | ⚠️ | 如果找不到合成，则返回 `False` |\n| 35 | `LoadFusionCompByName(compName)` | ✅ | 加载合成 |\n| 36 | `RenameFusionCompByName(oldName, newName)` | ✅ | 重命名合成 |\n| 37 | `AddVersion(versionName, versionType)` | ✅ | 添加分级版本 |\n| 38 | `GetCurrentVersion()` | ✅ | 返回版本信息 |\n| 39 | `DeleteVersionByName(versionName, versionType)` | ⚠️ | 如果未找到版本，则返回 `False` |\n| 40 | `LoadVersionByName(versionName, versionType)` | ✅ | 加载分级版本 |\n| 41 | `RenameVersionByName(oldName, newName, type)` | ✅ | 重命名版本 |\n| 42 | `GetVersionNameList(versionType)` | ✅ | 返回版本名称列表 |\n| 43 | `GetMediaPoolItem()` | ✅ | 返回源 MediaPool 项 |\n| 44 | `GetStereoConvergenceValues()` | ✅ | 返回立体关键帧 |\n| 45 | `GetStereoLeftFloatingWindowParams()` | ✅ | 返回立体参数 |\n| 46 | `GetStereoRightFloatingWindowParams()` | ✅ | 返回立体参数 |\n| 47 | `SetCDL([CDL map])` | ✅ | 设置 CDL 值 |\n| 48 | `AddTake(mediaPoolItem, startFrame, endFrame)` | ✅ | 添加拍摄片段 |\n| 49 | `GetSelectedTakeIndex()` | ✅ | 返回选中拍摄片段的索引 |\n| 50 | `GetTakesCount()` | ✅ | 返回拍摄片段数量 |\n| 51 | `GetTakeByIndex(idx)` | ✅ | 返回拍摄片段信息 |\n| 52 | `DeleteTakeByIndex(idx)` | ✅ | 删除拍摄片段 |\n| 53 | `SelectTakeByIndex(idx)` | ✅ | 选择拍摄片段 |\n| 54 | `FinalizeTake()` | ⚠️ | 如果没有选中拍摄片段，则返回 `False` |\n| 55 | `CopyGrades([tgtTimelineItems])` | ⚠️ | API 接受；需要匹配的项目 |\n| 56 | `SetClipEnabled(enabled)` | ✅ | 启用或禁用片段 |\n| 57 | `GetClipEnabled()` | ✅ | 返回启用状态 |\n| 58 | `UpdateSidecar()` | ⚠️ | 对非 BRAW 片段返回 `False` |\n| 59 | `GetUniqueId()` | ✅ | 返回 UUID 字符串 |\n| 60 | `LoadBurnInPreset(presetName)` | ⚠️ | API 接受；预设必须存在 |\n| 61 | `CreateMagicMask(mode)` | ⚠️ | 已测试；需要 DaVinci Neural Engine 和 Color 页面上下文 |\n| 62 | `RegenerateMagicMask()` | ⚠️ | 已测试；需要现有遮罩 |\n| 63 | `Stabilize()` | ✅ | 在支持的片段上返回 `True` |\n| 64 | `SmartReframe()` | ⚠️ | 已测试；需要特定的宽高比设置 |\n| 65 | `GetNodeGraph(layerIdx)` | ✅ | 返回 Graph 对象 |\n| 66 | `GetColorGroup()` | ✅ | 返回 ColorGroup |\n| 67 | `AssignToColorGroup(colorGroup)` | ✅ | 分配到组 |\n| 68 | `RemoveFromColorGroup()` | ⚠️ | 如果不在组中，则返回 `False` |\n| 69 | `ExportLUT(exportType, path)` | ✅ | 导出 LUT 文件 |\n| 70 | `GetLinkedItems()` | ✅ | 返回关联项目 |\n| 71 | `GetTrackTypeAndIndex()` | ✅ | 返回 `[trackType, trackIndex]` |\n| 72 | `GetSourceAudioChannelMapping()` | ✅ | 返回音频映射 |\n| 73 | `GetIsColorOutputCacheEnabled()` | ✅ | 返回缓存状态 |\n| 74 | `GetIsFusionOutputCacheEnabled()` | ✅ | 返回缓存状态 |\n| 75 | `SetColorOutputCache(cache_value)` | ⚠️ | 已测试；需要激活的颜色流程 |\n| 76 | `SetFusionOutputCache(cache_value)` | ⚠️ | 已测试；需要激活的 Fusion 流程 |\n\n### Gallery\n\n| 序号 | 方法 | 状态 | 测试结果\u002F备注 |\n|---|--------|--------|---------------------|\n| 1 | `GetAlbumName(galleryStillAlbum)` | ✅ | 返回相册名称 |\n| 2 | `SetAlbumName(galleryStillAlbum, albumName)` | ✅ | 设置相册名称 |\n| 3 | `GetCurrentStillAlbum()` | ✅ | 返回 GalleryStillAlbum |\n| 4 | `SetCurrentStillAlbum(galleryStillAlbum)` | ✅ | 设置当前相册 |\n| 5 | `GetGalleryStillAlbums()` | ✅ | 返回相册列表 |\n| 6 | `GetGalleryPowerGradeAlbums()` | ✅ | 返回功率分级相册 |\n| 7 | `CreateGalleryStillAlbum()` | ✅ | 创建静止相册 |\n| 8 | `CreateGalleryPowerGradeAlbum()` | ✅ | 创建功率分级相册 |\n\n### GalleryStillAlbum\n\n| 序号 | 方法 | 状态 | 测试结果\u002F备注 |\n|---|--------|--------|---------------------|\n| 1 | `GetStills()` | ✅ | 返回 GalleryStill 对象列表 |\n| 2 | `GetLabel(galleryStill)` | ✅ | 返回标签字符串 |\n| 3 | `SetLabel(galleryStill, label)` | ⚠️ | API 接受；但在某些版本中可能无法持久化 |\n| 4 | `ImportStills([filePaths])` | ✅ | 导入 DRX 静止文件（需要 Color 页面） |\n| 5 | `ExportStills([stills], folderPath, prefix, format)` | ✅ | 将静止图像及其配套的 .drx 分级文件导出。需要打开带有 Gallery 面板的 Color 页面。支持格式：dpx、cin、tif、jpg、png、ppm、bmp、xpm、drx。 |\n| 6 | `DeleteStills([galleryStill])` | ✅ | 从相册中删除静止图像 |\n\n> **注释（v2.0.8 及以上版本）：** 复合服务器的 `gallery_stills` 工具包含 `grab_and_export` 操作，可将 `GrabStill()` 和 `ExportStills()` 合并为一次调用——相比分别调用更可靠，因为它会保持实时的 GalleryStill 引用。返回导出文件列表（图像 + .drx 分级数据）。需要打开带有 Gallery 面板的 Color 页面。\n\n### 图表\n\n| 序号 | 方法 | 状态 | 测试结果\u002F备注 |\n|---|--------|--------|---------------------|\n| 1 | `GetNumNodes()` | ✅ | 返回节点数量（通过 ColorGroup 的前置和后置图） |\n| 2 | `SetLUT(nodeIndex, lutPath)` | ✅ | 在节点上设置 LUT |\n| 3 | `GetLUT(nodeIndex)` | ✅ | 返回 LUT 路径 |\n| 4 | `SetNodeCacheMode(nodeIndex, cache_value)` | ✅ | 返回 `True` |\n| 5 | `GetNodeCacheMode(nodeIndex)` | ✅ | 返回 `-1`（未设置缓存模式） |\n| 6 | `GetNodeLabel(nodeIndex)` | ✅ | 返回节点标签字符串 |\n| 7 | `GetToolsInNode(nodeIndex)` | ✅ | 返回 `None`（节点中无 OFX 工具） |\n| 8 | `SetNodeEnabled(nodeIndex, isEnabled)` | ✅ | 返回 `True` |\n| 9 | `ApplyGradeFromDRX(path, gradeMode)` | ✅ | 从 DRX 文件应用调色 |\n| 10 | `ApplyArriCdlLut()` | ✅ | 应用 ARRI CDL LUT |\n| 11 | `ResetAllGrades()` | ✅ | 重置所有调色 |\n\n### ColorGroup\n\n| 序号 | 方法 | 状态 | 测试结果\u002F备注 |\n|---|--------|--------|---------------------|\n| 1 | `GetName()` | ✅ | 返回组名 |\n| 2 | `SetName(groupName)` | ✅ | 设置组名 |\n| 3 | `GetClipsInTimeline(timeline)` | ✅ | 返回组中的片段 |\n| 4 | `GetPreClipNodeGraph()` | ✅ | 返回 Graph 对象 |\n| 5 | `GetPostClipNodeGraph()` | ✅ | 返回 Graph 对象 |\n\n---\n\n## 贡献说明\n\n我们欢迎各位的贡献！以下领域尤其需要帮助：\n\n### 寻求帮助：未测试的 API 方法\n\n仍有 **5 个方法**（占总数的 1.5%）尚未在实际运行的 DaVinci Resolve 实例中进行测试。如果您拥有所需的基础设施或素材，欢迎提交包含测试确认的 PR：\n\n1. **云项目相关方法**（4 个方法）—— 需要 DaVinci Resolve 云基础设施：\n   - `ProjectManager.CreateCloudProject`\n   - `ProjectManager.LoadCloudProject`\n   - `ProjectManager.ImportCloudProject`\n   - `ProjectManager.RestoreCloudProject`\n\n2. **HDR 分析**（1 个方法）—— 需要特定内容：\n   - `Timeline.AnalyzeDolbyVision` — 需要 HDR\u002FDolby Vision 内容\n\n### 如何贡献\n\n1. 克隆仓库并创建分支\n2. 创建功能分支 (`git checkout -b feature\u002Fmy-contribution`)\n3. 运行现有测试套件以确保不会引入问题\n4. 添加您的测试结果或修复代码\n5. 提交拉取请求\n\n### 其他贡献建议\n\n- **Windows 测试** — 所有测试均在 macOS 上完成；欢迎 Windows 平台验证\n- **Linux 测试** — DaVinci Resolve 支持 Linux；亟需增加测试覆盖率\n- **Resolve 版本兼容性** — 建议在 Resolve 18.x、19.0 或更高版本上进行测试\n- **Bug 报告** — 如果工具在您的环境中返回意外结果，请提交问题\n- **文档改进** — 完善示例、添加教程、翻译文档\n\n## 平台支持\n\n| 平台 | 状态 | Resolve 路径自动检测 | 备注 |\n|----------|--------|----------------------------|-------|\n| macOS | ✅ 已测试 | `\u002FLibrary\u002FApplication Support\u002FBlackmagic Design\u002F...` | 主要开发与测试平台 |\n| Windows | ✅ 支持 | `C:\\ProgramData\\Blackmagic Design\\...` | 社区已测试；欢迎提交 PR |\n| Linux | ⚠️ 实验性 | `\u002Fopt\u002Fresolve\u002F...` | 应该可行——欢迎测试与反馈 |\n\n## 安全考量\n\n本 MCP 服务器通过 DaVinci Resolve 的脚本 API 控制软件。部分工具执行的操作具有破坏性，或会与主机文件系统交互：\n\n| 工具 | 风险 | 缓解措施 |\n|------|------|------------|\n| `quit_app` \u002F `restart_app` | 终止 Resolve 进程——若存在未保存的更改或正在进行渲染，可能导致数据丢失 | MCP 客户端应在调用这些工具前要求用户明确确认。子进程调用使用硬编码命令列表，不存在 shell 注入风险。 |\n| `export_layout_preset` \u002F `import_layout_preset` \u002F `delete_layout_preset` | 读取、写入或删除 Resolve 布局预设目录中的文件 | 路径遍历防护机制可确保所有解析后的路径仅限于预期的预设目录内（v2.0.7 及以上版本）。 |\n| `save_project` | 在系统临时目录中创建和删除一个临时 `.drp` 文件 | 路径由服务器端生成，不涉及任何由 LLM 控制的输入。 |\n\n**针对 MCP 客户端开发者的建议：**\n- 为破坏性工具（如 `quit_app`、`restart_app`、`delete_layout_preset`）启用工具调用确认提示\n- 不应授予此服务器中所有工具的默认自动批准权限\n\n## 项目结构\n\n```\ndavinci-resolve-mcp\u002F\n├── install.py                    # 通用安装程序（macOS\u002FWindows\u002FLinux）\n├── src\u002F\n│   ├── server.py                # 复合型 MCP 服务器——27 个工具（默认）\n│   ├── resolve_mcp_server.py    # 完整版 MCP 服务器——342 个工具（高级用户）\n│   └── utils\u002F                   # 平台检测、Resolve 连接辅助工具\n├── tests\u002F                       # 5 阶段实时 API 测试套件（319\u002F319 通过）\n├── docs\u002F\n│   └── resolve_scripting_api.txt # 官方 Resolve 脚本 API 参考文档\n└── examples\u002F                    # 入门指南、标记点、媒体、时间线示例\n```\n\n## 许可证\n\nMIT\n\n## 作者\n\nSamuel Gursky (samgursky@gmail.com)\n- GitHub: [github.com\u002Fsamuelgursky](https:\u002F\u002Fgithub.com\u002Fsamuelgursky)\n\n## 致谢\n\n- Blackmagic Design 提供了 DaVinci Resolve 及其脚本 API\n- Model Context Protocol 团队促成了 AI 助手集成\n- Anthropic 提供的 Claude Code 在开发和测试中发挥了重要作用","# DaVinci Resolve MCP 快速上手指南\n\n本指南帮助开发者将 AI 助手（如 Claude、Cursor、Windsurf 等）连接到 DaVinci Resolve，通过自然语言控制后期制作流程。\n\n## 环境准备\n\n在开始之前，请确保满足以下系统和软件要求：\n\n*   **DaVinci Resolve Studio**: 版本 **18.5+** (macOS, Windows, 或 Linux)。\n    *   ⚠️ **注意**：免费版（Free Edition）**不支持**外部脚本功能，必须使用 Studio 版。\n*   **Python**: 推荐版本 **3.10 – 3.12**。\n    *   ⚠️ Python 3.13+ 可能与 Resolve 的脚本库存在 ABI 兼容性问题。\n*   **Resolve 设置**:\n    1.  启动 DaVinci Resolve。\n    2.  进入 `Preferences` (偏好设置) > `General` (常规)。\n    3.  将 `External scripting using` (外部脚本使用方式) 设置为 **Local**。\n\n## 安装步骤\n\n该工具提供通用安装脚本，可自动检测平台、配置虚拟环境并注册 MCP 客户端。\n\n1.  **克隆仓库**\n    ```bash\n    git clone https:\u002F\u002Fgithub.com\u002Fsamuelgursky\u002Fdavinci-resolve-mcp.git\n    cd davinci-resolve-mcp\n    ```\n\n2.  **运行安装脚本**\n    确保 DaVinci Resolve 正在运行，然后执行：\n    ```bash\n    python install.py\n    ```\n\n    脚本将自动完成以下操作：\n    *   创建 Python 虚拟环境。\n    *   定位 DaVinci Resolve 安装路径。\n    *   配置支持的 MCP 客户端（如 Cursor, Claude Desktop, Windsurf 等）。\n\n    **常用安装选项：**\n    ```bash\n    # 交互式选择客户端\n    python install.py\n\n    # 配置所有支持的客户端\n    python install.py --clients all\n\n    # 仅配置特定客户端 (例如 Cursor 和 Claude Desktop)\n    python install.py --clients cursor,claude-desktop\n\n    # 仅打印配置代码，不自动写入 (手动配置用)\n    python install.py --clients manual\n    ```\n\n## 基本使用\n\n安装完成后，重启你的 AI 编辑器或聊天客户端即可开始使用。\n\n### 1. 验证连接\n在支持 MCP 的 AI 助手对话框中，尝试发送以下自然语言指令：\n\n```text\n当前运行的 DaVinci Resolve 版本是多少？\n```\n\n### 2. 项目与时间线操作\n你可以直接指挥 AI 管理项目和剪辑：\n\n```text\n列出所有项目，并打开名为 \"My Film\" 的项目。\n创建一个名为 \"Assembly Cut\" 的新时间线，并将媒体池中的所有片段添加进去。\n```\n\n### 3. 高级功能示例\n利用 v2.1.0 新增的 Fusion 节点图控制或调色功能：\n\n```text\n在当前 Fusion 合成中添加一个 TextPlus 节点，并将其连接到 Merge 节点。\n为当前选中的片段应用蓝色标记。\n```\n\n### 服务器模式说明\n默认安装使用 **Compound 模式**（26 个复合工具），适合大多数用户，上下文占用低且响应快。\n如需使用包含 342 个独立工具的 **Full 模式**（适合高级开发者），可在启动时指定：\n\n```bash\npython src\u002Fserver.py --full\n```\n或在 MCP 配置文件中将命令指向 `src\u002Fresolve_mcp_server.py`。","某后期制作团队需要在深夜紧急处理一批素材，要求快速统一应用新的调色风格并导出预览图供客户确认。\n\n### 没有 davinci-resolve-mcp 时\n- 剪辑师必须手动在达芬奇中逐个打开时间线，重复执行“抓取静帧”和“导出”操作，耗时且极易出错。\n- 若需批量调整 Fusion 节点参数（如统一修改字幕位置或特效强度），只能依靠人工逐个选中节点修改，效率极低。\n- 临时导出的图片容易堆积在系统临时文件夹中，占用磁盘空间且需要后续人工清理。\n- 跨平台协作时，常因 macOS 或 Linux 的沙盒路径限制导致导出失败，排查问题耗费大量时间。\n\n### 使用 davinci-resolve-mcp 后\n- 团队成员只需向 AI 助手发送自然语言指令，davinci-resolve-mcp 即可自动遍历时间线，原子化执行 `grab_and_export` 动作，瞬间完成批量截图与调色文件（.drx）生成。\n- 通过调用新增的 `fusion_comp` 工具，AI 能直接定位并批量更新 Fusion 节点图中的参数，将原本数小时的节点调整工作压缩至分钟级。\n- 工具内置自动清理机制，在读取导出内容后立即删除本地临时文件，实现零文件堆积，保持工作环境整洁。\n- 自动处理跨平台沙盒路径重定向，智能规避系统写入限制，确保在 Windows、macOS 和 Linux 上均能稳定输出。\n\ndavinci-resolve-mcp 将繁琐的重复性手工操作转化为简单的自然语言交互，让创作者能专注于艺术决策而非软件流程。","https:\u002F\u002Foss.gittoolsai.com\u002Fimages\u002Fsamuelgursky_davinci-resolve-mcp_d5ebd884.png","samuelgursky","Samuel Gursky","https:\u002F\u002Foss.gittoolsai.com\u002Favatars\u002Fsamuelgursky_a6804a0b.jpg","Creative Producer & Technology Consultant","Bradford Operations","Brooklyn, NY",null,"www.samuelgursky.com","https:\u002F\u002Fgithub.com\u002Fsamuelgursky",[85,89,93],{"name":86,"color":87,"percentage":88},"Python","#3572A5",99.2,{"name":90,"color":91,"percentage":92},"Shell","#89e051",0.4,{"name":94,"color":95,"percentage":92},"Batchfile","#C1F12E",754,86,"2026-04-05T03:53:48","MIT",4,"macOS, Windows, Linux","未说明 (依赖 DaVinci Resolve Studio 的官方硬件需求)","未说明 (依赖 DaVinci Resolve Studio 的官方内存需求)",{"notes":105,"python":106,"dependencies":107},"必须安装 DaVinci Resolve Studio 版本（免费版不支持外部脚本）；需在 Resolve 偏好设置中启用'外部脚本使用：本地 (Local)'；服务器支持两种模式：默认复合模式（26 个工具）和全量模式（342 个工具）；安装脚本可自动配置多种 MCP 客户端（如 Claude, Cursor, Windsurf 等）。","3.10-3.12 (推荐), 3.13+ 可能存在兼容性问题",[108],"DaVinci Resolve Studio 18.5+",[44,15,45],[111,112,113,114,115,116,117],"blackmagic","blackmagic-design","blackmagicdesign","davinci-resolve","davinciresolve","mcp","mcp-server","2026-03-27T02:49:30.150509","2026-04-06T05:44:10.713283",[121,126,131,135,139,143],{"id":122,"question_zh":123,"answer_zh":124,"source_url":125},16823,"如何在 Windows 上配置 Claude Desktop 以运行此 MCP 服务器？","在 Windows 上，您需要手动编辑 Claude Desktop 的配置文件。步骤如下：\n1. 打开 Claude Desktop，进入 File -> Settings -> Developer -> Edit Config，这会打开包含 `claude_desktop_config.json` 的文件夹。\n2. 复制仓库中的 `mcp.json` 内容到 `claude_desktop_config.json`。\n3. 关键步骤：必须将命令中的脚本路径修改为绝对路径。例如：\n   \"command\": \"python\",\n   \"args\": [\"S:\u002Fsrc\u002Fdavinci-resolve-mcp\u002Fsrc\u002Fresolve_mcp.py\"]\n4. 完全重启 Claude Desktop（在 Windows 上需通过托盘图标退出再重新启动），以确保配置生效。","https:\u002F\u002Fgithub.com\u002Fsamuelgursky\u002Fdavinci-resolve-mcp\u002Fissues\u002F2",{"id":127,"question_zh":128,"answer_zh":129,"source_url":130},16824,"为什么 scriptapp(\"Resolve\") 返回 None 且无法连接？","这通常由以下原因导致：\n1. **Python 版本不兼容**：如果您使用的是 Python 3.13 或更高版本（如 3.14），二进制绑定可能不兼容。建议创建使用 Python 3.10 至 3.12 的虚拟环境。\n2. **版本限制**：DaVinci Resolve **免费版 (Free Edition)** 不支持外部脚本功能。您必须使用 **Studio 版**。\n3. **设置未开启**：确保在 Resolve 偏好设置中启用了“允许外部脚本控制 (Allow external scripting)”。\n服务器现在会在启动时检测 Python 版本并提供相应的警告信息。","https:\u002F\u002Fgithub.com\u002Fsamuelgursky\u002Fdavinci-resolve-mcp\u002Fissues\u002F16",{"id":132,"question_zh":133,"answer_zh":134,"source_url":130},16825,"推荐的 Python 版本是多少？","推荐使用 **Python 3.10 到 3.12**。避免使用 Python 3.13 或更高版本，因为 DaVinci Resolve 的二进制绑定（fusionscript）可能与新版本不兼容，导致 `scriptapp` 静默失败。如果检测到不受支持的 Python 版本，服务器启动时会发出警告。",{"id":136,"question_zh":137,"answer_zh":138,"source_url":130},16826,"是否支持 DaVinci Resolve 免费版？","不支持。此 MCP 服务器需要 **DaVinci Resolve Studio** 版本。免费版禁用了外部脚本功能（External Scripting），即使安装了相关模块，也无法通过 TCP 或本地接口进行控制。请确保您安装的是 Studio 版本。",{"id":140,"question_zh":141,"answer_zh":142,"source_url":125},16827,"如何通过 PyPI 或 GitHub 安装此服务器？","您可以通过以下两种方式安装：\n1. **从 PyPI 安装**：\n   `pip install mcp-server-davinci-resolve`\n2. **从 GitHub 安装**：\n   `pip install git+https:\u002F\u002Fgithub.com\u002Fsamuelgursky\u002Fservers.git#subdirectory=mcp-server-davinci-resolve`\n如果直接安装遇到问题，也可以克隆仓库后在本地运行 `pip install -e .` 进行开发模式安装。",{"id":144,"question_zh":145,"answer_zh":146,"source_url":147},16828,"该服务器存在哪些已知的安全风险？","静态分析工具 reachscan 指出该服务器具有执行系统命令和文件写入的高风险能力，这是由其功能决定的。具体包括：\n- **应用控制**：`quit_app` 和 `restart_app` 工具会调用 `subprocess` 来终止或启动 DaVinci Resolve 进程。\n- **文件操作**：`save_project` 和布局预设工具（如 `delete_layout_preset_tool`）包含 `os.remove` 和 `shutil.copy2` 调用，可删除或覆盖主机文件系统上的文件。\n用户在使用时应意识到 LLM 可能触发这些操作，建议在受控环境中运行。","https:\u002F\u002Fgithub.com\u002Fsamuelgursky\u002Fdavinci-resolve-mcp\u002Fissues\u002F21",[149,154,159,164,169,174],{"id":150,"version":151,"summary_zh":152,"released_at":153},99077,"v2.1.0","### v2.1.0 新增功能\n\n- **新增 `fusion_comp` 工具** — 这是一个包含 20 个操作的工具，公开了完整的 Fusion 合成节点图 API。您可以在当前活动的 Fusion 页面合成中执行添加\u002F删除\u002F查找节点、连接线、设置\u002F获取参数、管理关键帧、控制撤销分组、设置渲染范围以及触发渲染等操作。\n- **`timeline_item_fusion` 缓存操作** — 新增了 `get_cache_enabled` 和 `set_cache` 操作，用于直接在时间线项目上控制 Fusion 输出缓存。\n- **Fusion 节点图参考** — 文档字符串中包含了常用工具 ID（如 Merge、TextPlus、Background、Transform、ColorCorrector、DeltaKeyer 等），便于用户快速查找和使用。","2026-03-16T20:16:02",{"id":155,"version":156,"summary_zh":157,"released_at":158},99078,"v2.0.9","## 新增功能\n\n- **跨平台沙盒路径重定向** — `_resolve_safe_dir()` 现在能够处理 macOS（`\u002Fvar\u002Ffolders`、`\u002Fprivate\u002Fvar`）、Linux（`\u002Ftmp`、`\u002Fvar\u002Ftmp`）和 Windows（`AppData\\Local\\Temp`）中 Resolve 无法写入的沙盒路径。会将路径重定向到 `~\u002FDocuments\u002Fresolve-stills`，而不是桌面。\n- **`grab_and_export` 自动清理** — 导出的文件会被读取到响应中（DRX 以内联文本形式，图片以 base64 编码形式），随后自动从磁盘删除。不会产生文件堆积。若需保留文件在磁盘上，可传递 `cleanup: false` 参数。\n- **两台服务器同步** — `server.py` 和 `resolve_mcp_server.py` 现在使用相同版本，并且都通过 `_resolve_safe_dir()` 来处理所有面向 Resolve 的临时路径（项目导出、LUT 导出、静态图像导出）。\n- **新增 CLAUDE.md** — 发布检查清单，确保版本徽章、变更日志和 GitHub 发布保持同步。","2026-03-16T17:02:02",{"id":160,"version":161,"summary_zh":162,"released_at":163},99079,"v2.0.8","## 新增：`gallery_stills` 上的 `grab_and_export` 操作\n\n将 `GrabStill()` 和 `ExportStills()` 合并为一个原子调用，同时保留实时的 GalleryStill 引用，以确保导出的可靠性。返回包含已导出图像及其配套 `.drx` 调色文件的文件清单。\n\n### 变更\n\n- **新增 `grab_and_export` 操作** — 抓取当前帧作为画廊静帧并立即导出。相比分别调用 `grab_still` 和 `export_stills`，此方法更为可靠，因为它会保持对象的实时引用。\n- **格式回退链** — 如果请求的格式导出失败，则会自动尝试 tif 格式，再尝试 dpx 格式。\n- **macOS 沙盒路径重定向** — `\u002Fvar\u002Ffolders` 和 `\u002Fprivate\u002Fvar` 路径会被重定向到 `~\u002FDesktop\u002Fresolve-stills`，因为 Resolve 的进程无法写入沙盒化的临时目录。\n- **自动清理** — 默认在导出后从画廊中移除该静帧（`delete_after: true`）。\n- **文件清单响应** — 现在返回 `{files: [{name, path, size}], format, folder}`，而不再是仅返回 `{success: bool}`。\n\n### 重要发现\n\n`ExportStills()` 要求在 Color 页面上必须**显示 Gallery 面板**（`Workspace > Gallery`）。这一点并未在 Resolve 脚本 API 文档中提及。所有 9 种支持的格式（dpx、cin、tif、jpg、png、ppm、bmp、xpm、drx）在导出图像的同时，都会生成配套的 `.drx` 调色文件。\n\n### 使用示例\n\n```python\ngallery_stills(action=\"grab_and_export\", params={\n    \"folder_path\": \"\u002Fpath\u002Fto\u002Foutput\",\n    \"prefix\": \"my_still\",\n    \"format\": \"dpx\",\n    \"delete_after\": true\n})\n```","2026-03-16T15:38:07",{"id":165,"version":166,"summary_zh":167,"released_at":168},99080,"v2.0.7","## 安全性：布局预设工具的路径遍历防护\n\n### 新增功能\n\n- **布局预设工具的路径遍历防护** — `export_layout_preset`、`import_layout_preset` 和 `delete_layout_preset` 现在会验证解析后的文件路径是否位于预期的 Resolve 预设目录内，从而防止通过精心构造的预设名称（例如 `..\u002F..\u002Fetc\u002Fimportant`）进行路径遍历攻击。\n- **README 中的安全注意事项章节** — 详细说明了具有破坏性的工具（`quit_app`\u002F`restart_app`）、布局预设文件操作，以及针对 MCP 客户端开发者的确认提示建议。\n\n### 详情\n\n受外部静态分析（[reachscan](https:\u002F\u002Fmedium.com\u002F@vinmayN\u002Fi-scanned-50-mcp-servers-to-see-what-they-can-actually-do-46144659ceca)）的启发，该分析在 EXECUTE 和 WRITE 权限范围内发现了 13 处可被利用的漏洞：\n\n| 漏洞 | 评估 | 措施 |\n|-------|-------|------|\n| 4 处布局预设文件操作（`shutil.copy2`、`os.remove`） | **真实漏洞** — LLM 输入中的 `preset_name` 未经过路径遍历验证 | 已通过 `os.path.realpath()` 的路径限制检查修复 |\n| 8 次在 `quit_app`\u002F`restart_app`\u002Flaunch 中的子进程调用 | **设计使然** — 命令列表为硬编码，不存在 Shell 注入风险 | 已在新的“安全注意事项”章节中予以说明 |\n| 1 处在 `save_project` 中的 `os.remove()` | **误报** — 删除的是服务器创建的临时文件，路径不受 LLM 控制 | 无需更改 |","2026-03-15T21:52:44",{"id":170,"version":171,"summary_zh":172,"released_at":173},99081,"v2.0.6","## 修复：时间线项颜色分组操作在 `timeline_item_color` 中崩溃\n\n`_check()` 返回 `(pm, proj, err)`，但 `timeline_item_color` 却将其解包为 `(proj, _, _)`，将 ProjectManager 赋值给了 `proj`，而不是 Project。这导致 `assign_color_group` 和 `remove_from_color_group` 在调用 `proj.GetColorGroupsList()` 时抛出 `'NoneType' object is not callable` 异常而崩溃。\n\n**修复：**(proj, _, _) → (_, proj, _)","2026-03-14T14:43:45",{"id":175,"version":176,"summary_zh":177,"released_at":178},99082,"v2.0.5","## 新增功能\n\n### v2.0.5 — 懒加载连接恢复与空值保护\n- **懒加载连接恢复** — 完整服务器模式（`--full` 模式）现在会自动重连并自动启动 Resolve，行为与复合服务器一致。\n- **所有链式 API 调用的空值保护** — `GetProjectManager()`、`GetCurrentProject()`、`GetCurrentTimeline()` 失败时，现在会返回明确的错误信息，而非引发 `NoneType` 类型错误导致程序崩溃。\n- **辅助函数** — 新增 `get_resolve()`、`get_project_manager()`、`get_current_project()` 函数，替代了 178 处重复的样板代码。\n\n### v2.0.4 — 修复 apply_grade_from_drx 参数问题\n- 将 `mode` 参数重命名为 `grade_mode`，以匹配 Resolve API；同时修正文档中关于替换\u002F追加模式的描述，使其准确反映关键帧对齐模式。\n- 向后兼容 — 仍可接受 `mode` 参数，但优先使用 `grade_mode`。\n\n### v2.0.3 — 修复 GetNodeGraph 崩溃问题\n- 在 Resolve 中，`GetNodeGraph(0)` 会返回 `False`；现改为在未显式提供图层索引时，不进行调用。\n- 使用 `not g` 替代 `g is None` 进行检查，以捕获 `False` 返回值。\n\n### v2.0.2 — 支持 Antigravity\n- Google 的 Antigravity 已作为第 10 个 MCP 客户端加入。\n- 安装程序中客户端按字母顺序排列。\n\n### v2.0.1 — 错误修复\n- 修复 CreateMagicMask 参数类型问题、GetCurrentClipThumbnailImage 方法参数问题，以及 Python 3.13+ 的警告提示。\n\n### v2.0.0 — 重大重构\n- 26 工具复合服务器（默认）——将全部 324 个 API 方法归纳为 26 个上下文高效的工具。\n- 通用安装程序——无论 macOS、Windows 还是 Linux，只需运行 `python install.py` 即可完成安装，支持 10 个 MCP 客户端。\n- 懒加载 Resolve 连接——服务器会立即启动，仅在首次调用工具时才建立连接。","2026-03-14T14:02:01"]