@mastra/mcp 0.10.4 → 0.10.5-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
@@ -1,4 +1,5 @@
1
1
  import { MastraBase } from '@mastra/core/base';
2
+ import { MastraError, ErrorCategory, ErrorDomain } from '@mastra/core/error';
2
3
  import { createTool as createTool$1 } from '@mastra/core/tools';
3
4
  import { isZodType } from '@mastra/core/utils';
4
5
  import { Client } from '@modelcontextprotocol/sdk/client/index.js';
@@ -20,7 +21,6 @@ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
20
21
  import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js';
21
22
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
22
23
  import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
23
- import { streamSSE } from 'hono/streaming';
24
24
 
25
25
  // src/client/client.ts
26
26
  var PromptClientActions = class {
@@ -492,7 +492,42 @@ var InternalMastraMCPClient = class extends MastraBase {
492
492
  error: errorDetails,
493
493
  originalJsonSchema: inputSchema
494
494
  });
495
- throw new Error(errorDetails);
495
+ throw new MastraError({
496
+ id: "MCP_TOOL_INPUT_SCHEMA_CONVERSION_FAILED",
497
+ domain: ErrorDomain.MCP,
498
+ category: ErrorCategory.USER,
499
+ details: { error: errorDetails ?? "Unknown error" }
500
+ });
501
+ }
502
+ }
503
+ convertOutputSchema(outputSchema) {
504
+ if (!outputSchema) return;
505
+ if (isZodType(outputSchema)) {
506
+ return outputSchema;
507
+ }
508
+ try {
509
+ return convertJsonSchemaToZod(outputSchema);
510
+ } catch (error) {
511
+ let errorDetails;
512
+ if (error instanceof Error) {
513
+ errorDetails = error.stack;
514
+ } else {
515
+ try {
516
+ errorDetails = JSON.stringify(error);
517
+ } catch {
518
+ errorDetails = String(error);
519
+ }
520
+ }
521
+ this.log("error", "Failed to convert JSON schema to Zod schema using zodFromJsonSchema", {
522
+ error: errorDetails,
523
+ originalJsonSchema: outputSchema
524
+ });
525
+ throw new MastraError({
526
+ id: "MCP_TOOL_OUTPUT_SCHEMA_CONVERSION_FAILED",
527
+ domain: ErrorDomain.MCP,
528
+ category: ErrorCategory.USER,
529
+ details: { error: errorDetails ?? "Unknown error" }
530
+ });
496
531
  }
497
532
  }
498
533
  async tools() {
@@ -506,6 +541,7 @@ var InternalMastraMCPClient = class extends MastraBase {
506
541
  id: `${this.name}_${tool.name}`,
507
542
  description: tool.description || "",
508
543
  inputSchema: this.convertInputSchema(tool.inputSchema),
544
+ outputSchema: this.convertOutputSchema(tool.outputSchema),
509
545
  execute: async ({ context, runtimeContext }) => {
510
546
  const previousContext = this.currentOperationContext;
511
547
  this.currentOperationContext = runtimeContext || null;
@@ -609,7 +645,16 @@ To fix this you have three different options:
609
645
  const internalClient = await this.getConnectedClientForServer(serverName);
610
646
  allResources[serverName] = await internalClient.resources.list();
611
647
  } catch (error) {
612
- this.logger.error(`Failed to list resources from server ${serverName}`, { error });
648
+ const mastraError = new MastraError({
649
+ id: "MCP_CLIENT_LIST_RESOURCES_FAILED",
650
+ domain: ErrorDomain.MCP,
651
+ category: ErrorCategory.THIRD_PARTY,
652
+ details: {
653
+ serverName
654
+ }
655
+ }, error);
656
+ this.logger.trackException(mastraError);
657
+ this.logger.error("Failed to list resources from server:", { error: mastraError.toString() });
613
658
  }
614
659
  }
615
660
  return allResources;
@@ -621,30 +666,97 @@ To fix this you have three different options:
621
666
  const internalClient = await this.getConnectedClientForServer(serverName);
622
667
  allTemplates[serverName] = await internalClient.resources.templates();
623
668
  } catch (error) {
624
- this.logger.error(`Failed to list resource templates from server ${serverName}`, { error });
669
+ const mastraError = new MastraError({
670
+ id: "MCP_CLIENT_LIST_RESOURCE_TEMPLATES_FAILED",
671
+ domain: ErrorDomain.MCP,
672
+ category: ErrorCategory.THIRD_PARTY,
673
+ details: {
674
+ serverName
675
+ }
676
+ }, error);
677
+ this.logger.trackException(mastraError);
678
+ this.logger.error("Failed to list resource templates from server:", { error: mastraError.toString() });
625
679
  }
626
680
  }
627
681
  return allTemplates;
628
682
  },
629
683
  read: async (serverName, uri) => {
630
- const internalClient = await this.getConnectedClientForServer(serverName);
631
- return internalClient.resources.read(uri);
684
+ try {
685
+ const internalClient = await this.getConnectedClientForServer(serverName);
686
+ return internalClient.resources.read(uri);
687
+ } catch (error) {
688
+ throw new MastraError({
689
+ id: "MCP_CLIENT_READ_RESOURCE_FAILED",
690
+ domain: ErrorDomain.MCP,
691
+ category: ErrorCategory.THIRD_PARTY,
692
+ details: {
693
+ serverName,
694
+ uri
695
+ }
696
+ }, error);
697
+ }
632
698
  },
633
699
  subscribe: async (serverName, uri) => {
634
- const internalClient = await this.getConnectedClientForServer(serverName);
635
- return internalClient.resources.subscribe(uri);
700
+ try {
701
+ const internalClient = await this.getConnectedClientForServer(serverName);
702
+ return internalClient.resources.subscribe(uri);
703
+ } catch (error) {
704
+ throw new MastraError({
705
+ id: "MCP_CLIENT_SUBSCRIBE_RESOURCE_FAILED",
706
+ domain: ErrorDomain.MCP,
707
+ category: ErrorCategory.THIRD_PARTY,
708
+ details: {
709
+ serverName,
710
+ uri
711
+ }
712
+ }, error);
713
+ }
636
714
  },
637
715
  unsubscribe: async (serverName, uri) => {
638
- const internalClient = await this.getConnectedClientForServer(serverName);
639
- return internalClient.resources.unsubscribe(uri);
716
+ try {
717
+ const internalClient = await this.getConnectedClientForServer(serverName);
718
+ return internalClient.resources.unsubscribe(uri);
719
+ } catch (err) {
720
+ throw new MastraError({
721
+ id: "MCP_CLIENT_UNSUBSCRIBE_RESOURCE_FAILED",
722
+ domain: ErrorDomain.MCP,
723
+ category: ErrorCategory.THIRD_PARTY,
724
+ details: {
725
+ serverName,
726
+ uri
727
+ }
728
+ }, err);
729
+ }
640
730
  },
641
731
  onUpdated: async (serverName, handler) => {
642
- const internalClient = await this.getConnectedClientForServer(serverName);
643
- return internalClient.resources.onUpdated(handler);
732
+ try {
733
+ const internalClient = await this.getConnectedClientForServer(serverName);
734
+ return internalClient.resources.onUpdated(handler);
735
+ } catch (err) {
736
+ throw new MastraError({
737
+ id: "MCP_CLIENT_ON_UPDATED_RESOURCE_FAILED",
738
+ domain: ErrorDomain.MCP,
739
+ category: ErrorCategory.THIRD_PARTY,
740
+ details: {
741
+ serverName
742
+ }
743
+ }, err);
744
+ }
644
745
  },
645
746
  onListChanged: async (serverName, handler) => {
646
- const internalClient = await this.getConnectedClientForServer(serverName);
647
- return internalClient.resources.onListChanged(handler);
747
+ try {
748
+ const internalClient = await this.getConnectedClientForServer(serverName);
749
+ return internalClient.resources.onListChanged(handler);
750
+ } catch (err) {
751
+ throw new MastraError({
752
+ id: "MCP_CLIENT_ON_LIST_CHANGED_RESOURCE_FAILED",
753
+ domain: ErrorDomain.MCP,
754
+ category: ErrorCategory.THIRD_PARTY,
755
+ details: {
756
+ serverName
757
+ }
758
+ }, err);
759
+ }
648
760
  }
649
761
  };
650
762
  }
@@ -658,18 +770,50 @@ To fix this you have three different options:
658
770
  const internalClient = await this.getConnectedClientForServer(serverName);
659
771
  allPrompts[serverName] = await internalClient.prompts.list();
660
772
  } catch (error) {
661
- this.logger.error(`Failed to list prompts from server ${serverName}`, { error });
773
+ const mastraError = new MastraError({
774
+ id: "MCP_CLIENT_LIST_PROMPTS_FAILED",
775
+ domain: ErrorDomain.MCP,
776
+ category: ErrorCategory.THIRD_PARTY,
777
+ details: {
778
+ serverName
779
+ }
780
+ }, error);
781
+ this.logger.trackException(mastraError);
782
+ this.logger.error("Failed to list prompts from server:", { error: mastraError.toString() });
662
783
  }
663
784
  }
664
785
  return allPrompts;
665
786
  },
666
787
  get: async ({ serverName, name, args, version }) => {
667
- const internalClient = await this.getConnectedClientForServer(serverName);
668
- return internalClient.prompts.get({ name, args, version });
788
+ try {
789
+ const internalClient = await this.getConnectedClientForServer(serverName);
790
+ return internalClient.prompts.get({ name, args, version });
791
+ } catch (error) {
792
+ throw new MastraError({
793
+ id: "MCP_CLIENT_GET_PROMPT_FAILED",
794
+ domain: ErrorDomain.MCP,
795
+ category: ErrorCategory.THIRD_PARTY,
796
+ details: {
797
+ serverName,
798
+ name
799
+ }
800
+ }, error);
801
+ }
669
802
  },
670
803
  onListChanged: async (serverName, handler) => {
671
- const internalClient = await this.getConnectedClientForServer(serverName);
672
- return internalClient.prompts.onListChanged(handler);
804
+ try {
805
+ const internalClient = await this.getConnectedClientForServer(serverName);
806
+ return internalClient.prompts.onListChanged(handler);
807
+ } catch (error) {
808
+ throw new MastraError({
809
+ id: "MCP_CLIENT_ON_LIST_CHANGED_PROMPT_FAILED",
810
+ domain: ErrorDomain.MCP,
811
+ category: ErrorCategory.THIRD_PARTY,
812
+ details: {
813
+ serverName
814
+ }
815
+ }, error);
816
+ }
673
817
  }
674
818
  };
675
819
  }
@@ -701,21 +845,37 @@ To fix this you have three different options:
701
845
  async getTools() {
702
846
  this.addToInstanceCache();
703
847
  const connectedTools = {};
704
- await this.eachClientTools(async ({ serverName, tools }) => {
705
- for (const [toolName, toolConfig] of Object.entries(tools)) {
706
- connectedTools[`${serverName}_${toolName}`] = toolConfig;
707
- }
708
- });
848
+ try {
849
+ await this.eachClientTools(async ({ serverName, tools }) => {
850
+ for (const [toolName, toolConfig] of Object.entries(tools)) {
851
+ connectedTools[`${serverName}_${toolName}`] = toolConfig;
852
+ }
853
+ });
854
+ } catch (error) {
855
+ throw new MastraError({
856
+ id: "MCP_CLIENT_GET_TOOLS_FAILED",
857
+ domain: ErrorDomain.MCP,
858
+ category: ErrorCategory.THIRD_PARTY
859
+ }, error);
860
+ }
709
861
  return connectedTools;
710
862
  }
711
863
  async getToolsets() {
712
864
  this.addToInstanceCache();
713
865
  const connectedToolsets = {};
714
- await this.eachClientTools(async ({ serverName, tools }) => {
715
- if (tools) {
716
- connectedToolsets[serverName] = tools;
717
- }
718
- });
866
+ try {
867
+ await this.eachClientTools(async ({ serverName, tools }) => {
868
+ if (tools) {
869
+ connectedToolsets[serverName] = tools;
870
+ }
871
+ });
872
+ } catch (error) {
873
+ throw new MastraError({
874
+ id: "MCP_CLIENT_GET_TOOLSETS_FAILED",
875
+ domain: ErrorDomain.MCP,
876
+ category: ErrorCategory.THIRD_PARTY
877
+ }, error);
878
+ }
719
879
  return connectedToolsets;
720
880
  }
721
881
  /**
@@ -762,13 +922,19 @@ To fix this you have three different options:
762
922
  try {
763
923
  await mcpClient.connect();
764
924
  } catch (e) {
925
+ const mastraError = new MastraError({
926
+ id: "MCP_CLIENT_CONNECT_FAILED",
927
+ domain: ErrorDomain.MCP,
928
+ category: ErrorCategory.THIRD_PARTY,
929
+ text: `Failed to connect to MCP server ${name}: ${e instanceof Error ? e.stack || e.message : String(e)}`,
930
+ details: {
931
+ name
932
+ }
933
+ }, e);
934
+ this.logger.trackException(mastraError);
935
+ this.logger.error("MCPClient errored connecting to MCP server:", { error: mastraError.toString() });
765
936
  this.mcpClientsById.delete(name);
766
- this.logger.error(`MCPClient errored connecting to MCP server ${name}`, {
767
- error: e instanceof Error ? e.message : String(e)
768
- });
769
- throw new Error(
770
- `Failed to connect to MCP server ${name}: ${e instanceof Error ? e.stack || e.message : String(e)}`
771
- );
937
+ throw mastraError;
772
938
  }
773
939
  this.logger.debug(`Connected to ${name} MCP server`);
774
940
  return mcpClient;
@@ -798,6 +964,165 @@ var MCPConfiguration = class extends MCPClient {
798
964
  );
799
965
  }
800
966
  };
967
+
968
+ // ../../node_modules/.pnpm/hono@4.8.1/node_modules/hono/dist/utils/stream.js
969
+ var StreamingApi = class {
970
+ writer;
971
+ encoder;
972
+ writable;
973
+ abortSubscribers = [];
974
+ responseReadable;
975
+ aborted = false;
976
+ closed = false;
977
+ constructor(writable, _readable) {
978
+ this.writable = writable;
979
+ this.writer = writable.getWriter();
980
+ this.encoder = new TextEncoder();
981
+ const reader = _readable.getReader();
982
+ this.abortSubscribers.push(async () => {
983
+ await reader.cancel();
984
+ });
985
+ this.responseReadable = new ReadableStream({
986
+ async pull(controller) {
987
+ const { done, value } = await reader.read();
988
+ done ? controller.close() : controller.enqueue(value);
989
+ },
990
+ cancel: () => {
991
+ this.abort();
992
+ }
993
+ });
994
+ }
995
+ async write(input) {
996
+ try {
997
+ if (typeof input === "string") {
998
+ input = this.encoder.encode(input);
999
+ }
1000
+ await this.writer.write(input);
1001
+ } catch {
1002
+ }
1003
+ return this;
1004
+ }
1005
+ async writeln(input) {
1006
+ await this.write(input + "\n");
1007
+ return this;
1008
+ }
1009
+ sleep(ms) {
1010
+ return new Promise((res) => setTimeout(res, ms));
1011
+ }
1012
+ async close() {
1013
+ try {
1014
+ await this.writer.close();
1015
+ } catch {
1016
+ }
1017
+ this.closed = true;
1018
+ }
1019
+ async pipe(body) {
1020
+ this.writer.releaseLock();
1021
+ await body.pipeTo(this.writable, { preventClose: true });
1022
+ this.writer = this.writable.getWriter();
1023
+ }
1024
+ onAbort(listener) {
1025
+ this.abortSubscribers.push(listener);
1026
+ }
1027
+ abort() {
1028
+ if (!this.aborted) {
1029
+ this.aborted = true;
1030
+ this.abortSubscribers.forEach((subscriber) => subscriber());
1031
+ }
1032
+ }
1033
+ };
1034
+
1035
+ // ../../node_modules/.pnpm/hono@4.8.1/node_modules/hono/dist/helper/streaming/utils.js
1036
+ var isOldBunVersion = () => {
1037
+ const version = typeof Bun !== "undefined" ? Bun.version : void 0;
1038
+ if (version === void 0) {
1039
+ return false;
1040
+ }
1041
+ const result = version.startsWith("1.1") || version.startsWith("1.0") || version.startsWith("0.");
1042
+ isOldBunVersion = () => result;
1043
+ return result;
1044
+ };
1045
+
1046
+ // ../../node_modules/.pnpm/hono@4.8.1/node_modules/hono/dist/utils/html.js
1047
+ var HtmlEscapedCallbackPhase = {
1048
+ Stringify: 1};
1049
+ var resolveCallback = async (str, phase, preserveCallbacks, context, buffer) => {
1050
+ if (typeof str === "object" && !(str instanceof String)) {
1051
+ if (!(str instanceof Promise)) {
1052
+ str = str.toString();
1053
+ }
1054
+ if (str instanceof Promise) {
1055
+ str = await str;
1056
+ }
1057
+ }
1058
+ const callbacks = str.callbacks;
1059
+ if (!callbacks?.length) {
1060
+ return Promise.resolve(str);
1061
+ }
1062
+ if (buffer) {
1063
+ buffer[0] += str;
1064
+ } else {
1065
+ buffer = [str];
1066
+ }
1067
+ const resStr = Promise.all(callbacks.map((c) => c({ phase, buffer, context }))).then(
1068
+ (res) => Promise.all(
1069
+ res.filter(Boolean).map((str2) => resolveCallback(str2, phase, false, context, buffer))
1070
+ ).then(() => buffer[0])
1071
+ );
1072
+ {
1073
+ return resStr;
1074
+ }
1075
+ };
1076
+
1077
+ // ../../node_modules/.pnpm/hono@4.8.1/node_modules/hono/dist/helper/streaming/sse.js
1078
+ var SSEStreamingApi = class extends StreamingApi {
1079
+ constructor(writable, readable) {
1080
+ super(writable, readable);
1081
+ }
1082
+ async writeSSE(message) {
1083
+ const data = await resolveCallback(message.data, HtmlEscapedCallbackPhase.Stringify, false, {});
1084
+ const dataLines = data.split("\n").map((line) => {
1085
+ return `data: ${line}`;
1086
+ }).join("\n");
1087
+ const sseData = [
1088
+ message.event && `event: ${message.event}`,
1089
+ dataLines,
1090
+ message.id && `id: ${message.id}`,
1091
+ message.retry && `retry: ${message.retry}`
1092
+ ].filter(Boolean).join("\n") + "\n\n";
1093
+ await this.write(sseData);
1094
+ }
1095
+ };
1096
+ var run = async (stream2, cb, onError) => {
1097
+ try {
1098
+ await cb(stream2);
1099
+ } catch (e) {
1100
+ {
1101
+ console.error(e);
1102
+ }
1103
+ } finally {
1104
+ stream2.close();
1105
+ }
1106
+ };
1107
+ var contextStash = /* @__PURE__ */ new WeakMap();
1108
+ var streamSSE = (c, cb, onError) => {
1109
+ const { readable, writable } = new TransformStream();
1110
+ const stream2 = new SSEStreamingApi(writable, readable);
1111
+ if (isOldBunVersion()) {
1112
+ c.req.raw.signal.addEventListener("abort", () => {
1113
+ if (!stream2.closed) {
1114
+ stream2.abort();
1115
+ }
1116
+ });
1117
+ }
1118
+ contextStash.set(stream2.responseReadable, c);
1119
+ c.header("Transfer-Encoding", "chunked");
1120
+ c.header("Content-Type", "text/event-stream");
1121
+ c.header("Cache-Control", "no-cache");
1122
+ c.header("Connection", "keep-alive");
1123
+ run(stream2, cb);
1124
+ return c.newResponse(stream2.responseReadable);
1125
+ };
801
1126
  var MAXIMUM_MESSAGE_SIZE = 4 * 1024 * 1024;
802
1127
  var SSETransport = class {
803
1128
  messageUrl;
@@ -809,9 +1134,9 @@ var SSETransport = class {
809
1134
  /**
810
1135
  * Creates a new SSETransport, which will direct the MPC client to POST messages to messageUrl
811
1136
  */
812
- constructor(messageUrl, stream) {
1137
+ constructor(messageUrl, stream2) {
813
1138
  this.messageUrl = messageUrl;
814
- this.stream = stream;
1139
+ this.stream = stream2;
815
1140
  this._sessionId = crypto.randomUUID();
816
1141
  this.stream.onAbort(() => {
817
1142
  void this.close();
@@ -828,6 +1153,10 @@ var SSETransport = class {
828
1153
  if (this.stream.closed) {
829
1154
  throw new Error("SSE transport already closed!");
830
1155
  }
1156
+ await this.stream.writeSSE({
1157
+ event: "ping",
1158
+ data: ""
1159
+ });
831
1160
  await this.stream.writeSSE({
832
1161
  event: "endpoint",
833
1162
  data: `${this.messageUrl}?sessionId=${this.sessionId}`
@@ -882,8 +1211,6 @@ var SSETransport = class {
882
1211
  });
883
1212
  }
884
1213
  };
885
-
886
- // src/server/promptActions.ts
887
1214
  var ServerPromptActions = class {
888
1215
  getLogger;
889
1216
  getSdkServer;
@@ -903,15 +1230,23 @@ var ServerPromptActions = class {
903
1230
  try {
904
1231
  await this.getSdkServer().sendPromptListChanged();
905
1232
  } catch (error) {
1233
+ const mastraError = new MastraError(
1234
+ {
1235
+ id: "MCP_SERVER_PROMPT_LIST_CHANGED_NOTIFICATION_FAILED",
1236
+ domain: ErrorDomain.MCP,
1237
+ category: ErrorCategory.THIRD_PARTY,
1238
+ text: "Failed to send prompt list changed notification"
1239
+ },
1240
+ error
1241
+ );
906
1242
  this.getLogger().error("Failed to send prompt list changed notification:", {
907
- error: error instanceof Error ? error.message : String(error)
1243
+ error: mastraError.toString()
908
1244
  });
909
- throw error;
1245
+ this.getLogger().trackException(mastraError);
1246
+ throw mastraError;
910
1247
  }
911
1248
  }
912
1249
  };
913
-
914
- // src/server/resourceActions.ts
915
1250
  var ServerResourceActions = class {
916
1251
  getSubscriptions;
917
1252
  getLogger;
@@ -935,8 +1270,23 @@ var ServerResourceActions = class {
935
1270
  try {
936
1271
  await this.getSdkServer().sendResourceUpdated({ uri });
937
1272
  } catch (error) {
938
- this.getLogger().error("Failed to send resource updated notification:", { error });
939
- throw error;
1273
+ const mastraError = new MastraError(
1274
+ {
1275
+ id: "MCP_SERVER_RESOURCE_UPDATED_NOTIFICATION_FAILED",
1276
+ domain: ErrorDomain.MCP,
1277
+ category: ErrorCategory.THIRD_PARTY,
1278
+ text: "Failed to send resource updated notification",
1279
+ details: {
1280
+ uri
1281
+ }
1282
+ },
1283
+ error
1284
+ );
1285
+ this.getLogger().trackException(mastraError);
1286
+ this.getLogger().error("Failed to send resource updated notification:", {
1287
+ error: mastraError.toString()
1288
+ });
1289
+ throw mastraError;
940
1290
  }
941
1291
  } else {
942
1292
  this.getLogger().debug(`Resource ${uri} was updated, but no active subscriptions for it.`);
@@ -955,8 +1305,20 @@ var ServerResourceActions = class {
955
1305
  try {
956
1306
  await this.getSdkServer().sendResourceListChanged();
957
1307
  } catch (error) {
958
- this.getLogger().error("Failed to send resource list changed notification:", { error });
959
- throw error;
1308
+ const mastraError = new MastraError(
1309
+ {
1310
+ id: "MCP_SERVER_RESOURCE_LIST_CHANGED_NOTIFICATION_FAILED",
1311
+ domain: ErrorDomain.MCP,
1312
+ category: ErrorCategory.THIRD_PARTY,
1313
+ text: "Failed to send resource list changed notification"
1314
+ },
1315
+ error
1316
+ );
1317
+ this.getLogger().trackException(mastraError);
1318
+ this.getLogger().error("Failed to send resource list changed notification:", {
1319
+ error: mastraError.toString()
1320
+ });
1321
+ throw mastraError;
960
1322
  }
961
1323
  }
962
1324
  };
@@ -1166,8 +1528,8 @@ var MCPServer = class extends MCPServerBase {
1166
1528
  context
1167
1529
  );
1168
1530
  try {
1169
- const run = workflow.createRun({ runId: runtimeContext?.get("runId") });
1170
- const response = await run.start({ inputData: context, runtimeContext });
1531
+ const run2 = workflow.createRun({ runId: runtimeContext?.get("runId") });
1532
+ const response = await run2.start({ inputData: context, runtimeContext });
1171
1533
  return response;
1172
1534
  } catch (error) {
1173
1535
  this.logger.error(
@@ -1190,6 +1552,7 @@ var MCPServer = class extends MCPServerBase {
1190
1552
  name: workflowToolName,
1191
1553
  description: coreTool.description,
1192
1554
  parameters: coreTool.parameters,
1555
+ outputSchema: coreTool.outputSchema,
1193
1556
  execute: coreTool.execute,
1194
1557
  toolType: "workflow"
1195
1558
  };
@@ -1229,13 +1592,32 @@ var MCPServer = class extends MCPServerBase {
1229
1592
  name: toolName,
1230
1593
  description: coreTool.description,
1231
1594
  parameters: coreTool.parameters,
1595
+ outputSchema: coreTool.outputSchema,
1232
1596
  execute: coreTool.execute
1233
1597
  };
1234
1598
  this.logger.info(`Registered explicit tool: '${toolName}'`);
1235
1599
  }
1236
1600
  this.logger.info(`Total defined tools registered: ${Object.keys(definedConvertedTools).length}`);
1237
- const agentDerivedTools = this.convertAgentsToTools(agentsConfig, definedConvertedTools);
1238
- const workflowDerivedTools = this.convertWorkflowsToTools(workflowsConfig, definedConvertedTools);
1601
+ let agentDerivedTools = {};
1602
+ let workflowDerivedTools = {};
1603
+ try {
1604
+ agentDerivedTools = this.convertAgentsToTools(agentsConfig, definedConvertedTools);
1605
+ workflowDerivedTools = this.convertWorkflowsToTools(workflowsConfig, definedConvertedTools);
1606
+ } catch (e) {
1607
+ const mastraError = new MastraError(
1608
+ {
1609
+ id: "MCP_SERVER_AGENT_OR_WORKFLOW_TOOL_CONVERSION_FAILED",
1610
+ domain: ErrorDomain.MCP,
1611
+ category: ErrorCategory.USER
1612
+ },
1613
+ e
1614
+ );
1615
+ this.logger.trackException(mastraError);
1616
+ this.logger.error("Failed to convert tools:", {
1617
+ error: mastraError.toString()
1618
+ });
1619
+ throw mastraError;
1620
+ }
1239
1621
  const allConvertedTools = { ...definedConvertedTools, ...agentDerivedTools, ...workflowDerivedTools };
1240
1622
  const finalToolCount = Object.keys(allConvertedTools).length;
1241
1623
  const definedCount = Object.keys(definedConvertedTools).length;
@@ -1257,11 +1639,17 @@ var MCPServer = class extends MCPServerBase {
1257
1639
  this.server.setRequestHandler(ListToolsRequestSchema, async () => {
1258
1640
  this.logger.debug("Handling ListTools request");
1259
1641
  return {
1260
- tools: Object.values(this.convertedTools).map((tool) => ({
1261
- name: tool.name,
1262
- description: tool.description,
1263
- inputSchema: tool.parameters.jsonSchema
1264
- }))
1642
+ tools: Object.values(this.convertedTools).map((tool) => {
1643
+ const toolSpec = {
1644
+ name: tool.name,
1645
+ description: tool.description,
1646
+ inputSchema: tool.parameters.jsonSchema
1647
+ };
1648
+ if (tool.outputSchema) {
1649
+ toolSpec.outputSchema = tool.outputSchema.jsonSchema;
1650
+ }
1651
+ return toolSpec;
1652
+ })
1265
1653
  };
1266
1654
  });
1267
1655
  }
@@ -1284,7 +1672,6 @@ var MCPServer = class extends MCPServerBase {
1284
1672
  isError: true
1285
1673
  };
1286
1674
  }
1287
- this.logger.debug(`CallTool: Invoking '${request.params.name}' with arguments:`, request.params.arguments);
1288
1675
  const validation = tool.parameters.validate?.(request.params.arguments ?? {});
1289
1676
  if (validation && !validation.success) {
1290
1677
  this.logger.warn(`CallTool: Invalid tool arguments for '${request.params.name}'`, {
@@ -1303,17 +1690,38 @@ var MCPServer = class extends MCPServerBase {
1303
1690
  };
1304
1691
  }
1305
1692
  const result = await tool.execute(validation?.value, { messages: [], toolCallId: "" });
1693
+ this.logger.debug(`CallTool: Tool '${request.params.name}' executed successfully with result:`, result);
1306
1694
  const duration = Date.now() - startTime;
1307
1695
  this.logger.info(`Tool '${request.params.name}' executed successfully in ${duration}ms.`);
1308
- return {
1309
- content: [
1696
+ const response = { isError: false, content: [] };
1697
+ if (tool.outputSchema) {
1698
+ if (!result.structuredContent) {
1699
+ throw new Error(`Tool ${request.params.name} has an output schema but no structured content was provided.`);
1700
+ }
1701
+ const outputValidation = tool.outputSchema.validate?.(result.structuredContent ?? {});
1702
+ if (outputValidation && !outputValidation.success) {
1703
+ this.logger.warn(`CallTool: Invalid structured content for '${request.params.name}'`, {
1704
+ errors: outputValidation.error
1705
+ });
1706
+ throw new Error(
1707
+ `Invalid structured content for tool ${request.params.name}: ${JSON.stringify(outputValidation.error)}`
1708
+ );
1709
+ }
1710
+ response.structuredContent = result.structuredContent;
1711
+ }
1712
+ if (result.content) {
1713
+ response.content = result.content;
1714
+ } else if (response.structuredContent) {
1715
+ response.content = [{ type: "text", text: JSON.stringify(response.structuredContent) }];
1716
+ } else {
1717
+ response.content = [
1310
1718
  {
1311
1719
  type: "text",
1312
1720
  text: typeof result === "string" ? result : JSON.stringify(result)
1313
1721
  }
1314
- ],
1315
- isError: false
1316
- };
1722
+ ];
1723
+ }
1724
+ return response;
1317
1725
  } catch (error) {
1318
1726
  const duration = Date.now() - startTime;
1319
1727
  if (error instanceof z.ZodError) {
@@ -1587,7 +1995,23 @@ var MCPServer = class extends MCPServerBase {
1587
1995
  */
1588
1996
  async startStdio() {
1589
1997
  this.stdioTransport = new StdioServerTransport();
1590
- await this.server.connect(this.stdioTransport);
1998
+ try {
1999
+ await this.server.connect(this.stdioTransport);
2000
+ } catch (error) {
2001
+ const mastraError = new MastraError(
2002
+ {
2003
+ id: "MCP_SERVER_STDIO_CONNECTION_FAILED",
2004
+ domain: ErrorDomain.MCP,
2005
+ category: ErrorCategory.THIRD_PARTY
2006
+ },
2007
+ error
2008
+ );
2009
+ this.logger.trackException(mastraError);
2010
+ this.logger.error("Failed to connect MCP server using stdio transport:", {
2011
+ error: mastraError.toString()
2012
+ });
2013
+ throw mastraError;
2014
+ }
1591
2015
  this.logger.info("Started MCP Server (stdio)");
1592
2016
  }
1593
2017
  /**
@@ -1601,23 +2025,42 @@ var MCPServer = class extends MCPServerBase {
1601
2025
  * @param res HTTP response (must support .write/.end)
1602
2026
  */
1603
2027
  async startSSE({ url, ssePath, messagePath, req, res }) {
1604
- if (url.pathname === ssePath) {
1605
- await this.connectSSE({
1606
- messagePath,
1607
- res
1608
- });
1609
- } else if (url.pathname === messagePath) {
1610
- this.logger.debug("Received message");
1611
- if (!this.sseTransport) {
1612
- res.writeHead(503);
1613
- res.end("SSE connection not established");
1614
- return;
2028
+ try {
2029
+ if (url.pathname === ssePath) {
2030
+ await this.connectSSE({
2031
+ messagePath,
2032
+ res
2033
+ });
2034
+ } else if (url.pathname === messagePath) {
2035
+ this.logger.debug("Received message");
2036
+ if (!this.sseTransport) {
2037
+ res.writeHead(503);
2038
+ res.end("SSE connection not established");
2039
+ return;
2040
+ }
2041
+ await this.sseTransport.handlePostMessage(req, res);
2042
+ } else {
2043
+ this.logger.debug("Unknown path:", { path: url.pathname });
2044
+ res.writeHead(404);
2045
+ res.end();
1615
2046
  }
1616
- await this.sseTransport.handlePostMessage(req, res);
1617
- } else {
1618
- this.logger.debug("Unknown path:", { path: url.pathname });
1619
- res.writeHead(404);
1620
- res.end();
2047
+ } catch (e) {
2048
+ const mastraError = new MastraError(
2049
+ {
2050
+ id: "MCP_SERVER_SSE_START_FAILED",
2051
+ domain: ErrorDomain.MCP,
2052
+ category: ErrorCategory.USER,
2053
+ details: {
2054
+ url: url.toString(),
2055
+ ssePath,
2056
+ messagePath
2057
+ }
2058
+ },
2059
+ e
2060
+ );
2061
+ this.logger.trackException(mastraError);
2062
+ this.logger.error("Failed to start MCP Server (SSE):", { error: mastraError.toString() });
2063
+ throw mastraError;
1621
2064
  }
1622
2065
  }
1623
2066
  /**
@@ -1630,31 +2073,50 @@ var MCPServer = class extends MCPServerBase {
1630
2073
  * @param context Incoming Hono context
1631
2074
  */
1632
2075
  async startHonoSSE({ url, ssePath, messagePath, context }) {
1633
- if (url.pathname === ssePath) {
1634
- return streamSSE(context, async (stream) => {
1635
- await this.connectHonoSSE({
1636
- messagePath,
1637
- stream
2076
+ try {
2077
+ if (url.pathname === ssePath) {
2078
+ return streamSSE(context, async (stream2) => {
2079
+ await this.connectHonoSSE({
2080
+ messagePath,
2081
+ stream: stream2
2082
+ });
1638
2083
  });
1639
- });
1640
- } else if (url.pathname === messagePath) {
1641
- this.logger.debug("Received message");
1642
- const sessionId = context.req.query("sessionId");
1643
- this.logger.debug("Received message for sessionId", { sessionId });
1644
- if (!sessionId) {
1645
- return context.text("No sessionId provided", 400);
1646
- }
1647
- if (!this.sseHonoTransports.has(sessionId)) {
1648
- return context.text(`No transport found for sessionId ${sessionId}`, 400);
1649
- }
1650
- const message = await this.sseHonoTransports.get(sessionId)?.handlePostMessage(context);
1651
- if (!message) {
1652
- return context.text("Transport not found", 400);
2084
+ } else if (url.pathname === messagePath) {
2085
+ this.logger.debug("Received message");
2086
+ const sessionId = context.req.query("sessionId");
2087
+ this.logger.debug("Received message for sessionId", { sessionId });
2088
+ if (!sessionId) {
2089
+ return context.text("No sessionId provided", 400);
2090
+ }
2091
+ if (!this.sseHonoTransports.has(sessionId)) {
2092
+ return context.text(`No transport found for sessionId ${sessionId}`, 400);
2093
+ }
2094
+ const message = await this.sseHonoTransports.get(sessionId)?.handlePostMessage(context);
2095
+ if (!message) {
2096
+ return context.text("Transport not found", 400);
2097
+ }
2098
+ return message;
2099
+ } else {
2100
+ this.logger.debug("Unknown path:", { path: url.pathname });
2101
+ return context.text("Unknown path", 404);
1653
2102
  }
1654
- return message;
1655
- } else {
1656
- this.logger.debug("Unknown path:", { path: url.pathname });
1657
- return context.text("Unknown path", 404);
2103
+ } catch (e) {
2104
+ const mastraError = new MastraError(
2105
+ {
2106
+ id: "MCP_SERVER_HONO_SSE_START_FAILED",
2107
+ domain: ErrorDomain.MCP,
2108
+ category: ErrorCategory.USER,
2109
+ details: {
2110
+ url: url.toString(),
2111
+ ssePath,
2112
+ messagePath
2113
+ }
2114
+ },
2115
+ e
2116
+ );
2117
+ this.logger.trackException(mastraError);
2118
+ this.logger.error("Failed to start MCP Server (Hono SSE):", { error: mastraError.toString() });
2119
+ throw mastraError;
1658
2120
  }
1659
2121
  }
1660
2122
  /**
@@ -1783,7 +2245,17 @@ var MCPServer = class extends MCPServerBase {
1783
2245
  }
1784
2246
  }
1785
2247
  } catch (error) {
1786
- this.logger.error("startHTTP: Error handling Streamable HTTP request:", { error });
2248
+ const mastraError = new MastraError(
2249
+ {
2250
+ id: "MCP_SERVER_HTTP_CONNECTION_FAILED",
2251
+ domain: ErrorDomain.MCP,
2252
+ category: ErrorCategory.USER,
2253
+ text: "Failed to connect MCP server using HTTP transport"
2254
+ },
2255
+ error
2256
+ );
2257
+ this.logger.trackException(mastraError);
2258
+ this.logger.error("startHTTP: Error handling Streamable HTTP request:", { error: mastraError });
1787
2259
  if (!res.headersSent) {
1788
2260
  res.writeHead(500, { "Content-Type": "application/json" });
1789
2261
  res.end(
@@ -1797,8 +2269,6 @@ var MCPServer = class extends MCPServerBase {
1797
2269
  // Cannot determine original request ID in catch
1798
2270
  })
1799
2271
  );
1800
- } else {
1801
- this.logger.error("startHTTP: Error after headers sent:", error);
1802
2272
  }
1803
2273
  }
1804
2274
  }
@@ -1806,38 +2276,72 @@ var MCPServer = class extends MCPServerBase {
1806
2276
  messagePath,
1807
2277
  res
1808
2278
  }) {
1809
- this.logger.debug("Received SSE connection");
1810
- this.sseTransport = new SSEServerTransport(messagePath, res);
1811
- await this.server.connect(this.sseTransport);
1812
- this.server.onclose = async () => {
1813
- this.sseTransport = void 0;
1814
- await this.server.close();
1815
- };
1816
- res.on("close", () => {
1817
- this.sseTransport = void 0;
1818
- });
2279
+ try {
2280
+ this.logger.debug("Received SSE connection");
2281
+ this.sseTransport = new SSEServerTransport(messagePath, res);
2282
+ await this.server.connect(this.sseTransport);
2283
+ this.server.onclose = async () => {
2284
+ this.sseTransport = void 0;
2285
+ await this.server.close();
2286
+ };
2287
+ res.on("close", () => {
2288
+ this.sseTransport = void 0;
2289
+ });
2290
+ } catch (e) {
2291
+ const mastraError = new MastraError(
2292
+ {
2293
+ id: "MCP_SERVER_SSE_CONNECT_FAILED",
2294
+ domain: ErrorDomain.MCP,
2295
+ category: ErrorCategory.USER,
2296
+ details: {
2297
+ messagePath
2298
+ }
2299
+ },
2300
+ e
2301
+ );
2302
+ this.logger.trackException(mastraError);
2303
+ this.logger.error("Failed to connect to MCP Server (SSE):", { error: mastraError });
2304
+ throw mastraError;
2305
+ }
1819
2306
  }
1820
- async connectHonoSSE({ messagePath, stream }) {
2307
+ async connectHonoSSE({ messagePath, stream: stream2 }) {
1821
2308
  this.logger.debug("Received SSE connection");
1822
- const sseTransport = new SSETransport(messagePath, stream);
2309
+ const sseTransport = new SSETransport(messagePath, stream2);
1823
2310
  const sessionId = sseTransport.sessionId;
1824
2311
  this.logger.debug("SSE Transport created with sessionId:", { sessionId });
1825
2312
  this.sseHonoTransports.set(sessionId, sseTransport);
1826
- stream.onAbort(() => {
2313
+ stream2.onAbort(() => {
1827
2314
  this.logger.debug("SSE Transport aborted with sessionId:", { sessionId });
1828
2315
  this.sseHonoTransports.delete(sessionId);
1829
2316
  });
1830
- await this.server.connect(sseTransport);
1831
- this.server.onclose = async () => {
1832
- this.logger.debug("SSE Transport closed with sessionId:", { sessionId });
1833
- this.sseHonoTransports.delete(sessionId);
1834
- await this.server.close();
1835
- };
1836
- while (true) {
1837
- const sessionIds = Array.from(this.sseHonoTransports.keys() || []);
1838
- this.logger.debug("Active Hono SSE sessions:", { sessionIds });
1839
- await stream.write(":keep-alive\n\n");
1840
- await stream.sleep(6e4);
2317
+ try {
2318
+ await this.server.connect(sseTransport);
2319
+ this.server.onclose = async () => {
2320
+ this.logger.debug("SSE Transport closed with sessionId:", { sessionId });
2321
+ this.sseHonoTransports.delete(sessionId);
2322
+ await this.server.close();
2323
+ };
2324
+ while (true) {
2325
+ const sessionIds = Array.from(this.sseHonoTransports.keys() || []);
2326
+ this.logger.debug("Active Hono SSE sessions:", { sessionIds });
2327
+ await stream2.write(":keep-alive\n\n");
2328
+ await stream2.sleep(6e4);
2329
+ }
2330
+ } catch (e) {
2331
+ const mastraError = new MastraError(
2332
+ {
2333
+ id: "MCP_SERVER_HONO_SSE_CONNECT_FAILED",
2334
+ domain: ErrorDomain.MCP,
2335
+ category: ErrorCategory.USER,
2336
+ details: {
2337
+ messagePath
2338
+ }
2339
+ },
2340
+ e
2341
+ );
2342
+ this.logger.trackException(mastraError);
2343
+ this.logger.error("Failed to connect to MCP Server (Hono SSE):", { error: mastraError });
2344
+ throw mastraError;
1841
2345
  }
1842
2346
  }
1843
2347
  /**
@@ -1875,7 +2379,17 @@ var MCPServer = class extends MCPServerBase {
1875
2379
  await this.server.close();
1876
2380
  this.logger.info("MCP server closed.");
1877
2381
  } catch (error) {
1878
- this.logger.error("Error closing MCP server:", { error });
2382
+ const mastraError = new MastraError(
2383
+ {
2384
+ id: "MCP_SERVER_CLOSE_FAILED",
2385
+ domain: ErrorDomain.MCP,
2386
+ category: ErrorCategory.THIRD_PARTY
2387
+ },
2388
+ error
2389
+ );
2390
+ this.logger.trackException(mastraError);
2391
+ this.logger.error("Error closing MCP server:", { error: mastraError });
2392
+ throw mastraError;
1879
2393
  }
1880
2394
  }
1881
2395
  /**
@@ -1920,6 +2434,7 @@ var MCPServer = class extends MCPServerBase {
1920
2434
  name: tool.name,
1921
2435
  description: tool.description,
1922
2436
  inputSchema: tool.parameters?.jsonSchema || tool.parameters,
2437
+ outputSchema: tool.outputSchema?.jsonSchema || tool.outputSchema,
1923
2438
  toolType: tool.toolType
1924
2439
  }))
1925
2440
  };
@@ -1940,6 +2455,7 @@ var MCPServer = class extends MCPServerBase {
1940
2455
  name: tool.name,
1941
2456
  description: tool.description,
1942
2457
  inputSchema: tool.parameters?.jsonSchema || tool.parameters,
2458
+ outputSchema: tool.outputSchema?.jsonSchema || tool.outputSchema,
1943
2459
  toolType: tool.toolType
1944
2460
  };
1945
2461
  }
@@ -1953,30 +2469,47 @@ var MCPServer = class extends MCPServerBase {
1953
2469
  */
1954
2470
  async executeTool(toolId, args, executionContext) {
1955
2471
  const tool = this.convertedTools[toolId];
1956
- if (!tool) {
1957
- this.logger.warn(`ExecuteTool: Unknown tool '${toolId}' requested on MCPServer '${this.name}'.`);
1958
- throw new Error(`Unknown tool: ${toolId}`);
1959
- }
1960
- this.logger.debug(`ExecuteTool: Invoking '${toolId}' with arguments:`, args);
1961
- let validatedArgs = args;
1962
- if (tool.parameters instanceof z.ZodType && typeof tool.parameters.safeParse === "function") {
1963
- const validation = tool.parameters.safeParse(args ?? {});
1964
- if (!validation.success) {
1965
- const errorMessages = validation.error.errors.map((e) => `${e.path.join(".")}: ${e.message}`).join(", ");
1966
- this.logger.warn(`ExecuteTool: Invalid tool arguments for '${toolId}': ${errorMessages}`, {
1967
- errors: validation.error.format()
1968
- });
1969
- throw new z.ZodError(validation.error.issues);
2472
+ let validatedArgs;
2473
+ try {
2474
+ if (!tool) {
2475
+ this.logger.warn(`ExecuteTool: Unknown tool '${toolId}' requested on MCPServer '${this.name}'.`);
2476
+ throw new Error(`Unknown tool: ${toolId}`);
1970
2477
  }
1971
- validatedArgs = validation.data;
1972
- } else {
1973
- this.logger.debug(
1974
- `ExecuteTool: Tool '${toolId}' parameters is not a Zod schema with safeParse or is undefined. Skipping validation.`
2478
+ this.logger.debug(`ExecuteTool: Invoking '${toolId}' with arguments:`, args);
2479
+ if (tool.parameters instanceof z.ZodType && typeof tool.parameters.safeParse === "function") {
2480
+ const validation = tool.parameters.safeParse(args ?? {});
2481
+ if (!validation.success) {
2482
+ const errorMessages = validation.error.errors.map((e) => `${e.path.join(".")}: ${e.message}`).join(", ");
2483
+ this.logger.warn(`ExecuteTool: Invalid tool arguments for '${toolId}': ${errorMessages}`, {
2484
+ errors: validation.error.format()
2485
+ });
2486
+ throw new z.ZodError(validation.error.issues);
2487
+ }
2488
+ validatedArgs = validation.data;
2489
+ } else {
2490
+ this.logger.debug(
2491
+ `ExecuteTool: Tool '${toolId}' parameters is not a Zod schema with safeParse or is undefined. Skipping validation.`
2492
+ );
2493
+ }
2494
+ if (!tool.execute) {
2495
+ this.logger.error(`ExecuteTool: Tool '${toolId}' does not have an execute function.`);
2496
+ throw new Error(`Tool '${toolId}' cannot be executed.`);
2497
+ }
2498
+ } catch (error) {
2499
+ const mastraError = new MastraError(
2500
+ {
2501
+ id: "MCP_SERVER_TOOL_EXECUTE_PREPARATION_FAILED",
2502
+ domain: ErrorDomain.MCP,
2503
+ category: ErrorCategory.USER,
2504
+ details: {
2505
+ toolId,
2506
+ args
2507
+ }
2508
+ },
2509
+ error
1975
2510
  );
1976
- }
1977
- if (!tool.execute) {
1978
- this.logger.error(`ExecuteTool: Tool '${toolId}' does not have an execute function.`);
1979
- throw new Error(`Tool '${toolId}' cannot be executed.`);
2511
+ this.logger.trackException(mastraError);
2512
+ throw mastraError;
1980
2513
  }
1981
2514
  try {
1982
2515
  const finalExecutionContext = {
@@ -1987,8 +2520,21 @@ var MCPServer = class extends MCPServerBase {
1987
2520
  this.logger.info(`ExecuteTool: Tool '${toolId}' executed successfully.`);
1988
2521
  return result;
1989
2522
  } catch (error) {
2523
+ const mastraError = new MastraError(
2524
+ {
2525
+ id: "MCP_SERVER_TOOL_EXECUTE_FAILED",
2526
+ domain: ErrorDomain.MCP,
2527
+ category: ErrorCategory.USER,
2528
+ details: {
2529
+ toolId,
2530
+ validatedArgs
2531
+ }
2532
+ },
2533
+ error
2534
+ );
2535
+ this.logger.trackException(mastraError);
1990
2536
  this.logger.error(`ExecuteTool: Tool execution failed for '${toolId}':`, { error });
1991
- throw error instanceof Error ? error : new Error(`Execution of tool '${toolId}' failed: ${String(error)}`);
2537
+ throw mastraError;
1992
2538
  }
1993
2539
  }
1994
2540
  };