@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.
@@ -3,6 +3,7 @@ import type * as http from 'node:http';
3
3
  import type { InternalCoreTool } from '@mastra/core';
4
4
  import { createTool, makeCoreTool } from '@mastra/core';
5
5
  import type { ToolsInput, Agent } from '@mastra/core/agent';
6
+ import { ErrorCategory, ErrorDomain, MastraError } from '@mastra/core/error';
6
7
  import { MCPServerBase } from '@mastra/core/mcp';
7
8
  import type {
8
9
  MCPServerConfig,
@@ -38,6 +39,7 @@ import type {
38
39
  ResourceTemplate,
39
40
  ServerCapabilities,
40
41
  Prompt,
42
+ CallToolResult,
41
43
  } from '@modelcontextprotocol/sdk/types.js';
42
44
  import type { SSEStreamingApi } from 'hono/streaming';
43
45
  import { streamSSE } from 'hono/streaming';
@@ -319,6 +321,7 @@ export class MCPServer extends MCPServerBase {
319
321
  name: workflowToolName,
320
322
  description: coreTool.description,
321
323
  parameters: coreTool.parameters,
324
+ outputSchema: coreTool.outputSchema,
322
325
  execute: coreTool.execute!,
323
326
  toolType: 'workflow',
324
327
  };
@@ -368,14 +371,33 @@ export class MCPServer extends MCPServerBase {
368
371
  name: toolName,
369
372
  description: coreTool.description,
370
373
  parameters: coreTool.parameters,
374
+ outputSchema: coreTool.outputSchema,
371
375
  execute: coreTool.execute!,
372
376
  };
373
377
  this.logger.info(`Registered explicit tool: '${toolName}'`);
374
378
  }
375
379
  this.logger.info(`Total defined tools registered: ${Object.keys(definedConvertedTools).length}`);
376
380
 
377
- const agentDerivedTools = this.convertAgentsToTools(agentsConfig, definedConvertedTools);
378
- const workflowDerivedTools = this.convertWorkflowsToTools(workflowsConfig, definedConvertedTools);
381
+ let agentDerivedTools: Record<string, ConvertedTool> = {};
382
+ let workflowDerivedTools: Record<string, ConvertedTool> = {};
383
+ try {
384
+ agentDerivedTools = this.convertAgentsToTools(agentsConfig, definedConvertedTools);
385
+ workflowDerivedTools = this.convertWorkflowsToTools(workflowsConfig, definedConvertedTools);
386
+ } catch (e) {
387
+ const mastraError = new MastraError(
388
+ {
389
+ id: 'MCP_SERVER_AGENT_OR_WORKFLOW_TOOL_CONVERSION_FAILED',
390
+ domain: ErrorDomain.MCP,
391
+ category: ErrorCategory.USER,
392
+ },
393
+ e,
394
+ );
395
+ this.logger.trackException(mastraError);
396
+ this.logger.error('Failed to convert tools:', {
397
+ error: mastraError.toString(),
398
+ });
399
+ throw mastraError;
400
+ }
379
401
 
380
402
  const allConvertedTools = { ...definedConvertedTools, ...agentDerivedTools, ...workflowDerivedTools };
381
403
 
@@ -401,11 +423,17 @@ export class MCPServer extends MCPServerBase {
401
423
  this.server.setRequestHandler(ListToolsRequestSchema, async () => {
402
424
  this.logger.debug('Handling ListTools request');
403
425
  return {
404
- tools: Object.values(this.convertedTools).map(tool => ({
405
- name: tool.name,
406
- description: tool.description,
407
- inputSchema: tool.parameters.jsonSchema,
408
- })),
426
+ tools: Object.values(this.convertedTools).map(tool => {
427
+ const toolSpec: any = {
428
+ name: tool.name,
429
+ description: tool.description,
430
+ inputSchema: tool.parameters.jsonSchema,
431
+ };
432
+ if (tool.outputSchema) {
433
+ toolSpec.outputSchema = tool.outputSchema.jsonSchema;
434
+ }
435
+ return toolSpec;
436
+ }),
409
437
  };
410
438
  });
411
439
  }
@@ -430,8 +458,6 @@ export class MCPServer extends MCPServerBase {
430
458
  };
431
459
  }
432
460
 
433
- this.logger.debug(`CallTool: Invoking '${request.params.name}' with arguments:`, request.params.arguments);
434
-
435
461
  const validation = tool.parameters.validate?.(request.params.arguments ?? {});
436
462
  if (validation && !validation.success) {
437
463
  this.logger.warn(`CallTool: Invalid tool arguments for '${request.params.name}'`, {
@@ -451,17 +477,43 @@ export class MCPServer extends MCPServerBase {
451
477
  }
452
478
 
453
479
  const result = await tool.execute(validation?.value, { messages: [], toolCallId: '' });
480
+
481
+ this.logger.debug(`CallTool: Tool '${request.params.name}' executed successfully with result:`, result);
454
482
  const duration = Date.now() - startTime;
455
483
  this.logger.info(`Tool '${request.params.name}' executed successfully in ${duration}ms.`);
456
- return {
457
- content: [
484
+
485
+ const response: CallToolResult = { isError: false, content: [] };
486
+
487
+ if (tool.outputSchema) {
488
+ if (!result.structuredContent) {
489
+ throw new Error(`Tool ${request.params.name} has an output schema but no structured content was provided.`);
490
+ }
491
+ const outputValidation = tool.outputSchema.validate?.(result.structuredContent ?? {});
492
+ if (outputValidation && !outputValidation.success) {
493
+ this.logger.warn(`CallTool: Invalid structured content for '${request.params.name}'`, {
494
+ errors: outputValidation.error,
495
+ });
496
+ throw new Error(
497
+ `Invalid structured content for tool ${request.params.name}: ${JSON.stringify(outputValidation.error)}`,
498
+ );
499
+ }
500
+ response.structuredContent = result.structuredContent;
501
+ }
502
+
503
+ if (result.content) {
504
+ response.content = result.content;
505
+ } else if (response.structuredContent) {
506
+ response.content = [{ type: 'text', text: JSON.stringify(response.structuredContent) }];
507
+ } else {
508
+ response.content = [
458
509
  {
459
510
  type: 'text',
460
511
  text: typeof result === 'string' ? result : JSON.stringify(result),
461
512
  },
462
- ],
463
- isError: false,
464
- };
513
+ ];
514
+ }
515
+
516
+ return response;
465
517
  } catch (error) {
466
518
  const duration = Date.now() - startTime;
467
519
  if (error instanceof z.ZodError) {
@@ -645,7 +697,7 @@ export class MCPServer extends MCPServerBase {
645
697
  return;
646
698
  }
647
699
  this.subscribeResourceHandlerIsRegistered = true;
648
- this.server.setRequestHandler(SubscribeRequestSchema as any, async (request: { params: { uri: string } }) => {
700
+ this.server.setRequestHandler(SubscribeRequestSchema, async (request: { params: { uri: string } }) => {
649
701
  const uri = request.params.uri;
650
702
  this.logger.info(`Received resources/subscribe request for URI: ${uri}`);
651
703
  this.subscriptions.add(uri);
@@ -662,7 +714,7 @@ export class MCPServer extends MCPServerBase {
662
714
  }
663
715
  this.unsubscribeResourceHandlerIsRegistered = true;
664
716
 
665
- this.server.setRequestHandler(UnsubscribeRequestSchema as any, async (request: { params: { uri: string } }) => {
717
+ this.server.setRequestHandler(UnsubscribeRequestSchema, async (request: { params: { uri: string } }) => {
666
718
  const uri = request.params.uri;
667
719
  this.logger.info(`Received resources/unsubscribe request for URI: ${uri}`);
668
720
  this.subscriptions.delete(uri);
@@ -776,7 +828,23 @@ export class MCPServer extends MCPServerBase {
776
828
  */
777
829
  public async startStdio(): Promise<void> {
778
830
  this.stdioTransport = new StdioServerTransport();
779
- await this.server.connect(this.stdioTransport);
831
+ try {
832
+ await this.server.connect(this.stdioTransport);
833
+ } catch (error) {
834
+ const mastraError = new MastraError(
835
+ {
836
+ id: 'MCP_SERVER_STDIO_CONNECTION_FAILED',
837
+ domain: ErrorDomain.MCP,
838
+ category: ErrorCategory.THIRD_PARTY,
839
+ },
840
+ error,
841
+ );
842
+ this.logger.trackException(mastraError);
843
+ this.logger.error('Failed to connect MCP server using stdio transport:', {
844
+ error: mastraError.toString(),
845
+ });
846
+ throw mastraError;
847
+ }
780
848
  this.logger.info('Started MCP Server (stdio)');
781
849
  }
782
850
 
@@ -791,23 +859,42 @@ export class MCPServer extends MCPServerBase {
791
859
  * @param res HTTP response (must support .write/.end)
792
860
  */
793
861
  public async startSSE({ url, ssePath, messagePath, req, res }: MCPServerSSEOptions): Promise<void> {
794
- if (url.pathname === ssePath) {
795
- await this.connectSSE({
796
- messagePath,
797
- res,
798
- });
799
- } else if (url.pathname === messagePath) {
800
- this.logger.debug('Received message');
801
- if (!this.sseTransport) {
802
- res.writeHead(503);
803
- res.end('SSE connection not established');
804
- return;
862
+ try {
863
+ if (url.pathname === ssePath) {
864
+ await this.connectSSE({
865
+ messagePath,
866
+ res,
867
+ });
868
+ } else if (url.pathname === messagePath) {
869
+ this.logger.debug('Received message');
870
+ if (!this.sseTransport) {
871
+ res.writeHead(503);
872
+ res.end('SSE connection not established');
873
+ return;
874
+ }
875
+ await this.sseTransport.handlePostMessage(req, res);
876
+ } else {
877
+ this.logger.debug('Unknown path:', { path: url.pathname });
878
+ res.writeHead(404);
879
+ res.end();
805
880
  }
806
- await this.sseTransport.handlePostMessage(req, res);
807
- } else {
808
- this.logger.debug('Unknown path:', { path: url.pathname });
809
- res.writeHead(404);
810
- res.end();
881
+ } catch (e) {
882
+ const mastraError = new MastraError(
883
+ {
884
+ id: 'MCP_SERVER_SSE_START_FAILED',
885
+ domain: ErrorDomain.MCP,
886
+ category: ErrorCategory.USER,
887
+ details: {
888
+ url: url.toString(),
889
+ ssePath,
890
+ messagePath,
891
+ },
892
+ },
893
+ e,
894
+ );
895
+ this.logger.trackException(mastraError);
896
+ this.logger.error('Failed to start MCP Server (SSE):', { error: mastraError.toString() });
897
+ throw mastraError;
811
898
  }
812
899
  }
813
900
 
@@ -821,31 +908,50 @@ export class MCPServer extends MCPServerBase {
821
908
  * @param context Incoming Hono context
822
909
  */
823
910
  public async startHonoSSE({ url, ssePath, messagePath, context }: MCPServerHonoSSEOptions) {
824
- if (url.pathname === ssePath) {
825
- return streamSSE(context, async stream => {
826
- await this.connectHonoSSE({
827
- messagePath,
828
- stream,
911
+ try {
912
+ if (url.pathname === ssePath) {
913
+ return streamSSE(context, async stream => {
914
+ await this.connectHonoSSE({
915
+ messagePath,
916
+ stream,
917
+ });
829
918
  });
830
- });
831
- } else if (url.pathname === messagePath) {
832
- this.logger.debug('Received message');
833
- const sessionId = context.req.query('sessionId');
834
- this.logger.debug('Received message for sessionId', { sessionId });
835
- if (!sessionId) {
836
- return context.text('No sessionId provided', 400);
837
- }
838
- if (!this.sseHonoTransports.has(sessionId)) {
839
- return context.text(`No transport found for sessionId ${sessionId}`, 400);
840
- }
841
- const message = await this.sseHonoTransports.get(sessionId)?.handlePostMessage(context);
842
- if (!message) {
843
- return context.text('Transport not found', 400);
919
+ } else if (url.pathname === messagePath) {
920
+ this.logger.debug('Received message');
921
+ const sessionId = context.req.query('sessionId');
922
+ this.logger.debug('Received message for sessionId', { sessionId });
923
+ if (!sessionId) {
924
+ return context.text('No sessionId provided', 400);
925
+ }
926
+ if (!this.sseHonoTransports.has(sessionId)) {
927
+ return context.text(`No transport found for sessionId ${sessionId}`, 400);
928
+ }
929
+ const message = await this.sseHonoTransports.get(sessionId)?.handlePostMessage(context);
930
+ if (!message) {
931
+ return context.text('Transport not found', 400);
932
+ }
933
+ return message;
934
+ } else {
935
+ this.logger.debug('Unknown path:', { path: url.pathname });
936
+ return context.text('Unknown path', 404);
844
937
  }
845
- return message;
846
- } else {
847
- this.logger.debug('Unknown path:', { path: url.pathname });
848
- return context.text('Unknown path', 404);
938
+ } catch (e) {
939
+ const mastraError = new MastraError(
940
+ {
941
+ id: 'MCP_SERVER_HONO_SSE_START_FAILED',
942
+ domain: ErrorDomain.MCP,
943
+ category: ErrorCategory.USER,
944
+ details: {
945
+ url: url.toString(),
946
+ ssePath,
947
+ messagePath,
948
+ },
949
+ },
950
+ e,
951
+ );
952
+ this.logger.trackException(mastraError);
953
+ this.logger.error('Failed to start MCP Server (Hono SSE):', { error: mastraError.toString() });
954
+ throw mastraError;
849
955
  }
850
956
  }
851
957
 
@@ -1011,7 +1117,17 @@ export class MCPServer extends MCPServerBase {
1011
1117
  }
1012
1118
  }
1013
1119
  } catch (error) {
1014
- this.logger.error('startHTTP: Error handling Streamable HTTP request:', { error });
1120
+ const mastraError = new MastraError(
1121
+ {
1122
+ id: 'MCP_SERVER_HTTP_CONNECTION_FAILED',
1123
+ domain: ErrorDomain.MCP,
1124
+ category: ErrorCategory.USER,
1125
+ text: 'Failed to connect MCP server using HTTP transport',
1126
+ },
1127
+ error,
1128
+ );
1129
+ this.logger.trackException(mastraError);
1130
+ this.logger.error('startHTTP: Error handling Streamable HTTP request:', { error: mastraError });
1015
1131
  // If headers haven't been sent, send an error response
1016
1132
  if (!res.headersSent) {
1017
1133
  res.writeHead(500, { 'Content-Type': 'application/json' });
@@ -1025,9 +1141,6 @@ export class MCPServer extends MCPServerBase {
1025
1141
  id: null, // Cannot determine original request ID in catch
1026
1142
  }),
1027
1143
  );
1028
- } else {
1029
- // If headers were already sent (e.g., during SSE stream), just log the error
1030
- this.logger.error('startHTTP: Error after headers sent:', error);
1031
1144
  }
1032
1145
  }
1033
1146
  }
@@ -1039,18 +1152,35 @@ export class MCPServer extends MCPServerBase {
1039
1152
  messagePath: string;
1040
1153
  res: http.ServerResponse<http.IncomingMessage>;
1041
1154
  }) {
1042
- this.logger.debug('Received SSE connection');
1043
- this.sseTransport = new SSEServerTransport(messagePath, res);
1044
- await this.server.connect(this.sseTransport);
1155
+ try {
1156
+ this.logger.debug('Received SSE connection');
1157
+ this.sseTransport = new SSEServerTransport(messagePath, res);
1158
+ await this.server.connect(this.sseTransport);
1045
1159
 
1046
- this.server.onclose = async () => {
1047
- this.sseTransport = undefined;
1048
- await this.server.close();
1049
- };
1160
+ this.server.onclose = async () => {
1161
+ this.sseTransport = undefined;
1162
+ await this.server.close();
1163
+ };
1050
1164
 
1051
- res.on('close', () => {
1052
- this.sseTransport = undefined;
1053
- });
1165
+ res.on('close', () => {
1166
+ this.sseTransport = undefined;
1167
+ });
1168
+ } catch (e) {
1169
+ const mastraError = new MastraError(
1170
+ {
1171
+ id: 'MCP_SERVER_SSE_CONNECT_FAILED',
1172
+ domain: ErrorDomain.MCP,
1173
+ category: ErrorCategory.USER,
1174
+ details: {
1175
+ messagePath,
1176
+ },
1177
+ },
1178
+ e,
1179
+ );
1180
+ this.logger.trackException(mastraError);
1181
+ this.logger.error('Failed to connect to MCP Server (SSE):', { error: mastraError });
1182
+ throw mastraError;
1183
+ }
1054
1184
  }
1055
1185
 
1056
1186
  public async connectHonoSSE({ messagePath, stream }: { messagePath: string; stream: SSEStreamingApi }) {
@@ -1064,21 +1194,37 @@ export class MCPServer extends MCPServerBase {
1064
1194
  this.logger.debug('SSE Transport aborted with sessionId:', { sessionId });
1065
1195
  this.sseHonoTransports.delete(sessionId);
1066
1196
  });
1197
+ try {
1198
+ await this.server.connect(sseTransport);
1199
+ this.server.onclose = async () => {
1200
+ this.logger.debug('SSE Transport closed with sessionId:', { sessionId });
1201
+ this.sseHonoTransports.delete(sessionId);
1202
+ await this.server.close();
1203
+ };
1067
1204
 
1068
- await this.server.connect(sseTransport);
1069
- this.server.onclose = async () => {
1070
- this.logger.debug('SSE Transport closed with sessionId:', { sessionId });
1071
- this.sseHonoTransports.delete(sessionId);
1072
- await this.server.close();
1073
- };
1074
-
1075
- while (true) {
1076
- // This will keep the connection alive
1077
- // You can also await for a promise that never resolves
1078
- const sessionIds = Array.from(this.sseHonoTransports.keys() || []);
1079
- this.logger.debug('Active Hono SSE sessions:', { sessionIds });
1080
- await stream.write(':keep-alive\n\n');
1081
- await stream.sleep(60_000);
1205
+ while (true) {
1206
+ // This will keep the connection alive
1207
+ // You can also await for a promise that never resolves
1208
+ const sessionIds = Array.from(this.sseHonoTransports.keys() || []);
1209
+ this.logger.debug('Active Hono SSE sessions:', { sessionIds });
1210
+ await stream.write(':keep-alive\n\n');
1211
+ await stream.sleep(60_000);
1212
+ }
1213
+ } catch (e) {
1214
+ const mastraError = new MastraError(
1215
+ {
1216
+ id: 'MCP_SERVER_HONO_SSE_CONNECT_FAILED',
1217
+ domain: ErrorDomain.MCP,
1218
+ category: ErrorCategory.USER,
1219
+ details: {
1220
+ messagePath,
1221
+ },
1222
+ },
1223
+ e,
1224
+ );
1225
+ this.logger.trackException(mastraError);
1226
+ this.logger.error('Failed to connect to MCP Server (Hono SSE):', { error: mastraError });
1227
+ throw mastraError;
1082
1228
  }
1083
1229
  }
1084
1230
 
@@ -1119,7 +1265,17 @@ export class MCPServer extends MCPServerBase {
1119
1265
  await this.server.close();
1120
1266
  this.logger.info('MCP server closed.');
1121
1267
  } catch (error) {
1122
- this.logger.error('Error closing MCP server:', { error });
1268
+ const mastraError = new MastraError(
1269
+ {
1270
+ id: 'MCP_SERVER_CLOSE_FAILED',
1271
+ domain: ErrorDomain.MCP,
1272
+ category: ErrorCategory.THIRD_PARTY,
1273
+ },
1274
+ error,
1275
+ );
1276
+ this.logger.trackException(mastraError);
1277
+ this.logger.error('Error closing MCP server:', { error: mastraError });
1278
+ throw mastraError;
1123
1279
  }
1124
1280
  }
1125
1281
 
@@ -1160,7 +1316,7 @@ export class MCPServer extends MCPServerBase {
1160
1316
  * @returns An object containing an array of tool information.
1161
1317
  */
1162
1318
  public getToolListInfo(): {
1163
- tools: Array<{ name: string; description?: string; inputSchema: any; toolType?: MCPToolType }>;
1319
+ tools: Array<{ name: string; description?: string; inputSchema: any; outputSchema?: any; toolType?: MCPToolType }>;
1164
1320
  } {
1165
1321
  this.logger.debug(`Getting tool list information for MCPServer '${this.name}'`);
1166
1322
  return {
@@ -1169,6 +1325,7 @@ export class MCPServer extends MCPServerBase {
1169
1325
  name: tool.name,
1170
1326
  description: tool.description,
1171
1327
  inputSchema: tool.parameters?.jsonSchema || tool.parameters,
1328
+ outputSchema: tool.outputSchema?.jsonSchema || tool.outputSchema,
1172
1329
  toolType: tool.toolType,
1173
1330
  })),
1174
1331
  };
@@ -1181,7 +1338,7 @@ export class MCPServer extends MCPServerBase {
1181
1338
  */
1182
1339
  public getToolInfo(
1183
1340
  toolId: string,
1184
- ): { name: string; description?: string; inputSchema: any; toolType?: MCPToolType } | undefined {
1341
+ ): { name: string; description?: string; inputSchema: any; outputSchema?: any; toolType?: MCPToolType } | undefined {
1185
1342
  const tool = this.convertedTools[toolId];
1186
1343
  if (!tool) {
1187
1344
  this.logger.debug(`Tool '${toolId}' not found on MCPServer '${this.name}'`);
@@ -1192,6 +1349,7 @@ export class MCPServer extends MCPServerBase {
1192
1349
  name: tool.name,
1193
1350
  description: tool.description,
1194
1351
  inputSchema: tool.parameters?.jsonSchema || tool.parameters,
1352
+ outputSchema: tool.outputSchema?.jsonSchema || tool.outputSchema,
1195
1353
  toolType: tool.toolType,
1196
1354
  };
1197
1355
  }
@@ -1210,35 +1368,52 @@ export class MCPServer extends MCPServerBase {
1210
1368
  executionContext?: { messages?: any[]; toolCallId?: string },
1211
1369
  ): Promise<any> {
1212
1370
  const tool = this.convertedTools[toolId];
1213
- if (!tool) {
1214
- this.logger.warn(`ExecuteTool: Unknown tool '${toolId}' requested on MCPServer '${this.name}'.`);
1215
- throw new Error(`Unknown tool: ${toolId}`);
1216
- }
1371
+ let validatedArgs: any;
1372
+ try {
1373
+ if (!tool) {
1374
+ this.logger.warn(`ExecuteTool: Unknown tool '${toolId}' requested on MCPServer '${this.name}'.`);
1375
+ throw new Error(`Unknown tool: ${toolId}`);
1376
+ }
1217
1377
 
1218
- this.logger.debug(`ExecuteTool: Invoking '${toolId}' with arguments:`, args);
1219
-
1220
- let validatedArgs = args;
1221
- if (tool.parameters instanceof z.ZodType && typeof tool.parameters.safeParse === 'function') {
1222
- const validation = tool.parameters.safeParse(args ?? {});
1223
- if (!validation.success) {
1224
- const errorMessages = validation.error.errors
1225
- .map((e: z.ZodIssue) => `${e.path.join('.')}: ${e.message}`)
1226
- .join(', ');
1227
- this.logger.warn(`ExecuteTool: Invalid tool arguments for '${toolId}': ${errorMessages}`, {
1228
- errors: validation.error.format(),
1229
- });
1230
- throw new z.ZodError(validation.error.issues);
1378
+ this.logger.debug(`ExecuteTool: Invoking '${toolId}' with arguments:`, args);
1379
+
1380
+ if (tool.parameters instanceof z.ZodType && typeof tool.parameters.safeParse === 'function') {
1381
+ const validation = tool.parameters.safeParse(args ?? {});
1382
+ if (!validation.success) {
1383
+ const errorMessages = validation.error.errors
1384
+ .map((e: z.ZodIssue) => `${e.path.join('.')}: ${e.message}`)
1385
+ .join(', ');
1386
+ this.logger.warn(`ExecuteTool: Invalid tool arguments for '${toolId}': ${errorMessages}`, {
1387
+ errors: validation.error.format(),
1388
+ });
1389
+ throw new z.ZodError(validation.error.issues);
1390
+ }
1391
+ validatedArgs = validation.data;
1392
+ } else {
1393
+ this.logger.debug(
1394
+ `ExecuteTool: Tool '${toolId}' parameters is not a Zod schema with safeParse or is undefined. Skipping validation.`,
1395
+ );
1231
1396
  }
1232
- validatedArgs = validation.data;
1233
- } else {
1234
- this.logger.debug(
1235
- `ExecuteTool: Tool '${toolId}' parameters is not a Zod schema with safeParse or is undefined. Skipping validation.`,
1236
- );
1237
- }
1238
1397
 
1239
- if (!tool.execute) {
1240
- this.logger.error(`ExecuteTool: Tool '${toolId}' does not have an execute function.`);
1241
- throw new Error(`Tool '${toolId}' cannot be executed.`);
1398
+ if (!tool.execute) {
1399
+ this.logger.error(`ExecuteTool: Tool '${toolId}' does not have an execute function.`);
1400
+ throw new Error(`Tool '${toolId}' cannot be executed.`);
1401
+ }
1402
+ } catch (error) {
1403
+ const mastraError = new MastraError(
1404
+ {
1405
+ id: 'MCP_SERVER_TOOL_EXECUTE_PREPARATION_FAILED',
1406
+ domain: ErrorDomain.MCP,
1407
+ category: ErrorCategory.USER,
1408
+ details: {
1409
+ toolId,
1410
+ args,
1411
+ },
1412
+ },
1413
+ error,
1414
+ );
1415
+ this.logger.trackException(mastraError);
1416
+ throw mastraError;
1242
1417
  }
1243
1418
 
1244
1419
  try {
@@ -1250,8 +1425,21 @@ export class MCPServer extends MCPServerBase {
1250
1425
  this.logger.info(`ExecuteTool: Tool '${toolId}' executed successfully.`);
1251
1426
  return result;
1252
1427
  } catch (error) {
1428
+ const mastraError = new MastraError(
1429
+ {
1430
+ id: 'MCP_SERVER_TOOL_EXECUTE_FAILED',
1431
+ domain: ErrorDomain.MCP,
1432
+ category: ErrorCategory.USER,
1433
+ details: {
1434
+ toolId,
1435
+ validatedArgs: validatedArgs,
1436
+ },
1437
+ },
1438
+ error,
1439
+ );
1440
+ this.logger.trackException(mastraError);
1253
1441
  this.logger.error(`ExecuteTool: Tool execution failed for '${toolId}':`, { error });
1254
- throw error instanceof Error ? error : new Error(`Execution of tool '${toolId}' failed: ${String(error)}`);
1442
+ throw mastraError;
1255
1443
  }
1256
1444
  }
1257
1445
  }
@@ -1,21 +0,0 @@
1
- #!/bin/sh
2
- basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
3
-
4
- case `uname` in
5
- *CYGWIN*|*MINGW*|*MSYS*)
6
- if command -v cygpath > /dev/null 2>&1; then
7
- basedir=`cygpath -w "$basedir"`
8
- fi
9
- ;;
10
- esac
11
-
12
- if [ -z "$NODE_PATH" ]; then
13
- export NODE_PATH="/home/runner/work/mastra/mastra/packages/cli/dist/node_modules:/home/runner/work/mastra/mastra/packages/cli/node_modules:/home/runner/work/mastra/mastra/packages/node_modules:/home/runner/work/mastra/mastra/node_modules:/home/runner/work/mastra/node_modules:/home/runner/work/node_modules:/home/runner/node_modules:/home/node_modules:/node_modules:/home/runner/work/mastra/mastra/node_modules/.pnpm/node_modules"
14
- else
15
- export NODE_PATH="/home/runner/work/mastra/mastra/packages/cli/dist/node_modules:/home/runner/work/mastra/mastra/packages/cli/node_modules:/home/runner/work/mastra/mastra/packages/node_modules:/home/runner/work/mastra/mastra/node_modules:/home/runner/work/mastra/node_modules:/home/runner/work/node_modules:/home/runner/node_modules:/home/node_modules:/node_modules:/home/runner/work/mastra/mastra/node_modules/.pnpm/node_modules:$NODE_PATH"
16
- fi
17
- if [ -x "$basedir/node" ]; then
18
- exec "$basedir/node" "$basedir/../mastra/dist/index.js" "$@"
19
- else
20
- exec node "$basedir/../mastra/dist/index.js" "$@"
21
- fi