تتيح أحداث MCP لخادم MCP الخاص بك إرسال التحديثات إلى ChatGPT فور حدوثها، بحيث لا يحتاج أي وكيل إلى الاستعلام عنها. منذ يوم مطوري OpenAI في 29 سبتمبر 2026، يدعم ChatGPT مواصفات أحداث MCP المقترحة في الإصدار 2026-07-28 (MCP 2.0)، على جميع الخطط. يضيف خادمك ثلاث طرق (events/list، events/subscribe، events/unsubscribe)، ويعلن عن events في server/discover، ويمرر تحديًا للتحقق من الاتصال العكسي (callback verification challenge)، ويوقع كل تسليم باستخدام Standard Webhooks HMAC. يقبل ChatGPT تسليم الويب هوك (webhook delivery) فقط.
يغطي هذا الدليل كل شكل رسالة توثقها OpenAI، وقواعد الأمان التي يفرضها خادمك، واختبار الحلقة الكاملة. هل أنت جديد على البروتوكول؟ ابدأ بما هو بروتوكول MCP. ستقوم بإرسال مكالمات JSON-RPC ومحاكاة الاتصال العكسي (callback) في Apidog.
نظرة سريعة على أحداث MCP
| العنصر | ما يتوقعه ChatGPT |
|---|---|
| البروتوكول | MCP 2.0، الإصدار 2026-07-28 |
| القدرة | "events": {} في قدرات server/discover |
| الأساليب | events/list، events/subscribe، events/unsubscribe، على نفس نقطة النهاية الموثقة مثل أدواتك |
| التسليم | عبر الويب هوك فقط: لا استعلام، لا بث مباشر، لا إشعارات gap أو terminated |
| التوقيع | Standard Webhooks HMAC-SHA256 |
| الرؤوس (Headers) | webhook-id، webhook-timestamp، webhook-signature، X-MCP-Subscription-Id |
| السر (Secret) | whsec_ بالإضافة إلى base64 الذي يفك تشفيره إلى 24-64 بايت، مقدم من ChatGPT |
| حد الحمولة (Payload limit) | 256 كيلوبايت (262,144 بايت)، حدث واحد لكل طلب |
| معرف الاشتراك (Subscription ID) | حتمي: المبدأ، عنوان URL للاتصال العكسي، اسم الحدث، الوسائط |
| الاتصالات العكسية (Callbacks) | HTTPS، تم التحقق من التحدي، لا توجد عناوين خاصة، لا توجيهات |
المصادر: دليل OpenAI MCP Events ومسودة تصميم MCP Events.
لماذا الأحداث بدلاً من الاستقصاء (Polling)
بدون الأحداث، يقوم الوكيل الذي يراقب تعليقات المراجعة باستدعاء أداة بناءً على مؤقت ويقارن النتائج، مما يهدر الطلبات عندما لا يتغير شيء ويتأخر عندما يحدث شيء. تقوم أحداث MCP بعكس الاتجاه: خادمك يعرف متى يتغير سجل، لذلك يرسل التحديث. المقايضات هي مقايضات الويب هوكس مقابل الاستقصاء الكلاسيكية، الآن داخل MCP.
يستخدم ملخص يوم مطوري OpenAI لوحة مشروع: يطلب المستخدم من ChatGPT مراقبة المهام الجديدة، وعندما تظهر مهمة جديدة، يقرأ ChatGPT المستندات المرتبطة ويصيغ خطة. تضيف المستندات حالتين أخريين: تحويل تقارير الأخطاء في قناة إلى طلبات سحب (pull requests) أولية (message.created، تمت تصفيتها بواسطة channel_id)، وتطبيق تعليقات المراجعة على مستند (comment.created، تمت تصفيتها بواسطة document_id).
تأتي المواصفات من مجموعة عمل المشغلات والأحداث (Triggers and Events Working Group) التابعة لـ MCP (المستودع) وهي مصنفة على أنها تجريبية، لذا قم بتثبيت التعليمات البرمجية الخاصة بك على 2026-07-28. لمزيد من معلومات الإطلاق، راجع مركز DevDay 2026.
الإعلان عن الأحداث وتحديدها
أضف events إلى القدرات في استجابة server/discover الخاصة بك:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"resultType": "complete",
"supportedVersions": ["2026-07-28"],
"capabilities": { "tools": {}, "events": {} }
}
}
ثم أعد التعريفات من events/list. يحمل كل تعريف name، وdescription، وdelivery: ["webhook"]، وinputSchema لوسائط الاشتراك (عوامل التصفية الخاصة بك، مثل document_id)، وpayloadSchema لكائن data في كل تسليم. استخدم أسماء مستقرة وأوصافًا محددة، وطبق عوامل التصفية على خادمك، واعرض فقط الأحداث التي يمكن للحساب المتصل رؤيتها.
events/subscribe: الطلب والاستجابة
عندما يطلب المستخدم من ChatGPT مراقبة شيء ما، يستدعي ChatGPT events/subscribe:
{
"jsonrpc": "2.0",
"id": 2,
"method": "events/subscribe",
"params": {
"name": "comment.created",
"arguments": { "document_id": "doc_123" },
"delivery": {
"mode": "webhook",
"url": "https://receiver.example.com/mcp-events/callback_123",
"secret": "whsec_<base64-encoded-signing-key>"
},
"cursor": null
}
}
قبل القبول، قم بتفويض المستخدم لهذا الحدث وتلك الوسائط، وتحقق من صحة كليهما مقابل تعريفك، واطلب سر whsec_ الذي يفك تشفير base64 الخاص به إلى 24-64 بايت، وتحقق من الاتصال العكسي (القسم التالي)، وقم بتخزين الاشتراك مع مالكه، وعوامل التصفية، وعنوان URL، والسر، وتاريخ انتهاء الصلاحية. ثم أجب:
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"id": "sub_123",
"refreshBefore": "2026-10-02T12:00:00Z",
"cursor": null,
"truncated": false
}
}
ثلاث قواعد تحافظ على صحة الاشتراكات:
- معرفات حتمية. استخلص
idمن المبدأ المصادق عليه، وعنوان URL للاتصال العكسي، واسم الحدث، والوسائط. تشير مسودة التصميم إلى SHA-256 مقطوع لهذا المفتاح. - تحديثات (upserts) متطابقة. الاشتراك المتكرر بنفس الهوية يقوم بتحديث السجل الحالي. قارن الوسائط كـ JSON قياسي بحيث لا يمكن لترتيب المفاتيح إنشاء تكرارات.
- التحديث قبل
refreshBefore. يعيد ChatGPT استدعاءevents/subscribeقبل هذا الوقت بنفس الهوية ومؤشره المحفوظ الأخير؛ وتعيد أنت تاريخ انتهاء صلاحية جديدًا. إذا حمل التحديث سرًا جديدًا، فاستبدله ووقع بكلتا المفتاحين لفترة قصيرة. أعدcursor: nullللأحداث التي لا يمكنك إعادة تشغيلها.
التحقق من الاتصال العكسي قبل أي بيانات
قبل إرسال بيانات التطبيق، قم بنشر (POST) نص تحقق موقع بجهاز تحدي (challenge) جديد، أحادي الاستخدام، وقصير الأجل:
{ "type": "verification", "challenge": "a-single-use-random-value" }
امنحه webhook-id فريدًا (على سبيل المثال msg_verification_123) ونفس رؤوس التوقيع كالتسليم. يعيد ChatGPT {"challenge": "a-single-use-random-value"} برمز 2xx. قارن في وقت ثابت، ثم قم بتنشيط التسليم. عند الفشل، أعد خطأ JSON-RPC -32015 (CallbackEndpointError) مع data.reason مثل challenge_failed أو timeout. قم بتخزين تمريرة لكل مبدأ وعنوان URL لفترة محددة حتى لا تتكرر التحديات عند التحديثات.
يوجد التحدي لأن المشترك يوفر السر: بدونه، يمكن لأي شخص توجيه خادمك إلى عنوان URL للضحية وإغراقه. طبق نفس التصلب على كل طلب صادر: HTTPS فقط، قم بحل والتحقق من العنوان في وقت الاتصال، وحظر العناوين الخاصة والمحلية وغيرها غير العامة، ولا تتبع عمليات إعادة التوجيه مطلقًا.
تسليم وتوقيع الأحداث
عند وقوع حدث مطابق، قم بنشر (POST) كائن حدث واحد إلى عنوان URL للاتصال العكسي:
{
"eventId": "evt_456",
"name": "comment.created",
"timestamp": "2026-10-01T12:05:00Z",
"data": {
"document_id": "doc_123",
"comment_id": "comment_456",
"text": "Can we add the rollout dates to this section?",
"url": "https://docs.example.com/doc_123#comment_456"
},
"cursor": null
}
أرسل Content-Type: application/json، webhook-id (يساوي eventId)، webhook-timestamp (ثواني يونكس عند التوقيع)، webhook-signature، وX-MCP-Subscription-Id. قم بتسلسل النص مرة واحدة وأرسل هذه البايتات بالضبط، حيث يغطي التوقيعها.
ابق أقل من 256 كيلوبايت؛ للسجلات الكبيرة، أرسل ملخصًا واعرض أداة قراءة. تعامل مع النص الذي أنشأه المستخدم كبيانات ولا تضع أبدًا تعليمات النموذج في حمولة. أعد محاولة الفشل العابر مع التراجع الأسي المحدود، مع الحفاظ على معرف الحدث وتوقيع كل محاولة جديدة. لا تعيد المحاولة لـ 410 أو 413. يمكن أن تصل الأحداث خارج الترتيب، لذا اجعل أدوات الكتابة متطابقة. يغطي دليل تصميم الويب هوكس الموثوق به جداول إعادة المحاولة.
التحقق من توقيع الويب هوكس القياسي
وفقًا لمواصفات Standard Webhooks، المحتوى الموقع هو ${webhook-id}.${webhook-timestamp}.${body}، ومفتاح HMAC-SHA256 هو السر مفكوك تشفيره بـ base64 بعد إزالة whsec_، ويحتوي الرأس على توقيع واحد أو أكثر مفصول بمسافات v1,<base64>. تخبر مسودة MCP المستلمين برفض الطوابع الزمنية الأقدم من 5 دقائق وإزالة التكرارات بناءً على webhook-id.
يتحقق ChatGPT من جانبه، ولكن جهاز استقبال صارم خاص بك يعد Oracle اختبار محلي جيدًا. يستخدم هذا المستند فقط المكونات المدمجة في Node:
// receiver.mjs: جهاز استقبال ويب هوكس قياسي صارم للاختبارات المحلية (Node 18+)
import { createServer } from "node:http";
import { createHmac, timingSafeEqual } from "node:crypto";
const SECRET = process.env.WEBHOOK_SECRET; // whsec_...
const MAX_BYTES = 256 * 1024;
const TOLERANCE_S = 5 * 60;
const seen = new Set();
export function verify(raw, h, secret, now = Math.floor(Date.now() / 1000)) {
const id = h["webhook-id"], ts = h["webhook-timestamp"], sigs = h["webhook-signature"];
if (!id || !ts || !sigs) return false;
const t = Number(ts);
if (!Number.isInteger(t) || Math.abs(now - t) > TOLERANCE_S) return false;
const key = Buffer.from(secret.replace(/^whsec_/, ""), "base64");
const expected = createHmac("sha256", key).update(`${id}.${ts}.`).update(raw).digest();
return sigs.split(" ").some((s) => {
const [version, b64] = s.split(",");
const got = Buffer.from(b64 ?? "", "base64");
return version === "v1" && got.length === expected.length && timingSafeEqual(got, expected);
});
}
if (SECRET) createServer((req, res) => {
const chunks = [];
let size = 0;
req.on("data", (c) => { size += c.length; if (size <= MAX_BYTES) chunks.push(c); });
req.on("end", () => {
if (size > MAX_BYTES) return res.writeHead(413).end();
const raw = Buffer.concat(chunks);
if (!verify(raw, req.headers, SECRET)) return res.writeHead(401).end();
let body;
try { body = JSON.parse(raw); } catch { return res.writeHead(400).end(); }
if (body.type === "verification") {
res.writeHead(200, { "Content-Type": "application/json" });
return res.end(JSON.stringify({ challenge: body.challenge }));
}
const id = req.headers["webhook-id"];
if (!seen.has(id)) { seen.add(id); console.log(req.headers["x-mcp-subscription-id"], body.name, id); }
res.writeHead(200).end();
});
}).listen(8787);
قم بتشغيله باستخدام WEBHOOK_SECRET=whsec_... node receiver.mjs. يعيد 413 لأكثر من 256 كيلوبايت و 401 للتوقيع السيئ أو القديم، ويردد التحديات، ويسجل كل webhook-id مرة واحدة. لقد تحققنا من verify() مقابل متجه اختبار التوقيع في مكتبة JavaScript الخاصة بـ Standard Webhooks. للنظرية، اقرأ التحقق من توقيع الويب هوك.
يحظر خادمك العناوين الخاصة، لذلك لن يتم التسليم إلى localhost افتراضيًا. تسمح المسودة بالأهداف غير العامة فقط عند التكوين صراحة: أضف إدخال قائمة سماح خاص بالمطورين فقط، أو اكشف جهاز الاستقبال من خلال نفق.
اختبره قبل أن يفعل ChatGPT
فيما يلي اختبار Apidog لأوضاع الفشل التي تسردها OpenAI. قم بإنشاء بيئة باستخدام MCP_URL، MCP_TOKEN، CALLBACK_URL وWEBHOOK_SECRET، وأرسل كل مكالمة JSON-RPC كـ POST إلى {{MCP_URL}} مع Authorization: Bearer {{MCP_TOKEN}} بالإضافة إلى الرؤوس التي يتطلبها ربط Streamable HTTP: Accept: application/json, text/event-stream، MCP-Protocol-Version: 2026-07-28، وMcp-Method مضبوطًا على الطريقة. يحتاج كل نص أيضًا إلى params._meta مع io.modelcontextprotocol/protocolVersion وio.modelcontextprotocol/clientCapabilities. عينات OpenAI تهمل ذلك، ويؤدي _meta المفقود أيضًا إلى إرجاع -32602، لذلك ستنجح الخطوة 3 لسبب خاطئ.
- الاكتشاف (Discovery). أرسل
server/discoverوتأكد من وجود$.result.capabilities.eventsوأن$.result.supportedVersionsيحتوي على2026-07-28. أرسلevents/listوتأكد من أنdeliveryلكل حدث يتضمنwebhook. - اشتراك متطابق (Idempotent subscribe). أرسل نص الاشتراك أعلاه باستخدام
{{CALLBACK_URL}}و{{WEBHOOK_SECRET}}، مع معالج لاحق لاستخراج المتغير يحفظ$.result.idكـSUB_ID. أعد إرساله دون تغيير، ثم مع إعادة ترتيب مفاتيحarguments، وتأكد من أن$.result.idيساوي{{SUB_ID}}في كلتا المرتين. - التحقق من الصحة (Validation). أرسل سرًا يفك تشفيره إلى أقل من 24 بايت، ثم اتصالاً عكسيًا
http://. تحدد المسودة كلاهما إلى-32602(InvalidParams)؛ تأكد من$.error.code. يجب أن يفشل الاتصال العكسي لعنوان IP خاص أيضًا. - تحدي التحقق (Verification challenge). أنشئ نقطة نهاية Mock في Apidog تجيب بـ
{"challenge": "wrong"}واشترك باستخدام عنوان URL الخاص بـ Mock السحابي الخاص بها كاتصال عكسي. تأكد من أن$.error.codeهو-32015وأن$.error.data.reasonهوchallenge_failed. ثم وجهCALLBACK_URLإلى جهاز الاستقبال الخاص بك وتأكد من نجاح الاشتراك. - حمولة زائدة عن الحد (Oversize payload). قم بتشغيل حدث يتجاوز حجم نصه 262,144 بايت. يجب أن يرفضه المرسل الخاص بك؛ إذا تجاوز أحدها، يجيب جهاز الاستقبال بـ
413، ويجب أن تظهر سجلات خادمك محاولة واحدة، وليس إعادة محاولة. - إعادة التشغيل والعبث (Replay and tampering). انسخ رؤوس ونص تسليم موقع من سجل خادمك الصادر إلى طلب Apidog جديد. أعد إرساله فورًا:
200، ولا يوجد سطر سجل ثانٍ. قم بتغيير بايت واحد من النص:401. أعد الإرسال بعد 5 دقائق:401.
احفظ الخطوات كسيناريو وقم بتشغيله في CI باستخدام واجهة سطر أوامر Apidog. يغطي دليل اختبار خادم MCP استدعاءات الأدوات، ويقدم كيفية اختبار الويب هوكس تفاصيل أعمق حول أجهزة الاستقبال. ثم قم بتوصيل الخادم بـ ChatGPT عبر مكون إضافي وقم بتشغيل قائمة التحقق من دورة حياة OpenAI.
الأسئلة الشائعة
ما هي أحداث MCP؟ امتداد تجريبي لـ MCP يسمح للخادم بدفع إشعارات الأحداث إلى العميل بدلاً من أن يقوم العميل بالاستقصاء. يدعم ChatGPT وضع الويب هوك الخاص به في 2026-07-28.
هل يدعم ChatGPT الاستقصاء أو البث المباشر لأحداث MCP؟ لا. يدعم ChatGPT تسليم الويب هوك والتحقق من الاتصال العكسي فقط. الاستقصاء، والبث المباشر، وإشعارات gap وterminated غير مدعومة.
ما هي خطط ChatGPT التي تحصل على أحداث MCP؟ يقول ملخص يوم مطوري OpenAI أن الميزة متاحة لجميع الخطط.
من ينشئ سر التوقيع؟ المشترك. يرسل ChatGPT سر whsec_ في delivery.secret؛ يقوم خادمك بالتحقق والتخزين والتوقيع باستخدامه، ولا ينشئ سرًا خاصًا به أبدًا.
ما الفرق بين هذا وواجهة برمجة تطبيقات الوكلاء (Agents API)؟ تدفع أحداث MCP البيانات من خادمك إلى ChatGPT. تقوم واجهة برمجة تطبيقات وكلاء OpenAI بتشغيل وكلاء تقوم ببنائهم وتقرير تقدمهم عن طريق البث المباشر أو الويب هوكس.
الخطوة التالية
أضف "events": {} إلى خادم واحد، واكشف حدثًا واحدًا بفلتر واحد، وقم بتشغيل الفحوصات الستة مقابل جهاز استقبال محلي قبل توصيل ChatGPT. قم بتنزيل Apidog للاحتفاظ بهذه الفحوصات كسيناريو يتم تشغيله مع كل التزام.
