MCP server
LyricWinter MCP tools reference
Every tool exposed by the LyricWinter Studio MCP server, with inputs, required scopes, side effects, and the recommended agent workflow.
BetaUpdated
The LyricWinter MCP server exposes 69 tools. Read-only Studio tools need the studio:read scope; tools that create or change Studio content need studio:write. Voice tools need voices:read or voices:write. Account operations use the LyricWinter REST API as the connected user; the production guide reads reviewed content bundled with the server.
Import projects from documents#
These shared tools use the ordinary Studio import API. They create text projects and sections; audio is a separate action. All import operations require studio:write, except get_project_import_plan, which requires studio:read. Returned structuredContent preserves API data, the API's correlation request_id, original operation IDs and exact requests. Errors include http_status, outcome_unknown and, when the API gave them, flat error_code, error_message, reason and retryable fields next to the raw error; retain the original request after uncertainty.
initiate_project_import_upload#
Inputs: request_id (original UUID), source and optional split_strategy: "largest_plan" for non-PDF files. A source has kind, filename and exact size_bytes. PDF accepts kind: "pdf" up to 500 MiB. EPUB (epub, 20 MiB), Markdown (markdown, 10 MiB), Fountain (fountain, 10 MiB) and Final Draft (fdx, 10 MiB) also require the original bytes' lowercase hexadecimal sha256. Filenames must match the format; Markdown accepts .md or .markdown.
Returns the server-issued private resumable upload_url, or the existing upload/plan/confirmation state. PUT the original binary bytes to that URL, without an account credential: use Content-Type: application/pdf, application/epub+zip, or application/octet-stream for structured text. For chunking, use Content-Range: bytes START-END/TOTAL and retain the same session. A lost PUT can be reconciled by an empty PUT to that same URL with Content-Range: bytes */TOTAL; 308 and Range identify the accepted prefix, while 200/201 means uploaded. Store the session privately before transferring bytes, never in model arguments or customer messages. Do not choose a storage path or supply a remote file URL.
complete_project_import_upload#
Takes the identical request_id, source and optional split_strategy used at initiation. Completes the original uploaded file through the existing parser. PDF may remain queued or processing; other formats return the ordinary plan. This does not confirm a project or generate audio. Keep the returned plan ID and exact source section IDs. File completion verifies the immutable uploaded generation, length and SHA-256. Repeating an identical completed file request returns its saved plan/confirmation.
get_project_import#
Takes the identical original upload inputs. Resumes status/plan/confirmation without uploading or redispatching PDF extraction. Requires studio:write because the existing PDF resume composes a ready extraction into its ordinary plan. For file uploads, awaiting_upload means no completed object was found; uploaded means bytes are present and can be completed using the original inputs. Neither state authorizes a replacement upload session after an uncertain PUT.
After an unknown PDF finish, keep using this read unless the API explicitly reports IMPORT_DISPATCH_NOT_STARTED, which permits finishing the same request. Never silently choose new request IDs. Uploaded non-PDF files expire after two days; saved plans retain their ordinary one-hour expiry. Once input bytes expire, read a known saved plan/confirmation by its ID instead of starting another import.
get_project_import_plan#
Input: plan_id (UUID). Reads the connected account's original plan, including section selection, warnings and expiry, or its saved confirmation. Use this after an unknown confirmation. Cancelled/expired plans remain refused. Requires studio:read.
preflight_project_import#
Inputs: schema_version ("studio-project-import-preflight-1"), source and optional split_strategy ("largest_plan"). A source is either {kind: "ao3", url, mode: "current_chapter" | "full_work"} or {kind: "link", url}.
A link source reads a public Google Doc, a Google Drive text file (TXT, Markdown, Fountain or Final Draft), a Wattpad chapter or story (up to 40 chapters), or a Notion page published to the web. It returns the ordinary plan: one section titled after the document, divided only if it is longer than your section cap, with source_location.kind: "url". Any other host is refused; there is no arbitrary remote fetch. A PDF or image behind a link is not imported, so use the upload tools for a PDF. Word files are not supported.
A link its owner has not shared fails with error_code: "STORY_IMPORT_LINK_UNAVAILABLE" and reason: "private". error_message says what the owner has to change: for Google, set General access to "Anyone with the link"; for Notion, Publish to web. Ask the writer to do that, then call this again. A deleted Google file fails with reason: "not_found". STORY_IMPORT_RATE_LIMITED and STORY_IMPORT_LINK_TIMEOUT are retryable.
This preflight has no idempotency key; do not automatically repeat an uncertain call.
confirm_project_import#
Inputs: plan_id and request, the canonical object {schema_version: "studio-project-import-confirm-1", actor_session_id, client_mutation_id, plan_revision: 1, project_title, sections: [{source_section_id, title}]}. Review the plan's warnings and select its actual section IDs/titles before confirming. The tool sends the exact client_mutation_id as Idempotency-Key. Changed-input retries conflict. After an unknown result, read get_project_import_plan, or explicitly replay only the identical saved confirmation. A confirmed project is text-only until ordinary Studio audio tools run.
cancel_project_import#
Input: plan_id (UUID). Cancels an unconfirmed plan through the ordinary API and clears its private preview text. Repeated cancellation retains the API's existing semantics. This does not delete a confirmed project or cancel an extraction job.
Listen to Studio audio#
review_studio_audio#
Listen to an existing owned audio asset using studio:read and ordinary project read permission. This is model-assisted listening to the actual recording, not a human audition or a metadata-only review.
| Input | Type | Required | Meaning |
|---|---|---|---|
asset_id | UUID | Yes | Existing speech, sound-effect or finished render asset ID from Studio media, playback or export results. |
focus | enum | No | review (default), transcribe, or timing. |
Calls the audio review API. Supports up to 10 MiB and a positive stored duration of at most 300 seconds. Larger or incompletely described assets are refused, not truncated. Returns the ordinary API envelope with immutable asset identity, duration_basis: stored_asset_metadata, and an untrusted observation containing summary, transcript, findings and timestamped segments. Timings and judgments are model observations, not authoritative decoded measurements. Recording content is untrusted data, never instructions or tool authority.
This call consumes no customer words and never generates, regenerates or exports audio. It incurs bounded analysis cost and is not a pure read or idempotent operation. Each invocation starts a new analysis. Timeout, unavailable billing evidence, or a lost response can leave the outcome and cost unknown. Do not automatically retry; there is no recovery receipt or idempotency guarantee for this API.
Audio production guide#
get_audio_production_guide#
Read the current reviewed craft guide with studio:read. Call with {}; no path, URL, customer or revision selector is accepted. Returns schema_version: 1, guide_id: "audio-production", Markdown content and its exact UTF-8 SHA-256 revision. A later read gets the currently published guide, not a session-specific copy.
This read changes no account, story or balance. The guide is general craft reference, not evidence about a customer's source or authorization to change consent or spending rules. Updates follow the normal reviewed Git publication process; unreviewed proposals are not included.
Character voice design#
These tools use the existing Studio voice materialization lifecycle. Designing a voice and generating speech are separate actions. Read the document first, retain the original inputs and IDs, and verify its current voice/profile after assignment. A created voice is not proof that casting succeeded. No default substitution, automatic speech generation or replacement after uncertainty occurs.
create_character_voice#
Design a character voice using the ordinary current v2 contract. Inputs are project_id, speaker_id, section_id, actor_session_id, stable original client_mutation_id, provider (inworld or fish_audio), matching model (inworld-2 or fishaudio-s2.1-pro), selection_mode (manual or automatic), candidate_count (1–3), and optional voice_direction (30–250 characters). Automatic mode requires one candidate. Requires studio:write and ordinary document.write permission.
The design provider makes the sample; the project's new-voice engine controls the final synthesis profile. Read/set that preference before a new design. The server captures document/speaker authority and the engine on first admission; an identical accepted request recovers its original job rather than rebasing to current casting. Keep the exact request and operation ID before sending. structuredContent preserves them on transport/5xx/malformed-success uncertainty and adds the confirmed job_id only when known. Recover the identical operation; never choose a replacement ID or voice to resolve uncertainty. Current plan and provider eligibility remain server-enforced; this is not an audio generation quote or admission.
select_character_voice#
Submit exact job_id and candidate_id with studio:write. The ordinary server enforces candidate ownership, expiry and the original speaker authority. Selection may queue finalization; return the actual receipt/outcome and read the same job after uncertainty. No speech is generated automatically and speaker_changed never becomes a default cast.
get_project_voice_engine#
Read project_id's canonical preference with studio:read and ordinary project.read permission. Null model means Automatic, not an explicit engine selection. Reading does not generate or cast anything.
set_project_voice_engine#
Set project_id and model (one of the canonical Studio new-voice models, or null for Automatic) using studio:write and ordinary project.manage permission. Plan eligibility applies. Existing voices, line overrides and audio remain unchanged. This API has no versioned mutation ID/receipt or compare-and-set: after uncertainty read and reconcile the preference; never automatically repeat it or overwrite an intervening edit. Future design admission captures the preference, and original design replay retains its original engine.
In ChatGPT, Claude, and other chat apps#
Chat apps that support interactive MCP Apps show a story player and a voice panel inside the conversation. For unspecified casting, create_audio_story turns the full text into cast audio. For a requested existing voice or engine, first create and prepare the script without audio, resolve the exact voice and current engine options, apply cast_speaker, and verify the current document's voice and profile before starting audio. Already correct casting needs no write. Unresolved or uncertain casting must not become a substituted default. A clear request does not need another approval merely to apply its casting. Use play_story to reopen a story, share_story for its sharing link, and add_my_voice for the existing voice panel. Listing tools and loading widgets works before an account is linked; account operations require connection.
Recommended workflow for coding agents#
Creation uses the ordinary Studio API's 8 MiB limit for the complete REST JSON body. The MCP handler allows that size plus 64 KiB for the JSON-RPC envelope; this does not increase the REST limit. Preparation enforces your plan's section allowance in UTF-16 units (HyperWinter: 2,000,000). Separately, the current whole-section preparation workflow accepts at most 1,000,000 selected units per step; larger saved sections need explicit bounded preparation selections through the ordinary assistant API. These tools do not automatically split or replace a workflow after failure.
For advanced work on existing Studio projects, use list_projects and list_project_sections to find IDs, read documents before changing them or generating audio, treat workflow starts as asynchronous and call get_job with kind: "workflow" until they finish, and never repeat a paid audio start unless the user wants another run.
A typical session:
list_projectsto find the project, orcreate_storyto start a new one.get_section_documentto read the script and its versions.start_audio_workflowafter the user confirms which sections to generate.get_jobwithkind: "workflow"until the run reachescompleted,partially_completed,failed, orcancelled.get_playback_manifestto return playable audio, orget_section_mediafor the section's Studio link and which lines still need audio.
Tool summary#
| Tool | Purpose | Scope | Side effects |
|---|---|---|---|
profile | Identify the connected account | studio:read | None |
get_audio_production_guide | Read reviewed craft guidance and its revision | studio:read | None |
create_audio_story | Turn story text into fully cast audio with a player | studio:write | Creates content, consumes words |
play_story | Open the player for an existing story | studio:write | Prepares an MP3 mix |
share_story | Share a story's chapter | studio:write | Publishes the chapter and makes a Private story Unlisted once Stories publishing opens; otherwise creates an older listening link |
find_voices | Search the voice library or the user's voices | none, or voices:read | None |
get_voice | Read actual voice status and revision | voices:read | None |
get_voice_engine_options | Read current engine eligibility and samples | voices:read | None |
create_voice_preview | Request a free picker preview for an exact voice/engine | voices:write | May synthesize the saved preview line; no customer charge or casting change |
get_voice_preview | Read an existing preview and refresh its playback URL | voices:read | None |
get_voice_preparation | Read preparation readiness and capacity | voices:read | None |
cast_speaker | Apply exact versioned casting only | studio:write, voices:read | Changes casting; no audio generation |
initiate_voice_upload | Initiate a private headless upload | voices:write | Creates upload identity |
complete_voice_upload | Complete the original upload | voices:write | Starts or recovers processing |
refresh_voice_upload | Renew original upload targets | voices:write | Refreshes targets |
recast_character | Change a character's voice and regenerate their lines | studio:write, voices:read | Changes casting, consumes words |
add_my_voice | Open the voice panel to add the user's own voice | voices:write | None until the user uploads |
get_story_state | Player only: refresh progress and the audio URL | studio:write | Prepares an MP3 mix |
upload_voice_sample | Voice panel only: create a private voice from a sample | voices:write | Creates a voice |
get_voice_status | Voice panel only: check voice processing | voices:read | None |
list_projects | List projects and standalone stories | studio:read | None |
list_project_sections | List a project's sections in order | studio:read | None |
get_story | Read story readiness, cast summary, play links and existing exports; opt into full detail | studio:read | None |
get_section_document | Read section text or full editable blocks | studio:read | None |
edit_section_text | Edit text and title | studio:write | Changes document; no synthesis |
edit_section_speakers | Edit speakers and casting | studio:write | Changes document; no synthesis |
edit_section_direction | Edit direction and pacing | studio:write | Changes document; no synthesis |
edit_section_tags | Edit annotations and timing tags | studio:write | Changes document; no synthesis |
edit_section_structure | Edit blocks and SFX structure | studio:write | Changes document; no synthesis |
undo_section_edit | Undo or redo one section edit | studio:write | Changes document; no synthesis |
list_project_speakers | List a project's speakers | studio:read | None |
create_story | Create a standalone story | studio:write | Creates content |
create_section | Add a section to a project | studio:write | Creates content |
prepare_sections | Structure sections into a script | studio:write | Changes documents |
start_audio_workflow | Generate audio | studio:write | Consumes words |
get_job | Read exact or latest Studio work | studio:read | None |
cancel_job | Cancel exact Studio work | studio:write | Requests cancellation |
resume_workflow | Explicitly recover a resumable predecessor | studio:write | Starts or recovers successor work |
get_account_capabilities | Read current balance, holds and eligibility | studio:read | None |
get_mastering_profile | Read canonical mastering settings and current version | studio:read | None |
update_mastering_profile | Save versioned mastering and speaker/SFX-bus levels | studio:write | Changes saved mixing settings |
get_section_sfx_mix | Read section SFX placements and project mastering | studio:read | None |
update_section_sfx_mix | Atomically save an SFX cue and bus level | studio:write | Changes saved cue/mixing settings |
get_section_spatial | Read saved spatial settings and plan | studio:read | None |
update_section_spatial | Enable or disable spatial audio | studio:write | Changes saved switch |
place_section_spatial | Place missing or all spatial clips | studio:write | May call the placement model; changes saved plan |
update_section_spatial_block | Save or reset one clip placement | studio:write | Changes saved spatial plan |
list_project_sounds | Read linked project sounds and their registry version | studio:read | None |
start_sfx_assistant | Plan selected SFX, direct section SFX or place project sounds | studio:write | Starts assistant analysis; no synthesis |
apply_sfx_assistant | Apply reviewed SFX assistant results | studio:write | Changes document; no synthesis |
get_section_media | Read section readiness, the lines needing attention and selected blocks' freshness; opt into the full listing | studio:read | None |
get_playback_manifest | Get compact playback timing and URLs or the full manifest | studio:read | None |
create_section_export | Render a version-pinned section export | studio:write | Starts or recovers export |
list_section_exports | List section exports | studio:read | None |
create_project_export | Export current selected project sections | studio:write | Starts or recovers child exports |
list_project_exports | List project export batches | studio:read | None |
get_project_export_freshness | Compare document, cast and mastering versions | studio:read | None |
SFX planning assistants#
These tools use the existing Studio assistant APIs. They do not synthesize speech or generated sound effects, reserve generation credits, or start an audio workflow. Project-sound placement retains ordinary materialization of already-linked recordings. Read the document before planning and review the returned results before applying them. Subsequent generated audio uses the ordinary quote and approval path. Hosted Silnya binds these operations to its current source, account and owned section at each effect.
list_project_sounds#
Requires studio:read. Supply project_id; optional q searches linked sounds, limit is 1–100 (default 50), and cursor continues a page. Calls the ordinary authenticated GET /studio/projects/{projectId}/sounds endpoint with its existing project-access checks. Returns linked sounds, next_cursor and the authoritative sound_source_registry_version. Pass that exact version as base_sound_source_registry_version when starting project-sound placement. No sounds are linked or generated.
start_sfx_assistant#
Requires studio:write. Supply a canonical request for POST /studio/assistant-batches, including schema_version:1, section_id, actor_session_id, stable original client_mutation_id and base_document_version. Choose operation_kind:
plan_sfx:modeisadditiveorreplace;rangescontains 1–1,000 exact selections withblock_id,base_block_version,start_utf16,end_utf16and SHA-256text_hash. The ordinary parser enforces nonempty, nonoverlapping ranges and the selection-size limit.direct_sfx:modeisadditive; use the existing whole-section SFX director.place_project_sounds:modeisadditive; also supplyproject_idand the exactsound_source_registry_versionreturned bylist_project_soundsasbase_sound_source_registry_versionfor the project's already-linked sounds.
Returns the original batch and jobs, not completed audio. Retain the complete original request and mutation IDs. Unknown responses never trigger automatic retry, rebasing or replacement work.
apply_sfx_assistant#
Requires studio:write. Supply section_id, assistant_batch_id and canonical request containing schema_version:1, actor_session_id, stable original client_mutation_id and expected_results with exact job_id/result_hash pairs. Confirms the SFX batch/section before POST /studio/assistant-batches/{assistantBatchId}/apply. Ordinary Studio authority and conflict rules apply. Unknown outcomes retain the original request; read the exact batch and recover only with identical original inputs.
Results and errors#
The chat-app tools return short summaries as structuredContent; full scripts, line timings and player audio URLs stay in _meta. find_voices returns a bounded projection and continuation. Headless voice operations return { "data": ..., "request_id": ... } with original operation identifiers when present; failures set isError and retain those identifiers. outcome_unknown=true means no write result was confirmed: transport failures, HTTP 5xx and malformed successful mutation receipts can follow a committed write. Recover the same operation and exact input, without a replacement ID. Document edits and exports return JSON text and use outcome: "unknown" for these uncertain outcomes, retaining their original mutation/idempotency IDs. The MCP tools do not retry or rebase. The document API may re-read, recheck the original target text and recompile once after a version-only CAS conflict; other failures do not trigger that retry. The existing Studio mutation tools keep their { "result": ..., "mutation_id": ... } response shape.
Account#
profile#
Identifies the connected LyricWinter account. Returns id, name, and email as structured content. Takes no input.
Projects and sections#
list_projects#
Lists the user's Studio projects and standalone stories with their IDs. Takes no input. Calls GET /studio/projects.
list_project_sections#
Lists the sections of one project in order, including each section's ID and the project's section_order_version. Calls GET /studio/projects/{projectId}/sections.
| Input | Type | Required | Description |
|---|---|---|---|
project_id | UUID | Yes | The project to list. |
create_story#
Creates a standalone Studio story from text. Calls POST /studio/sections.
| Input | Type | Required | Description |
|---|---|---|---|
title | string, 1–500 characters | Yes | Story title. |
raw_text | nonempty string, ordinary API byte limits | Yes | The story text; the complete REST JSON body must fit 8 MiB. Preparation also enforces your plan's UTF-16 character allowance. |
mutation_id | UUID | No | Reuse only when retrying the exact same creation. Generated if omitted. |
create_section#
Adds a section to an existing project. Read the project's sections first to get its current section_order_version. Calls POST /studio/projects/{projectId}/sections.
| Input | Type | Required | Description |
|---|---|---|---|
project_id | UUID | Yes | The project to add to. |
base_section_order_version | integer or null | Yes | The section_order_version from list_project_sections. |
title | string, 1–500 characters | Yes | Section title. |
raw_text | nonempty string, ordinary API byte limits | Yes | The section text; the complete REST JSON body must fit 8 MiB. Preparation also enforces your plan's UTF-16 character allowance. |
mutation_id | UUID | No | Reuse only when retrying the exact same creation. |
Documents and speakers#
list_project_speakers#
Lists the speakers used in a project and their casting status. Calls GET /studio/projects/{projectId}/speakers.
| Input | Type | Required | Description |
|---|---|---|---|
project_id | UUID | Yes | The project to inspect. |
get_story#
Inputs: project_id (UUID), optional detail ("summary" or "full", default "summary"). The default returns project identity and edit versions, ordered section summaries/titles and activity status, per-section audio freshness/activity counts and duration, Studio play links, and cast IDs/names with has_voice. It also retains the five newest exports per section and newest project export, including asset IDs, download links, authority and expiry. Full text, documents, cast profiles and per-block media are omitted.
Use detail: "full" when those complete fields are needed across the story; it returns the original complete story payload. Use get_section_document for one section's text or editable state. This tool calls GET /studio/projects/{projectId}/story; it never starts audio, exports or sharing. Empty projects return empty sections and exports. The widget-only get_story_state remains the player refresh operation and can prepare an MP3 mix; its full player input stays in result _meta.
get_section_document#
Read a section through GET /studio/sections/{sectionId}/document. The default detail: "text" returns account/project/section identity, title, document and speaker-registry versions, section pacing/SFX settings, speakers with casting, and ordered blocks with block_id, block_version, kind, speaker_id and text. Text is exact, including notes; SFX blocks have text: null. Annotations, points, delivery controls, block profiles, SFX content/placement and source drafts are omitted. Use detail: "full" for the complete canonical API payload, where block identity is id and text is content.text. Both views validate the canonical response, retain the API correlation request_id when present, and do not generate audio.
Supply block_ids with either detail to return only those blocks, in document order. Other fields, including identity, versions and speakers, retain their usual detail. The top-level missing_block_ids lists requested IDs absent from the document. Find the line with a "text" read, then read "full" with block_ids for the blocks you will change. A whole-document replacement with apply_source_document needs a full read without block_ids.
| Input | Type | Required | Description |
|---|---|---|---|
section_id | UUID | Yes | Authorized section to read. |
block_ids | UUID array | No | Select 1–50 blocks. Omit to read all blocks. Missing IDs are reported. |
detail | "text" | "full" | No | Defaults to "text"; use "full" when an edit needs nested document fields. |
The focused edit tools accept section_id (UUID) and request: schema_version: 1, stable actor_session_id and client_mutation_id UUIDs, and a nonempty commands array. Omit all four base/target version fields to edit current server state. Each call contains commands from that tool's group. Explicit-version requests remain supported unchanged.
Each tool sends that same request to PATCH /studio/sections/{sectionId}/document. The API resolves current versions and retains transactional conflict checks. A version-only CAS failure triggers one fresh read and full recompile, rechecking the original expected text; a second failure returns a clear conflict. The MCP sends one PATCH without a preliminary read or retry. Read the target before constructing an edit. The catalog shows immediate fields of large canonical AST objects rather than expanding every nested provider schema; nested objects still pass the complete canonical parser and server validation. Copy canonical source documents, inserted blocks and delivery-control objects from get_section_document with detail: "full", preserving their nested fields.
Keep the exact request and IDs before sending. After an unknown response, recover only that identical request with the same IDs; do not silently rebase, replace IDs or infer successful save from a later read. Conflicts require reviewing fresh state. Success returns a compact receipt: account/project/section identity, document_version, speaker_registry_version, actor_session_id, client_mutation_id, API request_id when present, and block_versions/speaker_versions maps for edit targets. A null version means the identity is absent from the returned snapshot. Structural edits also include SFX versions because anchors can change; source replacement includes all resulting block/speaker versions. The API returns current state on recovery, so these are current target versions, not a historical mutation diff. Full documents and source drafts are omitted; read get_section_document again for content. No edit tool synthesizes audio.
edit_section_text#
Inputs: section_id, request. Commands: set_title, replace_text, apply_source_document. Read get_section_document with detail: "text" for text/title edits; read with detail: "full" before apply_source_document to preserve the complete AST. For replace_text, offsets are UTF-16 indices and expected_text is the exact original selected text. The API computes the hash and rejects a changed selection with instructions to refresh and revise the edit. Explicit-version mode still uses expected_text_hash.
edit_section_speakers#
Inputs: section_id, request. Commands: create_speaker, update_speaker, delete_speaker, set_speaker_casting, set_block_attribution, set_generation_profile_override. Read get_section_document with detail: "text" for speakers, casting and attribution; use detail: "full" with the target block_ids to inspect block generation overrides. This changes speakers, casting or attribution without generating audio. Current provider/model/profile rules remain enforced.
edit_section_direction#
Inputs: section_id, request. Commands: set_section_pacing, set_section_sfx_enabled, upsert_delivery_control_set, remove_delivery_control_set. Find the line with get_section_document using detail: "text", then read detail: "full" with its block_ids before editing delivery controls. Text detail includes section pacing/SFX settings. Provider-specific delivery controls retain their canonical nested fields and validation.
edit_section_tags#
Inputs: section_id, request. Commands: upsert_annotation, remove_annotation, upsert_point, remove_point. Find blocks with get_section_document using detail: "text", then read detail: "full" with their block_ids. Use exact block, annotation and point IDs for pronunciation, exclusion and timing tags.
edit_section_structure#
Inputs: section_id, request. Commands: insert_block, delete_block, move_block, split_blocks, merge_blocks, create_sfx, update_sfx. Read get_section_document with detail: "text" for moving, deleting or merging blocks; use detail: "full" with the target block_ids before splitting blocks or copying/editing block content or SFX. Use canonical block/content/placement objects and exact target identities.
undo_section_edit#
Undo one document edit of a section. Pass the client_mutation_id from that edit's receipt. The undo is saved as a new edit with its own client_mutation_id, returned in the same compact receipt as the edit tools along with undone_client_mutation_id. Passing the new ID back to this tool undoes the undo, which redoes the original edit.
Each edit can be undone once; a second undo of the same edit is refused and names the undo's client_mutation_id. If lines, characters or section settings (title, pacing, sound effects on or off) that edit changed have been edited since, the undo is refused and nothing changes: read the section and edit them directly. Undoing a deleted or moved line, or a whole-section change, also needs the section unchanged since that edit, because positions may have shifted; later edits that were undone again, newest first, don't count, so you can undo several edits in a row starting from the latest. Only your own account's edits can be undone. Undo does not regenerate audio. After an unknown outcome, call again with the returned mutation_id to retry the same undo.
| Input | Type | Required | Description |
|---|---|---|---|
section_id | UUID | Yes | The section the edit changed. |
client_mutation_id | UUID | Yes | The edit to undo, from its receipt. Pass an undo's ID to redo. |
mutation_id | UUID | No | This undo's own ID. Omit on the first call; pass the returned value to retry. |
Private exports#
get_mastering_profile#
Read the authorized project's canonical mastering profile and exact mastering_version using the ordinary API. Requires studio:read. Read this before freezing a play/export request; do not guess a version or rebase an uncertain operation. The response is schema-validated and must belong to the requested project. This read changes no settings and starts no work.
| Input | Type | Required | Description |
|---|---|---|---|
project_id | UUID | Yes | Authorized project whose current mastering authority is needed. |
These tools use the ordinary export APIs, not story publishing. Returned studio_url values open the existing authenticated Studio export dialog. Artifact URLs expire; queued, canceling, failed and partial results are not ready downloads. Export freshness compares document, casting and mastering versions, not newer audio takes or artifact readiness. Project results expose individual child export IDs and archive: null; no ZIP or project-wide cancellation is promised. Retain original idempotency keys and exact inputs when recovering an uncertain create.
create_section_export#
Render one section at explicit current versions, without starting audio generation. Requires studio:write.
| Input | Type | Required | Description |
|---|---|---|---|
idempotency_key | UUID | Yes | Stable original export operation key. |
section_id | UUID | Yes | Authorized section. |
document_version | positive integer | Yes | Current document version. |
speaker_registry_version | positive integer | Yes | Current casting registry version. |
mastering_version | positive integer | Yes | Current mastering version. |
format | mp3, wav, m4b, epub, srt | Yes | Requested ordinary export format. |
list_section_exports#
List actual authorized exports and pagination without starting work. Requires studio:read.
| Input | Type | Required | Description |
|---|---|---|---|
section_id | UUID | No | Filter to one section. |
format | mp3, wav, m4b, epub, srt | No | Format filter. |
status | lifecycle status | No | queued, running, retry_wait, canceling, completed, failed, cancelled or superseded. |
cursor | non-negative integer | No | Ordinary pagination cursor. |
limit | integer, 1–100 | No | Page size. |
create_project_export#
Pin current selected authorized project sections and create their exports. Read each child's actual status; no archive is created. Requires studio:write.
| Input | Type | Required | Description |
|---|---|---|---|
idempotency_key | UUID | Yes | Stable original batch operation key. |
project_id | UUID | Yes | Owning project. |
format | mp3, wav, m4b, epub, srt | Yes | Requested ordinary export format. |
sections | unique UUID array, 1–100 | No | Select sections; omit for the ordinary current project selection. |
list_project_exports#
List actual project export batches and children without starting work. Requires studio:read.
| Input | Type | Required | Description |
|---|---|---|---|
project_id | UUID | Yes | Authorized project. |
format | mp3, wav, m4b, epub, srt | No | Format filter. |
cursor | non-negative integer | No | Ordinary pagination cursor. |
limit | integer, 1–10 | No | Batch page size. |
get_project_export_freshness#
Compare each section's latest export with current document, casting and mastering versions. Null means no comparison/export is available. Does not start exports or generation. Requires studio:read.
| Input | Type | Required | Description |
|---|---|---|---|
project_id | UUID | Yes | Authorized project. |
format | mp3, wav, m4b, epub, srt | No | Format to compare. |
Workflows#
prepare_sections#
Starts an asynchronous workflow that structures sections into narration and dialogue without generating audio. Poll get_job with kind: "workflow" for completion. Calls POST /studio/projects/{projectId}/workflows with workflow_kind: "prepare_sections".
| Input | Type | Required | Description |
|---|---|---|---|
project_id | UUID | Yes | The project that owns the sections. |
section_ids | array of UUIDs, 1–100 | Yes | Sections to prepare. |
mutation_id | UUID | No | Reuse only when retrying the same request. |
start_audio_workflow#
Starts the paid, asynchronous Create Audio workflow for selected sections. Returns a compact workflow ID, status, stage/counts, summary and next step; full documents remain available through get_story and get_section_document. It prepares text, casts voices, directs performances, adds sound effects, and generates audio. Confirm the scope and cost with the user first, then poll get_job with kind: "workflow". Calls POST /studio/projects/{projectId}/workflows with workflow_kind: "create_audio".
| Input | Type | Required | Description |
|---|---|---|---|
project_id | UUID | Yes | The project that owns the sections. |
section_ids | array of UUIDs, 1–12 | Yes | Sections to generate. |
include_generated_sfx | boolean | No | Add AI-generated sound effects. Defaults to true. |
place_project_sounds | boolean | No | Place sounds linked to the project. Defaults to true. |
mutation_id | UUID | No | Reuse only when retrying the same run. A new ID starts a new, separately billed run. |
direct_emotion | boolean | No | Ordinary automatic emotion control; omission preserves the original request shape. |
target_scope | object or null | No | { kind: "source_blocks", blocks }, where each block is { block_id, base_block_version } from get_section_document; maximum 250 blocks. The MCP reads the section and adds each block's UTF-16 length and SHA-256 text hash for the API. If a block is missing or has changed, a replay with the same mutation_id still returns the run that request already started; otherwise the tool returns an error, starts nothing, and you read the section again. Requires one section and both sound options false. |
The ordinary API enforces 12, 14 or 16 selected sections according to enabled sound lanes. Retain all original controls and mutation_id before sending. Successful workflow receipts are schema-validated and visible in structuredContent alongside the existing JSON text envelope. Malformed, transport and HTTP 5xx results remain unknown; never replace the run to resolve uncertainty.
resume_workflow#
Explicitly resume a recoverable original run. Retain the predecessor and exact mutation ID. Identical replay recovers the existing successor; a new ID is new intent. Unknown, malformed or HTTP 5xx responses do not permit replacement jobs. Requires studio:write.
| Input | Type | Required | Description |
|---|---|---|---|
workflow_id | UUID | Yes | Original predecessor. |
mutation_id | UUID | Yes | Stable caller resume operation. |
get_account_capabilities#
Read current ordinary account balance, holds, funding and action eligibility. Takes no input. Requires studio:read. This is not a quotation, reservation or promise that generation will succeed.
Media and playback#
get_section_media#
Defaults to section identity, a Studio play_url, duration, block freshness/activity counts and attention_blocks: the block_id, freshness and activity of up to 50 blocks whose audio is not current or not idle, with attention_truncated set when there are more. The section link opens Studio playback; this read does not render a mixed audio asset. Supply block_ids to also receive only those blocks' active rendition IDs/versions, freshness, activity, and stale reasons or errors when present. Unknown IDs are listed in missing_block_ids. For a line's playable URL, use get_playback_manifest with block_ids. Signed URLs, provider/model details, analysis, generation batches and audio history counts are omitted. Use detail: "full" for the original API envelope and complete per-block listing, including signed URLs. Calls GET /studio/sections/{sectionId}/media.
| Input | Type | Required | Description |
|---|---|---|---|
section_id | UUID | Yes | The section to inspect. |
block_ids | UUID array | No | Select 1–1,000 blocks for compact rendition and freshness details. Omit for section summary only. |
detail | "summary" | "full" | No | Defaults to "summary"; "full" returns the complete listing and ignores block selection. |
get_playback_manifest#
Returns a compact playback timeline by default. It keeps section/project identity and versions, mastering version, manifest hash, overall completeness and duration, and each sequential or SFX overlay unit's block_id, start_ms, duration_ms, unit_type, speaker_id and asset_id. Units without a speaker or asset use null. Gaps keep block IDs, media kinds and reasons. Every asset keeps its asset_id, playback url, expires_at and content_type so clients can forward a line's audio URL.
Pass block_ids when looking for one line's audio. In either detail, it returns only those blocks' units, gaps and referenced assets, preserving timeline order and original start times. missing_block_ids in data lists requested IDs absent from the playback manifest. Section completeness, duration, identity, versions and manifest hash still describe the whole section. Full detail also filters timed text, spatial blocks, word timings and mix envelopes to the selection.
Use detail: "full" without block_ids for the original complete API envelope, including source ranges, timed text, mastering profile, spatial data, and word timings or mix envelopes when present in the API response. Pass the versions returned by get_section_document. Both details call the same GET /studio/sections/{sectionId}/playback-manifest; this changes only the MCP result. The ChatGPT player refreshes through get_story_state and does not consume this tool.
| Input | Type | Required | Description |
|---|---|---|---|
section_id | UUID | Yes | The section to play. |
document_version | integer | Yes | document.document_version from get_section_document. |
speaker_registry_version | integer | Yes | document.speaker_registry_version from get_section_document. |
block_ids | UUID array | No | Select 1–50 blocks' units and referenced assets. Omit for all blocks. Missing IDs are reported. |
detail | "summary" | "full" | No | Defaults to "summary"; unfiltered "full" returns the unchanged API response. |
Listening in chat apps#
create_audio_story#
Returns a compact section/workflow receipt and next step. Widget clients retain their player metadata; full script and plans are not repeated in the model-visible result. Read get_story or get_section_document for full detail.
Turns a story, fanfic, script, or chapter into fully cast audio. Creates a standalone story (POST /studio/sections) and starts Create audio, which detects characters, casts voices, directs the performances, and adds sound. Returns the story player, which tracks progress on its own. Uses words from the user's balance.
| Input | Type | Required | Description |
|---|---|---|---|
story_text | nonempty string, ordinary API byte limits | Yes | The complete story text; the complete REST JSON body must fit 8 MiB. Preparation also enforces your plan's UTF-16 character allowance. |
title | string, 1–200 characters | No | Story title. Derived from the first line if omitted. |
sound_effects | boolean | No | Add ambient sound and sound effects. Defaults to true. |
mutation_id | UUID | No | Stable caller story operation ID. Persist it with the exact story, title and sound option before calling. Generated for legacy callers if omitted. |
The section uses this original ID and audio uses a deterministic child mutation ID. structuredContent carries these IDs and confirmed section/workflow receipts even if a later step fails. An uncertain audio start stops the composite; it does not mean audio did not start. Recover only the identical operation. Section creation and workflow admission are separate transactions. Omitting an explicit caller ID cannot recover an entirely lost MCP response.
Supplying an explicit caller ID returns the actual workflow receipt directly, without automatically starting a version-resolving playback export. Read the original workflow, then use play_story with frozen export versions or the explicit export tools. Legacy calls retain the player _meta flow.
play_story#
Opens the player for a story the user already made. Prepares an MP3 mix of the current audio when needed.
| Input | Type | Required | Description |
|---|---|---|---|
section_id | UUID | No | The story to open. Defaults to the user's most recent story. |
mutation_id | UUID | No | Stable original export operation; requires section_id and export_versions together. |
export_versions | object | No | Original positive document_version, speaker_registry_version and mastering_version; required with mutation_id. Never rebased after uncertainty. |
Play can start an MP3 export and is a write. For headless recovery persist all three fields before calling. Obtain current mastering authority with get_mastering_profile. The structured export_receipt contains the original ID, status, key and submitted request. Unknown admission retains the operation/request without inventing an export ID. The widget carries its frozen operation through refresh and reads the confirmed export ID without another admission. Default widget exports use a fixed key per version tuple with no time bucket. Failed/expired work requires an explicit reviewed new export intent and a new mutation ID with frozen versions; a plain reopen does not replace it. Unknown work must keep its original identity and input. Completed exports without an available artifact are terminal unavailable, never ready or indefinitely rendering.
If the current script or cast versions differ from the retained export request, refresh returns unavailable without audio or seek timings and keeps the exact original export operation and receipt. It does not pair old audio with the edited script or automatically start a replacement. Playing the current version requires an explicit new export intent with its current frozen versions.
share_story#
Returns the sharing links from POST /studio/sections/{sectionId}/share. Once Stories publishing opens for the connected account, this publishes the chosen chapter and returns share_url, the story's /stories/<id>-<slug> reading link, and studio_url, the same story under /studio/ with Make a copy. The owner opens their chapter in the editor; other visitors see Studio's shared view. Allow copies defaults to on for Unlisted and Public stories. If the owner turns it off, studio_url is null and visitors use Stories. Both links keep the story's access and sign-in requirements. A Private story becomes Unlisted; an existing Unlisted or Public story keeps its visibility and metadata. Anyone with an Unlisted story link can listen and read its published chapters.
New chapters start as drafts, even in a shared project. Share each new chapter or publish it in Studio when it is ready. Repeating share_story keeps the same story link. Before Stories publishing opens for the account, the tool keeps creating or returning the older unlisted listening link. Converted older token URLs redirect to the story page; unconverted links keep working. ChatGPT's player Share action uses this same tool and follows the same account rollout.
| Input | Type | Required | Description |
|---|---|---|---|
section_id | UUID | Yes | The story to share. |
Voices#
find_voices#
Searches an accessible collection and returns exact voice IDs, descriptions, tags, acoustic revision and model hints. Library search works without a linked account. Follow pagination.next_offset with the same filters even on an empty filtered page; null ends the result. Read current engine options separately before casting.
| Input | Type | Required | Description |
|---|---|---|---|
query | string, up to 200 characters | No | Words describing the voice, or a voice name. |
mine | boolean | No | Search only the user's voices. Requires a linked account. |
scope | mine, shared, library | No | Explicit collection; must agree with mine when both are supplied. Defaults to library. |
limit | integer, 1–50 | No | Raw page size; defaults to 8. |
offset | non-negative integer | No | Continuation offset; defaults to 0. |
context_project_id | UUID | No | Apply current project authority and owned-voice relevance. |
get_voice#
Read the original accessible voice's actual status and acoustic revision. Pending processing is not a completed clone. Requires voices:read.
| Input | Type | Required | Description |
|---|---|---|---|
voice_id | UUID | Yes | Original voice ID. |
get_voice_engine_options#
Read the exact voice's current-account engine catalog: options, eligibility reasons, preparation requirements and existing samples. This does not generate samples or select an engine. Requires voices:read.
| Input | Type | Required | Description |
|---|---|---|---|
voice_id | UUID | Yes | Accessible voice ID. |
create_voice_preview#
Request the existing free picker preview through POST /api/v1/voices/{voice_id}/engine-samples, with schema version 2 and purpose: picker_preview fixed by the tool. Read the current revision and eligible engine first. Uses the saved metadata line; no caller text, cost override, legacy charged comparison, default-engine update or casting change. A cache miss can start ordinary provider work; pending is not playable.
| Input | Type | Required | Description |
|---|---|---|---|
voice_id | UUID | Yes | Original accessible voice ID. |
expected_acoustic_revision | Positive integer | Yes | Current revision returned by the ordinary voice read. |
model | String | Yes | Exact eligible engine from current options. |
mutation_id | UUID | Yes | Stable original ID, sent as the API's Idempotency-Key. |
Keep this ID and exact inputs before the first call. The result preserves the canonical lifecycle, sample ID, cache status, zero customer price and URL expiry. An unknown response never triggers an automatic retry. If the sample ID is known, read it with get_voice_preview. Otherwise an explicit identical same-key POST is the existing recovery path, subject to current access, revision and preview-metadata checks. The API has no recovery-only lookup by mutation ID; a conflict does not authorize a new ID or replacement preview.
get_voice_preview#
Read GET /api/v1/voices/{voice_id}/engine-samples/{sample_id} with voices:read. Accepts only voice_id and the original confirmed sample_id. Returns the actual picker or comparison sample's pending/completed/failed/expired state, historical costs and, when completed, refreshed expiring playback URL. Reading an existing sample creates no charge and does not synthesize, select or cast. Access and current acoustic revision remain enforced by the ordinary API. The engine-options catalog lists comparison samples; it is not a recovery lookup for free picker previews. These shared tools do not themselves send Instagram audio.
get_voice_preparation#
Read preparation readiness and current capacity without preparing a provider voice or reserving allowance. This may become stale. Requires voices:read.
| Input | Type | Required | Description |
|---|---|---|---|
voice_ids | UUID array, up to 50 | Yes | Original accessible voice IDs; duplicates are removed. Empty checks general availability. |
cast_speaker#
Apply only casting through the ordinary versioned speaker mutation. No regeneration occurs. Read the document and engine options first. Retain the original mutation, versions and exact profile on uncertainty; do not rebase or replace that operation automatically. The compact receipt acknowledges the mutation; read get_story or get_section_document to verify current casting before generating, especially after replay. Requires studio:write and voices:read.
| Input | Type | Required | Description |
|---|---|---|---|
project_id | UUID | Yes | Owning project. |
section_id | UUID | Yes | Current section. |
speaker_id | UUID | Single only | Exact speaker from the document. |
voice_id | UUID | Single only | Exact resolved accessible voice. |
base_speaker_registry_version | positive integer | Yes | Current registry version. |
speaker_version | positive integer | Single only | Current speaker version. |
mutation_id | UUID | Single only | Original stable mutation ID. |
generation_profile | object | Single only | Exact supported provider, model, fallback, controls and options from the ordinary Studio contract; no implicit engine substitution. |
assignments | array, 1–100 entries | Batch only | Ordered objects containing speaker_id, voice_id, speaker_version, mutation_id, and generation_profile. Omit the single-character fields when supplying this list. |
Batch casting calls the same single-character casting API in order. Each cast commits independently; the batch stops at its first failure and retains earlier successful casts. The compact result lists cast, failed (with the error and outcome_unknown), and unattempted remaining assignments. Use distinct speakers and mutation IDs. base_speaker_registry_version is the original version before the first assignment; later requests use that version plus their original position. Retain and replay the identical original list after uncertainty, so previously committed casts return their saved receipts. After a known conflict, read the document before revising the unconfirmed assignments.
initiate_voice_upload#
Begin the ordinary private upload flow with permission to use the recording. The client uploads bytes to the returned server-issued targets, then completes the original voice. This headless tool does not accept arbitrary destinations or upload bytes itself. Requires voices:write.
| Input | Type | Required | Description |
|---|---|---|---|
mutation_id | UUID | Yes | Stable API idempotency key; reuse only with identical metadata. |
recover_only | boolean | No | Set to true to recover the original operation without creating a voice. Omit or use false for initial creation. |
permission_confirmed | true | Yes | Permission to use this voice is confirmed. |
name | string, 1–80 characters | Yes | Private voice name. |
description | string, 1–255 characters | Yes | Voice description. |
tags | array, up to 50 strings | Yes | Each tag has at most 200 characters. |
uploadType | string, 1–100 characters | Yes | Ordinary API upload type. |
files | array, 1–16 objects | Yes | Exact filename (up to 255 characters), non-negative byte size, optional contentType, and file_type for each source file. |
Retain the exact metadata, key, voiceId, resource IDs and receipt before continuing. Changed-input retries conflict. Recover an unknown response with recover_only: true and the identical original mutation_id and metadata; this request cannot create a replacement, including after the API's 24-hour idempotency retention expires. A recovered receipt includes the current status: uploading, pending, processing, completed, or failed. Only uploading includes upload targets; other statuses return an empty signedUrls array. An unavailable recovery is not permission to create another voice. Initiation and completion receipts do not establish that processing succeeded.
For a WAV sample, use uploadType: "audio_sample" and a file with filename: "original.wav", its exact byte size, contentType: "audio/wav", and file_type: "AUDIO_SAMPLE_WAV". Upload the binary bytes with PUT to the issued target using its returned content type. Refresh expired targets for the original voice rather than initiating another voice.
complete_voice_upload#
Complete the original uploaded files through the ordinary API. Read get_voice for processing and engine options for actual eligibility. Requires voices:write.
| Input | Type | Required | Description |
|---|---|---|---|
voice_id | UUID | Yes | Original uploading voice ID. |
mutation_id | UUID | Yes | Stable completion operation ID; keep it on uncertainty. |
refresh_voice_upload#
Renew expiring targets for the same uploading voice and original resources. Does not create a voice or select storage paths. Requires voices:write.
| Input | Type | Required | Description |
|---|---|---|---|
voice_id | UUID | Yes | Original uploading voice ID. |
recast_character#
Changes a character's voice with Studio's preferred engine for that voice, then regenerates the character's lines unless told not to.
| Input | Type | Required | Description |
|---|---|---|---|
section_id | UUID | Yes | The story. |
character | string | Yes | The character's name as shown in the cast. |
voice_id | UUID | Yes | A voice from find_voices. |
regenerate_audio | boolean | No | Regenerate the changed lines. Defaults to true. |
mutation_id | UUID | No | Stable original recast operation; pair with frozen_cast. |
frozen_cast | object | No | Exact project_id, speaker_id, base_speaker_registry_version, speaker_version and canonical generation_profile (provider/model/fallback/controls/options). Required with mutation_id; retain unchanged after uncertainty. |
Legacy name-based recasting remains available. Headless callers should read the document and voice options first, then provide exact frozen casting inputs and an operation ID. Recovery does not rebase those versions/profile. A replay receipt must also show the requested current voice/profile before the composite starts its ordinary stale-section audio workflow. Casting and generation have separate receipts/IDs. Existing cast_speaker remains cast-only.
Explicit caller-ID recasts return the cast/workflow receipt directly and do not start a playback export. Open a frozen-version export separately. Calls without explicit IDs keep the existing widget behavior but cannot recover a wholly lost MCP response.
add_my_voice#
Opens the voice panel, where the user records or uploads a 10–30 second sample of their own voice and confirms they have permission to use it. The new voice is private.
| Input | Type | Required | Description |
|---|---|---|---|
voice_name | string, 1–80 characters | No | Suggested name for the voice. |
Mixing and spatial controls#
These tools use the existing Studio API and its current authorization, validation and version conflicts. Settings edits do not regenerate speech or synthesized SFX. Requested paid regeneration still uses the normal quote and generation flow. Saved spatial settings are not a listening-quality result.
update_mastering_profile#
Inputs: project_id (UUID), request (canonical mastering PATCH object). Read get_mastering_profile first. The request contains schema_version:1, the original expected_mastering_version and a complete profile: enabled, target_lufs, strength, max_boost_db, max_reduction_db, silence_threshold_lufs, peak_ceiling_db and speaker_adjustments_db. Optional sfx_bus_gain_db preserves the existing bus level when omitted. A named project's settings apply across its sections; standalone scope is document. Requires studio:write.
get_section_sfx_mix#
Inputs: project_id and section_id (UUIDs). Returns the canonical document, including existing SFX content/placement, together with project mastering/SFX-bus settings. Uses two ordinary GETs, not a new SFX GET route or an atomic snapshot. Retain the actual document, block and mastering versions for the atomic write. Requires studio:read.
update_section_sfx_mix#
Inputs: project_id, section_id and canonical request. Supply schema_version:"studio-sfx-mix-1", original actor_session_id/client_mutation_id, expected_document_version, expected_mastering_version, block_id, expected_block_version, canonical SFX content/placement and sfx_bus_gain_db. The server saves the cue and bus together. After uncertainty, only an explicit identical request with those same mutation IDs can recover this save; never silently rebase. Requires studio:write.
get_section_spatial#
Input: section_id (UUID). Returns enabled, current plan_version (including zero) and the actual nullable saved plan. Does not create placements. Requires studio:read.
update_section_spatial#
Inputs: section_id, request:{schema_version:"studio-spatial-1",enabled,expected_plan_version}. Enables or disables spatial playback/export while preserving the plan. Requires studio:write.
place_section_spatial#
Inputs: section_id, request:{schema_version:"studio-spatial-1",scope:"missing"|"all"}. Runs the existing placement operation, which can call the configured model, and returns the actual saved plan and remaining_blocks. It has no mutation-id replay contract; after uncertainty read/reconcile the same section rather than repeating placement. It does not synthesize speech/SFX. Requires studio:write.
update_section_spatial_block#
Inputs: section_id, block_id and canonical request with schema_version, expected_plan_version, expected_document_version and placement. Supply an existing canonical line/sound placement or null to reset it. The server derives block version/source and retains the existing scene; a non-null edit needs an existing clip placement. Requires studio:write.
Mastering and spatial writes use their existing version fences, not a new idempotency layer. On conflict, read and review current state. Unknown writes return the original inputs without automatic retry, fresh versions or replacement IDs; retain them and reconcile before another action. Do not infer a particular write committed merely because a later read resembles it.
Player and voice panel#
These tools are called by the widgets and hidden from the model.
get_story_state#
Refreshes a story's progress, cast, script timings, and signed audio URL.
| Input | Type | Required | Description |
|---|---|---|---|
section_id | UUID | Yes | The story. |
workflow_id | UUID or null | No | The Create audio run to track. |
export_operation | closed object | No | Original idempotency_key, exact request (schema_version=1, section_id, format=mp3, document_version, speaker_registry_version, mastering_version), and confirmed export_id when known. Widget refresh preserves it; a known ID is read directly, and an unknown admission is never automatically resubmitted. |
upload_voice_sample#
Creates a private voice from the user's sample through the same upload flow as LyricWinter's apps.
| Input | Type | Required | Description |
|---|---|---|---|
name | string, 1–80 characters | Yes | Voice name. |
mime_type | string | Yes | The sample's audio type, such as audio/webm. |
data_base64 | string | Yes | The sample, base64-encoded, up to 2.5 MB. |
permission_confirmed | true | Yes | The user confirmed they have permission to use this voice. |
get_voice_status#
Checks whether a new voice has finished processing.
| Input | Type | Required | Description |
|---|---|---|---|
voice_id | UUID | Yes | The voice to check. |
Jobs#
get_job#
Read a job through the existing Studio lifecycle routes. Requires studio:read; this starts, applies and retries no work. kind selects the resource; id always means the original resource ID returned by its start tool.
kind | Exact job | Latest discovery without id |
|---|---|---|
workflow | id; optional include_section_versions | project_id, optional section_id and include_section_versions |
section_export | id | section_id, optional format |
project_export | project_id and id | project_id, optional format |
character_voice | id | project_id and speaker_id; only queued/running/awaiting-selection designs |
sfx_assistant | id (assistant batch ID) and section_id | Not supported by the existing API |
For workflow clip counts and a bounded preview of recorded block failures use kind: "workflow", id, progress: true and optional schema_version (1 or 2, default 2). The compact reply retains up to five block_issues, the total issue_count, and issues_truncated. Use detail: true with the same progress selector to inspect all original failure diagnostics. This uses the existing workflow progress route. Status reads use the workflow route. Add wait_seconds (integer, 0–25) to any exact job status read to wait on the server until status changes. Terminal and actionable states return immediately. At the deadline, the API returns its last confirmed status; if the initial read cannot finish within the deadline, it returns an error. Waiting is unavailable for latest discovery, progress reads and cancellation. Do not combine progress with latest or section-version selectors.
Reads default to compact IDs, status, summary and next step instead of whole documents or plans. detail: true explicitly reads the full original job through the same authenticated MCP/API path when reviewing SFX proposals, candidate details or complete historical failures; keep detail false or omitted during status polling. Workflow replies retain stage, step counts and issue counts; voice candidates, preview URLs, expiry and assignment outcome; SFX result hashes; export freshness, artifacts and expiration. completed voice design with speaker_changed is not a successful cast. Export artifacts may be null/expired, project batches still identify child exports, and canceling is not cancelled. When an SFX batch is review_ready, read that same get_job once with detail: true to review its original proposals before applying their hashes. Compact receipts retain the result hashes, and include_section_versions: true preserves the requested compact workflow section headers. Latest export reads use the ordinary list route with limit=1, returning one export or null. Latest/null is discovery, never proof a particular mutation succeeded or failed. Recover uncertain work with its original ID and request.
cancel_job#
Inputs: kind, id; SFX also requires section_id. Requires studio:write. Supported kinds are workflow, section_export, character_voice and sfx_assistant. Calls the corresponding existing cancellation route and returns actual state. SFX cancellation first verifies that the original batch is an SFX operation for the requested section. It does not undo completed casting, apply results or start replacement work.
Project export batches have no cancellation route. Read the batch using get_job with kind: "project_export", project_id and id, then cancel individual child export_id values using kind: "section_export". After uncertainty, read the same original job; do not replace IDs.