Morpha
REMOTE · MORPHAREELS.AI · SCANNED SEP 21
AI editor to build, animate & export layered short-form video projects via one tool catalog.
Available components
How this component scores in each security and reliability category. Every signal is checked automatically against the live server, and we only credit what we can confirm. How we score → Why this is hard to score →
Endpoint Security97
- The endpoint's TLS certificate is valid, in date, and uses a strong key. View diagnostics → Pass
- Authorisation is enforced on tool calls, advertised via RFC 9728 protected-resource metadata. Discovery is public, which costs nothing: no tool can be invoked without a token. View diagnostics → Pass
- HTTPS is enforced; there's no plaintext access path. View diagnostics → Pass
- The HSTS (Strict-Transport-Security) header is present. View diagnostics → Pass
- DNSSEC check failed: this domain isn't protected by DNSSEC. See how to fix → View diagnostics → Fail
- The authorisation server supports Client ID Metadata Documents, the current MCP client-registration mechanism. View diagnostics → Pass
Transport & Reachability100
- Verified streamable-http transport via a live MCP handshake. View diagnostics → Pass
Schema Quality & AI Usability64
- AI-judged instruction clarity (excellent).Pass
- Context-footprint check failed: tool/resource definitions use about 24965 tokens (~254/item across 98 items; 98 tools + 0 resources), over budget; trim descriptions and params. See how to fix → Fail
- Usage-examples check failed: none of the tools include examples. See how to fix → Fail
Stability & Change Management45
- Stability check failed: schema churn in the 14 days we've observed: 2 tool removals, 0 breaking changes, 0 auth/transport breaks, 5 additions. See how to fix → Fail
Tool Coverage97
- 100% of tools have a non-trivial description (not blank, and not just the tool's name).Pass
- 91% of tool parameters carry a description.Partial
- Structured output schemas are declared (100% of tools); any adoption earns full credit.Pass
Tool Safety100
- No prompt-injection markers were found in the server instructions, tool names or descriptions we captured.Pass
- All 11 tool(s) whose name or description implies an irreversible operation declare an MCP destructiveHint annotation.Pass
- An AI judge read all 99 captured unit(s) of tool text and found none that tries to manipulate the model reading it.Pass
Capabilities100
- Implements a supported MCP spec version (2025-11-25); the latest is 2026-07-28.Pass
How do I install the Morpha MCP server?
Morpha is a hosted endpoint at https://morphareels.ai/mcp, so there is nothing to install locally. Ready-made configuration for Claude, Cursor, VS Code, Codex and 5 more is on this page, copied from each client's own documentation.
remote · morphareels.ai
claude mcp add --transport http ai-morphareels-morpha 'https://morphareels.ai/mcp'
{
"mcpServers": {
"ai-morphareels-morpha": {
"url": "https://morphareels.ai/mcp"
}
}
} {
"servers": {
"ai-morphareels-morpha": {
"type": "http",
"url": "https://morphareels.ai/mcp"
}
}
} [mcp_servers.ai-morphareels-morpha] url = "https://morphareels.ai/mcp"
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"ai-morphareels-morpha": {
"type": "remote",
"url": "https://morphareels.ai/mcp",
"enabled": true
}
}
} openclaw mcp add ai-morphareels-morpha --url 'https://morphareels.ai/mcp' --transport streamable-http
mcp_servers:
ai-morphareels-morpha:
url: "https://morphareels.ai/mcp" {
"McpServers": {
"ai-morphareels-morpha": {
"Transport": "http",
"Url": "https://morphareels.ai/mcp"
}
}
} assistant mcp add ai-morphareels-morpha -t streamable-http -u 'https://morphareels.ai/mcp'
{
"mcpServers": {
"ai-morphareels-morpha": {
"type": "http",
"url": "https://morphareels.ai/mcp"
}
}
} The mcpServers block is a cross-client convention. Remote transports vary, so check your client's docs.
Every change we have recorded for this component, newest first. Security-relevant changes are always shown. ▲ marks a change for the better, ▼ a change for the worse; unmarked changes are neutral.
- 20 Sept 26 +1
No change was recorded against any check on this day. Stability & Change Management went from 38 to 41.
- 19 Sept 26 0
- Server version: 1.0.372 → 1.0.373 functional
- 18 Sept 26 +1
No change was recorded against any check on this day. Stability & Change Management went from 31 to 35.
- 17 Sept 26 +4
- Tool “create_anonymous_account” was removed ▼ security
- The server rewrote its instructions, which are the text every model session reads security
- Tool “add_audio_overlay” rewrote its description, which is the text the model reads security
- Tool “add_image_layer” rewrote its description, which is the text the model reads security
- Tool “add_video_layer” rewrote its description, which is the text the model reads security
- Tool “create_upload_link” rewrote its description, which is the text the model reads security
- Tool “set_custom_font” rewrote its description, which is the text the model reads security
- Tool “set_image_filename” rewrote its description, which is the text the model reads security
- Tool “set_video_clip” rewrote its description, which is the text the model reads security
- Tool “upload_audio” rewrote its description, which is the text the model reads security
- Tool “upload_image” rewrote its description, which is the text the model reads security
- “create_upload_link” added a required parameter “name”, so existing callers break ▼ functional
- “create_upload_link” dropped the required parameter “filename” ▼ functional
- “add_audio_overlay” dropped the required parameter “anonymousToken” ▼ functional
- “add_caption_track” dropped the required parameter “anonymousToken” ▼ functional
- “add_color_keyframe” dropped the required parameter “anonymousToken” ▼ functional
- “add_curve” dropped the required parameter “anonymousToken” ▼ functional
- “add_embed_origin” dropped the required parameter “anonymousToken” ▼ functional
- “add_from_collection” dropped the required parameter “anonymousToken” ▼ functional
- “add_image_layer” dropped the required parameter “anonymousToken” ▼ functional
- “add_keyframe” dropped the required parameter “anonymousToken” ▼ functional
- “add_keyframes” dropped the required parameter “anonymousToken” ▼ functional
- “add_morpha_layer” dropped the required parameter “anonymousToken” ▼ functional
- “add_page” dropped the required parameter “anonymousToken” ▼ functional
- “add_shape” dropped the required parameter “anonymousToken” ▼ functional
- “add_speed_keyframe” dropped the required parameter “anonymousToken” ▼ functional
- “add_text_layer” dropped the required parameter “anonymousToken” ▼ functional
- “add_to_collection” dropped the required parameter “anonymousToken” ▼ functional
- “add_video_layer” dropped the required parameter “anonymousToken” ▼ functional
- “apply_preset” dropped the required parameter “anonymousToken” ▼ functional
- “apply_preset_stagger” dropped the required parameter “anonymousToken” ▼ functional
- “clip_processing_status” dropped the required parameter “anonymousToken” ▼ functional
- “create_project” dropped the required parameter “anonymousToken” ▼ functional
- “create_upload_link” dropped the required parameter “anonymousToken” ▼ functional
- “create_workspace” dropped the required parameter “anonymousToken” ▼ functional
- “cut_range” dropped the required parameter “anonymousToken” ▼ functional
- “delete_page” dropped the required parameter “anonymousToken” ▼ functional
- “delete_project” dropped the required parameter “anonymousToken” ▼ functional
- “delete_version” dropped the required parameter “anonymousToken” ▼ functional
- “describe_video” dropped the required parameter “anonymousToken” ▼ functional
- “detect_text_regions” dropped the required parameter “anonymousToken” ▼ functional
- “duplicate_layer” dropped the required parameter “anonymousToken” ▼ functional
- “duplicate_project” dropped the required parameter “anonymousToken” ▼ functional
- “fade_layer” dropped the required parameter “anonymousToken” ▼ functional
- “fit_duration_to_content” dropped the required parameter “anonymousToken” ▼ functional
- “freeze_frame” dropped the required parameter “anonymousToken” ▼ functional
- “group_layers” dropped the required parameter “anonymousToken” ▼ functional
- “inspect_layers” dropped the required parameter “anonymousToken” ▼ functional
- “list_collection” dropped the required parameter “anonymousToken” ▼ functional
- “list_fonts” dropped the required parameter “anonymousToken” ▼ functional
- “list_projects” dropped the required parameter “anonymousToken” ▼ functional
- “list_versions” dropped the required parameter “anonymousToken” ▼ functional
- “list_workspaces” dropped the required parameter “anonymousToken” ▼ functional
- “merge_caption_lines” dropped the required parameter “anonymousToken” ▼ functional
- “move_band” dropped the required parameter “anonymousToken” ▼ functional
- “move_layer” dropped the required parameter “anonymousToken” ▼ functional
- “move_project_to_workspace” dropped the required parameter “anonymousToken” ▼ functional
- “open_project” dropped the required parameter “anonymousToken” ▼ functional
- “reid_project” dropped the required parameter “anonymousToken” ▼ functional
- “remove_audio_overlay” dropped the required parameter “anonymousToken” ▼ functional
- “remove_color_keyframe” dropped the required parameter “anonymousToken” ▼ functional
- “remove_embed_origin” dropped the required parameter “anonymousToken” ▼ functional
- “remove_from_collection” dropped the required parameter “anonymousToken” ▼ functional
- “remove_keyframe” dropped the required parameter “anonymousToken” ▼ functional
- “remove_layer” dropped the required parameter “anonymousToken” ▼ functional
- “remove_speed_keyframe” dropped the required parameter “anonymousToken” ▼ functional
- “rename_group” dropped the required parameter “anonymousToken” ▼ functional
- “rename_layer” dropped the required parameter “anonymousToken” ▼ functional
- “rename_project” dropped the required parameter “anonymousToken” ▼ functional
- “rename_version” dropped the required parameter “anonymousToken” ▼ functional
- “rename_workspace” dropped the required parameter “anonymousToken” ▼ functional
- “render_status” dropped the required parameter “anonymousToken” ▼ functional
- “render_video” dropped the required parameter “anonymousToken” ▼ functional
- “reorder_layer” dropped the required parameter “anonymousToken” ▼ functional
- “reorder_pages” dropped the required parameter “anonymousToken” ▼ functional
- “restore_version” dropped the required parameter “anonymousToken” ▼ functional
- “safe_zones” dropped the required parameter “anonymousToken” ▼ functional
- “save_version” dropped the required parameter “anonymousToken” ▼ functional
- “select_page” dropped the required parameter “anonymousToken” ▼ functional
- “set_canvas_size” dropped the required parameter “anonymousToken” ▼ functional
- “set_clip_speed” dropped the required parameter “anonymousToken” ▼ functional
- “set_custom_font” dropped the required parameter “anonymousToken” ▼ functional
- “set_duration” dropped the required parameter “anonymousToken” ▼ functional
- “set_embed_origins” dropped the required parameter “anonymousToken” ▼ functional
- “set_group_box” dropped the required parameter “anonymousToken” ▼ functional
- “set_group_parent” dropped the required parameter “anonymousToken” ▼ functional
- “set_group_window” dropped the required parameter “anonymousToken” ▼ functional
- “set_image_filename” dropped the required parameter “anonymousToken” ▼ functional
- “set_keyframes_batch” dropped the required parameter “anonymousToken” ▼ functional
- “set_layer_block” dropped the required parameter “anonymousToken” ▼ functional
- “set_layer_fill” dropped the required parameter “anonymousToken” ▼ functional
- “set_layer_text” dropped the required parameter “anonymousToken” ▼ functional
- “set_layer_transition” dropped the required parameter “anonymousToken” ▼ functional
- “set_layer_visible” dropped the required parameter “anonymousToken” ▼ functional
- “set_loop” dropped the required parameter “anonymousToken” ▼ functional
- “set_matte_source” dropped the required parameter “anonymousToken” ▼ functional
- “set_pivot” dropped the required parameter “anonymousToken” ▼ functional
- “set_style” dropped the required parameter “anonymousToken” ▼ functional
- “set_text_background” dropped the required parameter “anonymousToken” ▼ functional
- “set_track_loop” dropped the required parameter “anonymousToken” ▼ functional
- “set_video_clip” dropped the required parameter “anonymousToken” ▼ functional
- “set_video_layer_muted” dropped the required parameter “anonymousToken” ▼ functional
- “set_video_layer_trim” dropped the required parameter “anonymousToken” ▼ functional
- “shift_group” dropped the required parameter “anonymousToken” ▼ functional
- “shift_track” dropped the required parameter “anonymousToken” ▼ functional
- “split_caption_line” dropped the required parameter “anonymousToken” ▼ functional
- “transcribe_clip” dropped the required parameter “anonymousToken” ▼ functional
- “ungroup_layers” dropped the required parameter “anonymousToken” ▼ functional
- “update_audio_overlay” dropped the required parameter “anonymousToken” ▼ functional
- “upload_audio” dropped the required parameter “anonymousToken” ▼ functional
- “upload_image” dropped the required parameter “anonymousToken” ▼ functional
- Schema quality: 280 → 250 ▲ functional
- Server version: 1.0.371 → 1.0.372 functional
- Server version: 1.0.370 → 1.0.371 functional
- Server version: 1.0.367 → 1.0.370 functional
- Server version: 1.0.365 → 1.0.367 functional
- Server version: 1.0.364 → 1.0.365 functional
- Server version: 1.0.362 → 1.0.364 functional
- Server version: 1.0.359 → 1.0.362 functional
- “add_audio_overlay” added an optional parameter “name” cosmetic
- “add_image_layer” added an optional parameter “name” cosmetic
- “set_image_filename” added an optional parameter “name” cosmetic
- “set_video_clip” added an optional parameter “name” cosmetic
- “update_audio_overlay” added an optional parameter “name” cosmetic
- “upload_audio” added an optional parameter “name” cosmetic
- “upload_image” added an optional parameter “name” cosmetic
- “add_audio_overlay” reworded the description of “filename” cosmetic
- “add_image_layer” reworded the description of “filename” cosmetic
- “add_video_layer” reworded the description of “clip” cosmetic
- “add_video_layer” reworded the description of “name” cosmetic
- “set_image_filename” reworded the description of “filename” cosmetic
- “set_video_clip” reworded the description of “clip” cosmetic
- “update_audio_overlay” reworded the description of “filename” cosmetic
- “upload_audio” dropped the optional parameter “filename” cosmetic
- “upload_image” dropped the optional parameter “filename” cosmetic
- 16 Sept 26 0
- The server rewrote its instructions, which are the text every model session reads security
- New tool “create_upload_link”, which the server declares destructive security
- Tool “add_embed_origin” rewrote its description, which is the text the model reads security
- Tool “remove_embed_origin” rewrote its description, which is the text the model reads security
- Tool “render_video” rewrote its description, which is the text the model reads security
- Tool “set_custom_font” rewrote its description, which is the text the model reads security
- Tool “set_embed_origins” rewrote its description, which is the text the model reads security
- Tool “create_anonymous_account” rewrote its description, which is the text the model reads security
- Tool “clip_processing_status” rewrote its description, which is the text the model reads security
- Tool “set_matte_source” rewrote its description, which is the text the model reads security
- Tool “set_duration” rewrote its description, which is the text the model reads security
- Tool “upload_audio” rewrote its description, which is the text the model reads security
- Tool “upload_image” rewrote its description, which is the text the model reads security
- Tool “select_page” no longer declares itself destructive security
- Tool “add_color_keyframe” is now declared destructive security
- Tool “add_keyframe” is now declared destructive security
- Tool “add_keyframes” is now declared destructive security
- Tool “add_speed_keyframe” is now declared destructive security
- Tool “render_video” is now declared destructive security
- Tool “save_version” is now declared destructive security
- Server version: 1.0.353 → 1.0.359 functional
- Server version: 1.0.347 → 1.0.353 functional
- Server version: 1.0.346 → 1.0.347 functional
- Server version: 1.0.340 → 1.0.346 functional
- Server version: 1.0.339 → 1.0.340 functional
- Server version: 1.0.337 → 1.0.339 functional
- “set_duration” reworded the description of “seconds” cosmetic
- 15 Sept 26 0
We did not load change detail this far back for this component, so this day may have recorded more than is shown.
- Tool “add_audio_overlay” now declares an output schema ▲ functional
- Tool “add_caption_track” now declares an output schema ▲ functional
- Tool “add_color_keyframe” now declares an output schema ▲ functional
- Tool “add_curve” now declares an output schema ▲ functional
- Tool “add_embed_origin” now declares an output schema ▲ functional
- Tool “add_from_collection” now declares an output schema ▲ functional
- Tool “add_image_layer” now declares an output schema ▲ functional
- Tool “add_keyframe” now declares an output schema ▲ functional
- Tool “add_keyframes” now declares an output schema ▲ functional
- Tool “add_morpha_layer” now declares an output schema ▲ functional
- Tool “add_page” now declares an output schema ▲ functional
- Tool “add_shape” now declares an output schema ▲ functional
- Tool “add_speed_keyframe” now declares an output schema ▲ functional
- Tool “add_text_layer” now declares an output schema ▲ functional
- Tool “add_to_collection” now declares an output schema ▲ functional
- Tool “add_video_layer” now declares an output schema ▲ functional
- Tool “apply_preset” now declares an output schema ▲ functional
- Tool “apply_preset_stagger” now declares an output schema ▲ functional
- Tool “clip_processing_status” now declares an output schema ▲ functional
- Tool “create_anonymous_account” now declares an output schema ▲ functional
- Tool “create_project” now declares an output schema ▲ functional
- Tool “create_workspace” now declares an output schema ▲ functional
- Tool “cut_range” now declares an output schema ▲ functional
- Tool “delete_page” now declares an output schema ▲ functional
- Tool “delete_project” now declares an output schema ▲ functional
- Tool “delete_version” now declares an output schema ▲ functional
- Tool “describe_video” now declares an output schema ▲ functional
- Tool “detect_text_regions” now declares an output schema ▲ functional
- Tool “duplicate_layer” now declares an output schema ▲ functional
- Tool “duplicate_project” now declares an output schema ▲ functional
- First check of Tool coverage: 100 functional
- Server version: 1.0.335 → 1.0.337 functional
- Server version: 1.0.334 → 1.0.335 functional
- 11 Sept 26 −2
We did not load change detail this far back for this component, so this day may have recorded more than is shown.
- 10 Sept 26 +2
We did not load change detail this far back for this component, so this day may have recorded more than is shown.
Diagnostic detail from the automated scan of this channel: what the scanner observed at each step, so you can see exactly where a check passed or failed. It is informational only and never changes the trust score.
Captured 21 Sept 2026 · Probed https://morphareels.ai/mcp
TLS valid
Negotiated TLS 1.3 with TLS_AES_128_GCM_SHA256 .
| Subject | Issuer | Valid from | Valid until | Key | Signature | Serial |
|---|---|---|---|---|---|---|
| CN=morphareels.ai | CN=WE1,O=Google Trust Services,C=US | 17 Aug 2026 | 15 Nov 2026 | ECDSA 256 | ECDSA-SHA256 | 3bf1f601a759df49133489fba5c7cc0b |
| SANs: morphareels.ai, *.morphareels.ai | ||||||
| CN=WE1,O=Google Trust Services,C=US (CA) | CN=GTS Root R4,O=Google Trust Services LLC,C=US | 13 Dec 2023 | 20 Feb 2029 | ECDSA 256 | ECDSA-SHA384 | 7ff31977972c224a76155d13b6d685e3 |
| CN=GTS Root R4,O=Google Trust Services LLC,C=US (CA) | CN=GlobalSign Root CA,OU=Root CA,O=GlobalSign nv-sa,C=BE | 15 Nov 2023 | 28 Jan 2028 | ECDSA 384 | SHA256-RSA | 7fe530bf331343bedd821610493d8a1b |
Background: What to check on a remote MCP endpoint →
DNSSEC insecure
Validation of morphareels.ai. — Not signed
| Zone | DS | Keys | Algorithms | Outcome |
|---|---|---|---|---|
| . | trust_anchor | 20326, 38696 | 8, 8 | Verified |
| ai. | present | 3799 | 8 | Verified |
| morphareels.ai. | absent | Unsigned (proven) parent-signed NSEC/NSEC3 proves an unsigned delegation |
Authentication Enforced and verified
The endpoint asked for a token and published valid RFC 9728 metadata describing how to get one.
| Result | Enforced and verified |
|---|---|
| Enforced | On tool calls |
| HTTP status | 200 |
WWW-Authenticate challenge Bearer resource_metadata="https://morphareels.ai/.well-known/oauth-protected-resource"
Bearer resource_metadata="https://morphareels.ai/.well-known/oauth-protected-resource" | Header | Value |
|---|---|
| strict-transport-security | max-age=31536000; includeSubDomains |
Protected resource metadata
| Document | https://morphareels.ai/.well-known/oauth-protected-resource |
|---|---|
| Retrieved | Yes |
| Resource | https://morphareels.ai/mcp |
| Authorisation server | https://morphareels.ai |
Background: How OAuth 2.1 works in the 2026 MCP spec →
Transports 2 probes
| Transport | URL | Outcome | Status | Location |
|---|---|---|---|---|
| streamable-http | https://morphareels.ai/mcp | Verified | 200 | |
| http (plaintext) | http://morphareels.ai/mcp | HTTPS enforced | 301 | https://morphareels.ai/mcp |
The tools this component advertises to a client, with an estimated token cost for each. Expand a tool to see its parameters and schema. The per-tool counts are indicative and are not scored directly; the schema's total context footprint is one signal in Schema Quality & AI Usability. A tool's description is untrusted text the model reads on every call, which is what makes this list a security surface and not just an inventory: how tool poisoning works →
add_audio_overlay Add audio overlay ~323
Add an audio overlay (mp3/m4a/wav/ogg) scheduled at a frame-aligned start. The asset must already be uploaded (upload_audio, create_upload_link, or the editor); pass the upload's returned `filename`, and its `name` as the track's label. 30 fps; convert seconds with frames = round(s * 30). Plays in the editor preview and is mixed into the MP4 export.
| Name | Type | Req | Description |
|---|---|---|---|
| endFrame | number | – | Optional end frame; omit to play the asset's full natural length from startFrame. |
| fadeInFrames | number | – | Linear fade-in length in frames. Default 0. |
| fadeOutFrames | number | – | Linear fade-out length in frames. Default 0. |
| filename | string | yes | The stored audio filename an upload returned. |
| gain | number | – | Linear gain 0..2. Default 1. |
| name | string | – | Optional label people see on the track: pass the upload's returned `name`. |
| projectId | string | yes | Opaque project id (a v4 UUID, from list_projects/create_project). Selects which existing project this call mutates. |
| sourceLayerId | string | – | Optional video layer element id ("video.<id>") to weld this overlay to. When set, the editor renders the overlay as a waveform footer on that clip and drags it with the clip instead of showing a stan… |
| startFrame | number | yes | Frame at which the overlay starts (0-indexed, 30 fps). |
| Name | Type | Req | Description |
|---|---|---|---|
| data | object|array|string|number|boolean|null | – | The payload, shaped by the tool. |
| editorUrl | string | – | Opens this project in the editor. |
| error | string | – | Why it failed. |
| note | string | – | What to do next when not ready. |
| ok | boolean | yes | Whether the call succeeded. |
| status | string | – | For cache-backed readers: whether the answer was ready. |
No examples provided.
add_caption_track Add caption track ~411
Build a caption track from pre-timed lines (e.g. derived from transcribe_clip's word timings). mode "line-sync" (default) creates one text layer per line, each shown only during its [startFrame, endFrame) window via hold-eased opacity keyframes — the active-line karaoke read; mode "static" makes a single layer with all lines joined. `style` picks a preset look. Lines default to a lower-third band. The caption layers are always wrapped in a "captions" group so they don't clutter the layers list. Returns the created text element ids plus `groupElementId` (the captions group).
| Name | Type | Req | Description |
|---|---|---|---|
| clip_element_id | string | – | Optional "video.<id>" to WELD the caption lines to (line-sync mode). When set, each line's startFrame/endFrame are treated as its window in the clip's OWN source timeline and the on-timeline position… |
| height | number | – | Band height. Default ~16% of canvas height. |
| lines | array | yes | Caption lines in order. Each: { text, startFrame, endFrame } — frames are 0-indexed at 30fps. |
| mode | string | – | "line-sync" (default): one timed layer per line. "static": one layer with all lines. |
| projectId | string | yes | Opaque project id (a v4 UUID, from list_projects/create_project). Selects which existing project this call mutates. |
| style | string | – | Caption look preset. Default "classic". |
| width | number | – | Band width. Default ~86% of canvas width. |
| x | number | – | Caption band centre x. Default canvas centre. |
| y | number | – | Caption band centre y. Default lower third (~80% of height). |
| Name | Type | Req | Description |
|---|---|---|---|
| data | object|array|string|number|boolean|null | – | The payload, shaped by the tool. |
| editorUrl | string | – | Opens this project in the editor. |
| error | string | – | Why it failed. |
| note | string | – | What to do next when not ready. |
| ok | boolean | yes | Whether the call succeeded. |
| status | string | – | For cache-backed readers: whether the answer was ready. |
No examples provided.
add_color_keyframe Add color keyframe ~315
Add or overwrite a colour keyframe on a fill track. Targets a leaf (shapes.<id>, image.<id>, video.<id>, group.<id>). The canvas backdrop is the pinned is_background image_layer (the literal 'background.canvas' is accepted as a synonym for its element id). The value is a Fill — adjacent keyframes crossfade stop-by-stop. 30 fps; frame is 0-indexed.
| Name | Type | Req | Description |
|---|---|---|---|
| easing | string | – | Interpolation to the next keyframe. Default linear. |
| elementId | string | yes | Element id (shapes/image/video/group prefixed). The pinned is_background image_layer is the canvas backdrop; 'background.canvas' is also accepted as a synonym. |
| frame | number | yes | Frame number, 0-indexed. 30 fps so frame 30 = 1 second. |
| projectId | string | yes | Opaque project id (a v4 UUID, from list_projects/create_project). Selects which existing project this call mutates. |
| property | string | yes | Currently only 'fill' is supported. |
| value | string|object | yes | Either '#rrggbb' (promoted to solid) or a Fill object: {type:"solid",color} / {type:"linear",stops:[{pos:0..1,color}],angle?} / {type:"radial",stops:[{pos:0..1,color}],cx?,cy?,radius?}. Adjacent keyf… |
| Name | Type | Req | Description |
|---|---|---|---|
| data | object|array|string|number|boolean|null | – | The payload, shaped by the tool. |
| editorUrl | string | – | Opens this project in the editor. |
| error | string | – | Why it failed. |
| note | string | – | What to do next when not ready. |
| ok | boolean | yes | Whether the call succeeded. |
| status | string | – | For cache-backed readers: whether the answer was ready. |
No examples provided.
add_curve Add curve ~259
Draw an editable arrow / curved line — a stroked quadratic bezier with an arrowhead. Specify the two endpoints (x1,y1)→(x2,y2) in canvas pixels; `bend` pushes the midpoint perpendicular (px, 0 = straight line, positive/negative curves either way). `color` #rrggbb, `stroke_width` px, `arrow_head` none|end|both (default end). Use this for callout arrows (e.g. swooping into a link).
| Name | Type | Req | Description |
|---|---|---|---|
| arrow_head | string | – | – |
| bend | number | – | Perpendicular bow of the curve in px. 0 = straight. |
| color | string | – | Stroke colour as #rrggbb. |
| projectId | string | yes | Opaque project id (a v4 UUID, from list_projects/create_project). Selects which existing project this call mutates. |
| stroke_width | number | – | Line thickness in px. |
| x1 | number | yes | Start x (canvas px). |
| x2 | number | yes | End x (canvas px) — the arrowhead end. |
| y1 | number | yes | Start y (canvas px). |
| y2 | number | yes | End y (canvas px). |
| Name | Type | Req | Description |
|---|---|---|---|
| data | object|array|string|number|boolean|null | – | The payload, shaped by the tool. |
| editorUrl | string | – | Opens this project in the editor. |
| error | string | – | Why it failed. |
| note | string | – | What to do next when not ready. |
| ok | boolean | yes | Whether the call succeeded. |
| status | string | – | For cache-backed readers: whether the answer was ready. |
No examples provided.
add_embed_origin Add embed origin ~173
Add one hostname to the project's embed allowlist (the hostnames permitted to load the public <morpha-video> embed). Idempotent — re-adding an existing entry is a no-op. The origin is normalized to a bare lowercased hostname (scheme/port/path stripped). Morpha sends that website no request; any page on it may then load the project. Reference: https://morphareels.ai/docs/tools#addembedoriginorigin
| Name | Type | Req | Description |
|---|---|---|---|
| origin | string | yes | Hostname or URL to allow, e.g. "example.com" or "https://example.com". Normalized to a bare lowercased hostname. |
| projectId | string | yes | Opaque project id (a v4 UUID, from list_projects/create_project). Selects which existing project this call mutates. |
| Name | Type | Req | Description |
|---|---|---|---|
| data | object|array|string|number|boolean|null | – | The payload, shaped by the tool. |
| editorUrl | string | – | Opens this project in the editor. |
| error | string | – | Why it failed. |
| note | string | – | What to do next when not ready. |
| ok | boolean | yes | Whether the call succeeded. |
| status | string | – | For cache-backed readers: whether the answer was ready. |
No examples provided.
add_from_collection Add from collection ~215
Add an item from the user's Collection into a project as a self-contained COPY. Pass the destination `projectId`, plus the `sourceProjectId` + `elementId` of an item from list_collection. Copies that layer (a whole group brings its children) plus its image/clip/font bytes into the destination at fresh ids and its original canvas position — fully detached, so it is immediately yours to edit and nothing links back to the source (deleting or changing the source never affects this copy). The element must actually be in the source project's collection and you must be able to read that project. An open editor on the destination picks the copy up within a few seconds — no refresh needed. Returns { addedElementId, count }.
| Name | Type | Req | Description |
|---|---|---|---|
| elementId | string | yes | The item's element id (from list_collection) — any leaf or group.<id>. |
| projectId | string | yes | Destination project the item is copied INTO. |
| sourceProjectId | string | yes | The item's home project id (from list_collection). |
| Name | Type | Req | Description |
|---|---|---|---|
| data | object|array|string|number|boolean|null | – | The payload, shaped by the tool. |
| editorUrl | string | – | Opens this project in the editor. |
| error | string | – | Why it failed. |
| note | string | – | What to do next when not ready. |
| ok | boolean | yes | Whether the call succeeded. |
| status | string | – | For cache-backed readers: whether the answer was ready. |
No examples provided.
add_image_layer Add image layer ~388
Add an image layer. The asset must already be uploaded (the editor's drag-drop, upload_image, create_upload_link, or POST /api/upload-asset/<projectId> with the raw bytes and an X-Upload-Name header). Every upload returns { filename, name }: pass `filename` (the stored file's id) here, and `name` as the layer's label. To duplicate an existing layer, reuse its filename — the editor auto-assigns a fresh id.
| Name | Type | Req | Description |
|---|---|---|---|
| block | object | – | OPTIONAL timeline window — {start, duration} in composition frames. OMIT IT (the default) and the layer is ALWAYS PRESENT: a persistent overlay that holds for the whole composition, which is what an… |
| filename | string | yes | The stored filename an upload returned (an id such as 3f2a9c1e-….png, or an older project's own name). |
| height | number | yes | Height in px (must be > 0). |
| name | string | – | Optional label people see in the Inspector and Timeline: pass the upload's returned `name`. Without it the layer is labelled by an older project's own filename, or by kind; never by a stored id. |
| projectId | string | yes | Opaque project id (a v4 UUID, from list_projects/create_project). Selects which existing project this call mutates. |
| width | number | yes | Width in px (must be > 0). |
| x | number | yes | Centre x in 1080-wide base coords. |
| y | number | yes | Centre y in 1920-tall base coords. |
| Name | Type | Req | Description |
|---|---|---|---|
| data | object|array|string|number|boolean|null | – | The payload, shaped by the tool. |
| editorUrl | string | – | Opens this project in the editor. |
| error | string | – | Why it failed. |
| note | string | – | What to do next when not ready. |
| ok | boolean | yes | Whether the call succeeded. |
| status | string | – | For cache-backed readers: whether the answer was ready. |
No examples provided.
add_keyframe Add keyframe ~266
Add or overwrite a keyframe on a layer's animation track. For leaves (image/video/shape), x/y/rotation keyframes are ABSOLUTE canvas-space values: x and y are the layer centre's pixel position (canvas is 1080×1920), rotation is degrees. For groups, x/y keyframes are translation offsets applied around the group's frozen pivot, and rotation is the group's absolute angle. scale orbits the layer/pivot centre (1 = no change). opacity is 0..1. 30 fps. When a keyframe track is present on a property, it OVERRIDES the layer's static base value at every frame.
| Name | Type | Req | Description |
|---|---|---|---|
| easing | string | – | Interpolation to the next keyframe. Default linear. |
| elementId | string | yes | Layer id (video.<id>, image.<id>, shapes.<id>, or group.<id>). |
| frame | number | yes | Frame number, 0-indexed. 30 fps so frame 30 = 1 second. |
| projectId | string | yes | Opaque project id (a v4 UUID, from list_projects/create_project). Selects which existing project this call mutates. |
| property | string | yes | – |
| value | number | yes | Track value at this frame. |
| Name | Type | Req | Description |
|---|---|---|---|
| data | object|array|string|number|boolean|null | – | The payload, shaped by the tool. |
| editorUrl | string | – | Opens this project in the editor. |
| error | string | – | Why it failed. |
| note | string | – | What to do next when not ready. |
| ok | boolean | yes | Whether the call succeeded. |
| status | string | – | For cache-backed readers: whether the answer was ready. |
No examples provided.
add_keyframes Add keyframes ~214
Add many keyframes to ONE element's ONE property in a single call, with an optional loop mode applied in the same call. The idiomatic form when every layer in a multi-element animation gets its own track (ripple dot pulse, snowflake fall, equaliser-bar wave). Factors elementId + property out of the loop body and folds set_track_loop in. Use set_keyframes_batch instead when you need to mix elements/properties in one atomic call.
| Name | Type | Req | Description |
|---|---|---|---|
| elementId | string | yes | Layer id (video.<id>, image.<id>, shapes.<id>, text.<id>, or group.<id>). |
| keyframes | array | yes | Keyframes for this track (one or more). |
| loop | string | – | Optional extrapolation mode applied to this track in the same call. Default 'hold'. |
| projectId | string | yes | Opaque project id (a v4 UUID, from list_projects/create_project). Selects which existing project this call mutates. |
| property | string | yes | – |
| Name | Type | Req | Description |
|---|---|---|---|
| data | object|array|string|number|boolean|null | – | The payload, shaped by the tool. |
| editorUrl | string | – | Opens this project in the editor. |
| error | string | – | Why it failed. |
| note | string | – | What to do next when not ready. |
| ok | boolean | yes | Whether the call succeeded. |
| status | string | – | For cache-backed readers: whether the answer was ready. |
No examples provided.
add_morpha_layer Add morpha layer ~251
Embed another of the user's projects ("a morpha") inside this one as a version-pinned band. The source's layers are inlined into the host as a collapsible group, re-keyed to fresh ids, pinned to one immutable version of the source. Pass the source project's id as source_morpha_id (and optionally a version label); the server resolves and inlines the pinned version. Editing the band's inner layers only affects THIS video — the change is local and never propagates back to the source. To pin the band to a different saved version, re-pin it from the editor's Inspector. describe_video marks an embedded band with morpha:true + source_morpha_id so you can tell it apart from a plain group.
| Name | Type | Req | Description |
|---|---|---|---|
| projectId | string | yes | Opaque project id (a v4 UUID, from list_projects/create_project). Selects which existing project this call mutates. |
| source_morpha_id | string | yes | The id of the project to embed. Must not be this project. |
| version | string | – | Optional version label of the source to pin (e.g. "v3"). Omit to pin the source's latest saved version. |
| Name | Type | Req | Description |
|---|---|---|---|
| data | object|array|string|number|boolean|null | – | The payload, shaped by the tool. |
| editorUrl | string | – | Opens this project in the editor. |
| error | string | – | Why it failed. |
| note | string | – | What to do next when not ready. |
| ok | boolean | yes | Whether the call succeeded. |
| status | string | – | For cache-backed readers: whether the answer was ready. |
No examples provided.
add_page Add page ~236
Append a page to the project — works on any project, turning a single-page video into a multi-page one. Without duplicate_index a blank page is appended, sized to the project's canvas. With duplicate_index the page at that position is deep-copied (a fresh id is minted). There is no limit on page count. The new page becomes the active page; its index is returned. For several versions of one video (hooks, languages, a sheet's rows), make pages of one project with add_page and duplicate_index. Exporting gives one video per page, and pages have no limit. To edit the copies, select_page each one and describe_video for its element ids; to export them, use the editor's Videos option or renderVideo with page.
| Name | Type | Req | Description |
|---|---|---|---|
| duplicate_index | number | – | Optional. 0-based index of an existing page to deep-copy instead of appending a blank one. |
| name | string | – | Optional name for the new page. |
| projectId | string | yes | Opaque project id (a v4 UUID, from list_projects/create_project). Selects which existing project this call mutates. |
| Name | Type | Req | Description |
|---|---|---|---|
| data | object|array|string|number|boolean|null | – | The payload, shaped by the tool. |
| editorUrl | string | – | Opens this project in the editor. |
| error | string | – | Why it failed. |
| note | string | – | What to do next when not ready. |
| ok | boolean | yes | Whether the call succeeded. |
| status | string | – | For cache-backed readers: whether the answer was ready. |
No examples provided.
add_shape Add shape ~329
Add a shape layer. `kind` selects the primitive: rect | ellipse | triangle | star | pentagon | hexagon | arrow | heart | rounded-rect | diamond | parallelogram | trapezoid | semicircle | ring | pill | cross | heptagon | octagon | star-4 | star-6 | sparkle | burst | arrow-left | double-arrow | chevron | block-arrow-up | curve | lightning | speech-bubble | location-pin | checkmark | x-mark | shield | cloud | crescent | teardrop | banner. All are native vector shapes; never substitute an image layer for one. Default-positioned in canvas centre if x/y/w/h omitted.
| Name | Type | Req | Description |
|---|---|---|---|
| block | object | – | OPTIONAL timeline window — {start, duration} in composition frames. OMIT IT (the default) and the layer is ALWAYS PRESENT: a persistent overlay that holds for the whole composition, which is what an… |
| color | string | – | Fill colour as #rrggbb. |
| height | number | – | – |
| kind | string | yes | – |
| projectId | string | yes | Opaque project id (a v4 UUID, from list_projects/create_project). Selects which existing project this call mutates. |
| width | number | – | – |
| x | number | – | – |
| y | number | – | – |
| Name | Type | Req | Description |
|---|---|---|---|
| data | object|array|string|number|boolean|null | – | The payload, shaped by the tool. |
| editorUrl | string | – | Opens this project in the editor. |
| error | string | – | Why it failed. |
| note | string | – | What to do next when not ready. |
| ok | boolean | yes | Whether the call succeeded. |
| status | string | – | For cache-backed readers: whether the answer was ready. |
No examples provided.
add_speed_keyframe Add speed keyframe ~248
Add or overwrite a speed-ramp (time-remap) keyframe on a video layer, for a rate that CHANGES over the clip. `frame` is a PROJECT-timeline frame and must sit on the clip (at or after its timeline_start_frame); the curve itself is anchored to the clip, so moving the clip carries the ramp with it and never changes its duration. For a constant slower/faster clip use set_clip_speed instead. `rate` is the playback rate at `frame`: 1 = real-time, 0.5 = half-speed, 2 = double-speed. Range: rate in [0.1, 8]. The ramp multiplies the layer's constant speed, and the clip's timeline length is derived from the resulting curve.
| Name | Type | Req | Description |
|---|---|---|---|
| elementId | string | yes | video.<id>. |
| frame | number | yes | Project-timeline frame number. |
| projectId | string | yes | Opaque project id (a v4 UUID, from list_projects/create_project). Selects which existing project this call mutates. |
| rate | number | yes | Playback rate at this frame (1 = real-time, in [0.1, 8]). |
| Name | Type | Req | Description |
|---|---|---|---|
| data | object|array|string|number|boolean|null | – | The payload, shaped by the tool. |
| editorUrl | string | – | Opens this project in the editor. |
| error | string | – | Why it failed. |
| note | string | – | What to do next when not ready. |
| ok | boolean | yes | Whether the call succeeded. |
| status | string | – | For cache-backed readers: whether the answer was ready. |
No examples provided.
add_text_layer Add text layer ~1,163
Create a new text layer — a first-class leaf that animates, groups, and z-orders exactly like an image or shape. The renderer draws live typeset text (multi-line, auto-fit to the box). Defaults: x/y = canvas centre, width 900, height 320, font_family "Hanken Grotesk", text_size derived from existing text layers (or ~10% of canvas height). Also accepts full type styling: font_weight (100-900), font_style (italic), text_transform, letter_spacing, line_height, text_align, text_autofit ("hug" default = box shrink-wraps the text at the fixed text_size, honouring literal newlines, so it can't re-wrap between preview and export — bake your own "\n" line breaks / "wrap"=fixed size + word-wrap to the box / "fit"=auto-size to fill the box, grows and shrinks / "shrink"=legacy shrink-only), text_valign (top/middle/bottom), an outline (stroke_width + stroke_color), and text_shadow. Returns the new layer's id + element id (text.<id>).
| Name | Type | Req | Description |
|---|---|---|---|
| block | object | – | OPTIONAL timeline window — {start, duration} in composition frames. OMIT IT (the default) and the layer is ALWAYS PRESENT: a persistent overlay that holds for the whole composition, which is what an… |
| curve | number | – | Curve the text onto an arc, in degrees of total sweep. 0 = straight (default). POSITIVE = a SMILE (⌣, ends rise); NEGATIVE = an ARCH (⌒, rainbow). Clamped ±135. A tasteful smile is ~+60. Single line… |
| decorations | object|null | – | Per-character underline / strikethrough. { underline?: [{start,end}], strikethrough?: [{start,end}] } — half-open character ranges [start,end) (UTF-16 offsets) into `text`. E.g. underline the first w… |
| font_family | string | – | Google Fonts family name, e.g. "Anton". Defaults to "Hanken Grotesk". |
| font_style | string | – | Italic toggle. Default normal. |
| font_weight | number | – | Font weight 100..900 (400 regular, 700 bold, 800 black). Default 400. |
| height | number | – | Box height in px (> 0). Default 320. |
| letter_spacing | number | – | Tracking between glyphs in px; may be negative. Default 0. |
| line_height | number | – | Line height as a multiple of font size (1.2 = 120%). |
| projectId | string | yes | Opaque project id (a v4 UUID, from list_projects/create_project). Selects which existing project this call mutates. |
| stroke_color | string | – | Outline colour as #rrggbb. Defaults to white when a width is set. |
| stroke_width | number | – | Outline width in px (0 = no outline). |
| text | string | – | The text to render. Newlines are honoured as hard line breaks. |
| text_align | string | – | Horizontal alignment of each line. Default center. |
| text_autofit | string | – | How text fits its box. "hug" (default for new layers): hold text_size FIXED and DERIVE the box from the measured text plus padding, honouring the literal newlines you pass — the box shrink-wraps the… |
| text_color | string | – | Text fill colour as #rrggbb. Defaults to white. |
| text_shadow | object|null | – | Drop shadow { offsetX, offsetY, blur, color }; color is any CSS colour (rgba allowed). null clears it. |
| text_size | number | – | Font size in px. Omit to derive from existing text layers (median) or the canvas height. |
| text_transform | string | – | Case transform applied before layout. Default none. |
| text_valign | string | – | Vertical alignment of the text block within its box. "middle" (default) centres it; "bottom" pins it to the box floor so extra wrapped lines grow upward from a fixed baseline (captions use this so a… |
| width | number | – | Box width in px (> 0). Default 900. |
| x | number | – | Centre x in canvas px. Defaults to canvas centre. |
| y | number | – | Centre y in canvas px. Defaults to canvas centre. |
| Name | Type | Req | Description |
|---|---|---|---|
| data | object|array|string|number|boolean|null | – | The payload, shaped by the tool. |
| editorUrl | string | – | Opens this project in the editor. |
| error | string | – | Why it failed. |
| note | string | – | What to do next when not ready. |
| ok | boolean | yes | Whether the call succeeded. |
| status | string | – | For cache-backed readers: whether the answer was ready. |
No examples provided.
add_to_collection Add to collection ~225
Add a layer to the user's reusable Collection. Pass ANY element id — a leaf (text.<id>, image.<id>, …) or a whole group.<id> (a lower-third, logo sting, brand intro). It then appears in the user's Collection (list_collection), where they — and, if this project is in a workspace, every teammate — can drop a self-contained COPY of it into any other project (add_from_collection). Copies are IMMUTABLE: adding copies the whole subtree + its asset bytes, so editing or deleting this source never changes a copy already placed elsewhere. Works on solo projects too (a personal Collection). Give the layer a clear name first (rename_layer / rename_group) — that name is what shows in the Collection.
| Name | Type | Req | Description |
|---|---|---|---|
| elementId | string | yes | The element id to add — any leaf (text/image/video/shapes.<id>) or a group.<id>. |
| projectId | string | yes | Opaque project id (a v4 UUID, from list_projects/create_project). Selects which existing project this call mutates. |
| Name | Type | Req | Description |
|---|---|---|---|
| data | object|array|string|number|boolean|null | – | The payload, shaped by the tool. |
| editorUrl | string | – | Opens this project in the editor. |
| error | string | – | Why it failed. |
| note | string | – | What to do next when not ready. |
| ok | boolean | yes | Whether the call succeeded. |
| status | string | – | For cache-backed readers: whether the answer was ready. |
No examples provided.
add_video_layer Add video layer ~250
Add a video layer. The clip must already be uploaded (the morphareels-sdk's client.addVideo, or the editor). An upload returns { filename, name }: pass `filename` (the stored clip's id) as `clip`, and `name` as the layer's label. To duplicate an existing layer, reuse its clip filename — the editor auto-assigns a fresh id.
| Name | Type | Req | Description |
|---|---|---|---|
| clip | string | yes | The stored clip filename an upload returned (an id such as 3f2a9c1e-….mp4, or an older project's own name). |
| height | number | yes | Height in px (must be > 0). |
| name | string | – | Optional label people see in the Inspector and Timeline: pass the upload's returned `name`. |
| projectId | string | yes | Opaque project id (a v4 UUID, from list_projects/create_project). Selects which existing project this call mutates. |
| width | number | yes | Width in px (must be > 0). |
| x | number | yes | Centre x in 1080-wide base coords. |
| y | number | yes | Centre y in 1920-tall base coords. |
| Name | Type | Req | Description |
|---|---|---|---|
| data | object|array|string|number|boolean|null | – | The payload, shaped by the tool. |
| editorUrl | string | – | Opens this project in the editor. |
| error | string | – | Why it failed. |
| note | string | – | What to do next when not ready. |
| ok | boolean | yes | Whether the call succeeded. |
| status | string | – | For cache-backed readers: whether the answer was ready. |
No examples provided.
apply_preset Apply preset ~82
Apply a canned animation preset to a layer.
| Name | Type | Req | Description |
|---|---|---|---|
| elementId | string | yes | – |
| preset | string | yes | – |
| projectId | string | yes | Opaque project id (a v4 UUID, from list_projects/create_project). Selects which existing project this call mutates. |
| startFrame | number | – | Frame to anchor on. Default 0. |
| Name | Type | Req | Description |
|---|---|---|---|
| data | object|array|string|number|boolean|null | – | The payload, shaped by the tool. |
| editorUrl | string | – | Opens this project in the editor. |
| error | string | – | Why it failed. |
| note | string | – | What to do next when not ready. |
| ok | boolean | yes | Whether the call succeeded. |
| status | string | – | For cache-backed readers: whether the answer was ready. |
No examples provided.
apply_preset_stagger Apply preset stagger ~189
Apply the same preset to a LIST of layers with a per-element startFrame offset — one call instead of N apply_preset calls. For diagonal pop-in grids, sequential list reveals, ring-pulse sweeps. The startFrame for entry i is `startFrame + i * stagger`. Order the elementIds in the visual order you want the animation to cascade.
| Name | Type | Req | Description |
|---|---|---|---|
| elementIds | array | yes | Layers to animate, ordered as the cascade should fire (first id gets startFrame; each next gets +stagger frames). |
| preset | string | yes | – |
| projectId | string | yes | Opaque project id (a v4 UUID, from list_projects/create_project). Selects which existing project this call mutates. |
| stagger | number | – | Frames between successive elements. Default 1. |
| startFrame | number | – | Base frame for the first element. Default 0. |
| Name | Type | Req | Description |
|---|---|---|---|
| data | object|array|string|number|boolean|null | – | The payload, shaped by the tool. |
| editorUrl | string | – | Opens this project in the editor. |
| error | string | – | Why it failed. |
| note | string | – | What to do next when not ready. |
| ok | boolean | yes | Whether the call succeeded. |
| status | string | – | For cache-backed readers: whether the answer was ready. |
No examples provided.
clip_processing_status Clip processing status ~350
Report whether a clip — or every video clip in the project, if `clip` is omitted — has been through the browser-side video-processing pipeline: proxy build, audio split, transcription, OCR (text regions). Processing never runs on the server. The preview proxy is mandatory: every processing run builds it (client.addVideo / client.processClip / client.processProject in the morphareels-sdk npm client, which drive local Chrome), and the Morpha editor builds any missing proxy for every page's clip when the project is opened. The other steps run through the same npm client or in the editor. Returns { ok: true, data: { clips: [{ clip, processed, steps: { proxy, audio_split, transcript, text_regions } }], allProcessed } }, where each step is 'ready' | 'pending' | 'running' | 'unavailable' | 'cancelled' | 'error'. 'cancelled' is a transcript the user stopped in the editor: it stays stopped across opens, and only the editor's Re-run starts it again. audio_split stays 'pending' until the user splits the clip's audio into its own track in the editor (Inspector → Audio → Split audio) or the SDK's audio_split step runs; it never gates `processed`, and an unsplit clip plays its own sound. Use it to know whether transcribe_clip / detect_text_regions will return data, and to surface an 'unprocessed' state to the user.
| Name | Type | Req | Description |
|---|---|---|---|
| clip | string | – | Optional clip filename (video.<id>.clip). Omit to report every video clip in the project. |
| projectId | string | yes | Project the clip(s) belong to. |
| Name | Type | Req | Description |
|---|---|---|---|
| data | object|array|string|number|boolean|null | – | The payload, shaped by the tool. |
| editorUrl | string | – | Opens this project in the editor. |
| error | string | – | Why it failed. |
| note | string | – | What to do next when not ready. |
| ok | boolean | yes | Whether the call succeeded. |
| status | string | – | For cache-backed readers: whether the answer was ready. |
No examples provided.
create_project Create project ~369
Create a new project and return its server-minted id. The id is an opaque v4 UUID assigned automatically — you never choose or name it; refer to the project by its `name`. By default this mints a fresh BLANK project (empty canvas, no layers) — creation is independent from cloning. Pass `fromProjectId` ONLY when you want to clone: the new project then copies that project's JSON, uploaded assets, and uploaded clips, and — like duplicate_project — FOLLOWS THE SOURCE'S workspace by default (cloning a team project stays in that team; a blank project is personal). Pass `workspaceId` (from list_workspaces) to place it in a specific workspace instead — requires an edit-capable role there — or null to force it into the caller's personal space. If the clone source lives in a workspace you can only view, the call FAILS rather than silently making a personal copy — pass workspaceId:null for a personal copy. The user's editor session won't auto-refresh — they'll need to reload to see the new project in the picker.
| Name | Type | Req | Description |
|---|---|---|---|
| fromProjectId | string | – | Optional id of an existing project to CLONE (copies its JSON + uploaded assets + clips). Omit to create a fresh blank project. |
| name | string | – | Recommended human-readable label, shown verbatim in the editor's project picker (the only user-facing handle for the project). Omit and the picker falls back to the opaque id. |
| workspaceId | string|null | – | Where to place the project. Omit to FOLLOW THE SOURCE (a clone inherits its source's workspace; a blank project is personal). A workspace id (from list_workspaces) places it there — requires an edit-… |
| Name | Type | Req | Description |
|---|---|---|---|
| data | object | – | The project that was created, blank or cloned. |
| editorUrl | string | – | Opens this project in the editor. |
| error | string | – | Why it failed. |
| note | string | – | What to do next when not ready. |
| ok | boolean | yes | Whether the call succeeded. |
| status | string | – | For cache-backed readers: whether the answer was ready. |
No examples provided.
create_upload_link Create upload link ~332
Put a file from the caller's own disk into a project: an image (.png/.jpg/.jpeg/.gif/.webp/.svg), an audio track (.mp3/.m4a/.wav/.ogg/.aac) or a font (.woff2/.woff/.ttf/.otf). Returns { uploadUrl, filename, name, command, expiresAt, maxBytes }. Run `command` from a shell (a curl line that PUTs the file's raw bytes to uploadUrl), then pass the returned `filename` (the file's id, never shown to a person) to add_image_layer, add_audio_overlay or set_custom_font. The link takes one file, stored under the id it was minted with, for 15 minutes; a second upload in that window replaces the first. The upload is checked as an editor drag-drop is: size cap (16 MB for an image or font, 50 MB for audio), SVG safety, storage quota. A client with no shell passes a public URL to upload_image or upload_audio instead. A video clip is not taken here, because its preview proxy is built on the caller's machine: use the morphareels-sdk's client.addVideo. Reference: https://morphareels.ai/docs/tools#createuploadlinkname
| Name | Type | Req | Description |
|---|---|---|---|
| name | string | yes | The file's own name or path on disk, with its extension (e.g. hero.jpg). `command` uploads that path, people see its last segment, and the file is stored under a new id. |
| projectId | string | yes | Project the file goes into. |
| Name | Type | Req | Description |
|---|---|---|---|
| data | object | – | A link that takes one file from the caller's disk, and the command that sends it. |
| editorUrl | string | – | Opens this project in the editor. |
| error | string | – | Why it failed. |
| note | string | – | What to do next when not ready. |
| ok | boolean | yes | Whether the call succeeded. |
| status | string | – | For cache-backed readers: whether the answer was ready. |
No examples provided.
create_workspace Create workspace ~166
Create a new workspace (a shared team space) owned by the caller, and return it as { id, name, role, memberCount }. Use this when the user wants a new place to group projects — then move_project_to_workspace files projects into it, and create_project can place new ones there directly. The caller becomes its owner. Requires an account with an email (workspace membership is email-based), so a keyless identity cannot create one. Refuses with a conflict if the caller already owns a workspace with the same name, which is almost always a repeated request rather than a genuine second workspace. Refer to it by `name` when talking to the user, never the id.
| Name | Type | Req | Description |
|---|---|---|---|
| name | string | yes | Human-readable workspace name, shown verbatim in the workspace switcher. |
| Name | Type | Req | Description |
|---|---|---|---|
| data | object|array|string|number|boolean|null | – | The payload, shaped by the tool. |
| editorUrl | string | – | Opens this project in the editor. |
| error | string | – | Why it failed. |
| note | string | – | What to do next when not ready. |
| ok | boolean | yes | Whether the call succeeded. |
| status | string | – | For cache-backed readers: whether the answer was ready. |
No examples provided.
cut_range Cut range ~310
Ripple-delete a time window [startFrame, endFrame) — remove that span and pull all later content earlier by delta = endFrame - startFrame (the NLE 'ripple delete' / 'close gap'). Shifts every keyframe, colour keyframe, marker, audio overlay, loop region, and start_at through the cut (a speed ramp is anchored to its clip and rides along unchanged), and is SOURCE-AWARE for video layers: a clip that straddles the cut is trimmed, and one whose interior is removed is SPLIT into two layers. Audio overlays interior to the cut are truncated at the seam (overlays have no source-in to bridge the gap). REFUSES to cut across a video layer that carries speed-ramp keyframes — remove them, or cut outside that layer's span, first. The composition length shrinks accordingly (an authored length loses only the overlap with its visible region). Frames are 0-indexed project-timeline frames at 30 fps; endFrame is exclusive and clamped to the composition length.
| Name | Type | Req | Description |
|---|---|---|---|
| endFrame | number | yes | End frame of the window to remove (0-indexed, EXCLUSIVE). Must be > startFrame; clamped to the composition length. |
| projectId | string | yes | Opaque project id (a v4 UUID, from list_projects/create_project). Selects which existing project this call mutates. |
| startFrame | number | yes | First frame of the window to remove (0-indexed, inclusive). |
| Name | Type | Req | Description |
|---|---|---|---|
| data | object|array|string|number|boolean|null | – | The payload, shaped by the tool. |
| editorUrl | string | – | Opens this project in the editor. |
| error | string | – | Why it failed. |
| note | string | – | What to do next when not ready. |
| ok | boolean | yes | Whether the call succeeded. |
| status | string | – | For cache-backed readers: whether the answer was ready. |
No examples provided.
delete_page Delete page ~124
Remove the page at `index`. Fails on an out-of-range index or when only one page remains — a project must keep at least one page. The active page stays active; when the active page itself is deleted, active_index falls to the neighbouring page (the one that slid into its position, or the new last page).
| Name | Type | Req | Description |
|---|---|---|---|
| index | number | yes | 0-based index of the page to remove. |
| projectId | string | yes | Opaque project id (a v4 UUID, from list_projects/create_project). Selects which existing project this call mutates. |
| Name | Type | Req | Description |
|---|---|---|---|
| data | object|array|string|number|boolean|null | – | The payload, shaped by the tool. |
| editorUrl | string | – | Opens this project in the editor. |
| error | string | – | Why it failed. |
| note | string | – | What to do next when not ready. |
| ok | boolean | yes | Whether the call succeeded. |
| status | string | – | For cache-backed readers: whether the answer was ready. |
No examples provided.
delete_project Delete project ~96
Permanently delete a project: its JSON, shortlist, versions, uploaded assets, and uploaded clips. Requires edit access — the owner, a workspace editor/admin/owner, or a direct-share editor; anyone else gets the opaque not-found. Deleting the last remaining project is allowed. The user's editor session won't auto-refresh — if they were viewing the deleted project they'll need to reload.
| Name | Type | Req | Description |
|---|---|---|---|
| projectId | string | yes | Project to delete. |
| Name | Type | Req | Description |
|---|---|---|---|
| data | object|array|string|number|boolean|null | – | The payload, shaped by the tool. |
| editorUrl | string | – | Opens this project in the editor. |
| error | string | – | Why it failed. |
| note | string | – | What to do next when not ready. |
| ok | boolean | yes | Whether the call succeeded. |
| status | string | – | For cache-backed readers: whether the answer was ready. |
No examples provided.
delete_version Delete version ~119
Permanently delete one saved version (bookmark or auto-snapshot). Accepts the version's UUID `id` or the `v<N>` shorthand. The bookmark v<N> sequence keeps gaps — numbers never re-shuffle — so any external snippet referencing the deleted `v<N>` will fail to resolve afterwards. Idempotent: deleting a non-existent version is a no-op.
| Name | Type | Req | Description |
|---|---|---|---|
| projectId | string | yes | Project whose version to delete. |
| versionId | string | yes | Version to delete. UUID `id` or `v<N>` shorthand. |
| Name | Type | Req | Description |
|---|---|---|---|
| data | object|array|string|number|boolean|null | – | The payload, shaped by the tool. |
| editorUrl | string | – | Opens this project in the editor. |
| error | string | – | Why it failed. |
| note | string | – | What to do next when not ready. |
| ok | boolean | yes | Whether the call succeeded. |
| status | string | – | For cache-backed readers: whether the answer was ready. |
No examples provided.
describe_video Describe video ~270
Structural OVERVIEW of the composition (the table of contents) — canvas size, duration, platform_safe_area (the part of the canvas TikTok / Reels UI and Instagram's feed crop leave visible: keep text, captions, logos and buttons inside it; null when nothing is covered or cropped), the backdrop summary, and a z-ordered tree (top of stack first) of every layer with its elementId, type, name, type label (filename/clip/text/kind), geometry (x/y/width/height), and which properties are animated. Does NOT include keyframe values or styles — those are unbounded. On a multi-page project the tree describes the ACTIVE page and the data carries a `pages` block ({ page_count, active_index, pages: [{ index, name, has_video }] }) — content tools target that active page; use select_page to switch which page they target, add_page / delete_page / reorder_pages to manage the pages. Start here, then call inspect_layers([elementId, …]) for full detail on the specific layers you'll change. Don't guess keyframe/style values from this overview.
| Name | Type | Req | Description |
|---|---|---|---|
| projectId | string | yes | Opaque project id (a v4 UUID, from list_projects/create_project). Selects which existing project this call mutates. |
| Name | Type | Req | Description |
|---|---|---|---|
| data | object|array|string|number|boolean|null | – | The payload, shaped by the tool. |
| editorUrl | string | – | Opens this project in the editor. |
| error | string | – | Why it failed. |
| note | string | – | What to do next when not ready. |
| ok | boolean | yes | Whether the call succeeded. |
| status | string | – | For cache-backed readers: whether the answer was ready. |
No examples provided.
detect_text_regions Detect text regions ~304
Return the OCR text regions detected in a clip's video frames OR a still image asset. Pass either `clip` (a video.<id>.clip filename) or `image` (an image layer's filename) — not both. Video clips are sampled every 0.3s at upload time; images are OCR'd once. Results are cached in R2 next to the source. Returns { status: 'ready' | 'not-ready', frames: [{ frame, time, words: [{ text, x0, y0, x1, y1, confidence }] }], videoWidth, videoHeight }. For an image there's a single frame (frame 0); videoWidth/videoHeight are the image's pixel dimensions. Each `words` entry is one detected text line — `text` may hold several words, the box is axis-aligned, and `confidence` is 0–100. Coordinates are in the SOURCE pixel space (not canvas space). Use to know where titles / subtitles / lower-thirds are baked into the video or image so the Morpha title + intro graphics can be positioned to not collide.
| Name | Type | Req | Description |
|---|---|---|---|
| clip | string | – | Video clip filename (the same value as `video.<id>.clip`). Pass this OR `image`. |
| image | string | – | Image layer filename (the same value as `image.<id>.filename`). Pass this OR `clip`. |
| projectId | string | yes | Project the clip/image belongs to. |
| Name | Type | Req | Description |
|---|---|---|---|
| data | object|array|string|number|boolean|null | – | The payload, shaped by the tool. |
| editorUrl | string | – | Opens this project in the editor. |
| error | string | – | Why it failed. |
| note | string | – | What to do next when not ready. |
| ok | boolean | yes | Whether the call succeeded. |
| status | string | – | For cache-backed readers: whether the answer was ready. |
No examples provided.
duplicate_layer Duplicate layer ~262
Composition primitive: clone a leaf (image.<id> / video.<id> / shapes.<id> / text.<id>) `count` times, applying a cumulative per-step transform — copy i is offset by i·(dx,dy) px, rotated by i·d_rotation°, and scaled by d_scale^i. One call instead of dozens: a circle of stars (dx/dy + d_rotation), a row of chevrons (dx), a fractal (d_scale<1 + d_rotation), a staggered grid. Styles are copied; animate the result afterwards (e.g. group + a cycle-loop track for endless marching).
| Name | Type | Req | Description |
|---|---|---|---|
| count | number | yes | Number of copies to create. |
| d_rotation | number | – | Per-step rotation in degrees. |
| d_scale | number | – | Per-step size multiplier (1 = no change). |
| dx | number | – | Per-step x offset in px. |
| dy | number | – | Per-step y offset in px. |
| elementId | string | yes | Leaf to clone (e.g. shapes.chevron-1). |
| projectId | string | yes | Opaque project id (a v4 UUID, from list_projects/create_project). Selects which existing project this call mutates. |
| Name | Type | Req | Description |
|---|---|---|---|
| data | object|array|string|number|boolean|null | – | The payload, shaped by the tool. |
| editorUrl | string | – | Opens this project in the editor. |
| error | string | – | Why it failed. |
| note | string | – | What to do next when not ready. |
| ok | boolean | yes | Whether the call succeeded. |
| status | string | – | For cache-backed readers: whether the answer was ready. |
No examples provided.
duplicate_project Duplicate project ~408
Duplicate an existing project into a brand-new one — a full copy of its layers, animations, styles, uploaded assets, and clips. Pass the SOURCE project's `projectId`; the copy gets a fresh id automatically (ids are opaque — never shown to the user). Defaults the copy's name to "<source name> copy" unless you pass `name`. WORKSPACE: the copy FOLLOWS THE SOURCE by default — a project in a workspace is copied into that SAME workspace, and a personal project stays personal. Pass `workspaceId` to override: a workspace id (from list_workspaces) to place the copy in a specific workspace (you need an edit-capable role there), or null to force the copy into your personal space. If the source lives in a workspace you can only VIEW, the call FAILS rather than silently making a personal copy — get an editor role there, or pass workspaceId:null. (Duplicating a project shared with you from a workspace you're NOT a member of lands in personal, since you can't be placed in that workspace.) The returned `workspaceId` tells you where it went. The user's editor won't auto-refresh — they reload to see the copy in the picker. For several versions of one video (hooks, languages, a sheet's rows), make pages of one project with add_page and duplicate_index. Exporting gives one video per page, and pages have no limit.
| Name | Type | Req | Description |
|---|---|---|---|
| name | string | – | Optional name for the copy. Shown verbatim in the picker; defaults to "<source name> copy". |
| projectId | string | yes | Id of the existing project to duplicate (the source). |
| workspaceId | string|null | – | Optional override for where the copy lives. Omit to FOLLOW THE SOURCE (a workspace project stays in its workspace; a personal one stays personal). A workspace id (from list_workspaces) places the cop… |
| Name | Type | Req | Description |
|---|---|---|---|
| data | object|array|string|number|boolean|null | – | The payload, shaped by the tool. |
| editorUrl | string | – | Opens this project in the editor. |
| error | string | – | Why it failed. |
| note | string | – | What to do next when not ready. |
| ok | boolean | yes | Whether the call succeeded. |
| status | string | – | For cache-backed readers: whether the answer was ready. |
No examples provided.
fade_layer Fade layer ~101
Fade a layer's opacity between two frames in one call.
| Name | Type | Req | Description |
|---|---|---|---|
| elementId | string | yes | – |
| fromFrame | number | yes | – |
| fromOpacity | number | yes | 0..1. |
| projectId | string | yes | Opaque project id (a v4 UUID, from list_projects/create_project). Selects which existing project this call mutates. |
| toFrame | number | yes | – |
| toOpacity | number | yes | 0..1. |
| Name | Type | Req | Description |
|---|---|---|---|
| data | object|array|string|number|boolean|null | – | The payload, shaped by the tool. |
| editorUrl | string | – | Opens this project in the editor. |
| error | string | – | Why it failed. |
| note | string | – | What to do next when not ready. |
| ok | boolean | yes | Whether the call succeeded. |
| status | string | – | For cache-backed readers: whether the answer was ready. |
No examples provided.
fit_duration_to_content Fit duration to content ~154
Clear an authored composition length and return to AUTO-FIT — the comp length tracks the furthest content (keyframe / video window / audio end) again, with a 1-second floor. The inverse of set_duration. NOTE: headless (no loaded media) this can UNDER-fit when a video layer's source_out_frame is null — its natural length is unmeasurable, so it contributes only its start frame; the length self-corrects the next time the project is opened in the editor, where the real clip durations are known.
| Name | Type | Req | Description |
|---|---|---|---|
| projectId | string | yes | Opaque project id (a v4 UUID, from list_projects/create_project). Selects which existing project this call mutates. |
| Name | Type | Req | Description |
|---|---|---|---|
| data | object|array|string|number|boolean|null | – | The payload, shaped by the tool. |
| editorUrl | string | – | Opens this project in the editor. |
| error | string | – | Why it failed. |
| note | string | – | What to do next when not ready. |
| ok | boolean | yes | Whether the call succeeded. |
| status | string | – | For cache-backed readers: whether the answer was ready. |
No examples provided.
freeze_frame Freeze frame ~301
Freeze the picture at a frame: the clip is CUT there and a still of that frame is inserted between the halves, pushing everything after it later (the NLE 'frame hold'). This is how you hold a moment — play, freeze, continue. The still is an ordinary IMAGE layer showing that frame for `holdFrames` (default 150 = 5s at 30fps), so you resize, split, move or delete it like any other layer. `image` is the filename of a PNG of that frame, already uploaded to the project's assets — rendering one needs a browser, so capture and upload it first. The reply's `frozenSourceFrame` is the SOURCE frame that was frozen, which differs from `frame` on a retimed clip. `frame` must be strictly inside the clip.
| Name | Type | Req | Description |
|---|---|---|---|
| elementId | string | yes | video.<id> to freeze. |
| frame | number | yes | Project-timeline frame to freeze at — must be strictly inside the clip. |
| holdFrames | number | – | How long the still holds, in frames. Defaults to 150 (5s at 30fps), the same default every added clip gets. |
| image | string | yes | Filename of an already-uploaded PNG of the frozen frame, in the project's assets. |
| projectId | string | yes | Opaque project id (a v4 UUID, from list_projects/create_project). Selects which existing project this call mutates. |
| Name | Type | Req | Description |
|---|---|---|---|
| data | object|array|string|number|boolean|null | – | The payload, shaped by the tool. |
| editorUrl | string | – | Opens this project in the editor. |
| error | string | – | Why it failed. |
| note | string | – | What to do next when not ready. |
| ok | boolean | yes | Whether the call succeeded. |
| status | string | – | For cache-backed readers: whether the answer was ready. |
No examples provided.
group_layers Group layers ~255
Wrap sibling elements in a new group. USE THIS whenever several layers are one thing — a butterfly assembled from wings + body + antennae, an icon built from primitives, a card + its title + badge, a lower-third — and name the group what the thing is; a multi-shape object left as loose siblings is a defect the user has to clean up, and the group's name is their only handle on it. The group composes its x/y/scale/rotation/opacity onto its descendants (so one track flies/spins/fades the whole thing) and pivots rotate/scale at its (pivotX, pivotY), seeded to the centroid of its children at create time. The group's x/y track values are translation offsets applied around the pivot — groups have no static body of their own. All listed elementIds must currently share the same parent (root, or one existing group).
| Name | Type | Req | Description |
|---|---|---|---|
| elementIds | array | yes | Element ids of the elements to wrap. Must all share the same parent. |
| name | string | – | Optional human-readable label. |
| projectId | string | yes | Opaque project id (a v4 UUID, from list_projects/create_project). Selects which existing project this call mutates. |
| Name | Type | Req | Description |
|---|---|---|---|
| data | object|array|string|number|boolean|null | – | The payload, shaped by the tool. |
| editorUrl | string | – | Opens this project in the editor. |
| error | string | – | Why it failed. |
| note | string | – | What to do next when not ready. |
| ok | boolean | yes | Whether the call succeeded. |
| status | string | – | For cache-backed readers: whether the answer was ready. |
No examples provided.
inspect_layers Inspect layers ~165
Full per-element drill-in — the 'open this layer' half of the browser. Returns each named element's COMPLETE record: all of its own fields plus its animation tracks (every keyframe), colour/fill tracks, track-loop (extrapolation) modes, and style. Pass the elementIds you read from describe_video; pull detail only for the handful of layers you're about to mutate, not the whole project.
| Name | Type | Req | Description |
|---|---|---|---|
| elementIds | array | yes | Element ids to inspect (image.<id>, video.<id>, text.<id>, shapes.<id>, group.<id>). Read them from describe_video's tree. |
| projectId | string | yes | Opaque project id (a v4 UUID, from list_projects/create_project). Selects which existing project this call mutates. |
| Name | Type | Req | Description |
|---|---|---|---|
| data | object|array|string|number|boolean|null | – | The payload, shaped by the tool. |
| editorUrl | string | – | Opens this project in the editor. |
| error | string | – | Why it failed. |
| note | string | – | What to do next when not ready. |
| ok | boolean | yes | Whether the call succeeded. |
| status | string | – | For cache-backed readers: whether the answer was ready. |
No examples provided.
list_collection List collection ~152
List the user's reusable Collection — layers they added with add_to_collection (lower-thirds, logo stings, brand intros, or any single layer). Returns { items: [{ scope, workspaceId, sourceProjectId, sourceProjectName, ownerEmail, elementId, name, kind, childCount }] }. `scope` is "personal" (from the user's own solo projects) or "team" (from a workspace they belong to). Show the user each item's `name` (and its `sourceProjectName`); `sourceProjectId` + `elementId` feed add_from_collection to drop a self-contained COPY into another project. Works on a solo account (personal items always included); takes no arguments.
Input schema present but exposes no named parameters.
| Name | Type | Req | Description |
|---|---|---|---|
| data | object|array|string|number|boolean|null | – | The payload, shaped by the tool. |
| editorUrl | string | – | Opens this project in the editor. |
| error | string | – | Why it failed. |
| note | string | – | What to do next when not ready. |
| ok | boolean | yes | Whether the call succeeded. |
| status | string | – | For cache-backed readers: whether the answer was ready. |
No examples provided.
list_fonts List fonts ~256
List available font families across every source the editor knows about (Google + Bunny + Fontshare + Fontsource + Velvetyne) PLUS the project's user-uploaded custom_fonts (surfaced as source: "custom"). Use this to discover families before set_layer_text / add_text_layer when you don't know what to pick. Returns { fonts: [{family, source, weights, italics}], total, returned, sources }. Filter via `q` (case-insensitive substring on family) and/or `source`; cap with `limit` (default 50, max 1000). Picking any returned family in font_family Just Works — the editor's loader dispatches to the right CSS/FontFace endpoint by source.
| Name | Type | Req | Description |
|---|---|---|---|
| limit | number | – | Max entries to return (default 50, max 1000). |
| projectId | string | yes | Opaque project id (a v4 UUID, from list_projects/create_project). Selects which existing project this call mutates. |
| q | string | – | Case-insensitive substring filter on family name. Omit to list everything. |
| source | string | – | Restrict to one source. Omit to span every source. "custom" returns only the project's uploaded faces. |
| Name | Type | Req | Description |
|---|---|---|---|
| data | object|array|string|number|boolean|null | – | The payload, shaped by the tool. |
| editorUrl | string | – | Opens this project in the editor. |
| error | string | – | Why it failed. |
| note | string | – | What to do next when not ready. |
| ok | boolean | yes | Whether the call succeeded. |
| status | string | – | For cache-backed readers: whether the answer was ready. |
No examples provided.
list_projects List projects ~232
List projects as { id, name, editorUrl } entries. The id is what every other tool's `projectId` argument takes. `name` is the human-readable label shown in the editor's project picker ("Untitled" when no name has been set — ids are opaque and never shown to the user, so always refer to a project by its name). `editorUrl` is a tappable link that opens that project in the editor — offer it to the user (by name) when they want to look at one. By default lists the user's OWN personal projects (those not in any workspace). Pass `workspaceId` (from list_workspaces) to instead list the projects that live in that workspace — including teammates' — each with the owner's `ownerEmail`. Call this when the user asks "what projects do I have?" or hasn't named a project but you need to operate on one.
| Name | Type | Req | Description |
|---|---|---|---|
| workspaceId | string | – | Optional workspace id (from list_workspaces). When given, lists that workspace's projects instead of the caller's personal ones; requires membership. Omit for personal projects. |
| Name | Type | Req | Description |
|---|---|---|---|
| data | object | – | The caller's projects. |
| editorUrl | string | – | Opens this project in the editor. |
| error | string | – | Why it failed. |
| note | string | – | What to do next when not ready. |
| ok | boolean | yes | Whether the call succeeded. |
| status | string | – | For cache-backed readers: whether the answer was ready. |
No examples provided.
What is the Morpha MCP server?
Morpha is an MCP server listed in the public MCP registry as ai.morphareels/morpha. AI editor to build, animate & export layered short-form video projects via one tool catalog. This page covers its hosted endpoint (https://morphareels.ai/mcp).
Is the Morpha MCP server safe to use?
Morpha scores 84 out of 100 on VerifyMCP. That is a record of what we were able to check automatically, not an endorsement. The category breakdown on this page shows every signal behind the number, including the ones we could not confirm.
What tools does the Morpha MCP server expose?
Morpha exposes 98 tools: list_projects, list_workspaces, create_workspace, rename_workspace, open_project, and 93 more. Their descriptions and schemas cost roughly 24,541 tokens of context every time the server is loaded.
Does the Morpha MCP server require authentication?
Yes. Morpha asked us for credentials when we connected, so you will need to authorise it in your MCP client before it can do anything.
Is the Morpha MCP server still maintained?
Morpha is still listed as active in the MCP registry. We last reached this channel on 21 September 2026. Those dates come from our own scans of the registry and the channel itself, not from anything the publisher announced.