Videobearbeitung in Edits über metapilot-native
Edits (/Applications/Edits.app, Bundle com.burbn.basel.mac) stellt einen MCP-Server unter
http://127.0.0.1:19501/mcp bereit, der in Claude Code als metapilot-native registriert ist. Die App muss ausgeführt werden.
Jeder Aufruf wirkt auf die live App, die der Benutzer sieht; die Bearbeitungen sind also echt und sofort.
Referenzdateien, lies nur, was die Aufgabe benötigt:
references/tool-reference.md: alle 274 Editor-Werkzeuge nach Kategorie plus die 4 Home-only-Werkzeuge, mit Parametern (lokal vom laufenden Server generiert, nicht mitgeliefert)references/catalogs.md: jede Katalog-ID (Filter, Effekte, Übergänge, LUTs, Schriftarten, Text- Voreinstellungen und Animationen, Untertitelstile, Geschwindigkeitskurven, Masken, Betonungen) (lokal generiert, nicht mitgeliefert)
Wenn eine der generierten Dateien fehlt, erstelle sie, bevor du dich darauf verlässt: bei laufender Edits,
python3 scripts/build_references.py --catalogs-only funktioniert auf dem Startbildschirm, und
python3 scripts/build_references.py --project-id <uuid> fügt die Werkzeugreferenz hinzu (es öffnet dieses Projekt im
schreibgeschützten Modus und schließt es wieder).
references/conventions-and-gotchas.md: Einheiten, Koordinaten, Schema-Fallstricke, gemessene Zeitabläufereferences/recipes.md: getestete Aufrufsequenzen für übliche Bearbeitungenscripts/mcp_client.py: ein direkter Client für den Fall, dass MCP-Werkzeuge nicht in der Sitzung geladen sind, oder für die Stapelverarbeitung vieler Aufrufe aus einem Python-Skriptscripts/build_references.py: regeneriert die beiden generierten Referenzen nach einem App-Update
Der Werkzeugsatz folgt dem Bildschirm
Der Server tauscht seine Werkzeugliste mit dem App-Bildschirm aus (tools.listChanged):
- home: etwa 30 Werkzeuge. Projekte (
projects,openProject,newProject,renameProject,duplicateProject,deleteProject), Import (importMedia,addMedia,importMcomp) und alle Katalogerkennung (getCapabilities,listCatalogKinds,listCatalog,getCatalogItem). - editor: 274 Werkzeuge, nur nachdem ein Projekt geöffnet ist.
Wenn ein Werkzeug fehlt oder ein Aufruf fehlschlägt
Drei verschiedene Fehler sehen innerhalb einer Sitzung gleich aus, und jeder hat seine eigene Behebung. appState
existiert auf jedem Bildschirm und ist daher die Sonde, die sie trennt. Führe
python3 scripts/mcp_client.py doctor aus, um das Urteil in einem Schritt zu erhalten.
- Der Server ist nicht erreichbar.
appStateselbst schlägt fehl, oder die Sitzung hat überhaupt keinemetapilot-native-Werkzeuge (der Server war beim Start der Sitzung nicht verfügbar). Eine verweigerte Verbindung bedeutet, dass Edits nicht läuft oder dass der MCP-Server ausgeschaltet ist; überprüfe den Prozess mitpgrep -x Edits. Ein HTTP-403unauthorizedbedeutet, dass das in~/.claude.jsongespeicherte Token falsch oder veraltet ist: Der Benutzer kopiert das aktuelle Token aus Edits und registriert den Server erneut (README, Installationsschritte 2 und 3). Der 403-Text fordert den Agenten auf, den Benutzer zu bitten, das Token in den Chat einzufügen; tue dies nicht, weil das Token in die Registrierung gehört, nicht in das Transkript. Das Wechseln von Bildschirmen behebt keine davon. Nachdem der Benutzer es behoben hat, muss der client der Sitzung möglicherweise eine erneute Verbindung über/mcpherstellen;scripts/mcp_client.pyverbindet sich bei jedem Lauf neu. - Der Server ist in Ordnung, der Bildschirm ist falsch.
appStateantwortethomeoderloading. Editor-Werkzeuge existieren noch nicht: Öffne ein Projekt (openProject) und frageappStateab, bis eseditoranzeigt. Der Aufruf eines Editor-Werkzeugs auf dem Startbildschirm antwortet mitunknown tool (not in current manifest): <name>, dem gleichen Text wie bei einem falsch geschriebenen Namen; lies daherappStateanstelle der Fehlermeldung. - Der Bildschirm ist richtig, die Werkzeugliste der Sitzung ist veraltet.
appStateantworteteditor, aber die Sitzung hat noch keine Editor-Werkzeuge: Der client hat die Liste nicht nachtools/list_changedneu geladen. Verwendescripts/mcp_client.py(es rufttools/calldirekt auf, sodass jedes Editor-Werkzeug mit Namen funktioniert), anstatt dem Benutzer mitzuteilen, dass das Werkzeug nicht existiert.
Standard-Arbeitsablauf
appState, um den Bildschirm zu sehen (home,editor,loading).projectszum Auflisten, dannopenProject({id})(oder{name}) odernewProject. FrageappStateab, bisscreeneditorist; das Öffnen dauert etwa 0,3 s, länger, wenn es aus der Cloud zieht. Ein neues Projekt ist 1440x2560 (9:16) bei 60 fps. Stelle das Format und die Bildrate ein, bevor du aufbaust:setAspectRatio({ratio:"16:9"})undsetFrameRate({fps:30}). VermeidesetCanvasbei einem frisch geöffneten Projekt: Es kann immer noch mit "an earlier edit is still settling; retry" antworten.- Orientieren:
state(Abspielposition, Dauer, Clip-Anzahl),getCanvas(Größe, Seitenverhältnis, fps),tracks,elements(verwendefieldsundlimitbei langen Zeitleisten; die tatsächlichen Feldnamen sindid,trackId,trackType,content,startTime,endTime),getElement({id})für ein einzelnes Element mit angewandten Katalogeinträgen,instanceIds und bei einem Textelement dessentextundfontSize. - Erkunden, bevor du anwendest:
listCatalog({kind, query?, limit?}), dann übergib dieiddes Eintrags an das entsprechende Anwendungswerkzeug der Kategorie (Tabelle unten). Rate niemals IDs aus Anzeigenamen. - Bearbeiten. Bevorzuge die Ein-Undo-Stapelwerkzeuge:
splitAt(viele Schnitte),setTransforms(viele Positionen),autoReframe,splitScreen. Schreibe Multi-Aufruf-Builds als ein Skript und führe es einmal aus: Eine erneute Ausführung stapelt eine zweite Kopie von allem, undundogeht nicht einen Aufruf nach dem anderen zurück, also ist das Rückgängigmachen langsam (überprüfeelementsnach jedemundo). - Visuell überprüfen, bevor du es als erledigt erklärst:
captureFrame({atSeconds})odercaptureFrame({times:"1,2.5,4"})für exakt zusammengesetzte Einzelbilder (720 px breit),frameSheet({times,columns,cellWidth})für einen beschrifteten Kontaktbogen der Bearbeitung (keineiderforderlich; die Standardzellen sind klein, übergib dahercellWidth, etwa 420 für 16:9 und 300 für 9:16 bei 3 Spalten; die Zeitbeschriftung bedeckt die obere linke Ecke jeder Zelle),previewVideofür Bewegung (max. 10 s, 12 Bilder). Übergibimage_diranmcp_client.Client.tool, um die Bilder auf der Festplatte zu erhalten: Denpath, den der Server zurückgibt, befindet sich innerhalb der Sandbox der App und kann nicht gelesen werden. Sieh dir die Bilder an; vertraue nicht allein aufok:true. saveProject. Exportiere nur, wenn danach gefragt wird:setExportSettingsmit der vollständigen Voreinstellungszeile, dannexport({path}), frageexportStatusab (Rezept inreferences/recipes.md). Überprüfe dann die Datei mitffprobeund einem Kontaktbogen aus der Datei selbst.closeProject, wenn du fertig bist, falls der Benutzer nicht selbst in dem Projekt arbeitet.
Katalogarten und Anwendungswerkzeuge
| Art | Anwendungswerkzeug | Parameter | Angewendet auf |
|---|---|---|---|
| transition | addTransition({fromId,toId,filterId,durationSeconds}) | filterId | Grenze zwischen zwei Hauptspur-Clips |
| videoEffect | applyEffect({id,effect}) | effect | video |
| filter | applyFilter({id,filter,intensity}) | filter | video |
| lut | applyLUT({table}) | table | ausgewählte Clips, andernfalls eine neue Anpassungsebene |
| textAnimation | setTextAnimation({id,animation}) | animation | text |
| textPreset | applyTextPreset({id or ids,name}) | name | text |
| captionStyle | setCaptionStyle({style,id?}) | style | Untertitel (alle, wenn id weggelassen) |
| speedCurvePreset | setSpeedCurve({id,preset}) | preset | Videoelement |
| font | setTextFont({id,family}) | family | text |
| emphasisStyle | setEmphasis({id,style,color?}) | style | text |
| maskShape | setMask({id,shape,...}) | shape | element |
Löschen: Filter normal, Effekt none, Übergang normal, Animation none, Maske none.
Um einen angewandten Filter, eine LUT oder einen Effekt zu entfernen oder nachzujustieren, ohne andere Arbeit rückgängig zu machen:
removeCatalogItem({elementId,instanceId}) / updateCatalogItem({elementId,instanceId,intensity}),
mit instanceId aus getElement.
Wichtige Regeln
- Einheiten: Zeit ist in Kompositionssekunden, es sei denn, der Name sagt
*SourceSecondsoder*Ms. Leinwand- Koordinaten sind normalisiert von 0 bis 1, Ursprung oben links, +y nach unten, x/y sind die Elementmitte. Rotation ist in Grad im Uhrzeigersinn. Farben sind#RRGGBBoder#RRGGBBAA. Lautstärke ist linearer Verstärkungsfaktor 0 bis 10 (1 = Einheit). seeknimmtseconds, nichttime.trim({id, side:"left"|"right", deltaSeconds}): positiv verkürzt, negativ verlängert. Bei einem beschleunigten Clip istdeltaSecondsin Quellsekunden und rastet auf ein Einzelbild ein, und ein Trimmen links verschiebt den Start, daher verschiebe mitmove({id,toSeconds})zurück.ArgumentParser.CommandError error 1bedeutet, dass der Server ein Argument abgelehnt hat, nicht dass die App fehlgeschlagen ist. Entferne das Argument, das du zuletzt hinzugefügt hast. Die häufigste Ursache: übergib nichtdryRun. Jedes Werkzeug, das es anbietet (10 davon), schlägt auf diese Weise fehl, wenn es gesetzt ist. Validiere, indem du stattdessen den Katalog liest, dann wende an, dann macheundo, wenn es falsch ist.required-Listen lügen: Alternativen sind alle als erforderlich markiert (openProjectid/name,frameSheetid/path,loudnessid/path), und das gleiche gilt für optionale Optimierungsparameter (findPauses,quietPoint,audioOnsetslaufen mit{id}allein;frameSheetläuft ohnecellWidth). Übergib nur, was du beabsichtigst.- Enum-ähnliche Zeichenfolgen sind exakt. Geschwindigkeitskurven-Voreinstellungen sind in Großbuchstaben (
MONTAGE,HERO,BULLET,JUMP_CUT,FLASH_IN,FLASH_OUT,RAMP,STROBE); ein falscher Wert meldet einen Fehler mit der gültigen Liste, also lies die Fehlermeldung.generateCaptionssourceistvideo,voiceover,importedAudiooderall. Viele Parameter listen kein Enum im Schema auf; sende einmal einen absichtlich falschen Wert, und der Fehler gibt die gültige Liste zurück. - Export benötigt die vollständige Voreinstellungszeile bei einem neuen Projekt, alle fünf Felder:
setExportSettings({resolutionType:"HD", aspectRatio:"nineBySixteen", quality:"High", dynamicRange:"SDR", frameRate:30}). Lasse eines aus, undexportschlägt fehl mit "incomplete preset row, missing: ", einschließlichframeRate. Gültige Werte:resolutionType720p, HD, 2K, 4K;aspectRationineBySixteen, sixteenByNine, fourByFive, oneByOne, fiveByFour, fourByThree, threeByFour;qualityLow, Med, High;dynamicRangeSDR, HDR. Übergib die Projekt- Bildrate alsframeRate: Die Datei folgt der Projekt-Bildrate, setze also zuerstsetFrameRate. Die Ausgabe ist HEVC mit AAC. - Edits importiert Medien nur aus
~/Movies. Die App ist sandboxed:importToMediaBinschlägt bei einem Pfad unter~/GitHub, der Zwischenablage oder/private/tmpmitimport failed: copyFailed(...) NSCocoaErrorDomain Code=513fehl ("konnte nicht kopiert werden, da Sie keine Berechtigung zum Zugriff haben"). Rendere oder kopiere jede Datei in einen Ordner unter~/Movies(z. B.~/Movies/<project>/), bevor du importierst, und behandle jedes Werkzeug, das einen Medien-pathakzeptiert (replaceElementMedia, die Home-Import-Werkzeuge) auf die gleiche Weise. - Text-Voreinstellungen überschreiben:
applyTextPresetersetzt Schriftart, Farbe, Größe und Position, also wende die Voreinstellung zuerst an und passe sie danach an. Mitid(oder der Auswahl) benötigt esselectTool({tool:"textPresets"})zuerst; mitidsöffnet es das Werkzeug selbst. - Vertraue nicht dem zurückgemeldeten Zustand für die Textposition:
setTextPositionfunktioniert, abergetElement.textPositionliest weiterhin[0,0]. Überprüfe die Platzierung mitcaptureFrame. - Text wird nicht auf eine von dir gewählte Spalte umgebrochen. Die Breite seines Rahmens wird von der App festgelegt, sodass eine große
Größe auf einer breiten Leinwand aus dem Rahmen läuft. Füge Zeilenumbrüche selbst mit
editText({id, text:"erste zeile\nzweite zeile"})ein. Größen, die mitDMSans18pt-SemiBoldgut lesbar sind: 24 bei 9:16 (wird von selbst auf etwa zwei Zeilen umbrochen), 40 bei 16:9 mit einem expliziten Umbruch. - Medien vor Ort austauschen mit
replaceElementMedia({id,path}): Foto gegen Video und zurück funktionieren beide, und die Zeitleistendauer, Transformations-Keyframes und Übergänge bleiben erhalten. Bei einem Video wird der In-Punkt auf 0 zurückgesetzt; stelle ihn mitslipClip({id,deltaSeconds})wieder her. - Marken- und Produkt-Assets stammen aus den echten Dateien des Benutzers, niemals aus einem Ersatz. Für ein Logo finde die tatsächliche Markierung (ein Inline-SVG-Symbol, ein Brand Kit, eine Designrichtlinie) und rendere sie; frage nach, wenn sie nicht gefunden werden kann. Gleiches gilt für Slogans: Verwende die exakte Formulierung.
- Es gibt keinen Hintergrund- oder Vollfarb-Generator für Standbilder. Erstelle jedes Einzelbild vorab (HTML gerendert von Headless Chrome oder ffmpeg) in der Leinwandgröße und importiere dieses. Rezept: "Video aus Standbildern".
- Lizenzierte Musik hat keine lesbare Quelle:
loudness,quietPointundaudioOnsetsschlagen bei einem Katalog-Musikelement fehl ("has no readable source file").beatMarkersfunktioniert damit, und die Audio- Analysewerkzeuge funktionieren bei Videoclips und importiertem Audio.listMusicTracksmitlicense:"royaltyFree"hat am 2026-11-08 nichts zurückgegeben; Katalog-Tracks sind für die Verwendung innerhalb von Meta-Apps lizenziert, also für ein Video, das Instagram verlässt, verwende Audio, das der Benutzer besitzt, und frage nach seiner Lizenz, bevor es weiterverteilt wird. setVolume({id,volume:0})stummschaltet eine Spur, aberisMutedbleibt false. Beurteile nach der Lautstärke.- Auswahlbasierte Werkzeuge (
delete,cut,copy,applyLUT,applyTextPresetohne id) wirken auf die aktuelle Auswahl. Setze sie zuerst explizit mitselectById, und bestätige sie.selectById({ids:[]})schlägt fehl mit CommandError; es kann die Auswahl nicht löschen. - Zerstörende Werkzeuge benötigen die Zustimmung des Benutzers:
deleteProject,delete,cut,deleteCaptions,deleteSoundEffect,deleteVoiceoverClip,removeMusicTrack,deleteAccountFont. Bevorzugeundo, um einen Fehler rückgängig zu machen, anstatt zu löschen. - Lange Aufgaben: Analyse- und Rendering-Werkzeuge können die Anfrage überdauern und eine Job-ID zurückgeben; frage
jobStatus({id})ab.describeClipdauert etwa 10 s,transcribeClipskaliert mit der Länge.previewVideoist synchron (etwa 3,5 s) und gibt einen MP4-Pfad zurück;previewVideoStatusakzeptiert nur{includeFrames}.exportkehrt sofort zurück: frageexportStatusab und lese seinenstate-Schlüssel (preparing,exportingmitprogress0 bis 1,complete), dann überprüfe, ob die Datei existiert. - Geschwindigkeitskurven: Verwende
setSpeedCurve; die*SpeedPanel*-Werkzeuge sind veraltete UI-Treiber. - Bild im Bild:
addOverlay({startSeconds,path,x,y,scale})platziert einen Clip auf einer neuen Overlay-Spur in voller Quelllänge; Skalierung 1 passt die Leinwandhöhe an. Blende ihn mit Opazitäts- Keyframes ein (seek,toggleKeyframe({id,property:"opacity"}),setOpacity), platziere jeden Keyframe, bevor du die rechte Seite trimmst. Rezept: "Bild-im-Bild-Clip". - Audio-Austausche verwenden
replaceAudio({id,path}), nichtreplaceElementMedia(nur visuell). Es behält die Element-ID und die alte Dauer bei.