بناء خوادم MCP

كشف الموارد

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

الأدوات تتيح للنموذج أن ينفّذ، والموارد تتيح له أن يقرأ: الملفات وصفوف قاعدة البيانات وملفات الإعداد — أي شيء تقبل تسليمه دون السماح بتعديله.

المورد مقابل الأداة

الفارق بينهما ليس «أهذه بيانات أم إجراء». فقد تُرجع الأداة بيانات خالصة وتبقى أداة. السؤال الحقيقي هو: من يبدأ العملية، وهل يمكن أن يتغير شيء نتيجة لها.

أيهما ينبغي أن يكون هذا؟

يبدؤها النموذج

اجعلها أداة

من يبدأالنموذج، أثناء المحادثة
تأخذ معطياتنعم، عبر مخطط JSON تحدده أنت
تغيّر الحالةنعم
الاكتشافtools/list
المزايا
  • يستطيع النموذج أن يقرر حاجته إليها من تلقاء نفسه
  • المعطيات تجعل أداة واحدة تغطي حالات كثيرة
العيوب
  • كل أداة طريق جديد ليخطئ النموذج على حسابك
  • تحتاج وصفاً دقيقاً لتُستدعى في الوقت المناسب
يرفقه المستخدم

اجعلها مورداً

من يبدأالمستخدم أو المضيف يرفقه
تأخذ معطياتلا، فالمعرّف URI هو العنوان
تغيّر الحالةلا، بحكم التعاقد
الاكتشافresources/list
المزايا
  • آمن للكشف على نطاق واسع لأن شيئاً لا يتضرر
  • قابل للتخزين المؤقت لأن المعرّف يدل على الشيء نفسه في كل مرة
العيوب
  • لا يستطيع النموذج طلبه من تلقاء نفسه
  • المورد الكبير قد يبتلع نافذة السياق

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

تعريف الموارد

تستخدم الموارد URIs لتحديد المحتوى:

from mcp.types import Resource

@server.list_resources()
async def list_resources():
    return [
        Resource(
            uri="config://app/settings",
            name="إعدادات التطبيق",
            description="تكوين التطبيق الحالي",
            mimeType="application/json"
        ),
        Resource(
            uri="file:///var/log/app.log",
            name="سجلات التطبيق",
            description="إدخالات سجل التطبيق الأخيرة",
            mimeType="text/plain"
        )
    ]

مخططات URI

يمكنك استخدام أي مخطط URI منطقي لبياناتك:

المخططحالة الاستخداممثال
file://الملفات المحليةfile:///home/user/doc.txt
db://سجلات قاعدة البياناتdb://users/123
config://التكوينconfig://app/settings
api://واجهات برمجة التطبيقات الخارجيةapi://weather/london

قراءة الموارد

نفذ معالج القراءة لإرجاع المحتوى:

from mcp.types import TextContent, BlobContent

@server.read_resource()
async def read_resource(uri: str):
    if uri == "config://app/settings":
        settings = load_app_settings()
        return [TextContent(
            type="text",
            text=json.dumps(settings, indent=2)
        )]

    if uri.startswith("file://"):
        path = uri.replace("file://", "")
        content = read_file(path)
        return [TextContent(type="text", text=content)]

    raise ValueError(f"مورد غير معروف: {uri}")

الموارد الثنائية

للبيانات الثنائية مثل الصور، استخدم BlobContent:

import base64

@server.read_resource()
async def read_resource(uri: str):
    if uri.startswith("image://"):
        image_data = load_image(uri)
        return [BlobContent(
            type="blob",
            data=base64.b64encode(image_data).decode(),
            mimeType="image/png"
        )]

الموارد الديناميكية

يمكن توليد الموارد ديناميكياً بناءً على المعلمات:

@server.list_resources()
async def list_resources():
    # توليد الموارد من قاعدة البيانات
    users = await db.get_all_users()
    return [
        Resource(
            uri=f"user://{user.id}",
            name=f"المستخدم: {user.name}",
            description=f"ملف تعريف {user.name}"
        )
        for user in users
    ]

التالي: معالجة الأخطاء، ولماذا يمثّل النموذج جمهوراً غير معتاد لها. :::

اختبار

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

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

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