MCP tool for assembling multiple source media files into a single OTIO timeline (multi-source sequence builder).
Project description
clipwright-sequence
MCP tool that assembles multiple source media files into a single multi-source OTIO
timeline for concatenation by clipwright-render.
Overview
clipwright-sequence accepts an ordered list of clip specifications and emits a single
OTIO timeline file (one V1 video track; A1 audio track left empty for BGM or mixing
by the calling agent). The timeline is consumed unchanged by clipwright-render, which
concatenates the clips into a single output video.
This fills the gap between single-source tools and multi-clip programs: every other
clipwright tool starts from one media file. clipwright-sequence is the authoring
primitive that builds a multi-source program OTIO before the final render pass.
Design principle (M3 — separation of annotation and realisation):
clipwright-sequence writes only the OTIO; it does not transcode or touch media files.
All media processing is deferred to clipwright-render.
Prerequisites
- Python 3.11 or later
clipwrightcore package (shared types, envelope, OTIO utils)CLIPWRIGHT_FFPROBEenvironment variable (orffprobeonPATH) — used to probe each source's duration and confirm video stream presence before building the timeline
No FFmpeg is needed at sequence-build time; FFmpeg is only invoked by clipwright-render
at realisation time.
MCP Tool: clipwright_build_sequence
Parameters
| Name | Type | Default | Description |
|---|---|---|---|
clips |
list[SequenceClip] |
required | Ordered list of clip specifications to assemble. Maximum 1000 entries per call (DC-GP-003). |
clips[].media |
string |
required | Path to the source media file. Must be co-located under the output directory (see Co-location Constraint). |
clips[].start_sec |
float | null |
null → 0.0 |
Start of the clip in seconds from the beginning of the source. Must be ≥ 0. |
clips[].end_sec |
float | null |
null → full duration |
End of the clip in seconds from the beginning of the source. Must be > 0 and ≤ source duration. |
output |
string |
required | Output OTIO timeline file path (.otio extension required). The parent directory must exist. |
Return value
{
"ok": true,
"summary": "Assembled a 3-clip sequence (approx total 45.2s) from 2 source(s). Generated sequence.otio. Pass it to clipwright-render to concatenate into a single video.",
"data": {
"clip_count": 3,
"total_duration_sec": 45.2,
"unique_source_count": 2
},
"artifacts": [{"role": "timeline", "path": "sequence.otio", "format": "otio"}],
"warnings": []
}
Note on
total_duration_sec: This value is an approximate estimate computed as the sum of the input clip ranges (DC-AM-003). The rendered output duration may differ slightly after per-frame normalisation inclipwright-render.
Error codes
| Code | Cause |
|---|---|
INVALID_INPUT |
clips is empty, exceeds 1000 entries, contains an invalid range (start_sec >= end_sec, end_sec > source duration), or output has a non-.otio extension |
INVALID_INPUT |
output parent directory does not exist |
INVALID_INPUT |
A source file has no video stream (audio-only file) |
INVALID_INPUT |
A source file's frame rate is undetermined (e.g. still-image stream or unusual capture device) |
FILE_NOT_FOUND |
A source media path does not exist |
PATH_NOT_ALLOWED |
A source file is located outside the output directory tree (co-location violation) |
PATH_NOT_ALLOWED |
output path and a source media path resolve to the same file |
PROBE_FAILED |
ffprobe could not determine a source's duration (corrupted file) |
DEPENDENCY_MISSING |
ffprobe binary not found (CLIPWRIGHT_FFPROBE unset and not on PATH) |
Co-location Constraint
All source media files must be located under the same directory as the output .otio
file (or in a recursive subdirectory of it).
Why this mirrors clipwright-render's rule — not a relaxation of it:
clipwright-render enforces a PATH_NOT_ALLOWED boundary: every source referenced in
an OTIO timeline must be co-located with the timeline file. If clipwright-sequence
were to accept sources from outside that boundary, the produced .otio would be valid
at build time but would fail immediately when passed to clipwright-render.
By enforcing the same co-location rule at sequence-build time, clipwright-sequence
guarantees that any .otio it produces will round-trip through clipwright-render
without a PATH_NOT_ALLOWED error. The constraint is a forward-compatibility guarantee,
not an arbitrary restriction.
Recursive subdirectories are permitted: sources may live anywhere inside the tree rooted at the output's parent directory.
project/
intro.mp4 ← allowed (same directory)
footage/
main.mp4 ← allowed (subdirectory)
broll.mp4 ← allowed (subdirectory)
sequence.otio ← output
/other/path/clip.mp4 ← PATH_NOT_ALLOWED
Symlink Sources
Symlink sources are not supported (DC-AS-005). Resolve symlinks to their real paths before passing them to this tool.
Two-Phase Workflow
clipwright_build_sequence(clips, output) # Phase 1 — build OTIO
│
▼ OTIO timeline with ordered V1 clips
clipwright_render(timeline, output_media) # Phase 2 — concatenate and encode
│
▼ single output video (intro + main + outro, or any sequence)
clipwright-sequence can be combined with other directive tools before the final render:
clipwright_build_sequence → clipwright_detect_color → clipwright_reduce_noise → clipwright_render
MCP Client Registration
Register clipwright-sequence as a standalone MCP server in your client configuration
(.mcp.json / claude_desktop_config.json). CLIPWRIGHT_FFPROBE is required.
{
"mcpServers": {
"clipwright-sequence": {
"command": "clipwright-sequence",
"env": {
"CLIPWRIGHT_FFPROBE": "/path/to/ffprobe"
}
}
}
}
clipwright-render (which materialises the OTIO into a video) still requires
CLIPWRIGHT_FFMPEG.
Usage Examples
Assemble intro + main + outro
# Via MCP call_tool
result = await session.call_tool("clipwright_build_sequence", {
"clips": [
{"media": "/project/intro.mp4"},
{"media": "/project/main.mp4", "start_sec": 10.0, "end_sec": 130.0},
{"media": "/project/outro.mp4"}
],
"output": "/project/sequence.otio"
})
# Then render
render_result = await session.call_tool("clipwright_render", {
"timeline": "/project/sequence.otio",
"output": "/project/final.mp4"
})
Splice two gameplay segments
result = await session.call_tool("clipwright_build_sequence", {
"clips": [
{"media": "/project/gameplay.mp4", "start_sec": 60.0, "end_sec": 180.0},
{"media": "/project/gameplay.mp4", "start_sec": 300.0, "end_sec": 420.0}
],
"output": "/project/highlights.otio"
})
The same source file may appear multiple times (with different ranges). Each unique source is probed exactly once.
B-roll interleave
result = await session.call_tool("clipwright_build_sequence", {
"clips": [
{"media": "/project/interview.mp4", "start_sec": 0.0, "end_sec": 30.0},
{"media": "/project/broll/cityscape.mp4"},
{"media": "/project/interview.mp4", "start_sec": 30.0, "end_sec": 60.0}
],
"output": "/project/edited.otio"
})
Installation
Within a uv workspace:
uv run --package clipwright-sequence clipwright-sequence
Or install from PyPI:
pip install clipwright-sequence
clipwright-sequence
License
MIT — See LICENSE for details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file clipwright_sequence-0.1.0.tar.gz.
File metadata
- Download URL: clipwright_sequence-0.1.0.tar.gz
- Upload date:
- Size: 12.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
14e1e835079a481a41753874ca22b32a14bae095eb5f35d2b6c8a8ac474883ca
|
|
| MD5 |
d68a65ac2b548180f99f204aa27103b6
|
|
| BLAKE2b-256 |
7286dbe4a3a96ff07599d99c05d8d649a0f552d9f6ea1518adf9ab039c81309a
|
Provenance
The following attestation bundles were made for clipwright_sequence-0.1.0.tar.gz:
Publisher:
publish.yml on satoh-y-0323/clipwright
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
clipwright_sequence-0.1.0.tar.gz -
Subject digest:
14e1e835079a481a41753874ca22b32a14bae095eb5f35d2b6c8a8ac474883ca - Sigstore transparency entry: 1899120337
- Sigstore integration time:
-
Permalink:
satoh-y-0323/clipwright@50e3ed9c05802f41403baa02e1069cf38318780e -
Branch / Tag:
refs/tags/v0.13.0 - Owner: https://github.com/satoh-y-0323
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@50e3ed9c05802f41403baa02e1069cf38318780e -
Trigger Event:
push
-
Statement type:
File details
Details for the file clipwright_sequence-0.1.0-py3-none-any.whl.
File metadata
- Download URL: clipwright_sequence-0.1.0-py3-none-any.whl
- Upload date:
- Size: 14.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
74f2ca894e9a2e66207b7630f65a617b9f7c2e9d3613808e7ed4b407d59422cf
|
|
| MD5 |
6e1c96fba02ffea3f0fa7b68598011ef
|
|
| BLAKE2b-256 |
fd40e90aa32a19e11156f890d9d0de41df7c8932a23f9e565e8912dfdd05821c
|
Provenance
The following attestation bundles were made for clipwright_sequence-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on satoh-y-0323/clipwright
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
clipwright_sequence-0.1.0-py3-none-any.whl -
Subject digest:
74f2ca894e9a2e66207b7630f65a617b9f7c2e9d3613808e7ed4b407d59422cf - Sigstore transparency entry: 1899120501
- Sigstore integration time:
-
Permalink:
satoh-y-0323/clipwright@50e3ed9c05802f41403baa02e1069cf38318780e -
Branch / Tag:
refs/tags/v0.13.0 - Owner: https://github.com/satoh-y-0323
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@50e3ed9c05802f41403baa02e1069cf38318780e -
Trigger Event:
push
-
Statement type: