@mastra/mcp 1.6.1-alpha.1 → 1.7.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.
@@ -126,6 +126,38 @@ Disconnects from all MCP servers and cleans up resources.
126
126
  async disconnect(): Promise<void>
127
127
  ```
128
128
 
129
+ ### `toMCPServerProxies()`
130
+
131
+ Returns a map of `MCPClientServerProxy` instances, one per configured server. Each proxy wraps the underlying client connection as an `MCPServerBase` instance, allowing external (non-Mastra) MCP servers to be registered in `mcpServers` and appear in Studio.
132
+
133
+ ```typescript
134
+ async toMCPServerProxies(): Promise<Record<string, MCPClientServerProxy>>
135
+ ```
136
+
137
+ Spread the result into the `mcpServers` config on `Mastra`:
138
+
139
+ ```typescript
140
+ import { Mastra } from '@mastra/core/mastra'
141
+ import { MCPClient } from '@mastra/mcp'
142
+
143
+ const mcpClient = new MCPClient({
144
+ servers: {
145
+ 'color-mixer': {
146
+ command: 'node',
147
+ args: ['path/to/color-mixer-server.js'],
148
+ },
149
+ },
150
+ })
151
+
152
+ export const mastra = new Mastra({
153
+ mcpServers: {
154
+ ...(await mcpClient.toMCPServerProxies()),
155
+ },
156
+ })
157
+ ```
158
+
159
+ This is useful for connecting external MCP servers that implement the MCP Apps extension or other features to Studio without wrapping them in a Mastra `MCPServer`.
160
+
129
161
  ### `resources` Property
130
162
 
131
163
  The `MCPClient` instance has a `resources` property that provides access to resource-related operations.
@@ -83,6 +83,8 @@ The constructor accepts an `MCPServerConfig` object with the following propertie
83
83
 
84
84
  **prompts** (`MCPServerPrompts`): An object defining how the server should handle MCP prompts. See Prompt Handling section for details.
85
85
 
86
+ **appResources** (`AppResources`): A map of \`ui://\` URIs to app resource configurations. Each entry defines an interactive HTML UI served via the MCP Apps extension (SEP-1865). See the MCP Apps section for details.
87
+
86
88
  ## Exposing agents as tools
87
89
 
88
90
  A powerful feature of `MCPServer` is its ability to automatically expose your Mastra Agents as callable tools. When you provide agents in the `agents` property of the configuration:
@@ -1263,6 +1265,68 @@ app.all('/mcp', async (req, res) => {
1263
1265
  app.listen(3000)
1264
1266
  ```
1265
1267
 
1268
+ ## MCP Apps (`appResources`)
1269
+
1270
+ The `appResources` option lets you serve interactive HTML UIs from your MCP server via the [MCP Apps extension](https://github.com/modelcontextprotocol/ext-apps). Each entry maps a `ui://` URI to an HTML app that renders in a sandboxed iframe in Mastra Studio.
1271
+
1272
+ ### `AppResources` type
1273
+
1274
+ **Key (URI)** (`string`): A \`ui://\` URI that identifies the app resource (e.g., \`ui://calculator/main\`).
1275
+
1276
+ Each value is an `AppResource` object:
1277
+
1278
+ **name** (`string`): Display name for the UI resource.
1279
+
1280
+ **description** (`string`): Optional description of the UI resource.
1281
+
1282
+ **html** (`string`): Inline HTML content for the UI. Provide either \`html\` or \`htmlPath\`.
1283
+
1284
+ **htmlPath** (`string`): Path to an HTML file. Resolved at server startup. Provide either \`html\` or \`htmlPath\`.
1285
+
1286
+ **meta** (`McpUiResourceMeta`): UI resource metadata (CSP, permissions, rendering preferences) from the official ext-apps SDK.
1287
+
1288
+ ### Example
1289
+
1290
+ ```typescript
1291
+ import { MCPServer } from '@mastra/mcp'
1292
+ import { createTool } from '@mastra/core/tools'
1293
+ import { z } from 'zod'
1294
+
1295
+ const calculatorTool = createTool({
1296
+ id: 'calculatorWithUI',
1297
+ description: 'An interactive calculator',
1298
+ inputSchema: z.object({
1299
+ num1: z.number(),
1300
+ num2: z.number(),
1301
+ operation: z.enum(['add', 'subtract']),
1302
+ }),
1303
+ execute: async ({ num1, num2, operation }) => {
1304
+ const result = operation === 'add' ? num1 + num2 : num1 - num2
1305
+ return {
1306
+ content: [{ type: 'text', text: 'An interactive calculator is displayed.' }],
1307
+ structuredContent: { result },
1308
+ }
1309
+ },
1310
+ })
1311
+
1312
+ const server = new MCPServer({
1313
+ id: 'app-server',
1314
+ name: 'App Server',
1315
+ version: '1.0.0',
1316
+ tools: { calculatorTool },
1317
+ appResources: {
1318
+ 'ui://calculator/main': {
1319
+ name: 'Interactive Calculator',
1320
+ html: '<html><body><h2>Calculator</h2>...</body></html>',
1321
+ },
1322
+ },
1323
+ })
1324
+ ```
1325
+
1326
+ Link a tool to its app resource by setting `_meta.ui.resourceUri` on the tool to the matching `ui://` URI. The server auto-normalizes this metadata when registering tools.
1327
+
1328
+ > **Note:** Visit [MCP Apps](https://mastra.ai/docs/mcp/mcp-apps) for the full app bridge API and usage patterns.
1329
+
1266
1330
  ## Related information
1267
1331
 
1268
1332
  - For connecting to MCP servers in Mastra, see the [MCPClient documentation](https://mastra.ai/reference/tools/mcp-client).
package/dist/index.cjs CHANGED
@@ -15,9 +15,11 @@ var crypto$1 = require('crypto');
15
15
  var error = require('@mastra/core/error');
16
16
  var equal = require('fast-deep-equal');
17
17
  var mcp = require('@mastra/core/mcp');
18
- var requestContext = require('@mastra/core/request-context');
19
18
  var schema = require('@mastra/core/schema');
19
+ var fs = require('fs');
20
+ var requestContext = require('@mastra/core/request-context');
20
21
  var utils = require('@mastra/core/utils');
22
+ var extApps = require('@modelcontextprotocol/ext-apps');
21
23
  var index_js$1 = require('@modelcontextprotocol/sdk/server/index.js');
22
24
  var sse_js$1 = require('@modelcontextprotocol/sdk/server/sse.js');
23
25
  var stdio_js$1 = require('@modelcontextprotocol/sdk/server/stdio.js');
@@ -542,7 +544,12 @@ var InternalMastraMCPClient = class extends base.MastraBase {
542
544
  ...capabilities.elicitation ?? {}
543
545
  },
544
546
  // Auto-enable roots capability if roots are provided
545
- ...hasRoots ? { roots: { listChanged: true, ...capabilities.roots ?? {} } } : {}
547
+ ...hasRoots ? { roots: { listChanged: true, ...capabilities.roots ?? {} } } : {},
548
+ // Advertise MCP Apps extension support so servers know we can render UI resources
549
+ extensions: {
550
+ ...capabilities.extensions ?? {},
551
+ "io.modelcontextprotocol/ui": {}
552
+ }
546
553
  };
547
554
  this.client = new index_js.Client(
548
555
  {
@@ -975,11 +982,16 @@ var InternalMastraMCPClient = class extends base.MastraBase {
975
982
  } else if (this.requireToolApproval === true) {
976
983
  requireApproval = true;
977
984
  }
985
+ const rawMeta = tool._meta;
986
+ const toolMeta = rawMeta ? this.stampServerIdInMeta(rawMeta) : void 0;
978
987
  const mastraTool = tools.createTool({
979
988
  id: `${this.name}_${tool.name}`,
980
989
  description: tool.description || "",
981
990
  inputSchema: await this.convertInputSchema(tool.inputSchema),
982
- strict: getMastraToolStrictMeta(tool._meta),
991
+ strict: getMastraToolStrictMeta(toolMeta),
992
+ // Preserve the full _meta from the remote MCP server (including ui.resourceUri
993
+ // for MCP Apps) so downstream consumers (e.g. Studio) can detect app tools.
994
+ ...toolMeta ? { mcp: { _meta: toolMeta } } : {},
983
995
  // Don't pass outputSchema to createTool — the MCP SDK's Client.callTool()
984
996
  // already validates structuredContent against the tool's outputSchema using AJV.
985
997
  // Passing it here causes Zod to strip unrecognized keys from the CallToolResult
@@ -1059,7 +1071,152 @@ var InternalMastraMCPClient = class extends base.MastraBase {
1059
1071
  }
1060
1072
  return toolsRes;
1061
1073
  }
1074
+ stampServerIdInMeta(meta) {
1075
+ const ui = meta.ui;
1076
+ if (!ui?.resourceUri) return meta;
1077
+ return {
1078
+ ...meta,
1079
+ ui: { ...ui, serverId: this.name }
1080
+ };
1081
+ }
1082
+ };
1083
+ var MCPClientServerProxy = class extends mcp.MCPServerBase {
1084
+ clientGetter;
1085
+ cachedClient = null;
1086
+ _cachedToolList = null;
1087
+ constructor(config, clientGetter) {
1088
+ const serverConfig = {
1089
+ name: config.name,
1090
+ version: config.version ?? "1.0.0",
1091
+ id: config.id,
1092
+ description: config.description,
1093
+ tools: {}
1094
+ };
1095
+ super(serverConfig);
1096
+ this.clientGetter = clientGetter;
1097
+ }
1098
+ async getClient() {
1099
+ if (!this.cachedClient) {
1100
+ this.cachedClient = await this.clientGetter();
1101
+ }
1102
+ return this.cachedClient;
1103
+ }
1104
+ convertSchema(schema$1) {
1105
+ if (schema.isStandardSchemaWithJSON(schema$1)) {
1106
+ return schema.standardSchemaToJSONSchema(schema$1);
1107
+ }
1108
+ return schema$1?.jsonSchema || schema$1;
1109
+ }
1110
+ async fetchToolList() {
1111
+ if (this._cachedToolList) return this._cachedToolList;
1112
+ const client = await this.getClient();
1113
+ const tools = await client.tools();
1114
+ this._cachedToolList = {
1115
+ tools: Object.entries(tools).map(([toolName, tool]) => ({
1116
+ id: toolName,
1117
+ name: tool.id || toolName,
1118
+ description: tool.description,
1119
+ inputSchema: this.convertSchema(tool.inputSchema),
1120
+ outputSchema: this.convertSchema(tool.outputSchema),
1121
+ toolType: tool.mcp?.toolType,
1122
+ _meta: tool.mcp?._meta
1123
+ }))
1124
+ };
1125
+ this.convertedTools = tools;
1126
+ return this._cachedToolList;
1127
+ }
1128
+ // ---------- MCPServerBase abstract implementations ----------
1129
+ convertTools(_tools, _agents, _workflows) {
1130
+ return {};
1131
+ }
1132
+ /**
1133
+ * Returns the cached tool list synchronously, or triggers an async fetch.
1134
+ * The Studio API handlers are async and will auto-await a returned Promise.
1135
+ */
1136
+ getToolListInfo() {
1137
+ if (this._cachedToolList) return this._cachedToolList;
1138
+ return this.fetchToolList();
1139
+ }
1140
+ getToolInfo(toolId) {
1141
+ if (this._cachedToolList) {
1142
+ return this._cachedToolList.tools.find((t) => t.id === toolId || t.name === toolId);
1143
+ }
1144
+ return this.fetchToolList().then((list) => list.tools.find((t) => t.id === toolId || t.name === toolId));
1145
+ }
1146
+ async executeTool(toolId, args, _executionContext) {
1147
+ const client = await this.getClient();
1148
+ const tools = await client.tools();
1149
+ const tool = tools[toolId];
1150
+ if (!tool) {
1151
+ throw new Error(`Tool '${toolId}' not found on remote MCP server '${this.name}'`);
1152
+ }
1153
+ if (!tool.execute) {
1154
+ throw new Error(`Tool '${toolId}' on remote MCP server '${this.name}' has no execute method`);
1155
+ }
1156
+ return tool.execute(args, _executionContext);
1157
+ }
1158
+ async listResources() {
1159
+ const client = await this.getClient();
1160
+ const resources = await client.resources.list();
1161
+ return {
1162
+ resources: resources.map((r) => ({
1163
+ uri: r.uri,
1164
+ name: r.name ?? r.uri,
1165
+ description: r.description,
1166
+ mimeType: r.mimeType,
1167
+ _meta: r._meta
1168
+ }))
1169
+ };
1170
+ }
1171
+ async readResource(uri) {
1172
+ const client = await this.getClient();
1173
+ const result = await client.resources.read(uri);
1174
+ return {
1175
+ contents: (result.contents ?? []).map((c) => ({
1176
+ uri: c.uri ?? uri,
1177
+ ...c.text !== void 0 ? { text: c.text } : {},
1178
+ ...c.blob !== void 0 ? { blob: c.blob } : {}
1179
+ }))
1180
+ };
1181
+ }
1182
+ // Transport methods — not applicable for client proxies
1183
+ async startStdio() {
1184
+ throw new Error("MCPClientServerProxy does not support stdio transport");
1185
+ }
1186
+ async startSSE(_options) {
1187
+ throw new Error("MCPClientServerProxy does not support SSE transport");
1188
+ }
1189
+ async startHonoSSE(_options) {
1190
+ throw new Error("MCPClientServerProxy does not support Hono SSE transport");
1191
+ }
1192
+ async startHTTP(_options) {
1193
+ throw new Error("MCPClientServerProxy does not support HTTP transport");
1194
+ }
1195
+ async close() {
1196
+ this.cachedClient = null;
1197
+ }
1198
+ getServerInfo() {
1199
+ return {
1200
+ id: this.id,
1201
+ name: this.name,
1202
+ description: this.description,
1203
+ version_detail: {
1204
+ version: this.version,
1205
+ release_date: this.releaseDate,
1206
+ is_latest: this.isLatest
1207
+ }
1208
+ };
1209
+ }
1210
+ getServerDetail() {
1211
+ return {
1212
+ ...this.getServerInfo(),
1213
+ packages: this.packages ?? [],
1214
+ remotes: this.remotes ?? []
1215
+ };
1216
+ }
1062
1217
  };
1218
+
1219
+ // src/client/configuration.ts
1063
1220
  var mcpClientInstances = /* @__PURE__ */ new Map();
1064
1221
  var TOOL_DISCOVERY_MAX_ATTEMPTS = 2;
1065
1222
  var MCPClient = class extends base.MastraBase {
@@ -1827,6 +1984,39 @@ To fix this you have three different options:
1827
1984
  }
1828
1985
  return { toolsets: connectedToolsets, errors };
1829
1986
  }
1987
+ /**
1988
+ * Creates MCPServerBase-compatible proxy objects for each server connection
1989
+ * in this MCPClient. The returned record can be spread directly into
1990
+ * Mastra's `mcpServers` config so that external (non-Mastra) servers
1991
+ * appear in Studio alongside native MCPServer instances.
1992
+ *
1993
+ * @returns Record mapping server names to MCPServerBase proxy instances
1994
+ *
1995
+ * @example
1996
+ * ```typescript
1997
+ * const mcp = new MCPClient({
1998
+ * servers: {
1999
+ * trailhead: { command: 'npx', args: ['trailhead-server'] },
2000
+ * },
2001
+ * });
2002
+ *
2003
+ * const mastra = new Mastra({
2004
+ * mcpServers: {
2005
+ * ...mcp.toMCPServerProxies(),
2006
+ * },
2007
+ * });
2008
+ * ```
2009
+ */
2010
+ toMCPServerProxies() {
2011
+ const proxies = {};
2012
+ for (const serverName of Object.keys(this.serverConfigs)) {
2013
+ proxies[serverName] = new MCPClientServerProxy(
2014
+ { name: serverName, id: serverName },
2015
+ () => this.getConnectedClientForServer(serverName)
2016
+ );
2017
+ }
2018
+ return proxies;
2019
+ }
1830
2020
  /**
1831
2021
  * Gets current session IDs for all connected MCP clients using Streamable HTTP transport.
1832
2022
  *
@@ -2684,19 +2874,28 @@ var MCPServer = class extends mcp.MCPServerBase {
2684
2874
  */
2685
2875
  constructor(opts) {
2686
2876
  super(opts);
2687
- this.resourceOptions = opts.resources;
2877
+ this.resourceOptions = this.mergeAppResources(opts.resources, opts.appResources);
2688
2878
  this.promptOptions = opts.prompts;
2689
2879
  this.jsonSchemaValidator = opts.jsonSchemaValidator;
2690
2880
  const capabilities = {
2691
2881
  tools: {},
2692
2882
  logging: { enabled: true }
2693
2883
  };
2694
- if (opts.resources) {
2884
+ if (this.resourceOptions) {
2695
2885
  capabilities.resources = { subscribe: true, listChanged: true };
2696
2886
  }
2697
2887
  if (opts.prompts) {
2698
2888
  capabilities.prompts = { listChanged: true };
2699
2889
  }
2890
+ const hasUiTools = Object.values(this.convertedTools).some(
2891
+ (tool) => tool.mcp?._meta?.ui?.resourceUri
2892
+ );
2893
+ if (hasUiTools || opts.appResources) {
2894
+ capabilities.extensions = {
2895
+ ...capabilities.extensions,
2896
+ "io.modelcontextprotocol/ui": {}
2897
+ };
2898
+ }
2700
2899
  this.server = new index_js$1.Server(
2701
2900
  {
2702
2901
  name: this.name,
@@ -2792,6 +2991,81 @@ var MCPServer = class extends mcp.MCPServerBase {
2792
2991
  req.on("error", reject);
2793
2992
  });
2794
2993
  }
2994
+ /**
2995
+ * Merges appResources into the resource system alongside any user-provided resources.
2996
+ *
2997
+ * App resources are auto-registered as `ui://` resources with the MCP Apps MIME type.
2998
+ * If the user also provides a `resources` config, the two are merged — user callbacks
2999
+ * take precedence for overlapping URIs.
3000
+ */
3001
+ mergeAppResources(userResources, appResources) {
3002
+ if (!appResources || Object.keys(appResources).length === 0) {
3003
+ return userResources;
3004
+ }
3005
+ const resolvedAppResources = /* @__PURE__ */ new Map();
3006
+ for (const [uri, appResource] of Object.entries(appResources)) {
3007
+ let html;
3008
+ if (appResource.html) {
3009
+ html = appResource.html;
3010
+ } else if (appResource.htmlPath) {
3011
+ html = fs.readFileSync(appResource.htmlPath, "utf-8");
3012
+ } else {
3013
+ this.logger.warn(`App resource '${uri}' has neither html nor htmlPath \u2014 skipping`);
3014
+ continue;
3015
+ }
3016
+ const resource = {
3017
+ uri,
3018
+ name: appResource.name,
3019
+ ...appResource.description ? { description: appResource.description } : {},
3020
+ mimeType: extApps.RESOURCE_MIME_TYPE,
3021
+ ...appResource.meta ? { _meta: { ui: appResource.meta } } : {}
3022
+ };
3023
+ resolvedAppResources.set(uri, { resource, html });
3024
+ }
3025
+ if (resolvedAppResources.size === 0) {
3026
+ return userResources;
3027
+ }
3028
+ const appListResources = async () => {
3029
+ return Array.from(resolvedAppResources.values()).map((r) => r.resource);
3030
+ };
3031
+ const appGetResourceContent = async ({ uri }) => {
3032
+ const appRes = resolvedAppResources.get(uri);
3033
+ if (appRes) {
3034
+ return { text: appRes.html };
3035
+ }
3036
+ throw new Error(`App resource not found: ${uri}`);
3037
+ };
3038
+ if (!userResources) {
3039
+ return {
3040
+ listResources: appListResources,
3041
+ getResourceContent: appGetResourceContent
3042
+ };
3043
+ }
3044
+ return {
3045
+ listResources: async ({ extra }) => {
3046
+ const userResourceList = await userResources.listResources({ extra });
3047
+ const appResourceList = await appListResources();
3048
+ const userUris = new Set(userResourceList.map((r) => r.uri));
3049
+ const nonConflicting = appResourceList.filter((r) => !userUris.has(r.uri));
3050
+ return [...userResourceList, ...nonConflicting];
3051
+ },
3052
+ getResourceContent: async ({ uri, extra }) => {
3053
+ const appRes = resolvedAppResources.get(uri);
3054
+ if (appRes) {
3055
+ try {
3056
+ const userResourceList = await userResources.listResources({ extra });
3057
+ if (userResourceList.some((r) => r.uri === uri)) {
3058
+ return userResources.getResourceContent({ uri, extra });
3059
+ }
3060
+ } catch {
3061
+ }
3062
+ return { text: appRes.html };
3063
+ }
3064
+ return userResources.getResourceContent({ uri, extra });
3065
+ },
3066
+ ...userResources.resourceTemplates ? { resourceTemplates: userResources.resourceTemplates } : {}
3067
+ };
3068
+ }
2795
3069
  /**
2796
3070
  * Creates a new Server instance configured with all handlers for HTTP sessions.
2797
3071
  * Each HTTP client connection gets its own Server instance to avoid routing conflicts.
@@ -2807,6 +3081,18 @@ var MCPServer = class extends mcp.MCPServerBase {
2807
3081
  if (this.promptOptions) {
2808
3082
  capabilities.prompts = { listChanged: true };
2809
3083
  }
3084
+ const hasUiTools = Object.values(this.convertedTools).some(
3085
+ (tool) => tool.mcp?._meta?.ui?.resourceUri
3086
+ );
3087
+ if (hasUiTools || this.resourceOptions) {
3088
+ const hasUiResources = this.definedResources?.some((r) => r.uri.startsWith("ui://"));
3089
+ if (hasUiTools || hasUiResources) {
3090
+ capabilities.extensions = {
3091
+ ...capabilities.extensions,
3092
+ "io.modelcontextprotocol/ui": {}
3093
+ };
3094
+ }
3095
+ }
2810
3096
  const serverInstance = new index_js$1.Server(
2811
3097
  {
2812
3098
  name: this.name,
@@ -2844,7 +3130,15 @@ var MCPServer = class extends mcp.MCPServerBase {
2844
3130
  }
2845
3131
  const toolMeta = withMastraToolStrictMeta(tool.mcp?._meta, tool.strict);
2846
3132
  if (toolMeta) {
2847
- toolSpec._meta = toolMeta;
3133
+ const uiMeta = toolMeta.ui;
3134
+ const legacyUri = toolMeta[extApps.RESOURCE_URI_META_KEY];
3135
+ if (uiMeta?.resourceUri && !legacyUri) {
3136
+ toolSpec._meta = { ...toolMeta, [extApps.RESOURCE_URI_META_KEY]: uiMeta.resourceUri };
3137
+ } else if (legacyUri && !uiMeta?.resourceUri) {
3138
+ toolSpec._meta = { ...toolMeta, ui: { ...toolMeta.ui ?? {}, resourceUri: legacyUri } };
3139
+ } else {
3140
+ toolSpec._meta = toolMeta;
3141
+ }
2848
3142
  }
2849
3143
  return toolSpec;
2850
3144
  })
@@ -4337,6 +4631,53 @@ Provided arguments: ${JSON.stringify(args, null, 2)}`,
4337
4631
  throw mastraError;
4338
4632
  }
4339
4633
  }
4634
+ /**
4635
+ * Reads the content of a resource by URI.
4636
+ *
4637
+ * Used by the Studio API to proxy `ui://` resource reads for MCP Apps rendering.
4638
+ *
4639
+ * @param uri - The resource URI to read (e.g. `ui://weather/dashboard`)
4640
+ * @returns Promise resolving to the resource content
4641
+ */
4642
+ async readResource(uri) {
4643
+ if (!this.resourceOptions?.getResourceContent) {
4644
+ throw new error.MastraError({
4645
+ id: "MCP_SERVER_RESOURCES_NOT_CONFIGURED",
4646
+ domain: error.ErrorDomain.MCP,
4647
+ category: error.ErrorCategory.USER,
4648
+ details: { uri }
4649
+ });
4650
+ }
4651
+ const extra = {};
4652
+ const result = await this.resourceOptions.getResourceContent({ uri, extra });
4653
+ const contents = Array.isArray(result) ? result : [result];
4654
+ return {
4655
+ contents: contents.map((c) => ({
4656
+ uri,
4657
+ ..."text" in c && c.text !== void 0 ? { text: c.text } : {},
4658
+ ..."blob" in c && c.blob !== void 0 ? { blob: c.blob } : {}
4659
+ }))
4660
+ };
4661
+ }
4662
+ /**
4663
+ * Lists all resources available on this MCP server.
4664
+ *
4665
+ * Used by the Studio API to discover `ui://` resources for MCP Apps.
4666
+ *
4667
+ * @returns Promise resolving to the list of resources
4668
+ */
4669
+ async listResources() {
4670
+ if (!this.resourceOptions?.listResources) {
4671
+ return { resources: [] };
4672
+ }
4673
+ const extra = {};
4674
+ if (this.definedResources) {
4675
+ return { resources: this.definedResources };
4676
+ }
4677
+ const resources = await this.resourceOptions.listResources({ extra });
4678
+ this.definedResources = resources;
4679
+ return { resources };
4680
+ }
4340
4681
  };
4341
4682
  function escapeHeaderValue(value) {
4342
4683
  return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
@@ -4597,6 +4938,7 @@ Object.defineProperty(exports, "startAuthorization", {
4597
4938
  exports.InMemoryOAuthStorage = InMemoryOAuthStorage;
4598
4939
  exports.InternalMastraMCPClient = InternalMastraMCPClient;
4599
4940
  exports.MCPClient = MCPClient;
4941
+ exports.MCPClientServerProxy = MCPClientServerProxy;
4600
4942
  exports.MCPOAuthClientProvider = MCPOAuthClientProvider;
4601
4943
  exports.MCPServer = MCPServer;
4602
4944
  exports.createIntrospectionValidator = createIntrospectionValidator;