This is page 1 of 4. Use http://codebase.md/samuelgursky/davinci-resolve-mcp?page={x} to view the full context.
# Directory Structure
```
├── .cursorrules
├── .gitignore
├── CHANGELOG.md
├── CHANGES.md
├── config
│ ├── cursor-mcp-example.json
│ ├── macos
│ │ ├── claude-desktop-config.template.json
│ │ └── cursor-mcp-config.template.json
│ ├── mcp-project-template.json
│ ├── README.md
│ ├── sample_config.json
│ └── windows
│ ├── claude-desktop-config.template.json
│ └── cursor-mcp-config.template.json
├── docs
│ ├── CHANGELOG.md
│ ├── COMMIT_MESSAGE.txt
│ ├── FEATURES.md
│ ├── PROJECT_MCP_SETUP.md
│ ├── TOOLS_README.md
│ └── VERSION.md
├── examples
│ ├── getting_started.py
│ ├── markers
│ │ ├── add_spaced_markers.py
│ │ ├── add_timecode_marker.py
│ │ ├── alternating_markers.py
│ │ ├── clear_add_markers.py
│ │ ├── README.md
│ │ └── test_marker_frames.py
│ ├── media
│ │ ├── import_folder.py
│ │ └── README.md
│ ├── README.md
│ └── timeline
│ ├── README.md
│ ├── timeline_check.py
│ └── timeline_info.py
├── INSTALL.md
├── LICENSE
├── logs
│ └── .gitkeep
├── README.md
├── requirements.txt
├── resolve_mcp_server.py
├── run-now.bat
├── run-now.sh
├── scripts
│ ├── batch_automation.py
│ ├── check-resolve-ready.bat
│ ├── check-resolve-ready.ps1
│ ├── check-resolve-ready.sh
│ ├── create_app_shortcut.sh
│ ├── create-release-zip.bat
│ ├── create-release-zip.sh
│ ├── launch.sh
│ ├── mcp_resolve_launcher.sh
│ ├── mcp_resolve-claude_start
│ ├── mcp_resolve-cursor_start
│ ├── README.md
│ ├── resolve_mcp_server.py
│ ├── restart-server.bat
│ ├── restart-server.sh
│ ├── run-now.bat
│ ├── run-now.sh
│ ├── run-server.sh
│ ├── server.sh
│ ├── setup
│ │ ├── install.bat
│ │ └── install.sh
│ ├── setup.sh
│ ├── utils.sh
│ ├── verify-installation.bat
│ └── verify-installation.sh
├── src
│ ├── __init__.py
│ ├── api
│ │ ├── __init__.py
│ │ ├── color_operations.py
│ │ ├── delivery_operations.py
│ │ ├── media_operations.py
│ │ ├── project_operations.py
│ │ └── timeline_operations.py
│ ├── bin
│ │ └── __init__.py
│ ├── main.py
│ ├── resolve_mcp_server.py
│ └── utils
│ ├── __init__.py
│ ├── app_control.py
│ ├── cloud_operations.py
│ ├── layout_presets.py
│ ├── object_inspection.py
│ ├── platform.py
│ ├── project_properties.py
│ └── resolve_connection.py
└── tests
├── benchmark_server.py
├── create_test_timeline.py
├── test_custom_timeline.py
├── test_improvements.py
├── test-after-restart.bat
└── test-after-restart.sh
```
# Files
--------------------------------------------------------------------------------
/logs/.gitkeep:
--------------------------------------------------------------------------------
```
```
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
```
# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
venv/
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg
# Logs and temporary files
logs/*.log
*.log
*.swp
.DS_Store
to_clean/
logs_backup/
cleanup_backup/
# Configuration files with sensitive info
# Don't ignore templates
.cursor/mcp.json
claude_desktop_config.json
!config-templates/*.template.json
# IDE specific files
.idea/
.vscode/
*.sublime-project
*.sublime-workspace
# Session-specific files
*.session
*.pid
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache/
# VS Code
.vscode/
# Cursor
.cursor/
# macOS specific files
.AppleDouble
.LSOverride
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Keep the logs directory but not its contents
logs/*
!logs/.gitkeep
# Any backup directories
*_backup/
# Cursor
.cursor/
```
--------------------------------------------------------------------------------
/.cursorrules:
--------------------------------------------------------------------------------
```
# DaVinci Resolve MCP Server development rules for Cursor
# Rules for the project
rules:
# Quick navigation commands
- name: View project structure
match: /(project|structure|files)/i
actions: ls -la
- name: Show main server file
match: /show (server|main|resolve_mcp_server)( file)?/i
actions: cat resolve_mcp_server.py
- name: Edit main server file
match: /edit (server|main|resolve_mcp_server)( file)?/i
actions: open resolve_mcp_server.py
# Run commands
- name: Run server in dev mode
match: /run( server)?( in dev)?/i
actions: ./run-now.sh
- name: Setup server
match: /setup( server)?/i
actions: ./setup.sh
# View logs and instructions
- name: Show README
match: /show readme/i
actions: cat README.md
- name: View changelog
match: /show changelog/i
actions: cat CHANGELOG.md
# DaVinci Resolve specific
- name: Check Resolve environment
match: /check (resolve|environment|env|paths)/i
actions: |
echo "RESOLVE_SCRIPT_API = $RESOLVE_SCRIPT_API"
echo "RESOLVE_SCRIPT_LIB = $RESOLVE_SCRIPT_LIB"
echo "PYTHONPATH = $PYTHONPATH"
- name: Check if Resolve is running
match: /is resolve running/i
actions: ps -ef | grep -i "[D]aVinci Resolve"
# Directory settings
directories:
# Ignore virtual environment folder in searches
- path: venv
excludeFromSearch: true
```
--------------------------------------------------------------------------------
/examples/media/README.md:
--------------------------------------------------------------------------------
```markdown
# Media Examples
This directory contains examples demonstrating how to work with media files and the Media Pool in DaVinci Resolve using the MCP server.
## Available Examples
### import_folder.py
Shows how to import a folder of media files into the Media Pool.
## Running the Examples
Ensure DaVinci Resolve is running and that you have a project open.
```bash
# From the root directory of the repository
python examples/media/import_folder.py
```
## Media Operations
Common media operations demonstrated in these examples:
- Importing media files into the Media Pool
- Creating and organizing bins (folders)
- Working with clips in the Media Pool
- Adding clips to timelines
## Common Issues
- File paths must be valid and accessible to DaVinci Resolve
- Some media formats may not be supported for import
- Large media files may take time to import and process
- DaVinci Resolve may have limitations on certain media operations depending on the version
```
--------------------------------------------------------------------------------
/examples/timeline/README.md:
--------------------------------------------------------------------------------
```markdown
# Timeline Examples
This directory contains examples demonstrating how to work with timelines in DaVinci Resolve using the MCP server.
## Available Examples
### timeline_info.py
Shows how to retrieve various information about timelines in a project.
### timeline_check.py
Demonstrates how to validate timeline properties and settings.
## Running the Examples
Ensure DaVinci Resolve is running and that you have a project open, preferably with multiple timelines.
```bash
# From the root directory of the repository
python examples/timeline/timeline_info.py
```
## Timeline Operations
Common operations demonstrated in these examples:
- Listing all timelines in a project
- Getting information about the current timeline
- Switching between timelines
- Creating new timelines
- Working with timeline settings
## Common Issues
- Some timeline operations require administrative access to the project
- Timeline operations may fail if the project is in read-only mode
- Creating timelines may be affected by project settings
```
--------------------------------------------------------------------------------
/examples/markers/README.md:
--------------------------------------------------------------------------------
```markdown
# Marker Examples
This directory contains examples demonstrating how to work with markers in DaVinci Resolve timelines using the MCP server.
## Available Examples
### add_timecode_marker.py
Shows how to add markers with timecode values at specified positions.
### add_spaced_markers.py
Demonstrates adding markers at regular intervals throughout a timeline.
### alternating_markers.py
Shows how to add markers with alternating colors and notes.
### clear_add_markers.py
Demonstrates how to clear all markers and then add new ones.
### test_marker_frames.py
A test script to verify marker placement at specific frames.
## Running the Examples
Ensure DaVinci Resolve is running and that you have a project open with at least one timeline.
```bash
# From the root directory of the repository
python examples/markers/add_timecode_marker.py
```
## Marker Colors
DaVinci Resolve supports the following marker colors that can be used in scripts:
- Blue
- Cyan
- Green
- Yellow
- Red
- Pink
- Purple
- Fuchsia
- Rose
- Lavender
- Sky
- Mint
- Lemon
- Sand
- Cocoa
- Cream
## Common Issues
- Make sure a timeline is open before trying to add markers
- Markers can only be placed on valid frames that contain media
- Some marker operations require specific permissions or project settings
```
--------------------------------------------------------------------------------
/examples/README.md:
--------------------------------------------------------------------------------
```markdown
# DaVinci Resolve MCP Examples
This directory contains example scripts demonstrating how to use the DaVinci Resolve MCP server with different features of DaVinci Resolve.
## Directory Structure
- **markers/** - Examples related to timeline markers and marker operations
- **timeline/** - Examples for timeline management and operations
- **media/** - Examples for media pool operations and media management
## How to Run Examples
1. Make sure DaVinci Resolve is running
2. Ensure the MCP server is set up (run `./scripts/check-resolve-ready.sh` first)
3. Use a Python environment with the MCP SDK installed
4. Run an example script with:
```bash
# Activate the virtual environment
source venv/bin/activate # macOS/Linux
# or
venv\Scripts\activate # Windows
# Run an example
python examples/markers/add_timecode_marker.py
```
## Example Categories
### Markers Examples
Examples in `markers/` demonstrate how to:
- Add markers at specific frames
- Add markers with timecode values
- Add markers at regular intervals
- Test marker frame placement
- Clear and replace markers
### Timeline Examples
Examples in `timeline/` demonstrate how to:
- Get information about timelines
- Check timeline properties
- Perform operations on timelines
### Media Examples
Examples in `media/` demonstrate how to:
- Import media into the media pool
- Organize media in bins
- Add media to timelines
## Creating Your Own Examples
When creating new examples, please follow these guidelines:
1. Place them in the appropriate category folder
2. Include clear comments explaining what the example does
3. Handle errors gracefully
4. Follow the code style of existing examples
If you create an example that doesn't fit in an existing category, feel free to create a new directory.
```
--------------------------------------------------------------------------------
/config/README.md:
--------------------------------------------------------------------------------
```markdown
# DaVinci Resolve MCP Configuration Templates
This directory contains configuration templates for integrating DaVinci Resolve MCP with different AI assistant clients.
## ⚠️ IMPORTANT: Path Configuration Required
**All template files require you to replace the placeholder paths with your actual paths to the repository.**
The templates contain placeholders like `${PROJECT_ROOT}` that **MUST** be replaced with your actual filesystem paths. Cursor and other tools **do not** automatically resolve these variables.
For example:
- Replace `${PROJECT_ROOT}` with `/Users/username/davinci-resolve-mcp` on macOS
- Replace `${PROJECT_ROOT}` with `C:\Users\username\davinci-resolve-mcp` on Windows
**Failure to replace these placeholders is the most common cause of connection problems.**
## Available Templates
### Cursor Integration
`cursor-mcp-config.template.json` - Template for configuring Cursor AI to use the DaVinci Resolve MCP server.
To use this template:
1. Copy the contents to your Cursor MCP configuration file:
- macOS: `~/.cursor/mcp.json`
- Windows: `%APPDATA%\Cursor\mcp.json`
2. Replace the placeholders with your actual paths:
- `${PROJECT_ROOT}` - Path to the DaVinci Resolve MCP repository
Example (macOS):
```json
{
"mcpServers": {
"davinci-resolve": {
"name": "DaVinci Resolve MCP",
"command": "/Users/username/davinci-resolve-mcp/venv/bin/python",
"args": ["/Users/username/davinci-resolve-mcp/resolve_mcp_server.py"]
}
}
}
```
### Claude Desktop Integration
`claude-desktop-config.template.json` - Template for configuring Claude Desktop to use the DaVinci Resolve MCP server.
To use this template:
- Copy the template to your Claude Desktop configuration directory (location varies by installation)
- Windows - %appdata%\Claude\claude_desktop_config.json
- Rename it to `claude_desktop_config.json`
- Replace the placeholders with your actual paths:
- `${PROJECT_ROOT}` - Path to the DaVinci Resolve MCP repository
## Automatic Setup
For automatic configuration, use the appropriate launch script which will set up the configuration for you:
```bash
# For Cursor
./scripts/mcp_resolve-cursor_start
# For Claude Desktop
./scripts/mcp_resolve-claude_start
```
Or use the universal launcher:
```bash
./scripts/mcp_resolve_launcher.sh
```
--------------------------------------------------------------------------------
/scripts/README.md:
--------------------------------------------------------------------------------
```markdown
# DaVinci Resolve MCP Scripts
This directory contains all the utility and launcher scripts for the DaVinci Resolve MCP server.
## Quick Start Scripts
### run-now.sh / run-now.bat
Quick start scripts for macOS/Linux and Windows that set up the environment and start the server in one step.
```bash
# macOS/Linux
./scripts/run-now.sh
# Windows
scripts\run-now.bat
```
## Pre-Launch Check Scripts
### check-resolve-ready.sh / check-resolve-ready.bat
Scripts that verify your environment is properly configured before launching the server.
```bash
# macOS/Linux
./scripts/check-resolve-ready.sh
# Windows
scripts\check-resolve-ready.bat
```
## Client-Specific Launch Scripts
### mcp_resolve-cursor_start
Dedicated script for launching the server configured for Cursor AI integration.
```bash
./scripts/mcp_resolve-cursor_start
```
### mcp_resolve-claude_start
Dedicated script for launching the server configured for Claude Desktop integration.
```bash
./scripts/mcp_resolve-claude_start
```
## Universal Launcher
### mcp_resolve_launcher.sh
Interactive launcher script that provides a menu for managing different server instances.
```bash
./scripts/mcp_resolve_launcher.sh
```
Command-line options:
- `--start-cursor` - Start the Cursor MCP server
- `--start-claude` - Start the Claude Desktop MCP server
- `--start-both` - Start both servers
- `--stop-all` - Stop all running servers
- `--status` - Show server status
- `--force` - Skip DaVinci Resolve running check
- `--project "Project Name"` - Open a specific project on startup
## Setup and Server Management
### setup.sh
Complete installation script that sets up the environment, virtual environment, and dependencies.
```bash
./scripts/setup.sh
```
### server.sh
Consolidated server management script with commands for starting, stopping, and checking server status.
```bash
./scripts/server.sh start
./scripts/server.sh stop
./scripts/server.sh status
```
## Utility Scripts
### utils.sh
Common utility functions used by other scripts.
## Script Organization
The scripts are organized by function:
- **Quick start scripts** - For getting up and running quickly
- **Environment check scripts** - For verifying proper configuration
- **Client-specific scripts** - For launching with specific AI assistants
- **Management scripts** - For controlling server operation
## Notes for Developers
- Most scripts include environment setup to ensure DaVinci Resolve can be accessed
- The launcher scripts have symbolic links in the root directory for easier access
- Scripts check for DaVinci Resolve before starting to avoid connection issues
```
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
```markdown
# DaVinci Resolve MCP Server
[](https://github.com/samuelgursky/davinci-resolve-mcp/releases)
[](https://www.blackmagicdesign.com/products/davinciresolve)
[](https://www.python.org/downloads/)
[](https://www.apple.com/macos/)
[](https://www.microsoft.com/windows)
[](https://opensource.org/licenses/MIT)
A Model Context Protocol (MCP) server that connects AI coding assistants (Cursor, Claude Desktop) to DaVinci Resolve, enabling them to query and control DaVinci Resolve through natural language.
## Features
For a comprehensive list of implemented and planned features, see [docs/FEATURES.md](docs/FEATURES.md).
## Requirements
- **macOS** or **Windows** with DaVinci Resolve installed
- **Python 3.6+**
- DaVinci Resolve running in the background
- (Optional) Node.js/npm for some features
## Installation Guide
For detailed installation instructions, please see [INSTALL.md](INSTALL.md). This guide covers:
- Prerequisites and system requirements
- Step-by-step installation process
- Configuration details
- Common troubleshooting steps
## Platform Support
| Platform | Status | One-Step Install | Quick Start |
|----------|--------|------------------|-------------|
| macOS | ✅ Stable | `./install.sh` | `./run-now.sh` |
| Windows | ✅ Stable | `install.bat` | `run-now.bat` |
| Linux | ❌ Not supported | N/A | N/A |
## Quick Start Guide
### New One-Step Installation (Recommended)
The easiest way to get started is with our new unified installation script. This script does everything automatically:
- Clone the repository:
```bash
git clone https://github.com/samuelgursky/davinci-resolve-mcp.git
cd davinci-resolve-mcp
```
- Make sure DaVinci Resolve Studio is installed and running
- Run the installation script:
**macOS/Linux:**
```bash
./install.sh
```
**Windows:**
```batch
install.bat
```
This will:
1. Automatically detect the correct paths on your system
2. Create a Python virtual environment
3. Install the MCP SDK from the official repository
4. Set up environment variables
5. Configure Cursor/Claude integration
6. Verify the installation is correct
7. Optionally start the MCP server
### Alternative Quick Start
You can also use the original quick start scripts:
**Windows Users:**
```bash
run-now.bat
```
**macOS Users:**
```bash
chmod +x run-now.sh
./run-now.sh
```
## Configuration
For configuration of DaVinci Resolve MCP with different AI assistant clients like Cursor or Claude, see the [config-templates](config-templates) directory.
## Troubleshooting
For detailed troubleshooting guidance, refer to the [INSTALL.md](INSTALL.md#troubleshooting) file which contains solutions to common issues.
### Common Issues
#### Path Resolution
- The installation scripts now use more robust path resolution, fixing issues with `run-now.sh` looking for files in the wrong locations
- Always let the scripts determine the correct paths based on their location
#### DaVinci Resolve Detection
- We've improved the process detection to reliably find DaVinci Resolve regardless of how it appears in the process list
- Make sure DaVinci Resolve is running before starting the MCP server
#### Environment Variables
- Make sure all required environment variables are set correctly
- Review the log file at `scripts/cursor_resolve_server.log` for troubleshooting
### Windows
- Make sure to use forward slashes (/) in configuration files
- Python must be installed and paths configured in configs
- DaVinci Resolve must be running before starting the server
### macOS
- Make sure scripts have execute permissions
- Check Console.app for any Python-related errors
- Verify environment variables are set correctly
- DaVinci Resolve must be running before starting the server
## Support
For issues and feature requests, please use the GitHub issue tracker.
## Launch Options
After installation, you have several ways to start the server:
### Client-Specific Launch Scripts
The repository includes dedicated scripts for launching with specific clients:
```bash
# For Cursor integration (macOS)
chmod +x scripts/mcp_resolve-cursor_start
./scripts/mcp_resolve-cursor_start
# For Claude Desktop integration (macOS)
chmod +x scripts/mcp_resolve-claude_start
./scripts/mcp_resolve-claude_start
```
These specialized scripts:
- Set up the proper environment for each client
- Verify DaVinci Resolve is running
- Configure client-specific settings
- Start the MCP server with appropriate parameters
### Pre-Launch Check
Before connecting AI assistants, verify your environment is properly configured:
```bash
# On macOS
./scripts/check-resolve-ready.sh
# On Windows
./scripts/check-resolve-ready.bat
```
These scripts will:
- Verify DaVinci Resolve is running (and offer to start it)
- Check environment variables are properly set
- Ensure the Python environment is configured correctly
- Validate Cursor/Claude configuration
- Optionally launch Cursor
### Universal Launcher
For advanced users, our unified launcher provides full control over both Cursor and Claude Desktop servers:
```bash
# Make the script executable (macOS only)
chmod +x scripts/mcp_resolve_launcher.sh
# Run in interactive mode
./scripts/mcp_resolve_launcher.sh
# Or use command line options
./scripts/mcp_resolve_launcher.sh --start-cursor # Start Cursor server (uses mcp_resolve-cursor_start)
./scripts/mcp_resolve_launcher.sh --start-claude # Start Claude Desktop server (uses mcp_resolve-claude_start)
./scripts/mcp_resolve_launcher.sh --start-both # Start both servers
./scripts/mcp_resolve_launcher.sh --stop-all # Stop all running servers
./scripts/mcp_resolve_launcher.sh --status # Show server status
```
Additional options:
- Force mode (skip Resolve running check): `--force`
- Project selection: `--project "Project Name"`
## Full Installation
For a complete manual installation:
1. Clone this repository:
```bash
git clone https://github.com/samuelgursky/davinci-resolve-mcp.git
cd davinci-resolve-mcp
```
2. Create a Python virtual environment:
```bash
# Create virtual environment
python -m venv venv
# Activate it
# On macOS/Linux:
source venv/bin/activate
# On Windows:
venv\Scripts\activate
# Install dependencies from requirements.txt
pip install -r requirements.txt
# Alternatively, install MCP SDK directly
pip install git+https://github.com/modelcontextprotocol/python-sdk.git
```
3. Set up DaVinci Resolve scripting environment variables:
**For macOS**:
```bash
export RESOLVE_SCRIPT_API="/Library/Application Support/Blackmagic Design/DaVinci Resolve/Developer/Scripting"
export RESOLVE_SCRIPT_LIB="/Applications/DaVinci Resolve/DaVinci Resolve.app/Contents/Libraries/Fusion/fusionscript.so"
export PYTHONPATH="$PYTHONPATH:$RESOLVE_SCRIPT_API/Modules/"
```
**For Windows**:
```cmd
set RESOLVE_SCRIPT_API=C:\ProgramData\Blackmagic Design\DaVinci Resolve\Support\Developer\Scripting
set RESOLVE_SCRIPT_LIB=C:\Program Files\Blackmagic Design\DaVinci Resolve\fusionscript.dll
set PYTHONPATH=%PYTHONPATH%;%RESOLVE_SCRIPT_API%\Modules
```
Alternatively, run the pre-launch check script which will set these for you:
```
# On macOS
./scripts/check-resolve-ready.sh
# On Windows
./scripts/check-resolve-ready.bat
```
4. Configure Cursor to use the server by creating a configuration file:
**For macOS** (`~/.cursor/mcp.json`):
```json
{
"mcpServers": {
"davinci-resolve": {
"name": "DaVinci Resolve MCP",
"command": "/path/to/your/venv/bin/python",
"args": [
"/path/to/your/davinci-resolve-mcp/src/main.py"
]
}
}
}
```
**For Windows** (`%APPDATA%\Cursor\mcp.json`):
```json
{
"mcpServers": {
"davinci-resolve": {
"name": "DaVinci Resolve MCP",
"command": "C:\\path\\to\\venv\\Scripts\\python.exe",
"args": ["C:\\path\\to\\davinci-resolve-mcp\\src\\main.py"]
}
}
}
```
5. Start the server using one of the client-specific scripts:
```bash
# For Cursor
./scripts/mcp_resolve-cursor_start
# For Claude Desktop
./scripts/mcp_resolve-claude_start
```
## Usage with AI Assistants
### Using with Cursor
1. Start the Cursor server using the dedicated script:
```bash
./scripts/mcp_resolve-cursor_start
```
Or use the universal launcher:
```bash
./scripts/mcp_resolve_launcher.sh --start-cursor
```
2. Start Cursor and open a project.
3. In Cursor's AI chat, you can now interact with DaVinci Resolve. Try commands like:
- "What version of DaVinci Resolve is running?"
- "List all projects in DaVinci Resolve"
- "Create a new timeline called 'My Sequence'"
- "Add a marker at the current position"
### Using with Claude Desktop
1. Create a `claude_desktop_config.json` file in your Claude Desktop configuration directory using the template in the `config-templates` directory.
2. Run the Claude Desktop server using the dedicated script:
```bash
./scripts/mcp_resolve-claude_start
```
Or use the universal launcher:
```bash
./scripts/mcp_resolve_launcher.sh --start-claude
```
3. In Claude Desktop, you can now interact with DaVinci Resolve using the same commands as with Cursor.
## Available Features
### General
- Get DaVinci Resolve version
- Get/switch current page (Edit, Color, Fusion, etc.)
### Project Management
- List available projects
- Get current project name
- Open project by name
- Create new project
- Save current project
### Timeline Operations
- List all timelines
- Get current timeline info
- Create new timeline
- Switch to timeline by name
- Add marker to timeline
### Media Pool Operations
- List media pool clips
- Import media file
- Create media bin
- Add clip to timeline
## Windows Support Notes
Windows support is stable in v1.3.3 and should not require additional troubleshooting:
- Ensure DaVinci Resolve is installed in the default location
- Environment variables are properly set as described above
- Windows paths may require adjustment based on your installation
- For issues, please check the logs in the `logs/` directory
## Troubleshooting
### DaVinci Resolve Connection
Make sure DaVinci Resolve is running before starting the server. If the server can't connect to Resolve, check that:
1. Your environment variables are set correctly
2. You have the correct paths for your DaVinci Resolve installation
3. You have restarted your terminal after setting environment variables
## Project Structure
```
davinci-resolve-mcp/
├── README.md # This file
├── docs/ # Documentation
│ ├── FEATURES.md # Feature list and status
│ ├── CHANGELOG.md # Version history
│ ├── VERSION.md # Version information
│ ├── TOOLS_README.md # Tools documentation
│ ├── PROJECT_MCP_SETUP.md # Project setup guide
│ └── COMMIT_MESSAGE.txt # Latest commit information
├── config-templates/ # Configuration templates
│ ├── sample_config.json # Example configuration
│ ├── cursor-mcp-example.json # Cursor config example
│ └── mcp-project-template.json # MCP project template
├── scripts/ # Utility scripts
│ ├── tests/ # Test scripts
│ │ ├── benchmark_server.py # Performance tests
│ │ ├── test_improvements.py # Test scripts
│ │ ├── test_custom_timeline.py # Timeline tests
│ │ ├── create_test_timeline.py # Create test timeline
│ │ ├── test-after-restart.sh # Test after restart (Unix)
│ │ └── test-after-restart.bat # Test after restart (Windows)
│ ├── batch_automation.py # Batch automation script
│ ├── restart-server.sh # Server restart script (Unix)
│ ├── restart-server.bat # Server restart script (Windows)
│ ├── run-now.sh # Quick start script (Unix)
│ └── run-now.bat # Quick start script (Windows)
├── resolve_mcp_server.py # Main server implementation
├── src/ # Source code
│ ├── api/ # API implementation
│ ├── features/ # Feature modules
│ └── utils/ # Utility functions
├── logs/ # Log files
├── tools/ # Development tools
├── assets/ # Project assets
└── examples/ # Example code
```
## License
MIT
## Acknowledgments
- Blackmagic Design for DaVinci Resolve and its API
- The MCP protocol team for enabling AI assistant integration
## Author
Samuel Gursky ([email protected])
- GitHub: [github.com/samuelgursky](https://github.com/samuelgursky)
## Future Plans
- Windows and Linux support
- Additional DaVinci Resolve features
- Support for Claude Desktop
## Development
If you'd like to contribute, please check the feature checklist in the repo and pick an unimplemented feature to work on. The code is structured with clear sections for different areas of functionality.
## License
MIT
## Acknowledgments
- Blackmagic Design for DaVinci Resolve and its API
- The MCP protocol team for enabling AI assistant integration
## Project Structure
After cleanup, the project has the following structure:
- `resolve_mcp_server.py` - The main MCP server implementation
- `run-now.sh` - Quick start script that handles setup and runs the server
- `setup.sh` - Complete setup script for installation
- `check-resolve-ready.sh` - Pre-launch check to verify DaVinci Resolve is ready
- `start-server.sh` - Script to start the server
- `run-server.sh` - Simplified script to run the server directly
**Key Directories:**
- `src/` - Source code and modules
- `assets/` - Project assets and resources
- `logs/` - Log files directory
- `scripts/` - Helper scripts
When developing, it's recommended to use `./run-now.sh` which sets up the environment and launches the server in one step.
## Changelog
See [docs/CHANGELOG.md](docs/CHANGELOG.md) for a detailed history of changes.
### Cursor-Specific Setup
When integrating with Cursor, follow these specific steps:
1. Make sure DaVinci Resolve is running before starting Cursor
2. Install required dependencies:
```bash
# From the davinci-resolve-mcp directory:
pip install -r requirements.txt
```
Note: This will install the MCP package and other dependencies automatically.
3. Set up the MCP server configuration in Cursor:
Create or edit `~/.cursor/mcp.json` on macOS (or `%USERPROFILE%\.cursor\mcp.json` on Windows):
```json
{
"mcpServers": {
"davinci-resolve": {
"name": "DaVinci Resolve MCP",
"command": "/path/to/your/venv/bin/python",
"args": [
"/path/to/your/davinci-resolve-mcp/src/main.py"
]
}
}
}
```
**Important Notes:**
- Use `main.py` as the entry point (not `resolve_mcp_server.py`)
- Use absolute paths in the configuration
4. Common issues:
- "Client closed" error: Check that paths are correct in mcp.json and dependencies are installed
- Connection problems: Make sure DaVinci Resolve is running before starting Cursor
- Environment variables: The main.py script will handle setting environment variables
```
--------------------------------------------------------------------------------
/resolve_mcp_server.py:
--------------------------------------------------------------------------------
```python
src/resolve_mcp_server.py
```
--------------------------------------------------------------------------------
/src/api/__init__.py:
--------------------------------------------------------------------------------
```python
"""
DaVinci Resolve MCP API Package
"""
```
--------------------------------------------------------------------------------
/src/__init__.py:
--------------------------------------------------------------------------------
```python
"""
DaVinci Resolve MCP Server Package
"""
```
--------------------------------------------------------------------------------
/src/utils/__init__.py:
--------------------------------------------------------------------------------
```python
"""
DaVinci Resolve MCP Utilities Package
"""
```
--------------------------------------------------------------------------------
/src/bin/__init__.py:
--------------------------------------------------------------------------------
```python
"""
DaVinci Resolve MCP Binary/Scripts Package
"""
```
--------------------------------------------------------------------------------
/run-now.sh:
--------------------------------------------------------------------------------
```bash
/Users/samuelgursky/davinci-resolve-mcp-20250401-02/davinci-resolve-mcp/scripts/run-now.sh
```
--------------------------------------------------------------------------------
/run-now.bat:
--------------------------------------------------------------------------------
```
/Users/samuelgursky/davinci-resolve-mcp-20250401-02/davinci-resolve-mcp/scripts/run-now.bat
```
--------------------------------------------------------------------------------
/config/mcp-project-template.json:
--------------------------------------------------------------------------------
```json
{
"mcpServers": {
"davinci-resolve": {
"name": "DaVinci Resolve Project-Specific",
"command": "${PROJECT_ROOT}/mcp_resolve-cursor_start",
"args": ["--project", "${PROJECT_NAME}"]
}
}
}
```
--------------------------------------------------------------------------------
/config/cursor-mcp-example.json:
--------------------------------------------------------------------------------
```json
{
"mcpServers": {
"davinci-resolve": {
"name": "DaVinci Resolve MCP",
"command": "/path/to/your/venv/bin/python",
"args": [
"/path/to/your/davinci-resolve-mcp/src/main.py"
]
}
}
}
```
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
```
# DaVinci Resolve MCP Server Dependencies
# MCP Protocol SDK with CLI support
mcp[cli]
# Dependencies for testing and automation scripts
requests>=2.28.0
psutil>=5.9.0
# JSON-RPC Server for API
jsonrpcserver>=5.0.0
# Git repository dependencies
git+https://github.com/modelcontextprotocol/python-sdk.git
```
--------------------------------------------------------------------------------
/config/macos/cursor-mcp-config.template.json:
--------------------------------------------------------------------------------
```json
{
"__IMPORTANT_NOTE__": "This is a template! You MUST replace ${PROJECT_ROOT} with your actual path to the project directory (e.g., /Users/username/davinci-resolve-mcp)",
"mcpServers": {
"davinci-resolve": {
"name": "DaVinci Resolve MCP",
"command": "${PROJECT_ROOT}/venv/bin/python",
"args": ["${PROJECT_ROOT}/resolve_mcp_server.py"]
}
}
}
```
--------------------------------------------------------------------------------
/config/windows/cursor-mcp-config.template.json:
--------------------------------------------------------------------------------
```json
{
"__IMPORTANT_NOTE__": "This is a template! You MUST replace ${PROJECT_ROOT} with your actual path to the project directory (e.g., C:\\Users\\username\\davinci-resolve-mcp)",
"mcpServers": {
"davinci-resolve": {
"name": "DaVinci Resolve MCP",
"command": "${PROJECT_ROOT}/venv/Scripts/python.exe",
"args": ["${PROJECT_ROOT}/resolve_mcp_server.py"]
}
}
}
```
--------------------------------------------------------------------------------
/scripts/run-server.sh:
--------------------------------------------------------------------------------
```bash
#!/bin/bash
# Wrapper script to run the DaVinci Resolve MCP Server with the virtual environment
# Source environment variables if not already set
if [ -z "$RESOLVE_SCRIPT_API" ]; then
source "/Users/samuelgursky/.zshrc"
fi
# Activate virtual environment and run server
"/Users/samuelgursky/davinci-resolve-mcp-20250326/scripts/venv/bin/python" "/Users/samuelgursky/davinci-resolve-mcp-20250326/scripts/resolve_mcp_server.py" "$@"
```
--------------------------------------------------------------------------------
/scripts/check-resolve-ready.bat:
--------------------------------------------------------------------------------
```
@echo off
REM DaVinci Resolve MCP Server - Pre-Launch Check for Windows
REM This batch file launches the PowerShell pre-launch check script
echo Starting DaVinci Resolve MCP Pre-Launch Check...
echo.
REM Run the PowerShell script with bypass execution policy for this session only
powershell -ExecutionPolicy Bypass -File "%~dp0scripts\check-resolve-ready.ps1"
echo.
if %ERRORLEVEL% EQU 0 (
echo Pre-launch check completed successfully.
) else (
echo Pre-launch check encountered issues. Please review any error messages above.
pause
)
```
--------------------------------------------------------------------------------
/config/windows/claude-desktop-config.template.json:
--------------------------------------------------------------------------------
```json
{
"mcpServers": {
"davinci-resolve": {
"name": "DaVinci Resolve MCP",
"command": "${PROJECT_ROOT}/venv/Scripts/python.exe",
"args": ["${PROJECT_ROOT}/resolve_mcp_server.py"],
"env": {
"RESOLVE_SCRIPT_API": "C:/ProgramData/Blackmagic Design/DaVinci Resolve/Support/Developer/Scripting",
"RESOLVE_SCRIPT_LIB": "C:/Program Files/Blackmagic Design/DaVinci Resolve/fusionscript.dll",
"PYTHONPATH": "C:/ProgramData/Blackmagic Design/DaVinci Resolve/Support/Developer/Scripting/Modules"
}
}
}
}
```
--------------------------------------------------------------------------------
/config/macos/claude-desktop-config.template.json:
--------------------------------------------------------------------------------
```json
{
"mcpServers": {
"davinci-resolve": {
"name": "DaVinci Resolve MCP",
"command": "${PROJECT_ROOT}/venv/bin/python",
"args": ["${PROJECT_ROOT}/resolve_mcp_server.py"],
"env": {
"RESOLVE_SCRIPT_API": "/Library/Application Support/Blackmagic Design/DaVinci Resolve/Developer/Scripting",
"RESOLVE_SCRIPT_LIB": "/Applications/DaVinci Resolve/DaVinci Resolve.app/Contents/Libraries/Fusion/fusionscript.so",
"PYTHONPATH": "$PYTHONPATH:/Library/Application Support/Blackmagic Design/DaVinci Resolve/Developer/Scripting/Modules/"
}
}
}
}
```
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
```markdown
# Changelog
## v1.3.8 - April 2025
### Improvements
- **Cursor Integration**: Added comprehensive documentation for Cursor setup process
- **Entry Point**: Standardized on `main.py` as the proper entry point (replaces direct use of `resolve_mcp_server.py`)
- **Configuration Templates**: Updated example configuration files to use correct paths
- **Documentation**: Added detailed troubleshooting for "client closed" errors in Cursor
### Fixed
- Ensured consistent documentation for environment setup
## v1.3.7 - Installation Improvements, Path Resolution Fixes, Enhanced Configuration
### Improvements
// ... existing content ...
```
--------------------------------------------------------------------------------
/config/sample_config.json:
--------------------------------------------------------------------------------
```json
{
"project_name": "MCP Automation Demo",
"timeline_name": "Demo Timeline",
"render_preset": "YouTube 1080p",
"media_files": [
"/Users/Media/sample_video.mp4",
"/Users/Media/interview.mov",
"/Users/Media/background.png",
"/Users/Media/music.wav"
],
"color_settings": {
"primary_correction": {
"gamma_red": 0.05,
"gamma_green": 0.02,
"gamma_blue": -0.03
},
"secondary_correction": {
"lift_master": -0.05,
"gamma_master": 0.02,
"gain_master": 0.1
}
},
"project_settings": {
"timelineFrameRate": "24",
"timelineResolutionWidth": 1920,
"timelineResolutionHeight": 1080
},
"render_settings": {
"destination": "/Users/Media/Output",
"format": "mp4",
"preset": "YouTube 1080p",
"use_in_out_range": false
},
"organize_bins": {
"Video": [".mp4", ".mov", ".mxf", ".avi"],
"Audio": [".wav", ".mp3", ".aac", ".m4a"],
"Images": [".png", ".jpg", ".jpeg", ".tiff", ".tif", ".exr"],
"Graphics": [".psd", ".ai", ".eps"]
}
}
```
--------------------------------------------------------------------------------
/src/main.py:
--------------------------------------------------------------------------------
```python
#!/usr/bin/env python3
"""
DaVinci Resolve MCP Server - Main Entry Point
This file serves as the main entry point for running the DaVinci Resolve MCP server
"""
import os
import sys
import argparse
import logging
from pathlib import Path
# Add the parent directory to sys.path to ensure imports work
project_dir = Path(__file__).parent.parent
sys.path.insert(0, str(project_dir))
# Import the connection utils first to set environment variables
from src.utils.resolve_connection import check_environment_variables, set_default_environment_variables
# Set up logging
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
handlers=[logging.StreamHandler()]
)
logger = logging.getLogger("davinci-resolve-mcp.main")
def check_setup():
"""Check if the environment is properly set up."""
env_status = check_environment_variables()
if not env_status["all_set"]:
logger.warning(f"Setting default environment variables. Missing: {env_status['missing']}")
set_default_environment_variables()
return True
def run_server(debug=False):
"""Run the MCP server."""
from src.resolve_mcp_server import mcp
# Set logging level based on debug flag
if debug:
logging.getLogger("davinci-resolve-mcp").setLevel(logging.DEBUG)
logger.info("Debug mode enabled")
# Run the server
logger.info("Starting DaVinci Resolve MCP Server...")
mcp.run()
def main():
"""Main entry point for the application."""
parser = argparse.ArgumentParser(description="DaVinci Resolve MCP Server")
parser.add_argument("--debug", action="store_true", help="Enable debug logging")
args = parser.parse_args()
if check_setup():
run_server(debug=args.debug)
else:
logger.error("Failed to set up the environment. Please check the configuration.")
return 1
return 0
if __name__ == "__main__":
sys.exit(main())
```
--------------------------------------------------------------------------------
/scripts/restart-server.bat:
--------------------------------------------------------------------------------
```
@echo off
:: Restart script for DaVinci Resolve MCP Server
:: Created as part of feature updates on March 29, 2024
echo ========================================================
echo DaVinci Resolve MCP Server - Restart Script
echo ========================================================
:: Change to the directory where the script is located
cd /d "%~dp0"
:: Check if the server is running
echo Checking for running server...
wmic process where "commandline like '%%python%%resolve_mcp_server.py%%'" get processid 2>nul | findstr /r "[0-9]" > temp_pid.txt
:: Check if any PID was found
set /p SERVER_PID=<temp_pid.txt
del temp_pid.txt
if not defined SERVER_PID (
echo No running DaVinci Resolve MCP Server detected.
) else (
echo Stopping existing DaVinci Resolve MCP Server with PID: %SERVER_PID%
:: Stop the process
taskkill /PID %SERVER_PID% /F
:: Wait a moment to ensure it's stopped
timeout /t 2 /nobreak > nul
echo Server process stopped.
)
:: Make sure we have the right environment
if exist setup.bat (
echo Setting up environment...
call setup.bat
) else (
echo Warning: setup.bat not found. Environment may not be properly configured.
)
:: Start the server again
echo Starting DaVinci Resolve MCP Server...
if exist "%SCRIPT_DIR%\..\run-now.bat" (
echo Starting server with run-now.bat...
start "" cmd /c "%SCRIPT_DIR%\..\run-now.bat"
:: Wait a moment
timeout /t 3 /nobreak > nul
:: Check if it started
wmic process where "commandline like '%%python%%resolve_mcp_server.py%%'" get processid 2>nul | findstr /r "[0-9]" > nul
if %ERRORLEVEL% EQU 0 (
echo DaVinci Resolve MCP Server started successfully!
) else (
echo Failed to start DaVinci Resolve MCP Server. Check logs for errors.
)
) else (
echo Error: run-now.bat not found. Cannot start the server.
exit /b 1
)
echo ========================================================
echo Restart operation completed.
echo ========================================================
```
--------------------------------------------------------------------------------
/scripts/create-release-zip.sh:
--------------------------------------------------------------------------------
```bash
#!/bin/bash
# create-release-zip.sh
# Script to create a versioned zip file for distribution
# Colors for terminal output
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
BLUE='\033[0;34m'
RED='\033[0;31m'
NC='\033[0m' # No Color
# Get the directory where this script is located
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
PROJECT_ROOT="$( cd "$SCRIPT_DIR/.." &> /dev/null && pwd )"
# Get version from VERSION.md
VERSION=$(grep -m 1 "Current Version:" "$PROJECT_ROOT/docs/VERSION.md" | sed 's/Current Version: //')
if [ -z "$VERSION" ]; then
echo -e "${RED}Error: Could not determine version from VERSION.md${NC}"
exit 1
fi
# Create filename with version
ZIP_FILE="davinci-resolve-mcp-v$VERSION.zip"
DIST_DIR="$PROJECT_ROOT/dist"
ZIP_PATH="$DIST_DIR/$ZIP_FILE"
# Ensure dist directory exists
mkdir -p "$DIST_DIR"
echo -e "${BLUE}=================================================${NC}"
echo -e "${BLUE} Creating Release Zip for DaVinci Resolve MCP ${NC}"
echo -e "${BLUE}=================================================${NC}"
echo -e "${YELLOW}Version: $VERSION${NC}"
echo -e "${YELLOW}Output file: $ZIP_FILE${NC}"
echo -e "${YELLOW}Output directory: $DIST_DIR${NC}"
echo ""
# Change to project root directory
cd "$PROJECT_ROOT" || exit 1
# Create zip file with tracked files
echo -e "${YELLOW}Adding tracked files to zip...${NC}"
git ls-files | zip -@ "$ZIP_PATH"
# Add untracked files (but exclude ignored files and the .git directory)
echo -e "${YELLOW}Adding untracked files to zip...${NC}"
git ls-files --others --exclude-standard | zip -@ "$ZIP_PATH"
# Check if the zip file was created successfully
if [ -f "$ZIP_PATH" ]; then
ZIP_SIZE=$(du -h "$ZIP_PATH" | cut -f1)
echo -e "${GREEN}Successfully created release zip: $ZIP_PATH (Size: $ZIP_SIZE)${NC}"
else
echo -e "${RED}Failed to create release zip${NC}"
exit 1
fi
echo -e "${YELLOW}Archive contents:${NC}"
unzip -l "$ZIP_PATH" | head -n 10
echo -e "${YELLOW}... (additional files)${NC}"
echo ""
echo -e "${GREEN}Release zip created successfully!${NC}"
exit 0
```
--------------------------------------------------------------------------------
/scripts/create_app_shortcut.sh:
--------------------------------------------------------------------------------
```bash
#!/bin/bash
# Script to create a macOS desktop app shortcut for the DaVinci Resolve MCP Server Launcher
# Get the absolute path to the project directory
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
PROJECT_DIR="$( cd "$SCRIPT_DIR/.." &> /dev/null && pwd )"
LAUNCHER_SCRIPT="$SCRIPT_DIR/launch.sh"
APP_NAME="DaVinci Resolve MCP Server.app"
APP_DIR="$HOME/Desktop/$APP_NAME"
# Make sure the launcher script is executable
chmod +x "$LAUNCHER_SCRIPT"
# Create the app structure
echo "Creating app structure at $APP_DIR..."
mkdir -p "$APP_DIR/Contents/MacOS"
mkdir -p "$APP_DIR/Contents/Resources"
# Create the Info.plist
cat > "$APP_DIR/Contents/Info.plist" << EOL
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleExecutable</key>
<string>app</string>
<key>CFBundleIconFile</key>
<string>AppIcon</string>
<key>CFBundleIdentifier</key>
<string>com.davinciresolve.mcpserver</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>DaVinci Resolve MCP Server</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSMinimumSystemVersion</key>
<string>10.13</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2023. All rights reserved.</string>
</dict>
</plist>
EOL
# Create the wrapper script
cat > "$APP_DIR/Contents/MacOS/app" << EOL
#!/bin/bash
cd "$PROJECT_DIR"
osascript -e 'tell application "Terminal" to do script "\"$LAUNCHER_SCRIPT\""'
EOL
# Make the wrapper script executable
chmod +x "$APP_DIR/Contents/MacOS/app"
# Copy a default icon if available, or create a placeholder
if [ -f "$PROJECT_DIR/assets/icon.icns" ]; then
cp "$PROJECT_DIR/assets/icon.icns" "$APP_DIR/Contents/Resources/AppIcon.icns"
fi
echo "App shortcut created at $APP_DIR"
echo "Double-click to launch the DaVinci Resolve MCP Server"
```
--------------------------------------------------------------------------------
/docs/VERSION.md:
--------------------------------------------------------------------------------
```markdown
# DaVinci Resolve MCP Server
Current Version: 1.3.8
## Release Information
### 1.3.8 Changes
- **Cursor Integration**: Added comprehensive documentation for Cursor setup process
- **Entry Point**: Standardized on `main.py` as the proper entry point (replaces direct use of `resolve_mcp_server.py`)
- **Configuration Templates**: Updated example configuration files to use correct paths
- **Fixed**: Ensured consistent documentation for environment setup
### 1.3.7 Changes
- Improved installation experience:
- New one-step installation script for macOS/Linux and Windows
- Enhanced path resolution in scripts
- More reliable DaVinci Resolve detection
- Support for absolute paths in project and global configurations
- Added comprehensive verification tools for troubleshooting
- Improved error handling and feedback
- Enhanced documentation with detailed installation guide
- Fixed configuration issues with project-level MCP configuration
- Updated documentation with detailed installation and troubleshooting steps
### 1.3.6 Changes
- Comprehensive Feature Additions:
- Complete MediaPoolItem and Folder object functionality
- Cache Management implementation
- Timeline Item Properties implementation
- Keyframe Control implementation
- Color Preset Management implementation
- LUT Export functionality
- Project directory restructuring
- Updated Implementation Progress Summary to reflect 100% completion of multiple feature sets
- Enhanced documentation and examples
### 1.3.5 Changes
- Updated Cursor integration with new templating system
- Added automatic Cursor MCP configuration generation
- Improved client-specific launcher scripts
- Fixed path handling in Cursor configuration
- Enhanced cross-platform compatibility
- Improved virtual environment detection and validation
### 1.3.4 Changes
- Improved template configuration for MCP clients
- Added clearer documentation for path configuration
- Fixed Cursor integration templates with correct Python path
- Simplified configuration process with better examples
- Enhanced README with prominent warnings about path replacement
- Removed environment variable requirements from configuration files
## About
DaVinci Resolve MCP Server connects DaVinci Resolve to AI assistants through the Model Context Protocol, allowing AI agents to control DaVinci Resolve directly through natural language.
For full changelog, see CHANGELOG.md
```
--------------------------------------------------------------------------------
/scripts/restart-server.sh:
--------------------------------------------------------------------------------
```bash
#!/bin/bash
# Restart script for DaVinci Resolve MCP Server
# Created as part of feature updates on March 29, 2024
echo "========================================================"
echo "DaVinci Resolve MCP Server - Restart Script"
echo "========================================================"
# Get the directory where the script is located
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
cd "$SCRIPT_DIR"
# Function to check if the server is running
check_server_running() {
# Look for Python processes running the server
pgrep -f "python.*resolve_mcp_server.py" > /dev/null
return $?
}
# Stop the server if it's running
if check_server_running; then
echo "Stopping existing DaVinci Resolve MCP Server..."
# Find the PID of the server process
SERVER_PID=$(pgrep -f "python.*resolve_mcp_server.py")
if [ -n "$SERVER_PID" ]; then
echo "Server process found with PID: $SERVER_PID"
kill $SERVER_PID
# Wait for the process to stop
for i in {1..5}; do
if ! ps -p $SERVER_PID > /dev/null; then
echo "Server process stopped successfully."
break
fi
echo "Waiting for server to stop... ($i/5)"
sleep 1
done
# Force kill if still running
if ps -p $SERVER_PID > /dev/null; then
echo "Server did not stop gracefully. Forcing termination..."
kill -9 $SERVER_PID
sleep 1
fi
else
echo "Could not determine server PID. Server might be running in an unexpected way."
fi
else
echo "No running DaVinci Resolve MCP Server detected."
fi
# Make sure we have the right environment
if [ -f "./setup.sh" ]; then
echo "Setting up environment..."
source ./setup.sh
else
echo "Warning: setup.sh not found. Environment may not be properly configured."
fi
# Start the server again
echo "Starting DaVinci Resolve MCP Server..."
if [ -f "$SCRIPT_DIR/../run-now.sh" ]; then
echo "Starting server with run-now.sh..."
"$SCRIPT_DIR/../run-now.sh" &
# Wait a moment and check if it started
sleep 2
if check_server_running; then
echo "DaVinci Resolve MCP Server started successfully!"
else
echo "Failed to start DaVinci Resolve MCP Server. Check logs for errors."
fi
else
echo "Error: run-now.sh not found. Cannot start the server."
exit 1
fi
echo "========================================================"
echo "Restart operation completed."
echo "========================================================"
```
--------------------------------------------------------------------------------
/tests/test-after-restart.bat:
--------------------------------------------------------------------------------
```
@echo off
:: Restart DaVinci Resolve MCP Server and run tests
:: This script combines server restart with automated testing
echo ========================================================
echo DaVinci Resolve MCP Server - Test After Restart
echo ========================================================
:: Change to the directory where the script is located
cd /d "%~dp0"
:: Check if DaVinci Resolve is running
tasklist | findstr "Resolve" > nul
if %ERRORLEVEL% NEQ 0 (
echo [33m⚠️ DaVinci Resolve is not running. Please start it before continuing.[0m
set /p continue_anyway=Start testing anyway? (y/n):
if /i not "%continue_anyway%"=="y" (
echo Aborting test.
exit /b 1
)
echo Continuing with testing despite DaVinci Resolve not running...
)
:: Step 1: Restart the server using the restart script
echo.
echo Step 1: Restarting DaVinci Resolve MCP Server...
if exist restart-server.bat (
call restart-server.bat
:: Check if restart was successful
timeout /t 3 /nobreak > nul
wmic process where "commandline like '%%python%%resolve_mcp_server.py%%'" get processid 2>nul | findstr /r "[0-9]" > nul
if %ERRORLEVEL% EQU 0 (
echo [32m✅ Server restart successful[0m
) else (
echo [31m❌ Server restart failed. Please check server logs for errors.[0m
exit /b 1
)
) else (
echo [31m❌ restart-server.bat not found. Cannot restart server.[0m
exit /b 1
)
:: Step 2: Create test timeline (optional)
echo.
echo Step 2: Create test timeline with media?
set /p create_timeline=Create test timeline? (y/n):
if /i "%create_timeline%"=="y" (
echo Creating test timeline...
if exist create_test_timeline.py (
python create_test_timeline.py
if %ERRORLEVEL% NEQ 0 (
echo [33m⚠️ Test timeline creation had issues, but we'll continue with testing.[0m
)
) else (
echo [31m❌ create_test_timeline.py not found. Skipping test timeline creation.[0m
)
) else (
echo Skipping test timeline creation.
)
:: Step 3: Run automated tests
echo.
echo Step 3: Running automated tests...
if exist test_improvements.py (
python test_improvements.py
set TEST_RESULT=%ERRORLEVEL%
if %TEST_RESULT% EQU 0 (
echo [32m✅ All tests passed![0m
) else (
echo [33m⚠️ Some tests failed. Check the logs for details.[0m
)
) else (
echo [31m❌ test_improvements.py not found. Cannot run tests.[0m
exit /b 1
)
echo.
echo ========================================================
echo Testing complete. Results logged to mcp_test_results.log
echo ========================================================
exit /b %TEST_RESULT%
```
--------------------------------------------------------------------------------
/tests/test-after-restart.sh:
--------------------------------------------------------------------------------
```bash
#!/bin/bash
# Restart DaVinci Resolve MCP Server and run tests
# This script combines server restart with automated testing
echo "========================================================"
echo "DaVinci Resolve MCP Server - Test After Restart"
echo "========================================================"
# Get the directory where the script is located
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
cd "$SCRIPT_DIR"
# Check if DaVinci Resolve is running
check_resolve_running() {
ps -ef | grep -i "[D]aVinci Resolve" > /dev/null
return $?
}
if ! check_resolve_running; then
echo "⚠️ DaVinci Resolve is not running. Please start it before continuing."
read -p "Start testing anyway? (y/n): " continue_anyway
if [[ "$continue_anyway" != "y" ]]; then
echo "Aborting test."
exit 1
fi
echo "Continuing with testing despite DaVinci Resolve not running..."
fi
# Step 1: Restart the server using the restart script
echo "Step 1: Restarting DaVinci Resolve MCP Server..."
if [ -f "./restart-server.sh" ]; then
./restart-server.sh
# Check if restart was successful
sleep 3
pgrep -f "python.*resolve_mcp_server.py" > /dev/null
if [ $? -eq 0 ]; then
echo "✅ Server restart successful"
else
echo "❌ Server restart failed. Please check server logs for errors."
exit 1
fi
else
echo "❌ restart-server.sh not found. Cannot restart server."
exit 1
fi
# Step 2: Create test timeline (optional)
echo
echo "Step 2: Create test timeline with media?"
read -p "Create test timeline? (y/n): " create_timeline
if [[ "$create_timeline" == "y" ]]; then
echo "Creating test timeline..."
if [ -f "./create_test_timeline.py" ]; then
python3 ./create_test_timeline.py
if [ $? -ne 0 ]; then
echo "⚠️ Test timeline creation had issues, but we'll continue with testing."
fi
else
echo "❌ create_test_timeline.py not found. Skipping test timeline creation."
fi
else
echo "Skipping test timeline creation."
fi
# Step 3: Run automated tests
echo
echo "Step 3: Running automated tests..."
if [ -f "./test_improvements.py" ]; then
python3 ./test_improvements.py
TEST_RESULT=$?
if [ $TEST_RESULT -eq 0 ]; then
echo "✅ All tests passed!"
else
echo "⚠️ Some tests failed. Check the logs for details."
fi
else
echo "❌ test_improvements.py not found. Cannot run tests."
exit 1
fi
echo
echo "========================================================"
echo "Testing complete. Results logged to mcp_test_results.log"
echo "========================================================"
exit $TEST_RESULT
```
--------------------------------------------------------------------------------
/scripts/create-release-zip.bat:
--------------------------------------------------------------------------------
```
@echo off
REM create-release-zip.bat
REM Script to create a versioned zip file for distribution on Windows
setlocal EnableDelayedExpansion
REM Colors for terminal output
set GREEN=[92m
set YELLOW=[93m
set BLUE=[94m
set RED=[91m
set NC=[0m
REM Get the directory where this script is located
set "SCRIPT_DIR=%~dp0"
set "PROJECT_ROOT=%SCRIPT_DIR%.."
REM Get version from VERSION.md
for /f "tokens=3" %%i in ('findstr /B /C:"Current Version:" "%PROJECT_ROOT%\docs\VERSION.md"') do (
set "VERSION=%%i"
goto :version_found
)
:version_found
if "%VERSION%"=="" (
echo %RED%Error: Could not determine version from VERSION.md%NC%
exit /b 1
)
REM Create filename with version
set "ZIP_FILE=davinci-resolve-mcp-v%VERSION%.zip"
set "DIST_DIR=%PROJECT_ROOT%\dist"
set "ZIP_PATH=%DIST_DIR%\%ZIP_FILE%"
REM Ensure dist directory exists
if not exist "%DIST_DIR%" mkdir "%DIST_DIR%"
echo %BLUE%=================================================%NC%
echo %BLUE% Creating Release Zip for DaVinci Resolve MCP %NC%
echo %BLUE%=================================================%NC%
echo %YELLOW%Version: %VERSION%%NC%
echo %YELLOW%Output file: %ZIP_FILE%%NC%
echo %YELLOW%Output directory: %DIST_DIR%%NC%
echo.
REM Change to project root directory
cd /d "%PROJECT_ROOT%" || exit /b 1
REM Check if 7-Zip is installed
where 7z >nul 2>&1
if %ERRORLEVEL% neq 0 (
echo %YELLOW%7-Zip not found, using PowerShell to create zip file%NC%
REM Create temporary file list
git ls-files > filelist.txt
git ls-files --others --exclude-standard >> filelist.txt
REM Use PowerShell to create the zip file
powershell -Command "Add-Type -Assembly System.IO.Compression.FileSystem; $zipFile = [System.IO.Compression.ZipFile]::Open('%ZIP_PATH%', [System.IO.Compression.ZipArchiveMode]::Create); Get-Content filelist.txt | ForEach-Object { if (Test-Path -Path $_ -PathType Leaf) { $file = $_; $entry = $zipFile.CreateEntry($file); $stream = $entry.Open(); $bytes = [System.IO.File]::ReadAllBytes($file); $stream.Write($bytes, 0, $bytes.Length); $stream.Close() } }; $zipFile.Dispose()"
REM Remove temporary file list
del filelist.txt
) else (
echo %YELLOW%Using 7-Zip to create zip file...%NC%
REM Create temporary file list
git ls-files > filelist.txt
git ls-files --others --exclude-standard >> filelist.txt
REM Use 7-Zip to create the zip file
7z a -tzip "%ZIP_PATH%" @filelist.txt
REM Remove temporary file list
del filelist.txt
)
REM Check if the zip file was created successfully
if exist "%ZIP_PATH%" (
echo %GREEN%Successfully created release zip: %ZIP_PATH%%NC%
) else (
echo %RED%Failed to create release zip%NC%
exit /b 1
)
echo %GREEN%Release zip created successfully!%NC%
exit /b 0
```
--------------------------------------------------------------------------------
/src/utils/platform.py:
--------------------------------------------------------------------------------
```python
#!/usr/bin/env python3
"""
Platform-specific functionality for DaVinci Resolve MCP Server
"""
import os
import sys
import platform
def get_platform():
"""Identify the current operating system platform.
Returns:
str: 'windows', 'darwin' (macOS), or 'linux'
"""
system = platform.system().lower()
if system == 'darwin':
return 'darwin'
elif system == 'windows':
return 'windows'
elif system == 'linux':
return 'linux'
return system
def get_resolve_paths():
"""Get platform-specific paths for DaVinci Resolve scripting API.
Returns:
dict: Dictionary containing api_path, lib_path, and modules_path
"""
platform_name = get_platform()
if platform_name == 'darwin': # macOS
api_path = "/Library/Application Support/Blackmagic Design/DaVinci Resolve/Developer/Scripting"
lib_path = "/Applications/DaVinci Resolve/DaVinci Resolve.app/Contents/Libraries/Fusion/fusionscript.so"
modules_path = os.path.join(api_path, "Modules")
elif platform_name == 'windows': # Windows
program_files = os.environ.get('PROGRAMDATA', 'C:\\ProgramData')
program_files_64 = os.environ.get('PROGRAMFILES', 'C:\\Program Files')
api_path = os.path.join(program_files, 'Blackmagic Design', 'DaVinci Resolve', 'Support', 'Developer', 'Scripting')
lib_path = os.path.join(program_files_64, 'Blackmagic Design', 'DaVinci Resolve', 'fusionscript.dll')
modules_path = os.path.join(api_path, "Modules")
elif platform_name == 'linux': # Linux (not fully implemented)
# Default locations for Linux - these may need to be adjusted
api_path = "/opt/resolve/Developer/Scripting"
lib_path = "/opt/resolve/libs/fusionscript.so"
modules_path = os.path.join(api_path, "Modules")
else:
# Fallback to macOS paths if unknown platform
api_path = "/Library/Application Support/Blackmagic Design/DaVinci Resolve/Developer/Scripting"
lib_path = "/Applications/DaVinci Resolve/DaVinci Resolve.app/Contents/Libraries/Fusion/fusionscript.so"
modules_path = os.path.join(api_path, "Modules")
return {
"api_path": api_path,
"lib_path": lib_path,
"modules_path": modules_path
}
def setup_environment():
"""Set up environment variables for DaVinci Resolve scripting.
Returns:
bool: True if setup was successful, False otherwise
"""
try:
paths = get_resolve_paths()
os.environ["RESOLVE_SCRIPT_API"] = paths["api_path"]
os.environ["RESOLVE_SCRIPT_LIB"] = paths["lib_path"]
# Add modules path to Python's path if it's not already there
if paths["modules_path"] not in sys.path:
sys.path.append(paths["modules_path"])
return True
except Exception as e:
print(f"Error setting up environment: {str(e)}")
return False
```
--------------------------------------------------------------------------------
/src/utils/resolve_connection.py:
--------------------------------------------------------------------------------
```python
#!/usr/bin/env python3
"""
DaVinci Resolve Connection Utilities
"""
import os
import logging
from .platform import get_platform, get_resolve_paths, setup_environment
logger = logging.getLogger("davinci-resolve-mcp.connection")
def initialize_resolve():
"""Initialize connection to DaVinci Resolve application."""
try:
# Import the DaVinci Resolve scripting module
import DaVinciResolveScript as dvr_script
# Get the resolve object
resolve = dvr_script.scriptapp("Resolve")
if resolve is None:
logger.error("Failed to get Resolve object. Is DaVinci Resolve running?")
return None
logger.info(f"Connected to DaVinci Resolve: {resolve.GetProductName()} {resolve.GetVersionString()}")
return resolve
except ImportError:
platform_name = get_platform()
paths = get_resolve_paths()
logger.error("Failed to import DaVinciResolveScript. Check environment variables.")
logger.error("RESOLVE_SCRIPT_API, RESOLVE_SCRIPT_LIB, and PYTHONPATH must be set correctly.")
if platform_name == 'darwin':
logger.error("On macOS, typically:")
logger.error(f'export RESOLVE_SCRIPT_API="{paths["api_path"]}"')
logger.error(f'export RESOLVE_SCRIPT_LIB="{paths["lib_path"]}"')
logger.error(f'export PYTHONPATH="$PYTHONPATH:{paths["modules_path"]}"')
elif platform_name == 'windows':
logger.error("On Windows, typically:")
logger.error(f'set RESOLVE_SCRIPT_API={paths["api_path"]}')
logger.error(f'set RESOLVE_SCRIPT_LIB={paths["lib_path"]}')
logger.error(f'set PYTHONPATH=%PYTHONPATH%;{paths["modules_path"]}')
elif platform_name == 'linux':
logger.error("On Linux, typically:")
logger.error(f'export RESOLVE_SCRIPT_API="{paths["api_path"]}"')
logger.error(f'export RESOLVE_SCRIPT_LIB="{paths["lib_path"]}"')
logger.error(f'export PYTHONPATH="$PYTHONPATH:{paths["modules_path"]}"')
return None
except Exception as e:
logger.error(f"Unexpected error initializing Resolve: {str(e)}")
return None
def check_environment_variables():
"""Check if the required environment variables are set."""
resolve_script_api = os.environ.get("RESOLVE_SCRIPT_API")
resolve_script_lib = os.environ.get("RESOLVE_SCRIPT_LIB")
missing_vars = []
if not resolve_script_api:
missing_vars.append("RESOLVE_SCRIPT_API")
if not resolve_script_lib:
missing_vars.append("RESOLVE_SCRIPT_LIB")
return {
"all_set": len(missing_vars) == 0,
"missing": missing_vars,
"resolve_script_api": resolve_script_api,
"resolve_script_lib": resolve_script_lib
}
def set_default_environment_variables():
"""Set the default environment variables based on platform."""
return setup_environment()
```
--------------------------------------------------------------------------------
/docs/COMMIT_MESSAGE.txt:
--------------------------------------------------------------------------------
```
Version 1.3.6 - Feature Consolidation and Project Restructuring
ADDED:
- Consolidated extensive feature additions into version 1.3.6:
- Complete MediaPoolItem and Folder object functionality
- Cache Management implementation
- Timeline Item Properties implementation
- Keyframe Control implementation
- Color Preset Management implementation
- LUT Export functionality
CHANGED:
- Major project directory restructuring:
- Moved documentation files to docs/ directory
- Moved test scripts to scripts/tests/ directory
- Moved configuration templates to config-templates/ directory
- Moved utility scripts to scripts/ directory
- Updated all scripts to work with the new directory structure
- Created simpler launcher scripts in the root directory
- Updated version number to 1.3.6 across all relevant files
- Reorganized changelog to consolidate planned features
- Enhanced documentation for better readability
FIXED:
- Path references in scripts to ensure cross-platform compatibility
- Launcher scripts to use the correct paths after restructuring
feat: Comprehensive reliability enhancements, testing tools, and documentation
This commit introduces several key improvements to the DaVinci Resolve MCP Server:
1. Color Page Operations:
- Added automatic clip selection with ensure_clip_selected helper function
- Improved error handling for color operations
- Enhanced error messages with actionable guidance
- Added fallback mechanisms for clip selection
2. Render Queue Operations:
- Added ensure_render_settings helper function
- Created validate_render_preset for better preset validation
- Implemented retry logic with progressive approaches
- Enhanced error reporting throughout render operations
3. Parameter Validation:
- Modified set_project_setting to accept Any type
- Added type conversion between strings and numbers
- Improved type validation with better error messages
- Updated imports for modern type handling
4. Testing Tools:
- Created test_improvements.py automated test script
- Added create_test_timeline.py environment generator
- Developed test-after-restart.sh/.bat combined testing scripts
- Implemented cross-platform testing frameworks
5. Documentation:
- Updated FEATURES.md with implementation status
- Added detailed testing results and next steps
- Created restart scripts for macOS/Linux and Windows
- Added comprehensive troubleshooting guide
- Created development best practices guide for future contributors
6. Server Management:
- Created restart-server.sh and restart-server.bat for easier server management
- Added automatic server detection and process management
- Improved environment validation during server startup
These improvements significantly enhance the reliability and maintainability of the MCP server, with particular focus on automatic recovery from common error states, providing clear, actionable error messages to users, and ensuring proper testing methodology.
NOTE: The server must be restarted to apply these changes.
```
--------------------------------------------------------------------------------
/scripts/run-now.sh:
--------------------------------------------------------------------------------
```bash
#!/bin/bash
# Quick setup script to get DaVinci Resolve MCP Server running
# Colors for terminal output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
NC='\033[0m' # No Color
# Get the directory where this script is located
SCRIPT_PATH="$(readlink -f "$0")"
SCRIPT_DIR="$(dirname "$SCRIPT_PATH")"
ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
VENV_DIR="$ROOT_DIR/venv"
SERVER_PATH="$ROOT_DIR/src/resolve_mcp_server.py"
echo -e "${GREEN}Setting up DaVinci Resolve MCP Server with virtual environment...${NC}"
echo -e "${YELLOW}Project root: $ROOT_DIR${NC}"
# Create and activate virtual environment
if [ ! -d "$VENV_DIR" ]; then
echo -e "${YELLOW}Creating Python virtual environment...${NC}"
python3 -m venv "$VENV_DIR"
fi
# Install dependencies from requirements.txt
echo -e "${YELLOW}Installing dependencies from requirements.txt...${NC}"
"$VENV_DIR/bin/pip" install -r "$ROOT_DIR/requirements.txt"
# Source environment variables from .zshrc if they exist
if grep -q "RESOLVE_SCRIPT_API" "$HOME/.zshrc"; then
echo -e "${YELLOW}Sourcing environment variables from .zshrc...${NC}"
source "$HOME/.zshrc"
else
echo -e "${YELLOW}Setting environment variables...${NC}"
export RESOLVE_SCRIPT_API="/Library/Application Support/Blackmagic Design/DaVinci Resolve/Developer/Scripting"
export RESOLVE_SCRIPT_LIB="/Applications/DaVinci Resolve/DaVinci Resolve.app/Contents/Libraries/Fusion/fusionscript.so"
export PYTHONPATH="$PYTHONPATH:$RESOLVE_SCRIPT_API/Modules/"
fi
# Make the server script executable
if [ -f "$SERVER_PATH" ]; then
echo -e "${YELLOW}Making server script executable...${NC}"
chmod +x "$SERVER_PATH"
else
echo -e "${RED}Error: Server script not found at $SERVER_PATH${NC}"
exit 1
fi
# Check if DaVinci Resolve is running
if ps -ef | grep -i "[D]aVinci Resolve" > /dev/null; then
echo -e "${GREEN}✓ DaVinci Resolve is running${NC}"
else
echo -e "${RED}✗ DaVinci Resolve is not running${NC}"
echo -e "${YELLOW}Please start DaVinci Resolve before continuing${NC}"
echo -e "${YELLOW}Waiting 10 seconds for you to start DaVinci Resolve...${NC}"
sleep 10
if ! ps -ef | grep -i "[D]aVinci Resolve" > /dev/null; then
echo -e "${RED}DaVinci Resolve still not running. Please start it manually.${NC}"
echo -e "${YELLOW}You can run this script again after starting DaVinci Resolve.${NC}"
exit 1
fi
echo -e "${GREEN}✓ DaVinci Resolve is now running${NC}"
fi
# Check if MCP command exists in the virtual environment
if [ ! -f "$VENV_DIR/bin/mcp" ]; then
echo -e "${RED}MCP command not found. Installing MCP[cli]...${NC}"
"$VENV_DIR/bin/pip" install "mcp[cli]"
if [ ! -f "$VENV_DIR/bin/mcp" ]; then
echo -e "${RED}Failed to install MCP. Please check your internet connection and try again.${NC}"
exit 1
fi
fi
# Run the server with the virtual environment's Python
echo -e "${GREEN}Starting DaVinci Resolve MCP Server...${NC}"
echo -e "${YELLOW}Using server script: $SERVER_PATH${NC}"
echo ""
cd "$ROOT_DIR"
"$VENV_DIR/bin/mcp" dev "$SERVER_PATH"
```
--------------------------------------------------------------------------------
/examples/markers/test_marker_frames.py:
--------------------------------------------------------------------------------
```python
#!/usr/bin/env python3
"""
Test Marker Frame Placement Script
This script demonstrates and tests the enhanced marker functionality in DaVinci Resolve.
It adds markers at different frame positions, including automatic frame selection,
to validate the marker functionality works correctly with various inputs.
Example Usage:
python test_marker_frames.py
The script will:
1. Connect to DaVinci Resolve
2. Test adding markers at different frame positions
3. Include automatic frame selection when no frame is specified
4. Output the results of each marker operation
"""
import os
import sys
import time
# Add the project root to the Python path
script_dir = os.path.dirname(os.path.abspath(__file__))
project_root = os.path.abspath(os.path.join(script_dir, '../..'))
sys.path.append(project_root)
# Set environment variables for DaVinci Resolve scripting
RESOLVE_API_PATH = "/Library/Application Support/Blackmagic Design/DaVinci Resolve/Developer/Scripting"
RESOLVE_LIB_PATH = "/Applications/DaVinci Resolve/DaVinci Resolve.app/Contents/Libraries/Fusion/fusionscript.so"
RESOLVE_MODULES_PATH = os.path.join(RESOLVE_API_PATH, "Modules")
os.environ["RESOLVE_SCRIPT_API"] = RESOLVE_API_PATH
os.environ["RESOLVE_SCRIPT_LIB"] = RESOLVE_LIB_PATH
sys.path.append(RESOLVE_MODULES_PATH)
# Import the timeline_operations module from the project
from src.api.timeline_operations import add_marker
# Import DaVinci Resolve scripting
import DaVinciResolveScript as dvr_script
def main():
"""Main function to test marker placement at different frames."""
# Connect to Resolve
resolve = dvr_script.scriptapp("Resolve")
if not resolve:
print("Error: Could not connect to DaVinci Resolve")
sys.exit(1)
print(f"Connected to {resolve.GetProductName()} {resolve.GetVersionString()}")
print("Testing marker placement at different frames...")
# Display current timeline information
project_manager = resolve.GetProjectManager()
current_project = project_manager.GetCurrentProject()
if not current_project:
print("Error: No project is currently open")
sys.exit(1)
current_timeline = current_project.GetCurrentTimeline()
if not current_timeline:
print("Error: No timeline is currently open")
sys.exit(1)
print(f"Current timeline: {current_timeline.GetName()}")
print(f"Timeline duration: {current_timeline.GetEndFrame()} frames")
# Test with different frames
# None = auto-selected frame, others are specific frame positions
test_frames = [None, 86450, 87000, 88000, 89000, 90000]
for frame in test_frames:
note = f"Test marker at {'auto-selected' if frame is None else frame}"
color = "Green" if frame is None else "Blue"
print(f"\nAttempting to add {color} marker at frame={frame or 'auto'} with note: '{note}'")
result = add_marker(resolve, frame, color, note)
print(f"Result: {result}")
# Small delay between operations
time.sleep(0.5)
print("\nMarker testing completed successfully!")
if __name__ == "__main__":
main()
```
--------------------------------------------------------------------------------
/docs/PROJECT_MCP_SETUP.md:
--------------------------------------------------------------------------------
```markdown
# Project-Specific DaVinci Resolve Integration with Cursor
This guide explains how to set up project-specific DaVinci Resolve integration with Cursor using MCP.
## Overview
Project-specific integration allows Cursor to interact with a specific DaVinci Resolve project automatically. When you open a Cursor project, it can automatically connect to a matching DaVinci Resolve project.
## Setup Steps
### 1. Copy the Template
Create a new file called `mcp.json` in your Cursor project's root directory (not in the `.cursor` folder). Copy the contents from `mcp-project-template.json`:
```json
{
"mcpServers": {
"davinci-resolve": {
"name": "DaVinci Resolve Project-Specific",
"command": "${PROJECT_ROOT}/mcp_resolve-cursor_start",
"args": ["--project", "${PROJECT_NAME}"]
}
}
}
```
### 2. Copy the Script
Copy the `mcp_resolve-cursor_start` script to your project root:
```bash
cp /path/to/davinci-resolve-mcp-20250326/mcp_resolve-cursor_start /path/to/your/project/
```
Also copy the `run-direct-server.sh` and `direct_resolve_server.py` files:
```bash
cp /path/to/davinci-resolve-mcp-20250326/run-direct-server.sh /path/to/your/project/
cp /path/to/davinci-resolve-mcp-20250326/direct_resolve_server.py /path/to/your/project/
```
Make them executable:
```bash
chmod +x /path/to/your/project/mcp_resolve-cursor_start
chmod +x /path/to/your/project/run-direct-server.sh
chmod +x /path/to/your/project/direct_resolve_server.py
```
### 3. Create a Python Virtual Environment
```bash
cd /path/to/your/project/
python -m venv venv
source venv/bin/activate
pip install jsonrpcserver
```
### 4. Modify Variable Replacement
By default, Cursor will replace:
- `${PROJECT_ROOT}` with the absolute path to your project
- `${PROJECT_NAME}` with the name of your project folder
If your DaVinci Resolve project has a different name than your Cursor project folder, you'll need to manually edit the `mcp.json` file in your project to specify the correct project name:
```json
{
"mcpServers": {
"davinci-resolve": {
"name": "DaVinci Resolve Project-Specific",
"command": "${PROJECT_ROOT}/mcp_resolve-cursor_start",
"args": ["--project", "Your DaVinci Resolve Project Name"]
}
}
}
```
## Troubleshooting
1. **Make sure DaVinci Resolve is running** before you start Cursor or open your project.
2. **Check the log files** for errors:
- `cursor_resolve_server.log` - Created by the startup script
- `resolve_direct_server.log` - Created by the direct server
3. **Verify project exists** - Make sure the project name specified in your `mcp.json` exists in DaVinci Resolve.
4. **Permission issues** - Ensure all scripts are executable and have the right permissions.
5. **Test manually** by running:
```bash
cd /path/to/your/project/
./mcp_resolve-cursor_start --project "Your Project Name"
```
## Advanced Configuration
If you need additional arguments or setup for your project integration, you can modify:
1. The `mcp.json` file in your project to add more arguments
2. The `mcp_resolve-cursor_start` script to include custom setup steps
## Support
For further assistance, please refer to the main documentation or reach out to the development team.
```
--------------------------------------------------------------------------------
/examples/getting_started.py:
--------------------------------------------------------------------------------
```python
#!/usr/bin/env python3
"""
Getting Started Example for DaVinci Resolve MCP
This example demonstrates the basics of connecting to DaVinci Resolve via MCP.
It shows how to:
1. Check if DaVinci Resolve is running
2. Get the current project information
3. List available timelines
4. Get the current page
Prerequisites:
- DaVinci Resolve must be running
- The MCP server must be properly set up
- A project should be open in DaVinci Resolve
"""
import os
import sys
import json
import time
from mcp.client import Client
# Connect to the MCP server
def connect_to_mcp_server():
"""Connect to the MCP server and return the client."""
print("Connecting to DaVinci Resolve MCP server...")
client = Client()
client.connect_to_local_server("DaVinciResolveMCP")
return client
# Get DaVinci Resolve version
def get_resolve_version(client):
"""Get the version of DaVinci Resolve."""
print("\n--- DaVinci Resolve Version ---")
response = client.resource("resolve://version")
print(f"DaVinci Resolve Version: {response}")
return response
# Get current page
def get_current_page(client):
"""Get the current page in DaVinci Resolve (Edit, Color, etc.)."""
print("\n--- Current Page ---")
response = client.resource("resolve://current-page")
print(f"Current Page: {response}")
return response
# List projects
def list_projects(client):
"""List all available projects in DaVinci Resolve."""
print("\n--- Available Projects ---")
response = client.resource("resolve://projects")
if isinstance(response, list):
if len(response) > 0:
for i, project in enumerate(response, 1):
print(f"{i}. {project}")
else:
print("No projects found.")
else:
print(f"Error: {response}")
return response
# Get current project
def get_current_project(client):
"""Get the name of the currently open project."""
print("\n--- Current Project ---")
response = client.resource("resolve://current-project")
print(f"Current Project: {response}")
return response
# List timelines
def list_timelines(client):
"""List all timelines in the current project."""
print("\n--- Available Timelines ---")
response = client.resource("resolve://timelines")
if isinstance(response, list):
if len(response) > 0:
for i, timeline in enumerate(response, 1):
print(f"{i}. {timeline}")
else:
print("No timelines found.")
else:
print(f"Error: {response}")
return response
# Main function
def main():
"""Main function to demonstrate basic DaVinci Resolve MCP functionality."""
try:
# Connect to the MCP server
client = connect_to_mcp_server()
print("Connected to MCP server!")
# Get DaVinci Resolve version
get_resolve_version(client)
# Get current page
get_current_page(client)
# List projects
list_projects(client)
# Get current project
get_current_project(client)
# List timelines
list_timelines(client)
print("\nGetting Started Example completed successfully!")
except Exception as e:
print(f"Error: {str(e)}")
print("\nTroubleshooting tips:")
print("1. Make sure DaVinci Resolve is running")
print("2. Check that the MCP server is running (`./run-now.sh`)")
print("3. Ensure a project is open in DaVinci Resolve")
print("4. Check environment variables are set correctly")
return 1
return 0
if __name__ == "__main__":
sys.exit(main())
```
--------------------------------------------------------------------------------
/src/api/project_operations.py:
--------------------------------------------------------------------------------
```python
#!/usr/bin/env python3
"""
DaVinci Resolve Project Operations
"""
import logging
from typing import List, Dict, Any
logger = logging.getLogger("davinci-resolve-mcp.project")
def list_projects(resolve) -> List[str]:
"""List all available projects in the current database."""
if resolve is None:
return ["Error: Not connected to DaVinci Resolve"]
project_manager = resolve.GetProjectManager()
if not project_manager:
return ["Error: Failed to get Project Manager"]
projects = project_manager.GetProjectListInCurrentFolder()
# Filter out any empty strings that might be in the list
return [p for p in projects if p]
def get_current_project_name(resolve) -> str:
"""Get the name of the currently open project."""
if resolve is None:
return "Error: Not connected to DaVinci Resolve"
project_manager = resolve.GetProjectManager()
if not project_manager:
return "Error: Failed to get Project Manager"
current_project = project_manager.GetCurrentProject()
if not current_project:
return "No project currently open"
return current_project.GetName()
def open_project(resolve, name: str) -> str:
"""Open a project by name."""
if resolve is None:
return "Error: Not connected to DaVinci Resolve"
if not name:
return "Error: Project name cannot be empty"
project_manager = resolve.GetProjectManager()
if not project_manager:
return "Error: Failed to get Project Manager"
# Check if project exists
projects = project_manager.GetProjectListInCurrentFolder()
if name not in projects:
return f"Error: Project '{name}' not found. Available projects: {', '.join(projects)}"
result = project_manager.LoadProject(name)
if result:
return f"Successfully opened project '{name}'"
else:
return f"Failed to open project '{name}'"
def create_project(resolve, name: str) -> str:
"""Create a new project with the given name."""
if resolve is None:
return "Error: Not connected to DaVinci Resolve"
if not name:
return "Error: Project name cannot be empty"
project_manager = resolve.GetProjectManager()
if not project_manager:
return "Error: Failed to get Project Manager"
# Check if project already exists
projects = project_manager.GetProjectListInCurrentFolder()
if name in projects:
return f"Error: Project '{name}' already exists"
result = project_manager.CreateProject(name)
if result:
return f"Successfully created project '{name}'"
else:
return f"Failed to create project '{name}'"
def save_project(resolve) -> str:
"""Save the current project."""
if resolve is None:
return "Error: Not connected to DaVinci Resolve"
project_manager = resolve.GetProjectManager()
if not project_manager:
return "Error: Failed to get Project Manager"
current_project = project_manager.GetCurrentProject()
if not current_project:
return "Error: No project currently open"
# DaVinci Resolve auto-saves projects, but we can perform an operation
# that forces a save, like creating a temp timeline and then removing it
project_name = current_project.GetName()
try:
# Get media pool to trigger a save indirectly
media_pool = current_project.GetMediaPool()
if not media_pool:
return "Project is likely already saved (auto-save enabled)"
# Another approach: DaVinci Resolve auto-saves, so we can just confirm the project exists
return f"Project '{project_name}' is saved (auto-save enabled in DaVinci Resolve)"
except Exception as e:
return f"Error checking project: {str(e)}"
```
--------------------------------------------------------------------------------
/scripts/resolve_mcp_server.py:
--------------------------------------------------------------------------------
```python
#!/usr/bin/env python3
"""
DaVinci Resolve MCP Server
A server that connects to DaVinci Resolve via the Model Context Protocol (MCP)
"""
import os
import sys
import logging
from typing import List, Dict, Any, Optional
from mcp.server.fastmcp import FastMCP
# Configure logging
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
handlers=[logging.StreamHandler()]
)
logger = logging.getLogger("davinci-resolve-mcp")
# Create MCP server instance
mcp = FastMCP("DaVinciResolveMCP")
# Initialize connection to DaVinci Resolve
def initialize_resolve():
"""Initialize connection to DaVinci Resolve application."""
try:
# Import the DaVinci Resolve scripting module
import DaVinciResolveScript as dvr_script
# Get the resolve object
resolve = dvr_script.scriptapp("Resolve")
if resolve is None:
logger.error("Failed to get Resolve object. Is DaVinci Resolve running?")
return None
logger.info(f"Connected to DaVinci Resolve: {resolve.GetProductName()} {resolve.GetVersionString()}")
return resolve
except ImportError:
logger.error("Failed to import DaVinciResolveScript. Check environment variables.")
logger.error("RESOLVE_SCRIPT_API, RESOLVE_SCRIPT_LIB, and PYTHONPATH must be set correctly.")
logger.error("On macOS, typically:")
logger.error('export RESOLVE_SCRIPT_API="/Library/Application Support/Blackmagic Design/DaVinci Resolve/Developer/Scripting"')
logger.error('export RESOLVE_SCRIPT_LIB="/Applications/DaVinci Resolve/DaVinci Resolve.app/Contents/Libraries/Fusion/fusionscript.so"')
logger.error('export PYTHONPATH="$PYTHONPATH:$RESOLVE_SCRIPT_API/Modules/"')
return None
except Exception as e:
logger.error(f"Unexpected error initializing Resolve: {str(e)}")
return None
# Initialize Resolve once at startup
resolve = initialize_resolve()
# ------------------
# MCP Tools/Resources
# ------------------
@mcp.resource("resolve://version")
def get_resolve_version() -> str:
"""Get DaVinci Resolve version information."""
if resolve is None:
return "Error: Not connected to DaVinci Resolve"
return f"{resolve.GetProductName()} {resolve.GetVersionString()}"
@mcp.resource("resolve://current-page")
def get_current_page() -> str:
"""Get the current page open in DaVinci Resolve (Edit, Color, Fusion, etc.)."""
if resolve is None:
return "Error: Not connected to DaVinci Resolve"
return resolve.GetCurrentPage()
@mcp.tool()
def switch_page(page: str) -> str:
"""Switch to a specific page in DaVinci Resolve.
Args:
page: The page to switch to. Options: 'media', 'cut', 'edit', 'fusion', 'color', 'fairlight', 'deliver'
"""
if resolve is None:
return "Error: Not connected to DaVinci Resolve"
valid_pages = ['media', 'cut', 'edit', 'fusion', 'color', 'fairlight', 'deliver']
page = page.lower()
if page not in valid_pages:
return f"Error: Invalid page. Choose from {', '.join(valid_pages)}"
resolve.OpenPage(page.capitalize())
return f"Successfully switched to {page} page"
# Start the server
if __name__ == "__main__":
try:
if resolve is None:
logger.error("Server started but not connected to DaVinci Resolve.")
logger.error("Make sure DaVinci Resolve is running and environment variables are correctly set.")
else:
logger.info("Successfully connected to DaVinci Resolve.")
logger.info("Starting DaVinci Resolve MCP Server")
mcp.run()
except KeyboardInterrupt:
logger.info("Server shutdown requested")
except Exception as e:
logger.error(f"Server error: {str(e)}")
sys.exit(1)
```
--------------------------------------------------------------------------------
/docs/TOOLS_README.md:
--------------------------------------------------------------------------------
```markdown
# DaVinci Resolve MCP Server Tools
This directory contains utilities for working with the DaVinci Resolve MCP Server:
- **benchmark_server.py**: Performance testing tool
- **batch_automation.py**: Workflow automation script
- **sample_config.json**: Example configuration file
## Benchmark Server
The benchmarking tool measures MCP server performance and reliability, helping identify bottlenecks and verify improvements.
### Features
- Measures response time for various operations
- Tracks success rates across multiple iterations
- Provides statistical analysis (min/max/avg/median/std dev)
- Monitors resource usage (memory, CPU, threads)
- Generates detailed logs and JSON reports
### Usage
```bash
python benchmark_server.py [--iterations=N] [--delay=SECONDS]
```
### Requirements
- DaVinci Resolve must be running with a project open
- DaVinci Resolve MCP Server must be running
- Python packages: `requests`, `psutil` (install with `pip install requests psutil`)
### Output
The tool generates:
1. A timestamped log file (`mcp_benchmark_*.log`)
2. A JSON results file (`benchmark_results_*.json`)
3. Console output with summary statistics
### Example Output
```
BENCHMARK SUMMARY
==================================================
Overall average response time: 154.32ms
Overall success rate: 97.5%
Operations ranked by speed (fastest first):
Switch to Edit Page: 98.45ms
Get Current Page: 102.78ms
List Timelines: 142.33ms
Project Settings - String: 188.92ms
Project Settings - Integer: 192.56ms
Clear Render Queue: 200.91ms
Resource usage change during benchmark:
Memory: 5.24MB
CPU: 2.3%
threads: 0
connections: 1
==================================================
```
## Batch Automation
The batch automation script demonstrates how to automate common DaVinci Resolve workflows using the MCP server.
### Available Workflows
- **color_grade**: Apply basic color grading to all clips
- **render_timeline**: Render a timeline with specific settings
- **organize_media**: Organize media into bins by type
### Usage
```bash
python batch_automation.py [--workflow=NAME] [--config=FILE]
```
Where:
- `--workflow` is one of: `color_grade`, `render_timeline`, `organize_media`
- `--config` is an optional path to a JSON configuration file
### Configuration
You can customize workflows by providing a JSON configuration file. See `sample_config.json` for an example.
Key configuration options:
- `project_name`: Name of the project to create or open
- `timeline_name`: Name of the timeline to use
- `media_files`: Array of file paths to import
- `render_preset`: Render preset to use
- Various settings for color correction, project settings, etc.
### Example Workflow: Color Grade
This workflow:
1. Creates or opens a project
2. Creates a timeline
3. Imports media files (if specified)
4. Switches to the color page
5. Adds a primary correction node with warm midtones
6. Adds a contrast node
7. Saves the project
### Example Workflow: Render Timeline
This workflow:
1. Creates or opens a project
2. Creates or selects a timeline
3. Imports media (for new timelines only)
4. Sets project settings
5. Switches to the deliver page
6. Clears the render queue
7. Adds the timeline to the render queue
8. Starts rendering
### Extending
You can create new workflows by adding methods to the `WorkflowManager` class:
```python
def run_workflow_custom(self) -> None:
"""My custom workflow."""
# Implement workflow steps here
# ...
# Then add it to the workflows dictionary:
workflows = {
"color_grade": self.run_workflow_color_grade,
"render_timeline": self.run_workflow_render_timeline,
"organize_media": self.run_workflow_organize_media,
"custom": self.run_workflow_custom
}
```
## Best Practices
- Always test workflows with sample data before using with production content
- Keep DaVinci Resolve open and with a project loaded before running tools
- Check the MCP server logs if operations fail
- Use the benchmark tool to identify slow operations
- Consider adding delays between operations if reliability issues occur
- Review logs after automation runs to identify any issues
```
--------------------------------------------------------------------------------
/scripts/verify-installation.bat:
--------------------------------------------------------------------------------
```
@echo off
REM verify-installation.bat
REM Script to verify that the DaVinci Resolve MCP installation has been properly set up
title DaVinci Resolve MCP Installation Verification
REM Colors for terminal output
set GREEN=[92m
set YELLOW=[93m
set BLUE=[94m
set RED=[91m
set NC=[0m
REM Get the script directory and project root
set "SCRIPT_DIR=%~dp0"
set "PROJECT_ROOT=%SCRIPT_DIR%.."
set "VENV_DIR=%PROJECT_ROOT%\venv"
echo %BLUE%===============================================%NC%
echo %BLUE% DaVinci Resolve MCP Installation Verification %NC%
echo %BLUE%===============================================%NC%
REM Check if virtual environment exists
echo %YELLOW%Checking Python virtual environment... %NC%
if exist "%VENV_DIR%\Scripts\python.exe" (
echo %GREEN%OK%NC%
set /a "venv_check=1"
) else (
echo %RED%MISSING%NC%
echo %RED%Virtual environment not found at: %VENV_DIR%%NC%
set /a "venv_check=0"
)
REM Check if MCP SDK is installed
echo %YELLOW%Checking MCP SDK installation... %NC%
"%VENV_DIR%\Scripts\pip" list | findstr "mcp" > nul
if %ERRORLEVEL% == 0 (
echo %GREEN%OK%NC%
set /a "mcp_check=1"
) else (
echo %RED%MISSING%NC%
echo %RED%MCP SDK not installed in the virtual environment%NC%
set /a "mcp_check=0"
)
REM Check if Resolve MCP server script exists
echo %YELLOW%Checking server script... %NC%
if exist "%PROJECT_ROOT%\src\resolve_mcp_server.py" (
echo %GREEN%OK%NC%
set /a "script_check=1"
) else (
echo %RED%MISSING%NC%
echo %RED%Server script not found at: %PROJECT_ROOT%\src\resolve_mcp_server.py%NC%
set /a "script_check=0"
)
REM Check if DaVinci Resolve is running
echo %YELLOW%Checking if DaVinci Resolve is running... %NC%
tasklist /FI "IMAGENAME eq Resolve.exe" 2>NUL | find /I /N "Resolve.exe">NUL
if %ERRORLEVEL% == 0 (
echo %GREEN%OK%NC%
set /a "resolve_check=1"
) else (
echo %RED%NOT RUNNING%NC%
echo %RED%DaVinci Resolve is not running - please start it%NC%
set /a "resolve_check=0"
)
REM Check Cursor MCP configuration
echo %YELLOW%Checking Cursor MCP configuration... %NC%
set "CURSOR_CONFIG_FILE=%APPDATA%\Cursor\mcp\config.json"
if exist "%CURSOR_CONFIG_FILE%" (
findstr "davinci-resolve" "%CURSOR_CONFIG_FILE%" > nul
if %ERRORLEVEL% == 0 (
echo %GREEN%OK%NC%
echo %GREEN%Cursor MCP config found at: %CURSOR_CONFIG_FILE%%NC%
set /a "cursor_check=1"
) else (
echo %RED%INVALID%NC%
echo %RED%Cursor MCP config does not contain 'davinci-resolve' entry%NC%
set /a "cursor_check=0"
)
) else (
echo %RED%MISSING%NC%
echo %RED%Cursor MCP config not found at: %CURSOR_CONFIG_FILE%%NC%
set /a "cursor_check=0"
)
REM Check if all environment variables are set
echo %YELLOW%Checking environment variables... %NC%
set /a "env_vars_missing=0"
if "%RESOLVE_SCRIPT_API%"=="" (
set /a "env_vars_missing=1"
)
if "%RESOLVE_SCRIPT_LIB%"=="" (
set /a "env_vars_missing=1"
)
if "%PYTHONPATH%"=="" (
set /a "env_vars_missing=1"
) else (
echo %PYTHONPATH% | findstr "Modules" > nul
if %ERRORLEVEL% NEQ 0 (
set /a "env_vars_missing=1"
)
)
if %env_vars_missing% == 0 (
echo %GREEN%OK%NC%
set /a "env_check=1"
) else (
echo %RED%MISSING%NC%
echo %RED%One or more required environment variables are not set%NC%
set /a "env_check=0"
)
REM Calculate total checks passed
set /a "total_checks=6"
set /a "passed_checks=venv_check+mcp_check+script_check+resolve_check+cursor_check+env_check"
echo %BLUE%=============================================%NC%
echo %YELLOW%Results: %passed_checks%/%total_checks% checks passed%NC%
if %passed_checks% == %total_checks% (
echo %GREEN%[✓] Installation verification completed successfully!%NC%
echo %GREEN%[✓] You can now use the MCP server with DaVinci Resolve%NC%
echo %YELLOW%To start the server, run:%NC%
echo %BLUE% run-now.bat%NC%
echo %YELLOW%Or for more options:%NC%
echo %BLUE% scripts\mcp_resolve-cursor_start%NC%
exit /b 0
) else (
echo %RED%[✗] Installation verification failed!%NC%
echo %YELLOW%Please fix the issues above and run this script again%NC%
exit /b 1
)
```
--------------------------------------------------------------------------------
/scripts/run-now.bat:
--------------------------------------------------------------------------------
```
@echo off
REM Quick Start Script for DaVinci Resolve MCP Server (Windows Version)
REM This script sets up the environment and starts the MCP server
echo ==============================================
echo DaVinci Resolve MCP Server - Quick Start
echo ==============================================
echo.
REM Get the script directory and root directory (using absolute paths)
set SCRIPT_DIR=%~dp0
set ROOT_DIR=%SCRIPT_DIR%..
echo Project root: %ROOT_DIR%
set VENV_DIR=%ROOT_DIR%venv
set RESOLVE_MCP_SERVER=%ROOT_DIR%src\resolve_mcp_server.py
REM Check if Python is installed
where python >nul 2>nul
if %ERRORLEVEL% NEQ 0 (
echo Python is not installed or not in your PATH
echo Please install Python 3.6+ from https://www.python.org/downloads/
echo Make sure to check "Add Python to PATH" during installation
pause
exit /b 1
)
REM Check if Node.js/npm is installed (warning only)
where npm >nul 2>nul
if %ERRORLEVEL% NEQ 0 (
echo WARNING: Node.js/npm is not installed or not in your PATH.
echo This might cause some features to not work properly.
echo You can install Node.js from https://nodejs.org/
echo Make sure to check the option to add to PATH during installation.
pause
)
REM Check if DaVinci Resolve is running - fixed process detection
echo Checking if DaVinci Resolve is running...
REM Simple check for Resolve process - avoid complex piping that causes syntax errors
tasklist /FI "IMAGENAME eq Resolve.exe" 2>nul | find /i "Resolve.exe" >nul
if not errorlevel 1 (
echo DaVinci Resolve is running, continuing...
goto :resolve_running
)
echo DaVinci Resolve is not running
echo Please start DaVinci Resolve before running this script
set /p START_RESOLVE="Would you like to try starting DaVinci Resolve now? (y/n): "
if /i not "%START_RESOLVE%"=="y" (
echo DaVinci Resolve must be running for the MCP server to function properly
pause
exit /b 1
)
REM Try to start DaVinci Resolve
echo Attempting to start DaVinci Resolve...
if exist "C:\Program Files\Blackmagic Design\DaVinci Resolve\Resolve.exe" (
echo Starting DaVinci Resolve from the correct path...
start "" "C:\Program Files\Blackmagic Design\DaVinci Resolve\Resolve.exe"
echo Waiting for DaVinci Resolve to start...
timeout /t 15 /nobreak >nul
echo DaVinci Resolve should be running now.
) else (
echo Could not find DaVinci Resolve executable at:
echo C:\Program Files\Blackmagic Design\DaVinci Resolve\Resolve.exe
echo Please start DaVinci Resolve manually
pause
exit /b 1
)
:resolve_running
REM Create virtual environment if it doesn't exist
if not exist "%VENV_DIR%\Scripts\python.exe" (
echo Creating Python virtual environment...
python -m venv "%VENV_DIR%"
if %ERRORLEVEL% NEQ 0 (
echo Failed to create virtual environment
pause
exit /b 1
)
)
REM Check if requirements.txt exists
if not exist "%ROOT_DIR%\requirements.txt" (
echo Error: Could not find requirements.txt at %ROOT_DIR%\requirements.txt
pause
exit /b 1
)
REM Install dependencies from requirements.txt
echo Installing dependencies from requirements.txt...
call "%VENV_DIR%\Scripts\pip" install -r "%ROOT_DIR%\requirements.txt"
REM Check if MCP CLI is installed
if not exist "%VENV_DIR%\Scripts\mcp.exe" (
echo MCP command not found. Installing MCP[cli]...
call "%VENV_DIR%\Scripts\pip" install "mcp[cli]"
if %ERRORLEVEL% NEQ 0 (
echo Failed to install MCP. Please check your internet connection and try again.
pause
exit /b 1
)
)
REM Set environment variables
echo Setting environment variables...
set RESOLVE_SCRIPT_API=C:\ProgramData\Blackmagic Design\DaVinci Resolve\Support\Developer\Scripting
set RESOLVE_SCRIPT_LIB=C:\Program Files\Blackmagic Design\DaVinci Resolve\fusionscript.dll
set PYTHONPATH=%PYTHONPATH%;%RESOLVE_SCRIPT_API%\Modules
REM Save environment variables for user
setx RESOLVE_SCRIPT_API "%RESOLVE_SCRIPT_API%" >nul
setx RESOLVE_SCRIPT_LIB "%RESOLVE_SCRIPT_LIB%" >nul
setx PYTHONPATH "%RESOLVE_SCRIPT_API%\Modules" >nul
REM Check if server script exists
if not exist "%RESOLVE_MCP_SERVER%" (
echo Error: Server script not found at %RESOLVE_MCP_SERVER%
pause
exit /b 1
)
REM Start the server
echo Starting DaVinci Resolve MCP Server...
echo Using server script: %RESOLVE_MCP_SERVER%
echo.
cd "%ROOT_DIR%"
"%VENV_DIR%\Scripts\mcp" dev "%RESOLVE_MCP_SERVER%"
```
--------------------------------------------------------------------------------
/examples/media/import_folder.py:
--------------------------------------------------------------------------------
```python
#!/usr/bin/env python3
"""
Script to import folder content, organize in a bin, and add to timeline
"""
import os
import sys
import glob
# Set environment variables for DaVinci Resolve scripting
RESOLVE_API_PATH = "/Library/Application Support/Blackmagic Design/DaVinci Resolve/Developer/Scripting"
RESOLVE_LIB_PATH = "/Applications/DaVinci Resolve/DaVinci Resolve.app/Contents/Libraries/Fusion/fusionscript.so"
RESOLVE_MODULES_PATH = os.path.join(RESOLVE_API_PATH, "Modules")
os.environ["RESOLVE_SCRIPT_API"] = RESOLVE_API_PATH
os.environ["RESOLVE_SCRIPT_LIB"] = RESOLVE_LIB_PATH
# Add the module path to Python's path if it's not already there
if RESOLVE_MODULES_PATH not in sys.path:
sys.path.append(RESOLVE_MODULES_PATH)
import DaVinciResolveScript as dvr_script
def main():
# Source folder path
source_folder = "/Users/samuelgursky/Desktop/20250326"
bin_name = os.path.basename(source_folder)
print(f"Importing from folder: {source_folder}")
print(f"Creating bin: {bin_name}")
# Connect to Resolve
print("Connecting to DaVinci Resolve...")
resolve = dvr_script.scriptapp("Resolve")
if not resolve:
print("Error: Failed to connect to DaVinci Resolve")
return
print(f"Connected to: {resolve.GetProductName()} {resolve.GetVersionString()}")
# Get project manager and current project
project_manager = resolve.GetProjectManager()
if not project_manager:
print("Error: Failed to get Project Manager")
return
current_project = project_manager.GetCurrentProject()
if not current_project:
print("Error: No project currently open")
return
print(f"Current project: {current_project.GetName()}")
# Get media pool
media_pool = current_project.GetMediaPool()
if not media_pool:
print("Error: Failed to get Media Pool")
return
# Create a bin for the imported content
root_folder = media_pool.GetRootFolder()
print(f"Creating bin '{bin_name}'...")
# Check if bin already exists
existing_bins = root_folder.GetSubFolderList()
target_bin = None
for bin in existing_bins:
if bin.GetName() == bin_name:
target_bin = bin
print(f"Bin '{bin_name}' already exists, using it")
break
# Create the bin if it doesn't exist
if not target_bin:
target_bin = media_pool.AddSubFolder(root_folder, bin_name)
if not target_bin:
print(f"Failed to create bin '{bin_name}', using root folder")
target_bin = root_folder
# Set the bin as the active folder
media_pool.SetCurrentFolder(target_bin)
# Import media from the folder
print(f"Importing media from {source_folder}...")
# Find all media files in the folder
media_extensions = [".mov", ".mp4", ".avi", ".mxf", ".wav", ".mp3", ".jpg", ".png", ".tif", ".exr"]
media_files = []
for ext in media_extensions:
media_files.extend(glob.glob(os.path.join(source_folder, f"*{ext}")))
media_files.extend(glob.glob(os.path.join(source_folder, f"*{ext.upper()}")))
if not media_files:
print(f"No media files found in {source_folder}")
# Try importing the folder directly
print("Trying to import the folder directly...")
imported_clips = media_pool.ImportMedia([source_folder])
if not imported_clips or len(imported_clips) == 0:
print("Failed to import any media")
return
else:
print(f"Found {len(media_files)} media files")
imported_clips = media_pool.ImportMedia(media_files)
if not imported_clips or len(imported_clips) == 0:
print("Failed to import media files")
return
print(f"Successfully imported {len(imported_clips)} clips")
# Create a new timeline named after the folder
timeline_name = f"{bin_name}_Timeline"
print(f"Creating timeline '{timeline_name}'...")
timeline = media_pool.CreateEmptyTimeline(timeline_name)
if not timeline:
print(f"Failed to create timeline '{timeline_name}'")
return
# Make sure the timeline is set as current
current_project.SetCurrentTimeline(timeline)
# Add all imported clips to the timeline
print("Adding clips to timeline...")
result = media_pool.AppendToTimeline(imported_clips)
if result and len(result) > 0:
print(f"Successfully added {len(result)} clips to timeline")
else:
print("Failed to add clips to timeline")
print("Import process complete!")
if __name__ == "__main__":
main()
```
--------------------------------------------------------------------------------
/tests/test_custom_timeline.py:
--------------------------------------------------------------------------------
```python
#!/usr/bin/env python3
"""
DaVinci Resolve MCP Server Test Script for Custom Timeline Creation
------------------------------------------------------------------
This script tests the enhanced CreateEmptyTimeline function with custom parameters.
Usage:
python test_custom_timeline.py
Requirements:
- DaVinci Resolve must be running with a project open
- DaVinci Resolve MCP Server must be running (after restart)
- requests module (pip install requests)
"""
import sys
import time
import requests
import logging
from typing import Dict, Any
# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler("custom_timeline_test.log"),
logging.StreamHandler()
]
)
logger = logging.getLogger(__name__)
# Server configuration
SERVER_URL = "http://localhost:8000/api"
def send_request(tool_name: str, params: Dict[str, Any]) -> Dict[str, Any]:
"""Send a request to the MCP server."""
try:
payload = {
"tool": tool_name,
"params": params
}
logger.info(f"Sending request: {tool_name} with params {params}")
response = requests.post(SERVER_URL, json=payload)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
logger.error(f"Request error: {e}")
return {"success": False, "error": str(e)}
def test_basic_timeline_creation():
"""Test basic timeline creation."""
logger.info("Testing basic timeline creation...")
# Create a test timeline with default settings
timeline_name = f"Basic_Test_Timeline_{int(time.time())}"
result = send_request("mcp_davinci_resolve_create_timeline", {"name": timeline_name})
if "error" in result and result.get("error"):
logger.error(f"❌ Basic timeline creation failed: {result.get('error')}")
return False
else:
logger.info(f"✅ Basic timeline created: {timeline_name}")
return True
def test_custom_timeline_creation():
"""Test enhanced timeline creation with custom parameters."""
logger.info("Testing custom timeline creation...")
# Create a custom timeline with specific parameters
timeline_name = f"Custom_Test_Timeline_{int(time.time())}"
params = {
"name": timeline_name,
"frame_rate": "23.976",
"resolution_width": 3840,
"resolution_height": 2160,
"start_timecode": "01:00:00:00"
}
result = send_request("mcp_davinci_resolve_create_empty_timeline", params)
if "error" in result and result.get("error"):
logger.error(f"❌ Custom timeline creation failed: {result.get('error')}")
return False
else:
logger.info(f"✅ Custom timeline created with parameters: {params}")
# Verify the timeline settings
logger.info("Retrieving timeline info to verify settings...")
# Switch to the created timeline
switch_result = send_request("mcp_davinci_resolve_set_current_timeline", {"name": timeline_name})
if "error" in switch_result and switch_result.get("error"):
logger.error(f"❌ Failed to switch to timeline: {switch_result.get('error')}")
return False
# Get timeline info
get_timeline_result = send_request("mcp_davinci_resolve_get_current_timeline", {})
if "error" in get_timeline_result or not isinstance(get_timeline_result, dict):
logger.error(f"❌ Failed to get timeline info: {get_timeline_result}")
return False
# Verify settings
resolution = get_timeline_result.get("resolution", {})
logger.info(f"Timeline info: {get_timeline_result}")
logger.info(f"Resolution: {resolution}")
logger.info(f"Framerate: {get_timeline_result.get('framerate')}")
logger.info(f"Start timecode: {get_timeline_result.get('start_timecode')}")
return True
def main():
"""Run the timeline creation tests."""
logger.info("Starting DaVinci Resolve MCP custom timeline creation tests")
logger.info("=" * 60)
# Run tests
basic_result = test_basic_timeline_creation()
custom_result = test_custom_timeline_creation()
# Summary
logger.info("=" * 60)
logger.info(f"Basic timeline creation: {'✅ PASSED' if basic_result else '❌ FAILED'}")
logger.info(f"Custom timeline creation: {'✅ PASSED' if custom_result else '❌ FAILED'}")
logger.info("=" * 60)
# Exit with appropriate code
if basic_result and custom_result:
logger.info("All tests passed!")
sys.exit(0)
else:
logger.error("Some tests failed. Check the logs for details.")
sys.exit(1)
if __name__ == "__main__":
main()
```
--------------------------------------------------------------------------------
/scripts/verify-installation.sh:
--------------------------------------------------------------------------------
```bash
#!/bin/bash
# verify-installation.sh
# Script to verify that the DaVinci Resolve MCP installation has been properly set up
# Colors for terminal output
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
BLUE='\033[0;34m'
RED='\033[0;31m'
NC='\033[0m' # No Color
# Get the script directory and project root
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
PROJECT_ROOT="$( cd "$SCRIPT_DIR/.." &> /dev/null && pwd )"
VENV_DIR="$PROJECT_ROOT/venv"
echo -e "${BLUE}===============================================${NC}"
echo -e "${BLUE} DaVinci Resolve MCP Installation Verification ${NC}"
echo -e "${BLUE}===============================================${NC}"
# Check if virtual environment exists
check_venv() {
echo -ne "${YELLOW}Checking Python virtual environment... ${NC}"
if [ -d "$VENV_DIR" ] && [ -f "$VENV_DIR/bin/python" ]; then
echo -e "${GREEN}OK${NC}"
return 0
else
echo -e "${RED}MISSING${NC}"
echo -e "${RED}Virtual environment not found at: $VENV_DIR${NC}"
return 1
fi
}
# Check if MCP SDK is installed
check_mcp_sdk() {
echo -ne "${YELLOW}Checking MCP SDK installation... ${NC}"
if "$VENV_DIR/bin/pip" list | grep -q "mcp"; then
echo -e "${GREEN}OK${NC}"
return 0
else
echo -e "${RED}MISSING${NC}"
echo -e "${RED}MCP SDK not installed in the virtual environment${NC}"
return 1
fi
}
# Check if Resolve MCP server script exists
check_server_script() {
echo -ne "${YELLOW}Checking server script... ${NC}"
if [ -f "$PROJECT_ROOT/src/resolve_mcp_server.py" ]; then
echo -e "${GREEN}OK${NC}"
return 0
else
echo -e "${RED}MISSING${NC}"
echo -e "${RED}Server script not found at: $PROJECT_ROOT/src/resolve_mcp_server.py${NC}"
return 1
fi
}
# Check if DaVinci Resolve is running
check_resolve_running() {
echo -ne "${YELLOW}Checking if DaVinci Resolve is running... ${NC}"
if ps -ef | grep -i "[D]aVinci Resolve" > /dev/null; then
echo -e "${GREEN}OK${NC}"
return 0
else
echo -e "${RED}NOT RUNNING${NC}"
echo -e "${RED}DaVinci Resolve is not running - please start it${NC}"
return 1
fi
}
# Check Cursor MCP configuration
check_cursor_config() {
echo -ne "${YELLOW}Checking Cursor MCP configuration... ${NC}"
CURSOR_CONFIG_FILE="$HOME/.cursor/mcp/config.json"
if [ -f "$CURSOR_CONFIG_FILE" ]; then
if grep -q "davinci-resolve" "$CURSOR_CONFIG_FILE"; then
echo -e "${GREEN}OK${NC}"
echo -e "${GREEN}Cursor MCP config found at: $CURSOR_CONFIG_FILE${NC}"
return 0
else
echo -e "${RED}INVALID${NC}"
echo -e "${RED}Cursor MCP config does not contain 'davinci-resolve' entry${NC}"
return 1
fi
else
echo -e "${RED}MISSING${NC}"
echo -e "${RED}Cursor MCP config not found at: $CURSOR_CONFIG_FILE${NC}"
return 1
fi
}
# Check if all environment variables are set
check_env_vars() {
echo -ne "${YELLOW}Checking environment variables... ${NC}"
local missing=0
if [ -z "$RESOLVE_SCRIPT_API" ]; then
missing=1
fi
if [ -z "$RESOLVE_SCRIPT_LIB" ]; then
missing=1
fi
if [ -z "$PYTHONPATH" ] || ! echo "$PYTHONPATH" | grep -q "Modules"; then
missing=1
fi
if [ $missing -eq 0 ]; then
echo -e "${GREEN}OK${NC}"
return 0
else
echo -e "${RED}MISSING${NC}"
echo -e "${RED}One or more required environment variables are not set${NC}"
return 1
fi
}
# Run all checks
run_all_checks() {
local passed=0
local total=0
check_venv
if [ $? -eq 0 ]; then ((passed++)); fi
((total++))
check_mcp_sdk
if [ $? -eq 0 ]; then ((passed++)); fi
((total++))
check_server_script
if [ $? -eq 0 ]; then ((passed++)); fi
((total++))
check_resolve_running
if [ $? -eq 0 ]; then ((passed++)); fi
((total++))
check_cursor_config
if [ $? -eq 0 ]; then ((passed++)); fi
((total++))
check_env_vars
if [ $? -eq 0 ]; then ((passed++)); fi
((total++))
echo -e "${BLUE}=============================================${NC}"
echo -e "${YELLOW}Results: $passed/$total checks passed${NC}"
if [ $passed -eq $total ]; then
echo -e "${GREEN}✓ Installation verification completed successfully!${NC}"
echo -e "${GREEN}✓ You can now use the MCP server with DaVinci Resolve${NC}"
echo -e "${YELLOW}To start the server, run:${NC}"
echo -e "${BLUE} ./run-now.sh${NC}"
echo -e "${YELLOW}Or for more options:${NC}"
echo -e "${BLUE} ./scripts/mcp_resolve-cursor_start${NC}"
return 0
else
echo -e "${RED}✗ Installation verification failed!${NC}"
echo -e "${YELLOW}Please fix the issues above and run this script again${NC}"
return 1
fi
}
# Run the verification
run_all_checks
exit $?
```
--------------------------------------------------------------------------------
/scripts/server.sh:
--------------------------------------------------------------------------------
```bash
#!/bin/bash
# Consolidated DaVinci Resolve MCP Server management script
# Usage: ./scripts/server.sh [start|stop|status|dev]
# Set current directory to project root
PROJECT_ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." && pwd )"
cd "$PROJECT_ROOT"
# Define environment variables if not already set
if [ -z "$RESOLVE_SCRIPT_API" ]; then
export RESOLVE_SCRIPT_API="/Library/Application Support/Blackmagic Design/DaVinci Resolve/Developer/Scripting"
fi
if [ -z "$RESOLVE_SCRIPT_LIB" ]; then
export RESOLVE_SCRIPT_LIB="/Applications/DaVinci Resolve/DaVinci Resolve.app/Contents/Libraries/Fusion/fusionscript.so"
fi
if [ -z "$PYTHONPATH" ]; then
export PYTHONPATH="$PYTHONPATH:$RESOLVE_SCRIPT_API/Modules/"
fi
# Check if DaVinci Resolve is running
check_resolve_running() {
RESOLVE_PROCESS=$(ps -ef | grep -i "[D]aVinci Resolve")
if [ -z "$RESOLVE_PROCESS" ]; then
echo "⚠️ DaVinci Resolve is not running."
echo "Please start DaVinci Resolve before starting the server."
return 1
else
echo "✅ DaVinci Resolve is running."
return 0
fi
}
# Check if server is already running
check_server_running() {
# Check for any process running our server script, whether via MCP or direct Python
if ps aux | grep "resolve_mcp_server\.py" | grep -v grep > /dev/null ; then
# Server is running
return 0
else
# Server is not running
return 1
fi
}
# Activate virtual environment if it exists
activate_venv() {
if [ -d "./venv" ]; then
source ./venv/bin/activate
echo "✅ Virtual environment activated."
else
echo "⚠️ No virtual environment found. Running with system Python."
fi
}
# Start the server
start_server() {
if check_server_running; then
echo "⚠️ MCP Server is already running."
return 0
fi
if ! check_resolve_running; then
read -p "Do you want to continue anyway? (y/n) " choice
case "$choice" in
y|Y ) echo "Continuing without DaVinci Resolve...";;
* ) echo "Aborting server start."; return 1;;
esac
fi
activate_venv
echo "🚀 Starting DaVinci Resolve MCP Server..."
mkdir -p "$PROJECT_ROOT/logs"
# Use direct Python as it's more reliable in background mode
nohup python3 "$PROJECT_ROOT/resolve_mcp_server.py" > "$PROJECT_ROOT/logs/server.log" 2>&1 &
# Give the server time to start
echo "Waiting for server to initialize..."
sleep 3
if check_server_running; then
echo "✅ Server started. Logs available at: $PROJECT_ROOT/logs/server.log"
return 0
else
echo "❌ Server failed to start. Check logs at: $PROJECT_ROOT/logs/server.log"
return 1
fi
}
# Stop the server
stop_server() {
if ! check_server_running; then
echo "⚠️ MCP Server is not running."
return 0
fi
echo "🛑 Stopping DaVinci Resolve MCP Server..."
# Kill any processes running the server
pkill -f "resolve_mcp_server\.py"
sleep 1
if check_server_running; then
echo "⚠️ Failed to stop all server processes. Trying with higher force..."
pkill -9 -f "resolve_mcp_server\.py"
sleep 1
if check_server_running; then
echo "❌ Could not stop all server processes. Manual cleanup required."
echo " Try running: killall -9 node; killall -9 python"
return 1
fi
fi
echo "✅ Server stopped."
return 0
}
# Start server in development mode
start_dev_mode() {
if check_server_running; then
echo "⚠️ An MCP Server is already running. Stopping it..."
stop_server
fi
check_resolve_running
activate_venv
echo "🚀 Starting DaVinci Resolve MCP Server in development mode..."
python3 "$PROJECT_ROOT/resolve_mcp_server.py"
}
# Show server status
show_status() {
if check_server_running; then
echo "✅ MCP Server is running."
# Display process info in a user-friendly way
echo -e "\nServer process details:"
ps aux | grep "resolve_mcp_server\.py" | grep -v grep | awk '{print "PID: " $2 " User: " $1 " Started: " $9 " Command: " $11 " " $12 " " $13}'
else
echo "❌ MCP Server is not running."
fi
check_resolve_running
}
# Create logs directory if it doesn't exist
mkdir -p "$PROJECT_ROOT/logs"
# Parse command line arguments
case "$1" in
start)
start_server
;;
stop)
stop_server
;;
restart)
stop_server
sleep 1
start_server
;;
status)
show_status
;;
dev)
start_dev_mode
;;
*)
echo "Usage: $0 {start|stop|restart|status|dev}"
echo ""
echo " start - Start the MCP server as a background process"
echo " stop - Stop the running MCP server"
echo " restart - Restart the MCP server"
echo " status - Check if the server is running"
echo " dev - Start in development mode (foreground)"
exit 1
;;
esac
exit 0
```
--------------------------------------------------------------------------------
/scripts/utils.sh:
--------------------------------------------------------------------------------
```bash
#!/bin/bash
# Utility functions for DaVinci Resolve MCP Server scripts
# Colors for terminal output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
BLUE='\033[0;34m'
PURPLE='\033[0;35m'
CYAN='\033[0;36m'
WHITE='\033[1;37m'
NC='\033[0m' # No Color
# Print a section header
print_header() {
local text="$1"
echo ""
echo -e "${WHITE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo -e "${WHITE} $text${NC}"
echo -e "${WHITE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo ""
}
# Print a status message
print_status() {
local status="$1"
local message="$2"
case "$status" in
"success")
echo -e "${GREEN}✓ $message${NC}"
;;
"warning")
echo -e "${YELLOW}⚠ $message${NC}"
;;
"error")
echo -e "${RED}✗ $message${NC}"
;;
"info")
echo -e "${BLUE}ℹ $message${NC}"
;;
*)
echo -e "${NC}$message${NC}"
;;
esac
}
# Check if a command exists
command_exists() {
command -v "$1" &>/dev/null
}
# Check if a port is in use
is_port_in_use() {
local port="$1"
lsof -i ":$port" &>/dev/null
}
# Kill processes using a port
kill_port_process() {
local port="$1"
local pids=$(lsof -t -i ":$port")
if [ -n "$pids" ]; then
print_status "info" "Stopping processes using port $port (PIDs: $pids)..."
kill $pids 2>/dev/null
sleep 1
# Check if they're still running and force kill if needed
pids=$(lsof -t -i ":$port")
if [ -n "$pids" ]; then
print_status "warning" "Forcing termination of processes using port $port..."
kill -9 $pids 2>/dev/null
fi
fi
}
# Check if DaVinci Resolve is running
is_resolve_running() {
# Try multiple patterns to detect DaVinci Resolve on macOS
if pgrep -i "DaVinci Resolve" &>/dev/null || \
pgrep -i "Resolve" &>/dev/null || \
ps -ef | grep -i "[D]aVinci Resolve" &>/dev/null || \
ps -ef | grep -i "Resolve.app" &>/dev/null; then
return 0
fi
# Check for Resolve process using the application path
if [ -d "/Applications/DaVinci Resolve" ] && \
ps -ef | grep -i "/Applications/DaVinci Resolve" | grep -v grep &>/dev/null; then
return 0
fi
return 1
}
# Function to compare version numbers
version_compare() {
if [[ "$1" == "$2" ]]; then
return 0
fi
local IFS=.
local i ver1=($1) ver2=($2)
# Fill empty fields with zeros
for ((i=${#ver1[@]}; i<${#ver2[@]}; i++)); do
ver1[i]=0
done
for ((i=${#ver2[@]}; i<${#ver1[@]}; i++)); do
ver2[i]=0
done
# Compare version numbers field by field
for ((i=0; i<${#ver1[@]}; i++)); do
if [[ ${ver1[i]} -gt ${ver2[i]} ]]; then
return 1 # ver1 > ver2
fi
if [[ ${ver1[i]} -lt ${ver2[i]} ]]; then
return 2 # ver1 < ver2
fi
done
return 0 # ver1 == ver2
}
# Check for Python and pip
check_python() {
if ! command_exists python3; then
print_status "error" "Python 3 is required but not installed. Please install Python 3 and try again."
return 1
fi
# Check version (need 3.6+)
python_version=$(python3 --version | awk '{print $2}')
required_version="3.6"
version_compare "$python_version" "$required_version"
result=$?
if [[ $result -eq 2 ]]; then
# Version is less than required
print_status "error" "Python 3.6+ is required. Your version: $python_version"
return 1
else
# Version is equal to or greater than required
return 0
fi
}
# Check for required environment variables
check_resolve_env() {
local all_set=true
local missing=""
if [ -z "$RESOLVE_SCRIPT_API" ]; then
all_set=false
missing="$missing RESOLVE_SCRIPT_API"
fi
if [ -z "$RESOLVE_SCRIPT_LIB" ]; then
all_set=false
missing="$missing RESOLVE_SCRIPT_LIB"
fi
if [ "$all_set" = false ]; then
return 1
fi
return 0
}
# Set Resolve environment variables
set_resolve_env() {
export RESOLVE_SCRIPT_API="/Library/Application Support/Blackmagic Design/DaVinci Resolve/Developer/Scripting"
export RESOLVE_SCRIPT_LIB="/Applications/DaVinci Resolve/DaVinci Resolve.app/Contents/Libraries/Fusion/fusionscript.so"
export PYTHONPATH="$PYTHONPATH:$RESOLVE_SCRIPT_API/Modules/"
}
# Check if a virtual environment exists
check_venv() {
local venv_dir="$1"
if [ ! -d "$venv_dir" ]; then
return 1
fi
if [ ! -f "$venv_dir/bin/python" ]; then
return 1
fi
return 0
}
# Check if a package is installed in the virtual environment
is_package_installed() {
local venv_dir="$1"
local package="$2"
"$venv_dir/bin/pip" list | grep -q "^$package "
}
# Install a package in the virtual environment
install_package() {
local venv_dir="$1"
local package="$2"
"$venv_dir/bin/pip" install "$package"
}
```
--------------------------------------------------------------------------------
/CHANGES.md:
--------------------------------------------------------------------------------
```markdown
# DaVinci Resolve MCP Integration - Recent Changes
## Version 1.3.7 - Installation Experience Improvements
### 1. New Unified Installation Process
- Created a comprehensive one-step installation experience:
- `install.sh` for macOS/Linux
- `install.bat` for Windows
- Added automatic validation and verification
- Simplified user experience with clear feedback
- Improved error handling with detailed messages
### 2. Fixed Path Resolution Issues
- Modified scripts to use the directory where they're executed as reference point
- Resolved issues with incorrect assumptions about directory structure
- Established consistent path handling across all scripts
- Added explicit log messages with configured paths
### 3. Improved DaVinci Resolve Detection
- Enhanced process detection methods for macOS and Windows
- Added retry mechanism with timeout for delayed startup
- Implemented more robust process matching patterns
- Added clear feedback when DaVinci Resolve isn't running
### 4. Enhanced Configuration Handling
- Improved configuration file generation with absolute paths
- Added support for both system-level and project-level configurations
- Ensured consistent path references between all configuration options
- Added detailed documentation on configuration options
### 5. New Verification Tools
- Created verification scripts (`verify-installation.sh` and `verify-installation.bat`)
- Implemented comprehensive checks for all dependencies
- Added detailed feedback for troubleshooting
- Enhanced error messages with suggested fixes
### 6. Updated Documentation
- Created comprehensive installation guide (`INSTALL.md`)
- Added detailed troubleshooting section
- Enhanced README with new installation options
- Improved explanations of configuration requirements
### 7. New Release Tooling
- Added scripts for creating versioned release packages
- Implemented automatic version extraction from VERSION.md
- Created cross-platform packaging tools for macOS/Linux and Windows
### 8. Improved Directory Structure
- Standardized to a single venv in the root directory
- Moved `resolve_mcp_server.py` to `src/` directory
- Restructured configuration files into `config/` directory
- Created dedicated `dist/` directory for release packages
- Moved installation scripts to `scripts/setup/`
- Reorganized test files into top-level `tests/` directory
- Created symlinks for backward compatibility
- Updated all scripts to use new standardized paths
## Previous Installation Issues Addressed
- Fixed issues with incorrect paths in `run-now.sh`
- Resolved DaVinci Resolve detection problems
- Improved configuration file generation for absolute paths
- Enhanced error feedback and logging
- Added more robust process detection patterns
- Implemented verification to catch common setup issues
- Added detailed troubleshooting documentation
## Installation Improvements
Based on troubleshooting experiences, the following improvements have been made to the installation process:
### 1. Fixed Path Resolution in Scripts
- Modified `run-now.sh` to use the directory where the script is located as the reference point
- Removed incorrect assumptions about directory structure
- Updated path references to use consistent `SCRIPT_DIR` variable throughout all scripts
### 2. Improved DaVinci Resolve Detection
- Changed detection method from `pgrep -q "DaVinci Resolve"` to `ps -ef | grep -i "[D]aVinci Resolve"` for more reliable detection
- Added a 10-second wait period with automatic retry when DaVinci Resolve is not detected
- Implemented more descriptive error messages when DaVinci Resolve is not running
### 3. Added Installation Verification
- Created verification scripts (`verify-installation.sh` and `verify-installation.bat`) to check installation integrity
- Verification covers Python environment, MCP SDK, configuration files, and DaVinci Resolve status
- Provides detailed feedback and suggestions for fixing issues
### 4. Enhanced Documentation
- Created a comprehensive installation guide (`INSTALL.md`) with step-by-step instructions
- Added detailed troubleshooting section to address common issues
- Updated README.md to reference new resources and include troubleshooting tips
### 5. Improved Configuration Setup
- Made the Cursor MCP configuration setup more robust and informative
- Added validation and feedback for environment variables
- Enhanced log file information for easier debugging
## Benefits of These Changes
- **More Reliable Installation:** Better path handling and detection methods
- **Easier Troubleshooting:** Verification tools and improved error messages
- **Clearer Documentation:** Step-by-step guide and troubleshooting solutions
- **Consistent Behavior:** Works correctly regardless of installation location
## How to Apply These Updates
If you already have a previous installation:
1. Pull the latest changes from the repository
2. Run the verification script to ensure everything is set up correctly:
- macOS/Linux: `./scripts/verify-installation.sh`
- Windows: `scripts\verify-installation.bat`
3. If verification fails, follow the suggested fixes or refer to the `INSTALL.md` guide
For new installations, simply follow the instructions in the `INSTALL.md` file.
```
--------------------------------------------------------------------------------
/examples/timeline/timeline_check.py:
--------------------------------------------------------------------------------
```python
#!/usr/bin/env python3
"""
Detailed timeline check to analyze clip positions and timecode mapping
"""
import os
import sys
# Set environment variables for DaVinci Resolve scripting
RESOLVE_API_PATH = "/Library/Application Support/Blackmagic Design/DaVinci Resolve/Developer/Scripting"
RESOLVE_LIB_PATH = "/Applications/DaVinci Resolve/DaVinci Resolve.app/Contents/Libraries/Fusion/fusionscript.so"
RESOLVE_MODULES_PATH = os.path.join(RESOLVE_API_PATH, "Modules")
os.environ["RESOLVE_SCRIPT_API"] = RESOLVE_API_PATH
os.environ["RESOLVE_SCRIPT_LIB"] = RESOLVE_LIB_PATH
sys.path.append(RESOLVE_MODULES_PATH)
# Import DaVinci Resolve scripting
import DaVinciResolveScript as dvr_script
def frame_to_tc(frame, fps):
"""Convert frame number to timecode"""
total_seconds = frame / fps
hours = int(total_seconds // 3600)
minutes = int((total_seconds % 3600) // 60)
seconds = int(total_seconds % 60)
frames = int((total_seconds - int(total_seconds)) * fps)
return f"{hours:02d}:{minutes:02d}:{seconds:02d}:{frames:02d}"
def main():
print("\n===== DETAILED TIMELINE ANALYSIS =====\n")
# Connect to Resolve
resolve = dvr_script.scriptapp("Resolve")
if not resolve:
print("Error: Failed to connect to DaVinci Resolve")
return
print(f"Connected to: {resolve.GetProductName()} {resolve.GetVersionString()}")
# Get project manager
project_manager = resolve.GetProjectManager()
current_project = project_manager.GetCurrentProject()
current_timeline = current_project.GetCurrentTimeline()
print(f"Project: {current_project.GetName()}")
print(f"Timeline: {current_timeline.GetName()}")
# Get timeline settings
fps = float(current_timeline.GetSetting("timelineFrameRate"))
print(f"Frame rate: {fps}")
start_frame = current_timeline.GetStartFrame()
end_frame = current_timeline.GetEndFrame()
# Calculate real timecodes
start_tc = frame_to_tc(start_frame, fps)
end_tc = frame_to_tc(end_frame, fps)
print(f"\nTimeline spans frames {start_frame} to {end_frame}")
print(f"Timeline estimated timecode: {start_tc} to {end_tc}")
# Check if we can get actual timecode
try:
start_timecode = current_timeline.GetStartTimecode()
print(f"Timeline actual start timecode: {start_timecode}")
except:
print("Could not get actual start timecode")
# Check timecode display settings
tc_drop = current_timeline.GetSetting("timelineDropFrameTimecode")
print(f"Drop frame: {tc_drop}")
# Get playhead position
try:
playhead_frame = current_timeline.GetCurrentVideoFrame()
playhead_tc = frame_to_tc(playhead_frame, fps)
print(f"\nPlayhead at frame {playhead_frame} (approx. TC: {playhead_tc})")
except Exception as e:
print(f"Error getting playhead: {str(e)}")
# Get clips
clips = []
for track_idx in range(1, 5): # Check first 4 video tracks
try:
track_clips = current_timeline.GetItemListInTrack("video", track_idx)
if track_clips and len(track_clips) > 0:
clips.extend(track_clips)
except:
continue
print(f"\nFound {len(clips)} clips:")
for i, clip in enumerate(clips):
clip_name = clip.GetName()
start_frame = clip.GetStart()
end_frame = clip.GetEnd()
# Get the source frame info
try:
source_start = clip.GetLeftOffset()
source_end = source_start + (end_frame - start_frame)
print(f" Clip {i+1}: '{clip_name}'")
print(f" Timeline: frames {start_frame}-{end_frame} ({frame_to_tc(start_frame, fps)}-{frame_to_tc(end_frame, fps)})")
print(f" Source: frames {source_start}-{source_end}")
except Exception as e:
print(f" Clip {i+1}: '{clip_name}'")
print(f" Timeline: frames {start_frame}-{end_frame} ({frame_to_tc(start_frame, fps)}-{frame_to_tc(end_frame, fps)})")
print(f" Source info error: {str(e)}")
# Get markers
markers = current_timeline.GetMarkers() or {}
print(f"\nFound {len(markers)} markers:")
sorted_markers = sorted(markers.items())
for frame, marker_data in sorted_markers:
color = marker_data.get("color", "Unknown")
name = marker_data.get("name", "")
tc = frame_to_tc(frame, fps)
print(f" Marker at frame {frame} (TC: {tc}):")
print(f" Color: {color}")
print(f" Name: {name}")
# Try to determine timeline start offset
try:
one_hour_frames = int(fps * 60 * 60)
print("\nTimeline offset analysis:")
print(f" One hour in frames: {one_hour_frames}")
print(f" If timeline starts at 01:00:00:00, first frame should be {one_hour_frames}")
offset = start_frame - one_hour_frames
print(f" Detected offset: {offset} frames")
if offset >= 0:
print(f" Timeline appears to start at {frame_to_tc(offset + one_hour_frames, fps)}")
else:
print(f" Timeline appears to start at {frame_to_tc(one_hour_frames - abs(offset), fps)}")
except Exception as e:
print(f"Error analyzing offset: {str(e)}")
print("\n===== END OF ANALYSIS =====")
if __name__ == "__main__":
main()
```
--------------------------------------------------------------------------------
/scripts/setup.sh:
--------------------------------------------------------------------------------
```bash
#!/bin/bash
# DaVinci Resolve MCP Server Setup Script
# Colors for terminal output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
NC='\033[0m' # No Color
echo -e "${GREEN}Setting up DaVinci Resolve MCP Server...${NC}"
# Check if Python 3 is installed
if ! command -v python3 &> /dev/null; then
echo -e "${RED}Error: Python 3 is required but not installed.${NC}"
echo "Please install Python 3 and try again."
exit 1
fi
# Create and activate virtual environment
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
VENV_DIR="$SCRIPT_DIR/venv"
echo -e "${YELLOW}Creating Python virtual environment at $VENV_DIR...${NC}"
python3 -m venv "$VENV_DIR"
# Activate virtual environment (source doesn't work in scripts)
VENV_PYTHON="$VENV_DIR/bin/python"
VENV_PIP="$VENV_DIR/bin/pip"
# Install MCP SDK in the virtual environment with CLI support
echo -e "${YELLOW}Installing MCP SDK with CLI support in virtual environment...${NC}"
"$VENV_PIP" install "mcp[cli]"
# Check if DaVinci Resolve is installed
if [ ! -d "/Applications/DaVinci Resolve" ]; then
echo -e "${RED}Warning: DaVinci Resolve installation not found at the default location.${NC}"
echo "If DaVinci Resolve is installed in a different location, you'll need to manually update the environment variables."
else
echo -e "${GREEN}DaVinci Resolve installation found.${NC}"
fi
# Set up environment variables
RESOLVE_SCRIPT_API="/Library/Application Support/Blackmagic Design/DaVinci Resolve/Developer/Scripting"
RESOLVE_SCRIPT_LIB="/Applications/DaVinci Resolve/DaVinci Resolve.app/Contents/Libraries/Fusion/fusionscript.so"
# Check if Scripting API directory exists
if [ ! -d "$RESOLVE_SCRIPT_API" ]; then
echo -e "${RED}Warning: DaVinci Resolve Scripting API folder not found at the expected location.${NC}"
echo "This might be due to a different version of DaVinci Resolve or custom installation."
else
echo -e "${GREEN}DaVinci Resolve Scripting API found.${NC}"
fi
# Add environment variables to shell profile
SHELL_PROFILE=""
if [ -f "$HOME/.zshrc" ]; then
SHELL_PROFILE="$HOME/.zshrc"
elif [ -f "$HOME/.bash_profile" ]; then
SHELL_PROFILE="$HOME/.bash_profile"
elif [ -f "$HOME/.bashrc" ]; then
SHELL_PROFILE="$HOME/.bashrc"
fi
if [ -n "$SHELL_PROFILE" ]; then
echo -e "${YELLOW}Adding environment variables to $SHELL_PROFILE...${NC}"
# Check if variables are already in the profile
if grep -q "RESOLVE_SCRIPT_API" "$SHELL_PROFILE"; then
echo -e "${YELLOW}Environment variables already exist in $SHELL_PROFILE. Skipping...${NC}"
else
echo "" >> "$SHELL_PROFILE"
echo "# DaVinci Resolve MCP Server environment variables" >> "$SHELL_PROFILE"
echo "export RESOLVE_SCRIPT_API=\"$RESOLVE_SCRIPT_API\"" >> "$SHELL_PROFILE"
echo "export RESOLVE_SCRIPT_LIB=\"$RESOLVE_SCRIPT_LIB\"" >> "$SHELL_PROFILE"
echo "export PYTHONPATH=\"\$PYTHONPATH:\$RESOLVE_SCRIPT_API/Modules/\"" >> "$SHELL_PROFILE"
echo -e "${GREEN}Environment variables added to $SHELL_PROFILE${NC}"
fi
else
echo -e "${RED}Warning: Could not find a shell profile to update.${NC}"
echo "Please manually add the following environment variables to your shell profile:"
echo "export RESOLVE_SCRIPT_API=\"$RESOLVE_SCRIPT_API\""
echo "export RESOLVE_SCRIPT_LIB=\"$RESOLVE_SCRIPT_LIB\""
echo "export PYTHONPATH=\"\$PYTHONPATH:\$RESOLVE_SCRIPT_API/Modules/\""
fi
# Create wrapper script to run server with the virtual environment
cat > "$SCRIPT_DIR/run-server.sh" << EOF
#!/bin/bash
# Wrapper script to run the DaVinci Resolve MCP Server with the virtual environment
# Source environment variables if not already set
if [ -z "\$RESOLVE_SCRIPT_API" ]; then
source "$SHELL_PROFILE"
fi
# Activate virtual environment and run server
"$VENV_DIR/bin/python" "$SCRIPT_DIR/../src/main.py" "\$@"
EOF
chmod +x "$SCRIPT_DIR/run-server.sh"
# Set up Cursor configuration
CURSOR_CONFIG_DIR="$HOME/.cursor"
CURSOR_MCP_CONFIG="$CURSOR_CONFIG_DIR/mcp.json"
if [ ! -d "$CURSOR_CONFIG_DIR" ]; then
echo -e "${YELLOW}Creating Cursor config directory...${NC}"
mkdir -p "$CURSOR_CONFIG_DIR"
fi
# Get the full path to the wrapper script
SERVER_PATH="$SCRIPT_DIR/run-server.sh"
# Check if Cursor MCP config exists
if [ -f "$CURSOR_MCP_CONFIG" ]; then
echo -e "${YELLOW}Found existing Cursor MCP config. Not modifying it.${NC}"
echo "To manually add the DaVinci Resolve MCP server, edit $CURSOR_MCP_CONFIG and add:"
echo "{\"mcpServers\": {\"davinci-resolve\": {\"command\": \"$SERVER_PATH\"}}}"
else
echo -e "${YELLOW}Creating Cursor MCP config...${NC}"
cat > "$CURSOR_MCP_CONFIG" << EOF
{
"mcpServers": {
"davinci-resolve": {
"command": "$SERVER_PATH"
}
}
}
EOF
echo -e "${GREEN}Created Cursor MCP config at $CURSOR_MCP_CONFIG${NC}"
fi
# Make the server script executable
chmod +x "$SCRIPT_DIR/resolve_mcp_server.py"
echo -e "${GREEN}Setup completed!${NC}"
echo ""
echo -e "${YELLOW}Important:${NC}"
echo "1. Make sure to restart your terminal or run 'source $SHELL_PROFILE' to apply the environment variables."
echo "2. DaVinci Resolve must be running before starting the MCP server."
echo "3. You can test the server by running: $SCRIPT_DIR/run-server.sh"
echo " or with the MCP CLI: $VENV_DIR/bin/mcp dev $SCRIPT_DIR/resolve_mcp_server.py"
echo ""
echo -e "${GREEN}Happy editing with DaVinci Resolve and your AI assistant!${NC}"
```
--------------------------------------------------------------------------------
/examples/timeline/timeline_info.py:
--------------------------------------------------------------------------------
```python
#!/usr/bin/env python3
"""
Get detailed timeline information from DaVinci Resolve
"""
import os
import sys
# Set environment variables for DaVinci Resolve scripting
RESOLVE_API_PATH = "/Library/Application Support/Blackmagic Design/DaVinci Resolve/Developer/Scripting"
RESOLVE_LIB_PATH = "/Applications/DaVinci Resolve/DaVinci Resolve.app/Contents/Libraries/Fusion/fusionscript.so"
RESOLVE_MODULES_PATH = os.path.join(RESOLVE_API_PATH, "Modules")
os.environ["RESOLVE_SCRIPT_API"] = RESOLVE_API_PATH
os.environ["RESOLVE_SCRIPT_LIB"] = RESOLVE_LIB_PATH
sys.path.append(RESOLVE_MODULES_PATH)
# Import DaVinci Resolve scripting
import DaVinciResolveScript as dvr_script
def main():
print("\n===== Timeline Information =====\n")
# Connect to Resolve
resolve = dvr_script.scriptapp("Resolve")
if not resolve:
print("Error: Failed to connect to DaVinci Resolve")
return
print(f"Connected to: {resolve.GetProductName()} {resolve.GetVersionString()}")
# Get project manager
project_manager = resolve.GetProjectManager()
if not project_manager:
print("Error: Failed to get Project Manager")
return
# Get current project
current_project = project_manager.GetCurrentProject()
if not current_project:
print("Error: No project currently open")
return
print(f"Current project: {current_project.GetName()}")
# Get current timeline
current_timeline = current_project.GetCurrentTimeline()
if not current_timeline:
print("Error: No timeline currently active")
return
timeline_name = current_timeline.GetName()
print(f"Current timeline: {timeline_name}")
# Get timeline frame rate
try:
frame_rate = float(current_timeline.GetSetting("timelineFrameRate"))
print(f"Timeline frame rate: {frame_rate} fps")
except Exception as e:
print(f"Error getting frame rate: {str(e)}")
frame_rate = 24.0
# Get timeline information
start_frame = current_timeline.GetStartFrame()
end_frame = current_timeline.GetEndFrame()
print(f"Timeline frame range: {start_frame} to {end_frame}")
# Calculate timecode equivalent of the frame range
hours_start = start_frame // (frame_rate * 60 * 60)
minutes_start = (start_frame % (frame_rate * 60 * 60)) // (frame_rate * 60)
seconds_start = (start_frame % (frame_rate * 60)) // frame_rate
frames_start = start_frame % frame_rate
hours_end = end_frame // (frame_rate * 60 * 60)
minutes_end = (end_frame % (frame_rate * 60 * 60)) // (frame_rate * 60)
seconds_end = (end_frame % (frame_rate * 60)) // frame_rate
frames_end = end_frame % frame_rate
start_tc = f"{int(hours_start):02d}:{int(minutes_start):02d}:{int(seconds_start):02d}:{int(frames_start):02d}"
end_tc = f"{int(hours_end):02d}:{int(minutes_end):02d}:{int(seconds_end):02d}:{int(frames_end):02d}"
print(f"Timeline approx. timecode range: {start_tc} to {end_tc}")
# Calculate various time positions
one_hour_frames = int(frame_rate * 60 * 60)
print(f"\nTime calculations:")
print(f"One hour in frames: {one_hour_frames}")
print(f"01:00:00:00 would be frame: {one_hour_frames}")
print(f"02:00:00:00 would be frame: {one_hour_frames * 2}")
# Get clips in timeline
clips = []
for track_idx in range(1, 5): # Check first 4 video tracks
try:
track_clips = current_timeline.GetItemListInTrack("video", track_idx)
if track_clips and len(track_clips) > 0:
clips.extend(track_clips)
except:
continue
print(f"\nFound {len(clips)} clips in timeline:")
for i, clip in enumerate(clips):
clip_start = clip.GetStart()
clip_end = clip.GetEnd()
clip_name = clip.GetName()
print(f"Clip {i+1}: '{clip_name}'")
print(f" Frame range: {clip_start} to {clip_end}")
print(f" Duration: {clip_end - clip_start} frames")
# Calculate timecode equivalent (rough estimate)
hours_start = clip_start // (frame_rate * 60 * 60)
minutes_start = (clip_start % (frame_rate * 60 * 60)) // (frame_rate * 60)
seconds_start = (clip_start % (frame_rate * 60)) // frame_rate
frames_start = clip_start % frame_rate
tc_start = f"{int(hours_start):02d}:{int(minutes_start):02d}:{int(seconds_start):02d}:{int(frames_start):02d}"
print(f" Approx. start TC: {tc_start}")
print()
# Get existing markers
markers = current_timeline.GetMarkers() or {}
print(f"\nFound {len(markers)} markers in timeline:")
sorted_markers = sorted(markers.items())
for frame, marker_data in sorted_markers:
color = marker_data.get("color", "Unknown")
name = marker_data.get("name", "")
# Calculate timecode equivalent (rough estimate)
hours = frame // (frame_rate * 60 * 60)
minutes = (frame % (frame_rate * 60 * 60)) // (frame_rate * 60)
seconds = (frame % (frame_rate * 60)) // frame_rate
frames = frame % frame_rate
tc = f"{int(hours):02d}:{int(minutes):02d}:{int(seconds):02d}:{int(frames):02d}"
print(f"Marker at frame {frame} (approx. TC: {tc}):")
print(f" Color: {color}")
print(f" Name: {name}")
print()
print("\n===== End of Information =====")
if __name__ == "__main__":
main()
```
--------------------------------------------------------------------------------
/examples/markers/alternating_markers.py:
--------------------------------------------------------------------------------
```python
#!/usr/bin/env python3
"""
Add alternating color markers every 10 seconds for 60 seconds in the current timeline
"""
import os
import sys
# Set environment variables for DaVinci Resolve scripting
RESOLVE_API_PATH = "/Library/Application Support/Blackmagic Design/DaVinci Resolve/Developer/Scripting"
RESOLVE_LIB_PATH = "/Applications/DaVinci Resolve/DaVinci Resolve.app/Contents/Libraries/Fusion/fusionscript.so"
RESOLVE_MODULES_PATH = os.path.join(RESOLVE_API_PATH, "Modules")
os.environ["RESOLVE_SCRIPT_API"] = RESOLVE_API_PATH
os.environ["RESOLVE_SCRIPT_LIB"] = RESOLVE_LIB_PATH
sys.path.append(RESOLVE_MODULES_PATH)
# Import DaVinci Resolve scripting
import DaVinciResolveScript as dvr_script
def main():
print("\n===== Adding Alternating Color Markers =====\n")
# Connect to Resolve
resolve = dvr_script.scriptapp("Resolve")
if not resolve:
print("Error: Failed to connect to DaVinci Resolve")
return
print(f"Connected to: {resolve.GetProductName()} {resolve.GetVersionString()}")
# Get project manager
project_manager = resolve.GetProjectManager()
if not project_manager:
print("Error: Failed to get Project Manager")
return
# Get current project
current_project = project_manager.GetCurrentProject()
if not current_project:
print("Error: No project currently open")
return
print(f"Current project: {current_project.GetName()}")
# Get current timeline
current_timeline = current_project.GetCurrentTimeline()
if not current_timeline:
print("Error: No timeline currently active")
return
timeline_name = current_timeline.GetName()
print(f"Current timeline: {timeline_name}")
# Get timeline frame rate
try:
frame_rate = float(current_timeline.GetSetting("timelineFrameRate"))
print(f"Timeline frame rate: {frame_rate} fps")
except Exception as e:
print(f"Error getting frame rate: {str(e)}")
frame_rate = 24.0 # Default to 24 fps
print(f"Using default frame rate: {frame_rate} fps")
# Get timeline frame range
start_frame = current_timeline.GetStartFrame()
end_frame = current_timeline.GetEndFrame()
print(f"Timeline frame range: {start_frame} to {end_frame}")
# Get existing markers to avoid conflicts
existing_markers = current_timeline.GetMarkers() or {}
print(f"Found {len(existing_markers)} existing markers")
# Calculate frame positions for markers (every 10 seconds for 60 seconds)
markers_to_add = []
# Get clips to ensure we're adding markers on actual clips
clips = []
for track_idx in range(1, 5): # Check first 4 video tracks
try:
track_clips = current_timeline.GetItemListInTrack("video", track_idx)
if track_clips and len(track_clips) > 0:
clips.extend(track_clips)
except:
continue
if not clips:
print("Error: No clips found in timeline")
return
# Find a reference clip to use as starting point
reference_clip = clips[0]
reference_start = reference_clip.GetStart()
print(f"Reference clip start: {reference_start}")
# Calculate one hour in frames
one_hour_in_frames = int(frame_rate * 60 * 60)
# Calculate start frame at 01:00:00:00 (subtract one hour from current 02:00:00:00)
start_frame_position = reference_start - one_hour_in_frames
print(f"New start position (01:00:00:00): {start_frame_position}")
# Calculate frame positions (every 10 seconds)
frames_per_10_sec = int(frame_rate * 10)
colors = ["Blue", "Red", "Green", "Yellow", "Purple", "Cyan"]
# Prepare markers at 0, 10, 20, 30, 40, 50, 60 seconds (7 markers total)
for i in range(7):
offset_frames = i * frames_per_10_sec
frame_position = start_frame_position + offset_frames
color_index = i % len(colors)
markers_to_add.append({
"frame": frame_position,
"color": colors[color_index],
"note": f"{i*10} seconds marker (01:00:00:00 + {i*10}s)"
})
# Add markers
print("\n--- Adding Markers ---")
markers_added = 0
for marker in markers_to_add:
frame = marker["frame"]
color = marker["color"]
note = marker["note"]
# Skip if marker already exists at this frame
if frame in existing_markers:
print(f"Skipping frame {frame}: Marker already exists")
continue
# Verify the frame is within a clip
frame_in_clip = False
for clip in clips:
if clip.GetStart() <= frame <= clip.GetEnd():
frame_in_clip = True
break
if not frame_in_clip:
print(f"Skipping frame {frame}: Not within a clip")
continue
# Add the marker
print(f"Adding {color} marker at frame {frame} ({note})")
result = current_timeline.AddMarker(
frame,
color,
note,
note,
1,
""
)
if result:
print(f"✓ Successfully added marker")
markers_added += 1
else:
print(f"✗ Failed to add marker")
# Get final count of markers
final_markers = current_timeline.GetMarkers() or {}
print(f"\nAdded {markers_added} new markers")
print(f"Timeline now has {len(final_markers)} total markers")
print("\n===== Completed =====")
if __name__ == "__main__":
main()
```
--------------------------------------------------------------------------------
/examples/markers/clear_add_markers.py:
--------------------------------------------------------------------------------
```python
#!/usr/bin/env python3
"""
Clear existing markers and add new alternating color markers at visible timeline positions
"""
import os
import sys
# Set environment variables for DaVinci Resolve scripting
RESOLVE_API_PATH = "/Library/Application Support/Blackmagic Design/DaVinci Resolve/Developer/Scripting"
RESOLVE_LIB_PATH = "/Applications/DaVinci Resolve/DaVinci Resolve.app/Contents/Libraries/Fusion/fusionscript.so"
RESOLVE_MODULES_PATH = os.path.join(RESOLVE_API_PATH, "Modules")
os.environ["RESOLVE_SCRIPT_API"] = RESOLVE_API_PATH
os.environ["RESOLVE_SCRIPT_LIB"] = RESOLVE_LIB_PATH
sys.path.append(RESOLVE_MODULES_PATH)
# Import DaVinci Resolve scripting
import DaVinciResolveScript as dvr_script
def main():
print("\n===== Clearing and Adding New Markers =====\n")
# Connect to Resolve
resolve = dvr_script.scriptapp("Resolve")
if not resolve:
print("Error: Failed to connect to DaVinci Resolve")
return
print(f"Connected to: {resolve.GetProductName()} {resolve.GetVersionString()}")
# Get project manager
project_manager = resolve.GetProjectManager()
if not project_manager:
print("Error: Failed to get Project Manager")
return
# Get current project
current_project = project_manager.GetCurrentProject()
if not current_project:
print("Error: No project currently open")
return
print(f"Current project: {current_project.GetName()}")
# Get current timeline
current_timeline = current_project.GetCurrentTimeline()
if not current_timeline:
print("Error: No timeline currently active")
return
timeline_name = current_timeline.GetName()
print(f"Current timeline: {timeline_name}")
# Get timeline frame rate
try:
frame_rate = float(current_timeline.GetSetting("timelineFrameRate"))
print(f"Timeline frame rate: {frame_rate} fps")
except Exception as e:
print(f"Error getting frame rate: {str(e)}")
frame_rate = 24.0 # Default to 24 fps
print(f"Using default frame rate: {frame_rate} fps")
# Get timeline frame range
start_frame = current_timeline.GetStartFrame()
end_frame = current_timeline.GetEndFrame()
print(f"Timeline frame range: {start_frame} to {end_frame}")
# Clear existing markers
existing_markers = current_timeline.GetMarkers() or {}
print(f"Found {len(existing_markers)} existing markers to clear")
if existing_markers:
for frame in existing_markers:
current_timeline.DeleteMarkerAtFrame(frame)
print("All existing markers cleared")
# Get clips to ensure we're adding markers on actual clips
clips = []
for track_idx in range(1, 5): # Check first 4 video tracks
try:
track_clips = current_timeline.GetItemListInTrack("video", track_idx)
if track_clips and len(track_clips) > 0:
clips.extend(track_clips)
except:
continue
if not clips:
print("Error: No clips found in timeline")
return
# Define exact positions visible in the timeline for markers
# Based on the screenshot where the playhead is at 01:00:00:00
# We'll add markers at consistent intervals within the visible clips
print("\n--- Adding Markers at Specific Positions ---")
# Define the marker positions based on the visible clips
colors = ["Blue", "Red", "Green", "Yellow", "Purple", "Cyan"]
marker_positions = []
# Add positions for the first clip (approximately first half of timeline)
first_clip_start = 86400 # 01:00:00:00
# Add markers at specific positions in 10-second intervals
for i in range(6): # Add 6 markers in the 60-second span
frame = first_clip_start + (i * int(frame_rate * 10)) # Every 10 seconds
color_index = i % len(colors)
marker_positions.append({
"frame": frame,
"color": colors[color_index],
"note": f"Marker {i+1}: {i*10} seconds"
})
# Add a few markers in the other clips visible in the timeline
second_clip_start = 87351 # Start of DaVinciResolveMCP-01_v04.mov
third_clip_start = 88446 # Start of DaVinciResolveMCP-01_v02.mov
fourth_clip_start = 89469 # Start of DaVinciResolveMCP-01_v03.mov
# Add one marker in each clip
additional_markers = [
{"frame": second_clip_start + 240, "color": "Red", "note": "Clip 2 marker"},
{"frame": third_clip_start + 240, "color": "Green", "note": "Clip 3 marker"},
{"frame": fourth_clip_start + 240, "color": "Purple", "note": "Clip 4 marker"}
]
marker_positions.extend(additional_markers)
# Add markers
markers_added = 0
for marker in marker_positions:
frame = marker["frame"]
color = marker["color"]
note = marker["note"]
# Verify the frame is within a clip
frame_in_clip = False
for clip in clips:
if clip.GetStart() <= frame <= clip.GetEnd():
frame_in_clip = True
break
if not frame_in_clip:
print(f"Skipping frame {frame}: Not within a clip")
continue
# Add the marker
print(f"Adding {color} marker at frame {frame} ({note})")
result = current_timeline.AddMarker(
frame,
color,
note,
note,
1,
""
)
if result:
print(f"✓ Successfully added marker")
markers_added += 1
else:
print(f"✗ Failed to add marker")
# Get final count of markers
final_markers = current_timeline.GetMarkers() or {}
print(f"\nAdded {markers_added} new markers")
print(f"Timeline now has {len(final_markers)} total markers")
print("\n===== Completed =====")
if __name__ == "__main__":
main()
```
--------------------------------------------------------------------------------
/tests/create_test_timeline.py:
--------------------------------------------------------------------------------
```python
#!/usr/bin/env python3
"""
DaVinci Resolve Test Timeline Generator
---------------------------------------
This script creates a test timeline with sample media for testing the MCP server.
It generates colored test frames as clips if no media is available.
Usage:
python create_test_timeline.py
Requirements:
- DaVinci Resolve must be running
- requests module (pip install requests)
"""
import os
import sys
import time
import requests
import logging
import tempfile
import subprocess
from typing import Dict, Any, List, Optional
# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[
logging.StreamHandler()
]
)
logger = logging.getLogger(__name__)
# Server configuration
SERVER_URL = "http://localhost:8000/api"
def send_request(tool_name: str, params: Dict[str, Any]) -> Dict[str, Any]:
"""Send a request to the MCP server."""
try:
payload = {
"tool": tool_name,
"params": params
}
response = requests.post(SERVER_URL, json=payload)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
logger.error(f"Request error: {e}")
return {"success": False, "error": str(e)}
def create_test_media() -> List[str]:
"""Create test media files for import."""
logger.info("Creating test media files...")
media_files = []
temp_dir = tempfile.gettempdir()
try:
# Create three colored test frames using ffmpeg if available
colors = ["red", "green", "blue"]
for color in colors:
output_file = os.path.join(temp_dir, f"test_{color}.mp4")
# Check if ffmpeg is available
try:
# Create a 5-second test video with the specified color
cmd = [
"ffmpeg", "-y", "-f", "lavfi", "-i", f"color=c={color}:s=1280x720:r=30:d=5",
"-c:v", "libx264", "-pix_fmt", "yuv420p", output_file
]
subprocess.run(cmd, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
media_files.append(output_file)
logger.info(f"Created {color} test media: {output_file}")
except (subprocess.SubprocessError, FileNotFoundError) as e:
logger.error(f"Failed to create test media: {e}")
# Try an alternative method if ffmpeg fails
break
except Exception as e:
logger.error(f"Error creating test media: {e}")
if not media_files:
logger.warning("Could not create test media. The timeline will be empty.")
return media_files
def setup_test_project() -> bool:
"""Create a test project."""
logger.info("Setting up test project...")
# Create a new project
result = send_request("mcp_davinci_resolve_create_project", {"name": "MCP_Test_Project"})
if "error" in result and result["error"]:
logger.error(f"Failed to create project: {result['error']}")
# Try opening the project if it already exists
open_result = send_request("mcp_davinci_resolve_open_project", {"name": "MCP_Test_Project"})
if "error" in open_result and open_result["error"]:
logger.error(f"Failed to open existing project: {open_result['error']}")
return False
else:
logger.info("Opened existing test project")
else:
logger.info("Created new test project")
# Set project settings
send_request("mcp_davinci_resolve_set_project_setting",
{"setting_name": "timelineFrameRate", "setting_value": 30})
return True
def create_test_timeline() -> bool:
"""Create a test timeline with imported media."""
logger.info("Creating test timeline...")
# Create timeline
result = send_request("mcp_davinci_resolve_create_timeline", {"name": "MCP_Test_Timeline"})
if "error" in result and result["error"]:
logger.error(f"Failed to create timeline: {result['error']}")
return False
logger.info("Created test timeline")
# Set as current timeline
send_request("mcp_davinci_resolve_set_current_timeline", {"name": "MCP_Test_Timeline"})
# Create and import test media
media_files = create_test_media()
# Import media files
for media_file in media_files:
import_result = send_request("mcp_davinci_resolve_import_media",
{"file_path": media_file})
if "error" not in import_result or not import_result["error"]:
logger.info(f"Imported media: {media_file}")
# Add to timeline (after short delay to ensure media is processed)
time.sleep(1)
clip_name = os.path.basename(media_file)
add_result = send_request("mcp_davinci_resolve_add_clip_to_timeline",
{"clip_name": clip_name, "timeline_name": "MCP_Test_Timeline"})
if "error" not in add_result or not add_result["error"]:
logger.info(f"Added clip to timeline: {clip_name}")
else:
logger.warning(f"Failed to add clip to timeline: {add_result.get('error', 'Unknown error')}")
else:
logger.warning(f"Failed to import media: {import_result.get('error', 'Unknown error')}")
return True
def main() -> None:
"""Run the test timeline creation process."""
logger.info("Starting DaVinci Resolve test timeline setup")
logger.info("=" * 50)
# Set up test project
if not setup_test_project():
logger.error("Failed to set up test project. Exiting.")
sys.exit(1)
# Create test timeline with media
if not create_test_timeline():
logger.error("Failed to create test timeline. Exiting.")
sys.exit(1)
logger.info("=" * 50)
logger.info("Test timeline setup complete!")
logger.info("You can now use this timeline to test the MCP server features.")
logger.info("=" * 50)
if __name__ == "__main__":
main()
```
--------------------------------------------------------------------------------
/examples/markers/add_timecode_marker.py:
--------------------------------------------------------------------------------
```python
#!/usr/bin/env python3
"""
CLI utility to add a marker at a specific timecode position
Usage: ./add_timecode_marker.py <timecode> [color] [note]
Example: ./add_timecode_marker.py 01:00:15:00 Red "My marker note"
"""
import os
import sys
import argparse
# Set environment variables for DaVinci Resolve scripting
RESOLVE_API_PATH = "/Library/Application Support/Blackmagic Design/DaVinci Resolve/Developer/Scripting"
RESOLVE_LIB_PATH = "/Applications/DaVinci Resolve/DaVinci Resolve.app/Contents/Libraries/Fusion/fusionscript.so"
RESOLVE_MODULES_PATH = os.path.join(RESOLVE_API_PATH, "Modules")
os.environ["RESOLVE_SCRIPT_API"] = RESOLVE_API_PATH
os.environ["RESOLVE_SCRIPT_LIB"] = RESOLVE_LIB_PATH
sys.path.append(RESOLVE_MODULES_PATH)
# Import DaVinci Resolve scripting
import DaVinciResolveScript as dvr_script
def tc_to_frame(tc_str, fps):
"""Convert timecode string to frame number"""
if not tc_str:
return 0
# Handle timecode format "HH:MM:SS:FF"
parts = tc_str.split(":")
if len(parts) != 4:
return 0
hours = int(parts[0])
minutes = int(parts[1])
seconds = int(parts[2])
frames = int(parts[3])
total_frames = int(round(
(hours * 3600 + minutes * 60 + seconds) * fps + frames
))
return total_frames
def frame_to_tc(frame, fps):
"""Convert frame number to timecode string"""
total_seconds = frame / fps
hours = int(total_seconds // 3600)
minutes = int((total_seconds % 3600) // 60)
seconds = int(total_seconds % 60)
frames = int((total_seconds - int(total_seconds)) * fps)
return f"{hours:02d}:{minutes:02d}:{seconds:02d}:{frames:02d}"
def add_marker(timecode, color="Blue", note=""):
"""Add a marker at the specified timecode"""
print(f"Attempting to add {color} marker at {timecode} with note: {note}")
# Connect to Resolve
resolve = dvr_script.scriptapp("Resolve")
if not resolve:
print("Error: Failed to connect to DaVinci Resolve")
return False
print(f"Connected to: {resolve.GetProductName()} {resolve.GetVersionString()}")
# Get project manager
project_manager = resolve.GetProjectManager()
current_project = project_manager.GetCurrentProject()
if not current_project:
print("Error: No project currently open")
return False
# Get current timeline
current_timeline = current_project.GetCurrentTimeline()
if not current_timeline:
print("Error: No timeline currently active")
return False
timeline_name = current_timeline.GetName()
print(f"Timeline: {timeline_name}")
# Get frame rate
fps = float(current_timeline.GetSetting("timelineFrameRate"))
print(f"Frame rate: {fps} fps")
# Get timeline start timecode
start_tc = current_timeline.GetStartTimecode()
if not start_tc:
start_tc = "01:00:00:00" # Default
print(f"Timeline start timecode: {start_tc}")
# Convert input timecode to frame number
frame = tc_to_frame(timecode, fps)
print(f"Converted {timecode} to frame: {frame}")
# Validate color
valid_colors = [
"Blue", "Cyan", "Green", "Yellow", "Red", "Pink", "Purple", "Fuchsia",
"Rose", "Lavender", "Sky", "Mint", "Lemon", "Sand", "Cocoa", "Cream"
]
if color not in valid_colors:
print(f"Warning: Invalid color '{color}'. Using Blue instead.")
color = "Blue"
# Get clips to check if frame is valid
clips = []
for track_idx in range(1, 5): # Check first 4 video tracks
try:
track_clips = current_timeline.GetItemListInTrack("video", track_idx)
if track_clips and len(track_clips) > 0:
clips.extend(track_clips)
except:
continue
# Check if frame is within a clip
frame_in_clip = False
for clip in clips:
if clip.GetStart() <= frame <= clip.GetEnd():
frame_in_clip = True
clip_name = clip.GetName()
print(f"Frame {frame} is within clip: {clip_name}")
break
if not frame_in_clip:
print(f"Warning: Frame {frame} is not within any clip. Marker may not appear correctly.")
# Add the marker
print(f"Adding marker: Frame={frame}, Color={color}, Note='{note}'")
result = current_timeline.AddMarker(
frame,
color,
note or "Marker",
note,
1,
""
)
if result:
print(f"✓ Successfully added {color} marker at {timecode} (frame {frame})")
return True
else:
print(f"✗ Failed to add marker at {timecode} (frame {frame})")
# Check if a marker already exists at this frame
markers = current_timeline.GetMarkers() or {}
if frame in markers:
print(f"A marker already exists at frame {frame}.")
# Try alternate position
alt_frame = frame + 1
print(f"Trying alternate position: frame {alt_frame} ({frame_to_tc(alt_frame, fps)})")
alt_result = current_timeline.AddMarker(
alt_frame,
color,
note or "Marker",
note,
1,
""
)
if alt_result:
print(f"✓ Successfully added {color} marker at alternate position: {frame_to_tc(alt_frame, fps)} (frame {alt_frame})")
return True
return False
def main():
# Parse command line arguments
parser = argparse.ArgumentParser(description="Add a marker at a specific timecode position")
parser.add_argument("timecode", help="Timecode position (HH:MM:SS:FF)")
parser.add_argument("color", nargs="?", default="Blue", help="Marker color")
parser.add_argument("note", nargs="?", default="", help="Marker note")
args = parser.parse_args()
# Validate timecode format
if not args.timecode or len(args.timecode.split(":")) != 4:
print("Error: Invalid timecode format. Use HH:MM:SS:FF format.")
return
# Add the marker
success = add_marker(args.timecode, args.color, args.note)
print(f"\nMarker {'added successfully' if success else 'addition failed'}")
if __name__ == "__main__":
if len(sys.argv) < 2:
print(f"Usage: {sys.argv[0]} <timecode> [color] [note]")
print(f"Example: {sys.argv[0]} 01:00:15:00 Red \"My marker note\"")
sys.exit(1)
main()
```
--------------------------------------------------------------------------------
/INSTALL.md:
--------------------------------------------------------------------------------
```markdown
# DaVinci Resolve MCP Integration - Installation Guide
This guide provides step-by-step instructions for installing and configuring the DaVinci Resolve MCP integration for use with Cursor AI. The integration allows Cursor AI to control DaVinci Resolve through its API.
## Prerequisites
- DaVinci Resolve installed (Free or Studio version)
- Python 3.9+ installed
- Cursor AI installed
## Installation Steps
### 1. New One-Step Installation (Recommended)
We now provide a unified installation script that handles everything automatically, with robust error detection and configuration:
**macOS/Linux:**
```bash
# Make sure DaVinci Resolve is running, then:
./install.sh
```
**Windows:**
```bash
# Make sure DaVinci Resolve is running, then:
install.bat
```
This new installation script will:
- Detect the correct installation path automatically
- Create the Python virtual environment
- Install all required dependencies
- Set up environment variables
- Generate the correct Cursor MCP configuration
- Verify the installation
- Optionally start the server if everything is correct
### 2. Quick Start (Alternative)
The earlier quick start scripts are still available:
**macOS/Linux:**
```bash
# Make sure DaVinci Resolve is already running before executing this script
./run-now.sh
```
**Windows:**
```bash
# Make sure DaVinci Resolve is already running before executing this script
run-now.bat
```
### 3. Manual Setup (Advanced)
If you prefer to set up the integration manually or if you encounter issues with the automatic methods:
#### Step 3.1: Create a Python Virtual Environment
```bash
python3 -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
```
#### Step 3.2: Install Dependencies
```bash
# Install all required dependencies from requirements.txt
pip install -r requirements.txt
```
Alternatively, you can install just the MCP SDK:
```bash
pip install "mcp[cli]"
```
#### Step 3.3: Set Environment Variables
On macOS/Linux, add the following to your `~/.zshrc` or `~/.bashrc`:
```bash
export RESOLVE_SCRIPT_API="/Library/Application Support/Blackmagic Design/DaVinci Resolve/Developer/Scripting"
export RESOLVE_SCRIPT_LIB="/Applications/DaVinci Resolve/DaVinci Resolve.app/Contents/Libraries/Fusion/fusionscript.so"
export PYTHONPATH="$PYTHONPATH:$RESOLVE_SCRIPT_API/Modules/"
```
On Windows, set these environment variables in PowerShell or through System Properties:
```powershell
$env:RESOLVE_SCRIPT_API = "C:\ProgramData\Blackmagic Design\DaVinci Resolve\Support\Developer\Scripting"
$env:RESOLVE_SCRIPT_LIB = "C:\Program Files\Blackmagic Design\DaVinci Resolve\fusionscript.dll"
$env:PYTHONPATH = "$env:PYTHONPATH;$env:RESOLVE_SCRIPT_API\Modules\"
```
#### Step 3.4: Configure Cursor
The installation creates two MCP configuration files:
**System-level configuration**:
- macOS/Linux: `~/.cursor/mcp/config.json`
- Windows: `%APPDATA%\Cursor\mcp\config.json`
**Project-level configuration**:
- In the project root: `.cursor/mcp.json`
Both configurations use absolute paths to the Python interpreter and script. This ensures Cursor can find the correct files regardless of how the project is opened.
#### Sample configuration:
```json
{
"mcpServers": {
"davinci-resolve": {
"name": "DaVinci Resolve MCP",
"command": "/Users/username/davinci-resolve-mcp/venv/bin/python",
"args": ["/Users/username/davinci-resolve-mcp/resolve_mcp_server.py"]
}
}
}
```
The installation scripts automatically create both configuration files with the correct absolute paths for your system. If you need to move the project to a new location, you'll need to run the installation script again to update the paths.
### 4. Start the Integration
For a more controlled setup with additional options:
**macOS/Linux:**
```bash
# From the scripts directory
cd scripts
./mcp_resolve-cursor_start
```
### 5. Verify Your Installation
After completing the installation steps, you can verify that everything is set up correctly by running:
**macOS/Linux:**
```bash
./scripts/verify-installation.sh
```
**Windows:**
```bash
scripts\verify-installation.bat
```
This verification script checks:
- Python virtual environment setup
- MCP SDK installation
- DaVinci Resolve running status
- Cursor configuration
- Environment variables
- Server script presence
If all checks pass, you're ready to use the integration. If any checks fail, the script will provide guidance on how to fix the issues.
## Troubleshooting
### DaVinci Resolve Detection Issues
If the script cannot detect that DaVinci Resolve is running:
1. Make sure DaVinci Resolve is actually running before executing scripts
2. The detection method has been updated to use `ps -ef | grep -i "[D]aVinci Resolve"` instead of `pgrep`, which provides more reliable detection
### Path Resolution Issues
If you see errors related to file paths:
1. The scripts now use the directory where they're located as the reference point
2. Check that the `resolve_mcp_server.py` file exists in the expected location
3. Verify that your Cursor MCP configuration points to the correct paths
4. If you move the project to a new location, you'll need to run the installation script again to update the paths
### Environment Variables
If you encounter Python import errors:
1. Verify that the environment variables are correctly set
2. The paths may differ depending on your DaVinci Resolve installation location
3. You can check the log file at `scripts/cursor_resolve_server.log` for details
### Cursor Configuration Issues
If Cursor isn't connecting to the MCP server:
1. Check both the system-level and project-level configuration files
2. Ensure the paths in the configurations match your actual installation
3. The absolute paths must be correct - verify they point to your actual installation location
4. After moving the project, run `./install.sh` or `install.bat` again to update the paths
## Configuration Reference
The integration creates two configuration files:
1. **System-level config** (for global use): `~/.cursor/mcp/config.json` (macOS/Linux) or `%APPDATA%\Cursor\mcp\config.json` (Windows)
2. **Project-level config** (for specific project use): `.cursor/mcp.json` in the project root
Both configurations have the same structure:
```json
{
"mcpServers": {
"davinci-resolve": {
"name": "DaVinci Resolve MCP",
"command": "<absolute-path-to-python-interpreter>",
"args": ["<absolute-path-to-resolve_mcp_server.py>"]
}
}
}
```
## Support
If you encounter any issues not covered in this guide, please file an issue on the GitHub repository.
```
--------------------------------------------------------------------------------
/examples/markers/add_spaced_markers.py:
--------------------------------------------------------------------------------
```python
#!/usr/bin/env python3
"""
Add markers at regular intervals using proper timecode conversion
This script adds markers at specified intervals starting from a given timecode
"""
import os
import sys
import argparse
# Set environment variables for DaVinci Resolve scripting
RESOLVE_API_PATH = "/Library/Application Support/Blackmagic Design/DaVinci Resolve/Developer/Scripting"
RESOLVE_LIB_PATH = "/Applications/DaVinci Resolve/DaVinci Resolve.app/Contents/Libraries/Fusion/fusionscript.so"
RESOLVE_MODULES_PATH = os.path.join(RESOLVE_API_PATH, "Modules")
os.environ["RESOLVE_SCRIPT_API"] = RESOLVE_API_PATH
os.environ["RESOLVE_SCRIPT_LIB"] = RESOLVE_LIB_PATH
sys.path.append(RESOLVE_MODULES_PATH)
# Import DaVinci Resolve scripting
import DaVinciResolveScript as dvr_script
def tc_to_frame(tc_str, fps):
"""Convert timecode string to frame number"""
if not tc_str:
return 0
# Handle timecode format "HH:MM:SS:FF"
parts = tc_str.split(":")
if len(parts) != 4:
return 0
hours = int(parts[0])
minutes = int(parts[1])
seconds = int(parts[2])
frames = int(parts[3])
total_frames = int(round(
(hours * 3600 + minutes * 60 + seconds) * fps + frames
))
return total_frames
def frame_to_tc(frame, fps):
"""Convert frame number to timecode string"""
total_seconds = frame / fps
hours = int(total_seconds // 3600)
minutes = int((total_seconds % 3600) // 60)
seconds = int(total_seconds % 60)
frames = int((total_seconds - int(total_seconds)) * fps)
return f"{hours:02d}:{minutes:02d}:{seconds:02d}:{frames:02d}"
def add_markers(start_tc="01:00:00:00", interval_seconds=10, count=7, clear_existing=True):
"""Add markers at regular intervals"""
print(f"\n===== ADDING {count} MARKERS AT {interval_seconds}-SECOND INTERVALS =====\n")
print(f"Starting at: {start_tc}")
# Connect to Resolve
resolve = dvr_script.scriptapp("Resolve")
if not resolve:
print("Error: Failed to connect to DaVinci Resolve")
return
print(f"Connected to: {resolve.GetProductName()} {resolve.GetVersionString()}")
# Get project manager
project_manager = resolve.GetProjectManager()
current_project = project_manager.GetCurrentProject()
if not current_project:
print("Error: No project currently open")
return
print(f"Current project: {current_project.GetName()}")
# Get current timeline
current_timeline = current_project.GetCurrentTimeline()
if not current_timeline:
print("Error: No timeline currently active")
return
timeline_name = current_timeline.GetName()
print(f"Timeline: {timeline_name}")
# Get frame rate
fps = float(current_timeline.GetSetting("timelineFrameRate"))
print(f"Frame rate: {fps} fps")
# Get timeline start timecode
timeline_start_tc = current_timeline.GetStartTimecode()
if not timeline_start_tc:
timeline_start_tc = "01:00:00:00" # Default
print(f"Timeline start timecode: {timeline_start_tc}")
# Clear existing markers if requested
if clear_existing:
existing_markers = current_timeline.GetMarkers() or {}
print(f"Clearing {len(existing_markers)} existing markers")
for frame in existing_markers:
current_timeline.DeleteMarkerAtFrame(frame)
# Get clips to check if frames are valid
clips = []
for track_idx in range(1, 5): # Check first 4 video tracks
try:
track_clips = current_timeline.GetItemListInTrack("video", track_idx)
if track_clips and len(track_clips) > 0:
clips.extend(track_clips)
except:
continue
if not clips:
print("Error: No clips found in timeline")
return
# Convert start timecode to frame
start_frame = tc_to_frame(start_tc, fps)
print(f"Start position: {start_tc} (frame {start_frame})")
# Define colors
colors = ["Blue", "Red", "Green", "Yellow", "Purple", "Cyan", "Pink"]
# Calculate interval in frames
interval_frames = int(interval_seconds * fps)
print(f"Interval: {interval_seconds} seconds ({interval_frames} frames)")
# Add markers
print("\n--- Adding Markers ---")
markers_added = 0
for i in range(count):
# Calculate frame position
frame = start_frame + (i * interval_frames)
target_tc = frame_to_tc(frame, fps)
# Validate frame is within a clip
frame_in_clip = False
clip_name = ""
for clip in clips:
if clip.GetStart() <= frame <= clip.GetEnd():
frame_in_clip = True
clip_name = clip.GetName()
break
if not frame_in_clip:
print(f"Skipping position {target_tc} (frame {frame}): Not within any clip")
continue
# Select color
color_index = i % len(colors)
color = colors[color_index]
# Create marker note
note = f"Marker {i+1}: {interval_seconds*i} seconds from start"
print(f"Adding {color} marker at {target_tc} (frame {frame}) in clip: {clip_name}")
result = current_timeline.AddMarker(
frame,
color,
note,
note,
1,
""
)
if result:
print(f"✓ Successfully added marker")
markers_added += 1
else:
print(f"✗ Failed to add marker - checking if position already has a marker")
# Check if a marker already exists
markers = current_timeline.GetMarkers() or {}
if frame in markers:
# Try alternate position
alt_frame = frame + 1
alt_tc = frame_to_tc(alt_frame, fps)
print(f"Trying alternate position: {alt_tc} (frame {alt_frame})")
alt_result = current_timeline.AddMarker(
alt_frame,
color,
note,
note,
1,
""
)
if alt_result:
print(f"✓ Successfully added marker at alternate position")
markers_added += 1
# Get final count of markers
final_markers = current_timeline.GetMarkers() or {}
print(f"\nAdded {markers_added} new markers")
print(f"Timeline now has {len(final_markers)} total markers")
print("\n===== COMPLETED =====")
def main():
# Parse command line arguments
parser = argparse.ArgumentParser(description="Add markers at regular intervals")
parser.add_argument("--start", "-s", default="01:00:00:00", help="Start timecode (HH:MM:SS:FF)")
parser.add_argument("--interval", "-i", type=int, default=10, help="Interval in seconds between markers")
parser.add_argument("--count", "-c", type=int, default=7, help="Number of markers to add")
parser.add_argument("--keep", "-k", action="store_true", help="Keep existing markers (don't clear)")
args = parser.parse_args()
# Validate timecode format
if len(args.start.split(":")) != 4:
print("Error: Invalid start timecode format. Use HH:MM:SS:FF format.")
return
# Add the markers
add_markers(args.start, args.interval, args.count, not args.keep)
if __name__ == "__main__":
main()
```
--------------------------------------------------------------------------------
/src/utils/object_inspection.py:
--------------------------------------------------------------------------------
```python
#!/usr/bin/env python3
"""
DaVinci Resolve MCP Server - Object Inspection Utilities
This module provides functions for inspecting DaVinci Resolve API objects:
- Exploring available methods and properties
- Generating structured documentation
- Inspecting nested objects
- Converting between Python and Lua objects if needed
"""
import sys
import inspect
from typing import Any, Dict, List, Optional, Union, Callable
def get_object_methods(obj: Any) -> Dict[str, Dict[str, Any]]:
"""
Get all methods of a DaVinci Resolve object with their documentation.
Args:
obj: A DaVinci Resolve API object
Returns:
A dictionary of method names and their details
"""
if obj is None:
return {"error": "Cannot inspect None object"}
methods = {}
# Get all object attributes
for attr_name in dir(obj):
# Skip private/internal attributes
if attr_name.startswith('_'):
continue
try:
attr = getattr(obj, attr_name)
# Check if it's a callable method
if callable(attr):
# Get the method signature if possible
try:
signature = str(inspect.signature(attr))
except (ValueError, TypeError):
signature = "()"
# Get the docstring if available
doc = inspect.getdoc(attr) or ""
methods[attr_name] = {
"signature": signature,
"doc": doc,
"type": "method"
}
except Exception as e:
methods[attr_name] = {
"error": str(e),
"type": "error"
}
return methods
def get_object_properties(obj: Any) -> Dict[str, Dict[str, Any]]:
"""
Get all properties (non-callable attributes) of a DaVinci Resolve object.
Args:
obj: A DaVinci Resolve API object
Returns:
A dictionary of property names and their details
"""
if obj is None:
return {"error": "Cannot inspect None object"}
properties = {}
# Get all object attributes
for attr_name in dir(obj):
# Skip private/internal attributes
if attr_name.startswith('_'):
continue
try:
attr = getattr(obj, attr_name)
# Skip if it's a method
if callable(attr):
continue
# Get the property value and type
properties[attr_name] = {
"value": str(attr),
"type": type(attr).__name__,
"type_category": "property"
}
except Exception as e:
properties[attr_name] = {
"error": str(e),
"type_category": "error"
}
return properties
def inspect_object(obj: Any, max_depth: int = 1) -> Dict[str, Any]:
"""
Inspect a DaVinci Resolve API object and return its methods and properties.
Args:
obj: A DaVinci Resolve API object
max_depth: Maximum depth for nested object inspection
Returns:
A dictionary containing the object's methods and properties
"""
if obj is None:
return {"error": "Cannot inspect None object"}
result = {
"type": type(obj).__name__,
"methods": get_object_methods(obj),
"properties": get_object_properties(obj),
}
# Add string representation
try:
result["str"] = str(obj)
except Exception as e:
result["str_error"] = str(e)
# Add repr representation
try:
result["repr"] = repr(obj)
except Exception as e:
result["repr_error"] = str(e)
return result
def get_lua_table_keys(lua_table: Any) -> List[str]:
"""
Get all keys from a Lua table object (if the object supports Lua table iteration).
Args:
lua_table: A Lua table object from DaVinci Resolve API
Returns:
A list of keys from the Lua table
"""
if lua_table is None:
return []
keys = []
# Check for DaVinci-specific Lua table iteration methods
if hasattr(lua_table, 'GetKeyList'):
try:
# Some DaVinci Resolve objects have a GetKeyList() method
return lua_table.GetKeyList()
except:
pass
# Try different iteration methods that might work with Lua tables
try:
# Some Lua tables can be iterated directly
for key in lua_table:
keys.append(key)
return keys
except:
pass
# Try manual iteration with pairs-like behavior (if available)
# This is a fallback for APIs that don't support Python-style iteration
return []
def convert_lua_to_python(lua_obj: Any) -> Any:
"""
Convert a Lua object from DaVinci Resolve API to a Python object.
Args:
lua_obj: A Lua object from DaVinci Resolve API
Returns:
The converted Python object
"""
# Handle None
if lua_obj is None:
return None
# Handle primitive types
if isinstance(lua_obj, (str, int, float, bool)):
return lua_obj
# Try to convert Lua tables to Python dicts or lists
if hasattr(lua_obj, 'GetKeyList') or hasattr(lua_obj, '__iter__'):
keys = get_lua_table_keys(lua_obj)
# If we found keys, convert to dict
if keys:
result = {}
for key in keys:
try:
# Get the value for this key
value = lua_obj[key]
# Recursively convert nested Lua objects
result[key] = convert_lua_to_python(value)
except:
result[key] = None
return result
# Try to convert to list if it appears numeric-indexed
try:
# Common Lua pattern for numeric arrays (1-indexed)
result = []
index = 1 # Lua arrays typically start at 1
while True:
try:
value = lua_obj[index]
result.append(convert_lua_to_python(value))
index += 1
except:
break
# If we found items, return as list
if result:
return result
except:
pass
# If conversion failed, return string representation
return str(lua_obj)
def print_object_help(obj: Any) -> str:
"""
Generate a human-readable help string for a DaVinci Resolve API object.
Args:
obj: A DaVinci Resolve API object
Returns:
A formatted help string describing the object's methods and properties
"""
if obj is None:
return "Cannot provide help for None object"
obj_type = type(obj).__name__
methods = get_object_methods(obj)
properties = get_object_properties(obj)
help_text = [f"Help for {obj_type} object:"]
help_text.append("\n" + "=" * 40 + "\n")
# Add methods
if methods:
help_text.append("METHODS:")
help_text.append("-" * 40)
for name, info in sorted(methods.items()):
if "error" in info:
continue
signature = info.get("signature", "()")
doc = info.get("doc", "").strip()
help_text.append(f"{name}{signature}")
if doc:
help_text.append(f" {doc}\n")
else:
help_text.append("")
# Add properties
if properties:
help_text.append("\nPROPERTIES:")
help_text.append("-" * 40)
for name, info in sorted(properties.items()):
if "error" in info:
continue
value = info.get("value", "")
type_name = info.get("type", "")
help_text.append(f"{name}: {type_name} = {value}")
return "\n".join(help_text)
```
--------------------------------------------------------------------------------
/scripts/mcp_resolve_launcher.sh:
--------------------------------------------------------------------------------
```bash
#!/bin/bash
# mcp_resolve_launcher.sh
# Interactive launcher script for DaVinci Resolve MCP servers
# Allows selecting which server(s) to start or stop
# Colors for terminal output
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
BLUE='\033[0;34m'
RED='\033[0;31m'
NC='\033[0m' # No Color
BOLD='\033[1m'
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
CURSOR_SCRIPT="$SCRIPT_DIR/mcp_resolve-cursor_start"
CLAUDE_SCRIPT="$SCRIPT_DIR/mcp_resolve-claude_start"
# Get repository root directory (parent of scripts directory)
REPO_ROOT="$( cd "$SCRIPT_DIR/.." &> /dev/null && pwd )"
# Display banner
echo -e "${BLUE}=============================================${NC}"
echo -e "${BLUE} DaVinci Resolve - MCP Server Launcher ${NC}"
echo -e "${BLUE}=============================================${NC}"
# Check if DaVinci Resolve is running
check_resolve_running() {
# Try to detect with pgrep
if pgrep -q "Resolve"; then
echo -e "${GREEN}✓ DaVinci Resolve is running${NC}"
return 0
fi
# Fallback: use ps to check for Resolve process
if ps -ef | grep -q "[R]esolve" || ps -ef | grep -q "[D]aVinci Resolve"; then
echo -e "${GREEN}✓ DaVinci Resolve is running${NC}"
return 0
fi
echo -e "${RED}✗ DaVinci Resolve is not running${NC}"
echo -e "${YELLOW}Please start DaVinci Resolve before continuing${NC}"
return 1
}
# Find server PIDs
find_server_pids() {
# Look for cursor server (using mcp dev with resolve_mcp_server.py)
CURSOR_PID=$(pgrep -f "mcp dev.*resolve_mcp_server.py" | head -1)
# Look for Claude server (using mcp dev with resolve_mcp_server.py)
CLAUDE_PID=$(pgrep -f "mcp dev.*resolve_mcp_server.py" | head -1)
# If both are found and they're the same, set one to empty
if [ "$CURSOR_PID" = "$CLAUDE_PID" ] && [ -n "$CURSOR_PID" ]; then
# We need to disambiguate - look at log files
if ps -p "$CURSOR_PID" -o command= | grep -q "cursor"; then
CLAUDE_PID=""
else
# If we can't determine, just assume it's the Cursor server
CLAUDE_PID=""
fi
fi
}
# Display server status
show_status() {
find_server_pids
echo -e "\n${BOLD}Current Server Status:${NC}"
if [ -n "$CURSOR_PID" ]; then
echo -e "${GREEN}● Cursor MCP Server: Running (PID: $CURSOR_PID)${NC}"
else
echo -e "${RED}○ Cursor MCP Server: Not running${NC}"
fi
if [ -n "$CLAUDE_PID" ]; then
echo -e "${GREEN}● Claude Desktop MCP Server: Running (PID: $CLAUDE_PID)${NC}"
else
echo -e "${RED}○ Claude Desktop MCP Server: Not running${NC}"
fi
echo ""
}
# Stop server by PID
stop_server() {
local pid=$1
local name=$2
if [ -n "$pid" ]; then
echo -e "${YELLOW}Stopping $name MCP Server (PID: $pid)...${NC}"
kill "$pid" 2>/dev/null
# Wait for process to exit
for i in {1..5}; do
if ! ps -p "$pid" > /dev/null 2>&1; then
echo -e "${GREEN}✓ $name MCP Server stopped${NC}"
return 0
fi
sleep 1
done
# Force kill if still running
echo -e "${YELLOW}Server still running. Force killing...${NC}"
kill -9 "$pid" 2>/dev/null
echo -e "${GREEN}✓ $name MCP Server force stopped${NC}"
else
echo -e "${YELLOW}$name MCP Server is not running${NC}"
fi
}
# Start Cursor server
start_cursor() {
local force_flag=""
local project_flag=""
if [ "$1" = "force" ]; then
force_flag="--force"
fi
if [ -n "$2" ]; then
project_flag="--project \"$2\""
fi
echo -e "${YELLOW}Starting Cursor MCP Server...${NC}"
# Check if script exists
if [ ! -f "$CURSOR_SCRIPT" ]; then
echo -e "${RED}✗ Cursor startup script not found: $CURSOR_SCRIPT${NC}"
return 1
fi
# Execute the script
command="$CURSOR_SCRIPT $force_flag $project_flag"
eval "$command" &
echo -e "${GREEN}✓ Cursor MCP Server starting in the background${NC}"
}
# Start Claude server
start_claude() {
local force_flag=""
local project_flag=""
if [ "$1" = "force" ]; then
force_flag="--force"
fi
if [ -n "$2" ]; then
project_flag="--project \"$2\""
fi
echo -e "${YELLOW}Starting Claude Desktop MCP Server...${NC}"
# Check if script exists
if [ ! -f "$CLAUDE_SCRIPT" ]; then
echo -e "${RED}✗ Claude Desktop startup script not found: $CLAUDE_SCRIPT${NC}"
return 1
fi
# Execute the script
command="$CLAUDE_SCRIPT $force_flag $project_flag"
eval "$command" &
echo -e "${GREEN}✓ Claude Desktop MCP Server starting in the background${NC}"
}
# Interactive menu
show_menu() {
echo -e "${BOLD}DaVinci Resolve MCP Server Launcher${NC}"
echo -e "${YELLOW}Select an option:${NC}"
echo "1) Start Cursor MCP Server"
echo "2) Start Claude Desktop MCP Server"
echo "3) Start both servers"
echo "4) Stop Cursor MCP Server"
echo "5) Stop Claude Desktop MCP Server"
echo "6) Stop both servers"
echo "7) Show server status"
echo "8) Exit"
echo -e "${YELLOW}Enter your choice [1-8]:${NC} "
}
# Process menu selection
process_selection() {
local choice="$1"
local force_mode="$2"
local project_name="$3"
case "$choice" in
1)
find_server_pids
if [ -n "$CURSOR_PID" ]; then
echo -e "${YELLOW}Cursor MCP Server is already running (PID: $CURSOR_PID)${NC}"
echo -e "${YELLOW}Stop it first before starting a new instance.${NC}"
else
start_cursor "$force_mode" "$project_name"
fi
;;
2)
find_server_pids
if [ -n "$CLAUDE_PID" ]; then
echo -e "${YELLOW}Claude Desktop MCP Server is already running (PID: $CLAUDE_PID)${NC}"
echo -e "${YELLOW}Stop it first before starting a new instance.${NC}"
else
start_claude "$force_mode" "$project_name"
fi
;;
3)
find_server_pids
if [ -n "$CURSOR_PID" ]; then
echo -e "${YELLOW}Cursor MCP Server is already running (PID: $CURSOR_PID)${NC}"
else
start_cursor "$force_mode" "$project_name"
fi
if [ -n "$CLAUDE_PID" ]; then
echo -e "${YELLOW}Claude Desktop MCP Server is already running (PID: $CLAUDE_PID)${NC}"
else
start_claude "$force_mode" "$project_name"
fi
;;
4)
find_server_pids
stop_server "$CURSOR_PID" "Cursor"
;;
5)
find_server_pids
stop_server "$CLAUDE_PID" "Claude Desktop"
;;
6)
find_server_pids
stop_server "$CURSOR_PID" "Cursor"
stop_server "$CLAUDE_PID" "Claude Desktop"
;;
7)
show_status
;;
8)
echo -e "${GREEN}Exiting. Goodbye!${NC}"
exit 0
;;
*)
echo -e "${RED}Invalid option. Please try again.${NC}"
;;
esac
}
# Check command line arguments
PROJECT_NAME=""
FORCE_MODE=""
MENU_OPTION=""
while [[ $# -gt 0 ]]; do
case $1 in
--project|-p)
PROJECT_NAME="$2"
echo -e "${YELLOW}Will use project: $2${NC}"
shift 2
;;
--force|-f)
FORCE_MODE="force"
echo -e "${YELLOW}Force mode enabled: Will skip Resolve running check${NC}"
shift
;;
--start-cursor)
MENU_OPTION="1"
shift
;;
--start-claude)
MENU_OPTION="2"
shift
;;
--start-both)
MENU_OPTION="3"
shift
;;
--stop-cursor)
MENU_OPTION="4"
shift
;;
--stop-claude)
MENU_OPTION="5"
shift
;;
--stop-all)
MENU_OPTION="6"
shift
;;
--status)
MENU_OPTION="7"
shift
;;
*)
echo -e "${YELLOW}Unknown argument: $1${NC}"
shift
;;
esac
done
# Check Resolve is running (unless we're stopping servers)
if [[ "$FORCE_MODE" != "force" && "$MENU_OPTION" != "4" && "$MENU_OPTION" != "5" && "$MENU_OPTION" != "6" && "$MENU_OPTION" != "7" ]]; then
check_resolve_running
fi
# Non-interactive mode if an option was provided via command line
if [ -n "$MENU_OPTION" ]; then
process_selection "$MENU_OPTION" "$FORCE_MODE" "$PROJECT_NAME"
exit 0
fi
# Interactive mode
while true; do
show_status
show_menu
read -r choice
process_selection "$choice" "$FORCE_MODE" "$PROJECT_NAME"
echo -e "\nPress Enter to continue..."
read -r
clear
done
```