vivid-mcp
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| VIVID_API_KEY | Yes | Your VIVID API key. Get it from vividai.tv under Settings → API key. | |
| VIVID_API_URL | No | The VIVID API base URL. | https://vivid-api.vividoai.workers.dev |
Instructions
Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.
VIVID is an AI content studio for e-commerce (vividai.tv). This server drives the account linked to the API key. Typical flow: vivid_whoami → vivid_list_models → vivid_generate_image / vivid_generate_video → vivid_job_status → vivid_share_asset (or vivid_download_asset on the local server). Files must be public URLs (vivid_upload_file accepts a URL; the local stdio server also accepts absolute local paths). Every generation costs credits; the models list shows the price. Check credits with vivid_whoami before large batches. If credits run out, call vivid_buy_credits and show the user the link: they pay in their browser (never ask for card details), then retry the call that failed. vivid_record_ui screen-records a scripted walkthrough of vividai.tv with a local Chromium (no credits) and uploads it as a video asset for the timeline tools.
Capabilities
Features and capabilities supported by this server
Protocol revision2025-11-25
| Capability | Details |
|---|---|
| tools | {
"listChanged": true
} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| vivid_whoamiA | Return the VIVID account linked to the API key: name, email, plan and remaining credits. Call this first to check the connection. |
| vivid_buy_creditsA | Get the link where the user buys a credit pack (500 / 1,500 / 5,000 credits) and can turn on auto top-up. Use it when a call fails for lack of credits or before a big batch that the balance (vivid_whoami) will not cover. This tool never charges anything: the user picks the pack and pays in their browser. Show them the link, wait for them to confirm, then continue. |
| vivid_usageA | Monthly usage summary for the account (analyses, images, videos vs plan limits) and current credits. |
| vivid_list_modelsA | List the AI models available to this account with their cost in credits and capabilities. Use the returned |
| vivid_chatA | Run one chat completion on VIVID's LLM routing (Grok, Claude, OpenAI GPT via Kie.ai; Kimi via Wavespeed) paid in credits: provider price + 50%, billed per token (list with vivid_list_models type="llm", prices in credits per 1M tokens). Non-streaming. Pass the full conversation each call (system/user/assistant); image parts as {type:"image_url", image_url:{url}} on vision models. Returns the reply text, token usage and the credits charged. |
| vivid_generate_imageA | Generate one or more images on VIVID from a text prompt. Feature saved products and testimonials by NAME with |
| vivid_generate_videoA | Start a video generation on VIVID. Pick a model with vivid_list_models (type=video) and respect its durations / resolutions / aspect ratios. Reference images, start/end frames and audio must be public URLs (use vivid_upload_file for local files). Credits are pre-charged (credits/second × duration). Videos take 1-5 minutes: by default this returns the jobId immediately — poll with vivid_job_status. Note: a model's start/end frame and reference images can be mutually exclusive (e.g. Seedance 2.5): the backend resolves it and returns a warning. Reference videos (referenceVideoUrls) work on models whose vivid_list_models entry has |
| vivid_job_statusA | Check a generation job (image or video). For video jobs this also triggers the provider status refresh, so call it to advance a processing job. Returns status, asset id and download URL when done. |
| vivid_list_jobsA | List recent generation jobs, newest first. Filter by type (image_gen, video_ugc, product_analysis…) or status (pending, processing, completed, failed). |
| vivid_list_assetsC | Browse the account gallery: generated images/videos, uploaded products, testimonials (type: image | video | audio; category: generated | ecommerce | model | context | video …). |
| vivid_get_assetB | Metadata for one asset (type, filename, favorite/public flags, share link if public, originating job). |
| vivid_download_assetB | Download an asset (image / video) to a local directory and return the saved path. |
| vivid_share_assetA | Make an asset public and get a shareable URL (no login required), or revoke sharing — revoking breaks the link for everyone who has it. Also toggles the favorite flag. Only change sharing when the user asked to. The reply carries |
| vivid_upload_fileA | Upload a local file (absolute path) or a remote URL — image, video or audio — to VIVID's temporary storage and get a public URL to use as startFrameUrl, referenceImageUrls, objectImageUrls or audioFileUrls. Temporary files expire after 7 days; generated results are stored permanently in the gallery. |
| vivid_list_referencesA | The account's saved PRODUCTS (from product analysis: name, category, colors, material…) and TESTIMONIALS / characters (name, gender, age, look…) with their asset ids. Use the names in vivid_generate_image |
| vivid_analyze_productA | Analyze a product photo: vision analysis (name, category, colors, material, finish, style, keywords) + a clean e-commerce render, saved to the account as a PRODUCT you can then feature by name in vivid_generate_image |
| vivid_create_testimonialA | Create a reusable TESTIMONIAL on the account — a consistent person you can cast by name in vivid_generate_image |
| vivid_list_voicesA | List the text-to-speech providers and preset voices available on VIVID (Deepgram Aura-2, MiniMax HD presets, OmniVoice voice design, Gemini 3.1 Flash) with their credit cost. Use it before vivid_generate_voice. |
| vivid_generate_voiceA | Synthesize speech from text with a preset, designed or previously saved voice. This tool never clones a voice from an audio file or URL. Providers: "gemini" = Google Gemini 3.1 Flash presets like Kore/Puck/Zephyr/Charon/Aoede (1 credit/clip), "minimax" = MiniMax Speech 2.8 HD presets (ids from vivid_list_voices → minimax[]) or the id of a voice the account holder saved in the VIVID web app, with an optional emotion (1 credit/clip), "omnivoice" = voice designed from an English description (0.5), "deepgram" = Aura-2 presets (free). Saved voices can only be created in the VIVID web app, after the account holder confirms they own the voice, gives biometric consent and confirms they are 18+; this tool cannot create, import or modify a saved voice. Returns a public MP3 URL (7-day temp storage) and optionally downloads it. |
| vivid_list_projectsA | List the account projects (brand containers) — use a project id to group generations. |
| vivid_generate_musicA | Generate an original music track from a text brief (genre, mood, instruments, BPM, use). Credits are charged only when the track is ready. Providers: "suno-v6" (default, 6 credits for TWO takes of the same brief: |
| vivid_music_statusA | Get the track of a vivid_generate_music call that returned status "processing". Waits up to |
| vivid_list_music_providersA | Music generation providers with credits, capabilities (exact duration, vocals, max length) and whether each is configured on the server. |
| vivid_search_soundsA | Search the Freesound.org library for existing music, loops and sound effects (free, no credits). By default only licenses usable in commercial content are returned: CC0 (no attribution) and CC BY (credit the author — |
| vivid_transcribeA | Speech-to-text with Deepgram Nova-3 (free). Input: a VIVID asset id, a public URL, or a local audio/video file (uploaded for you). Returns JSON with |
| vivid_retouchA | Edit ONLY one object/area of an image and leave every other pixel untouched — e.g. "the ring on the left hand" → "make it a plain yellow gold band". Say WHERE with |
| vivid_compare_productA | Visual quality control: checks that the product in a generated/retouched image matches the real product photo (SKU card). Vision LLM compares shape, proportions, materials/finish, colours, stones/elements, logos, hardware — product only, background ignored. Returns match 0–1, verdict pass|review|fail, a list of differences with severity, a summary and a |
| vivid_product_sheetA | The reference sheet of a saved product is a 2×2 grid (front, two category-specific angles, worn/in use) drawn by Nano Banana 2.1 from the product photos; every panel is checked against the real photo with the same vision QC as vivid_compare_product. This tool only reads: it returns the current sheet (four panels and the grid with download links, the QC scores, or the failure message) and what a new one would cost, and waits up to |
| vivid_create_product_sheetA | The reference sheet of a saved product is a 2×2 grid (front, two category-specific angles, worn/in use) drawn by Nano Banana 2.1 from the product photos; every panel is checked against the real photo with the same vision QC as vivid_compare_product. Starts a new sheet: 13 credits, or free for the first sheet of a free account (vivid_product_sheet shows the price first, for free). One failed check is regenerated for free, a second failure refunds everything. Takes 1–3 minutes: waits up to |
| vivid_list_editor_projectsA | List the saved video-editor projects (timelines) of the account. Use the id with vivid_render_project. |
| vivid_analyze_audioA | Tempo and transient analysis of a music / voice file, computed on the VIVID server (free, cached per asset). Returns bpm, firstBeatMs, the beat grid (beats[] / downbeats[] in ms from the start of the file, constant tempo) and peaks[] — the detected hits/accents/drops ({ms, strength 0–1}). Use beats for metronomic cuts and peaks for cuts on what the ear hears (dynamic montage, "tagli sui picchi"): pass them as clip boundaries (UPDATE_CLIP startMs/durationMs) or let CUT_TO_BEAT do it (grid beats|peaks). Input: VIVID asset id, public URL or local file (uploaded for you). MP3 or WAV only. First 90 s analysed by default. |
| vivid_get_editor_projectA | Load a saved editor project and return its timeline: canvas preset, tracks, media library (assets with local ids), clips (id, track, start/duration/source offset, speed, transitions, animations), canvas objects (position/size/rotation, effects, masks) and text overlays. Use the ids in vivid_edit_timeline. Pass raw=true to get the full project JSON instead. |
| vivid_create_editor_projectA | Create a new editor project (timeline) on the account: pick a canvas preset, import media (VIVID assets, URLs or local files), optionally apply an initial batch of commands, and save. Returns the project id (use it with vivid_edit_timeline / vivid_render_project) and the timeline summary. Media added here is available to ADD_CLIP by its local id (= asset id unless localId is given). Commands are the same editing operations as the VIVID editor: [{ "type", "payload" }], one typed payload per type. Timeline: ADD_CLIP {assetId, canvasObject?{x,y,w,h,rotation,opacity,blendMode}} (places the whole asset at the first free gap of a matching track; then trim it with UPDATE_CLIP) · UPDATE_CLIP {id, startMs?, durationMs?, sourceOffsetMs?, playbackRate?, volume?, opacity?} · REMOVE_CLIP {id} · SPLIT_CLIP {clipId, splitAtMs} · DUPLICATE_CLIP {id} · DETACH_AUDIO {clipId} · ADD_TRACK {type:'visual'|'audio'} · CUT_TO_BEAT {audioClipId (an AUDIO clip id in the timeline), beatInterval (1–32: beats or peaks between cuts; 4 = one cut per bar), grid?: 'beats' (constant BPM grid, default) | 'peaks' (detected hits/accents — right for cuts "sui picchi", drops, voice, music without a steady tempo), minStrength? (grid peaks: 0–1, keep only hits ≥ it), mode?: 'redistribute' (default: re-slice all visual clips in order to fill the music) | 'snap' (only nudge existing edges), syncClips?: 'all' | [clipIds]} — the audio is analysed on the server automatically (free); to plan cuts by hand call vivid_analyze_audio and use its beats/peaks (ms) as UPDATE_CLIP boundaries. Look: SET_TRANSITION {clipId, edge:'in'|'out', type:'dissolve'|'fade-black' (visual) | 'crossfade'|'fade-in'|'fade-out' (audio), durationMs} · SET_CLIP_ANIMATION {clipId, phase:'in'|'out', type:'fade'|'slide-up'|'slide-down'|'zoom-in'|'zoom-out'|'zoom-pan'|'spin'|'blur-reveal', durationMs} · SET_CINEMATIC_LOOK {look} · SET_CANVAS_PRESET {id,label,width,height} (crop/reframe: landscape 1280x720, landscape-fhd 1920x1080, portrait 720x1280, portrait-fhd 1080x1920, square 1080x1080, social 864x1080) · UPDATE_CANVAS_OBJECT {id, x?, y?, w?, h?, rotation?, blendMode?}. Text: ADD_TEXT {text, startMs, endMs, x (0-1), y (0-1), fontFamily?, fontSize?, color?, animation?, fill?} · UPDATE_TEXT {id, ...} · REMOVE_TEXT {id}. fill = animated gradient on the glyphs: {type:'gradient', colors:['#ff6ec4','#7873f5','#4ade80','#facc15'], angle: 100, animate:'shift'|'none', speed?: periods/s (0.35)} — presets: iridescent, sunset, ocean, gold, candy (same colors as the in-app Fill picker). Subtitles (CapCut-style word-level captions): SET_SUBTITLES {cues:[{text, startMs, endMs, words?:[{word,startMs,endMs}]}] | null, templateId?:'outline-reveal'|'ugc-pop'|'karaoke-marker'|'cinematic-fade'|'neon-cyberpunk'|'playful-wiggle', position? (0 top – 100 bottom), styleOverrides?:{fontSize,color,highlightColor,…}, layout?:{x,y,scale,maxWidthPct,rotation}}. Get cues from vivid_transcribe (its cues[] carry per-word timing) on the voice/video asset; words are synthesized evenly when omitted. Keyframes & effects (v2): SET_ANIMATIONS {objectId, objectType:'canvas'|'text', animations:{x|y|scale|rotation|opacity|blur|...: {keyframes:[{t (ms), v, easing?}]}}} · SET_OBJECT_ANIMATION · ADD_EFFECT {objectId, objectType, effect:{type:'blur'|'vignette'|'colorGrade'|'grain'|'glitch'|'chromaticAberration'|'pixelate', ...}, replace?} · REMOVE_EFFECT {objectId, objectType, effectType} · SET_EFFECT_KEYFRAMES {objectId, objectType, effectType, param, keyframes:[{t (ms FROM THE CLIP START — not the timeline), v, easing? 'linear'|'easeInCubic'|'easeOutCubic'|'easeInOutCubic' (default)|'easeOutBack'|'easeOutElastic'|'easeOutBounce'|[x1,y1,x2,y2] bezier}] | null} — animates one value of an effect already on the object (ADD_EFFECT first, same batch is fine): cameraShake.intensity|speed, motionBlur.intensity, flash.intensity|decayMs, zoomBlur.amount|centerX|centerY, lightLeak.intensity|speed|hue, blur.amount, vignette.intensity|size, colorGrade.brightness|contrast|saturation|hue, grain/glitch/chromaticAberration/pixelate values. Use it for anything that changes over time (a shake that builds up, a leak that fades in). Motion & light effects (canvas objects only): {type:'motionBlur', intensity 0–1 (shutter = intensity × 2 frames; blurs the clip's OWN movement — keyframes, intro/outro, shake, beat pump — not motion inside the footage, so pair it with SET_ANIMATIONS or SET_CLIP_ANIMATION), samples? 2–32} · {type:'cameraShake', intensity 0–1 (1 = ±3% of the short side, ±2°), speed? Hz 0.5–20 (6), seed?} · {type:'flash', intensity 0–1, color? '#rrggbb' (white), everyBeats? 1–16, bpm? (used only when the project has no analysed music), decayMs? 30–2000 (150)} · {type:'zoomBlur', amount 0–1, centerX? centerY? 0–1} · {type:'lightLeak', intensity 0–1, speed? 0.1–4, hue? 0–360 (25 = warm)}. Effect recipes (one style across the edit, preferred over hand-written effects/keyframes): APPLY_EFFECT_RECIPE {recipe:'beat-flash' (flash pinned to the music's real beats — the audio is analysed on the server automatically, like CUT_TO_BEAT) | 'punch-in' (scale pop + motion blur on every cut) | 'whip' (fast slide-in from alternating sides + motion blur on every cut) | 'handheld' (subtle shake) | 'light-leak' | 'clear' (removes what recipes added), intensity? 0–1 (0.6), clipIds? (default all visual clips), everyBeats? (beat-flash), color? (beat-flash), audioClipId? (beat-flash)} — its keyframes sit on the timeline, so send it AFTER CUT_TO_BEAT or anything that moves clips. · SET_MASK {objectId, mask:{type:'rect'|'circle'|'reveal'|'clipPath'|'none', ...}} · ADD_AUDIO_REACTIVE. Speed: UPDATE_CLIP.playbackRate is constant per clip; SET_SPEED_RAMP {clipId, preset:'speed-up'|'slow-down'|'slow-mo-hit'|'punch-in'|'ease-in-out'|'none'} or {clipId, keyframes:[{t (ms from clip start on the timeline), v (rate 0.1–8)}]} gives a variable speed (linear between keyframes; the clip keeps its timeline duration unless the source runs out, then it is shortened). Ids: read them from vivid_get_editor_project or from "created" in the previous result; a batch is applied one command at a time, so a later command can use a clip created earlier in the same batch. |
| vivid_edit_timelineA | Apply editing commands to a saved editor project — clips, trims, speed and speed ramps, transitions, canvas preset (16:9 ↔ 9:16), texts (incl. animated gradient fills), word-level subtitles, masks, keyframes, audio — through the same engine as the VIVID web editor, then save it back under the same id. Optionally import media first. Returns applied/errors (plus warnings for things applied but likely not visible, e.g. motion blur on a still clip), the ids created, and the updated timeline. Render the result with vivid_render_project. Commands are the same editing operations as the VIVID editor: [{ "type", "payload" }], one typed payload per type. Timeline: ADD_CLIP {assetId, canvasObject?{x,y,w,h,rotation,opacity,blendMode}} (places the whole asset at the first free gap of a matching track; then trim it with UPDATE_CLIP) · UPDATE_CLIP {id, startMs?, durationMs?, sourceOffsetMs?, playbackRate?, volume?, opacity?} · REMOVE_CLIP {id} · SPLIT_CLIP {clipId, splitAtMs} · DUPLICATE_CLIP {id} · DETACH_AUDIO {clipId} · ADD_TRACK {type:'visual'|'audio'} · CUT_TO_BEAT {audioClipId (an AUDIO clip id in the timeline), beatInterval (1–32: beats or peaks between cuts; 4 = one cut per bar), grid?: 'beats' (constant BPM grid, default) | 'peaks' (detected hits/accents — right for cuts "sui picchi", drops, voice, music without a steady tempo), minStrength? (grid peaks: 0–1, keep only hits ≥ it), mode?: 'redistribute' (default: re-slice all visual clips in order to fill the music) | 'snap' (only nudge existing edges), syncClips?: 'all' | [clipIds]} — the audio is analysed on the server automatically (free); to plan cuts by hand call vivid_analyze_audio and use its beats/peaks (ms) as UPDATE_CLIP boundaries. Look: SET_TRANSITION {clipId, edge:'in'|'out', type:'dissolve'|'fade-black' (visual) | 'crossfade'|'fade-in'|'fade-out' (audio), durationMs} · SET_CLIP_ANIMATION {clipId, phase:'in'|'out', type:'fade'|'slide-up'|'slide-down'|'zoom-in'|'zoom-out'|'zoom-pan'|'spin'|'blur-reveal', durationMs} · SET_CINEMATIC_LOOK {look} · SET_CANVAS_PRESET {id,label,width,height} (crop/reframe: landscape 1280x720, landscape-fhd 1920x1080, portrait 720x1280, portrait-fhd 1080x1920, square 1080x1080, social 864x1080) · UPDATE_CANVAS_OBJECT {id, x?, y?, w?, h?, rotation?, blendMode?}. Text: ADD_TEXT {text, startMs, endMs, x (0-1), y (0-1), fontFamily?, fontSize?, color?, animation?, fill?} · UPDATE_TEXT {id, ...} · REMOVE_TEXT {id}. fill = animated gradient on the glyphs: {type:'gradient', colors:['#ff6ec4','#7873f5','#4ade80','#facc15'], angle: 100, animate:'shift'|'none', speed?: periods/s (0.35)} — presets: iridescent, sunset, ocean, gold, candy (same colors as the in-app Fill picker). Subtitles (CapCut-style word-level captions): SET_SUBTITLES {cues:[{text, startMs, endMs, words?:[{word,startMs,endMs}]}] | null, templateId?:'outline-reveal'|'ugc-pop'|'karaoke-marker'|'cinematic-fade'|'neon-cyberpunk'|'playful-wiggle', position? (0 top – 100 bottom), styleOverrides?:{fontSize,color,highlightColor,…}, layout?:{x,y,scale,maxWidthPct,rotation}}. Get cues from vivid_transcribe (its cues[] carry per-word timing) on the voice/video asset; words are synthesized evenly when omitted. Keyframes & effects (v2): SET_ANIMATIONS {objectId, objectType:'canvas'|'text', animations:{x|y|scale|rotation|opacity|blur|...: {keyframes:[{t (ms), v, easing?}]}}} · SET_OBJECT_ANIMATION · ADD_EFFECT {objectId, objectType, effect:{type:'blur'|'vignette'|'colorGrade'|'grain'|'glitch'|'chromaticAberration'|'pixelate', ...}, replace?} · REMOVE_EFFECT {objectId, objectType, effectType} · SET_EFFECT_KEYFRAMES {objectId, objectType, effectType, param, keyframes:[{t (ms FROM THE CLIP START — not the timeline), v, easing? 'linear'|'easeInCubic'|'easeOutCubic'|'easeInOutCubic' (default)|'easeOutBack'|'easeOutElastic'|'easeOutBounce'|[x1,y1,x2,y2] bezier}] | null} — animates one value of an effect already on the object (ADD_EFFECT first, same batch is fine): cameraShake.intensity|speed, motionBlur.intensity, flash.intensity|decayMs, zoomBlur.amount|centerX|centerY, lightLeak.intensity|speed|hue, blur.amount, vignette.intensity|size, colorGrade.brightness|contrast|saturation|hue, grain/glitch/chromaticAberration/pixelate values. Use it for anything that changes over time (a shake that builds up, a leak that fades in). Motion & light effects (canvas objects only): {type:'motionBlur', intensity 0–1 (shutter = intensity × 2 frames; blurs the clip's OWN movement — keyframes, intro/outro, shake, beat pump — not motion inside the footage, so pair it with SET_ANIMATIONS or SET_CLIP_ANIMATION), samples? 2–32} · {type:'cameraShake', intensity 0–1 (1 = ±3% of the short side, ±2°), speed? Hz 0.5–20 (6), seed?} · {type:'flash', intensity 0–1, color? '#rrggbb' (white), everyBeats? 1–16, bpm? (used only when the project has no analysed music), decayMs? 30–2000 (150)} · {type:'zoomBlur', amount 0–1, centerX? centerY? 0–1} · {type:'lightLeak', intensity 0–1, speed? 0.1–4, hue? 0–360 (25 = warm)}. Effect recipes (one style across the edit, preferred over hand-written effects/keyframes): APPLY_EFFECT_RECIPE {recipe:'beat-flash' (flash pinned to the music's real beats — the audio is analysed on the server automatically, like CUT_TO_BEAT) | 'punch-in' (scale pop + motion blur on every cut) | 'whip' (fast slide-in from alternating sides + motion blur on every cut) | 'handheld' (subtle shake) | 'light-leak' | 'clear' (removes what recipes added), intensity? 0–1 (0.6), clipIds? (default all visual clips), everyBeats? (beat-flash), color? (beat-flash), audioClipId? (beat-flash)} — its keyframes sit on the timeline, so send it AFTER CUT_TO_BEAT or anything that moves clips. · SET_MASK {objectId, mask:{type:'rect'|'circle'|'reveal'|'clipPath'|'none', ...}} · ADD_AUDIO_REACTIVE. Speed: UPDATE_CLIP.playbackRate is constant per clip; SET_SPEED_RAMP {clipId, preset:'speed-up'|'slow-down'|'slow-mo-hit'|'punch-in'|'ease-in-out'|'none'} or {clipId, keyframes:[{t (ms from clip start on the timeline), v (rate 0.1–8)}]} gives a variable speed (linear between keyframes; the clip keeps its timeline duration unless the source runs out, then it is shortened). Ids: read them from vivid_get_editor_project or from "created" in the previous result; a batch is applied one command at a time, so a later command can use a clip created earlier in the same batch. |
| vivid_render_projectA | Queue a render (MP4 export) of a saved video-editor project. VIVID renders in the browser: the job returns an |
| vivid_render_statusA | Status of a render job created with vivid_render_project: queued, rendering (with progress), completed (with the output asset and download URL) or failed. |
| vivid_record_uiA | Record a screen-capture video of vividai.tv (or any site) by driving a local Chromium with Playwright: a scripted list of steps (navigate, move, click, type, scroll, wait) is executed with a visible cursor, smooth mouse moves and click ripples, and the result is uploaded to VIVID as a video asset ready for vivid_create_editor_project / vivid_edit_timeline (pass the returned durationMs as media[].durationMs). On VIVID sites the browser is logged into the account of VIVID_API_KEY automatically (login=true), so app pages open directly; other sites never receive the session. Runs on THIS machine: needs Google Chrome (or |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
No prompts | |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
No resources | |
TDQS
Scored across 37 tools
Most tools target a clearly distinct resource plus action (generate_image vs generate_video vs generate_music vs generate_voice; analyze_product vs compare_product vs retouch), and paired read/create tools like vivid_product_sheet vs vivid_create_product_sheet are explicitly contrasted. Some overlap remains: vivid_list_references (products/testimonials) vs vivid_list_assets, and the three separate status tools (vivid_job_status, vivid_music_status, vivid_render_status) require the agent to remember which job type each one belongs to.
Nearly everything follows a vivid_verb_noun snake_case convention with a shared prefix, which makes the set predictable. Minor deviations: noun-only names (vivid_whoami, vivid_usage) and the timeline/project vocabulary split where create/get/list_editor_project sit alongside vivid_edit_timeline and vivid_render_project.
The domain is genuinely broad — multi-modal generation, asset management, product QC, a full video-editor command surface, rendering and screen recording — so 37 tools is defensible rather than bloated. Still, it sits well past the comfortable range, and several groups could be consolidated (multiple list_* and status_* tools), pushing it into heavy territory for an agent to hold in context.
Coverage is strong end-to-end: account/credits, upload→generate→inspect→download→share assets, product analysis and QC, testimonials, music/voice/TTS/transcription, timeline create/edit/render/status and UI recording. The notable gap is deletion — there is no tool to remove assets, references/products, editor projects or jobs, so cleanup paths dead-end even though creation and read paths are complete.