# What Are MCP Events and How Do They Work?

AI agents have become good at doing things. Connect one to an MCP server and it can open a pull request, update a ticket or post in Slack. What agents have been bad at is noticing things. Unless a person asks, or the agent checks on a timer, nothing tells it that a build just failed or a customer just replied.

MCP Events is a proposed extension to the Model Context Protocol that closes this gap. It lets an MCP server notify an agent the moment something happens in a connected app, so the agent can react without anyone prompting it.

In this guide, we'll cover what MCP Events are, what they're used for, how they work, where the specification stands today (including OpenAI's early support in ChatGPT), and how MCP Events compare to webhooks, the technology they're built on.

## What are MCP Events?

MCP Events are notifications that an MCP server sends to an MCP client when something happens in an upstream system. The server publishes a list of event types it can emit, such as `message.created` or `incident.created`. The client subscribes to the ones it cares about, and the server notifies it each time a matching event occurs.

If tools are how an agent acts on the world, events are how the world gets an agent's attention. A new Slack message, a GitHub push or a PagerDuty incident can now start an agent's work directly, with no user in the loop.

Each event is a small JSON object with four parts: a unique `eventId`, the event `name`, a `timestamp`, and a `data` payload that follows a schema the server published in advance. The agent reads the event, decides what to do, and usually calls the same server's tools to fetch more detail or take action.

You may also see MCP Events called MCP triggers. The group defining them is the MCP Triggers & Events Working Group, and some platforms label their implementation "Triggers".

## Why MCP needed events

Until now, MCP has been request-based. The client calls a tool, the server answers. To learn that something changed, a client had two options, both described in the [working group's charter](https://modelcontextprotocol.io/community/working-groups/triggers-events):

* Poll: call a tool on a schedule and check whether anything is new. Most checks find nothing, and every check costs a request, and often model tokens too.
* Hold a connection open: keep a Server-Sent Events (SSE) stream alive and wait. That works for a local server, but not for a remote server running on serverless infrastructure, or for an agent that isn't running when the event happens.

Neither suits an agent that should wake up only when there's something to do. MCP Events adds a standard way for the server to do the waiting and push the event when it happens. If you've worked with APIs and webhooks, this is the same pull-versus-push shift, applied to agents.

## Common MCP Events use cases

Any MCP server that wraps a system where things happen can expose events. Here are the patterns that come up most often in the draft specification and in early implementations:

Code and CI/CD: A push, a new pull request or a failed CI run notifies a coding agent. The agent reads the failure, investigates and opens a draft fix. This is the same trigger that [GitHub webhooks](/webhooks/platforms/page/1/github) have provided for years, now aimed at an agent.

Team chat and feedback: A new message in a channel such as `#product-feedback` notifies the agent, which triages it, files an issue or drafts a pull request. OpenAI uses this exact scenario, with a `message.created` event filtered by channel, in its [MCP Events guide](https://developers.openai.com/plugins/build/mcp-events).

Documents and review: A new comment on a document notifies the agent, which applies the requested edit. Filters on the subscription (for example, a `document_id`) keep the agent focused on one document.

Incidents and on-call: A new incident notifies the agent, which gathers logs, checks recent deploys and posts a first summary before a human picks it up. Subscription arguments can narrow this to a severity or a service.

Email and inbox triage: An incoming email from a given sender notifies the agent, which summarizes it or drafts a reply.

Long-running work: A job, export or agent task finishes and the client is notified, instead of checking back. The working group is coordinating with the MCP Agents working group on this case for task completion.

In every case the pattern is the one webhooks made familiar: an event occurs in one system and a notification carries it to another. The difference is the receiver. With MCP Events, the receiver is an agent that reasons about the event and decides what to do, instead of code that runs the same handler every time.

## How MCP Events work

MCP Events adds three methods to the protocol: `events/list`, `events/subscribe` and `events/unsubscribe`. Here's how a subscription works with webhook delivery, the mode most remote servers and ChatGPT use. The method names and fields below come from the [draft design](https://github.com/modelcontextprotocol/experimental-ext-triggers-events/blob/main/docs/design-sketch-proposal.md) and may change before the specification is final.

![MCP Events webhook flow: an agent subscribes through an MCP server, and each upstream event reaches the agent as a signed webhook](./images/mcp-events-webhook-flow.png)

The agent subscribes through the MCP server once. After that, each event in the upstream app reaches the agent as a signed webhook, and the agent acts by calling the server's tools.

1. Discover. The server advertises an `events` capability. The client calls `events/list` and gets each event type's name, description, supported delivery modes, an `inputSchema` for the subscription arguments (filters such as a channel or document ID) and a `payloadSchema` describing the event data.
2. Subscribe. The client calls `events/subscribe` with the event name, its arguments and a delivery object: a callback URL plus a signing secret that the client generates (a `whsec_` value). The server checks that the user is allowed to see those events, stores the subscription and returns a subscription ID and a `refreshBefore` expiry time.
3. Verify the callback. Before sending any real data, the server POSTs a signed verification message with a single-use challenge to the callback URL. The receiver proves it wants the traffic by echoing the challenge back in a `2xx` response. This stops anyone from using an MCP server to flood a URL they don't own.
4. Deliver. When a matching event occurs, the server POSTs it to the callback URL, signed using Standard Webhooks. A `2xx` response acknowledges it; anything else is retried with exponential backoff.
5. Refresh or unsubscribe. Subscriptions expire at `refreshBefore` unless the client calls `events/subscribe` again with the same arguments. The client can call `events/unsubscribe` to stop delivery straight away.

### Three delivery modes

The draft defines three ways to deliver events. A server lists which ones each event type supports, and the client SDK picks one.

| Mode | Method | How events arrive | Best for |
| --- | --- | --- | --- |
| Webhook | `events/subscribe` | The server POSTs each event to a callback URL | Remote servers and clients that aren't always connected |
| Push | `events/stream` | Events stream over a long-lived request (SSE or stdio) | Local servers and clients holding a live session |
| Poll | `events/poll` | The client asks for events since its last cursor | Simple servers that hold no subscription state |

The agent never sees the delivery mechanics. The client SDK runs the subscription, and the model only sees events as they arrive.

### What a delivered event looks like

In webhook mode, an event is an HTTP `POST` with a JSON body and Standard Webhooks signature headers, plus one MCP-specific header that tells the receiver which subscription (and which secret) it belongs to:

```http
POST /mcp-events/sub_7d2e9a HTTP/1.1
Content-Type: application/json
webhook-id: evt_01J9ZK4Q8M
webhook-timestamp: 1791363600
webhook-signature: v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2pj9o9NDN/H/pI4=
X-MCP-Subscription-Id: sub_7d2e9a

{
  "eventId": "evt_01J9ZK4Q8M",
  "name": "incident.created",
  "timestamp": "2026-10-07T09:00:00Z",
  "data": {
    "incident_id": "INC-2041",
    "service": "checkout-api",
    "severity": "P1",
    "url": "https://status.example.com/incidents/INC-2041"
  },
  "cursor": null
}

```

A few properties of the design are worth knowing before you build on it:

* At-least-once delivery. Retries mean the same event can arrive twice. Deduplicate on `eventId`, and make the tools an agent calls in response idempotent.
* No ordering guarantee. Events can arrive out of order. Use `timestamp` when order matters.
* Cursors for replay. Where the upstream system keeps history, a cursor lets a client resume after downtime without missing events. Servers that can't replay return `cursor: null`.
* Small, untrusted payloads. Servers should send just enough to triage the event and let the agent fetch the rest with a tool. Event data is untrusted input with the same prompt-injection risk as a tool result.
* Receiving an event doesn't grant permission to act. Any tool call the agent makes in response goes through the server's normal authorization checks.

## MCP Events vs. webhooks

In webhook mode, an MCP Event is a webhook: an HTTP `POST` from one system to another when something happens, signed with an HMAC secret. What MCP Events add is a standard way for an agent to find, subscribe to and manage those webhooks at runtime, across every MCP server, without a developer setting each one up by hand.

|  | Webhooks | MCP Events |
| --- | --- | --- |
| Who subscribes | A developer, through the provider's dashboard or API | The MCP client, at runtime, through `events/subscribe` |
| How events are discovered | Reading each provider's documentation | `events/list`, with a JSON Schema for arguments and payload |
| Subscription lifetime | Usually until someone deletes the endpoint | Expires at `refreshBefore` unless the client refreshes it |
| Delivery | HTTP `POST` | Webhook `POST`, a push stream or polling |
| Signing | Different scheme per provider | One scheme: Standard Webhooks HMAC-SHA256 |
| Endpoint verification | Varies; many providers skip it | Required before the first delivery |
| Filtering | Usually by event type only | Server-defined arguments, such as a channel or document ID |
| Payload | Often the full object | A minimal summary; the agent fetches details with tools |
| Who reacts | Code you wrote for that event | An agent that decides what to do |

### What stays the same

The reliability problems of webhooks carry straight over. MCP Events have at-least-once delivery, no ordering guarantee and retries with backoff, so you still need [idempotent processing](/webhooks/guides/implement-webhook-idempotency), [signature verification](/webhooks/guides/complete-guide-to-webhook-security) and a plan for bursts and downtime. An agent can make the cost of getting this wrong higher: a duplicated event might mean a duplicated pull request or a second reply to a customer.

### Do MCP Events replace webhooks?

No. Most MCP servers that emit events will sit on top of the webhooks their upstream product already sends. A GitHub MCP server, for example, would receive GitHub's webhook, decide which subscriptions match, and send an MCP Event to each. Webhooks remain the plumbing between systems; MCP Events are the standard way to bring that plumbing to agents.

## Running MCP Events in production

The protocol messages are the easy part. What takes the work is the webhook infrastructure underneath, and it looks different depending on which side you're building.

### If your MCP server sends events

Adding events to an MCP server turns it into a webhook producer, with everything that involves:

* Durable subscription storage. Subscriptions, their callback URLs, secrets and expiry times have to survive restarts for as long as you granted them.
* Signing every request. Each delivery is signed with that subscription's own secret, and re-signed with a fresh timestamp on every retry.
* Retries with limits. Retry failures with exponential backoff, keep the same event ID across attempts, and stop after a bounded number of tries. ChatGPT asks servers not to retry `410` or `413` responses.
* SSRF protection. The callback URL comes from the client, so resolve and check the destination IP at connection time, block private and internal addresses, and never follow redirects.
* Endpoint verification. Run the challenge handshake before activating delivery, and cache the result per user and URL.
* Access checks over time. If a user loses access to the channel or document they subscribed to, delivery has to stop.
* Fan-out and limits. One upstream event can match many subscriptions. ChatGPT accepts one event per request, with a body of at most 256 KiB.

### If you receive events

If you're building an MCP client or an agent platform, or you want a gateway between MCP servers and your agents, you're on the receiving end. The draft design explicitly expects this pattern: the callback URL doesn't have to be the client itself, and a common setup is a proxy that receives the webhooks and passes events on to clients.

The receiving side needs to:

* Verify the signature against the raw request body, and reject requests with a `webhook-timestamp` more than five minutes old.
* Answer the verification challenge by echoing it back, or no events will arrive.
* Acknowledge fast and process later. Return `2xx` only once the event is safely stored, then hand it to the agent asynchronously. See [why synchronous processing breaks](/webhooks/guides/why-you-should-stop-processing-your-webhooks-synchronously).
* Deduplicate on `eventId`, so a retried event doesn't trigger the agent twice.
* Absorb bursts. One busy channel or a CI storm can send hundreds of events in a minute. Queue them and control how fast they reach your agents.
* See what happened. When an agent doesn't react, you need to know whether the event arrived, what it contained and what your endpoint returned.

### While you're building

If you're building an MCP server, send test deliveries to the [Hookdeck Console](https://console.hookdeck.com) to check the body, headers and signature exactly as a receiver will see them. If you're building a receiver, the [Hookdeck CLI](/docs/cli) forwards events to `localhost` and lets you replay them while you iterate.

## The current status of MCP Events

MCP Events is a draft, not part of the official MCP specification, but it already has a major production implementation in ChatGPT.

### The specification

The [MCP Triggers & Events Working Group](https://modelcontextprotocol.io/community/working-groups/triggers-events) was chartered in March 2026 to define how MCP servers proactively notify clients. It is led by Clare Liguori of AWS and Peter Alexander of Anthropic.

The working design is a [draft proposal](https://github.com/modelcontextprotocol/experimental-ext-triggers-events/blob/main/docs/design-sketch-proposal.md) by Peter Alexander, first dated February 2026, in the group's [experimental repository](https://github.com/modelcontextprotocol/experimental-ext-triggers-events). The repository states that its contents are exploratory and are not official MCP specifications. No Specification Enhancement Proposal (SEP) for events has been accepted yet, and the group still lists subscription lifecycle as open work. Expect field names and behavior to change.

### Early OpenAI support in ChatGPT

At DevDay on September 29, 2026, OpenAI announced support for the proposed MCP Events specification, so plugins can start automations in ChatGPT when something happens in a connected app. OpenAI's [MCP Events guide](https://developers.openai.com/plugins/build/mcp-events) describes how it works today:

|  | ChatGPT's implementation |
| --- | --- |
| Protocol version | MCP 2.0 (`2026-07-28`) |
| Methods | `events/list`, `events/subscribe`, `events/unsubscribe` on the same authenticated endpoint as your tools |
| Delivery | Webhook only; no polling or push streams |
| Callback verification | Signed challenge, echoed back before delivery starts |
| Signing | Standard Webhooks headers plus `X-MCP-Subscription-Id` |
| Payload limit | One event per request, 256 KiB maximum |
| Not supported | The draft's `gap` and `terminated` control messages |
| Where it runs | Work chats on ChatGPT web, the desktop app with Cloud selected, and dots |

In practice, a ChatGPT user tells the agent what to watch and what to do, for example "watch this document for review comments and apply the edits." ChatGPT subscribes through your MCP server, receives each event in that chat and follows the user's instructions.

## Next steps

MCP Events give agents a standard way to react to the world, and in production they run on webhooks. Getting them right means getting webhooks right: verified, queued, retried, deduplicated and observable.

### Continue learning

* [What are webhooks and how do they work?](/webhooks/guides/what-are-webhooks-how-they-work): the foundation MCP Events build on.
* [Webhooks and AI agents](/webhooks/guides/webhooks-ai-agents-integration-patterns): integration patterns for event-driven agents.
* [Webhook security guide](/webhooks/guides/complete-guide-to-webhook-security): signatures, replay protection and more.
* [Webhook retry best practices](/webhooks/guides/webhook-retry-best-practices): backoff and retry limits for senders.

### Test MCP Events with Hookdeck

Because each MCP Event in webhook mode is a signed webhook, the tools you use to debug webhooks work for MCP Events today. Use the [Hookdeck Console](https://console.hookdeck.com) to inspect test deliveries from your MCP server, and the [Hookdeck CLI](/docs/cli) to forward events to a local receiver and replay them while you build.

## Sources

* [MCP Triggers and Events Working Group charter](https://modelcontextprotocol.io/community/working-groups/triggers-events)
* [MCP Events design sketch (draft proposal)](https://github.com/modelcontextprotocol/experimental-ext-triggers-events/blob/main/docs/design-sketch-proposal.md)
* [Triggers & Events experimental repository](https://github.com/modelcontextprotocol/experimental-ext-triggers-events)
* [OpenAI: MCP Events (Plugins docs)](https://developers.openai.com/plugins/build/mcp-events)