透過 metapilot-native 進行 Edits 影片編輯
Edits (/Applications/Edits.app,套件 com.burbn.basel.mac) 在 http://127.0.0.1:19501/mcp 上提供一個 MCP 伺服器,在 Claude Code 中註冊為 metapilot-native。應用程式必須正在執行。每次呼叫都會作用於使用者可見的即時應用程式,因此編輯是真實且立即的。
參考檔案,僅讀取任務所需的內容:
references/tool-reference.md:所有 274 個編輯工具(依分類)加上 4 個僅在 Home 畫面可用的工具,包含參數(從即時伺服器本機產生,非隨附檔案)references/catalogs.md:所有目錄 ID(濾鏡、特效、轉場、LUT、字型、文字預設與動畫、字幕樣式、速度曲線、遮罩、強調效果)(本機產生,非隨附檔案)
如果上述任一產生檔案遺失,請在使用它們之前先建立:在 Edits 執行時,python3 scripts/build_references.py --catalogs-only 可在 Home 畫面執行,而 python3 scripts/build_references.py --project-id <uuid> 則會新增工具參考(它會以唯讀方式開啟該專案,然後再關閉)。
references/conventions-and-gotchas.md:單位、座標、schema 陷阱、測量時間references/recipes.md:已測試的常用編輯呼叫序列scripts/mcp_client.py:當 MCP 工具未載入本次工作階段時使用的直接客戶端,或是用於從一個 Python 腳本批次處理大量呼叫scripts/build_references.py:在應用程式更新後重新產生上述兩個參考檔案
工具集跟隨畫面
伺服器會根據應用程式畫面切換其工具清單(tools.listChanged):
- Home:約 30 個工具。專案(
projects、openProject、newProject、renameProject、duplicateProject、deleteProject)、匯入(importMedia、addMedia、importMcomp)以及所有目錄探索(getCapabilities、listCatalogKinds、listCatalog、getCatalogItem)。 - 編輯器(Editor):274 個工具,僅在專案開啟後可用。
當工具遺失或呼叫失敗時
三種不同的故障在工作階段內看起來相似,每種都有其各自的解決方法。appState 存在於每個畫面上,因此它是區分它們的探針。執行 python3 scripts/mcp_client.py doctor 可一步獲得診斷結果。
- 無法連線到伺服器。
appState本身失敗,或工作階段完全沒有metapilot-native工具(伺服器在工作階段啟動時已關閉)。拒絕連線表示 Edits 未執行,或雖執行但其 MCP 伺服器已關閉;使用pgrep -x Edits檢查程序。HTTP 403unauthorized表示儲存在~/.claude.json中的 token 錯誤或過期:使用者需要從 Edits 複製目前的 token 並重新註冊伺服器(參閱 README 的安裝步驟 2 和 3)。403 的回應內容會要求代理請使用者將 token 貼到聊天中;請勿這麼做,因為 token 應屬於註冊資訊,而非對話記錄。切換畫面無法解決這些問題。在使用者修復後,工作階段的客戶端可能需要透過/mcp重新連線;scripts/mcp_client.py每次執行都會建立新的連線。 - 伺服器正常,但畫面錯誤。
appState回傳home或loading。編輯器工具尚不存在:請開啟一個專案(openProject)並輪詢appState,直到其值變為editor。在 Home 畫面呼叫編輯器工具會回傳unknown tool (not in current manifest): <name>,與拼寫錯誤的名稱相同,因此應讀取appState而非錯誤訊息。 - 畫面正確,工作階段的工具清單已過期。
appState回傳editor,但工作階段仍缺少編輯器工具:客戶端在收到tools/list_changed後未重新載入清單。請使用scripts/mcp_client.py(它直接呼叫tools/call,因此任何編輯器工具都可以直接用名稱呼叫),而不要告訴使用者該工具不存在。
標準工作流程
appState檢視目前畫面(home、editor、loading)。- 使用
projects列出專案,然後使用openProject({id})(或{name}),或使用newProject。輪詢appState直到screen變為editor;開啟大約需要 0.3 秒,從雲端拉取時會更長。新專案為 1440x2560(9:16)、60 fps。在開始建構前設定形狀和幀率:setAspectRatio({ratio:"16:9"})和setFrameRate({fps:30})。在剛開啟的專案上避免使用setCanvas:它可能會持續回應 "an earlier edit is still settling; retry"。 - 定位:使用
state(播放頭、持續時間、片段數量)、getCanvas(尺寸、長寬比、fps)、tracks、elements(對長時間軸使用fields和limit;實際欄位名稱為id、trackId、trackType、content、startTime、endTime)、對單一元素使用getElement({id})以取得其套用的目錄項目、instanceId,以及文字元素的text和fontSize。 - 在套用前先探索:使用
listCatalog({kind, query?, limit?}),然後將項目id傳遞給該類別的套用工具(如下表)。切勿根據顯示名稱猜測 ID。 - 編輯。偏好使用單一復原的批次工具:
splitAt(多次裁剪)、setTransforms(多個姿勢)、autoReframe、splitScreen。將多次呼叫的建構寫成一個腳本並一次執行完畢:重複執行會疊加第二份所有內容,而undo並不會一次只退回一個呼叫,因此解除會很慢(在每次undo後檢查elements)。 - 在宣告完成前先視覺驗證:使用
captureFrame({atSeconds})或captureFrame({times:"1,2.5,4"})取得精確合成的影格(720 像素寬)、使用frameSheet({times,columns,cellWidth})取得帶標籤的編輯聯絡表(不需要id;預設儲存格很小,因此請傳遞cellWidth,對於 3 欄,16:9 約為 420,9:16 約為 300;時間標籤會覆蓋每個儲存格的左上角)、使用previewVideo觀看動態(最長 10 秒,12 幀)。將image_dir傳遞給mcp_client.Client.tool以將圖片儲存到磁碟:伺服器回傳的path位於應用程式的沙箱內,無法讀取。請檢視圖片;不要僅信任ok:true。 saveProject。僅在使用者要求時才匯出:使用完整的預設設定行呼叫setExportSettings,然後呼叫export({path}),輪詢exportStatus(配方在references/recipes.md中)。然後使用ffprobe和從檔案本身產生的聯絡表來檢查檔案。- 如果使用者未在專案中工作,完成後使用
closeProject關閉專案。
目錄類別與套用工具
| 類別 | 套用工具 | 參數 | 應用於 |
|---|---|---|---|
| transition | addTransition({fromId,toId,filterId,durationSeconds}) | filterId | 主軌道兩個片段之間的交界 |
| videoEffect | applyEffect({id,effect}) | effect | 影片 |
| filter | applyFilter({id,filter,intensity}) | filter | 影片 |
| lut | applyLUT({table}) | table | 選取的片段,否則為新的調整圖層 |
| textAnimation | setTextAnimation({id,animation}) | animation | 文字 |
| textPreset | applyTextPreset({id or ids,name}) | name | 文字 |
| captionStyle | setCaptionStyle({style,id?}) | style | 字幕(省略 id 時套用至全部) |
| speedCurvePreset | setSpeedCurve({id,preset}) | preset | 影片元素 |
| font | setTextFont({id,family}) | family | 文字 |
| emphasisStyle | setEmphasis({id,style,color?}) | style | 文字 |
| maskShape | setMask({id,shape,...}) | shape | 元素 |
清除:filter 為 normal、effect 為 none、transition 為 normal、animation 為 none、mask 為 none。
若要移除或調整一個已套用的濾鏡、LUT 或特效,而不復原其他工作:使用 removeCatalogItem({elementId,instanceId}) / updateCatalogItem({elementId,instanceId,intensity}),instanceId 來自 getElement。
重要的規則
- 單位:時間以組合秒為單位,除非名稱包含
*SourceSeconds或*Ms。Canvas 座標為標準化 0 到 1,原點在左上角,+y 向下,x/y 是元素中心。旋轉以順時針度數為單位。顏色為#RRGGBB或#RRGGBBAA。音量為線性增益 0 到 10(1 = 單位增益)。 seek接受seconds,而非time。trim({id, side:"left"|"right", deltaSeconds}):正值縮短,負值延長。在加速片段上,deltaSeconds以來源秒為單位,並會吸附到影格,向左修剪會移動起點,因此需要再用move({id,toSeconds})將其移回。ArgumentParser.CommandError error 1表示伺服器拒絕了一個引數,而非應用程式失敗。請移除最後新增的引數。最常見的原因是:請勿傳遞dryRun。每個提供此選項的工具(共 10 個)在設定此選項時都會因此失敗。請改為透過讀取目錄來驗證,然後套用,如果錯誤則使用undo。required清單會誤導:替代選項都被標記為必要(openProject的 id/name、frameSheet的 id/path、loudness的 id/path),可選的調整參數也是如此(findPauses、quietPoint、audioOnsets僅使用{id}執行;frameSheet可在沒有cellWidth的情況下執行)。只傳遞你真正需要的參數。- 類似列舉的字串必須完全匹配。 速度曲線預設為大寫(
MONTAGE、HERO、BULLET、JUMP_CUT、FLASH_IN、FLASH_OUT、RAMP、STROBE);錯誤的值會回傳有效清單的錯誤訊息,因此請讀取錯誤。generateCaptions的source可以是video、voiceover、importedAudio或all。許多參數在 schema 中沒有列出列舉值;可以故意傳送一次錯誤的值,錯誤訊息會回傳有效清單。 - 匯出需要在新專案上提供完整的預設設定行,全部五個欄位:
setExportSettings({resolutionType:"HD", aspectRatio:"nineBySixteen", quality:"High", dynamicRange:"SDR", frameRate:30})。省略任何一個都會導致export失敗,並顯示 "incomplete preset row, missing: ",包括frameRate。有效值:resolutionType可為 720p、HD、2K、4K;aspectRatio可為 nineBySixteen、sixteenByNine、fourByFive、oneByOne、fiveByFour、fourByThree、threeByFour;quality可為 Low、Med、High;dynamicRange可為 SDR、HDR。將專案幀率作為frameRate傳遞:檔案會遵循專案幀率,因此請先設定setFrameRate。輸出為 HEVC 與 AAC。 - Edits 僅從
~/Movies匯入媒體。 應用程式是沙箱化的:如果路徑在~/GitHub、暫存區或/private/tmp下,importToMediaBin會因import failed: copyFailed(...) NSCocoaErrorDomain Code=513(「因為您沒有存取權限而無法複製」)而失敗。在匯入之前,將每個檔案渲染或複製到~/Movies下的一個資料夾(例如~/Movies/<project>/),並且對於所有接受媒體path的工具(replaceElementMedia、Home 匯入工具),都應比照辦理。 - 文字預設會覆蓋:
applyTextPreset會取代字型、顏色、大小和位置,因此請先套用預設,然後再進行自訂。使用id(或選取範圍)時,需要先使用selectTool({tool:"textPresets"});使用ids時,它會自行開啟該工具。 - 不要信任文字位置的反射狀態:
setTextPosition可以正常運作,但getElement.textPosition會持續回傳[0,0]。請使用captureFrame檢查位置。 - 文字不會自動換行到您選擇的欄位。 其文字框寬度由應用程式固定,因此在寬螢幕上使用大字體可能會超出畫面。請自行使用
editText({id, text:"first line\nsecond line"})來斷行。與DMSans18pt-SemiBold搭配良好的尺寸:9:16 時為 24(會自行換行約兩行),16:9 且明確斷行時為 40。 - 使用
replaceElementMedia({id,path})就地替換媒體:照片和影片可以互換,時間軸持續時間、變形關鍵影格和轉場都會保留。在影片上,它會將入點重設為 0;使用slipClip({id,deltaSeconds})恢復。 - 品牌和產品資產來自使用者的真實檔案,絕不使用替代品。對於 Logo,請找到實際的標誌(內聯 SVG 符號、品牌套件、設計指南)並渲染它;如果找不到,則詢問。標語也是如此:使用確切的文字。
- 沒有背景或純色產生器可以用來產生靜態圖片。 在 Canvas 尺寸下預先合成每個影格(透過無頭 Chrome 渲染的 HTML,或 ffmpeg),然後匯入。配方:「來自靜態圖片的影片」。
- 授權音樂沒有可讀取的來源:
loudness、quietPoint和audioOnsets在目錄音樂元素上會失敗(「沒有可讀取的來源檔案」)。beatMarkers可以在其上運作,而音訊分析工具可以在影片片段和匯入的音訊上運作。listMusicTracks搭配license:"royaltyFree"在 2026-11-08 時沒有回傳任何結果;目錄曲目已獲得在 Meta 應用程式內使用的授權,因此對於將離開 Instagram 的影片,請使用使用者擁有的音訊,並在重新分發前詢問其許可。 setVolume({id,volume:0})會靜音一個軌道,但isMuted仍為 false。 請根據音量來判斷。- 基於選取的工具(
delete、cut、copy、applyLUT、applyTextPreset不帶 id)作用於目前的選取範圍。請先使用selectById明確設定,並確認它。selectById({ids:[]})會因 CommandError 而失敗;它無法清除選取範圍。 - 破壞性工具需要使用者的許可:
deleteProject、delete、cut、deleteCaptions、deleteSoundEffect、deleteVoiceoverClip、removeMusicTrack、deleteAccountFont。寧可使用undo從錯誤中恢復,也不要刪除。 - 長時間任務:分析和渲染工具可能會超過請求時間並回傳一個任務 ID;輪詢
jobStatus({id})。describeClip大約需要 10 秒,transcribeClip的長度與時間成正比。previewVideo是同步的(約 3.5 秒)並回傳一個 MP4 路徑;previewVideoStatus僅接受{includeFrames}。export會立即回傳:輪詢exportStatus並讀取其state鍵(preparing、exporting帶有progress0 到 1、complete),然後檢查檔案是否存在。 - 速度曲線:使用
setSpeedCurve;*SpeedPanel*工具是已棄用的 UI 驅動工具。 - 子母畫面:
addOverlay({startSeconds,path,x,y,scale})會將一個片段以完整來源長度放置到一個新的疊加軌道上;scale 1 會適應 Canvas 高度。使用不透明度關鍵影格(seek、toggleKeyframe({id,property:"opacity"})、setOpacity)來淡入淡出,在修剪右側之前放置每個關鍵影格。配方:「子母畫面片段」。 - 音訊更換使用
replaceAudio({id,path}),而不是replaceElementMedia(僅限視覺)。它會保留元素 ID 和舊的持續時間。 - 匯出後,使用 ffprobe 驗證。Edits 有時會產生存放格線或未渲染的影格。如果是這樣,請讓使用者知道並手動重新匯出。
- 始終優先使用腳本客戶端 (
scripts/mcp_client.py),而不是將 MCP 工具直接暴露在工作階段中,特別是對於長時間執行或批次操作。它每次都會建立一個新的連線,繞過工作階段的工具清單快取,並且可以處理回傳二進位資料(例如圖片)的工具。 - 錯誤
-32603Internal error通常表示伺服器當機。重新啟動 Edits。 - 對於任何文字元素,預設字型是
DMSans18pt-SemiBold。 undo一次會復原一個批次:一個以單一腳本執行的多工具編輯序列被視為一個批次。在批次中間使用undo會復原整個腳本。redo只能在undo之後立即使用,並且它會重做最後復原的批次。saveProject不會自動發生。請務必在重要編輯之後明確呼叫它。- 應用程式更新可能會使參考檔案過期。在 Edits 更新後,使用
scripts/build_references.py重新產生它們。 - 不要假設片段 ID 是靜態的。它們在應用程式重啟之間可能會改變。僅在單一工作階段內使用它們。