# Account MCP Events

The authenticated `/mcp/account` endpoint supports MCP `2026-07-28` and the existing legacy versions.
The public `/mcp` endpoint stays keyless. It has no Events capability.
Create a read or read-write key through the existing Account settings.
Each subscription belongs to that key and its account. The dispatcher stops delivery when you remove the key.

The operator must configure the fixed relay URL and private credential before enabling Events.
The operator must first verify destination validation and IP pinning in the deployed relay.
Check authenticated `server/discover` for `capabilities.events`. Do not infer readiness from this document.

## Protocol

Modern requests require these fields in `params._meta`:

- `io.modelcontextprotocol/protocolVersion`: `2026-07-28`.
- `io.modelcontextprotocol/clientCapabilities`: an object.

Clients should also send `io.modelcontextprotocol/clientInfo` with their name and version. This field is optional.
The server rejects missing or malformed metadata with HTTP 400 and JSON-RPC error `-32602`.

Send matching `MCP-Protocol-Version` and `Mcp-Method` headers.
Send the matching `Mcp-Name` header for these methods:

- `tools/call`.
- `resources/read`.
- `prompts/get`.

Encode unsafe header values with the exact `=?base64?...?=` sentinel.
Modern results include `resultType: "complete"`. Cacheable results include `ttlMs` and `cacheScope`.
The server marks account cache scope as private. Modern requests need no initialization or session ID.
The server supports legacy initialization and result shapes.

## Sighting changes

`events/list` describes `checklist.sighting_changed` after the operator enables Events.
Optional arguments filter by `animalId` and `deleted`.
`data` contains these fields:

- `animalId`.
- `seenAt`.
- `updatedAt`.
- `deleted`.

The timestamp records the committed occurrence time.

Database triggers capture catalog and source-taxon sighting inserts and changes in the mutation transaction.
These mutations use the same outbox:

- Browser sync.
- Account import.
- `mark_seen`.

An unchanged sighting produces no new event. Failed transactions produce no queued delivery.
The database deduplicates events across both sighting stores.

Call `events/subscribe` with these parameters:

- `name`: the event name.
- `arguments`: the filters.
- `delivery`: the object below.

```json
{
  "mode": "webhook",
  "url": "https://receiver.example.com/mcp-events/callback",
  "secret": "whsec_<base64-encoded-signing-key>"
}
```

Use a signing secret with 24–64 bytes. Encode those bytes in canonical base64 after the `whsec_` prefix.
The server verifies a signed, short-lived challenge before activating a new subscription.
The server caches successful verification for five minutes. Each cache entry uses these values:

- MCP key.
- Callback URL.
- Signing secret.

Concurrent requests use database leases.

The server derives each subscription ID from these values:

- Account.
- MCP key.
- Callback URL.
- Event name.
- Canonical arguments.

Refresh the same identity with `events/subscribe`. You can reorder argument keys without changing the ID.
The server grants one day by default. It grants at most seven days and never exceeds the requested lifetime.
The server uses the default for `ttlMs: null`. It returns the expiration in `refreshBefore`.
The MCP key can expire before that time. The dispatcher stops delivery when the key expires or the owner removes it.

The server retains the previous signing secret for five minutes after rotation.
Deliveries include both Standard Webhooks signatures during that window.
The dispatcher removes the previous secret after that window.
Call `events/unsubscribe` with the original values:

- Event name.
- Arguments.
- Callback URL.

The server accepts repeated unsubscribe requests.

Limits per MCP key are 20 live subscriptions and 60 subscription requests per hour.
This event has no protocol replay. Cursor values remain null.
The server returns an unsupported-feature error for these options:

- Non-null cursors.
- Replay-age options.
- Polling.
- Streaming.

## Delivery and release

The Worker sends exact signed bytes to its fixed relay using a private per-consumer bearer credential.
It never fetches an arbitrary callback URL. The relay never receives a signing secret.
The relay enforces these transport rules:

- Validate destination IPs on every connection.
- Pin destination IPs.
- Block redirects.

Terraform owns the relay bindings and the one-minute retry cron.
GitHub deployment inputs are `vars.MCP_EVENTS_RELAY_URL` and `secrets.MCP_EVENTS_RELAY_TOKEN`.
The corresponding Worker bindings use the same names.
Keep both unset until deployed transport checks pass. The existing deployment workflow applies migrations before the Worker release.

Before delivery, the dispatcher checks these values:

- Account.
- MCP key.
- Subscription.
- Expiration.

Retries preserve event IDs and body bytes. Each attempt has a fresh signing timestamp and signature.
The dispatcher retries these failures with exponential backoff and jitter:

- Network failures.
- HTTP 429.
- HTTP 5xx.

The dispatcher stops after six attempts or one day. A 410 stops that subscription; a 413 stops that delivery.
Outbox records and occurrences expire after one day. Signing secrets stay in the private product database.

The lifecycle harness verifies product behavior with real SQLite and an instrumented relay boundary.
It does not prove deployed TLS pinning or native ChatGPT behavior.
After deployment:

1. Rescan the authenticated plugin.
2. Subscribe in Work Cloud.
3. Trigger matching and nonmatching sightings.

Before reporting native-host readiness, verify these results:

- Callback acknowledgement.
- ChatGPT response.
- Successful unsubscribe.

References:

- [OpenAI MCP Events](https://developers.openai.com/plugins/build/mcp-events).
- [Events draft](https://github.com/modelcontextprotocol/experimental-ext-triggers-events/blob/main/docs/design-sketch-proposal.md).
- [MCP discovery](https://modelcontextprotocol.io/specification/2026-07-28/server/discover).
- [MCP Streamable HTTP](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/streamable-http).
- [MCP caching](https://modelcontextprotocol.io/specification/2026-07-28/server/utilities/caching).
