Un server MCP transformă un API în câteva instrumente cu nume, pe care un agent le apelează în mijlocul unei conversații, iar o job lungă încape în spatele unui astfel de instrument atunci când instrumentul returnează un handle la care agentul așteaptă în tururi limitate. Lipești un link de podcast, ceri rezumatul în franceză și nu se scrie niciun cod.
Un agent de cod poate folosi API-ul VocalStack așa cum o face orice program: citește referința API, scrie câteva linii cu SDK-ul și le rulează. Aceasta este calea potrivită pentru ceva ce va rula fără agent.
MCP (Model Context Protocol) este pentru celălalt caz: vorbești cu un asistent și vrei ca el să transcrie ceva acum, fără cod. Un server MCP publică o listă scurtă de instrumente cu nume, fiecare cu o descriere și o schemă JSON pentru argumentele sale. Agentul citește lista o singură dată și apelează un instrument după nume atunci când o cerere se potrivește cu el. „Transcrie acest podcast și spune-mi ce au spus despre prețuri” devine trei apeluri de instrumente, iar agentul nu vede niciodată o rută HTTP.
Serverele sunt de două feluri. Un server local rulează ca subproces al clientului și comunică prin stdio, cum funcționează majoritatea serverelor pentru sisteme de fișiere și baze de date. Un server la distanță stă în spatele unui URL și vorbește Streamable HTTP, transportul care l-a înlocuit pe vechiul HTTP-plus-SSE (server-sent events) în revizia din martie 2025 a specificației. Clientul trimite fiecare cerere, iar serverul răspunde pe aceeași conexiune; orice are de spus înainte de rezultatul final este transmis în flux înaintea lui. Orice client scris pentru specificația actuală poate folosi oricare dintre cele două tipuri.
Serverul VocalStack este de tipul la distanță, la {{api}}/v1/mcp, iar folosirea lui costă cât costă API-ul. Tot ce ai nevoie este URL-ul.
Deschide zona Developers din Dashboard, la {{app}}/developers. Primul tab, Connect an AI agent, arată URL-ul serverului și un fragment de configurare pentru fiecare client. Cele trei fragmente de mai jos corespund celor afișate acolo.
Rulează aceasta în terminal:
claude mcp add --transport http vocalstack {{api}}/v1/mcp
Adaugă aceasta în .cursor/mcp.json din proiectul tău, sau în ~/.cursor/mcp.json pentru fiecare proiect:
{"mcpServers":{"vocalstack":{"url":"{{api}}/v1/mcp"}}}
Orice client care suportă Streamable HTTP poate adăuga serverul cu acest URL. Aceasta este forma generică afișată de Dashboard:
{
"vocalstack": {
"type": "streamable-http",
"url": "{{api}}/v1/mcp"
}
}
Nu ai nevoie de o cheie API ca să începi. La prima conectare a clientului, te autentifici cu contul tău VocalStack în browser, iar clientul păstrează tokenul. Dashboard-ul o spune într-o singură frază: „You'll sign in with your VocalStack account the first time. No key needed.”
Aceasta este specificația de autorizare MCP în acțiune, nu un truc al VocalStack. Un server la distanță răspunde unei cereri neautentificate cu un 401 care indică metadatele sale de resursă protejată: un document JSON mic care numește serverul de autorizare și scopurile cerute de server. Clientul le citește, rulează în browser un flux OAuth 2.1 standard și revine cu un token emis doar pentru acel server. Orice server MCP la distanță care urmează specificația te autentifică în același fel, motiv pentru care clienții de mai sus pot face asta fără să știe nimic despre VocalStack.
Funcționează și o cheie API, pentru un client care rulează pe un server sau într-un script. Trimite-o ca Authorization: Bearer vs_key_..., același header pe care îl acceptă API-ul REST. Cheile se creează la Developers → API keys. Cele două instrumente de transcriere au nevoie de permisiunile Write și Stream audio. A doua pare ciudată pentru un fișier, dar instrumentele trec prin același punct de creare ca orice transcriere, inclusiv cele live, iar acel punct verifică ambele. Instrumentele de citire au nevoie de Read; list_voices cere doar o credențială validă.
Odată autentificat, agentul vede nouă instrumente. Rareori le vei numi tu, dar a le cunoaște explică ce face agentul mai departe.
Fiecare instrument primește și returnează JSON în camelCase, cu aceleași nume de câmpuri ca tipurile de pe fir din /v1; handle-ul unei transcrieri este transcriptionId.
transcribe_url pornește transcrierea unui audio sau video de la un URL public: un link către un fișier, un episod de podcast, un videoclip YouTube. Transmisiunile live nu sunt acceptate. Argumente opționale: name, spokenLanguage (omite-l ca limba să fie detectată), speakerLabels (auto, on sau off) și startS/endS pentru a transcrie doar o parte a audio-ului.transcribe_file face același lucru pentru un fișier pe care agentul îl are, trimis ca fileBase64 cu filename. Dimensiunea decodată este limitată la 10 MiB, aproximativ zece minute de MP3 la 128 kbps; pentru ceva mai mare, dă agentului un link.Ambele returnează imediat transcriptionId, state: "queued" și un indiciu next care numește instrumentul de așteptare. Transcrierile create de agent pornesc private, fără link de partajare.
Un agent nu poate aștepta o transmisiune live mai răbdător decât poți tu; ar apela tot timpul instrumentul de așteptare până când cineva i-ar lua laptopul. O înregistrare terminată are un sfârșit, iar asta așteaptă următoarea pereche de instrumente.
Un apel de instrument este o cerere HTTP, iar cererile HTTP nu sunt făcute să dureze o oră. Clienții renunță la ele, proxy-urile le închid, iar un model blocat pe un instrument nu poate face altceva. Așadar, modelul pentru orice job lung prin MCP este cel pe care îl folosește și API-ul REST: pornești jobul și primești un handle, aștepți o vreme limitată și apelezi din nou dacă nu e gata. Handle-ul, nu conexiunea, poartă starea.
wait_for_transcription blochează până când jobul ajunge done sau failed, sau până trece timeoutS (implicit 50 de secunde, maximum 60, ceea ce păstrează apelul sub timeout-urile pe care le aplică majoritatea clienților și proxy-urilor). Dacă rezultatul spune timedOut: true, jobul încă rulează, iar agentul apelează din nou instrumentul. Cât timp instrumentul așteaptă, serverul trimite notificări de progres MCP dacă clientul le-a cerut: un procent și o fază, de exemplu „fetching 3.1 / 8.0 MB” sau „transcribing 01:25 of 02:00”.get_transcription returnează starea și, odată terminat, textul. format: "text" dă câte o linie pe segment, sub forma [mm:ss] Speaker 1: ...; "segments" dă linii cu timp, cu start, end, speaker și speakerName; includeWords: true adaugă timpii cuvintelor. Rezultatele sunt paginate (offset, limit, implicit 500 de segmente), cu un nextOffset când mai rămân.Paginarea există pentru model, nu pentru rețea. Tot ce returnează un instrument este lipit în fereastra de context a agentului, unde concurează cu conversația ta și costă tokeni la fiecare tură ulterioară. O ședință de două ore înseamnă zeci de mii de cuvinte; dacă ar returna totul deodată, întrebarea ta ar ieși din context. Instrumentele MCP bune returnează o pagină și un cursor și lasă agentul să decidă cât are nevoie.
O deconectare sau un timeout nu anulează niciodată jobul, pentru că jobul trăiește pe server, nu în cererea MCP. Odată terminat, jobul devine o intrare în plus în biblioteca ta, iar următoarele instrumente îl tratează ca pe oricare altul.
list_transcriptions listează transcrierile contului, cele mai noi primele, cu stare și durată; lifecycle este active, archived sau all.search_transcriptions caută ce s-a spus în toate transcrierile, în orice limbă, și returnează liniile care se potrivesc, fiecare cu transcrierea sa și secunda în care a fost rostită. transcriptionId restrânge căutarea la o singură transcriere; lang adaugă o traducere a fiecărui rezultat.Găsirea unei linii este jumătatea ieftină. Alte două instrumente stabilesc ce a spus întregul.
get_summary returnează titlul AI și rezumatul unei transcrieri terminate, opțional tradus cu lang. state: "pending" înseamnă că rezumatul este încă scris (de obicei e gata în câteva secunde după terminarea jobului), iar agentul întreabă din nou.translate_transcription returnează o transcriere terminată într-o altă limbă, ca text sau segmente cu timp, paginată ca get_transcription. Traducerile sunt stocate, deci a cere din nou nu repetă lucrul.list_voices listează vocile care pot citi o transcriere într-o limbă: id, nume, gen și accent când sunt cunoscute, o notă de calitate și dacă este vocea implicită sau una dintre vocile tale clonate. Descrie vocile; nu face una să spună ceva (mai multe despre ce nu face serverul, mai jos).Iată cum se înlănțuie instrumentele în practică.
Odată adăugat serverul, o conversație în Claude Code arată așa. Lipești un link de podcast și ceri rezumatul în franceză.
Agentul apelează transcribe_url:
{ "url": "https://example.org/episodes/42.mp3", "name": "Episode 42", "speakerLabels": "auto" }
Primește înapoi un transcriptionId și state: "queued" și urmează indiciul next:
{ "transcriptionId": "4f1c...", "timeoutS": 50 }
Un episod de cincizeci de minute se transcrie de multe ori mai repede decât se redă, dar nu într-o singură așteptare. Prima așteptare returnează timedOut: true cu progres de, să zicem, 61 la sută, deci agentul mai apelează o dată și primește state: "done".
Acum agentul apelează get_summary cu lang: "fr":
{ "transcriptionId": "4f1c...", "lang": "fr" }
Dacă rezumatul este încă pending, agentul așteaptă câteva secunde; altfel îți dă un titlu și un rezumat în franceză. Întrebi „unde au vorbit despre prețuri?” și agentul apelează search_transcriptions cu query: "pricing" și același transcriptionId, citând liniile care se potrivesc cu marcajele lor de timp. Dacă vrei tot textul în franceză, apelează translate_transcription.
Câteva apeluri de instrumente, fără cod, și o transcriere în bibliotecă. Fiecare dintre aceste apeluri a trecut prin aceleași porți ca o cerere REST, iar acele porți stabilesc factura și limitele.
Serverul MCP este API-ul prin altă intrare: aceleași limite, aceeași factură.
POST /v1/transcriptions: se aplică rata de creare a planului (10, 100 sau un număr personalizat de transcrieri pornite pe oră), plafonul de transcrieri simultane (1, 5 sau nelimitat) și creditul tău. Creditul de $5 de la înregistrare acoperă o primă sesiune, fără card.isError: true cu codul de eroare al API-ului REST, o propoziție pe care modelul o poate folosi și câmpurile retryable și retryAfterS. insufficient_credit vine cu un topUpUrl; rate_limited spune cât să aștepți. Asta contează mai mult decât pare: un model citește textul erorii, deci o propoziție pe care o poate folosi transformă un impas în următorul apel de instrument./v1/mcp în sine: un agent în buclă primește un HTTP 429 cu Retry-After înainte ca vreun instrument să ruleze.idempotencyKey: refolosirea cheii unui apel terminat reia primul rezultat, iar refolosirea ei cu alte argumente este refuzată, deci un agent care reîncearcă de unul singur nu pornește niciodată un al doilea job. Orice instrument care cheltuie bani ar trebui să ofere asta; agenții reîncearcă mult mai liber decât oamenii.Acestea sunt marginile a ceea ce face serverul. Două lucruri rămân în afara lor, intenționat.
Serverul nu are niciun instrument care transformă text arbitrar în vorbire, și nu se planifică unul. VocalStack vorbește transcrieri și traducerile lor, cu o voce predefinită sau clonată, și nimic altceva. list_voices îi spune unui agent ce voci pot citi o transcriere într-o limbă, nu cum să faci o voce să spună ceva nou.
Instrumentele de transcriere refuză și transmisiunile live. Un stream YouTube live sau un stream radio are nevoie de o transcriere live, pornită din Dashboard sau prin POST /v1/transcriptions/live din referința API. Un videoclip YouTube terminat este un fișier, iar transcribe_url îl acceptă.
Dacă preferi să scrii singur codul, transcrierea unui fișier cu API-ul parcurge aceiași pași ca apelurile HTTP, iar tutorialul în timp real acoperă WebSocket-ul.