# com.framesail/framesail (remote · api.framesail.com)

Create long-form YouTube videos end to end: script, storyboard, voiceover, final MP4.

- Trust score: 81/100 (high trust)
- Change this week: +8
- Registry status: active
- Liveness: live
- Owner verified: no
- Last scored: 2026-08-03

## Components

- remote · `api.framesail.com`: 81/100 (this document), [markdown](https://verifymcp.io/servers/com-framesail-framesail/api.md), [page](https://verifymcp.io/servers/com-framesail-framesail/api)

## Channel facts

- Endpoint: `https://api.framesail.com/mcp`
- Transports: `streamable-http`
- Auth: `none`
- Version: `1.0.0`

## Trust breakdown

How this component scores in each security and reliability category. Every signal is checked automatically against the live server, and we only credit what we can confirm. Scores are 0–100 per category. Scoring method: https://verifymcp.io/docs/scoring (what has changed: https://verifymcp.io/docs/scoring/changelog)

Scored 2026-08-03.

- **Endpoint Security**: 94/100
  - The endpoint's TLS certificate is valid, in date, and uses a strong key.
  - Authorisation is enforced on tool calls, advertised via RFC 9728 protected-resource metadata. Discovery is public, which costs nothing: no tool can be invoked without a token.
  - HTTPS is enforced; there's no plaintext access path.
  - The HSTS (Strict-Transport-Security) header is present.
  - DNSSEC check failed: this domain isn't protected by DNSSEC.
  - The authorisation server offers only Dynamic Client Registration (RFC 7591), which MCP 2026-07-28 deprecated in favour of Client ID Metadata Documents.
- **Transport & Reachability**: 100/100
  - Verified streamable-http transport via a live MCP handshake.
- **Schema Quality & AI Usability**: 73/100
  - AI-judged instruction clarity (excellent).
  - Context-footprint check failed: tool/resource definitions use about 9752 tokens (~143/item across 68 items; 68 tools + 0 resources), over budget; trim descriptions and params.
  - Usage-examples check failed: none of the tools include examples.
- **Stability & Change Management**: 27/100
  - Stability observed for 8 of 30 days with no destabilising changes; credit accrues until the full window elapses.
- **Tool Coverage**: 100/100
  - 100% of tools have a non-trivial description (not blank, and not just the tool's name).
  - 100% of tool parameters carry a description.
- **Capabilities**: 100/100
  - Implements a supported MCP spec version (2025-11-25); the latest is 2026-07-28.

## Install

### Claude

```bash
claude mcp add --transport http com-framesail-framesail https://api.framesail.com/mcp
```

### Codex

```toml
[mcp_servers.com-framesail-framesail]
url = "https://api.framesail.com/mcp"
```

### opencode

```json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "com-framesail-framesail": {
      "type": "remote",
      "url": "https://api.framesail.com/mcp",
      "enabled": true
    }
  }
}
```

### OpenClaw

```bash
openclaw mcp add com-framesail-framesail --url https://api.framesail.com/mcp --transport streamable-http
```

### Hermes

```yaml
mcp_servers:
  com-framesail-framesail:
    url: "https://api.framesail.com/mcp"
```

### Other

```json
{
  "mcpServers": {
    "com-framesail-framesail": {
      "type": "http",
      "url": "https://api.framesail.com/mcp"
    }
  }
}
```

The mcpServers block is a cross-client convention. Remote transports vary, so check your client's docs.

## Changelog

Every change recorded for this component, newest first. Days that predate change tracking, or that we cannot explain, say so: "we were watching and nothing happened" and "we were not watching" are different claims.

### 2026-08-02 (score 81, +1)

No change was recorded against any check on this day. Stability & Change Management went from 20 to 23. That category is still filling its 30-day observation window: 6 days of observed history at the previous scan, 7 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-07-31 (score 80, +5)

- [functional] We updated how we score, so this day's move reflects our rubric, not a change to the server

### 2026-07-29 (score 75, +1)

No change was recorded against any check on this day. Stability & Change Management went from 7 to 10. That category is still filling its 30-day observation window: 2 days of observed history at the previous scan, 3 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-07-28 (score 74, +1)

No change was recorded against any check on this day. Stability & Change Management went from 3 to 7. That category is still filling its 30-day observation window: 1 days of observed history at the previous scan, 2 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-07-27 (score 73, 0)

- [functional] We updated how we score, so this day's move reflects our rubric, not a change to the server

### 2026-07-26 (score 73)

First indexed and scored.

## MCP tools (68)

### `list_channels` (~38 tokens)

List channels

List your channels. Every project lives in a channel, which owns the
    reusable styles (art/narrative/director) that drive generation.

### `create_channel` (~73 tokens)

Create channel

Create a new channel — the container for projects and their reusable
    styles. Use when the user wants a fresh creative identity rather than
    adding to an existing channel.

Input parameters:

- `description` (string): Optional free-text description of the channel's content focus
- `name` (string, required): Display name for the new channel

### `list_projects` (~37 tokens)

List projects

List projects in a channel.

Input parameters:

- `channel_id` (string, required): ID of the channel whose projects to list, from list_channels or create_channel

### `create_project` (~116 tokens)

Create project

Create a project. The description (the video concept/topic) seeds script
    generation, so write a meaningful one. The response's web_url is the
    project's page in the web app — share it so the user can follow along.

Input parameters:

- `channel_id` (string, required): ID of the channel to create the project in, from list_channels or create_channel
- `description` (string): The video concept/topic; seeds script generation, so make it specific and meaningful
- `title` (string, required): Project title shown in the app

### `get_project` (~43 tokens)

Get project

Fetch a project row — settings, voice config, default style, export URL.

Input parameters:

- `project_id` (string, required): Project ID, as returned by create_project or list_projects

### `update_project` (~132 tokens)

Update project

Patch project fields. Updatable: title, description, asset_mix,
    sfx_level, video_concept, voice_mix, voice_tts_provider,
    script_target_minutes, narrator_speed. (The narrator's TTS voice is NOT
    here — use set_narrator_voice.)

Input parameters:

- `fields` (object, required): Partial dict of fields to patch; allowed keys: title, description, asset_mix, sfx_level, video_concept, voice_mix, voice_tts_provider, script_target_minutes, narrator_speed
- `project_id` (string, required): Project ID, as returned by create_project or list_projects

### `delete_project` (~62 tokens)

Delete project

Permanently delete a project and everything in it (script versions,
    assets, voiceover, segments, renders). Irreversible — confirm with your
    user first.

Input parameters:

- `project_id` (string, required): ID of the project to permanently delete, from list_projects

### `set_project_style` (~98 tokens)

Set project style

Set the project's default style — the style whose art/narrative/director
    fields drive its generations. Use after create_style to put a new visual
    identity into effect, or to switch a project between channel styles.

Input parameters:

- `project_id` (string, required): Project ID, as returned by create_project or list_projects
- `style_id` (string, required): ID of the style to make the project's default, from create_style or list_styles

### `update_caption_config` (~102 tokens)

Update caption config

Merge a patch into the project's burned-in caption config (keys like
    enabled, plus styling). Read the current value from get_project
    (caption_config). Applies at the next export — no rebuild needed.

Input parameters:

- `caption_config` (object, required): Partial caption config to merge (keys like enabled, plus styling); read the current value from get_project's caption_config
- `project_id` (string, required): Project ID, as returned by create_project or list_projects

### `get_pipeline_progress` (~191 tokens)

Get pipeline progress

THE resume/orientation tool: one call returns every pipeline step's
    state (script -> scan -> reference_images -> voices -> voiceover ->
    style_templates -> storyboard -> segment_assets -> scenes -> export), any
    running jobs, and a next_action telling you exactly what to do next. Call
    this when picking up an existing project, after any await_jobs, or whenever
    you're unsure where a video stands — never guess pipeline position.

    Every step carries a web_url — the page in the Framesail web app where your
    user can see that step's output. Share it whenever you present a step's
    results ("review the storyboard here: ...") so they can inspect and edit in
    the browser; the app and this API act on the same live state.

Input parameters:

- `project_id` (string, required): Project ID, as returned by create_project or list_projects

### `get_workflow_status` (~188 tokens)

Get workflow status

Poll this between steps: returns active + recently-finished AI jobs
    (scope by project_id, or style_id for style analysis), plus per-segment-
    asset render statuses for projects. A step is done when its jobs reach
    status=complete (or error, with a user-readable message). NOTE: finished
    jobs drop out of `jobs` after ~30s — a short list does NOT mean work was
    lost; judge render batches by `segment_assets` statuses (or
    get_pipeline_progress), never by counting jobs. Prefer await_jobs over
    polling this in a tight loop.

Input parameters:

- `project_id` (string): Project ID to scope jobs to; pass exactly one of project_id or style_id
- `style_id` (string): Style ID to scope jobs to (style analysis); pass exactly one of project_id or style_id

### `await_jobs` (~179 tokens)

Wait for jobs

Block (server-side) until the scope has no pending/running jobs, or the
    timeout passes — use this instead of polling get_workflow_status yourself.
    Returns {done, jobs}. If done=false the work is still running: just call
    await_jobs again (a 3-5 minute storyboard takes a few consecutive calls).
    Keep timeout_seconds <= 50 so the client doesn't time out the tool call.

Input parameters:

- `project_id` (string): Project ID whose jobs to wait for; pass exactly one of project_id or style_id
- `style_id` (string): Style ID whose analysis/template jobs to wait for; pass exactly one of project_id or style_id
- `timeout_seconds` (integer): Max seconds to block server-side before returning done=false; keep <= 50 so the client doesn't time out the tool call

### `get_section_template` (~93 tokens)

Get section template

Inspect the prompt sections a generation job exposes for per-call
    override via editable_sections (jobs: script, script_scan, storyboard,
    segment_image, segment_video, voice_block, ...). Sections marked locked
    cannot be overridden.

Input parameters:

- `job` (string, required): Generation job name, e.g. "script", "script_scan", "storyboard", "segment_image", "segment_video", "voice_block"

### `list_models` (~109 tokens)

List models

List the models allowed for a generation job, with display names, credit
    estimates, and each model's settings_schema — the valid keys for that
    tool's `settings` param (e.g. image quality/orientation, video duration).
    The first entry is the default every tool uses when model is omitted.

Input parameters:

- `job` (string, required): Generation job whose allowed models to list, e.g. "script", "storyboard", "segment_image", "segment_video", "voice_block"

### `generate_script` (~134 tokens)

Generate script

Generate the project's script from its description/concept and the
    channel's narrative style. Async — returns {job_id}; poll get_workflow_status.

Input parameters:

- `editable_sections`: Per-call prompt section overrides, keyed by section name; see get_section_template("script") for the sections this job exposes
- `model` (string): Model ID to generate with; empty uses the default (see list_models("script"))
- `project_id` (string, required): Project ID, as returned by create_project or list_projects
- `settings`: Model-specific settings; valid keys come from the model's settings_schema in list_models("script")

### `get_script` (~87 tokens)

Get script

Read the active script's full text + the version list. Use this to show
    the script to your user for review/feedback before scan_script — the
    review-edit-resave loop (get_script -> discuss -> save_script) is the
    expected workflow when the user wants input.

Input parameters:

- `project_id` (string, required): Project ID, as returned by create_project or list_projects

### `save_script` (~98 tokens)

Save script

Save script text (your own draft, or an edited version of the generated
    one — saving creates a new version, old versions are kept). Run scan_script
    afterwards so assets and voice blocks reflect the new text.

Input parameters:

- `content` (string, required): Full script text to save as a new version; plain prose narration, optionally with scene headings
- `project_id` (string, required): Project ID, as returned by create_project or list_projects

### `revise_script` (~160 tokens)

Revise script

AI-rewrite a passage of the active script in the project's narrative
    voice (the same in-editor revise the UI offers). selected_text must appear
    verbatim in the script; omit it to revise the whole script. Synchronous —
    returns {revised_text}, which is NOT saved: splice it over selected_text
    (or replace the full script) and call save_script to keep it.

Input parameters:

- `instruction` (string, required): Natural-language edit instruction, e.g. "make the intro punchier"
- `project_id` (string, required): Project ID, as returned by create_project or list_projects
- `selected_text` (string): Exact passage to rewrite; must appear verbatim in the active script. Omit to revise the whole script

### `activate_script_version` (~85 tokens)

Activate script version

Switch the project's active script to another saved version (ids come
    from get_script's version list — every save_script creates one). Re-run
    scan_script / rescan_voice_blocks afterwards if the text differs, since
    downstream artifacts follow the active version.

Input parameters:

- `script_id` (string, required): ID of the script version to activate, from get_script's version list

### `scan_script` (~141 tokens)

Scan script

Analyze the active script: extracts character/environment/object assets
    and splits narration into voice blocks. DESTRUCTIVE on re-run (assets are
    recreated, not merged — curated descriptions, reference images, and voices
    are lost; prefer rescan_voice_blocks after script edits). Async — returns
    {job_id}.

Input parameters:

- `editable_sections`: Per-call prompt section overrides, keyed by section name; see get_section_template("script_scan")
- `model` (string): Model ID to scan with; empty uses the default (see list_models("script_scan"))
- `project_id` (string, required): Project ID, as returned by create_project or list_projects

### `list_assets` (~175 tokens)

List assets

List the project's assets extracted by scan_script — characters,
    environments, objects. Each has a description (the spec every shot uses to
    render it — surfaced top-level here; the raw row nests it at
    ai_output.description), an optional reference image (file_path is a public
    URL — view_image it), and for characters a voice_id. Review these after
    scan_script: fix descriptions, then generate_asset_reference for each one
    (all of them need a reference image before voiceover). asset_type filter:
    "character" | "environment" | "object".

Input parameters:

- `asset_type` (string): Optional filter: "character", "environment", or "object"; empty lists all asset types
- `project_id` (string, required): Project ID, as returned by create_project or list_projects

### `create_asset` (~138 tokens)

Create asset

Manually add a character/environment/object the scan missed.
    asset_type: "character" | "environment" | "object". The description is the
    generation-facing spec of its look — be specific.

Input parameters:

- `asset_type` (string, required): Kind of asset: "character", "environment", or "object"
- `description` (string): Generation-facing spec of the asset's look; every shot renders from it, so be specific
- `name` (string, required): Asset name as the script refers to it (e.g. the character's name)
- `project_id` (string, required): Project ID, as returned by create_project or list_projects

### `update_asset` (~84 tokens)

Update asset

Rename an asset and/or rewrite its description. If the look changed,
    regenerate its reference image afterwards so renders match.

Input parameters:

- `asset_id` (string, required): Asset ID, as returned by list_assets or create_asset
- `description` (string): New generation-facing look description; empty leaves it unchanged
- `name` (string): New asset name; empty leaves the name unchanged

### `delete_asset` (~41 tokens)

Delete asset

Delete a project asset (e.g. one the scan over-extracted).

Input parameters:

- `asset_id` (string, required): ID of the asset to delete, from list_assets

### `generate_asset_reference` (~205 tokens)

Generate asset reference image

Render an asset's reference image in the channel's art style — the
    visual anchor that keeps a character/environment looking identical across
    every shot. EVERY character, environment, and object asset needs one before
    generate_voiceover (the server enforces this; fire the jobs for all assets,
    then one await_jobs). Async — the job writes the image onto the asset row:
    await_jobs(project_id), then list_assets and view_image the file_path to
    check likeness.

Input parameters:

- `asset_id` (string, required): ID of the asset to render a reference image for, from list_assets
- `editable_sections`: Per-call prompt section overrides, keyed by section name; see get_section_template for the reference-image job
- `model` (string): Image model ID; empty uses the server default for reference images
- `settings`: Model-specific settings (e.g. image quality/orientation); valid keys come from the model's settings_schema in list_models

### `set_character_voice` (~96 tokens)

Set character voice

Bind a TTS voice to a character asset — required before generate_voiceover
    for every character with dialogue (the narrator's voice is separate:
    set_narrator_voice). Browse ids with list_voices.

Input parameters:

- `asset_id` (string, required): Character asset ID, from list_assets
- `voice_id` (string, required): TTS voice ID, from list_voices (use the provider matching the project's voice_tts_provider)

### `list_voices` (~100 tokens)

List voices

List available TTS voices (id, label, preview audio URL) for a provider:
    "minimax" (default engine) or "elevenlabs". Match the project's
    voice_tts_provider (see get_project) so picked ids work with its engine.

Input parameters:

- `provider` (string): TTS engine to list voices for: "minimax" (default engine) or "elevenlabs"; match the project's voice_tts_provider

### `set_narrator_voice` (~102 tokens)

Set narrator voice

Set the project's narrator TTS voice — required before generate_voiceover
    whenever the script has narration. Browse ids with list_voices. (Character
    dialogue voices are separate: set_character_voice.)

Input parameters:

- `project_id` (string, required): Project ID, as returned by create_project or list_projects
- `voice_id` (string, required): TTS voice ID for the narrator, from list_voices (use the provider matching the project's voice_tts_provider)

### `list_voice_blocks` (~50 tokens)

List voice blocks

List the project's voice blocks (per-speaker narration chunks) with
    their audio status and assigned voices.

Input parameters:

- `project_id` (string, required): Project ID, as returned by create_project or list_projects

### `update_voice_block` (~116 tokens)

Update voice block

Override one voice block's voice or playback volume (block ids from
    list_voice_blocks). Re-run generate_voiceover for the block afterwards if
    you changed its voice — existing audio is not regenerated automatically.

Input parameters:

- `voice_block_id` (string, required): Voice block ID, from list_voice_blocks
- `voice_id` (string): New TTS voice ID for this block, from list_voices; empty leaves the voice unchanged
- `volume`: Playback volume for this block, 0-1; omit to leave unchanged

### `rescan_voice_blocks` (~117 tokens)

Rescan voice blocks

Re-extract voice blocks from the active script WITHOUT touching assets
    or their reference images — the non-destructive alternative to scan_script
    after a script edit. Existing audio is superseded by the new block split,
    so re-run generate_voiceover afterwards. Async — returns {job_id}.

Input parameters:

- `model` (string): Model ID for the re-extraction; empty uses the default (see list_models("voice_block_scan"))
- `project_id` (string, required): Project ID, as returned by create_project or list_projects

### `generate_voiceover` (~274 tokens)

Generate voiceover

Generate TTS audio for the project's voice blocks. Without
    voice_block_ids it fills gaps: only blocks with no audio yet run, so
    re-calling it is always safe (already-generated and currently-generating
    blocks are skipped, never re-billed). Pass voice_block_ids to explicitly
    REgenerate those blocks (e.g. after changing a block's voice). Speakers
    must have voices bound first — set_narrator_voice / set_character_voice.
    Optional editable_sections/settings apply to every selected block (see
    get_section_template("voice_block") and list_models("voice_block")).
    Async — returns one job per block.

Input parameters:

- `editable_sections`: Per-call prompt section overrides applied to every selected block; see get_section_template("voice_block")
- `model` (string): TTS model ID; empty uses the default (see list_models("voice_block"))
- `project_id` (string, required): Project ID, as returned by create_project or list_projects
- `settings`: Model-specific TTS settings applied to every selected block; valid keys come from the model's settings_schema in list_models("voice_block")
- `voice_block_ids`: Block IDs (from list_voice_blocks) to explicitly REgenerate; omit to fill gaps — only blocks with no audio yet run

### `generate_storyboard` (~207 tokens)

Generate storyboard

Plan the full visual storyboard: segments, shot pacing, image/video
    prompts, overlays, continuation chains — driven by the channel's director
    and art styles. Requires voiceover to exist (timing comes from it).
    BEFORE calling: confirm the project's asset_mix with your user (image vs
    video vs generated_graphic percentages, update_project) — the storyboard
    plans against it and video-heavy mixes multiply the later render cost.
    Async — returns {job_id}; this is the longest LLM step.

Input parameters:

- `editable_sections`: Per-call prompt section overrides, keyed by section name; see get_section_template("storyboard")
- `model` (string): Model ID to plan with; empty uses the default (see list_models("storyboard"))
- `project_id` (string, required): Project ID, as returned by create_project or list_projects
- `settings`: Model-specific settings; valid keys come from the model's settings_schema in list_models("storyboard")

### `get_segments` (~177 tokens)

List segments

List the storyboard's segments (narration span, type, duration, creative
    direction). The 1-based segment_number is the handle every segment tool takes
    (update/split/combine/continuation/regenerate) — you never need a UUID.

    Each segment also reports `continues_from_segment`. When set, this shot is a
    CONTINUATION of that earlier segment: its rendered frame carries over (same
    composition, characters, and setting) and only the delta changes — an added
    overlay, a shifted expression, a closer angle, a slow reframe. Null means a
    fresh, independent shot. The storyboard plans these chains automatically;
    adjust them with set_segment_continuation.

Input parameters:

- `project_id` (string, required): Project ID, as returned by create_project or list_projects

### `get_segment_assets` (~95 tokens)

Get segment assets

List one segment's assets (images/video/overlays) including their
    status, config (prompts, model), and public URLs of rendered files —
    pass an image's public_url to view_image to actually look at it.

Input parameters:

- `project_id` (string, required): Project ID, as returned by create_project or list_projects
- `segment_number` (integer, required): 1-based segment number, as reported by get_segments

### `regenerate_segment_asset` (~262 tokens)

Regenerate segment asset

Regenerate a segment's primary image or video with optional overrides —
    the API equivalent of the editor's expert drawer. asset_type: "image" |
    "video" (for a video segment, "image" targets its start frame). Use a
    different model, override prompt sections (see
    get_section_template("segment_image")), or tweak settings (e.g. image
    quality), then re-run just this asset. Async — returns {job_id}.

Input parameters:

- `asset_type` (string, required): "image" or "video"; for a video segment, "image" targets its start frame
- `editable_sections`: Per-call prompt section overrides, keyed by section name; see get_section_template("segment_image") or ("segment_video")
- `model` (string): Model ID to render with; empty uses the job's default (see list_models("segment_image") / list_models("segment_video"))
- `project_id` (string, required): Project ID, as returned by create_project or list_projects
- `segment_number` (integer, required): 1-based segment number, as reported by get_segments
- `settings`: Model-specific settings (e.g. image quality, video duration); valid keys come from the model's settings_schema in list_models

### `change_segment_type` (~147 tokens)

Change segment type

Change a segment's visual type: "image" | "video" | "overlay_scene".
    carry_frame=true reuses the already-rendered image as the video start
    frame (or vice versa) instead of recreating it.

Input parameters:

- `carry_frame` (boolean): True reuses the already-rendered frame as the new type's starting visual instead of recreating it from scratch
- `project_id` (string, required): Project ID, as returned by create_project or list_projects
- `segment_number` (integer, required): 1-based segment number, as reported by get_segments
- `segment_type` (string, required): New visual type: "image", "video", or "overlay_scene"

### `update_segment_content` (~174 tokens)

Rewrite segment content

Rewrite one segment's creative direction from feedback ("make this shot
    a close-up", "show the machine from above") — an LLM rewrites the shot's
    prompts; continuation links, SFX, and overlays are preserved. The visual
    assets reset to not_started: re-render them afterwards (generate_segments
    or regenerate_segment_asset). For a precise prompt tweak with no rewrite,
    use regenerate_segment_asset with editable_sections instead.

Input parameters:

- `project_id` (string, required): Project ID, as returned by create_project or list_projects
- `segment_number` (integer, required): 1-based segment number, as reported by get_segments
- `user_input` (string, required): Natural-language feedback describing the change to this shot, e.g. "make this a close-up" or "show the machine from above"

### `split_segment` (~160 tokens)

Split segment

Split a segment at the given time offsets (ms, 1-3 cuts → 2-4 parts).
    inherit_index picks which resulting part keeps the original creative data.
    Later segments renumber — re-check get_segments before further edits.

Input parameters:

- `inherit_index` (integer): 0-based index of the resulting part that keeps the original creative data (default: the first part)
- `offsets_ms` (array, required): Cut points as millisecond offsets from the segment start, ascending; 1-3 cuts producing 2-4 parts
- `project_id` (string, required): Project ID, as returned by create_project or list_projects
- `segment_number` (integer, required): 1-based number of the segment to split, as reported by get_segments

### `combine_segments` (~147 tokens)

Combine segments

Merge a segment with an adjacent one (segment numbers must be
    neighbors). keep: "this" | "other" — whose creative data survives. Later
    segments renumber — re-check get_segments before further edits.

Input parameters:

- `keep` (string): Whose creative data survives the merge: "this" (segment_number) or "other" (with_segment_number)
- `project_id` (string, required): Project ID, as returned by create_project or list_projects
- `segment_number` (integer, required): 1-based segment number, as reported by get_segments
- `with_segment_number` (integer, required): 1-based number of the adjacent segment to merge with (must neighbor segment_number)

### `set_segment_continuation` (~163 tokens)

Set segment continuation

Make a segment's image render as a continuation of an EARLIER segment's
    frame (same composition evolving — the storyboard's continues_from_segment,
    settable after the fact). continues_from is that earlier segment's number;
    pass 0 to clear the link. Regenerate the segment's image afterwards — the
    reference is applied at generation time.

Input parameters:

- `continues_from` (integer): 1-based number of the EARLIER segment whose frame this one continues; pass 0 to clear the link
- `project_id` (string, required): Project ID, as returned by create_project or list_projects
- `segment_number` (integer, required): 1-based number of the segment whose image should continue an earlier frame, as reported by get_segments

### `add_segment_sfx` (~111 tokens)

Add segment sound effect

Attach a sound effect from the audio library to a segment (find track
    ids via browse_audio_library with category="sfx"). Re-run build_scenes to
    get it onto the timeline.

Input parameters:

- `library_track_id` (string, required): Audio library track ID, from browse_audio_library(category="sfx")
- `project_id` (string, required): Project ID, as returned by create_project or list_projects
- `segment_number` (integer, required): 1-based segment number, as reported by get_segments

### `remove_segment_sfx` (~122 tokens)

Remove segment sound effect

Remove a sound effect from a segment. With one SFX attached, no name
    needed; with several, pass sfx_name (the asset name shown by
    get_segment_assets).

Input parameters:

- `project_id` (string, required): Project ID, as returned by create_project or list_projects
- `segment_number` (integer, required): 1-based segment number, as reported by get_segments
- `sfx_name` (string): Name of the SFX asset to remove, as shown by get_segment_assets; needed only when the segment has several SFX attached

### `generate_segments` (~243 tokens)

Render segment assets

Render every actionable segment asset (images, video clips, overlays)
    across the project, in dependency order. THE most expensive call in the
    pipeline: ALWAYS dry_run=true first, show your user the estimate next to
    get_credit_balance, and wait for a fresh yes before the real run — prior
    blanket permission ("do the whole thing") does not cover this spend. Pass
    segment_numbers to render only a subset — e.g. segments 1-18 for the
    opening minute before committing to the full video. Safe to re-run:
    completed and currently-generating assets are skipped, so a second call
    only picks up new/failed work. Async — one job per asset; await_jobs until
    all complete.

Input parameters:

- `dry_run` (boolean): True returns the credit-cost estimate without rendering anything; ALWAYS run true first and get user approval before the real run
- `project_id` (string, required): Project ID, as returned by create_project or list_projects
- `segment_numbers`: 1-based segment numbers (from get_segments) to render only a subset; omit to render every actionable asset in the project

### `build_scenes` (~56 tokens)

Build scenes

Compile segments + assets + voiceover into the editor/render timeline
    (scenes). Run after segment assets are complete, before export.

Input parameters:

- `project_id` (string, required): Project ID, as returned by create_project or list_projects

### `list_scenes` (~40 tokens)

List scenes

List the project's scenes (composition layers, durations, layout).

Input parameters:

- `project_id` (string, required): Project ID, as returned by create_project or list_projects

### `director_note` (~162 tokens)

Director note (one scene)

Edit ONE scene with a natural-language note (the same director chat the
    editor UI uses): move/restyle/add/remove layers and overlays, retime, etc.
    Synchronous — returns the applied mutations + updated scene. Use
    list_scenes to find scene ids; for notes spanning the whole video use
    project_director_note instead.

Input parameters:

- `conversation_history`: Prior chat turns as [{"role": ..., "content": ...}] to continue an editing conversation on this scene; omit to start fresh
- `message` (string, required): Natural-language edit note for this scene, e.g. "move the caption to the top" or "remove the overlay"
- `scene_id` (string, required): ID of the scene to edit, from list_scenes

### `project_director_note` (~141 tokens)

Director note (whole project)

Apply a project-WIDE director note ("make the intro punchier", "all
    captions bigger", "tighten pacing in the back half"). A routing pass picks
    only the scenes the note applies to and edits each one. Synchronous — a
    few seconds per affected scene. Returns the per-scene results; re-run
    export_video afterwards to see changes in the final render.

Input parameters:

- `message` (string, required): Project-wide director note in natural language, e.g. "make the intro punchier" or "all captions bigger"
- `project_id` (string, required): Project ID, as returned by create_project or list_projects

### `export_video` (~69 tokens)

Export video

Render the final MP4 (Remotion). Fetches the current timeline and queues
    the render. Async — poll get_workflow_status for the video_export job, then
    call get_video_url.

Input parameters:

- `project_id` (string, required): Project ID, as returned by create_project or list_projects

### `get_video_url` (~37 tokens)

Get video download URL

Download URL for the most recent completed export.

Input parameters:

- `project_id` (string, required): Project ID, as returned by create_project or list_projects

### `list_styles` (~69 tokens)

List styles

List the channel's style rows (variable groups). Styles hold the
    art_style / narrative_style / director_style / script_prompt fields that
    drive every generation step, plus any custom @variables.

Input parameters:

- `channel_id` (string, required): ID of the channel that owns the styles, from list_channels

### `get_style` (~75 tokens)

Get style

Fetch one style row — its inputs (reference material) and analyzed
    fields (art_style, narrative_style, director_style, script_prompt, ...).
    Show fields to the user for review; fine-tune with update_style_fields.

Input parameters:

- `style_id` (string, required): Style ID, as returned by create_style or list_styles

### `update_style_fields` (~156 tokens)

Update style fields

Hand-edit a style's analyzed fields after reviewing them — e.g. tighten
    the art_style wording or adjust the director_style pacing rules. `fields`
    is the FULL flat dict to write: {key: {"value": str, "applies_to": [...]}}
    (fetch with get_style, modify, send back). Editing fields does NOT trigger
    re-analysis, so your edits stick.

Input parameters:

- `fields` (object, required): FULL flat dict of analyzed fields to write, shaped {key: {"value": str, "applies_to": [...]}} — fetch with get_style, modify, send the whole dict back
- `style_id` (string, required): Style ID, as returned by create_style or list_styles

### `list_style_presets` (~117 tokens)

List style presets

The curated preset catalog for the no-AI style creation path, grouped
    by axis (art_style / narrative_style / director_style). Show the user the
    labels + descriptions and let THEM pick one per axis — don't choose
    silently. Art presets include preview image URLs (view_image works on
    them). Create with create_style(presets={axis: id, ...}) — instant, no
    analysis job. Full field text lands on the style row (get_style shows it
    after creation).

### `create_style` (~268 tokens)

Create style

Create a style. Two mutually exclusive paths:

    References (best): inputs=[{"input_type": "youtube" | "text", "value":
    "<url or description>"}] — YouTube videos are watched and text directions
    read; async analysis writes the style's art/narrative/director fields:
    await_jobs(style_id=...) before using the style. (Image/video FILE
    references require the multipart REST endpoint POST /styles.)

    Presets (instant, no analysis): presets={"art_style": id,
    "narrative_style": id, "director_style": id} — all three axes, ids from
    list_style_presets.

Input parameters:

- `channel_id` (string, required): ID of the channel to create the style in, from list_channels
- `inputs`: Reference material to analyze, [{"input_type": "youtube" | "text", "value": "<url or description>"}]; triggers an async analysis job. Mutually exclusive with presets
- `name` (string, required): Display name for the style
- `presets`: Preset IDs per axis, {"art_style": id, "narrative_style": id, "director_style": id}, from list_style_presets; instant, no analysis. Mutually exclusive with inputs

### `analyze_style` (~59 tokens)

Re-analyze style

Re-run style analysis (after changing a style's inputs). Async —
    await_jobs(style_id=...) until the style_analysis job completes.

Input parameters:

- `style_id` (string, required): ID of the style to re-analyze, from create_style or list_styles

### `generate_style_template` (~252 tokens)

Generate style template

Render one of a style's two template images — a REAL step of style
    setup, not an optional extra: a style isn't finished until both its
    character and environment templates are rendered (the app shows them on
    the style card). Asset reference images render against them (characters →
    character template; environments and objects → environment template), and
    segment renders fall back on them when a shot has no asset reference — so
    finish BOTH before generate_asset_reference. Run once per template_type
    ("character" | "environment") for every new style; skip only types the
    style already has (get_style shows them). Async — await_jobs(style_id=...),
    then get_style.

Input parameters:

- `editable_sections`: Per-call prompt section overrides, keyed by section name; see get_section_template for the template job
- `model` (string): Image model ID; empty uses the template job's default (see list_models)
- `style_id` (string, required): Style ID, as returned by create_style or list_styles
- `template_type` (string, required): Which of the style's two template images to render: "character" or "environment" — run once for each

### `delete_style` (~63 tokens)

Delete style

Delete a style (e.g. a failed analysis experiment). Don't delete a
    style that projects still use as their default — rebind them first with
    set_project_style.

Input parameters:

- `style_id` (string, required): ID of the style to delete, from list_styles

### `set_provider_key` (~121 tokens)

Set provider key

Register a BYOK provider API key (encrypted at rest, BYOK plan only).
    Jobs whose model belongs to this provider then run on YOUR key and charge
    0 credits. Providers: openai, gemini, anthropic, fal, elevenlabs, minimax.

Input parameters:

- `key` (string, required): The provider API key to register; stored encrypted at rest
- `provider` (string, required): Provider the key belongs to: "openai", "gemini", "anthropic", "fal", "elevenlabs", or "minimax"

### `list_provider_keys` (~24 tokens)

List provider keys

List registered BYOK providers (masked — only the last 4 characters).

### `whoami` (~46 tokens)

Who am I

Verify the connection: the account email and plan behind the current
    credential. Call once after connecting — before creating anything — to
    confirm you're on the right account; costs nothing.

### `get_credit_balance` (~55 tokens)

Get credit balance

Current credit balance + plan info. Check before expensive steps (a
    full segment render can cost hundreds of credits — generate_segments
    dry_run gives the estimate). Jobs covered by a BYOK provider key bill 0.

### `browse_audio_library` (~132 tokens)

Browse audio library

Browse the audio library for background music and sound effects.
    category: "music" | "sfx". Returns track ids for add_music_track /
    add_segment_sfx.

Input parameters:

- `category` (string): Track kind: "music" (background tracks) or "sfx" (sound effects); empty returns both
- `genre` (string): Filter by the track's genre tag; empty for no filter
- `mood` (string): Filter by the track's mood tag; empty for no filter
- `search` (string): Free-text search over track names/descriptions; empty for no filter

### `list_music_tracks` (~41 tokens)

List music tracks

List the project's background music tracks (volume, loop, timing).

Input parameters:

- `project_id` (string, required): Project ID, as returned by create_project or list_projects

### `add_music_track` (~210 tokens)

Add music track

Add background music to the project from the audio library (find track
    ids with browse_audio_library, category="music"). Defaults loop the track
    under the whole video at bed level (volume 0.12 ≈ -18.4 dB under narration —
    don't raise it without being asked); re-run export_video to hear it.

Input parameters:

- `library_track_id` (string, required): Audio library track ID, from browse_audio_library(category="music")
- `loop` (boolean): True loops the track under the whole video; false plays it once
- `name` (string): Display name for the track on the project's timeline
- `project_id` (string, required): Project ID, as returned by create_project or list_projects
- `start_frame` (integer): Timeline frame at which the track starts (0 = start of the video)
- `volume` (number): Playback volume 0-1; the 0.12 default sits at bed level under narration — don't raise it unless asked

### `update_music_track` (~108 tokens)

Update music track

Tweak a music track. fields keys: name, volume (0-1), loop, start_frame,
    duration_frames, position, trim_start_frame, trim_end_frame.

Input parameters:

- `fields` (object, required): Partial dict of track fields to patch; allowed keys: name, volume (0-1), loop, start_frame, duration_frames, position, trim_start_frame, trim_end_frame
- `track_id` (string, required): Music track ID, from list_music_tracks or add_music_track

### `remove_music_track` (~37 tokens)

Remove music track

Remove a music track from the project.

Input parameters:

- `track_id` (string, required): ID of the music track to remove, from list_music_tracks

### `view_image` (~106 tokens)

View image

Fetch a rendered Framesail image so you (and your user) can SEE it —
    pass a URL from get_segment_assets, get_style, or asset endpoints. Returns
    the image inline. Only Framesail media URLs are allowed.

Input parameters:

- `url` (string, required): Public Framesail media URL to fetch — a public_url from get_segment_assets, a file_path from list_assets, or a template/preset image URL from get_style / list_style_presets; other hosts are rejected

## Diagnostics

Captured diagnostic sections: TLS, DNSSEC, Authorisation, Transports. The full working is on the page: https://verifymcp.io/servers/com-framesail-framesail/api#diagnostics

## Score history

- 2026-08-03: 81
- 2026-08-02: 81
- 2026-08-01: 80
- 2026-07-31: 80
- 2026-07-30: 75
- 2026-07-29: 75
- 2026-07-28: 74
- 2026-07-27: 73
- 2026-07-26: 73

## Links

- Remote endpoint: https://api.framesail.com/mcp
- Website: https://framesail.com/developers
- Changelog RSS feed: https://verifymcp.io/servers/com-framesail-framesail/api/changelog.xml
- Changelog JSON feed: https://verifymcp.io/servers/com-framesail-framesail/api/changelog.json
- HTML version of this page: https://verifymcp.io/servers/com-framesail-framesail/api
