@mastra/mcp 1.0.0-beta.2 → 1.0.0-beta.4

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,38 +1,38 @@
1
1
  'use strict';
2
2
 
3
+ var $RefParser = require('@apidevtools/json-schema-ref-parser');
3
4
  var base = require('@mastra/core/base');
4
5
  var error = require('@mastra/core/error');
5
- var protocol_js = require('@modelcontextprotocol/sdk/shared/protocol.js');
6
- var equal = require('fast-deep-equal');
7
- var uuid = require('uuid');
8
- var $RefParser = require('@apidevtools/json-schema-ref-parser');
9
6
  var tools = require('@mastra/core/tools');
10
7
  var utils = require('@mastra/core/utils');
11
- var index_js$1 = require('@modelcontextprotocol/sdk/client/index.js');
12
- var sse_js$1 = require('@modelcontextprotocol/sdk/client/sse.js');
13
- var stdio_js$1 = require('@modelcontextprotocol/sdk/client/stdio.js');
14
- var streamableHttp_js$1 = require('@modelcontextprotocol/sdk/client/streamableHttp.js');
8
+ var index_js = require('@modelcontextprotocol/sdk/client/index.js');
9
+ var sse_js = require('@modelcontextprotocol/sdk/client/sse.js');
10
+ var stdio_js = require('@modelcontextprotocol/sdk/client/stdio.js');
11
+ var streamableHttp_js = require('@modelcontextprotocol/sdk/client/streamableHttp.js');
12
+ var protocol_js = require('@modelcontextprotocol/sdk/shared/protocol.js');
15
13
  var types_js = require('@modelcontextprotocol/sdk/types.js');
16
14
  var exitHook = require('exit-hook');
17
15
  var zod = require('zod');
18
16
  var zodFromJsonSchema = require('zod-from-json-schema');
19
17
  var zodFromJsonSchemaV3 = require('zod-from-json-schema-v3');
18
+ var equal = require('fast-deep-equal');
19
+ var uuid = require('uuid');
20
20
  var crypto$1 = require('crypto');
21
21
  var mcp = require('@mastra/core/mcp');
22
22
  var requestContext = require('@mastra/core/request-context');
23
- var index_js = require('@modelcontextprotocol/sdk/server/index.js');
24
- var sse_js = require('@modelcontextprotocol/sdk/server/sse.js');
25
- var stdio_js = require('@modelcontextprotocol/sdk/server/stdio.js');
26
- var streamableHttp_js = require('@modelcontextprotocol/sdk/server/streamableHttp.js');
23
+ var index_js$1 = require('@modelcontextprotocol/sdk/server/index.js');
24
+ var sse_js$1 = require('@modelcontextprotocol/sdk/server/sse.js');
25
+ var stdio_js$1 = require('@modelcontextprotocol/sdk/server/stdio.js');
26
+ var streamableHttp_js$1 = require('@modelcontextprotocol/sdk/server/streamableHttp.js');
27
27
 
28
28
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
29
29
 
30
- var equal__default = /*#__PURE__*/_interopDefault(equal);
31
30
  var $RefParser__default = /*#__PURE__*/_interopDefault($RefParser);
31
+ var equal__default = /*#__PURE__*/_interopDefault(equal);
32
32
 
33
- // src/client/configuration.ts
33
+ // src/client/client.ts
34
34
 
35
- // src/client/elicitationActions.ts
35
+ // src/client/actions/elicitation.ts
36
36
  var ElicitationClientActions = class {
37
37
  client;
38
38
  logger;
@@ -85,6 +85,23 @@ var ElicitationClientActions = class {
85
85
  this.client.setElicitationRequestHandler(handler);
86
86
  }
87
87
  };
88
+
89
+ // src/client/actions/progress.ts
90
+ var ProgressClientActions = class {
91
+ client;
92
+ logger;
93
+ constructor({ client, logger }) {
94
+ this.client = client;
95
+ this.logger = logger;
96
+ }
97
+ /**
98
+ * Set a notification handler for progress updates.
99
+ * @param handler The callback function to handle progress notifications.
100
+ */
101
+ onUpdate(handler) {
102
+ this.client.setProgressNotificationHandler(handler);
103
+ }
104
+ };
88
105
  var PromptClientActions = class {
89
106
  client;
90
107
  logger;
@@ -398,15 +415,21 @@ var InternalMastraMCPClient = class extends base.MastraBase {
398
415
  timeout;
399
416
  logHandler;
400
417
  enableServerLogs;
418
+ enableProgressTracking;
401
419
  serverConfig;
402
420
  transport;
403
421
  currentOperationContext = null;
422
+ exitHookUnsubscribe;
423
+ sigTermHandler;
424
+ _roots;
404
425
  /** Provides access to resource operations (list, read, subscribe, etc.) */
405
426
  resources;
406
427
  /** Provides access to prompt operations (list, get, notifications) */
407
428
  prompts;
408
429
  /** Provides access to elicitation operations (request handling) */
409
430
  elicitation;
431
+ /** Provides access to progress operations (notifications) */
432
+ progress;
410
433
  /**
411
434
  * @internal
412
435
  */
@@ -423,8 +446,16 @@ var InternalMastraMCPClient = class extends base.MastraBase {
423
446
  this.logHandler = server.logger;
424
447
  this.enableServerLogs = server.enableServerLogs ?? true;
425
448
  this.serverConfig = server;
426
- const clientCapabilities = { ...capabilities, elicitation: {} };
427
- this.client = new index_js$1.Client(
449
+ this.enableProgressTracking = !!server.enableProgressTracking;
450
+ this._roots = server.roots ?? [];
451
+ const hasRoots = this._roots.length > 0 || !!capabilities.roots;
452
+ const clientCapabilities = {
453
+ ...capabilities,
454
+ elicitation: {},
455
+ // Auto-enable roots capability if roots are provided
456
+ ...hasRoots ? { roots: { listChanged: true, ...capabilities.roots ?? {} } } : {}
457
+ };
458
+ this.client = new index_js.Client(
428
459
  {
429
460
  name,
430
461
  version
@@ -434,9 +465,13 @@ var InternalMastraMCPClient = class extends base.MastraBase {
434
465
  }
435
466
  );
436
467
  this.setupLogging();
468
+ if (hasRoots) {
469
+ this.setupRootsHandler();
470
+ }
437
471
  this.resources = new ResourceClientActions({ client: this, logger: this.logger });
438
472
  this.prompts = new PromptClientActions({ client: this, logger: this.logger });
439
473
  this.elicitation = new ElicitationClientActions({ client: this, logger: this.logger });
474
+ this.progress = new ProgressClientActions({ client: this, logger: this.logger });
440
475
  }
441
476
  /**
442
477
  * Log a message at the specified level
@@ -475,13 +510,70 @@ var InternalMastraMCPClient = class extends base.MastraBase {
475
510
  );
476
511
  }
477
512
  }
513
+ /**
514
+ * Set up handler for roots/list requests from the server.
515
+ *
516
+ * Per MCP spec (https://modelcontextprotocol.io/specification/2025-11-25/client/roots):
517
+ * When a server sends a roots/list request, the client responds with the configured roots.
518
+ */
519
+ setupRootsHandler() {
520
+ this.log("debug", "Setting up roots/list request handler");
521
+ this.client.setRequestHandler(types_js.ListRootsRequestSchema, async () => {
522
+ this.log("debug", `Responding to roots/list request with ${this._roots.length} roots`);
523
+ return { roots: this._roots };
524
+ });
525
+ }
526
+ /**
527
+ * Get the currently configured roots.
528
+ *
529
+ * @returns Array of configured filesystem roots
530
+ */
531
+ get roots() {
532
+ return [...this._roots];
533
+ }
534
+ /**
535
+ * Update the list of filesystem roots and notify the server.
536
+ *
537
+ * Per MCP spec, when roots change, the client sends a `notifications/roots/list_changed`
538
+ * notification to inform the server that it should re-fetch the roots list.
539
+ *
540
+ * @param roots - New list of filesystem roots
541
+ *
542
+ * @example
543
+ * ```typescript
544
+ * await client.setRoots([
545
+ * { uri: 'file:///home/user/projects', name: 'Projects' },
546
+ * { uri: 'file:///tmp', name: 'Temp' }
547
+ * ]);
548
+ * ```
549
+ */
550
+ async setRoots(roots) {
551
+ this.log("debug", `Updating roots to ${roots.length} entries`);
552
+ this._roots = [...roots];
553
+ await this.sendRootsListChanged();
554
+ }
555
+ /**
556
+ * Send a roots/list_changed notification to the server.
557
+ *
558
+ * Per MCP spec, clients that support `listChanged` MUST send this notification
559
+ * when the list of roots changes. The server will then call roots/list to get
560
+ * the updated list.
561
+ */
562
+ async sendRootsListChanged() {
563
+ if (!this.transport) {
564
+ this.log("debug", "Cannot send roots/list_changed: not connected");
565
+ return;
566
+ }
567
+ this.log("debug", "Sending notifications/roots/list_changed");
568
+ await this.client.notification({ method: "notifications/roots/list_changed" });
569
+ }
478
570
  async connectStdio(command) {
479
571
  this.log("debug", `Using Stdio transport for command: ${command}`);
480
572
  try {
481
- this.transport = new stdio_js$1.StdioClientTransport({
573
+ this.transport = new stdio_js.StdioClientTransport({
482
574
  command,
483
575
  args: this.serverConfig.args,
484
- env: { ...stdio_js$1.getDefaultEnvironment(), ...this.serverConfig.env || {} }
576
+ env: { ...stdio_js.getDefaultEnvironment(), ...this.serverConfig.env || {} }
485
577
  });
486
578
  await this.client.connect(this.transport, { timeout: this.serverConfig.timeout ?? this.timeout });
487
579
  this.log("debug", `Successfully connected to MCP server via Stdio`);
@@ -497,7 +589,7 @@ var InternalMastraMCPClient = class extends base.MastraBase {
497
589
  if (!shouldTrySSE) {
498
590
  try {
499
591
  this.log("debug", "Trying Streamable HTTP transport...");
500
- const streamableTransport = new streamableHttp_js$1.StreamableHTTPClientTransport(url, {
592
+ const streamableTransport = new streamableHttp_js.StreamableHTTPClientTransport(url, {
501
593
  requestInit,
502
594
  reconnectionOptions: this.serverConfig.reconnectionOptions,
503
595
  authProvider
@@ -515,7 +607,7 @@ var InternalMastraMCPClient = class extends base.MastraBase {
515
607
  if (shouldTrySSE) {
516
608
  this.log("debug", "Falling back to deprecated HTTP+SSE transport...");
517
609
  try {
518
- const sseTransport = new sse_js$1.SSEClientTransport(url, { requestInit, eventSourceInit, authProvider });
610
+ const sseTransport = new sse_js.SSEClientTransport(url, { requestInit, eventSourceInit, authProvider });
519
611
  await this.client.connect(sseTransport, { timeout: this.serverConfig.timeout ?? this.timeout });
520
612
  this.transport = sseTransport;
521
613
  this.log("debug", "Successfully connected using deprecated HTTP+SSE transport.");
@@ -568,14 +660,19 @@ var InternalMastraMCPClient = class extends base.MastraBase {
568
660
  reject(e);
569
661
  }
570
662
  });
571
- exitHook.asyncExitHook(
572
- async () => {
573
- this.log("debug", `Disconnecting MCP server during exit`);
574
- await this.disconnect();
575
- },
576
- { wait: 5e3 }
577
- );
578
- process.on("SIGTERM", () => exitHook.gracefulExit());
663
+ if (!this.exitHookUnsubscribe) {
664
+ this.exitHookUnsubscribe = exitHook.asyncExitHook(
665
+ async () => {
666
+ this.log("debug", `Disconnecting MCP server during exit`);
667
+ await this.disconnect();
668
+ },
669
+ { wait: 5e3 }
670
+ );
671
+ }
672
+ if (!this.sigTermHandler) {
673
+ this.sigTermHandler = () => exitHook.gracefulExit();
674
+ process.on("SIGTERM", this.sigTermHandler);
675
+ }
579
676
  this.log("debug", `Successfully connected to MCP server`);
580
677
  return this.isConnected;
581
678
  }
@@ -589,7 +686,7 @@ var InternalMastraMCPClient = class extends base.MastraBase {
589
686
  * @internal
590
687
  */
591
688
  get sessionId() {
592
- if (this.transport instanceof streamableHttp_js$1.StreamableHTTPClientTransport) {
689
+ if (this.transport instanceof streamableHttp_js.StreamableHTTPClientTransport) {
593
690
  return this.transport.sessionId;
594
691
  }
595
692
  return void 0;
@@ -610,8 +707,63 @@ var InternalMastraMCPClient = class extends base.MastraBase {
610
707
  throw e;
611
708
  } finally {
612
709
  this.transport = void 0;
613
- this.isConnected = Promise.resolve(false);
710
+ this.isConnected = null;
711
+ if (this.exitHookUnsubscribe) {
712
+ this.exitHookUnsubscribe();
713
+ this.exitHookUnsubscribe = void 0;
714
+ }
715
+ if (this.sigTermHandler) {
716
+ process.off("SIGTERM", this.sigTermHandler);
717
+ this.sigTermHandler = void 0;
718
+ }
719
+ }
720
+ }
721
+ /**
722
+ * Checks if an error indicates a session invalidation that requires reconnection.
723
+ *
724
+ * Common session-related errors include:
725
+ * - "No valid session ID provided" (HTTP 400)
726
+ * - "Server not initialized" (HTTP 400)
727
+ * - Connection refused errors
728
+ *
729
+ * @param error - The error to check
730
+ * @returns true if the error indicates a session problem requiring reconnection
731
+ *
732
+ * @internal
733
+ */
734
+ isSessionError(error) {
735
+ if (!(error instanceof Error)) {
736
+ return false;
737
+ }
738
+ const errorMessage = error.message.toLowerCase();
739
+ return errorMessage.includes("no valid session") || errorMessage.includes("session") || errorMessage.includes("server not initialized") || errorMessage.includes("http 400") || errorMessage.includes("http 401") || errorMessage.includes("http 403") || errorMessage.includes("econnrefused") || errorMessage.includes("fetch failed") || errorMessage.includes("connection refused");
740
+ }
741
+ /**
742
+ * Forces a reconnection to the MCP server by disconnecting and reconnecting.
743
+ *
744
+ * This is useful when the session becomes invalid (e.g., after server restart)
745
+ * and the client needs to establish a fresh connection.
746
+ *
747
+ * @returns Promise resolving when reconnection is complete
748
+ * @throws {Error} If reconnection fails
749
+ *
750
+ * @internal
751
+ */
752
+ async forceReconnect() {
753
+ this.log("debug", "Forcing reconnection to MCP server...");
754
+ try {
755
+ if (this.transport) {
756
+ await this.transport.close();
757
+ }
758
+ } catch (e) {
759
+ this.log("debug", "Error during force disconnect (ignored)", {
760
+ error: e instanceof Error ? e.message : String(e)
761
+ });
614
762
  }
763
+ this.transport = void 0;
764
+ this.isConnected = null;
765
+ await this.connect();
766
+ this.log("debug", "Successfully reconnected to MCP server");
615
767
  }
616
768
  async listResources() {
617
769
  this.log("debug", `Requesting resources from MCP server`);
@@ -699,6 +851,12 @@ var InternalMastraMCPClient = class extends base.MastraBase {
699
851
  return handler(request.params);
700
852
  });
701
853
  }
854
+ setProgressNotificationHandler(handler) {
855
+ this.log("debug", "Setting progress notification handler");
856
+ this.client.setNotificationHandler(types_js.ProgressNotificationSchema, (notification) => {
857
+ handler(notification.params);
858
+ });
859
+ }
702
860
  async convertInputSchema(inputSchema) {
703
861
  if (utils.isZodType(inputSchema)) {
704
862
  return inputSchema;
@@ -772,7 +930,7 @@ var InternalMastraMCPClient = class extends base.MastraBase {
772
930
  }
773
931
  async tools() {
774
932
  this.log("debug", `Requesting tools from MCP server`);
775
- const { tools: tools$1 } = await this.client.listTools({ timeout: this.timeout });
933
+ const { tools: tools$1 } = await this.client.listTools({}, { timeout: this.timeout });
776
934
  const toolsRes = {};
777
935
  for (const tool of tools$1) {
778
936
  this.log("debug", `Processing tool: ${tool.name}`);
@@ -785,12 +943,14 @@ var InternalMastraMCPClient = class extends base.MastraBase {
785
943
  execute: async (input, context) => {
786
944
  const previousContext = this.currentOperationContext;
787
945
  this.currentOperationContext = context?.requestContext || null;
788
- try {
789
- this.log("debug", `Executing tool: ${tool.name}`, { toolArgs: input });
946
+ const executeToolCall = async () => {
947
+ this.log("debug", `Executing tool: ${tool.name}`, { toolArgs: input, runId: context?.runId });
790
948
  const res = await this.client.callTool(
791
949
  {
792
950
  name: tool.name,
793
- arguments: input
951
+ arguments: input,
952
+ // Use runId as progress token if available, otherwise generate a random UUID
953
+ ...this.enableProgressTracking ? { _meta: { progressToken: context?.runId || crypto.randomUUID() } } : {}
794
954
  },
795
955
  types_js.CallToolResultSchema,
796
956
  {
@@ -798,8 +958,31 @@ var InternalMastraMCPClient = class extends base.MastraBase {
798
958
  }
799
959
  );
800
960
  this.log("debug", `Tool executed successfully: ${tool.name}`);
961
+ if (res.structuredContent !== void 0) {
962
+ return res.structuredContent;
963
+ }
801
964
  return res;
965
+ };
966
+ try {
967
+ return await executeToolCall();
802
968
  } catch (e) {
969
+ if (this.isSessionError(e)) {
970
+ this.log("debug", `Session error detected for tool ${tool.name}, attempting reconnection...`, {
971
+ error: e instanceof Error ? e.message : String(e)
972
+ });
973
+ try {
974
+ await this.forceReconnect();
975
+ this.log("debug", `Retrying tool ${tool.name} after reconnection...`);
976
+ return await executeToolCall();
977
+ } catch (reconnectError) {
978
+ this.log("error", `Reconnection or retry failed for tool ${tool.name}`, {
979
+ originalError: e instanceof Error ? e.message : String(e),
980
+ reconnectError: reconnectError instanceof Error ? reconnectError.stack : String(reconnectError),
981
+ toolArgs: input
982
+ });
983
+ throw e;
984
+ }
985
+ }
803
986
  this.log("error", `Error calling tool: ${tool.name}`, {
804
987
  error: e instanceof Error ? e.stack : JSON.stringify(e, null, 2),
805
988
  toolArgs: input
@@ -823,8 +1006,6 @@ var InternalMastraMCPClient = class extends base.MastraBase {
823
1006
  return toolsRes;
824
1007
  }
825
1008
  };
826
-
827
- // src/client/configuration.ts
828
1009
  var mcpClientInstances = /* @__PURE__ */ new Map();
829
1010
  var MCPClient = class extends base.MastraBase {
830
1011
  serverConfigs = {};
@@ -897,6 +1078,48 @@ To fix this you have three different options:
897
1078
  this.addToInstanceCache();
898
1079
  return this;
899
1080
  }
1081
+ /**
1082
+ * Provides access to progress-related operations for tracking long-running operations.
1083
+ *
1084
+ * Progress tracking allows MCP servers to send updates about the status of ongoing operations,
1085
+ * providing real-time feedback to users about task completion and current state.
1086
+ *
1087
+ * @example
1088
+ * ```typescript
1089
+ * // Set up handler for progress updates from a server
1090
+ * await mcp.progress.onUpdate('serverName', (params) => {
1091
+ * console.log(`Progress: ${params.progress}%`);
1092
+ * console.log(`Status: ${params.message}`);
1093
+ *
1094
+ * if (params.total) {
1095
+ * console.log(`Completed ${params.progress} of ${params.total} items`);
1096
+ * }
1097
+ * });
1098
+ * ```
1099
+ */
1100
+ get progress() {
1101
+ this.addToInstanceCache();
1102
+ return {
1103
+ onUpdate: async (serverName, handler) => {
1104
+ try {
1105
+ const internalClient = await this.getConnectedClientForServer(serverName);
1106
+ return internalClient.progress.onUpdate(handler);
1107
+ } catch (err) {
1108
+ throw new error.MastraError(
1109
+ {
1110
+ id: "MCP_CLIENT_ON_UPDATE_PROGRESS_FAILED",
1111
+ domain: error.ErrorDomain.MCP,
1112
+ category: error.ErrorCategory.THIRD_PARTY,
1113
+ details: {
1114
+ serverName
1115
+ }
1116
+ },
1117
+ err
1118
+ );
1119
+ }
1120
+ }
1121
+ };
1122
+ }
900
1123
  /**
901
1124
  * Provides access to elicitation-related operations for interactive user input collection.
902
1125
  *
@@ -2142,7 +2365,7 @@ var MCPServer = class extends mcp.MCPServerBase {
2142
2365
  if (opts.prompts) {
2143
2366
  capabilities.prompts = { listChanged: true };
2144
2367
  }
2145
- this.server = new index_js.Server({ name: this.name, version: this.version }, { capabilities });
2368
+ this.server = new index_js$1.Server({ name: this.name, version: this.version }, { capabilities });
2146
2369
  this.logger.info(
2147
2370
  `Initialized MCPServer '${this.name}' v${this.version} (ID: ${this.id}) with tools: ${Object.keys(this.convertedTools).join(", ")} and resources. Capabilities: ${JSON.stringify(capabilities)}`
2148
2371
  );
@@ -2187,6 +2410,41 @@ var MCPServer = class extends mcp.MCPServerBase {
2187
2410
  this.logger.debug(`Received elicitation response: ${JSON.stringify(response)}`);
2188
2411
  return response;
2189
2412
  }
2413
+ /**
2414
+ * Reads and parses the JSON body from an HTTP request.
2415
+ * If the request body was already parsed by middleware (e.g., express.json()),
2416
+ * it uses the pre-parsed body from req.body. Otherwise, it reads from the stream.
2417
+ *
2418
+ * This allows the MCP server to work with Express apps that use express.json()
2419
+ * globally without requiring special route exclusions.
2420
+ *
2421
+ * @param req - The incoming HTTP request
2422
+ * @param options - Optional configuration
2423
+ * @param options.preParsedOnly - If true, only return pre-parsed body from middleware,
2424
+ * returning undefined if not available. This allows the caller to fall back to
2425
+ * their own body reading logic (e.g., SDK's getRawBody with size limits).
2426
+ */
2427
+ async readJsonBody(req, options) {
2428
+ const reqWithBody = req;
2429
+ if (reqWithBody.body !== void 0) {
2430
+ return reqWithBody.body;
2431
+ }
2432
+ if (options?.preParsedOnly) {
2433
+ return void 0;
2434
+ }
2435
+ return new Promise((resolve, reject) => {
2436
+ let data = "";
2437
+ req.on("data", (chunk) => data += chunk);
2438
+ req.on("end", () => {
2439
+ try {
2440
+ resolve(JSON.parse(data));
2441
+ } catch (e) {
2442
+ reject(e);
2443
+ }
2444
+ });
2445
+ req.on("error", reject);
2446
+ });
2447
+ }
2190
2448
  /**
2191
2449
  * Creates a new Server instance configured with all handlers for HTTP sessions.
2192
2450
  * Each HTTP client connection gets its own Server instance to avoid routing conflicts.
@@ -2203,7 +2461,7 @@ var MCPServer = class extends mcp.MCPServerBase {
2203
2461
  if (this.promptOptions) {
2204
2462
  capabilities.prompts = { listChanged: true };
2205
2463
  }
2206
- const serverInstance = new index_js.Server({ name: this.name, version: this.version }, { capabilities });
2464
+ const serverInstance = new index_js$1.Server({ name: this.name, version: this.version }, { capabilities });
2207
2465
  this.registerHandlersOnServer(serverInstance);
2208
2466
  return serverInstance;
2209
2467
  }
@@ -2575,7 +2833,9 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
2575
2833
  try {
2576
2834
  const proxiedContext = context?.requestContext || new requestContext.RequestContext();
2577
2835
  if (context?.mcp?.extra) {
2578
- proxiedContext.set("mcp.extra", context.mcp.extra);
2836
+ Object.entries(context.mcp.extra).forEach(([key, value]) => {
2837
+ proxiedContext.set(key, value);
2838
+ });
2579
2839
  }
2580
2840
  const response = await agent.generate(inputData.message, {
2581
2841
  ...context ?? {},
@@ -2644,10 +2904,16 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
2644
2904
  inputData
2645
2905
  );
2646
2906
  try {
2647
- const run2 = await workflow.createRun({ runId: context?.requestContext?.get("runId") });
2907
+ const proxiedContext = context?.requestContext || new requestContext.RequestContext();
2908
+ if (context?.mcp?.extra) {
2909
+ Object.entries(context.mcp.extra).forEach(([key, value]) => {
2910
+ proxiedContext.set(key, value);
2911
+ });
2912
+ }
2913
+ const run2 = await workflow.createRun({ runId: proxiedContext?.get("runId") });
2648
2914
  const response = await run2.start({
2649
2915
  inputData,
2650
- requestContext: context?.requestContext,
2916
+ requestContext: proxiedContext,
2651
2917
  tracingContext: context?.tracingContext
2652
2918
  });
2653
2919
  return response;
@@ -2766,7 +3032,7 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
2766
3032
  * ```
2767
3033
  */
2768
3034
  async startStdio() {
2769
- this.stdioTransport = new stdio_js.StdioServerTransport();
3035
+ this.stdioTransport = new stdio_js$1.StdioServerTransport();
2770
3036
  try {
2771
3037
  await this.server.connect(this.stdioTransport);
2772
3038
  } catch (error$1) {
@@ -2803,7 +3069,7 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
2803
3069
  *
2804
3070
  * @example
2805
3071
  * ```typescript
2806
- * import http from 'http';
3072
+ * import http from 'node:http';
2807
3073
  *
2808
3074
  * const httpServer = http.createServer(async (req, res) => {
2809
3075
  * await server.startSSE({
@@ -2834,7 +3100,8 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
2834
3100
  res.end("SSE connection not established");
2835
3101
  return;
2836
3102
  }
2837
- await this.sseTransport.handlePostMessage(req, res);
3103
+ const parsedBody = await this.readJsonBody(req, { preParsedOnly: true });
3104
+ await this.sseTransport.handlePostMessage(req, res, parsedBody);
2838
3105
  } else {
2839
3106
  this.logger.debug("Unknown path:", { path: url.pathname });
2840
3107
  res.writeHead(404);
@@ -2961,8 +3228,8 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
2961
3228
  *
2962
3229
  * @example
2963
3230
  * ```typescript
2964
- * import http from 'http';
2965
- * import { randomUUID } from 'crypto';
3231
+ * import http from 'node:http';
3232
+ * import { randomUUID } from 'node:crypto';
2966
3233
  *
2967
3234
  * const httpServer = http.createServer(async (req, res) => {
2968
3235
  * await server.startHTTP({
@@ -3006,7 +3273,7 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
3006
3273
  httpPath,
3007
3274
  req,
3008
3275
  res,
3009
- options = { sessionIdGenerator: () => crypto$1.randomUUID() }
3276
+ options
3010
3277
  }) {
3011
3278
  this.logger.debug(`startHTTP: Received ${req.method} request to ${url.pathname}`);
3012
3279
  if (url.pathname !== httpPath) {
@@ -3015,11 +3282,18 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
3015
3282
  res.end();
3016
3283
  return;
3017
3284
  }
3018
- if (options?.serverless) {
3019
- this.logger.debug("startHTTP: Running in serverless (stateless) mode");
3285
+ const isStatelessMode = options?.serverless || options && "sessionIdGenerator" in options && options.sessionIdGenerator === void 0;
3286
+ if (isStatelessMode) {
3287
+ this.logger.debug("startHTTP: Running in stateless mode (serverless or sessionIdGenerator: undefined)");
3020
3288
  await this.handleServerlessRequest(req, res);
3021
3289
  return;
3022
3290
  }
3291
+ const mergedOptions = {
3292
+ sessionIdGenerator: () => crypto$1.randomUUID(),
3293
+ // default: enabled
3294
+ ...options
3295
+ // user-provided overrides default
3296
+ };
3023
3297
  const sessionId = req.headers["mcp-session-id"];
3024
3298
  let transport;
3025
3299
  this.logger.debug(
@@ -3034,40 +3308,18 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
3034
3308
  `startHTTP: Handling GET request for existing session ${sessionId}. Calling transport.handleRequest.`
3035
3309
  );
3036
3310
  }
3037
- const body = req.method === "POST" ? await new Promise((resolve, reject) => {
3038
- let data = "";
3039
- req.on("data", (chunk) => data += chunk);
3040
- req.on("end", () => {
3041
- try {
3042
- resolve(JSON.parse(data));
3043
- } catch (e) {
3044
- reject(e);
3045
- }
3046
- });
3047
- req.on("error", reject);
3048
- }) : void 0;
3311
+ const body = req.method === "POST" ? await this.readJsonBody(req) : void 0;
3049
3312
  await transport.handleRequest(req, res, body);
3050
3313
  } else {
3051
3314
  this.logger.debug(`startHTTP: No existing Streamable HTTP session ID found. ${req.method}`);
3052
3315
  if (req.method === "POST") {
3053
- const body = await new Promise((resolve, reject) => {
3054
- let data = "";
3055
- req.on("data", (chunk) => data += chunk);
3056
- req.on("end", () => {
3057
- try {
3058
- resolve(JSON.parse(data));
3059
- } catch (e) {
3060
- reject(e);
3061
- }
3062
- });
3063
- req.on("error", reject);
3064
- });
3316
+ const body = await this.readJsonBody(req);
3065
3317
  const { isInitializeRequest } = await import('@modelcontextprotocol/sdk/types.js');
3066
3318
  if (isInitializeRequest(body)) {
3067
3319
  this.logger.debug("startHTTP: Received Streamable HTTP initialize request, creating new transport.");
3068
- transport = new streamableHttp_js.StreamableHTTPServerTransport({
3069
- ...options,
3070
- sessionIdGenerator: () => crypto$1.randomUUID(),
3320
+ transport = new streamableHttp_js$1.StreamableHTTPServerTransport({
3321
+ ...mergedOptions,
3322
+ sessionIdGenerator: mergedOptions.sessionIdGenerator,
3071
3323
  onsessioninitialized: (id) => {
3072
3324
  this.streamableHTTPTransports.set(id, transport);
3073
3325
  }
@@ -3171,24 +3423,13 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
3171
3423
  async handleServerlessRequest(req, res) {
3172
3424
  try {
3173
3425
  this.logger.debug(`handleServerlessRequest: Received ${req.method} request`);
3174
- const body = req.method === "POST" ? await new Promise((resolve, reject) => {
3175
- let data = "";
3176
- req.on("data", (chunk) => data += chunk);
3177
- req.on("end", () => {
3178
- try {
3179
- resolve(JSON.parse(data));
3180
- } catch (e) {
3181
- reject(new Error(`Invalid JSON in request body: ${e instanceof Error ? e.message : String(e)}`));
3182
- }
3183
- });
3184
- req.on("error", reject);
3185
- }) : void 0;
3426
+ const body = req.method === "POST" ? await this.readJsonBody(req) : void 0;
3186
3427
  this.logger.debug(`handleServerlessRequest: Processing ${req.method} request`, {
3187
3428
  method: body?.method,
3188
3429
  id: body?.id
3189
3430
  });
3190
3431
  const transientServer = this.createServerInstance();
3191
- const tempTransport = new streamableHttp_js.StreamableHTTPServerTransport({
3432
+ const tempTransport = new streamableHttp_js$1.StreamableHTTPServerTransport({
3192
3433
  sessionIdGenerator: void 0,
3193
3434
  enableJsonResponse: true
3194
3435
  });
@@ -3250,7 +3491,7 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
3250
3491
  }) {
3251
3492
  try {
3252
3493
  this.logger.debug("Received SSE connection");
3253
- this.sseTransport = new sse_js.SSEServerTransport(messagePath, res);
3494
+ this.sseTransport = new sse_js$1.SSEServerTransport(messagePath, res);
3254
3495
  await this.server.connect(this.sseTransport);
3255
3496
  this.server.onclose = async () => {
3256
3497
  this.sseTransport = void 0;
@@ -3613,6 +3854,7 @@ Provided arguments: ${JSON.stringify(args, null, 2)}`,
3613
3854
  }
3614
3855
  };
3615
3856
 
3857
+ exports.InternalMastraMCPClient = InternalMastraMCPClient;
3616
3858
  exports.MCPClient = MCPClient;
3617
3859
  exports.MCPServer = MCPServer;
3618
3860
  //# sourceMappingURL=index.cjs.map