AINSOF API
Search AINSOF music, hear it, cut it to time, score a video with it and get the credits that travel with it. One address answers both REST and MCP.
Base URL: https://mcp.ainsof.io/
The AINSOF API searches AINSOF music and works with its music: find cues from a brief, a name or a reference recording; get a cue's versions, stems, previews and cue sheet; choose music for a video's length; score a video; and cut a cue to length.
One endpoint serves two interfaces: REST (a JSON body with an action) and MCP (JSON-RPC, for AI assistants). Each MCP tool runs the same code as its REST action; about_ainsof is the one MCP-only tool.
All audio is clean, at 192 kbps (MP3 for tracks and edits; the audio inside a scored MP4 is AAC), for auditioning and cutting. Publishing the music needs a licence.
Start here
New to the API? The Get started guide takes you from a key to your first result.
Base URL and requests
POST https://mcp.ainsof.io/
Send a JSON body. action selects the operation; when it is omitted, search runs. Responses are JSON (Content-Type: application/json), and cross-origin requests are allowed from any origin.
A GET on the base URL is not an API call: it returns 405 with a JSON-RPC error unless the client asks for HTML.
search, soundtrack, score_video, analyze_video and fit wait up to 20 seconds for their job (similar waits up to 25 seconds and answers in one go). If it has not finished, the response is 202 with error: "still_running"; send the identical request again and it continues the same job.
Authentication
No key is required. Every action and every MCP tool can be called without a key. The video actions ask a person to sign in once on ainsof.io (see Video below).
With a key, send it as a bearer token: Authorization: Bearer <your key>. Keys start with ain_. Create and manage them at https://ainsof.io/account/api-keys after signing in with Google or email: up to 5 active keys, and up to 10 new keys a day. A key is shown once, when it is created; AINSOF does not store the key itself.
What a key changes:
- Allowance. 1,000 successful requests per rolling 24 hours per key (the key's
daily_limit), instead of 300 per network address. - Counting. Usage is counted per key, so several people behind one office address do not share an allowance.
- Private work. Video renders, deliveries and edits are matched only to requests made with the same key. Anonymous identical requests share the same work.
- Video.
analyze_video,score_videoanddeliver_scoreneed a signed-in person. A key created on ainsof.io counts as one; without a key, the first video request answers401 sign_in_requiredwith a link to sign in.
An unrecognised key is refused with 401 unauthorized; a revoked key with 403 forbidden. Any Authorization header with a value is looked up as a key; to call anonymously, omit the header.
A search with a key
curl https://mcp.ainsof.io/ \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $AINSOF_API_KEY" \
-d '{"action": "search", "brief": "dark cinematic trailer tension, pulsing synths", "top_k": 2}'import os, requests
r = requests.post(
"https://mcp.ainsof.io/",
headers={"Authorization": f"Bearer {os.environ['AINSOF_API_KEY']}"},
json={
"action": "search",
"brief": "dark cinematic trailer tension, pulsing synths",
"top_k": 2
},
timeout=60,
)
print(r.json())const res = await fetch("https://mcp.ainsof.io/", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${process.env.AINSOF_API_KEY}`,
},
body: JSON.stringify({
"action": "search",
"brief": "dark cinematic trailer tension, pulsing synths",
"top_k": 2
}),
});
const data = await res.json();{
"ok": true,
"catalogue_note": "Every track in these results is an original AINSOF composition. If your brief named a commercial song or artist, these are original alternatives in that spirit — not the …",
"how_to_present": "Present each cue as: the album cover as a markdown image , then the title in bold, then album and catalogue number, composer, publisher, BPM and lengt …",
"results": [
{
"track_id": "AIN-CAT 047_007",
"title": "Tectonic Will",
"album_cover_url": "https://mcp.ainsof.io/cover/AIN-CAT_047.jpg?v=2",
"album_cover_thumb_url": "https://mcp.ainsof.io/cover/AIN-CAT_047.jpg?v=2&w=220",
"album": "Bedrock Ballistic (Raw Force Hybrid Trailer)",
"catalogue": "AIN-CAT 047",
"composers": [
{
"name": "Roman Marin",
"society": "PRS",
"ipi": "392438537",
"performance_share": "50%"
}
],
"publisher": "AINSOF (Or Chausha AINSOF)",
"style": "Hybrid Trailer",
"also": [
"Aggressive Hybrid Trailer",
"Dark Cinematic Trailer"
],
"feels": [
"Intense",
"Aggressive",
"…"
],
"length": "2:11",
"bpm": 137,
"description": "This aggressive hybrid trailer track, clocking in at 137.2 BPM, delivers an intense and foreboding sonic experience. Driven by powerful cinematic percussion, taiko drums, …",
"listen_url": "https://play.ainsof.io/#AIN-CAT_047_007",
"audio_url": "https://mcp.ainsof.io/p/AIN-CAT_047_007?raw=1",
"also_available": "7 more versions: CUT_15, CUT_30, CUT_40, CUT_60, MUSIC_BED, NO_PERCUSSION, UNDERSCORE · 5 stems"
},
"…"
],
"licensing": "… (see The licensing object)"
}Limits
| Caller | Allowance | Counted per |
|---|---|---|
| Anonymous | 300 successful requests per rolling 24 hours | network address |
| With a key | the key's daily_limit, 1,000 for keys created on ainsof.io | key |
- What counts: requests that succeed. Errors, refusals and
202 still_runningreplies do not count. MCP protocol messages (initialize,tools/list,ping, …) do not count; eachtools/callcounts as the action it runs. - Anonymous callers: opening AINSOF media links on
mcp.ainsof.io(for example anaudio_url, a rendered video or an edit) also counts against the address that opens them. - Reset: the window is rolling. Each request stops counting 24 hours after it was made; there is no fixed daily reset.
- When exceeded:
429witherror: "rate_limited". No rate-limit headers are sent. A key's limit can be raised on request.
Other limits:
| Item | Limit |
|---|---|
search results (top_k) | 25 (name lookups: see search) |
soundtrack options | 3 |
musical_description | 1000 characters |
musical_styles | 4 labels, 80 characters each |
fit seconds | 1 to 300 |
fit edits in progress | 2 per caller (key, or address when anonymous) |
feedback text fields | truncated to 4,000 characters |
Upload slot (get_upload_link) | 2 hours, one upload |
analyze_video, score_video | videos up to 15 minutes |
similar searches | 600 per hour per caller, then 429 slow_down |
| Video sign-in links | 200 new links per network address per hour |
| Keys per account | 5 active; 10 created per 24 hours |
Errors
Errors return ok: false and an error value, often with a message. Some also carry tell_the_user (guidance for AI assistants) and contact.
Most error values are snake_case codes. Some validation and lookup errors carry a plain sentence in error instead; these are listed with each action. Use the HTTP status together with error.
| Status | error | Meaning |
|---|---|---|
| 202 | still_running | The job is still running. Send the identical request again. |
| 400 | body must be JSON | The body is not valid JSON. |
| 400 | unknown action: <name> | action is not recognised. |
| 401 | unauthorized | The key is not recognised. |
| 403 | forbidden | The key has been revoked. |
| 405 | POST only | Wrong HTTP method. |
| 429 | rate_limited | The daily allowance is used up. |
| 500 | internal error | Unexpected server error. |
| 503 | engine_unavailable | The search engine, renderer or editor did not pick up the job. Nothing was done. |
Action-specific errors are listed with each action.
Unrecognised key
curl https://mcp.ainsof.io/ \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ain_000000000000000000000000" \
-d '{"action": "search", "brief": "piano"}'import os, requests
r = requests.post(
"https://mcp.ainsof.io/",
headers={"Authorization": "Bearer ain_000000000000000000000000"},
json={
"action": "search",
"brief": "piano"
},
timeout=60,
)
print(r.json())const res = await fetch("https://mcp.ainsof.io/", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer ain_000000000000000000000000",
},
body: JSON.stringify({
"action": "search",
"brief": "piano"
}),
});
const data = await res.json();{
"ok": false,
"error": "unauthorized",
"message": "That key is not recognised."
}Anonymous allowance used up
curl https://mcp.ainsof.io/ \
-H "Content-Type: application/json" \
-d '{"action": "search", "brief": "warm acoustic"}'import os, requests
r = requests.post(
"https://mcp.ainsof.io/",
json={
"action": "search",
"brief": "warm acoustic"
},
timeout=60,
)
print(r.json())const res = await fetch("https://mcp.ainsof.io/", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
"action": "search",
"brief": "warm acoustic"
}),
});
const data = await res.json();{
"ok": false,
"error": "rate_limited",
"message": "You have reached the free daily limit. It resets on a rolling 24 hours. A free key raises it to 1000 a day — create one at https://ainsof.io/account/api-keys (sign in with Google or email) — or get in touch and we will raise it further.",
"tell_the_user": "Say plainly that the daily free limit was reached and it resets within 24 hours. Do NOT say the catalogue has nothing, do NOT say the track does not exist, and do NOT go and search the web instead. Nothing was searched.",
"contact": "info@ainsof.io"
}Links in responses
Links are on AINSOF addresses, except get_upload_link.upload_url, a one-time signed address for uploading a file. Audio and file links redirect to a short-lived signed address each time they are opened; /cover/ serves the image directly, and watch, upload and download links open AINSOF pages.
| Field | Address | Opens |
|---|---|---|
listen_url | https://play.ainsof.io/#<TRACK>[/<VERSION>] | AINSOF player page for the preview. |
audio_url | https://mcp.ainsof.io/p/<TRACK>[/<VERSION>]?raw=1 | 302 to the preview MP3 (signed for 1 hour). |
album_cover_url | https://mcp.ainsof.io/cover/<ALBUM>.jpg?v=2 | The artwork (JPEG). |
album_cover_thumb_url | the same with &w=220 | Resized artwork; w accepts 64 to 1024. |
video_url (score_video) | https://mcp.ainsof.io/v/<id> | 302 to the AINSOF watch page. |
download_url (score_video) | https://mcp.ainsof.io/v/<id>/download | 302 to https://ainsof.io/download?v=<id>, which asks for a sign-in before the MP4 downloads. |
download_url (deliver_score) | https://mcp.ainsof.io/z/<id> | 302 to ainsof.io, which asks for a sign-in before the zip downloads. |
listen_url (fit) | https://mcp.ainsof.io/f/<id> | 302 to the edit (MP3). |
download_url (fit) | https://mcp.ainsof.io/f/<id>/zip | 302 to https://ainsof.io/download, which asks for sign-in before downloading. |
upload_page | https://mcp.ainsof.io/upload/<id> | 302 to the AINSOF upload page. |
video_url (get_upload_link) | https://mcp.ainsof.io/u/<id>/<name> | 404 until the upload has arrived, then 302 to the uploaded file. |
<TRACK> is the track id with spaces replaced by underscores, e.g. AIN-CAT_031_002. A file link whose file does not exist answers 404; the watch, upload and download pages redirect regardless.
Objects
Result
One cue in a search or soundtrack answer.
track_idAIN-CAT 031_002. Actions that take a track_id accept it with a space or an underscore (AIN-CAT 031_002 or AIN-CAT_031_002).titlealbum_cover_urlnull when the album code has no artwork.album_cover_thumb_urlalbumcatalogueAIN-CAT 031.composersname, society, ipi, performance_share.publisherstylealsofeelslengthm:ss; under 10 seconds, seconds with one decimal (e.g. 5.7s).bpmdescriptionlisten_urlnull when no preview could be confirmed.audio_urlnull together with listen_url.listenalso_available5 more versions: CUT_15, CUT_30, CUT_40, CUT_60, UNDERSCORE · 3 stems. Use track to get their links.Credits
Returned by track and cue_sheet.
track_idcataloguealbumtitleisrcbpmkeyduration_secpublishercomposersname, ipi, society, perf_share (performance share).album_cover_urlalbum_cover_thumb_urlThe licensing object
Attached to most answers as licensing.
statuspreview, or licensed for keys AINSOF has flagged with an existing licence.what_you_havebeyond_onlinenote and uses: uses that are agreed directly with AINSOF.contactinfo@ainsof.io.how_it_works{
"status": "preview",
"what_you_have": "You have full search across the AINSOF catalogue, and every track you download is a complete preview — the whole piece, start to finish, so you can cut to it and see whether it truly works. The preview is for auditioning; publication requires a separate licence.",
"beyond_online": {
"note": "A preview does not grant permission for publication, broadcast, advertising or other release. This connector does not sell licences or initiate a purchase; it provides discovery, auditioning and rights information.",
"uses": [
"Trailers and promos",
"Broadcast television and radio",
"Cinema and theatrical",
"Paid advertising campaigns",
"Games and apps",
"Anything exclusive, or any territory you need locked"
]
},
"contact": "info@ainsof.io",
"how_it_works": [
"Search and audition catalogue previews without purchasing anything.",
"Cue sheets identify the music and credits; they are not a licence.",
"For technical support, privacy requests or questions about an existing licence, contact info@ainsof.io."
]
}Music
Search
https://mcp.ainsof.io/Find cues from a written brief, or look one up by its title, album, album code, track id, ISRC or composer.
RESTaction: "search"MCPsearch_music
searchis also what runs whenactionis omitted.- Names are looked up, not searched. When the whole brief is a cue title, an album name (with or without its subtitle in brackets), an album code such as
AIN-CAT 031, a track id, an ISRC (any separators) or a composer's full name, the answer is that cue, that album or that writer's cues, andfound_by_namesays so. A title inside a short brief is moved to the top of an ordinary search instead. - Negatives are enforced.
no vocals,no singing,no voice,no lyrics,without vocals,instrumental onlyandnon-vocal, andnot/no/nothing/without/avoidfollowed by a style word (for exampleno electronic), remove matching cues instead of only influencing the ranking. What was enforced is listed inenforced. - Non-English briefs. A brief written mostly in a non-Latin script (more than 30% of its letters, e.g. Hebrew, Arabic, Cyrillic, Chinese, Japanese, Korean) is translated into an English search phrase before searching;
translated_from.we_searched_forshows the phrase used. Other languages are searched as written. - Composers inside a brief. When a brief also names a composer, that composer's cues among the matches are listed first and
composer_notesays how many of the results are theirs.
Request body application/json
actionsearch.briefrequiredlink is sent (see Reference search).top_kResponse 200
oktrue.resultsfound_by_nameenforced["no vocals"].constraint_notecomposer_notetranslated_fromwe_searched_for: the English phrase that was searched; tell_the_user: guidance for an AI assistant.catalogue_notehow_to_presentlicensingErrors
| Status | error | When |
|---|---|---|
| 400 | give me a brief or a reference link | Neither brief nor link was sent. |
| 400 | translate_first | A non-English brief could not be translated. Nothing was searched. |
| 503 | lookup_unavailable | The brief is a track or album identifier and the name lookup is briefly unavailable. |
| 500 | could not queue the search | The search job could not be created. |
| 202 | still_running | The search did not finish within the wait. Send the identical request again; it continues the same search. |
| 503 | engine_unavailable | The search engine did not pick up the job. Nothing was searched. |
| 503 | search_failed | The search could not run. |
Search by description
curl https://mcp.ainsof.io/ \
-H "Content-Type: application/json" \
-d '{"action": "search", "brief": "warm acoustic guitar underscore, hopeful, no vocals", "top_k": 3}'import os, requests
r = requests.post(
"https://mcp.ainsof.io/",
json={
"action": "search",
"brief": "warm acoustic guitar underscore, hopeful, no vocals",
"top_k": 3
},
timeout=60,
)
print(r.json())const res = await fetch("https://mcp.ainsof.io/", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
"action": "search",
"brief": "warm acoustic guitar underscore, hopeful, no vocals",
"top_k": 3
}),
});
const data = await res.json();{
"ok": true,
"enforced": [
"no vocals"
],
"catalogue_note": "Every track in these results is an original AINSOF composition. If your brief named a commercial song or artist, these are original alternatives in that spirit — not the named recording, and not a cover of it.",
"how_to_present": "Use only the AINSOF album artwork attached to this result or its album_cover_thumb_url. Never search for, generate or substitute artwork from Spotify, Apple Music or another artist. If it cannot be displayed, show the album title without an image. Present each cue as: the album cover as a markdown image , then the title in bold, then album and catalogue number, composer, publisher, BPM and length, then the listen link as an ordinary markdown link. The artwork reaches you twice — attached to this reply as image blocks, and as a URL on every row. Each attached cover is preceded by a line naming its album (\"Album cover — <album> · <catalogue>\"), so you always know which record a picture belongs to: show it beside the cues from that album. Covers are sent one per album, not one per cue, so several cues can share the same picture. Interfaces differ: some render the markdown image inline, some hide remote images behind a click, some show only the attachment. Write the markdown image regardless, since it costs nothing where it does not render. But never assume the customer can see it: never let the cover carry a fact the words do not. Named in text, the album survives every client. listen_url on a row opens the complete preview of that cue. Every cue here is a preview for auditioning; licensing is at the foot of this answer, and both are true of the whole list rather than of any one row. also_available on a row is an INVENTORY, not a limit: \"7 more versions: CUT_15, CUT_30, CUT_40, CUT_60, UNDERSCORE, NO_CHOIR · 8 stems\" means we hold each of those named lengths and mixes of that cue, plus eight separated stems. The version names are on the row precisely so you can answer \"do you have a 30?\" from what you already have — read them and say yes, rather than calling get_track to find out. Stems are counted rather than named, because their names are long and nobody picks a cue off a stem list. Never read a short row as a thin catalogue and never tell a customer a cue has no 30-second cut or no stems. Call get_track when you need the actual FILES — a listen link for a specific version or stem, or the full credits — not to discover which versions exist, because that is already written above. ⚠️ Do NOT build a custom audio player, HTML widget or iframe for these results. A generated player runs under a content policy that blocks our audio host, so the controls appear and nothing plays — which looks broken to the customer and is worse than a plain link that works. A markdown link plays. Use it. Never mention scores, rankings, identifiers, tokens, link expiry, iframes, content policies or anything about how the search works. If something cannot be done, say plainly what failed and offer to try again. If the brief named a commercial song or artist, open with the plain fact that AINSOF is an original catalogue and these are original alternatives in that spirit — never present a result as the named recording or a cover of it.",
"results": [
{
"track_id": "AIN-CAT 058_001",
"title": "Azahar",
"album_cover_url": "https://mcp.ainsof.io/cover/AIN-CAT_058.jpg?v=2",
"album_cover_thumb_url": "https://mcp.ainsof.io/cover/AIN-CAT_058.jpg?v=2&w=220",
"album": "Naranja Amarga (Live Spanish Guitar)",
"catalogue": "AIN-CAT 058",
"composers": [
{
"name": "Hanan Alter",
"society": "PRS",
"ipi": "1307867336",
"performance_share": "50%"
}
],
"publisher": "AINSOF (Or Chausha AINSOF)",
"style": "Spanish Acoustic Folk",
"also": [
"Spanish Guitar",
"Latin Acoustic",
"Acoustic Folk"
],
"feels": [
"Heartfelt",
"Reflective",
"Hopeful"
],
"length": "2:35",
"bpm": 128,
"description": "This warm and intimate acoustic guitar piece, performed in D minor at a flowing 127.84 BPM, offers a delicate and reflective journey. Its gentle three-beat pulse and tender melody evoke images of sun-dappled courtyards and orange blossoms, capturing quiet moments between Spain and Mexico. With an emotional peak around 139 seconds, the track is ideal for understated cultural storytelling, reflective travel, and scenes of gentle romance. The solo acoustic guitar creates a heartfelt and hopeful atmosphere, concluding its 155-second duration with a lingering sense of bittersweet beauty. It's a piece designed for quiet contemplation rather than overt sadness, perfect for adding a touch of authentic, live-recorded warmth. The track's organic feel and intimate sound make it highly versatile for emotional depth.",
"listen_url": "https://play.ainsof.io/#AIN-CAT_058_001",
"audio_url": "https://mcp.ainsof.io/p/AIN-CAT_058_001?raw=1",
"also_available": "5 more versions: CUT_15, CUT_30, CUT_40, CUT_60, UNDERSCORE · 3 stems"
},
{
"track_id": "AIN-CAT 059_006",
"title": "Farruca",
"album_cover_url": "https://mcp.ainsof.io/cover/AIN-CAT_059.jpg?v=2",
"album_cover_thumb_url": "https://mcp.ainsof.io/cover/AIN-CAT_059.jpg?v=2&w=220",
"album": "Juerga Larga (Live Flamenco)",
"catalogue": "AIN-CAT 059",
"composers": [
{
"name": "Idan Zion",
"society": "ASCAP",
"ipi": "1100892299",
"performance_share": "50%"
}
],
"publisher": "AINSOF (Or Chausha AINSOF)",
"style": "Acoustic Flamenco Farruca",
"also": [
"Farruca",
"Spanish Guitar",
"Acoustic Flamenco"
],
"feels": [
"Passionate",
"Energetic",
"Nostalgic"
],
"length": "1:45",
"bpm": 89,
"description": "This D minor Farruca, performed at 89.29 BPM, features two acoustic guitars—a lead and a rhythm—creating a gentle, intimate, and exposed soundscape without bass or percussion. Its unhurried yet energetic and passionate delivery evokes a reflective and nostalgic mood, ideal for moments of quiet contemplation or a solitary flamenco dance. The track builds to an emotional peak at 101 seconds before concluding at 102 seconds, making it perfect for understated emotional beats in film or documentary. It captures the essence of a live, acoustic Spanish guitar performance, offering a romantic and hopeful texture for various media.",
"listen_url": "https://play.ainsof.io/#AIN-CAT_059_006",
"audio_url": "https://mcp.ainsof.io/p/AIN-CAT_059_006?raw=1",
"also_available": "4 more versions: CUT_15, CUT_30, CUT_40, CUT_60 · 2 stems"
}
],
"licensing": {
"status": "preview",
"what_you_have": "You have full search across the AINSOF catalogue, and every track you download is a complete preview — the whole piece, start to finish, so you can cut to it and see whether it truly works. The preview is for auditioning; publication requires a separate licence.",
"beyond_online": {
"note": "A preview does not grant permission for publication, broadcast, advertising or other release. This connector does not sell licences or initiate a purchase; it provides discovery, auditioning and rights information.",
"uses": [
"Trailers and promos",
"Broadcast television and radio",
"Cinema and theatrical"
]
},
"contact": "info@ainsof.io",
"how_it_works": [
"Search and audition catalogue previews without purchasing anything.",
"Cue sheets identify the music and credits; they are not a licence.",
"For technical support, privacy requests or questions about an existing licence, contact info@ainsof.io."
]
}
}Look up a cue by title
curl https://mcp.ainsof.io/ \
-H "Content-Type: application/json" \
-d '{"action": "search", "brief": "Shine On Today"}'import os, requests
r = requests.post(
"https://mcp.ainsof.io/",
json={
"action": "search",
"brief": "Shine On Today"
},
timeout=60,
)
print(r.json())const res = await fetch("https://mcp.ainsof.io/", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
"action": "search",
"brief": "Shine On Today"
}),
});
const data = await res.json();{
"ok": true,
"found_by_name": "This is the cue asked for by name, from the AINSOF catalogue.",
"catalogue_note": "Every track in these results is an original AINSOF composition. If your brief named a commercial song or artist, these are original alternatives in that spirit — not the named recording, and not a cover of it.",
"how_to_present": "Use only the AINSOF album artwork attached to this result or its album_cover_thumb_url. Never search for, generate or substitute artwork from Spotify, Apple Music or another artist. If it cannot be displayed, show the album title without an image. Present each cue as: the album cover as a markdown image , then the title in bold, then album and catalogue number, composer, publisher, BPM and length, then the listen link as an ordinary markdown link. The artwork reaches you twice — attached to this reply as image blocks, and as a URL on every row. Each attached cover is preceded by a line naming its album (\"Album cover — <album> · <catalogue>\"), so you always know which record a picture belongs to: show it beside the cues from that album. Covers are sent one per album, not one per cue, so several cues can share the same picture. Interfaces differ: some render the markdown image inline, some hide remote images behind a click, some show only the attachment. Write the markdown image regardless, since it costs nothing where it does not render. But never assume the customer can see it: never let the cover carry a fact the words do not. Named in text, the album survives every client. listen_url on a row opens the complete preview of that cue. Every cue here is a preview for auditioning; licensing is at the foot of this answer, and both are true of the whole list rather than of any one row. also_available on a row is an INVENTORY, not a limit: \"7 more versions: CUT_15, CUT_30, CUT_40, CUT_60, UNDERSCORE, NO_CHOIR · 8 stems\" means we hold each of those named lengths and mixes of that cue, plus eight separated stems. The version names are on the row precisely so you can answer \"do you have a 30?\" from what you already have — read them and say yes, rather than calling get_track to find out. Stems are counted rather than named, because their names are long and nobody picks a cue off a stem list. Never read a short row as a thin catalogue and never tell a customer a cue has no 30-second cut or no stems. Call get_track when you need the actual FILES — a listen link for a specific version or stem, or the full credits — not to discover which versions exist, because that is already written above. ⚠️ Do NOT build a custom audio player, HTML widget or iframe for these results. A generated player runs under a content policy that blocks our audio host, so the controls appear and nothing plays — which looks broken to the customer and is worse than a plain link that works. A markdown link plays. Use it. Never mention scores, rankings, identifiers, tokens, link expiry, iframes, content policies or anything about how the search works. If something cannot be done, say plainly what failed and offer to try again. If the brief named a commercial song or artist, open with the plain fact that AINSOF is an original catalogue and these are original alternatives in that spirit — never present a result as the named recording or a cover of it.",
"results": [
{
"track_id": "AIN-CAT 031_002",
"title": "Shine On Today",
"album_cover_url": "https://mcp.ainsof.io/cover/AIN-CAT_031.jpg?v=2",
"album_cover_thumb_url": "https://mcp.ainsof.io/cover/AIN-CAT_031.jpg?v=2&w=220",
"album": "Shining Ahead (Corporate Advertising)",
"catalogue": "AIN-CAT 031",
"composers": [
{
"name": "Alon Peretz",
"society": "PRS",
"ipi": "687184598",
"performance_share": "50%"
}
],
"publisher": "AINSOF (Or Chausha AINSOF)",
"style": "Advertising Pop",
"also": [
"Acoustic Pop",
"Folk Pop",
"Indie Pop"
],
"feels": [
"Uplifting",
"Optimistic",
"Carefree"
],
"length": "2:31",
"bpm": 84,
"description": "This uplifting and sunny D major track, flowing at 83.96 BPM, radiates lighthearted optimism and positive energy. Featuring a bright blend of acoustic guitar, keys, bass, drums, percussion, and playful whistles, it creates an effortlessly cheerful and organic soundscape. The addition of tuba, synth, FX, and subtle vocals adds texture to its feelgood, indie pop character. Ideal for capturing moments of joy and carefree adventure, this track is perfect for a wide range of visual content. It evokes scenes of bright mornings and happy family gatherings, making it a versatile choice for positive storytelling.",
"listen_url": "https://play.ainsof.io/#AIN-CAT_031_002",
"audio_url": "https://mcp.ainsof.io/p/AIN-CAT_031_002?raw=1",
"also_available": "7 more versions: CUT_15, CUT_30, CUT_40, CUT_60, NO_MELODY, NO_PERCUSSION, NO_VOCAL · 11 stems"
}
],
"licensing": {
"status": "preview",
"what_you_have": "You have full search across the AINSOF catalogue, and every track you download is a complete preview — the whole piece, start to finish, so you can cut to it and see whether it truly works. The preview is for auditioning; publication requires a separate licence.",
"beyond_online": {
"note": "A preview does not grant permission for publication, broadcast, advertising or other release. This connector does not sell licences or initiate a purchase; it provides discovery, auditioning and rights information.",
"uses": [
"Trailers and promos",
"Broadcast television and radio",
"Cinema and theatrical"
]
},
"contact": "info@ainsof.io",
"how_it_works": [
"Search and audition catalogue previews without purchasing anything.",
"Cue sheets identify the music and credits; they are not a licence.",
"For technical support, privacy requests or questions about an existing licence, contact info@ainsof.io."
]
}
}A non-English brief
curl https://mcp.ainsof.io/ \
-H "Content-Type: application/json" \
-d '{"action": "search", "brief": "מוזיקה עצובה לפסנתר", "top_k": 2}'import os, requests
r = requests.post(
"https://mcp.ainsof.io/",
json={
"action": "search",
"brief": "מוזיקה עצובה לפסנתר",
"top_k": 2
},
timeout=60,
)
print(r.json())const res = await fetch("https://mcp.ainsof.io/", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
"action": "search",
"brief": "מוזיקה עצובה לפסנתר",
"top_k": 2
}),
});
const data = await res.json();{
"ok": true,
"translated_from": {
"we_searched_for": "Sad piano music.",
"tell_the_user": "Their brief was rewritten into English before searching, because the catalogue matcher reads English only. Answer them in their own language, and show them this English phrase so they can correct it if it missed what they meant."
},
"catalogue_note": "Every track in these results is an original AINSOF composition. If your brief named a commercial song or artist, these are original alternatives in that spirit — not the named recording, and not a cover of it.",
"how_to_present": "Use only the AINSOF album artwork attached to this result or its album_cover_thumb_url. Never search for, generate or substitute artwork from Spotify, Apple Music or another artist. If it cannot be displayed, show the album title without an image. Present each cue as: the album cover as a markdown image , then the title in bold, then album and catalogue number, composer, publisher, BPM and length, then the listen link as an ordinary markdown link. The artwork reaches you twice — attached to this reply as image blocks, and as a URL on every row. Each attached cover is preceded by a line naming its album (\"Album cover — <album> · <catalogue>\"), so you always know which record a picture belongs to: show it beside the cues from that album. Covers are sent one per album, not one per cue, so several cues can share the same picture. Interfaces differ: some render the markdown image inline, some hide remote images behind a click, some show only the attachment. Write the markdown image regardless, since it costs nothing where it does not render. But never assume the customer can see it: never let the cover carry a fact the words do not. Named in text, the album survives every client. listen_url on a row opens the complete preview of that cue. Every cue here is a preview for auditioning; licensing is at the foot of this answer, and both are true of the whole list rather than of any one row. also_available on a row is an INVENTORY, not a limit: \"7 more versions: CUT_15, CUT_30, CUT_40, CUT_60, UNDERSCORE, NO_CHOIR · 8 stems\" means we hold each of those named lengths and mixes of that cue, plus eight separated stems. The version names are on the row precisely so you can answer \"do you have a 30?\" from what you already have — read them and say yes, rather than calling get_track to find out. Stems are counted rather than named, because their names are long and nobody picks a cue off a stem list. Never read a short row as a thin catalogue and never tell a customer a cue has no 30-second cut or no stems. Call get_track when you need the actual FILES — a listen link for a specific version or stem, or the full credits — not to discover which versions exist, because that is already written above. ⚠️ Do NOT build a custom audio player, HTML widget or iframe for these results. A generated player runs under a content policy that blocks our audio host, so the controls appear and nothing plays — which looks broken to the customer and is worse than a plain link that works. A markdown link plays. Use it. Never mention scores, rankings, identifiers, tokens, link expiry, iframes, content policies or anything about how the search works. If something cannot be done, say plainly what failed and offer to try again. If the brief named a commercial song or artist, open with the plain fact that AINSOF is an original catalogue and these are original alternatives in that spirit — never present a result as the named recording or a cover of it.",
"results": [
{
"track_id": "AIN-CAT 065_004",
"title": "Rooms Grow Colder",
"album_cover_url": "https://mcp.ainsof.io/cover/AIN-CAT_065.jpg?v=2",
"album_cover_thumb_url": "https://mcp.ainsof.io/cover/AIN-CAT_065.jpg?v=2&w=220",
"album": "Under Everything (Melodic Emotional Keys)",
"catalogue": "AIN-CAT 065",
"composers": [
{
"name": "Or Chausha",
"society": "PRS",
"ipi": "640537754",
"performance_share": "25%"
},
{
"name": "Itai Haim Lahav",
"society": "PRS",
"ipi": "1354269637",
"performance_share": "25%"
}
],
"publisher": "AINSOF (Or Chausha AINSOF)",
"style": "Melancholic Cinematic Piano Underscore",
"also": [
"Sad Piano",
"Emotional Underscore",
"Cinematic Drama"
],
"feels": [
"Melancholic",
"Sorrowful",
"Reflective"
],
"length": "2:54",
"bpm": 115,
"description": "A deeply melancholic and intimate piano underscore, 'Rooms Grow Colder' evokes a profound sense of loss and quiet reflection. Delicate piano melodies, supported by warm pads, subtle keys, and ethereal synth textures, weave a sorrowful narrative in A minor at 115 BPM. The track maintains a restrained, vulnerable energy, building gently towards a poignant emotional peak near its conclusion at 160 seconds. It is a heartfelt journey through bittersweet memories and the tender process of saying goodbye, perfect for moments of quiet contemplation and emotional storytelling. The overall mood is dreamy and reflective, offering solace in its delicate beauty. This instrumental piece is designed to underscore profound personal moments and cinematic drama.",
"listen_url": "https://play.ainsof.io/#AIN-CAT_065_004",
"audio_url": "https://mcp.ainsof.io/p/AIN-CAT_065_004?raw=1",
"also_available": "7 more versions: CUT_15, CUT_30, CUT_40, CUT_60, NO_DRUM, NO_PIANO_KEY, UNDERSCORE · 8 stems"
},
{
"track_id": "AIN-CAT 065_007",
"title": "Nothing to Fix",
"album_cover_url": "https://mcp.ainsof.io/cover/AIN-CAT_065.jpg?v=2",
"album_cover_thumb_url": "https://mcp.ainsof.io/cover/AIN-CAT_065.jpg?v=2&w=220",
"album": "Under Everything (Melodic Emotional Keys)",
"catalogue": "AIN-CAT 065",
"composers": [
{
"name": "Or Chausha",
"society": "PRS",
"ipi": "640537754",
"performance_share": "25%"
},
{
"name": "Itai Haim Lahav",
"society": "PRS",
"ipi": "1354269637",
"performance_share": "25%"
}
],
"publisher": "AINSOF (Or Chausha AINSOF)",
"style": "Cinematic Emotional Underscore",
"also": [
"Sad Piano",
"Melodic Underscore",
"Ambient Cinematic"
],
"feels": [
"Melancholic",
"Dreamy",
"Reflective"
],
"length": "2:46",
"bpm": 90,
"description": "This melodic and intimate emotional cue, set at a gentle 90 BPM in C minor, is led by expressive Keys, soft Pads, and delicate Percussion, creating a reflective atmosphere. The 166-second track, featuring Bells, Synth Textures, Guitar, and FX Keys, builds to an emotional peak at 142 seconds before a tender fade at 164 seconds. It evokes a dreamy, melancholic, and reflective mood, perfect for personal, vulnerable, and quietly dramatic moments. Ideal for cinematic underscore in dramas or documentaries, it provides a tender backdrop for storytelling about loss, quiet hope, or new beginnings. This piece is suited for moments of introspection, gentle farewells, or the warmth of childhood memories. Its subtle drama and heartfelt sentiment make it perfect for emotional storytelling in film, TV, and social media.",
"listen_url": "https://play.ainsof.io/#AIN-CAT_065_007",
"audio_url": "https://mcp.ainsof.io/p/AIN-CAT_065_007?raw=1",
"also_available": "7 more versions: CUT_15, CUT_30, CUT_40, CUT_60, NO_DRUM, NO_PIANO_KEY, UNDERSCORE · 7 stems"
}
],
"licensing": {
"status": "preview",
"what_you_have": "You have full search across the AINSOF catalogue, and every track you download is a complete preview — the whole piece, start to finish, so you can cut to it and see whether it truly works. The preview is for auditioning; publication requires a separate licence.",
"beyond_online": {
"note": "A preview does not grant permission for publication, broadcast, advertising or other release. This connector does not sell licences or initiate a purchase; it provides discovery, auditioning and rights information.",
"uses": [
"Trailers and promos",
"Broadcast television and radio",
"Cinema and theatrical"
]
},
"contact": "info@ainsof.io",
"how_it_works": [
"Search and audition catalogue previews without purchasing anything.",
"Cue sheets identify the music and credits; they are not a licence.",
"For technical support, privacy requests or questions about an existing licence, contact info@ainsof.io."
]
}
}Search by reference
https://mcp.ainsof.io/Find AINSOF cues that sound like a reference recording, given a link or an artist and title.
RESTaction: "search"MCPsearch_by_reference
- Same action as
search, withlinkinstead ofbrief. If both are sent, the search runs onlink. - Accepted references: a YouTube, Spotify, Apple Music or Deezer link, or
artist - title. SoundCloud and TikTok links are not supported; send the artist and title instead. - Results are ranked candidates, not verified sound-alikes;
reference_match.similarity_verifiedis alwaysfalse. - The first reply may be
202 still_running; send the identical request again to continue the same search. - A link that cannot be resolved fails with
503 search_failed. Sending the same link again will not help; sendartist - titleinstead.
Request body application/json
actionrequiredsearch.linkrequiredartist - title.musical_descriptionsearch. Translated when written in a non-Latin script.musical_stylesdisco, funk). Results are restricted to cues whose style tags match at least one label.top_kResponse 200
oktrue.resultsheardartist — title.reference_match.methodreference_only, reference_and_musical_context or reference_and_catalogue_styles.reference_match.context_retrievalnot_requested, candidates_found or no_embedding_candidates.reference_match.context_sourcecaller_supplied_not_independently_verified.reference_match.musical_descriptionreference_match.translated_fromreference_match.reference_sourcemetadata_only or audio_or_catalogue.reference_match.similarity_verifiedfalse.reference_match.style_matchingrequested, unsupported_after_constraints, unavailable_in_verified_shortlist, returned, note, and matches (per cue: the requested style and the style tag it matched).reference_match.notecatalogue_note, how_to_present, licensingsearch.Errors
| Status | error | When |
|---|---|---|
| 400 | invalid_musical_styles | musical_styles is not an array of up to 4 valid labels. |
| 400 | invalid_musical_description | musical_description is not text or is longer than 1000 characters. |
| 503 | reference_context_translation_unavailable | The musical description could not be translated. |
| 503 | reference_context_unavailable | The musical-context search failed. |
| 503 | reference_style_catalogue_unavailable | Library style data could not be loaded completely. |
| 202 / 500 / 503 | still_running, could not queue the search, engine_unavailable, search_failed | As in search. |
Reference by artist and title
curl https://mcp.ainsof.io/ \
-H "Content-Type: application/json" \
-d '{"action": "search", "link": "Hans Zimmer - Time", "top_k": 3}'import os, requests
r = requests.post(
"https://mcp.ainsof.io/",
json={
"action": "search",
"link": "Hans Zimmer - Time",
"top_k": 3
},
timeout=60,
)
print(r.json())const res = await fetch("https://mcp.ainsof.io/", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
"action": "search",
"link": "Hans Zimmer - Time",
"top_k": 3
}),
});
const data = await res.json();{
"ok": true,
"heard": "Hans Zimmer — Time",
"reference_match": {
"method": "reference_only",
"context_retrieval": "not_requested",
"reference_source": "audio_or_catalogue",
"similarity_verified": false,
"note": "These are ranked catalogue candidates, not verified sound-alikes. No musical description was supplied. Add the reference's known style, groove and instruments to refine the search; do not invent them."
},
"catalogue_note": "Every track in these results is an original AINSOF composition. If your brief named a commercial song or artist, these are original alternatives in that spirit — not the named recording, and not a cover of it.",
"how_to_present": "Use only the AINSOF album artwork attached to this result or its album_cover_thumb_url. Never search for, generate or substitute artwork from Spotify, Apple Music or another artist. If it cannot be displayed, show the album title without an image. Present each cue as: the album cover as a markdown image , then the title in bold, then album and catalogue number, composer, publisher, BPM and length, then the listen link as an ordinary markdown link. The artwork reaches you twice — attached to this reply as image blocks, and as a URL on every row. Each attached cover is preceded by a line naming its album (\"Album cover — <album> · <catalogue>\"), so you always know which record a picture belongs to: show it beside the cues from that album. Covers are sent one per album, not one per cue, so several cues can share the same picture. Interfaces differ: some render the markdown image inline, some hide remote images behind a click, some show only the attachment. Write the markdown image regardless, since it costs nothing where it does not render. But never assume the customer can see it: never let the cover carry a fact the words do not. Named in text, the album survives every client. listen_url on a row opens the complete preview of that cue. Every cue here is a preview for auditioning; licensing is at the foot of this answer, and both are true of the whole list rather than of any one row. also_available on a row is an INVENTORY, not a limit: \"7 more versions: CUT_15, CUT_30, CUT_40, CUT_60, UNDERSCORE, NO_CHOIR · 8 stems\" means we hold each of those named lengths and mixes of that cue, plus eight separated stems. The version names are on the row precisely so you can answer \"do you have a 30?\" from what you already have — read them and say yes, rather than calling get_track to find out. Stems are counted rather than named, because their names are long and nobody picks a cue off a stem list. Never read a short row as a thin catalogue and never tell a customer a cue has no 30-second cut or no stems. Call get_track when you need the actual FILES — a listen link for a specific version or stem, or the full credits — not to discover which versions exist, because that is already written above. ⚠️ Do NOT build a custom audio player, HTML widget or iframe for these results. A generated player runs under a content policy that blocks our audio host, so the controls appear and nothing plays — which looks broken to the customer and is worse than a plain link that works. A markdown link plays. Use it. Never mention scores, rankings, identifiers, tokens, link expiry, iframes, content policies or anything about how the search works. If something cannot be done, say plainly what failed and offer to try again. If the brief named a commercial song or artist, open with the plain fact that AINSOF is an original catalogue and these are original alternatives in that spirit — never present a result as the named recording or a cover of it.",
"results": [
{
"track_id": "AIN-CAT 041_004",
"title": "Prime Ascension",
"album_cover_url": "https://mcp.ainsof.io/cover/AIN-CAT_041.jpg?v=2",
"album_cover_thumb_url": "https://mcp.ainsof.io/cover/AIN-CAT_041.jpg?v=2&w=220",
"album": "Heroic Dominion (Orchestral Kinetic Heroics)",
"catalogue": "AIN-CAT 041",
"composers": [
{
"name": "Alexander Okunev",
"society": "PRS",
"ipi": "499092207",
"performance_share": "50%"
}
],
"publisher": "AINSOF (Or Chausha AINSOF)",
"style": "Cinematic Hybrid Orchestral",
"also": [
"Superhero Score",
"Trailer Music",
"Action Adventure Score"
],
"feels": [
"Heroic",
"Triumphant",
"Empowering"
],
"length": "2:39",
"bpm": 125,
"description": "This cinematic hybrid orchestral score, set at a driving 125 BPM in F minor, embodies a noble hero's journey from challenge to ultimate triumph. Featuring expressive piano, soaring legato strings, proud brass melodies, and an epic choir, it builds with powerful percussion and taiko to a grand, triumphant climax at 148 seconds. The track's intense and uplifting energy, punctuated by impactful hits, braams, and whooshes, perfectly underscores moments of heroic transformation and ascending power. With its blend of orchestral and synth elements, including synth bass and synth brass, it creates a modern, monumental soundscape. This is the sound of victory and determination, designed to inspire and elevate. It is ideal for blockbuster trailers and climactic scenes, creating a truly epic and empowering atmosphere.",
"listen_url": "https://play.ainsof.io/#AIN-CAT_041_004",
"audio_url": "https://mcp.ainsof.io/p/AIN-CAT_041_004?raw=1",
"also_available": "7 more versions: CUT_15, CUT_30, CUT_40, CUT_60, NO_CHOIR, NO_PERCUSSION, UNDERSCORE · 14 stems"
},
{
"track_id": "AIN-CAT 005_008",
"title": "Battleforged Awakening",
"album_cover_url": "https://mcp.ainsof.io/cover/AIN-CAT_005.jpg?v=2",
"album_cover_thumb_url": "https://mcp.ainsof.io/cover/AIN-CAT_005.jpg?v=2&w=220",
"album": "Veil Of Wonders (Symphonic Mystery Adventure)",
"catalogue": "AIN-CAT 005",
"composers": [
{
"name": "Alexander Okunev",
"society": "PRS",
"ipi": "499092207",
"performance_share": "50%"
}
],
"publisher": "AINSOF (Or Chausha AINSOF)",
"style": "Epic Cinematic Fantasy Orchestral",
"also": [
"Orchestral Adventure",
"Fantasy Score",
"Trailer Music"
],
"feels": [
"Epic",
"Magical",
"Adventurous"
],
"length": "3:00",
"bpm": 131,
"description": "This epic cinematic orchestral track, set in E minor and surging at 130.81 BPM, conjures a world where ancient mysteries awaken under a moon's ethereal glow, leading to a powerful, battle-forged destiny. Grand choirs, soaring strings, and powerful brass combine with the percussive force of Taiko drums and timpani, alongside the exotic textures of Duduk and Bagpipes, creating an intense and adventurous soundscape. The track's very high energy and intense mood build steadily towards a dramatic emotional peak at 177 seconds, culminating in a powerful, conclusive statement at 178 seconds. With its blend of traditional and hybrid orchestral elements, including electric guitar, it evokes a sense of both magic and impending conflict. This instrumental piece, featuring prominent choir and wordless vocals, is ideal for fantasy film trailers, video game scores, or any dramatic content requiring a sense of heroic struggle and magical discovery.",
"listen_url": "https://play.ainsof.io/#AIN-CAT_005_008",
"audio_url": "https://mcp.ainsof.io/p/AIN-CAT_005_008?raw=1",
"also_available": "8 more versions: BRASS_STRINGS, CUT_15, CUT_30, CUT_40, CUT_60, NO_CHOIR, NO_DRUM_PERCUSSION, UNDERSCORE · 5 stems"
}
],
"licensing": {
"status": "preview",
"what_you_have": "You have full search across the AINSOF catalogue, and every track you download is a complete preview — the whole piece, start to finish, so you can cut to it and see whether it truly works. The preview is for auditioning; publication requires a separate licence.",
"beyond_online": {
"note": "A preview does not grant permission for publication, broadcast, advertising or other release. This connector does not sell licences or initiate a purchase; it provides discovery, auditioning and rights information.",
"uses": [
"Trailers and promos",
"Broadcast television and radio",
"Cinema and theatrical"
]
},
"contact": "info@ainsof.io",
"how_it_works": [
"Search and audition catalogue previews without purchasing anything.",
"Cue sheets identify the music and credits; they are not a licence.",
"For technical support, privacy requests or questions about an existing licence, contact info@ainsof.io."
]
}
}Find similar
https://mcp.ainsof.io/Find AINSOF cues that sound like an AINSOF cue: the whole cue, or a passage of it that you mark.
RESTaction: "similar"MCPfind_similar
- Send
fromandtoto mark a passage (5 to 60 seconds long), for example the hook or the bar before the drop. Leave them out to compare whole cues. - Each result carries
similarityand, for a passage,matching_passage: the part of that cue that sounds closest to the one you marked. - A passage that runs past the end of the cue is matched from its last seconds.
- The cue you start from is never returned in its own results.
- For a song by another artist (a YouTube, Spotify, Apple Music or Deezer link) use
searchwithlinkinstead.
Request body application/json
actionrequiredsimilar.track_idrequiredAIN-CAT 030_001 or Along The River.fromtotop_kResponse 200
oktrue.referencetrack_id, title, album_code, and passage (from, to, label) or "whole cue".how_matchedresultssimilarity (0 to 1) and, for a passage, matching_passage (from, to, label).catalogue_note, how_to_present, licensingsearch.Errors
| Status | error | When |
|---|---|---|
| 400 | track_id is required | No track_id was sent. |
| 400 | invalid_passage | from/to are missing a value, negative, shorter than 5 seconds or longer than 60. |
| 400 | invalid_request | track_id is not a cue id (for example an unknown title or an album code); message explains. |
| 429 | slow_down | Too many similarity searches in a short time. Try again shortly. |
| 503 | similar_failed | The comparison could not run, the cue is not yet indexed for sound matching, or no cue has that id. This does not mean nothing is similar; try again later. |
Tracks like a marked passage
curl https://mcp.ainsof.io/ \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $AINSOF_API_KEY" \
-d '{"action": "similar", "track_id": "AIN-CAT 030_001", "from": 107, "to": 122, "top_k": 3}'import os, requests
r = requests.post(
"https://mcp.ainsof.io/",
headers={"Authorization": f"Bearer {os.environ['AINSOF_API_KEY']}"},
json={
"action": "similar",
"track_id": "AIN-CAT 030_001",
"from": 107,
"to": 122,
"top_k": 3
},
timeout=60,
)
print(r.json())const res = await fetch("https://mcp.ainsof.io/", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${process.env.AINSOF_API_KEY}`,
},
body: JSON.stringify({
"action": "similar",
"track_id": "AIN-CAT 030_001",
"from": 107,
"to": 122,
"top_k": 3
}),
});
const data = await res.json();{
"ok": true,
"reference": {
"track_id": "AIN-CAT 030_001",
"title": "Along The River",
"album_code": "AIN-CAT 030",
"passage": {
"from": 107,
"to": 122,
"label": "1:47–2:02"
}
},
"how_matched": "Compared by sound against every AINSOF cue, window by window; matching_passage is the part of each result that sounds closest to the marked passage.",
"results": [
{
"track_id": "AIN-CAT 024_002",
"title": "Spring In a Bottle",
"album": "Heartwood (Live Acoustic Embrace)",
"catalogue": "AIN-CAT 024",
"listen_url": "https://play.ainsof.io/#AIN-CAT_024_002",
"…": "…",
"similarity": 0.9669,
"matching_passage": {
"from": 15,
"to": 25,
"label": "0:15–0:25"
}
},
{
"track_id": "AIN-CAT 030_002",
"title": "Desert Journey",
"…": "…",
"similarity": 0.9627,
"matching_passage": {
"from": 80,
"to": 90,
"label": "1:20–1:30"
}
},
"…"
],
"licensing": "… (see The licensing object)"
}Get a cue
https://mcp.ainsof.io/Return one cue in full: credits, description, every version and every stem, each with its own preview link.
RESTaction: "track"MCPget_track
track_idaccepts the id with a space or an underscore (AIN-CAT 031_002,AIN-CAT_031_002) or the cue's title.- An album name or album code is not a cue: the 404 message lists the album's cue ids instead.
- Composer entries in
track,cue_sheetandfituseperf_share; result rows fromsearchandsoundtrackuseperformance_share.
Request body application/json
actionrequiredtrack.track_idrequiredResponse 200
oktrue.creditsalbum_cover_url and album_cover_thumb_url. null if the cue has no credits record.trackalso_available) plus the fields below.track.versionsversion, label, length, listen_url.track.stemsstem, label, listen_url. Request a stem from preview as STEM_<stem>.track.listentrack.licencePreview for auditioning · no publication rights granted.track.music_key, vibe, scenes, use_cases, not_forcue_sheet_availabletrue.licensingErrors
| Status | error | When |
|---|---|---|
| 400 | track_id is required | track_id missing. |
| 404 | (a sentence) | Nothing matched the id or title. The sentence is in error; for an album or composer name it says so and how to proceed. |
Get a cue by id
curl https://mcp.ainsof.io/ \
-H "Content-Type: application/json" \
-d '{"action": "track", "track_id": "AIN-CAT 031_002"}'import os, requests
r = requests.post(
"https://mcp.ainsof.io/",
json={
"action": "track",
"track_id": "AIN-CAT 031_002"
},
timeout=60,
)
print(r.json())const res = await fetch("https://mcp.ainsof.io/", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
"action": "track",
"track_id": "AIN-CAT 031_002"
}),
});
const data = await res.json();{
"ok": true,
"credits": {
"track_id": "AIN-CAT 031_002",
"catalogue": "AIN-CAT 031",
"album": "Shining Ahead (Corporate Advertising)",
"title": "Shine On Today",
"isrc": "BG-A47-26-02477",
"bpm": 84,
"key": "D major",
"duration_sec": 151,
"publisher": "AINSOF (Or Chausha AINSOF)",
"composers": [
{
"ipi": "687184598",
"name": "Alon Peretz",
"society": "PRS",
"perf_share": "50%"
}
],
"album_cover_url": "https://mcp.ainsof.io/cover/AIN-CAT_031.jpg?v=2",
"album_cover_thumb_url": "https://mcp.ainsof.io/cover/AIN-CAT_031.jpg?v=2&w=220"
},
"track": {
"track_id": "AIN-CAT 031_002",
"title": "Shine On Today",
"album_cover_url": "https://mcp.ainsof.io/cover/AIN-CAT_031.jpg?v=2",
"album_cover_thumb_url": "https://mcp.ainsof.io/cover/AIN-CAT_031.jpg?v=2&w=220",
"album": "Shining Ahead (Corporate Advertising)",
"catalogue": "AIN-CAT 031",
"composers": [
{
"ipi": "687184598",
"name": "Alon Peretz",
"society": "PRS",
"perf_share": "50%"
}
],
"publisher": "AINSOF (Or Chausha AINSOF)",
"style": "Advertising Pop",
"also": [
"Acoustic Pop",
"Folk Pop",
"Indie Pop"
],
"feels": [
"Uplifting",
"Optimistic",
"Carefree"
],
"length": "2:31",
"bpm": 84,
"description": "This uplifting and sunny D major track, flowing at 83.96 BPM, radiates lighthearted optimism and positive energy. Featuring a bright blend of acoustic guitar, keys, bass, drums, percussion, and playful whistles, it creates an effortlessly cheerful and organic soundscape. The addition of tuba, synth, FX, and subtle vocals adds texture to its feelgood, indie pop character. Ideal for capturing moments of joy and carefree adventure, this track is perfect for a wide range of visual content. It evokes scenes of bright mornings and happy family gatherings, making it a versatile choice for positive storytelling.",
"versions": [
{
"version": "CUT_15",
"label": "15s",
"length": "0:15",
"listen_url": "https://play.ainsof.io/#AIN-CAT_031_002/CUT_15"
},
{
"version": "CUT_30",
"label": "30s",
"length": "0:30",
"listen_url": "https://play.ainsof.io/#AIN-CAT_031_002/CUT_30"
},
{
"version": "CUT_40",
"label": "40s",
"length": "0:40",
"listen_url": "https://play.ainsof.io/#AIN-CAT_031_002/CUT_40"
}
],
"stems": [
{
"stem": "ACC",
"label": "Acc",
"listen_url": "https://play.ainsof.io/#AIN-CAT_031_002/STEM_ACC"
},
{
"stem": "BASS",
"label": "Bass",
"listen_url": "https://play.ainsof.io/#AIN-CAT_031_002/STEM_BASS"
},
{
"stem": "DRUMS",
"label": "Drums",
"listen_url": "https://play.ainsof.io/#AIN-CAT_031_002/STEM_DRUMS"
}
],
"listen_url": "https://play.ainsof.io/#AIN-CAT_031_002",
"audio_url": "https://mcp.ainsof.io/p/AIN-CAT_031_002?raw=1",
"listen": "Open listen_url to hear the complete preview. Every entry under versions and stems carries its own listen_url — cutdowns, instrumentals and individual stems all play the same way.",
"licence": "Preview for auditioning · no publication rights granted",
"music_key": "D major",
"vibe": "Bright, organic, and irresistibly cheerful, evoking a sense of carefree optimism.",
"scenes": [
"Sun-drenched morning routines",
"Family road trips",
"DIY project montages"
],
"use_cases": [
"Upbeat TV commercials",
"Lifestyle brand campaigns",
"Social media content for positive messaging"
],
"not_for": [
"Dramatic or suspenseful narratives",
"Somber or melancholic storytelling",
"High-stakes action sequences"
]
},
"cue_sheet_available": true,
"licensing": {
"status": "preview",
"what_you_have": "You have full search across the AINSOF catalogue, and every track you download is a complete preview — the whole piece, start to finish, so you can cut to it and see whether it truly works. The preview is for auditioning; publication requires a separate licence.",
"beyond_online": {
"note": "A preview does not grant permission for publication, broadcast, advertising or other release. This connector does not sell licences or initiate a purchase; it provides discovery, auditioning and rights information.",
"uses": [
"Trailers and promos",
"Broadcast television and radio",
"Cinema and theatrical"
]
},
"contact": "info@ainsof.io",
"how_it_works": [
"Search and audition catalogue previews without purchasing anything.",
"Cue sheets identify the music and credits; they are not a licence.",
"For technical support, privacy requests or questions about an existing licence, contact info@ainsof.io."
]
}
}Preview links
https://mcp.ainsof.io/Return the player link and audio link for one version or stem of a cue.
RESTaction: "preview"MCPlisten_link
versiontakes any version name fromtrack(MAIN,CUT_30,UNDERSCORE, …) or a stem asSTEM_<name>, in any case.audio_urlis the clean MP3 at 192 kbps (watermarked: false).
Request body application/json
actionrequiredpreview.track_idrequiredversionSTEM_<name>. Case-insensitive.Response 200
oktrue.track_idversioncataloguealbum_cover_thumb_urllisten_urlaudio_urlwatermarkedfalse: the audio is the clean MP3 at 192 kbps.licensingErrors
| Status | error | When |
|---|---|---|
| 400 | track_id is required | track_id missing. |
| 404 | (a sentence) | The id or title does not resolve to a cue. |
| 404 | not_available | No preview is stored for that cue and version. |
A 15-second cut
curl https://mcp.ainsof.io/ \
-H "Content-Type: application/json" \
-d '{"action": "preview", "track_id": "AIN-CAT_031_002", "version": "cut_15"}'import os, requests
r = requests.post(
"https://mcp.ainsof.io/",
json={
"action": "preview",
"track_id": "AIN-CAT_031_002",
"version": "cut_15"
},
timeout=60,
)
print(r.json())const res = await fetch("https://mcp.ainsof.io/", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
"action": "preview",
"track_id": "AIN-CAT_031_002",
"version": "cut_15"
}),
});
const data = await res.json();{
"ok": true,
"track_id": "AIN-CAT 031_002",
"version": "CUT_15",
"catalogue": "AIN-CAT 031",
"album_cover_thumb_url": "https://mcp.ainsof.io/cover/AIN-CAT_031.jpg?v=2&w=220",
"listen_url": "https://play.ainsof.io/#AIN-CAT_031_002/CUT_15",
"audio_url": "https://mcp.ainsof.io/p/AIN-CAT_031_002/CUT_15?raw=1",
"watermarked": false,
"licensing": {
"status": "preview",
"what_you_have": "You have full search across the AINSOF catalogue, and every track you download is a complete preview — the whole piece, start to finish, so you can cut to it and see whether it truly works. The preview is for auditioning; publication requires a separate licence.",
"beyond_online": {
"note": "A preview does not grant permission for publication, broadcast, advertising or other release. This connector does not sell licences or initiate a purchase; it provides discovery, auditioning and rights information.",
"uses": [
"Trailers and promos",
"Broadcast television and radio",
"Cinema and theatrical"
]
},
"contact": "info@ainsof.io",
"how_it_works": [
"Search and audition catalogue previews without purchasing anything.",
"Cue sheets identify the music and credits; they are not a licence.",
"For technical support, privacy requests or questions about an existing licence, contact info@ainsof.io."
]
}
}A stem, cue named by title
curl https://mcp.ainsof.io/ \
-H "Content-Type: application/json" \
-d '{"action": "preview", "track_id": "Shine On Today", "version": "STEM_BASS"}'import os, requests
r = requests.post(
"https://mcp.ainsof.io/",
json={
"action": "preview",
"track_id": "Shine On Today",
"version": "STEM_BASS"
},
timeout=60,
)
print(r.json())const res = await fetch("https://mcp.ainsof.io/", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
"action": "preview",
"track_id": "Shine On Today",
"version": "STEM_BASS"
}),
});
const data = await res.json();{
"ok": true,
"track_id": "AIN-CAT 031_002",
"version": "STEM_BASS",
"catalogue": "AIN-CAT 031",
"album_cover_thumb_url": "https://mcp.ainsof.io/cover/AIN-CAT_031.jpg?v=2&w=220",
"listen_url": "https://play.ainsof.io/#AIN-CAT_031_002/STEM_BASS",
"audio_url": "https://mcp.ainsof.io/p/AIN-CAT_031_002/STEM_BASS?raw=1",
"watermarked": false,
"licensing": {
"status": "preview",
"what_you_have": "You have full search across the AINSOF catalogue, and every track you download is a complete preview — the whole piece, start to finish, so you can cut to it and see whether it truly works. The preview is for auditioning; publication requires a separate licence.",
"beyond_online": {
"note": "A preview does not grant permission for publication, broadcast, advertising or other release. This connector does not sell licences or initiate a purchase; it provides discovery, auditioning and rights information.",
"uses": [
"Trailers and promos",
"Broadcast television and radio",
"Cinema and theatrical"
]
},
"contact": "info@ainsof.io",
"how_it_works": [
"Search and audition catalogue previews without purchasing anything.",
"Cue sheets identify the music and credits; they are not a licence.",
"For technical support, privacy requests or questions about an existing licence, contact info@ainsof.io."
]
}
}Cue sheet
https://mcp.ainsof.io/Return a cue's credits and a plain-text cue sheet.
RESTaction: "cue_sheet"MCPcue_sheet
- The cue sheet lists the performance share only.
- This response has no
licensingblock.
Request body application/json
actionrequiredcue_sheet.track_idrequiredResponse 200
oktrue.track_idcreditscue_sheetnoteErrors
| Status | error | When |
|---|---|---|
| 400 | track_id is required | track_id missing. |
| 404 | (a sentence) | Nothing matched the id or title. |
Cue sheet
curl https://mcp.ainsof.io/ \
-H "Content-Type: application/json" \
-d '{"action": "cue_sheet", "track_id": "AIN-CAT 031_002"}'import os, requests
r = requests.post(
"https://mcp.ainsof.io/",
json={
"action": "cue_sheet",
"track_id": "AIN-CAT 031_002"
},
timeout=60,
)
print(r.json())const res = await fetch("https://mcp.ainsof.io/", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
"action": "cue_sheet",
"track_id": "AIN-CAT 031_002"
}),
});
const data = await res.json();{
"ok": true,
"track_id": "AIN-CAT 031_002",
"credits": {
"track_id": "AIN-CAT 031_002",
"catalogue": "AIN-CAT 031",
"album": "Shining Ahead (Corporate Advertising)",
"title": "Shine On Today",
"isrc": "BG-A47-26-02477",
"bpm": 84,
"key": "D major",
"duration_sec": 151,
"publisher": "AINSOF (Or Chausha AINSOF)",
"composers": [
{
"ipi": "687184598",
"name": "Alon Peretz",
"society": "PRS",
"perf_share": "50%"
}
]
},
"cue_sheet": "AINSOF MUSIC — CUE SHEET\n\nTitle Shine On Today\nAlbum Shining Ahead (Corporate Advertising)\nCatalogue AIN-CAT 031\nISRC BG-A47-26-02477\nDuration 151 sec\nTempo / Key 84 BPM D major\n\nPublisher AINSOF (Or Chausha AINSOF) (100%)\n\nWriters\n Alon Peretz\n IPI 687184598 PRS performance 50%\n\nMaster and publishing controlled by AINSOF.\nLicensing information: ainsof.io",
"note": "Save this as a .txt or paste it into your delivery paperwork. AINSOF controls both master and publishing, so these figures are ours to state."
}Video
Music for a video
https://mcp.ainsof.io/Return up to three cues for a video of a given length, each with the version to use.
RESTaction: "soundtrack"MCPfind_soundtrack
- The video's description, product, scenes, edit pace and narration are turned into a musical brief;
video.read_asshows the brief that was searched. - Options that can be heard now come first; among them, options that need no edit come first.
- When a stock cut is chosen and its preview is confirmed, the option plays that cut:
listen_urlandaudio_urlpoint at it,preview_versionnames it andfull_mix_listen_urlkeeps the full mix.
Request body application/json
actionrequiredsoundtrack.duration_secrequireddescriptiontranslate_first).productscenescuts_per_minhas_narrationtrue if someone speaks over the video; the brief then asks for underscore.Response 200
oktrue.videoduration_sec as sent, and read_as: the brief that was searched.optionsoptions[].for_your_videouse, <n>s cut, custom <n>s cut or full mix preview; needs_edit, whether the audio must still be cut or trimmed to the video; why, one sentence; trim_from_sec, seconds to trim from the end of the chosen cut, when applicable.options[].versionsversion, label, length, listen_url).options[].preview_versionlisten_url and audio_url play.options[].full_mix_listen_urlcatalogue_note, licensingsearch.Errors
| Status | error | When |
|---|---|---|
| 400 | duration_sec is required — the video length is what makes this different from a search | duration_sec missing, zero or negative. |
| 400 | translate_first | description is not in English. Nothing was searched. |
| 500 | could not queue the search | The search job could not be created. |
| 202 | still_running | Send the identical request again. |
| 503 | engine_unavailable | The search engine did not pick up the job. |
| 503 | search_failed | The search could not run. |
A 30-second product video
curl https://mcp.ainsof.io/ \
-H "Content-Type: application/json" \
-d '{"action": "soundtrack", "duration_sec": 30, "description": "upbeat modern tech product launch, confident and bright", "cuts_per_min": 20}'import os, requests
r = requests.post(
"https://mcp.ainsof.io/",
json={
"action": "soundtrack",
"duration_sec": 30,
"description": "upbeat modern tech product launch, confident and bright",
"cuts_per_min": 20
},
timeout=60,
)
print(r.json())const res = await fetch("https://mcp.ainsof.io/", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
"action": "soundtrack",
"duration_sec": 30,
"description": "upbeat modern tech product launch, confident and bright",
"cuts_per_min": 20
}),
});
const data = await res.json();{
"ok": true,
"video": {
"duration_sec": 30,
"read_as": "Instrumental music that sounds like upbeat modern tech product launch, confident and bright, instrumental."
},
"catalogue_note": "Every track in these results is an original AINSOF composition. If your brief named a commercial song or artist, these are original alternatives in that spirit — not the named recording, and not a cover of it.",
"options": [
{
"track_id": "AIN-CAT 031_006",
"title": "Joy in Motion",
"album_cover_url": "https://mcp.ainsof.io/cover/AIN-CAT_031.jpg?v=2",
"album_cover_thumb_url": "https://mcp.ainsof.io/cover/AIN-CAT_031.jpg?v=2&w=220",
"album": "Shining Ahead (Corporate Advertising)",
"catalogue": "AIN-CAT 031",
"composers": [
{
"name": "Alon Peretz",
"society": "PRS",
"ipi": "687184598",
"performance_share": "50%"
}
],
"publisher": "AINSOF (Or Chausha AINSOF)",
"style": "Uplifting Acoustic Pop",
"also": [
"Indie Pop",
"Folk Pop",
"Acoustic Pop"
],
"feels": [
"Happy",
"Uplifting",
"Playful"
],
"length": "0:30",
"bpm": 156,
"description": "This energetic and uplifting instrumental track, set in G major at a brisk 156.25 BPM, radiates pure joy and optimism. Driven by a lively blend of acoustic guitar, bass, drums, and keys, it creates a bright and feel-good atmosphere. The track builds to an emotional peak at 133 seconds before concluding at 134 seconds, making it ideal for dynamic edits and montages. Its playful and hopeful character, enhanced by subtle strings and percussion, evokes a sense of carefree adventure and positive energy. Perfect for conveying warmth and inspiration, it avoids any hint of melancholy or tension, maintaining a consistently cheerful mood throughout its 136-second duration.",
"versions": [
{
"version": "CUT_30",
"label": "30s",
"length": "0:30",
"listen_url": "https://play.ainsof.io/#AIN-CAT_031_006/CUT_30"
}
],
"listen_url": "https://play.ainsof.io/#AIN-CAT_031_006/CUT_30",
"audio_url": "https://mcp.ainsof.io/p/AIN-CAT_031_006/CUT_30?raw=1",
"for_your_video": {
"use": "30s cut",
"needs_edit": false,
"why": "Exactly 30s — drops straight onto a 30s edit."
},
"full_mix_listen_url": "https://play.ainsof.io/#AIN-CAT_031_006",
"preview_version": "CUT_30",
"also_available": "5 more versions: CUT_15, CUT_40, CUT_60, NO_MELODY, NO_PERCUSSION · 9 stems"
},
{
"track_id": "AIN-CAT 042_003",
"title": "Structured Light",
"album_cover_url": "https://mcp.ainsof.io/cover/AIN-CAT_042.jpg?v=2",
"album_cover_thumb_url": "https://mcp.ainsof.io/cover/AIN-CAT_042.jpg?v=2&w=220",
"album": "Light in Motion (Corporate Inspiration)",
"catalogue": "AIN-CAT 042",
"composers": [
{
"name": "Elram Bokser",
"society": "PRS",
"ipi": "856013446",
"performance_share": "50%"
}
],
"publisher": "AINSOF (Or Chausha AINSOF)",
"style": "Inspirational Corporate Pop",
"also": [
"Uplifting Pop",
"Motivational Corporate",
"Smooth Dance Pop"
],
"feels": [
"Inspiring",
"Uplifting",
"Optimistic"
],
"length": "0:30",
"bpm": 141,
"description": "A bright and uplifting track, 'Structured Light' delivers smooth, structured inspiration with harmonic clarity and a steady, motivational pulse at 140.62 BPM in D major. Featuring a blend of Piano, Acoustic Guitars, Organ, Acoustic Drums, and Vocals, it creates a confident and hopeful atmosphere. The high-energy arrangement builds towards an emotional peak at 124 seconds, making it ideal for conveying progress and optimism. This piece is perfectly suited for explainer videos, technology showcases, and corporate content, providing a positive and forward-looking backdrop for any project.",
"versions": [
{
"version": "CUT_30",
"label": "30s",
"length": "0:30",
"listen_url": "https://play.ainsof.io/#AIN-CAT_042_003/CUT_30"
}
],
"listen_url": "https://play.ainsof.io/#AIN-CAT_042_003/CUT_30",
"audio_url": "https://mcp.ainsof.io/p/AIN-CAT_042_003/CUT_30?raw=1",
"for_your_video": {
"use": "30s cut",
"needs_edit": false,
"why": "Exactly 30s — drops straight onto a 30s edit."
},
"full_mix_listen_url": "https://play.ainsof.io/#AIN-CAT_042_003",
"preview_version": "CUT_30",
"also_available": "6 more versions: CUT_15, CUT_40, CUT_60, NO_MELODY, NO_PERCUSSION, NO_VOCAL · 13 stems"
}
],
"licensing": {
"status": "preview",
"what_you_have": "You have full search across the AINSOF catalogue, and every track you download is a complete preview — the whole piece, start to finish, so you can cut to it and see whether it truly works. The preview is for auditioning; publication requires a separate licence.",
"beyond_online": {
"note": "A preview does not grant permission for publication, broadcast, advertising or other release. This connector does not sell licences or initiate a purchase; it provides discovery, auditioning and rights information.",
"uses": [
"Trailers and promos",
"Broadcast television and radio",
"Cinema and theatrical"
]
},
"contact": "info@ainsof.io",
"how_it_works": [
"Search and audition catalogue previews without purchasing anything.",
"Cue sheets identify the music and credits; they are not a licence.",
"For technical support, privacy requests or questions about an existing licence, contact info@ainsof.io."
]
}
}Score a video
https://mcp.ainsof.io/Mix AINSOF music onto a video and return the rendered MP4 .
RESTaction: "score_video"MCPscore_my_video
- Before AINSOF works with a video, a person signs in once on ainsof.io (Google or email). With a key created on ainsof.io this has already happened. Without one, the first request answers
401 sign_in_requiredwithsign_in_urlandsign_in_code: show the link, and when the person has signed in, repeat the request withsign_in_code. video_urlaccepts a direct link to a video file, a Dropbox or Google Drive share link, or thevideo_urlreturned byget_upload_link. YouTube, Vimeo, Dailymotion and Twitch pages are not supported.brief,track_idandsectionsare all optional: leave them out and AINSOF watches the film first and chooses the music for what it shows and how it feels (returned asfilm).- Section and silence boundaries are moved onto the video's measured cuts.
- An identical request made within 15 minutes returns the same render rather than starting another. Requests made with a key are only matched to that key's renders.
- Renders usually take longer than one request waits: expect
202 still_running, and repeat the same request unchanged. That reply includesdelivery_requestwith the arguments to repeat (add yoursign_in_codeif you signed in without a key). - Watching the result is free. Downloading the file opens ainsof.io, which asks for a quick sign-in (Google or email) first.
- Videos up to 15 minutes.
Request body application/json
actionrequiredscore_video.video_urlrequiredsign_in_codesign_in_required, once the person has signed in. Pass the same code to every video action; it stays valid for 30 days. Not needed with a key created on ainsof.io.brieftrack_idversionCUT_30. Upper-cased.music_offset_db0 is level. When omitted, the renderer's default applies.silencesat (seconds, required) and for (duration in seconds, default 1).sectionsfrom and to (seconds, required), plus brief (English), track_id, version or stems (an array of stem names from that cue; the schema asks for track_id with it). Every section needs a brief, track_id or stems.user_requestproject_typeother.music_intenttense build, minimal, no vocals. Kept as anonymous usage statistics.Response 200
oktrue.video_urldelivery_request{"tool": "deliver_score", "arguments": {…}}: the public arguments to send to deliver_score.download_urlhttps://mcp.ainsof.io/v/<id>/download, which opens ainsof.io and asks for a sign-in before the file downloads.storage_signature_valid_for_hours1.ainsof_link_availabilityformatmp4.usedtrack_id, title, album, version, bpm, style, why.cuesmixmusic_sits_db_under_your_audio and how_to_change.videoduration_sec, cut_count, shot_count, average_shot_sec, cuts_per_min.music_stopssectionsalso_consideredcues.how_to_revisenotelicensingfilmdownload_needssyncvideo.cut_times_sec, scenes, cut_sourceErrors
| Status | error | When |
|---|---|---|
| 401 | sign_in_required | No signed-in person yet (only without a key created on ainsof.io). The answer carries sign_in_url (a page on ainsof.io where the person signs in with Google or email), sign_in_code, message, tell_the_user (what to say) and next (what to do after). Repeat the same request with sign_in_code once the person has signed in. Sent before they finish, it answers the same way with the same code; an unknown or expired code gets a new one, with a note. A code works for 30 days from when it was issued. |
| 400 | video_url is required | video_url missing. |
| 400 | section_needs_music | A section has no brief, track_id or stems. |
| 400 | translate_first | brief (without track_id) or a section brief is not in English. |
| 410 | upload_expired | The uploaded video is no longer available; request a new upload link. |
| 500 | could not queue the render | The render job could not be created. |
| 202 | still_running | Still rendering. Repeat the identical request; delivery_request is included. |
| 503 | engine_unavailable | The renderer did not pick up the job. Nothing was rendered. |
| 422 | video_failed | The video could not be processed; message gives the reason. |
| 500 | video_failed | The render finished without a file, or its link could not be created. |
| 429 | slow_down | More than 200 new sign-in links from one network address in an hour. Try again in a few minutes. |
| 503 | try_again | The sign-in could not be checked just now. Nothing was done; try again. |
Score a video from a brief
curl https://mcp.ainsof.io/ \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $AINSOF_API_KEY" \
-d '{"action": "score_video", "video_url": "https://example.com/spot.mp4", "brief": "warm acoustic, hopeful"}'import os, requests
r = requests.post(
"https://mcp.ainsof.io/",
headers={"Authorization": f"Bearer {os.environ['AINSOF_API_KEY']}"},
json={
"action": "score_video",
"video_url": "https://example.com/spot.mp4",
"brief": "warm acoustic, hopeful"
},
timeout=60,
)
print(r.json())const res = await fetch("https://mcp.ainsof.io/", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${process.env.AINSOF_API_KEY}`,
},
body: JSON.stringify({
"action": "score_video",
"video_url": "https://example.com/spot.mp4",
"brief": "warm acoustic, hopeful"
}),
});
const data = await res.json();{
"ok": true,
"video_url": "https://mcp.ainsof.io/v/<render-id>",
"delivery_request": {
"tool": "deliver_score",
"arguments": {
"video_url": "https://example.com/spot.mp4",
"brief": "warm acoustic, hopeful"
}
},
"download_url": "https://mcp.ainsof.io/v/<render-id>/download",
"storage_signature_valid_for_hours": 1,
"ainsof_link_availability": "The AINSOF link creates a new temporary storage signature whenever it is opened and remains available until the render is deleted on its seven-day schedule.",
"format": "mp4",
"used": {
"track_id": "<track_id>",
"title": "<title>",
"album": "<album>",
"version": "<version>",
"bpm": "<bpm>",
"style": "<style>",
"why": "<reason>"
},
"cues": "<from the render>",
"mix": {
"music_sits_db_under_your_audio": "<dB>",
"how_to_change": "Call again with music_offset_db — a lower number is quieter music, 0 is level with your audio."
},
"video": {
"duration_sec": "<seconds>",
"cut_count": "<n>",
"shot_count": "<n>",
"average_shot_sec": "<seconds>",
"cuts_per_min": "<n>"
},
"also_considered": "<from the render>",
"how_to_revise": "Call score_my_video again with the same arguments and change only what the user asked to change. …",
"note": "The music on this render is AINSOF's clean 192 kbps audio (no watermark), edited to your picture — right for showing and approving an idea, not licensed for release. Licensing it delivers the lossless master.",
"licensing": "… (see The licensing object)"
}Analyze a video
https://mcp.ainsof.io/Measure a video for scoring: length, frame rate, resolution, cuts, edit pace, storyboard frames and an optional transcript.
RESTaction: "analyze_video"MCPanalyze_video
- Before AINSOF works with a video, a person signs in once on ainsof.io (Google or email). With a key created on ainsof.io this has already happened. Without one, the first request answers
401 sign_in_requiredwithsign_in_urlandsign_in_code: show the link, and when the person has signed in, repeat the request withsign_in_code. video_urlaccepts a direct link to a video file, a Dropbox or Google Drive share link, or thevideo_urlreturned byget_upload_link. YouTube, Vimeo, Dailymotion and Twitch pages are not supported.- Videos up to 15 minutes. Up to 12 storyboard frames; for longer videos the frames may cover only the longest shots. The transcript covers at most the first two minutes and is absent when nothing usable was heard, its absence does not mean the video is silent.
- Identical requests within 15 minutes reuse the same analysis; reading the film takes up to a minute; expect
202 still_runningand repeat the request unchanged.
Request body application/json
actionrequiredanalyze_video.video_urlrequiredsign_in_codesign_in_required, once the person has signed in. Pass the same code to every video action; it stays valid for 30 days. Not needed with a key created on ainsof.io.user_requestproject_typemusic_intenttense build, minimal, no vocals. Kept as anonymous usage statistics.Response 200
oktrue.filmmusic.search, a description ready for soundtrack).video.duration_sec, fps, width, height, has_audiovideo.scenes, accents_sec, peak_sec, cut_sourcevideo.cut_count, shot_count, average_shot_sec, cuts_per_minvideo.cut_times_secvideo.shotsat, shot_from, shot_to, jpeg_b64 (base64 JPEG). Over MCP, jpeg_b64 is removed and each frame is attached as an image instead.video.transcriptcovers_up_to_sec and a note when partial.nextscoring_this_in_partssections for this video.licensingErrors
| Status | error | When |
|---|---|---|
| 401 | sign_in_required | No signed-in person yet (only without a key created on ainsof.io). The answer carries sign_in_url (a page on ainsof.io where the person signs in with Google or email), sign_in_code, message, tell_the_user (what to say) and next (what to do after). Repeat the same request with sign_in_code once the person has signed in. Sent before they finish, it answers the same way with the same code; an unknown or expired code gets a new one, with a note. A code works for 30 days from when it was issued. |
| 400 | video_url is required | video_url missing. |
| 410 | upload_expired | The uploaded video is no longer available. |
| 500 | could not queue the analysis | The job could not be created. |
| 202 | still_running | Repeat the identical request. |
| 503 | engine_unavailable | The analyzer did not respond. Nothing was done. |
| 422 | video_failed | The video could not be processed; message gives the reason. |
| 429 | slow_down | More than 200 new sign-in links from one network address in an hour. Try again in a few minutes. |
| 503 | try_again | The sign-in could not be checked just now. Nothing was done; try again. |
Analyze a video
curl https://mcp.ainsof.io/ \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $AINSOF_API_KEY" \
-d '{"action": "analyze_video", "video_url": "https://example.com/spot.mp4"}'import os, requests
r = requests.post(
"https://mcp.ainsof.io/",
headers={"Authorization": f"Bearer {os.environ['AINSOF_API_KEY']}"},
json={
"action": "analyze_video",
"video_url": "https://example.com/spot.mp4"
},
timeout=60,
)
print(r.json())const res = await fetch("https://mcp.ainsof.io/", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${process.env.AINSOF_API_KEY}`,
},
body: JSON.stringify({
"action": "analyze_video",
"video_url": "https://example.com/spot.mp4"
}),
});
const data = await res.json();{
"ok": true,
"video": {
"duration_sec": "<seconds>",
"fps": "<fps>",
"width": "<px>",
"height": "<px>",
"has_audio": "<true|false>",
"cut_count": "<n>",
"shot_count": "<n>",
"average_shot_sec": "<seconds>",
"cuts_per_min": "<n>",
"cut_times_sec": [
"<seconds>",
"…"
],
"shots": [
{
"at": "<seconds>",
"shot_from": "<seconds>",
"shot_to": "<seconds>",
"jpeg_b64": "<base64 JPEG>"
},
"…"
]
},
"next": "Pass duration_sec and cuts_per_min to find_soundtrack for a better match, or call score_my_video to have the music mixed onto this video.",
"licensing": "… (see The licensing object)"
}Deliver a score
https://mcp.ainsof.io/Return the finished score as a zip: the scored video, each section's music as a separate MP3 (192 kbps) named by the timecode it starts at, and a cue sheet.
RESTaction: "deliver_score"MCPdeliver_score
- Before AINSOF works with a video, a person signs in once on ainsof.io (Google or email). With a key created on ainsof.io this has already happened. Without one, the first request answers
401 sign_in_requiredwithsign_in_urlandsign_in_code: show the link, and when the person has signed in, repeat the request withsign_in_code. - Send the same arguments used for
score_video(or thedelivery_request.argumentsit returned), plussign_in_codeif you signed in without a key, sincedelivery_requestdoes not include it. The most recent render with identical arguments from the last 7 days is delivered; nothing is re-rendered. - If a render has no package but its video exists, the response is
200withformat: "mp4"and adownload_urlthat opens the video's watch page (/v/<id>). - Downloading the zip opens ainsof.io, which asks for a quick sign-in (Google or email) first.
Request body application/json
actionrequireddeliver_score.video_urlrequiredsign_in_codesign_in_required, once the person has signed in. Pass the same code to every video action; it stays valid for 30 days. Not needed with a key created on ainsof.io.brief, track_id, version, music_offset_db, silences, sectionsscore_video. Any difference finds a different render (or none).Response 200
oktrue.download_urlstorage_signature_valid_for_hours1.ainsof_link_availabilityformatzip.containsSCORED.mp4, audio/ (one MP3 per section, 192 kbps 48 kHz, named by start timecode), SCORE.txt, CUE_SHEET.csv.piecesnotelicensingdownload_needssyncErrors
| Status | error | When |
|---|---|---|
| 401 | sign_in_required | No signed-in person yet (only without a key created on ainsof.io). The answer carries sign_in_url (a page on ainsof.io where the person signs in with Google or email), sign_in_code, message, tell_the_user (what to say) and next (what to do after). Repeat the same request with sign_in_code once the person has signed in. Sent before they finish, it answers the same way with the same code; an unknown or expired code gets a new one, with a note. A code works for 30 days from when it was issued. |
| 400 | video_url is required | video_url missing. |
| 404 | nothing_to_deliver | No render with these arguments in the last 7 days. |
| 422 | video_failed | That render failed. |
| 202 | still_running | Still rendering; includes delivery_request. |
| 409 | no_package | The render has no package and no stored video; run score_video again. |
| 500 | delivery_failed | The package link could not be created. |
| 409 | preview_refresh_required | The render was made before the move to clean audio; score it again. |
| 503 | delivery_lookup_failed | The render could not be looked up just now. Nothing was done; try again. |
| 429 | slow_down | More than 200 new sign-in links from one network address in an hour. Try again in a few minutes. |
| 503 | try_again | The sign-in could not be checked just now. Nothing was done; try again. |
Deliver the score made above
curl https://mcp.ainsof.io/ \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $AINSOF_API_KEY" \
-d '{"action": "deliver_score", "video_url": "https://example.com/spot.mp4", "brief": "warm acoustic, hopeful"}'import os, requests
r = requests.post(
"https://mcp.ainsof.io/",
headers={"Authorization": f"Bearer {os.environ['AINSOF_API_KEY']}"},
json={
"action": "deliver_score",
"video_url": "https://example.com/spot.mp4",
"brief": "warm acoustic, hopeful"
},
timeout=60,
)
print(r.json())const res = await fetch("https://mcp.ainsof.io/", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${process.env.AINSOF_API_KEY}`,
},
body: JSON.stringify({
"action": "deliver_score",
"video_url": "https://example.com/spot.mp4",
"brief": "warm acoustic, hopeful"
}),
});
const data = await res.json();{
"ok": true,
"download_url": "https://mcp.ainsof.io/z/<render-id>",
"storage_signature_valid_for_hours": 1,
"ainsof_link_availability": "The AINSOF link creates a new temporary storage signature whenever it is opened and remains available until the package is deleted on its seven-day schedule.",
"format": "zip",
"contains": {
"SCORED.mp4": "the video you approved",
"audio/": "one MP3 per section, 192kbps 48kHz from the clean audio, edited to the picture exactly as used and named with the timecode it starts at. Drop each at its timecode at unity gain and you have the render — the levels are in the files.",
"SCORE.txt": "what plays where, and where the music stops",
"CUE_SHEET.csv": "the same as a spreadsheet, for delivery paperwork"
},
"pieces": "<from the render>",
"note": "The audio in this package is AINSOF's clean 192 kbps audio (no watermark), for cutting and showing — not licensed for release. Licensing delivers every file as the lossless master.",
"licensing": "… (see The licensing object)"
}Upload a video
https://mcp.ainsof.io/Create a one-time upload slot for a video that is on the user's computer, and the video_url to score it with afterwards.
RESTaction: "get_upload_link"MCPget_upload_link
- Give a person
upload_page(a page with a file picker). A client that can run commands can insteadPUTthe file toupload_urlonce, with a videoContent-Typesuch asvideo/mp4. The upload slot is valid for 2 hours. - After the upload, pass
video_urltoscore_videooranalyze_video.
Request body application/json
actionrequiredget_upload_link.filename., _ and - become _; the last 80 characters are kept.Response 200
oktrue.upload_pagehow_to_uploadupload_urlPUT.upload_commandcurl command for that PUT.video_urlnextvalid_for_hours2.noteErrors
| Status | error | When |
|---|---|---|
| 500 | could not create an upload link | The upload slot could not be created. |
| 500 | could not create a safely managed upload link | The upload could not be recorded for clean-up. |
Create an upload link
curl https://mcp.ainsof.io/ \
-H "Content-Type: application/json" \
-d '{"action": "get_upload_link", "filename": "spot.mp4"}'import os, requests
r = requests.post(
"https://mcp.ainsof.io/",
json={
"action": "get_upload_link",
"filename": "spot.mp4"
},
timeout=60,
)
print(r.json())const res = await fetch("https://mcp.ainsof.io/", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
"action": "get_upload_link",
"filename": "spot.mp4"
}),
});
const data = await res.json();{
"ok": true,
"upload_page": "https://mcp.ainsof.io/upload/<upload-id>",
"how_to_upload": "Give the user upload_page as a link to open — a page with a file picker, … ",
"upload_url": "<signed upload address>",
"upload_command": "curl -X PUT -H \"content-type: video/mp4\" --upload-file \"/path/to/spot.mp4\" \"<upload_url>\"",
"video_url": "https://mcp.ainsof.io/u/<upload-id>/spot.mp4",
"next": "Once the upload finishes, call score_my_video with video_url set to the value above and the brief they gave you.",
"valid_for_hours": 2,
"note": "The file goes straight from their machine to our storage — it never passes through this conversation. …"
}Editing
Cut a cue to length
https://mcp.ainsof.io/Cut one cue to a target length, to a video's exact length, or into a loop, optionally with every stem cut the same way.
RESTaction: "fit"MCPfit_to_length
kind: "length"returns the nearest musical length (a 5-second request may come back at 6 to 8 seconds);videoreturns exactlyseconds;loopreturns a seamless loop of whole bars close toseconds.hit_atplaces the cue's climax on that second.- Listening (
listen_url) needs nothing.download_urlopens ainsof.io, which asks the person to sign in (Google or email) before the zip downloads. Edits are kept for 7 days. - An identical request within 15 minutes returns the same edit. Each caller (key, or address when anonymous) can have two edits in progress.
Request body application/json
actionrequiredfit.track_idrequiredsecondsrequiredkind: "video", the video's length). Rounded to 0.1.kindlength, video or loop. Case-insensitive.hit_atstemsversionResponse 200
oktrue.tracktrack_id, title, album, catalogue, composers (each with perf_share), publisher, album_cover_url, album_cover_thumb_url.askedseconds, kind, hit_at, stems, version as understood.got_secondsedit_reviewmethod, review_required and a note. When review_required is true the edit is one continuous excerpt near the real ending rather than an opening joined to it: audition it before using it.howhit_lands_atstemslisten_urldownload_urlkept_for_days7.how_to_presentlicensingstatus: "preview" and edit-specific what_you_have and how_it_works.Errors
| Status | error | When |
|---|---|---|
| 400 | track_id is required | No cue named (message explains). |
| 400 | seconds must be between 1 and 300 | seconds out of range. |
| 400 | kind must be length, video or loop | Unknown kind. |
| 400 | hit_at must be a second inside the edit (and loops have no hit point) | Invalid hit_at. |
| 400 | version must be a version name such as MAIN or CUT_30 | Invalid version. |
| 400 | stems are cut from the full song only — use version MAIN with stems, or this version without stems | stems with a version other than MAIN. |
| 404 | (a sentence) | The cue was not found. |
| 429 | busy | Two edits are already in progress for this caller. |
| 429 | queue_full | Too many edits are waiting right now. Try again shortly. |
| 503 | queue_failed | The job could not be queued. Nothing was cut. |
| 202 | still_running | Repeat the identical request. |
| 503 | engine_unavailable | The editor is not responding. Nothing was cut. |
| 422 | fit_failed | The edit could not be made; message gives the reason. |
A 15-second edit
curl https://mcp.ainsof.io/ \
-H "Content-Type: application/json" \
-d '{"action": "fit", "track_id": "AIN-CAT 031_002", "seconds": 15}'import os, requests
r = requests.post(
"https://mcp.ainsof.io/",
json={
"action": "fit",
"track_id": "AIN-CAT 031_002",
"seconds": 15
},
timeout=60,
)
print(r.json())const res = await fetch("https://mcp.ainsof.io/", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
"action": "fit",
"track_id": "AIN-CAT 031_002",
"seconds": 15
}),
});
const data = await res.json();{
"ok": true,
"track": {
"track_id": "AIN-CAT 031_002",
"title": "Shine On Today",
"album": "Shining Ahead (Corporate Advertising)",
"catalogue": "AIN-CAT 031",
"composers": [
{
"ipi": "687184598",
"name": "Alon Peretz",
"society": "PRS",
"perf_share": "50%"
}
],
"publisher": "AINSOF (Or Chausha AINSOF)",
"album_cover_thumb_url": "https://mcp.ainsof.io/cover/AIN-CAT_031.jpg?v=2&w=220",
"album_cover_url": "https://mcp.ainsof.io/cover/AIN-CAT_031.jpg?v=2"
},
"asked": {
"seconds": 15,
"kind": "length",
"hit_at": null,
"stems": false,
"version": "MAIN"
},
"got_seconds": 14.626,
"edit_review": {
"method": "opening_jump_ending",
"review_required": false,
"note": "Audition the edit to judge its musical suitability."
},
"how": "The opening (5.4s), then a jump of 74 whole bars into the song's real ending.",
"hit_lands_at": null,
"stems": [],
"listen_url": "https://mcp.ainsof.io/f/969b183d-adcc-49ed-b1fb-0704e3efce3b",
"download_url": "https://mcp.ainsof.io/f/969b183d-adcc-49ed-b1fb-0704e3efce3b/zip",
"kept_for_days": 7,
"how_to_present": "Use only the AINSOF album artwork attached to this result or its album_cover_thumb_url. Never search for, generate or substitute artwork from Spotify, Apple Music or another artist. If it cannot be displayed, show the album title without an image. If edit_review.review_required is true, state that this is an ending excerpt and needs listening approval; do not describe it as a successful opening-to-ending edit. Say what was asked and what came back (lengths are musical: the nearest length where the song still ends on its real ending — a 5-second request may come back at 6-8 seconds; a video edit is exactly the video's length). Give the listen link as an ordinary markdown link, and the download link for the zip (MP3 192k mix, plus every stem cut at the same points when stems were asked for) — it opens ainsof.io, which asks the person to sign in (Google or email) before the file downloads. Do not build an audio player. Never mention job ids or how the edit was computed beyond the one-line description in `how`.",
"licensing": {
"status": "preview",
"what_you_have": "This edit is a full-quality preview for auditioning and offline editing. It does not grant permission for publication, broadcast, advertising or other release. This connector does not sell licences or initiate a purchase.",
"beyond_online": {
"note": "A preview does not grant permission for publication, broadcast, advertising or other release. This connector does not sell licences or initiate a purchase; it provides discovery, auditioning and rights information.",
"uses": [
"Trailers and promos",
"Broadcast television and radio",
"Cinema and theatrical"
]
},
"contact": "info@ainsof.io",
"how_it_works": [
"Listening is free. Downloading the zip asks for a sign-in on ainsof.io (Google or email).",
"Edits are kept for 7 days; ask again any time for a new one.",
"Cue sheets identify the music and credits; they are not a licence."
]
}
}Feedback
Send feedback
https://mcp.ainsof.io/Send AINSOF a user's verdict on an answer, only with that user's consent.
RESTaction: "feedback"MCPfeedback
- Nothing is stored unless
consentedis the booleantrue.
Request body application/json
actionrequiredfeedback.aboutrequiredverdictrequiredconsentedrequiredtrue only if the user agreed that their words may be sent to AINSOF.in_their_wordsexpectedtrack_idbriefResponse 200
oktrue.thankstell_the_userErrors
| Status | error | When |
|---|---|---|
| 400 | about is required — which tool is this feedback for? | about missing. |
| 400 | verdict must be good, bad or partly | Invalid verdict. |
| 400 | consent_required | consented is not true. Nothing was stored. |
| 503 | feedback_not_confirmed | The feedback could not be confirmed as saved. |
Send consented feedback
curl https://mcp.ainsof.io/ \
-H "Content-Type: application/json" \
-d '{"action": "feedback", "about": "search_music", "verdict": "partly", "consented": true, "in_their_words": "<their words>", "brief": "warm acoustic, hopeful"}'import os, requests
r = requests.post(
"https://mcp.ainsof.io/",
json={
"action": "feedback",
"about": "search_music",
"verdict": "partly",
"consented": True,
"in_their_words": "<their words>",
"brief": "warm acoustic, hopeful"
},
timeout=60,
)
print(r.json())const res = await fetch("https://mcp.ainsof.io/", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
"action": "feedback",
"about": "search_music",
"verdict": "partly",
"consented": true,
"in_their_words": "<their words>",
"brief": "warm acoustic, hopeful"
}),
});
const data = await res.json();{
"ok": true,
"thanks": "Logged. Thank you.",
"tell_the_user": "Nothing. Do not mention that feedback was sent."
}MCP server
Endpoint: https://mcp.ainsof.io, Streamable HTTP. POST one JSON-RPC 2.0 message per request; every response is application/json. No SSE stream is offered (GET returns 405) and no session id is issued. Batched JSON-RPC arrays are not supported.
Protocol versions: 2024-11-05, 2025-03-26, 2025-06-18, 2025-11-25. The server answers with the version the client asked for, or 2025-11-25 if it does not know it.
Methods: initialize, ping, notifications/* (answered 202 with no body), tools/list, tools/call, resources/list, resources/read. Any other method returns JSON-RPC error -32601.
Keys: only tools/call checks the key; initialize and tools/list work without one. Pass the key as an HTTP header, in any client that lets you set one on a remote MCP server. In Claude Code:
claude mcp add --transport http ainsof https://mcp.ainsof.io --header "Authorization: Bearer $AINSOF_API_KEY"
Without the header, tools run anonymously under the anonymous allowance.
Tool results: the first content block of every tools/call result is the JSON text of the same object the matching REST action returns. After it, get_track, cue_sheet, listen_link and fit_to_length attach the album cover as an image, preceded by a text line AINSOF album cover — <album> · <code>; search_music, search_by_reference, find_similar and find_soundtrack attach up to four album covers at 120 px, each preceded by a text line naming the album; those four and fit_to_length also return the object as structuredContent; analyze_video attaches its storyboard frames as images, each preceded by its timecode, and removes jpeg_b64 from the JSON.
Errors: a failed tool call is a normal JSON-RPC result with isError: true, and its text block holds the same {ok: false, error, …} object as REST. still_running and sign_in_required are returned with isError: false. HTTP status is 200 either way.
about_ainsof has no REST action. It returns a description of AINSOF, its library, technology, privacy and data handling.
Calling a tool that does not exist returns a result with isError: true and unknown tool: <name>. Batched JSON-RPC arrays are not supported.
Video tools and sign-in: without a key created on ainsof.io, analyze_video, score_my_video and deliver_score first answer sign_in_required (not an error) with sign_in_url and sign_in_code. Show the link; when the person says they have signed in, call the tool again with the same arguments plus sign_in_code, and keep passing it to every video tool in the conversation.
Tools
| Tool | Title | REST action | Required |
|---|---|---|---|
find_soundtrack | Find a soundtrack for a video | soundtrack | duration_sec |
score_my_video | Put AINSOF music onto a video | score_video | video_url |
deliver_score | Get the finished score as files | deliver_score | video_url |
fit_to_length | Cut a cue to any length | fit | track_id, seconds |
get_upload_link | Upload a video from this computer | get_upload_link | None |
feedback | Send AINSOF the user's feedback, with their consent | feedback | about, verdict, consented |
analyze_video | Understand a video | analyze_video | video_url |
search_music | Search AINSOF music by description | search (with brief) | brief |
search_by_reference | Find music that sounds like a reference | search (with link) | link |
listen_link | Get a listen link for a track | preview | track_id |
about_ainsof | Who AINSOF is | — (MCP only) | None |
cue_sheet | Get a track's cue sheet | cue_sheet | track_id |
get_track | Get full details for one track | track | track_id |
find_similar | Find tracks like an AINSOF track | similar | track_id |
initialize
curl https://mcp.ainsof.io/ \
-H "Content-Type: application/json" \
-d '{"jsonrpc": "2.0", "id": 1, "method": "initialize", "params": {"protocolVersion": "2025-06-18", "capabilities": {}, "clientInfo": {"name": "my-app", "version": "1.0"}}}'{
"jsonrpc": "2.0",
"id": 1,
"result": {
"protocolVersion": "2025-06-18",
"instructions": "AINSOF is a music superpowers creative company. Powered by a curated licensed\ncatalogue and AI tools, built for sync. Ne …",
"capabilities": {
"tools": {},
"resources": {},
"extensions": {
"io.modelcontextprotocol/ui": {
"mimeTypes": [
"text/html;profile=mcp-app"
]
}
}
},
"serverInfo": {
"name": "AINSOF",
"title": "AINSOF",
"version": "1.0.8",
"description": "Human-made production music and purpose-built technology for matching music to picture — a curated AINSOF catalogue that …",
"websiteUrl": "https://mcp.ainsof.io/",
"icons": [
{
"src": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAIBElEQVR4nNVYfUxUVxY/97xhZACHzxmDKaYrWqNAtto1LYK0Zb …",
"mimeType": "image/png",
"sizes": [
"48x48"
]
},
{
"src": "https://mcp.ainsof.io/assets/icon-48.png?v=20260803-2",
"mimeType": "image/png",
"sizes": [
"48x48"
]
},
{
"src": "https://mcp.ainsof.io/assets/icon-96.png?v=20260803-2",
"mimeType": "image/png",
"sizes": [
"96x96"
]
}
]
}
}
}tools/call (get_track)
curl https://mcp.ainsof.io/ \
-H "Content-Type: application/json" \
-d '{"jsonrpc": "2.0", "id": 5, "method": "tools/call", "params": {"name": "get_track", "arguments": {"track_id": "AIN-CAT 031_002"}}}'{
"jsonrpc": "2.0",
"id": 5,
"result": {
"content": [
{
"type": "text",
"text": "{\n \"ok\": true,\n \"credits\": {\n \"track_id\": \"AIN-CAT 031_002\",\n \"catalogue …"
},
{
"type": "text",
"text": "AINSOF album cover — Shining Ahead (Corporate Advertising) · AIN-CAT 031"
},
{
"type": "image",
"data": "<base64 JPEG>",
"mimeType": "image/jpeg"
}
],
"isError": false
}
}tools/call with an unrecognised key
curl https://mcp.ainsof.io/ \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ain_000000000000000000000000" \
-d '{"jsonrpc": "2.0", "id": 8, "method": "tools/call", "params": {"name": "get_track", "arguments": {"track_id": "AIN-CAT 031_002"}}}'{
"jsonrpc": "2.0",
"id": 8,
"result": {
"content": [
{
"type": "text",
"text": "{\n \"ok\": false,\n \"error\": \"unauthorized\",\n \"message\": \"That key is not recognised.\"\n}"
}
],
"isError": true
}
}