> ## Documentation Index
> Fetch the complete documentation index at: https://www.tella.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Model Context Protocol (MCP)

> Connect AI assistants to your Tella workspace

Tella's MCP server provides a standardized interface that allows any compatible AI assistant to access your Tella workspace. List videos, manage playlists, edit clips, upload new clips and B-roll videos, apply layouts, and more — all through natural language.

## Endpoint

```
https://api.tella.com/mcp
```

## Setup

<Tabs>
  <Tab title="Claude Code">
    Run this command in your terminal:

    ```bash theme={null}
    claude mcp add --transport http --scope user tella https://api.tella.com/mcp
    ```

    Or for one-click install: [Add Tella MCP Server](claude://mcp/add?transport=http\&name=tella\&url=https://api.tella.com/mcp)

    You'll be prompted to authenticate with your Tella account.
  </Tab>

  <Tab title="Claude Desktop">
    Add to your `claude_desktop_config.json`:

    ```json theme={null}
    {
      "mcpServers": {
        "tella": {
          "command": "npx",
          "args": [
            "mcp-remote",
            "https://api.tella.com/mcp"
          ]
        }
      }
    }
    ```
  </Tab>

  <Tab title="Cursor">
    Add to your MCP settings:

    ```json theme={null}
    {
      "mcpServers": {
        "tella": {
          "command": "npx",
          "args": [
            "mcp-remote",
            "https://api.tella.com/mcp"
          ]
        }
      }
    }
    ```
  </Tab>

  <Tab title="Codex">
    Run this command in your terminal:

    ```bash theme={null}
    codex mcp add tella -- npx mcp-remote https://api.tella.com/mcp
    ```

    Or add it to your `~/.codex/config.toml` manually:

    ```toml theme={null}
    [mcp_servers.tella]
    command = "npx"
    args = ["mcp-remote", "https://api.tella.com/mcp"]
    ```

    You'll be prompted to authenticate with your Tella account.
  </Tab>
</Tabs>

## Authentication

The MCP server uses OAuth 2.1 for authentication. When you first connect, you'll be redirected to Tella to authorize access. The connection uses your Tella account permissions — you can only access videos and playlists in workspaces you belong to.

## Managing videos

Organize and share your workspace: list and update videos, manage playlists and tags, control access, and export finished videos.

### Videos

<AccordionGroup>
  <Accordion title="list_videos">
    List all videos in your workspace with pagination support.

    **Parameters:**

    * `cursor` (optional): Pagination cursor from previous response
    * `limit` (optional): Items per page (1-100, default: 20)
    * `playlistId` (optional): Filter videos by playlist
    * `tagIds` (optional): Filter videos by tag IDs, comma-separated. Multiple tags are combined with AND. Ignored when `playlistId` is set
  </Accordion>

  <Accordion title="get_video">
    Get video information. Returns summary fields by default. Use include flags for additional data.

    **Parameters:**

    * `id` (required): Video ID
    * `includeTranscript` (optional): Include transcript text
    * `includeChapters` (optional): Include chapter markers
    * `includeThumbnails` (optional): Include thumbnail URLs
    * `includeExports` (optional): Include export status
  </Accordion>

  <Accordion title="create_video">
    Create a new video from an uploaded source. Call `create_source` first (`kind: "video"`), `PUT` the bytes to the returned `uploadUrl`, then pass the `sourceId` here — it becomes the new video's first clip.

    **Parameters:**

    * `sourceId` (required): Source ID from `create_source` (`kind: "video"`)
    * All `update_video` settings except `id` — `name`, `description`, `playbackRate`, `captionsEnabled`, `transcriptEnabled`, `commentsEnabled`, `downloadsEnabled`, `linkScope`, `password`, `searchEngineIndexingEnabled`, `studioSound`, and `dimensions` — to configure the new video in the same call. When `dimensions` is omitted, the canvas is sized from the uploaded video.
  </Accordion>

  <Accordion title="update_video">
    Update video metadata and settings.

    **Parameters:**

    * `id` (required): Video ID
    * `name` (optional): Video title
    * `description` (optional): Video description
    * `playbackRate` (optional): Default playback speed (0.5-2.0)
    * `captionsEnabled` (optional): Show captions by default
    * `transcriptEnabled` (optional): Show transcript tab
    * `commentsEnabled` (optional): Allow comments
    * `downloadsEnabled` (optional): Allow downloads
    * `linkScope` (optional): Access level — `public`, `private`, `password`, or `embedonly`
    * `password` (optional): Password for protected videos
    * `searchEngineIndexingEnabled` (optional): Allow search engine indexing
    * `studioSound` (optional): Studio Sound (AI audio enhancement) master switch. Enabling it also starts generating the enhanced audio tracks in the background; playback and exports fall back to raw audio until they are ready. Individual clips can opt out via `update_clip`'s `studioSound`.
    * `dimensions` (optional): Canvas size in pixels as `{ width, height }` (each 16–4096). Changing it remaps every clip and section layout to a ratio-appropriate equivalent — the same transform as switching size in the editor's Setup → Size. Editor presets: `1920x1080` (16:9), `1920x1200` (16:10), `1440x1080` (4:3), `1080x1080` (1:1), `1080x1350` (4:5), `1080x1920` (9:16). No-op when the video already has the requested size.
  </Accordion>

  <Accordion title="delete_video">
    Delete a video (moves to trash).

    **Parameters:**

    * `id` (required): Video ID
  </Accordion>

  <Accordion title="duplicate_video">
    Create a copy of a video. Supports trimming to extract a time range or specific chapter.

    **Parameters:**

    * `id` (required): Video ID to duplicate
    * `name` (optional): Name for the duplicate
    * `startTime` (optional): Trim start time in seconds (use with endTime)
    * `endTime` (optional): Trim end time in seconds (use with startTime)
    * `chapterIndex` (optional): Extract a specific chapter by 0-based index (cannot be combined with startTime/endTime)
  </Accordion>

  <Accordion title="export_video">
    Start a video export. Use `get_export_status` to poll until the export completes or fails.

    Returns an `export` object. Pass its `exportId` value to `get_export_status`.

    **Parameters:**

    * `id` (required): Video ID
    * `granularity` (optional): `video` (full video, default), `clips` (one file per clip), or `raw` (raw recordings)
    * `resolution` (optional): `4k` for 4K; omit for default
    * `fps` (optional): Frames per second — `30` or `60`
    * `subtitles` (optional): Burn in subtitles
    * `speed` (optional): Playback speed — `0.5`, `0.75`, `1`, `1.25`, `1.5`, `1.75`, or `2`
  </Accordion>

  <Accordion title="get_export_status">
    Get an export's current status and progress. Poll this after `export_video` until `export.status` is `completed` or `failed`; `export.downloadUrl` appears when the export is ready.

    **Parameters:**

    * `id` (required): Video ID
    * `exportId` (required): The `export.exportId` value returned by `export_video`
  </Accordion>

  <Accordion title="add_collaborator_to_video">
    Add a collaborator to a video. The user must be a member of your workspace.

    **Parameters:**

    * `id` (required): Video ID
    * `email` (required): Email address of the user to add
    * `role` (required): Role to grant — `editor` or `viewer`
  </Accordion>

  <Accordion title="update_collaborator_on_video">
    Change a collaborator's role on a video.

    **Parameters:**

    * `id` (required): Video ID
    * `userId` (required): User ID of the collaborator
    * `role` (required): New role — `editor` or `viewer`
  </Accordion>

  <Accordion title="remove_collaborator_from_video">
    Remove a collaborator from a video.

    **Parameters:**

    * `id` (required): Video ID
    * `userId` (required): User ID of the collaborator to remove
  </Accordion>
</AccordionGroup>

### Playlists

<AccordionGroup>
  <Accordion title="list_playlists">
    List all playlists in your workspace.

    **Parameters:**

    * `visibility` (optional): Filter by `personal` or `org`
    * `cursor` (optional): Pagination cursor
    * `limit` (optional): Items per page (1-100, default: 20)
  </Accordion>

  <Accordion title="create_playlist">
    Create a new playlist.

    **Parameters:**

    * `name` (required): Playlist name
    * `description` (optional): Playlist description
    * `emoji` (optional): Emoji icon
    * `visibility` (optional): `personal` or `org`
    * `linkScope` (optional): Access level — `public`, `private`, or `password`
    * `password` (optional): Password for protected playlists
  </Accordion>

  <Accordion title="get_playlist">
    Get detailed information about a playlist.

    **Parameters:**

    * `id` (required): Playlist ID
  </Accordion>

  <Accordion title="update_playlist">
    Update playlist metadata and settings.

    **Parameters:**

    * `id` (required): Playlist ID
    * `name` (optional): Playlist name
    * `description` (optional): Playlist description
    * `emoji` (optional): Emoji icon
    * `linkScope` (optional): Access level
    * `password` (optional): Password for protected playlists
    * `searchEngineIndexingEnabled` (optional): Allow search engine indexing
  </Accordion>

  <Accordion title="delete_playlist">
    Delete a playlist.

    **Parameters:**

    * `id` (required): Playlist ID
  </Accordion>

  <Accordion title="add_video_to_playlist">
    Add a video to a playlist.

    **Parameters:**

    * `playlistId` (required): Playlist ID
    * `videoId` (required): Video ID to add
  </Accordion>

  <Accordion title="remove_video_from_playlist">
    Remove a video from a playlist.

    **Parameters:**

    * `playlistId` (required): Playlist ID
    * `videoId` (required): Video ID to remove
  </Accordion>

  <Accordion title="list_playlist_groups">
    List sidebar playlist groups.

    Personal groups are only visible to the authenticated user. Org groups are shared with the whole workspace.

    **Parameters:**

    * `visibility` (optional): Filter by `personal` or `org`
  </Accordion>

  <Accordion title="create_playlist_group">
    Create a sidebar group to organize playlists into.

    **Parameters:**

    * `name` (required): Group name
    * `emoji` (optional): Emoji icon
    * `visibility` (optional): `personal` or `org`. Defaults to `personal`
  </Accordion>

  <Accordion title="update_playlist_group">
    Rename a playlist group, change its icon, or move it within its sidebar section.

    **Parameters:**

    * `id` (required): Playlist group ID
    * `name` (optional): New group name
    * `emoji` (optional): Emoji icon
    * `position` (optional): 0-based position in the sidebar section
  </Accordion>

  <Accordion title="delete_playlist_group">
    Delete a playlist group.

    Playlists inside the group are not deleted. They become ungrouped.

    **Parameters:**

    * `id` (required): Playlist group ID
  </Accordion>

  <Accordion title="move_playlist_to_group">
    Move a playlist into a group, or remove it from its group.

    The group's visibility must match the playlist's visibility. Org playlists can only move into org groups, and personal playlists can only move into personal groups.

    **Parameters:**

    * `playlistId` (required): Playlist ID
    * `groupId` (optional): Target playlist group ID. Omit it to remove the playlist from its group
    * `position` (optional): 0-based position in the target group, or in the ungrouped sidebar section when `groupId` is omitted
  </Accordion>
</AccordionGroup>

### Tags

Tags categorize videos across your library. Workspace tags are shared with everyone in the workspace; private tags are only visible to you. Filter your library by tag with `list_videos`' `tagIds` parameter.

<AccordionGroup>
  <Accordion title="list_tags">
    List all tags visible to you: the workspace's shared tags plus your private tags.

    No parameters.
  </Accordion>

  <Accordion title="create_tag">
    Create a tag for categorizing videos. When no color is given, one is derived from the name.

    **Parameters:**

    * `name` (required): Tag name
    * `scope` (optional): Tag visibility — `workspace` (default) or `private`
    * `color` (optional): Tag color as a hex value, e.g. `#6366f1`
    * `description` (optional): Tag description
  </Accordion>

  <Accordion title="update_tag">
    Update a tag's name, color, and/or description. Private tags can only be updated by their creator.

    **Parameters:**

    * `id` (required): Tag ID
    * `name` (optional): New tag name
    * `color` (optional): New tag color as a hex value, e.g. `#6366f1`
    * `description` (optional): New tag description
  </Accordion>

  <Accordion title="delete_tag">
    Permanently delete a tag and remove it from all videos.

    **Parameters:**

    * `id` (required): Tag ID
  </Accordion>

  <Accordion title="list_video_tags">
    List the tags on a video that are visible to you.

    **Parameters:**

    * `videoId` (required): Video ID
  </Accordion>

  <Accordion title="add_video_tag">
    Tag a video. Requires edit access to the video. Adding a private tag only affects your own library.

    **Parameters:**

    * `videoId` (required): Video ID
    * `tagId` (required): Tag ID
  </Accordion>

  <Accordion title="remove_video_tag">
    Untag a video. Requires edit access to the video.

    **Parameters:**

    * `videoId` (required): Video ID
    * `tagId` (required): Tag ID
  </Accordion>
</AccordionGroup>

## Editing videos

Build and refine the video itself: upload sources, add and cut clips, apply layouts, and add zooms, blurs, highlights, overlays, and sound effects.

### Sources

A source is an uploaded file (video, audio, or image) that can be turned into a new video or clip, or referenced as B-roll media, an overlay, a clip background, background music, or a sound effect. Create a source, upload the bytes to the returned pre-signed URL, then reference the `sourceId` from `create_video`, `upload_clip`, `add_layout` / `update_layout`, `add_overlay`, `update_clip`, `set_background_music`, or `add_sound_effect`.

<AccordionGroup>
  <Accordion title="create_source">
    Create a new source upload. Returns a `sourceId` and a pre-signed `uploadUrl` — `PUT` the file bytes to `uploadUrl` (the URL expires after 1 hour). Once uploaded, the `sourceId` can be used by `create_video` (video only, to create a new video), by `upload_clip` (video only, to add a new clip), by `add_layout` / `update_layout` (as B-roll media), by `add_overlay`, by `update_clip` (as an image/video background), by `set_background_music` (audio only), or by `add_sound_effect` (audio only).

    Upload the file as-is: any common container is accepted (MP4, MOV, WebM, MP3, WAV, M4A, …). The `.mp4` in the upload URL is just the storage key, not a container requirement — there's no need to remux or re-encode before uploading.

    For audio files, set `kind: "audio"` with the audio's duration and omit `width` / `height`.

    For images, set `kind: "image"` and omit `duration`. Tella hosts the uploaded image for rendering — you never deal with raw image URLs.

    **Parameters:**

    * `kind` (optional): Source kind — `video` (default), `audio`, or `image`
    * `width` (video/image): Width in pixels — required for `video` and `image`, omit for `audio`
    * `height` (video/image): Height in pixels — required for `video` and `image`, omit for `audio`
    * `duration` (video/audio): Duration in seconds — required for `video` and `audio`, ignored for `image`
  </Accordion>
</AccordionGroup>

### Chapters

Chapter timestamps use seconds on the final video timeline. Chapter IDs are not stable, so chapter updates always replace the complete list rather than targeting individual chapters.

<AccordionGroup>
  <Accordion title="get_chapters">
    Get every chapter on a video, ordered by timestamp.

    **Parameters:**

    * `videoId` (required): Video ID
  </Accordion>

  <Accordion title="set_chapters">
    Replace every chapter on a video. Timestamps must be non-negative, ascending, and within the video duration. Pass an empty `chapters` array to clear all chapters.

    **Parameters:**

    * `videoId` (required): Video ID
    * `chapters` (required): Complete replacement array of `{timestampSeconds, title, description}` objects
  </Accordion>
</AccordionGroup>

### Clips

A clip is a section of a video — Tella videos are made up of one or more clips. Each clip has its own cuts, layouts, transcript, and editing tools.

<Note>
  **Every timestamp is on the clip's playback timeline** — the video as watched, cuts applied, the same timeline as `get_transcript` and thumbnails. No conversions needed. The one exception is stored cut *definitions* (`get_clip`'s `cuts` / `update_clip`'s `cuts`), which describe removed ranges of the raw recording; cuts are always undoable by replacing them with `[]`.
</Note>

<AccordionGroup>
  <Accordion title="upload_clip">
    Add a new clip to a video from an uploaded source. Call `create_source` first, `PUT` the bytes to the returned `uploadUrl`, then pass the `sourceId` here.

    **Parameters:**

    * `videoId` (required): Video ID
    * `sourceId` (required): Source ID returned by `create_source`
    * `name` (optional): Clip name. Defaults to the next `Clip N`.
  </Accordion>

  <Accordion title="list_clips">
    List clips in a video, ordered by their position.

    **Parameters:**

    * `videoId` (required): Video ID
  </Accordion>

  <Accordion title="get_clip">
    Get a single clip's details.

    **Parameters:**

    * `videoId` (required): Video ID
    * `id` (required): Clip ID
  </Accordion>

  <Accordion title="update_clip">
    Update a clip's name, ordering, cuts, background, or Studio Sound opt-out.

    **Parameters:**

    * `videoId` (required): Video ID
    * `id` (required): Clip ID
    * `name` (optional): New clip name
    * `order` (optional): New position within the video
    * `cuts` (optional): Replaces the clip's full cut set. Each cut is `{startTimeMs, durationMs}` in ms of the raw recording (the playback timeline you'd get after clearing all cuts). Pass `[]` to clear all cuts. To cut what you currently see, use `cut_clip` instead.
    * `background` (optional): Background `{type, color?, sourceId?, gradientColor1?, gradientColor2?, gradientAngle?}`. `type` is one of `solid`, `image`, `video`, `gradient`. For `image` and `video`, pass a `sourceId` from `create_source` (`kind: "image"` or `kind: "video"`).
    * `studioSound` (optional): Per-clip Studio Sound opt-out. `false` disables enhanced audio for this clip while the video-level switch (`update_video`'s `studioSound`) stays on; `true` re-enables it.
  </Accordion>

  <Accordion title="delete_clip">
    Remove a clip from its video.

    **Parameters:**

    * `videoId` (required): Video ID
    * `id` (required): Clip ID
  </Accordion>

  <Accordion title="duplicate_clip">
    Duplicate a clip. The copy is inserted right after the original by default.

    **Parameters:**

    * `videoId` (required): Video ID
    * `id` (required): Clip ID to duplicate
    * `name` (optional): Name for the new clip
    * `order` (optional): Position for the new clip
  </Accordion>

  <Accordion title="reorder_clip">
    Move a clip to a new position; other clips shift to stay contiguous.

    **Parameters:**

    * `videoId` (required): Video ID
    * `id` (required): Clip ID
    * `order` (required): New 0-based position
  </Accordion>

  <Accordion title="cut_clip">
    Cut one or more time ranges from a clip in a single call. Overlapping or adjacent ranges are merged into the clip's existing cuts. To clear all cuts, call `update_clip` with `cuts: []`.

    **Parameters:**

    * `videoId` (required): Video ID
    * `id` (required): Clip ID
    * `cuts` (required): Array of `{fromMs, toMs}` ranges to cut, in ms on the clip's playback timeline (what you currently see and hear — the same timeline as `get_transcript` and `get_silences`). All ranges are resolved against the playback timeline as it is when the call starts, so send every range in one call instead of issuing many `cut_clip` calls.
  </Accordion>

  <Accordion title="cut_clip_by_transcript">
    Cut one or more ranges from a clip by referencing word indices in the transcript. The server resolves each word's exact start/end ms — no padding is applied. Use `get_transcript` to look up word indices.

    **Parameters:**

    * `videoId` (required): Video ID
    * `id` (required): Clip ID
    * `wordRanges` (required): Array of `{fromWordIndex, toWordIndex}` ranges. Both indices are inclusive and come from the clip's transcript (indices are stable — already-cut words are simply absent).
  </Accordion>

  <Accordion title="get_silences">
    Detect silent ranges in the clip's audio, in ms on the clip's playback timeline (cuts applied) — pass them directly to `cut_clip`. Silences already removed by cuts are not reported.

    **Parameters:**

    * `videoId` (required): Video ID
    * `id` (required): Clip ID
    * `minDurationMs` (optional): Minimum silence length to report, in ms. Defaults to 200.
  </Accordion>

  <Accordion title="remove_fillers">
    Auto-detect and cut filler words ("um", "uh", etc.) from the clip's transcript.

    **Parameters:**

    * `videoId` (required): Video ID
    * `id` (required): Clip ID
  </Accordion>

  <Accordion title="remove_silences">
    Auto-detect and cut silent pauses from the clip's audio, like the editor's Remove silences tool.

    **Parameters:**

    * `videoId` (required): Video ID
    * `id` (required): Clip ID
    * `mode` (optional): How aggressively to remove silences — `natural` cuts pauses longer than 800ms, `fast` longer than 500ms, `faster` longer than 300ms. Defaults to `natural`.
  </Accordion>

  <Accordion title="list_sources">
    List the underlying recordings (camera, screen, mic) the clip was cut from.

    **Parameters:**

    * `videoId` (required): Video ID
    * `id` (required): Clip ID
  </Accordion>

  <Accordion title="get_clip_thumbnail">
    Get a thumbnail of the clip — the rendered composite at the given time on the clip's playback timeline (cuts applied), including the clip's layouts, b-roll media, zooms, and masks. Static formats (jpg/png/webp/gif) return inline image content the model can see, plus a signed URL. `mp4` returns a URL only.

    **Parameters:**

    * `videoId` (required): Video ID
    * `id` (required): Clip ID
    * `format` (optional): `jpg` (default), `png`, `webp`, `gif`, or `mp4`
    * `inpointMs` (optional): Frame offset in ms on the clip's playback timeline, cuts applied (default 0)
    * `durationMs` (optional): Duration of the animated preview. Only valid when `format` is `gif` or `mp4`.
    * `width` (optional): Output width in pixels (default 320). The thumbnail keeps the video's aspect ratio.
    * `height` (optional): Output height in pixels. Derived from the video's aspect ratio when omitted.
    * `download` (optional): Suggest a download disposition on the signed URL

    While the video is still uploading or converting, the tool returns a result with `code: "thumbnail_not_ready"` and `status: "processing"` instead of an image — retry once the video finishes processing. Other upstream failures return `code: "thumbnail_fetch_failed"` with a signed URL to fetch manually.
  </Accordion>

  <Accordion title="get_video_thumbnail">
    Get a thumbnail of an entire video. Same format/sizing options as `get_clip_thumbnail`. It also returns the same `thumbnail_not_ready` processing result while the video is still being processed.

    **Parameters:**

    * `id` (required): Video ID
    * `format` (optional): `jpg`, `png`, `webp`, `gif`, or `mp4`
    * `inpointMs` (optional): Frame offset in ms from the video's playback start (cumulative across clips, cuts applied)
    * `durationMs` (optional): Duration of the animated preview (gif/mp4 only)
    * `width` / `height` (optional): Output dimensions
  </Accordion>

  <Accordion title="set_video_thumbnail">
    Set a video's thumbnail. Two modes, mutually exclusive:

    * **Uploaded image**: call `create_source` with `kind: "image"`, HTTP PUT the image bytes to the returned `uploadUrl`, then pass the `sourceId` here.
    * **Frame from the video**: pass `inpointMs`, a time on the video's playback timeline (cuts applied, cumulative across clips). Preview candidate frames first with `get_video_thumbnail` using the same `inpointMs`.

    Setting one mode clears the other.

    **Parameters:**

    * `id` (required): Video ID
    * `sourceId` (optional): Uploaded image source ID
    * `inpointMs` (optional): Thumbnail frame time in ms
  </Accordion>

  <Accordion title="remove_video_thumbnail">
    Remove a video's custom thumbnail (uploaded image or picked frame) and revert to the default auto-generated thumbnail.

    **Parameters:**

    * `id` (required): Video ID
  </Accordion>

  <Accordion title="get_source_thumbnail">
    Get a thumbnail of a specific source recording.

    **Parameters:**

    * `videoId` (required): Video ID
    * `clipId` (required): Clip ID
    * `sourceId` (required): Source recording ID
    * `format` (optional): `jpg`, `png`, `webp`, `gif`, or `mp4`
    * `inpointMs` (optional): Frame offset from the source's start
    * `durationMs` (optional): Duration of the animated preview (gif/mp4 only)
    * `width` / `height` (optional): Output dimensions
  </Accordion>

  <Accordion title="get_source_waveform">
    Get the waveform data for a source recording's audio track.

    **Parameters:**

    * `videoId` (required): Video ID
    * `clipId` (required): Clip ID
    * `sourceId` (required): Source recording ID
  </Accordion>

  <Accordion title="get_transcript">
    Transcript for the clip (cuts applied — what the viewer hears). Word indices are stable identifiers for `cut_clip_by_transcript`; they don't shift when cuts change. To see words that were cut out, clear the cuts first (`update_clip` with `cuts: []`) — cuts are always undoable.

    **Parameters:**

    * `videoId` (required): Video ID
    * `id` (required): Clip ID
  </Accordion>
</AccordionGroup>

### Layouts

A layout decides how a clip's camera and screen layers are composed at a given time. Apply a layout to the whole clip (no `startTimeMs`/`durationMs`) or to a specific time range. Times are in ms on the clip's playback timeline (cuts applied). Read the clip first to see its `layoutSceneType` — that determines which `kind` values are valid.

The `layout` field is a structured object discriminated by `kind`:

| `kind`          | Valid scene types               | Variant fields                                                                                                                                                           |
| --------------- | ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `fullscreen`    | `cameraSubject`, `basicSubject` | `style: regular \| stretch` (camera-subject) or `screenFit: cover \| letterbox` (basic-subject)                                                                          |
| `middle`        | `cameraSubject`, `basicSubject` | `shape` (camera-subject)                                                                                                                                                 |
| `side-by-side`  | `combi` (landscape)             | `position: left \| right`, `style: regular \| even \| overlap`, `size` (when `style=overlap`)                                                                            |
| `tv-presenter`  | `combi` (landscape)             | `position: left \| right`, `style: regular \| full \| overlap`                                                                                                           |
| `camera-bubble` | `combi` (all ratios)            | `position` (9-way), `shape: circle \| square \| landscape \| portrait`, `size: S \| M \| L`, optional `style: regular \| full`, optional `screenFit` (when `style=full`) |
| `camera-only`   | `combi` (all ratios)            | `style: fullscreen \| middle`, `punchIn` (when `style=fullscreen`), `shape` (when `style=middle`)                                                                        |
| `screen-only`   | `combi` (all ratios)            | `style: fullscreen \| middle`, `screenFit` (when `style=fullscreen`)                                                                                                     |

<AccordionGroup>
  <Accordion title="list_layouts">
    List the layouts on a clip, including the synthetic base layout (the layout that spans the whole clip).

    **Parameters:**

    * `videoId` (required): Video ID
    * `id` (required): Clip ID
  </Accordion>

  <Accordion title="add_layout">
    Add a layout to a clip. Pass `startTimeMs` + `durationMs` for a time range, or omit both for a clip-spanning layout. To add b-roll, give a time range and set `media` — you can omit `layout` and the server applies a full-frame b-roll layout suited to the clip automatically (screen-only for combi clips, fullscreen for basic/camera-subject clips). To use a specific layout instead, pass `layout` with a `kind` valid for the clip's scene type (see the table above).

    **Parameters:**

    * `videoId` (required): Video ID
    * `id` (required): Clip ID
    * `layout` (optional): Structured layout object (see table above). Omit it to apply the default full-frame b-roll layout for the clip's scene type.
    * `startTimeMs` (optional): Start time in ms on the clip's playback timeline (cuts applied)
    * `durationMs` (optional): Duration in ms. Minimum 200ms.
    * `transitionStyle` (optional): Transition into the layout — `spring` or `hardCut`. Only valid on time-ranged layouts. When omitted, the user's saved layout intro transition is used; the saved outro transition is applied when the following layout begins or resumes.
    * `media` (optional): B-roll content displayed during the layout. Only valid on time-ranged layouts. Either:

      * `{type: "image", sourceId}` for an image, or
      * `{type: "video", sourceId}` for a video.

      In both cases `sourceId` comes from `create_source` (`kind: "image"` or `kind: "video"`) after you upload the bytes.

      Add an optional `slot` to choose which slot the media fills: `screen` (the main subject frame — the default) or `camera` (the bubble/presentation slot, a media bubble shown over the recording behind it). Each slot needs a layout that renders it: the `screen` slot (default) requires a layout that shows the screen frame — not `camera-only` or any `*-camera-only-*` variant — and the `camera` slot requires a layout that renders the camera (e.g. `camera-bubble`, `side-by-side`, `tv-presenter`). Pointing media at a slot the layout doesn't show is rejected. One call fills one slot; a section can hold media in both slots by adding to one slot here and the other with `update_layout`.

    Example:

    ```json theme={null}
    {
      "videoId": "vid_…",
      "id": "cl_…",
      "layout": {"kind": "side-by-side", "position": "left", "style": "regular"},
      "startTimeMs": 5000,
      "durationMs": 4000
    }
    ```
  </Accordion>

  <Accordion title="update_layout">
    Update a layout on a clip. Only provided fields change.

    **Parameters:**

    * `videoId` (required): Video ID
    * `id` (required): Clip ID
    * `layoutId` (required): Layout ID (use `base` for the clip-spanning layout)
    * `layout` (optional): New structured layout
    * `startTimeMs` (optional): New start time in ms on the clip's playback timeline (cuts applied)
    * `durationMs` (optional): New duration in ms. Minimum 200ms.
    * `transitionStyle` (optional): `spring` or `hardCut`. Rejected on the base layout.
    * `media` (optional): Set the layout's B-roll content for one slot. Rejected on the base layout. Same shape as `add_layout`'s `media`, including the optional `slot` field. Additive per slot: media in the other slot is preserved, and media already in the targeted slot is replaced.
  </Accordion>

  <Accordion title="remove_layout">
    Remove a non-base layout from a clip. Use `update_layout` to change the base layout.

    **Parameters:**

    * `videoId` (required): Video ID
    * `id` (required): Clip ID
    * `layoutId` (required): Layout ID
  </Accordion>

  <Accordion title="generate_auto_layouts">
    Let AI watch the clip and lay it out — the same as the editor's "Auto layouts". The AI picks an editing style (or follows `style`), sets the clip's base layout, and adds time-ranged layout changes. Generation watches the actual video, so this can take on the order of a minute for longer clips.

    <Warning>
      This replaces the clip's existing layouts with the generated ones.
    </Warning>

    **Parameters:**

    * `videoId` (required): Video ID
    * `id` (required): Clip ID
    * `style` (optional): Editing style guiding the AI's layout choices — one of `product-demo-portrait`, `product-demo-round`, `product-demo-square`, `product-demo-wide`, `presentation-tv-show`, `presentation-portrait`, `tutorial-round`, `tutorial-square`, `intro`, `outro`, `intro-and-outro`. Omit to let the AI pick one based on the clip's content.
    * `instructions` (optional): Free-form guidance for the AI, e.g. "keep the camera visible the whole time" or "punch in whenever a menu is opened".
  </Accordion>
</AccordionGroup>

### Background Music

Set one story-level audio track that loops over the whole video and is included in exports. This is separate from per-clip sound effects. Volume ranges from 0 to 1 and defaults to 0.2.

<AccordionGroup>
  <Accordion title="set_background_music">
    Set or replace the video's background music track. Call `create_source` first (`kind: "audio"` with the track's duration), `PUT` the audio bytes to the returned `uploadUrl`, then pass the `sourceId` here.

    **Parameters:**

    * `videoId` (required): Video ID
    * `sourceId` (required): Audio source ID from `create_source` (`kind: "audio"`)
    * `volume` (optional): Volume from 0 to 1 (default 0.2)
    * `name` (optional): Display name for the track
  </Accordion>

  <Accordion title="remove_background_music">
    Remove the video's background music track.

    **Parameters:**

    * `videoId` (required): Video ID
  </Accordion>
</AccordionGroup>

### Zooms

Zoom into a specific point on the clip's screen layer for a time range (the camera is unaffected). Use `manualZoom` for a fixed focus point or `trackingZoom` to follow the cursor in the screen recording. Times are in ms on the clip's playback timeline (cuts applied).

<AccordionGroup>
  <Accordion title="list_zooms">
    List zooms on a clip.

    **Parameters:**

    * `videoId` (required): Video ID
    * `id` (required): Clip ID
  </Accordion>

  <Accordion title="add_zoom">
    Add a zoom to a clip.

    **Parameters:**

    * `videoId` (required): Video ID
    * `id` (required): Clip ID
    * `type` (required): `manualZoom` or `trackingZoom`
    * `startTimeMs` (required): Start time in ms on the clip's playback timeline (cuts applied)
    * `durationMs` (required): Duration in ms
    * `focusPoint`: Required for `manualZoom` (rejected if missing); ignored for `trackingZoom`. Percentages — `{xPct, yPct}` (0-100).
    * `scale` (required): Magnification factor (1 = no zoom, 3.5 = max). A zoom without a scale cannot be rendered.
  </Accordion>

  <Accordion title="update_zoom">
    Update an existing zoom. Only provided fields change.

    **Parameters:**

    * `videoId` (required): Video ID
    * `id` (required): Clip ID
    * `zoomId` (required): Zoom ID
    * `type` (optional): `manualZoom` or `trackingZoom`
    * `startTimeMs` (optional): New start time in ms on the clip's playback timeline (cuts applied)
    * `durationMs` (optional): New duration
    * `focusPoint` (optional): New focus point
    * `scale` (optional): New magnification
  </Accordion>

  <Accordion title="remove_zoom">
    Remove a zoom from a clip.

    **Parameters:**

    * `videoId` (required): Video ID
    * `id` (required): Clip ID
    * `zoomId` (required): Zoom ID
  </Accordion>

  <Accordion title="generate_auto_zooms">
    Automatically generate tracking zooms from the mouse clicks in the clip's screen recording — the same as the editor's "Generate zooms". Every click opens a zoom window; nearby windows are merged. Requires the clip to contain a screen recording; returns an empty list when it has no usable mouse clicks.

    <Warning>
      By default this removes the clip's existing tracking zooms first, so repeated calls regenerate instead of stacking. Pass `replaceExisting: false` to keep them. Manual zooms are never touched.
    </Warning>

    **Parameters:**

    * `videoId` (required): Video ID
    * `id` (required): Clip ID
    * `intensity` (optional): How aggressively to zoom — `slow`, `medium` (default), or `fast`. `slow` opens fewer, longer windows; `fast` opens shorter, tighter ones at a higher scale.
    * `scale` (optional): Override the magnification factor (1 = no zoom, 3.5 = max). Defaults to the intensity preset's scale (1.5 for slow/medium, 2 for fast).
    * `replaceExisting` (optional): Defaults to `true` — existing tracking zooms are removed first. Pass `false` to keep them.
  </Accordion>
</AccordionGroup>

### Blurs and highlights

Mask a rectangular region of the clip's screen layer to either blur it (hide sensitive info) or highlight it (draw attention). Both share the same shape: a rectangle defined by a top-left `point` and `dimensions`, both in percentages. Times are in ms on the clip's playback timeline (cuts applied).

<AccordionGroup>
  <Accordion title="list_blurs / list_highlights">
    List blur or highlight masks on a clip.

    **Parameters:**

    * `videoId` (required): Video ID
    * `id` (required): Clip ID
  </Accordion>

  <Accordion title="add_blur / add_highlight">
    Add a blur or highlight mask to a clip.

    **Parameters:**

    * `videoId` (required): Video ID
    * `id` (required): Clip ID
    * `startTimeMs` (required): Start time in ms on the clip's playback timeline (cuts applied)
    * `durationMs` (required): Duration in ms
    * `point` (required): Top-left corner — `{xPct, yPct}` (0-100)
    * `dimensions` (required): Rectangle size — `{widthPct, heightPct}` (0-100)
  </Accordion>

  <Accordion title="update_blur / update_highlight">
    Update an existing blur or highlight.

    **Parameters:**

    * `videoId` (required): Video ID
    * `id` (required): Clip ID
    * `maskId` (required): Mask ID
    * `startTimeMs` (optional): New start time in ms on the clip's playback timeline (cuts applied)
    * `durationMs` (optional): New duration
    * `point` (optional): New top-left
    * `dimensions` (optional): New size
  </Accordion>

  <Accordion title="remove_blur / remove_highlight">
    Remove a blur or highlight from a clip.

    **Parameters:**

    * `videoId` (required): Video ID
    * `id` (required): Clip ID
    * `maskId` (required): Mask ID
  </Accordion>
</AccordionGroup>

### Overlays

Place an image or video on top of a clip for a time range. Both reference a `sourceId` from `create_source` (`kind: "image"` or `kind: "video"` — upload the bytes first); the overlay type follows the source's kind. Position uses a percentage `point` (so it survives ratio changes) and a pixel `dimensions` box (so the shape never distorts).

<Note>
  `startTimeMs` and `durationMs` are milliseconds on the clip's **playback timeline** (with cuts applied) — the same timeline as the cut transcript. A start at or past the end of the clip is rejected with a `400`.
</Note>

<AccordionGroup>
  <Accordion title="list_overlays">
    List the image and video overlays on a clip.

    **Parameters:**

    * `videoId` (required): Video ID
    * `id` (required): Clip ID
  </Accordion>

  <Accordion title="add_overlay">
    Add an image or video overlay on top of a clip. Call `create_source` first (`kind: "image"` or `kind: "video"`), `PUT` the bytes, then pass the returned `sourceId` — the overlay type follows the source's kind. When `point`/`dimensions` are omitted, a centered box is computed from the source.

    **Parameters:**

    * `videoId` (required): Video ID
    * `id` (required): Clip ID
    * `startTimeMs` (required): Start time in ms on the clip playback timeline (with cuts applied), the same timeline as the cut transcript
    * `durationMs` (required): Duration in ms
    * `sourceId` (required): Source ID from `create_source`
    * `name` (optional): Overlay name
    * `point` (optional): Top-left corner — `{xPct, yPct}` (0-100), as a percentage of the story canvas
    * `dimensions` (optional): Overlay size in artboard pixels — `{width, height}`
  </Accordion>

  <Accordion title="update_overlay">
    Update an existing overlay. Only provided fields change.

    **Parameters:**

    * `videoId` (required): Video ID
    * `id` (required): Clip ID
    * `overlayId` (required): Overlay ID
    * `startTimeMs` (optional): New start time in ms on the clip playback timeline (with cuts applied)
    * `durationMs` (optional): New duration in ms
    * `name` (optional): Overlay name
    * `point` (optional): New top-left — `{xPct, yPct}` (0-100)
    * `dimensions` (optional): New size in artboard pixels — `{width, height}`
  </Accordion>

  <Accordion title="remove_overlay">
    Remove an overlay from a clip.

    **Parameters:**

    * `videoId` (required): Video ID
    * `id` (required): Clip ID
    * `overlayId` (required): Overlay ID
  </Accordion>
</AccordionGroup>

### Sound effects

Add an audio clip to play over a clip for a time range. Upload the audio with `create_source` first (`kind: "audio"` with the audio's duration), then reference the returned `sourceId`. Upload the audio file as-is — MP3, WAV, M4A, and other common formats are accepted; no need to wrap it in an MP4.

<Note>
  `startTimeMs` and `durationMs` are milliseconds on the clip's **playback timeline** (with cuts applied) — the same timeline as the cut transcript. A start at or past the end of the clip is rejected with a `400`.
</Note>

<AccordionGroup>
  <Accordion title="list_sound_effects">
    List the sound effects on a clip.

    **Parameters:**

    * `videoId` (required): Video ID
    * `id` (required): Clip ID
  </Accordion>

  <Accordion title="add_sound_effect">
    Add a sound effect to a clip from an uploaded audio source. Call `create_source` first (`kind: "audio"` with the audio's duration), `PUT` the audio file as-is (MP3, WAV, M4A, …) to the returned `uploadUrl`, then pass the `sourceId` here.

    **Parameters:**

    * `videoId` (required): Video ID
    * `id` (required): Clip ID
    * `sourceId` (required): Source ID for the audio (from `create_source`)
    * `startTimeMs` (required): Start time in ms on the clip playback timeline (with cuts applied), the same timeline as the cut transcript
    * `durationMs` (required): Duration in ms
    * `name` (optional): Sound effect name
    * `volume` (optional): Playback volume (0 = muted, 1 = original). Defaults to 1.
  </Accordion>

  <Accordion title="update_sound_effect">
    Update an existing sound effect. Only provided fields change.

    **Parameters:**

    * `videoId` (required): Video ID
    * `id` (required): Clip ID
    * `soundEffectId` (required): Sound effect ID
    * `startTimeMs` (optional): New start time in ms on the clip playback timeline (with cuts applied)
    * `durationMs` (optional): New duration in ms
    * `name` (optional): Sound effect name
    * `volume` (optional): Playback volume (0 = muted, 1 = original)
  </Accordion>

  <Accordion title="remove_sound_effect">
    Remove a sound effect from a clip.

    **Parameters:**

    * `videoId` (required): Video ID
    * `id` (required): Clip ID
    * `soundEffectId` (required): Sound effect ID
  </Accordion>
</AccordionGroup>

## Example prompts

Once connected, you can ask your AI assistant things like:

* "List all my Tella videos"
* "Get the transcript for video xyz"
* "Create a playlist called 'Product Updates' and add my latest 3 videos"
* "Create a 'Customer facing' tag and add it to my demo videos"
* "Show me all videos tagged 'Onboarding'"
* "Make my onboarding video public and enable downloads"
* "Trim the first 5 seconds off the intro clip"
* "Add a side-by-side layout to the demo clip from 10s to 20s with the camera on the left"
* "Add a B-roll image of our product logo at 30s for 4 seconds"
* "Upload this video file as a new clip at the end of my onboarding video"
* "Add this product demo clip as B-roll between 12s and 20s of the intro"
* "Find the silent gaps in my latest clip longer than 1.5 seconds"
* "Remove all the filler words from the keynote clip"
* "Blur the email address in the bottom-left of the screen between 12s and 18s"
* "Zoom into the top-right of the screen at 25s for 3 seconds"
* "Generate zooms for my demo clip wherever I clicked"
* "Auto-layout my tutorial clip and keep the camera visible the whole time"
* "Turn on Studio Sound for my latest video"
* "Add my logo as an overlay in the top-right corner from 5s to 10s"
* "Play this whoosh sound effect at 8s when the transition happens"

## Troubleshooting

### Authentication issues

If you're having trouble authenticating, try clearing your MCP auth cache:

```bash theme={null}
rm -rf ~/.mcp-auth
```

Then reconnect to trigger a fresh OAuth flow.

### Connection issues

Ensure you're using a compatible MCP client. The server uses HTTP transport.
