Skip to main content
Cue’s MCP server exposes eight tools. Each authenticates with your API key and bills exactly like the REST endpoint it wraps. Cold calls return a job_id you poll with check_job. Five are the workflows. Three are plumbing. The five workflow tools take an optional idempotency_key. On map_beats it replays the original job. On the other four it only prevents a duplicate charge on a warm call, and it does nothing at all on a cold one. See what an Idempotency-Key does.

match_music

Match licensed music to a video. Wraps POST /v1/match. Returns a ranked shortlist, each track carrying a track_id you can pass to loop_music or get_sync_points.
string
A video you have already ingested. Provide this or video_url.
string
A public video URL. This ingests only, see the note below.
integer
default:"20"
A maximum, not a count. The shortlist is planned at 10 tracks, so any value above 10 still returns at most 10. A smaller value slices the same ranked list.
string
A mood to steer the search, for example “uplifting” or “tense”.
string
A free-text brief for the vibe, for example “warm indie folk, no vocals”.
boolean
default:"false"
Embed sync points on every returned track. Cache-only, so see the note under get_sync_points.
string
Advanced. Request a specific analysis engine. Clamped to your account’s tier, so leave it unset to use your default.
video_url does not match in one step. It ingests the video and returns a video_id with a poll of /v1/videos/{video_id}, and there is no job_id in that response. Poll it with check_video_status, then call match_music again with the video_id. Passing that response to check_job gives it nothing to poll.
Example call
Result
A video_id whose analysis is not cached yet returns 202 with a job_id and a poll of /v1/match/jobs/{job_id} instead. Poll it with check_job(job_id, "match").

underscore

Match licensed music to a script. No video needed. Wraps POST /v1/underscore. Returns a ranked shortlist, each track with its title, artist, tempo, its Soundstripe song id, and a match_map showing which words pulled which sound. Synchronous, and billed flat per call. A call that comes back with no tracks bills nothing. Like every Cue tool it returns identity and analysis, not audio.
string
required
The short-form script or copy to score. Up to 7000 characters.
string
Optional platform hint (tiktok, reels, shorts, linkedin, youtube). Steers pace and genre.
string
A mood to steer the search.
string
A free-text brief for the vibe.
The shortlist is a fixed size. There is no amount parameter, because the price is flat and the work is the same either way.
Example call
Result
There is no video_id on this response. There was no video.

loop_music

Stretch a short track to cover a long video, as a downbeat-aligned, integer-bar self-loop with musical seams and fades that covers the whole clip. Wraps POST /v1/loop. Soundstripe tracks only. A video that is not long enough returns applicable: false and is not billed.
string
required
The long video to score.
string
required
A track to loop. This is the Soundstripe song id, so one from your own catalog works.
boolean
default:"false"
Also return a mix block. If the video has a voiceover, this is how to sit the music under it. Render mix.duck.envelope_points as attenuation on the music, interpolating linearly between points. voiceover: false means there is nothing to duck. Adds no charge. Full recipe on Loop, auto-mix.
The first call for a given (video_id, track_id) pair is cold. It returns {status: "processing", job_id, poll} and nothing else, and it bills the higher cold rate. Poll it with check_job(job_id, "loop"). Every later call for that same pair returns the plan directly at the low rate. A track you have already looped over one video is cold again on the next video.
Example call
Result (warm)
Over MCP the plan drops plan.options, the full copies of every alternative, because they are duplicates that would eat an agent’s context. plan.alternates carries a summary of each one instead, in the same fields as the chosen plan. REST keeps options in full. See Loop for how to read the plan and Render loops under your own license for how to turn it into audio.

get_sync_points

Where to cut. Labeled sync offsets for one track against a video, best first. Wraps POST /v1/align.
string
required
The video to align against.
string
required
A track from match_music, or a Soundstripe song id you already hold.
integer
default:"12"
How many sync points to return, up to 50. The response is a slice of one ranked list, so asking for more gives you further down the same ranking.
boolean
default:"false"
Also return the mix block, the same one loop_music returns. Adds no charge.
A cold call returns {status: "processing", job_id, poll} and bills the higher cold rate. Poll it with check_job(job_id, "align"). Warm needs either the points for that exact (video_id, track_id) pair to be cached, or both profiles Cue would score them from: the video’s sync profile and the track’s audio profile. The video’s profile is warmed in the background after ingest and that warm is best-effort, so a track you have aligned many times can still come back cold on a new video.
Example call
Result (warm)
label names the musical moment the clip opens on, and it is one of Intro, Build, Peak, Breakdown or Outro. It is "" for an ordinary mid-song moment, which is common, and null when the energy fallback produced the point rather than the beat-sync engine. It is never “Drop”, deliberately: a drop is a genre-specific event and most of the catalog does not have one, so the biggest-energy moment is called Peak in every genre. score orders this response and nothing else. Do not compare it across tracks.

map_beats

Map a track’s beats and downbeats. Send audio, get the grid. Wraps POST /v1/beats.
string
required
An https:// or s3:// URL to the audio. A presigned link from your own storage works.
string
Your own identifier, echoed back on the job so you can reconcile a batch without keeping your own job table.
number
Your catalog’s tempo, between 20 and 400. Worth a large accuracy gain when it is right. Pass it only if you trust the octave, since a value at half or double the real tempo is worse than nothing. Cue verifies it against its own reading and ignores it when the two disagree by an octave.
string
The SHA-256 of the audio bytes, 64 hex characters. When this account has already mapped those exact bytes, the job resolves from cache without fetching the file.
Example call
Always async. Returns { job_id, status: "processing", poll }. Poll with check_job(job_id, "beats"). Billed per minute of audio, once, on success. A failed job bills nothing. Over MCP a long grid is summarised to its first 400 beats, because a full one would exceed the tool-output limit and fail the call. When that happens the response sets beats_truncated: true, carries beats_total and downbeats_total, and points at GET /v1/beats/{job_id}, which returns all of it. See Map a track’s beats.

ingest_video

Add a video for reuse. Wraps POST /v1/videos. Returns a video_id. Poll check_video_status until it reads ready.
string
required
The URL to fetch. Anything Cue can GET works, including a presigned link from your own storage, so you do not have to make the file public.
Example call
Result
The call returns before a single byte is downloaded, so a source that is too large or is not a video fails later, on the video row, not here. Watch check_video_status for it.
Holding the bytes locally instead? That is the REST upload flow. POST /v1/videos with a filename for a presigned upload URL, PUT the bytes, then POST /v1/videos/{video_id}/ingest to start processing. It is not exposed over MCP on purpose, because the last step has no tool, so an agent that started it here could never finish and would poll a video that never began processing.

check_video_status

Is a video processing, ready, or failed? Wraps GET /v1/videos/{id}. Never billed.
string
required
The video to check.
Result (ready)
Result (failed)
reason is populated only on failed and is prefixed with a token you can switch on. See Errors & rate limits for the list.

check_job

Poll an async job returned by match_music, loop_music, get_sync_points or map_beats. Returns processing until it is done, then the result. The job bills once, on completion, so polling adds nothing and skipping it saves nothing.
string
required
The job_id from the tool that returned status: "processing". A bare UUID, or 32 hex characters for a beats job.
string
default:"match"
Which job: "match", "loop", "align" or "beats". Anything else is treated as "match".
Example call
Result (still running)
Result (complete)
A failed job comes back as a tool error carrying the worker’s reason, not as a status: "failed" result. Loop, sync and match jobs fail as 502. A beats job fails as 422, and so does one that was never picked up, which was not billed and can simply be resubmitted.