MCP server for WeftCut video editor, exposing desktop app domain operations (media conformance, analysis, subtitle parsing, pause detection, shot detection, speech synthesis/transcription, motif catalog management) as tools to external AI agents
WeftCut MCP server demonstrates solid foundational work with 10 well-named, action-verb-prefixed tools covering a specialized video editing domain. Tool descriptions are present and contextually rich (avg ~250 chars, above 194-char production baseline). Parameter descriptions are comprehensive with technical depth (layer_id resolution, amplitude thresholds in dBFS, microsecond precision). However, there are critical gaps: output schemas are completely undocumented across all 10 tools, no return type specifications are visible in the source. Parameters lack formal type constraints (enums, min/max bounds in schema); dependencies between parameters (e.g., install_motif's mode/target_id relationship) are documented in text but not enforced structurally. Error recovery guidance is minimal, tools describe what they do but not how to diagnose failures. The motif workflow (write_motif_draft → preview_motif_draft → install_motif) is well-composed but depends on implicit caller understanding.
Analyze VideoClip layer for shot changes using frame-by-frame comparison. Returns shot boundaries and per-frame change scores.
Apply subtitle document (SRT, ASS, or VTT format) to the timeline. This tool is handled by the hybrid orchestrator (parse_subtitles napi compute → TS-actor add_caption_track write). Stub in Rust returns internal error.
Delete an installed or draft user Motif by id. Built-ins and unknown ids are refused (list_motifs reports what exists). Placed layers referencing it degrade to an error placeholder.
Detect silent/quiet pauses in audio layer using peak amplitude analysis. Returns pause regions (timeline-absolute), noise floor amplitude, and peaks file source (raw or effect).
Read a Motif's source { manifest, html } — any built-in, installed, or draft. Read this before editing so you can base your changes on the current source. id comes from list_motifs.
Install a draft. mode 'new' publishes under the draft's own id; 'update' republishes over target_id, or over the target the draft recorded at write_motif_draft { from } when target_id is omitted (refused when it has neither) — bumping the version so every placement re-renders, and rebinding + migrating current-project layers. Returns { motif_id }.
Output schemas completely undocumented across all 10 tools. Return types and field structures are described in English prose but not in JSON Schema format. LLMs cannot infer response structure to plan downstream calls or extract fields for subsequent tool invocations.
Numeric and enum parameters lack formal JSON Schema constraints. threshold_amp, sensitivity, width, height, mode are described with ranges/enums in text but not declared in JSON Schema (no min/max/enum fields). Callers and LLMs cannot enforce or validate boundaries programmatically.
Inferred effective spec: 2026-07-28+.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | B | 72 | 2026-07-28+ | v2 |
List every motif add_motif_layer can place — built-ins plus installed and draft user motifs. Returns [{ id, name, version, size: [w, h], default_duration_s, props_schema, status, content_hash, has_params_ui, target_id? }]; status is builtin | installed | draft. Read props_schema before add_motif_layer — unknown prop keys reject. Drafts are placeable immediately for preview.
Liveness check returning 'pong'
Render one frame of a Motif (draft / installed / built-in) as a base64 PNG, so you can SEE your output and self-correct. id, t_sec (content time); optional props (default: the manifest defaults) and width/height (default: the motif's own size). Needs the app's preview runtime; errors rather than hangs when it is not ready.
Write a Motif draft from { manifest, html }. Returns { draft_id }. The draft is placeable immediately (via add_motif_layer) for preview, and re-writable. from (optional) records an existing Motif id as the draft's UPDATE target so a later install_motif {mode:'update'} republishes over it; omit from for a brand-new Motif (installs as new). The manifest's id/version are ignored — app-assigned. Expose tweakable controls via props_schema.
Error handling and recovery guidance is minimal. Tools describe failures (e.g., 'Stub in Rust returns internal error' for apply_subtitles, 'errors rather than hangs' for preview_motif_draft) but do not provide actionable recovery steps. LLMs cannot diagnose failures or know whether to retry, ask user, or abort. No error response format is documented.
Implicit dependencies between parameters are documented in prose but not enforced structurally. install_motif's mode='update' requires either target_id OR draft's recorded 'from' target; description states 'refused when it has neither' but JSON Schema cannot express this conditional logic. LLMs may pass both or neither without detection until runtime.
Complex object parameters lack formal schema definitions. write_motif_draft's 'manifest' and preview_motif_draft's 'props' are typed as 'object' with guidance to 'copy from get_motif_source' or 'use manifest defaults'. Callers do not have a machine-readable schema for valid keys, types, and required fields. This forces LLMs to infer structure from documentation or examples.
Destructive tools (install_motif, delete_motif) lack confirmation or dry-run patterns. delete_motif irreversibly removes user motifs; install_motif bumps versions and rebinds layers project-wide. No dry-run option, confirmation step, or rollback mechanism is documented. An agent mistake triggers cascading side effects.
ping tool has trivial description (27 chars, well below 50-char minimum for production patterns). While appropriate for a liveness check, it does not explain WHEN to call it (only for connectivity checks?) or what failure means. Pattern:tool-description baseline is 50-200 chars.