#
tokens: 49781/50000 66/85 files (page 1/4)
lines: off (toggle) GitHub
raw markdown copy
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

[![Version](https://img.shields.io/badge/version-1.3.8-blue.svg)](https://github.com/samuelgursky/davinci-resolve-mcp/releases)
[![DaVinci Resolve](https://img.shields.io/badge/DaVinci%20Resolve-18.5+-darkred.svg)](https://www.blackmagicdesign.com/products/davinciresolve)
[![Python](https://img.shields.io/badge/python-3.6+-green.svg)](https://www.python.org/downloads/)
[![macOS](https://img.shields.io/badge/macOS-stable-brightgreen.svg)](https://www.apple.com/macos/)
[![Windows](https://img.shields.io/badge/Windows-stable-brightgreen.svg)](https://www.microsoft.com/windows)
[![License](https://img.shields.io/badge/license-MIT-blue.svg)](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 
```
Page 1/4FirstPrevNextLast