@mastra/mcp 0.10.5-alpha.0 → 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.cjs CHANGED
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var base = require('@mastra/core/base');
4
+ var error = require('@mastra/core/error');
4
5
  var tools = require('@mastra/core/tools');
5
6
  var utils = require('@mastra/core/utils');
6
7
  var index_js$1 = require('@modelcontextprotocol/sdk/client/index.js');
@@ -12,7 +13,6 @@ var types_js = require('@modelcontextprotocol/sdk/types.js');
12
13
  var exitHook = require('exit-hook');
13
14
  var zod = require('zod');
14
15
  var zodFromJsonSchema = require('zod-from-json-schema');
15
- var error = require('@mastra/core/error');
16
16
  var equal = require('fast-deep-equal');
17
17
  var uuid = require('uuid');
18
18
  var crypto$1 = require('crypto');
@@ -23,7 +23,6 @@ var index_js = require('@modelcontextprotocol/sdk/server/index.js');
23
23
  var sse_js = require('@modelcontextprotocol/sdk/server/sse.js');
24
24
  var stdio_js = require('@modelcontextprotocol/sdk/server/stdio.js');
25
25
  var streamableHttp_js = require('@modelcontextprotocol/sdk/server/streamableHttp.js');
26
- var streaming = require('hono/streaming');
27
26
 
28
27
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
29
28
 
@@ -484,22 +483,57 @@ var InternalMastraMCPClient = class extends base.MastraBase {
484
483
  }
485
484
  try {
486
485
  return zodFromJsonSchema.convertJsonSchemaToZod(inputSchema);
487
- } catch (error) {
486
+ } catch (error$1) {
488
487
  let errorDetails;
489
- if (error instanceof Error) {
490
- errorDetails = error.stack;
488
+ if (error$1 instanceof Error) {
489
+ errorDetails = error$1.stack;
491
490
  } else {
492
491
  try {
493
- errorDetails = JSON.stringify(error);
492
+ errorDetails = JSON.stringify(error$1);
494
493
  } catch {
495
- errorDetails = String(error);
494
+ errorDetails = String(error$1);
496
495
  }
497
496
  }
498
497
  this.log("error", "Failed to convert JSON schema to Zod schema using zodFromJsonSchema", {
499
498
  error: errorDetails,
500
499
  originalJsonSchema: inputSchema
501
500
  });
502
- throw new Error(errorDetails);
501
+ throw new error.MastraError({
502
+ id: "MCP_TOOL_INPUT_SCHEMA_CONVERSION_FAILED",
503
+ domain: error.ErrorDomain.MCP,
504
+ category: error.ErrorCategory.USER,
505
+ details: { error: errorDetails ?? "Unknown error" }
506
+ });
507
+ }
508
+ }
509
+ convertOutputSchema(outputSchema) {
510
+ if (!outputSchema) return;
511
+ if (utils.isZodType(outputSchema)) {
512
+ return outputSchema;
513
+ }
514
+ try {
515
+ return zodFromJsonSchema.convertJsonSchemaToZod(outputSchema);
516
+ } catch (error$1) {
517
+ let errorDetails;
518
+ if (error$1 instanceof Error) {
519
+ errorDetails = error$1.stack;
520
+ } else {
521
+ try {
522
+ errorDetails = JSON.stringify(error$1);
523
+ } catch {
524
+ errorDetails = String(error$1);
525
+ }
526
+ }
527
+ this.log("error", "Failed to convert JSON schema to Zod schema using zodFromJsonSchema", {
528
+ error: errorDetails,
529
+ originalJsonSchema: outputSchema
530
+ });
531
+ throw new error.MastraError({
532
+ id: "MCP_TOOL_OUTPUT_SCHEMA_CONVERSION_FAILED",
533
+ domain: error.ErrorDomain.MCP,
534
+ category: error.ErrorCategory.USER,
535
+ details: { error: errorDetails ?? "Unknown error" }
536
+ });
503
537
  }
504
538
  }
505
539
  async tools() {
@@ -513,6 +547,7 @@ var InternalMastraMCPClient = class extends base.MastraBase {
513
547
  id: `${this.name}_${tool.name}`,
514
548
  description: tool.description || "",
515
549
  inputSchema: this.convertInputSchema(tool.inputSchema),
550
+ outputSchema: this.convertOutputSchema(tool.outputSchema),
516
551
  execute: async ({ context, runtimeContext }) => {
517
552
  const previousContext = this.currentOperationContext;
518
553
  this.currentOperationContext = runtimeContext || null;
@@ -935,6 +970,165 @@ var MCPConfiguration = class extends MCPClient {
935
970
  );
936
971
  }
937
972
  };
973
+
974
+ // ../../node_modules/.pnpm/hono@4.8.1/node_modules/hono/dist/utils/stream.js
975
+ var StreamingApi = class {
976
+ writer;
977
+ encoder;
978
+ writable;
979
+ abortSubscribers = [];
980
+ responseReadable;
981
+ aborted = false;
982
+ closed = false;
983
+ constructor(writable, _readable) {
984
+ this.writable = writable;
985
+ this.writer = writable.getWriter();
986
+ this.encoder = new TextEncoder();
987
+ const reader = _readable.getReader();
988
+ this.abortSubscribers.push(async () => {
989
+ await reader.cancel();
990
+ });
991
+ this.responseReadable = new ReadableStream({
992
+ async pull(controller) {
993
+ const { done, value } = await reader.read();
994
+ done ? controller.close() : controller.enqueue(value);
995
+ },
996
+ cancel: () => {
997
+ this.abort();
998
+ }
999
+ });
1000
+ }
1001
+ async write(input) {
1002
+ try {
1003
+ if (typeof input === "string") {
1004
+ input = this.encoder.encode(input);
1005
+ }
1006
+ await this.writer.write(input);
1007
+ } catch {
1008
+ }
1009
+ return this;
1010
+ }
1011
+ async writeln(input) {
1012
+ await this.write(input + "\n");
1013
+ return this;
1014
+ }
1015
+ sleep(ms) {
1016
+ return new Promise((res) => setTimeout(res, ms));
1017
+ }
1018
+ async close() {
1019
+ try {
1020
+ await this.writer.close();
1021
+ } catch {
1022
+ }
1023
+ this.closed = true;
1024
+ }
1025
+ async pipe(body) {
1026
+ this.writer.releaseLock();
1027
+ await body.pipeTo(this.writable, { preventClose: true });
1028
+ this.writer = this.writable.getWriter();
1029
+ }
1030
+ onAbort(listener) {
1031
+ this.abortSubscribers.push(listener);
1032
+ }
1033
+ abort() {
1034
+ if (!this.aborted) {
1035
+ this.aborted = true;
1036
+ this.abortSubscribers.forEach((subscriber) => subscriber());
1037
+ }
1038
+ }
1039
+ };
1040
+
1041
+ // ../../node_modules/.pnpm/hono@4.8.1/node_modules/hono/dist/helper/streaming/utils.js
1042
+ var isOldBunVersion = () => {
1043
+ const version = typeof Bun !== "undefined" ? Bun.version : void 0;
1044
+ if (version === void 0) {
1045
+ return false;
1046
+ }
1047
+ const result = version.startsWith("1.1") || version.startsWith("1.0") || version.startsWith("0.");
1048
+ isOldBunVersion = () => result;
1049
+ return result;
1050
+ };
1051
+
1052
+ // ../../node_modules/.pnpm/hono@4.8.1/node_modules/hono/dist/utils/html.js
1053
+ var HtmlEscapedCallbackPhase = {
1054
+ Stringify: 1};
1055
+ var resolveCallback = async (str, phase, preserveCallbacks, context, buffer) => {
1056
+ if (typeof str === "object" && !(str instanceof String)) {
1057
+ if (!(str instanceof Promise)) {
1058
+ str = str.toString();
1059
+ }
1060
+ if (str instanceof Promise) {
1061
+ str = await str;
1062
+ }
1063
+ }
1064
+ const callbacks = str.callbacks;
1065
+ if (!callbacks?.length) {
1066
+ return Promise.resolve(str);
1067
+ }
1068
+ if (buffer) {
1069
+ buffer[0] += str;
1070
+ } else {
1071
+ buffer = [str];
1072
+ }
1073
+ const resStr = Promise.all(callbacks.map((c) => c({ phase, buffer, context }))).then(
1074
+ (res) => Promise.all(
1075
+ res.filter(Boolean).map((str2) => resolveCallback(str2, phase, false, context, buffer))
1076
+ ).then(() => buffer[0])
1077
+ );
1078
+ {
1079
+ return resStr;
1080
+ }
1081
+ };
1082
+
1083
+ // ../../node_modules/.pnpm/hono@4.8.1/node_modules/hono/dist/helper/streaming/sse.js
1084
+ var SSEStreamingApi = class extends StreamingApi {
1085
+ constructor(writable, readable) {
1086
+ super(writable, readable);
1087
+ }
1088
+ async writeSSE(message) {
1089
+ const data = await resolveCallback(message.data, HtmlEscapedCallbackPhase.Stringify, false, {});
1090
+ const dataLines = data.split("\n").map((line) => {
1091
+ return `data: ${line}`;
1092
+ }).join("\n");
1093
+ const sseData = [
1094
+ message.event && `event: ${message.event}`,
1095
+ dataLines,
1096
+ message.id && `id: ${message.id}`,
1097
+ message.retry && `retry: ${message.retry}`
1098
+ ].filter(Boolean).join("\n") + "\n\n";
1099
+ await this.write(sseData);
1100
+ }
1101
+ };
1102
+ var run = async (stream2, cb, onError) => {
1103
+ try {
1104
+ await cb(stream2);
1105
+ } catch (e) {
1106
+ {
1107
+ console.error(e);
1108
+ }
1109
+ } finally {
1110
+ stream2.close();
1111
+ }
1112
+ };
1113
+ var contextStash = /* @__PURE__ */ new WeakMap();
1114
+ var streamSSE = (c, cb, onError) => {
1115
+ const { readable, writable } = new TransformStream();
1116
+ const stream2 = new SSEStreamingApi(writable, readable);
1117
+ if (isOldBunVersion()) {
1118
+ c.req.raw.signal.addEventListener("abort", () => {
1119
+ if (!stream2.closed) {
1120
+ stream2.abort();
1121
+ }
1122
+ });
1123
+ }
1124
+ contextStash.set(stream2.responseReadable, c);
1125
+ c.header("Transfer-Encoding", "chunked");
1126
+ c.header("Content-Type", "text/event-stream");
1127
+ c.header("Cache-Control", "no-cache");
1128
+ c.header("Connection", "keep-alive");
1129
+ run(stream2, cb);
1130
+ return c.newResponse(stream2.responseReadable);
1131
+ };
938
1132
  var MAXIMUM_MESSAGE_SIZE = 4 * 1024 * 1024;
939
1133
  var SSETransport = class {
940
1134
  messageUrl;
@@ -946,9 +1140,9 @@ var SSETransport = class {
946
1140
  /**
947
1141
  * Creates a new SSETransport, which will direct the MPC client to POST messages to messageUrl
948
1142
  */
949
- constructor(messageUrl, stream) {
1143
+ constructor(messageUrl, stream2) {
950
1144
  this.messageUrl = messageUrl;
951
- this.stream = stream;
1145
+ this.stream = stream2;
952
1146
  this._sessionId = crypto.randomUUID();
953
1147
  this.stream.onAbort(() => {
954
1148
  void this.close();
@@ -965,6 +1159,10 @@ var SSETransport = class {
965
1159
  if (this.stream.closed) {
966
1160
  throw new Error("SSE transport already closed!");
967
1161
  }
1162
+ await this.stream.writeSSE({
1163
+ event: "ping",
1164
+ data: ""
1165
+ });
968
1166
  await this.stream.writeSSE({
969
1167
  event: "endpoint",
970
1168
  data: `${this.messageUrl}?sessionId=${this.sessionId}`
@@ -1336,8 +1534,8 @@ var MCPServer = class extends mcp.MCPServerBase {
1336
1534
  context
1337
1535
  );
1338
1536
  try {
1339
- const run = workflow.createRun({ runId: runtimeContext?.get("runId") });
1340
- const response = await run.start({ inputData: context, runtimeContext });
1537
+ const run2 = workflow.createRun({ runId: runtimeContext?.get("runId") });
1538
+ const response = await run2.start({ inputData: context, runtimeContext });
1341
1539
  return response;
1342
1540
  } catch (error) {
1343
1541
  this.logger.error(
@@ -1360,6 +1558,7 @@ var MCPServer = class extends mcp.MCPServerBase {
1360
1558
  name: workflowToolName,
1361
1559
  description: coreTool.description,
1362
1560
  parameters: coreTool.parameters,
1561
+ outputSchema: coreTool.outputSchema,
1363
1562
  execute: coreTool.execute,
1364
1563
  toolType: "workflow"
1365
1564
  };
@@ -1399,6 +1598,7 @@ var MCPServer = class extends mcp.MCPServerBase {
1399
1598
  name: toolName,
1400
1599
  description: coreTool.description,
1401
1600
  parameters: coreTool.parameters,
1601
+ outputSchema: coreTool.outputSchema,
1402
1602
  execute: coreTool.execute
1403
1603
  };
1404
1604
  this.logger.info(`Registered explicit tool: '${toolName}'`);
@@ -1445,11 +1645,17 @@ var MCPServer = class extends mcp.MCPServerBase {
1445
1645
  this.server.setRequestHandler(types_js.ListToolsRequestSchema, async () => {
1446
1646
  this.logger.debug("Handling ListTools request");
1447
1647
  return {
1448
- tools: Object.values(this.convertedTools).map((tool) => ({
1449
- name: tool.name,
1450
- description: tool.description,
1451
- inputSchema: tool.parameters.jsonSchema
1452
- }))
1648
+ tools: Object.values(this.convertedTools).map((tool) => {
1649
+ const toolSpec = {
1650
+ name: tool.name,
1651
+ description: tool.description,
1652
+ inputSchema: tool.parameters.jsonSchema
1653
+ };
1654
+ if (tool.outputSchema) {
1655
+ toolSpec.outputSchema = tool.outputSchema.jsonSchema;
1656
+ }
1657
+ return toolSpec;
1658
+ })
1453
1659
  };
1454
1660
  });
1455
1661
  }
@@ -1472,7 +1678,6 @@ var MCPServer = class extends mcp.MCPServerBase {
1472
1678
  isError: true
1473
1679
  };
1474
1680
  }
1475
- this.logger.debug(`CallTool: Invoking '${request.params.name}' with arguments:`, request.params.arguments);
1476
1681
  const validation = tool.parameters.validate?.(request.params.arguments ?? {});
1477
1682
  if (validation && !validation.success) {
1478
1683
  this.logger.warn(`CallTool: Invalid tool arguments for '${request.params.name}'`, {
@@ -1491,17 +1696,38 @@ var MCPServer = class extends mcp.MCPServerBase {
1491
1696
  };
1492
1697
  }
1493
1698
  const result = await tool.execute(validation?.value, { messages: [], toolCallId: "" });
1699
+ this.logger.debug(`CallTool: Tool '${request.params.name}' executed successfully with result:`, result);
1494
1700
  const duration = Date.now() - startTime;
1495
1701
  this.logger.info(`Tool '${request.params.name}' executed successfully in ${duration}ms.`);
1496
- return {
1497
- content: [
1702
+ const response = { isError: false, content: [] };
1703
+ if (tool.outputSchema) {
1704
+ if (!result.structuredContent) {
1705
+ throw new Error(`Tool ${request.params.name} has an output schema but no structured content was provided.`);
1706
+ }
1707
+ const outputValidation = tool.outputSchema.validate?.(result.structuredContent ?? {});
1708
+ if (outputValidation && !outputValidation.success) {
1709
+ this.logger.warn(`CallTool: Invalid structured content for '${request.params.name}'`, {
1710
+ errors: outputValidation.error
1711
+ });
1712
+ throw new Error(
1713
+ `Invalid structured content for tool ${request.params.name}: ${JSON.stringify(outputValidation.error)}`
1714
+ );
1715
+ }
1716
+ response.structuredContent = result.structuredContent;
1717
+ }
1718
+ if (result.content) {
1719
+ response.content = result.content;
1720
+ } else if (response.structuredContent) {
1721
+ response.content = [{ type: "text", text: JSON.stringify(response.structuredContent) }];
1722
+ } else {
1723
+ response.content = [
1498
1724
  {
1499
1725
  type: "text",
1500
1726
  text: typeof result === "string" ? result : JSON.stringify(result)
1501
1727
  }
1502
- ],
1503
- isError: false
1504
- };
1728
+ ];
1729
+ }
1730
+ return response;
1505
1731
  } catch (error) {
1506
1732
  const duration = Date.now() - startTime;
1507
1733
  if (error instanceof zod.z.ZodError) {
@@ -1855,10 +2081,10 @@ var MCPServer = class extends mcp.MCPServerBase {
1855
2081
  async startHonoSSE({ url, ssePath, messagePath, context }) {
1856
2082
  try {
1857
2083
  if (url.pathname === ssePath) {
1858
- return streaming.streamSSE(context, async (stream) => {
2084
+ return streamSSE(context, async (stream2) => {
1859
2085
  await this.connectHonoSSE({
1860
2086
  messagePath,
1861
- stream
2087
+ stream: stream2
1862
2088
  });
1863
2089
  });
1864
2090
  } else if (url.pathname === messagePath) {
@@ -2084,13 +2310,13 @@ var MCPServer = class extends mcp.MCPServerBase {
2084
2310
  throw mastraError;
2085
2311
  }
2086
2312
  }
2087
- async connectHonoSSE({ messagePath, stream }) {
2313
+ async connectHonoSSE({ messagePath, stream: stream2 }) {
2088
2314
  this.logger.debug("Received SSE connection");
2089
- const sseTransport = new SSETransport(messagePath, stream);
2315
+ const sseTransport = new SSETransport(messagePath, stream2);
2090
2316
  const sessionId = sseTransport.sessionId;
2091
2317
  this.logger.debug("SSE Transport created with sessionId:", { sessionId });
2092
2318
  this.sseHonoTransports.set(sessionId, sseTransport);
2093
- stream.onAbort(() => {
2319
+ stream2.onAbort(() => {
2094
2320
  this.logger.debug("SSE Transport aborted with sessionId:", { sessionId });
2095
2321
  this.sseHonoTransports.delete(sessionId);
2096
2322
  });
@@ -2104,8 +2330,8 @@ var MCPServer = class extends mcp.MCPServerBase {
2104
2330
  while (true) {
2105
2331
  const sessionIds = Array.from(this.sseHonoTransports.keys() || []);
2106
2332
  this.logger.debug("Active Hono SSE sessions:", { sessionIds });
2107
- await stream.write(":keep-alive\n\n");
2108
- await stream.sleep(6e4);
2333
+ await stream2.write(":keep-alive\n\n");
2334
+ await stream2.sleep(6e4);
2109
2335
  }
2110
2336
  } catch (e) {
2111
2337
  const mastraError = new error.MastraError(
@@ -2214,6 +2440,7 @@ var MCPServer = class extends mcp.MCPServerBase {
2214
2440
  name: tool.name,
2215
2441
  description: tool.description,
2216
2442
  inputSchema: tool.parameters?.jsonSchema || tool.parameters,
2443
+ outputSchema: tool.outputSchema?.jsonSchema || tool.outputSchema,
2217
2444
  toolType: tool.toolType
2218
2445
  }))
2219
2446
  };
@@ -2234,6 +2461,7 @@ var MCPServer = class extends mcp.MCPServerBase {
2234
2461
  name: tool.name,
2235
2462
  description: tool.description,
2236
2463
  inputSchema: tool.parameters?.jsonSchema || tool.parameters,
2464
+ outputSchema: tool.outputSchema?.jsonSchema || tool.outputSchema,
2237
2465
  toolType: tool.toolType
2238
2466
  };
2239
2467
  }