@mastra/mcp 1.15.1 → 1.16.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +59 -0
- package/dist/client/actions/elicitation.d.ts +1 -1
- package/dist/client/actions/elicitation.d.ts.map +1 -1
- package/dist/client/actions/progress.d.ts +1 -1
- package/dist/client/actions/progress.d.ts.map +1 -1
- package/dist/client/actions/prompt.d.ts +1 -1
- package/dist/client/actions/prompt.d.ts.map +1 -1
- package/dist/client/actions/resource.d.ts +38 -11
- package/dist/client/actions/resource.d.ts.map +1 -1
- package/dist/client/client.d.ts +3 -2
- package/dist/client/client.d.ts.map +1 -1
- package/dist/client/configuration.d.ts +50 -14
- package/dist/client/configuration.d.ts.map +1 -1
- package/dist/client/types.d.ts +65 -10
- package/dist/client/types.d.ts.map +1 -1
- package/dist/client/url-policy.d.ts +67 -0
- package/dist/client/url-policy.d.ts.map +1 -0
- package/dist/docs/SKILL.md +3 -3
- package/dist/docs/assets/SOURCE_MAP.json +1 -1
- package/dist/docs/references/docs-connections-overview.md +94 -0
- package/dist/docs/references/docs-mcp-overview.md +229 -278
- package/dist/docs/references/reference-tools-mcp-client.md +54 -0
- package/dist/docs/references/reference-tools-mcp-server.md +1 -1
- package/dist/index.cjs +2435 -275
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2403 -243
- package/dist/index.js.map +1 -1
- package/dist/server/__tests__/mock-extra.d.ts +15 -0
- package/dist/server/__tests__/mock-extra.d.ts.map +1 -0
- package/dist/server/notificationBroadcast.d.ts +1 -1
- package/dist/server/notificationBroadcast.d.ts.map +1 -1
- package/dist/server/promptActions.d.ts +1 -1
- package/dist/server/promptActions.d.ts.map +1 -1
- package/dist/server/resourceActions.d.ts +1 -1
- package/dist/server/resourceActions.d.ts.map +1 -1
- package/dist/server/server.d.ts +10 -12
- package/dist/server/server.d.ts.map +1 -1
- package/dist/server/toolActions.d.ts +1 -1
- package/dist/server/toolActions.d.ts.map +1 -1
- package/dist/server/types.d.ts +7 -7
- package/dist/server/types.d.ts.map +1 -1
- package/dist/shared/oauth-types.d.ts +8 -6
- package/dist/shared/oauth-types.d.ts.map +1 -1
- package/package.json +18 -14
- package/dist/docs/references/docs-mcp-mcp-apps.md +0 -306
|
@@ -2,18 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
# MCP overview
|
|
4
4
|
|
|
5
|
-
Mastra supports the [Model Context Protocol (MCP)](https://modelcontextprotocol.io/introduction), an open standard for connecting AI agents to external tools and resources.
|
|
5
|
+
Mastra supports the [Model Context Protocol (MCP)](https://modelcontextprotocol.io/introduction), an open standard for connecting AI agents to external tools and resources.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Use [`MCPClient`](https://mastra.ai/reference/tools/mcp-client) to connect to MCP servers. Use [`MCPServer`](https://mastra.ai/reference/tools/mcp-server) to expose Mastra agents, tools, workflows, prompts, and resources to other MCP-compatible systems.
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
## Connect to MCP servers
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
2. `MCPServer`: Exposes Mastra tools, agents, workflows, prompts, and resources to MCP-compatible clients.
|
|
13
|
-
|
|
14
|
-
## Get started
|
|
15
|
-
|
|
16
|
-
To use MCP, install the required dependency:
|
|
11
|
+
Install the MCP package:
|
|
17
12
|
|
|
18
13
|
**npm**:
|
|
19
14
|
|
|
@@ -39,382 +34,338 @@ yarn add @mastra/mcp@latest
|
|
|
39
34
|
bun add @mastra/mcp@latest
|
|
40
35
|
```
|
|
41
36
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
The `MCPClient` connects Mastra primitives to external MCP servers, which can be local packages (invoked using `npx`) or remote HTTP(S) endpoints. Each server must be configured with either a `command` or a `url`, depending on how it's hosted.
|
|
37
|
+
Configure each server with a local command or remote URL:
|
|
45
38
|
|
|
46
39
|
```typescript
|
|
47
40
|
import { MCPClient } from '@mastra/mcp'
|
|
48
41
|
|
|
49
|
-
export const
|
|
50
|
-
id: '
|
|
42
|
+
export const mcpClient = new MCPClient({
|
|
43
|
+
id: 'my-mcp-client',
|
|
51
44
|
servers: {
|
|
52
45
|
wikipedia: {
|
|
53
46
|
command: 'npx',
|
|
54
47
|
args: ['-y', 'wikipedia-mcp'],
|
|
55
48
|
},
|
|
56
49
|
weather: {
|
|
57
|
-
url: new URL(
|
|
58
|
-
|
|
59
|
-
|
|
50
|
+
url: new URL('https://weather.example.com/mcp'),
|
|
51
|
+
requestInit: {
|
|
52
|
+
headers: {
|
|
53
|
+
Authorization: `Bearer ${process.env.WEATHER_API_KEY}`,
|
|
54
|
+
},
|
|
55
|
+
},
|
|
60
56
|
},
|
|
61
57
|
},
|
|
62
58
|
})
|
|
63
59
|
```
|
|
64
60
|
|
|
65
|
-
Visit [
|
|
66
|
-
|
|
67
|
-
> **Authentication:** For connecting to OAuth-protected MCP servers, including completing the browser-based authorization flow with `authenticate()`, see the [OAuth Authentication](https://mastra.ai/reference/tools/mcp-client) section.
|
|
68
|
-
|
|
69
|
-
## Using `MCPClient` with an agent
|
|
61
|
+
> **Authentication:** For OAuth-protected servers, use `authenticate()` to complete the browser-based authorization flow. Visit [OAuth authentication](https://mastra.ai/reference/tools/mcp-client) for configuration details.
|
|
70
62
|
|
|
71
|
-
|
|
63
|
+
Pass tools from the configured servers to an agent:
|
|
72
64
|
|
|
73
65
|
```typescript
|
|
74
66
|
import { Agent } from '@mastra/core/agent'
|
|
75
|
-
import {
|
|
67
|
+
import { mcpClient } from '../mcp/client'
|
|
76
68
|
|
|
77
|
-
export const
|
|
78
|
-
id: '
|
|
79
|
-
name: '
|
|
80
|
-
description: 'You are a helpful AI assistant',
|
|
69
|
+
export const assistant = new Agent({
|
|
70
|
+
id: 'assistant',
|
|
71
|
+
name: 'Assistant',
|
|
81
72
|
instructions: `
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
Answer questions using the information you find using the MCP Servers.`,
|
|
73
|
+
Use the available MCP tools to answer questions.
|
|
74
|
+
Include the source of any information you retrieve.
|
|
75
|
+
`,
|
|
87
76
|
model: 'openai/gpt-5.6-sol',
|
|
88
|
-
tools: await
|
|
77
|
+
tools: await mcpClient.listTools(),
|
|
89
78
|
})
|
|
90
79
|
```
|
|
91
80
|
|
|
92
|
-
|
|
81
|
+
### Static and runtime tools
|
|
82
|
+
|
|
83
|
+
Choose how to load tools based on whether the server configuration changes between requests:
|
|
84
|
+
|
|
85
|
+
| | Static tools | Runtime toolsets |
|
|
86
|
+
| ----------- | ---------------------------------- | ---------------------------------------- |
|
|
87
|
+
| Method | `await mcpClient.listTools()` | `await mcpClient.listToolsets()` |
|
|
88
|
+
| Use case | Shared, fixed configuration | Per-user or per-request configuration |
|
|
89
|
+
| Credentials | Shared by all requests | Can vary between requests |
|
|
90
|
+
| Agent API | `tools` in the `Agent` constructor | `toolsets` in `generate()` or `stream()` |
|
|
91
|
+
|
|
92
|
+
The preceding agent example uses static tools. For runtime credentials, create a client for the request and pass its toolsets when calling the agent:
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
import { MCPClient } from '@mastra/mcp'
|
|
96
|
+
import { mastra } from './mastra'
|
|
97
|
+
|
|
98
|
+
export async function handleRequest(prompt: string, apiKey: string) {
|
|
99
|
+
const userMcpClient = new MCPClient({
|
|
100
|
+
servers: {
|
|
101
|
+
weather: {
|
|
102
|
+
url: new URL('https://weather.example.com/mcp'),
|
|
103
|
+
requestInit: {
|
|
104
|
+
headers: { Authorization: `Bearer ${apiKey}` },
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
})
|
|
109
|
+
|
|
110
|
+
const agent = mastra.getAgent('assistant')
|
|
111
|
+
const response = await agent.generate(prompt, {
|
|
112
|
+
toolsets: await userMcpClient.listToolsets(),
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
await userMcpClient.disconnect()
|
|
116
|
+
return response.text
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Visit [`listTools()`](https://mastra.ai/reference/tools/mcp-client) and [`listToolsets()`](https://mastra.ai/reference/tools/mcp-client) for their full APIs.
|
|
93
121
|
|
|
94
|
-
|
|
122
|
+
### Tool approval
|
|
95
123
|
|
|
96
|
-
|
|
124
|
+
Set `requireToolApproval` on a server to require approval for all its tools:
|
|
97
125
|
|
|
98
126
|
```typescript
|
|
99
|
-
|
|
127
|
+
const mcpClient = new MCPClient({
|
|
100
128
|
servers: {
|
|
101
129
|
github: {
|
|
102
|
-
url: new URL('
|
|
130
|
+
url: new URL('https://github.example.com/mcp'),
|
|
103
131
|
requireToolApproval: true,
|
|
104
132
|
},
|
|
105
133
|
},
|
|
106
134
|
})
|
|
107
135
|
```
|
|
108
136
|
|
|
109
|
-
You can also
|
|
110
|
-
|
|
111
|
-
## Configuring `MCPServer`
|
|
112
|
-
|
|
113
|
-
To expose agents, tools, and workflows from your Mastra application to external systems over HTTP(S) use the `MCPServer` class. This makes them accessible to any system or agent that supports the protocol.
|
|
137
|
+
You can also provide a function that decides based on the tool name, arguments, or annotations:
|
|
114
138
|
|
|
115
139
|
```typescript
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
import { testAgent } from '../agents/test-agent'
|
|
119
|
-
import { testWorkflow } from '../workflows/test-workflow'
|
|
120
|
-
import { testTool } from '../tools/test-tool'
|
|
121
|
-
|
|
122
|
-
export const testMcpServer = new MCPServer({
|
|
123
|
-
id: 'test-mcp-server',
|
|
124
|
-
name: 'Test Server',
|
|
125
|
-
version: '1.0.0',
|
|
126
|
-
agents: { testAgent },
|
|
127
|
-
tools: { testTool },
|
|
128
|
-
workflows: { testWorkflow },
|
|
129
|
-
})
|
|
140
|
+
requireToolApproval: ({ toolName }) => toolName.startsWith('delete_')
|
|
130
141
|
```
|
|
131
142
|
|
|
132
|
-
Visit [
|
|
143
|
+
Treat tool annotations from servers you don't control as untrusted hints. Visit [tool approval](https://mastra.ai/reference/tools/mcp-client) for the callback context and security guidance.
|
|
133
144
|
|
|
134
|
-
|
|
145
|
+
### Security
|
|
135
146
|
|
|
136
|
-
|
|
147
|
+
MCP servers run code and return content on your agent's behalf, so configure them with the same care as any other external dependency:
|
|
137
148
|
|
|
138
|
-
|
|
149
|
+
- **Stdio subprocess environment**: subprocesses inherit only the MCP SDK's curated environment whitelist (for example `PATH` and `HOME` on POSIX), not the full parent environment. Set `inheritDefaultEnv: false` on a server to pass only the variables you list in `env`.
|
|
150
|
+
- **Outbound host restriction**: when HTTP server URLs come from untrusted configuration, set `allowedHosts` to restrict which hosts the client will contact. On the default fetch path this also blocks redirect hops before they're sent; a custom `fetch` gets its final response URL validated after the request runs, so it must enforce redirect policy itself when preventing outbound contact is required.
|
|
151
|
+
- **Tool response trust**: tool results are untrusted model input. Use [input and output processors](https://mastra.ai/docs/agents/processors) to inspect or sanitize content before it reaches the model, and `requireToolApproval` to gate sensitive tools.
|
|
139
152
|
|
|
140
|
-
|
|
141
|
-
import { Mastra } from '@mastra/core/mastra'
|
|
153
|
+
Visit the [MCPClient security reference](https://mastra.ai/reference/tools/mcp-client) for enforcement details of each option.
|
|
142
154
|
|
|
143
|
-
|
|
155
|
+
### MCP registries
|
|
144
156
|
|
|
145
|
-
|
|
146
|
-
mcpServers: { testMcpServer },
|
|
147
|
-
})
|
|
148
|
-
```
|
|
157
|
+
Registries provide hosted or packaged MCP servers. The client configuration above works with registry endpoints and commands.
|
|
149
158
|
|
|
150
|
-
|
|
159
|
+
| Registry | Connection | Notes |
|
|
160
|
+
| ----------------------------------------------- | ----------------- | --------------------------------------------- |
|
|
161
|
+
| [Klavis AI](https://klavis.ai) | Hosted HTTP | Enterprise authentication and managed servers |
|
|
162
|
+
| [mcp.run](https://www.mcp.run/) | Signed SSE URL | Treat the profile URL as a secret |
|
|
163
|
+
| [Composio](https://mcp.composio.dev) | Hosted SSE URL | URLs are often tied to one user account |
|
|
164
|
+
| [Smithery](https://smithery.ai) | CLI or hosted URL | Run local packages through `npx` |
|
|
165
|
+
| [Apify](https://mcp.apify.com) | Hosted HTTP | Authenticate with an Apify API token |
|
|
166
|
+
| [Ampersand](https://docs.withampersand.com/mcp) | SSE or stdio | Connect to configured SaaS integrations |
|
|
151
167
|
|
|
152
|
-
|
|
168
|
+
Store signed URLs, API keys, and tokens in environment variables. Follow the registry's documentation to obtain the endpoint, command, and credentials for each server.
|
|
153
169
|
|
|
154
|
-
|
|
155
|
-
| ----------------- | ---------------------------------------------- | ---------------------------------------------------- |
|
|
156
|
-
| **Use Case** | Single-user, static config (e.g., CLI tool) | Multi-user, runtime config (e.g., SaaS app) |
|
|
157
|
-
| **Configuration** | Fixed at agent initialization | Per-request, runtime |
|
|
158
|
-
| **Credentials** | Shared across all uses | Can vary per user/request |
|
|
159
|
-
| **Agent Setup** | Tools added in `Agent` constructor | Tools passed in `.generate()` or `.stream()` options |
|
|
170
|
+
## Expose a Mastra MCP server
|
|
160
171
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
Use the `.listTools()` method to fetch tools from all configured MCP servers. This is suitable when configuration (such as API keys) is static and consistent across users or requests. Call it once and pass the result to the `tools` property when defining your agent. Visit [listTools()](https://mastra.ai/reference/tools/mcp-client) for more information.
|
|
172
|
+
Create an `MCPServer` to expose Mastra primitives to external MCP clients:
|
|
164
173
|
|
|
165
174
|
```typescript
|
|
166
|
-
import {
|
|
167
|
-
|
|
168
|
-
import {
|
|
175
|
+
import { MCPServer } from '@mastra/mcp'
|
|
176
|
+
import { assistant } from '../agents/assistant'
|
|
177
|
+
import { weatherTool } from '../tools/weather'
|
|
178
|
+
import { weatherWorkflow } from '../workflows/weather'
|
|
169
179
|
|
|
170
|
-
export const
|
|
171
|
-
id: '
|
|
172
|
-
|
|
180
|
+
export const mcpServer = new MCPServer({
|
|
181
|
+
id: 'my-mcp-server',
|
|
182
|
+
name: 'My MCP Server',
|
|
183
|
+
version: '1.0.0',
|
|
184
|
+
agents: { assistant },
|
|
185
|
+
tools: { weatherTool },
|
|
186
|
+
workflows: { weatherWorkflow },
|
|
173
187
|
})
|
|
174
188
|
```
|
|
175
189
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
Use the `.listToolsets()` method when tool configuration may vary by request or user, such as in a multi-tenant system where each user provides their own API key. This method returns toolsets that can be passed to the `toolsets` option in the agent's `.generate()` or `.stream()` calls.
|
|
190
|
+
Register the server on the main `Mastra` instance:
|
|
179
191
|
|
|
180
192
|
```typescript
|
|
181
|
-
import {
|
|
182
|
-
import {
|
|
183
|
-
|
|
184
|
-
async function handleRequest(userPrompt: string, userApiKey: string) {
|
|
185
|
-
const userMcp = new MCPClient({
|
|
186
|
-
servers: {
|
|
187
|
-
weather: {
|
|
188
|
-
url: new URL('http://localhost:8080/mcp'),
|
|
189
|
-
requestInit: {
|
|
190
|
-
headers: {
|
|
191
|
-
Authorization: `Bearer ${userApiKey}`,
|
|
192
|
-
},
|
|
193
|
-
},
|
|
194
|
-
},
|
|
195
|
-
},
|
|
196
|
-
})
|
|
197
|
-
|
|
198
|
-
const agent = mastra.getAgent('testAgent')
|
|
193
|
+
import { Mastra } from '@mastra/core/mastra'
|
|
194
|
+
import { mcpServer } from './mcp/server'
|
|
199
195
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
196
|
+
export const mastra = new Mastra({
|
|
197
|
+
mcpServers: { mcpServer },
|
|
198
|
+
})
|
|
199
|
+
```
|
|
203
200
|
|
|
204
|
-
|
|
201
|
+
> **Authentication:** Protect HTTP MCP servers with OAuth middleware. Visit [OAuth protection](https://mastra.ai/reference/tools/mcp-server) for setup instructions.
|
|
205
202
|
|
|
206
|
-
|
|
207
|
-
data: response.text,
|
|
208
|
-
})
|
|
209
|
-
}
|
|
210
|
-
```
|
|
203
|
+
Visit the [`MCPServer` reference](https://mastra.ai/reference/tools/mcp-server) for prompts, resources, transports, and other server options.
|
|
211
204
|
|
|
212
|
-
|
|
205
|
+
## Build MCP Apps
|
|
213
206
|
|
|
214
|
-
|
|
207
|
+
The [MCP Apps extension](https://github.com/modelcontextprotocol/ext-apps) lets MCP tools serve interactive HTML interfaces through `ui://` resources. Mastra Studio renders these apps in sandboxed iframes on tool pages and in agent chat.
|
|
215
208
|
|
|
216
|
-
MCP
|
|
209
|
+
Use an MCP App when a tool result benefits from interaction, such as a form, calculator, color picker, or data visualization.
|
|
217
210
|
|
|
218
|
-
|
|
211
|
+
### Define an app resource
|
|
219
212
|
|
|
220
|
-
|
|
213
|
+
Return a short `content` summary for the model and place UI data in `structuredContent`. Link the tool to its app by setting `_meta.ui.resourceUri` to the same `ui://` URI used in `appResources`:
|
|
221
214
|
|
|
222
215
|
```typescript
|
|
223
|
-
import {
|
|
216
|
+
import { MCPServer } from '@mastra/mcp'
|
|
217
|
+
import { createTool } from '@mastra/core/tools'
|
|
218
|
+
import { z } from 'zod'
|
|
219
|
+
|
|
220
|
+
export const calculatorTool = createTool({
|
|
221
|
+
id: 'calculatorWithUI',
|
|
222
|
+
description: 'Calculate the sum of two numbers',
|
|
223
|
+
inputSchema: z.object({
|
|
224
|
+
num1: z.number(),
|
|
225
|
+
num2: z.number(),
|
|
226
|
+
}),
|
|
227
|
+
execute: async ({ num1, num2 }) => ({
|
|
228
|
+
content: [{ type: 'text', text: 'The result is displayed in the calculator app.' }],
|
|
229
|
+
structuredContent: { result: num1 + num2 },
|
|
230
|
+
}),
|
|
231
|
+
})
|
|
224
232
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
233
|
+
calculatorTool._meta = {
|
|
234
|
+
ui: { resourceUri: 'ui://calculator/main' },
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
export const calculatorMcpServer = new MCPServer({
|
|
238
|
+
id: 'calculator-app-server',
|
|
239
|
+
name: 'Calculator App Server',
|
|
240
|
+
version: '1.0.0',
|
|
241
|
+
tools: { calculatorTool },
|
|
242
|
+
appResources: {
|
|
243
|
+
'ui://calculator/main': {
|
|
244
|
+
name: 'Calculator',
|
|
245
|
+
htmlPath: './src/mastra/mcp/calculator.html',
|
|
234
246
|
},
|
|
235
247
|
},
|
|
236
248
|
})
|
|
237
249
|
```
|
|
238
250
|
|
|
239
|
-
|
|
251
|
+
The model sees `content`, while the app receives `structuredContent`. Visit [`appResources`](https://mastra.ai/reference/tools/mcp-server) for inline HTML, file paths, metadata, and content security policy options.
|
|
240
252
|
|
|
241
|
-
|
|
253
|
+
### Connect the app to Studio
|
|
242
254
|
|
|
243
|
-
|
|
255
|
+
Use the `App` class from `@modelcontextprotocol/ext-apps` inside the HTML resource. Register event handlers before calling `connect()`:
|
|
244
256
|
|
|
245
|
-
|
|
257
|
+
```html
|
|
258
|
+
<!doctype html>
|
|
259
|
+
<html>
|
|
260
|
+
<body>
|
|
261
|
+
<p id="result">Waiting for input</p>
|
|
262
|
+
<button id="recalculate">Recalculate</button>
|
|
246
263
|
|
|
247
|
-
|
|
248
|
-
import {
|
|
249
|
-
|
|
250
|
-
const mcp = new MCPClient({
|
|
251
|
-
servers: {
|
|
252
|
-
marketing: {
|
|
253
|
-
// Example profile name
|
|
254
|
-
url: new URL(process.env.MCP_RUN_SSE_URL!), // Get URL from mcp.run profile
|
|
255
|
-
},
|
|
256
|
-
},
|
|
257
|
-
})
|
|
258
|
-
```
|
|
264
|
+
<script type="module">
|
|
265
|
+
import { App } from 'https://cdn.jsdelivr.net/npm/@modelcontextprotocol/ext-apps/+esm'
|
|
259
266
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
> ```bash
|
|
263
|
-
> MCP_RUN_SSE_URL=https://www.mcp.run/api/mcp/sse?nonce=...
|
|
264
|
-
> ```
|
|
267
|
+
const app = new App({ name: 'Calculator', version: '1.0.0' })
|
|
268
|
+
let toolInput
|
|
265
269
|
|
|
266
|
-
|
|
270
|
+
app.ontoolinput = params => {
|
|
271
|
+
toolInput = params.arguments
|
|
272
|
+
}
|
|
267
273
|
|
|
268
|
-
|
|
274
|
+
document.querySelector('#recalculate').addEventListener('click', async () => {
|
|
275
|
+
const result = await app.callServerTool({
|
|
276
|
+
name: 'calculatorWithUI',
|
|
277
|
+
arguments: toolInput,
|
|
278
|
+
})
|
|
279
|
+
document.querySelector('#result').textContent = JSON.stringify(result)
|
|
269
280
|
|
|
270
|
-
|
|
271
|
-
|
|
281
|
+
await app.sendMessage({
|
|
282
|
+
role: 'user',
|
|
283
|
+
content: [{ type: 'text', text: 'Explain the recalculated result.' }],
|
|
284
|
+
})
|
|
285
|
+
})
|
|
272
286
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
},
|
|
278
|
-
gmail: {
|
|
279
|
-
url: new URL('https://mcp.composio.dev/gmail/[private-url-path]'),
|
|
280
|
-
},
|
|
281
|
-
},
|
|
282
|
-
})
|
|
287
|
+
await app.connect()
|
|
288
|
+
</script>
|
|
289
|
+
</body>
|
|
290
|
+
</html>
|
|
283
291
|
```
|
|
284
292
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
_Note: Composio URLs are typically tied to a single user account, making them best suited for personal automation rather than multi-tenant applications._
|
|
293
|
+
The guest-side APIs serve different parts of the interaction:
|
|
288
294
|
|
|
289
|
-
|
|
295
|
+
| API | Purpose |
|
|
296
|
+
| ---------------------- | ----------------------------------------------------- |
|
|
297
|
+
| `app.ontoolinput` | Receive the arguments from the host tool call |
|
|
298
|
+
| `app.callServerTool()` | Call an MCP tool from inside the iframe |
|
|
299
|
+
| `app.sendMessage()` | Add a user message to chat and start a new model turn |
|
|
300
|
+
| `app.connect()` | Connect to the host after registering event handlers |
|
|
290
301
|
|
|
291
|
-
|
|
302
|
+
The interaction follows this sequence:
|
|
292
303
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
304
|
+
1. The agent calls the tool.
|
|
305
|
+
2. The tool returns model-facing `content` and UI-facing `structuredContent`.
|
|
306
|
+
3. Studio renders the associated app resource.
|
|
307
|
+
4. The app receives tool input and can call server tools or send chat messages.
|
|
296
308
|
|
|
297
|
-
|
|
298
|
-
servers: {
|
|
299
|
-
sequentialThinking: {
|
|
300
|
-
command: 'npx',
|
|
301
|
-
args: [
|
|
302
|
-
'-y',
|
|
303
|
-
'@smithery/cli@latest',
|
|
304
|
-
'run',
|
|
305
|
-
'@smithery-ai/server-sequential-thinking',
|
|
306
|
-
'--config',
|
|
307
|
-
'{}',
|
|
308
|
-
],
|
|
309
|
-
},
|
|
310
|
-
},
|
|
311
|
-
})
|
|
312
|
-
```
|
|
313
|
-
|
|
314
|
-
```typescript
|
|
315
|
-
// Windows
|
|
316
|
-
import { MCPClient } from '@mastra/mcp'
|
|
317
|
-
|
|
318
|
-
const mcp = new MCPClient({
|
|
319
|
-
servers: {
|
|
320
|
-
sequentialThinking: {
|
|
321
|
-
command: 'npx',
|
|
322
|
-
args: [
|
|
323
|
-
'-y',
|
|
324
|
-
'@smithery/cli@latest',
|
|
325
|
-
'run',
|
|
326
|
-
'@smithery-ai/server-sequential-thinking',
|
|
327
|
-
'--config',
|
|
328
|
-
'{}',
|
|
329
|
-
],
|
|
330
|
-
},
|
|
331
|
-
},
|
|
332
|
-
})
|
|
333
|
-
```
|
|
309
|
+
Visit the external [`App` API reference](https://apps.extensions.modelcontextprotocol.io/api/classes/app.App.html) for all guest-side methods and lifecycle hooks.
|
|
334
310
|
|
|
335
|
-
|
|
311
|
+
### Register MCP Apps
|
|
336
312
|
|
|
337
|
-
|
|
313
|
+
For a local app, pass the tool to an agent and register its MCP server on `Mastra`:
|
|
338
314
|
|
|
339
315
|
```typescript
|
|
340
|
-
import {
|
|
316
|
+
import { Agent } from '@mastra/core/agent'
|
|
317
|
+
import { Mastra } from '@mastra/core/mastra'
|
|
318
|
+
import { calculatorMcpServer, calculatorTool } from './mcp/calculator'
|
|
319
|
+
|
|
320
|
+
const calculatorAgent = new Agent({
|
|
321
|
+
id: 'calculator-agent',
|
|
322
|
+
name: 'Calculator Agent',
|
|
323
|
+
instructions: 'Use the calculator tool for arithmetic.',
|
|
324
|
+
model: 'openai/gpt-5-mini',
|
|
325
|
+
tools: { calculatorTool },
|
|
326
|
+
})
|
|
341
327
|
|
|
342
|
-
export const
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
url: new URL('https://mcp.apify.com'),
|
|
346
|
-
requestInit: {
|
|
347
|
-
headers: {
|
|
348
|
-
Authorization: `Bearer ${process.env.APIFY_TOKEN}`,
|
|
349
|
-
},
|
|
350
|
-
},
|
|
351
|
-
},
|
|
352
|
-
},
|
|
328
|
+
export const mastra = new Mastra({
|
|
329
|
+
agents: { calculatorAgent },
|
|
330
|
+
mcpServers: { calculatorMcpServer },
|
|
353
331
|
})
|
|
354
332
|
```
|
|
355
333
|
|
|
356
|
-
|
|
334
|
+
For an external MCP server that implements MCP Apps, load its tools with `MCPClient.listTools()` and register its proxy so Studio can resolve the remote app resources:
|
|
357
335
|
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
336
|
+
```typescript
|
|
337
|
+
import { Agent } from '@mastra/core/agent'
|
|
338
|
+
import { Mastra } from '@mastra/core/mastra'
|
|
339
|
+
import { mcpClient } from './mcp/client'
|
|
361
340
|
|
|
362
|
-
|
|
341
|
+
const tools = await mcpClient.listTools()
|
|
342
|
+
const mcpServers = mcpClient.toMCPServerProxies()
|
|
363
343
|
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
apiKey: process.env.AMPERSAND_API_KEY,
|
|
371
|
-
project: process.env.AMPERSAND_PROJECT_ID,
|
|
372
|
-
integrationName: process.env.AMPERSAND_INTEGRATION_NAME,
|
|
373
|
-
groupRef: process.env.AMPERSAND_GROUP_REF,
|
|
374
|
-
})}`,
|
|
375
|
-
},
|
|
376
|
-
},
|
|
344
|
+
const agent = new Agent({
|
|
345
|
+
id: 'remote-app-agent',
|
|
346
|
+
name: 'Remote App Agent',
|
|
347
|
+
instructions: 'Use the available remote tools.',
|
|
348
|
+
model: 'openai/gpt-5-mini',
|
|
349
|
+
tools,
|
|
377
350
|
})
|
|
378
|
-
```
|
|
379
351
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
// MCPClient with Ampersand MCP Server using stdio transport
|
|
385
|
-
export const mcp = new MCPClient({
|
|
386
|
-
servers: {
|
|
387
|
-
'@amp-labs/mcp-server': {
|
|
388
|
-
command: 'npx',
|
|
389
|
-
args: [
|
|
390
|
-
'-y',
|
|
391
|
-
'@amp-labs/mcp-server@latest',
|
|
392
|
-
'--transport',
|
|
393
|
-
'stdio',
|
|
394
|
-
'--project',
|
|
395
|
-
process.env.AMPERSAND_PROJECT_ID,
|
|
396
|
-
'--integrationName',
|
|
397
|
-
process.env.AMPERSAND_INTEGRATION_NAME,
|
|
398
|
-
'--groupRef',
|
|
399
|
-
process.env.AMPERSAND_GROUP_REF, // optional
|
|
400
|
-
],
|
|
401
|
-
env: {
|
|
402
|
-
AMPERSAND_API_KEY: process.env.AMPERSAND_API_KEY,
|
|
403
|
-
},
|
|
404
|
-
},
|
|
405
|
-
},
|
|
352
|
+
export const mastra = new Mastra({
|
|
353
|
+
agents: { agent },
|
|
354
|
+
mcpServers,
|
|
406
355
|
})
|
|
407
356
|
```
|
|
408
357
|
|
|
409
|
-
|
|
358
|
+
Tools loaded through `listTools()` include a `serverId` in `_meta.ui`, allowing Studio to resolve each app resource without scanning every server. Visit [`toMCPServerProxies()`](https://mastra.ai/reference/tools/mcp-client) for proxy configuration details.
|
|
359
|
+
|
|
360
|
+
### Sandbox security
|
|
410
361
|
|
|
411
|
-
|
|
362
|
+
Mastra Studio uses [`@mcp-ui/client`](https://www.npmjs.com/package/@mcp-ui/client) to load app HTML through a sandbox proxy and communicate over JSON-RPC with `postMessage`.
|
|
412
363
|
|
|
413
|
-
|
|
364
|
+
App iframes allow scripts, forms, and popups. They can't access the parent page's DOM, cookies, or storage. The host controls all communication with the guest app.
|
|
414
365
|
|
|
415
|
-
##
|
|
366
|
+
## Next steps
|
|
416
367
|
|
|
417
|
-
- [
|
|
418
|
-
- [
|
|
419
|
-
- [
|
|
420
|
-
- [
|
|
368
|
+
- [Use tools with agents](https://mastra.ai/docs/agents/using-tools)
|
|
369
|
+
- [`MCPClient` reference](https://mastra.ai/reference/tools/mcp-client)
|
|
370
|
+
- [`MCPServer` reference](https://mastra.ai/reference/tools/mcp-server)
|
|
371
|
+
- [MCP Apps extension specification](https://github.com/modelcontextprotocol/ext-apps)
|