@mastra/mcp-docs-server 1.2.8-alpha.2 → 1.2.8-alpha.23
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/agent-builder/integrations.md +1 -3
- package/.docs/docs/agents/overview.md +17 -13
- package/.docs/docs/agents/skills.md +1 -3
- package/.docs/docs/agents/structured-output.md +14 -7
- package/.docs/docs/agents/using-tools.md +66 -49
- package/.docs/docs/browser/agent-browser.md +1 -0
- package/.docs/docs/browser/firecrawl.md +129 -0
- package/.docs/docs/browser/overview.md +16 -2
- package/.docs/docs/capabilities/channels/slack.md +111 -1
- package/.docs/docs/deployment/mastra-server.md +35 -0
- package/.docs/docs/deployment/monorepo.md +2 -0
- package/.docs/docs/deployment/overview.md +6 -0
- package/.docs/docs/deployment/sandbox.md +277 -0
- package/.docs/docs/editor/overview.md +2 -6
- package/.docs/docs/editor/tools.md +2 -6
- package/.docs/docs/evals/multi-turn.md +178 -0
- package/.docs/docs/evals/overview.md +1 -0
- package/.docs/docs/evals/running-in-ci.md +3 -9
- package/.docs/docs/getting-started/build-with-ai.md +2 -6
- package/.docs/docs/getting-started/manual-install.md +1 -1
- package/.docs/docs/index.md +17 -13
- package/.docs/docs/long-running-agents/background-tasks.md +2 -2
- package/.docs/docs/long-running-agents/durable-agents.md +2 -1
- package/.docs/docs/long-running-agents/goals.md +3 -1
- package/.docs/docs/mastra-platform/database.md +12 -6
- package/.docs/docs/mastra-platform/deploy.md +14 -7
- package/.docs/docs/mastra-platform/environments.md +5 -4
- package/.docs/docs/mastra-platform/observability.md +4 -12
- package/.docs/docs/mastra-platform/overview.md +1 -1
- package/.docs/docs/mastra-platform/regions.md +73 -0
- package/.docs/docs/mastra-platform/workspace.md +111 -0
- package/.docs/docs/mcp/overview.md +1 -1
- package/.docs/docs/memory/observational-memory.md +77 -2
- package/.docs/docs/memory/overview.md +4 -0
- package/.docs/docs/observability/feedback.md +4 -0
- package/.docs/docs/observability/integrations/bridges/otel.md +1 -3
- package/.docs/docs/observability/integrations/exporters/otel.md +1 -3
- package/.docs/docs/server/auth/fga.md +40 -0
- package/.docs/docs/server/auth/simple-auth.md +1 -3
- package/.docs/docs/server/request-context.md +2 -0
- package/.docs/docs/studio/overview.md +2 -0
- package/.docs/docs/workflows/control-flow.md +1 -3
- package/.docs/docs/workspace/filesystem.md +1 -0
- package/.docs/docs/workspace/sandbox.md +1 -0
- package/.docs/guides/getting-started/quickstart.md +40 -25
- package/.docs/guides/index.md +1 -1
- package/.docs/guides/migrations/vnext-to-standard-apis.md +1 -3
- package/.docs/models/environment-variables.md +3 -0
- package/.docs/models/gateways/netlify.md +3 -1
- package/.docs/models/gateways/openrouter.md +343 -345
- package/.docs/models/gateways/vercel.md +8 -5
- package/.docs/models/index.md +1 -1
- package/.docs/models/providers/aki-io.md +78 -0
- package/.docs/models/providers/alibaba-token-plan-cn.md +22 -21
- package/.docs/models/providers/alibaba-token-plan.md +22 -21
- package/.docs/models/providers/ambient.md +12 -10
- package/.docs/models/providers/baseten.md +3 -2
- package/.docs/models/providers/cline-pass.md +82 -0
- package/.docs/models/providers/crossmodel.md +2 -1
- package/.docs/models/providers/deepinfra.md +4 -7
- package/.docs/models/providers/deepseek.md +3 -1
- package/.docs/models/providers/empiriolabs.md +2 -1
- package/.docs/models/providers/evroc.md +3 -2
- package/.docs/models/providers/google.md +6 -4
- package/.docs/models/providers/inferx.md +3 -3
- package/.docs/models/providers/kilo.md +1 -1
- package/.docs/models/providers/kimi-for-coding.md +10 -11
- package/.docs/models/providers/llmgateway.md +5 -8
- package/.docs/models/providers/moonshotai-cn.md +3 -2
- package/.docs/models/providers/moonshotai.md +3 -2
- package/.docs/models/providers/nebius.md +3 -1
- package/.docs/models/providers/novita-ai.md +3 -1
- package/.docs/models/providers/ollama-cloud.md +25 -42
- package/.docs/models/providers/opencode-go.md +5 -3
- package/.docs/models/providers/opencode.md +4 -2
- package/.docs/models/providers/orcarouter.md +1 -1
- package/.docs/models/providers/privatemode-ai.md +10 -10
- package/.docs/models/providers/thinkingmachines.md +73 -0
- package/.docs/models/providers/togetherai.md +2 -6
- package/.docs/models/providers/wandb.md +2 -1
- package/.docs/models/providers/zenmux.md +3 -1
- package/.docs/models/providers.md +3 -0
- package/.docs/reference/acp/acp-agent.md +2 -0
- package/.docs/reference/acp/create-acp-tool.md +28 -0
- package/.docs/reference/agent-controller/session.md +15 -0
- package/.docs/reference/agents/agent.md +13 -1
- package/.docs/reference/agents/durable-agent.md +23 -0
- package/.docs/reference/agents/generate.md +19 -1
- package/.docs/reference/browser/firecrawl-browser.md +71 -0
- package/.docs/reference/cli/create-mastra.md +118 -43
- package/.docs/reference/cli/mastra.md +47 -5
- package/.docs/reference/code-sdk/mount-agent-controller.md +4 -4
- package/.docs/reference/core/getMCPServer.md +1 -3
- package/.docs/reference/core/getMCPServerById.md +1 -3
- package/.docs/reference/core/getWorkflow.md +1 -3
- package/.docs/reference/core/listMCPServers.md +2 -6
- package/.docs/reference/datasets/addItem.md +1 -3
- package/.docs/reference/datasets/addItems.md +1 -3
- package/.docs/reference/datasets/compareExperiments.md +1 -3
- package/.docs/reference/datasets/create.md +1 -3
- package/.docs/reference/datasets/dataset.md +2 -6
- package/.docs/reference/datasets/datasets-manager.md +5 -15
- package/.docs/reference/datasets/delete.md +1 -3
- package/.docs/reference/datasets/deleteExperiment.md +1 -3
- package/.docs/reference/datasets/deleteItem.md +1 -3
- package/.docs/reference/datasets/deleteItems.md +1 -3
- package/.docs/reference/datasets/get.md +1 -3
- package/.docs/reference/datasets/getDetails.md +1 -3
- package/.docs/reference/datasets/getExperiment.md +1 -3
- package/.docs/reference/datasets/getItem.md +1 -3
- package/.docs/reference/datasets/getItemHistory.md +1 -3
- package/.docs/reference/datasets/list.md +1 -3
- package/.docs/reference/datasets/listExperimentResults.md +1 -3
- package/.docs/reference/datasets/listExperiments.md +1 -3
- package/.docs/reference/datasets/listItems.md +1 -3
- package/.docs/reference/datasets/listVersions.md +1 -3
- package/.docs/reference/datasets/startExperiment.md +1 -3
- package/.docs/reference/datasets/startExperimentAsync.md +1 -3
- package/.docs/reference/datasets/update.md +1 -3
- package/.docs/reference/datasets/updateItem.md +1 -3
- package/.docs/reference/editor/mastra-editor.md +1 -3
- package/.docs/reference/evals/context-recall.md +205 -0
- package/.docs/reference/evals/create-scorer.md +4 -10
- package/.docs/reference/evals/mastra-scorer.md +1 -3
- package/.docs/reference/evals/run-evals.md +94 -2
- package/.docs/reference/file-based-agents/tools.md +7 -6
- package/.docs/reference/index.md +5 -0
- package/.docs/reference/memory/observational-memory.md +21 -0
- package/.docs/reference/observability/tracing/exporters/posthog.md +39 -1
- package/.docs/reference/observability/tracing/processors/sensitive-data-filter.md +1 -3
- package/.docs/reference/processors/token-limiter-processor.md +1 -3
- package/.docs/reference/rag/database-config.md +12 -0
- package/.docs/reference/streaming/agents/stream.md +3 -1
- package/.docs/reference/templates/overview.md +6 -32
- package/.docs/reference/tools/create-tool.md +78 -52
- package/.docs/reference/tools/mcp-client.md +104 -24
- package/.docs/reference/tools/mcp-server.md +143 -44
- package/.docs/reference/tools/tavily.md +1 -1
- package/.docs/reference/tools/vector-query-tool.md +22 -0
- package/.docs/reference/vectors/mongodb.md +2 -0
- package/.docs/reference/vectors/turbopuffer.md +4 -0
- package/.docs/reference/voice/mistral.md +127 -0
- package/.docs/reference/workspace/daytona-sandbox.md +2 -6
- package/.docs/reference/workspace/platform-filesystem.md +182 -0
- package/.docs/reference/workspace/platform-sandbox.md +200 -0
- package/.docs/reference/workspace/railway-sandbox.md +37 -1
- package/CHANGELOG.md +78 -0
- package/dist/{chunk-GLPCVXXO.js → chunk-HGADBLKG.js} +2 -2
- package/dist/{chunk-GLPCVXXO.js.map → chunk-HGADBLKG.js.map} +1 -1
- package/dist/index.js +1 -1
- package/dist/stdio.js +1 -1
- package/dist/tools/docs.d.ts.map +1 -1
- package/package.json +7 -7
|
@@ -37,9 +37,7 @@ import { MastraEditor } from '@mastra/editor'
|
|
|
37
37
|
import { ComposioToolProvider } from '@mastra/editor/composio'
|
|
38
38
|
|
|
39
39
|
export const mastra = new Mastra({
|
|
40
|
-
agents: {
|
|
41
|
-
/* your agents */
|
|
42
|
-
},
|
|
40
|
+
agents: {/* your agents */},
|
|
43
41
|
editor: new MastraEditor({
|
|
44
42
|
toolProviders: {
|
|
45
43
|
composio: new ComposioToolProvider({
|
|
@@ -44,17 +44,31 @@ export const weatherTool = createTool({
|
|
|
44
44
|
location: z.string().describe('City name'),
|
|
45
45
|
}),
|
|
46
46
|
outputSchema: z.object({
|
|
47
|
-
|
|
47
|
+
location: z.string(),
|
|
48
|
+
temperatureCelsius: z.number(),
|
|
49
|
+
conditions: z.string(),
|
|
48
50
|
}),
|
|
49
51
|
execute: async ({ location }) => {
|
|
50
52
|
return {
|
|
51
|
-
|
|
53
|
+
location,
|
|
54
|
+
temperatureCelsius: 21,
|
|
55
|
+
conditions: 'sunny',
|
|
52
56
|
}
|
|
53
57
|
},
|
|
54
58
|
})
|
|
55
59
|
```
|
|
56
60
|
|
|
57
|
-
If you need to create an agent, create a new file and use `import { Agent } from "@mastra/core/agent"`. The constructor takes `{ id, name, instructions, model }`. The `model` property is a string in Mastra's model router format
|
|
61
|
+
If you need to create an agent, create a new file and use `import { Agent } from "@mastra/core/agent"`. The constructor takes `{ id, name, instructions, model }`. The `model` property is a string in Mastra's model router format. No provider import is needed for this format. Don't install any AI SDK package unless Mastra's documentation says otherwise.
|
|
62
|
+
|
|
63
|
+
By defining the model using `provider/model` format Mastra automatically looks for environment variables for the given provider. The defined model requires an environment variable to be set for the provider. OpenAI: `OPENAI_API_KEY`. Anthropic: `ANTHROPIC_API_KEY`. Google: `GOOGLE_API_KEY`. Example: Any `openai/<model>` requires the `OPENAI_API_KEY` environment variable. Go to <https://mastra.ai/models/environment-variables> for a full list of supported providers and their environment variable names.
|
|
64
|
+
|
|
65
|
+
Short list of known model IDs are:
|
|
66
|
+
|
|
67
|
+
- `openai/gpt-5.5`, `openai/gpt-5-mini`
|
|
68
|
+
- `anthropic/claude-sonnet-4-6`, `anthropic/claude-opus-4-7`, `anthropic/claude-haiku-4-5`
|
|
69
|
+
- `google/gemini-2.5-flash`
|
|
70
|
+
|
|
71
|
+
Go to <https://mastra.ai/models> for a full list of supported models.
|
|
58
72
|
|
|
59
73
|
Add a tool an agent by importing the tool and passing it to the agent constructor as a tools object.
|
|
60
74
|
|
|
@@ -83,16 +97,6 @@ export const weatherAgent = new Agent({
|
|
|
83
97
|
})
|
|
84
98
|
```
|
|
85
99
|
|
|
86
|
-
By defining the model using `provider/model` format Mastra automatically looks for environment variables for the given provider. The defined model requires an environment variable to be set for the provider. OpenAI: `OPENAI_API_KEY`. Anthropic: `ANTHROPIC_API_KEY`. Google: `GOOGLE_API_KEY`. Example: Any `openai/<model>` requires the `OPENAI_API_KEY` environment variable. Go to <https://mastra.ai/models/environment-variables> for a full list of supported providers and their environment variable names.
|
|
87
|
-
|
|
88
|
-
Short list of known model IDs are:
|
|
89
|
-
|
|
90
|
-
- `openai/gpt-5.5`, `openai/gpt-5-mini`
|
|
91
|
-
- `anthropic/claude-sonnet-4-6`, `anthropic/claude-opus-4-7`, `anthropic/claude-haiku-4-5`
|
|
92
|
-
- `google/gemini-2.5-flash`
|
|
93
|
-
|
|
94
|
-
Go to <https://mastra.ai/models> for a full list of supported models.
|
|
95
|
-
|
|
96
100
|
Create a Mastra entry point at `src/mastra/index.ts` and register the agent:
|
|
97
101
|
|
|
98
102
|
```ts
|
|
@@ -85,9 +85,7 @@ export const agent = new Agent({
|
|
|
85
85
|
skills: [
|
|
86
86
|
'./skills/code-review', // path to a SKILL.md directory
|
|
87
87
|
'./skills/testing', // another filesystem skill
|
|
88
|
-
createSkill({
|
|
89
|
-
/* ... */
|
|
90
|
-
}), // inline skill
|
|
88
|
+
createSkill({/* ... */}), // inline skill
|
|
91
89
|
],
|
|
92
90
|
})
|
|
93
91
|
```
|
|
@@ -197,9 +197,9 @@ If your tools aren't being called when structured output is enabled, or you rece
|
|
|
197
197
|
|
|
198
198
|
When your model doesn't support tools and structured output together, you have three options:
|
|
199
199
|
|
|
200
|
-
1. **Use `jsonPromptInjection
|
|
201
|
-
2. **Use a separate structuring model
|
|
202
|
-
3. **Use `prepareStep
|
|
200
|
+
1. **Use `jsonPromptInjection`**: Set it to `'auto'` to select native structured output when supported and inline prompt injection otherwise, or choose an explicit injection mode
|
|
201
|
+
2. **Use a separate structuring model**: Pass a `model` to `structuredOutput` to use a second LLM for structuring
|
|
202
|
+
3. **Use `prepareStep`**: Handle tools and structured output in separate steps
|
|
203
203
|
|
|
204
204
|
Each approach is detailed in the sections below.
|
|
205
205
|
|
|
@@ -209,9 +209,7 @@ Structured output support varies across LLMs due to differences in their APIs. T
|
|
|
209
209
|
|
|
210
210
|
### `jsonPromptInjection`
|
|
211
211
|
|
|
212
|
-
By default, Mastra passes the schema to the model provider using the `response_format` API parameter.
|
|
213
|
-
|
|
214
|
-
If your model provider doesn't support `response_format`, you'll get an error from the API. When this happens, set `jsonPromptInjection: true`. This adds the schema to the system prompt instead, instructing the model to output JSON. This is less reliable than the API parameter approach.
|
|
212
|
+
By default, Mastra passes the schema to the model provider using the `response_format` API parameter. Set `jsonPromptInjection: 'auto'` to let Mastra choose the mode from its model capability data. Mastra uses native structured output for supported models and inline prompt injection for unsupported models or models without capability data.
|
|
215
213
|
|
|
216
214
|
```typescript
|
|
217
215
|
import { z } from 'zod'
|
|
@@ -224,13 +222,20 @@ const response = await testAgent.generate('Help me plan my day.', {
|
|
|
224
222
|
activities: z.array(z.string()),
|
|
225
223
|
}),
|
|
226
224
|
),
|
|
227
|
-
jsonPromptInjection:
|
|
225
|
+
jsonPromptInjection: 'auto',
|
|
228
226
|
},
|
|
229
227
|
})
|
|
230
228
|
|
|
231
229
|
console.log(response.object)
|
|
232
230
|
```
|
|
233
231
|
|
|
232
|
+
Use an explicit mode when you need to override the capability-based choice:
|
|
233
|
+
|
|
234
|
+
- `false` or omitted: Use the provider's native structured output.
|
|
235
|
+
- `'inline'`: Add the schema instructions to the latest user message.
|
|
236
|
+
- `true` or `'system'`: Add the schema instructions to the system message.
|
|
237
|
+
- `'auto'`: Use native structured output when the model supports it. Otherwise, use inline prompt injection.
|
|
238
|
+
|
|
234
239
|
> **Gemini 2.5 with tools:** Gemini 2.5 models don't support combining `response_format` (structured output) with function calling (tools) in the same API call. If your agent has tools and you're using `structuredOutput` with a Gemini 2.5 model, you must set `jsonPromptInjection: true` to avoid the error `Function calling with a response mime type: 'application/json' is unsupported`.
|
|
235
240
|
>
|
|
236
241
|
> ```typescript
|
|
@@ -246,6 +251,8 @@ console.log(response.object)
|
|
|
246
251
|
|
|
247
252
|
When `model` is provided to the `structuredOutput` property, Mastra uses a separate internal agent to handle the structured output. The main agent will handle all of the steps (including tool calling) and the structured output model will handle only the generation of structured output.
|
|
248
253
|
|
|
254
|
+
**For AI agents:** The `model` property is a string in Mastra's model router format: `provider/model`, for example `openai/gpt-5.5`, `openai/gpt-5-mini`, `anthropic/claude-sonnet-4-6` or `google/gemini-2.5-pro`. Use `/` and not `:` as a separator. Example: `openai/<model>`, not `openai:<model>`, and don't pass a provider object. No provider import is needed for this format. Don't install any AI SDK package unless Mastra's documentation says otherwise. By defining the model using `provider/model` format Mastra automatically looks for environment variables for the given provider. The defined model requires an environment variable to be set for the provider. OpenAI: `OPENAI_API_KEY`. Anthropic: `ANTHROPIC_API_KEY`. Google: `GOOGLE_API_KEY`.
|
|
255
|
+
|
|
249
256
|
```typescript
|
|
250
257
|
const response = await testAgent.generate('Tell me about TypeScript.', {
|
|
251
258
|
structuredOutput: {
|
|
@@ -14,7 +14,7 @@ Use tools when an agent needs additional context or information from remote reso
|
|
|
14
14
|
|
|
15
15
|
Import [`createTool`](https://mastra.ai/reference/tools/create-tool) from `@mastra/core/tools` and define a tool with an `id`, `description`, `inputSchema`, `outputSchema`, and `execute` function.
|
|
16
16
|
|
|
17
|
-
This example
|
|
17
|
+
This example creates a tool that fetches weather data from an API. The `execute` function receives input validated against `inputSchema` as its first argument and an optional execution context as its second. You can destructure the input fields directly in the function signature.
|
|
18
18
|
|
|
19
19
|
```typescript
|
|
20
20
|
import { createTool } from '@mastra/core/tools'
|
|
@@ -27,15 +27,21 @@ export const weatherTool = createTool({
|
|
|
27
27
|
location: z.string(),
|
|
28
28
|
}),
|
|
29
29
|
outputSchema: z.object({
|
|
30
|
-
|
|
30
|
+
location: z.string(),
|
|
31
|
+
temperatureCelsius: z.number(),
|
|
32
|
+
conditions: z.string(),
|
|
31
33
|
}),
|
|
32
|
-
execute: async
|
|
33
|
-
const {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
const
|
|
34
|
+
execute: async ({ location }, { abortSignal }) => {
|
|
35
|
+
const response = await fetch(`https://wttr.in/${location}?format=j1`, {
|
|
36
|
+
signal: abortSignal,
|
|
37
|
+
})
|
|
38
|
+
const data = await response.json()
|
|
37
39
|
|
|
38
|
-
return {
|
|
40
|
+
return {
|
|
41
|
+
location,
|
|
42
|
+
temperatureCelsius: Number(data.current_condition[0].temp_C),
|
|
43
|
+
conditions: data.current_condition[0].weatherDesc[0].value,
|
|
44
|
+
}
|
|
39
45
|
},
|
|
40
46
|
})
|
|
41
47
|
```
|
|
@@ -76,10 +82,12 @@ export const weatherTool = createTool({
|
|
|
76
82
|
location: z.string(),
|
|
77
83
|
}),
|
|
78
84
|
outputSchema: z.object({
|
|
79
|
-
|
|
85
|
+
location: z.string(),
|
|
86
|
+
temperatureCelsius: z.number(),
|
|
87
|
+
conditions: z.string(),
|
|
80
88
|
}),
|
|
81
|
-
execute: async
|
|
82
|
-
|
|
89
|
+
execute: async ({ location }) => {
|
|
90
|
+
return { location, temperatureCelsius: 21, conditions: 'sunny' }
|
|
83
91
|
},
|
|
84
92
|
})
|
|
85
93
|
```
|
|
@@ -101,11 +109,13 @@ export const weatherTool = createTool({
|
|
|
101
109
|
),
|
|
102
110
|
outputSchema: toStandardJsonSchema(
|
|
103
111
|
v.object({
|
|
104
|
-
|
|
112
|
+
location: v.string(),
|
|
113
|
+
temperatureCelsius: v.number(),
|
|
114
|
+
conditions: v.string(),
|
|
105
115
|
}),
|
|
106
116
|
),
|
|
107
|
-
execute: async
|
|
108
|
-
|
|
117
|
+
execute: async ({ location }) => {
|
|
118
|
+
return { location, temperatureCelsius: 21, conditions: 'sunny' }
|
|
109
119
|
},
|
|
110
120
|
})
|
|
111
121
|
```
|
|
@@ -123,10 +133,12 @@ export const weatherTool = createTool({
|
|
|
123
133
|
location: 'string',
|
|
124
134
|
}),
|
|
125
135
|
outputSchema: type({
|
|
126
|
-
|
|
136
|
+
location: 'string',
|
|
137
|
+
temperatureCelsius: 'number',
|
|
138
|
+
conditions: 'string',
|
|
127
139
|
}),
|
|
128
|
-
execute: async
|
|
129
|
-
|
|
140
|
+
execute: async ({ location }) => {
|
|
141
|
+
return { location, temperatureCelsius: 21, conditions: 'sunny' }
|
|
130
142
|
},
|
|
131
143
|
})
|
|
132
144
|
```
|
|
@@ -195,40 +207,44 @@ export const researchAgent = new Agent({
|
|
|
195
207
|
|
|
196
208
|
## Share tools across agents
|
|
197
209
|
|
|
198
|
-
Direct imports are the
|
|
210
|
+
Direct imports are the best choice when one tool is used by multiple agents. Each agent imports the tool and adds it to its `tools` record. Dependencies remain explicit and each agent can be used independently.
|
|
199
211
|
|
|
200
|
-
|
|
212
|
+
```typescript
|
|
213
|
+
import { createTool } from '@mastra/core/tools'
|
|
214
|
+
|
|
215
|
+
export const weatherTool = createTool({
|
|
216
|
+
id: 'weather-tool',
|
|
217
|
+
// Rest of the tool definition...
|
|
218
|
+
})
|
|
219
|
+
```
|
|
201
220
|
|
|
202
221
|
```typescript
|
|
203
222
|
import { Agent } from '@mastra/core/agent'
|
|
204
|
-
import {
|
|
205
|
-
import { weatherTool } from './tools/weather-tool'
|
|
223
|
+
import { weatherTool } from '../tools/weather-tool'
|
|
206
224
|
|
|
207
|
-
export const
|
|
208
|
-
id: '
|
|
209
|
-
name: '
|
|
210
|
-
instructions:
|
|
211
|
-
You are a helpful weather assistant.
|
|
212
|
-
Use the weatherTool to fetch current weather data.`,
|
|
225
|
+
export const weatherAgent = new Agent({
|
|
226
|
+
id: 'weather-agent',
|
|
227
|
+
name: 'Weather Agent',
|
|
228
|
+
instructions: 'Answer questions about current weather.',
|
|
213
229
|
model: 'openai/gpt-5.5',
|
|
214
|
-
tools:
|
|
215
|
-
if (!mastra) {
|
|
216
|
-
throw new Error('Mastra instance is required to resolve shared tools')
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
return { weatherTool: mastra.getTool('weather') }
|
|
220
|
-
},
|
|
230
|
+
tools: { weatherTool },
|
|
221
231
|
})
|
|
232
|
+
```
|
|
222
233
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
234
|
+
```typescript
|
|
235
|
+
import { Agent } from '@mastra/core/agent'
|
|
236
|
+
import { weatherTool } from '../tools/weather-tool'
|
|
237
|
+
|
|
238
|
+
export const travelAgent = new Agent({
|
|
239
|
+
id: 'travel-agent',
|
|
240
|
+
name: 'Travel Agent',
|
|
241
|
+
instructions: 'Help users plan trips.',
|
|
242
|
+
model: 'openai/gpt-5.5',
|
|
243
|
+
tools: { weatherTool },
|
|
226
244
|
})
|
|
227
245
|
```
|
|
228
246
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
For API details, see [`Mastra.getTool()`](https://mastra.ai/reference/core/getTool), [`Mastra.getToolById()`](https://mastra.ai/reference/core/getToolById), [`Mastra.listTools()`](https://mastra.ai/reference/core/listTools), and the [`Agent` reference](https://mastra.ai/reference/agents/agent).
|
|
247
|
+
If you need to access tools from the Mastra instance, see [`Mastra.getTool()`](https://mastra.ai/reference/core/getTool), [`Mastra.getToolById()`](https://mastra.ai/reference/core/getToolById), [`Mastra.listTools()`](https://mastra.ai/reference/core/listTools), and the [`Agent` reference](https://mastra.ai/reference/agents/agent).
|
|
232
248
|
|
|
233
249
|
## Shape output for the model
|
|
234
250
|
|
|
@@ -242,8 +258,8 @@ export const weatherTool = createTool({
|
|
|
242
258
|
|
|
243
259
|
return {
|
|
244
260
|
location,
|
|
245
|
-
|
|
246
|
-
|
|
261
|
+
temperatureCelsius: Number(data.current_condition[0].temp_C),
|
|
262
|
+
conditions: data.current_condition[0].weatherDesc[0].value,
|
|
247
263
|
weatherIconUrl: data.current_condition[0].weatherIconUrl[0].value,
|
|
248
264
|
source: data,
|
|
249
265
|
}
|
|
@@ -254,7 +270,7 @@ export const weatherTool = createTool({
|
|
|
254
270
|
value: [
|
|
255
271
|
{
|
|
256
272
|
type: 'text',
|
|
257
|
-
text: `${output.location}: ${output.
|
|
273
|
+
text: `${output.location}: ${output.temperatureCelsius}°C and ${output.conditions}`,
|
|
258
274
|
},
|
|
259
275
|
{ type: 'image-url', url: output.weatherIconUrl },
|
|
260
276
|
],
|
|
@@ -358,23 +374,24 @@ export const weatherTool = createTool({
|
|
|
358
374
|
id: 'weather-tool',
|
|
359
375
|
description: 'Get weather information',
|
|
360
376
|
inputSchema: z.object({
|
|
361
|
-
|
|
377
|
+
location: z.string(),
|
|
362
378
|
}),
|
|
363
379
|
outputSchema: z.object({
|
|
364
|
-
|
|
380
|
+
location: z.string(),
|
|
381
|
+
temperatureCelsius: z.number(),
|
|
365
382
|
conditions: z.string(),
|
|
366
383
|
}),
|
|
367
384
|
// Called when the complete input is available
|
|
368
385
|
onInputAvailable: ({ input, toolCallId }) => {
|
|
369
|
-
console.log(`Weather requested for: ${input.
|
|
386
|
+
console.log(`Weather requested for: ${input.location}`)
|
|
370
387
|
},
|
|
371
|
-
execute: async
|
|
372
|
-
const weather = await fetchWeather(
|
|
388
|
+
execute: async ({ location }) => {
|
|
389
|
+
const weather = await fetchWeather(location)
|
|
373
390
|
return weather
|
|
374
391
|
},
|
|
375
392
|
// Called after successful execution
|
|
376
393
|
onOutput: ({ output, toolName }) => {
|
|
377
|
-
console.log(`${toolName} result: ${output.
|
|
394
|
+
console.log(`${toolName} result: ${output.temperatureCelsius}°C, ${output.conditions}`)
|
|
378
395
|
},
|
|
379
396
|
})
|
|
380
397
|
```
|
|
@@ -105,5 +105,6 @@ This adds `browser_record` and `browser_record_caption` to the agent's toolset.
|
|
|
105
105
|
|
|
106
106
|
- [Browser overview](https://mastra.ai/docs/browser/overview)
|
|
107
107
|
- [Stagehand](https://mastra.ai/docs/browser/stagehand)
|
|
108
|
+
- [Firecrawl](https://mastra.ai/docs/browser/firecrawl)
|
|
108
109
|
- [Browser recording (alpha)](https://mastra.ai/docs/browser/recording)
|
|
109
110
|
- [AgentBrowser reference](https://mastra.ai/reference/browser/agent-browser)
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
> Discover all available pages from the documentation index: https://mastra.ai/llms.txt
|
|
2
|
+
|
|
3
|
+
# Firecrawl
|
|
4
|
+
|
|
5
|
+
The `@mastra/browser-firecrawl` package provides browser automation using the [Firecrawl Browser Sandbox](https://docs.firecrawl.dev/features/browser). It provisions remote browser sessions through the Firecrawl API and drives them with the same deterministic, accessibility-first tools as [AgentBrowser](https://mastra.ai/docs/browser/agent-browser).
|
|
6
|
+
|
|
7
|
+
`FirecrawlBrowser` extends `AgentBrowser`, so agents get the same toolset (`browser_goto`, `browser_snapshot`, `browser_click`, and so on) while the browser itself runs in Firecrawl's hosted infrastructure. No local Chromium install is needed.
|
|
8
|
+
|
|
9
|
+
## When to use Firecrawl
|
|
10
|
+
|
|
11
|
+
Use Firecrawl when you need:
|
|
12
|
+
|
|
13
|
+
- Hosted browser sessions without managing local Chromium binaries
|
|
14
|
+
- Browser automation in environments that can't launch a local browser
|
|
15
|
+
- Per-thread sandbox isolation with automatic session cleanup
|
|
16
|
+
- Named Firecrawl profiles that persist cookies and login state between sessions
|
|
17
|
+
|
|
18
|
+
## Quickstart
|
|
19
|
+
|
|
20
|
+
Install the package:
|
|
21
|
+
|
|
22
|
+
**npm**:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm install @mastra/browser-firecrawl
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
**pnpm**:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
pnpm add @mastra/browser-firecrawl
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
**Yarn**:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
yarn add @mastra/browser-firecrawl
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
**Bun**:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
bun add @mastra/browser-firecrawl
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Set your Firecrawl API key:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
FIRECRAWL_API_KEY=fc-...
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Create a browser instance and assign it to an agent:
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
import { Agent } from '@mastra/core/agent'
|
|
56
|
+
import { FirecrawlBrowser } from '@mastra/browser-firecrawl'
|
|
57
|
+
|
|
58
|
+
const browser = new FirecrawlBrowser({
|
|
59
|
+
apiKey: process.env.FIRECRAWL_API_KEY,
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
export const firecrawlAgent = new Agent({
|
|
63
|
+
id: 'firecrawl-agent',
|
|
64
|
+
name: 'Firecrawl Agent',
|
|
65
|
+
model: 'openai/gpt-5.5',
|
|
66
|
+
browser,
|
|
67
|
+
instructions: `You are a web automation assistant.
|
|
68
|
+
|
|
69
|
+
When interacting with pages:
|
|
70
|
+
1. Use browser_snapshot to get the current page state and element refs
|
|
71
|
+
2. Use the refs (like @e1, @e2) to target elements for clicks and typing
|
|
72
|
+
3. After actions, take another snapshot to verify the result`,
|
|
73
|
+
})
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
If `apiKey` is omitted, the provider reads `FIRECRAWL_API_KEY` from the environment.
|
|
77
|
+
|
|
78
|
+
## Session scope
|
|
79
|
+
|
|
80
|
+
`FirecrawlBrowser` follows the same `scope` option as `AgentBrowser`:
|
|
81
|
+
|
|
82
|
+
- `'thread'` (default): Each conversation thread gets its own Firecrawl sandbox session. Sessions are deleted when the thread's browser closes.
|
|
83
|
+
- `'shared'`: One Firecrawl sandbox session is shared across all threads and deleted when the browser closes.
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
const browser = new FirecrawlBrowser({
|
|
87
|
+
scope: 'shared',
|
|
88
|
+
})
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Session options
|
|
92
|
+
|
|
93
|
+
Pass Firecrawl-specific session options under the `firecrawl` key. These map to the Firecrawl `browser()` API:
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
const browser = new FirecrawlBrowser({
|
|
97
|
+
firecrawl: {
|
|
98
|
+
ttl: 600,
|
|
99
|
+
activityTtl: 120,
|
|
100
|
+
profile: {
|
|
101
|
+
name: 'my-profile',
|
|
102
|
+
saveChanges: true,
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
})
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
- `ttl`: Maximum session lifetime in seconds.
|
|
109
|
+
- `activityTtl`: Idle timeout in seconds before Firecrawl recycles the session.
|
|
110
|
+
- `profile`: Named Firecrawl profile that persists cookies and login state. Set `saveChanges: true` to save profile changes when the session ends.
|
|
111
|
+
|
|
112
|
+
> **Note:** The nested `firecrawl.profile` option refers to a profile stored in Firecrawl's infrastructure. It's different from the top-level `profile` option inherited from `AgentBrowser`, which is a local Playwright user-data directory path.
|
|
113
|
+
|
|
114
|
+
## Self-hosted Firecrawl
|
|
115
|
+
|
|
116
|
+
To use a self-hosted Firecrawl API, set `apiUrl`:
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
const browser = new FirecrawlBrowser({
|
|
120
|
+
apiUrl: 'https://firecrawl.internal.example.com',
|
|
121
|
+
})
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## Related
|
|
125
|
+
|
|
126
|
+
- [Browser overview](https://mastra.ai/docs/browser/overview)
|
|
127
|
+
- [AgentBrowser](https://mastra.ai/docs/browser/agent-browser)
|
|
128
|
+
- [Browser recording (alpha)](https://mastra.ai/docs/browser/recording)
|
|
129
|
+
- [FirecrawlBrowser reference](https://mastra.ai/reference/browser/firecrawl-browser)
|
|
@@ -4,10 +4,11 @@
|
|
|
4
4
|
|
|
5
5
|
Browser support enables agents to navigate websites, interact with page elements, fill forms, and extract data. Mastra provides browser capabilities through SDK providers that wrap browser automation libraries and a CLI provider for agents that drive browsers through command-line tools.
|
|
6
6
|
|
|
7
|
-
Mastra supports
|
|
7
|
+
Mastra supports three SDK providers and one CLI provider:
|
|
8
8
|
|
|
9
9
|
- [**AgentBrowser**](https://mastra.ai/docs/browser/agent-browser): A Playwright-based provider with accessibility-first element targeting. Best for general web automation and scraping.
|
|
10
10
|
- [**Stagehand**](https://mastra.ai/docs/browser/stagehand): A Browserbase provider with AI-powered element detection. Best for complex interactions that benefit from natural language selectors.
|
|
11
|
+
- [**FirecrawlBrowser**](https://mastra.ai/docs/browser/firecrawl): A Firecrawl Browser Sandbox provider that runs AgentBrowser tools against hosted browser sessions. Best for running automation on hosted browser sessions without managing local browser infrastructure.
|
|
11
12
|
- [**BrowserViewer**](https://mastra.ai/docs/browser/browser-viewer): A CLI provider that launches Chrome and injects CDP URLs into CLI tools like agent-browser, browser-use, and browse. Best for workspace agents that drive browsers through shell commands.
|
|
12
13
|
- [**Browser recording (alpha)**](https://mastra.ai/docs/browser/recording): An opt-in tool layer that saves browser sessions as Motion-JPEG AVI videos with optional captions.
|
|
13
14
|
|
|
@@ -86,7 +87,19 @@ The agent automatically receives all browser tools from the provider.
|
|
|
86
87
|
|
|
87
88
|
## Cloud providers
|
|
88
89
|
|
|
89
|
-
|
|
90
|
+
All SDK providers support connecting to cloud browser services instead of launching a local browser.
|
|
91
|
+
|
|
92
|
+
### Firecrawl Browser Sandbox (FirecrawlBrowser native)
|
|
93
|
+
|
|
94
|
+
FirecrawlBrowser provisions hosted sessions through the Firecrawl API:
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
import { FirecrawlBrowser } from '@mastra/browser-firecrawl'
|
|
98
|
+
|
|
99
|
+
const browser = new FirecrawlBrowser({
|
|
100
|
+
apiKey: process.env.FIRECRAWL_API_KEY,
|
|
101
|
+
})
|
|
102
|
+
```
|
|
90
103
|
|
|
91
104
|
### Browserbase (Stagehand native)
|
|
92
105
|
|
|
@@ -167,6 +180,7 @@ const browser = new AgentBrowser({
|
|
|
167
180
|
|
|
168
181
|
- [AgentBrowser](https://mastra.ai/docs/browser/agent-browser)
|
|
169
182
|
- [Stagehand](https://mastra.ai/docs/browser/stagehand)
|
|
183
|
+
- [Firecrawl](https://mastra.ai/docs/browser/firecrawl)
|
|
170
184
|
- [Browser recording (alpha)](https://mastra.ai/docs/browser/recording)
|
|
171
185
|
- [BrowserViewer](https://mastra.ai/docs/browser/browser-viewer)
|
|
172
186
|
- [MastraBrowser reference](https://mastra.ai/reference/browser/mastra-browser)
|
|
@@ -63,7 +63,59 @@ Create the Slack app from a manifest:
|
|
|
63
63
|
2. Select **Create an app**.
|
|
64
64
|
3. Select **From a manifest**.
|
|
65
65
|
4. Choose the workspace where the agent should run.
|
|
66
|
-
5. Paste this manifest, then select **Create
|
|
66
|
+
5. Paste this manifest, then select **Create**. Slack accepts JSON or YAML, so use whichever tab matches the format shown in the app creation modal:
|
|
67
|
+
|
|
68
|
+
**JSON**:
|
|
69
|
+
|
|
70
|
+
```json
|
|
71
|
+
{
|
|
72
|
+
"display_information": {
|
|
73
|
+
"name": "mastra-agent"
|
|
74
|
+
},
|
|
75
|
+
"features": {
|
|
76
|
+
"app_home": {
|
|
77
|
+
"home_tab_enabled": false,
|
|
78
|
+
"messages_tab_enabled": true,
|
|
79
|
+
"messages_tab_read_only_enabled": false
|
|
80
|
+
},
|
|
81
|
+
"bot_user": {
|
|
82
|
+
"display_name": "mastra-agent",
|
|
83
|
+
"always_online": true
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
"oauth_config": {
|
|
87
|
+
"scopes": {
|
|
88
|
+
"bot": [
|
|
89
|
+
"im:write",
|
|
90
|
+
"app_mentions:read",
|
|
91
|
+
"channels:history",
|
|
92
|
+
"channels:read",
|
|
93
|
+
"chat:write",
|
|
94
|
+
"users:read",
|
|
95
|
+
"im:read",
|
|
96
|
+
"im:history"
|
|
97
|
+
]
|
|
98
|
+
},
|
|
99
|
+
"pkce_enabled": false
|
|
100
|
+
},
|
|
101
|
+
"settings": {
|
|
102
|
+
"event_subscriptions": {
|
|
103
|
+
"request_url": "https://<YOUR-PUBLIC-URL>/api/agents/<YOUR-AGENT-ID>/channels/slack/webhook",
|
|
104
|
+
"bot_events": ["app_mention", "message.channels", "message.im"]
|
|
105
|
+
},
|
|
106
|
+
"interactivity": {
|
|
107
|
+
"is_enabled": true,
|
|
108
|
+
"request_url": "https://<YOUR-PUBLIC-URL>/api/agents/<YOUR-AGENT-ID>/channels/slack/webhook"
|
|
109
|
+
},
|
|
110
|
+
"org_deploy_enabled": false,
|
|
111
|
+
"socket_mode_enabled": false,
|
|
112
|
+
"token_rotation_enabled": false,
|
|
113
|
+
"is_mcp_enabled": false
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
**YAML**:
|
|
67
119
|
|
|
68
120
|
```yaml
|
|
69
121
|
display_information:
|
|
@@ -211,12 +263,70 @@ Mention the bot in the channel:
|
|
|
211
263
|
|
|
212
264
|
The agent responds in the thread. Response content depends on the model, instructions, memory, and tools configured on the agent.
|
|
213
265
|
|
|
266
|
+
## Authentication
|
|
267
|
+
|
|
268
|
+
The Slack adapter has no built-in user allowlist. Once the app is installed, anyone in the workspace can talk to the agent by sending it a direct message or mentioning it in a channel where it's a member. Slack verifies each request with the signing secret, and Mastra runs the agent for every valid message the webhook receives.
|
|
269
|
+
|
|
270
|
+
The main mechanism for controlling access is channel membership. The bot only receives events from direct messages and from channels it has been invited to, so the set of channels the bot belongs to defines who can reach it. Keep the bot out of channels where it shouldn't respond, and remove it from a channel to cut off access.
|
|
271
|
+
|
|
272
|
+
For finer control, gate on the sender's identity. Every request carries the sender's Slack user ID in the channel [request context](#request-context), so you can allow or deny specific users in an input processor or tool before the agent acts.
|
|
273
|
+
|
|
274
|
+
### Server authentication
|
|
275
|
+
|
|
276
|
+
The Slack webhook route is exempt from Mastra's [server authentication](https://mastra.ai/docs/server/auth). Slack can't send a bearer token, so Mastra registers the channel webhook as a public route and verifies each request with the Slack signing secret instead. This holds even when you enable a provider like [`MastraAuthSimple`](https://mastra.ai/docs/server/auth/simple-auth): the rest of your API stays protected, but the webhook route relies on the signing secret rather than your server auth. Keep `SLACK_SIGNING_SECRET` set so the adapter can reject requests that Slack didn't sign.
|
|
277
|
+
|
|
278
|
+
### External channels
|
|
279
|
+
|
|
280
|
+
Shared channels ([Slack Connect](https://slack.com/connect)) let people from other workspaces join a conversation. If a workspace member adds the bot to a shared channel, everyone in that channel can talk to the agent, including external members outside your organization. Anyone who can reach the agent can also reach the tools and data it has access to.
|
|
281
|
+
|
|
282
|
+
Treat adding the bot to a shared or external channel as granting those participants access to the agent. Before you do, confirm the agent's tools and data are safe to expose to outside members, and gate on the sender's user ID when you need to restrict who the agent responds to.
|
|
283
|
+
|
|
284
|
+
## Request context
|
|
285
|
+
|
|
286
|
+
On every message, Mastra places a channel context object on the [request context](https://mastra.ai/docs/server/request-context) under the `channel` key. It carries the sender's Slack display name and user ID, the bot's own identity, and details about where the message came from. Read it from an input processor or a tool to identify the user or branch on the conversation type:
|
|
287
|
+
|
|
288
|
+
```typescript
|
|
289
|
+
import { createTool } from '@mastra/core/tools'
|
|
290
|
+
import type { ChannelContext } from '@mastra/core/channels'
|
|
291
|
+
import { z } from 'zod'
|
|
292
|
+
|
|
293
|
+
export const whoami = createTool({
|
|
294
|
+
id: 'whoami',
|
|
295
|
+
description: 'Return the Slack identity of the current user',
|
|
296
|
+
inputSchema: z.object({}),
|
|
297
|
+
execute: async (_input, context) => {
|
|
298
|
+
const channel = context?.requestContext?.get('channel') as ChannelContext | undefined
|
|
299
|
+
|
|
300
|
+
return {
|
|
301
|
+
platform: channel?.platform,
|
|
302
|
+
userId: channel?.userId,
|
|
303
|
+
userName: channel?.userName,
|
|
304
|
+
isDM: channel?.isDM,
|
|
305
|
+
}
|
|
306
|
+
},
|
|
307
|
+
})
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
The channel context includes:
|
|
311
|
+
|
|
312
|
+
- `botMention`, `botUserId`, and `botUserName`: The bot's own identity on Slack.
|
|
313
|
+
- `channelId` and `threadId`: The Slack channel and thread the message arrived on.
|
|
314
|
+
- `isDM`: Whether the message is a direct message.
|
|
315
|
+
- `platform`: The platform identifier, `slack` for this adapter.
|
|
316
|
+
- `userId` and `userName`: The sender's Slack user ID and display name.
|
|
317
|
+
|
|
318
|
+
Mastra also turns this context into a short system message. The agent learns the platform and its own identity, plus whether the conversation is a direct message or a public channel. See [thread context](https://mastra.ai/docs/capabilities/channels/overview) in the channels overview for how to change that behavior.
|
|
319
|
+
|
|
214
320
|
## Production deployment
|
|
215
321
|
|
|
216
322
|
When you deploy the Mastra server, update both request URLs in the Slack app settings to the production webhook URL. The tunnel URL used for local development is temporary and changes when the tunnel restarts.
|
|
217
323
|
|
|
218
324
|
Channels on serverless platforms may need `waitUntil` and shared pub/sub configuration so background responses and thread leases work across short-lived instances. See [serverless deployment](https://mastra.ai/docs/capabilities/channels/overview) in the channels overview.
|
|
219
325
|
|
|
326
|
+
### Idle servers
|
|
327
|
+
|
|
328
|
+
Platform servers scale down to idle when they aren't receiving traffic, and that's fine for Slack. The next event, such as a mention or direct message, wakes the server by delivering its webhook request, and the server resumes handling requests. The first response after the server has been idle can take a little longer while it starts up, which is expected. Slack expects a `200` acknowledgement within 3 seconds and retries the event up to three times when delivery fails or times out, so a very slow cold start may take a retry before the agent responds. Subsequent messages respond at normal speed while the server stays warm.
|
|
329
|
+
|
|
220
330
|
## Related
|
|
221
331
|
|
|
222
332
|
- [Channels overview](https://mastra.ai/docs/capabilities/channels/overview)
|