MCP Etkinlikleri, MCP sunucunuzda bir değişiklik gerçekleştiği anda ChatGPT'ye güncelleme göndermenizi sağlar; araçların periyodik yoklama yapmasına gerek kalmaz. OpenAI DevDay'den bu yana, 29 Eylül 2026 itibarıyla ChatGPT tüm planlarda, 2026-07-28 protokol sürümündeki (MCP 2.0) önerilen MCP Etkinlikleri spesifikasyonunu destekler. Sunucunuzun üç yöntem (events/list, events/subscribe, events/unsubscribe) eklemesi, server/discover içinde events yeteneğini duyurması, geri arama doğrulamasını geçmesi ve tüm teslimatları Standart Webhook'lar HMAC ile imzalaması gerekir. ChatGPT yalnızca webhook teslimatını kabul eder. Bu kılavuzda mesaj biçimlerini, sunucunuzda uygulamanız gereken güvenlik kontrollerini ve uçtan uca test akışını ele alacağız. MCP'ye yeniyseniz, önce MCP'nin ne olduğunu öğrenin. JSON-RPC çağrılarını göndermek ve geri aramayı taklit etmek için Apidog kullanabilirsiniz.
MCP Etkinlikleri bir bakışta
| Öğe | ChatGPT'nin bekledikleri |
|---|---|
| Protokol | MCP 2.0, sürüm 2026-07-28
|
| Yetenek |
server/discover yeteneklerinde "events": {}
|
| Yöntemler |
events/list, events/subscribe, events/unsubscribe; araçlarınızla aynı, kimliği doğrulanmış uç noktada |
| Teslimat | Yalnızca webhook: yoklama, akış, gap veya terminated bildirimi yok |
| İmzalama | Standart Webhook'lar HMAC-SHA256 |
| Başlıklar |
webhook-id, webhook-timestamp, webhook-signature, X-MCP-Subscription-Id
|
| Gizli anahtar | ChatGPT tarafından sağlanan, whsec_ önekli ve base64 çözüldüğünde 24–64 bayt olan anahtar |
| Yük limiti | 256 KiB (262.144 bayt), istek başına bir etkinlik |
| Abonelik kimliği | Asıl, geri arama URL'si, etkinlik adı ve argümanlardan türetilmiş deterministik kimlik |
| Geri aramalar | HTTPS, challenge ile doğrulanmış, özel adreslere ve yönlendirmelere kapalı |
Kaynaklar: OpenAI'ın MCP Etkinlikleri kılavuzu ve MCP Etkinlikleri tasarım taslağı.
Neden yoklama yerine etkinlikler?
Yoklama kullanan bir araç, örneğin inceleme yorumlarını kontrol etmek için belirli aralıklarla API çağrısı yapar ve önceki sonuçla yeni sonucu karşılaştırır. Değişiklik yoksa gereksiz istek üretir; değişiklik varsa da bir sonraki yoklama turuna kadar gecikme yaşanır.
MCP Etkinlikleri bu akışı tersine çevirir: Değişikliği bilen sunucu, eşleşen olay gerçekleştiğinde güncellemeyi doğrudan gönderir. Bu yaklaşımın artıları ve eksileri, klasik webhook ve yoklama karşılaştırmasıyla aynıdır.
OpenAI'ın DevDay özetindeki örnekte kullanıcı, ChatGPT'den yeni proje görevlerini izlemesini ister. Yeni görev oluştuğunda ChatGPT bağlantılı belgeleri okuyabilir ve plan taslağı hazırlayabilir. Belgelerdeki diğer örnekler:
- Bir kanaldaki hata raporlarını taslak çekme isteğine dönüştürmek:
message.created,channel_idfiltresiyle. - Bir belgeye inceleme yorumları uygulamak:
comment.created,document_idfiltresiyle.
Spesifikasyon, MCP Tetikleyiciler ve Etkinlikler Çalışma Grubu tarafından hazırlanmıştır ve hâlâ deneysel olarak etiketlenir. Bu nedenle uygulamanızı 2026-07-28 sürümüne sabitleyin. DevDay lansmanının geri kalanı için DevDay 2026 merkezine bakın.
Etkinlikleri duyurun ve tanımlayın
Önce server/discover yanıtındaki yeteneklere events ekleyin:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"resultType": "complete",
"supportedVersions": ["2026-07-28"],
"capabilities": { "tools": {}, "events": {} }
}
}
Ardından events/list yanıtında kullanılabilir etkinlikleri döndürün. Her etkinlik tanımı şunları içermelidir:
namedescriptiondelivery: ["webhook"]- Abonelik filtreleri için
inputSchema - Her teslimattaki
datanesnesi içinpayloadSchema
Örneğin document_id gibi filtreleri inputSchema içinde tanımlayın. Etkinlik adlarını kararlı, açıklamalarını ise belirli tutun. Filtrelemeyi istemcide değil sunucuda uygulayın ve yalnızca bağlı hesabın görme yetkisi olan olayları listeleyin.
events/subscribe: istek ve yanıt
Kullanıcı ChatGPT'den bir kaynağı izlemesini istediğinde ChatGPT aşağıdaki gibi bir events/subscribe çağrısı yapar:
{
"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
}
}
Aboneliği kabul etmeden önce şu kontrolleri uygulayın:
- Kullanıcının istenen etkinlik ve argümanlar için yetkisini doğrulayın.
- Etkinlik adını ve argümanları etkinlik tanımınızdaki şemaya göre doğrulayın.
-
whsec_önekli gizli anahtarın base64 çözüldüğünde 24–64 bayt olduğunu kontrol edin. - Geri arama URL'sini doğrulayın.
- Aboneliği sahip, filtreler, URL, gizli anahtar ve son kullanma bilgisiyle saklayın.
Başarılı bir abonelik için aşağıdaki biçimde yanıt verin:
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"id": "sub_123",
"refreshBefore": "2026-10-02T12:00:00Z",
"cursor": null,
"truncated": false
}
}
Abonelik yaşam döngüsünde üç temel kural vardır:
-
Deterministik kimlikler:
iddeğerini kimliği doğrulanmış asıl, geri arama URL'si, etkinlik adı ve argümanlardan türetin. Tasarım taslağı, bu anahtarın kırpılmış SHA-256 özetini önerir. - İdempotent upsert işlemleri: Aynı kimlikle gelen tekrar abonelik isteği mevcut kaydı güncellemelidir. Yinelenmeleri önlemek için argümanları kanonik JSON biçiminde karşılaştırın.
-
refreshBeforeöncesinde yenileme: ChatGPT, bu zamandan önce aynı kimlik ve son kaydedilen imleçleevents/subscribeçağrısını yeniler. Yeni son kullanma zamanını döndürün. Yenilemede yeni gizli anahtar geldiyse anahtarı değiştirin ve kısa bir geçiş süresinde her iki anahtarla imzalayın. Olayları yeniden oynatamıyorsanızcursor: nulldöndürün.
Herhangi bir veriden önce geri aramayı doğrulayın
Uygulama verisi göndermeden önce yeni, tek kullanımlık ve kısa ömürlü bir challenge içeren imzalı POST isteği gönderin:
{ "type": "verification", "challenge": "a-single-use-random-value" }
Bu istekte benzersiz bir webhook-id kullanın; örneğin msg_verification_123. Normal etkinlik teslimatlarıyla aynı imzalama başlıklarını ekleyin.
ChatGPT aşağıdaki gövdeyi 2xx durum koduyla döndürmelidir:
{ "challenge": "a-single-use-random-value" }
Challenge değerini sabit zamanda karşılaştırın ve yalnızca eşleşirse teslimatı etkinleştirin. Doğrulama başarısız olursa -32015 kodlu CallbackEndpointError döndürün:
{
"code": -32015,
"message": "CallbackEndpointError",
"data": {
"reason": "challenge_failed"
}
}
timeout gibi uygun hata nedenlerini de data.reason içinde belirtin.
Doğrulama sonucunu asıl ve URL başına sınırlı süreyle önbelleğe alın. Böylece yenileme işlemlerinde tekrar challenge göndermeniz gerekmez.
Bu doğrulama adımı önemlidir: Abone gizli anahtarı sağladığı için, saldırganların sunucunuzu rastgele bir kurban URL'sine yönlendirip istek yağmuruna tutması engellenir.
Tüm giden webhook isteklerinde aşağıdaki SSRF korumalarını uygulayın:
- Yalnızca HTTPS URL'lerine izin verin.
- Hedef adresi bağlantı zamanında çözümleyip doğrulayın.
- Özel, yerel ve diğer genel olmayan IP aralıklarını engelleyin.
- HTTP yönlendirmelerini asla takip etmeyin.
Etkinlikleri teslim edin ve imzalayın
Eşleşen olay oluştuğunda geri arama URL'sine olay nesnesi olarak POST isteği gönderin:
{
"eventId": "evt_456",
"name": "comment.created",
"timestamp": "2026-10-01T12:05:00Z",
"data": {
"document_id": "doc_123",
"comment_id": "comment_456",
"text": "Bu bölüme dağıtım tarihlerini ekleyebilir miyiz?",
"url": "https://docs.example.com/doc_123#comment_456"
},
"cursor": null
}
İstekle birlikte şu başlıkları gönderin:
Content-Type: application/json
webhook-id: evt_456
webhook-timestamp: <unix-saniye>
webhook-signature: v1,<signature>
X-MCP-Subscription-Id: sub_123
Dikkat edilmesi gereken uygulama ayrıntıları:
- Gövdeyi yalnızca bir kez serileştirin; imza bu tam baytları kapsadığı için gönderilen baytlar imzalanan baytlarla aynı olmalıdır.
- Yükü 256 KiB altında tutun.
- Büyük kayıtlar için tam içeriği göndermek yerine özet gönderin ve ayrıntılar için bir okuma aracı sunun.
- Kullanıcı tarafından yazılmış metni yalnızca veri olarak işleyin; yük içine model talimatları yerleştirmeyin.
- Geçici hatalarda kademeli üstel geri çekilme kullanın.
- Yeniden denemelerde aynı olay kimliğini koruyun, ancak her denemeyi yeniden imzalayın.
-
410ve413yanıtlarında yeniden deneme yapmayın. - Olaylar sırasız ulaşabileceği için yazma araçlarınızı idempotent tasarlayın.
Yeniden deneme stratejileri için güvenilir webhook tasarım kılavuzuna bakın.
Standart Webhook imzasını doğrulayın
Standart Webhook'lar spesifikasyonuna göre imzalanan içerik şu biçimdedir:
${webhook-id}.${webhook-timestamp}.${body}
HMAC-SHA256 anahtarı, whsec_ öneki kaldırıldıktan sonra base64 ile çözülen gizli anahtardır. webhook-signature başlığı, boşlukla ayrılmış bir veya daha fazla v1, imzası içerebilir.
MCP taslağı, alıcıların aşağıdaki kontrolleri yapmasını önerir:
- 5 dakikadan eski zaman damgalarını reddetmek.
-
webhook-iddeğerine göre yinelenen teslimatları kaldırmak.
ChatGPT imzayı kendi tarafında doğrular. Ancak yerel bir alıcı yazmak, entegrasyon testi için iyi bir oracle sağlar. Aşağıdaki örnek yalnızca Node.js yerleşik modüllerini kullanır:
// receiver.mjs: yerel testler için sıkı Standart Webhook alıcısı (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);
}
Alıcıyı çalıştırın:
WEBHOOK_SECRET=whsec_... node receiver.mjs
Bu alıcı:
- 256 KiB üzerindeki isteklerde
413döndürür. - Geçersiz veya eski imzalarda
401döndürür. - Doğrulama challenge'ını yankılar.
- Her
webhook-iddeğerini yalnızca bir kez günlüğe yazar.
verify() işlevini Standart Webhook JavaScript kütüphanesinin imzalama test vektörleriyle doğrulayın. Daha fazla ayrıntı için webhook imza doğrulaması kılavuzunu inceleyin.
Sunucunuz özel adresleri engellediği için varsayılan olarak localhost hedeflerine teslimat yapmamalıdır. Taslak, genel olmayan hedeflere yalnızca açıkça yapılandırıldığında izin verir. Geliştirme için bir izin listesi kullanın veya alıcıyı güvenli bir tünel aracılığıyla dışarı açın.
ChatGPT'ye bağlamadan önce test edin
OpenAI'ın belirttiği hata modlarını doğrulamak için bir Apidog test akışı oluşturun.
Önce şu ortam değişkenlerini tanımlayın:
MCP_URL
MCP_TOKEN
CALLBACK_URL
WEBHOOK_SECRET
Her JSON-RPC çağrısını {{MCP_URL}} adresine POST olarak gönderin. Yetkilendirme başlığı:
Authorization: Bearer {{MCP_TOKEN}}
Akışlanabilir HTTP bağlamasının gerektirdiği başlıkları ekleyin:
Accept: application/json, text/event-stream
MCP-Protocol-Version: 2026-07-28
Mcp-Method: <çağrılan-yöntem>
Her gövdenin params._meta alanında ayrıca aşağıdaki değerler bulunmalıdır:
io.modelcontextprotocol/protocolVersionio.modelcontextprotocol/clientCapabilities
Bu alanların tanımı için MCP params._meta spesifikasyonuna bakın. OpenAI örnekleri bunu atlayabilir; ancak eksik _meta, -32602 hatası döndürebilir ve testinizin yanlış nedenle geçmesine yol açabilir.
Keşif
server/discovergönderin.$.result.capabilities.eventsalanının bulunduğunu ve$.result.supportedVersionslistesinin2026-07-28içerdiğini doğrulayın. Ardındanevents/listgönderin ve her olayındeliveryalanındawebhookbulunduğunu kontrol edin.İdempotent abonelik
Yukarıdaki abonelik gövdesini{{CALLBACK_URL}}ve{{WEBHOOK_SECRET}}ile gönderin.$.result.iddeğeriniSUB_IDolarak kaydetmek için bir değişken çıkarma son işlemcisi ekleyin. İsteği değiştirmeden yeniden gönderin. Sonraargumentsanahtarlarının sırasını değiştirerek tekrar gönderin. Her iki durumda da$.result.iddeğerinin{{SUB_ID}}ile aynı olduğunu doğrulayın.Geri arama girdisi doğrulaması
Base64 çözüldüğünde 24 bayttan kısa bir gizli anahtar gönderin. Ardındanhttp://ile başlayan bir geri arama URL'si deneyin. Taslak, iki durumu da-32602(InvalidParams) ile eşler.$.error.codealanını doğrulayın. Özel IP adresine işaret eden geri arama URL'si de başarısız olmalıdır.Challenge doğrulaması
{"challenge": "wrong"}yanıtını dönen bir Apidog sahte uç noktası oluşturun. Bu bulut sahte URL'sini geri arama olarak kullanarak abone olun.$.error.codedeğerinin-32015,$.error.data.reasondeğerinin isechallenge_failedolduğunu doğrulayın. ArdındanCALLBACK_URLdeğerini yerel alıcınıza yönlendirin ve aboneliğin başarıyla tamamlandığını kontrol edin.Büyük yük
Gövdesi 262.144 baytı aşan bir olay tetikleyin. Göndericiniz bu olayı reddetmelidir. Eğer istek alıcıya ulaşırsa alıcı413döndürmeli; sunucu günlüklerinde tek deneme görünmeli ve yeniden deneme yapılmamalıdır.Yeniden oynatma ve kurcalama
İmzalı teslimatın başlıklarını ve gövdesini sunucunuzun giden günlüklerinden yeni bir Apidog isteğine kopyalayın. İsteği hemen yeniden gönderin:200dönmeli, ancak ikinci günlük satırı oluşmamalıdır. Gövdedeki bir baytı değiştirin:401dönmelidir. Aynı isteği 5 dakika sonra tekrar gönderin: yine401dönmelidir.
Bu adımları bir senaryo olarak kaydedin ve Apidog CLI ile CI ortamında çalıştırın. Araç çağrıları için MCP sunucu test playbook'unu, alıcı testleri için ise webhook'ları nasıl test edeceğiniz rehberini kullanın. Ardından sunucunuzu bir eklenti aracılığıyla ChatGPT'ye bağlayın ve OpenAI'ın yaşam döngüsü kontrol listesini uygulayın.
SSS
MCP Etkinlikleri nelerdir?
Bir sunucunun, istemcinin yoklama yapması yerine olay bildirimlerini istemciye göndermesini sağlayan deneysel bir MCP uzantısıdır. ChatGPT, 2026-07-28 sürümünde webhook modunu destekler.
ChatGPT, MCP Etkinlikleri için yoklamayı veya akışı destekliyor mu?
Hayır. ChatGPT yalnızca webhook teslimatını ve geri arama doğrulamasını destekler. Yoklama, akış, gap ve terminated bildirimleri desteklenmez.
Hangi ChatGPT planları MCP Etkinliklerini kullanabilir?
OpenAI'ın DevDay özeti, özelliğin tüm planlarda kullanılabildiğini belirtir.
İmzalama gizli anahtarını kim oluşturur?
Abone. ChatGPT, delivery.secret içinde whsec_ önekli gizli anahtarı gönderir. Sunucunuz bu değeri doğrular, saklar ve webhook'ları bununla imzalar; anahtarı kendisi üretmez.
Bu yaklaşım Agents API'den nasıl farklıdır?
MCP Etkinlikleri, sunucunuzdan ChatGPT'ye veri gönderir. OpenAI Agents API ise oluşturduğunuz ajanları çalıştırır ve ilerlemelerini akış veya webhook aracılığıyla bildirir.
Sonraki adım
Sunucunuza "events": {} ekleyin, filtrelenmiş tek bir etkinlik tanımlayın ve ChatGPT'ye bağlanmadan önce yerel alıcınıza karşı altı kontrolü çalıştırın. Bu kontrolleri her taahhütte çalışan bir senaryo olarak saklamak için Apidog'u indirin.
Top comments (0)