MCP Events

Tell your agent when a webhook fails

The Expose MCP server supports MCP Events. An agent subscribes to request.completed on one of your tunnels, and Expose sends it a signed webhook for every request that matches, such as a Stripe webhook your app answered with a 500. The agent hears about the failure instead of asking for the latest requests again and again.

A request.completed event
{
  "eventId": "evt_01k9x3m7c2…",
  "name": "request.completed",
  "timestamp": "2026-11-11T09:41:12Z",
  "data": {
    "tunnel": "shop.eu-1.sharedwithexpose.com",
    "request_id": "…",
    "started_at": "2026-11-11T09:41:12Z",
    "method": "POST",
    "path": "/stripe/webhook",
    "status": 500,
    "duration_ms": 112,
    "request_content_type": "application/json",
    "response_content_type": "text/html"
  },
  "cursor": null
}

How it works

  1. 1. Ask your agent

    "Tell me when a Stripe webhook to shop.eu-1.sharedwithexpose.com fails." It subscribes with the tunnel's public host and the filters it needs.

  2. 2. Expose watches the tunnel

    The Expose server that carries your tunnel reports its requests about once a second, only while somebody subscribes to it.

  3. 3. Your agent gets the event

    A signed webhook with the method, path, status and duration of the request. Headers and bodies stay with Expose.

  4. 4. It looks closer

    With the event's request_id, expose.get_request returns the headers and body, for up to 30 minutes.

Filters

The same filters as expose.list_requests. Filter on status error when only failures matter.

tunnel
Required. The tunnel's public host, such as shop.eu-1.sharedwithexpose.com. The subscription keeps watching when the tunnel reconnects on the same host.
method
Only requests with this HTTP method, such as POST.
status
A code like 404, a class like 5xx, or error for every 4xx, 5xx and request that got no answer.
path
Only requests whose path or query contains this text, such as /stripe.

Subscribing

Clients send events/subscribe with their own webhook URL and secret. Your agent does this for you; this is what it sends.

events/subscribe
{
  "method": "events/subscribe",
  "params": {
    "name": "request.completed",
    "arguments": {
      "tunnel": "shop.eu-1.sharedwithexpose.com",
      "path": "/stripe",
      "status": "error"
    },
    "delivery": {
      "mode": "webhook",
      "url": "https://agent.example.com/hooks/expose",
      "secret": "whsec_…"
    }
  }
}

Delivery and limits

Webhook delivery
Events are signed with Standard Webhooks, and the webhook-id is the event id, so receivers can drop duplicates. Failed deliveries are retried over about 14 minutes.
Verified callbacks
Before the first delivery to a URL, it has to echo a signed challenge. Callbacks must be https on public addresses, and redirects aren't followed.
A day at a time
Subscriptions last up to 24 hours. Subscribing again refreshes one, can rotate its secret and reports how deliveries went.
Rate limited
Up to 30 events a minute per subscription, so a busy tunnel can't flood your agent; the next refresh says when events were dropped. Up to 50 subscriptions per account.

Which agents

MCP Events is a draft extension of the Model Context Protocol (SEP-3415), and Expose delivers events by webhook. ChatGPT subscribes to them today: connect the Expose app and ask it to watch a tunnel. Other clients that implement webhook delivery of the draft subscribe the same way.

Coding agents such as Claude Code, Codex and Amp don't receive MCP Events. They use expose.list_requests with the same filters whenever you ask them to check.

What leaves Expose

  • A summary, not the request. Events carry the method, path, status, duration and content types. Secret query values in the path are redacted.
  • Only your tunnels. A request reaches your subscriptions only when the tunnel was opened with your Expose token.
  • Only to your agent. Events go to the webhook URL your client subscribed with, for ChatGPT one of OpenAI's.
  • Your call. Disconnecting an app on your profile page ends its subscriptions.