שרת MCP הופך API לכמה כלים עם שם, שהסוכן קורא להם בתוך השיחה, ועבודה ארוכה נכנסת לתוכו כשהכלי מחזיר מזהה שהסוכן ממתין לו בתורות מוגבלים. הדביקו קישור לפודקאסט, בקשו את עיקרו בצרפתית, ולא נכתב אף קוד.
סוכן קוד יכול להשתמש ב־API של VocalStack כמו כל תוכנה: לקרוא את מדריך ה־API, לכתוב כמה שורות עם ה־SDK ולהריץ אותן. זו הדרך הנכונה למשהו שירוץ בלי הסוכן.
MCP (Model Context Protocol) מיועד למקרה האחר: אתם משוחחים עם עוזר ורוצים שיתמלל משהו עכשיו, בלי קוד. שרת MCP מפרסם רשימה קצרה של כלים בעלי שם, ולכל אחד מהם יש תיאור וסכמת JSON לארגומנטים שלו. הסוכן קורא את הרשימה פעם אחת, וקורא לכלי בשמו כשבקשה מתאימה לו. „תמלל את הפודקאסט הזה וספר לי מה הם אמרו על תמחור” הופך לשלוש קריאות לכלים, והסוכן לעולם לא רואה נתיב HTTP.
שרתים מגיעים בשני סוגים. שרת מקומי רץ כתת־תהליך של הלקוח ומדבר דרך stdio, וכך פועלים רוב שרתי מערכת הקבצים והמסדים. שרת מרוחק יושב מאחורי כתובת URL ומדבר Streamable HTTP, שיטת התעבורה שהחליפה את HTTP עם SSE (אירועים שנשלחים מהשרת) בגרסת המפרט ממרץ 2025. הלקוח שולח כל בקשה, והשרת עונה על אותו חיבור; כל מה שהוא צריך לומר לפני התוצאה הסופית נשלח לפניה כזרם. כל לקוח שנכתב נגד המפרט הנוכחי יכול להשתמש בכל אחד מהסוגים.
השרת של VocalStack הוא מהסוג המרוחק, בכתובת {{api}}/v1/mcp, והשימוש בו עולה מה שה־API עולה. כל מה שצריך הוא הכתובת.
פתחו את אזור המפתחים בלוח הבקרה ב־{{app}}/developers. הכרטיסייה הראשונה, Connect an AI agent, מציגה את כתובת השרת ואת קטע ההגדרה לכל לקוח. שלושת הקטעים שלהלן תואמים לאלה המוצגים שם.
הריצו את זה בטרמינל:
claude mcp add --transport http vocalstack {{api}}/v1/mcp
הוסיפו את זה ל־.cursor/mcp.json בפרויקט, או ל־~/.cursor/mcp.json לכל הפרויקטים:
{"mcpServers":{"vocalstack":{"url":"{{api}}/v1/mcp"}}}
כל לקוח שתומך ב־Streamable HTTP יכול להוסיף את השרת עם הכתובת הזו. זו הצורה הכללית שלוח הבקרה מציג:
{
"vocalstack": {
"type": "streamable-http",
"url": "{{api}}/v1/mcp"
}
}
אין צורך במפתח API כדי להתחיל. בפעם הראשונה שהלקוח מתחבר, אתם מתחברים לחשבון ה־VocalStack שלכם בדפדפן, והלקוח שומר את האסימון. לוח הבקרה מסביר את זה במשפט אחד: „תתחברו לחשבון VocalStack שלכם בפעם הראשונה. אין צורך במפתח.”
זה לא טריק של VocalStack, אלא מפרט ההרשאה של MCP בפעולה. שרת מרוחק עונה לבקשה לא מאומתת בתשובת 401 שמצביעה על ה־protected-resource metadata שלו: מסמך JSON קטן ששם את שרת ההרשאה ואת ההרשאות (scopes) שהשרת דורש. הלקוח קורא אותו, מריץ בדפדפן זרימת OAuth 2.1 סטנדרטית, וחוזר עם אסימון שהונפק לשרת הזה בלבד. כל שרת MCP מרוחק שפועל לפי המפרט מתחבר באותה צורה, וזו הסיבה שהלקוחות שלמעלה יכולים לעשות זאת בלי לדעת דבר על VocalStack.
גם מפתח API עובד, ללקוח שרץ על שרת או בסקריפט. שלחו אותו כ־Authorization: Bearer vs_key_..., אותה כותרת ש־REST API מקבל. מפתחות נוצרים תחת Developers → API keys. שני כלי התמלול דורשים את ההרשאות Write ו־Stream audio. ההרשאה השנייה נשמעת מוזרה לקובץ, אבל הכלים עוברים דרך אותה נקודת יצירה כמו כל תמלול, כולל תמלולים חיים, והנקודה הזו בודקת את שתיהן. כלי הקריאה דורשים Read; list_voices דורש רק אישור תקף.
אחרי שנכנסתם, הסוכן רואה תשעה כלים. לא סביר שתקראו להם בשמם בעצמכם, אבל היכרות איתם מסבירה מה הסוכן עושה אחר כך.
כל כלי מקבל ומחזיר JSON ב־camelCase, עם אותם שמות שדות כמו טיפוסי ה־/v1; המזהה של תמלול הוא ה־transcriptionId שלו.
transcribe_url מתחיל תמלול של שמע או וידאו בכתובת URL ציבורית: קישור לקובץ, לפרק פודקאסט, לסרטון ביוטיוב. שידורים חיים לא מתקבלים. ארגומנטים אופציונליים: name, spokenLanguage (השמיטו אותו כדי לזהות את השפה), speakerLabels (auto, on או off) ו־startS/endS כדי לתמלל רק חלק מהשמע.transcribe_file עושה אותו דבר לקובץ שהסוכן מחזיק, שנשלח כ־fileBase64 עם filename. הגודל המפוענח מוגבל ל־10 MiB, בערך עשר דקות של MP3 ב־128 kbps; לכל דבר גדול מזה, תנו לסוכן קישור.שני הכלים מחזירים מיד את transcriptionId, state: "queued" ורמז next ששם את כלי ההמתנה. תמלולים שנוצרו על ידי סוכן מתחילים כפרטיים, בלי קישור שיתוף.
סוכן לא יכול לשבת על שידור חי בסבלנות רבה יותר ממכם; הוא ימשיך לקרוא לכלי ההמתנה עד שמישהו ייקח ממנו את המחשב הנייד. לתמלול שהסתיים יש סוף, וזה מה שהזוג הבא של כלים מחכה לו.
קריאה לכלי היא בקשת HTTP אחת, ובקשות HTTP לא נועדו להימשך שעה. לקוחות מוותרים עליהן, פרוקסים סוגרים אותן, ומודל שחסום על כלי אחד לא יכול לעשות דבר אחר. לכן הדפוס לכל עבודה ארוכה מאחורי MCP הוא אותו דפוס שה־REST API משתמש בו: מתחילים את העבודה ומקבלים מזהה, ממתינים לו זמן מוגבל, וקוראים שוב אם היא לא הסתיימה. המצב נשמר במזהה, לא בחיבור.
wait_for_transcription חוסם עד שהעבודה מסתיימת ב־done או ב־failed, או עד ש־timeoutS עובר (ברירת המחדל היא 50 שניות, המקסימום 60, כדי להישאר מתחת לטיימאאוטים שרוב הלקוחות והפרוקסים מפעילים). אם התוצאה אומרת timedOut: true, העבודה עדיין רצה והסוכן קורא לכלי שוב. בזמן ההמתנה השרת שולח הודעות התקדמות של MCP, אם הלקוח ביקש אותן: אחוז ושלב, כמו „מורידים 3.1 / 8.0 MB” או „מתמללים 01:25 מתוך 02:00”.get_transcription מחזיר את הסטטוס ואת הטקסט, אחרי שהעבודה הסתיימה. format: "text" נותן שורה לכל קטע בתבנית [mm:ss] Speaker 1: ...; "segments" נותן שורות מתוזמנות עם start, end, speaker ו־speakerName; includeWords: true מוסיף תזמוני מילים. התוצאות מחולקות לעמודים (offset, limit, ברירת מחדל 500 קטעים) עם nextOffset כשנשארים עוד.החלוקה לעמודים נועדה למודל, לא לרשת. כל מה שכלי מחזיר נדבק להקשר של הסוכן, שם הוא מתחרה בשיחה שלכם ועולה בטוקנים בכל תור מאוחר יותר. שיחה של שעתיים היא עשרות אלפי מילים; החזרה שלהן בבת אחת תדחוף את השאלה שלכם מחוץ להקשר. כלי MCP טובים מחזירים עמוד ומצביע, ונותנים לסוכן להחליט כמה הוא צריך.
ניתוק או טיימאאוט לעולם לא מבטלים את העבודה, כי העבודה חיה בשרת ולא בבקשת ה־MCP. כשהיא מסתיימת, היא עוד פריט בספרייה שלכם, והכלים הבאים מתייחסים אליה כמו לכל אחד אחר.
list_transcriptions מציג את התמלולים של החשבון, מהחדש לישן, עם מצב ומשך; lifecycle הוא active, archived או all.search_transcriptions מחפש מה נאמר בכל התמלולים, בכל שפה, ומחזיר את השורות שנמצאו, כל אחת עם התמלול שלה והשנייה שבה נאמרה. transcriptionId מצמצם את החיפוש לתמלול אחד; lang מוסיף תרגום לכל תוצאה.מציאת שורה היא החצי הזול. שני כלים נוספים מסבירים מה כל הדבר אמר.
get_summary מחזיר את הכותרת והסיכום שה־AI כתב לתמלול שהסתיים, ואפשר לקבל אותם מתורגמים עם lang. state: "pending" פירושו שהסיכום עדיין נכתב (בדרך כלל הוא מוכן תוך שניות מסיום העבודה), והסוכן שואל שוב.translate_transcription מחזיר תמליל שהסתיים בשפה אחרת, כטקסט או כקטעים מתוזמנים, מחולקים לעמודים כמו ב־get_transcription. תרגומים נשמרים, כך שבקשה חוזרת לא חוזרת על העבודה.list_voices מציג את הקולות שיכולים להקריא תמליל בשפה: מזהה, שם, מין, מבטא כשידוע, דירוג איכות, ואם זה הקול שמוגדר כברירת מחדל או אחד הקולות המשובטים שלכם. הוא מתאר קולות; הוא לא גורם לאחד מהם לומר משהו חדש (על כך בהמשך).הנה איך הכלים משתלבים זה בזה בפועל.
אחרי שהשרת מתווסף, שיחה ב־Claude Code נראית כך. אתם מדביקים קישור לפודקאסט ומבקשים את עיקרו בצרפתית.
הסוכן קורא ל־transcribe_url:
{ "url": "https://example.org/episodes/42.mp3", "name": "Episode 42", "speakerLabels": "auto" }
הוא מקבל בחזרה transcriptionId ו־state: "queued", ועוקב אחרי הרמז next:
{ "transcriptionId": "4f1c...", "timeoutS": 50 }
פרק של חמישים דקות מתומלל הרבה יותר מהר מאורכו, אבל לא בתוך המתנה אחת. ההמתנה הראשונה מחזירה timedOut: true עם התקדמות של, נניח, 61 אחוז, ולכן הסוכן קורא לכלי פעם נוספת ומקבל state: "done".
עכשיו הסוכן קורא ל־get_summary עם lang: "fr":
{ "transcriptionId": "4f1c...", "lang": "fr" }
אם הסיכום עדיין pending, הסוכן ממתין כמה שניות; אחרת הוא מוסר לכם כותרת וסיכום בצרפתית. שאלו „איפה דיברו על תמחור?” והוא קורא ל־search_transcriptions עם query: "pricing" ואותו transcriptionId, ומצטט את השורות המתאימות עם חותמות הזמן שלהן. בקשו את כל התוכן בצרפתית, והוא קורא ל־translate_transcription.
כמה קריאות לכלים, בלי קוד, ותמלול בספרייה. כל אחת מהקריאות האלה עברה דרך אותם שערים כמו בקשת REST, והשערים האלה הם שקובעים את החיוב ואת המגבלות.
שרת ה־MCP הוא ה־API דרך כניסה אחרת: אותן מגבלות, אותו חיוב.
POST /v1/transcriptions: חלים עליהם קצב היצירה של המסלול (10, 100 או מספר מותאם אישית של תמלולים שנפתחים בשעה), התקרה לתמלולים במקביל (1, 5 או ללא הגבלה) והקרדיט שלו. קרדיט ההרשמה של $5 מכסה סשן ראשון, בלי צורך בכרטיס אשראי.isError: true עם קוד השגיאה של ה־REST API, משפט שהמודל יכול לפעול לפיו, והשדות retryable ו־retryAfterS. insufficient_credit נושא topUpUrl; rate_limited אומר כמה לחכות. זה חשוב יותר ממה שנשמע: מודל קורא את טקסט השגיאה, ומשפט שהוא יכול לפעול לפיו הופך מבוי סתום לקריאת הכלי הבאה./v1/mcp עצמה: סוכן בלולאה מקבל HTTP 429 עם Retry-After לפני שכלי כלשהו רץ.idempotencyKey: שימוש חוזר במפתח של קריאה שהושלמה מחזיר את התוצאה הראשונה, ושימוש חוזר בו עם ארגומנטים אחרים נדחה, כך שסוכן שמנסה שוב מעצמו לעולם לא מתחיל עבודה שנייה. כל כלי שמוציא כסף צריך להציע את זה; סוכנים מנסים שוב הרבה יותר בחופשיות מאנשים.אלה גבולות מה שהשרת עושה. יש שני דברים שנמצאים מחוץ להם בכוונה.
לשרת אין כלי שהופך טקסט שרירותי לדיבור, וגם לא מתוכנן כזה. VocalStack מדבר תמלולים ותרגומים שלהם, בקול מוכן או משובט, ולא מעבר לזה. list_voices אומר לסוכן אילו קולות יכולים להקריא תמליל בשפה, לא איך לגרום לקול לומר משהו חדש.
כלי התמלול גם מסרבים לשידורים חיים. שידור חי של YouTube או של תחנת רדיו דורש תמלול בשידור חי, שמתחילים מלוח הבקרה או דרך POST /v1/transcriptions/live במדריך ה־API. סרטון YouTube שהסתיים הוא קובץ, ו־transcribe_url מקבל אותו.
אם תעדיפו לכתוב את הקוד בעצמכם, תמלול קובץ עם ה־API עובר על אותם שלבים כקריאות HTTP, ומדריך תמלול בזמן אמת מכסה את ה־WebSocket.