@mastra/mcp-docs-server 1.1.33-alpha.4 → 1.1.33-alpha.6
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/.docs/docs/agents/guardrails.md +60 -0
- package/.docs/docs/agents/processors.md +36 -0
- package/.docs/docs/deployment/workflow-runners.md +7 -1
- package/.docs/docs/mcp/overview.md +25 -0
- package/.docs/docs/server/auth/fga.md +141 -0
- package/.docs/docs/server/auth/workos.md +52 -9
- package/.docs/guides/deployment/temporal.md +232 -0
- package/.docs/reference/auth/workos.md +54 -9
- package/.docs/reference/index.md +2 -0
- package/.docs/reference/processors/cost-guard-processor.md +112 -0
- package/.docs/reference/processors/processor-interface.md +5 -0
- package/.docs/reference/processors/regex-filter-processor.md +106 -0
- package/.docs/reference/tools/perplexity.md +0 -2
- package/.docs/reference/tools/tavily.md +0 -2
- package/CHANGELOG.md +8 -0
- package/package.json +5 -5
|
@@ -184,6 +184,28 @@ export const privateAgent = new Agent({
|
|
|
184
184
|
|
|
185
185
|
> **Note:** Visit [`PIIDetector()`](https://mastra.ai/reference/processors/pii-detector) reference for a full list of configuration options.
|
|
186
186
|
|
|
187
|
+
### Enforce cost limits
|
|
188
|
+
|
|
189
|
+
The `CostGuardProcessor()` monitors cumulative estimated cost across the agentic loop, blocking or warning when a monetary limit is exceeded. It queries cost data from observability storage before each LLM call. Cost checks are approximate — metrics are persisted asynchronously, so fast-running agents may briefly exceed the configured limit before the guard triggers.
|
|
190
|
+
|
|
191
|
+
```typescript
|
|
192
|
+
import { CostGuardProcessor } from '@mastra/core/processors'
|
|
193
|
+
|
|
194
|
+
export const budgetedAgent = new Agent({
|
|
195
|
+
id: 'budgeted-agent',
|
|
196
|
+
name: 'Budgeted Agent',
|
|
197
|
+
inputProcessors: [
|
|
198
|
+
new CostGuardProcessor({
|
|
199
|
+
maxCost: 5.0,
|
|
200
|
+
scope: 'thread',
|
|
201
|
+
window: '24h',
|
|
202
|
+
}),
|
|
203
|
+
],
|
|
204
|
+
})
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
> **Note:** Visit [`CostGuardProcessor()`](https://mastra.ai/reference/processors/cost-guard-processor) reference for scoping modes, time windows, metric persistence delays, and the `onViolation` callback. Requires observability storage with `getMetricAggregate` support.
|
|
208
|
+
|
|
187
209
|
## Processor strategies
|
|
188
210
|
|
|
189
211
|
Many built-in processors support a `strategy` parameter that controls how they handle flagged content. Supported values include: `block`, `warn`, `detect`, `redact`, `rewrite`, and `translate`.
|
|
@@ -201,6 +223,44 @@ inputProcessors: [
|
|
|
201
223
|
]
|
|
202
224
|
```
|
|
203
225
|
|
|
226
|
+
## Violation callbacks
|
|
227
|
+
|
|
228
|
+
All processors support an `onViolation` callback that fires when a policy violation is detected, regardless of strategy. Use it for side effects like alerting, logging to external systems, or sending notifications.
|
|
229
|
+
|
|
230
|
+
The callback receives a `ProcessorViolation` object with `processorId`, `message`, and `detail` (processor-specific metadata).
|
|
231
|
+
|
|
232
|
+
```typescript
|
|
233
|
+
import { CostGuardProcessor, ModerationProcessor, PIIDetector } from '@mastra/core/processors'
|
|
234
|
+
|
|
235
|
+
// Alert when cost limits are exceeded
|
|
236
|
+
const costGuard = new CostGuardProcessor({
|
|
237
|
+
maxCost: 10.0,
|
|
238
|
+
scope: 'resource',
|
|
239
|
+
window: '30d',
|
|
240
|
+
})
|
|
241
|
+
|
|
242
|
+
costGuard.onViolation = ({ processorId, message, detail }) => {
|
|
243
|
+
alertSystem.notify(`[${processorId}] ${message}`)
|
|
244
|
+
// detail contains: { usage, limit, totalUsage, scope, scopeKey }
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Log moderation violations
|
|
248
|
+
const moderation = new ModerationProcessor({
|
|
249
|
+
model: 'openai/gpt-5-nano',
|
|
250
|
+
strategy: 'block',
|
|
251
|
+
})
|
|
252
|
+
|
|
253
|
+
moderation.onViolation = ({ processorId, message, detail }) => {
|
|
254
|
+
auditLog.write({ processor: processorId, violation: message, categories: detail })
|
|
255
|
+
}
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
The `onViolation` property is part of the base [`Processor` interface](https://mastra.ai/reference/processors/processor-interface), so any processor — including custom ones — can use it. The runner automatically invokes `onViolation` when any processor calls `abort()`. For processors using a `warn` strategy (like `CostGuardProcessor`), the callback also fires on warnings without blocking the request.
|
|
259
|
+
|
|
260
|
+
Errors thrown by the callback are silently caught to prevent interfering with the processor's main logic.
|
|
261
|
+
|
|
262
|
+
For more on how violation callbacks integrate with the processor pipeline, see [Violation callbacks](https://mastra.ai/docs/agents/processors) in the Processors documentation.
|
|
263
|
+
|
|
204
264
|
## Handle blocked requests
|
|
205
265
|
|
|
206
266
|
When a processor calls `abort()`, the agent stops processing. How you detect this depends on whether you use `generate()` or `stream()`.
|
|
@@ -657,6 +657,42 @@ The retry mechanism:
|
|
|
657
657
|
- Tracks retry count via the `retryCount` parameter
|
|
658
658
|
- Respects `maxProcessorRetries` limit on the agent
|
|
659
659
|
|
|
660
|
+
### Violation callbacks
|
|
661
|
+
|
|
662
|
+
All processors expose an `onViolation` property that fires whenever a policy violation is detected — both when `abort()` is called (block strategy) and when a processor issues a warning (warn strategy). Use it for alerting, logging, or side effects without affecting the processor's main logic:
|
|
663
|
+
|
|
664
|
+
```typescript
|
|
665
|
+
import { ModerationProcessor, CostGuardProcessor } from '@mastra/core/processors'
|
|
666
|
+
|
|
667
|
+
const moderation = new ModerationProcessor({
|
|
668
|
+
model: 'openai/gpt-5-nano',
|
|
669
|
+
strategy: 'block',
|
|
670
|
+
})
|
|
671
|
+
|
|
672
|
+
moderation.onViolation = ({ processorId, message, detail }) => {
|
|
673
|
+
// Log to external monitoring, send alerts, update dashboards
|
|
674
|
+
monitor.track('processor_violation', { processorId, message, detail })
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
const costGuard = new CostGuardProcessor({
|
|
678
|
+
maxCost: 10.0,
|
|
679
|
+
scope: 'resource',
|
|
680
|
+
window: '30d',
|
|
681
|
+
})
|
|
682
|
+
|
|
683
|
+
costGuard.onViolation = ({ processorId, message, detail }) => {
|
|
684
|
+
alertSystem.notify(`[${processorId}] ${message}`)
|
|
685
|
+
}
|
|
686
|
+
```
|
|
687
|
+
|
|
688
|
+
The callback receives a `ProcessorViolation` object with:
|
|
689
|
+
|
|
690
|
+
- `processorId`: The ID of the processor that detected the violation
|
|
691
|
+
- `message`: A human-readable description of what was violated
|
|
692
|
+
- `detail`: Processor-specific metadata (e.g. cost usage, detected PII types, moderation categories)
|
|
693
|
+
|
|
694
|
+
`onViolation` is part of the base [`Processor` interface](https://mastra.ai/reference/processors/processor-interface), so any custom processor can use it too. The runner automatically invokes it when any processor calls `abort()`. Errors thrown inside the callback are silently caught to prevent interfering with the processor pipeline.
|
|
695
|
+
|
|
660
696
|
### Abort and tripwire chunks
|
|
661
697
|
|
|
662
698
|
Calling `abort(reason, options)` throws a `TripWire` error that ends processing. On streams, Mastra emits a `tripwire` chunk clients can detect:
|
|
@@ -6,4 +6,10 @@ Mastra [workflows](https://mastra.ai/docs/workflows/overview) can be executed us
|
|
|
6
6
|
|
|
7
7
|
Inngest is a developer platform for running background workflows without managing infrastructure. Mastra workflows can be deployed to Inngest, which provides step memoization, automatic retries, real-time monitoring, and suspend/resume capabilities.
|
|
8
8
|
|
|
9
|
-
Visit the [Inngest deployment guide](https://mastra.ai/guides/deployment/inngest) for setup instructions and the [Inngest workflow example](https://github.com/mastra-ai/mastra/tree/main/examples/inngest) for a complete implementation.
|
|
9
|
+
Visit the [Inngest deployment guide](https://mastra.ai/guides/deployment/inngest) for setup instructions and the [Inngest workflow example](https://github.com/mastra-ai/mastra/tree/main/examples/inngest) for a complete implementation.
|
|
10
|
+
|
|
11
|
+
## Temporal
|
|
12
|
+
|
|
13
|
+
Temporal is a durable execution platform for orchestrating long-running workflows. Mastra workflows can run on Temporal workers, with each `createStep` mapped to a Temporal activity for automatic retries and durable state.
|
|
14
|
+
|
|
15
|
+
The `@mastra/temporal` package is experimental and not ready for production use. Visit the [Temporal deployment guide](https://mastra.ai/guides/deployment/temporal) for setup instructions.
|
|
@@ -332,6 +332,31 @@ const mcp = new MCPClient({
|
|
|
332
332
|
})
|
|
333
333
|
```
|
|
334
334
|
|
|
335
|
+
**Apify**:
|
|
336
|
+
|
|
337
|
+
[Apify](https://apify.com) is the largest marketplace of tools for AI, with thousands of ready-made [Actors](https://apify.com/store) to extract real-time data from any website, track competitors, generate leads, analyze sentiment, or orchestrate your apps. Connect your agent through the [Apify MCP Server](https://mcp.apify.com).
|
|
338
|
+
|
|
339
|
+
```typescript
|
|
340
|
+
import { MCPClient } from '@mastra/mcp'
|
|
341
|
+
|
|
342
|
+
export const mcp = new MCPClient({
|
|
343
|
+
servers: {
|
|
344
|
+
apify: {
|
|
345
|
+
url: new URL('https://mcp.apify.com'),
|
|
346
|
+
requestInit: {
|
|
347
|
+
headers: {
|
|
348
|
+
Authorization: `Bearer ${process.env.APIFY_TOKEN}`,
|
|
349
|
+
},
|
|
350
|
+
},
|
|
351
|
+
},
|
|
352
|
+
},
|
|
353
|
+
})
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
Get your API token from the [Apify Console](https://console.apify.com/settings/integrations) and store it as `APIFY_TOKEN` in your environment.
|
|
357
|
+
|
|
358
|
+
To pick specific Actors and tools, use the [Apify MCP server configurator](https://mcp.apify.com) and copy the generated URL.
|
|
359
|
+
|
|
335
360
|
**Ampersand**:
|
|
336
361
|
|
|
337
362
|
[Ampersand](https://withampersand.com?utm_source=mastra-docs) offers an [MCP Server](https://docs.withampersand.com/mcp) that allows you to connect your agent to 150+ integrations with SaaS products like Salesforce, Hubspot, and Zendesk.
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# Fine-Grained Authorization (FGA)
|
|
2
|
+
|
|
3
|
+
Fine-Grained Authorization (FGA) adds resource-level permission checks to your Mastra application. While RBAC answers "can this role do this action?", FGA answers **"can this user do this action on this specific resource?"**
|
|
4
|
+
|
|
5
|
+
## When to use FGA
|
|
6
|
+
|
|
7
|
+
FGA is designed for multi-tenant B2B products where permissions are contextual:
|
|
8
|
+
|
|
9
|
+
- A user might be an **admin** of Team A but only a **member** of Team B
|
|
10
|
+
- Thread access should be limited to the user's own organization
|
|
11
|
+
- Workflow execution should be scoped to a specific team or project
|
|
12
|
+
- Tool access depends on the user's relationship to a resource
|
|
13
|
+
|
|
14
|
+
## Configuration
|
|
15
|
+
|
|
16
|
+
Configure FGA in your Mastra server config alongside authentication and RBAC:
|
|
17
|
+
|
|
18
|
+
```typescript
|
|
19
|
+
import { Mastra } from '@mastra/core/mastra';
|
|
20
|
+
import { MastraFGAPermissions } from '@mastra/core/auth/ee';
|
|
21
|
+
import { MastraAuthWorkos, MastraFGAWorkos } from '@mastra/auth-workos';
|
|
22
|
+
|
|
23
|
+
const mastra = new Mastra({
|
|
24
|
+
server: {
|
|
25
|
+
auth: new MastraAuthWorkos({
|
|
26
|
+
/* ... */
|
|
27
|
+
fetchMemberships: true,
|
|
28
|
+
}),
|
|
29
|
+
fga: new MastraFGAWorkos({
|
|
30
|
+
resourceMapping: {
|
|
31
|
+
agent: { fgaResourceType: 'team', deriveId: (ctx) => ctx.user.teamId },
|
|
32
|
+
workflow: { fgaResourceType: 'team', deriveId: (ctx) => ctx.user.teamId },
|
|
33
|
+
thread: { fgaResourceType: 'workspace-thread', deriveId: ({ resourceId }) => resourceId },
|
|
34
|
+
},
|
|
35
|
+
permissionMapping: {
|
|
36
|
+
[MastraFGAPermissions.AGENTS_EXECUTE]: 'manage-workflows',
|
|
37
|
+
[MastraFGAPermissions.WORKFLOWS_EXECUTE]: 'manage-workflows',
|
|
38
|
+
[MastraFGAPermissions.MEMORY_READ]: 'read',
|
|
39
|
+
[MastraFGAPermissions.MEMORY_WRITE]: 'update',
|
|
40
|
+
},
|
|
41
|
+
}),
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
When using `MastraFGAWorkos`, set `fetchMemberships: true` on `MastraAuthWorkos`. WorkOS FGA checks need the user's organization memberships to resolve the correct membership ID for authorization.
|
|
47
|
+
|
|
48
|
+
Use `thread` as the resource-mapping key for memory authorization. `MastraFGAWorkos` still accepts the legacy alias `memory`, but new configs should prefer `thread`.
|
|
49
|
+
|
|
50
|
+
### Resource mapping
|
|
51
|
+
|
|
52
|
+
The `resourceMapping` tells Mastra how to resolve FGA resource types and IDs from request context. Keys are Mastra resource types, values define the FGA resource type and how to derive the ID:
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
resourceMapping: {
|
|
56
|
+
// When checking "can user execute agent X?", resolve the FGA resource
|
|
57
|
+
// as the user's team (type: 'team', id: user.teamId)
|
|
58
|
+
agent: {
|
|
59
|
+
fgaResourceType: 'team',
|
|
60
|
+
deriveId: (ctx) => ctx.user.teamId,
|
|
61
|
+
},
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
`deriveId()` receives:
|
|
66
|
+
|
|
67
|
+
- `user` — the authenticated user
|
|
68
|
+
- `resourceId` — the owning Mastra resource ID when available (for example, a thread's `resourceId`)
|
|
69
|
+
- `requestContext` — the current request context for advanced tenant resolution
|
|
70
|
+
|
|
71
|
+
Return `undefined` from `deriveId()` to fall back to the original Mastra resource ID.
|
|
72
|
+
|
|
73
|
+
For thread and memory checks, Mastra still passes the raw `threadId` as the resource being checked, but it also forwards the thread's owning `resourceId` into `deriveId()`. This lets you map thread permissions to composite tenant IDs such as `userId-teamId-orgId`.
|
|
74
|
+
|
|
75
|
+
### Permission mapping
|
|
76
|
+
|
|
77
|
+
The `permissionMapping` translates Mastra's internal permission strings to your FGA provider's permission slugs:
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
import { MastraFGAPermissions } from '@mastra/core/auth/ee';
|
|
81
|
+
|
|
82
|
+
permissionMapping: {
|
|
83
|
+
[MastraFGAPermissions.AGENTS_EXECUTE]: 'manage-workflows', // Mastra permission -> WorkOS permission slug
|
|
84
|
+
[MastraFGAPermissions.MEMORY_READ]: 'read',
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
If no mapping exists for a permission, the original string is passed through.
|
|
89
|
+
|
|
90
|
+
## Enforcement points
|
|
91
|
+
|
|
92
|
+
When an FGA provider is configured, Mastra automatically checks authorization at these lifecycle points:
|
|
93
|
+
|
|
94
|
+
| Lifecycle point | Permission checked | Resource |
|
|
95
|
+
| -------------------------------------- | ---------------------------------------------- | -------------------------------------- |
|
|
96
|
+
| Agent execution (`generate`, `stream`) | `agents:execute` | `{ type: 'agent', id: agentId }` |
|
|
97
|
+
| Workflow execution | `workflows:execute` | `{ type: 'workflow', id: workflowId }` |
|
|
98
|
+
| Tool execution | `tools:execute` | `{ type: 'tool', id: toolName }` |
|
|
99
|
+
| Thread/memory access | `memory:read`, `memory:write`, `memory:delete` | `{ type: 'thread', id: threadId }` |
|
|
100
|
+
| MCP tool execution | `tools:execute` | `{ type: 'tool', id: toolName }` |
|
|
101
|
+
| HTTP routes (opt-in) | Configured per route | Configured per route |
|
|
102
|
+
|
|
103
|
+
All checks are **no-ops when FGA is not configured**, maintaining backward compatibility.
|
|
104
|
+
|
|
105
|
+
## Custom FGA provider
|
|
106
|
+
|
|
107
|
+
Implement `IFGAProvider` to use any FGA backend:
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
import { FGADeniedError } from '@mastra/core/auth/ee'
|
|
111
|
+
import type { FGACheckParams, IFGAProvider, MastraFGAPermissionInput } from '@mastra/core/auth/ee'
|
|
112
|
+
|
|
113
|
+
class MyFGAProvider implements IFGAProvider {
|
|
114
|
+
async check(user: any, params: FGACheckParams): Promise<boolean> {
|
|
115
|
+
// Your authorization logic
|
|
116
|
+
return true
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
async require(user: any, params: FGACheckParams): Promise<void> {
|
|
120
|
+
const allowed = await this.check(user, params)
|
|
121
|
+
if (!allowed) {
|
|
122
|
+
throw new FGADeniedError(user, params.resource, params.permission)
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
async filterAccessible<T extends { id: string }>(
|
|
127
|
+
user: any,
|
|
128
|
+
resources: T[],
|
|
129
|
+
resourceType: string,
|
|
130
|
+
permission: MastraFGAPermissionInput,
|
|
131
|
+
): Promise<T[]> {
|
|
132
|
+
// Filter resources the user can access
|
|
133
|
+
return resources
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Related
|
|
139
|
+
|
|
140
|
+
- [Authentication overview](https://mastra.ai/docs/server/auth)
|
|
141
|
+
- [WorkOS authentication](https://mastra.ai/docs/server/auth/workos)
|
|
@@ -81,16 +81,34 @@ export const mastra = new Mastra({
|
|
|
81
81
|
|
|
82
82
|
## Configuration
|
|
83
83
|
|
|
84
|
-
###
|
|
84
|
+
### Default authorization
|
|
85
85
|
|
|
86
|
-
By default, `MastraAuthWorkos`
|
|
86
|
+
By default, `MastraAuthWorkos` grants access to any authenticated WorkOS user. The authorization check succeeds when the resolved user object contains both a Mastra user ID and a WorkOS user ID.
|
|
87
87
|
|
|
88
|
-
|
|
89
|
-
2. Extracts all roles from their memberships
|
|
90
|
-
3. Checks if any role has the slug 'admin'
|
|
91
|
-
4. Grants access only if the user has admin role in at least one organization
|
|
88
|
+
### FGA membership loading
|
|
92
89
|
|
|
93
|
-
|
|
90
|
+
Set `fetchMemberships: true` when you use [`MastraFGAWorkos`](https://mastra.ai/docs/server/auth/fga). This tells the auth provider to load the user's WorkOS organization memberships during authentication so FGA checks can resolve the correct organization membership ID.
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
import { MastraAuthWorkos, MastraFGAWorkos } from '@mastra/auth-workos'
|
|
94
|
+
|
|
95
|
+
const workosAuth = new MastraAuthWorkos({
|
|
96
|
+
apiKey: process.env.WORKOS_API_KEY,
|
|
97
|
+
clientId: process.env.WORKOS_CLIENT_ID,
|
|
98
|
+
fetchMemberships: true,
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
const workosFga = new MastraFGAWorkos({
|
|
102
|
+
apiKey: process.env.WORKOS_API_KEY,
|
|
103
|
+
clientId: process.env.WORKOS_CLIENT_ID,
|
|
104
|
+
})
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
When `fetchMemberships` is `false`, Mastra skips the extra WorkOS `listOrganizationMemberships()` call on each authenticated request.
|
|
108
|
+
|
|
109
|
+
### Service tokens and custom JWT templates
|
|
110
|
+
|
|
111
|
+
For machine-to-machine or service-account access, you can configure `MastraAuthWorkos` to trust verified bearer-token claims from a WorkOS custom JWT template.
|
|
94
112
|
|
|
95
113
|
```typescript
|
|
96
114
|
import { MastraAuthWorkos } from '@mastra/auth-workos'
|
|
@@ -98,12 +116,37 @@ import { MastraAuthWorkos } from '@mastra/auth-workos'
|
|
|
98
116
|
const workosAuth = new MastraAuthWorkos({
|
|
99
117
|
apiKey: process.env.WORKOS_API_KEY,
|
|
100
118
|
clientId: process.env.WORKOS_CLIENT_ID,
|
|
101
|
-
|
|
102
|
-
|
|
119
|
+
redirectUri: process.env.WORKOS_REDIRECT_URI,
|
|
120
|
+
trustJwtClaims: true,
|
|
121
|
+
jwtClaims: {
|
|
122
|
+
organizationId: 'org_id',
|
|
123
|
+
organizationMembershipId: 'urn:mastra:organization_membership_id',
|
|
103
124
|
},
|
|
104
125
|
})
|
|
105
126
|
```
|
|
106
127
|
|
|
128
|
+
This is useful when your JWT template already includes the exact FGA context Mastra needs, such as `organizationMembershipId`, tenant IDs, or service-principal identifiers. When `trustJwtClaims` is enabled, Mastra can fall back to those verified claims if a bearer token is not meant to round-trip through `workos.userManagement.getUser()`.
|
|
129
|
+
|
|
130
|
+
### Custom authorization
|
|
131
|
+
|
|
132
|
+
If you need stricter authorization, subclass `MastraAuthWorkos` and override `authorizeUser()`:
|
|
133
|
+
|
|
134
|
+
```typescript
|
|
135
|
+
import { MastraAuthWorkos } from '@mastra/auth-workos'
|
|
136
|
+
import type { HonoRequest } from 'hono'
|
|
137
|
+
|
|
138
|
+
class AdminOnlyWorkosAuth extends MastraAuthWorkos {
|
|
139
|
+
async authorizeUser(user: any, _request: HonoRequest): Promise<boolean> {
|
|
140
|
+
return user?.metadata?.role === 'admin'
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const workosAuth = new AdminOnlyWorkosAuth({
|
|
145
|
+
apiKey: process.env.WORKOS_API_KEY,
|
|
146
|
+
clientId: process.env.WORKOS_CLIENT_ID,
|
|
147
|
+
})
|
|
148
|
+
```
|
|
149
|
+
|
|
107
150
|
> **Info:** Visit [MastraAuthWorkos](https://mastra.ai/reference/auth/workos) for all available configuration options.
|
|
108
151
|
|
|
109
152
|
## Client-side setup
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
# Temporal workflow
|
|
2
|
+
|
|
3
|
+
[Temporal](https://temporal.io/) is a durable execution platform for orchestrating long-running, fault-tolerant workflows. The `@mastra/temporal` package lets you author workflows with the standard Mastra API and run them on a Temporal cluster.
|
|
4
|
+
|
|
5
|
+
> **Warning:** `@mastra/temporal` is experimental and not ready for production use. The API may change between releases. See the [package README](https://github.com/mastra-ai/mastra/tree/main/workflows/temporal) for the current state.
|
|
6
|
+
|
|
7
|
+
## How Temporal works with Mastra
|
|
8
|
+
|
|
9
|
+
Mastra workflows authored with `createWorkflow()` and `createStep()` map onto Temporal's workflow and activity model. The `MastraPlugin` for the Temporal worker compiles your Mastra entry file at bundle time:
|
|
10
|
+
|
|
11
|
+
- Each `createStep()` handler is extracted into a Temporal activity.
|
|
12
|
+
- Each `createWorkflow()` is rewritten into a Temporal workflow that invokes those activities.
|
|
13
|
+
- The plugin registers the generated activities and workflows with the worker automatically.
|
|
14
|
+
|
|
15
|
+
When a run starts through `mastra.getWorkflow(...).createRun().start(...)`, the Mastra client hands control to Temporal. Temporal then drives durable execution, retries, and state persistence on the worker.
|
|
16
|
+
|
|
17
|
+
## Setup
|
|
18
|
+
|
|
19
|
+
Install the required packages:
|
|
20
|
+
|
|
21
|
+
**npm**:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm install @mastra/temporal@latest @temporalio/client @temporalio/worker @temporalio/envconfig
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
**pnpm**:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
pnpm add @mastra/temporal@latest @temporalio/client @temporalio/worker @temporalio/envconfig
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
**Yarn**:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
yarn add @mastra/temporal@latest @temporalio/client @temporalio/worker @temporalio/envconfig
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
**Bun**:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
bun add @mastra/temporal@latest @temporalio/client @temporalio/worker @temporalio/envconfig
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
You also need access to a Temporal cluster. For local development, you can run one with Docker (see [Running locally](#running-locally)).
|
|
46
|
+
|
|
47
|
+
## Building a Temporal-backed workflow
|
|
48
|
+
|
|
49
|
+
This guide walks through creating a workflow with Temporal and Mastra, demonstrating a counter application that increments a value.
|
|
50
|
+
|
|
51
|
+
### Temporal initialization
|
|
52
|
+
|
|
53
|
+
Initialize the Temporal integration to obtain Mastra-compatible workflow helpers. The `createWorkflow()` and `createStep()` functions are bound to a Temporal client and a task queue.
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
import { init } from '@mastra/temporal'
|
|
57
|
+
import { Client, Connection } from '@temporalio/client'
|
|
58
|
+
import { loadClientConnectConfig } from '@temporalio/envconfig'
|
|
59
|
+
|
|
60
|
+
const config = loadClientConnectConfig()
|
|
61
|
+
const connection = await Connection.connect(config.connectionOptions)
|
|
62
|
+
const client = new Client({ connection })
|
|
63
|
+
|
|
64
|
+
export const { createWorkflow, createStep } = init({
|
|
65
|
+
client,
|
|
66
|
+
taskQueue: 'mastra',
|
|
67
|
+
})
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
`loadClientConnectConfig()` reads standard Temporal environment variables such as `TEMPORAL_ADDRESS`, `TEMPORAL_NAMESPACE`, and mTLS settings. See the [Temporal envconfig docs](https://docs.temporal.io/develop/typescript/temporal-clients) for the full list.
|
|
71
|
+
|
|
72
|
+
### Creating steps
|
|
73
|
+
|
|
74
|
+
Define the individual steps that will compose your workflow. Each step becomes a Temporal activity.
|
|
75
|
+
|
|
76
|
+
```ts
|
|
77
|
+
import { z } from 'zod'
|
|
78
|
+
import { createWorkflow, createStep } from '../temporal'
|
|
79
|
+
|
|
80
|
+
const incrementStep = createStep({
|
|
81
|
+
id: 'increment',
|
|
82
|
+
inputSchema: z.object({
|
|
83
|
+
value: z.number(),
|
|
84
|
+
}),
|
|
85
|
+
outputSchema: z.object({
|
|
86
|
+
value: z.number(),
|
|
87
|
+
}),
|
|
88
|
+
execute: async ({ inputData }) => {
|
|
89
|
+
return { value: inputData.value + 1 }
|
|
90
|
+
},
|
|
91
|
+
})
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Creating the workflow
|
|
95
|
+
|
|
96
|
+
Compose the steps into a workflow. The workflow `id` must be a static string literal so the build-time transformer can derive its Temporal export name.
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
const workflow = createWorkflow({
|
|
100
|
+
id: 'increment-workflow',
|
|
101
|
+
steps: [incrementStep],
|
|
102
|
+
inputSchema: z.object({
|
|
103
|
+
value: z.number(),
|
|
104
|
+
}),
|
|
105
|
+
outputSchema: z.object({
|
|
106
|
+
value: z.number(),
|
|
107
|
+
}),
|
|
108
|
+
}).then(incrementStep)
|
|
109
|
+
|
|
110
|
+
workflow.commit()
|
|
111
|
+
|
|
112
|
+
export { workflow as incrementWorkflow }
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Configuring the Mastra instance
|
|
116
|
+
|
|
117
|
+
Register the workflow with Mastra. The execution is driven by the Temporal worker.
|
|
118
|
+
|
|
119
|
+
```ts
|
|
120
|
+
import { Mastra } from '@mastra/core'
|
|
121
|
+
import { PinoLogger } from '@mastra/loggers'
|
|
122
|
+
import { incrementWorkflow } from './workflows'
|
|
123
|
+
|
|
124
|
+
export const mastra = new Mastra({
|
|
125
|
+
workflows: { incrementWorkflow },
|
|
126
|
+
logger: new PinoLogger({ name: 'Mastra', level: 'info' }),
|
|
127
|
+
})
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Running the worker
|
|
131
|
+
|
|
132
|
+
The worker is a long-lived Node.js process that polls a Temporal task queue. Install `MastraPlugin` and point its `src` option at the Mastra entry file that registers your workflows.
|
|
133
|
+
|
|
134
|
+
```ts
|
|
135
|
+
import { MastraPlugin } from '@mastra/temporal/worker'
|
|
136
|
+
import { NativeConnection, Worker } from '@temporalio/worker'
|
|
137
|
+
|
|
138
|
+
const connection = await NativeConnection.connect({
|
|
139
|
+
address: 'localhost:7233',
|
|
140
|
+
})
|
|
141
|
+
|
|
142
|
+
const mastraPlugin = new MastraPlugin()
|
|
143
|
+
|
|
144
|
+
await mastraPlugin.prebuild({
|
|
145
|
+
entryFile: import.meta.resolve('./index.ts'),
|
|
146
|
+
})
|
|
147
|
+
|
|
148
|
+
const worker = await Worker.create({
|
|
149
|
+
connection,
|
|
150
|
+
namespace: 'default',
|
|
151
|
+
taskQueue: 'mastra',
|
|
152
|
+
plugins: [mastraPlugin],
|
|
153
|
+
})
|
|
154
|
+
|
|
155
|
+
await worker.run()
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
`MastraPlugin` rewrites the entry file into a workflow-only bundle and wires step handlers in as Temporal activities. You do not need to pass `activities` or `workflowsPath` to `Worker.create()` manually.
|
|
159
|
+
|
|
160
|
+
## Running workflows
|
|
161
|
+
|
|
162
|
+
### Running locally
|
|
163
|
+
|
|
164
|
+
1. Start a local Temporal server. The simplest option is the `temporalio/auto-setup` Docker image:
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
docker run --rm -p 7233:7233 -p 8080:8080 temporalio/auto-setup:latest
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
2. Open the Temporal UI at <http://localhost:8080> to inspect namespaces, workflows, and activities.
|
|
171
|
+
|
|
172
|
+
3. Start the worker. In a new terminal, run:
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
npx tsx src/mastra/worker.ts
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
4. Trigger a workflow run from a script or any process that imports your Mastra instance:
|
|
179
|
+
|
|
180
|
+
```ts
|
|
181
|
+
import { mastra } from '../src/mastra'
|
|
182
|
+
|
|
183
|
+
const run = await mastra.getWorkflow('incrementWorkflow').createRun()
|
|
184
|
+
const result = await run.start({ inputData: { value: 5 } })
|
|
185
|
+
|
|
186
|
+
console.log(result)
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
5. Monitor execution in the Temporal UI under **Workflows** to see step-by-step activity progress and retry history.
|
|
190
|
+
|
|
191
|
+
### Running in production
|
|
192
|
+
|
|
193
|
+
For production, use [Temporal Cloud](https://temporal.io/cloud) or a self-hosted Temporal cluster. Configure the client and worker connections through environment variables read by `@temporalio/envconfig`:
|
|
194
|
+
|
|
195
|
+
```bash
|
|
196
|
+
TEMPORAL_ADDRESS=your-namespace.tmprl.cloud:7233
|
|
197
|
+
TEMPORAL_NAMESPACE=your-namespace
|
|
198
|
+
TEMPORAL_API_KEY=your-api-key
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
See the [Temporal Cloud connection docs](https://docs.temporal.io/cloud/get-started) for mTLS and API key options.
|
|
202
|
+
|
|
203
|
+
> **Warning:** The Temporal worker must run as a long-lived process. Do not deploy it to serverless platforms with short execution limits, such as AWS Lambda or Vercel functions. Use a container, VM, or worker-friendly platform such as Fly.io, Railway, or Kubernetes.
|
|
204
|
+
|
|
205
|
+
## Configuration options
|
|
206
|
+
|
|
207
|
+
### `taskQueue`
|
|
208
|
+
|
|
209
|
+
Required. Identifies the Temporal task queue your worker polls. The same value must be passed to `init()` (used by the client to start runs) and to `Worker.create()` (used by the worker to receive them).
|
|
210
|
+
|
|
211
|
+
### `startToCloseTimeout`
|
|
212
|
+
|
|
213
|
+
Optional. Sets the maximum time a single activity (step) is allowed to run before Temporal cancels it and applies the retry policy. Defaults to `1 minute`.
|
|
214
|
+
|
|
215
|
+
```ts
|
|
216
|
+
export const { createWorkflow, createStep } = init({
|
|
217
|
+
client,
|
|
218
|
+
taskQueue: 'mastra',
|
|
219
|
+
startToCloseTimeout: '5 minutes',
|
|
220
|
+
})
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
## Constraints and notes
|
|
224
|
+
|
|
225
|
+
- Workflow ids must be static string literals. The build-time transformer reads the literal value to derive Temporal workflow export names.
|
|
226
|
+
- Activities are generated automatically from `createStep()` handlers. Do not pass them in `Worker.create({ activities })`.
|
|
227
|
+
|
|
228
|
+
## Related
|
|
229
|
+
|
|
230
|
+
- [Workflow runners](https://mastra.ai/docs/deployment/workflow-runners)
|
|
231
|
+
- [Workflows overview](https://mastra.ai/docs/workflows/overview)
|
|
232
|
+
- [Temporal documentation](https://docs.temporal.io/)
|
|
@@ -28,7 +28,13 @@ export const mastra = new Mastra({
|
|
|
28
28
|
|
|
29
29
|
**name** (`string`): Custom name for the auth provider instance. (Default: `"workos"`)
|
|
30
30
|
|
|
31
|
-
**
|
|
31
|
+
**redirectUri** (`string`): OAuth redirect URI used by WorkOS AuthKit. Set this when you use the built-in WorkOS sign-in flow. (Default: `process.env.WORKOS_REDIRECT_URI`)
|
|
32
|
+
|
|
33
|
+
**fetchMemberships** (`boolean`): Loads organization memberships during authentication. Set this to \`true\` when you use \`MastraFGAWorkos\` so FGA checks can resolve the correct organization membership ID. (Default: `false`)
|
|
34
|
+
|
|
35
|
+
**trustJwtClaims** (`boolean`): Trusts verified bearer-token claims enough to construct a \`WorkOSUser\` even when \`workos.userManagement.getUser()\` does not apply. Use this for service-account or machine-to-machine tokens backed by a WorkOS custom JWT template. (Default: `false`)
|
|
36
|
+
|
|
37
|
+
**jwtClaims** (`{ userId?: string; workosId?: string; email?: string; name?: string; organizationId?: string; organizationMembershipId?: string }`): Maps verified bearer JWT claims into the authenticated \`WorkOSUser\`. Useful for custom JWT templates that include \`organizationMembershipId\` or other FGA-specific claims.
|
|
32
38
|
|
|
33
39
|
## Environment variables
|
|
34
40
|
|
|
@@ -38,24 +44,63 @@ The following environment variables are automatically used when constructor opti
|
|
|
38
44
|
|
|
39
45
|
**WORKOS\_CLIENT\_ID** (`string`): Your WorkOS Client ID. Can be found in your WorkOS Dashboard under Applications.
|
|
40
46
|
|
|
47
|
+
**WORKOS\_REDIRECT\_URI** (`string`): OAuth redirect URI used by WorkOS AuthKit when you use the built-in session-based flow.
|
|
48
|
+
|
|
41
49
|
## Default authorization behavior
|
|
42
50
|
|
|
43
|
-
By default, `MastraAuthWorkos`
|
|
51
|
+
By default, `MastraAuthWorkos` authorizes any authenticated WorkOS user whose resolved user object includes both `id` and `workosId`.
|
|
44
52
|
|
|
45
53
|
1. **Token Verification**: The access token is verified with WorkOS to ensure it's valid and not expired
|
|
46
54
|
2. **User Retrieval**: User information is extracted from the verified token
|
|
47
|
-
3. **
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
55
|
+
3. **Authorization Decision**: Access is granted if the resolved user contains the required identifiers
|
|
56
|
+
|
|
57
|
+
This means that by default, `MastraAuthWorkos` acts as an authentication provider rather than a role gate.
|
|
58
|
+
|
|
59
|
+
## FGA membership loading
|
|
60
|
+
|
|
61
|
+
Set `fetchMemberships: true` when you use `MastraFGAWorkos`. This loads the user's WorkOS organization memberships during authentication so FGA checks can resolve the correct organization membership ID.
|
|
62
|
+
|
|
63
|
+
When `fetchMemberships` is `false`, Mastra skips the extra WorkOS `listOrganizationMemberships()` call on each authenticated request.
|
|
64
|
+
|
|
65
|
+
## Service tokens and JWT claims
|
|
66
|
+
|
|
67
|
+
If your WorkOS JWT template includes custom claims, you can map them directly into the authenticated `WorkOSUser`.
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
import { MastraAuthWorkos } from '@mastra/auth-workos'
|
|
71
|
+
|
|
72
|
+
const auth = new MastraAuthWorkos({
|
|
73
|
+
apiKey: process.env.WORKOS_API_KEY,
|
|
74
|
+
clientId: process.env.WORKOS_CLIENT_ID,
|
|
75
|
+
redirectUri: process.env.WORKOS_REDIRECT_URI,
|
|
76
|
+
trustJwtClaims: true,
|
|
77
|
+
jwtClaims: {
|
|
78
|
+
organizationId: 'org_id',
|
|
79
|
+
organizationMembershipId: 'urn:mastra:organization_membership_id',
|
|
80
|
+
},
|
|
81
|
+
})
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
When `trustJwtClaims` is enabled, Mastra can authenticate verified bearer tokens for service principals even if `getUser()` is not the right lookup path. This is the preferred way to pass pre-resolved `organizationMembershipId` values into FGA checks for machine-to-machine flows.
|
|
51
85
|
|
|
52
|
-
|
|
86
|
+
## Custom authorization
|
|
53
87
|
|
|
54
|
-
|
|
88
|
+
If you need stricter authorization, subclass `MastraAuthWorkos` and override `authorizeUser()`:
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
import { MastraAuthWorkos } from '@mastra/auth-workos'
|
|
92
|
+
import type { HonoRequest } from 'hono'
|
|
93
|
+
|
|
94
|
+
class AdminOnlyWorkosAuth extends MastraAuthWorkos {
|
|
95
|
+
async authorizeUser(user: any, _request: HonoRequest): Promise<boolean> {
|
|
96
|
+
return user?.metadata?.role === 'admin'
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
```
|
|
55
100
|
|
|
56
101
|
## WorkOS user type
|
|
57
102
|
|
|
58
|
-
The `
|
|
103
|
+
The `WorkOSUser` type available inside `authorizeUser()` and other WorkOS auth hooks includes Mastra's normalized user fields plus WorkOS-specific metadata. WorkOS also allows administrators to set up custom JWT templates, so the exact structure may vary based on your configuration. The following example shows what a WorkOS-backed user object might look like:
|
|
59
104
|
|
|
60
105
|
```javascript
|
|
61
106
|
{
|
package/.docs/reference/index.md
CHANGED
|
@@ -160,6 +160,7 @@ The Reference section provides documentation of Mastra's API, including paramete
|
|
|
160
160
|
- [Span filtering](https://mastra.ai/reference/observability/tracing/span-filtering)
|
|
161
161
|
- [Spans](https://mastra.ai/reference/observability/tracing/spans)
|
|
162
162
|
- [BatchPartsProcessor](https://mastra.ai/reference/processors/batch-parts-processor)
|
|
163
|
+
- [CostGuardProcessor](https://mastra.ai/reference/processors/cost-guard-processor)
|
|
163
164
|
- [LanguageDetector](https://mastra.ai/reference/processors/language-detector)
|
|
164
165
|
- [MessageHistory](https://mastra.ai/reference/processors/message-history-processor)
|
|
165
166
|
- [ModerationProcessor](https://mastra.ai/reference/processors/moderation-processor)
|
|
@@ -167,6 +168,7 @@ The Reference section provides documentation of Mastra's API, including paramete
|
|
|
167
168
|
- [PrefillErrorHandler](https://mastra.ai/reference/processors/prefill-error-handler)
|
|
168
169
|
- [Processor Interface](https://mastra.ai/reference/processors/processor-interface)
|
|
169
170
|
- [PromptInjectionDetector](https://mastra.ai/reference/processors/prompt-injection-detector)
|
|
171
|
+
- [RegexFilterProcessor](https://mastra.ai/reference/processors/regex-filter-processor)
|
|
170
172
|
- [SemanticRecall](https://mastra.ai/reference/processors/semantic-recall-processor)
|
|
171
173
|
- [SkillSearchProcessor](https://mastra.ai/reference/processors/skill-search-processor)
|
|
172
174
|
- [StreamErrorRetryProcessor](https://mastra.ai/reference/processors/stream-error-retry-processor)
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# CostGuardProcessor
|
|
2
|
+
|
|
3
|
+
The `CostGuardProcessor` enforces monetary cost limits across the agentic loop, blocking or warning when a configurable cost threshold is exceeded.
|
|
4
|
+
|
|
5
|
+
It uses `processInputStep` to check the cost limit before each LLM call. Cost data is queried from the observability storage APIs (`getMetricAggregate`) for all scopes. For `resource` and `thread` scopes, it aggregates cost across runs within a configurable time window (defaults to 7 days). For `run` scope, it queries cost for the current trace.
|
|
6
|
+
|
|
7
|
+
For token-based limits, use `TokenLimiterProcessor` instead.
|
|
8
|
+
|
|
9
|
+
Supports three scoping modes:
|
|
10
|
+
|
|
11
|
+
- **Run scope**: Tracks cost within a single agent run via trace ID
|
|
12
|
+
- **Resource scope** (default): Tracks cumulative cost per `resourceId` across runs
|
|
13
|
+
- **Thread scope**: Tracks cumulative cost per `threadId` across runs
|
|
14
|
+
|
|
15
|
+
> **Approximate cost guard.** Cost data is persisted asynchronously via buffered exporters in the observability pipeline. Fast-running agents may exceed the configured limit before metrics are available for query. Treat `maxCost` as a best-effort threshold, not a hard ceiling.
|
|
16
|
+
|
|
17
|
+
## Usage example
|
|
18
|
+
|
|
19
|
+
Track cumulative cost per resource (default scope):
|
|
20
|
+
|
|
21
|
+
```typescript
|
|
22
|
+
import { CostGuardProcessor } from '@mastra/core/processors'
|
|
23
|
+
|
|
24
|
+
const costGuard = new CostGuardProcessor({
|
|
25
|
+
maxCost: 1.0,
|
|
26
|
+
})
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Track cumulative cost per thread with a 24-hour window:
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
import { CostGuardProcessor } from '@mastra/core/processors'
|
|
33
|
+
|
|
34
|
+
const costGuard = new CostGuardProcessor({
|
|
35
|
+
maxCost: 5.0,
|
|
36
|
+
scope: 'thread',
|
|
37
|
+
window: '24h',
|
|
38
|
+
})
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Attach to an agent with an `onViolation` callback:
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
import { Agent } from '@mastra/core/agent'
|
|
45
|
+
import { CostGuardProcessor } from '@mastra/core/processors'
|
|
46
|
+
|
|
47
|
+
const costGuard = new CostGuardProcessor({
|
|
48
|
+
maxCost: 5.0,
|
|
49
|
+
scope: 'resource',
|
|
50
|
+
window: '30d',
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
costGuard.onViolation = ({ detail }) => {
|
|
54
|
+
console.log(`Cost exceeded for ${detail.scopeKey}: $${detail.usage}/$${detail.limit}`)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const agent = new Agent({
|
|
58
|
+
name: 'my-agent',
|
|
59
|
+
model: 'openai/gpt-5-nano',
|
|
60
|
+
processors: {
|
|
61
|
+
input: [costGuard],
|
|
62
|
+
},
|
|
63
|
+
})
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Constructor parameters
|
|
67
|
+
|
|
68
|
+
**maxCost** (`number`): Maximum estimated cost allowed (e.g. 0.50 for $0.50 USD). Must be a positive number. Uses cost data from observability metrics. This is an approximate limit due to metric persistence delays.
|
|
69
|
+
|
|
70
|
+
**scope** (`'run' | 'resource' | 'thread'`): Scope for cost tracking. 'run' tracks cost within the current agent run via trace ID. 'resource' tracks cumulative cost per resourceId across runs (default). 'thread' tracks cumulative cost per threadId across runs. All scopes require observability storage with getMetricAggregate support. (Default: `'resource'`)
|
|
71
|
+
|
|
72
|
+
**window** (`'1h' | '6h' | '24h' | '7d' | '30d' | '365d'`): Time window for cost aggregation when using 'resource' or 'thread' scope. Only applicable to non-run scopes. (Default: `'7d'`)
|
|
73
|
+
|
|
74
|
+
**strategy** (`'block' | 'warn'`): Strategy when the cost limit is exceeded. 'block' aborts with a TripWire error. 'warn' logs a warning but allows the step to proceed. (Default: `'block'`)
|
|
75
|
+
|
|
76
|
+
**message** (`string`): Custom message template for the abort reason. Supports {usage} and {limit} placeholders. (Default: `'Cost guard: cost limit exceeded ({usage}/{limit})'`)
|
|
77
|
+
|
|
78
|
+
## Instance properties
|
|
79
|
+
|
|
80
|
+
**id** (`'cost-guard'`): Processor identifier.
|
|
81
|
+
|
|
82
|
+
**name** (`'Cost Guard'`): Processor display name.
|
|
83
|
+
|
|
84
|
+
**onViolation** (`(violation: ProcessorViolation) => void | Promise<void>`): Callback invoked when a cost violation is detected, regardless of strategy. Part of the generalized Processor interface. Use for side effects like alerting, logging to external systems, or emailing users. Errors thrown by this callback are silently caught.
|
|
85
|
+
|
|
86
|
+
**processInputStep** (`(args: ProcessInputStepArgs) => Promise<void>`): Checks cumulative estimated cost against maxCost before each LLM call. Queries observability storage for cost data: run scope filters by trace ID, resource/thread scopes filter by their respective IDs with a time window. Calls abort() when the limit is exceeded (block strategy) or logs a warning (warn strategy). Cost checks are approximate due to metric persistence delays.
|
|
87
|
+
|
|
88
|
+
## Error behavior
|
|
89
|
+
|
|
90
|
+
When the `block` strategy is active (default), `CostGuardProcessor` calls `abort()` with `retry: false` when the cost limit is exceeded. The TripWire metadata includes:
|
|
91
|
+
|
|
92
|
+
- `processorId`: `'cost-guard'`
|
|
93
|
+
- `usage`: Current cumulative usage (`estimatedCost`, `costUnit`)
|
|
94
|
+
- `maxCost`: The configured cost limit
|
|
95
|
+
- `scope`: The active scope (`'run'`, `'resource'`, or `'thread'`)
|
|
96
|
+
- `scopeKey`: The scope identifier for resource/thread scopes (if applicable)
|
|
97
|
+
|
|
98
|
+
## Scoping behavior
|
|
99
|
+
|
|
100
|
+
| Scope | Tracks across runs | Filter | Requires context |
|
|
101
|
+
| ---------- | ------------------ | --------------------------- | -------------------------------- |
|
|
102
|
+
| `run` | No | `traceId` from current span | Tracing context (automatic) |
|
|
103
|
+
| `resource` | Yes | `resourceId` + time window | `resourceId` in `RequestContext` |
|
|
104
|
+
| `thread` | Yes | `threadId` + time window | `threadId` in `RequestContext` |
|
|
105
|
+
|
|
106
|
+
All scopes require observability storage with `getMetricAggregate` support. If the Mastra instance does not have observability storage configured, an error is thrown at registration time.
|
|
107
|
+
|
|
108
|
+
For `run` scope, the processor reads the trace ID from the current span's tracing context. If no tracing context is available, the check is skipped (fail-open).
|
|
109
|
+
|
|
110
|
+
For `resource` and `thread` scopes, if the required context ID is missing at runtime, the check is skipped. Observability query failures are handled with a fail-open strategy: if a query fails, cost is treated as zero.
|
|
111
|
+
|
|
112
|
+
> **Note on metric persistence delay.** The observability pipeline uses buffered exporters that flush metrics asynchronously. There is a short delay between when an LLM call completes and when its cost metrics are available for query. During high-frequency agent execution, the cost guard may not detect a limit breach until one or more steps after the actual cost exceeded the threshold.
|
|
@@ -80,6 +80,9 @@ interface Processor<TId extends string = string, TTripwireMetadata = unknown> {
|
|
|
80
80
|
/** When true, processOutputStream also receives `data-*` chunks. Default: false. */
|
|
81
81
|
processDataParts?: boolean
|
|
82
82
|
|
|
83
|
+
/** Callback invoked when this processor detects a violation, regardless of strategy. */
|
|
84
|
+
onViolation?: (violation: ProcessorViolation) => void | Promise<void>
|
|
85
|
+
|
|
83
86
|
processInput?(
|
|
84
87
|
args: ProcessInputArgs<TTripwireMetadata>,
|
|
85
88
|
): Promise<ProcessInputResult> | ProcessInputResult
|
|
@@ -120,6 +123,8 @@ interface Processor<TId extends string = string, TTripwireMetadata = unknown> {
|
|
|
120
123
|
|
|
121
124
|
**processDataParts** (`boolean`): When true, the processOutputStream method also receives \`data-\*\` chunks emitted by tools via writer.custom(). Defaults to false.
|
|
122
125
|
|
|
126
|
+
**onViolation** (`(violation: ProcessorViolation) => void | Promise<void>`): Optional callback invoked when the processor detects a policy violation, regardless of strategy (block or warn). Use for side effects like alerting, logging to external systems, or emailing users. Errors thrown by this callback are silently caught to prevent interfering with processor logic. The violation object contains processorId, message, and a processor-specific detail field.
|
|
127
|
+
|
|
123
128
|
## Message arguments
|
|
124
129
|
|
|
125
130
|
Most processor methods receive both `messages` and `messageList`. They point to the same underlying conversation but expose it differently.
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# RegexFilterProcessor
|
|
2
|
+
|
|
3
|
+
The `RegexFilterProcessor` applies zero-cost regex pattern matching to filter, redact, or block content in agent messages. No LLM calls are made — all detection is regex-based.
|
|
4
|
+
|
|
5
|
+
Supports built-in presets for common patterns (PII, secrets, URLs) and custom regex rules. Can be applied to input, output, or both phases.
|
|
6
|
+
|
|
7
|
+
## Usage example
|
|
8
|
+
|
|
9
|
+
Block PII in input messages:
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
import { RegexFilterProcessor } from '@mastra/core/processors'
|
|
13
|
+
|
|
14
|
+
const filter = new RegexFilterProcessor({
|
|
15
|
+
presets: ['pii'],
|
|
16
|
+
strategy: 'block',
|
|
17
|
+
phase: 'input',
|
|
18
|
+
})
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Redact secrets in output:
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
import { RegexFilterProcessor } from '@mastra/core/processors'
|
|
25
|
+
|
|
26
|
+
const filter = new RegexFilterProcessor({
|
|
27
|
+
presets: ['secrets'],
|
|
28
|
+
strategy: 'redact',
|
|
29
|
+
phase: 'output',
|
|
30
|
+
})
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Custom rules:
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
import { RegexFilterProcessor } from '@mastra/core/processors'
|
|
37
|
+
|
|
38
|
+
const filter = new RegexFilterProcessor({
|
|
39
|
+
rules: [{ name: 'internal-id', pattern: /INTERNAL-\d{6}/g, replacement: '[INTERNAL_ID]' }],
|
|
40
|
+
strategy: 'redact',
|
|
41
|
+
})
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Attach to an agent:
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
import { Agent } from '@mastra/core/agent'
|
|
48
|
+
import { RegexFilterProcessor } from '@mastra/core/processors'
|
|
49
|
+
|
|
50
|
+
const agent = new Agent({
|
|
51
|
+
name: 'my-agent',
|
|
52
|
+
model: 'openai/gpt-5-nano',
|
|
53
|
+
processors: {
|
|
54
|
+
input: [
|
|
55
|
+
new RegexFilterProcessor({
|
|
56
|
+
presets: ['pii', 'secrets'],
|
|
57
|
+
strategy: 'block',
|
|
58
|
+
}),
|
|
59
|
+
],
|
|
60
|
+
},
|
|
61
|
+
})
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Constructor parameters
|
|
65
|
+
|
|
66
|
+
**rules** (`RegexRule[]`): Custom regex rules to apply. Each rule has a name, a regex pattern, and an optional replacement string.
|
|
67
|
+
|
|
68
|
+
**rules.name** (`string`): Display name for the rule (used in match reports and error messages).
|
|
69
|
+
|
|
70
|
+
**rules.pattern** (`RegExp`): The regex pattern to match against.
|
|
71
|
+
|
|
72
|
+
**rules.replacement** (`string`): Replacement string for redact strategy. Defaults to '\[REDACTED]'.
|
|
73
|
+
|
|
74
|
+
**presets** (`('pii' | 'secrets' | 'urls')[]`): Built-in preset categories. 'pii' matches emails, phone numbers, SSNs, credit cards. 'secrets' matches API keys, bearer tokens, AWS keys. 'urls' matches HTTP/HTTPS URLs.
|
|
75
|
+
|
|
76
|
+
**strategy** (`'block' | 'redact' | 'warn'`): Strategy when a pattern match is found. 'block' aborts with a TripWire error. 'redact' replaces matched content with replacement text. 'warn' logs a warning but passes content through unchanged. (Default: `'block'`)
|
|
77
|
+
|
|
78
|
+
**phase** (`'input' | 'output' | 'all'`): Phases to apply the filter. 'input' filters input messages. 'output' filters output stream and result. 'all' filters both. (Default: `'all'`)
|
|
79
|
+
|
|
80
|
+
## Returns
|
|
81
|
+
|
|
82
|
+
**id** (`'regex-filter'`): Processor identifier.
|
|
83
|
+
|
|
84
|
+
**name** (`'Regex Filter'`): Processor display name.
|
|
85
|
+
|
|
86
|
+
**processInput** (`(args: ProcessInputArgs) => ProcessInputResult`): Checks input messages against all configured rules. Blocks, redacts, or warns depending on strategy. Skipped when phase is output.
|
|
87
|
+
|
|
88
|
+
**processOutputStream** (`(args: ProcessOutputStreamArgs) => Promise<ChunkType | null | undefined>`): Checks streaming text-delta chunks against all configured rules. Skipped when phase is input.
|
|
89
|
+
|
|
90
|
+
**processOutputResult** (`(args: ProcessOutputResultArgs) => ProcessorMessageResult`): Checks output messages against all configured rules. Blocks, redacts, or warns depending on strategy. Skipped when phase is input.
|
|
91
|
+
|
|
92
|
+
## Error behavior
|
|
93
|
+
|
|
94
|
+
When the `block` strategy is active (default), `RegexFilterProcessor` throws a `TripWire` error with `retry: false` when any pattern matches. The TripWire metadata includes:
|
|
95
|
+
|
|
96
|
+
- `processorId`: `'regex-filter'`
|
|
97
|
+
- `matches`: Array of match objects with `rule`, `match` (redacted to `'[REDACTED_MATCH]'`), and `index`
|
|
98
|
+
- `strategy`: `'block'`
|
|
99
|
+
|
|
100
|
+
## Built-in presets
|
|
101
|
+
|
|
102
|
+
| Preset | Patterns | Default replacement |
|
|
103
|
+
| --------- | ------------------------------------------------ | ---------------------------------------------- |
|
|
104
|
+
| `pii` | Emails, phone numbers, SSNs, credit card numbers | `[EMAIL]`, `[PHONE]`, `[SSN]`, `[CREDIT_CARD]` |
|
|
105
|
+
| `secrets` | API keys, bearer tokens, AWS access keys | `[API_KEY]`, `[BEARER_TOKEN]`, `[AWS_KEY]` |
|
|
106
|
+
| `urls` | HTTP/HTTPS URLs | `[URL]` |
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
# Perplexity tools
|
|
2
2
|
|
|
3
|
-
Added in: `@mastra/perplexity@0.1.0-alpha.0`
|
|
4
|
-
|
|
5
3
|
The `@mastra/perplexity` package wraps the [Perplexity Search API](https://docs.perplexity.ai/docs/search/quickstart) as a Mastra-compatible tool. It exposes a factory function that returns a tool created with [`createTool()`](https://mastra.ai/reference/tools/create-tool) and full Zod input/output schemas.
|
|
6
4
|
|
|
7
5
|
For chat completions or agentic workflows powered by Perplexity, use Mastra's built-in [Perplexity model provider](https://mastra.ai/models/providers/perplexity) or [Perplexity Agent provider](https://mastra.ai/models/providers/perplexity-agent). Those are separate from this Search tool.
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
# Tavily tools
|
|
2
2
|
|
|
3
|
-
**Added in:** `@mastra/tavily@0.1.0-alpha.0`
|
|
4
|
-
|
|
5
3
|
The `@mastra/tavily` package wraps the [Tavily](https://app.tavily.com) API as Mastra-compatible tools. It exposes factory functions for search, extract, crawl, and map — each returning a tool created with [`createTool()`](https://mastra.ai/reference/tools/create-tool) that includes full Zod input/output schemas.
|
|
6
4
|
|
|
7
5
|
## Installation
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# @mastra/mcp-docs-server
|
|
2
2
|
|
|
3
|
+
## 1.1.33-alpha.5
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [[`86c0298`](https://github.com/mastra-ai/mastra/commit/86c0298e647306423c842f9d5ac827bd616bd13d), [`7fce309`](https://github.com/mastra-ai/mastra/commit/7fce30912b14170bfc41f0ac736cca0f39fe0cd4), [`86c0298`](https://github.com/mastra-ai/mastra/commit/86c0298e647306423c842f9d5ac827bd616bd13d), [`7997c2e`](https://github.com/mastra-ai/mastra/commit/7997c2e55ddd121562a4098cd8d2b89c68433bf1), [`e97ccb9`](https://github.com/mastra-ai/mastra/commit/e97ccb900f8b7a390ce82c9f8eb8d6eb2c5e3777), [`c5daf48`](https://github.com/mastra-ai/mastra/commit/c5daf48556e98c46ae06caf00f92c249912007e9), [`cd96779`](https://github.com/mastra-ai/mastra/commit/cd9677937f113b2856dc8b9f3d4bdabcee58bb2e)]:
|
|
8
|
+
- @mastra/core@1.32.0-alpha.2
|
|
9
|
+
- @mastra/mcp@1.6.1-alpha.1
|
|
10
|
+
|
|
3
11
|
## 1.1.33-alpha.2
|
|
4
12
|
|
|
5
13
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mastra/mcp-docs-server",
|
|
3
|
-
"version": "1.1.33-alpha.
|
|
3
|
+
"version": "1.1.33-alpha.6",
|
|
4
4
|
"description": "MCP server for accessing Mastra.ai documentation, changelogs, and news.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
"jsdom": "^26.1.0",
|
|
30
30
|
"local-pkg": "^1.1.2",
|
|
31
31
|
"zod": "^4.3.6",
|
|
32
|
-
"@mastra/
|
|
33
|
-
"@mastra/
|
|
32
|
+
"@mastra/core": "1.32.0-alpha.2",
|
|
33
|
+
"@mastra/mcp": "^1.6.1-alpha.1"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@hono/node-server": "^1.19.11",
|
|
@@ -46,9 +46,9 @@
|
|
|
46
46
|
"tsx": "^4.21.0",
|
|
47
47
|
"typescript": "^6.0.3",
|
|
48
48
|
"vitest": "4.1.5",
|
|
49
|
-
"@internal/types-builder": "0.0.65",
|
|
50
49
|
"@internal/lint": "0.0.90",
|
|
51
|
-
"@
|
|
50
|
+
"@internal/types-builder": "0.0.65",
|
|
51
|
+
"@mastra/core": "1.32.0-alpha.2"
|
|
52
52
|
},
|
|
53
53
|
"homepage": "https://mastra.ai",
|
|
54
54
|
"repository": {
|