About Kdenlive Automation
Kdenlive Automation is an MCP server published by IO-AtelierTech in the Developer Tools category: python packages for automating Kdenlive video editor via JSON-RPC. It has been installed 0 times through Conduid.
The repository has 3 stars and 0 forks, with the last commit 8 months ago. Six months or more without a commit doesn't mean the server is broken, but check the open issues (0) before depending on it in production.
Install
npx kdenlive-automationThis server has no ConduID identity, so agent calls to it are not receipted. Pin the version you install and review the source before granting it credentials.
Ask AI
Ask AI about Kdenlive Automation
Powered by Claude · Grounded in docs
Security checks
- ·README presentNot checked yet.
- ·License declaredNot checked yet.
- ·Tests presentNot checked yet.
- ·Dependencies pinnedNot checked yet.
- ·No dynamic code executionNot checked yet.
- !Scoped permissionsDoesn't declare a permission scope. Assume it can do anything its process can.
README
Kdenlive Automation
Python packages for automating Kdenlive video editor via JSON-RPC over WebSocket.
Packages
| Package | Description | PyPI |
|---|---|---|
| kdenlive-api | Python client library for programmatic control of Kdenlive | |
| kdenlive-mcp | MCP server for AI assistant integration (Claude, etc.) |
Requirements
- Python 3.11+
- Kdenlive with WebSocket server enabled (built from
IO-AtelierTech/kdenlive) - uv for package management (recommended)
Installation
From PyPI
# Client library only
pip install kdenlive-api
# MCP server (includes kdenlive-api)
pip install kdenlive-mcp
From Source
git clone https://github.com/IO-AtelierTech/kdenlive-automation.git
cd kdenlive-automation
# Install both packages in development mode
uv sync
Quick Start
Using kdenlive-api
import asyncio
from kdenlive_api import KdenliveClient
async def main():
async with KdenliveClient() as kdenlive:
# Get project info
info = await kdenlive.project.get_info()
print(f"Project: {info.name} ({info.width}x{info.height} @ {info.fps}fps)")
# Import media files
clip_ids = await kdenlive.bin.import_clips([
"/path/to/video1.mp4",
"/path/to/video2.mp4"
])
# Add clip to timeline
timeline_clip_id = await kdenlive.timeline.insert_clip(
bin_clip_id=clip_ids[0],
track_id=1,
position=0
)
# Apply an effect
await kdenlive.effects.add(
effect_id="brightness",
clip_id=timeline_clip_id
)
# Set effect property
await kdenlive.effects.set_property(
clip_id=timeline_clip_id,
effect_id="brightness",
property="level",
value=1.2
)
# Render the project
job = await kdenlive.render.start(
preset_name="YouTube 1080p",
output_path="/path/to/output.mp4"
)
# Monitor render progress
async for progress in kdenlive.render.watch(job.job_id):
print(f"Rendering: {progress.progress}%")
print("Done!")
asyncio.run(main())
Using kdenlive-mcp with Claude
Start the MCP server:
kdenlive-mcp
Or run directly:
uv run kdenlive-mcp
See MCP Configuration Guide for Claude Desktop setup.
API Namespaces
project
Project lifecycle management.
await kdenlive.project.open("/path/to/project.kdenlive")
await kdenlive.project.save()
await kdenlive.project.close(save_changes=True)
await kdenlive.project.new(profile="atsc_1080p_25")
await kdenlive.project.undo()
await kdenlive.project.redo()
info = await kdenlive.project.get_info()
timeline
Timeline operations and clip manipulation.
# Get timeline state
info = await kdenlive.timeline.get_info()
tracks = await kdenlive.timeline.get_tracks()
clips = await kdenlive.timeline.get_clips(track_id=1)
position = await kdenlive.timeline.get_position()
# Manipulate clips
clip_id = await kdenlive.timeline.insert_clip(bin_clip_id, track_id, position)
await kdenlive.timeline.move_clip(clip_id, new_track_id, new_position)
await kdenlive.timeline.resize_clip(clip_id, in_point=10, out_point=200)
new_clips = await kdenlive.timeline.split_clip(clip_id, position=125)
await kdenlive.timeline.delete_clip(clip_id)
# Track management
track_id = await kdenlive.timeline.add_track("video", name="VFX")
await kdenlive.timeline.set_track_property(track_id, "locked", True)
await kdenlive.timeline.delete_track(track_id)
# Navigation
await kdenlive.timeline.seek(1500)
await kdenlive.timeline.set_selection([clip_id1, clip_id2])
bin
Media bin and clip management.
# List contents
clips = await kdenlive.bin.list_clips(folder_id="folder1")
folders = await kdenlive.bin.list_folders()
clip_info = await kdenlive.bin.get_clip_info(clip_id)
# Import media
clip_id = await kdenlive.bin.import_clip("/path/to/video.mp4")
clip_ids = await kdenlive.bin.import_clips(["/path/to/a.mp4", "/path/to/b.mp4"])
# Organize
folder_id = await kdenlive.bin.create_folder("B-Roll", parent_id="folder1")
await kdenlive.bin.rename_item(clip_id, "New Name")
await kdenlive.bin.move_item(clip_id, target_folder_id="folder2")
await kdenlive.bin.delete_clip(clip_id)
await kdenlive.bin.delete_folder(folder_id)
# Markers
markers = await kdenlive.bin.get_clip_markers(clip_id)
marker_id = await kdenlive.bin.add_clip_marker(clip_id, position=100, comment="Good take")
await kdenlive.bin.delete_clip_marker(clip_id, marker_id)
effects
Effect application and keyframe animation.
# Browse effects
effects = await kdenlive.effects.list_available()
effect_info = await kdenlive.effects.get_info("brightness")
# Apply effects
effect_id = await kdenlive.effects.add("brightness", clip_id)
clip_effects = await kdenlive.effects.get_clip_effects(clip_id)
await kdenlive.effects.enable(clip_id, effect_id)
await kdenlive.effects.disable(clip_id, effect_id)
await kdenlive.effects.remove(clip_id, effect_id)
# Properties
value = await kdenlive.effects.get_property(clip_id, effect_id, "level")
await kdenlive.effects.set_property(clip_id, effect_id, "level", 1.5)
# Keyframes
keyframes = await kdenlive.effects.get_keyframes(clip_id, effect_id, "level")
await kdenlive.effects.set_keyframe(clip_id, effect_id, "level", position=50, value=1.2)
await kdenlive.effects.delete_keyframe(clip_id, effect_id, "level", position=50)
# Batch operations
await kdenlive.effects.copy_to_clips(source_clip_id, effect_id, [target1, target2])
await kdenlive.effects.reorder(clip_id, effect_id, new_index=0)
render
Render job management.
# Presets
presets = await kdenlive.render.get_presets()
preset_info = await kdenlive.render.get_preset_info("YouTube 1080p")
# Render
job = await kdenlive.render.start("YouTube 1080p", "/output/video.mp4")
jobs = await kdenlive.render.start_with_guides("YouTube 1080p", "/output/")
# Monitor
status = await kdenlive.render.get_status(job.job_id)
active = await kdenlive.render.get_active_job()
all_jobs = await kdenlive.render.get_jobs()
# Control
await kdenlive.render.stop(job.job_id)
await kdenlive.render.stop_all()
# Stream progress
async for progress in kdenlive.render.watch(job.job_id):
print(f"{progress.progress}% - Frame {progress.frame}/{progress.total_frames}")
asset
Asset discovery and favorites.
categories = await kdenlive.asset.list_categories()
results = await kdenlive.asset.search("blur")
effects = await kdenlive.asset.get_effects_by_category("video")
# Favorites
favorites = await kdenlive.asset.get_favorites()
await kdenlive.asset.add_favorite("brightness")
await kdenlive.asset.remove_favorite("brightness")
# Effect presets
presets = await kdenlive.asset.get_presets("brightness")
await kdenlive.asset.save_preset("brightness", "My Preset")
await kdenlive.asset.delete_preset("brightness", "My Preset")
transition
Transition management between clips.
types = await kdenlive.transition.list()
transition = await kdenlive.transition.add("dissolve", from_clip_id, to_clip_id)
props = await kdenlive.transition.get_properties(transition.id)
await kdenlive.transition.set_property(transition.id, "duration", 25)
await kdenlive.transition.remove(transition.id)
composition
Composition (track blending) operations.
compositions = await kdenlive.composition.list()
comp = await kdenlive.composition.add("qtblend", track_id=2, position=0)
props = await kdenlive.composition.get_properties(comp.id)
await kdenlive.composition.set_property(comp.id, "opacity", 80)
await kdenlive.composition.remove(comp.id)
Mock Mode
Develop and test without a running Kdenlive instance:
# Enable mock mode
client = KdenliveClient(mock=True)
async with client:
# Returns mock data
info = await client.project.get_info()
print(info.name) # "Mock Project"
Connection Options
client = KdenliveClient(
url="ws://localhost:9876", # WebSocket URL
mock=False, # Use mock mode
reconnect=True, # Auto-reconnect on disconnect
reconnect_delay=1.0, # Seconds between reconnect attempts
)
Error Handling
from kdenlive_api.exceptions import (
KdenliveError,
ConnectionError,
ProjectNotOpenError,
ClipNotFoundError,
TrackNotFoundError,
EffectNotFoundError,
RenderInProgressError,
)
try:
await kdenlive.timeline.delete_clip(999)
except ClipNotFoundError:
print("Clip does not exist")
except KdenliveError as e:
print(f"Kdenlive error: {e}")
Documentation
- API Reference - Complete API documentation
- MCP Configuration - Setting up with Claude Desktop
- Interface Contract - JSON-RPC protocol specification
Development
# Install dev dependencies
uv sync --all-extras
# Fetch latest RPC schema
./scripts/fetch-schema.sh
# Run linting
uv run ruff check packages/
# Run formatting
uv run ruff format packages/
# Run tests
uv run pytest
# Build packages
uv build packages/kdenlive-api
uv build packages/kdenlive-mcp
Contributing
Contributions are welcome! Please see the Contributing Guide for details.
License
MIT License - see LICENSE for details.
Related
- Kdenlive - Free and open source video editor
- IO-AtelierTech/kdenlive - Kdenlive fork with WebSocket RPC support
- MCP - Model Context Protocol
README mirrored from the source repository 4 months ago. The original is authoritative.