بناء خوادم MCP

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

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

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

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

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

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

بدء العملية

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

ارتباط النقل

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

خدمة الطلب

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

الإغلاق

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

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

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

from mcp.server import Server
from mcp.types import Tool, TextContent

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

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

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

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

المكونالغرض
nameمعرف فريد (snake_case)
descriptionماذا تفعل الأداة (الذكاء الاصطناعي يقرأ هذا!)
inputSchemaمخطط JSON للمعلمات
@server.list_tools()
async def list_tools():
    return [
        Tool(
            name="get_weather",
            description="الحصول على الطقس الحالي لمدينة",
            inputSchema={
                "type": "object",
                "properties": {
                    "city": {
                        "type": "string",
                        "description": "اسم المدينة (مثل 'لندن'، 'طوكيو')"
                    },
                    "units": {
                        "type": "string",
                        "enum": ["celsius", "fahrenheit"],
                        "default": "celsius"
                    }
                },
                "required": ["city"]
            }
        )
    ]

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

عندما يستدعي الذكاء الاصطناعي أداة، يستقبل معالجك الاسم والوسائط:

@server.call_tool()
async def call_tool(name: str, arguments: dict):
    if name == "get_weather":
        city = arguments["city"]
        units = arguments.get("units", "celsius")

        # منطقك هنا (مثل استدعاء API الطقس)
        weather = fetch_weather(city, units)

        return [TextContent(
            type="text",
            text=f"الطقس في {city}: {weather}"
        )]

    raise ValueError(f"أداة غير معروفة: {name}")

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

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

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

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

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

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

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

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

اختبار

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

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

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