Triggers are in draft. Breaking change may happen without notice.
Triggers let an MCP server surface events from its upstream service. When a user activates a trigger, Smithery hands your server a callback URL to register with the upstream provider. When the provider fires, it POSTs to Smithery, which re-signs the payload and delivers it to the consumer’s subscription URL.
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. Method names, field names, and wire shapes for the methods we do implement match the proposal, so that once MCP ships a standard events primitive, migration for webhook-only servers is a prefix drop: ai.smithery/events/list → events/list. Servers that also want to support poll or push will need additional work when that happens.
What Smithery implements today:
events/list — full parity
events/subscribe in webhook mode only
events/unsubscribe
What Smithery does not implement (yet):
poll and push (events/stream) delivery modes
- Cursor replay — events start “from now”
- TTL refresh — subscriptions persist until
unsubscribe is called
deliveryStatus reporting
Smithery generates the subscription id and supplies a delivery.url on the callbacks.smithery.run domain.
How it works
- The consumer creates a trigger through Smithery.
- Smithery calls your
ai.smithery/events/subscribe with a high-entropy id and a delivery.url on callbacks.smithery.run.
- Your server uses the connection’s credentials to register or start whatever event source it needs.
- Your MCP server POSTs events directly to Smithery. Smithery signs and fans out.
- When the consumer deletes the trigger, 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. Smithery trust-passes the upstream payload without transformation. |
ai.smithery/events/subscribe
Smithery calls this once when a consumer activates a trigger. Register a webhook with the upstream service pointing at delivery.url. Smithery does not call subscribe again for the same id; the subscription stays active until unsubscribe is called.
Request:
{
"jsonrpc": "2.0",
"id": 3,
"method": "ai.smithery/events/subscribe",
"params": {
"id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"name": "page.updated",
"params": { "workspace_id": "w_123" },
"delivery": {
"mode": "webhook",
"url": "https://callbacks.smithery.run/t/f47ac10b-58cc-4372-a567-0e02b2c3d479"
}
}
}
Response:
{
"jsonrpc": "2.0",
"id": 3,
"result": {}
}
| Param | Description |
|---|
id | High-entropy subscription identifier generated by Smithery. Persist this with your upstream webhook record so unsubscribe can find it. |
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 | HTTPS URL on callbacks.smithery.run where events should be POSTed. |
ai.smithery/events/unsubscribe
Smithery calls this when the consumer deletes the trigger, or on eager cleanup. Tear down the upstream registration you created.
{
"jsonrpc": "2.0",
"id": 4,
"method": "ai.smithery/events/unsubscribe",
"params": {
"id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"delivery": {
"url": "https://callbacks.smithery.run/t/f47ac10b-58cc-4372-a567-0e02b2c3d479"
}
}
}
Response:
{
"jsonrpc": "2.0",
"id": 4,
"result": {}
}
Your server looks up the subscription by (id, delivery.url) and deregisters the corresponding upstream webhook.
Event delivery
Your server is not involved at event time. The upstream provider POSTs directly to delivery.url; Smithery wraps the payload in the standard envelope, signs it per Standard Webhooks, and delivers it to the consumer’s subscription URL.
You are responsible for:
- Declaring a
payloadSchema that accurately describes the data field.
- Configuring upstream webhook registration so the payload delivered to Smithery 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. Smithery does not run code per event.
Callback URL contract
Smithery mints one delivery.url per subscription. It is:
- HTTPS only.
- Stable for the lifetime of the subscription — no rotation.
- Unique per
id — inferring tenancy from the URL is safe.
Some providers require pre-approved destination domains (Stripe, corporate-managed SaaS). Smithery’s callback domain is callbacks.smithery.run and is stable — you can allow-list it with your upstream provider. Field shapes elsewhere in this doc are still draft and may change, but the callback host will not.
Authentication of upstream deliveries
The id segment in delivery.url is high-entropy and functions as a bearer capability — Smithery trusts any POST to that URL as belonging to the named subscription. Upstream provider signatures (e.g. GitHub’s X-Hub-Signature-256, Stripe’s Stripe-Signature) are not verified by Smithery in v1. If your upstream supports a configurable webhook secret, you may set one at registration time and include verification logic in a future ai.smithery/events/deliver hook; until then, treat delivery.url secrecy as the authentication boundary.
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 | { id, name, params, delivery: { mode, url } } | {} |
ai.smithery/events/unsubscribe | { id, delivery: { url } } | {} |
Callback URL contract
| Property | Value |
|---|
| Scheme | https:// only |
| Host | callbacks.smithery.run |
| Path | /t/{id} — unique per subscription |
| Lifetime | Stable for the lifetime of the subscription |
| Payload | Raw upstream body, unmodified by Smithery before delivery |
Learn more