@mastra/mcp-docs-server 1.1.42 → 1.1.43-alpha.0

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.
Files changed (32) hide show
  1. package/.docs/docs/agents/acp.md +21 -158
  2. package/.docs/docs/agents/processors.md +143 -0
  3. package/.docs/docs/agents/signals.md +229 -9
  4. package/.docs/docs/build-with-ai/skills.md +3 -3
  5. package/.docs/docs/editor/overview.md +11 -10
  6. package/.docs/docs/getting-started/build-with-ai.md +37 -0
  7. package/.docs/docs/mastra-platform/observability.md +4 -4
  8. package/.docs/docs/memory/multi-user-threads.md +1 -1
  9. package/.docs/docs/memory/working-memory.md +27 -0
  10. package/.docs/docs/observability/metrics/querying.md +1 -1
  11. package/.docs/docs/server/pubsub.md +124 -0
  12. package/.docs/docs/studio/auth.md +20 -0
  13. package/.docs/reference/acp/acp-agent.md +228 -0
  14. package/.docs/reference/acp/create-acp-tool.md +131 -0
  15. package/.docs/reference/agents/agent.md +51 -1
  16. package/.docs/reference/agents/durable-agent.md +239 -0
  17. package/.docs/reference/cli/mastra.md +5 -5
  18. package/.docs/reference/client-js/agents.md +41 -7
  19. package/.docs/reference/index.md +9 -0
  20. package/.docs/reference/processors/response-cache.md +2 -2
  21. package/.docs/reference/pubsub/base.md +168 -0
  22. package/.docs/reference/pubsub/caching-pubsub.md +102 -0
  23. package/.docs/reference/pubsub/event-emitter.md +72 -0
  24. package/.docs/reference/pubsub/google-cloud-pubsub.md +94 -0
  25. package/.docs/reference/pubsub/redis-streams.md +108 -0
  26. package/.docs/reference/pubsub/unix-socket-pubsub.md +52 -0
  27. package/.docs/reference/storage/libsql.md +6 -0
  28. package/.docs/reference/storage/mongodb.md +3 -0
  29. package/.docs/reference/storage/postgresql.md +3 -0
  30. package/CHANGELOG.md +8 -0
  31. package/package.json +5 -5
  32. package/.docs/docs/agents/response-caching.md +0 -150
@@ -97,7 +97,7 @@ The behavior options are:
97
97
  - `ifIdle.behavior: 'persist'`: Save the signal or message to memory without starting a stream.
98
98
  - `ifIdle.behavior: 'discard'`: Ignore the signal or message while the thread is idle.
99
99
 
100
- Pass `ifIdle.streamOptions` when the idle wake-up stream needs options such as model settings, tools, or runtime context. You do not need to repeat `memory.resource` or `memory.thread`; Mastra uses the top-level `resourceId` and `threadId` for the thread.
100
+ Pass `ifIdle.streamOptions` when the idle wake-up stream needs options such as model settings, tools, or runtime context. You don't need to repeat `memory.resource` or `memory.thread`; Mastra uses the top-level `resourceId` and `threadId` for the thread.
101
101
 
102
102
  ```typescript
103
103
  agent.sendMessage('Continue with the next step.', {
@@ -143,6 +143,10 @@ The model receives the signal as context like this:
143
143
 
144
144
  Use XML-safe `tagName` and attribute names. They can contain letters, numbers, underscores, periods, and hyphens. They must start with a letter or underscore.
145
145
 
146
+ ### Storage support
147
+
148
+ Notification inbox storage is available in the storage adapters that support richer memory and signal workflows: [libSQL](https://mastra.ai/reference/storage/libsql), [PostgreSQL](https://mastra.ai/reference/storage/postgresql), and [MongoDB](https://mastra.ai/reference/storage/mongodb). These adapters expose notification records through `getStore('notifications')`.
149
+
146
150
  ## Send processor context
147
151
 
148
152
  Processors can send reactive signals during a run. A processor should inspect the chat history, react to a specific trigger, and avoid sending the same context more than once.
@@ -220,7 +224,224 @@ When the agent is idle:
220
224
  <user source="chat" delivery="new-message">Also cover the edge cases.</user>
221
225
  ```
222
226
 
223
- Top-level `attributes` always apply. The selected branch's `attributes` are merged into them at delivery time. The `delivery` name shown above is not a special Mastra API field. It is a custom attribute name used for this example, you can add any attribute names that suit your use case.
227
+ Top-level `attributes` always apply. The selected branch's `attributes` are merged into them at delivery time. The `delivery` name shown above isn't a special Mastra API field. It's a custom attribute name used for this example. Add any attribute names that suit your use case.
228
+
229
+ ## State signals
230
+
231
+ State signals expose named, thread-scoped context lanes. Use them for durable context that changes over time, such as browser state, editor state, or a background watcher result.
232
+
233
+ Each state signal needs:
234
+
235
+ - `id`: The state lane name, such as `browser`.
236
+ - `cacheKey`: A producer-owned key for deduping the current state.
237
+ - `mode`: `snapshot` for an authoritative state copy, or `delta` for a change event.
238
+
239
+ Use `sendStateSignal()` when an external producer detects a state change.
240
+
241
+ ```typescript
242
+ await agent.sendStateSignal(
243
+ {
244
+ id: 'browser',
245
+ mode: 'snapshot',
246
+ cacheKey: 'browser:https://example.com:3-tabs',
247
+ contents: 'Browser is open on https://example.com with 3 tabs.',
248
+ value: {
249
+ activeUrl: 'https://example.com',
250
+ tabCount: 3,
251
+ open: true,
252
+ },
253
+ },
254
+ {
255
+ resourceId: 'user_123',
256
+ threadId: 'thread_456',
257
+ },
258
+ )
259
+ ```
260
+
261
+ When Mastra accepts a state signal, it stores compact tracking metadata on the thread. The metadata records the lane's current `cacheKey`, current mode, version, last signal id, and last snapshot signal id. If a producer sends the same `cacheKey` and mode again while that state is still current, Mastra skips the duplicate.
262
+
263
+ State signal fields have separate roles:
264
+
265
+ - `contents`: The representation the model reads.
266
+ - `value`: The structured snapshot for `mode: 'snapshot'`.
267
+ - `delta`: The structured change for `mode: 'delta'`.
268
+ - `metadata.state`: The runtime tracking envelope with `id`, `mode`, `cacheKey`, `version`, and `threadId`.
269
+
270
+ Use `computeStateSignal()` when a processor owns a state lane. Mastra calls it once per model input step after `processInputStep()`. If the processor omits `id`, Mastra uses the processor id as the state lane id. Set `stateId` when the public state lane should differ from the processor id.
271
+
272
+ ```typescript
273
+ import type { ComputeStateSignalArgs, Processor } from '@mastra/core/processors'
274
+
275
+ export const browserStateProcessor: Processor = {
276
+ id: 'browser-state',
277
+ stateId: 'browser',
278
+ computeStateSignal(args: ComputeStateSignalArgs) {
279
+ const browser = readCurrentBrowserState()
280
+ const previous = readMostRecentBrowserState(args.activeStateSignals)
281
+ const changed = previous ? diffBrowserState(previous, browser) : browser
282
+ const shouldRefreshSnapshot = Boolean(args.lastSnapshot && !args.contextWindow.hasSnapshot)
283
+
284
+ if (previous && Object.keys(changed).length === 0 && !shouldRefreshSnapshot) {
285
+ return
286
+ }
287
+
288
+ const isDelta = Boolean(previous && !shouldRefreshSnapshot)
289
+
290
+ return {
291
+ mode: isDelta ? 'delta' : 'snapshot',
292
+ cacheKey: stableBrowserStateCacheKey(browser),
293
+ contents: isDelta ? describeBrowserDelta(changed) : describeBrowserSnapshot(browser),
294
+ value: browser,
295
+ ...(isDelta ? { delta: changed } : {}),
296
+ }
297
+ },
298
+ }
299
+ ```
300
+
301
+ Mastra passes `lastSnapshot` and `deltasSinceSnapshot` into `computeStateSignal()`. It resolves them from message history when the current message list doesn't contain the latest snapshot. The processor still owns merge and diff logic.
302
+
303
+ `contextWindow.hasSnapshot` tells the processor whether the active message window already contains a snapshot for this state lane. If it's `false`, return a fresh `snapshot` so the model sees the current state even after older state messages are trimmed from the context window.
304
+
305
+ The built-in browser context processor emits state under the `browser` id with snapshot and delta modes.
306
+
307
+ ## Notification signals
308
+
309
+ Notification signals represent external events such as GitHub activity, email, Slack mentions, CI status, incidents, recordings, or direct messages. Use `agent.sendNotificationSignal()` when the event should create a durable inbox record.
310
+
311
+ Notification delivery has two phases:
312
+
313
+ - **Ingress**: `agent.sendNotificationSignal()` stores a notification record, then resolves the agent's delivery policy.
314
+ - **Dispatch**: Mastra consumes due records stamped with `deliverAt` or `summaryAt` and emits full notification or summary signals.
315
+
316
+ A notification record stores the source, kind, priority, summary, payload, resource id, thread id, agent id, coalescing keys, and delivery metadata. The delivery decision controls what happens after ingress:
317
+
318
+ - `deliver` or `queue`: Emit a full `<notification>` signal and mark the record `delivered`.
319
+ - `defer`: Keep the record `pending` with `deliverAt`.
320
+ - `summarize`: Keep the record `pending` with `summaryAt`, or emit an immediate summary when the policy requests it.
321
+ - `persist`: Keep the record `pending` in the inbox without scheduled delivery.
322
+ - `discard`: Mark the record `discarded` and emit no signal.
323
+
324
+ The default delivery policy is priority-aware:
325
+
326
+ | Priority | Active thread | Idle thread |
327
+ | -------- | -------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- |
328
+ | `urgent` | Deliver a full notification immediately | Deliver a full notification immediately |
329
+ | `high` | Emit a summary immediately, keep `deliverAt`, then deliver the full notification when the thread is idle | Deliver a full notification immediately |
330
+ | `medium` | Batch with `summaryAt` and later deliver one notification summary | Deliver a full notification immediately |
331
+ | `low` | Batch with `summaryAt` and later deliver one notification summary | Batch with `summaryAt` and later deliver one notification summary without waking the model loop |
332
+
333
+ ```typescript
334
+ await agent.sendNotificationSignal(
335
+ {
336
+ source: 'github',
337
+ kind: 'ci-status',
338
+ priority: 'high',
339
+ summary: 'CI failed on main: 3 tests failed.',
340
+ payload: {
341
+ repository: 'acme/app',
342
+ branch: 'main',
343
+ },
344
+ dedupeKey: 'github:acme/app:main:ci',
345
+ },
346
+ {
347
+ resourceId: 'user_123',
348
+ threadId: 'thread_456',
349
+ },
350
+ )
351
+ ```
352
+
353
+ The model receives full notifications as context:
354
+
355
+ ```xml
356
+ <notification source="github" type="ci-status" priority="high" status="delivered">CI failed on main: 3 tests failed.</notification>
357
+ ```
358
+
359
+ Notification summaries tell the model that inbox records are waiting:
360
+
361
+ ```xml
362
+ <notification-summary pending="10">github: 3, email: 5, slack: 2</notification-summary>
363
+ ```
364
+
365
+ When Mastra emits a summary, it clears `summaryAt` and sets `summarySignalId` on each summarized record. The records stay pending and readable. When Mastra emits a full notification, it sets `deliveredSignalId` and marks the record `delivered`. If the inbox tool reads a notification first, it can inject the full notification signal and mark the record `seen`, which prevents duplicate full delivery.
366
+
367
+ Configure a delivery policy on the agent when some notifications should wait for a different dispatch window or summary rollup.
368
+
369
+ ```typescript
370
+ export const supportAgent = new Agent({
371
+ id: 'support-agent',
372
+ name: 'Support Agent',
373
+ instructions: 'Help the user triage updates.',
374
+ model: 'openai/gpt-5.5',
375
+ notifications: {
376
+ deliveryPolicy: {
377
+ priorities: {
378
+ urgent: 'deliver',
379
+ },
380
+ decide: ({ record }) => {
381
+ if (record.priority === 'low') {
382
+ return {
383
+ action: 'summarize',
384
+ summaryAt: new Date(Date.now() + 30 * 60 * 1000),
385
+ }
386
+ }
387
+ },
388
+ },
389
+ },
390
+ })
391
+ ```
392
+
393
+ Enable scheduled dispatch at the Mastra level so deferred notifications and summary rollups are delivered through the existing workflow scheduler.
394
+
395
+ ```typescript
396
+ export const mastra = new Mastra({
397
+ agents: { supportAgent },
398
+ storage,
399
+ notifications: {
400
+ dispatch: {
401
+ enabled: true,
402
+ cron: '*/1 * * * *',
403
+ batchSize: 100,
404
+ },
405
+ },
406
+ })
407
+ ```
408
+
409
+ `notifications.dispatch.enabled` registers an internal workflow with the default cron `*/1 * * * *`. The dispatcher reads due notification records from storage, groups summaries by `agentId`, `resourceId`, and `threadId`, and emits signals through the Agent thread runtime. It isn't a user-facing entrypoint.
410
+
411
+ ### Notification inbox tool
412
+
413
+ Use `createNotificationInboxTool()` to give agents one tool for inbox actions instead of many CRUD tools.
414
+
415
+ ```typescript
416
+ import { createNotificationInboxTool } from '@mastra/core/notifications'
417
+
418
+ const notificationsStorage = await storage.getStore('notifications')
419
+
420
+ export const supportAgent = new Agent({
421
+ id: 'support-agent',
422
+ name: 'Support Agent',
423
+ instructions: 'Help the user triage updates.',
424
+ model: 'openai/gpt-5.5',
425
+ tools: {
426
+ notificationInbox: createNotificationInboxTool({ storage: notificationsStorage }),
427
+ },
428
+ })
429
+ ```
430
+
431
+ The tool id is `notification-inbox`. It supports these actions:
432
+
433
+ - `list`: List notifications for the current thread.
434
+ - `read`: Deliver readable full notification signals into the chat when possible, then mark records `seen`.
435
+ - `markSeen`: Mark one record `seen`.
436
+ - `dismiss`: Mark one record `dismissed`.
437
+ - `archive`: Mark one record `archived`.
438
+ - `search`: Search notification summaries in the current thread.
439
+
440
+ The tool uses the current `threadId` from the tool execution context unless one is provided. Use `read` after a `<notification-summary>` signal when the agent needs the full records behind the summary. The `read` result reports how many notifications will be delivered; it doesn't use normal tool output as the main context channel for the notification contents.
441
+
442
+ `sendNotificationSignal()` requires a storage domain with `notifications` support. LibSQL supports notifications. Other storage adapters need matching notification domain support before they can store notification records.
443
+
444
+ Use `sendSignal({ type: 'notification' })` only for lower-level notification-shaped context that should bypass inbox storage.
224
445
 
225
446
  ## Compatibility
226
447
 
@@ -229,7 +450,7 @@ Mastra still accepts legacy signal payloads such as `type: 'user-message'` and `
229
450
  - `type: 'user-message'`: Normalizes to `type: 'user'` and `tagName: 'user'`
230
451
  - `type: 'system-reminder'`: Normalizes to `type: 'reactive'` and `tagName: 'system-reminder'`
231
452
 
232
- Existing stored signal rows and older clients continue to load through the compatibility layer.
453
+ Existing stored signal rows and older clients continue to load through the compatibility layer. New clients call the message routes when the server supports them; React's thread signal path falls back to the legacy `/signals` route when it detects an older server.
233
454
 
234
455
  > **Note:** Visit [Agent signals reference](https://mastra.ai/reference/agents/agent) for the full message, signal, and subscription types.
235
456
 
@@ -264,11 +485,8 @@ const subscription = await agent.subscribeToThread({
264
485
  threadId: 'thread_456',
265
486
  })
266
487
 
267
- await agent.sendSignal({
268
- signal: {
269
- type: 'user-message',
270
- contents: 'Show the shorter version.',
271
- },
488
+ await agent.sendMessage({
489
+ message: 'Show the shorter version.',
272
490
  resourceId: 'user_123',
273
491
  threadId: 'thread_456',
274
492
  })
@@ -307,7 +525,9 @@ Use heartbeats together with client-side reconnect logic. Heartbeats reduce idle
307
525
  - [`Agent.queueMessage()`](https://mastra.ai/reference/agents/agent)
308
526
  - [`Agent.sendSignal()`](https://mastra.ai/reference/agents/agent)
309
527
  - [`Agent.subscribeToThread()`](https://mastra.ai/reference/agents/agent)
310
- - [Server agent routes](https://mastra.ai/reference/server/routes)
528
+ - [`client.getAgent().sendMessage()`](https://mastra.ai/reference/client-js/agents)
529
+ - [`client.getAgent().queueMessage()`](https://mastra.ai/reference/client-js/agents)
311
530
  - [`client.getAgent().sendSignal()`](https://mastra.ai/reference/client-js/agents)
531
+ - [Server agent routes](https://mastra.ai/reference/server/routes)
312
532
  - [`client.getAgent().subscribeToThread()`](https://mastra.ai/reference/client-js/agents)
313
533
  - [`client.getAgent().sendToolApproval()`](https://mastra.ai/reference/client-js/agents)
@@ -32,6 +32,8 @@ bun x skills add mastra-ai/skills
32
32
 
33
33
  Mastra skills work with any coding agent that supports the [Skills standard](https://agentskills.io/), including Claude Code, Cursor, Codex, OpenCode, and others.
34
34
 
35
+ They're also available on [GitHub](https://github.com/mastra-ai/skills).
36
+
35
37
  ## Update skill
36
38
 
37
39
  To update to the latest version of the Mastra skill, run:
@@ -58,6 +60,4 @@ yarn dlx skills update mastra
58
60
 
59
61
  ```bash
60
62
  bun x skills update mastra
61
- ```
62
-
63
- They're also available on [GitHub](https://github.com/mastra-ai/skills).
63
+ ```
@@ -149,16 +149,17 @@ The `editor.agent` namespace also exposes `getById`, `list`, `listResolved`, and
149
149
 
150
150
  The same operations are available over HTTP through the Mastra server. Use these when you want to manage stored agents from a separate service or from a non-TypeScript client:
151
151
 
152
- | Method | Path | Description |
153
- | -------- | -------------------------------------- | ---------------------------------------------------------------- |
154
- | `GET` | `/stored/agents` | List all stored agents. |
155
- | `POST` | `/stored/agents` | Create a stored agent. |
156
- | `GET` | `/stored/agents/:storedAgentId` | Get a stored agent by ID. |
157
- | `PATCH` | `/stored/agents/:storedAgentId` | Update a stored agent. |
158
- | `DELETE` | `/stored/agents/:storedAgentId` | Delete a stored agent. |
159
- | `POST` | `/stored/agents/:storedAgentId/export` | Export a stored agent's override as a deterministic JSON config. |
160
-
161
- The export endpoint returns only the fields the agent's [`editor` config](https://mastra.ai/reference/agents/agent) allows, so the output matches the per-agent file the code source writes to disk. The Client SDK wraps these endpoints with `client.listStoredAgents()`, `client.createStoredAgent()`, `client.getStoredAgent()`, and `client.getStoredAgent(id).export()`. Version management endpoints live under `/stored/agents/:storedAgentId/versions`, see [version management](https://mastra.ai/reference/client-js/agents) for the full list.
152
+ | Method | Path | Description |
153
+ | -------- | ------------------------------------------ | ---------------------------------------------------------------- |
154
+ | `GET` | `/stored/agents` | List all stored agents. |
155
+ | `POST` | `/stored/agents` | Create a stored agent. |
156
+ | `GET` | `/stored/agents/:storedAgentId` | Get a stored agent by ID. |
157
+ | `PATCH` | `/stored/agents/:storedAgentId` | Update a stored agent. |
158
+ | `DELETE` | `/stored/agents/:storedAgentId` | Delete a stored agent. |
159
+ | `GET` | `/stored/agents/:storedAgentId/dependents` | List agents that reference this agent as a sub-agent. |
160
+ | `POST` | `/stored/agents/:storedAgentId/export` | Export a stored agent's override as a deterministic JSON config. |
161
+
162
+ The dependents endpoint helps warn before deleting or unsharing an agent that other agents depend on: `dependents` lists caller-readable agents by `id` and `name`, while `hiddenCount` aggregates cross-workspace references the caller cannot read (surfaced only when the target is public). The export endpoint returns only the fields the agent's [`editor` config](https://mastra.ai/reference/agents/agent) allows, so the output matches the per-agent file the code source writes to disk. The Client SDK wraps these endpoints with `client.listStoredAgents()`, `client.createStoredAgent()`, `client.getStoredAgent()`, `client.getStoredAgent(id).dependents()`, and `client.getStoredAgent(id).export()`. Version management endpoints live under `/stored/agents/:storedAgentId/versions`, see [version management](https://mastra.ai/reference/client-js/agents) for the full list.
162
163
 
163
164
  ### Automated experimentation
164
165
 
@@ -40,6 +40,43 @@ In addition to documentation access, the [MCP Docs Server](https://mastra.ai/doc
40
40
 
41
41
  Learn how to use the [MCP Docs Server](https://mastra.ai/docs/build-with-ai/mcp-docs-server).
42
42
 
43
+ ## Mastra CLI
44
+
45
+ The [Mastra CLI](https://mastra.ai/reference/cli/mastra) gives your coding agent a direct line to your Mastra runtime. Agents can invoke agents, run workflows, execute tools, inspect memory, run evals, and query traces and logs.
46
+
47
+ **npm**:
48
+
49
+ ```bash
50
+ npm install mastra@latest -g
51
+ ```
52
+
53
+ **pnpm**:
54
+
55
+ ```bash
56
+ pnpm add mastra@latest -g
57
+ ```
58
+
59
+ **Yarn**:
60
+
61
+ ```bash
62
+ yarn global add mastra@latest
63
+ ```
64
+
65
+ **Bun**:
66
+
67
+ ```bash
68
+ bun add mastra@latest --global
69
+ ```
70
+
71
+ For example, your coding agent can run an agent, then pull traces to inspect the results:
72
+
73
+ ```bash
74
+ mastra api --url http://localhost:4111 agent run weather-agent '{"messages":"What is the weather in London?"}'
75
+ mastra api --url http://localhost:4111 trace list
76
+ ```
77
+
78
+ See the [CLI commands reference](https://mastra.ai/reference/cli/mastra) for the full list of available commands.
79
+
43
80
  ## Embedded package docs
44
81
 
45
82
  Mastra packages ship with embedded documentation in `dist/docs`. When you install a Mastra package, your AI agent can read these files directly from `node_modules` to understand the package's APIs and patterns.
@@ -105,25 +105,25 @@ After your project is publishing traces, logs, or scores to Mastra Platform Obse
105
105
  **npm**:
106
106
 
107
107
  ```bash
108
- npx mastra api trace list --pretty
108
+ npx mastra api trace list
109
109
  ```
110
110
 
111
111
  **pnpm**:
112
112
 
113
113
  ```bash
114
- pnpm dlx mastra api trace list --pretty
114
+ pnpm dlx mastra api trace list
115
115
  ```
116
116
 
117
117
  **Yarn**:
118
118
 
119
119
  ```bash
120
- yarn dlx mastra api trace list --pretty
120
+ yarn dlx mastra api trace list
121
121
  ```
122
122
 
123
123
  **Bun**:
124
124
 
125
125
  ```bash
126
- bun x mastra api trace list --pretty
126
+ bun x mastra api trace list
127
127
  ```
128
128
 
129
129
  For observability commands, the CLI targets the hosted observability API and can infer credentials from your project environment. See the [`mastra api` CLI reference](https://mastra.ai/reference/cli/mastra) for available observability commands, filtering, pagination, credential resolution, and direct `curl` examples.
@@ -135,7 +135,7 @@ const memory = new Memory({
135
135
 
136
136
  The model reads identity from the `<turn>` tag on the current message and from prior tagged messages brought back through `lastMessages`.
137
137
 
138
- ### With observational memory (recommended)
138
+ ### With Observational Memory (recommended)
139
139
 
140
140
  [Observational Memory](https://mastra.ai/docs/memory/observational-memory) (OM) extracts per-user facts into a background log without burning the agent's tool budget. The default Observer model reads `<turn>` tags natively and produces named attribution like `Alice stated her favorite color is teal.` and `Bob asked for QA sign-off before publish.`
141
141
 
@@ -393,6 +393,33 @@ const response = await agent.generate('What do you know about me?', {
393
393
  })
394
394
  ```
395
395
 
396
+ ## Opt in to state signals (experimental)
397
+
398
+ By default, working memory reaches the model as part of the system message. You can opt into delivering it as a [state signal](https://mastra.ai/docs/agents/signals) instead by setting `useStateSignals: true`:
399
+
400
+ ```typescript
401
+ const memory = new Memory({
402
+ storage: new LibSQLStore({ url: 'file:./mastra.db' }),
403
+ options: {
404
+ workingMemory: {
405
+ enabled: true,
406
+ template: '# User\n- name:\n- location:',
407
+ useStateSignals: true, // experimental: deliver as state signal
408
+ },
409
+ },
410
+ })
411
+ ```
412
+
413
+ What changes:
414
+
415
+ - **Storage is identical.** The same resource/thread `workingMemory` field is read and written.
416
+ - **The tool is the same shape, exposed under a new name.** Writes still flow through the same underlying tool; on this path it is registered as `setWorkingMemory` (instead of `updateWorkingMemory`). The rename keeps legacy strip filters from removing tool-call parts so they persist as a normal audit trail and the next model step picks the new value up automatically.
417
+ - **Delivery only.** Instead of folding into the system prompt, `Memory` auto-attaches a `WorkingMemoryStateProcessor` that emits the current working memory as a `state` signal with `stateId: 'working-memory'`.
418
+
419
+ You inherit the standard state-signal benefits: thread-scoped tracking metadata, `cacheKey` dedup so identical snapshots are only emitted once, and `contextWindow.hasSnapshot` re-injection when an older snapshot rolls out of the window.
420
+
421
+ The default (`useStateSignals: false`) keeps the existing system-message behavior unchanged. `useStateSignals` is not supported with template working memory `version: 'vnext'`.
422
+
396
423
  ## Examples
397
424
 
398
425
  - [Working memory with template](https://github.com/mastra-ai/mastra/tree/main/examples/memory-with-template)
@@ -78,7 +78,7 @@ The `@mastra/client-js` SDK wraps the same routes as `mastraClient.getMetricAggr
78
78
  ```bash
79
79
  mastra api metric aggregate \
80
80
  '{"name":["mastra_agent_duration_ms"],"aggregation":"avg"}' \
81
- --url http://localhost:4111 --pretty
81
+ --url http://localhost:4111
82
82
  ```
83
83
 
84
84
  By default the CLI targets hosted Mastra observability (`https://observability.mastra.ai`). Pass `--url http://localhost:4111` to query a local `mastra dev` server. See [`mastra api metric aggregate`](https://mastra.ai/reference/cli/mastra) and the surrounding entries for the full command list.
@@ -0,0 +1,124 @@
1
+ # PubSub
2
+
3
+ Mastra uses a publish/subscribe (pub/sub) system as its internal event bus. Components publish events to named topics, and other components subscribe to those topics to react. The backend you configure decides how far those events travel: within one process, across processes on one host, or across separate instances.
4
+
5
+ You set the backend once on the `Mastra` instance, and the rest of the system uses it without changes. By default, Mastra uses an in-process backend that needs no setup.
6
+
7
+ ## How Mastra uses PubSub
8
+
9
+ Several built-in systems publish and subscribe to events through the same pub/sub bus:
10
+
11
+ - **Workflow execution**: The scheduler publishes a `workflow.start` event, and a long-lived worker consumes it to run the workflow. Step and lifecycle events flow over pub/sub during execution.
12
+ - **Scheduled workflows**: The scheduler dispatches due runs by publishing to the workflow topic. See [Scheduled workflows](https://mastra.ai/docs/workflows/scheduled-workflows).
13
+ - **Background tasks**: A task manager dispatches work to a worker group and fans task lifecycle updates out to subscribers, which is how background task streams stay live. See [Background task streaming](https://mastra.ai/docs/streaming/background-task-streaming).
14
+ - **Agent signals**: Sending a signal to an active agent run publishes an event on a thread topic, so a run executing in another process receives the signal.
15
+ - **Resumable streams**: Stream chunks are published per run, so a client that reconnects can replay what it missed.
16
+
17
+ Because these systems run on one bus, the backend you choose applies to all of them at once.
18
+
19
+ ## Delivery modes
20
+
21
+ Backends deliver events in one of two modes, defined by the [`PubSub`](https://mastra.ai/reference/pubsub/base) contract:
22
+
23
+ - **Pull**: Consumers read from the backend on their own, which Mastra does with a long-lived worker loop. Distributed backends such as [`RedisStreamsPubSub`](https://mastra.ai/reference/pubsub/redis-streams) use this mode.
24
+ - **Push**: Events arrive without the consumer asking, either in process or over HTTP. The default [`EventEmitterPubSub`](https://mastra.ai/reference/pubsub/event-emitter) delivers this way in process.
25
+
26
+ Subscribers can also opt into work distribution. A group of subscribers that share a consumer group split the events between them, so each event is handled once. Subscribers without a group each receive every event, which fans the stream out to all of them.
27
+
28
+ ## Default backend
29
+
30
+ When you do not set the `pubsub` option, Mastra uses [`EventEmitterPubSub`](https://mastra.ai/reference/pubsub/event-emitter). It delivers events in process using a Node.js [`EventEmitter`](https://nodejs.org/api/events.html#class-eventemitter), so it works without any external service.
31
+
32
+ ```typescript
33
+ import { Mastra } from '@mastra/core'
34
+
35
+ // No pubsub option: Mastra uses EventEmitterPubSub
36
+ export const mastra = new Mastra({})
37
+ ```
38
+
39
+ Because it runs in process, events are not persisted and do not reach other processes. The default suits a single instance, which covers most applications.
40
+
41
+ ## Choosing a backend
42
+
43
+ Set the `pubsub` option on the `Mastra` instance to choose a backend. Each backend implements the same [`PubSub`](https://mastra.ai/reference/pubsub/base) contract, so the rest of your application does not change.
44
+
45
+ The deciding question is where the subscriber runs.
46
+
47
+ | Backend | Scope | Mode | Package |
48
+ | ----------------------------------------------------------------------------- | ---------------------------- | ------------- | ----------------------------- |
49
+ | [`EventEmitterPubSub`](https://mastra.ai/reference/pubsub/event-emitter) | Single process | Pull and push | `@mastra/core` |
50
+ | [`UnixSocketPubSub`](https://mastra.ai/reference/pubsub/unix-socket-pubsub) | Multiple processes, one host | Push | `@mastra/core` |
51
+ | [`RedisStreamsPubSub`](https://mastra.ai/reference/pubsub/redis-streams) | Distributed, multiple hosts | Pull | `@mastra/redis-streams` |
52
+ | [`GoogleCloudPubSub`](https://mastra.ai/reference/pubsub/google-cloud-pubsub) | Distributed, multiple hosts | Pull | `@mastra/google-cloud-pubsub` |
53
+
54
+ ### Multiple processes on one host
55
+
56
+ Use [`UnixSocketPubSub`](https://mastra.ai/reference/pubsub/unix-socket-pubsub) when several processes on the same machine need to share a stream. It delivers events over a Unix domain socket and elects one process as a broker. If the broker exits, the remaining processes elect a new one.
57
+
58
+ ```typescript
59
+ import { Mastra } from '@mastra/core'
60
+ import { UnixSocketPubSub } from '@mastra/core/events'
61
+
62
+ export const mastra = new Mastra({
63
+ pubsub: new UnixSocketPubSub('/tmp/mastra/events.sock'),
64
+ })
65
+ ```
66
+
67
+ ### Distributed deployments
68
+
69
+ Use a distributed backend when you run more than one instance or host, so every instance receives the same events. This matters whenever a request handled by one instance must reach work running on another. For example, sending a signal to an agent run requires the signal event to cross the process boundary to the instance that owns the run. With the in-process default, that instance never receives the event.
70
+
71
+ Both backends below deliver across processes and hosts and persist events for redelivery.
72
+
73
+ The following example uses [Redis Streams](https://redis.io/docs/latest/develop/data-types/streams/):
74
+
75
+ ```typescript
76
+ import { Mastra } from '@mastra/core'
77
+ import { RedisStreamsPubSub } from '@mastra/redis-streams'
78
+
79
+ export const mastra = new Mastra({
80
+ pubsub: new RedisStreamsPubSub({
81
+ url: 'redis://localhost:6379',
82
+ }),
83
+ })
84
+ ```
85
+
86
+ The following example uses [Google Cloud Pub/Sub](https://cloud.google.com/pubsub/docs):
87
+
88
+ ```typescript
89
+ import { Mastra } from '@mastra/core'
90
+ import { GoogleCloudPubSub } from '@mastra/google-cloud-pubsub'
91
+
92
+ export const mastra = new Mastra({
93
+ pubsub: new GoogleCloudPubSub({
94
+ projectId: 'my-project',
95
+ }),
96
+ })
97
+ ```
98
+
99
+ ## Resumable streams
100
+
101
+ Resumable streams let a client reconnect and replay events it missed, which requires the backend to keep recent history. Distributed backends such as [`RedisStreamsPubSub`](https://mastra.ai/reference/pubsub/redis-streams) persist events, so they support replay on their own.
102
+
103
+ In-process delivery does not keep history. To add replay on top of [`EventEmitterPubSub`](https://mastra.ai/reference/pubsub/event-emitter), wrap it in [`CachingPubSub`](https://mastra.ai/reference/pubsub/caching-pubsub), which records published events per topic so a late or reconnecting subscriber can catch up before continuing with live events.
104
+
105
+ ```typescript
106
+ import { Mastra } from '@mastra/core'
107
+ import { CachingPubSub, EventEmitterPubSub } from '@mastra/core/events'
108
+ import { InMemoryServerCache } from '@mastra/core/cache'
109
+
110
+ const cache = new InMemoryServerCache()
111
+
112
+ export const mastra = new Mastra({
113
+ pubsub: new CachingPubSub(new EventEmitterPubSub(), cache),
114
+ })
115
+ ```
116
+
117
+ > **Note:** Visit the [PubSub reference](https://mastra.ai/reference/pubsub/base) for the full delivery contract and the configuration options for each backend.
118
+
119
+ ## Related
120
+
121
+ - [PubSub reference](https://mastra.ai/reference/pubsub/base)
122
+ - [Mastra class](https://mastra.ai/reference/core/mastra-class)
123
+ - [Background task streaming](https://mastra.ai/docs/streaming/background-task-streaming)
124
+ - [Scheduled workflows](https://mastra.ai/docs/workflows/scheduled-workflows)
@@ -46,6 +46,26 @@ Setting [`server.auth`](https://mastra.ai/reference/configuration) does two thin
46
46
 
47
47
  Studio detects available capabilities by calling the `GET /api/auth/capabilities` endpoint. The response tells Studio which login methods to render and, if the user is already authenticated, includes their user info and permissions.
48
48
 
49
+ ## Pass a token through the URL
50
+
51
+ When another application embeds or links to Studio, it can hand over an authorization token through the `auth_header` URL parameter. This is useful when an external host already holds a token and wants to open an authenticated Studio session without showing the login screen.
52
+
53
+ The `auth_header` value always populates the `Authorization` request header. The parameter sets that one header only, so include any scheme prefix the server expects in the value, such as `Bearer`.
54
+
55
+ Open Studio with the token in the query string:
56
+
57
+ ```text
58
+ https://your-studio-host/?auth_header=Bearer%20your-token
59
+ ```
60
+
61
+ Studio handles the token as follows:
62
+
63
+ - It reads `auth_header` once on load and sends the value as the `Authorization` header on every API request in that session.
64
+ - It removes `auth_header` from the address bar while preserving other query parameters and the hash.
65
+ - It keeps the token in memory only and never writes it to local storage, so the token stays transient and does not persist across page reloads.
66
+
67
+ The token rides in a URL parameter, so the host application is responsible for how that URL is generated and transmitted. URL parameters can be exposed through browser history, referrer headers, and server access logs.
68
+
49
69
  ## Role-based access control
50
70
 
51
71
  RBAC lets you control what each user can see and do inside Studio. It's separate from authentication: `server.auth` handles who the user is, while `server.rbac` handles what they can do.