@mastra/mcp-docs-server 1.2.19-alpha.15 → 1.2.19-alpha.16

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 (31) hide show
  1. package/.docs/docs/channels.md +27 -1
  2. package/.docs/docs/memory/semantic-recall.md +19 -0
  3. package/.docs/docs/observability/metrics/overview.md +31 -44
  4. package/.docs/docs/server/server-adapters.md +97 -26
  5. package/.docs/models/environment-variables.md +4 -0
  6. package/.docs/models/gateways/netlify.md +2 -1
  7. package/.docs/models/gateways/openrouter.md +3 -1
  8. package/.docs/models/gateways/vercel.md +5 -2
  9. package/.docs/models/index.md +1 -1
  10. package/.docs/models/providers/agnes.md +74 -0
  11. package/.docs/models/providers/cline-pass.md +4 -2
  12. package/.docs/models/providers/deepseek.md +4 -6
  13. package/.docs/models/providers/digitalocean.md +3 -3
  14. package/.docs/models/providers/edenai.md +4 -5
  15. package/.docs/models/providers/iteracompute.md +73 -0
  16. package/.docs/models/providers/kilo.md +9 -7
  17. package/.docs/models/providers/nano-gpt.md +8 -8
  18. package/.docs/models/providers/neosmith.md +104 -0
  19. package/.docs/models/providers/openai.md +2 -2
  20. package/.docs/models/providers/standardcompute.md +73 -0
  21. package/.docs/models/providers/vivgrid.md +2 -1
  22. package/.docs/models/providers/wandb.md +2 -1
  23. package/.docs/models/providers/zai.md +2 -1
  24. package/.docs/models/providers.md +4 -0
  25. package/.docs/reference/index.md +2 -0
  26. package/.docs/reference/observability/metrics/automatic-metrics.md +1 -1
  27. package/.docs/reference/observability/metrics/queries.md +462 -0
  28. package/.docs/reference/server/elysia-adapter.md +184 -0
  29. package/CHANGELOG.md +7 -0
  30. package/package.json +4 -4
  31. package/.docs/docs/observability/metrics/querying.md +0 -314
@@ -0,0 +1,184 @@
1
+ > Discover all available pages from the documentation index: https://mastra.ai/llms.txt
2
+
3
+ # Elysia adapter
4
+
5
+ The `@mastra/elysia` package provides a server adapter for running Mastra with [Elysia](https://elysiajs.com).
6
+
7
+ > **Note:** For general adapter concepts, constructor options, and initialization flow, see [Server Adapters](https://mastra.ai/docs/server/server-adapters).
8
+
9
+ ## Installation
10
+
11
+ Install the Elysia adapter and Elysia framework:
12
+
13
+ **npm**:
14
+
15
+ ```bash
16
+ npm install @mastra/elysia@latest elysia
17
+ ```
18
+
19
+ **pnpm**:
20
+
21
+ ```bash
22
+ pnpm add @mastra/elysia@latest elysia
23
+ ```
24
+
25
+ **Yarn**:
26
+
27
+ ```bash
28
+ yarn add @mastra/elysia@latest elysia
29
+ ```
30
+
31
+ **Bun**:
32
+
33
+ ```bash
34
+ bun add @mastra/elysia@latest elysia
35
+ ```
36
+
37
+ ## Usage example
38
+
39
+ ```typescript
40
+ import { Elysia } from 'elysia'
41
+ import { MastraServer } from '@mastra/elysia'
42
+ import { mastra } from './mastra'
43
+
44
+ const app = new Elysia()
45
+ const server = new MastraServer({ app, mastra })
46
+
47
+ await server.init()
48
+
49
+ app.listen(3000)
50
+
51
+ console.log('Server running on http://localhost:3000')
52
+ ```
53
+
54
+ ## Constructor parameters
55
+
56
+ **app** (`Elysia`): Elysia app instance
57
+
58
+ **mastra** (`Mastra`): Mastra instance
59
+
60
+ **prefix** (`string`): Route path prefix (e.g., /api/v2) (Default: `''`)
61
+
62
+ **openapiPath** (`string`): Path to serve OpenAPI spec (e.g., /openapi.json) (Default: `''`)
63
+
64
+ **bodyLimitOptions** (`BodyLimitOptions`): Request body size limits
65
+
66
+ **streamOptions** (`StreamOptions`): Stream redaction config. When true (default), redacts sensitive data from stream chunks before sending to clients. (Default: `{ redact: true }`)
67
+
68
+ **customRouteAuthConfig** (`Map<string, boolean>`): Per-route auth overrides. Keys are METHOD:PATH (e.g., GET:/api/health). Value false makes route public, true requires auth.
69
+
70
+ **tools** (`ToolsInput`): Available tools for the server
71
+
72
+ **taskStore** (`InMemoryTaskStore`): Task store for A2A (Agent-to-Agent) operations
73
+
74
+ **mcpOptions** (`MCPOptions`): MCP transport options. Set serverless: true for stateless environments like Vercel Edge.
75
+
76
+ ## Adding custom routes
77
+
78
+ Add routes directly to the Elysia app:
79
+
80
+ ```typescript
81
+ import { Elysia } from 'elysia'
82
+ import { MastraServer } from '@mastra/elysia'
83
+ import { mastra } from './mastra'
84
+
85
+ const app = new Elysia()
86
+ const server = new MastraServer({ app, mastra })
87
+
88
+ // Before init - runs before Mastra middleware
89
+ app.get('/early-health', () => ({ status: 'ok' }))
90
+
91
+ await server.init()
92
+
93
+ // After init - has access to Mastra context
94
+ app.get('/custom', ({ mastra }) => {
95
+ return { agents: Object.keys(mastra.listAgents()) }
96
+ })
97
+ ```
98
+
99
+ > **Tip:** Routes added before `init()` run without Mastra context. Add routes after `init()` to access the Mastra instance and request context.
100
+
101
+ When you want Mastra-managed auth and route metadata such as `requiresAuth`, prefer [`registerApiRoute()`](https://mastra.ai/reference/server/register-api-route). For raw Elysia routes mounted directly on `app`, use `createAuthMiddleware()`:
102
+
103
+ ```typescript
104
+ import { Elysia } from 'elysia'
105
+ import { createAuthMiddleware, MastraServer } from '@mastra/elysia'
106
+ import { mastra } from './mastra'
107
+
108
+ const app = new Elysia()
109
+ const server = new MastraServer({ app, mastra })
110
+
111
+ await server.init()
112
+
113
+ app.get('/custom/protected', async ctx => {
114
+ const authResponse = await createAuthMiddleware({ mastra })(ctx)
115
+ if (authResponse) return authResponse
116
+
117
+ const user = ctx.requestContext.get('user')
118
+ return { user }
119
+ })
120
+
121
+ app.get('/custom/public', async ctx => {
122
+ const authResponse = await createAuthMiddleware({ mastra, requiresAuth: false })(ctx)
123
+ if (authResponse) return authResponse
124
+
125
+ return { ok: true }
126
+ })
127
+ ```
128
+
129
+ ## Accessing context
130
+
131
+ In Elysia handlers registered after `init()`, access Mastra context from the handler context:
132
+
133
+ ```typescript
134
+ app.get('/custom', ({ mastra, requestContext, abortSignal }) => {
135
+ const agent = mastra.getAgent('myAgent')
136
+ const user = requestContext.get('user')
137
+
138
+ return { agent: agent.name, user, aborted: abortSignal.aborted }
139
+ })
140
+ ```
141
+
142
+ Available context keys:
143
+
144
+ | Key | Description |
145
+ | ----------------------- | -------------------------------------------------------------- |
146
+ | `mastra` | Mastra instance |
147
+ | `requestContext` | Request context map |
148
+ | `abortSignal` | Request cancellation signal |
149
+ | `registeredTools` | Available tools |
150
+ | `taskStore` | Task store for A2A operations |
151
+ | `customRouteAuthConfig` | Per-route auth overrides |
152
+ | `user` | Authenticated user in `requestContext` when auth is configured |
153
+
154
+ ## OpenAPI helpers
155
+
156
+ Use `getMastraOpenAPIDoc()` when you need to pass Mastra's generated OpenAPI document to Elysia tooling such as `@elysiajs/openapi`:
157
+
158
+ ```typescript
159
+ import { openapi } from '@elysiajs/openapi'
160
+ import { Elysia } from 'elysia'
161
+ import { getMastraOpenAPIDoc, MastraServer } from '@mastra/elysia'
162
+ import { mastra } from './mastra'
163
+
164
+ const app = new Elysia()
165
+ const server = new MastraServer({ app, mastra })
166
+
167
+ await server.init()
168
+
169
+ app.use(
170
+ openapi({
171
+ documentation: getMastraOpenAPIDoc(server),
172
+ }),
173
+ )
174
+ ```
175
+
176
+ Call `clearMastraOpenAPICache(server)` if you need to regenerate the cached document for the same server instance.
177
+
178
+ ## MCP support
179
+
180
+ The Elysia adapter supports both MCP HTTP and MCP SSE transports.
181
+
182
+ ## Manual initialization
183
+
184
+ For custom middleware ordering, call each method separately instead of `init()`. See [manual initialization](https://mastra.ai/docs/server/server-adapters) for details.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # @mastra/mcp-docs-server
2
2
 
3
+ ## 1.2.19-alpha.16
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [[`b05f486`](https://github.com/mastra-ai/mastra/commit/b05f48612984d5fe2447ea2d6cdd5c604d285b97), [`7960688`](https://github.com/mastra-ai/mastra/commit/7960688828e04eaf3106e34f7758fa580257eef6)]:
8
+ - @mastra/core@1.62.0-alpha.10
9
+
3
10
  ## 1.2.19-alpha.15
4
11
 
5
12
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mastra/mcp-docs-server",
3
- "version": "1.2.19-alpha.15",
3
+ "version": "1.2.19-alpha.16",
4
4
  "description": "MCP server for accessing Mastra.ai documentation, changelogs, and news.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -28,7 +28,7 @@
28
28
  "jsdom": "^26.1.0",
29
29
  "local-pkg": "^1.1.2",
30
30
  "zod": "^4.4.3",
31
- "@mastra/core": "1.62.0-alpha.9",
31
+ "@mastra/core": "1.62.0-alpha.10",
32
32
  "@mastra/mcp": "^1.17.2-alpha.2"
33
33
  },
34
34
  "devDependencies": {
@@ -45,9 +45,9 @@
45
45
  "tsx": "^4.23.1",
46
46
  "typescript": "^6.0.3",
47
47
  "vitest": "4.1.10",
48
+ "@internal/types-builder": "0.0.100",
48
49
  "@internal/lint": "0.0.125",
49
- "@mastra/core": "1.62.0-alpha.9",
50
- "@internal/types-builder": "0.0.100"
50
+ "@mastra/core": "1.62.0-alpha.10"
51
51
  },
52
52
  "homepage": "https://mastra.ai",
53
53
  "repository": {
@@ -1,314 +0,0 @@
1
- > Discover all available pages from the documentation index: https://mastra.ai/llms.txt
2
-
3
- # Querying metrics
4
-
5
- Mastra exposes the same five OLAP queries (`getMetricAggregate`, `getMetricBreakdown`, `getMetricTimeSeries`, `getMetricPercentiles`, and discovery helpers) through three surfaces: an in-process store accessor and the runtime HTTP API, plus the `mastra api metric` CLI. All three accept the same Zod-validated input shapes, so you can move from a one-off CLI investigation to a programmatic dashboard tool without re-learning the API.
6
-
7
- **For AI agents:** Run `npx mastra api metric aggregate '{"name":"mastra_agent_duration_ms","aggregation":"avg"}'` to query average agent latency directly instead of writing a temporary script. Querying local metrics requires a running Mastra server with an OLAP-capable observability store; start the local server with `npx mastra dev`, or pass the reachable server's base URL with `--url`. Run `npx mastra api metric aggregate --schema` before constructing a different query. Install Mastra's skill with `npx skills add mastra-ai/skills --skill mastra` for complete API CLI discovery, targeting, schema, authentication, and error-handling guidance.
8
-
9
- ## When to use this
10
-
11
- - Build a custom dashboard or KPI tile alongside Studio.
12
- - Power a scheduled alert that fires when token cost or latency crosses a threshold.
13
- - Give an agent a tool that reads its own performance metrics and explains them in chat.
14
- - Run one-off investigations from a terminal with `mastra api metric ...`.
15
-
16
- For setup of the observability store itself, see the [Metrics overview](https://mastra.ai/docs/observability/metrics/overview). For the list of metric names you can query, see the [Automatic metrics reference](https://mastra.ai/reference/observability/metrics/automatic-metrics).
17
-
18
- > **Note:** Metric queries are served by the observability domain, which requires an OLAP-capable store (DuckDB locally, ClickHouse in production). See [Metrics overview](https://mastra.ai/docs/observability/metrics/overview) for setup. If the observability store isn't configured, `getStore('observability')` returns `null`.
19
-
20
- ## Surfaces
21
-
22
- ### In-process
23
-
24
- Inside a tool, server route, or workflow step, get the observability store from the Mastra storage:
25
-
26
- ```typescript
27
- import { createTool } from '@mastra/core/tools'
28
- import { z } from 'zod'
29
-
30
- export const agentLatencyTool = createTool({
31
- id: 'agentLatency',
32
- description: 'Average agent latency over the last hour.',
33
- inputSchema: z.object({}),
34
- execute: async (_input, context) => {
35
- const observability = await context.mastra!.getStorage()!.getStore('observability')
36
- if (!observability) {
37
- throw new Error('Observability domain is not configured (requires DuckDB or ClickHouse)')
38
- }
39
-
40
- const result = await observability.getMetricAggregate({
41
- name: ['mastra_agent_duration_ms'],
42
- aggregation: 'avg',
43
- filters: {
44
- timestamp: { start: new Date(Date.now() - 60 * 60 * 1000) },
45
- },
46
- })
47
-
48
- return { averageMs: result.value }
49
- },
50
- })
51
- ```
52
-
53
- `getStore('observability')` returns `null` when the configured backend doesn't support OLAP queries.
54
-
55
- ### HTTP
56
-
57
- The `mastra dev` server (and any deployed Mastra runtime) exposes the same queries under `/api/observability/metrics/*`. Aggregate, breakdown, time series, and percentile endpoints take a JSON body with `POST`. Discovery endpoints use `GET` with query parameters.
58
-
59
- ```bash
60
- curl -sS -X POST http://localhost:4111/api/observability/metrics/aggregate \
61
- -H "content-type: application/json" \
62
- -d '{"name":["mastra_agent_duration_ms"],"aggregation":"avg"}'
63
- ```
64
-
65
- Available routes:
66
-
67
- - `POST /api/observability/metrics/aggregate`
68
- - `POST /api/observability/metrics/breakdown`
69
- - `POST /api/observability/metrics/timeseries`
70
- - `POST /api/observability/metrics/percentiles`
71
- - `GET /api/observability/metrics` (raw rows, paginated)
72
- - `GET /api/observability/discovery/metric-names`
73
- - `GET /api/observability/discovery/metric-label-keys`
74
- - `GET /api/observability/discovery/metric-label-values`
75
-
76
- The `@mastra/client-js` SDK wraps the same routes as `mastraClient.getMetricAggregate(...)`, `getMetricBreakdown(...)`, and so on.
77
-
78
- ### CLI
79
-
80
- `mastra api metric ...` calls the same endpoints with a single JSON argument, so an agent or shell script can fetch metrics without writing any code:
81
-
82
- ```bash
83
- mastra api metric aggregate \
84
- '{"name":["mastra_agent_duration_ms"],"aggregation":"avg"}' \
85
- --url http://localhost:4111
86
- ```
87
-
88
- 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.
89
-
90
- ## Queries
91
-
92
- ### `getMetricAggregate`
93
-
94
- Returns a single scalar, the building block for KPI cards.
95
-
96
- Inputs:
97
-
98
- - `name`: Array of one or more metric names.
99
- - `aggregation`: One of `'sum' | 'avg' | 'min' | 'max' | 'count' | 'count_distinct' | 'last'`.
100
- - `filters`: Optional [filter object](#filtering).
101
- - `comparePeriod`: Optional `'previous_period' | 'previous_day' | 'previous_week'` for period-over-period comparison.
102
-
103
- Response:
104
-
105
- - `value`, `previousValue`, `changePercent`.
106
- - `estimatedCost`, `costUnit`, `previousEstimatedCost`, `costChangePercent` for token metrics.
107
-
108
- ```typescript
109
- const observability = await mastra.getStorage()!.getStore('observability')
110
-
111
- const cost = await observability!.getMetricAggregate({
112
- name: ['mastra_model_total_input_tokens', 'mastra_model_total_output_tokens'],
113
- aggregation: 'sum',
114
- comparePeriod: 'previous_day',
115
- })
116
-
117
- console.log(cost.value, cost.estimatedCost, cost.costUnit, cost.changePercent)
118
- ```
119
-
120
- ### `getMetricBreakdown`
121
-
122
- Groups rows by one or more dimensions and aggregates each group, the building block for top-N tables (e.g. "tokens by agent").
123
-
124
- Inputs:
125
-
126
- - `name`: Array of metric names.
127
- - `groupBy`: Array of fields to group by (for example `['entityName']`).
128
- - `aggregation`: Same enum as above.
129
- - `limit`: Server-side top-K cap. Required for high-cardinality `groupBy`.
130
- - `orderDirection`: `'ASC' | 'DESC'` (defaults to `DESC`).
131
- - `filters`: Optional.
132
-
133
- Response: `groups[]`, each with `dimensions` (record of group keys to values), `value`, and `estimatedCost`.
134
-
135
- ```typescript
136
- const byAgent = await observability!.getMetricBreakdown({
137
- name: ['mastra_model_total_input_tokens'],
138
- groupBy: ['entityName'],
139
- aggregation: 'sum',
140
- limit: 10,
141
- orderDirection: 'DESC',
142
- })
143
- ```
144
-
145
- ### `getMetricTimeSeries`
146
-
147
- Buckets values by a fixed interval, the building block for line and bar charts.
148
-
149
- Inputs:
150
-
151
- - `name`: Array of metric names.
152
- - `interval`: One of `'1m' | '5m' | '15m' | '1h' | '1d'`.
153
- - `aggregation`: Same enum.
154
- - `groupBy`: Optional. When omitted, multiple metric names are summed into one series. Use one call per metric to keep them separate.
155
- - `filters`: Optional.
156
-
157
- Response: `series[]`, each with `name`, `costUnit`, and `points[]` of `{ timestamp, value, estimatedCost }`.
158
-
159
- ```typescript
160
- const inputTokens = await observability!.getMetricTimeSeries({
161
- name: ['mastra_model_total_input_tokens'],
162
- aggregation: 'sum',
163
- interval: '1h',
164
- filters: {
165
- timestamp: { start: new Date(Date.now() - 24 * 60 * 60 * 1000) },
166
- },
167
- })
168
- ```
169
-
170
- ### `getMetricPercentiles`
171
-
172
- Returns percentile values bucketed by time, the building block for latency charts.
173
-
174
- Inputs:
175
-
176
- - `name`: Single metric name (string, not array).
177
- - `percentiles`: Array of numbers between `0` and `1`, for example `[0.5, 0.95, 0.99]`.
178
- - `interval`: Same enum as `getMetricTimeSeries`.
179
- - `filters`: Optional.
180
-
181
- Response: `series[]`, each with `percentile` and `points[]` of `{ timestamp, value }`.
182
-
183
- ```typescript
184
- const latency = await observability!.getMetricPercentiles({
185
- name: 'mastra_agent_duration_ms',
186
- percentiles: [0.5, 0.95],
187
- interval: '1h',
188
- })
189
- ```
190
-
191
- ### Discovery
192
-
193
- Use these endpoints to populate dropdowns or to give an agent the menu of values it can filter by. All discovery routes are `GET` and live under `/api/observability/discovery/`.
194
-
195
- **Metric-specific** (also exposed as `mastra api metric` subcommands):
196
-
197
- | Method | Args | Path suffix | CLI |
198
- | ---------------------- | ------------------------------------------- | --------------------- | -------------------------------- |
199
- | `getMetricNames` | `{ prefix?, limit? }` | `metric-names` | `mastra api metric names` |
200
- | `getMetricLabelKeys` | `{ metricName }` | `metric-label-keys` | `mastra api metric label-keys` |
201
- | `getMetricLabelValues` | `{ metricName, labelKey, prefix?, limit? }` | `metric-label-values` | `mastra api metric label-values` |
202
-
203
- **Shared with traces and logs** (HTTP-only, no dedicated CLI subcommand):
204
-
205
- | Method | Args | Path suffix |
206
- | ----------------- | ----------------- | --------------- |
207
- | `getEntityTypes` | `{}` | `entity-types` |
208
- | `getEntityNames` | `{ entityType? }` | `entity-names` |
209
- | `getServiceNames` | `{}` | `service-names` |
210
- | `getEnvironments` | `{}` | `environments` |
211
- | `getTags` | `{ entityType? }` | `tags` |
212
-
213
- ## Filtering
214
-
215
- Every query accepts the same `filters` object. The most useful fields:
216
-
217
- - `name`: Restrict to specific metric names. (Top-level `name` already does this for aggregate/breakdown/timeseries. Use `filters.name` when you want to mix multiple metrics under a single query.)
218
- - `timestamp`: `{ start, end, startExclusive, endExclusive }`. Both bounds are optional. Omit `end` for "until now".
219
- - `provider`, `model`, `costUnit`: For token and cost metrics.
220
- - `labels`: Exact key-value match on metric labels, for example `{ status: 'error' }` for duration metrics.
221
- - Correlation fields: `entityType`, `entityName`, `parentEntityName`, `rootEntityName`, `userId`, `organizationId`, `resourceId`, `runId`, `sessionId`, `threadId`, `requestId`, `executionSource`, `environment`, `serviceName`, `experimentId`, `tags`.
222
-
223
- The same `filters` shape works across all three surfaces:
224
-
225
- ```typescript
226
- // In-process
227
- await observability!.getMetricAggregate({
228
- name: ['mastra_tool_duration_ms'],
229
- aggregation: 'avg',
230
- filters: { entityName: 'weatherTool', labels: { status: 'error' } },
231
- })
232
- ```
233
-
234
- ```bash
235
- # CLI
236
- mastra api metric aggregate \
237
- '{"name":["mastra_tool_duration_ms"],"aggregation":"avg","filters":{"entityName":"weatherTool","labels":{"status":"error"}}}' \
238
- --url http://localhost:4111
239
- ```
240
-
241
- ```bash
242
- # HTTP
243
- curl -sS -X POST http://localhost:4111/api/observability/metrics/aggregate \
244
- -H "content-type: application/json" \
245
- -d '{"name":["mastra_tool_duration_ms"],"aggregation":"avg","filters":{"entityName":"weatherTool","labels":{"status":"error"}}}'
246
- ```
247
-
248
- ### Always provide a time range
249
-
250
- `filters.timestamp` is optional, but you should treat it as required for any query that runs against a production store. Observability tables are typically partitioned (or chunked, for TimescaleDB) by event time. When you supply `timestamp.start` (and ideally `end`), the backend can prune to the partitions that overlap the range, usually one or two. Without a time range, the planner has to scan every partition, which can be hundreds of segments over a year of retention and is the most common cause of slow OLAP queries on Postgres-backed stores.
251
-
252
- A safe default for ad-hoc queries is the last 24 hours; alerts and dashboards should match their actual evaluation window:
253
-
254
- ```typescript
255
- await observability!.getMetricAggregate({
256
- name: ['mastra_agent_duration_ms'],
257
- aggregation: 'p95',
258
- filters: {
259
- timestamp: { start: new Date(Date.now() - 24 * 60 * 60 * 1000) },
260
- },
261
- })
262
- ```
263
-
264
- This guidance applies to all backends (ClickHouse, Postgres v-next, DuckDB), but matters most for Postgres v-next where each missing time bound translates directly into one extra partition scan.
265
-
266
- ## Example: build a custom KPI tile
267
-
268
- The following tool returns input-token volume and estimated cost for the last hour. An agent or a dashboard can call it as `structuredContent` without re-implementing the query.
269
-
270
- ```typescript
271
- import { createTool } from '@mastra/core/tools'
272
- import { z } from 'zod'
273
-
274
- export const tokenKpiTool = createTool({
275
- id: 'tokenKpi',
276
- description: 'Returns input-token volume and estimated cost for the last hour.',
277
- inputSchema: z.object({}),
278
- outputSchema: z.object({
279
- inputTokens: z.number().nullable(),
280
- estimatedCost: z.number().nullable(),
281
- costUnit: z.string().nullable(),
282
- changePercent: z.number().nullable(),
283
- }),
284
- execute: async (_input, context) => {
285
- const observability = await context.mastra!.getStorage()!.getStore('observability')
286
- if (!observability) {
287
- throw new Error('Observability domain is not configured (requires DuckDB or ClickHouse)')
288
- }
289
-
290
- const result = await observability.getMetricAggregate({
291
- name: ['mastra_model_total_input_tokens'],
292
- aggregation: 'sum',
293
- filters: {
294
- timestamp: { start: new Date(Date.now() - 60 * 60 * 1000) },
295
- },
296
- comparePeriod: 'previous_period',
297
- })
298
-
299
- return {
300
- inputTokens: result.value,
301
- estimatedCost: result.estimatedCost ?? null,
302
- costUnit: result.costUnit ?? null,
303
- changePercent: result.changePercent ?? null,
304
- }
305
- },
306
- })
307
- ```
308
-
309
- ## Related
310
-
311
- - [Metrics overview](https://mastra.ai/docs/observability/metrics/overview)
312
- - [Automatic metrics reference](https://mastra.ai/reference/observability/metrics/automatic-metrics)
313
- - [CLI: `mastra api metric ...`](https://mastra.ai/reference/cli/mastra)
314
- - [Studio observability](https://mastra.ai/docs/studio/observability)