تغيّر مراجعة Model Context Protocol المؤرخة في 28 يوليو 2026 طريقة تشغيل MCP البعيد. أصبح قلب البروتوكول عديم الحالة ويعتمد على طلبات مستقلة. يحمل كل طلب المعلومات اللازمة لمعالجته، ولذلك يستطيع موازن الحمل إرسال الاستدعاء التالي إلى نسخة أخرى من الخادم. تضيف المراجعة أيضاً server/discover، وطلبات Multi Round-Trip Requests (MRTR)، ورؤوس توجيه إلزامية، وتلميحات للتخزين المؤقت، وإطاراً للإضافات، وقواعد تفويض أقوى. تستند التفاصيل المعيارية في هذا الدليل إلى إعلان الإصدار الرسمي وسجل تغييرات المواصفة.
هذا تغيير في حالة البروتوكول، وليس إلزاماً بجعل منطق الأعمال كله عديم الحالة. ما زال بإمكان الأداة استخدام قاعدة بيانات أو طابور أو workflow دائم. الذي يختفي هو الحالة المخفية المرتبطة بجلسة نقل MCP، وهذا مهم عند الانتقال من عملية واحدة إلى نسخ متعددة.
ما الذي تغيّر مقارنة ببروتوكول 2025
كانت دورة الحياة القديمة تبدأ بطلب initialize ثم إشعار notifications/initialized. وفي Streamable HTTP كان الخادم قد يصدر Mcp-Session-Id ويربط الرسائل اللاحقة بذلك الاتصال. في 2026-07-28 أزيل تبادل initialize ورأس الجلسة البروتوكولي. يعلن كل طلب إصدار البروتوكول وقدرات العميل داخل _meta. وينبغي للعميل أيضاً إرسال io.modelcontextprotocol/clientInfo، بينما ينبغي للخادم تعريف نفسه في بيانات نتيجة الطلب.
يساعد الجدول التالي في تخطيط الترحيل:
| المجال | سلوك 2025 | سلوك 2026-07-28 |
|---|---|---|
| دورة الحياة | initialize وnotifications/initialized |
لا توجد مصافحة بروتوكولية |
| الجلسة | Mcp-Session-Id اختياري في HTTP |
لا توجد جلسة على مستوى البروتوكول |
| القدرات | تفاوض مرة واحدة | تعلن مع كل طلب |
| الاكتشاف | بعد initialize أو بالاتفاق | على الخادم الحديث توفير server/discover، واستدعاؤه من العميل اختياري |
| الخادم إلى العميل | طلبات عبر قناة مفتوحة | يعيد MRTR طلبات الإدخال داخل النتيجة |
| توجيه HTTP | غالباً ما يقرأ البوابة JSON | رأسا Mcp-Method وMcp-Name عند الحاجة |
| القوائم والقراءة | العميل يحدد حداثة البيانات | تلميحا ttlMs وcacheScope |
| الاستئناف | كان SSE يدعم معرّفات الأحداث | لا يوجد استئناف بـLast-Event-ID، ويجب إنشاء طلب جديد |
| تسجيل العميل | كان DCR المسار الآلي المعتاد | CIMD مفضل، وDCR للتوافق السابق |
تنقل المراجعة Tasks إلى الإضافة io.modelcontextprotocol/tasks، وتستبدل قناة التغييرات القديمة بـsubscriptions/listen، وتضع Roots وSampling وLogging وHTTP+SSE القديم في حالة إهمال. تمنح السياسة مهلة لا تقل عن اثني عشر شهراً، لكن لا ينبغي للتطبيقات الجديدة اعتمادها.
معنى البروتوكول عديم الحالة عملياً
في Streamable HTTP الحديث يعرض الخادم نقطة MCP واحدة تقبل POST. يرسل العميل طلب JSON-RPC أو إشعاراً واحداً مع كل POST. تكون النتيجة كائن JSON واحداً أو تدفق SSE خاصاً بذلك الطلب. لا ينشئ الخادم معرّف جلسة، ولا يملك التدفق المنقطع سجل أحداث يمكن استئنافه. في HTTP يعد إغلاق تدفق النتيجة إشارة إلغاء.
تصف الرؤوس والجسم العملية نفسها. هذا مثال على استدعاء أداة بسيط:
POST /mcp HTTP/1.1
Accept: application/json, text/event-stream
Content-Type: application/json
MCP-Protocol-Version: 2026-07-28
Mcp-Method: tools/call
Mcp-Name: search
{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"search","arguments":{"q":"otters"},"_meta":{"io.modelcontextprotocol/protocolVersion":"2026-07-28","io.modelcontextprotocol/clientCapabilities":{},"io.modelcontextprotocol/clientInfo":{"name":"catalog-app","version":"1.0.0"}}}}
يجب أن تطابق قيمة MCP-Protocol-Version القيمة الموجودة في _meta. يرفض الخادم الحديث الرأس الإلزامي المفقود أو غير المتطابق عبر HTTP 400 ورمز الخطأ HeaderMismatch، أي -32020. ويجب عليه إعادة فحص الرؤوس بعد مرور الطلب عبر البوابة. يمنع ذلك توجيه الطلب إلى أداة باسم بينما ينفذ التطبيق أداة أخرى.
يغيّر انعدام الحالة قابلية التوسع، ولا يغيّر معنى العمل. إذا احتاج workflow إلى الاستمرار، فأعد من الأداة handle صريحاً واطلبه في الاستدعاء التالي. خزّن الحالة المرجعية في قاعدة بيانات أو خدمة workflow، واربط handle بالمستخدم والعملية، وضع له مدة انتهاء. لا يعتبر handle أو requestState أو وسيط أداة غير متحقق منه دليلاً على الإذن.
server/discover وتوافق الإصدارات
يجب على كل خادم حديث تنفيذ RPC المسمى server/discover. تعلن نتيجته الإصدارات والقدرات المدعومة، ويمكن أن تحتوي على تعليمات اختيارية. يستطيع العميل استدعاءه أولاً لاختيار إصدار، أو إرسال طلب حديث مباشرة. لذلك يفيد discovery، لكنه ليس مصافحة إلزامية على العميل.
عندما لا يدعم الخادم الإصدار المطلوب، يعيد UnsupportedProtocolVersionError مع قائمة الإصدارات المدعومة. يختار العميل إصداراً مشتركاً ثم يعيد الطلب. يجب على العميل الذي يدعم العصرين تصنيف تجربة الاكتشاف بحذر. قد يشير رد 400 فارغ أو بلا خطأ JSON-RPC حديث معروف إلى نقطة نهاية قديمة. أما الخطأ الحديث المعروف فيعني وجوب تصحيح الطلب أو إعادة التفاوض. لا تثبت أخطاء المصادقة أو البنية التحتية أن الخادم قديم.
يمكن لـSDK حديث اختبار اتصال standard input وتثبيت العصر لذلك الاتصال. ويستطيع الخادم الاحتفاظ بمسار legacy أثناء استخدام العملاء الجدد للطلبات الحديثة. لا تستنتج العصر من اتصال TCP ناجح أو من 404 عام.
يستبدل MRTR طلبات الخادم إلى العميل
يزيل التنسيق الحديث قناة طلبات JSON-RPC من الخادم إلى العميل. عندما تحتاج الأداة إلى تأكيد أو قيمة مفقودة أو خطوة بمساعدة النموذج، تعيد نتيجة مؤقتة بدلاً من إبقاء التدفق مفتوحاً. تحمل النتيجة resultType: "input_required" وخريطة inputRequests. يجيب العميل عن الطلبات ثم يعيد استدعاء الطريقة الأصلية مع inputResponses. إعادة المحاولة طلب جديد وقد تصل إلى نسخة أخرى.
يمكن أن يبدو مسار التأكيد كما يلي:
{
"resultType": "input_required",
"inputRequests": {
"confirm": {
"type": "elicitation",
"message": "Delete three files?",
"schema": {"type": "boolean"}
}
},
"requestState": "signed-opaque-state"
}
يرسل العميل بعد ذلك inputResponses.confirm ويعيد requestState بايتاً ببايت. يجب أن يدخل الخادم معالج الطلب من جديد كما لو كان طلباً جديداً. اجعل المعالج idempotent، واستخرج الخطوة الحالية من الحالة المتحققة، ولا تطلب إلا البيانات التي ما زالت ناقصة. لا تسجل العملية المدمرة مكتملة قبل التحقق من التأكيد.
ليس requestState حاوية آمنة. يمر عبر العميل ويجب معاملته كمدخل يتحكم فيه مهاجم. وقّعه باستخدام HMAC أو تشفير موثق، واربطه بالهوية والطريقة الأصلية والوسائط المهمة ومدة الانتهاء، وارفض التلاعب قبل تشغيل المعالج. التوقيع لا يخفي المحتوى، لذلك لا تضع أسراراً فيه. يوفر TypeScript SDK codec لحالة الطلب وhook للتحقق. يستطيع legacy shim تحويل معالج input_required نفسه إلى الطلبات القديمة elicitation/create وsampling/createMessage وroots/list أثناء دعم عملاء 2025.
للعمليات الطويلة استخدم إضافة Tasks مع handle دائم، واستطلاع tasks/get، وtasks/update عندما يحتاج العميل إلى إدخال.
تلميحات التخزين المؤقت والكتالوجات الحتمية
تحمل النتائج الحديثة للعمليات tools/list وprompts/list وresources/list وresources/templates/list وresources/read الحقلين ttlMs وcacheScope. ttlMs تلميح غير سالب للحداثة بالمللي ثانية، يشبه max-age في HTTP. تعني القيمة صفر أن النتيجة قديمة فوراً. في الخوادم القديمة يجب معاملة الحقل المفقود كصفر. تخبر القيمة الموجبة العميل متى يستطيع تجنب جلب جديد، لكنها لا تضمن بقاء البيانات دون تغيير. افحص الحداثة عند الحاجة، ولا تحول TTL إلى polling مستمر.
يجب أن يضم مفتاح التخزين المؤقت الطريقة وكل وسيط يؤثر في النتيجة، بما في ذلك URI المورد وcursor القائمة المقسمة إلى صفحات. لا تخزن نتيجة تحتوي inputResponses أو requestState، لأن سياقها غير موجود في مفتاح قائمة بسيط. يتيح cacheScope: "public" مشاركة النتيجة بين سياقات التفويض، لذلك استخدمه فقط للبيانات الخالية من تفاصيل المستخدم أو الصلاحيات. تبقى صلاحيات كل أداة ضرورية حتى عند تخزين الكتالوج.
ينبغي للخادم إعادة الأدوات بترتيب حتمي. يحافظ الترتيب الثابت على استقرار prompts النموذج ويحسن إعادة استخدام التخزين بعد إعادة الاتصال. يمكن لإشعار listChanged أن يكمل TTL، لكنه لا يستبدل التلميح الصحيح.
OAuth والأمان
التفويض اختياري في MCP. يجب على خادم HTTP الذي يحمي الموارد اتباع ملف OAuth 2.1 في مواصفة 2026. يعمل الخادم كـresource server، وعليه نشر OAuth Protected Resource Metadata وفق RFC 9728. ينبغي لرد 401 الإشارة إليها عبر WWW-Authenticate وإضافة تحدي scopes مفيد. يجب على العميل دعم عنوان URL في الرأس وشكلي well-known.
قد تحدد البيانات الوصفية أكثر من authorization server. يجب أن يدعم العملاء OAuth Authorization Server Metadata وفق RFC 8414 وOpenID Connect Discovery. بالنسبة إلى issuer يحتوي على مسار، تُجرب أشكال إدخال المسار أولاً ثم شكل OpenID الذي يضيف المسار.
يفضل تسجيل العميل الآن Client ID Metadata Documents. ويظل التسجيل المسبق صالحاً. أما Dynamic Client Registration فأصبح مساراً احتياطياً مهجوراً. عند استخدام DCR، أرسل application_type الصحيح لعميل سطح المكتب أو CLI. تحقق من PKCE، واستخدم S256، وسجل redirect URI بدقة، واستعمل HTTPS باستثناء callback مسموح على localhost.
يجب على العميل حفظ issuer المتحقق منه مع معاملة PKCE. إذا احتوت استجابة التفويض على iss، فقارنه قبل استبدال الرمز. ترتبط بيانات الاعتماد بالـissuer الذي أصدرها، ولا يجوز إعادة استخدامها مع authorization server آخر. أرسل URI القانوني لخادم MCP باعتباره resource وفق RFC 8707 في طلبَي التفويض والرمز. يجب على الخادم التحقق من audience ورفض الرموز المخصصة لمورد آخر.
في Streamable HTTP تحقق من Origin لمنع DNS rebinding. ينبغي للخادم المحلي الاستماع على localhost فقط. لا تضع bearer tokens في query strings أو السجلات، واطلب موافقة صريحة قبل كشف الموارد الخاصة أو استدعاء الأدوات، وتعامل مع أوصاف الأدوات وannotations كبيانات غير موثوقة إن لم يكن الخادم موثوقاً. يعني 401 أن التفويض مفقود أو غير صالح. يعني 403 نقص الصلاحيات، وينبغي أن يحمل insufficient_scope متى أمكن.
ترحيل TypeScript SDK
يقسم TypeScript SDK v2 حزم العميل والخادم والنواة وruntime. راجع دليل SDK لدعم 2026-07-28 ودليل الترحيل من v1 إلى v2. لا يعني تحديث SDK وحده أن البايتات الحديثة ستُرسل على السلك. يتفاوض عميل v2 مع legacy افتراضياً، لذلك فعّل versionNegotiation صراحة.
بالنسبة إلى عميل يعمل مع العصرين، يوضح الدليل الشكل التالي:
import { Client } from '@modelcontextprotocol/client';
const client = new Client(
{ name: 'catalog-app', version: '1.0.0' },
{ versionNegotiation: { mode: 'auto' } },
);
await client.connect(transport);
يختبر mode: 'auto' server/discover ويعود إلى handshake 2025 فقط مع peer قديم فعلاً. ثبّت 2026-07-28 إذا كان fallback سيخفي عدم توافق. يبني createMcpHandler(factory) خادماً HTTP حديثاً جديداً لكل طلب ويمكنه خدمة العصرين. لاختيار العصر في stdio استخدم serveStdio(() => buildServer()).
استبدل تسجيل معالجات v1 المبني على المخططات بسلاسل الطرق مثل setRequestHandler('tools/call', handler). واستبدل قراءة ctx.sessionId بـhandles للتطبيق أو requestState متحقق منه. واستبدل elicitation الدفعية بـinputRequired(...). لا يرسل الطلب الحديث إشعار log من دون io.modelcontextprotocol/logLevel. استخدم codemod الخاص بالـSDK كمساعدة ميكانيكية، لا كاختبار توافق.
للتحقق، مرّر createMcpHandler عبر transport اختبار مبني على fetch واحتفظ بتغطية مستقلة لـlegacy handshake. افحص الرؤوس و_meta وidempotency لإعادة المحاولة ونطاق الكاش وaudience وحالة HTTP باستخدام عميل قديم وحديث.
قائمة الترحيل
- احصر العملاء والخوادم ووسائل النقل ومخازن الجلسات ومخازن أحداث SSE وأي قراءة لـ
Mcp-Session-Id. - حدد endpoint الذي يخدم الحركة الحديثة والمسار الذي سيبقى للـlegacy مؤقتاً.
- حدّث SDK وثبّت الإصدارات الفعلية في lockfile.
- أضف
server/discoverوسياسة تفاوض للإصدارات. - اجعل كل طلب مكتفياً بذاته وتحقق من
_metaوالرؤوس المنعكسة. - استبدل الحالة المرتبطة بالجلسة بـhandles صريحة أو
requestStateموقّع ومنتهي الصلاحية. - أعد كتابة تفاعل الخادم باستخدام MRTR واجعل إعادة المحاولة آمنة.
- أضف
ttlMsوcacheScopeوترتيباً حتمياً للكتالوجات والموارد. - حدّث البوابات وWAF والمقاييس والتتبّع لقراءة
Mcp-MethodوMcp-Name. - طبّق فحوص issuer وresource وaudience وPKCE وredirect وOrigin وscopes.
- لا تعتمد HTTP+SSE أو Roots أو Sampling أو Logging أو DCR في الكود الجديد.
- انشر تدريجياً مع المراقبة، وقارن أخطاء العصرين، ثم احذف طبقة التوافق بعد نقل المستهلكين.
استكشاف الأخطاء وإصلاحها
| العرض | السبب المحتمل | الإجراء |
|---|---|---|
HTTP 400 مع -32020 |
رأس مفقود أو مختلف عن الجسم | أعد حساب MCP-Protocol-Version وMcp-Method وMcp-Name من نفس الكائن |
| HTTP 400 وخطأ إصدار | الطرف الآخر لا يخدم المراجعة المطلوبة | اختر إصداراً من supported أو استخدم مسار legacy |
| HTTP 404 وmethod-not-found | نقطة النهاية حديثة لكن الطريقة غير موجودة | افحص الطريقة والإضافة، ولا تبدأ initialize عشوائياً |
| HTTP 401 أو 403 أثناء discovery | المصادقة منعت الاختبار | أصلح بيانات الاعتماد والبيانات الوصفية، فالخطأ لا يثبت legacy |
| لا توجد إشعارات log | غاب io.modelcontextprotocol/logLevel |
فعّله لكل طلب أو استخدم stderr وOpenTelemetry |
| آثار جانبية مكررة | لم يعد التدفق قابلاً للاستئناف | استخدم idempotency keys ومعرّف طلب جديد |
| ظهور بيانات مستخدم في cache آخر | وُسمت النتيجة public خطأً |
استخدم private وحافظ على فحص principal |
| عميل قديم يتلقى 405 على GET | يتوقع HTTP+SSE | أبق مسار legacy مؤقتاً |
للاطلاع على سياق البنية، راجع production AI agent architecture وMCP server with TypeScript and OAuth.
المصادر
يتبع هذا الدليل مواصفة MCP 2026-07-28، وسجل التغييرات والميزات المهجورة، ومتطلبات Streamable HTTP، وSEP-2575 عن MCP عديم الحالة، وإعلان الإصدار 2026-07-28، ومواصفة تفويض MCP، ووثائق ترحيل TypeScript SDK.