@mastra/mcp 2.5.0-alpha.3 → 2.6.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.
Files changed (40) hide show
  1. package/dist/cli/generate-K-rW1Wck.js +219 -0
  2. package/dist/cli/generate-K-rW1Wck.js.map +1 -0
  3. package/dist/cli/generate.d.ts +18 -0
  4. package/dist/cli/generate.d.ts.map +1 -0
  5. package/dist/cli/index.d.ts +3 -0
  6. package/dist/cli/index.d.ts.map +1 -0
  7. package/dist/cli/index.js +33 -0
  8. package/dist/cli/index.js.map +1 -0
  9. package/dist/cli/json-schema-dialect-B5B7l9Po.js +133 -0
  10. package/dist/cli/json-schema-dialect-B5B7l9Po.js.map +1 -0
  11. package/dist/cli/typegen-CLDjVF16.js +364 -0
  12. package/dist/cli/typegen-CLDjVF16.js.map +1 -0
  13. package/dist/cli/typegen.d.ts +14 -0
  14. package/dist/cli/typegen.d.ts.map +1 -0
  15. package/dist/client/client.d.ts +2 -1
  16. package/dist/client/client.d.ts.map +1 -1
  17. package/dist/client/configuration.d.ts +30 -10
  18. package/dist/client/configuration.d.ts.map +1 -1
  19. package/dist/client/index.d.ts +1 -1
  20. package/dist/client/index.d.ts.map +1 -1
  21. package/dist/client/types.d.ts +38 -1
  22. package/dist/client/types.d.ts.map +1 -1
  23. package/dist/docs/SKILL.md +2 -3
  24. package/dist/docs/assets/SOURCE_MAP.json +1 -1
  25. package/dist/docs/references/docs-connections-mcp.md +159 -50
  26. package/dist/docs/references/docs-connections-overview.md +1 -1
  27. package/dist/docs/references/docs-guides-mcp-authentication-authorization.md +2 -2
  28. package/dist/docs/references/reference-migrations-mcp-v2.md +1 -1
  29. package/dist/docs/references/reference-tools-mcp-client.md +202 -11
  30. package/dist/docs/references/reference-tools-mcp-server.md +5 -3
  31. package/dist/index.cjs +116 -121
  32. package/dist/index.cjs.map +1 -1
  33. package/dist/index.js +116 -121
  34. package/dist/index.js.map +1 -1
  35. package/dist/server/server.d.ts +13 -1
  36. package/dist/server/server.d.ts.map +1 -1
  37. package/dist/shared/json-schema-dialect.d.ts +34 -0
  38. package/dist/shared/json-schema-dialect.d.ts.map +1 -1
  39. package/package.json +22 -17
  40. package/dist/docs/references/docs-guides-mcp-events.md +0 -306
package/dist/index.cjs CHANGED
@@ -12979,6 +12979,89 @@ const SCHEMA_MAP_KEYWORDS$1 = /* @__PURE__ */ new Set([
12979
12979
  const MAX_JSON_SCHEMA_NODES = 1e4;
12980
12980
  var Unconvertible = class extends Error {};
12981
12981
  /**
12982
+ * Bounds the work a validator or type generator can be asked to do for an untrusted schema.
12983
+ * Only schema-bearing keywords are walked, so deeply nested annotation data such as `default`
12984
+ * or `examples` does not count. The counted nodes are returned so callers can also budget
12985
+ * across a whole catalogue rather than one schema at a time.
12986
+ *
12987
+ * The keyword lists are intentionally wider than the conversion sets above: this walk has to
12988
+ * reach every position that can carry validation rules, including `dependencies`,
12989
+ * `prefixItems`, and `contentSchema`.
12990
+ */
12991
+ function jsonSchemaComplexity(schema) {
12992
+ const seen = /* @__PURE__ */ new Set();
12993
+ let nodes = 0;
12994
+ const stack = [{
12995
+ value: schema,
12996
+ depth: 0
12997
+ }];
12998
+ const schemaMapKeywords = [
12999
+ "$defs",
13000
+ "definitions",
13001
+ "properties",
13002
+ "patternProperties",
13003
+ "dependentSchemas",
13004
+ "dependencies"
13005
+ ];
13006
+ const schemaArrayKeywords = [
13007
+ "prefixItems",
13008
+ "allOf",
13009
+ "anyOf",
13010
+ "oneOf",
13011
+ "items"
13012
+ ];
13013
+ const schemaKeywords = [
13014
+ "additionalProperties",
13015
+ "unevaluatedProperties",
13016
+ "additionalItems",
13017
+ "unevaluatedItems",
13018
+ "items",
13019
+ "contains",
13020
+ "propertyNames",
13021
+ "not",
13022
+ "if",
13023
+ "then",
13024
+ "else",
13025
+ "contentSchema"
13026
+ ];
13027
+ while (stack.length > 0) {
13028
+ const { value, depth } = stack.pop();
13029
+ if (value === null || typeof value !== "object" || Array.isArray(value) || seen.has(value)) continue;
13030
+ seen.add(value);
13031
+ nodes += 1;
13032
+ if (depth > 128) return {
13033
+ error: `JSON Schema exceeds the maximum depth of 128`,
13034
+ limit: "depth",
13035
+ nodes
13036
+ };
13037
+ if (nodes > 1e4) return {
13038
+ error: `JSON Schema exceeds the maximum node count of ${MAX_JSON_SCHEMA_NODES}`,
13039
+ limit: "nodes",
13040
+ nodes
13041
+ };
13042
+ const record = value;
13043
+ for (const keyword of schemaMapKeywords) {
13044
+ const schemas = record[keyword];
13045
+ if (schemas && typeof schemas === "object" && !Array.isArray(schemas)) for (const child of Object.values(schemas)) stack.push({
13046
+ value: child,
13047
+ depth: depth + 1
13048
+ });
13049
+ }
13050
+ for (const keyword of schemaArrayKeywords) {
13051
+ const schemas = record[keyword];
13052
+ if (Array.isArray(schemas)) for (const child of schemas) stack.push({
13053
+ value: child,
13054
+ depth: depth + 1
13055
+ });
13056
+ }
13057
+ for (const keyword of schemaKeywords) if (record[keyword] !== void 0) stack.push({
13058
+ value: record[keyword],
13059
+ depth: depth + 1
13060
+ });
13061
+ }
13062
+ return { nodes };
13063
+ }
13064
+ /**
12982
13065
  * Converts a 2019-09 schema (e.g. from zod v3) into 2020-12 form. Tuples are the
12983
13066
  * only structural difference handled: array-form `items` becomes `prefixItems`,
12984
13067
  * and `additionalItems` becomes `items`.
@@ -15169,75 +15252,6 @@ async function fetchFollowingAllowedRedirects(fetchImpl, url, init, allowedHosts
15169
15252
  //#endregion
15170
15253
  //#region src/client/client.ts
15171
15254
  const DEFAULT_SERVER_CONNECT_TIMEOUT_MSEC = 3e3;
15172
- /**
15173
- * Bounds the work a validator can be asked to do for an untrusted tool catalogue.
15174
- * Only schema-bearing keywords are walked, so deeply nested annotation data such as
15175
- * `default` or `examples` does not count.
15176
- */
15177
- function getJsonSchemaComplexityError(schema) {
15178
- const seen = /* @__PURE__ */ new Set();
15179
- let nodes = 0;
15180
- const stack = [{
15181
- value: schema,
15182
- depth: 0
15183
- }];
15184
- const schemaMapKeywords = [
15185
- "$defs",
15186
- "definitions",
15187
- "properties",
15188
- "patternProperties",
15189
- "dependentSchemas",
15190
- "dependencies"
15191
- ];
15192
- const schemaArrayKeywords = [
15193
- "prefixItems",
15194
- "allOf",
15195
- "anyOf",
15196
- "oneOf",
15197
- "items"
15198
- ];
15199
- const schemaKeywords = [
15200
- "additionalProperties",
15201
- "unevaluatedProperties",
15202
- "additionalItems",
15203
- "unevaluatedItems",
15204
- "items",
15205
- "contains",
15206
- "propertyNames",
15207
- "not",
15208
- "if",
15209
- "then",
15210
- "else",
15211
- "contentSchema"
15212
- ];
15213
- while (stack.length > 0) {
15214
- const { value, depth } = stack.pop();
15215
- if (value === null || typeof value !== "object" || Array.isArray(value) || seen.has(value)) continue;
15216
- seen.add(value);
15217
- nodes += 1;
15218
- if (depth > 128) return `JSON Schema exceeds the maximum depth of 128`;
15219
- if (nodes > 1e4) return `JSON Schema exceeds the maximum node count of ${MAX_JSON_SCHEMA_NODES}`;
15220
- const record = value;
15221
- for (const keyword of schemaMapKeywords) {
15222
- const schemas = record[keyword];
15223
- if (schemas && typeof schemas === "object" && !Array.isArray(schemas)) for (const child of Object.values(schemas)) stack.push({
15224
- value: child,
15225
- depth: depth + 1
15226
- });
15227
- }
15228
- for (const keyword of schemaArrayKeywords) {
15229
- const schemas = record[keyword];
15230
- if (Array.isArray(schemas)) for (const child of schemas) stack.push({
15231
- value: child,
15232
- depth: depth + 1
15233
- });
15234
- }
15235
- for (const keyword of schemaKeywords) if (record[keyword] !== void 0) stack.push({
15236
- value: record[keyword],
15237
- depth: depth + 1
15238
- });
15239
- }
15240
- }
15241
15255
  const SUPPORTED_DIALECTS = /* @__PURE__ */ new Set([
15242
15256
  JSON_SCHEMA_2020_12,
15243
15257
  `${JSON_SCHEMA_2020_12}#`,
@@ -15443,6 +15457,7 @@ var InternalMastraMCPClient = class extends _mastra_core_base.MastraBase {
15443
15457
  name;
15444
15458
  client;
15445
15459
  timeout;
15460
+ processHooks;
15446
15461
  logHandler;
15447
15462
  serverLogLevel;
15448
15463
  enableProgressTracking;
@@ -15479,12 +15494,13 @@ var InternalMastraMCPClient = class extends _mastra_core_base.MastraBase {
15479
15494
  /**
15480
15495
  * @internal
15481
15496
  */
15482
- constructor({ name, version = "1.0.0", clientInfo, server, timeout = _modelcontextprotocol_client.DEFAULT_REQUEST_TIMEOUT_MSEC, webhook }) {
15497
+ constructor({ name, version = "1.0.0", clientInfo, server, timeout = _modelcontextprotocol_client.DEFAULT_REQUEST_TIMEOUT_MSEC, registerProcessHooks = true, webhook }) {
15483
15498
  super({ name: "MastraMCPClient" });
15484
15499
  this.webhook = webhook;
15485
15500
  loadInputSchemaMetaValidator();
15486
15501
  this.name = name;
15487
15502
  this.timeout = timeout;
15503
+ this.processHooks = registerProcessHooks;
15488
15504
  this.logHandler = server.logger;
15489
15505
  this.serverLogLevel = server.enableServerLogs ?? true ? server.serverLogLevel ?? DEFAULT_SERVER_LOG_LEVEL : void 0;
15490
15506
  this.serverConfig = server;
@@ -15827,7 +15843,7 @@ var InternalMastraMCPClient = class extends _mastra_core_base.MastraBase {
15827
15843
  reject(e);
15828
15844
  }
15829
15845
  });
15830
- this.registerProcessHooks();
15846
+ if (this.processHooks) this.registerProcessHooks();
15831
15847
  return this.isConnected;
15832
15848
  }
15833
15849
  /**
@@ -16370,7 +16386,7 @@ var InternalMastraMCPClient = class extends _mastra_core_base.MastraBase {
16370
16386
  buildToolFromListEntry(tool, serverMeta) {
16371
16387
  const rawInputSchema = tool.inputSchema;
16372
16388
  const inputSchema = rawInputSchema && typeof rawInputSchema === "object" && "jsonSchema" in rawInputSchema ? rawInputSchema.jsonSchema : rawInputSchema;
16373
- const inputSchemaError = getJsonSchemaComplexityError(inputSchema) ?? getInputSchemaError(inputSchema);
16389
+ const inputSchemaError = jsonSchemaComplexity(inputSchema).error ?? getInputSchemaError(inputSchema);
16374
16390
  if (inputSchemaError) {
16375
16391
  const details = {
16376
16392
  serverName: this.name,
@@ -16412,7 +16428,7 @@ var InternalMastraMCPClient = class extends _mastra_core_base.MastraBase {
16412
16428
  ...annotations ? { annotations } : {}
16413
16429
  } } : {};
16414
16430
  const outputSchema = tool.outputSchema ? withDefaultDialect("jsonSchema" in tool.outputSchema ? tool.outputSchema.jsonSchema : tool.outputSchema) : void 0;
16415
- const outputSchemaComplexityError = outputSchema ? getJsonSchemaComplexityError(outputSchema) : void 0;
16431
+ const outputSchemaComplexityError = outputSchema ? jsonSchemaComplexity(outputSchema).error : void 0;
16416
16432
  let outputValidationSchema;
16417
16433
  const getOutputValidationSchema = async () => {
16418
16434
  if (!outputSchema) return void 0;
@@ -17354,6 +17370,10 @@ var MCPClientServerProxy = class extends _mastra_core_mcp.MCPServerBase {
17354
17370
  //#endregion
17355
17371
  //#region src/client/configuration.ts
17356
17372
  const mcpClientInstances = /* @__PURE__ */ new Map();
17373
+ /** Reads the shared cache without promising the snapshot shape it was created with. */
17374
+ function cachedClient(id) {
17375
+ return mcpClientInstances.get(id);
17376
+ }
17357
17377
  const TOOL_DISCOVERY_MAX_ATTEMPTS = 2;
17358
17378
  const LOOPBACK_IPV4 = /^127\.(?:\d{1,3})\.(?:\d{1,3})\.(?:\d{1,3})$/;
17359
17379
  function isLoopbackHostname(hostname) {
@@ -17386,10 +17406,12 @@ function isLoopbackHostname(hostname) {
17386
17406
  * if packaged docs are unavailable.
17387
17407
  */
17388
17408
  var MCPClient = class extends _mastra_core_base.MastraBase {
17409
+ typegen;
17389
17410
  serverConfigs = {};
17390
17411
  id;
17391
17412
  defaultTimeout;
17392
17413
  defaultClientInfo;
17414
+ registerProcessHooks;
17393
17415
  webhook;
17394
17416
  mcpClientsById = /* @__PURE__ */ new Map();
17395
17417
  disconnectPromise = null;
@@ -17434,6 +17456,7 @@ var MCPClient = class extends _mastra_core_base.MastraBase {
17434
17456
  super({ name: "MCPClient" });
17435
17457
  this.defaultTimeout = args.timeout ?? _modelcontextprotocol_client.DEFAULT_REQUEST_TIMEOUT_MSEC;
17436
17458
  this.defaultClientInfo = args.clientInfo && { ...args.clientInfo };
17459
+ this.registerProcessHooks = args.registerProcessHooks ?? true;
17437
17460
  this.serverConfigs = args.servers;
17438
17461
  this.webhook = args.webhook && {
17439
17462
  options: { ...args.webhook },
@@ -17442,16 +17465,13 @@ var MCPClient = class extends _mastra_core_base.MastraBase {
17442
17465
  this.id = args.id ?? this.makeId();
17443
17466
  if (args.id) {
17444
17467
  this.id = args.id;
17445
- const cached = mcpClientInstances.get(this.id);
17446
- if (cached && (!(0, fast_deep_equal.default)(cached.serverConfigs, args.servers) || !(0, fast_deep_equal.default)(cached.defaultClientInfo, args.clientInfo))) {
17447
- const existingInstance = mcpClientInstances.get(this.id);
17448
- if (existingInstance) {
17449
- existingInstance.disconnect();
17450
- mcpClientInstances.delete(this.id);
17451
- }
17468
+ const cached = cachedClient(this.id);
17469
+ if (cached && (!(0, fast_deep_equal.default)(cached.serverConfigs, args.servers) || !(0, fast_deep_equal.default)(cached.defaultClientInfo, args.clientInfo) || cached.registerProcessHooks !== this.registerProcessHooks || cached.typegen?.outFile !== args.typegen?.outFile)) {
17470
+ cached.disconnect();
17471
+ mcpClientInstances.delete(this.id);
17452
17472
  }
17453
17473
  } else this.id = this.makeId();
17454
- const existingInstance = mcpClientInstances.get(this.id);
17474
+ const existingInstance = cachedClient(this.id);
17455
17475
  if (existingInstance) {
17456
17476
  if (!args.id) throw new Error(`MCPClient was initialized multiple times with the same configuration options.
17457
17477
 
@@ -17464,6 +17484,11 @@ To fix this you have three different options:
17464
17484
  `);
17465
17485
  return existingInstance;
17466
17486
  }
17487
+ const { typegen } = args;
17488
+ if (typegen !== void 0) {
17489
+ if (!typegen || typeof typegen.outFile !== "string" || !typegen.outFile.trim() || typegen.outFile.includes("\0")) throw new Error("typegen.outFile must be a nonempty file path");
17490
+ this.typegen = Object.freeze({ outFile: typegen.outFile });
17491
+ }
17467
17492
  mcpClientInstances.set(this.id, this);
17468
17493
  this.addToInstanceCache();
17469
17494
  return this;
@@ -17927,9 +17952,10 @@ onListChanged: async (serverName, handler) => {
17927
17952
  if (!mcpClientInstances.has(this.id)) mcpClientInstances.set(this.id, this);
17928
17953
  }
17929
17954
  makeId() {
17930
- const text = JSON.stringify(this.defaultClientInfo === void 0 ? this.serverConfigs : {
17955
+ const text = JSON.stringify(this.defaultClientInfo === void 0 && this.registerProcessHooks ? this.serverConfigs : {
17931
17956
  servers: this.serverConfigs,
17932
- clientInfo: this.defaultClientInfo
17957
+ ...this.defaultClientInfo === void 0 ? {} : { clientInfo: this.defaultClientInfo },
17958
+ ...this.registerProcessHooks ? {} : { registerProcessHooks: false }
17933
17959
  }).normalize("NFKC");
17934
17960
  return (0, crypto$1.createHash)("sha256").update("MCPClient").update(text).digest("hex");
17935
17961
  }
@@ -18170,24 +18196,6 @@ onListChanged: async (serverName, handler) => {
18170
18196
  async listTools() {
18171
18197
  return (await this.listToolsWithErrors()).tools;
18172
18198
  }
18173
- /**
18174
- * Retrieves all tools from all configured servers with namespaced names,
18175
- * along with any per-server errors.
18176
- *
18177
- * Like listTools(), but also returns errors for servers that failed to connect
18178
- * or list tools. This allows callers to report specific failure reasons per server.
18179
- *
18180
- * @returns Object with successful `tools`, legacy string `errors`, and structured `errorDetails`.
18181
- * Transient connection failures are retried once after reconnecting the affected server.
18182
- *
18183
- * @example
18184
- * ```typescript
18185
- * const { tools, errors, errorDetails } = await mcp.listToolsWithErrors();
18186
- * for (const [name, err] of Object.entries(errors)) {
18187
- * console.error(`Server ${name} failed: ${err}`, errorDetails[name]);
18188
- * }
18189
- * ```
18190
- */
18191
18199
  async listToolsWithErrors(options) {
18192
18200
  this.addToInstanceCache();
18193
18201
  const connectedTools = {};
@@ -18243,23 +18251,6 @@ onListChanged: async (serverName, handler) => {
18243
18251
  async listToolsets() {
18244
18252
  return (await this.listToolsetsWithErrors()).toolsets;
18245
18253
  }
18246
- /**
18247
- * Returns toolsets organized by server name, along with any per-server errors.
18248
- *
18249
- * Like listToolsets(), but also returns errors for servers that failed to connect
18250
- * or list tools. This allows callers to report specific failure reasons per server.
18251
- *
18252
- * @returns Object with successful `toolsets`, legacy string `errors`, and structured `errorDetails`.
18253
- * Transient connection failures are retried once after reconnecting the affected server.
18254
- *
18255
- * @example
18256
- * ```typescript
18257
- * const { toolsets, errors, errorDetails } = await mcp.listToolsetsWithErrors();
18258
- * for (const [name, err] of Object.entries(errors)) {
18259
- * console.error(`Server ${name} failed: ${err}`, errorDetails[name]);
18260
- * }
18261
- * ```
18262
- */
18263
18254
  async listToolsetsWithErrors(options) {
18264
18255
  this.addToInstanceCache();
18265
18256
  const connectedToolsets = {};
@@ -18590,6 +18581,7 @@ onListChanged: async (serverName, handler) => {
18590
18581
  name,
18591
18582
  server: config,
18592
18583
  timeout: config.timeout ?? this.defaultTimeout,
18584
+ registerProcessHooks: this.registerProcessHooks,
18593
18585
  clientInfo: {
18594
18586
  name: config.clientInfo?.name ?? this.defaultClientInfo?.name,
18595
18587
  version: config.clientInfo?.version ?? this.defaultClientInfo?.version
@@ -20270,6 +20262,7 @@ var MCPServer = class extends _mastra_core_mcp.MCPServerBase {
20270
20262
  eventsOptions;
20271
20263
  eventsInspector;
20272
20264
  webhooks;
20265
+ legacy;
20273
20266
  httpHandler;
20274
20267
  nodeHandler;
20275
20268
  stdioHandle;
@@ -20285,6 +20278,7 @@ var MCPServer = class extends _mastra_core_mcp.MCPServerBase {
20285
20278
  this.loadAppResources(config.appResources);
20286
20279
  this.requestStateCodec = this.createRequestStateCodec(config.requestState);
20287
20280
  this.eventsOptions = config.eventsOptions ?? {};
20281
+ this.legacy = config.legacy ?? "reject";
20288
20282
  const webhook = this.eventsOptions.webhook;
20289
20283
  this.eventRegistry = new ServerEventRegistry(config.events, { webhook: webhook !== void 0 });
20290
20284
  if (webhook && this.eventRegistry.size > 0) this.webhooks = new WebhookDispatcher({
@@ -20814,7 +20808,7 @@ var MCPServer = class extends _mastra_core_mcp.MCPServerBase {
20814
20808
  resumeSchema: execution.resumeSchema
20815
20809
  });
20816
20810
  }
20817
- const result = this.toCallToolResult(name, tool, execution.output);
20811
+ const result = server.projectCallToolResult(this.toCallToolResult(name, tool, execution.output), this.toolInfo(name, tool).outputSchema);
20818
20812
  this.logger.info(`Tool '${name}' finished in ${Date.now() - startedAt}ms.`);
20819
20813
  return result;
20820
20814
  } catch (error) {
@@ -21080,7 +21074,7 @@ var MCPServer = class extends _mastra_core_mcp.MCPServerBase {
21080
21074
  getNodeHandler() {
21081
21075
  if (!this.nodeHandler) {
21082
21076
  this.httpHandler = (0, _modelcontextprotocol_server.createMcpHandler)(() => this.createServerInstance(), {
21083
- legacy: "reject",
21077
+ legacy: this.legacy,
21084
21078
  onerror: (error) => this.logger.error("MCP handler error", { error: error.toString() })
21085
21079
  });
21086
21080
  this.nodeHandler = (0, _modelcontextprotocol_node.toNodeHandler)(this.httpHandler, { onerror: (error) => this.logger.error("MCP Node handler adapter error", { error: error.toString() }) });
@@ -21100,7 +21094,8 @@ var MCPServer = class extends _mastra_core_mcp.MCPServerBase {
21100
21094
  }
21101
21095
  /**
21102
21096
  * Handles one Streamable HTTP request at `httpPath`. Every request is
21103
- * self-contained; requests without a 2026-07-28 envelope are rejected.
21097
+ * self-contained; requests without a 2026-07-28 envelope are rejected unless
21098
+ * `legacy: 'stateless'` is configured.
21104
21099
  */
21105
21100
  async startHTTP({ url, httpPath, req, res, options }) {
21106
21101
  if (url.pathname !== httpPath) {