@mastra/mcp 1.9.2-alpha.0 → 1.10.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 CHANGED
@@ -1,5 +1,37 @@
1
1
  # @mastra/mcp
2
2
 
3
+ ## 1.10.0-alpha.1
4
+
5
+ ### Minor Changes
6
+
7
+ - Added MCP server Fine-Grained Authorization mapping overrides for tool authorization. ([#17529](https://github.com/mastra-ai/mastra/pull/17529))
8
+
9
+ Use the new `fga` option on `MCPServer` to customize the resource and permission mappings used for `tools/list` and `tools/call` checks without changing the Mastra instance-level `tool` mapping used by internal agent and workflow tool execution.
10
+
11
+ ```ts
12
+ const server = new MCPServer({
13
+ name: 'My Server',
14
+ version: '1.0.0',
15
+ tools: { getData },
16
+ fga: {
17
+ resourceMapping: {
18
+ tool: {
19
+ fgaResourceType: 'user',
20
+ deriveId: ({ user }) => user.id,
21
+ },
22
+ },
23
+ permissionMapping: {
24
+ 'tools:execute': 'read',
25
+ },
26
+ },
27
+ });
28
+ ```
29
+
30
+ ### Patch Changes
31
+
32
+ - Updated dependencies [[`575f815`](https://github.com/mastra-ai/mastra/commit/575f815c5c3567b71c0b83cbb7fa98c8253a9d9c), [`306909a`](https://github.com/mastra-ai/mastra/commit/306909a693de77d709b38706e2673c9547d24a28), [`5191af8`](https://github.com/mastra-ai/mastra/commit/5191af80c799eea25357c545fc05d91b3883531d), [`43bd3d4`](https://github.com/mastra-ai/mastra/commit/43bd3d421987463fdf35386a45199c49499ed069), [`e6fa79e`](https://github.com/mastra-ai/mastra/commit/e6fa79ec72a2ddffdd25e85270398951e9d552a4), [`904bcdf`](https://github.com/mastra-ai/mastra/commit/904bcdf7b8004aa7be823f9f70ca63580e47e470), [`7f5ee1d`](https://github.com/mastra-ai/mastra/commit/7f5ee1dca46daee8d2817f2ebe49e6335da81956), [`1e9aab5`](https://github.com/mastra-ai/mastra/commit/1e9aab50ff11e6e88fde4d7cbf512c44a9fe8d61), [`bf8eb6d`](https://github.com/mastra-ai/mastra/commit/bf8eb6d0ec213a403eb9265a594ad283c44ab3dc), [`493a328`](https://github.com/mastra-ai/mastra/commit/493a328f4346a1deeb9f1e2e44c8f2a3a4d7591b), [`029a414`](https://github.com/mastra-ai/mastra/commit/029a4141719793bd3e898a39eb5a0466a55f5f3a), [`b147b29`](https://github.com/mastra-ai/mastra/commit/b147b2907f0cd1aa812efe6d6e3f58d22e66fc88), [`d371ac1`](https://github.com/mastra-ai/mastra/commit/d371ac1d9820afaaf7cfdbc380a475946a994d8f), [`cf182b7`](https://github.com/mastra-ai/mastra/commit/cf182b7fb495767946d9840ef29f19cfa906f31f), [`a049c2a`](https://github.com/mastra-ai/mastra/commit/a049c2a9dfb41d0ee2e7a28874a88cd64fd5669f), [`b147b29`](https://github.com/mastra-ai/mastra/commit/b147b2907f0cd1aa812efe6d6e3f58d22e66fc88), [`2a96528`](https://github.com/mastra-ai/mastra/commit/2a9652848dfa3c5a2426f952e9d93554c26fd90f), [`2656d9c`](https://github.com/mastra-ai/mastra/commit/2656d9c2976d4f3354253bfbbbf9b88a1b2bbf34), [`63e3fe1`](https://github.com/mastra-ai/mastra/commit/63e3fe13cc1ea96f91d7c68aea92f400faf9e4da), [`1d4ce8d`](https://github.com/mastra-ai/mastra/commit/1d4ce8daaa54511f325c1b609d31b8e54009d677), [`8c68372`](https://github.com/mastra-ai/mastra/commit/8c68372e85fe0b066ec12c58bd29ffb93e54c552)]:
33
+ - @mastra/core@1.42.0-alpha.4
34
+
3
35
  ## 1.9.2-alpha.0
4
36
 
5
37
  ### Patch Changes
@@ -3,7 +3,7 @@ name: mastra-mcp
3
3
  description: Documentation for @mastra/mcp. Use when working with @mastra/mcp APIs, configuration, or implementation.
4
4
  metadata:
5
5
  package: "@mastra/mcp"
6
- version: "1.9.2-alpha.0"
6
+ version: "1.10.0-alpha.1"
7
7
  ---
8
8
 
9
9
  ## When to use
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.9.2-alpha.0",
2
+ "version": "1.10.0-alpha.1",
3
3
  "package": "@mastra/mcp",
4
4
  "exports": {
5
5
  "UnauthorizedError": {
@@ -83,7 +83,7 @@ calculatorTool._meta = {
83
83
 
84
84
  ## Connecting MCP Apps to agents
85
85
 
86
- Agents consume tools — they do not need to know about MCP servers. Pass tools to the agent's `tools` config, and register the MCP server at the Mastra level so Studio can resolve app resources.
86
+ Agents consume tools — they don't need to know about MCP servers. Pass tools to the agent's `tools` config, and register the MCP server at the Mastra level so Studio can resolve app resources.
87
87
 
88
88
  ```typescript
89
89
  import { Agent } from '@mastra/core/agent'
@@ -158,8 +158,8 @@ Agent calls tool → Tool returns brief content + structuredContent
158
158
 
159
159
  Tools with app resources should return two fields:
160
160
 
161
- - `content`: A brief text summary for the model. Keep this short so the agent does not parrot the full result.
162
- - `structuredContent`: The data payload that hydrates the UI. The model does not see this field.
161
+ - `content`: A brief text summary for the model. Keep this short so the agent doesn't parrot the full result.
162
+ - `structuredContent`: The data payload that hydrates the UI. The model doesn't see this field.
163
163
 
164
164
  ```typescript
165
165
  execute: async ({ num1, num2, operation }) => {
@@ -294,7 +294,7 @@ App iframes are sandboxed with the following permissions:
294
294
  - `allow-forms`: Allows form submission
295
295
  - `allow-popups`: Permits `window.open()` and link targets
296
296
 
297
- The iframe does not have access to the parent page's DOM, cookies, or storage. All communication happens through the JSON-RPC postMessage protocol managed by `@mcp-ui/client`'s `AppRenderer` on the host side and `@modelcontextprotocol/ext-apps`'s `App` class on the guest side.
297
+ The iframe doesn't have access to the parent page's DOM, cookies, or storage. All communication happens through the JSON-RPC postMessage protocol managed by `@mcp-ui/client`'s `AppRenderer` on the host side and `@modelcontextprotocol/ext-apps`'s `App` class on the guest side.
298
298
 
299
299
  ## Related
300
300
 
@@ -53,7 +53,7 @@ When using `MastraFGAWorkos`, set `fetchMemberships: true` on `MastraAuthWorkos`
53
53
 
54
54
  Use `thread` as the resource-mapping key for memory authorization. `MastraFGAWorkos` still accepts the legacy alias `memory`, but new configs should prefer `thread`.
55
55
 
56
- When `server.fga` is configured, Mastra enforces FGA on protected actions. If a protected action has no authenticated user, Mastra denies it. If `server.fga` is not configured, these FGA checks are skipped and Mastra keeps the previous behavior.
56
+ When `server.fga` is configured, Mastra enforces FGA on protected actions. If a protected action has no authenticated user, Mastra denies it. If `server.fga` isn't configured, these FGA checks are skipped and Mastra keeps the previous behavior.
57
57
 
58
58
  ### Resource mapping
59
59
 
@@ -100,7 +100,7 @@ Use `validatePermissions()` to validate the full set of permissions Mastra may e
100
100
 
101
101
  ### Stored resource scoping
102
102
 
103
- FGA authorizes access to a resource. It does not automatically filter stored records that live in shared storage. Enable stored resource scoping when the built-in stored resource APIs are used in a multi-tenant app.
103
+ FGA authorizes access to a resource. It doesn't automatically filter stored records that live in shared storage. Enable stored resource scoping when the built-in stored resource APIs are used in a multi-tenant app.
104
104
 
105
105
  ```typescript
106
106
  const mastra = new Mastra({
@@ -136,7 +136,7 @@ If `requireScope` is `true` or omitted, scoped stored resource routes fail when
136
136
 
137
137
  Mastra includes route-level FGA metadata for built-in resource routes, including agents, workflows, tools, MCP tools, memory threads, responses, conversations, and stored resources. Stored resource route coverage includes `/stored/agents`, `/stored/mcp-clients`, `/stored/prompt-blocks`, `/stored/scorers`, `/stored/skills`, and `/stored/workspaces`. A route is checked when it has route-level `fga` metadata, when Mastra can derive built-in metadata for that route, or when the provider supplies metadata with `resolveRouteFGA()`.
138
138
 
139
- To deny protected routes that do not resolve FGA metadata, configure route policy coverage on the FGA provider:
139
+ To deny protected routes that don't resolve FGA metadata, configure route policy coverage on the FGA provider:
140
140
 
141
141
  ```typescript
142
142
  const fga = new MastraFGAWorkos({
@@ -202,20 +202,20 @@ const fga = new MastraFGAWorkos({
202
202
 
203
203
  When an FGA provider is configured, Mastra automatically checks authorization at these lifecycle points:
204
204
 
205
- | Lifecycle point | Permission checked | Resource type | Resource ID |
206
- | ---------------------------------------------------------------- | ----------------------------------------------- | -------------------- | ------------------------------------------------------------------- |
207
- | Agent execution (`generate`, `stream`) | `agents:execute` | `agent` | `agentId` |
208
- | Built-in workflow HTTP execution routes and `Workflow.execute()` | `workflows:execute` | `workflow` | `workflowId` |
209
- | Standalone tool execution | `tools:execute` | `tool` | `toolName` |
210
- | Agent tool execution | `tools:execute` | `tool` | `${agentId}:${toolName}` |
211
- | MCP tool execution | `tools:execute` | `tool` | `JSON.stringify([serverName, toolName])` |
212
- | Thread and memory access | `memory:read`, `memory:write`, `memory:delete` | `thread` | `threadId` |
213
- | Stored resource routes | Stored resource permission for the route action | Stored resource type | Route record ID, or the stored-resource scope for collection routes |
214
- | HTTP resource routes | Configured per route | Configured per route | Configured per route |
205
+ | Lifecycle point | Permission checked | Resource type | Resource ID |
206
+ | ---------------------------------------------------------------- | ----------------------------------------------- | --------------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
207
+ | Agent execution (`generate`, `stream`) | `agents:execute` | `agent` | `agentId` |
208
+ | Built-in workflow HTTP execution routes and `Workflow.execute()` | `workflows:execute` | `workflow` | `workflowId` |
209
+ | Standalone tool execution | `tools:execute` | `tool` | `toolName` |
210
+ | Agent tool execution | `tools:execute` | `tool` | `${agentId}:${toolName}` |
211
+ | MCP tool execution | `tools:execute` | `tool` by default, or the server-level `fga.resourceMapping` override | `JSON.stringify([serverName, toolName])` by default, or the server-level derived ID |
212
+ | Thread and memory access | `memory:read`, `memory:write`, `memory:delete` | `thread` | `threadId` |
213
+ | Stored resource routes | Stored resource permission for the route action | Stored resource type | Route record ID, or the stored-resource scope for collection routes |
214
+ | HTTP resource routes | Configured per route | Configured per route | Configured per route |
215
215
 
216
- For OAuth-protected MCP servers, HTTP MCP transports pass authenticated data as `extra.authInfo`. If an `MCPServer` is registered on an FGA-enabled Mastra instance, configure `mapAuthInfoToUser` so Mastra can set `requestContext.get('user')` before checking `tools/list` and `tools/call`. See [MCPServer authentication context](https://mastra.ai/reference/tools/mcp-server).
216
+ For OAuth-protected MCP servers, HTTP MCP transports pass authenticated data as `extra.authInfo`. If an `MCPServer` is registered on an FGA-enabled Mastra instance, configure `mapAuthInfoToUser` so Mastra can set `requestContext.get('user')` before checking `tools/list` and `tools/call`. Use the server-level `fga` option when MCP tool checks need different resource or permission mapping than internal agent and workflow tool checks. See [MCPServer authentication context](https://mastra.ai/reference/tools/mcp-server).
217
217
 
218
- Direct SDK calls to `createRun().start()`, `resume()`, or `restart()` are not independently checked by core FGA in this release. Make those calls from a protected route or guard them in application code. Pass a `requestContext` with an authenticated user when invoking protected entry points directly.
218
+ Direct SDK calls to `createRun().start()`, `resume()`, or `restart()` aren't independently checked by core FGA in this release. Make those calls from a protected route or guard them in application code. Pass a `requestContext` with an authenticated user when invoking protected entry points directly.
219
219
 
220
220
  Core agent, internal workflow, tool, and memory checks also pass `requestContext` and action metadata to the FGA provider. Route checks pass `requestContext`. Thread checks pass the owning `resourceId` when available.
221
221
 
@@ -153,7 +153,7 @@ const agent = new Agent({
153
153
  })
154
154
  ```
155
155
 
156
- When `forwardInstructions` is omitted (the default), instructions are still cached and can be inspected via [`getServerInstructions()`](#getserverinstructions), but are not added to any agent's system prompt.
156
+ When `forwardInstructions` is omitted (the default), instructions are still cached and can be inspected via [`getServerInstructions()`](#getserverinstructions), but aren't added to any agent's system prompt.
157
157
 
158
158
  > **Security note:** server instructions are forwarded verbatim (subject only to length truncation) into the agent's system prompt. A malicious or compromised MCP server can use them to inject instructions the agent will treat as trusted system guidance. Only enable `forwardInstructions` for servers you trust, and prefer reviewing instructions with `getServerInstructions()` before forwarding instructions from third-party servers.
159
159
 
@@ -179,7 +179,7 @@ const res = await agent.stream(prompt, {
179
179
 
180
180
  ### `getServerInstructions()`
181
181
 
182
- Returns the instructions currently known for each configured MCP server. Servers that have not connected yet, or do not advertise instructions, return `undefined`.
182
+ Returns the instructions currently known for each configured MCP server. Servers that haven't connected yet, or don't advertise instructions, return `undefined`.
183
183
 
184
184
  ```typescript
185
185
  getServerInstructions(): Record<string, string | undefined>
@@ -1065,9 +1065,9 @@ await agent.generate('Hello!', {
1065
1065
 
1066
1066
  ## Handling auth failures inside custom fetch
1067
1067
 
1068
- A custom `fetch` should not `throw` when authentication is unavailable. The Streamable HTTP transport in the MCP SDK opens a long-lived `GET /mcp` "standalone listener" stream in the background to receive server-pushed notifications. Errors on that stream are retried with exponential backoff, and a thrown `fetch` or a cleanly-closed stream can produce an indefinite reconnect loop at roughly one attempt per second.
1068
+ A custom `fetch` shouldn't `throw` when authentication is unavailable. The Streamable HTTP transport in the MCP SDK opens a long-lived `GET /mcp` "standalone listener" stream in the background to receive server-pushed notifications. Errors on that stream are retried with exponential backoff, and a thrown `fetch` or a cleanly-closed stream can produce an indefinite reconnect loop at roughly one attempt per second.
1069
1069
 
1070
- Return a synthetic `Response` instead. The [MCP Streamable HTTP specification](https://modelcontextprotocol.io/specification/2025-03-26/basic/transports) defines `405 Method Not Allowed` as the signal a server returns when it does not offer the GET SSE stream, and the SDK honors it as a terminal status that stops the listener cleanly. Use this to disable the listener when your server does not push notifications.
1070
+ Return a synthetic `Response` instead. The [MCP Streamable HTTP specification](https://modelcontextprotocol.io/specification/2025-03-26/basic/transports) defines `405 Method Not Allowed` as the signal a server returns when it doesn't offer the GET SSE stream, and the SDK honors it as a terminal status that stops the listener cleanly. Use this to disable the listener when your server doesn't push notifications.
1071
1071
 
1072
1072
  The following pattern waits for an auth token on POST requests, attaches it to outgoing headers, and short-circuits the GET listener with a synthetic 405:
1073
1073
 
@@ -1108,7 +1108,7 @@ const mcpClient = new MCPClient({
1108
1108
  })
1109
1109
  ```
1110
1110
 
1111
- Return `405` for the GET listener only when your server does not push notifications back to the client. If your server uses the standalone GET stream, attach the auth token on `GET` requests as well and let the request through.
1111
+ Return `405` for the GET listener only when your server doesn't push notifications back to the client. If your server uses the standalone GET stream, attach the auth token on `GET` requests as well and let the request through.
1112
1112
 
1113
1113
  ## Using SSE request headers
1114
1114
 
@@ -69,6 +69,8 @@ The constructor accepts an `MCPServerConfig` object with the following propertie
69
69
 
70
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
71
 
72
+ **fga** (`{ resourceMapping?: Partial<Record<'tool' | 'tools', { fgaResourceType: string; deriveId?: ({ user, resourceId, requestContext }) => string | undefined }>>; permissionMapping?: Record<string, string> }`): Overrides resource and permission mappings for this MCP server's \`tools/list\` and \`tools/call\` FGA checks. Use this when MCP authorization should be scoped differently from internal agent or workflow tool execution.
73
+
72
74
  **repository** (`Repository`): Optional repository information for the server's source code.
73
75
 
74
76
  **releaseDate** (`string`): Optional release date of this server version (ISO 8601 string). Defaults to the time of instantiation if not provided.
@@ -1129,6 +1131,49 @@ const server = new MCPServer({
1129
1131
  })
1130
1132
  ```
1131
1133
 
1134
+ ### Scope MCP tool FGA separately
1135
+
1136
+ Use `fga.resourceMapping` and `fga.permissionMapping` when MCP clients need a different authorization scope than internal agent or workflow tool execution. The override applies only to `tools/list` and `tools/call` checks for this MCP server.
1137
+
1138
+ ```typescript
1139
+ import { MastraFGAPermissions } from '@mastra/core/auth/ee'
1140
+
1141
+ const server = new MCPServer({
1142
+ id: 'my-server',
1143
+ name: 'My Server',
1144
+ version: '1.0.0',
1145
+ tools: { getUserData },
1146
+ mapAuthInfoToUser: ({ authInfo }) => {
1147
+ const user = authInfo as {
1148
+ extra?: {
1149
+ userId?: string
1150
+ organizationMembershipId?: string
1151
+ }
1152
+ }
1153
+
1154
+ if (!user.extra?.userId) {
1155
+ return null
1156
+ }
1157
+
1158
+ return {
1159
+ id: user.extra.userId,
1160
+ organizationMembershipId: user.extra.organizationMembershipId,
1161
+ }
1162
+ },
1163
+ fga: {
1164
+ resourceMapping: {
1165
+ tool: {
1166
+ fgaResourceType: 'user',
1167
+ deriveId: ({ user }) => (user as { id: string }).id,
1168
+ },
1169
+ },
1170
+ permissionMapping: {
1171
+ [MastraFGAPermissions.TOOLS_EXECUTE]: 'read',
1172
+ },
1173
+ },
1174
+ })
1175
+ ```
1176
+
1132
1177
  ### Setting Up Authentication Middleware
1133
1178
 
1134
1179
  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
@@ -2779,6 +2779,7 @@ var MCPServer = class extends mcp.MCPServerBase {
2779
2779
  promptOptions;
2780
2780
  jsonSchemaValidator;
2781
2781
  mapAuthInfoToUser;
2782
+ fga;
2782
2783
  subscriptions = /* @__PURE__ */ new Set();
2783
2784
  currentLoggingLevel;
2784
2785
  /**
@@ -2919,6 +2920,7 @@ var MCPServer = class extends mcp.MCPServerBase {
2919
2920
  this.promptOptions = opts.prompts;
2920
2921
  this.jsonSchemaValidator = opts.jsonSchemaValidator;
2921
2922
  this.mapAuthInfoToUser = opts.mapAuthInfoToUser;
2923
+ this.fga = opts.fga;
2922
2924
  const capabilities = {
2923
2925
  tools: {},
2924
2926
  logging: { enabled: true }
@@ -4566,11 +4568,17 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
4566
4568
  if (!user) {
4567
4569
  throw new FGADeniedError({ id: "unknown" }, { type: "tool", id: resourceId }, MastraFGAPermissions.TOOLS_EXECUTE);
4568
4570
  }
4571
+ const { resource, permission } = this.resolveToolFGAParams({
4572
+ user,
4573
+ resourceId,
4574
+ requestContext,
4575
+ permission: MastraFGAPermissions.TOOLS_EXECUTE
4576
+ });
4569
4577
  await requireFGA({
4570
4578
  fgaProvider,
4571
4579
  user,
4572
- resource: { type: "tool", id: resourceId },
4573
- permission: MastraFGAPermissions.TOOLS_EXECUTE,
4580
+ resource,
4581
+ permission,
4574
4582
  requestContext,
4575
4583
  context: {
4576
4584
  resourceId
@@ -4582,6 +4590,28 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
4582
4590
  }
4583
4591
  });
4584
4592
  }
4593
+ resolveToolFGAParams({
4594
+ user,
4595
+ resourceId,
4596
+ requestContext,
4597
+ permission
4598
+ }) {
4599
+ const mappedPermission = this.fga?.permissionMapping?.[permission] ?? permission;
4600
+ const resourceMapping = this.fga?.resourceMapping?.tool ?? this.fga?.resourceMapping?.tools;
4601
+ if (!resourceMapping) {
4602
+ return {
4603
+ resource: { type: "tool", id: resourceId },
4604
+ permission: mappedPermission
4605
+ };
4606
+ }
4607
+ return {
4608
+ resource: {
4609
+ type: resourceMapping.fgaResourceType,
4610
+ id: resourceMapping.deriveId?.({ user, resourceId, requestContext }) ?? resourceId
4611
+ },
4612
+ permission: mappedPermission
4613
+ };
4614
+ }
4585
4615
  /**
4586
4616
  * Executes a specific tool provided by this MCP server.
4587
4617
  *