@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.js
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
|
+
import $RefParser from '@apidevtools/json-schema-ref-parser';
|
|
1
2
|
import { MastraBase } from '@mastra/core/base';
|
|
2
3
|
import { MastraError, ErrorCategory, ErrorDomain } from '@mastra/core/error';
|
|
3
|
-
import { DEFAULT_REQUEST_TIMEOUT_MSEC } from '@modelcontextprotocol/sdk/shared/protocol.js';
|
|
4
|
-
import equal from 'fast-deep-equal';
|
|
5
|
-
import { v5 } from 'uuid';
|
|
6
|
-
import $RefParser from '@apidevtools/json-schema-ref-parser';
|
|
7
4
|
import { createTool } from '@mastra/core/tools';
|
|
8
|
-
import {
|
|
5
|
+
import { isZodType, makeCoreTool } from '@mastra/core/utils';
|
|
9
6
|
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
10
7
|
import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';
|
|
11
8
|
import { StdioClientTransport, getDefaultEnvironment } from '@modelcontextprotocol/sdk/client/stdio.js';
|
|
12
9
|
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
|
|
13
|
-
import {
|
|
10
|
+
import { DEFAULT_REQUEST_TIMEOUT_MSEC } from '@modelcontextprotocol/sdk/shared/protocol.js';
|
|
11
|
+
import { ListRootsRequestSchema, ListResourcesResultSchema, ReadResourceResultSchema, ListResourceTemplatesResultSchema, ListPromptsResultSchema, GetPromptResultSchema, PromptListChangedNotificationSchema, ResourceUpdatedNotificationSchema, ResourceListChangedNotificationSchema, ElicitRequestSchema, ProgressNotificationSchema, ListToolsRequestSchema, CallToolRequestSchema, SetLevelRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, ListResourceTemplatesRequestSchema, SubscribeRequestSchema, UnsubscribeRequestSchema, ListPromptsRequestSchema, PromptSchema, GetPromptRequestSchema, CallToolResultSchema, ErrorCode, JSONRPCMessageSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
14
12
|
import { asyncExitHook, gracefulExit } from 'exit-hook';
|
|
15
13
|
import { z } from 'zod';
|
|
16
14
|
import { convertJsonSchemaToZod } from 'zod-from-json-schema';
|
|
17
15
|
import { convertJsonSchemaToZod as convertJsonSchemaToZod$1 } from 'zod-from-json-schema-v3';
|
|
16
|
+
import equal from 'fast-deep-equal';
|
|
17
|
+
import { v5 } from 'uuid';
|
|
18
18
|
import { randomUUID } from 'crypto';
|
|
19
19
|
import { MCPServerBase } from '@mastra/core/mcp';
|
|
20
20
|
import { RequestContext } from '@mastra/core/request-context';
|
|
@@ -23,9 +23,9 @@ import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js';
|
|
|
23
23
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
24
24
|
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
|
|
25
25
|
|
|
26
|
-
// src/client/
|
|
26
|
+
// src/client/client.ts
|
|
27
27
|
|
|
28
|
-
// src/client/
|
|
28
|
+
// src/client/actions/elicitation.ts
|
|
29
29
|
var ElicitationClientActions = class {
|
|
30
30
|
client;
|
|
31
31
|
logger;
|
|
@@ -78,6 +78,23 @@ var ElicitationClientActions = class {
|
|
|
78
78
|
this.client.setElicitationRequestHandler(handler);
|
|
79
79
|
}
|
|
80
80
|
};
|
|
81
|
+
|
|
82
|
+
// src/client/actions/progress.ts
|
|
83
|
+
var ProgressClientActions = class {
|
|
84
|
+
client;
|
|
85
|
+
logger;
|
|
86
|
+
constructor({ client, logger }) {
|
|
87
|
+
this.client = client;
|
|
88
|
+
this.logger = logger;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Set a notification handler for progress updates.
|
|
92
|
+
* @param handler The callback function to handle progress notifications.
|
|
93
|
+
*/
|
|
94
|
+
onUpdate(handler) {
|
|
95
|
+
this.client.setProgressNotificationHandler(handler);
|
|
96
|
+
}
|
|
97
|
+
};
|
|
81
98
|
var PromptClientActions = class {
|
|
82
99
|
client;
|
|
83
100
|
logger;
|
|
@@ -367,6 +384,7 @@ var ResourceClientActions = class {
|
|
|
367
384
|
|
|
368
385
|
// src/client/client.ts
|
|
369
386
|
var DEFAULT_SERVER_CONNECT_TIMEOUT_MSEC = 3e3;
|
|
387
|
+
var SSE_FALLBACK_STATUS_CODES = [400, 404, 405];
|
|
370
388
|
function convertLogLevelToLoggerMethod(level) {
|
|
371
389
|
switch (level) {
|
|
372
390
|
case "debug":
|
|
@@ -391,17 +409,21 @@ var InternalMastraMCPClient = class extends MastraBase {
|
|
|
391
409
|
timeout;
|
|
392
410
|
logHandler;
|
|
393
411
|
enableServerLogs;
|
|
412
|
+
enableProgressTracking;
|
|
394
413
|
serverConfig;
|
|
395
414
|
transport;
|
|
396
415
|
currentOperationContext = null;
|
|
397
416
|
exitHookUnsubscribe;
|
|
398
417
|
sigTermHandler;
|
|
418
|
+
_roots;
|
|
399
419
|
/** Provides access to resource operations (list, read, subscribe, etc.) */
|
|
400
420
|
resources;
|
|
401
421
|
/** Provides access to prompt operations (list, get, notifications) */
|
|
402
422
|
prompts;
|
|
403
423
|
/** Provides access to elicitation operations (request handling) */
|
|
404
424
|
elicitation;
|
|
425
|
+
/** Provides access to progress operations (notifications) */
|
|
426
|
+
progress;
|
|
405
427
|
/**
|
|
406
428
|
* @internal
|
|
407
429
|
*/
|
|
@@ -418,7 +440,15 @@ var InternalMastraMCPClient = class extends MastraBase {
|
|
|
418
440
|
this.logHandler = server.logger;
|
|
419
441
|
this.enableServerLogs = server.enableServerLogs ?? true;
|
|
420
442
|
this.serverConfig = server;
|
|
421
|
-
|
|
443
|
+
this.enableProgressTracking = !!server.enableProgressTracking;
|
|
444
|
+
this._roots = server.roots ?? [];
|
|
445
|
+
const hasRoots = this._roots.length > 0 || !!capabilities.roots;
|
|
446
|
+
const clientCapabilities = {
|
|
447
|
+
...capabilities,
|
|
448
|
+
elicitation: {},
|
|
449
|
+
// Auto-enable roots capability if roots are provided
|
|
450
|
+
...hasRoots ? { roots: { listChanged: true, ...capabilities.roots ?? {} } } : {}
|
|
451
|
+
};
|
|
422
452
|
this.client = new Client(
|
|
423
453
|
{
|
|
424
454
|
name,
|
|
@@ -429,9 +459,13 @@ var InternalMastraMCPClient = class extends MastraBase {
|
|
|
429
459
|
}
|
|
430
460
|
);
|
|
431
461
|
this.setupLogging();
|
|
462
|
+
if (hasRoots) {
|
|
463
|
+
this.setupRootsHandler();
|
|
464
|
+
}
|
|
432
465
|
this.resources = new ResourceClientActions({ client: this, logger: this.logger });
|
|
433
466
|
this.prompts = new PromptClientActions({ client: this, logger: this.logger });
|
|
434
467
|
this.elicitation = new ElicitationClientActions({ client: this, logger: this.logger });
|
|
468
|
+
this.progress = new ProgressClientActions({ client: this, logger: this.logger });
|
|
435
469
|
}
|
|
436
470
|
/**
|
|
437
471
|
* Log a message at the specified level
|
|
@@ -470,6 +504,63 @@ var InternalMastraMCPClient = class extends MastraBase {
|
|
|
470
504
|
);
|
|
471
505
|
}
|
|
472
506
|
}
|
|
507
|
+
/**
|
|
508
|
+
* Set up handler for roots/list requests from the server.
|
|
509
|
+
*
|
|
510
|
+
* Per MCP spec (https://modelcontextprotocol.io/specification/2025-11-25/client/roots):
|
|
511
|
+
* When a server sends a roots/list request, the client responds with the configured roots.
|
|
512
|
+
*/
|
|
513
|
+
setupRootsHandler() {
|
|
514
|
+
this.log("debug", "Setting up roots/list request handler");
|
|
515
|
+
this.client.setRequestHandler(ListRootsRequestSchema, async () => {
|
|
516
|
+
this.log("debug", `Responding to roots/list request with ${this._roots.length} roots`);
|
|
517
|
+
return { roots: this._roots };
|
|
518
|
+
});
|
|
519
|
+
}
|
|
520
|
+
/**
|
|
521
|
+
* Get the currently configured roots.
|
|
522
|
+
*
|
|
523
|
+
* @returns Array of configured filesystem roots
|
|
524
|
+
*/
|
|
525
|
+
get roots() {
|
|
526
|
+
return [...this._roots];
|
|
527
|
+
}
|
|
528
|
+
/**
|
|
529
|
+
* Update the list of filesystem roots and notify the server.
|
|
530
|
+
*
|
|
531
|
+
* Per MCP spec, when roots change, the client sends a `notifications/roots/list_changed`
|
|
532
|
+
* notification to inform the server that it should re-fetch the roots list.
|
|
533
|
+
*
|
|
534
|
+
* @param roots - New list of filesystem roots
|
|
535
|
+
*
|
|
536
|
+
* @example
|
|
537
|
+
* ```typescript
|
|
538
|
+
* await client.setRoots([
|
|
539
|
+
* { uri: 'file:///home/user/projects', name: 'Projects' },
|
|
540
|
+
* { uri: 'file:///tmp', name: 'Temp' }
|
|
541
|
+
* ]);
|
|
542
|
+
* ```
|
|
543
|
+
*/
|
|
544
|
+
async setRoots(roots) {
|
|
545
|
+
this.log("debug", `Updating roots to ${roots.length} entries`);
|
|
546
|
+
this._roots = [...roots];
|
|
547
|
+
await this.sendRootsListChanged();
|
|
548
|
+
}
|
|
549
|
+
/**
|
|
550
|
+
* Send a roots/list_changed notification to the server.
|
|
551
|
+
*
|
|
552
|
+
* Per MCP spec, clients that support `listChanged` MUST send this notification
|
|
553
|
+
* when the list of roots changes. The server will then call roots/list to get
|
|
554
|
+
* the updated list.
|
|
555
|
+
*/
|
|
556
|
+
async sendRootsListChanged() {
|
|
557
|
+
if (!this.transport) {
|
|
558
|
+
this.log("debug", "Cannot send roots/list_changed: not connected");
|
|
559
|
+
return;
|
|
560
|
+
}
|
|
561
|
+
this.log("debug", "Sending notifications/roots/list_changed");
|
|
562
|
+
await this.client.notification({ method: "notifications/roots/list_changed" });
|
|
563
|
+
}
|
|
473
564
|
async connectStdio(command) {
|
|
474
565
|
this.log("debug", `Using Stdio transport for command: ${command}`);
|
|
475
566
|
try {
|
|
@@ -486,7 +577,7 @@ var InternalMastraMCPClient = class extends MastraBase {
|
|
|
486
577
|
}
|
|
487
578
|
}
|
|
488
579
|
async connectHttp(url) {
|
|
489
|
-
const { requestInit, eventSourceInit, authProvider, connectTimeout } = this.serverConfig;
|
|
580
|
+
const { requestInit, eventSourceInit, authProvider, connectTimeout, fetch } = this.serverConfig;
|
|
490
581
|
this.log("debug", `Attempting to connect to URL: ${url}`);
|
|
491
582
|
let shouldTrySSE = url.pathname.endsWith(`/sse`);
|
|
492
583
|
if (!shouldTrySSE) {
|
|
@@ -495,7 +586,8 @@ var InternalMastraMCPClient = class extends MastraBase {
|
|
|
495
586
|
const streamableTransport = new StreamableHTTPClientTransport(url, {
|
|
496
587
|
requestInit,
|
|
497
588
|
reconnectionOptions: this.serverConfig.reconnectionOptions,
|
|
498
|
-
authProvider
|
|
589
|
+
authProvider,
|
|
590
|
+
fetch
|
|
499
591
|
});
|
|
500
592
|
await this.client.connect(streamableTransport, {
|
|
501
593
|
timeout: connectTimeout ?? DEFAULT_SERVER_CONNECT_TIMEOUT_MSEC
|
|
@@ -504,13 +596,23 @@ var InternalMastraMCPClient = class extends MastraBase {
|
|
|
504
596
|
this.log("debug", "Successfully connected using Streamable HTTP transport.");
|
|
505
597
|
} catch (error) {
|
|
506
598
|
this.log("debug", `Streamable HTTP transport failed: ${error}`);
|
|
599
|
+
const status = error?.code;
|
|
600
|
+
if (status !== void 0 && !SSE_FALLBACK_STATUS_CODES.includes(status)) {
|
|
601
|
+
throw error;
|
|
602
|
+
}
|
|
507
603
|
shouldTrySSE = true;
|
|
508
604
|
}
|
|
509
605
|
}
|
|
510
606
|
if (shouldTrySSE) {
|
|
511
607
|
this.log("debug", "Falling back to deprecated HTTP+SSE transport...");
|
|
512
608
|
try {
|
|
513
|
-
const
|
|
609
|
+
const sseEventSourceInit = fetch ? { ...eventSourceInit, fetch } : eventSourceInit;
|
|
610
|
+
const sseTransport = new SSEClientTransport(url, {
|
|
611
|
+
requestInit,
|
|
612
|
+
eventSourceInit: sseEventSourceInit,
|
|
613
|
+
authProvider,
|
|
614
|
+
fetch
|
|
615
|
+
});
|
|
514
616
|
await this.client.connect(sseTransport, { timeout: this.serverConfig.timeout ?? this.timeout });
|
|
515
617
|
this.transport = sseTransport;
|
|
516
618
|
this.log("debug", "Successfully connected using deprecated HTTP+SSE transport.");
|
|
@@ -610,7 +712,7 @@ var InternalMastraMCPClient = class extends MastraBase {
|
|
|
610
712
|
throw e;
|
|
611
713
|
} finally {
|
|
612
714
|
this.transport = void 0;
|
|
613
|
-
this.isConnected =
|
|
715
|
+
this.isConnected = null;
|
|
614
716
|
if (this.exitHookUnsubscribe) {
|
|
615
717
|
this.exitHookUnsubscribe();
|
|
616
718
|
this.exitHookUnsubscribe = void 0;
|
|
@@ -621,6 +723,53 @@ var InternalMastraMCPClient = class extends MastraBase {
|
|
|
621
723
|
}
|
|
622
724
|
}
|
|
623
725
|
}
|
|
726
|
+
/**
|
|
727
|
+
* Checks if an error indicates a session invalidation that requires reconnection.
|
|
728
|
+
*
|
|
729
|
+
* Common session-related errors include:
|
|
730
|
+
* - "No valid session ID provided" (HTTP 400)
|
|
731
|
+
* - "Server not initialized" (HTTP 400)
|
|
732
|
+
* - Connection refused errors
|
|
733
|
+
*
|
|
734
|
+
* @param error - The error to check
|
|
735
|
+
* @returns true if the error indicates a session problem requiring reconnection
|
|
736
|
+
*
|
|
737
|
+
* @internal
|
|
738
|
+
*/
|
|
739
|
+
isSessionError(error) {
|
|
740
|
+
if (!(error instanceof Error)) {
|
|
741
|
+
return false;
|
|
742
|
+
}
|
|
743
|
+
const errorMessage = error.message.toLowerCase();
|
|
744
|
+
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");
|
|
745
|
+
}
|
|
746
|
+
/**
|
|
747
|
+
* Forces a reconnection to the MCP server by disconnecting and reconnecting.
|
|
748
|
+
*
|
|
749
|
+
* This is useful when the session becomes invalid (e.g., after server restart)
|
|
750
|
+
* and the client needs to establish a fresh connection.
|
|
751
|
+
*
|
|
752
|
+
* @returns Promise resolving when reconnection is complete
|
|
753
|
+
* @throws {Error} If reconnection fails
|
|
754
|
+
*
|
|
755
|
+
* @internal
|
|
756
|
+
*/
|
|
757
|
+
async forceReconnect() {
|
|
758
|
+
this.log("debug", "Forcing reconnection to MCP server...");
|
|
759
|
+
try {
|
|
760
|
+
if (this.transport) {
|
|
761
|
+
await this.transport.close();
|
|
762
|
+
}
|
|
763
|
+
} catch (e) {
|
|
764
|
+
this.log("debug", "Error during force disconnect (ignored)", {
|
|
765
|
+
error: e instanceof Error ? e.message : String(e)
|
|
766
|
+
});
|
|
767
|
+
}
|
|
768
|
+
this.transport = void 0;
|
|
769
|
+
this.isConnected = null;
|
|
770
|
+
await this.connect();
|
|
771
|
+
this.log("debug", "Successfully reconnected to MCP server");
|
|
772
|
+
}
|
|
624
773
|
async listResources() {
|
|
625
774
|
this.log("debug", `Requesting resources from MCP server`);
|
|
626
775
|
return await this.client.request({ method: "resources/list" }, ListResourcesResultSchema, {
|
|
@@ -707,6 +856,12 @@ var InternalMastraMCPClient = class extends MastraBase {
|
|
|
707
856
|
return handler(request.params);
|
|
708
857
|
});
|
|
709
858
|
}
|
|
859
|
+
setProgressNotificationHandler(handler) {
|
|
860
|
+
this.log("debug", "Setting progress notification handler");
|
|
861
|
+
this.client.setNotificationHandler(ProgressNotificationSchema, (notification) => {
|
|
862
|
+
handler(notification.params);
|
|
863
|
+
});
|
|
864
|
+
}
|
|
710
865
|
async convertInputSchema(inputSchema) {
|
|
711
866
|
if (isZodType(inputSchema)) {
|
|
712
867
|
return inputSchema;
|
|
@@ -780,7 +935,7 @@ var InternalMastraMCPClient = class extends MastraBase {
|
|
|
780
935
|
}
|
|
781
936
|
async tools() {
|
|
782
937
|
this.log("debug", `Requesting tools from MCP server`);
|
|
783
|
-
const { tools } = await this.client.listTools({ timeout: this.timeout });
|
|
938
|
+
const { tools } = await this.client.listTools({}, { timeout: this.timeout });
|
|
784
939
|
const toolsRes = {};
|
|
785
940
|
for (const tool of tools) {
|
|
786
941
|
this.log("debug", `Processing tool: ${tool.name}`);
|
|
@@ -793,12 +948,14 @@ var InternalMastraMCPClient = class extends MastraBase {
|
|
|
793
948
|
execute: async (input, context) => {
|
|
794
949
|
const previousContext = this.currentOperationContext;
|
|
795
950
|
this.currentOperationContext = context?.requestContext || null;
|
|
796
|
-
|
|
797
|
-
this.log("debug", `Executing tool: ${tool.name}`, { toolArgs: input });
|
|
951
|
+
const executeToolCall = async () => {
|
|
952
|
+
this.log("debug", `Executing tool: ${tool.name}`, { toolArgs: input, runId: context?.runId });
|
|
798
953
|
const res = await this.client.callTool(
|
|
799
954
|
{
|
|
800
955
|
name: tool.name,
|
|
801
|
-
arguments: input
|
|
956
|
+
arguments: input,
|
|
957
|
+
// Use runId as progress token if available, otherwise generate a random UUID
|
|
958
|
+
...this.enableProgressTracking ? { _meta: { progressToken: context?.runId || crypto.randomUUID() } } : {}
|
|
802
959
|
},
|
|
803
960
|
CallToolResultSchema,
|
|
804
961
|
{
|
|
@@ -810,7 +967,27 @@ var InternalMastraMCPClient = class extends MastraBase {
|
|
|
810
967
|
return res.structuredContent;
|
|
811
968
|
}
|
|
812
969
|
return res;
|
|
970
|
+
};
|
|
971
|
+
try {
|
|
972
|
+
return await executeToolCall();
|
|
813
973
|
} catch (e) {
|
|
974
|
+
if (this.isSessionError(e)) {
|
|
975
|
+
this.log("debug", `Session error detected for tool ${tool.name}, attempting reconnection...`, {
|
|
976
|
+
error: e instanceof Error ? e.message : String(e)
|
|
977
|
+
});
|
|
978
|
+
try {
|
|
979
|
+
await this.forceReconnect();
|
|
980
|
+
this.log("debug", `Retrying tool ${tool.name} after reconnection...`);
|
|
981
|
+
return await executeToolCall();
|
|
982
|
+
} catch (reconnectError) {
|
|
983
|
+
this.log("error", `Reconnection or retry failed for tool ${tool.name}`, {
|
|
984
|
+
originalError: e instanceof Error ? e.message : String(e),
|
|
985
|
+
reconnectError: reconnectError instanceof Error ? reconnectError.stack : String(reconnectError),
|
|
986
|
+
toolArgs: input
|
|
987
|
+
});
|
|
988
|
+
throw e;
|
|
989
|
+
}
|
|
990
|
+
}
|
|
814
991
|
this.log("error", `Error calling tool: ${tool.name}`, {
|
|
815
992
|
error: e instanceof Error ? e.stack : JSON.stringify(e, null, 2),
|
|
816
993
|
toolArgs: input
|
|
@@ -834,8 +1011,6 @@ var InternalMastraMCPClient = class extends MastraBase {
|
|
|
834
1011
|
return toolsRes;
|
|
835
1012
|
}
|
|
836
1013
|
};
|
|
837
|
-
|
|
838
|
-
// src/client/configuration.ts
|
|
839
1014
|
var mcpClientInstances = /* @__PURE__ */ new Map();
|
|
840
1015
|
var MCPClient = class extends MastraBase {
|
|
841
1016
|
serverConfigs = {};
|
|
@@ -908,6 +1083,48 @@ To fix this you have three different options:
|
|
|
908
1083
|
this.addToInstanceCache();
|
|
909
1084
|
return this;
|
|
910
1085
|
}
|
|
1086
|
+
/**
|
|
1087
|
+
* Provides access to progress-related operations for tracking long-running operations.
|
|
1088
|
+
*
|
|
1089
|
+
* Progress tracking allows MCP servers to send updates about the status of ongoing operations,
|
|
1090
|
+
* providing real-time feedback to users about task completion and current state.
|
|
1091
|
+
*
|
|
1092
|
+
* @example
|
|
1093
|
+
* ```typescript
|
|
1094
|
+
* // Set up handler for progress updates from a server
|
|
1095
|
+
* await mcp.progress.onUpdate('serverName', (params) => {
|
|
1096
|
+
* console.log(`Progress: ${params.progress}%`);
|
|
1097
|
+
* console.log(`Status: ${params.message}`);
|
|
1098
|
+
*
|
|
1099
|
+
* if (params.total) {
|
|
1100
|
+
* console.log(`Completed ${params.progress} of ${params.total} items`);
|
|
1101
|
+
* }
|
|
1102
|
+
* });
|
|
1103
|
+
* ```
|
|
1104
|
+
*/
|
|
1105
|
+
get progress() {
|
|
1106
|
+
this.addToInstanceCache();
|
|
1107
|
+
return {
|
|
1108
|
+
onUpdate: async (serverName, handler) => {
|
|
1109
|
+
try {
|
|
1110
|
+
const internalClient = await this.getConnectedClientForServer(serverName);
|
|
1111
|
+
return internalClient.progress.onUpdate(handler);
|
|
1112
|
+
} catch (err) {
|
|
1113
|
+
throw new MastraError(
|
|
1114
|
+
{
|
|
1115
|
+
id: "MCP_CLIENT_ON_UPDATE_PROGRESS_FAILED",
|
|
1116
|
+
domain: ErrorDomain.MCP,
|
|
1117
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1118
|
+
details: {
|
|
1119
|
+
serverName
|
|
1120
|
+
}
|
|
1121
|
+
},
|
|
1122
|
+
err
|
|
1123
|
+
);
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
1126
|
+
};
|
|
1127
|
+
}
|
|
911
1128
|
/**
|
|
912
1129
|
* Provides access to elicitation-related operations for interactive user input collection.
|
|
913
1130
|
*
|
|
@@ -2178,8 +2395,8 @@ var MCPServer = class extends MCPServerBase {
|
|
|
2178
2395
|
}
|
|
2179
2396
|
});
|
|
2180
2397
|
this.elicitation = {
|
|
2181
|
-
sendRequest: async (request) => {
|
|
2182
|
-
return this.handleElicitationRequest(request);
|
|
2398
|
+
sendRequest: async (request, options) => {
|
|
2399
|
+
return this.handleElicitationRequest(request, void 0, options);
|
|
2183
2400
|
}
|
|
2184
2401
|
};
|
|
2185
2402
|
}
|
|
@@ -2189,15 +2406,51 @@ var MCPServer = class extends MCPServerBase {
|
|
|
2189
2406
|
*
|
|
2190
2407
|
* @param request - The elicitation request containing message and schema
|
|
2191
2408
|
* @param serverInstance - Optional server instance to use; defaults to main server for backward compatibility
|
|
2409
|
+
* @param options - Optional request options (timeout, signal, etc.)
|
|
2192
2410
|
* @returns Promise that resolves to the client's response
|
|
2193
2411
|
*/
|
|
2194
|
-
async handleElicitationRequest(request, serverInstance) {
|
|
2412
|
+
async handleElicitationRequest(request, serverInstance, options) {
|
|
2195
2413
|
this.logger.debug(`Sending elicitation request: ${request.message}`);
|
|
2196
2414
|
const server = serverInstance || this.server;
|
|
2197
|
-
const response = await server.elicitInput(request);
|
|
2415
|
+
const response = await server.elicitInput(request, options);
|
|
2198
2416
|
this.logger.debug(`Received elicitation response: ${JSON.stringify(response)}`);
|
|
2199
2417
|
return response;
|
|
2200
2418
|
}
|
|
2419
|
+
/**
|
|
2420
|
+
* Reads and parses the JSON body from an HTTP request.
|
|
2421
|
+
* If the request body was already parsed by middleware (e.g., express.json()),
|
|
2422
|
+
* it uses the pre-parsed body from req.body. Otherwise, it reads from the stream.
|
|
2423
|
+
*
|
|
2424
|
+
* This allows the MCP server to work with Express apps that use express.json()
|
|
2425
|
+
* globally without requiring special route exclusions.
|
|
2426
|
+
*
|
|
2427
|
+
* @param req - The incoming HTTP request
|
|
2428
|
+
* @param options - Optional configuration
|
|
2429
|
+
* @param options.preParsedOnly - If true, only return pre-parsed body from middleware,
|
|
2430
|
+
* returning undefined if not available. This allows the caller to fall back to
|
|
2431
|
+
* their own body reading logic (e.g., SDK's getRawBody with size limits).
|
|
2432
|
+
*/
|
|
2433
|
+
async readJsonBody(req, options) {
|
|
2434
|
+
const reqWithBody = req;
|
|
2435
|
+
if (reqWithBody.body !== void 0) {
|
|
2436
|
+
return reqWithBody.body;
|
|
2437
|
+
}
|
|
2438
|
+
if (options?.preParsedOnly) {
|
|
2439
|
+
return void 0;
|
|
2440
|
+
}
|
|
2441
|
+
return new Promise((resolve, reject) => {
|
|
2442
|
+
let data = "";
|
|
2443
|
+
req.on("data", (chunk) => data += chunk);
|
|
2444
|
+
req.on("end", () => {
|
|
2445
|
+
try {
|
|
2446
|
+
resolve(JSON.parse(data));
|
|
2447
|
+
} catch (e) {
|
|
2448
|
+
reject(e);
|
|
2449
|
+
}
|
|
2450
|
+
});
|
|
2451
|
+
req.on("error", reject);
|
|
2452
|
+
});
|
|
2453
|
+
}
|
|
2201
2454
|
/**
|
|
2202
2455
|
* Creates a new Server instance configured with all handlers for HTTP sessions.
|
|
2203
2456
|
* Each HTTP client connection gets its own Server instance to avoid routing conflicts.
|
|
@@ -2283,8 +2536,8 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
2283
2536
|
};
|
|
2284
2537
|
}
|
|
2285
2538
|
const sessionElicitation = {
|
|
2286
|
-
sendRequest: async (request2) => {
|
|
2287
|
-
return this.handleElicitationRequest(request2, serverInstance);
|
|
2539
|
+
sendRequest: async (request2, options) => {
|
|
2540
|
+
return this.handleElicitationRequest(request2, serverInstance, options);
|
|
2288
2541
|
}
|
|
2289
2542
|
};
|
|
2290
2543
|
const mcpOptions = {
|
|
@@ -2586,7 +2839,9 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
2586
2839
|
try {
|
|
2587
2840
|
const proxiedContext = context?.requestContext || new RequestContext();
|
|
2588
2841
|
if (context?.mcp?.extra) {
|
|
2589
|
-
|
|
2842
|
+
Object.entries(context.mcp.extra).forEach(([key, value]) => {
|
|
2843
|
+
proxiedContext.set(key, value);
|
|
2844
|
+
});
|
|
2590
2845
|
}
|
|
2591
2846
|
const response = await agent.generate(inputData.message, {
|
|
2592
2847
|
...context ?? {},
|
|
@@ -2655,10 +2910,16 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
2655
2910
|
inputData
|
|
2656
2911
|
);
|
|
2657
2912
|
try {
|
|
2658
|
-
const
|
|
2913
|
+
const proxiedContext = context?.requestContext || new RequestContext();
|
|
2914
|
+
if (context?.mcp?.extra) {
|
|
2915
|
+
Object.entries(context.mcp.extra).forEach(([key, value]) => {
|
|
2916
|
+
proxiedContext.set(key, value);
|
|
2917
|
+
});
|
|
2918
|
+
}
|
|
2919
|
+
const run2 = await workflow.createRun({ runId: proxiedContext?.get("runId") });
|
|
2659
2920
|
const response = await run2.start({
|
|
2660
2921
|
inputData,
|
|
2661
|
-
requestContext:
|
|
2922
|
+
requestContext: proxiedContext,
|
|
2662
2923
|
tracingContext: context?.tracingContext
|
|
2663
2924
|
});
|
|
2664
2925
|
return response;
|
|
@@ -2814,7 +3075,7 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
2814
3075
|
*
|
|
2815
3076
|
* @example
|
|
2816
3077
|
* ```typescript
|
|
2817
|
-
* import http from 'http';
|
|
3078
|
+
* import http from 'node:http';
|
|
2818
3079
|
*
|
|
2819
3080
|
* const httpServer = http.createServer(async (req, res) => {
|
|
2820
3081
|
* await server.startSSE({
|
|
@@ -2845,7 +3106,8 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
2845
3106
|
res.end("SSE connection not established");
|
|
2846
3107
|
return;
|
|
2847
3108
|
}
|
|
2848
|
-
await this.
|
|
3109
|
+
const parsedBody = await this.readJsonBody(req, { preParsedOnly: true });
|
|
3110
|
+
await this.sseTransport.handlePostMessage(req, res, parsedBody);
|
|
2849
3111
|
} else {
|
|
2850
3112
|
this.logger.debug("Unknown path:", { path: url.pathname });
|
|
2851
3113
|
res.writeHead(404);
|
|
@@ -2972,8 +3234,8 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
2972
3234
|
*
|
|
2973
3235
|
* @example
|
|
2974
3236
|
* ```typescript
|
|
2975
|
-
* import http from 'http';
|
|
2976
|
-
* import { randomUUID } from 'crypto';
|
|
3237
|
+
* import http from 'node:http';
|
|
3238
|
+
* import { randomUUID } from 'node:crypto';
|
|
2977
3239
|
*
|
|
2978
3240
|
* const httpServer = http.createServer(async (req, res) => {
|
|
2979
3241
|
* await server.startHTTP({
|
|
@@ -3052,34 +3314,12 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
3052
3314
|
`startHTTP: Handling GET request for existing session ${sessionId}. Calling transport.handleRequest.`
|
|
3053
3315
|
);
|
|
3054
3316
|
}
|
|
3055
|
-
const body = req.method === "POST" ? await
|
|
3056
|
-
let data = "";
|
|
3057
|
-
req.on("data", (chunk) => data += chunk);
|
|
3058
|
-
req.on("end", () => {
|
|
3059
|
-
try {
|
|
3060
|
-
resolve(JSON.parse(data));
|
|
3061
|
-
} catch (e) {
|
|
3062
|
-
reject(e);
|
|
3063
|
-
}
|
|
3064
|
-
});
|
|
3065
|
-
req.on("error", reject);
|
|
3066
|
-
}) : void 0;
|
|
3317
|
+
const body = req.method === "POST" ? await this.readJsonBody(req) : void 0;
|
|
3067
3318
|
await transport.handleRequest(req, res, body);
|
|
3068
3319
|
} else {
|
|
3069
3320
|
this.logger.debug(`startHTTP: No existing Streamable HTTP session ID found. ${req.method}`);
|
|
3070
3321
|
if (req.method === "POST") {
|
|
3071
|
-
const body = await
|
|
3072
|
-
let data = "";
|
|
3073
|
-
req.on("data", (chunk) => data += chunk);
|
|
3074
|
-
req.on("end", () => {
|
|
3075
|
-
try {
|
|
3076
|
-
resolve(JSON.parse(data));
|
|
3077
|
-
} catch (e) {
|
|
3078
|
-
reject(e);
|
|
3079
|
-
}
|
|
3080
|
-
});
|
|
3081
|
-
req.on("error", reject);
|
|
3082
|
-
});
|
|
3322
|
+
const body = await this.readJsonBody(req);
|
|
3083
3323
|
const { isInitializeRequest } = await import('@modelcontextprotocol/sdk/types.js');
|
|
3084
3324
|
if (isInitializeRequest(body)) {
|
|
3085
3325
|
this.logger.debug("startHTTP: Received Streamable HTTP initialize request, creating new transport.");
|
|
@@ -3189,18 +3429,7 @@ Provided arguments: ${JSON.stringify(request.params.arguments, null, 2)}`
|
|
|
3189
3429
|
async handleServerlessRequest(req, res) {
|
|
3190
3430
|
try {
|
|
3191
3431
|
this.logger.debug(`handleServerlessRequest: Received ${req.method} request`);
|
|
3192
|
-
const body = req.method === "POST" ? await
|
|
3193
|
-
let data = "";
|
|
3194
|
-
req.on("data", (chunk) => data += chunk);
|
|
3195
|
-
req.on("end", () => {
|
|
3196
|
-
try {
|
|
3197
|
-
resolve(JSON.parse(data));
|
|
3198
|
-
} catch (e) {
|
|
3199
|
-
reject(new Error(`Invalid JSON in request body: ${e instanceof Error ? e.message : String(e)}`));
|
|
3200
|
-
}
|
|
3201
|
-
});
|
|
3202
|
-
req.on("error", reject);
|
|
3203
|
-
}) : void 0;
|
|
3432
|
+
const body = req.method === "POST" ? await this.readJsonBody(req) : void 0;
|
|
3204
3433
|
this.logger.debug(`handleServerlessRequest: Processing ${req.method} request`, {
|
|
3205
3434
|
method: body?.method,
|
|
3206
3435
|
id: body?.id
|
|
@@ -3631,6 +3860,6 @@ Provided arguments: ${JSON.stringify(args, null, 2)}`,
|
|
|
3631
3860
|
}
|
|
3632
3861
|
};
|
|
3633
3862
|
|
|
3634
|
-
export { MCPClient, MCPServer };
|
|
3863
|
+
export { InternalMastraMCPClient, MCPClient, MCPServer };
|
|
3635
3864
|
//# sourceMappingURL=index.js.map
|
|
3636
3865
|
//# sourceMappingURL=index.js.map
|