@mastra/mcp 1.0.0-beta.3 → 1.0.0-beta.5
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/CHANGELOG.md +124 -0
- package/README.md +61 -4
- package/dist/client/{elicitationActions.d.ts → actions/elicitation.d.ts} +2 -2
- package/dist/client/actions/elicitation.d.ts.map +1 -0
- package/dist/client/actions/progress.d.ts +23 -0
- package/dist/client/actions/progress.d.ts.map +1 -0
- package/dist/client/{promptActions.d.ts → actions/prompt.d.ts} +2 -2
- package/dist/client/actions/prompt.d.ts.map +1 -0
- package/dist/client/{resourceActions.d.ts → actions/resource.d.ts} +2 -2
- package/dist/client/actions/resource.d.ts.map +1 -0
- package/dist/client/client.d.ts +76 -138
- package/dist/client/client.d.ts.map +1 -1
- package/dist/client/configuration.d.ts +23 -1
- package/dist/client/configuration.d.ts.map +1 -1
- package/dist/client/index.d.ts +2 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/types.d.ts +237 -0
- package/dist/client/types.d.ts.map +1 -0
- package/dist/index.cjs +316 -86
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +298 -69
- package/dist/index.js.map +1 -1
- package/dist/server/server.d.ts +19 -3
- package/dist/server/server.d.ts.map +1 -1
- package/dist/server/types.d.ts +11 -4
- package/dist/server/types.d.ts.map +1 -1
- package/package.json +3 -3
- package/dist/client/elicitationActions.d.ts.map +0 -1
- package/dist/client/promptActions.d.ts.map +0 -1
- package/dist/client/resourceActions.d.ts.map +0 -1
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
|
|
12
|
-
var sse_js
|
|
13
|
-
var stdio_js
|
|
14
|
-
var 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/
|
|
33
|
+
// src/client/client.ts
|
|
34
34
|
|
|
35
|
-
// src/client/
|
|
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;
|
|
@@ -374,6 +391,7 @@ var ResourceClientActions = class {
|
|
|
374
391
|
|
|
375
392
|
// src/client/client.ts
|
|
376
393
|
var DEFAULT_SERVER_CONNECT_TIMEOUT_MSEC = 3e3;
|
|
394
|
+
var SSE_FALLBACK_STATUS_CODES = [400, 404, 405];
|
|
377
395
|
function convertLogLevelToLoggerMethod(level) {
|
|
378
396
|
switch (level) {
|
|
379
397
|
case "debug":
|
|
@@ -398,17 +416,21 @@ var InternalMastraMCPClient = class extends base.MastraBase {
|
|
|
398
416
|
timeout;
|
|
399
417
|
logHandler;
|
|
400
418
|
enableServerLogs;
|
|
419
|
+
enableProgressTracking;
|
|
401
420
|
serverConfig;
|
|
402
421
|
transport;
|
|
403
422
|
currentOperationContext = null;
|
|
404
423
|
exitHookUnsubscribe;
|
|
405
424
|
sigTermHandler;
|
|
425
|
+
_roots;
|
|
406
426
|
/** Provides access to resource operations (list, read, subscribe, etc.) */
|
|
407
427
|
resources;
|
|
408
428
|
/** Provides access to prompt operations (list, get, notifications) */
|
|
409
429
|
prompts;
|
|
410
430
|
/** Provides access to elicitation operations (request handling) */
|
|
411
431
|
elicitation;
|
|
432
|
+
/** Provides access to progress operations (notifications) */
|
|
433
|
+
progress;
|
|
412
434
|
/**
|
|
413
435
|
* @internal
|
|
414
436
|
*/
|
|
@@ -425,8 +447,16 @@ var InternalMastraMCPClient = class extends base.MastraBase {
|
|
|
425
447
|
this.logHandler = server.logger;
|
|
426
448
|
this.enableServerLogs = server.enableServerLogs ?? true;
|
|
427
449
|
this.serverConfig = server;
|
|
428
|
-
|
|
429
|
-
this.
|
|
450
|
+
this.enableProgressTracking = !!server.enableProgressTracking;
|
|
451
|
+
this._roots = server.roots ?? [];
|
|
452
|
+
const hasRoots = this._roots.length > 0 || !!capabilities.roots;
|
|
453
|
+
const clientCapabilities = {
|
|
454
|
+
...capabilities,
|
|
455
|
+
elicitation: {},
|
|
456
|
+
// Auto-enable roots capability if roots are provided
|
|
457
|
+
...hasRoots ? { roots: { listChanged: true, ...capabilities.roots ?? {} } } : {}
|
|
458
|
+
};
|
|
459
|
+
this.client = new index_js.Client(
|
|
430
460
|
{
|
|
431
461
|
name,
|
|
432
462
|
version
|
|
@@ -436,9 +466,13 @@ var InternalMastraMCPClient = class extends base.MastraBase {
|
|
|
436
466
|
}
|
|
437
467
|
);
|
|
438
468
|
this.setupLogging();
|
|
469
|
+
if (hasRoots) {
|
|
470
|
+
this.setupRootsHandler();
|
|
471
|
+
}
|
|
439
472
|
this.resources = new ResourceClientActions({ client: this, logger: this.logger });
|
|
440
473
|
this.prompts = new PromptClientActions({ client: this, logger: this.logger });
|
|
441
474
|
this.elicitation = new ElicitationClientActions({ client: this, logger: this.logger });
|
|
475
|
+
this.progress = new ProgressClientActions({ client: this, logger: this.logger });
|
|
442
476
|
}
|
|
443
477
|
/**
|
|
444
478
|
* Log a message at the specified level
|
|
@@ -477,13 +511,70 @@ var InternalMastraMCPClient = class extends base.MastraBase {
|
|
|
477
511
|
);
|
|
478
512
|
}
|
|
479
513
|
}
|
|
514
|
+
/**
|
|
515
|
+
* Set up handler for roots/list requests from the server.
|
|
516
|
+
*
|
|
517
|
+
* Per MCP spec (https://modelcontextprotocol.io/specification/2025-11-25/client/roots):
|
|
518
|
+
* When a server sends a roots/list request, the client responds with the configured roots.
|
|
519
|
+
*/
|
|
520
|
+
setupRootsHandler() {
|
|
521
|
+
this.log("debug", "Setting up roots/list request handler");
|
|
522
|
+
this.client.setRequestHandler(types_js.ListRootsRequestSchema, async () => {
|
|
523
|
+
this.log("debug", `Responding to roots/list request with ${this._roots.length} roots`);
|
|
524
|
+
return { roots: this._roots };
|
|
525
|
+
});
|
|
526
|
+
}
|
|
527
|
+
/**
|
|
528
|
+
* Get the currently configured roots.
|
|
529
|
+
*
|
|
530
|
+
* @returns Array of configured filesystem roots
|
|
531
|
+
*/
|
|
532
|
+
get roots() {
|
|
533
|
+
return [...this._roots];
|
|
534
|
+
}
|
|
535
|
+
/**
|
|
536
|
+
* Update the list of filesystem roots and notify the server.
|
|
537
|
+
*
|
|
538
|
+
* Per MCP spec, when roots change, the client sends a `notifications/roots/list_changed`
|
|
539
|
+
* notification to inform the server that it should re-fetch the roots list.
|
|
540
|
+
*
|
|
541
|
+
* @param roots - New list of filesystem roots
|
|
542
|
+
*
|
|
543
|
+
* @example
|
|
544
|
+
* ```typescript
|
|
545
|
+
* await client.setRoots([
|
|
546
|
+
* { uri: 'file:///home/user/projects', name: 'Projects' },
|
|
547
|
+
* { uri: 'file:///tmp', name: 'Temp' }
|
|
548
|
+
* ]);
|
|
549
|
+
* ```
|
|
550
|
+
*/
|
|
551
|
+
async setRoots(roots) {
|
|
552
|
+
this.log("debug", `Updating roots to ${roots.length} entries`);
|
|
553
|
+
this._roots = [...roots];
|
|
554
|
+
await this.sendRootsListChanged();
|
|
555
|
+
}
|
|
556
|
+
/**
|
|
557
|
+
* Send a roots/list_changed notification to the server.
|
|
558
|
+
*
|
|
559
|
+
* Per MCP spec, clients that support `listChanged` MUST send this notification
|
|
560
|
+
* when the list of roots changes. The server will then call roots/list to get
|
|
561
|
+
* the updated list.
|
|
562
|
+
*/
|
|
563
|
+
async sendRootsListChanged() {
|
|
564
|
+
if (!this.transport) {
|
|
565
|
+
this.log("debug", "Cannot send roots/list_changed: not connected");
|
|
566
|
+
return;
|
|
567
|
+
}
|
|
568
|
+
this.log("debug", "Sending notifications/roots/list_changed");
|
|
569
|
+
await this.client.notification({ method: "notifications/roots/list_changed" });
|
|
570
|
+
}
|
|
480
571
|
async connectStdio(command) {
|
|
481
572
|
this.log("debug", `Using Stdio transport for command: ${command}`);
|
|
482
573
|
try {
|
|
483
|
-
this.transport = new stdio_js
|
|
574
|
+
this.transport = new stdio_js.StdioClientTransport({
|
|
484
575
|
command,
|
|
485
576
|
args: this.serverConfig.args,
|
|
486
|
-
env: { ...stdio_js
|
|
577
|
+
env: { ...stdio_js.getDefaultEnvironment(), ...this.serverConfig.env || {} }
|
|
487
578
|
});
|
|
488
579
|
await this.client.connect(this.transport, { timeout: this.serverConfig.timeout ?? this.timeout });
|
|
489
580
|
this.log("debug", `Successfully connected to MCP server via Stdio`);
|
|
@@ -493,16 +584,17 @@ var InternalMastraMCPClient = class extends base.MastraBase {
|
|
|
493
584
|
}
|
|
494
585
|
}
|
|
495
586
|
async connectHttp(url) {
|
|
496
|
-
const { requestInit, eventSourceInit, authProvider, connectTimeout } = this.serverConfig;
|
|
587
|
+
const { requestInit, eventSourceInit, authProvider, connectTimeout, fetch } = this.serverConfig;
|
|
497
588
|
this.log("debug", `Attempting to connect to URL: ${url}`);
|
|
498
589
|
let shouldTrySSE = url.pathname.endsWith(`/sse`);
|
|
499
590
|
if (!shouldTrySSE) {
|
|
500
591
|
try {
|
|
501
592
|
this.log("debug", "Trying Streamable HTTP transport...");
|
|
502
|
-
const streamableTransport = new streamableHttp_js
|
|
593
|
+
const streamableTransport = new streamableHttp_js.StreamableHTTPClientTransport(url, {
|
|
503
594
|
requestInit,
|
|
504
595
|
reconnectionOptions: this.serverConfig.reconnectionOptions,
|
|
505
|
-
authProvider
|
|
596
|
+
authProvider,
|
|
597
|
+
fetch
|
|
506
598
|
});
|
|
507
599
|
await this.client.connect(streamableTransport, {
|
|
508
600
|
timeout: connectTimeout ?? DEFAULT_SERVER_CONNECT_TIMEOUT_MSEC
|
|
@@ -511,13 +603,23 @@ var InternalMastraMCPClient = class extends base.MastraBase {
|
|
|
511
603
|
this.log("debug", "Successfully connected using Streamable HTTP transport.");
|
|
512
604
|
} catch (error) {
|
|
513
605
|
this.log("debug", `Streamable HTTP transport failed: ${error}`);
|
|
606
|
+
const status = error?.code;
|
|
607
|
+
if (status !== void 0 && !SSE_FALLBACK_STATUS_CODES.includes(status)) {
|
|
608
|
+
throw error;
|
|
609
|
+
}
|
|
514
610
|
shouldTrySSE = true;
|
|
515
611
|
}
|
|
516
612
|
}
|
|
517
613
|
if (shouldTrySSE) {
|
|
518
614
|
this.log("debug", "Falling back to deprecated HTTP+SSE transport...");
|
|
519
615
|
try {
|
|
520
|
-
const
|
|
616
|
+
const sseEventSourceInit = fetch ? { ...eventSourceInit, fetch } : eventSourceInit;
|
|
617
|
+
const sseTransport = new sse_js.SSEClientTransport(url, {
|
|
618
|
+
requestInit,
|
|
619
|
+
eventSourceInit: sseEventSourceInit,
|
|
620
|
+
authProvider,
|
|
621
|
+
fetch
|
|
622
|
+
});
|
|
521
623
|
await this.client.connect(sseTransport, { timeout: this.serverConfig.timeout ?? this.timeout });
|
|
522
624
|
this.transport = sseTransport;
|
|
523
625
|
this.log("debug", "Successfully connected using deprecated HTTP+SSE transport.");
|
|
@@ -596,7 +698,7 @@ var InternalMastraMCPClient = class extends base.MastraBase {
|
|
|
596
698
|
* @internal
|
|
597
699
|
*/
|
|
598
700
|
get sessionId() {
|
|
599
|
-
if (this.transport instanceof streamableHttp_js
|
|
701
|
+
if (this.transport instanceof streamableHttp_js.StreamableHTTPClientTransport) {
|
|
600
702
|
return this.transport.sessionId;
|
|
601
703
|
}
|
|
602
704
|
return void 0;
|
|
@@ -617,7 +719,7 @@ var InternalMastraMCPClient = class extends base.MastraBase {
|
|
|
617
719
|
throw e;
|
|
618
720
|
} finally {
|
|
619
721
|
this.transport = void 0;
|
|
620
|
-
this.isConnected =
|
|
722
|
+
this.isConnected = null;
|
|
621
723
|
if (this.exitHookUnsubscribe) {
|
|
622
724
|
this.exitHookUnsubscribe();
|
|
623
725
|
this.exitHookUnsubscribe = void 0;
|
|
@@ -628,6 +730,53 @@ var InternalMastraMCPClient = class extends base.MastraBase {
|
|
|
628
730
|
}
|
|
629
731
|
}
|
|
630
732
|
}
|
|
733
|
+
/**
|
|
734
|
+
* Checks if an error indicates a session invalidation that requires reconnection.
|
|
735
|
+
*
|
|
736
|
+
* Common session-related errors include:
|
|
737
|
+
* - "No valid session ID provided" (HTTP 400)
|
|
738
|
+
* - "Server not initialized" (HTTP 400)
|
|
739
|
+
* - Connection refused errors
|
|
740
|
+
*
|
|
741
|
+
* @param error - The error to check
|
|
742
|
+
* @returns true if the error indicates a session problem requiring reconnection
|
|
743
|
+
*
|
|
744
|
+
* @internal
|
|
745
|
+
*/
|
|
746
|
+
isSessionError(error) {
|
|
747
|
+
if (!(error instanceof Error)) {
|
|
748
|
+
return false;
|
|
749
|
+
}
|
|
750
|
+
const errorMessage = error.message.toLowerCase();
|
|
751
|
+
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");
|
|
752
|
+
}
|
|
753
|
+
/**
|
|
754
|
+
* Forces a reconnection to the MCP server by disconnecting and reconnecting.
|
|
755
|
+
*
|
|
756
|
+
* This is useful when the session becomes invalid (e.g., after server restart)
|
|
757
|
+
* and the client needs to establish a fresh connection.
|
|
758
|
+
*
|
|
759
|
+
* @returns Promise resolving when reconnection is complete
|
|
760
|
+
* @throws {Error} If reconnection fails
|
|
761
|
+
*
|
|
762
|
+
* @internal
|
|
763
|
+
*/
|
|
764
|
+
async forceReconnect() {
|
|
765
|
+
this.log("debug", "Forcing reconnection to MCP server...");
|
|
766
|
+
try {
|
|
767
|
+
if (this.transport) {
|
|
768
|
+
await this.transport.close();
|
|
769
|
+
}
|
|
770
|
+
} catch (e) {
|
|
771
|
+
this.log("debug", "Error during force disconnect (ignored)", {
|
|
772
|
+
error: e instanceof Error ? e.message : String(e)
|
|
773
|
+
});
|
|
774
|
+
}
|
|
775
|
+
this.transport = void 0;
|
|
776
|
+
this.isConnected = null;
|
|
777
|
+
await this.connect();
|
|
778
|
+
this.log("debug", "Successfully reconnected to MCP server");
|
|
779
|
+
}
|
|
631
780
|
async listResources() {
|
|
632
781
|
this.log("debug", `Requesting resources from MCP server`);
|
|
633
782
|
return await this.client.request({ method: "resources/list" }, types_js.ListResourcesResultSchema, {
|
|
@@ -714,6 +863,12 @@ var InternalMastraMCPClient = class extends base.MastraBase {
|
|
|
714
863
|
return handler(request.params);
|
|
715
864
|
});
|
|
716
865
|
}
|
|
866
|
+
setProgressNotificationHandler(handler) {
|
|
867
|
+
this.log("debug", "Setting progress notification handler");
|
|
868
|
+
this.client.setNotificationHandler(types_js.ProgressNotificationSchema, (notification) => {
|
|
869
|
+
handler(notification.params);
|
|
870
|
+
});
|
|
871
|
+
}
|
|
717
872
|
async convertInputSchema(inputSchema) {
|
|
718
873
|
if (utils.isZodType(inputSchema)) {
|
|
719
874
|
return inputSchema;
|
|
@@ -787,7 +942,7 @@ var InternalMastraMCPClient = class extends base.MastraBase {
|
|
|
787
942
|
}
|
|
788
943
|
async tools() {
|
|
789
944
|
this.log("debug", `Requesting tools from MCP server`);
|
|
790
|
-
const { tools: tools$1 } = await this.client.listTools({ timeout: this.timeout });
|
|
945
|
+
const { tools: tools$1 } = await this.client.listTools({}, { timeout: this.timeout });
|
|
791
946
|
const toolsRes = {};
|
|
792
947
|
for (const tool of tools$1) {
|
|
793
948
|
this.log("debug", `Processing tool: ${tool.name}`);
|
|
@@ -800,12 +955,14 @@ var InternalMastraMCPClient = class extends base.MastraBase {
|
|
|
800
955
|
execute: async (input, context) => {
|
|
801
956
|
const previousContext = this.currentOperationContext;
|
|
802
957
|
this.currentOperationContext = context?.requestContext || null;
|
|
803
|
-
|
|
804
|
-
this.log("debug", `Executing tool: ${tool.name}`, { toolArgs: input });
|
|
958
|
+
const executeToolCall = async () => {
|
|
959
|
+
this.log("debug", `Executing tool: ${tool.name}`, { toolArgs: input, runId: context?.runId });
|
|
805
960
|
const res = await this.client.callTool(
|
|
806
961
|
{
|
|
807
962
|
name: tool.name,
|
|
808
|
-
arguments: input
|
|
963
|
+
arguments: input,
|
|
964
|
+
// Use runId as progress token if available, otherwise generate a random UUID
|
|
965
|
+
...this.enableProgressTracking ? { _meta: { progressToken: context?.runId || crypto.randomUUID() } } : {}
|
|
809
966
|
},
|
|
810
967
|
types_js.CallToolResultSchema,
|
|
811
968
|
{
|
|
@@ -817,7 +974,27 @@ var InternalMastraMCPClient = class extends base.MastraBase {
|
|
|
817
974
|
return res.structuredContent;
|
|
818
975
|
}
|
|
819
976
|
return res;
|
|
977
|
+
};
|
|
978
|
+
try {
|
|
979
|
+
return await executeToolCall();
|
|
820
980
|
} catch (e) {
|
|
981
|
+
if (this.isSessionError(e)) {
|
|
982
|
+
this.log("debug", `Session error detected for tool ${tool.name}, attempting reconnection...`, {
|
|
983
|
+
error: e instanceof Error ? e.message : String(e)
|
|
984
|
+
});
|
|
985
|
+
try {
|
|
986
|
+
await this.forceReconnect();
|
|
987
|
+
this.log("debug", `Retrying tool ${tool.name} after reconnection...`);
|
|
988
|
+
return await executeToolCall();
|
|
989
|
+
} catch (reconnectError) {
|
|
990
|
+
this.log("error", `Reconnection or retry failed for tool ${tool.name}`, {
|
|
991
|
+
originalError: e instanceof Error ? e.message : String(e),
|
|
992
|
+
reconnectError: reconnectError instanceof Error ? reconnectError.stack : String(reconnectError),
|
|
993
|
+
toolArgs: input
|
|
994
|
+
});
|
|
995
|
+
throw e;
|
|
996
|
+
}
|
|
997
|
+
}
|
|
821
998
|
this.log("error", `Error calling tool: ${tool.name}`, {
|
|
822
999
|
error: e instanceof Error ? e.stack : JSON.stringify(e, null, 2),
|
|
823
1000
|
toolArgs: input
|
|
@@ -841,8 +1018,6 @@ var InternalMastraMCPClient = class extends base.MastraBase {
|
|
|
841
1018
|
return toolsRes;
|
|
842
1019
|
}
|
|
843
1020
|
};
|
|
844
|
-
|
|
845
|
-
// src/client/configuration.ts
|
|
846
1021
|
var mcpClientInstances = /* @__PURE__ */ new Map();
|
|
847
1022
|
var MCPClient = class extends base.MastraBase {
|
|
848
1023
|
serverConfigs = {};
|
|
@@ -915,6 +1090,48 @@ To fix this you have three different options:
|
|
|
915
1090
|
this.addToInstanceCache();
|
|
916
1091
|
return this;
|
|
917
1092
|
}
|
|
1093
|
+
/**
|
|
1094
|
+
* Provides access to progress-related operations for tracking long-running operations.
|
|
1095
|
+
*
|
|
1096
|
+
* Progress tracking allows MCP servers to send updates about the status of ongoing operations,
|
|
1097
|
+
* providing real-time feedback to users about task completion and current state.
|
|
1098
|
+
*
|
|
1099
|
+
* @example
|
|
1100
|
+
* ```typescript
|
|
1101
|
+
* // Set up handler for progress updates from a server
|
|
1102
|
+
* await mcp.progress.onUpdate('serverName', (params) => {
|
|
1103
|
+
* console.log(`Progress: ${params.progress}%`);
|
|
1104
|
+
* console.log(`Status: ${params.message}`);
|
|
1105
|
+
*
|
|
1106
|
+
* if (params.total) {
|
|
1107
|
+
* console.log(`Completed ${params.progress} of ${params.total} items`);
|
|
1108
|
+
* }
|
|
1109
|
+
* });
|
|
1110
|
+
* ```
|
|
1111
|
+
*/
|
|
1112
|
+
get progress() {
|
|
1113
|
+
this.addToInstanceCache();
|
|
1114
|
+
return {
|
|
1115
|
+
onUpdate: async (serverName, handler) => {
|
|
1116
|
+
try {
|
|
1117
|
+
const internalClient = await this.getConnectedClientForServer(serverName);
|
|
1118
|
+
return internalClient.progress.onUpdate(handler);
|
|
1119
|
+
} catch (err) {
|
|
1120
|
+
throw new error.MastraError(
|
|
1121
|
+
{
|
|
1122
|
+
id: "MCP_CLIENT_ON_UPDATE_PROGRESS_FAILED",
|
|
1123
|
+
domain: error.ErrorDomain.MCP,
|
|
1124
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
1125
|
+
details: {
|
|
1126
|
+
serverName
|
|
1127
|
+
}
|
|
1128
|
+
},
|
|
1129
|
+
err
|
|
1130
|
+
);
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
};
|
|
1134
|
+
}
|
|
918
1135
|
/**
|
|
919
1136
|
* Provides access to elicitation-related operations for interactive user input collection.
|
|
920
1137
|
*
|
|
@@ -2160,7 +2377,7 @@ var MCPServer = class extends mcp.MCPServerBase {
|
|
|
2160
2377
|
if (opts.prompts) {
|
|
2161
2378
|
capabilities.prompts = { listChanged: true };
|
|
2162
2379
|
}
|
|
2163
|
-
this.server = new index_js.Server({ name: this.name, version: this.version }, { capabilities });
|
|
2380
|
+
this.server = new index_js$1.Server({ name: this.name, version: this.version }, { capabilities });
|
|
2164
2381
|
this.logger.info(
|
|
2165
2382
|
`Initialized MCPServer '${this.name}' v${this.version} (ID: ${this.id}) with tools: ${Object.keys(this.convertedTools).join(", ")} and resources. Capabilities: ${JSON.stringify(capabilities)}`
|
|
2166
2383
|
);
|
|
@@ -2185,8 +2402,8 @@ var MCPServer = class extends mcp.MCPServerBase {
|
|
|
2185
2402
|
}
|
|
2186
2403
|
});
|
|
2187
2404
|
this.elicitation = {
|
|
2188
|
-
sendRequest: async (request) => {
|
|
2189
|
-
return this.handleElicitationRequest(request);
|
|
2405
|
+
sendRequest: async (request, options) => {
|
|
2406
|
+
return this.handleElicitationRequest(request, void 0, options);
|
|
2190
2407
|
}
|
|
2191
2408
|
};
|
|
2192
2409
|
}
|
|
@@ -2196,15 +2413,51 @@ var MCPServer = class extends mcp.MCPServerBase {
|
|
|
2196
2413
|
*
|
|
2197
2414
|
* @param request - The elicitation request containing message and schema
|
|
2198
2415
|
* @param serverInstance - Optional server instance to use; defaults to main server for backward compatibility
|
|
2416
|
+
* @param options - Optional request options (timeout, signal, etc.)
|
|
2199
2417
|
* @returns Promise that resolves to the client's response
|
|
2200
2418
|
*/
|
|
2201
|
-
async handleElicitationRequest(request, serverInstance) {
|
|
2419
|
+
async handleElicitationRequest(request, serverInstance, options) {
|
|
2202
2420
|
this.logger.debug(`Sending elicitation request: ${request.message}`);
|
|
2203
2421
|
const server = serverInstance || this.server;
|
|
2204
|
-
const response = await server.elicitInput(request);
|
|
2422
|
+
const response = await server.elicitInput(request, options);
|
|
2205
2423
|
this.logger.debug(`Received elicitation response: ${JSON.stringify(response)}`);
|
|
2206
2424
|
return response;
|
|
2207
2425
|
}
|
|
2426
|
+
/**
|
|
2427
|
+
* Reads and parses the JSON body from an HTTP request.
|
|
2428
|
+
* If the request body was already parsed by middleware (e.g., express.json()),
|
|
2429
|
+
* it uses the pre-parsed body from req.body. Otherwise, it reads from the stream.
|
|
2430
|
+
*
|
|
2431
|
+
* This allows the MCP server to work with Express apps that use express.json()
|
|
2432
|
+
* globally without requiring special route exclusions.
|
|
2433
|
+
*
|
|
2434
|
+
* @param req - The incoming HTTP request
|
|
2435
|
+
* @param options - Optional configuration
|
|
2436
|
+
* @param options.preParsedOnly - If true, only return pre-parsed body from middleware,
|
|
2437
|
+
* returning undefined if not available. This allows the caller to fall back to
|
|
2438
|
+
* their own body reading logic (e.g., SDK's getRawBody with size limits).
|
|
2439
|
+
*/
|
|
2440
|
+
async readJsonBody(req, options) {
|
|
2441
|
+
const reqWithBody = req;
|
|
2442
|
+
if (reqWithBody.body !== void 0) {
|
|
2443
|
+
return reqWithBody.body;
|
|
2444
|
+
}
|
|
2445
|
+
if (options?.preParsedOnly) {
|
|
2446
|
+
return void 0;
|
|
2447
|
+
}
|
|
2448
|
+
return new Promise((resolve, reject) => {
|
|
2449
|
+
let data = "";
|
|
2450
|
+
req.on("data", (chunk) => data += chunk);
|
|
2451
|
+
req.on("end", () => {
|
|
2452
|
+
try {
|
|
2453
|
+
resolve(JSON.parse(data));
|
|
2454
|
+
} catch (e) {
|
|
2455
|
+
reject(e);
|
|
2456
|
+
}
|
|
2457
|
+
});
|
|
2458
|
+
req.on("error", reject);
|
|
2459
|
+
});
|
|
2460
|
+
}
|
|
2208
2461
|
/**
|
|
2209
2462
|
* Creates a new Server instance configured with all handlers for HTTP sessions.
|
|
2210
2463
|
* Each HTTP client connection gets its own Server instance to avoid routing conflicts.
|
|
@@ -2221,7 +2474,7 @@ var MCPServer = class extends mcp.MCPServerBase {
|
|
|
2221
2474
|
if (this.promptOptions) {
|
|
2222
2475
|
capabilities.prompts = { listChanged: true };
|
|
2223
2476
|
}
|
|
2224
|
-
const serverInstance = new index_js.Server({ name: this.name, version: this.version }, { capabilities });
|
|
2477
|
+
const serverInstance = new index_js$1.Server({ name: this.name, version: this.version }, { capabilities });
|
|
2225
2478
|
this.registerHandlersOnServer(serverInstance);
|
|
2226
2479
|
return serverInstance;
|
|
2227
2480
|
}
|
|
@@ -2290,8 +2543,8 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
2290
2543
|
};
|
|
2291
2544
|
}
|
|
2292
2545
|
const sessionElicitation = {
|
|
2293
|
-
sendRequest: async (request2) => {
|
|
2294
|
-
return this.handleElicitationRequest(request2, serverInstance);
|
|
2546
|
+
sendRequest: async (request2, options) => {
|
|
2547
|
+
return this.handleElicitationRequest(request2, serverInstance, options);
|
|
2295
2548
|
}
|
|
2296
2549
|
};
|
|
2297
2550
|
const mcpOptions = {
|
|
@@ -2593,7 +2846,9 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
2593
2846
|
try {
|
|
2594
2847
|
const proxiedContext = context?.requestContext || new requestContext.RequestContext();
|
|
2595
2848
|
if (context?.mcp?.extra) {
|
|
2596
|
-
|
|
2849
|
+
Object.entries(context.mcp.extra).forEach(([key, value]) => {
|
|
2850
|
+
proxiedContext.set(key, value);
|
|
2851
|
+
});
|
|
2597
2852
|
}
|
|
2598
2853
|
const response = await agent.generate(inputData.message, {
|
|
2599
2854
|
...context ?? {},
|
|
@@ -2662,10 +2917,16 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
2662
2917
|
inputData
|
|
2663
2918
|
);
|
|
2664
2919
|
try {
|
|
2665
|
-
const
|
|
2920
|
+
const proxiedContext = context?.requestContext || new requestContext.RequestContext();
|
|
2921
|
+
if (context?.mcp?.extra) {
|
|
2922
|
+
Object.entries(context.mcp.extra).forEach(([key, value]) => {
|
|
2923
|
+
proxiedContext.set(key, value);
|
|
2924
|
+
});
|
|
2925
|
+
}
|
|
2926
|
+
const run2 = await workflow.createRun({ runId: proxiedContext?.get("runId") });
|
|
2666
2927
|
const response = await run2.start({
|
|
2667
2928
|
inputData,
|
|
2668
|
-
requestContext:
|
|
2929
|
+
requestContext: proxiedContext,
|
|
2669
2930
|
tracingContext: context?.tracingContext
|
|
2670
2931
|
});
|
|
2671
2932
|
return response;
|
|
@@ -2784,7 +3045,7 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
2784
3045
|
* ```
|
|
2785
3046
|
*/
|
|
2786
3047
|
async startStdio() {
|
|
2787
|
-
this.stdioTransport = new stdio_js.StdioServerTransport();
|
|
3048
|
+
this.stdioTransport = new stdio_js$1.StdioServerTransport();
|
|
2788
3049
|
try {
|
|
2789
3050
|
await this.server.connect(this.stdioTransport);
|
|
2790
3051
|
} catch (error$1) {
|
|
@@ -2821,7 +3082,7 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
2821
3082
|
*
|
|
2822
3083
|
* @example
|
|
2823
3084
|
* ```typescript
|
|
2824
|
-
* import http from 'http';
|
|
3085
|
+
* import http from 'node:http';
|
|
2825
3086
|
*
|
|
2826
3087
|
* const httpServer = http.createServer(async (req, res) => {
|
|
2827
3088
|
* await server.startSSE({
|
|
@@ -2852,7 +3113,8 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
2852
3113
|
res.end("SSE connection not established");
|
|
2853
3114
|
return;
|
|
2854
3115
|
}
|
|
2855
|
-
await this.
|
|
3116
|
+
const parsedBody = await this.readJsonBody(req, { preParsedOnly: true });
|
|
3117
|
+
await this.sseTransport.handlePostMessage(req, res, parsedBody);
|
|
2856
3118
|
} else {
|
|
2857
3119
|
this.logger.debug("Unknown path:", { path: url.pathname });
|
|
2858
3120
|
res.writeHead(404);
|
|
@@ -2979,8 +3241,8 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
2979
3241
|
*
|
|
2980
3242
|
* @example
|
|
2981
3243
|
* ```typescript
|
|
2982
|
-
* import http from 'http';
|
|
2983
|
-
* import { randomUUID } from 'crypto';
|
|
3244
|
+
* import http from 'node:http';
|
|
3245
|
+
* import { randomUUID } from 'node:crypto';
|
|
2984
3246
|
*
|
|
2985
3247
|
* const httpServer = http.createServer(async (req, res) => {
|
|
2986
3248
|
* await server.startHTTP({
|
|
@@ -3059,38 +3321,16 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
3059
3321
|
`startHTTP: Handling GET request for existing session ${sessionId}. Calling transport.handleRequest.`
|
|
3060
3322
|
);
|
|
3061
3323
|
}
|
|
3062
|
-
const body = req.method === "POST" ? await
|
|
3063
|
-
let data = "";
|
|
3064
|
-
req.on("data", (chunk) => data += chunk);
|
|
3065
|
-
req.on("end", () => {
|
|
3066
|
-
try {
|
|
3067
|
-
resolve(JSON.parse(data));
|
|
3068
|
-
} catch (e) {
|
|
3069
|
-
reject(e);
|
|
3070
|
-
}
|
|
3071
|
-
});
|
|
3072
|
-
req.on("error", reject);
|
|
3073
|
-
}) : void 0;
|
|
3324
|
+
const body = req.method === "POST" ? await this.readJsonBody(req) : void 0;
|
|
3074
3325
|
await transport.handleRequest(req, res, body);
|
|
3075
3326
|
} else {
|
|
3076
3327
|
this.logger.debug(`startHTTP: No existing Streamable HTTP session ID found. ${req.method}`);
|
|
3077
3328
|
if (req.method === "POST") {
|
|
3078
|
-
const body = await
|
|
3079
|
-
let data = "";
|
|
3080
|
-
req.on("data", (chunk) => data += chunk);
|
|
3081
|
-
req.on("end", () => {
|
|
3082
|
-
try {
|
|
3083
|
-
resolve(JSON.parse(data));
|
|
3084
|
-
} catch (e) {
|
|
3085
|
-
reject(e);
|
|
3086
|
-
}
|
|
3087
|
-
});
|
|
3088
|
-
req.on("error", reject);
|
|
3089
|
-
});
|
|
3329
|
+
const body = await this.readJsonBody(req);
|
|
3090
3330
|
const { isInitializeRequest } = await import('@modelcontextprotocol/sdk/types.js');
|
|
3091
3331
|
if (isInitializeRequest(body)) {
|
|
3092
3332
|
this.logger.debug("startHTTP: Received Streamable HTTP initialize request, creating new transport.");
|
|
3093
|
-
transport = new streamableHttp_js.StreamableHTTPServerTransport({
|
|
3333
|
+
transport = new streamableHttp_js$1.StreamableHTTPServerTransport({
|
|
3094
3334
|
...mergedOptions,
|
|
3095
3335
|
sessionIdGenerator: mergedOptions.sessionIdGenerator,
|
|
3096
3336
|
onsessioninitialized: (id) => {
|
|
@@ -3196,24 +3436,13 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
3196
3436
|
async handleServerlessRequest(req, res) {
|
|
3197
3437
|
try {
|
|
3198
3438
|
this.logger.debug(`handleServerlessRequest: Received ${req.method} request`);
|
|
3199
|
-
const body = req.method === "POST" ? await
|
|
3200
|
-
let data = "";
|
|
3201
|
-
req.on("data", (chunk) => data += chunk);
|
|
3202
|
-
req.on("end", () => {
|
|
3203
|
-
try {
|
|
3204
|
-
resolve(JSON.parse(data));
|
|
3205
|
-
} catch (e) {
|
|
3206
|
-
reject(new Error(`Invalid JSON in request body: ${e instanceof Error ? e.message : String(e)}`));
|
|
3207
|
-
}
|
|
3208
|
-
});
|
|
3209
|
-
req.on("error", reject);
|
|
3210
|
-
}) : void 0;
|
|
3439
|
+
const body = req.method === "POST" ? await this.readJsonBody(req) : void 0;
|
|
3211
3440
|
this.logger.debug(`handleServerlessRequest: Processing ${req.method} request`, {
|
|
3212
3441
|
method: body?.method,
|
|
3213
3442
|
id: body?.id
|
|
3214
3443
|
});
|
|
3215
3444
|
const transientServer = this.createServerInstance();
|
|
3216
|
-
const tempTransport = new streamableHttp_js.StreamableHTTPServerTransport({
|
|
3445
|
+
const tempTransport = new streamableHttp_js$1.StreamableHTTPServerTransport({
|
|
3217
3446
|
sessionIdGenerator: void 0,
|
|
3218
3447
|
enableJsonResponse: true
|
|
3219
3448
|
});
|
|
@@ -3275,7 +3504,7 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
3275
3504
|
}) {
|
|
3276
3505
|
try {
|
|
3277
3506
|
this.logger.debug("Received SSE connection");
|
|
3278
|
-
this.sseTransport = new sse_js.SSEServerTransport(messagePath, res);
|
|
3507
|
+
this.sseTransport = new sse_js$1.SSEServerTransport(messagePath, res);
|
|
3279
3508
|
await this.server.connect(this.sseTransport);
|
|
3280
3509
|
this.server.onclose = async () => {
|
|
3281
3510
|
this.sseTransport = void 0;
|
|
@@ -3638,6 +3867,7 @@ Provided arguments: ${JSON.stringify(args, null, 2)}`,
|
|
|
3638
3867
|
}
|
|
3639
3868
|
};
|
|
3640
3869
|
|
|
3870
|
+
exports.InternalMastraMCPClient = InternalMastraMCPClient;
|
|
3641
3871
|
exports.MCPClient = MCPClient;
|
|
3642
3872
|
exports.MCPServer = MCPServer;
|
|
3643
3873
|
//# sourceMappingURL=index.cjs.map
|