Un serveur MCP transforme une API en quelques outils nommés qu'un agent appelle au cours d'une conversation, et une tâche longue s'y intègre lorsque l'outil renvoie un identifiant sur lequel l'agent attend par tours bornés. Collez le lien d'un podcast, demandez-en l'essentiel en français, et aucun code n'est écrit.
Un agent de codage peut utiliser l'API VocalStack comme n'importe quel programme : il lit la référence de l'API, écrit quelques lignes avec le SDK, et les exécute. C'est la bonne voie pour un traitement qui tournera sans l'agent.
MCP (le Model Context Protocol) sert à l'autre cas : vous dialoguez avec un assistant et voulez qu'il transcrive quelque chose tout de suite, sans code. Un serveur MCP publie une courte liste d'outils nommés, chacun avec une description et un schéma JSON pour ses arguments. L'agent lit cette liste une fois, et appelle un outil par son nom lorsqu'une demande correspond. « Transcris ce podcast et dis-moi ce qu'ils ont dit sur les tarifs » devient trois appels d'outils, et l'agent ne voit jamais de route HTTP.
Il existe deux types de serveurs. Un serveur local s'exécute comme sous-processus du client et communique via stdio, ce qui est le cas de la plupart des serveurs de système de fichiers et de bases de données. Un serveur distant se trouve derrière une URL et parle Streamable HTTP, le transport qui a remplacé l'ancien transport HTTP-plus-SSE (server-sent events) dans la révision de mars 2025 de la spécification. Le client envoie chaque requête, et le serveur répond sur la même connexion ; ce qu'il doit dire avant le résultat final est diffusé en amont. Tout client conforme à la spécification actuelle peut utiliser l'un ou l'autre type.
Le serveur de VocalStack est du type distant, à l'adresse {{api}}/v1/mcp, et son usage coûte ce que coûte l'API. Il suffit de l'URL.
Ouvrez la zone Developers du tableau de bord, à l'adresse {{app}}/developers. Le premier onglet, Connect an AI agent, affiche l'URL du serveur et un extrait de configuration pour chaque client. Les trois extraits ci-dessous correspondent à ceux affichés là-bas.
Exécutez cette commande dans votre terminal :
claude mcp add --transport http vocalstack {{api}}/v1/mcp
Ajoutez ceci à .cursor/mcp.json dans votre projet, ou à ~/.cursor/mcp.json pour tous les projets :
{"mcpServers":{"vocalstack":{"url":"{{api}}/v1/mcp"}}}
Tout client qui prend en charge Streamable HTTP peut ajouter le serveur avec cette URL. Voici la forme générique affichée par le tableau de bord :
{
"vocalstack": {
"type": "streamable-http",
"url": "{{api}}/v1/mcp"
}
}
Vous n'avez pas besoin de clé API pour commencer. À la première connexion du client, vous vous connectez à votre compte VocalStack dans le navigateur, et le client conserve le jeton. Le tableau de bord le résume en une ligne : « Vous vous connecterez avec votre compte VocalStack la première fois. Aucune clé nécessaire. »
C'est la spécification d'autorisation de MCP à l'œuvre, pas une astuce de VocalStack. Un serveur distant répond à une requête non authentifiée par une 401 qui renvoie vers ses métadonnées de ressource protégée : un petit document JSON qui nomme le serveur d'autorisation et les scopes que le serveur exige. Le client le lit, lance un flux OAuth 2.1 standard dans votre navigateur, et revient avec un jeton émis pour ce seul serveur. Tout serveur MCP distant qui suit la spécification vous connecte de la même façon, ce qui permet aux clients ci-dessus de le faire sans rien savoir de VocalStack.
Une clé API fonctionne aussi, pour un client qui tourne sur un serveur ou dans un script. Envoyez-la sous la forme Authorization: Bearer vs_key_..., le même en-tête qu'accepte l'API REST. Les clés se créent sous Developers → API keys. Les deux outils de transcription exigent les permissions Write et Stream audio. La seconde surprend pour un fichier, mais les outils passent par le même point de création que toute transcription, y compris les transcriptions en direct, et ce point vérifie les deux. Les outils de lecture demandent Read ; list_voices n'exige qu'un identifiant valide.
Une fois connecté, l'agent voit neuf outils. Vous les nommerez rarement vous-même, mais les connaître explique ce que fait l'agent ensuite.
Chaque outil prend et renvoie du JSON en camelCase, avec les mêmes noms de champs que les types de /v1 ; l'identifiant d'une transcription est son transcriptionId.
transcribe_url lance la transcription d'un contenu audio ou vidéo à une URL publique : un lien vers un fichier, un épisode de podcast, une vidéo YouTube. Les flux en direct ne sont pas acceptés. Arguments facultatifs : name, spokenLanguage (omettez-le pour détecter la langue), speakerLabels (auto, on ou off) et startS/endS pour ne transcrire qu'une partie de l'audio.transcribe_file fait de même pour un fichier que l'agent détient, envoyé en fileBase64 avec son filename. La taille décodée est limitée à 10 MiB, soit environ dix minutes de MP3 à 128 kbit/s ; pour un contenu plus volumineux, donnez à l'agent un lien.Les deux renvoient immédiatement le transcriptionId, state: "queued" et un indice next nommant l'outil d'attente. Les transcriptions créées par un agent démarrent en privé, sans lien de partage.
Un agent ne peut pas suivre une diffusion en direct plus patiemment que vous ; il appellerait l'outil d'attente jusqu'à ce qu'on lui retire l'ordinateur. Un enregistrement terminé a une fin, et c'est ce qu'attend la paire d'outils suivante.
Un appel d'outil est une seule requête HTTP, et les requêtes HTTP ne sont pas censées durer une heure. Les clients abandonnent, les proxys les coupent, et un modèle bloqué sur un outil ne peut rien faire d'autre. Le schéma pour tout traitement long derrière MCP est donc celui que suit aussi l'API REST : lancer le traitement et obtenir un identifiant, attendre pendant un temps borné, puis rappeler si ce n'est pas terminé. L'état est porté par l'identifiant, pas par la connexion.
wait_for_transcription bloque jusqu'à ce que le traitement soit done ou failed, ou jusqu'à ce que timeoutS soit écoulé (50 secondes par défaut, 60 au maximum, ce qui garde l'appel sous les délais que la plupart des clients et proxys appliquent). Si le résultat indique timedOut: true, le traitement tourne encore et l'agent rappelle l'outil. Pendant l'attente, le serveur envoie des notifications de progression MCP si le client les a demandées : un pourcentage et une phase, par exemple "fetching 3.1 / 8.0 MB" ou "transcribing 01:25 of 02:00".get_transcription renvoie l'état et, une fois terminé, le texte. format: "text" donne une ligne par segment sous la forme [mm:ss] Speaker 1: ... ; "segments" donne des lignes horodatées avec start, end, speaker et speakerName ; includeWords: true ajoute les horodatages des mots. Les résultats sont paginés (offset, limit, 500 segments par défaut) avec un nextOffset lorsqu'il en reste.La pagination existe pour le modèle, pas pour le réseau. Tout ce qu'un outil renvoie est collé dans la fenêtre de contexte de l'agent, où il rivalise avec votre conversation et coûte des jetons à chaque tour suivant. Une réunion de deux heures représente des dizaines de milliers de mots ; tout renvoyer d'un coup repousserait la question posée hors du contexte. Les bons outils MCP renvoient une page et un curseur, et laissent l'agent décider de ce dont il a besoin.
Une déconnexion ou un délai d'attente n'annule jamais le traitement, car le traitement vit sur le serveur, pas dans la requête MCP. Une fois terminé, il devient une entrée de plus dans votre bibliothèque, et les outils suivants le traitent comme les autres.
list_transcriptions liste les transcriptions du compte, de la plus récente à la plus ancienne, avec l'état et la durée ; lifecycle vaut active, archived ou all.search_transcriptions recherche ce qui a été dit dans toutes les transcriptions, dans n'importe quelle langue, et renvoie les lignes correspondantes, chacune avec sa transcription et la seconde où elle a été prononcée. transcriptionId restreint la recherche à une seule transcription ; lang ajoute une traduction de chaque résultat.Trouver une ligne est la moitié facile. Deux autres outils déterminent ce que l'ensemble a dit.
get_summary renvoie le titre et le résumé générés par l'IA d'une transcription terminée, éventuellement traduits avec lang. state: "pending" signifie que le résumé est encore en cours de rédaction (il est généralement prêt quelques secondes après la fin du traitement), et l'agent repose la question.translate_transcription renvoie une transcription terminée dans une autre langue, sous forme de texte ou de segments horodatés, paginée comme get_transcription. Les traductions sont conservées, donc redemander ne refait pas le travail.list_voices liste les voix capables de lire une transcription dans une langue : identifiant, nom, genre et accent lorsqu'ils sont connus, une note de qualité, et si c'est la voix par défaut ou l'une de vos voix clonées. Il décrit les voix ; il ne fait pas parler l'une d'elles (voir plus loin ce que le serveur ne fait pas).Voici comment les outils s'enchaînent en pratique.
Une fois le serveur ajouté, une conversation dans Claude Code se déroule ainsi. Vous collez le lien d'un podcast et demandez-en l'essentiel en français.
L'agent appelle transcribe_url :
{ "url": "https://example.org/episodes/42.mp3", "name": "Episode 42", "speakerLabels": "auto" }
Il reçoit un transcriptionId et state: "queued", et suit l'indice next :
{ "transcriptionId": "4f1c...", "timeoutS": 50 }
Un épisode de cinquante minutes est transcrit bien plus vite qu'il ne se joue, mais pas en un seul appel d'attente. Le premier appel d'attente renvoie timedOut: true avec une progression à, disons, 61 %, si bien que l'agent rappelle l'outil une fois de plus et obtient state: "done".
L'agent appelle maintenant get_summary avec lang: "fr" :
{ "transcriptionId": "4f1c...", "lang": "fr" }
Si le résumé est encore pending, l'agent attend quelques secondes ; sinon il vous remet un titre et un résumé en français. Demandez « où ont-ils parlé des tarifs ? », et il appelle search_transcriptions avec query: "pricing" et le même transcriptionId, puis cite les lignes correspondantes avec leurs horodatages. Demandez la totalité en français, et il appelle translate_transcription.
Quelques appels d'outils, aucun code, et une transcription dans votre bibliothèque. Chacun de ces appels est passé par les mêmes contrôles qu'une requête REST, et ce sont ces contrôles qui fixent la facturation et les limites.
Le serveur MCP est l'API par une autre porte : mêmes limites, même facturation.
POST /v1/transcriptions : le plafond de création du forfait (10, 100 ou un nombre personnalisé de transcriptions lancées par heure), son plafond de transcriptions simultanées (1, 5 ou illimité) et son crédit s'appliquent tous. Le crédit d'inscription de $5 couvre une première session, sans carte bancaire.isError: true avec le code d'erreur de l'API REST, une phrase que le modèle peut exploiter, et les champs retryable et retryAfterS. insufficient_credit porte une topUpUrl ; rate_limited indique combien de temps attendre. Cela compte plus qu'il n'y paraît : un modèle lit le texte de l'erreur, donc une phrase exploitable transforme une impasse en appel d'outil suivant./v1/mcp elle-même : un agent en boucle reçoit un HTTP 429 avec Retry-After avant que tout outil ne tourne.idempotencyKey : réutiliser la clé d'un appel terminé rejoue le premier résultat, et la réutiliser avec d'autres arguments est refusé, si bien qu'un agent qui réessaie de son propre chef ne lance jamais un second traitement. Tout outil qui dépense de l'argent devrait proposer cette option ; les agents réessaient bien plus librement que les humains.Ce sont les bords de ce que fait le serveur. Deux choses restent délibérément hors de ces bords.
Le serveur n'a aucun outil qui transforme un texte arbitraire en parole, et aucun n'est prévu. VocalStack fait lire les transcriptions et leurs traductions, avec une voix prédéfinie ou clonée, et rien d'autre. list_voices indique à un agent quelles voix peuvent lire une transcription dans une langue, pas comment faire dire quelque chose de nouveau à une voix.
Les outils de transcription refusent aussi les flux en direct. Un flux de diffusion YouTube en direct ou une radio demande une transcription en direct, lancée depuis le tableau de bord ou via POST /v1/transcriptions/live dans la référence de l'API. Une vidéo YouTube terminée est un fichier, et transcribe_url la prend en charge.
Si vous préférez écrire le code vous-même, transcrire un fichier avec l'API détaille les mêmes étapes sous forme d'appels HTTP, et le tutoriel temps réel couvre le WebSocket.