CapCut from Claude
The CapCut MCP was built for Codex. This skill is the Claude adaptation: the official material is kept verbatim under official/ (plugin v0.2.6), and this file states how to use it here, plus what was verified in real use (2026-10-26/27, Claude desktop Code tab, Windows).
Paths below are relative to this skill's folder (~/.claude/skills/capcut/).
If official/ is missing (fresh clone), run python scripts/fetch_official.py first — it downloads CapCut's plugin bundle from CapCut's CDN (the official material is not redistributed in this repo). --force refreshes it to the latest published version.
0. Connection (do this first if tools are missing or failing)
The only working way to connect is local MCP servers in the Claude desktop config, via mcp-remote. Adding CapCut as a claude.ai custom connector does NOT work: CapCut's OAuth server rejects Claude's dynamic client registration ("无法在 CapCut 的登录服务中注册"), and a client ID cannot be supplied.
%LOCALAPPDATA%\Claude-Data\<profile>\claude_desktop_config.json (or %APPDATA%\Claude\claude_desktop_config.json) → mcpServers:
"capcut": {"command": "cmd", "args": ["/c", "npx", "-y", "mcp-remote", "https://www.capcut.com/api/external_mcp"]},
"capcut_resource": {"command": "cmd", "args": ["/c", "npx", "-y", "mcp-remote", "https://www.capcut.com/api/external_mcp/resource"]}
capcut= account-bound tools (OAuth).capcut_resource= identity-free card tools (no login). Back up the config before editing; the user must fully quit and reopen Claude after editing.
Setup from scratch (no mcp__capcut__* tools in the session):
- Check prerequisites:
node --version(≥14) andnpxon PATH. - Find the live config: search
%LOCALAPPDATA%\Claude-Data\*\claude_desktop_config.jsonfirst, then%APPDATA%\Claude\claude_desktop_config.json. Read it, copy it toclaude_desktop_config.json.bak-<date>, add the two entries undermcpServers(create the key if absent) without touching anything else, and re-parse the file as JSON to confirm it's valid. - Ask the user to sign the system default browser into the CapCut account the drafts should live in, then fully quit Claude (tray icon → Quit) and reopen it.
- On start, mcp-remote opens the CapCut authorize page in that browser; the user approves (an instant flash-and-close means it auto-approved — fine).
- The current session cannot see servers added after it started: continue in a new Code-tab session. Verify there with
start_stdraft_session(should return asession_id) andsearch_capcut_material(type: music). - Optional: sign Claude's built-in browser into the same CapCut account so drafts can be inspected there.
- OAuth tokens are cached in
~/.mcp-auth/mcp-remote-v1/<hash>_tokens.jsonand<hash>_client_info.json. - Re-authorize / switch account: ask the user first; delete those two files; the user signs the system default browser into the desired CapCut account (same login method — Google/email/TikTok are different accounts) before restarting; then fully quit and reopen Claude; mcp-remote opens the CapCut authorize page (it may flash and close if that browser is already signed in — that is success). Verify with
start_stdraft_session. - Symptom
get user workspace failed: check login erroron every call = the cached grant is dead → re-authorize as above. - Re-authorizing logs the same account out of other CapCut web sessions (including Claude's built-in browser); the user must sign in there again.
- Drafts are saved into whichever account the MCP is authorized as. If the user can't see a draft, compare accounts first.
1. Which surface works
| Surface | Status |
|---|---|
| Claude desktop Code tab session | Everything below works. Use this for CapCut work. |
| Phone remote-controlling a Code-tab session | Same as Code tab (tools run on the PC). |
| Desktop Chat / phone chat reaching the PC tools | Draft tools fail with "missing session_id" (the bridge appears to drop a parameter literally named session_id); cards may not show. Don't do draft editing there. |
| Phone chat on its own | No CapCut at all (servers are local to the PC). |
Cards (capcut_resource: templates_preview_v2, editing_plan, video_preview, background_music, billing_confirmation) are fetched but not rendered in the Code tab — results arrive as text/JSON. Never wait on a card; read the data and present it yourself.
2. Official docs to read (only what the task needs)
Must-read for any draft work: official/capcut-stdraft-builder/reference/application.md (function contracts). Everything else only when the task touches it.
| Task | Read |
|---|---|
| Rough-cut handoff or captions on an existing video | official/video-editing/references/post-editing.md |
| Session/version/push/conflicts | official/web-collaborative-editing/SKILL.official.md (+ references/conflict-recovery.md) |
| Field-level protocol questions | official/capcut-stdraft-builder/reference/STDraft_Protocol.md, validation.md |
| Materials | official/video-editing/references/materials.md |
| Captions | official/video-editing/references/auto-captions.md |
| AI rough cut | official/video-editing/references/ai-rough-cut.md |
| Image/video generation | official/generate-media/SKILL.official.md + references/ |
| Template search | official/search-templates/SKILL.official.md |
Ignore Codex-only parts: codex plugin install/upgrade, codex app-server/capcut-login.mjs OAuth, "New-Task Handoff"/fork, require_escalated sandbox flags, TTY ticket entry, "end the turn silently after a card".
3. Core workflow: build/edit a cloud draft
Shell: run commands in the Bash tool (Git Bash), not PowerShell. Use forward-slash Windows paths (D:/proj/clip.mp4) or single-quoted ones. Work in the user's project folder (e.g. <project>/capcut_work/) so upload maps and drafts survive the session.
- Upload local media with the official uploader only (never hand-rolled VOD code):
capcut_asset_upload_credentialwithversion: 2andfiles: [{file_name, size_bytes}]for the whole batch →upload_ticket(a short-lived single-batch capability; it necessarily passes through this conversation once — never log it elsewhere).- Write the ticket with no trailing-newline issues, pipe it on stdin (never in argv), delete the file:
(single file:cd <project>/capcut_work && printf '%s\n' '<ticket>' > ticket.tmp node ~/.claude/skills/capcut/official/capcut-upload/scripts/capcut-upload.mjs \ --files '[{"client_id":"c1","file":"D:/proj/a.mp4"},{"client_id":"c2","file":"D:/proj/b.mp3"}]' \ --upload-ticket-stdin --json < ticket.tmp > upload_result.json 2> upload_stderr.txt; rm -f ticket.tmp--file <path> --client-id c1; progress → stderr, JSON → stdout.) - Success = non-empty
vidandsetPublic.success:true. Save aname → {vid, duration}map (upload_map.json); never re-upload items that already have a vid. Tickets expire in ~1 h.
- Session:
start_stdraft_sessiononce per draft; keepsession_id. Before each edit round callcheck_stdraft_state(session_id, local_package_id):- brand-new draft: pass
""; expectserver_package_id:""→ build from scratch and push withbase_package_id:""; - otherwise follow the baseline table in
official/web-collaborative-editing/SKILL.official.md(stale →get_stdraft_snapshotfirst).
- brand-new draft: pass
- Build locally with the official atomic functions (Python ≥3.8, stdlib only, run with
python -B,sys.path.insert(0, "C:/Users/<user>/.claude/skills/capcut/official/capcut-stdraft-builder/scripts")):apply_video,apply_audio,apply_text,apply_text_template,apply_captions,apply_video_effect,apply_filter,apply_transition,update_material,update_placement,update_caption_text,remove_material,unset_attribute. Chainresult["draft"]. New draft root:{"version":"0.1.0","segments":[{"id":"draft","type":"DRAFT","attributes":{"width":1920,"height":1080,"ratio_type":"16:9"}}]}.- Mute a clip:
apply_video(..., volume=0.0). Times are integer ms. SOURCE_RANGE_UNVERIFIEDis raised for every vid/sid source — expected. Check it yourself:source_start_ms + duration_ms × speedmust not exceed the source length (fromupload_map.json, orduration_msin the music search result).- Picking search results: prefer an item whose
duration_mscovers the needed length and whose title/caption fits the mood; say which one you chose.
- Mute a clip:
- Prepare the push:
python -B ~/.claude/skills/capcut/scripts/draft_tool.py slim draft.json draft_slim.json(short ids, one segment per line, re-validated, warns over ~60k chars). Readdraft_slim.jsonand paste its full text verbatim asstdraft_jsoninpush_stdraft_snapshot(this costs its size in tokens twice — keep drafts lean). - After push: if the result was saved to a file by the harness, run
draft_tool.py summary <file>/urls <file>; if it came back inline, save it topush_result.jsonfirst (or pipe it:... summary -). Give the userweb_editor_urlas a Markdown link labelled withweb_editor_textverbatim (server-localized, may be e.g. "Buksan sa CapCut"). Use the returnedstdraft_json/server_package_idas the next baseline.- Normal server rewrites (not errors):
vid://→asset://<id>; DRAFT gets a random id and losesratio_type; layers are renumbered;end.msis added everywhere; TEXT getsfont_color/line_max_widthand aPATCHchild ("style copy"); VIDEO getscrop/background.*defaults; AUDIOmeta_typebecomes lowercase. Compare content, timing, volume, speed, transitions and keyframes — not ids or layer numbers.
- Normal server rewrites (not errors):
- Optionally open
embed_editor_urlin the built-in browser to look; it only works if that browser is signed into the same CapCut account. Large projects take 30–60 s to load; text may only draw after a segment is selected.
Push pitfalls (verified)
- Timeout ≠ failure. First push into a new account copies every media file and can exceed the client timeout while still succeeding. Never blindly re-push:
check_stdraft_statefirst; if a version now exists,get_stdraft_snapshot(summarise via draft_tool) and continue from it. A blind re-push returnsSTDRAFT_VERSION_CONFLICT. - A draft created by a timed-out push may not show in the Library and returns no URL; one more push on top of it (same content, correct base) returns the editor URLs.
- Size: ~55k chars pushed reliably; ~90k did not fit in one call. Keep pushes lean (drop optional keyframes/styles, add them in the web editor).
4. Verified capability boundaries
Works and survives cloud save: video clips (source in-point, duration, volume, speed), transitions (add/replace/remove; same layer, contiguous), music & sound effects (sid:// from search or own vid://; volume; no auto-loop), filters with intensity, plain text (font, size, colour, position, border), font swap, text effects (flower), text templates (server adds an IN animation; slot count unverifiable), captions with word timing and update_caption_text, remove/unset, placement/layer/timing changes, scale_*/alpha keyframes on clips with speed 1.
Lost or broken on save:
VIDEO_EFFECTsegments (video effects and face effects) are dropped entirely — tell the user to add effects in the web editor.- Keyframes on clips whose
speed ≠ 1get their times rescaled by the speed and are mostly dropped. - Anything the builder doesn't cover (masks, stickers, curves, grading) must be done in the web editor.
- Export/render is not available through the MCP: the user exports in the CapCut editor.
Materials search: music, sound_effect, video_effect honour the prompt; font, text_effect, text_template, face_effect, transition, filter return a fixed curated list (max 20) regardless of prompt — there is no plain cross-dissolve; curated fonts are Latin (Chinese falls back to the default font vimo://7317175475195875841, which renders CJK). Video footage/images are not searchable — upload them.
Automatic captions (auto_caption_submit / auto_caption_query): speech recognition only; Pro membership needed (free accounts get PAYWALL_REQUIRED — show benefit_check_label link verbatim). Useless for song lyrics (a whole song returned one garbage line) — use local Whisper + known lyrics for lyric timing instead.
Template search: capcut_template_search → poll capcut_template_search_poll_v2 until terminal → templates_preview_v2(search_id) returns the template data (card not rendered; list title, duration, usage and page_url for the user). Relevance is loose; results persist 15 days; max 10.
AI rough cut (AI Lab): capcut_ailab_start_edit(assets=[{resource_id: <vid>, file_name}], query) → poll → a plan event arrives with status loop_turn_completed; relay the plan to the user, then capcut_ailab_submit_plan_response without card_id (the plan's event id is rejected as plan_card_id_invalid) and with the user's exact choice text. Music and final-video events follow (~2 min for a 10 s cut). Call video_preview with the final event's context/resources unchanged to get the result's editable STDraft (stdraft field) — import it into a draft session to keep editing. Audio-only assets are rejected (unsupported_edit_file_name). Do not use AI Lab for caption-only requests.
Image/video generation (Seedream / Seedance): spends credits. Cards don't render here, so: submit with confirmed:false (no unique_key) → on CONFIRMATION_REQUIRED tell the user the exact credits_amount → only after the user explicitly approves that amount in chat, retry with confirmed:true and the returned unique_key/same generate_id. Never confirm on the user's behalf. Poll capcut_generation_poll until next_action=none, then generation_result(task_id) to get the final media. The generated asset is returned as a vid:// usable in drafts. Image generation costs 20 credits, video generation costs 100 credits (as of 2026-11), and a ~10 second video takes about 3 minutes User may need to purchase credits via the CapCut web site. Always ask before spending credits.
Common fixes
| Problem | Fix |
|---|---|
All mcp__capcut__* tools missing | Check config file (section 0). Fully quit and reopen Claude. Verify in a new Code tab. |
| All calls return "check login error" | Re-authorize (section 0). |
upload_ticket calls fail | version:2 is required; files array with file_name/size_bytes. |
push_stdraft_snapshot returns auth errors | Re-authorize (section 0). |
| Draft not visible in browser | Account mismatch (section 0). |
| Timed out push | Check state, don't blindly re-push (section 3.5). |
auto_caption_submit fails | Speech only; Pro needed; not for music. |
| AI Lab plan card invalid | Omit card_id; submit with user choice text only (section 4). |
| Generation confirms without user | Never do that; ask first. |