@mastra/mcp 2.5.0-alpha.1 → 2.5.0-alpha.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client/actions/events.d.ts +66 -0
- package/dist/client/actions/events.d.ts.map +1 -0
- package/dist/client/client.d.ts +63 -1
- package/dist/client/client.d.ts.map +1 -1
- package/dist/client/configuration.d.ts +49 -0
- package/dist/client/configuration.d.ts.map +1 -1
- package/dist/client/events/errors.d.ts +13 -0
- package/dist/client/events/errors.d.ts.map +1 -0
- package/dist/client/events/index.d.ts +3 -0
- package/dist/client/events/index.d.ts.map +1 -0
- package/dist/client/events/mode.d.ts +58 -0
- package/dist/client/events/mode.d.ts.map +1 -0
- package/dist/client/events/poll-driver.d.ts +6 -0
- package/dist/client/events/poll-driver.d.ts.map +1 -0
- package/dist/client/events/push-driver.d.ts +7 -0
- package/dist/client/events/push-driver.d.ts.map +1 -0
- package/dist/client/events/stream-router.d.ts +42 -0
- package/dist/client/events/stream-router.d.ts.map +1 -0
- package/dist/client/events/subscription.d.ts +118 -0
- package/dist/client/events/subscription.d.ts.map +1 -0
- package/dist/client/events/types.d.ts +181 -0
- package/dist/client/events/types.d.ts.map +1 -0
- package/dist/client/events/webhook-driver.d.ts +10 -0
- package/dist/client/events/webhook-driver.d.ts.map +1 -0
- package/dist/client/events/webhook-receiver.d.ts +41 -0
- package/dist/client/events/webhook-receiver.d.ts.map +1 -0
- package/dist/client/index.d.ts +1 -0
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/types.d.ts +3 -0
- package/dist/client/types.d.ts.map +1 -1
- package/dist/docs/SKILL.md +2 -1
- package/dist/docs/assets/SOURCE_MAP.json +1 -1
- package/dist/docs/references/docs-guides-mcp-authentication-authorization.md +2 -2
- package/dist/docs/references/docs-guides-mcp-events.md +306 -0
- package/dist/docs/references/reference-tools-mcp-client.md +236 -0
- package/dist/docs/references/reference-tools-mcp-server.md +170 -0
- package/dist/index.cjs +5242 -11216
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5282 -11267
- package/dist/index.js.map +1 -1
- package/dist/integrations/events-cursor-store.d.ts +25 -0
- package/dist/integrations/events-cursor-store.d.ts.map +1 -0
- package/dist/integrations/events-signals.d.ts +99 -0
- package/dist/integrations/events-signals.d.ts.map +1 -0
- package/dist/integrations/events-tools.d.ts +24 -0
- package/dist/integrations/events-tools.d.ts.map +1 -0
- package/dist/integrations/events-utils.d.ts +18 -0
- package/dist/integrations/events-utils.d.ts.map +1 -0
- package/dist/integrations/index.d.ts +5 -0
- package/dist/integrations/index.d.ts.map +1 -0
- package/dist/server/events/actions.d.ts +35 -0
- package/dist/server/events/actions.d.ts.map +1 -0
- package/dist/server/events/define-event.d.ts +19 -0
- package/dist/server/events/define-event.d.ts.map +1 -0
- package/dist/server/events/handlers.d.ts +49 -0
- package/dist/server/events/handlers.d.ts.map +1 -0
- package/dist/server/events/index.d.ts +7 -0
- package/dist/server/events/index.d.ts.map +1 -0
- package/dist/server/events/inspector.d.ts +14 -0
- package/dist/server/events/inspector.d.ts.map +1 -0
- package/dist/server/events/registry.d.ts +59 -0
- package/dist/server/events/registry.d.ts.map +1 -0
- package/dist/server/events/ring-buffer.d.ts +56 -0
- package/dist/server/events/ring-buffer.d.ts.map +1 -0
- package/dist/server/events/stream.d.ts +56 -0
- package/dist/server/events/stream.d.ts.map +1 -0
- package/dist/server/events/types.d.ts +203 -0
- package/dist/server/events/types.d.ts.map +1 -0
- package/dist/server/events/webhook-dispatcher.d.ts +98 -0
- package/dist/server/events/webhook-dispatcher.d.ts.map +1 -0
- package/dist/server/events/webhook-store.d.ts +60 -0
- package/dist/server/events/webhook-store.d.ts.map +1 -0
- package/dist/server/events/webhook-transport.d.ts +44 -0
- package/dist/server/events/webhook-transport.d.ts.map +1 -0
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/server.d.ts +53 -1
- package/dist/server/server.d.ts.map +1 -1
- package/dist/shared/events/capability.d.ts +25 -0
- package/dist/shared/events/capability.d.ts.map +1 -0
- package/dist/shared/events/constants.d.ts +53 -0
- package/dist/shared/events/constants.d.ts.map +1 -0
- package/dist/shared/events/index.d.ts +7 -0
- package/dist/shared/events/index.d.ts.map +1 -0
- package/dist/shared/events/schemas.d.ts +356 -0
- package/dist/shared/events/schemas.d.ts.map +1 -0
- package/dist/shared/events/types.d.ts +37 -0
- package/dist/shared/events/types.d.ts.map +1 -0
- package/dist/shared/events/webhook-url.d.ts +59 -0
- package/dist/shared/events/webhook-url.d.ts.map +1 -0
- package/dist/shared/events/webhook.d.ts +60 -0
- package/dist/shared/events/webhook.d.ts.map +1 -0
- package/package.json +8 -7
|
@@ -1414,6 +1414,176 @@ const server = new MCPServer({
|
|
|
1414
1414
|
|
|
1415
1415
|
Link a tool to its app resource by setting `mcp._meta.ui.resourceUri` in `createTool()` to the matching `ui://` URI. The server normalizes this metadata for older hosts when listing tools, and returns the same link on successful tool call results. Visit [MCP Apps](https://mastra.ai/docs/connections/mcp) for the full app bridge API and usage patterns.
|
|
1416
1416
|
|
|
1417
|
+
## Events (experimental)
|
|
1418
|
+
|
|
1419
|
+
> **Warning:** Events implement [SEP-3415](https://github.com/modelcontextprotocol/modelcontextprotocol/pull/3415), a draft MCP extension. The wire format and this API may change in any release.
|
|
1420
|
+
|
|
1421
|
+
For an end-to-end walkthrough, see the [MCP events guide](https://mastra.ai/docs/guides/mcp-events).
|
|
1422
|
+
|
|
1423
|
+
The `events` option lets clients subscribe to things that happen on your server, such as a ticket being created or a build finishing. The server advertises the `io.modelcontextprotocol/events` extension and answers `events/list`, `events/poll` and `events/stream` over both stdio and Streamable HTTP. With [`eventsOptions.webhook`](#webhook-delivery) set, it also answers `events/subscribe` and `events/unsubscribe` and POSTs occurrences to client webhook URLs.
|
|
1424
|
+
|
|
1425
|
+
Declare each event type with `defineEvent()` and publish occurrences with `server.events.emit()`:
|
|
1426
|
+
|
|
1427
|
+
```typescript
|
|
1428
|
+
import { MCPServer, defineEvent } from '@mastra/mcp'
|
|
1429
|
+
import { z } from 'zod'
|
|
1430
|
+
|
|
1431
|
+
const server = new MCPServer({
|
|
1432
|
+
id: 'tickets',
|
|
1433
|
+
name: 'Tickets',
|
|
1434
|
+
version: '1.0.0',
|
|
1435
|
+
tools: {},
|
|
1436
|
+
events: {
|
|
1437
|
+
'ticket.created': defineEvent({
|
|
1438
|
+
description: 'A ticket was created',
|
|
1439
|
+
inputSchema: z.object({ project: z.string().optional() }),
|
|
1440
|
+
payloadSchema: z.object({ id: z.string(), project: z.string() }),
|
|
1441
|
+
match: (args, data) => !args.project || data.project === args.project,
|
|
1442
|
+
}),
|
|
1443
|
+
},
|
|
1444
|
+
})
|
|
1445
|
+
|
|
1446
|
+
await server.events.emit('ticket.created', { id: 't-1', project: 'web' })
|
|
1447
|
+
```
|
|
1448
|
+
|
|
1449
|
+
A client that subscribed with `{ project: 'web' }` receives this occurrence. A client that subscribed with `{ project: 'api' }` doesn't.
|
|
1450
|
+
|
|
1451
|
+
`match` filters on the arguments the client chooses, so it doesn't control who can subscribe. To restrict callers, add `authorize`. It receives the validated arguments and the caller's `requestContext`, which includes `user` when you set `mapAuthInfoToUser`:
|
|
1452
|
+
|
|
1453
|
+
```typescript
|
|
1454
|
+
const ticketCreated = defineEvent({
|
|
1455
|
+
inputSchema: z.object({ project: z.string() }),
|
|
1456
|
+
payloadSchema: z.object({ id: z.string(), project: z.string() }),
|
|
1457
|
+
match: (args, data) => data.project === args.project,
|
|
1458
|
+
authorize: ({ arguments: args, requestContext }) => {
|
|
1459
|
+
const user = requestContext.get('user') as { projects: string[] } | undefined
|
|
1460
|
+
return user?.projects.includes(args.project) ?? false
|
|
1461
|
+
},
|
|
1462
|
+
})
|
|
1463
|
+
```
|
|
1464
|
+
|
|
1465
|
+
`authorize` runs on every `events/poll`, every `events/stream` open, and every webhook `events/subscribe`, including refreshes. An open stream isn't checked again until it reconnects, and a webhook subscription until its next refresh. A caller who loses access keeps receiving occurrences until then. FGA isn't applied to events; use `authorize` to restrict them.
|
|
1466
|
+
|
|
1467
|
+
### `defineEvent()` options
|
|
1468
|
+
|
|
1469
|
+
**description** (`string`): Description returned by events/list.
|
|
1470
|
+
|
|
1471
|
+
**inputSchema** (`StandardSchemaWithJSON`): Schema for the subscription arguments. Advertised as JSON Schema. Arguments that fail validation are rejected with error -32602, and match and poll receive the parsed value.
|
|
1472
|
+
|
|
1473
|
+
**payloadSchema** (`StandardSchemaWithJSON`): Schema for the event data. Advertised as JSON Schema and enforced by server.events.emit().
|
|
1474
|
+
|
|
1475
|
+
**match** (`(args, data) => boolean`): Decides whether an emitted event reaches a subscription with these arguments. Applies to push streams and to polls served from the buffer. Defaults to delivering every event.
|
|
1476
|
+
|
|
1477
|
+
**authorize** (`(context) => boolean | Promise<boolean>`): Decides whether the caller may receive this type with these arguments. Receives arguments, requestContext and delivery ('poll', 'push' or 'webhook'). Runs on every events/poll, before a poll source is called, on every events/stream open, and on every webhook events/subscribe, including refreshes. Returning false rejects the request with -32024. A refresh that is denied also removes the webhook subscription. If it throws, the client gets a generic -32603 error and the details are logged on the server. Defaults to allowing every caller.
|
|
1478
|
+
|
|
1479
|
+
**poll** (`(context) => Promise<MCPServerEventPollResult>`): Pull source for events/poll. Receives arguments, cursor (null means start from now), maxEvents, maxAgeMs, requestContext and signal. Returns { events, cursor, hasMore?, nextPollMs?, truncated? }. Each event needs data and a stable eventId (clients dedupe by it, so return the same id whenever the same occurrence is polled); a missing timestamp defaults to now. If poll or match throws, the client gets a generic -32603 error and the details are logged on the server.
|
|
1480
|
+
|
|
1481
|
+
**delivery** (`Array<'poll' | 'push' | 'webhook'>`): Restricts the advertised delivery modes to this list. It only narrows the modes from the table below, and a definition left with no mode throws when the server is constructed.
|
|
1482
|
+
|
|
1483
|
+
**bufferSize** (`number`): Number of emitted events kept in memory for replay and buffered polls. (Default: `1000`)
|
|
1484
|
+
|
|
1485
|
+
**pollIntervalMs** (`number`): nextPollMs suggested to clients that poll the buffer.
|
|
1486
|
+
|
|
1487
|
+
### Delivery modes
|
|
1488
|
+
|
|
1489
|
+
How a type is served depends on where its events come from:
|
|
1490
|
+
|
|
1491
|
+
| Definition | Advertised `delivery` | Source |
|
|
1492
|
+
| ---------- | ------------------------------------------------------------------------ | -------------------------------------------------------- |
|
|
1493
|
+
| No `poll` | `['push', 'poll']`, plus `'webhook'` when `eventsOptions.webhook` is set | `server.events.emit()`. Polls read the in-memory buffer. |
|
|
1494
|
+
| `poll` | `['poll']` | Your `poll` function, called for each `events/poll`. |
|
|
1495
|
+
|
|
1496
|
+
A type with a `poll` source can't also be pushed: `delivery` can't add `'push'` to it, and `server.events.emit()` throws for it. The advertised modes never change after the server starts, because clients only learn them from `events/list`. To push events, define a type without `poll` and emit to it.
|
|
1497
|
+
|
|
1498
|
+
A request for a mode the type doesn't advertise fails with `-32026`. An unknown event name fails with `-32023`.
|
|
1499
|
+
|
|
1500
|
+
### Push streams
|
|
1501
|
+
|
|
1502
|
+
Each `events/stream` request is one subscription. The server sends `notifications/events/active` first, then one `notifications/events/event` per matching occurrence. Every notification carries the request id as `_meta["io.modelcontextprotocol/subscriptionId"]`. When the request includes a `cursor`, buffered events after it are replayed before live ones. If that cursor is older than the buffer, `active` reports `truncated: true`.
|
|
1503
|
+
|
|
1504
|
+
When no other message has been sent for `heartbeatIntervalMs`, the stream sends `notifications/events/heartbeat` with the current cursor. Cancelling the request, or calling `server.close()`, ends the stream and releases its listener and timer.
|
|
1505
|
+
|
|
1506
|
+
### `eventsOptions`
|
|
1507
|
+
|
|
1508
|
+
**heartbeatIntervalMs** (`number`): Longest gap between messages on a push stream. (Default: `30000`)
|
|
1509
|
+
|
|
1510
|
+
**listPageSize** (`number`): Number of event types per events/list page. (Default: `100`)
|
|
1511
|
+
|
|
1512
|
+
**maxStreams** (`number`): Most push streams open at once across all clients. Further events/stream requests are rejected with -32025 until one closes. A Mastra client retries the rejection when reconnecting an established subscription; a new subscribe() call rejects with it. (Default: `1024`)
|
|
1513
|
+
|
|
1514
|
+
**webhook** (`MCPServerWebhookOptions`): Enables webhook delivery for event types without a poll source. Without it, the server doesn't advertise webhook or answer events/subscribe.
|
|
1515
|
+
|
|
1516
|
+
### Webhook delivery
|
|
1517
|
+
|
|
1518
|
+
With `eventsOptions.webhook` set, a client can register a callback URL with `events/subscribe`, and the server POSTs each matching occurrence to it, signed with the client's secret using [Standard Webhooks](https://www.standardwebhooks.com/) HMAC-SHA256.
|
|
1519
|
+
|
|
1520
|
+
```typescript
|
|
1521
|
+
const server = new MCPServer({
|
|
1522
|
+
id: 'tickets',
|
|
1523
|
+
name: 'Tickets',
|
|
1524
|
+
version: '1.0.0',
|
|
1525
|
+
tools: {},
|
|
1526
|
+
events: {
|
|
1527
|
+
'ticket.created': defineEvent({ payloadSchema: z.object({ id: z.string() }) }),
|
|
1528
|
+
},
|
|
1529
|
+
eventsOptions: {
|
|
1530
|
+
webhook: { ttl: { defaultMs: 30 * 60_000 } },
|
|
1531
|
+
},
|
|
1532
|
+
})
|
|
1533
|
+
```
|
|
1534
|
+
|
|
1535
|
+
The server enforces these rules:
|
|
1536
|
+
|
|
1537
|
+
- **Authentication:** Webhook subscriptions need an authenticated caller. Without `authInfo` on the request, `events/subscribe` fails with `-32024`. A subscription is identified by the caller, the URL, the event name, and the arguments, so repeating `events/subscribe` refreshes the same subscription and returns the same `id`.
|
|
1538
|
+
- **Authorization:** `authorize` runs on each subscribe and each refresh. When it denies a refresh, the subscription is removed and no further occurrences are POSTed. A Mastra client can't tell this `-32024` from the one for an unauthenticated caller, so in its default delivery mode it reports `MCP_EVENTS_WEBHOOK_UNAVAILABLE`, tries push, and then rejects with the same `-32024`.
|
|
1539
|
+
- **Callback URLs:** The URL must use `https`. Every address it resolves to must be publicly routable: loopback, private, link-local, and other special-purpose ranges are rejected with `-32602` and `data.reason`. The check runs again before every delivery, and the request connects to the address that passed, to prevent DNS rebinding. Redirects are never followed.
|
|
1540
|
+
- **Verification:** Before the first delivery to a URL, the server POSTs a signed verification challenge, and the endpoint must echo it. A failed or unreachable endpoint fails `events/subscribe` with `-32027` and a `data.reason` such as `challenge_failed` or `timeout`. The result is cached per caller and URL. URLs accepted by `allowedUrls` skip this step.
|
|
1541
|
+
- **Lifetime:** Each subscription expires at the returned `refreshBefore` time unless the client refreshes it. A requested `ttlMs` is clamped to the `ttl` bounds.
|
|
1542
|
+
- **Retries:** Each occurrence is retried with exponential backoff until it's acknowledged with a `2xx`, `retry.maxAttempts` is reached, or `retry.maxWindowMs` has passed. A `410` or `413` response stops retries for that occurrence. The `cursor` in each body only advances past occurrences that are acknowledged or given up on.
|
|
1543
|
+
- **Suspension:** When most deliveries to a subscription fail over `suspend.windowMs`, the server pauses it and reports `active: false` in `deliveryStatus` on the next refresh. The refresh resumes delivery.
|
|
1544
|
+
- **Errors:** Clients only see a failure category such as `timeout` or `http_5xx`, never the endpoint's response body or headers.
|
|
1545
|
+
|
|
1546
|
+
**ttl** (`{ defaultMs?: number; minMs?: number; maxMs?: number }`): Subscription lifetime granted when the client omits ttlMs, and the bounds a requested ttlMs is clamped to. Defaults to 30 minutes, 60 seconds, and 24 hours.
|
|
1547
|
+
|
|
1548
|
+
**allowNoExpiry** (`boolean`): Grants ttlMs: null requests a subscription that never expires. Otherwise they get ttl.maxMs. Only enable it with a durable store, because clients with no-expiry subscriptions don't need to refresh after a server restart. (Default: `false`)
|
|
1549
|
+
|
|
1550
|
+
**store** (`WebhookSubscriptionStore`): Stores subscription records (identity, secret, expiry) with async get, set, delete, and list methods. The default keeps them in memory, so subscriptions are lost on restart until clients refresh. (Default: `InMemoryWebhookSubscriptionStore`)
|
|
1551
|
+
|
|
1552
|
+
**url** (`{ allowPrivate?: boolean; allowInsecure?: boolean; lookup?: WebhookLookup }`): Callback URL policy. allowPrivate accepts non-public addresses and allowInsecure accepts http. Use them for local development only. lookup replaces DNS resolution.
|
|
1553
|
+
|
|
1554
|
+
**allowedUrls** (`(url: URL) => boolean`): Returns true for URLs you trust, which then skip the verification challenge.
|
|
1555
|
+
|
|
1556
|
+
**verificationTtlMs** (`number`): How long a successful verification is remembered for a caller and URL. (Default: `86400000`)
|
|
1557
|
+
|
|
1558
|
+
**timeoutMs** (`number`): Timeout for each delivery attempt. (Default: `5000`)
|
|
1559
|
+
|
|
1560
|
+
**retry** (`{ maxAttempts?: number; initialDelayMs?: number; maxDelayMs?: number; maxWindowMs?: number }`): Retry policy for each occurrence. Defaults to 5 attempts, a 1 second initial delay, a 5 minute maximum delay, and a 15 minute window. Time spent suspended doesn't count against the window.
|
|
1561
|
+
|
|
1562
|
+
**suspend** (`{ windowMs?: number; minAttempts?: number; failureRate?: number }`): Suspends a subscription when at least failureRate of at least minAttempts attempts fail within windowMs. Defaults to 0.95, 100, and 60 minutes.
|
|
1563
|
+
|
|
1564
|
+
**maxPending** (`number`): Undelivered occurrences kept per subscription. On overflow the oldest are dropped and the client receives a gap body, so it reports truncated: true. (Default: `1000`)
|
|
1565
|
+
|
|
1566
|
+
**maxSubscriptions** (`number`): Most webhook subscriptions this process keeps across all callers. New subscriptions past the limit are rejected with -32025, and a Mastra client falls back to push or poll unless it forced webhook delivery. Refreshing an existing subscription still works. (Default: `1000`)
|
|
1567
|
+
|
|
1568
|
+
**maxSubscriptionsPerPrincipal** (`number`): Most webhook subscriptions one authenticated caller can hold. (Default: `100`)
|
|
1569
|
+
|
|
1570
|
+
**secretGraceMs** (`number`): After a client rotates its secret, deliveries are signed with both secrets for this long. (Default: `300000`)
|
|
1571
|
+
|
|
1572
|
+
**transport** (`WebhookTransport`): Replaces the HTTP client that sends deliveries, for example in tests.
|
|
1573
|
+
|
|
1574
|
+
### `server.events.emit(name, data, options?)`
|
|
1575
|
+
|
|
1576
|
+
Records an occurrence, delivers it to matching push streams and webhook subscriptions, and returns it with its `eventId`, `timestamp` and `cursor`. `options.eventId` and `options.timestamp` override the defaults (a random UUID and the current time). It throws when `name` isn't configured, when `data` fails `payloadSchema`, or when the type has a `poll` source.
|
|
1577
|
+
|
|
1578
|
+
`server.events.list()` returns the descriptors `events/list` serves.
|
|
1579
|
+
|
|
1580
|
+
### Limits
|
|
1581
|
+
|
|
1582
|
+
- Emitted events stay in the process that emitted them. Push streams, webhook subscriptions, and buffered polls only see events emitted by the same `MCPServer` instance, so a serverless or multi-instance deployment needs a `poll` source backed by shared storage.
|
|
1583
|
+
- The buffer is in memory. A restarted server treats earlier cursors as a gap and reports `truncated: true`.
|
|
1584
|
+
- Webhook delivery state (pending retries, suspension, verification results) is in memory and rebuilt when clients refresh.
|
|
1585
|
+
- Changes to the list of event types aren't announced yet. The server doesn't advertise `listChanged` or send `notifications/events/list_changed`, because the MCP TypeScript SDK 2.2.0 doesn't carry the `eventsListChanged` filter on `subscriptions/listen`. Clients should re-run `events/list` to see changed event types.
|
|
1586
|
+
|
|
1417
1587
|
## Related information
|
|
1418
1588
|
|
|
1419
1589
|
- For connecting to MCP servers in Mastra, see the [MCPClient documentation](https://mastra.ai/reference/tools/mcp-client).
|