| name | dub-studio |
|---|---|
| description | Drive Dub Studio on this computer through its MCP server - dub a video into another language with the speakers' own cloned voices, make a voice-over, translated or original-language subtitles, or a transcript; get a file's transcript, translated subtitles, dubbed video, voice and background apart or on-screen text in one call; fix the translation, the timing and the speakers line by line; cut, join and move lines on the timeline; restyle the subtitles, add titles and blur boxes; cast the characters of a series and give them library voices; export the same video in several languages; export SRT or TXT; save the result to a folder - either at once with a result back, or in the studio's window while the user watches. Use whenever the user asks for anything the studio does. |
Dub Studio serves MCP at http://127.0.0.1:8793/mcp while it is open (Streamable HTTP,
stateless JSON-RPC). Every tool runs the same code as a button of the studio, through the
routes its window calls.
- It is a Windows desktop application. If it is not installed, download the installer or the portable archive from https://github.com/timoncool/dub-studio/releases/latest. It is made for an NVIDIA card; its first start offers to download the models.
- Start it. The MCP server is up as soon as its window is:
http://127.0.0.1:8793/mcp. Nothing else to install - no npx, no bridge. - Connect (below), then call
studio_status. If models are missing,models_statusnames them andmodels_downloadfetches them.
claude mcp add --transport http dub-studio http://127.0.0.1:8793/mcpOther clients: { "mcpServers": { "dub-studio": { "type": "streamable-http", "url": "http://127.0.0.1:8793/mcp" } } }.
The server also serves this skill (resource studio://skill, prompt studio), the
language codes (studio://languages), every edit of a project with its fields
(studio://patch-ops) and a prompt dub_video (a file, a language, a mode). It speaks MCP
2026-07-28 (stateless: every request carries its version in _meta, server/discover
describes the server) and the handshake revisions 2025-11-25, 2025-06-18 and
2025-03-26 through initialize. Only agents on this computer and the studio's own window
may connect.
The user sees it in the studio too: Settings, Agent (MCP) shows whether an agent is connected and the address to paste.
- Start with
studio_status. It tells what runs now, what finished last, and whether the required models are there. - Long work is a job:
project_analyze,project_dub_audio,project_render,project_export_lang,project_retranslate,project_remix,segment_shorten,project_resume,voices_download_pack,glossary_extract, and a download by link (project_create_from_url, whosefetch.idis waited for the same way). Each answers ajob_id; thenstudio_waitwith it (oruntil: analyze | dub_audio | render | export_lang | retranslate | remix | align | shorten | download | voices_pack | separate | detect_text | glossary | idle) instead of polling. It returns within a minute (30 s by default, 55 at most) with how far the work got; call it again.job_getandjobs_listread jobs (jobs_listwith apidalso shows the project's last stored job),job_cancelstops one,project_resumestarts a project's interrupted or failed job again where it stopped. - One job holds the graphics card at a time, and a preview frame is made there too:
project_frameanswers "busy" while a job runs.studio_wait until: idle, then take the frame. - Edits are instant and saved. A line whose words, timing, speaker or voice changed is
dirty;
project_dub_audioandproject_rendervoice only the dirty lines again, the rest comes from the cache.segment_regenmarks one line,segments_regen_allevery line. Changing the mode, the target language, the translation's tone or the voices makes every line dirty. - How the dub sounds: a voiced line loses the silence around it before it is fitted to its
slot (long pauses inside shrink only when it would not fit), and a cloned voice's reference is
cut from the separated vocals in full band, at word boundaries - so is a
voice_from_speakervoice, which is refused withno_separationwhen the project has no separated vocals and no separation engine is installed, and fails with the reason when its line cannot be separated. - Answers are short by default:
project_getleaves out word timings and the vision context, an edit answers what it changed and how many lines are dirty. Passresponse_format: detailedfor everything - and only take a project forproject_putfrom a detailedproject_get, or the fields left out are lost. - Look ids up, never guess them:
projects_list,project_get(line ids, title and blur box idx),voices_list,casting_get,casting_library_list,models_status,engine_presets_get. - Files on this computer are passed by path:
project_create(a video, and subtitles to import), the one-call tools (below),models_import,project_save_output,project_export_textandexport_subtitles(a folder).project_filesnames the project's own files. - Destructive tools say so: deleting, cancelling, replacing a project, analyzing again (it replaces the lines), retranslating, remixing, and edits that overwrite text are marked destructive, so your client asks the user first.
- The OpenRouter key never comes back:
settings_getandstudio_capabilitiesshow onlyor_key_set,openrouter_statuswhere the key comes from. - Two ways to do a thing. The tools above do it at once and answer the result - a
transcript (
project_transcript), a fixed line, a render - with or without the window. Theeditor_*andui_*tools do the same in the studio's window while the user watches (below). Use the window when the user wants to see it done or to learn how; use the atomic tools for batches and for work nobody watches. - The window keeps up with you. Whatever you change with any tool, the open window reads again at once: the lines, the lists, the settings, a job you started (its progress shows in the window, a render in its Files panel). The window's undo never erases your edits or what your jobs saved, even when the user started a job of their own meanwhile: after your change its history starts again, and an undo made on an older state is refused.
google_status reports whether a key is configured; google_set_key verifies and stores it,
google_delete_key removes it. The key is never returned. google_models lists available TTS
model IDs and generation methods. Set tts_provider=google, google_tts_model to an ID without
models/, and google_tts_mode=standard|batch|auto using settings_set (auto: up to 10 phrases
as direct requests, more as one Batch). Voices and autocasting use or_tts_voice and
or_tts_autocast; standard concurrency uses or_concurrency.
Run project_dub_audio or project_render, then studio_wait. Batch uses Google's discounted
asynchronous service and may wait in its queue for up to the documented 24-hour target.
project_google_tts_report returns the batch under way, the last job (phrases asked, cached, ok,
failed with their reasons, tariff-based estimated USD cost, not an invoice) and the batches done.
A phrase already voiced comes from the project's cache and is not paid again. Cancelling the local
job stops waiting; it does not cancel the remote Google batch, and the next job finds that same
paid batch by its name instead of sending it again. cloud_spend shows what the cloud cost, and
cloud_daily_limit_usd caps what agents and programs spend a day (0 = no limit).
tts_style on each segment is voice direction metadata, never part of the spoken text.
The renderer keeps existing takes; pinned takes remain protected until explicitly unpinned.
The same results come two ways.
- One call on a file - when the user wants a result of a file and nothing more: "the
transcript of this", "Spanish subtitles for it", "dub it into Russian", "take the voice
off the music", "what does the sign say".
transcribe_file(text, SRT, VTT or JSON with speakers and word timings),translate_file(SRT, VTT or JSON),dub_file(the finished video, copied intoout_dirwhen given),separate_file(the voice and the background as WAV) anddetect_text_file(the text in the picture, with its boxes and times) take the file'spathand answer the result itself. The file is read where it lies, never copied.export_subtitleswrites a project's subtitles as SRT, VTT, ASS or TXT, in its target language or the original. - Each makes a project of the file, listed by
projects_listwithsource: agent. The same tool called again with the same file and arguments finds that project and answers from the finished work at once; a changed file or other arguments make another project.project_deletemoves it to the system's recycle bin,project_restoretakes it back; nothing else does. - A call waits for the studio up to
seconds(45 by default, 55 at most). When the work takes longer it answersdone: falsewith thejobat work:studio_waitwith itsjob_id, then call the tool again with the same arguments - the finished stages are kept, anddub_filegoes on from the analysis to the render. dub_filetells what fell back indegradations, read off the finished dub:background_not_separated(no voice separator: no music or effects under the dub),ocr_skipped(no on-screen text reader: the text in the picture stays as it is),single_speaker(every line voiced as one speaker; its detail says whether the diarizer is missing),voices_not_cast(autocast left thesespeakerson their own cloned voice),voices_not_as_asked,no_speech. Tell the user;models_statusandmodels_downloadbring a missing model. Its copy inout_diris<file>.<tgt_lang>, or with (2), (3) when that name is another file's; called again, it answers the copy already there.- Work in the studio - when the result needs looking at and fixing: the translation
line by line, the speakers, the voices and the characters, the look of the subtitles,
titles, blur, several languages:
project_create,project_analyze, the edits andproject_render, as the recipes below go. - A one-call project is an ordinary project: its
project_idgoes toproject_get, the edits andproject_renderlike any other. Called again after its settings were changed in the studio (mode, languages, subtitles), a one-call tool analyzes it anew as it asks.
Take one call when the user asks for a result; take the studio when they want to see,
choose or correct. They combine: transcribe_file, then project_get with its
project_id, segment_update where a line is wrong, and export_subtitles.
Dub a video
studio_status; if models are missing,models_downloadandstudio_wait.project_createwith the video'spath; keep itsproject_id.project_analyzewithtgt_lang(a code ofstudio://languages) andmode: dub(voiceoverfor a voice-over,nodubfor subtitles only,transcribefor a transcript);studio_waitwith itsjob_id.project_get: read the translation line by line and fix it withsegment_update.project_render;studio_waitwith itsjob_id.project_frameat a moment with speech to see the burned-in subtitles.project_save_outputinto the folder the user wants; tell them the path.
Dub a video from a link
url_tool_status: the componentytdlpmust be installed (models_downloadwithids: ["ytdlp"]otherwise).url_probewith theurl: the title, the length, the qualities and the site's subtitles made by people (subtitles, apart from the languages of the automatic ones inauto_subtitles); the preview is its link,thumbnail. A refusal names its code and ahint: a proxy for a geo block,cookies(the path of a cookies.txt) for an age check, a members' video or a bot check.project_create_from_urlwithurl,qualityand, to take the site's subtitles as the project's imported ones,subs_lang. It downloads in the background beside the jobs:studio_waitwith itsfetch.idasjob_id; the result names theproject_id.url_fetch_cancelstops it,url_fetch_resumecontinues an interrupted or failed one.- Go on as in Dub a video from
project_analyze. The user answers for their right to the content.
Fix the translation and render again
project_getwithfrom/toaround the moment, orids.segment_updatewithtgt_text(andstart/endorspeakerwhen they are wrong);segments_hidefor a line that should be neither voiced nor subtitled,segments_keep_originalwhere the original voice should stay.project_dub_audioto hear it quickly, orproject_renderfor the video; either voices only the dirty lines.studio_wait, thenproject_frameto check.
Make the translation fit the timing
project_get: every voiced line of a dub or voice-over hasfit-verdictfits(spoken at its own pace),tight(the render speeds it up withineff_cap: up to 4x withspeech_rate_on, else the naturalcap) orimpossible,overwhen it does not fit, and after a renderrendered.neededagainstrendered.eff_capfor the text the render voiced.calibrated: trueonce three clips of that voice were measured; before that the language's usual pace is used.segment_shortenwith theidsof the lines, orall_over: true;studio_wait. The translation model rewrites each shorter within the slot's character limit; the result listsshortened,rejected(other script, not shorter, echo of the source).project_dub_audiovoices the new text. Withsettings_setauto_shorten"1"(the default) a render does this by itself once for lines that did not fit.
Pick the better take of a line
takes_listwith the lineid: the last five voicings with their text, duration and QC similarity;activeis what the mix plays.take_selectwithtake(itsn) - a take of other text brings that text back - thenproject_dub_audiomixes again without voicing. While another take is pinned it is refused:take_pinwithpinned: falsefirst.take_pinwithpinned: truekeeps the active take through regenerations and QC; editing the line's text unpins it.
Only subtitles, or a transcript
project_analyzewithmode: nodub(translated subtitles over the original audio) ormode: transcribe(the transcript in the original language).project_export_textwithformat: srt(orvtt,ass,txt,json) anddir-text: srcfor the original words,tgtfor the translation,bothfor bilingual srt, vtt or ass (the translation and the original as two lines of each subtitle,ordersays which is on top, the project's own order when left out);namegoes withdironly (withoutdirthe file lands in the project's folder as subtitles.srt, transcript.srt, bilingual.srt, the same .vtt and .ass, translation.txt or transcript.txt).project_renderburns the subtitles in instead,subtitles_burn_setwithon: falseleaves the picture clean.subtitles_content_setchooses what they say apart from what is heard:transcribe(a dub with subtitles in the original language),translate, orbilingual(the translation with the original as a smaller second line,orderandsecondarystyle it); an mkv output also carries them as subtitle tracks with their languages.- Subtitles the user already has:
project_createwithsubtitles_path(.srt, .ass, .ssa);project_analyzetakes their text and timing instead of recognising speech, andimport_translated: truewhen they are already intgt_lang.
The same video in several languages
- Finish and check the first language (the layout, the style, the titles and the blur carry over).
project_export_langwithlang, one language at a time: each answers a newproject_idand ajob_id;studio_waitwith the job before the next.project_save_outputfor each new project.
Cast the characters
project_analyzewithcasting: true(content_type: realfor live action,animefor drawn characters; look at a frame withproject_frame source: originalif unsure).casting_get: the characters with their speakers and lines;casting_avatarshows a face.casting_updateto name them, set their gender, adub_voicefromvoices_list(null clones their own voice) and aspeech_notefor the translation's tone.voice_slots_assigndeals library voices by gender instead;voice_from_speakermakes a library voice of a speaker.casting_library_savekeeps the cast; the next episode'sproject_analyzewithcasting: trueandcasting_ref(a slug ofcasting_library_list) applies it.
Names and terms the same in every line and episode
glossary_get: the project's glossary (stale: true- the translation was made with other term translations or keep marks; pronunciation,asr_fixand note do not count).glossary_extractcollects candidates from the text (a job:studio_wait, the entries are in its result);glossary_setwithmerge: trueadds the ones to keep. An entry hastermand eithertranslationorkeep: true(left as written);pronunciationchanges only what the voice says,asr_fixlists how speech recognition misspells the term (analysis corrects it).project_retranslatewith the project'stgt_langandmodetranslates again with the glossary.series_glossary_setwithmerge: trueand the entries keeps them in a saved casting; the next episode'sproject_analyzewith thatcasting_refadds them to its glossary.series_glossary_getreads it.
A line whose tts_skip is set in project_get is not voiced: nothing is left to say once sound tags
([music], (laughs), ♪…♪), speaker labels and markup are taken out; tts_text shows what the voice says
when it differs from the translation. The chosen voice engine keeps its own expression tags in the text
(Higgs <|emotion:anger|>, Drama 3 [laughs] and <whisper>…</whisper>, Supertonic <laugh>);
tts_ignored names the markup it does not read and that is taken off: another engine's tags, + stress
for an engine that does not read it.
A batch into one folder
For each file: project_create, project_analyze, studio_wait, project_render,
studio_wait, project_save_output with the same dir and the file's own name - a name
already there gets (2), (3).
The cloud instead of the graphics card
openrouter_set_key stores a key (it is checked first; openrouter_verify only checks);
openrouter_models lists the models of a stage and openrouter_voices a speech model's
voices. settings_set switches the stages: or_llm_on/or_llm (translation),
or_vision_on/or_vision, or_tts_on/or_tts_model/or_tts_voice, or_asr_on/or_asr.
engine_presets_get and engine_preset_apply set everything for this computer's card or
for the cloud at once. The proxy has three modes: system (as in Windows), custom (its own
address, kind giving the scheme of an address without one) and off; proxy_test checks a mode
and address before proxy_settings_set stores them (proxy_settings_get shows them, the password hidden).
With llm_provider (and vision_provider) set to agent - "Agent (MCP)" beside Gemma, a local server
and OpenRouter in Settings, Models - the studio asks you what it would ask its own model: translating
the lines, shortening them, the glossary (target llm) and the video's frames for subtitle style,
titles and scene (target vision). Keep calling assistant_requests_wait; each request carries the
instructions, the request, answer_schema and, for frames, images - a file path on this computer
and a URL of this server for each, named in the request as [image N: path]; read them as pictures.
Answer with assistant_request_answer: the JSON object answer_schema describes, written by the
instructions, as the studio's model would. A request waits about nine minutes, then the stage fails
with that reason.
The studio's window is the second way in: editor_* tools work in its editor exactly as
the user's clicks do - the list scrolls to the line, the line lights up, the frame and the
timeline change - and every step is shown to the user as "Agent: ..." at the top of the
window. They need the window open (the desktop app, or the studio's address in a browser);
without it they answer that the window is not open, and everything else still works.
- Start:
editor_openwith the project'spid(a transcript opens its transcript view, where onlyeditor_state,editor_seek,editor_select,editor_play,editor_pauseandeditor_modework).editor_statetells what the editor shows: the playhead, the line under it, the selection, undo and redo, the export's status. - Show:
editor_selecta line (or a blur box, a title) - the lane switches, the playhead moves there and it is highlighted;editor_seekmoves the playhead and waits for the frame;editor_playplays one line or from a moment,editor_pausestops;editor_frameis the frame the user sees now;editor_laneswitches the left lane. - Edit:
editor_segment_update(text, timing, speaker, hidden, original voice),editor_segment_add,editor_segments_delete; the montage:editor_segment_splitcuts a line at a moment (the playhead by default),editor_segments_mergejoins neighbouring lines,editor_segment_movemoves a line along the timeline keeping its length. The look:editor_mode,editor_style,editor_preset,editor_blur_add,editor_blur_update,editor_title_add,editor_title_update,editor_subtitles_content(the subtitle languages, both with the original's line styled). Each is one step of the window's undo:editor_undo,editor_redo. - Fit and takes:
editor_shortenshortens one line or all that do not fit, as the line's and the list's buttons do (it answers at once;studio_wait until: shorten);editor_takesunfolds a line's takes under it,editor_take_selectpicks one (the window mixes again:studio_wait until: dub_audio),editor_take_pinpins it. - Glossary:
editor_glossaryopens or closes its window,editor_glossary_setchanges it there as editing and Save do,editor_glossary_extractcollects candidates there for the user to confirm (studio_wait until: glossary; keep the chosen ones witheditor_glossary_setandmerge: true). They refuse while the window holds the user's unsaved edits. - Export:
editor_exportstarts the render as the Export button does; the user watches it in the Files panel, and Explorer shows the file when it is done.editor_stateshows its status;studio_wait until: renderwaits for it. - Anything else on screen:
ui_read_pagelists the visible controls with refs (a line of the transcript, a blur box, a title and a recent project each read as one line with its controls and fields; a key or password field reads only as filled or empty, and is masked inui_screenshottoo),ui_click,ui_type,ui_select,ui_press_key(Space plays, Ctrl+Z undoes, Ctrl+K opens the command palette),ui_scroll;ui_screenshotis a picture of the whole window;ui_navigate,ui_open_settings,ui_open_help;ui_notifytells the user something;ui_consoleshows the page's errors. The control you click is highlighted for the user. - Confirmations are the page's own: deleting a project or a saved cast asks in a dialog
of the page;
ui_read_pagelists it first. Click its confirm button only when the user asked for the deletion.
Show the user how to fix a translation
editor_openwith the pid;ui_notifywhat you are going to do.project_transcriptwithtext: tgt(oreditor_state) to find the line.editor_selectit - the user sees the line and the frame;editor_playit.editor_segment_updatewith the newtgt_text;editor_frameto see the subtitle.project_dub_audioto voice the dirty lines (the window shows the progress), theneditor_playthe line again.
Cut and join lines on the timeline
editor_selectthe line;editor_seekto the pause where it should be cut.editor_segment_split(the playhead is the moment;tgt_textandtgt_text_2give the halves' translations), theneditor_segment_updateeach half's speaker when two people speak.editor_segments_mergefor lines broken in the middle of a sentence;editor_segment_movewithshiftfor a line that starts too early or too late.editor_playthe stretch;editor_undoif it sounds wrong.
Export while the user watches
editor_state: the project is open and nothing renders.editor_export;ui_notifythat the render started.studio_wait until: render;editor_stateshows the export done;ui_notifythe result, orproject_filesfor the path.
- studio:
studio_status,studio_wait,studio_system(card, video memory, RAM),studio_capabilities. - jobs:
jobs_list,job_get,job_cancel. - models:
models_status,models_download(runs in the background beside the jobs: wait withstudio_waituntil: download),models_cancel_download(a pause: the same ids continue it),models_remove(frees disk space),models_import(files already on disk),models_select(a quantisation or a recogniser),models_folder_open(the folder in Explorer, for the user),models_update_plan(what this release updates, adds and no longer needs, with the reasons: the update screen),models_update_apply(its button: downloads, then removes what former releases left),models_update_later(its «Later»). - settings:
settings_get,settings_set,engine_presets_get,engine_preset_apply,proxy_test,proxy_settings_get,proxy_settings_set,fonts_list,caption_presets_list,launch_defaults_get,launch_defaults_set(what the start screen's form opens with),studio_paths(where the data, projects and models are). - diagnostics:
diagnostics_get(version, system, card against CUDA, ffmpeg, components, the engines' missing DLLs and the latest log lines),diagnostics_report(a ZIP for a bug report, keys masked),diagnostics_report_revealanddiagnostics_logs_reveal(in Explorer, for the user). - journal: the activity journal the user reads in the window's status bar, kept across restarts;
your changes are written there by themselves (verb, kind and what you named).
journal_get,journal_note(a line of your own: what you did, what you need from them),journal_delete,journal_clear. - openrouter:
openrouter_status,openrouter_set_key,openrouter_delete_key,openrouter_verify,openrouter_models,openrouter_voices,openrouter_catalog,openrouter_catalog_refresh. - local server (Ollama, LM Studio, vLLM, llama-server for translation and vision):
local_server_models,local_server_key_status,local_server_key_set,local_server_key_delete; the provider of each stage issettings_setllm_provider/vision_provider(local, server, openrouter). - project:
projects_list(query, since, until),project_create,project_get,project_transcript(the transcript without the window),project_analyze,project_resume,project_retranslate,project_remix,project_align,project_dub_audio,project_render,project_export_lang,project_put,project_patch(any edit by its op),project_delete,project_restore,project_waveform,project_frame. - videos by link (yt-dlp):
url_probe,project_create_from_url(in the background, wait withstudio_wait),url_fetches_list,url_fetch_get,url_fetch_cancel,url_fetch_resume,url_fetch_delete,url_tool_status,url_tool_update(a newer yt-dlp, checked against its release's SHA-256; it is checked once a day anyway). - one call on a file:
transcribe_file,translate_file,dub_file,separate_file,detect_text_file, andexport_subtitlesfor a project's subtitles. - files:
project_files,project_export_text(SRT, VTT, ASS, TXT, JSON; bilingual),project_save_output,project_open_output,project_reveal,project_save_text(a text file into the project's folder, e.g. the glossary as TSV). - lines:
segment_update,segment_add,segments_delete,segments_hide,segments_keep_original,segments_reorder,segment_regen,segments_regen_all,segment_split(cut a line in two),segments_merge(join neighbours),segment_shorten(fit the translation to the slot). - takes:
takes_list,take_select,take_pin. - what the project makes:
project_mode_set,audio_output_set,subtitles_content_set,subtitles_burn_set,subtitles_position_set,translation_target_set,translation_style_set,rewrite_set,voice_set,voice_emotion_set(cloned voices: each line from its own piece of the original, or one steady voice per speaker for a narrator),gain_set,loudness_set(even out loudness, on by default),voiceover_gain_set,original_track_set. - subtitles, titles, blur:
caption_style_set(all lines or one),caption_preset_set,title_add,title_update,titles_delete,blur_add,blur_update,blurs_delete,blur_enable. - casting:
casting_get,casting_update,casting_avatar,casting_library_list,casting_library_save,casting_library_delete,casting_library_avatar. - glossary:
glossary_get,glossary_set,glossary_extract,series_glossary_get,series_glossary_set. - voices:
voices_list,voices_catalog,voice_download,voices_download_pack,voice_rename,voice_delete,voice_from_speaker,voice_slots_assign; noise out of a voice's reference (DPDFNet, a job):voice_denoise, and its original back:voice_restore; a voice from the user's microphone:voice_record_devices,voice_record_start,voice_record_level,voice_record_stop. - the window:
ui_screenshot,ui_read_page,ui_click,ui_type,ui_select,ui_press_key,ui_scroll,ui_navigate,ui_open_settings,ui_open_help,ui_notify,ui_console. - the editor, in front of the user:
editor_open,editor_state,editor_frame,editor_seek,editor_select,editor_play,editor_pause,editor_lane,editor_segment_update,editor_segment_add,editor_segments_delete,editor_segment_split,editor_segments_merge,editor_segment_move,editor_mode,editor_style,editor_preset,editor_blur_add,editor_blur_update,editor_title_add,editor_title_update,editor_undo,editor_redo,editor_export,editor_subtitles_content,editor_shorten,editor_takes,editor_take_select,editor_take_pin,editor_glossary,editor_glossary_set,editor_glossary_extract.