غلّف واجهة REST موجودة كخادم MCP يستطيع الوكلاء استدعاءه دون تخمين. ولّد الأدوات من ملف OpenAPI باستخدام FastMCP، أو ابنِها يدويًا باستخدام TypeScript، وتعامل مع المصادقة والمهام البطيئة للصور والفيديو، ثم اختبر باستخدام Inspector وانشر عبر stdio أو HTTP.
واجهة REST API الخاصة بك تعمل بالفعل، ومع ذلك ما زال الوكلاء يتعثرون في استخدامها. إنهم يخمّنون أسماء المعاملات، ويعجزون عن معالجة استجابات JSON بحجم 40 KB، ويستدعون DELETE حين كانوا يقصدون GET. الحل ليس نموذجًا أذكى. إنه طبقة رقيقة تفصل بينهما: خادم MCP يخبر الوكيل بدقة بالإجراءات المتاحة، وشكل كل مدخل، وما الذي يعود منه. يوضح هذا الدرس كيفية تحويل API إلى خادم MCP انطلاقًا من مواصفات OpenAPI الخاصة بها، أولًا باستخدام الشيفرة المولّدة، ثم يدويًا، بما في ذلك المصادقة والمهام البطيئة والاختبار والنشر.
تحتاج إلى ثلاثة أشياء قبل البدء: واجهة API يمكنك استدعاؤها بالفعل باستخدام curl، وملف OpenAPI 3.x الخاص بها (أو الصبر لكتابته)، وعميل MCP مثل Claude Desktop أو Cursor أو VS Code لتجربة النتيجة. تستغرق النسخة الأولى العاملة فترة بعد ظهر واحدة. أما الصقل فهو المكان الذي يذهب إليه معظم الوقت الحقيقي، وهو أيضًا مصدر الجودة.
💡 النسخة المختصرة: يغلّف MCP واجهة API الخاصة بك في أدوات. لكل أداة اسم ووصف ومخطط JSON Schema لمدخلاتها. يختار الوكيل الأدوات بقراءة هذه الأوصاف، لذلك تهم الأوصاف أكثر من تفاصيل بروتوكول HTTP.
لماذا تغليف API كخادم MCP
صُممت REST لمطورين يقرؤون الوثائق مرة واحدة ثم يكتبون الكود استنادًا إليها. الوكيل يعمل بطريقة مختلفة. إنه يقرأ ما يعرضه الخادم في بداية الجلسة، ثم يقرر استنادًا إلى تلك القائمة وحدها أي استدعاء يجري. إذا كانت القائمة غامضة، فإنه يخمّن. وإذا كانت القائمة ضخمة، فإنه يستنفد نافذة السياق قبل أن يكتب المستخدم كلمة واحدة.
يحل خادم MCP المشكلتين بالطريقة التي يعمل بها عامل المقسّم الهاتفي: يستقبل طلبًا واضحًا، ويوجهه إلى الخط الصحيح، ويعيد إجابة نظيفة.
ما الذي يراه الوكيل فعلًا
عند اتصال العميل، يطلب من الخادم قائمة أدواته. كل مدخلة تحمل name، وdescription، وinputSchema مكتوبًا بصيغة JSON Schema، واختياريًا outputSchema ومجموعة من annotations. هذا هو السطح الكامل. الوكيل لا يرى مساراتك ولا أفعال HTTP ولا رموز الحالة. إنه يرى أسماء وجملًا ومخططات.
REST إلى MCP في لمحة
لكل جزء من عملية OpenAPI مكان محدد في جانب MCP:
REST / OpenAPI
أداة MCP
operationId
الأداة name
summary وdescription
الأداة description
معاملات المسار والاستعلام والجسم
inputSchema، كائن JSON Schema واحد مسطّح
مخطط استجابة 200
outputSchema والمحتوى المنظَّم
استجابات 4xx و5xx
نتيجة فيها isError: true ورسالة قابلة للقراءة
مخطط الأمان
إعداد الخادم: توكن من متغير بيئة، أو OAuth للخوادم البعيدة
روابط الترقيم بالصفحات
مدخلات صريحة cursor وlimit
ظهر المحتوى المنظَّم ومخططات المخرجات مع مراجعة 2025-06-18 للمواصفة، لذا تحقق من أن إصدار SDK لديك يدعمهما قبل أن تعتمد على outputSchema.
تحويل عمليات OpenAPI إلى أدوات
افتح المواصفات، وقاوم الرغبة في كشف كل شيء. تتحول API تضم 120 نقطة نهاية إلى خادم يضم 120 أداة، ولا تستهلك قائمة الأدوات وحدها آلاف التوكنات في كل محادثة. ابدأ صغيرًا، وأحسن تسمية الأشياء، وصِفها كما قد يصفها زميل في العمل.
اختر العمليات، لا نقاط النهاية
اطرح أربعة أسئلة على كل نقطة نهاية قبل أن تصبح أداة:
هل سيطلب شخص من مساعد أن ينفذ هذا بلغة عادية؟
هل من الآمن استدعاؤه مرتين إذا أعاد الوكيل المحاولة؟
هل تتسع الاستجابة في بضعة كيلوبايتات، أو يمكنك تقليمها حتى تتسع؟
هل تخص جمهورًا آخر، مثل الإدارة أو الفوترة أو الأدوات الداخلية؟
كل ما يفشل في السؤال الأول أو الأخير يبقى خارجًا. خمس إلى عشر أدوات مختارة بعناية أفضل من مئة أداة خام. تستحق التدفقات متعددة الخطوات أداة واحدة: إذا كان "إنشاء سلة، وإضافة عناصر، ثم الدفع" يحدث دائمًا بالتسلسل، فينبغي أن يرى الوكيل إجراءً واحدًا هو place_order.
سمِّ كل أداة وصِفها
ابدأ من operationId، ثم أعد كتابته كفعل واسم. يجيب الوصف الجيد عن ثلاثة أسئلة: ماذا تفعل الأداة، ومتى تُستخدم بدلًا من جاراتها، وماذا تعيد.
مولّد
معاد كتابته
الاسم
OrdersController_findAll
search_orders
الوصف
"البحث عن الكل"
"ابحث عن الطلبات حسب بريد العميل الإلكتروني أو الحالة أو نطاق التاريخ. تعيد حتى 20 طلبًا مع المعرّف والحالة والإجمالي. استخدم get_order لبنود الطلب."
سطّح معاملات المسار والاستعلام والجسم في كائن واحد. احتفظ بقيم enum، وحدّد الحقول الإلزامية، وامنح كل خاصية وصفًا قصيرًا مع قيمة مثال، واضبط حدودًا مثل maximum وmaxLength حتى لا يطلب النموذج 10,000 صف. عملية OpenAPI بهذا الشكل:
{
"name": "get_order",
"description": "Fetch one order by id. Returns status, total and line items. Use search_orders when you only have an email.",
"inputSchema": {
"type": "object",
"properties": {
"order_id": { "type": "string", "description": "Order id, for example ord_8f2c1" }
},
"required": ["order_id"]
}
}
طريقتان لبناء الخادم
يمكنك توليد خادم مباشرة من المواصفة في دقائق، أو كتابة كل أداة يدويًا. يفعل معظم الفرق الأمرين: يولّدون أولًا ليروا الشكل، ثم يضبطون يدويًا الأدوات الخمس التي تهم.
التوليد باستخدام FastMCP
تستطيع مكتبة FastMCP الخاصة بلغة Python بناء خادم مباشرة من وثيقة OpenAPI:
يقرأ الخادم المواصفة، وينشئ الأدوات، ويمرر كل استدعاء عبر عميل httpx الذي تمرره، وهنا توجد أيضًا ترويسة المصادقة. تُسقط خرائط المسارات الإدارية والداخلية قبل أن يراها الوكيل أبدًا.
⚠️ تحقق من الإصدار: يختلف التعيين الافتراضي بين الإصدارات الرئيسية في FastMCP. تحوّل الإصدارات الحديثة كل عملية إلى أداة، بينما كانت إصدارات 2.x الأقدم تعيّن بعض مسارات GET إلى موارد. ثبّت إصدارك، واضبط خرائط المسارات بشكل صريح، وتأكد من مسار الاستيراد في الوثائق الخاصة بالإصدار الذي ثبّتّه.
عندما يقصر التوليد
تحذّر وثائق FastMCP نفسها من أن الخوادم المنتقاة بعناية تمنح النماذج نتائج أفضل بوضوح من الخوادم المحوّلة تلقائيًا، خاصة مع واجهات API التي تضم نقاط نهاية ومعاملات كثيرة. ستفهم السبب في أول تشغيل للاختبار:
أسماء مثل get_orders_by_id_using_get لا يكتبها أي إنسان
أوصاف منسوخة من وثائق المطورين، مكتوبة لقرّاء يعرفون النظام مسبقًا
استجابات تعيد كل الحقول، بما فيها الأعلام الداخلية
أربع أدوات كان يجب أن تكون أداة واحدة
أصلحها بهذا الترتيب: التقليم، ثم إعادة التسمية، ثم إعادة كتابة الأوصاف، ثم تقليم الاستجابات، ثم دمج التدفقات.
البناء اليدوي باستخدام TypeScript
بالنسبة إلى الأدوات المهمة، يمنحك SDK الرسمي في TypeScript تحكمًا كاملًا. ثبّت @modelcontextprotocol/sdk وzod، ثم سجّل كل أداة مع مخطط ومعالج:
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
const API = "https://api.example.com";
const TOKEN = process.env.ORDERS_API_TOKEN;
const server = new McpServer({ name: "orders", version: "1.0.0" });
server.registerTool(
"get_order",
{
title: "Get order",
description:
"Fetch one order by id. Returns status, total and line items. Use search_orders when you only have an email.",
inputSchema: { order_id: z.string().describe("Order id, for example ord_8f2c1") },
annotations: { readOnlyHint: true },
},
async ({ order_id }) => {
const res = await fetch(`${API}/orders/${encodeURIComponent(order_id)}`, {
headers: { Authorization: `Bearer ${TOKEN}` },
});
if (!res.ok) {
return {
isError: true,
content: [{ type: "text", text: `Orders API returned ${res.status}. Check the id and try again.` }],
};
}
const order = await res.json();
return { content: [{ type: "text", text: JSON.stringify(order) }] };
}
);
await server.connect(new StdioServerTransport());
هناك تفصيلتان تقومان بالعمل الثقيل. يخبر التعليق التوضيحي readOnlyHint العميل بأن هذا الاستدعاء آمن للتشغيل دون طلب تأكيد، ويعيد فرع الخطأ isError: true مع رسالة قابلة للقراءة، فيستطيع الوكيل أن يحاول مرة أخرى بدل أن يتوقف.
المصادقة والأسرار وضوابط الحماية
الخادم يحمل بيانات الاعتماد. النموذج لا يحملها أبدًا.
أبقِ التوكنات خارج الأوامر النصية
اقرأ توكن API من متغير بيئي أو من مدير أسرار عند بدء تشغيل العملية. لا تقبله أبدًا كوسيط أداة، ولا تعرضه في رسالة خطأ، ولا تسجّل ترويسات الطلبات أبدًا. أنشئ أضيق توكن تسمح به API: توكن للقراءة فقط لخادم للقراءة فقط. بالنسبة إلى الخوادم البعيدة، يقوم مسار التفويض في MCP على OAuth 2.1، لذا يسجّل كل مستخدم دخوله بحسابه الخاص، وتحمل كل استدعاء صلاحياته هو بدلًا من حساب مشترك فائق الصلاحيات.
ضع تعليقات توضيحية على الأدوات الخطرة
التعليقات التوضيحية تلميحات تساعد العملاء على تحديد متى يطلبون تأكيد المستخدم:
التعليق التوضيحي
اضبطه عندما
readOnlyHint: true
تقرأ الأداة فقط، مثل GET أو البحث
destructiveHint: true
تحذف الأداة بيانات أو تستبدلها
idempotentHint: true
تكرار الاستدعاء بالمدخل نفسه لا يغيّر شيئًا إضافيًا
openWorldHint: true
تصل الأداة إلى أنظمة خارج نطاقك، مثل الويب المفتوح
تعامل معها كتلميحات لا كفرض، لأن العميل لا ينبغي أن يثق في تعليقات توضيحية من خادم لا يعرفه. الحماية الحقيقية تقع على عاتقك: اشحن الإصدار الأول للقراءة فقط، وأضف أدوات الكتابة واحدة تلو الأخرى، وامنح الأدوات المدمّرة مدخل dry_run أو confirm حتى يضطر الوكيل إلى أن يكون صريحًا.
المهام البطيئة والاستعلام الدوري والوسائط
يشترك توليد الصور وتصيير الفيديو وتصدير التقارير في نمط واحد: تجيب API فورًا بمعرّف المهمة، ويصل الناتج بعد ثوانٍ أو دقائق. أداة تتوقف عن الاستجابة لثلاث دقائق ستنتهي مهلتها في معظم العملاء. يحل رف تذاكر الطلبات في المطبخ المشكلة نفسها في المطعم: تأخذ الطلب، وتسلّم تذكرة، وتنادي على الرقم حين يصبح الطبق جاهزًا.
الإنشاء ثم الاستعلام ثم الجلب
قسّم المهمة إلى ثلاث أدوات: واحدة تبدأها، وواحدة تتحقق منها، وواحدة تلغيها. تعيد أداة البدء معرّفًا وتلميحًا عن وقت العودة للتحقق. تعيد أداة التحقق كائن حالة صغيرًا، queued أو running أو succeeded أو failed، بالإضافة إلى رابط بمجرد أن يصبح هناك ما يُجلب. أعد الروابط، لا بايتات الملفات: صورة بحجم 5 MB تُلصق في السياق لا تفيد أحدًا.
server.registerTool(
"get_render",
{
description:
"Check a render started with start_render. Call again after next_poll_in_seconds until status is succeeded or failed.",
inputSchema: { render_id: z.string() },
annotations: { readOnlyHint: true },
},
async ({ render_id }) => {
const job = await api(`/renders/${render_id}`); // api() is your fetch helper
const done = job.status === "succeeded" || job.status === "failed";
const body = {
status: job.status,
url: job.output?.[0] ?? null,
next_poll_in_seconds: done ? null : 5,
};
return { content: [{ type: "text", text: JSON.stringify(body) }] };
}
);
مثال حقيقي للصور والفيديو
يتبع موصل PicassoIA الخاص بالمنصة هذا التصميم. تعيد أدواته generate_image وedit_image وgenerate_video_picassoia وgenerate_video_seedance كائن predict_id فور قبول وحدة GPU للمهمة، مع وقت تقديري. ثم يستدعي الوكيل get_generation بعد next_poll_in_seconds المُعاد، ويكرر ذلك حتى تصبح الحالة succeeded أو failed. تقوم أداة cancel_generation بإيقاف مهمة تعمل، مع تنبيه صريح واحد في تعليماتها: لا يمكن إلغاء فيديو تُصيّره وحدة GPU بالفعل.
وتقع تحت ذلك REST API على نمط Replicate عند https://api.picassoia.com/v1، مع مصادقة بتوكن Bearer. ينشئ POST /v1/models/{owner}/{name}/predictions مهمة، ويقرأ GET /v1/predictions/{id} حالتها، ويوقفها POST /v1/predictions/{id}/cancel. وهذا ما يجعلها هدفًا نموذجيًا للتحويل، وتتوافق النماذج الأربعة خلف الموصل مع أدواته الأربع للتوليد:
ينبغي أن تظهر الحدود في أوصاف الأدوات أيضًا. تسمح API بخمسة طلبات تشغيل متزامنة لكل حساب، مشتركة بين التوكنات واتصالات MCP، مع أوامر نصية تصل إلى 4,000 حرف، لذا يخبر الوصفُ الجيد الوكيلَ بأن ينتظر مهمة قيد التشغيل قبل أن يُطلق السادسة. تحقّق من شروط الخطة الحالية على موقع PicassoIA قبل أن تبني منتجًا فوق API.
اختبر ثم انشر
الوكيل مختبِر لا يرحم: يستخدم أدواتك بطرق لم تخطط لها. اختبر بأدوات مناسبة قبل أن تسلّمه إياها.
شغّل MCP Inspector
MCP Inspector هو واجهة التصحيح الرسمية. وجّهه إلى خادمك، مثلًا npx @modelcontextprotocol/inspector node dist/server.js، وسيعرض كل أداة، ويتيح لك استدعاء كل واحدة منها باستخدام JSON خام، ويعرض النتيجة الدقيقة التي يتلقاها العميل. ثم اربط عميلًا حقيقيًا ونفّذ عشرة أوامر نصية واقعية. في كل منها تحقق من ثلاثة أمور: هل اختار الوكيل الأداة الصحيحة، وهل ملأ المعاملات بشكل صحيح، وهل منحته الاستجابة ما يكفي للإجابة؟
اختر stdio أو HTTP
stdio
Streamable HTTP
طريقة التشغيل
عملية محلية يبدأها العميل
خدمة بعيدة خلف عنوان URL
المصادقة
متغيرات البيئة على جهاز المستخدم
OAuth أو توكنات Bearer
الاستخدام الأمثل
الأدوات الشخصية والتطوير
الفرق والواجهات المشتركة
انتبه إلى
لا تطبع السجلات أبدًا على stdout
TLS وحدود المعدل والتوسع الأفقي
حلّ Streamable HTTP محل نقل HTTP plus SSE الأقدم في مراجعة 2025-03-26 للمواصفة، والبروتوكول ما زال يتطور، لذا ثبّت إصدار SDK لديك واقرأ سجل التغييرات قبل الترقية.
خمسة أخطاء شائعة
كشف كل نقطة نهاية. قوائم الأدوات تكلّف توكنات في كل دور.
الكتابة إلى stdout في خادم stdio. يحمل stdout البروتوكول نفسه. أرسل السجلات إلى stderr.
إعادة الحمولة الكاملة من المصدر. قلّصها إلى الحقول التي يحتاجها الوكيل، وقسّم الباقي على صفحات.
رمي الاستثناءات. أعد نتيجة isError مع رسالة تقول ما الذي يجب تجربته بعد ذلك.
تداخل الأوصاف. إذا بدت أداتان متشابهتين، يختار الوكيل عشوائيًا. وضّح متى تُفضَّل كل واحدة.
كتابة عشرين وصفًا لأداة يدويًا أمر مرهق، ويؤدي نموذج لغوي كبير (LLM) هذه المهمة جيدًا حين تزوده بقواعد. على PicassoIA، يناسب Claude Sonnet 5 هذا الغرض: تذكر صفحة النموذج مهام البرمجة متعددة الخطوات واستخدام الأدوات ضمن نقاط قوته، ويقبل موجه نظام، ويتيح لك اختيار مقدار التفكير الذي يقوم به.
اضبط موجه النظام مرة واحدة. مثلًا: You write MCP tool definitions. For each OpenAPI operation return a verb_noun name, a description that says what the tool does, when to use it and what it returns, and a flat JSON Schema with example values. Never copy internal parameter names.
الصق عملية واحدة في كل مرة في حقل الأمر النصي، أو مجموعة صغيرة من العمليات المرتبطة. مواصفة كاملة بحجم 5 MB تنتج مخرجات مشوشة.
اختر مستوى الجهد.low هو الأسرع ويوقف التفكير، وmedium يناسب دفعة من العمليات البسيطة، وhigh يستحق الجهد الإضافي مع أجسام الطلبات المتداخلة.
اترك الحد الأقصى للتوكنات على 8192، وهو الافتراضي، لدفعات من خمس إلى ثماني عمليات.
أرفق لقطة شاشة إذا كان كل ما لديك وثائق مُصيَّرة. يقبل حقل الصورة صورة واحدة.
راجع قبل الشحن. شغّل كل مسودة عبر MCP Inspector وأصلح الأسماء المتداخلة.
💡 هل تحتاج إلى مخرجات يجب أن تُحلَّل بصيغة JSON في كل مرة؟ صُمم GPT 5 Structured لإعادة JSON نظيفًا، وهو مناسب لمسودات المخططات التي تنوي تحميلها مباشرة في الكود.
ابنِ مجموعة أدوات الوكيل الخاصة بك
اختر API واحدة، وخمس أدوات، وفترة بعد ظهر متاحة. انشر نسخة القراءة فقط أولًا، واختبرها بعشرة أوامر نصية حقيقية، وبعد ذلك فقط أضف الأدوات التي تكتب أو تحذف.
يحتاج الوكلاء إلى أشياء يعرضونها، لا إلى بيانات يقرؤونها فقط. جرّب بنفسك على Picasso IA: اكتب أمرًا نصيًا في PicassoIA Image، واختر 16:9، ثم حسّن النتيجة باستخدام PicassoIA Image Editor Pro، الذي يقبل حتى ثلاث صور مرجعية. حين تبدو الصورة الثابتة صحيحة، حرّكها باستخدام Picasso IA Video أو مدّد اللقطة إلى عشر ثوانٍ باستخدام Seedance 2.5 Lite. جرّب مشاهدك الخاصة، وحين تكون مستعدًا، ابنِ أداة MCP التي تمكّن وكيلك من فعل الشيء نفسه.