Sign inGet Started

MCP Events

MCP Events lets an MCP client hear about what happens in Bird without polling. Your client subscribes to an event, such as an email arriving in a mailbox, and the hosted Bird MCP server posts each matching event to a callback URL the client owns. The client wakes your agent with the event, and the agent acts on it with Bird's tools.

MCP Events implements the MCP triggers and events extension with webhook delivery. Your MCP client handles the protocol: you connect it to mcp.bird.com and ask it to watch for something. ChatGPT supports it today.

Before you start

  • Connect your client to the hosted server at https://mcp.bird.com/, or its /dynamic endpoint. The /public endpoint and the local bird mcp server do not serve MCP Events.
  • Sign in with an account that can manage webhooks. Each subscription needs the webhooks:write scope and the read scope of its event, which the client requests when you sign in.
  • Use a client that supports the extension and its webhook delivery mode.

Events you can subscribe to

EventRead scopeFilters
email_mailbox.message_receivedmailbox:readmailbox_id, thread_id
email.deliveredemails:readbroadcast_id
sms.receivedsms:readto, a number of yours in E.164 format
whatsapp.receivedwhatsapp:readnone
amb.receivedamb:readnone

events/list returns the events your sign-in can subscribe to, each with its filters and payload schema. A filter narrows the subscription to one resource: mailbox_id set to mbx_… delivers only the mail that arrives in that mailbox. An event without filters delivers every occurrence in the workspace.

After you create a mailbox through the MCP server, the response suggests subscribing to its mail, with the event and mailbox_id filled in.

How a subscription works

  1. Subscribe. The client calls events/subscribe with the event, its filters, a callback URL and a signing secret of its own (whsec_…).
  2. Verify. Before creating anything, we post a signed {"type":"verification","challenge":"…"} to the callback. The callback must answer with a 2xx whose JSON body echoes challenge, within 4 seconds.
  3. Receive. Each matching event arrives as a POST to the callback, signed with the client's secret.
  4. Renew. A subscription lasts until its refreshBefore time, at most 24 hours and at least 5 minutes from the client's suggested ttlMs. Calling events/subscribe again with the same event, filters and callback renews it in place. A new signing secret replaces the old one once the callback verifies it, and the old one keeps signing for 5 minutes.
  5. End. The client calls events/unsubscribe, or stops renewing and the subscription expires.

Subscribing again from the same sign-in with the same event, filters and callback is idempotent: it renews the subscription you have rather than creating another.

Deliveries

Each delivery is a Standard Webhooks request:

  • webhook-id carries the event's ID, so the client can drop a repeat.
  • webhook-timestamp and webhook-signature sign the body with the client's secret.
  • X-MCP-Subscription-Id names the subscription, so the client can pick its secret before reading the body.

The body is {"eventId", "name", "timestamp", "data", "cursor": null}, where data is the event's payload as events/list describes it. We keep no replayable history, so cursor is always null.

A body is at most 256 KiB. An amb.received event that would be larger has its message text cut short at a character boundary and carries body_truncated: true; the client fetches the whole message with amb_get. Any other event that would exceed the limit is not sent.

A delivery that fails is retried eight times over about eight hours, so an event your agent acts on is not stale when it lands. If the callback answers 410 Gone or 413 Content Too Large, we drop that one event and keep the subscription. Failed deliveries never pause a subscription: it ends when its lease runs out.

When a subscription ends

A subscription ends when the client unsubscribes, when it expires, or when someone deletes it in Bird, from the dashboard's Webhooks list or through the API. Deleting it stops deliveries at once, but the client is not told: while it still holds the subscription, it creates it again at its next renewal, verifying its callback again. To stop a subscription for good, remove it from the client as well.

If the sign-in behind a subscription is revoked, or loses the event's read scope, we stop delivering to it, and it expires within its lease.

See your subscriptions

Every subscription is a webhook endpoint in your workspace. The dashboard's Webhooks list shows each one with its client's logo, its event and its filters, and you can delete it there. Subscriptions count toward your organization's webhook endpoint limit.

Troubleshooting

ErrorWhat it meansWhat to do
-32015 CallbackEndpointErrorThe callback did not verify. data.reason is connection_refused, timeout, tls_error, http_4xx, http_5xx or challenge_failed.Make the callback publicly reachable over HTTPS, and have it echo challenge within 4 seconds.
-32013 with data.limit: "subscriptions"The organization has no webhook endpoint left.Delete an endpoint you no longer need, then subscribe again.
-32013 with data.limit: "rate"Too many callback verifications in a short time.Wait, then retry the same request.
-32012The sign-in lacks the event's read scope or webhooks:write. data.required names the missing one.Sign in again and grant it.
-32602A filter the event does not take, or a callback that is not HTTPS.Use the filters events/list returns.

Next steps