@mastra/mcp 1.8.1 → 1.9.0-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 +77 -0
- package/dist/client/client.d.ts +5 -0
- package/dist/client/client.d.ts.map +1 -1
- package/dist/client/configuration.d.ts +7 -0
- package/dist/client/configuration.d.ts.map +1 -1
- package/dist/client/types.d.ts +17 -0
- package/dist/client/types.d.ts.map +1 -1
- package/dist/docs/SKILL.md +2 -1
- package/dist/docs/assets/SOURCE_MAP.json +1 -1
- package/dist/docs/references/docs-mcp-mcp-apps.md +3 -3
- package/dist/docs/references/docs-mcp-overview.md +1 -1
- package/dist/docs/references/docs-server-auth-fga.md +258 -0
- package/dist/docs/references/reference-tools-mcp-client.md +53 -2
- package/dist/docs/references/reference-tools-mcp-server.md +33 -1
- package/dist/index.cjs +95 -20
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +95 -20
- package/dist/index.js.map +1 -1
- package/dist/server/server.d.ts +3 -0
- package/dist/server/server.d.ts.map +1 -1
- package/package.json +7 -7
|
@@ -22,7 +22,7 @@ const myAgent = new Agent({
|
|
|
22
22
|
name: 'MyExampleAgent',
|
|
23
23
|
description: 'A generalist to help with basic questions.',
|
|
24
24
|
instructions: 'You are a helpful assistant.',
|
|
25
|
-
model: 'openai/gpt-5.
|
|
25
|
+
model: 'openai/gpt-5.5',
|
|
26
26
|
})
|
|
27
27
|
|
|
28
28
|
const weatherTool = createTool({
|
|
@@ -67,6 +67,8 @@ The constructor accepts an `MCPServerConfig` object with the following propertie
|
|
|
67
67
|
|
|
68
68
|
**instructions** (`string`): Optional instructions describing how to use the server and its features.
|
|
69
69
|
|
|
70
|
+
**mapAuthInfoToUser** (`({ authInfo, extra, requestContext }) => unknown | null | undefined | Promise<unknown | null | undefined>`): Maps MCP transport auth data from \`extra.authInfo\` into the \`user\` value used by Mastra FGA checks. Use this when an OAuth-protected MCP server is registered on a Mastra instance with an FGA provider.
|
|
71
|
+
|
|
70
72
|
**repository** (`Repository`): Optional repository information for the server's source code.
|
|
71
73
|
|
|
72
74
|
**releaseDate** (`string`): Optional release date of this server version (ISO 8601 string). Defaults to the time of instantiation if not provided.
|
|
@@ -1097,6 +1099,36 @@ Whatever you set on `req.auth` in your HTTP middleware becomes available as `con
|
|
|
1097
1099
|
req.auth = { ... } → context?.mcp?.extra?.authInfo.extra = { ... }
|
|
1098
1100
|
```
|
|
1099
1101
|
|
|
1102
|
+
### Map auth data for FGA
|
|
1103
|
+
|
|
1104
|
+
When an `MCPServer` is registered on a Mastra instance with a fine-grained authorization (FGA) provider, Mastra checks `requestContext.get('user')` before listing or calling tools. HTTP MCP transports pass authenticated data as `extra.authInfo`, so use `mapAuthInfoToUser` to set the user shape expected by your FGA provider.
|
|
1105
|
+
|
|
1106
|
+
```typescript
|
|
1107
|
+
const server = new MCPServer({
|
|
1108
|
+
id: 'my-server',
|
|
1109
|
+
name: 'My Server',
|
|
1110
|
+
version: '1.0.0',
|
|
1111
|
+
tools: { getUserData },
|
|
1112
|
+
mapAuthInfoToUser: ({ authInfo }) => {
|
|
1113
|
+
const user = authInfo as {
|
|
1114
|
+
extra?: {
|
|
1115
|
+
userId?: string
|
|
1116
|
+
organizationMembershipId?: string
|
|
1117
|
+
}
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
if (!user.extra?.userId) {
|
|
1121
|
+
return null
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
return {
|
|
1125
|
+
id: user.extra.userId,
|
|
1126
|
+
organizationMembershipId: user.extra.organizationMembershipId,
|
|
1127
|
+
}
|
|
1128
|
+
},
|
|
1129
|
+
})
|
|
1130
|
+
```
|
|
1131
|
+
|
|
1100
1132
|
### Setting Up Authentication Middleware
|
|
1101
1133
|
|
|
1102
1134
|
To pass data to your tools, populate `req.auth` on the Node.js request object in your HTTP server middleware before calling `server.startHTTP()`.
|
package/dist/index.cjs
CHANGED
|
@@ -425,6 +425,7 @@ function isReconnectableMCPError(error) {
|
|
|
425
425
|
|
|
426
426
|
// src/client/client.ts
|
|
427
427
|
var DEFAULT_SERVER_CONNECT_TIMEOUT_MSEC = 3e3;
|
|
428
|
+
var DEFAULT_INSTRUCTIONS_MAX_LENGTH = 512;
|
|
428
429
|
var require2 = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
|
|
429
430
|
var SSE_FALLBACK_STATUS_CODES = [400, 404, 405];
|
|
430
431
|
var DATADOG_TRACER_TEST_SYMBOL = /* @__PURE__ */ Symbol.for("mastra.mcp.dd-trace-test-tracer");
|
|
@@ -507,6 +508,7 @@ var InternalMastraMCPClient = class extends base.MastraBase {
|
|
|
507
508
|
exitHookUnsubscribe;
|
|
508
509
|
sigTermHandler;
|
|
509
510
|
sigHupHandler;
|
|
511
|
+
serverInstructions;
|
|
510
512
|
_roots;
|
|
511
513
|
requireToolApproval;
|
|
512
514
|
/** Provides access to resource operations (list, read, subscribe, etc.) */
|
|
@@ -753,11 +755,19 @@ var InternalMastraMCPClient = class extends base.MastraBase {
|
|
|
753
755
|
} else {
|
|
754
756
|
throw new Error("Server configuration must include either a command or a url.");
|
|
755
757
|
}
|
|
758
|
+
this.refreshServerInstructions();
|
|
756
759
|
resolve(true);
|
|
757
760
|
const originalOnClose = this.client.onclose;
|
|
758
761
|
this.client.onclose = () => {
|
|
759
762
|
this.log("debug", `MCP server connection closed`);
|
|
763
|
+
const staleTransport = this.transport;
|
|
764
|
+
this.transport = void 0;
|
|
760
765
|
this.isConnected = null;
|
|
766
|
+
this.serverInstructions = void 0;
|
|
767
|
+
if (staleTransport) {
|
|
768
|
+
void staleTransport.close().catch(() => {
|
|
769
|
+
});
|
|
770
|
+
}
|
|
761
771
|
if (typeof originalOnClose === "function") {
|
|
762
772
|
originalOnClose();
|
|
763
773
|
}
|
|
@@ -815,6 +825,18 @@ var InternalMastraMCPClient = class extends base.MastraBase {
|
|
|
815
825
|
}
|
|
816
826
|
return null;
|
|
817
827
|
}
|
|
828
|
+
get instructions() {
|
|
829
|
+
return this.serverInstructions;
|
|
830
|
+
}
|
|
831
|
+
get forwardInstructions() {
|
|
832
|
+
return this.serverConfig.forwardInstructions ?? false;
|
|
833
|
+
}
|
|
834
|
+
get instructionsMaxLength() {
|
|
835
|
+
return this.serverConfig.instructionsMaxLength ?? DEFAULT_INSTRUCTIONS_MAX_LENGTH;
|
|
836
|
+
}
|
|
837
|
+
refreshServerInstructions() {
|
|
838
|
+
this.serverInstructions = this.client.getInstructions();
|
|
839
|
+
}
|
|
818
840
|
async disconnect() {
|
|
819
841
|
if (!this.transport) {
|
|
820
842
|
this.log("debug", "Disconnect called but no transport was connected.");
|
|
@@ -832,6 +854,7 @@ var InternalMastraMCPClient = class extends base.MastraBase {
|
|
|
832
854
|
} finally {
|
|
833
855
|
this.transport = void 0;
|
|
834
856
|
this.isConnected = null;
|
|
857
|
+
this.serverInstructions = void 0;
|
|
835
858
|
if (this.exitHookUnsubscribe) {
|
|
836
859
|
this.exitHookUnsubscribe();
|
|
837
860
|
this.exitHookUnsubscribe = void 0;
|
|
@@ -870,6 +893,7 @@ var InternalMastraMCPClient = class extends base.MastraBase {
|
|
|
870
893
|
}
|
|
871
894
|
this.transport = void 0;
|
|
872
895
|
this.isConnected = null;
|
|
896
|
+
this.serverInstructions = void 0;
|
|
873
897
|
await this.connect();
|
|
874
898
|
this.log("debug", "Successfully reconnected to MCP server");
|
|
875
899
|
}
|
|
@@ -1008,7 +1032,10 @@ var InternalMastraMCPClient = class extends base.MastraBase {
|
|
|
1008
1032
|
requireApproval,
|
|
1009
1033
|
mcpMetadata: {
|
|
1010
1034
|
serverName: this.name,
|
|
1011
|
-
serverVersion: this.client.getServerVersion()?.version
|
|
1035
|
+
serverVersion: this.client.getServerVersion()?.version,
|
|
1036
|
+
serverInstructions: this.serverInstructions,
|
|
1037
|
+
forwardInstructions: this.forwardInstructions,
|
|
1038
|
+
instructionsMaxLength: this.instructionsMaxLength
|
|
1012
1039
|
},
|
|
1013
1040
|
execute: async (input, context) => {
|
|
1014
1041
|
const operationContext = context?.requestContext ?? null;
|
|
@@ -1872,6 +1899,19 @@ To fix this you have three different options:
|
|
|
1872
1899
|
await this.getConnectedClientForServer(serverName);
|
|
1873
1900
|
}
|
|
1874
1901
|
}
|
|
1902
|
+
/**
|
|
1903
|
+
* Returns instructions advertised by connected MCP servers during initialize.
|
|
1904
|
+
*
|
|
1905
|
+
* Servers that have not connected yet, or did not advertise instructions,
|
|
1906
|
+
* return `undefined`.
|
|
1907
|
+
*/
|
|
1908
|
+
getServerInstructions() {
|
|
1909
|
+
const instructions = {};
|
|
1910
|
+
for (const serverName of Object.keys(this.serverConfigs)) {
|
|
1911
|
+
instructions[serverName] = this.mcpClientsById.get(serverName)?.instructions;
|
|
1912
|
+
}
|
|
1913
|
+
return instructions;
|
|
1914
|
+
}
|
|
1875
1915
|
/**
|
|
1876
1916
|
* Retrieves all tools from all configured servers with namespaced names.
|
|
1877
1917
|
*
|
|
@@ -2317,7 +2357,7 @@ function createSimpleTokenProvider(accessToken, options) {
|
|
|
2317
2357
|
});
|
|
2318
2358
|
}
|
|
2319
2359
|
|
|
2320
|
-
//
|
|
2360
|
+
// ../../../../../setup-pnpm/node_modules/.bin/store/v11/links/@/hono/4.12.18/a4592d669eb2c33e4f24995614864047f2c1a155accc9d64dd2de0f4e8d608a9/node_modules/hono/dist/utils/stream.js
|
|
2321
2361
|
var StreamingApi = class {
|
|
2322
2362
|
writer;
|
|
2323
2363
|
encoder;
|
|
@@ -2394,7 +2434,7 @@ var StreamingApi = class {
|
|
|
2394
2434
|
}
|
|
2395
2435
|
};
|
|
2396
2436
|
|
|
2397
|
-
//
|
|
2437
|
+
// ../../../../../setup-pnpm/node_modules/.bin/store/v11/links/@/hono/4.12.18/a4592d669eb2c33e4f24995614864047f2c1a155accc9d64dd2de0f4e8d608a9/node_modules/hono/dist/helper/streaming/utils.js
|
|
2398
2438
|
var isOldBunVersion = () => {
|
|
2399
2439
|
const version = typeof Bun !== "undefined" ? Bun.version : void 0;
|
|
2400
2440
|
if (version === void 0) {
|
|
@@ -2405,7 +2445,7 @@ var isOldBunVersion = () => {
|
|
|
2405
2445
|
return result;
|
|
2406
2446
|
};
|
|
2407
2447
|
|
|
2408
|
-
//
|
|
2448
|
+
// ../../../../../setup-pnpm/node_modules/.bin/store/v11/links/@/hono/4.12.18/a4592d669eb2c33e4f24995614864047f2c1a155accc9d64dd2de0f4e8d608a9/node_modules/hono/dist/utils/html.js
|
|
2409
2449
|
var HtmlEscapedCallbackPhase = {
|
|
2410
2450
|
Stringify: 1};
|
|
2411
2451
|
var resolveCallback = async (str, phase, preserveCallbacks, context, buffer) => {
|
|
@@ -2436,7 +2476,7 @@ var resolveCallback = async (str, phase, preserveCallbacks, context, buffer) =>
|
|
|
2436
2476
|
}
|
|
2437
2477
|
};
|
|
2438
2478
|
|
|
2439
|
-
//
|
|
2479
|
+
// ../../../../../setup-pnpm/node_modules/.bin/store/v11/links/@/hono/4.12.18/a4592d669eb2c33e4f24995614864047f2c1a155accc9d64dd2de0f4e8d608a9/node_modules/hono/dist/helper/streaming/sse.js
|
|
2440
2480
|
var SSEStreamingApi = class extends StreamingApi {
|
|
2441
2481
|
constructor(writable, readable) {
|
|
2442
2482
|
super(writable, readable);
|
|
@@ -2743,6 +2783,7 @@ var MCPServer = class extends mcp.MCPServerBase {
|
|
|
2743
2783
|
definedPrompts;
|
|
2744
2784
|
promptOptions;
|
|
2745
2785
|
jsonSchemaValidator;
|
|
2786
|
+
mapAuthInfoToUser;
|
|
2746
2787
|
subscriptions = /* @__PURE__ */ new Set();
|
|
2747
2788
|
currentLoggingLevel;
|
|
2748
2789
|
/**
|
|
@@ -2844,6 +2885,7 @@ var MCPServer = class extends mcp.MCPServerBase {
|
|
|
2844
2885
|
* @param opts.prompts - Optional prompt configuration for exposing reusable templates
|
|
2845
2886
|
* @param opts.id - Optional unique identifier (generated if not provided)
|
|
2846
2887
|
* @param opts.description - Optional description of what the server does
|
|
2888
|
+
* @param opts.mapAuthInfoToUser - Optional mapper from MCP `extra.authInfo` to the FGA user context
|
|
2847
2889
|
*
|
|
2848
2890
|
* @example
|
|
2849
2891
|
* ```typescript
|
|
@@ -2880,6 +2922,7 @@ var MCPServer = class extends mcp.MCPServerBase {
|
|
|
2880
2922
|
this.resourceOptions = this.mergeAppResources(opts.resources, opts.appResources);
|
|
2881
2923
|
this.promptOptions = opts.prompts;
|
|
2882
2924
|
this.jsonSchemaValidator = opts.jsonSchemaValidator;
|
|
2925
|
+
this.mapAuthInfoToUser = opts.mapAuthInfoToUser;
|
|
2883
2926
|
const capabilities = {
|
|
2884
2927
|
tools: {},
|
|
2885
2928
|
logging: { enabled: true }
|
|
@@ -3116,7 +3159,7 @@ var MCPServer = class extends mcp.MCPServerBase {
|
|
|
3116
3159
|
*/
|
|
3117
3160
|
registerHandlersOnServer(serverInstance) {
|
|
3118
3161
|
serverInstance.setRequestHandler(types_js.ListToolsRequestSchema, async (_request, extra) => {
|
|
3119
|
-
const proxiedContext = this.createProxiedRequestContext(extra);
|
|
3162
|
+
const proxiedContext = await this.createProxiedRequestContext(extra);
|
|
3120
3163
|
const tools = await this.getAuthorizedConvertedToolEntries(proxiedContext);
|
|
3121
3164
|
return {
|
|
3122
3165
|
tools: tools.map(([, tool]) => {
|
|
@@ -3196,12 +3239,7 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
3196
3239
|
return this.handleElicitationRequest(request2, serverInstance, options);
|
|
3197
3240
|
}
|
|
3198
3241
|
};
|
|
3199
|
-
const proxiedContext =
|
|
3200
|
-
if (extra) {
|
|
3201
|
-
Object.entries(extra).forEach(([key, value]) => {
|
|
3202
|
-
proxiedContext.set(key, value);
|
|
3203
|
-
});
|
|
3204
|
-
}
|
|
3242
|
+
const proxiedContext = await this.createProxiedRequestContext(extra);
|
|
3205
3243
|
const mcpOptions = {
|
|
3206
3244
|
messages: [],
|
|
3207
3245
|
toolCallId: "",
|
|
@@ -4480,22 +4518,50 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
4480
4518
|
_meta: withMastraToolStrictMeta(tool.mcp?._meta, tool.strict)
|
|
4481
4519
|
};
|
|
4482
4520
|
}
|
|
4483
|
-
createProxiedRequestContext(extra) {
|
|
4521
|
+
async createProxiedRequestContext(extra) {
|
|
4484
4522
|
const proxiedContext = new requestContext.RequestContext();
|
|
4523
|
+
let extraRecord;
|
|
4485
4524
|
if (extra && typeof extra === "object") {
|
|
4486
|
-
|
|
4525
|
+
extraRecord = extra;
|
|
4526
|
+
Object.entries(extraRecord).forEach(([key, value]) => {
|
|
4487
4527
|
proxiedContext.set(key, value);
|
|
4488
4528
|
});
|
|
4489
4529
|
}
|
|
4530
|
+
await this.resolveMappedFGAUser(proxiedContext, extraRecord);
|
|
4490
4531
|
return proxiedContext;
|
|
4491
4532
|
}
|
|
4533
|
+
async resolveMappedFGAUser(requestContext, extra) {
|
|
4534
|
+
if (!requestContext) {
|
|
4535
|
+
return void 0;
|
|
4536
|
+
}
|
|
4537
|
+
const existingUser = requestContext.get("user");
|
|
4538
|
+
if (existingUser) {
|
|
4539
|
+
return existingUser;
|
|
4540
|
+
}
|
|
4541
|
+
if (!this.mapAuthInfoToUser) {
|
|
4542
|
+
return void 0;
|
|
4543
|
+
}
|
|
4544
|
+
const authInfo = extra && "authInfo" in extra ? extra.authInfo : requestContext.get("authInfo");
|
|
4545
|
+
if (!authInfo) {
|
|
4546
|
+
return void 0;
|
|
4547
|
+
}
|
|
4548
|
+
const user = await this.mapAuthInfoToUser({
|
|
4549
|
+
authInfo,
|
|
4550
|
+
extra: extra ?? { authInfo },
|
|
4551
|
+
requestContext
|
|
4552
|
+
});
|
|
4553
|
+
if (user) {
|
|
4554
|
+
requestContext.set("user", user);
|
|
4555
|
+
}
|
|
4556
|
+
return user;
|
|
4557
|
+
}
|
|
4492
4558
|
async getAuthorizedConvertedToolEntries(requestContext) {
|
|
4493
4559
|
const entries = Object.entries(this.convertedTools);
|
|
4494
4560
|
const fgaProvider = this.mastra?.getServer?.()?.fga;
|
|
4495
4561
|
if (!fgaProvider) {
|
|
4496
4562
|
return entries;
|
|
4497
4563
|
}
|
|
4498
|
-
const user =
|
|
4564
|
+
const user = await this.resolveMappedFGAUser(requestContext);
|
|
4499
4565
|
if (!user) {
|
|
4500
4566
|
return [];
|
|
4501
4567
|
}
|
|
@@ -4519,17 +4585,26 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
4519
4585
|
if (!fgaProvider) {
|
|
4520
4586
|
return;
|
|
4521
4587
|
}
|
|
4522
|
-
const {
|
|
4523
|
-
const resourceId =
|
|
4524
|
-
const user = requestContext
|
|
4588
|
+
const { getMCPToolFGAResourceId, requireFGA, FGADeniedError, MastraFGAPermissions } = await import('@mastra/core/auth/ee');
|
|
4589
|
+
const resourceId = getMCPToolFGAResourceId(this.id, toolId);
|
|
4590
|
+
const user = await this.resolveMappedFGAUser(requestContext);
|
|
4525
4591
|
if (!user) {
|
|
4526
4592
|
throw new FGADeniedError({ id: "unknown" }, { type: "tool", id: resourceId }, MastraFGAPermissions.TOOLS_EXECUTE);
|
|
4527
4593
|
}
|
|
4528
|
-
await
|
|
4594
|
+
await requireFGA({
|
|
4529
4595
|
fgaProvider,
|
|
4530
4596
|
user,
|
|
4531
4597
|
resource: { type: "tool", id: resourceId },
|
|
4532
|
-
permission: MastraFGAPermissions.TOOLS_EXECUTE
|
|
4598
|
+
permission: MastraFGAPermissions.TOOLS_EXECUTE,
|
|
4599
|
+
requestContext,
|
|
4600
|
+
context: {
|
|
4601
|
+
resourceId
|
|
4602
|
+
},
|
|
4603
|
+
metadata: {
|
|
4604
|
+
mcpServerId: this.id,
|
|
4605
|
+
mcpServerName: this.name,
|
|
4606
|
+
toolId
|
|
4607
|
+
}
|
|
4533
4608
|
});
|
|
4534
4609
|
}
|
|
4535
4610
|
/**
|