@mastra/mcp 1.16.0 → 1.17.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/dist/index.js CHANGED
@@ -23741,25 +23741,31 @@ onListChanged: async (serverName, handler) => {
23741
23741
  * }
23742
23742
  * ```
23743
23743
  */
23744
- async listToolsWithErrors() {
23744
+ async listToolsWithErrors(options) {
23745
23745
  this.addToInstanceCache();
23746
23746
  const connectedTools = {};
23747
23747
  const errors = {};
23748
+ const durations = {};
23748
23749
  const settled = await this.discoverAcrossServers((serverName) => this.getToolsForServer(serverName), {
23749
23750
  errorId: "MCP_CLIENT_GET_TOOLS_FAILED",
23750
23751
  logMessage: "Failed to list tools from server:"
23751
- });
23752
- for (const { serverName, value, error } of settled) {
23752
+ }, options);
23753
+ for (const { serverName, value, error, duration } of settled) {
23754
+ durations[serverName] = duration;
23753
23755
  if (error !== void 0) {
23754
23756
  errors[serverName] = error;
23755
23757
  continue;
23756
23758
  }
23757
23759
  for (const [toolName, toolConfig] of Object.entries(value)) connectedTools[`${serverName}_${toolName}`] = toolConfig;
23758
23760
  }
23759
- return {
23761
+ const result = {
23760
23762
  tools: connectedTools,
23761
23763
  errors
23762
23764
  };
23765
+ return options ? {
23766
+ ...result,
23767
+ durations
23768
+ } : result;
23763
23769
  }
23764
23770
  /**
23765
23771
  * Returns toolsets organized by server name for dynamic tool injection.
@@ -23804,25 +23810,31 @@ onListChanged: async (serverName, handler) => {
23804
23810
  * }
23805
23811
  * ```
23806
23812
  */
23807
- async listToolsetsWithErrors() {
23813
+ async listToolsetsWithErrors(options) {
23808
23814
  this.addToInstanceCache();
23809
23815
  const connectedToolsets = {};
23810
23816
  const errors = {};
23817
+ const durations = {};
23811
23818
  const settled = await this.discoverAcrossServers((serverName) => this.getToolsForServer(serverName), {
23812
23819
  errorId: "MCP_CLIENT_GET_TOOLSETS_FAILED",
23813
23820
  logMessage: "Failed to list toolsets from server:"
23814
- });
23815
- for (const { serverName, value, error } of settled) {
23821
+ }, options);
23822
+ for (const { serverName, value, error, duration } of settled) {
23823
+ durations[serverName] = duration;
23816
23824
  if (error !== void 0) {
23817
23825
  errors[serverName] = error;
23818
23826
  continue;
23819
23827
  }
23820
23828
  connectedToolsets[serverName] = value;
23821
23829
  }
23822
- return {
23830
+ const result = {
23823
23831
  toolsets: connectedToolsets,
23824
23832
  errors
23825
23833
  };
23834
+ return options ? {
23835
+ ...result,
23836
+ durations
23837
+ } : result;
23826
23838
  }
23827
23839
  /**
23828
23840
  * Discovers every configured server's tools as plain, serializable definitions.
@@ -23856,27 +23868,33 @@ onListChanged: async (serverName, handler) => {
23856
23868
  * Useful when caching a catalog, since it lets you avoid persisting a partial manifest that
23857
23869
  * silently omits a server which happened to be down at discovery time.
23858
23870
  */
23859
- async listToolDefinitionsWithErrors() {
23871
+ async listToolDefinitionsWithErrors(options) {
23860
23872
  this.addToInstanceCache();
23861
23873
  const definitions = {};
23862
23874
  const errors = {};
23875
+ const durations = {};
23863
23876
  const settled = await this.discoverAcrossServers(async (serverName) => {
23864
23877
  return (await this.getConnectedClientForServer(serverName)).toolDefinitions();
23865
23878
  }, {
23866
23879
  errorId: "MCP_CLIENT_GET_TOOL_DEFINITIONS_FAILED",
23867
23880
  logMessage: "Failed to list tool definitions from server:"
23868
- });
23869
- for (const { serverName, value, error } of settled) {
23881
+ }, options);
23882
+ for (const { serverName, value, error, duration } of settled) {
23883
+ durations[serverName] = duration;
23870
23884
  if (error !== void 0) {
23871
23885
  errors[serverName] = error;
23872
23886
  continue;
23873
23887
  }
23874
23888
  definitions[serverName] = value;
23875
23889
  }
23876
- return {
23890
+ const result = {
23877
23891
  definitions,
23878
23892
  errors
23879
23893
  };
23894
+ return options ? {
23895
+ ...result,
23896
+ durations
23897
+ } : result;
23880
23898
  }
23881
23899
  /**
23882
23900
  * Rebuilds an executable Mastra tool from a cached {@link SerializableMCPToolDefinition}.
@@ -23940,14 +23958,21 @@ onListChanged: async (serverName, handler) => {
23940
23958
  * Backs `listTools`/`listToolsets`, `resources.list`/`templates`, and
23941
23959
  * `prompts.list`.
23942
23960
  */
23943
- async discoverAcrossServers(operation, onError) {
23961
+ async discoverAcrossServers(operation, onError, options) {
23944
23962
  const serverNames = Object.keys(this.serverConfigs);
23945
23963
  return Promise.all(serverNames.map(async (serverName) => {
23964
+ const startedAt = performance.now();
23965
+ let timer;
23946
23966
  try {
23967
+ const operationPromise = operation(serverName);
23947
23968
  return {
23948
23969
  serverName,
23949
- value: await operation(serverName),
23950
- error: void 0
23970
+ value: options?.perServerTimeoutMs === void 0 ? await operationPromise : await Promise.race([operationPromise, new Promise((_, reject) => {
23971
+ timer = setTimeout(() => reject(/* @__PURE__ */ new Error(`Discovery timed out after ${options.perServerTimeoutMs}ms`)), options.perServerTimeoutMs);
23972
+ timer.unref?.();
23973
+ })]),
23974
+ error: void 0,
23975
+ duration: performance.now() - startedAt
23951
23976
  };
23952
23977
  } catch (error) {
23953
23978
  const mastraError = new MastraError({
@@ -23961,8 +23986,11 @@ onListChanged: async (serverName, handler) => {
23961
23986
  return {
23962
23987
  serverName,
23963
23988
  value: void 0,
23964
- error: error instanceof Error ? error.message : String(error)
23989
+ error: error instanceof Error ? error.message : String(error),
23990
+ duration: performance.now() - startedAt
23965
23991
  };
23992
+ } finally {
23993
+ clearTimeout(timer);
23966
23994
  }
23967
23995
  }));
23968
23996
  }
@@ -26506,6 +26534,8 @@ var MCPServer = class extends MCPServerBase {
26506
26534
  stdioTransport;
26507
26535
  sseTransport;
26508
26536
  sseHonoTransports;
26537
+ /** Auth info for the in-flight Hono SSE message POST, keyed by session id. */
26538
+ sseHonoAuthInfo = /* @__PURE__ */ new Map();
26509
26539
  streamableHTTPTransports = /* @__PURE__ */ new Map();
26510
26540
  httpServerInstances = /* @__PURE__ */ new Map();
26511
26541
  resourceOptions;
@@ -27682,7 +27712,7 @@ var MCPServer = class extends MCPServerBase {
27682
27712
  * export default app;
27683
27713
  * ```
27684
27714
  */
27685
- async startHonoSSE({ url, ssePath, messagePath, context }) {
27715
+ async startHonoSSE({ url, ssePath, messagePath, context, authInfo }) {
27686
27716
  const honoContext = context;
27687
27717
  try {
27688
27718
  if (url.pathname === ssePath) return streamSSE(honoContext, async (stream) => {
@@ -27697,6 +27727,8 @@ var MCPServer = class extends MCPServerBase {
27697
27727
  this.logger.debug("Received message for sessionId", { sessionId });
27698
27728
  if (!sessionId) return honoContext.text("No sessionId provided", 400);
27699
27729
  if (!this.sseHonoTransports.has(sessionId)) return honoContext.text(`No transport found for sessionId ${sessionId}`, 400);
27730
+ if (authInfo) this.sseHonoAuthInfo.set(sessionId, authInfo);
27731
+ else this.sseHonoAuthInfo.delete(sessionId);
27700
27732
  const message = await this.sseHonoTransports.get(sessionId)?.handlePostMessage(honoContext);
27701
27733
  if (!message) return honoContext.text("Transport not found", 400);
27702
27734
  return message;
@@ -28049,12 +28081,22 @@ var MCPServer = class extends MCPServerBase {
28049
28081
  stream.onAbort(() => {
28050
28082
  this.logger.debug("SSE Transport aborted with sessionId:", { sessionId });
28051
28083
  this.sseHonoTransports.delete(sessionId);
28084
+ this.sseHonoAuthInfo.delete(sessionId);
28052
28085
  });
28053
28086
  try {
28054
28087
  await this.server.connect(sseTransport);
28088
+ const onmessage = sseTransport.onmessage?.bind(sseTransport);
28089
+ if (onmessage) sseTransport.onmessage = (message, extra) => {
28090
+ const authInfo = this.sseHonoAuthInfo.get(sessionId);
28091
+ onmessage(message, authInfo ? {
28092
+ ...extra,
28093
+ authInfo
28094
+ } : extra);
28095
+ };
28055
28096
  this.server.onclose = async () => {
28056
28097
  this.logger.debug("SSE Transport closed with sessionId:", { sessionId });
28057
28098
  this.sseHonoTransports.delete(sessionId);
28099
+ this.sseHonoAuthInfo.delete(sessionId);
28058
28100
  await this.server.close();
28059
28101
  };
28060
28102
  while (true) {