بناء خوادم MCP

أساسيات خادم MCP

5 دقيقة للقراءة

انتهينا من الهندسة، وهذا هو الجزء الذي ستكتبه بنفسك.

دورة حياة الخادم

لأن البروتوكول بلا حالة، فدورة حياة الخادم هي في معظمها دورة حياة عملية لا دورة حياة بروتوكول. ومعرفة المرحلة التي علقت فيها تمثل معظم عملية التصحيح، والمرحلتان الأوليان تبدوان متطابقتين من الخارج.

دورة حياة الخادم — أين تحدث الأعطال

بدء العملية

تُنفَّذ الاستيرادات وتُسجَّل المعالجات. خطأ استيراد واحد يقتل الخادم هنا فلا يعرض المضيف شيئاً إطلاقاً

ارتباط النقل

يتصل العميل عبر stdio أو Streamable HTTP. المسار الخطأ أو المفسّر الخطأ يوقفك هنا

خدمة الطلب

كل طلب يصل مكتفياً بذاته، يُتحقق منه عبر ‎_meta الخاص به، ثم يُوزَّع. ويتكرر ذلك باستقلال إلى ما لا نهاية

الإغلاق

حرّر مقابض الملفات والاتصالات. فقد يقطع العميل النقل في أي لحظة دون إنذار

لاحظ ما ليس مرحلة هنا: لا توجد خطوة لتبادل القدرات. فالقدرات تصل مع كل طلب بدل الاتفاق عليها مرة واحدة في البداية، ولهذا لا يحمل الاتصال أي ذاكرة، وعلى معالجك أن يكون قادراً على خدمة طلب بارد في أي لحظة.

إنشاء نسخة الخادم

from mcp.server import MCPServer

# إنشاء خادم باسم فريد
mcp = MCPServer(name="my-awesome-server")

الصنف MCPServer هو الواجهة عالية المستوى، وهو ما يستخدمه دليل البدء السريع الخاص بالـ SDK نفسه. يوجد تحته أيضاً صنف Server منخفض المستوى تلجأ إليه حين تحتاج إلى تشكيل استجابات البروتوكول الخام بنفسك، وهو ما يفعله درس معالجة الأخطاء بالضبط. أما في بقية هذه الدورة فـ MCPServer هو الخيار الافتراضي الصحيح.

اسم الخادم يظهر في السجلات ويساعد في تحديد خادمك عند تكوين عدة خوادم MCP.

تسجيل الأدوات

الأدوات هي الطريقة الأساسية للتفاعل بين الذكاء الاصطناعي وخادمك. كل أداة تحتاج:

المكونمن أين يأتي
nameاسم الدالة، ما لم تتجاوزه صراحة
descriptionنص التوثيق — وهذا هو الجزء الذي يقرأه النموذج
inputSchemaيُولَّد من تلميحات الأنواع والقيم الافتراضية
from typing import Literal


@mcp.tool()
def get_weather(city: str, units: Literal["celsius", "fahrenheit"] = "celsius") -> str:
    """الحصول على الطقس الحالي لمدينة، مثل "لندن" أو "طوكيو"."""
    return fetch_weather(city, units)

النوع Literal هنا يؤدي عملاً حقيقياً: فهو يتحول إلى enum داخل المخطط المُولَّد، وبذلك يُقيَّد النموذج بالقيمتين اللتين يعالجهما كودك فعلاً بدلاً من أن نثق بأنه سيخمّنهما. كل ما يمكنك التعبير عنه بتلميح نوع هو شيء تتوقف عن التحقق منه يدوياً.

التعامل مع استدعاءات الأدوات

الدالة نفسها هي المعالِج. تصل الوسائط كمعاملات عادية، بعد التحقق منها مسبقاً وفق المخطط الذي أنتجته تلميحات الأنواع:

@mcp.tool()
async def get_weather(city: str, units: Literal["celsius", "fahrenheit"] = "celsius") -> str:
    """الحصول على الطقس الحالي لمدينة، مثل "لندن" أو "طوكيو"."""
    weather = await fetch_weather(city, units)
    return f"الطقس في {city}: {weather}"

لا يوجد جدول توزيع ولا سلسلة if name == ...، لأن الـ SDK يوجّه الاستدعاء إلى الدالة التي زيّنتها. يمكن أن تكون المعالِجات def أو async def؛ استخدم async def فور لمسك للشبكة، وهو ما يحدث فوراً في معظم الأدوات الحقيقية.

أوصاف الأدوات مهمة

الوصف ليس توثيقاً. إنه الشيء الوحيد الذي يقرأه النموذج ليقرر ما إذا كانت هذه الأداة هي المناسبة لما طلبه المستخدم للتو — وهو يقرأ قائمة مرشحين على البارد، قبل أن يعرف شيئاً عن موضوع المحادثة.

الأداة نفسها موصوفة بطريقتين

ما يُتجاهَل
name: search_kb
description: "البحث في KB"

ثلاثة تغييرات، كل واحد منها يعالج إخفاقاً بعينه:

التغييرالإخفاق الذي يمنعه
كتابة knowledge_base كاملة بدل kbتخمين النموذج لما يشمله الاختصار
تسمية ما بداخلها: السياسات وأدلة التشغيل والتقاريرتجاهل الأداة في أسئلة كانت تستطيع الإجابة عنها
تسمية ما ليس بداخلها: لا كود ولا تذاكراستدعاء الأداة في أسئلة ستفشل فيها

السطر الأخير هو ما يغفله الناس عادة. إخبار النموذج بحدود الأداة لا يقل قيمة عن إخباره ببدايتها.

في القسم التالي، سنضيف موارد لكشف البيانات التي يمكن للذكاء الاصطناعي قراءتها. :::

اختبار

اختبار الوحدة 2: بناء خوادم MCP

خذ الاختبار
هل كان هذا الدرس مفيدًا؟

سجّل الدخول للتقييم