Bir MCP sunucusu bir API'yi, ajanın konuşma sırasında çağırdığı birkaç adlandırılmış araca dönüştürür. Araç, ajanın sınırlı turlarda beklediği bir tutacak verdiğinde uzun bir iş de bunun arkasına sığar. Bir podcast bağlantısı yapıştırın, Fransızca özetini isteyin; hiç kod yazılmaz.
Bir kodlama ajanı, VocalStack API'sini herhangi bir program gibi kullanabilir: API referansını okur, SDK ile birkaç satır yazar ve çalıştırır. Ajanın yanında çalışmayacak bir iş için doğru yol budur.
MCP (Model Context Protocol), başka durum içindir: bir asistanla konuşuyorsunuz ve kod yazmadan bir şeyin hemen transkripsiyonunu istiyorsunuz. Bir MCP sunucusu, her biri açıklaması ve argümanları için JSON şeması olan kısa bir adlandırılmış araç listesi yayımlar. Ajan listeyi bir kez okur ve bir istek bir araçla eşleştiğinde onu adıyla çağırır. "Bu podcast'i transkript et ve fiyatlandırma hakkında ne söylediklerini anlat" isteği üç araç çağrısına dönüşür ve ajan hiçbir HTTP yolunu görmez.
Sunucular iki türde gelir. Yerel sunucu, istemcinin alt süreci olarak çalışır ve stdio üzerinden konuşur; dosya sistemi ve veritabanı sunucularının çoğu böyle çalışır. Uzak sunucu bir URL arkasında durur ve Streamable HTTP konuşur; bu, belirtimin Mart 2025 revizyonunda eski HTTP-plus-SSE (server-sent events) taşıyıcısının yerini alan taşıyıcıdır. İstemci her isteği gönderir, sunucu yanıtı aynı bağlantı üzerinden verir; son sonuçtan önce söylemek istediği her şey ondan önce akıtılır. Güncel belirtime göre yazılmış her istemci iki türü de kullanabilir.
VocalStack'in sunucusu uzak türdendir, adresi {{api}}/v1/mcp ve kullanımı API'nin maliyetine denk gelir. Tek ihtiyacınız olan URL'dir.
Panel'in {{app}}/developers Developers alanını açın. İlk sekme olan Connect an AI agent, sunucu URL'sini ve her istemci için kurulum kodunu gösterir. Aşağıdaki üç kod parçası oradakilerle aynıdır.
Terminalinizde bunu çalıştırın:
claude mcp add --transport http vocalstack {{api}}/v1/mcp
Bu kodu projenizdeki .cursor/mcp.json dosyasına ekleyin ya da her proje için ~/.cursor/mcp.json dosyasına ekleyin:
{"mcpServers":{"vocalstack":{"url":"{{api}}/v1/mcp"}}}
Streamable HTTP destekleyen her istemci sunucuyu bu URL ile ekleyebilir. Aşağıdaki, Panel'in gösterdiği genel biçimdir:
{
"vocalstack": {
"type": "streamable-http",
"url": "{{api}}/v1/mcp"
}
}
Başlamak için API anahtarına ihtiyacınız yok. İstemci ilk kez bağlandığında tarayıcıda VocalStack hesabınızla giriş yaparsınız ve istemci token'ı saklar. Panel bunu tek satırda belirtir: "İlk seferinde VocalStack hesabınızla giriş yapacaksınız. Anahtar gerekmez."
Bu, VocalStack'e özgü bir numara değil, MCP'nin yetkilendirme belirtiminin çalışmasıdır. Uzak bir sunucu, kimliği doğrulanmamış isteğe, korumalı kaynak üst verisine işaret eden bir 401 yanıtı verir: sunucunun hangi yetkilendirme sunucusunu ve hangi kapsamları istediğini adlandıran küçük bir JSON belgesi. İstemci bunu okur, tarayıcınızda standart bir OAuth 2.1 akışı çalıştırır ve yalnızca o sunucu için verilmiş bir token ile geri döner. Belirtimi izleyen her uzak MCP sunucusu sizi aynı şekilde oturum açtırır; yukarıdaki istemcilerin VocalStack hakkında hiçbir şey bilmeden bunu yapabilmesinin nedeni budur.
Bir API anahtarı da çalışır; sunucuda ya da bir betikte çalışan bir istemci için. Anahtarı Authorization: Bearer vs_key_... olarak gönderin; REST API'nin kabul ettiği başlığın aynısıdır. Anahtarlar Developers → API keys altında oluşturulur. İki transkripsiyon aracı Write ve Stream audio izinlerini gerektirir. İkincisi bir dosya için garip görünebilir, ama araçlar her transkripsiyonun geçtiği, canlılar dahil, aynı oluşturma noktasından geçer ve bu nokta ikisini de denetler. Okuma araçları Read ister; list_voices yalnızca geçerli bir kimlik bilgisi ister.
Oturum açtığınızda ajan dokuz araç görür. Bunları kendiniz nadiren adlandıracaksınız, ama ajanın bir sonraki adımda ne yaptığını anlamak için bilmek işe yarar.
Her araç camelCase JSON alır ve döndürür; alan adları /v1 wire türleriyle aynıdır. Bir transkripsiyonun tutacağı transcriptionId'dir.
transcribe_url, herkese açık bir URL'deki ses ya da videoyu transkripsiyona başlatır: bir dosya bağlantısı, bir podcast bölümü, bir YouTube videosu. Canlı yayınlar kabul edilmez. İsteğe bağlı argümanlar: name, spokenLanguage (dili algılamak için atlayın), speakerLabels (auto, on veya off) ve yalnızca bir kısmını transkript etmek için startS/endS.transcribe_file aynısını, ajanın elinde olan bir dosya için yapar; filename ile birlikte fileBase64 olarak gönderilir. Çözülmüş boyut 10 MiB ile sınırlıdır, yaklaşık on dakikalık 128 kbps MP3; daha büyükler için ajana bir bağlantı verin.Her ikisi de hemen transcriptionId, state: "queued" ve bekleme aracını gösteren bir next ipucuyla döner. Ajanın oluşturduğu transkripsiyonlar özel olarak başlar, paylaşım bağlantısı olmadan.
Ajan canlı bir yayını sizin kadar sabırla izleyemez; biri dizüstü bilgisayarı elinden alana kadar bekleme aracını çağırmaya devam ederdi. Bitmiş bir kaydın bir sonu vardır ve sonraki araç çifti bunu bekler.
Bir araç çağrısı tek bir HTTP isteğidir ve HTTP istekleri bir saat sürmek için tasarlanmamıştır. İstemciler onlardan vazgeçer, proxy'ler bağlantıyı kapatır ve tek bir araçta takılan bir model başka hiçbir şey yapamaz. Bu yüzden MCP arkasındaki uzun her iş için model, REST API'nin de kullandığı kalıptır: işi başlatın, bir tutacak alın, sınırlı bir süre bekleyin ve bitmediyse yeniden çağırın. Durumu taşıyan, bağlantı değil, tutacaktır.
wait_for_transcription, iş done ya da failed olana kadar ya da timeoutS süresi dolana kadar bloklar (varsayılan 50 saniye, en fazla 60; bu, çoğu istemci ve proxy'nin uyguladığı zaman aşımlarının altında kalmayı sağlar). Sonuç timedOut: true derse iş hâlâ çalışıyordur ve ajan aracı yeniden çağırır. Araç beklerken, istemci istediyse sunucu MCP ilerleme bildirimleri gönderir: bir yüzde ve "3.1 / 8.0 MB getiriliyor" ya da "02:00 içinden 01:25 transkript ediliyor" gibi bir aşama.get_transcription durumu ve bittiğinde metni döndürür. format: "text" her segment için bir satır verir: [mm:ss] Speaker 1: ...; "segments" start, end, speaker ve speakerName alanlarıyla zamanlanmış satırlar verir; includeWords: true kelime zamanlamalarını ekler. Sonuçlar sayfalanır (offset, limit, varsayılan 500 segment) ve daha fazlası kalırsa nextOffset döner.Sayfalama ağ için değil, model için vardır. Bir aracın döndürdüğü her şey ajanın bağlam penceresine yapıştırılır; orada konuşmanızla yarışır ve sonraki her turda token maliyeti doğurur. İki saatlik bir toplantı on binlerce kelimedir; hepsini bir kerede döndürmek sorduğunuz soruyu bağlamın dışına iterdi. İyi MCP araçları bir sayfa ve bir imleç döndürür ve ne kadarına ihtiyaç olduğuna ajanın karar vermesine izin verir.
Bir bağlantı kesilmesi ya da zaman aşımı işi asla iptal etmez, çünkü iş MCP isteğinde değil sunucuda yaşar. Bittiğinde iş kütüphanenizde bir girdi daha olur ve sonraki araçlar onu diğer her girdi gibi ele alır.
list_transcriptions, hesabın transkripsiyonlarını en yenisinden başlayarak, durum ve süreyle listeler; lifecycle active, archived ya da all olabilir.search_transcriptions, söylenen her şeyi her dilde tüm transkripsiyonlarda arar ve eşleşen satırları, her birinin transkripsiyonu ve konuşulduğu saniyesiyle döndürür. transcriptionId aramayı tek bir transkripsiyonla sınırlar; lang her eşleşmeye bir çeviri ekler.Bir satır bulmak ucuz olan yarıdır. Tüm metnin ne söylediğini çözmek için iki araç daha vardır.
get_summary, bitmiş bir transkripsiyonun AI başlığını ve özetini döndürür; isteğe bağlı olarak lang ile çevrilir. state: "pending", özetin hâlâ yazıldığı anlamına gelir (iş bittikten birkaç saniye içinde hazır olur) ve ajan tekrar sorar.translate_transcription, bitmiş bir transkripti başka bir dile çevirir; metin ya da zamanlanmış segmentler olarak, get_transcription gibi sayfalanmış. Çeviriler saklanır, bu yüzden tekrar sormak işi yinelemez.list_voices, bir dilde bir transkripti okuyabilen sesleri listeler: kimlik, ad, bilindiğinde cinsiyet ve aksan, bir kalite puanı ve varsayılan mı yoksa klonlanmış seslerinizden biri mi. Sesleri tanımlar; birinin yeni bir şey söylemesini sağlamaz (sunucunun ne yapmadığı hakkında aşağıda daha fazlası).Araçların pratikte nasıl zincirlendiği şöyle:
Sunucu eklendikten sonra Claude Code'daki bir konuşma şöyle ilerler. Bir podcast bağlantısı yapıştırır ve Fransızca özetini istersiniz.
Ajan transcribe_url çağırır:
{ "url": "https://example.org/episodes/42.mp3", "name": "Episode 42", "speakerLabels": "auto" }
Bir transcriptionId ve state: "queued" geri alır ve next ipucunu izler:
{ "transcriptionId": "4f1c...", "timeoutS": 50 }
Elli dakikalık bir bölüm, oynatılma süresinden çok daha hızlı transkript edilir, ama tek bir beklemede değil. İlk bekleme timedOut: true ile döner, ilerleme örneğin yüzde 61'de; ajan aracı bir kez daha çağırır ve state: "done" alır.
Şimdi ajan lang: "fr" ile get_summary çağırır:
{ "transcriptionId": "4f1c...", "lang": "fr" }
Özet hâlâ pending ise ajan birkaç saniye bekler; aksi halde size Fransızca bir başlık ve özet verir. "Fiyatlandırma hakkında nerede konuştular?" diye sorarsanız, query: "pricing" ve aynı transcriptionId ile search_transcriptions çağırır ve eşleşen satırları zaman damgalarıyla alıntılar. Tamamını Fransızca isterseniz translate_transcription çağırır.
Birkaç araç çağrısı, kod yok ve kütüphanenizde bir transkripsiyon. Bu çağrıların her biri REST isteğiyle aynı kapılardan geçti ve faturayı ile sınırları belirleyen de bu kapılardır.
MCP sunucusu, API'ye farklı bir ön kapıdan erişmektir: aynı sınırlar, aynı fatura.
POST /v1/transcriptions ile aynı oluşturma noktasından geçer: planın oluşturma hızı (saatte başlatılan transkripsiyon sayısı: 10, 100 ya da özel bir sayı), eşzamanlı transkripsiyon sınırı (1, 5 ya da sınırsız) ve kredisi geçerlidir. $5'lik kayıt kredisi ilk oturumu karşılar, kart gerekmez.isError: true, REST API'nin hata kodu, modelin hareket edebileceği bir cümle ve retryable ile retryAfterS alanlarını döndürür. insufficient_credit bir topUpUrl taşır; rate_limited ne kadar beklenmesi gerektiğini söyler. Bu, göründüğünden daha önemlidir: model hata metnini okur ve hareket edebileceği bir cümle, çıkmaz sokağı bir sonraki araç çağrısına çevirir./v1/mcp isteğinin kendisine de uygulanır: döngüdeki bir ajan, hiçbir araç çalışmadan Retry-After ile HTTP 429 alır.idempotencyKey alır: tamamlanmış bir çağrının anahtarını yeniden kullanmak ilk sonucu tekrar oynatır, farklı argümanlarla yeniden kullanmak ise reddedilir; böylece kendi kendine yeniden deneyen bir ajan asla ikinci bir iş başlatmaz. Para harcayan her araç bunu sunmalıdır; ajanlar insanlardan çok daha serbestçe yeniden dener.Bunlar sunucunun yaptıklarının kenarlarıdır. Bilerek bunların dışında kalan iki şey vardır.
Sunucuda serbest metni konuşmaya dönüştüren bir araç yoktur ve bir tane planlanmamıştır. VocalStack transkriptleri ve çevirilerini, hazır ya da klonlanmış bir sesle okur; başka bir şey okumaz. list_voices ajana bir dilde hangi seslerin bir transkripti okuyabileceğini söyler, bir sesin yeni bir şey söylemesini nasıl sağlayacağını değil.
Transkripsiyon araçları canlı yayınları da reddeder. Bir YouTube canlı yayını ya da radyo yayını, Panel'den ya da API referansındaki POST /v1/transcriptions/live üzerinden başlatılan bir canlı transkripsiyon gerektirir. Bitmiş bir YouTube videosu bir dosyadır ve transcribe_url onu alır.
Kodu kendiniz yazmak isterseniz, API ile dosya transkripsiyonu aynı adımları HTTP çağrıları olarak anlatır ve gerçek zamanlı eğitici WebSocket'i kapsar.