بناء خوادم MCP
أساسيات خادم MCP
انتهينا من الهندسة، وهذا هو الجزء الذي ستكتبه بنفسك.
دورة حياة الخادم
لأن البروتوكول بلا حالة، فدورة حياة الخادم هي في معظمها دورة حياة عملية لا دورة حياة بروتوكول. ومعرفة المرحلة التي علقت فيها تمثل معظم عملية التصحيح، والمرحلتان الأوليان تبدوان متطابقتين من الخارج.
دورة حياة الخادم — أين تحدث الأعطال
تُنفَّذ الاستيرادات وتُسجَّل المعالجات. خطأ استيراد واحد يقتل الخادم هنا فلا يعرض المضيف شيئاً إطلاقاً
يتصل العميل عبر 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}")
أوصاف الأدوات مهمة
الوصف ليس توثيقاً. إنه الشيء الوحيد الذي يقرأه النموذج ليقرر ما إذا كانت هذه الأداة هي المناسبة لما طلبه المستخدم للتو — ويقرأه مرة واحدة عند تبادل القدرات، قبل أن يعرف شيئاً عن موضوع المحادثة.
الأداة نفسها موصوفة بطريقتين
ثلاثة تغييرات، كل واحد منها يعالج إخفاقاً بعينه:
| التغيير | الإخفاق الذي يمنعه |
|---|---|
كتابة knowledge_base كاملة بدل kb | تخمين النموذج لما يشمله الاختصار |
| تسمية ما بداخلها: السياسات وأدلة التشغيل والتقارير | تجاهل الأداة في أسئلة كانت تستطيع الإجابة عنها |
| تسمية ما ليس بداخلها: لا كود ولا تذاكر | استدعاء الأداة في أسئلة ستفشل فيها |
السطر الأخير هو ما يغفله الناس عادة. إخبار النموذج بحدود الأداة لا يقل قيمة عن إخباره ببدايتها.
في القسم التالي، سنضيف موارد لكشف البيانات التي يمكن للذكاء الاصطناعي قراءتها. :::
سجّل الدخول للتقييم