Allternit’s public MCP servers support MCP Events with webhook delivery. Instead of polling, an AI app subscribes once and Allternit posts to it when something happens: an agent needs approval, a run finished, a thread needs you, a message arrived, a subscription needs you to sign in again. Both advertise "events": { "listChanged": false } in server/discover. The edge answers events/* itself, so subscribing works while your computer is asleep. Events are produced on your computer, so they arrive once it’s back online.

Events

Agents server

Vendor bot connector

On a bot connector, bot_id is always that bot. Passing a different bot_id is refused with -32012. Filter arguments are optional strings; an event is delivered when its data has every value you passed. events/list returns each event’s inputSchema and payloadSchema.

Subscribe

  • Callback URL: https:// only, no credentials, no private, loopback, link-local or carrier-grade NAT addresses. The address is checked again on every delivery, and we connect to exactly the address we checked. Redirects are not followed.
  • Secret: you choose it. whsec_ plus base64 of 24 to 64 bytes.
  • Idempotent: the same app, server, URL, event name and arguments always give the same id. Subscribing again refreshes it.
  • TTL: leave out ttlMs for 24 hours. Anything you ask for is clamped to between 1 minute and 7 days; ttlMs: null (no expiry) gets 7 days. Subscribe again before refreshBefore, or deliveries stop.
  • Secret rotation: refresh with a new secret. For the next hour, deliveries are signed with both the new and the old key (two space-separated signatures), so you can switch over without dropping events.
  • Replay: user events are available for seven-day catch-up. Cursors are scoped to the authenticated subscription, including its filters and target. Initial subscribe starts at the current position; a refresh with a saved cursor queues matching retained events. truncated: true reports matching history older than that window. Cursors stay behind earlier recoverable deliveries, so out-of-order delivery cannot silently skip them.
  • Limit: 50 live subscriptions per app per server (-32013).

Verification challenge

Before a new subscription goes live (and again when you change the secret, or after a day), we POST a signed challenge to your URL:
Answer 2xx with the same value:
If you don’t, events/subscribe fails with -32015 CallbackEndpointError and data.reason set to connection_refused, timeout, tls_error, http_4xx, http_5xx or challenge_failed.

Deliveries

  • Signed with Standard Webhooks: base64 HMAC-SHA256 of "<webhook-id>.<webhook-timestamp>.<raw body>" keyed with your decoded secret. Reject timestamps more than five minutes old.
  • webhook-id equals eventId and stays the same on every retry. Deduplicate on it.
  • Any 2xx within 10 seconds is delivered. Other answers and network errors are retried with backoff (30 s, 2 min, 10 min, 30 min, 1 h, then every 2 h) for 24 hours.
  • 410 Gone ends the subscription. 413 drops that event without retrying. Bodies are never larger than 256 KiB.

When access ends

If you remove the app’s approval in Allternit (or revoke a vendor bot CLI key), or stop one subscription in Connected apps, the subscriptions end at once, and each callback gets one signed message:
events/unsubscribe with the same name, arguments and URL ends one subscription. It always answers {}.

Seeing and ending subscriptions

Owners see every app’s subscriptions in Settings › Connected apps (Desktop, ai.allternit.com, the phone layout and the m.allternit.com app). Under each approved app it lists the events it gets in plain words, when each was last sent, the last delivery error, and Stop for one subscription. See Connected apps. Subscriptions a vendor agent made with an allternit-bot CLI key are listed under that key instead (GET /api/v1/vendor-bots/:id/cli-keys, see allternit-bot CLI), and stop the same way. Stopping one ends it at once and its callback gets the same signed terminated message, with "reason": "ended_by_owner". The app is still approved, so it can subscribe again; removing the approval ends all of them. The routes behind it (cloud API, Clerk session or compute-scoped API key; 503 mcp_edge_not_configured until the edge is on):

Errors

For runtime developers: forwarding events to the cloud

Events start in each runtime’s bot_events ledger. A runtime forwards them to POST https://api.allternit.com/api/v1/runtime/events, signed with its device credential the same way cloud-api signs relayed requests to it:
  • Up to 100 events and 1 MiB per request. id (1–128 characters) is the idempotency key for that runtime; resending it answers duplicate.
  • Ledger names map onto the event list above (channel.message.received becomes message.received, agent.approval.requested becomes approval.requested, run.completed becomes agent.run.completed). Other types are answered ignored, so a forwarder can send its whole outbox. Outbound echoes (own: true) are ignored.
  • bot_id and thread_id are copied into data. data must be an object of at most 250 KiB.
  • The answer lists one result per event, in order: {"results":[{"id","status","eventId"?}],"accepted","duplicates","ignored","rejected"} with status one of accepted, duplicate, ignored, too_large, invalid. Advance the cursor past every result; on 5xx resend the same batch. 401 means the signature, clock or device credential is wrong.

The other direction: apps that send events to Allternit

Allternit is also an MCP Events client. When a server you connected as a connector advertises events, a bot can subscribe to its events and wake on them: the runtime subscribes with a webhook URL on api.allternit.com, which verifies each Standard Webhooks delivery and relays it to your computer. See Wake a bot from a connected app’s events and the Connector events API.

ChatGPT interoperability

OpenAI’s MCP Events integration uses protocol 2026-07-28, webhook delivery and callback verification. It works in Work web chats, desktop Work chats with Cloud selected, and dots. Rescan a plugin after changing its event catalog. ChatGPT does not support polling, streaming, or the draft’s gap / terminated control notifications. Allternit stops delivery on revocation regardless of whether the client understands a termination notification. A 2xx acknowledges receipt; task execution and output are asynchronous. Test discovery, filtered subscriptions, refresh/replay, real task output, unsubscribe, revocation and duplicate deliveries before describing a plugin workflow as verified.