Documentation Index
Fetch the complete documentation index at: https://smithery.ai/docs/llms.txt
Use this file to discover all available pages before exploring further.
Triggers are in preview. Breaking changes may happen without notice.
Triggers let an MCP server surface events from its upstream service. When a consumer activates a trigger via Smithery, Smithery proxies the subscribe call straight through to your server with the consumer’s webhook URL and signing secret. When the upstream provider fires, your server POSTs the event directly to the consumer — Smithery is not in the delivery path.
Your server is not in the hot path for events — only for setup and teardown. This keeps trigger support compatible with serverless runtimes.
Alignment with the MCP Events proposal
This extension tracks the webhook slice of the MCP committee’s events proposal. Smithery is intentionally minimal: it implements only what the spec requires for webhook delivery, and skips optional surface area while the proposal is still draft.
What Smithery implements today:
events/list — full parity
events/subscribe in webhook mode only, with mandatory TTL refresh
events/unsubscribe
What Smithery does not implement:
poll and push (events/stream) delivery modes
- Cursor replay — events start “from now”
truncated, maxAge, maxEvents parameters
- Control envelopes (
gap, terminated)
deliveryStatus reporting
- Asymmetric endpoint verification or server signing
Smithery acts as the spec’s “client” against your server: it forwards the consumer’s delivery.url and Standard Webhooks delivery.secret unchanged. Your server signs deliveries with that secret and POSTs them to that URL.
How it works
- The consumer creates a trigger through Smithery, supplying their own webhook URL and Standard Webhooks secret.
- Smithery, authenticated as the connection’s principal, calls your
ai.smithery/events/subscribe and forwards the consumer’s delivery.url and delivery.secret unchanged.
- Your server uses the connection’s credentials to register an upstream webhook (or start whatever event source it needs) and returns
{ id, refreshBefore }.
- Before
refreshBefore, the consumer re-POSTs through Smithery, which re-calls subscribe with the same key — your server treats this as an idempotent upsert and resets the TTL.
- When the upstream fires, your server POSTs the event directly to the consumer’s
delivery.url, signed with delivery.secret. Smithery is not involved in delivery.
- When the consumer deletes the trigger (or stops refreshing), Smithery calls
ai.smithery/events/unsubscribe to tear down the upstream registration.
Negotiation
Advertise the extension in your initialize response:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"protocolVersion": "2025-11-25",
"capabilities": {
"extensions": {
"ai.smithery/events": {}
}
},
"serverInfo": { "name": "NotionMCP", "version": "1.0.0" }
}
}
Methods
ai.smithery/events/list
Return the catalog of event types your server supports. Each entry declares the params a subscriber must provide and the payload your server will deliver.
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"events": [
{
"name": "page.updated",
"description": "Fires when a page in the watched workspace is updated.",
"delivery": ["webhook"],
"inputSchema": {
"type": "object",
"properties": {
"workspace_id": { "type": "string" }
},
"required": ["workspace_id"]
},
"payloadSchema": {
"type": "object",
"properties": {
"page_id": { "type": "string" },
"updated_at": { "type": "string", "format": "date-time" }
}
}
}
]
}
}
| Field | Type | Description |
|---|
name | string | Unique event name scoped to your server. |
description | string | Human-readable summary of when this event fires. |
delivery | string[] | Delivery modes this event supports. For Smithery, return ["webhook"]. |
inputSchema | object | JSON Schema for the params a subscriber must supply (e.g. workspace or channel scoping). Mirrors the inputSchema convention from tools. |
payloadSchema | object | JSON Schema describing the data object your server emits. |
ai.smithery/events/subscribe
Smithery calls this when a consumer activates a trigger, and again before each refreshBefore to keep the subscription alive. Register an upstream webhook pointing at delivery.url, retain delivery.secret to sign each POST, and return a stable subscription id plus a fresh refreshBefore.
Request:
{
"jsonrpc": "2.0",
"id": 3,
"method": "ai.smithery/events/subscribe",
"params": {
"name": "page.updated",
"params": { "workspace_id": "w_123" },
"delivery": {
"mode": "webhook",
"url": "https://my-app.example.com/events",
"secret": "whsec_<base64 of 24-64 random bytes>"
}
}
}
Response:
{
"jsonrpc": "2.0",
"id": 3,
"result": {
"id": "sub_a3f1c8e2b0d49f7e",
"refreshBefore": "2026-04-22T13:00:00.000Z"
}
}
| Param | Description |
|---|
name | The event name from events/list. |
params | Subscriber-supplied arguments conforming to the event’s inputSchema. |
delivery.mode | Always "webhook" for this extension. |
delivery.url | The consumer’s HTTPS webhook endpoint. POSTs go here directly. |
delivery.secret | The consumer’s Standard Webhooks whsec_ secret. Sign each POST to delivery.url with this secret. |
| Result field | Description |
|---|
id | Stable subscription handle deterministic over (principal, name, params, delivery.url). The receiver uses it to look up the right secret via the X-MCP-Subscription-Id header. |
refreshBefore | ISO 8601 timestamp at which the subscription expires unless refreshed. Pick a TTL that reflects how long you can hold soft state for (e.g. 30 minutes). |
Idempotent upsert and TTL refresh
ai.smithery/events/subscribe is keyed by (principal, name, params, delivery.url). If a subscription with the same key already exists, treat the call as an upsert:
- TTL — reset, return a new
refreshBefore.
delivery.secret — replace. During rotation, the spec recommends dual-signing with the old and new secrets for a short grace window using Standard Webhooks’ multi-signature support.
id — unchanged.
If the subscription has expired (or your server lost it on restart), create a fresh one for the same key and return a new id.
If Smithery stops refreshing before refreshBefore, expire the subscription and tear down the upstream webhook — no explicit unsubscribe is required.
ai.smithery/events/unsubscribe
Smithery calls this on eager teardown (consumer deleted the trigger). Tear down the upstream registration you created.
{
"jsonrpc": "2.0",
"id": 4,
"method": "ai.smithery/events/unsubscribe",
"params": {
"name": "page.updated",
"params": { "workspace_id": "w_123" },
"delivery": {
"url": "https://my-app.example.com/events"
}
}
}
Response:
{
"jsonrpc": "2.0",
"id": 4,
"result": {}
}
Look up the subscription by (principal, name, params, delivery.url) and deregister the corresponding upstream webhook. The subscription id is not accepted here — the key is the canonical identifier.
Event delivery
When an upstream event arrives, POST it to delivery.url, signed with the Standard Webhooks headers and the consumer’s delivery.secret. The consumer verifies the signature and processes the event.
You are responsible for:
- Declaring a
payloadSchema that accurately describes the data field.
- Configuring upstream webhook registration so the payload delivered to the consumer matches that schema.
- Never including secrets or PII the consumer shouldn’t see.
If the upstream payload requires transformation (unwrapping envelopes, hydrating IDs, redacting fields), do it at registration time — use the provider’s webhook filter or payload-shape features.
The body sent to the consumer is an EventOccurrence:
{
"eventId": "evt_01HW...",
"name": "page.updated",
"timestamp": "2026-04-22T12:00:00.000Z",
"data": {
"page_id": "...",
"updated_at": "2026-04-22T12:00:00.000Z"
}
}
| Field | Description |
|---|
eventId | Stable event identifier. Use the upstream’s stable id (Stripe evt_*, GitHub delivery GUID, Gmail message id) so the receiver can dedupe across retries. |
name | The event name from events/list. |
timestamp | ISO 8601 timestamp of the upstream event. |
data | Payload conforming to the event’s payloadSchema. |
Webhook signing
Sign every POST with the Standard Webhooks HMAC profile.
Required headers:
| Header | Value |
|---|
webhook-id | Stable event id for deduplication |
webhook-timestamp | Unix seconds |
webhook-signature | v1,<base64 HMAC-SHA256(delivery.secret, "id.timestamp.body")> |
X-MCP-Subscription-Id | The subscription id you returned from events/subscribe. The receiver uses this to look up the right secret before parsing the body. |
Sign the raw request body with a Standard Webhooks library. Each retry attempt MUST regenerate the timestamp and signature so receivers do not reject a later attempt as stale.
API reference
Extension capability
Advertise during initialize under capabilities.extensions:
{ "ai.smithery/events": {} }
MCP methods (Smithery → server)
| Method | Params | Result |
|---|
ai.smithery/events/list | — | { events: [{ name, description, delivery, inputSchema, payloadSchema }] } |
ai.smithery/events/subscribe | { name, params, delivery: { mode, url, secret } } | { id, refreshBefore } |
ai.smithery/events/unsubscribe | { name, params, delivery: { url } } | {} |
Learn more