خادم MCP يحوّل واجهة API إلى بضع أدوات مسماة يستدعيها الوكيل أثناء المحادثة، ويمكن أن تبقى مهمة طويلة خلفه حين تعيد الأداة مقبضًا ينتظره الوكيل على دفعات محدودة. الصق رابط بودكاست، واطلب ملخصه بالفرنسية، دون كتابة أي شيفرة برمجية.
يمكن لوكيل برمجة أن يستخدم واجهة VocalStack API كما تستخدمها أي برمجية: أن يقرأ مرجع API، ويكتب بضعة أسطر باستخدام SDK، ثم يشغّلها. هذا هو المسار الصحيح لما سيعمل من دون الوكيل.
MCP (بروتوكول سياق النموذج) مخصص للحالة الأخرى: أنت تتحدث مع مساعد وتريد منه أن يفرّغ شيئًا الآن، دون شيفرة. يعلن خادم MCP قائمة قصيرة من الأدوات المسماة، ولكل أداة وصف ومخطط JSON لوسائطها. يقرأ الوكيل القائمة مرة واحدة، ويستدعي الأداة باسمها حين يطابق طلب ما وصفها. «فرّغ هذا البودكاست وأخبرني بما قالوه عن الأسعار» تصبح ثلاثة استدعاءات للأدوات، ولا يرى الوكيل أي مسار HTTP أبدًا.
تأتي الخوادم في نوعين. الخادم المحلي يعمل كعملية فرعية للعميل ويتواصل عبر stdio، وهذه هي طريقة عمل معظم خوادم نظام الملفات وقواعد البيانات. أما الخادم البعيد فيقع خلف عنوان URL ويتحدث بروتوكول Streamable HTTP، وهو النقل الذي حلّ محل نقل HTTP-plus-SSE (أحداث يرسلها الخادم) الأقدم في مراجعة المواصفة لشهر مارس 2025. يرسل العميل كل طلب، ويرد الخادم على الاتصال نفسه؛ وأي شيء يريد قوله قبل النتيجة النهائية يُبث قبلها. وأي عميل مكتوب وفق المواصفة الحالية يستطيع استخدام أي من النوعين.
خادم VocalStack من النوع البعيد، على العنوان {{api}}/v1/mcp، وتكلفة استخدامه هي تكلفة الـ API نفسها. كل ما تحتاجه هو العنوان.
افتح منطقة Developers في لوحة التحكم عبر {{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 في المرة الأولى. لا حاجة إلى مفتاح.»
هذا ما تفعله مواصفة التفويض في MCP، وليس حيلة خاصة بـVocalStack. يرد الخادم البعيد على الطلب غير المصادَق عليه برمز 401 يشير إلى بيانات وصفية للمورد المحمي: وثيقة JSON صغيرة تسمّي خادم التفويض والنطاقات التي يطلبها الخادم. يقرأها العميل، ويجري تدفق 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 عام: رابط ملف، أو حلقة بودكاست، أو فيديو على YouTube. لا تُقبل البثوث المباشرة. الوسائط الاختيارية: 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 يعيد العنوان والملخص اللذين يولّدهما الذكاء الاصطناعي لتفريغ منتهٍ، ويمكن ترجمتهما باستخدام 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.