Skip to content

Build2 publishers2 min readPublished

ChatGPT's MCP Events require servers to store subscriptions and sign every webhook

ChatGPT has accepted MCP Events in all plans since OpenAI's DevDay on 29 September 2026, delivered only by HMAC-signed webhook. Swapping a polling tool for events means running subscription storage and callback checks against an experimental spec.

The Engineer · Build desk

Illustration accompanying ChatGPT's MCP Events require servers to store subscriptions and sign every webhook

What happened

  • Servers advertise an events capability in server/discover and implement events/list, events/subscribe and events/unsubscribe.
  • OpenAI requires servers to provide persistent subscription storage and outbound HTTPS access to the callback URLs ChatGPT supplies.
  • ChatGPT's integration leaves out the draft spec's gap and terminated control notifications.
  • OpenAI's documented cases include turning channel bug reports into draft pull requests via message.created, filtered by channel_id.
  • The spec comes from the MCP Triggers and Events Working Group and is experimental, so the dev.to guide advises pinning to 2026-07-28.

Compiled by The EngineerSomething wrong?How this is made

Why it matters

  • cost A server that answered tool calls statelessly now has to keep subscription records through restarts and refresh them on schedule, so event support costs a database and an outbound HTTPS sender.
  • exposure Filtering and access control run on the server, so a subscribe handler that skips the authorization check would deliver one account's events into another user's chat.
  • decision Pinning to one experimental protocol version leaves teams deciding whether to keep their polling tools for clients that do not speak 2026-07-28.

When a user asks ChatGPT to watch a document or a channel, ChatGPT calls events/subscribe with the event name, the filter arguments and a webhook destination made of a callback URL and a signing secret [9]. OpenAI's documentation lists what the server does before it accepts [10]:

1. Check that the user is authorized for that event and those arguments. 2. Validate the name and arguments against the event definition, and require a secret prefixed `whsec_` whose base64 value decodes to 24 to 64 bytes. 3. Validate the callback URL, then verify it with a signed request carrying a fresh, single-use, short-lived challenge [11]. 4. Store the subscription with its owner, filters, callback URL, secret and expiration.

That byte range gives an HMAC key of 192 to 512 bits [1]. The `whsec_` prefix also makes the secret easy to find in a log file, for better and for worse. Deliveries are signed under the Standard Webhooks scheme, according to the dev.to guide [3].

The subscription ID has the strictest rules. OpenAI asks for an ID derived deterministically from the authenticated principal, the callback URL, the event name and the arguments [12]. The draft design sketch proposes a truncated SHA-256 hash of that key, the dev.to guide says [13].

The refresh loop is why. According to the guide, ChatGPT calls events/subscribe again before `refreshBefore`, with the same identity and the last stored cursor, and expects a new expiry in the reply [14]. A matching identity has to update the existing subscription [15]. OpenAI also requires arguments to be compared as canonical JSON, so a change in key order does not create a duplicate [15]. The guide adds that when a refresh carries a new secret, the server replaces the stored one [16]. Event types that cannot replay return a null cursor [19].

I think the draft gets the hard parts right. Subscribe is idempotent, grants expire, and no application data leaves the server until the callback has answered a challenge [15] [14] [11].

The dev.to guide makes the case against polling this way: an agent calling a tool on a timer sends requests when nothing has changed and can see updates late [17]. With events, the server detects the change and pushes it to ChatGPT straight away [18]. The documentation does not describe how the server learns of a change. If the system behind the MCP server can only be polled, I think the polling moves from the agent into the server. The saving then depends on whether one server-side check covers many subscriptions.

What to watch

  • A new MCP Events draft from the Triggers and Events Working Group would force servers pinned to 2026-07-28 to migrate.
  • ChatGPT adding the draft's gap and terminated notifications, or polling and streaming delivery, would change what a server has to build.
Loading claim ledger
Loading source directory links
Loading share composer
Loading topic controls
Loading related stories