شرح MCP وفق المواصفة: ما هو الخادم حقًا
سطر JSON واحد إلى subprocess يعيد 13 تعريف tool، وفق مراجعة 2026-07-28 التي أزالت handshake.
في هذه الصفحة
ثبّت خادم MCP منشورًا، وأرسل إليه سطرًا واحدًا من JSON، واقرأ ما يعود.
npm i @modelcontextprotocol/server-everything@2026.8.31
echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' \
| npx @modelcontextprotocol/server-everything stdio{"result":{"tools":[{"name":"echo","title":"Echo Tool","description":"Echoes
back the input string","inputSchema":{"$schema":"http://json-schema.org/draft-07/
schema#","type":"object","properties":{"message":{"type":"string","description":
"Message to echo"}},"required":["message"]},"annotations":{"readOnlyHint":true,
… … 7,663 bytes on one line …
"jsonrpc":"2.0","id":1}ثلاثة عشر تعريف tool، في سطر واحد، من عملية قرأت سطرًا واحدًا من دخلها القياسي. لقد تحدثت الآن Model Context Protocol، بلا SDK، ولا مكتبة عميل، ولا framework. هذا هو الأمر كله: transport، وصيغة رسائل، ومجموعة صغيرة من الطرق المسماة.
عرّف الفصل 18 الـ tool بوصفها شيئين: JSON Schema يراه النموذج، وendpoint في كودك لا يراه النموذج أبدًا. وبنى الفصل 23 harness يمسك فهرسًا منها. لم يُجب أي منهما عن السؤال الذي يحدد ما إذا كان أي من ذلك قابلًا لإعادة الاستخدام: من يكتب schema، وكيف ينتقل مما كتبه صاحبه إلى prompt الخاص بك؟ MCP إجابة واحدة عن هذا السؤال، ويستحق القراءة من الأصل، لأن كل ما كُتب عنه تقريبًا يصف مراجعة لم تعد موجودة.
هناك ثلاثة أشياء خاطئة في الأمر الذي شغّلته للتو، وكل واحد منها قسم في هذا الفصل. لم يحمل إصدار البروتوكول، لذلك كان خادم ملتزم سيرفضه. ومع ذلك حصل على إجابة، لسبب تسميه المواصفة خطرًا لا ميزة. وطلب واحدة من ثلاث بدائيات من دون أن يكتشف أصلًا أن الاثنتين الأخريين موجودتان.
المشكلة التي يحلها، والتشبيه الذي تطرحه المواصفة نفسها
رابط إلى القسم: المشكلة التي يحلها، والتشبيه الذي تطرحه المواصفة نفسهاقبل السلك، الحساب. لديك تطبيقات AI و أشياء ينبغي أن تستطيع الوصول إليها — تقويم، ونظام تتبع تذاكر، وقاعدة بيانات مستودع، وأداة تصميم. بلا عقد مشترك، يكتب أحدهم تكاملًا، وكل واحد منها schema وendpoint وقصة مصادقة وعبء صيانة. ومع وجود عقد، يكتب مورّد الأداة خادمًا، ويكتب مورّد التطبيق عميلًا، ويصبح المجموع .
ليست هذه ملاحظة جديدة، وتقول المواصفة لمن تعود الفكرة:
يستلهم MCP بعضًا من Language Server Protocol، الذي يوحّد طريقة إضافة دعم لغات البرمجة عبر منظومة كاملة من أدوات التطوير. وبطريقة مشابهة، يوحّد MCP طريقة دمج context وأدوات إضافية في منظومة تطبيقات AI.1
خذ هذه المقارنة حرفيًا لا بوصفها مجاملة. قبل ذلك البروتوكول، كان دعم لغة في محرر يعني plugin لكل محرر؛ بعده، صار فريق اللغة يشحن خادمًا واحدًا ويحصل عليه كل محرر. لم يكن معيار النجاح الأناقة، بل توقف عدد التكاملات عن التضاعف. وينطبق الأمر نفسه هنا: القيمة في عدد التطبيقات، لا في التصميم. البروتوكول الذي يتحدثه منتجان ليس إلا صيغة بيانات مع مراسم إضافية.
ما يوجد فعليًا على السلك
رابط إلى القسم: ما يوجد فعليًا على السلكرسائل MCP هي JSON-RPC 2.0. الطلب كائن يحتوي على jsonrpc وid وmethod وparams اختيارية؛ وتحمل الاستجابة id نفسه وإما result أو error؛ أما الإشعار فهو طلب بلا id ولا يحصل على رد. تضيف المواصفة ثلاثة قيود فوق ذلك: يجب أن يكون id نصًا أو رقمًا ويجب ألا يكون null، ويجب ألا يتصادم مع طلب آخر ما زال قيد التنفيذ، ويجب أن تحمل كل نتيجة حقل resultType.2
على stdio transport — وهو الذي استخدمه الأمر أعلاه — قاعدة التأطير هي سطر واحد لكل رسالة:
تُفصل الرسائل بأسطر جديدة، وMUST NOT تحتوي على أسطر جديدة مضمّنة. […] MUST NOT يكتب الخادم أي شيء إلى
stdoutالخاص به لا يكون رسالة MCP صالحة.3
هذه العبارة الأخيرة هي أكثر طريقة شائعة ينكسر بها خادم منزلي الصنع، وينكسر بصمت: console.log عابر، أو شريط تقدم، أو تحذير deprecation من اعتماد، فيصطدم محلل أسطر العميل بشيء ليس JSON. مخرج النجاة في القسم نفسه — may يكتب الخادم ما يشاء إلى stderr، وshould not يعامل العميل ذلك كخطأ. الخادم المرجعي أعلاه يطبع Starting default (STDIO) server... في كل تشغيل، على stderr، ولهذا استمر pipe في العمل.
الـ transport القياسي الآخر هو Streamable HTTP: كل رسالة هي POST إلى endpoint واحد، والرد إما كائن JSON أو stream من Server-Sent Events بنطاق الطلب — وهي صيغة السلك التي حللها الفصل 14 يدويًا. الدلالات متطابقة في كليهما، لأن transport هو binding: يحدد التأطير والتسليم، لا المعنى.4
أول شيء كان خاطئًا: لم يكن هناك إصدار
رابط إلى القسم: أول شيء كان خاطئًا: لم يكن هناك إصدارأرسل الأمر أعلاه tools/list ولا شيء غيره. وفق المراجعة الحالية، هذا الطلب مشوّه، وعلى خادم ملتزم أن يرفضه.
منذ 2026-07-28، MCP بروتوكول عديم الحالة، وتقول المواصفة ذلك بلا مواربة:
Model Context Protocol (MCP) هو بروتوكول عديم الحالة: كل المعلومات اللازمة لمعالجة طلب موجودة داخل الطلب نفسه. يعالج الخادم كل طلب بشكل مستقل؛ ولا ينبغي استنتاج أي حالة من طلبات سابقة، حتى تلك الموجودة على الاتصال أو stream نفسه.2
لذلك يحمل كل طلب إصدار البروتوكول الخاص به وقدرات العميل الخاصة به، داخل كائن _meta محجوز ضمن params. حقلان من هذه الحقول مطلوبان في كل طلب بلا استثناء؛ والطلب الذي ينقصه أي منهما مشوّه وعلى الخادم must أن يجيب -32602:2
مفتاح _meta | مطلوب | ما هو |
|---|---|---|
io.modelcontextprotocol/protocolVersion | نعم | المراجعة التي يتحدث بها هذا الطلب، مثل "2026-07-28" |
io.modelcontextprotocol/clientCapabilities | نعم | ما يستطيع العميل فعله للخادم في هذا الطلب |
io.modelcontextprotocol/clientInfo | لا (لكن should) | اسم العميل وإصداره، للعرض والسجلات فقط |
io.modelcontextprotocol/logLevel | لا | أدنى مستوى log ينبغي أن يصدره الخادم لهذا الطلب |
مكتوبًا كاملًا، يكون tools/list الصحيح هكذا — وهذه آخر مرة يعرض فيها هذا الفصل metadata كاملة، لأنها موجودة في كل طلب من الآن فصاعدًا:
{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{"_meta":{
"io.modelcontextprotocol/protocolVersion":"2026-07-28",
"io.modelcontextprotocol/clientCapabilities":{"elicitation":{"form":{}}},
"io.modelcontextprotocol/clientInfo":{"name":"bare-hands","version":"0.0.1"}}}}كائن القدرات هو التفاوض. لم تعد هناك خطوة تفاوض منفصلة: يعلن العميل ما يستطيع فعله في كل طلب، ويعلن الخادم ما يستطيع فعله في النتيجة، ولا يجوز لأي طرف استخدام ميزة لم يعلنها الطرف الآخر. الخادم الذي يحتاج قدرة لم يعلنها العميل must أن يجيب -32021 ويسمي القدرة الناقصة في data.requiredCapabilities. والخادم الذي لا يتحدث الإصدار المطلوب must أن يجيب -32022 ويسرد الإصدارات التي يتحدثها.2
العملاء الذين يريدون الإجابة مسبقًا يمكنهم طلبها: server/discover هي RPC إلزامية تعيد الإصدارات المدعومة، والقدرات، والهوية، وكتلة اختيارية من instructions في رحلة واحدة ذهابًا وإيابًا.5 استدعاؤها اختياري. تنفيذها ليس كذلك.
الشيء الثاني الذي كان خاطئًا: كان الخادم legacy
رابط إلى القسم: الشيء الثاني الذي كان خاطئًا: كان الخادم legacyنجح الأمر. وفق المراجعة الحالية، ما كان ينبغي أن ينجح، والسبب يستحق قياسًا لا فقرة، لأنه يختصر حالة المنظومة بأكملها في سطر واحد.
افحص الخادم المرجعي بالطريقة التي تطلب المواصفة من عميل حديث أن يفحص بها:
echo '{"jsonrpc":"2.0","id":1,"method":"server/discover","params":{"_meta":{
"io.modelcontextprotocol/protocolVersion":"2026-07-28",
"io.modelcontextprotocol/clientCapabilities":{}}}}' \
| npx @modelcontextprotocol/server-everything stdio{"jsonrpc":"2.0","id":1,"error":{"code":-32601,"message":"Method not found"}}هذا هو الفرع الثالث من قاعدة التوافق: DiscoverResult يعني حديثًا، وخطأ حديث معروف يعني حديثًا لكن بإصدار خاطئ، وأي شيء آخر — بما في ذلك -32601 — يعني legacy، فارجع إلى handshake initialize.3 إذن افعل ذلك، طالبًا المراجعة الحالية:
→ {"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2026-07-28",
"capabilities":{},"clientInfo":{"name":"bare-hands","version":"0.0.1"}}}
← {"result":{"protocolVersion":"2025-11-25","capabilities":{"tools":{"listChanged":true},
"prompts":{"listChanged":true},"resources":{"subscribe":true,"listChanged":true},
"logging":{},"tasks":{…},"completions":{}},"serverInfo":{"name":"mcp-servers/everything",
"title":"Everything Reference Server","version":"2.0.0"},"instructions":"…"}}طلب العميل 2026-07-28 وأجاب الخادم 2025-11-25. في 7 سبتمبر 2026، لا يطبق الخادم المرجعي الرسمي — حزمة npm @modelcontextprotocol/server-everything، الإصدار 2026.8.31، المنشورة في 31 أغسطس 2026 — المراجعة الحالية. وكذلك، بحسب التواريخ، TypeScript SDK الذي بُني عليه: صدر الإصدار 1.30.0 في 27 يوليو 2026، قبل المراجعة بيوم واحد.
اقرأ النتيجة لا القيل والقال. كل ما كُتب تقريبًا عن MCP يصف بروتوكولًا فيه handshake initialize، وجلسة، وطلب roots/list يرسله الخادم إلى العميل، وHTTP+SSE transport. الأربعة اختفت أو في طريقها إلى الاختفاء. عندما تقرأ أي شيء عن MCP، بما في ذلك هذه الصفحة، فأول ما تبحث عنه هو رقم المراجعة.
والسبب في نجاح الأمر الأول جدًا مذكور في المواصفة بوصفه خطرًا لا ميزة:
بعض خوادم legacy لا تتحقق من أن الطلب يصل بعد
initializeوقد تعالج method ملتبسة الحقبة (مثلtools/call) وفق دلالات legacy. يعطي الفحص فشلًا حتميًا بدلًا من ذلك.3
مقاس: إرسال tools/list إلى ذلك الخادم بلا أي handshake يعيد الفهرس كاملًا. طريقة كان ينبغي رفضها تمت خدمتها، وهذا بالضبط سبب قول المواصفة إن عليك الفحص أولًا بـ server/discover حتى عندما لا تدعم إلا الإصدارات الحديثة.
ثلاثة أدوار، والجملة التي ينبغي اقتباسها من الوثيقة كلها
رابط إلى القسم: ثلاثة أدوار، والجملة التي ينبغي اقتباسها من الوثيقة كلهالدى MCP ثلاثة أطراف، والتمييز بين الأولين هو ما يخلطه الناس:
Host. التطبيق: منتج chat، أو المحرر، أو الـ agent. يملك المحادثة، والنموذج، والاعتمادات، وموافقة المستخدم. ينشئ العملاء ويفرض حد الأمان بينهم.
Client. موصل داخل host. يتحدث كل client إلى خادم واحد بالضبط — علاقة صارمة 1:1 — ويرفق إصدار البروتوكول والقدرات بكل طلب يوجهه.
Server. عملية أو خدمة تكشف موارد وtools وprompts. يمكن أن تكون محلية أو بعيدة، وتعمل مستقلًا، ومهمتها كلها نطاق واحد مركز.6
قاعدة «خادم واحد بالضبط» ليست مسك دفاتر. إنها ما يجعل مبدأ التصميم أدناه قابلًا للتنفيذ، وهذه هي الجملة التي ينبغي أخذها من المواصفة إن أخذت واحدة فقط:
ينبغي ألا تستطيع الخوادم قراءة المحادثة كلها، ولا «الرؤية داخل» خوادم أخرى. تتلقى الخوادم فقط المعلومات السياقية الضرورية. يبقى تاريخ المحادثة الكامل لدى host. يحافظ كل خادم على العزل. يتحكم host في التفاعلات العابرة للخوادم.6
هذا يقلب النموذج الذهني الذي يأتي به معظم الناس. خادم طقس توصله بمساعدك لا يرى ما سألت عنه. يرى tools/call مع الوسائط التي اختارها النموذج، ولا شيء آخر — لا الجولات السابقة، ولا system prompt الخاص بك، ولا النتائج التي أعادها خادم التقويم قبل لحظة. إذا احتاج خادمان إلى التعاون، ينقل host قيمة من أحدهما إلى الآخر، عمدًا، لأن النموذج طلب ذلك. ولهذا يكون العزل خاصية الأمان التي يستند إليها الفصل 30: للخادم المخترق نصف قطر ضرر صغير ومحدد، وتوسيعه يتطلب تعاون host.
الشيء الثالث: ثلاث بدائيات، مرتبة بحسب من يتحكم
رابط إلى القسم: الشيء الثالث: ثلاث بدائيات، مرتبة بحسب من يتحكمطلب الأمر الأول من ذلك الخادم tools وحصل على ثلاثة عشر. اسأله السؤالين الآخرين وسيجيب عليهما أيضًا: resources/list يعيد سبعة، وprompts/list يعيد أربعة. لم يظهر أي منها، لأن لا شيء طلبها. وهذا يقودنا إلى العمود الفقري التعليمي لـ MCP، الموجود في المواصفة كجدول لا يقتبسه أحد تقريبًا:
| Primitive | Control | Description | Example |
|---|---|---|---|
| Prompts | User-controlled | قوالب تفاعلية تُستدعى باختيار المستخدم | أوامر Slash، خيارات قائمة |
| Resources | Application-controlled | بيانات سياقية يرفقها العميل ويديرها | محتويات ملفات، تاريخ git |
| Tools | Model-controlled | دوال مكشوفة للـ LLM لاتخاذ إجراءات | طلبات API POST، كتابة ملفات |
ليست «ثلاث طرق لكشف قدرة». بل ثلاث إجابات عن من يقرر أن هذا يحدث. النموذج يقرر استدعاء tool. التطبيق يقرر إرفاق resource. والشخص يقرر تشغيل prompt. أخطئ في ذلك وستظل الميزة تعمل، لكنها تعمل في اللحظة الخطأ وللسبب الخطأ.
أوضح طريقة للإحساس بذلك هي التقويم. هذا خادم يكشف التقويم نفسه ثلاث مرات، مرة بكل primitive، في مئة سطر من Node عادي بلا تبعيات:
const TOOL = {
name: "create_event",
description: "Create a calendar event. Writes to the calendar.",
inputSchema: {
type: "object",
properties: {
title: { type: "string", description: "Event title." },
startsAt: { type: "string", format: "date-time", description: "Start, ISO 8601 UTC." },
},
required: ["title"],
},
};
switch (method) {
case "resources/read":
return ok(id, { contents: [{ uri: "calendar://week",
mimeType: "application/json", text: JSON.stringify(EVENTS) }],
ttlMs: 60000, cacheScope: "private" });
case "prompts/get":
return ok(id, { description: PROMPT.description, messages: [{ role: "user",
content: { type: "text", text: `Read calendar://week and draft a plan. ` +
`Focus: ${params.arguments?.focus ?? "balance"}.` } }] });
case "tools/list":
return ok(id, { tools: [TOOL], ttlMs: 300000, cacheScope: "public" });
}شغّله واسأله بالطرق الثلاث. خرج حقيقي، رسالة واحدة في كل سطر على السلك، ملفوف هنا للصفحة، مع حذف _meta من الطلب وكتلة هوية الخادم:
→ resources/read {"uri":"calendar://week"}
← {"resultType":"complete","contents":[{"uri":"calendar://week",
"mimeType":"application/json","text":"[{\"id\":\"e1\",\"title\":\"Standup\",
\"startsAt\":\"2026-09-07T09:00:00Z\"},{\"id\":\"e2\",\"title\":\"Design review\",
\"startsAt\":\"2026-09-09T15:00:00Z\"}]"}],"ttlMs":60000,"cacheScope":"private"}
→ prompts/get {"name":"prepare_week","arguments":{"focus":"deep work"}}
← {"resultType":"complete","description":"Read the week and draft a plan.",
"messages":[{"role":"user","content":{"type":"text",
"text":"Read calendar://week and draft a plan. Focus: deep work."}}]}
→ tools/call {"name":"create_event","arguments":{"title":"Dentist",
"startsAt":"2026-09-10T08:30:00Z"}}
← {"resultType":"complete","content":[{"type":"text",
"text":"Created e3: Dentist at 2026-09-10T08:30:00Z"}],
"structuredContent":{"id":"e3","title":"Dentist","startsAt":"2026-09-10T08:30:00Z"},
"isError":false}ثلاث methods، وثلاثة أشكال، وتقويم واحد. والآن المغزى:
قراءة الأسبوع resource
رابط إلى القسم: قراءة الأسبوع resourceتُعنون عبر URI، وهي خاملة، والتطبيق هو الذي يقرر هل يرفقها بالمحادثة. لا يوجد في البروتوكول ما يسمح للنموذج بأن يصل إليها من تلقاء نفسه. تحمل النتيجة ttlMs وcacheScope، وهما جديدان في هذه المراجعة، لكي يستطيع العميل cache الأسبوع لدقيقة بدل polling.
إنشاء حدث tool
رابط إلى القسم: إنشاء حدث toolله schema، وله آثار جانبية، والنموذج يقرر متى يستدعيه. تحمل نتيجته isError، وهو الحقل الذي دافع عنه الفصل 18: يعود فشل التحقق كـ tool result يستطيع النموذج قراءتها وتصحيحها، لا كخطأ بروتوكول.
«حضّر أسبوعي» prompt
رابط إلى القسم: «حضّر أسبوعي» promptهو قالب مسمى يأخذ وسائط والشخص يستدعيه — أمر slash في القائمة. يعيد رسائل، لا إجابة. إنه طريقة لمؤلف الخادم كي يشحن الصياغة التي تعمل مع tools الخاصة به، وهي بالضبط المعرفة التي يملكها مؤلف الخادم ولا يملكها المستخدم.
يكاد الجميع يجعلون هذه الثلاثة كلها tools. النتيجة فهرس يتنافس فيه read كان ينبغي أن يرفقه التطبيق بصمت على attention النموذج مع write يحتاج موافقة، وفيه الشيء الوحيد الذي أراد الشخص زرًا له مدفون داخل schema. لا يكلف تصحيح ذلك شيئًا، ويُحسم قبل أن تكتب سطرًا واحدًا.
الخادم لا يستطيع الاتصال بك
رابط إلى القسم: الخادم لا يستطيع الاتصال بكلدى tool التقويم وسيط مطلوب واحد، title، وstartsAt اختياري. اطلب منه إنشاء حدث بلا تاريخ، ويعود شيء مثير للاهتمام:
→ tools/call {"name":"create_event","arguments":{"title":"Dentist"}}
← {"resultType":"input_required",
"inputRequests":{"when":{"method":"elicitation/create","params":{"mode":"form",
"message":"When should \"Dentist\" start?",
"requestedSchema":{"type":"object",
"properties":{"startsAt":{"type":"string","format":"date-time"}},
"required":["startsAt"]}}}},
"requestState":"eyJ0aXRsZSI6IkRlbnRpc3QifQ=="}لم يرسل الخادم طلبًا. لقد أجاب عن الطلب الذي تلقاه، مع resultType: "input_required" ووصف لما لا يزال يحتاجه. يجمع العميل الإجابة من الشخص، ثم يعيد إرسال الاستدعاء الأصلي — مع id جديد، حاملًا inputResponses ومرددًا requestState المعتمة:
→ tools/call {"name":"create_event","arguments":{"title":"Dentist"},
"inputResponses":{"when":{"action":"accept",
"content":{"startsAt":"2026-09-10T08:30:00Z"}}},
"requestState":"eyJ0aXRsZSI6IkRlbnRpc3QifQ=="}
← {"resultType":"complete","content":[{"type":"text",
"text":"Created e3: Dentist at 2026-09-10T08:30:00Z"}],"isError":false}هذه هي Multi Round-Trip Requests، أُدخلت في المراجعة الحالية، واستبدلت التصميم الأقدم حيث كانت الخوادم ترسل طلبات JSON-RPC عائدة إلى العملاء. تنص مواصفة transport الآن على القاعدة بصراحة: «الخوادم لا تبدأ طلبات JSON-RPC والعملاء لا يرسلون استجابات JSON-RPC».4 توجد جهة مبادرة واحدة، وهي host.
تركب ميزتان من جهة العميل على تلك الآلية، وإحداهما تحمل اسمًا سيوقعك في اللبس.
Elicitation هو أن يطلب الخادم من الشخص شيئًا: نموذجًا مع JSON Schema مقيّدة عمدًا — كائنات مسطحة، وخصائص بدائية، بلا تداخل — بحيث يستطيع أي عميل عرضها بلا محرك تخطيط. وتحمل قاعدة صارمة: على الخوادم must not استخدام وضع النموذج لطلب «passwords, API keys, access tokens, or payment credentials»، وmust استخدام وضع URL لهذه الأشياء، الذي يرسل المستخدم إلى صفحة لا يقرأها العميل أبدًا.7
Sampling هو أن يطلب الخادم توليدًا من نموذج host، لكي يكون الخادم ذكيًا من دون امتلاك API key. وهنا تحذير المفردات، لأن هذه الكلمة تعني شيئًا آخر بالفعل في هذا المساق: هذا ليس sampling في الفصل 17. لا يتعلق شيء هنا بالحرارة، أو top-p، أو شكل توزيع الاحتمالات. إنه استدعاء نموذج متداخل يسافر بالعكس عبر بروتوكول.
وهناك سبب ثانٍ لعدم التسرع في استخدامه: اعتبارًا من هذه المراجعة، sampling deprecated، إلى جانب roots وlogging، ضمن SEP-2577، مع هجرة مقترحة مباشرة — «ادمج مباشرة مع APIs مزودي LLM بدل Sampling».8 لم تفشل الفكرة تقنيًا؛ فشلت في تبرير مساحة سطحها، والبروتوكول القادر على إزالة الأشياء أصح من بروتوكول لا يستطيع.
اكسره عمدًا: الاتصالات ليست جلسات
رابط إلى القسم: اكسره عمدًا: الاتصالات ليست جلساتتبدو انعدام الحالة تفصيلًا في wire format حتى تختبرها. خذ التبادل ذي الرسائل الثلاث أعلاه وشغّل كل رسالة في عملية منفصلة — node calendar.mjs جديدة، بلا ذاكرة مشتركة، ولا شيء محمول:
process A tools/call (no date) → resultType: input_required
requestState: eyJ0aXRsZSI6IkRlbnRpc3QifQ==
process B tools/call (with the answer, same requestState)
→ resultType: complete
"Created e3: Dentist at 2026-09-10T08:30:00Z"
process C resources/read calendar://week
→ events: 2 (Standup, Design review)أكملت العملية B، التي لم ترَ السؤال قط، استدعاء multi-round-trip بدأته العملية A. هذا هو مغزى requestState: تنتقل الاستمرارية داخل الرسالة، فلا يعتمد شيء على أن تكون العملية هي نفسها.
العملية C هي الفشل. أُنشئ الحدث وليس هناك — لأن الخادم التجريبي يحتفظ بـ EVENTS في مصفوفة على مستوى الوحدة، والمصفوفة على مستوى الوحدة هي حالة اتصال. تسمي ملاحظة المواصفة الخطأ بدقة:
الاتصال المفتوح، مثل عملية STDIO، ليس محادثة ولا جلسة: قد يخلط العملاء طلبات غير مرتبطة على transport نفسه، ولا يجوز للخادم أن يعامل هوية الاتصال أو العملية كبديل لاستمرارية المحادثة أو الجلسة.2
الإصلاح الموصوف ليس جلسة. إنه handle صريح: تعيد tool إنشاء معرّفًا معتمًا، وكل استدعاء لاحق يأخذه كوسيط عادي. لا يملك البروتوكول أي مفهوم له على الإطلاق — «من منظور السلك، handle نص عادي في tool result ووسيط عادي لاستدعاءات tool لاحقة».9 وهذا يضع النموذج مسؤولًا عن حمله، ويضع الخادم مسؤولًا عن التحقق في كل استدعاء على حدة من أن هذا المستدعي مسموح له باستخدامه، لأن handle اسم وليس إذنًا.
ما يكلّفه الخادم قبل أن يفعل أي شيء
رابط إلى القسم: ما يكلّفه الخادم قبل أن يفعل أي شيءكل tool يكشفها خادم هي schema تدخل في prompt الخاص بك في كل طلب، وقد قاس الفصل 24 ما يفعله ذلك بالنافذة. يضيف MCP بندًا ثانيًا يسهل تفويته، لذلك يستحق كلاهما العد على الخادم المرجعي أعلاه.
13 tool definitions (name + description + inputSchema): 1,307 tokens
cheapest tool, get-tiny-image 52
costliest tool, gzip-file-as-resource 235
server `instructions`, returned by discovery: 312 tokens
------
one server, connected, before it is used: 1,619 tokensملاحظتان. الأولى حسابية: صِل خمسة خوادم بهذا الحجم وسيُحجز تقريبًا ثمانية آلاف token من نافذتك في كل جولة، إلى الأبد، سواء استخدم النموذج أيًا منها أم لا — وهي الآلية خلف تخفيض 150,000 إلى 2,000 الذي اقتبسه الفصل 24، وسبب وجود اكتشاف tools في الوقت المناسب.
الثانية ملاحظة أمنية ترتدي زي محاسبة. instructions هو نص بلغة طبيعية، كتبه مؤلف الخادم، ويهبط في prompt الخاص بالـ host، وأوصاف tools بجانبه كذلك. تقول المواصفة ما ينبغي فعله حيال ذلك في مبادئها الأمنية: ينبغي اعتبار annotations وأوصاف tools «غير موثوقة، ما لم تُؤخذ من خادم موثوق»، وعلى hosts «الحصول على موافقة صريحة من المستخدم قبل استدعاء أي tool».1 وصل خادم MCP ليس إضافة اعتماد. إنه منح غريب 1,619 token من system prompt الخاص بك وحق الاستدعاء. الفصل 30 هو ما يحدث عندما يكون ذلك الغريب عدائيًا.
قسم مؤرخ: مراجعة 2026-07-28، وما تكسره
رابط إلى القسم: قسم مؤرخ: مراجعة 2026-07-28، وما تكسرهكل شيء في هذا القسم صحيح عن مراجعة البروتوكول 2026-07-28، الحالية، كما قُرئت في 7 سبتمبر 2026. تُؤرّخ المراجعات بصيغة YYYY-MM-DD والتاريخ هو آخر مرة أُجري فيها تغيير غير متوافق إلى الخلف.10 الوثيقة المعيارية هي ملف TypeScript، schema/2026-07-28/schema.ts؛ وJSON Schema المجاور له مولد منه، ولهذا تُقرأ المواصفة هنا في TypeScript، ولهذا فإن تعليم MCP من أي شيء آخر هو تعليم ترجمة.
| ما تغيّر | كان | أصبح الآن | يكسر |
|---|---|---|---|
| The handshake | initialize + notifications/initialized، مرة لكل اتصال | أُزيل؛ كل طلب يحمل إصدار _meta والقدرات | كل عميل كُتب قبل هذه المراجعة |
| Sessions | ترويسة Mcp-Session-Id، حالة بنطاق الاتصال | أُزيلت؛ تنتقل الحالة في handles صريحة يصكّها الخادم | list endpoints التي كانت تختلف حسب الاتصال |
| Discovery | يُستنتج من نتيجة initialize | server/discover، وعلى الخوادم must تنفيذه | لا شيء، لكنه أصبح الآن إلزامي التنفيذ |
| Server-to-client calls | كان الخادم يرسل roots/list، sampling/createMessage، elicitation/create | InputRequiredResult وإعادة محاولة من العميل | كل خادم كان يدفع طلبًا إلى عميل |
| Result shape | أي كائن | resultType مطلوب: "complete" أو "input_required" | لا شيء: الحقل الغائب يجب أن يُقرأ كـ "complete" |
| Subscriptions | HTTP GET stream، resources/subscribe | stream واحد subscriptions/listen مع أنواع opt-in | اختفى GET endpoint |
| Stream resumption | إعادة تشغيل Last-Event-ID على Streamable HTTP | أُزيل؛ stream المنقطع يفقد الطلب، أعد الإصدار بـ id جديد | العملاء الذين اعتمدوا على إعادة التسليم |
| Roots | ميزة عميل تستطيع الخوادم طلبها | deprecated (SEP-2577)؛ مرّر المسارات كوسائط tool أو resource URIs | لا شيء بعد — نافذة اثني عشر شهرًا |
| Sampling and logging | ميزات عميل | deprecated (SEP-2577) | لا شيء بعد — نافذة اثني عشر شهرًا |
| HTTP+SSE transport | deprecated منذ 2025-03-26 | Deprecated بموجب سياسة دورة الحياة (SEP-2596) | انتقل إلى Streamable HTTP |
| Client registration | OAuth 2.0 Dynamic Client Registration، RFC 7591 | deprecated لصالح Client ID Metadata Documents | محفوظ لخوادم authorization التي لا تملكها |
| Error codes | -32002 لـ resource غير موجود | -32602؛ -32020–-32099 محجوزة للمواصفة | رموز جديدة -32020، -32021، -32022 |
تغيير الحوكمة أسفل ذلك الجدول أهم من أي صف منفرد. تبنت هذه المراجعة دورة حياة ميزات وسياسة deprecation: الميزات Active أو Deprecated أو Removed، والميزة deprecated توثق مسار هجرتها وتبقى في المواصفة اثني عشر شهرًا على الأقل قبل أن تصبح مؤهلة للإزالة، وهناك سجل يسرد كل ما هو حاليًا في حالة Deprecated.8 قبل تلك السياسة، كانت «deprecated» في بروتوكول AI تعني ما قالته آخر تدوينة. الآن تعني تاريخًا.
عرض التفاصيل
Extensions، وهي الجزء الذي لم يكتب عنه أحد بعد.
خارج النواة، يعرّف MCP extensions اختيارية — «دائمًا opt-in وتتطلب دعمًا صريحًا من العميل والخادم كليهما»، وتُعلن عبر حقل extensions في قدرات العميل والخادم.1 ثلاث منها تستحق معرفتها بالاسم:
- Tasks (
io.modelcontextprotocol/tasks)، نُقلت من البروتوكول الأساسي إلى extension رسمية في هذه المراجعة: تنفيذ غير متزامن لعمليات طويلة، مع polling عبرtasks/get، وإدخال أثناء التنفيذ عبرtasks/update، وhandles دائمة. إنها الإجابة عن tool تستغرق عشرين دقيقة، وهو ما عالجه الفصل 23 بحدث تقدم وإشارة تصل إلى tool. - Skills over MCP، مجموعة عمل تجعل skills الخاصة بالـ agent — موضوع الفصل 28 — قابلة للاكتشاف والاستهلاك عبر البروتوكول.
- MCP Apps، واجهة تفاعلية تُعرض inline في المحادثة: مخططات، ونماذج، ومشغلات فيديو.
ولاحظ ما يعنيه «التفاوض» الآن: لا توجد initialization للتفاوض عندها، لذلك تُعلن extension لكل طلب مثل كل شيء آخر.
أين يقع MCP مقارنة بكل ما يُخلط به
رابط إلى القسم: أين يقع MCP مقارنة بكل ما يُخلط بههذه مفردات الكتلة كلها في مكان واحد.
| ما هو | من يتحدث إلى من | متى يكون هو الجواب | |
|---|---|---|---|
| API عادية | واجهة لبرنامج | كودك ↔ خدمة | أنت تكتب المستدعي. تتحكم في schema والمصادقة ومعالجة الأخطاء، ولا توجد مشكلة اكتشاف لحلها. |
| MCP | بروتوكول لكشف tools وبيانات وقوالب لتطبيق AI | host ↔ server، عميل واحد لكل منهما | شخص آخر كتب القدرة وينبغي أن تستطيع hosts كثيرة استخدامها بلا تكامل مفصل خصيصًا. |
| RAG | تقنية للعثور على نص ووضعه في prompt | كودك ↔ فهرسك | يحتاج النموذج أن يعرف شيئًا. الفصل 19. MCP طريقة لتسليم retriever؛ ليس retriever. |
| Agent skills | مجلد يحتوي على SKILL.md يقرؤه النموذج reads | model ↔ مستند | المعرفة إجرائية — كيف نفعل نحن هذا — وهي نثر، لا دالة. الفصل 28. |
| A2A | بروتوكول لتعاون agents كأنداد | agent ↔ agent | الطرف الآخر يفكر، ويخطط، ويحمل حالة عبر مهمة طويلة، بدل أن يجيب عن استدعاء. |
| ACP | كان بروتوكولًا منفصلًا لتواصل agents | — | لم يعد مقارنة حيّة. انظر أدناه. |
اثنان منها يستحقان جملة لكل واحد، لأنهما موضع الالتباس فعلًا.
MCP مقابل A2A ليس منافسة، وكلا المواصفتين تقولان ذلك. ترسم وثائق A2A الخط بحسب ما يوجد في الطرف الآخر: MCP «يعرّف كيف يتفاعل agent AI مع tools وresources فردية ويستخدمها، مثل قاعدة بيانات أو API»، حيث تؤدي tool «وظائف محددة، وغالبًا عديمة الحالة»؛ أما A2A فيتناول agents، وهي «أنظمة أكثر استقلالية» تستطيع «الاستدلال، والتخطيط، واستخدام عدة tools، والحفاظ على حالة عبر تفاعلات أطول، والانخراط في حوارات معقدة غالبًا متعددة الجولات». خلاصته الخاصة هي الجملة التي ينبغي تذكرها: «A2A يتعلق بـ agents وهي تتشارك في المهام، بينما MCP يتعلق أكثر بـ agents وهي تستخدم القدرات».11 يتداخل الاثنان — يستخدم تطبيق A2A للوصول إلى agents أخرى، ويستخدم كل agent MCP للوصول إلى tools الخاصة به. رسم الفصل 25 ذلك الخط داخل عملية واحدة، بين سؤال sub-agent وتسليمه المحادثة؛ أما A2A فيرسمه بين المؤسسات.
MCP مقابل ACP مقارنة ذات فرضية قديمة، ولهذا تحديدًا تستحق الإجابة. كان Agent Communication Protocol معيارًا مفتوحًا منفصلًا لرسائل agent-to-agent. تفتح وثائقه الآن بالإشعار: «ACP أصبح الآن جزءًا من A2A تحت Linux Foundation!»12 الإجابة الصادقة عن «MCP أم ACP؟» في سبتمبر 2026 هي أن السؤال يملك خيارًا أقل مما توحي به الصفحات المتصدرة له.
أما المقارنة التي يطلبها الناس أكثر، mcp vs api، فلديها أقل إجابة إثارة: MCP هو API. ما يضيفه ليس قوة، بل اصطلاحات — مجموعة ثابتة من أسماء methods، واستدعاء discovery، وتسلسل تحكم فوق primitives، ونموذج عزل. تتخلى عن حرية تصميم واجهتك الخاصة وتحصل على كل host يتحدث البروتوكول، وهذه هي المقايضة التي عرضها كل بروتوكول على الإطلاق.
إلى أين نذهب بعد ذلك
رابط إلى القسم: إلى أين نذهب بعد ذلكيمكنك الآن قراءة المواصفة بلا مترجم، والتمييز بين resource وtool وprompt بحسب من يتحكم بها، وكتابة طلب يدويًا عندما تكذب عليك مكتبة العميل، وتأريخ أي مقالة MCP تقرأها بحسب الميزات deprecated التي ما زالت تعلمها كأنها حالية.
ما لم تفعله هو شحن واحد. يكتب الفصل 27 الخادم نفسه مرتين — TypeScript وPython، جنبًا إلى جنب، لأن MCP هو المنطقة ثنائية اللغة حقًا في هذا المساق والأرقام تقول ذلك في الاتجاهين. يغطي الـ transports الحيين بشكل صحيح، وinspector، والتغليف، ونصف البروتوكول الذي تركه هذا الفصل عمدًا: authorization. لأنه في اللحظة التي يكون فيها خادمك بعيدًا لا subprocess على حاسوبك المحمول، سيقدم عميل غريب token، وقاعدة المواصفة حول ما يجوز لك فعله به صارمة على نحو غير معتاد.
وهذا يطرح السؤال الذي يجب أن يجيب عنه الفصل التالي، وليس سؤالًا وديًا: إذا وصل token إلى خادمك وكان صادرًا لـ audience شخص آخر، فما الذي يمنعك بالضبط من تمريره؟
المصادر والمنهج
رابط إلى القسم: المصادر والمنهجكل اقتباس، واسم method، ورمز خطأ، وقاعدة في هذا الفصل قُرئت من مواصفة Model Context Protocol، مراجعة 2026-07-28، في 7 سبتمبر 2026. أُنتج كل trace محليًا على Node 22: خادم التقويم التجريبي 101 سطر بلا تبعيات، والخادم المرجعي هو حزمة npm المنشورة المسماة أدناه. لم يُستدعَ أي API مدفوع لكتابة هذا الفصل — لا شيء هنا يحتاج نموذجًا، وهذه بحد ذاتها هي الفكرة.
القياسات: @modelcontextprotocol/server-everything@2026.8.31، منشور في 31 أغسطس 2026، مبني على @modelcontextprotocol/sdk@1.30.0، منشور في 27 يوليو 2026 — قبل المراجعة التي يصفها هذا الفصل بيوم واحد. يجيب server/discover بـ -32601، ويتفاوض على 2025-11-25 عندما يُطلب منه 2026-07-28، ويخدم tools/list بلا أي handshake. فهرسه 13 tools في 7,663 بايت؛ أعداد token هي o200k_base عبر tiktoken، على name وdescription وinputSchema لكل تعريف، وهذا ما يعرضه المزود داخل prompt الخاص بك لا وزن إطار JSON-RPC.
Anthropic، Code execution with MCP: building more efficient agents، 4 نوفمبر 2025، هو مصدر رقم 150,000 إلى 2,000، المقتبس والمستخدم في الفصل 24 والمشار إليه هنا فقط.
المراجع
رابط إلى القسم: المراجع-
Specification،
modelcontextprotocol.io/specification/latest(يعيد التوجيه إلى/2026-07-28)، قُرئ في 7 سبتمبر 2026. مصدر مقارنة Language Server Protocol؛ والعبارة التي تقول إن المواصفة «based on the TypeScript schema inschema.ts»؛ وملخص البروتوكول الأساسي («Stateless, self-contained requests»، «Per-request capability negotiation»); وقائمة extensions (Tasks, Skills over MCP, MCP Apps) والعبارة التي تقول إن extensions «are always opt-in and require explicit support from both client and server»؛ ومبادئ Security وTrust & Safety، بما في ذلك «Hosts must obtain explicit user consent before invoking any tool» والتعامل مع tool annotations كغير موثوقة. ↩ ↩2 ↩3 -
Base Protocol،
modelcontextprotocol.io/specification/2026-07-28/basic. مصدر قيود JSON-RPC (id غير null، وعدم إعادة استخدام id، وresultTypeالمطلوبة)؛ وقسم Statelessness وملاحظته أن عملية stdio مفتوحة ليست جلسة؛ وجدول المفتاح المحجوز_metaوحالة الوجوب/الاختيار لكل حقل per-request؛ وقاعدة-32602للحقل المطلوب الناقص؛ وقاعدةMissingRequiredClientCapability(-32021)؛ وسياسة تخصيص error-code. ↩ ↩2 ↩3 ↩4 ↩5 -
stdio transport،
modelcontextprotocol.io/specification/2026-07-28/basic/transports/stdio. مصدر قواعد التأطير المحدد بالأسطر الجديدة، ومتطلب نقاءstdout، وسماحstderr، وفحص التوافق الخلفي ذي النتائج الثلاث — بما في ذلك التحذير من أن بعض خوادم legacy تعالج methods ملتبسة الحقبة بلا handshake، وهو ما يعيد قياسه هذا الفصل. ↩ ↩2 ↩3 -
Transports overview،
modelcontextprotocol.io/specification/2026-07-28/basic/transports. مصدر تأطير «transport is a binding» والعبارة التي تقول إن الخوادم لا تبدأ طلبات JSON-RPC والعملاء لا يرسلون استجابات JSON-RPC. ↩ ↩2 -
Discovery،
modelcontextprotocol.io/specification/2026-07-28/server/discover. مصدر إلزاميةserver/discover، وشكلDiscoverResult، وحقلinstructionsالموصوف بأنه «optional natural-language guidance for LLMs on how to use this server effectively». ↩ -
Architecture،
modelcontextprotocol.io/specification/2026-07-28/architecture. مصدر تعريفات host/client/server، وقاعدة 1:1 بين client وserver، ومبادئ التصميم الأربعة، التي يُقتبس منها هنا مبدأ العزل بلا نقطته الخامسة «Host process enforces security boundaries»، وقسم capability-negotiation. ↩ ↩2 -
Elicitation،
.../client/elicitation، وSampling،.../client/sampling. مصدر وضعي elicitation وschema المقيّدة الخاصة بهما؛ وحظر طلب credentials عبر form mode؛ وتعريف sampling، ومتطلب human-in-the-loop الخاص به، وتحذير deprecation المرفق به. ↩ -
Key Changes،
modelcontextprotocol.io/specification/2026-07-28/changelog، وFeature lifecycle and deprecation policy،.../community/feature-lifecycle. مصدر كل صف في جدول التغييرات: إزالة sessions وترويسةMcp-Session-Id(SEP-2567)؛ وstatelessness وإزالةinitialize(SEP-2575)؛ وserver/discover(SEP-2575)؛ وsubscriptions/listen(SEP-2575)؛ وMulti Round-Trip Requests وresultType(SEP-2322)؛ وإزالة stream resumability (SEP-2575)؛ وdeprecation لـ Roots وSampling وLogging (SEP-2577)؛ وإعادة تصنيف HTTP+SSE (SEP-2596)؛ وdeprecation لـ Dynamic Client Registration لصالح Client ID Metadata Documents؛ وإعادة ترقيم error-code؛ ونافذة deprecation ذات الاثني عشر شهرًا. ↩ ↩2 -
Tools،
modelcontextprotocol.io/specification/2026-07-28/server/tools، وServer Features،.../server. مصدر جدول control hierarchy المستنسخ أعلاه؛ وأشكالtools/listوtools/call؛ وتمييزisErrorبين أخطاء البروتوكول وأخطاء تنفيذ tool؛ وقواعد أسماء tools وملاحظة namespace التي توصي بـ «prefixing tool names with a server identifier»؛ والإرشادات غير المعيارية «Stateful Tools» حول handles الصريحة. ↩ -
Versioning،
modelcontextprotocol.io/specification/versioning. مصدر مخططYYYY-MM-DD، وحالات المراجعة Draft/Current/Final، والتأكيد على أن 2026-07-28 هي الحالية، وقواعد التفاوض per-request. يسرد جدول مستوى SDK فيmodelcontextprotocol.io/docs/sdkTypeScript وPython وC# وGo وRust في Tier 1، وJava وRuby في Tier 2، وSwift وPHP وKotlin في Tier 3. ↩ -
A2A Protocol، الإصدار 1.0.0،
a2a-protocol.org— المواصفة وصفحة A2A and MCP: Relationship and Distinction، قُرئتا في 7 سبتمبر 2026. مصدر التمييز بين tools وagents، والعبارة التي تقول إن البروتوكولين «address distinct but highly complementary needs»، وصياغة partnering/using. ↩ -
Agent Communication Protocol،
agentcommunicationprotocol.dev، قُرئ في 7 سبتمبر 2026: «ACP is now part of A2A under the Linux Foundation!»، لافتة أُضيفت فوق مواصفة ما زالت تُقدَّم كاملة — architecture وagent manifest وagent discovery وبنية الرسائل وstateful agents ودورة حياة run وقائمة REST endpoint كلها ما زالت تجيب 200. لم تختفِ المواصفة؛ المشروع هو الذي اختفى. ↩