@mastra/mcp 1.6.1-alpha.0 → 1.6.1-alpha.1
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 +9 -0
- package/dist/docs/SKILL.md +1 -1
- package/dist/docs/assets/SOURCE_MAP.json +1 -1
- package/dist/docs/references/docs-mcp-overview.md +25 -0
- package/dist/index.cjs +79 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +79 -5
- package/dist/index.js.map +1 -1
- package/dist/server/server.d.ts +16 -2
- package/dist/server/server.d.ts.map +1 -1
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# @mastra/mcp
|
|
2
2
|
|
|
3
|
+
## 1.6.1-alpha.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Added Fine-Grained Authorization (FGA) enforcement to MCP tool execution. Both transport-driven calls and direct `executeTool()` calls now run the same authorization checks when a request user is present, and typed FGA permission constants are accepted in MCP server authorization config. ([#15410](https://github.com/mastra-ai/mastra/pull/15410))
|
|
8
|
+
|
|
9
|
+
- Updated dependencies [[`86c0298`](https://github.com/mastra-ai/mastra/commit/86c0298e647306423c842f9d5ac827bd616bd13d), [`7fce309`](https://github.com/mastra-ai/mastra/commit/7fce30912b14170bfc41f0ac736cca0f39fe0cd4), [`7997c2e`](https://github.com/mastra-ai/mastra/commit/7997c2e55ddd121562a4098cd8d2b89c68433bf1), [`e97ccb9`](https://github.com/mastra-ai/mastra/commit/e97ccb900f8b7a390ce82c9f8eb8d6eb2c5e3777), [`c5daf48`](https://github.com/mastra-ai/mastra/commit/c5daf48556e98c46ae06caf00f92c249912007e9), [`cd96779`](https://github.com/mastra-ai/mastra/commit/cd9677937f113b2856dc8b9f3d4bdabcee58bb2e)]:
|
|
10
|
+
- @mastra/core@1.32.0-alpha.2
|
|
11
|
+
|
|
3
12
|
## 1.6.1-alpha.0
|
|
4
13
|
|
|
5
14
|
### Patch Changes
|
package/dist/docs/SKILL.md
CHANGED
|
@@ -332,6 +332,31 @@ const mcp = new MCPClient({
|
|
|
332
332
|
})
|
|
333
333
|
```
|
|
334
334
|
|
|
335
|
+
**Apify**:
|
|
336
|
+
|
|
337
|
+
[Apify](https://apify.com) is the largest marketplace of tools for AI, with thousands of ready-made [Actors](https://apify.com/store) to extract real-time data from any website, track competitors, generate leads, analyze sentiment, or orchestrate your apps. Connect your agent through the [Apify MCP Server](https://mcp.apify.com).
|
|
338
|
+
|
|
339
|
+
```typescript
|
|
340
|
+
import { MCPClient } from '@mastra/mcp'
|
|
341
|
+
|
|
342
|
+
export const mcp = new MCPClient({
|
|
343
|
+
servers: {
|
|
344
|
+
apify: {
|
|
345
|
+
url: new URL('https://mcp.apify.com'),
|
|
346
|
+
requestInit: {
|
|
347
|
+
headers: {
|
|
348
|
+
Authorization: `Bearer ${process.env.APIFY_TOKEN}`,
|
|
349
|
+
},
|
|
350
|
+
},
|
|
351
|
+
},
|
|
352
|
+
},
|
|
353
|
+
})
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
Get your API token from the [Apify Console](https://console.apify.com/settings/integrations) and store it as `APIFY_TOKEN` in your environment.
|
|
357
|
+
|
|
358
|
+
To pick specific Actors and tools, use the [Apify MCP server configurator](https://mcp.apify.com) and copy the generated URL.
|
|
359
|
+
|
|
335
360
|
**Ampersand**:
|
|
336
361
|
|
|
337
362
|
[Ampersand](https://withampersand.com?utm_source=mastra-docs) offers an [MCP Server](https://docs.withampersand.com/mcp) that allows you to connect your agent to 150+ integrations with SaaS products like Salesforce, Hubspot, and Zendesk.
|
package/dist/index.cjs
CHANGED
|
@@ -2826,9 +2826,11 @@ var MCPServer = class extends mcp.MCPServerBase {
|
|
|
2826
2826
|
* This allows us to create multiple server instances with identical functionality.
|
|
2827
2827
|
*/
|
|
2828
2828
|
registerHandlersOnServer(serverInstance) {
|
|
2829
|
-
serverInstance.setRequestHandler(types_js.ListToolsRequestSchema, async () => {
|
|
2829
|
+
serverInstance.setRequestHandler(types_js.ListToolsRequestSchema, async (_request, extra) => {
|
|
2830
|
+
const proxiedContext = this.createProxiedRequestContext(extra);
|
|
2831
|
+
const tools = await this.getAuthorizedConvertedToolEntries(proxiedContext);
|
|
2830
2832
|
return {
|
|
2831
|
-
tools:
|
|
2833
|
+
tools: tools.map(([, tool]) => {
|
|
2832
2834
|
const toolSpec = {
|
|
2833
2835
|
name: tool.id || "unknown",
|
|
2834
2836
|
description: tool.description,
|
|
@@ -2920,6 +2922,7 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
2920
2922
|
throw new Error(`The "extra" key is now nested under "mcp.extra" in tool arguments`);
|
|
2921
2923
|
}
|
|
2922
2924
|
};
|
|
2925
|
+
await this.enforceToolExecutionFGA(request.params.name, proxiedContext);
|
|
2923
2926
|
const result = await tool.execute(validation?.value ?? request.params.arguments ?? {}, mcpOptions);
|
|
2924
2927
|
const duration = Date.now() - startTime;
|
|
2925
2928
|
if (tools.isValidationError(result)) {
|
|
@@ -4111,7 +4114,24 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
4111
4114
|
* });
|
|
4112
4115
|
* ```
|
|
4113
4116
|
*/
|
|
4114
|
-
getToolListInfo() {
|
|
4117
|
+
getToolListInfo(requestContext) {
|
|
4118
|
+
const fgaProvider = this.mastra?.getServer?.()?.fga;
|
|
4119
|
+
if (fgaProvider && requestContext) {
|
|
4120
|
+
return this.getAuthorizedConvertedToolEntries(requestContext).then((tools) => ({
|
|
4121
|
+
tools: tools.map(([toolId, tool]) => ({
|
|
4122
|
+
id: toolId,
|
|
4123
|
+
name: tool.id || toolId,
|
|
4124
|
+
description: tool.description,
|
|
4125
|
+
inputSchema: this.convertSchema(tool.parameters),
|
|
4126
|
+
outputSchema: this.convertSchema(tool.outputSchema),
|
|
4127
|
+
toolType: tool.mcp?.toolType,
|
|
4128
|
+
_meta: withMastraToolStrictMeta(tool.mcp?._meta, tool.strict)
|
|
4129
|
+
}))
|
|
4130
|
+
}));
|
|
4131
|
+
}
|
|
4132
|
+
if (fgaProvider && !requestContext) {
|
|
4133
|
+
return { tools: [] };
|
|
4134
|
+
}
|
|
4115
4135
|
this.logger.debug("Getting tool list", { server: this.name });
|
|
4116
4136
|
return {
|
|
4117
4137
|
tools: Object.entries(this.convertedTools).map(([toolId, tool]) => ({
|
|
@@ -4119,7 +4139,7 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
4119
4139
|
name: tool.id || toolId,
|
|
4120
4140
|
description: tool.description,
|
|
4121
4141
|
inputSchema: this.convertSchema(tool.parameters),
|
|
4122
|
-
outputSchema: this.convertSchema(tool.
|
|
4142
|
+
outputSchema: this.convertSchema(tool.outputSchema),
|
|
4123
4143
|
toolType: tool.mcp?.toolType,
|
|
4124
4144
|
_meta: withMastraToolStrictMeta(tool.mcp?._meta, tool.strict)
|
|
4125
4145
|
}))
|
|
@@ -4159,6 +4179,58 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
4159
4179
|
_meta: withMastraToolStrictMeta(tool.mcp?._meta, tool.strict)
|
|
4160
4180
|
};
|
|
4161
4181
|
}
|
|
4182
|
+
createProxiedRequestContext(extra) {
|
|
4183
|
+
const proxiedContext = new requestContext.RequestContext();
|
|
4184
|
+
if (extra && typeof extra === "object") {
|
|
4185
|
+
Object.entries(extra).forEach(([key, value]) => {
|
|
4186
|
+
proxiedContext.set(key, value);
|
|
4187
|
+
});
|
|
4188
|
+
}
|
|
4189
|
+
return proxiedContext;
|
|
4190
|
+
}
|
|
4191
|
+
async getAuthorizedConvertedToolEntries(requestContext) {
|
|
4192
|
+
const entries = Object.entries(this.convertedTools);
|
|
4193
|
+
const fgaProvider = this.mastra?.getServer?.()?.fga;
|
|
4194
|
+
if (!fgaProvider) {
|
|
4195
|
+
return entries;
|
|
4196
|
+
}
|
|
4197
|
+
const user = requestContext.get("user");
|
|
4198
|
+
if (!user) {
|
|
4199
|
+
return [];
|
|
4200
|
+
}
|
|
4201
|
+
const accessible = await Promise.all(
|
|
4202
|
+
entries.map(async ([toolId, tool]) => {
|
|
4203
|
+
try {
|
|
4204
|
+
await this.enforceToolExecutionFGA(toolId, requestContext);
|
|
4205
|
+
return [toolId, tool];
|
|
4206
|
+
} catch (error) {
|
|
4207
|
+
if (error instanceof Error && error.name === "FGADeniedError") {
|
|
4208
|
+
return null;
|
|
4209
|
+
}
|
|
4210
|
+
throw error;
|
|
4211
|
+
}
|
|
4212
|
+
})
|
|
4213
|
+
);
|
|
4214
|
+
return accessible.filter((entry) => entry !== null);
|
|
4215
|
+
}
|
|
4216
|
+
async enforceToolExecutionFGA(toolId, requestContext) {
|
|
4217
|
+
const fgaProvider = this.mastra?.getServer?.()?.fga;
|
|
4218
|
+
if (!fgaProvider) {
|
|
4219
|
+
return;
|
|
4220
|
+
}
|
|
4221
|
+
const { checkFGA, FGADeniedError, MastraFGAPermissions } = await import('@mastra/core/auth/ee');
|
|
4222
|
+
const resourceId = JSON.stringify([this.id, toolId]);
|
|
4223
|
+
const user = requestContext?.get("user");
|
|
4224
|
+
if (!user) {
|
|
4225
|
+
throw new FGADeniedError({ id: "unknown" }, { type: "tool", id: resourceId }, MastraFGAPermissions.TOOLS_EXECUTE);
|
|
4226
|
+
}
|
|
4227
|
+
await checkFGA({
|
|
4228
|
+
fgaProvider,
|
|
4229
|
+
user,
|
|
4230
|
+
resource: { type: "tool", id: resourceId },
|
|
4231
|
+
permission: MastraFGAPermissions.TOOLS_EXECUTE
|
|
4232
|
+
});
|
|
4233
|
+
}
|
|
4162
4234
|
/**
|
|
4163
4235
|
* Executes a specific tool provided by this MCP server.
|
|
4164
4236
|
*
|
|
@@ -4241,8 +4313,10 @@ Provided arguments: ${JSON.stringify(args, null, 2)}`,
|
|
|
4241
4313
|
try {
|
|
4242
4314
|
const finalExecutionContext = {
|
|
4243
4315
|
messages: executionContext?.messages || [],
|
|
4244
|
-
toolCallId: executionContext?.toolCallId || crypto$1.randomUUID()
|
|
4316
|
+
toolCallId: executionContext?.toolCallId || crypto$1.randomUUID(),
|
|
4317
|
+
requestContext: executionContext?.requestContext
|
|
4245
4318
|
};
|
|
4319
|
+
await this.enforceToolExecutionFGA(toolId, finalExecutionContext.requestContext);
|
|
4246
4320
|
const result = await tool.execute(validatedArgs, finalExecutionContext);
|
|
4247
4321
|
this.logger.info("Tool executed successfully", { tool: toolId });
|
|
4248
4322
|
return result;
|