@mastra/mcp 0.10.4 → 0.10.5-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +7 -7
- package/CHANGELOG.md +28 -0
- package/dist/_tsup-dts-rollup.d.cts +88 -80
- package/dist/_tsup-dts-rollup.d.ts +88 -80
- package/dist/index.cjs +714 -168
- package/dist/index.js +699 -153
- package/integration-tests/node_modules/.bin/vitest +2 -2
- package/integration-tests/package.json +2 -2
- package/package.json +7 -7
- package/src/__fixtures__/tools.ts +0 -9
- package/src/client/client.ts +45 -1
- package/src/client/configuration.ts +166 -35
- package/src/server/promptActions.ts +13 -2
- package/src/server/resourceActions.ts +32 -4
- package/src/server/server.test.ts +84 -0
- package/src/server/server.ts +302 -114
- package/integration-tests/node_modules/.bin/mastra +0 -21
package/dist/index.cjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var base = require('@mastra/core/base');
|
|
4
|
+
var error = require('@mastra/core/error');
|
|
4
5
|
var tools = require('@mastra/core/tools');
|
|
5
6
|
var utils = require('@mastra/core/utils');
|
|
6
7
|
var index_js$1 = require('@modelcontextprotocol/sdk/client/index.js');
|
|
@@ -22,7 +23,6 @@ var index_js = require('@modelcontextprotocol/sdk/server/index.js');
|
|
|
22
23
|
var sse_js = require('@modelcontextprotocol/sdk/server/sse.js');
|
|
23
24
|
var stdio_js = require('@modelcontextprotocol/sdk/server/stdio.js');
|
|
24
25
|
var streamableHttp_js = require('@modelcontextprotocol/sdk/server/streamableHttp.js');
|
|
25
|
-
var streaming = require('hono/streaming');
|
|
26
26
|
|
|
27
27
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
28
28
|
|
|
@@ -483,22 +483,57 @@ var InternalMastraMCPClient = class extends base.MastraBase {
|
|
|
483
483
|
}
|
|
484
484
|
try {
|
|
485
485
|
return zodFromJsonSchema.convertJsonSchemaToZod(inputSchema);
|
|
486
|
-
} catch (error) {
|
|
486
|
+
} catch (error$1) {
|
|
487
487
|
let errorDetails;
|
|
488
|
-
if (error instanceof Error) {
|
|
489
|
-
errorDetails = error.stack;
|
|
488
|
+
if (error$1 instanceof Error) {
|
|
489
|
+
errorDetails = error$1.stack;
|
|
490
490
|
} else {
|
|
491
491
|
try {
|
|
492
|
-
errorDetails = JSON.stringify(error);
|
|
492
|
+
errorDetails = JSON.stringify(error$1);
|
|
493
493
|
} catch {
|
|
494
|
-
errorDetails = String(error);
|
|
494
|
+
errorDetails = String(error$1);
|
|
495
495
|
}
|
|
496
496
|
}
|
|
497
497
|
this.log("error", "Failed to convert JSON schema to Zod schema using zodFromJsonSchema", {
|
|
498
498
|
error: errorDetails,
|
|
499
499
|
originalJsonSchema: inputSchema
|
|
500
500
|
});
|
|
501
|
-
throw new
|
|
501
|
+
throw new error.MastraError({
|
|
502
|
+
id: "MCP_TOOL_INPUT_SCHEMA_CONVERSION_FAILED",
|
|
503
|
+
domain: error.ErrorDomain.MCP,
|
|
504
|
+
category: error.ErrorCategory.USER,
|
|
505
|
+
details: { error: errorDetails ?? "Unknown error" }
|
|
506
|
+
});
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
convertOutputSchema(outputSchema) {
|
|
510
|
+
if (!outputSchema) return;
|
|
511
|
+
if (utils.isZodType(outputSchema)) {
|
|
512
|
+
return outputSchema;
|
|
513
|
+
}
|
|
514
|
+
try {
|
|
515
|
+
return zodFromJsonSchema.convertJsonSchemaToZod(outputSchema);
|
|
516
|
+
} catch (error$1) {
|
|
517
|
+
let errorDetails;
|
|
518
|
+
if (error$1 instanceof Error) {
|
|
519
|
+
errorDetails = error$1.stack;
|
|
520
|
+
} else {
|
|
521
|
+
try {
|
|
522
|
+
errorDetails = JSON.stringify(error$1);
|
|
523
|
+
} catch {
|
|
524
|
+
errorDetails = String(error$1);
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
this.log("error", "Failed to convert JSON schema to Zod schema using zodFromJsonSchema", {
|
|
528
|
+
error: errorDetails,
|
|
529
|
+
originalJsonSchema: outputSchema
|
|
530
|
+
});
|
|
531
|
+
throw new error.MastraError({
|
|
532
|
+
id: "MCP_TOOL_OUTPUT_SCHEMA_CONVERSION_FAILED",
|
|
533
|
+
domain: error.ErrorDomain.MCP,
|
|
534
|
+
category: error.ErrorCategory.USER,
|
|
535
|
+
details: { error: errorDetails ?? "Unknown error" }
|
|
536
|
+
});
|
|
502
537
|
}
|
|
503
538
|
}
|
|
504
539
|
async tools() {
|
|
@@ -512,6 +547,7 @@ var InternalMastraMCPClient = class extends base.MastraBase {
|
|
|
512
547
|
id: `${this.name}_${tool.name}`,
|
|
513
548
|
description: tool.description || "",
|
|
514
549
|
inputSchema: this.convertInputSchema(tool.inputSchema),
|
|
550
|
+
outputSchema: this.convertOutputSchema(tool.outputSchema),
|
|
515
551
|
execute: async ({ context, runtimeContext }) => {
|
|
516
552
|
const previousContext = this.currentOperationContext;
|
|
517
553
|
this.currentOperationContext = runtimeContext || null;
|
|
@@ -614,8 +650,17 @@ To fix this you have three different options:
|
|
|
614
650
|
try {
|
|
615
651
|
const internalClient = await this.getConnectedClientForServer(serverName);
|
|
616
652
|
allResources[serverName] = await internalClient.resources.list();
|
|
617
|
-
} catch (error) {
|
|
618
|
-
|
|
653
|
+
} catch (error$1) {
|
|
654
|
+
const mastraError = new error.MastraError({
|
|
655
|
+
id: "MCP_CLIENT_LIST_RESOURCES_FAILED",
|
|
656
|
+
domain: error.ErrorDomain.MCP,
|
|
657
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
658
|
+
details: {
|
|
659
|
+
serverName
|
|
660
|
+
}
|
|
661
|
+
}, error$1);
|
|
662
|
+
this.logger.trackException(mastraError);
|
|
663
|
+
this.logger.error("Failed to list resources from server:", { error: mastraError.toString() });
|
|
619
664
|
}
|
|
620
665
|
}
|
|
621
666
|
return allResources;
|
|
@@ -626,31 +671,98 @@ To fix this you have three different options:
|
|
|
626
671
|
try {
|
|
627
672
|
const internalClient = await this.getConnectedClientForServer(serverName);
|
|
628
673
|
allTemplates[serverName] = await internalClient.resources.templates();
|
|
629
|
-
} catch (error) {
|
|
630
|
-
|
|
674
|
+
} catch (error$1) {
|
|
675
|
+
const mastraError = new error.MastraError({
|
|
676
|
+
id: "MCP_CLIENT_LIST_RESOURCE_TEMPLATES_FAILED",
|
|
677
|
+
domain: error.ErrorDomain.MCP,
|
|
678
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
679
|
+
details: {
|
|
680
|
+
serverName
|
|
681
|
+
}
|
|
682
|
+
}, error$1);
|
|
683
|
+
this.logger.trackException(mastraError);
|
|
684
|
+
this.logger.error("Failed to list resource templates from server:", { error: mastraError.toString() });
|
|
631
685
|
}
|
|
632
686
|
}
|
|
633
687
|
return allTemplates;
|
|
634
688
|
},
|
|
635
689
|
read: async (serverName, uri) => {
|
|
636
|
-
|
|
637
|
-
|
|
690
|
+
try {
|
|
691
|
+
const internalClient = await this.getConnectedClientForServer(serverName);
|
|
692
|
+
return internalClient.resources.read(uri);
|
|
693
|
+
} catch (error$1) {
|
|
694
|
+
throw new error.MastraError({
|
|
695
|
+
id: "MCP_CLIENT_READ_RESOURCE_FAILED",
|
|
696
|
+
domain: error.ErrorDomain.MCP,
|
|
697
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
698
|
+
details: {
|
|
699
|
+
serverName,
|
|
700
|
+
uri
|
|
701
|
+
}
|
|
702
|
+
}, error$1);
|
|
703
|
+
}
|
|
638
704
|
},
|
|
639
705
|
subscribe: async (serverName, uri) => {
|
|
640
|
-
|
|
641
|
-
|
|
706
|
+
try {
|
|
707
|
+
const internalClient = await this.getConnectedClientForServer(serverName);
|
|
708
|
+
return internalClient.resources.subscribe(uri);
|
|
709
|
+
} catch (error$1) {
|
|
710
|
+
throw new error.MastraError({
|
|
711
|
+
id: "MCP_CLIENT_SUBSCRIBE_RESOURCE_FAILED",
|
|
712
|
+
domain: error.ErrorDomain.MCP,
|
|
713
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
714
|
+
details: {
|
|
715
|
+
serverName,
|
|
716
|
+
uri
|
|
717
|
+
}
|
|
718
|
+
}, error$1);
|
|
719
|
+
}
|
|
642
720
|
},
|
|
643
721
|
unsubscribe: async (serverName, uri) => {
|
|
644
|
-
|
|
645
|
-
|
|
722
|
+
try {
|
|
723
|
+
const internalClient = await this.getConnectedClientForServer(serverName);
|
|
724
|
+
return internalClient.resources.unsubscribe(uri);
|
|
725
|
+
} catch (err) {
|
|
726
|
+
throw new error.MastraError({
|
|
727
|
+
id: "MCP_CLIENT_UNSUBSCRIBE_RESOURCE_FAILED",
|
|
728
|
+
domain: error.ErrorDomain.MCP,
|
|
729
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
730
|
+
details: {
|
|
731
|
+
serverName,
|
|
732
|
+
uri
|
|
733
|
+
}
|
|
734
|
+
}, err);
|
|
735
|
+
}
|
|
646
736
|
},
|
|
647
737
|
onUpdated: async (serverName, handler) => {
|
|
648
|
-
|
|
649
|
-
|
|
738
|
+
try {
|
|
739
|
+
const internalClient = await this.getConnectedClientForServer(serverName);
|
|
740
|
+
return internalClient.resources.onUpdated(handler);
|
|
741
|
+
} catch (err) {
|
|
742
|
+
throw new error.MastraError({
|
|
743
|
+
id: "MCP_CLIENT_ON_UPDATED_RESOURCE_FAILED",
|
|
744
|
+
domain: error.ErrorDomain.MCP,
|
|
745
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
746
|
+
details: {
|
|
747
|
+
serverName
|
|
748
|
+
}
|
|
749
|
+
}, err);
|
|
750
|
+
}
|
|
650
751
|
},
|
|
651
752
|
onListChanged: async (serverName, handler) => {
|
|
652
|
-
|
|
653
|
-
|
|
753
|
+
try {
|
|
754
|
+
const internalClient = await this.getConnectedClientForServer(serverName);
|
|
755
|
+
return internalClient.resources.onListChanged(handler);
|
|
756
|
+
} catch (err) {
|
|
757
|
+
throw new error.MastraError({
|
|
758
|
+
id: "MCP_CLIENT_ON_LIST_CHANGED_RESOURCE_FAILED",
|
|
759
|
+
domain: error.ErrorDomain.MCP,
|
|
760
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
761
|
+
details: {
|
|
762
|
+
serverName
|
|
763
|
+
}
|
|
764
|
+
}, err);
|
|
765
|
+
}
|
|
654
766
|
}
|
|
655
767
|
};
|
|
656
768
|
}
|
|
@@ -663,19 +775,51 @@ To fix this you have three different options:
|
|
|
663
775
|
try {
|
|
664
776
|
const internalClient = await this.getConnectedClientForServer(serverName);
|
|
665
777
|
allPrompts[serverName] = await internalClient.prompts.list();
|
|
666
|
-
} catch (error) {
|
|
667
|
-
|
|
778
|
+
} catch (error$1) {
|
|
779
|
+
const mastraError = new error.MastraError({
|
|
780
|
+
id: "MCP_CLIENT_LIST_PROMPTS_FAILED",
|
|
781
|
+
domain: error.ErrorDomain.MCP,
|
|
782
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
783
|
+
details: {
|
|
784
|
+
serverName
|
|
785
|
+
}
|
|
786
|
+
}, error$1);
|
|
787
|
+
this.logger.trackException(mastraError);
|
|
788
|
+
this.logger.error("Failed to list prompts from server:", { error: mastraError.toString() });
|
|
668
789
|
}
|
|
669
790
|
}
|
|
670
791
|
return allPrompts;
|
|
671
792
|
},
|
|
672
793
|
get: async ({ serverName, name, args, version }) => {
|
|
673
|
-
|
|
674
|
-
|
|
794
|
+
try {
|
|
795
|
+
const internalClient = await this.getConnectedClientForServer(serverName);
|
|
796
|
+
return internalClient.prompts.get({ name, args, version });
|
|
797
|
+
} catch (error$1) {
|
|
798
|
+
throw new error.MastraError({
|
|
799
|
+
id: "MCP_CLIENT_GET_PROMPT_FAILED",
|
|
800
|
+
domain: error.ErrorDomain.MCP,
|
|
801
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
802
|
+
details: {
|
|
803
|
+
serverName,
|
|
804
|
+
name
|
|
805
|
+
}
|
|
806
|
+
}, error$1);
|
|
807
|
+
}
|
|
675
808
|
},
|
|
676
809
|
onListChanged: async (serverName, handler) => {
|
|
677
|
-
|
|
678
|
-
|
|
810
|
+
try {
|
|
811
|
+
const internalClient = await this.getConnectedClientForServer(serverName);
|
|
812
|
+
return internalClient.prompts.onListChanged(handler);
|
|
813
|
+
} catch (error$1) {
|
|
814
|
+
throw new error.MastraError({
|
|
815
|
+
id: "MCP_CLIENT_ON_LIST_CHANGED_PROMPT_FAILED",
|
|
816
|
+
domain: error.ErrorDomain.MCP,
|
|
817
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
818
|
+
details: {
|
|
819
|
+
serverName
|
|
820
|
+
}
|
|
821
|
+
}, error$1);
|
|
822
|
+
}
|
|
679
823
|
}
|
|
680
824
|
};
|
|
681
825
|
}
|
|
@@ -707,21 +851,37 @@ To fix this you have three different options:
|
|
|
707
851
|
async getTools() {
|
|
708
852
|
this.addToInstanceCache();
|
|
709
853
|
const connectedTools = {};
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
854
|
+
try {
|
|
855
|
+
await this.eachClientTools(async ({ serverName, tools }) => {
|
|
856
|
+
for (const [toolName, toolConfig] of Object.entries(tools)) {
|
|
857
|
+
connectedTools[`${serverName}_${toolName}`] = toolConfig;
|
|
858
|
+
}
|
|
859
|
+
});
|
|
860
|
+
} catch (error$1) {
|
|
861
|
+
throw new error.MastraError({
|
|
862
|
+
id: "MCP_CLIENT_GET_TOOLS_FAILED",
|
|
863
|
+
domain: error.ErrorDomain.MCP,
|
|
864
|
+
category: error.ErrorCategory.THIRD_PARTY
|
|
865
|
+
}, error$1);
|
|
866
|
+
}
|
|
715
867
|
return connectedTools;
|
|
716
868
|
}
|
|
717
869
|
async getToolsets() {
|
|
718
870
|
this.addToInstanceCache();
|
|
719
871
|
const connectedToolsets = {};
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
872
|
+
try {
|
|
873
|
+
await this.eachClientTools(async ({ serverName, tools }) => {
|
|
874
|
+
if (tools) {
|
|
875
|
+
connectedToolsets[serverName] = tools;
|
|
876
|
+
}
|
|
877
|
+
});
|
|
878
|
+
} catch (error$1) {
|
|
879
|
+
throw new error.MastraError({
|
|
880
|
+
id: "MCP_CLIENT_GET_TOOLSETS_FAILED",
|
|
881
|
+
domain: error.ErrorDomain.MCP,
|
|
882
|
+
category: error.ErrorCategory.THIRD_PARTY
|
|
883
|
+
}, error$1);
|
|
884
|
+
}
|
|
725
885
|
return connectedToolsets;
|
|
726
886
|
}
|
|
727
887
|
/**
|
|
@@ -768,13 +928,19 @@ To fix this you have three different options:
|
|
|
768
928
|
try {
|
|
769
929
|
await mcpClient.connect();
|
|
770
930
|
} catch (e) {
|
|
931
|
+
const mastraError = new error.MastraError({
|
|
932
|
+
id: "MCP_CLIENT_CONNECT_FAILED",
|
|
933
|
+
domain: error.ErrorDomain.MCP,
|
|
934
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
935
|
+
text: `Failed to connect to MCP server ${name}: ${e instanceof Error ? e.stack || e.message : String(e)}`,
|
|
936
|
+
details: {
|
|
937
|
+
name
|
|
938
|
+
}
|
|
939
|
+
}, e);
|
|
940
|
+
this.logger.trackException(mastraError);
|
|
941
|
+
this.logger.error("MCPClient errored connecting to MCP server:", { error: mastraError.toString() });
|
|
771
942
|
this.mcpClientsById.delete(name);
|
|
772
|
-
|
|
773
|
-
error: e instanceof Error ? e.message : String(e)
|
|
774
|
-
});
|
|
775
|
-
throw new Error(
|
|
776
|
-
`Failed to connect to MCP server ${name}: ${e instanceof Error ? e.stack || e.message : String(e)}`
|
|
777
|
-
);
|
|
943
|
+
throw mastraError;
|
|
778
944
|
}
|
|
779
945
|
this.logger.debug(`Connected to ${name} MCP server`);
|
|
780
946
|
return mcpClient;
|
|
@@ -804,6 +970,165 @@ var MCPConfiguration = class extends MCPClient {
|
|
|
804
970
|
);
|
|
805
971
|
}
|
|
806
972
|
};
|
|
973
|
+
|
|
974
|
+
// ../../node_modules/.pnpm/hono@4.8.1/node_modules/hono/dist/utils/stream.js
|
|
975
|
+
var StreamingApi = class {
|
|
976
|
+
writer;
|
|
977
|
+
encoder;
|
|
978
|
+
writable;
|
|
979
|
+
abortSubscribers = [];
|
|
980
|
+
responseReadable;
|
|
981
|
+
aborted = false;
|
|
982
|
+
closed = false;
|
|
983
|
+
constructor(writable, _readable) {
|
|
984
|
+
this.writable = writable;
|
|
985
|
+
this.writer = writable.getWriter();
|
|
986
|
+
this.encoder = new TextEncoder();
|
|
987
|
+
const reader = _readable.getReader();
|
|
988
|
+
this.abortSubscribers.push(async () => {
|
|
989
|
+
await reader.cancel();
|
|
990
|
+
});
|
|
991
|
+
this.responseReadable = new ReadableStream({
|
|
992
|
+
async pull(controller) {
|
|
993
|
+
const { done, value } = await reader.read();
|
|
994
|
+
done ? controller.close() : controller.enqueue(value);
|
|
995
|
+
},
|
|
996
|
+
cancel: () => {
|
|
997
|
+
this.abort();
|
|
998
|
+
}
|
|
999
|
+
});
|
|
1000
|
+
}
|
|
1001
|
+
async write(input) {
|
|
1002
|
+
try {
|
|
1003
|
+
if (typeof input === "string") {
|
|
1004
|
+
input = this.encoder.encode(input);
|
|
1005
|
+
}
|
|
1006
|
+
await this.writer.write(input);
|
|
1007
|
+
} catch {
|
|
1008
|
+
}
|
|
1009
|
+
return this;
|
|
1010
|
+
}
|
|
1011
|
+
async writeln(input) {
|
|
1012
|
+
await this.write(input + "\n");
|
|
1013
|
+
return this;
|
|
1014
|
+
}
|
|
1015
|
+
sleep(ms) {
|
|
1016
|
+
return new Promise((res) => setTimeout(res, ms));
|
|
1017
|
+
}
|
|
1018
|
+
async close() {
|
|
1019
|
+
try {
|
|
1020
|
+
await this.writer.close();
|
|
1021
|
+
} catch {
|
|
1022
|
+
}
|
|
1023
|
+
this.closed = true;
|
|
1024
|
+
}
|
|
1025
|
+
async pipe(body) {
|
|
1026
|
+
this.writer.releaseLock();
|
|
1027
|
+
await body.pipeTo(this.writable, { preventClose: true });
|
|
1028
|
+
this.writer = this.writable.getWriter();
|
|
1029
|
+
}
|
|
1030
|
+
onAbort(listener) {
|
|
1031
|
+
this.abortSubscribers.push(listener);
|
|
1032
|
+
}
|
|
1033
|
+
abort() {
|
|
1034
|
+
if (!this.aborted) {
|
|
1035
|
+
this.aborted = true;
|
|
1036
|
+
this.abortSubscribers.forEach((subscriber) => subscriber());
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
};
|
|
1040
|
+
|
|
1041
|
+
// ../../node_modules/.pnpm/hono@4.8.1/node_modules/hono/dist/helper/streaming/utils.js
|
|
1042
|
+
var isOldBunVersion = () => {
|
|
1043
|
+
const version = typeof Bun !== "undefined" ? Bun.version : void 0;
|
|
1044
|
+
if (version === void 0) {
|
|
1045
|
+
return false;
|
|
1046
|
+
}
|
|
1047
|
+
const result = version.startsWith("1.1") || version.startsWith("1.0") || version.startsWith("0.");
|
|
1048
|
+
isOldBunVersion = () => result;
|
|
1049
|
+
return result;
|
|
1050
|
+
};
|
|
1051
|
+
|
|
1052
|
+
// ../../node_modules/.pnpm/hono@4.8.1/node_modules/hono/dist/utils/html.js
|
|
1053
|
+
var HtmlEscapedCallbackPhase = {
|
|
1054
|
+
Stringify: 1};
|
|
1055
|
+
var resolveCallback = async (str, phase, preserveCallbacks, context, buffer) => {
|
|
1056
|
+
if (typeof str === "object" && !(str instanceof String)) {
|
|
1057
|
+
if (!(str instanceof Promise)) {
|
|
1058
|
+
str = str.toString();
|
|
1059
|
+
}
|
|
1060
|
+
if (str instanceof Promise) {
|
|
1061
|
+
str = await str;
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
const callbacks = str.callbacks;
|
|
1065
|
+
if (!callbacks?.length) {
|
|
1066
|
+
return Promise.resolve(str);
|
|
1067
|
+
}
|
|
1068
|
+
if (buffer) {
|
|
1069
|
+
buffer[0] += str;
|
|
1070
|
+
} else {
|
|
1071
|
+
buffer = [str];
|
|
1072
|
+
}
|
|
1073
|
+
const resStr = Promise.all(callbacks.map((c) => c({ phase, buffer, context }))).then(
|
|
1074
|
+
(res) => Promise.all(
|
|
1075
|
+
res.filter(Boolean).map((str2) => resolveCallback(str2, phase, false, context, buffer))
|
|
1076
|
+
).then(() => buffer[0])
|
|
1077
|
+
);
|
|
1078
|
+
{
|
|
1079
|
+
return resStr;
|
|
1080
|
+
}
|
|
1081
|
+
};
|
|
1082
|
+
|
|
1083
|
+
// ../../node_modules/.pnpm/hono@4.8.1/node_modules/hono/dist/helper/streaming/sse.js
|
|
1084
|
+
var SSEStreamingApi = class extends StreamingApi {
|
|
1085
|
+
constructor(writable, readable) {
|
|
1086
|
+
super(writable, readable);
|
|
1087
|
+
}
|
|
1088
|
+
async writeSSE(message) {
|
|
1089
|
+
const data = await resolveCallback(message.data, HtmlEscapedCallbackPhase.Stringify, false, {});
|
|
1090
|
+
const dataLines = data.split("\n").map((line) => {
|
|
1091
|
+
return `data: ${line}`;
|
|
1092
|
+
}).join("\n");
|
|
1093
|
+
const sseData = [
|
|
1094
|
+
message.event && `event: ${message.event}`,
|
|
1095
|
+
dataLines,
|
|
1096
|
+
message.id && `id: ${message.id}`,
|
|
1097
|
+
message.retry && `retry: ${message.retry}`
|
|
1098
|
+
].filter(Boolean).join("\n") + "\n\n";
|
|
1099
|
+
await this.write(sseData);
|
|
1100
|
+
}
|
|
1101
|
+
};
|
|
1102
|
+
var run = async (stream2, cb, onError) => {
|
|
1103
|
+
try {
|
|
1104
|
+
await cb(stream2);
|
|
1105
|
+
} catch (e) {
|
|
1106
|
+
{
|
|
1107
|
+
console.error(e);
|
|
1108
|
+
}
|
|
1109
|
+
} finally {
|
|
1110
|
+
stream2.close();
|
|
1111
|
+
}
|
|
1112
|
+
};
|
|
1113
|
+
var contextStash = /* @__PURE__ */ new WeakMap();
|
|
1114
|
+
var streamSSE = (c, cb, onError) => {
|
|
1115
|
+
const { readable, writable } = new TransformStream();
|
|
1116
|
+
const stream2 = new SSEStreamingApi(writable, readable);
|
|
1117
|
+
if (isOldBunVersion()) {
|
|
1118
|
+
c.req.raw.signal.addEventListener("abort", () => {
|
|
1119
|
+
if (!stream2.closed) {
|
|
1120
|
+
stream2.abort();
|
|
1121
|
+
}
|
|
1122
|
+
});
|
|
1123
|
+
}
|
|
1124
|
+
contextStash.set(stream2.responseReadable, c);
|
|
1125
|
+
c.header("Transfer-Encoding", "chunked");
|
|
1126
|
+
c.header("Content-Type", "text/event-stream");
|
|
1127
|
+
c.header("Cache-Control", "no-cache");
|
|
1128
|
+
c.header("Connection", "keep-alive");
|
|
1129
|
+
run(stream2, cb);
|
|
1130
|
+
return c.newResponse(stream2.responseReadable);
|
|
1131
|
+
};
|
|
807
1132
|
var MAXIMUM_MESSAGE_SIZE = 4 * 1024 * 1024;
|
|
808
1133
|
var SSETransport = class {
|
|
809
1134
|
messageUrl;
|
|
@@ -815,9 +1140,9 @@ var SSETransport = class {
|
|
|
815
1140
|
/**
|
|
816
1141
|
* Creates a new SSETransport, which will direct the MPC client to POST messages to messageUrl
|
|
817
1142
|
*/
|
|
818
|
-
constructor(messageUrl,
|
|
1143
|
+
constructor(messageUrl, stream2) {
|
|
819
1144
|
this.messageUrl = messageUrl;
|
|
820
|
-
this.stream =
|
|
1145
|
+
this.stream = stream2;
|
|
821
1146
|
this._sessionId = crypto.randomUUID();
|
|
822
1147
|
this.stream.onAbort(() => {
|
|
823
1148
|
void this.close();
|
|
@@ -834,6 +1159,10 @@ var SSETransport = class {
|
|
|
834
1159
|
if (this.stream.closed) {
|
|
835
1160
|
throw new Error("SSE transport already closed!");
|
|
836
1161
|
}
|
|
1162
|
+
await this.stream.writeSSE({
|
|
1163
|
+
event: "ping",
|
|
1164
|
+
data: ""
|
|
1165
|
+
});
|
|
837
1166
|
await this.stream.writeSSE({
|
|
838
1167
|
event: "endpoint",
|
|
839
1168
|
data: `${this.messageUrl}?sessionId=${this.sessionId}`
|
|
@@ -888,8 +1217,6 @@ var SSETransport = class {
|
|
|
888
1217
|
});
|
|
889
1218
|
}
|
|
890
1219
|
};
|
|
891
|
-
|
|
892
|
-
// src/server/promptActions.ts
|
|
893
1220
|
var ServerPromptActions = class {
|
|
894
1221
|
getLogger;
|
|
895
1222
|
getSdkServer;
|
|
@@ -908,16 +1235,24 @@ var ServerPromptActions = class {
|
|
|
908
1235
|
this.clearDefinedPrompts();
|
|
909
1236
|
try {
|
|
910
1237
|
await this.getSdkServer().sendPromptListChanged();
|
|
911
|
-
} catch (error) {
|
|
1238
|
+
} catch (error$1) {
|
|
1239
|
+
const mastraError = new error.MastraError(
|
|
1240
|
+
{
|
|
1241
|
+
id: "MCP_SERVER_PROMPT_LIST_CHANGED_NOTIFICATION_FAILED",
|
|
1242
|
+
domain: error.ErrorDomain.MCP,
|
|
1243
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
1244
|
+
text: "Failed to send prompt list changed notification"
|
|
1245
|
+
},
|
|
1246
|
+
error$1
|
|
1247
|
+
);
|
|
912
1248
|
this.getLogger().error("Failed to send prompt list changed notification:", {
|
|
913
|
-
error:
|
|
1249
|
+
error: mastraError.toString()
|
|
914
1250
|
});
|
|
915
|
-
|
|
1251
|
+
this.getLogger().trackException(mastraError);
|
|
1252
|
+
throw mastraError;
|
|
916
1253
|
}
|
|
917
1254
|
}
|
|
918
1255
|
};
|
|
919
|
-
|
|
920
|
-
// src/server/resourceActions.ts
|
|
921
1256
|
var ServerResourceActions = class {
|
|
922
1257
|
getSubscriptions;
|
|
923
1258
|
getLogger;
|
|
@@ -940,9 +1275,24 @@ var ServerResourceActions = class {
|
|
|
940
1275
|
this.getLogger().info(`Sending notifications/resources/updated for externally notified resource: ${uri}`);
|
|
941
1276
|
try {
|
|
942
1277
|
await this.getSdkServer().sendResourceUpdated({ uri });
|
|
943
|
-
} catch (error) {
|
|
944
|
-
|
|
945
|
-
|
|
1278
|
+
} catch (error$1) {
|
|
1279
|
+
const mastraError = new error.MastraError(
|
|
1280
|
+
{
|
|
1281
|
+
id: "MCP_SERVER_RESOURCE_UPDATED_NOTIFICATION_FAILED",
|
|
1282
|
+
domain: error.ErrorDomain.MCP,
|
|
1283
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
1284
|
+
text: "Failed to send resource updated notification",
|
|
1285
|
+
details: {
|
|
1286
|
+
uri
|
|
1287
|
+
}
|
|
1288
|
+
},
|
|
1289
|
+
error$1
|
|
1290
|
+
);
|
|
1291
|
+
this.getLogger().trackException(mastraError);
|
|
1292
|
+
this.getLogger().error("Failed to send resource updated notification:", {
|
|
1293
|
+
error: mastraError.toString()
|
|
1294
|
+
});
|
|
1295
|
+
throw mastraError;
|
|
946
1296
|
}
|
|
947
1297
|
} else {
|
|
948
1298
|
this.getLogger().debug(`Resource ${uri} was updated, but no active subscriptions for it.`);
|
|
@@ -960,9 +1310,21 @@ var ServerResourceActions = class {
|
|
|
960
1310
|
this.clearDefinedResourceTemplates();
|
|
961
1311
|
try {
|
|
962
1312
|
await this.getSdkServer().sendResourceListChanged();
|
|
963
|
-
} catch (error) {
|
|
964
|
-
|
|
965
|
-
|
|
1313
|
+
} catch (error$1) {
|
|
1314
|
+
const mastraError = new error.MastraError(
|
|
1315
|
+
{
|
|
1316
|
+
id: "MCP_SERVER_RESOURCE_LIST_CHANGED_NOTIFICATION_FAILED",
|
|
1317
|
+
domain: error.ErrorDomain.MCP,
|
|
1318
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
1319
|
+
text: "Failed to send resource list changed notification"
|
|
1320
|
+
},
|
|
1321
|
+
error$1
|
|
1322
|
+
);
|
|
1323
|
+
this.getLogger().trackException(mastraError);
|
|
1324
|
+
this.getLogger().error("Failed to send resource list changed notification:", {
|
|
1325
|
+
error: mastraError.toString()
|
|
1326
|
+
});
|
|
1327
|
+
throw mastraError;
|
|
966
1328
|
}
|
|
967
1329
|
}
|
|
968
1330
|
};
|
|
@@ -1172,8 +1534,8 @@ var MCPServer = class extends mcp.MCPServerBase {
|
|
|
1172
1534
|
context
|
|
1173
1535
|
);
|
|
1174
1536
|
try {
|
|
1175
|
-
const
|
|
1176
|
-
const response = await
|
|
1537
|
+
const run2 = workflow.createRun({ runId: runtimeContext?.get("runId") });
|
|
1538
|
+
const response = await run2.start({ inputData: context, runtimeContext });
|
|
1177
1539
|
return response;
|
|
1178
1540
|
} catch (error) {
|
|
1179
1541
|
this.logger.error(
|
|
@@ -1196,6 +1558,7 @@ var MCPServer = class extends mcp.MCPServerBase {
|
|
|
1196
1558
|
name: workflowToolName,
|
|
1197
1559
|
description: coreTool.description,
|
|
1198
1560
|
parameters: coreTool.parameters,
|
|
1561
|
+
outputSchema: coreTool.outputSchema,
|
|
1199
1562
|
execute: coreTool.execute,
|
|
1200
1563
|
toolType: "workflow"
|
|
1201
1564
|
};
|
|
@@ -1235,13 +1598,32 @@ var MCPServer = class extends mcp.MCPServerBase {
|
|
|
1235
1598
|
name: toolName,
|
|
1236
1599
|
description: coreTool.description,
|
|
1237
1600
|
parameters: coreTool.parameters,
|
|
1601
|
+
outputSchema: coreTool.outputSchema,
|
|
1238
1602
|
execute: coreTool.execute
|
|
1239
1603
|
};
|
|
1240
1604
|
this.logger.info(`Registered explicit tool: '${toolName}'`);
|
|
1241
1605
|
}
|
|
1242
1606
|
this.logger.info(`Total defined tools registered: ${Object.keys(definedConvertedTools).length}`);
|
|
1243
|
-
|
|
1244
|
-
|
|
1607
|
+
let agentDerivedTools = {};
|
|
1608
|
+
let workflowDerivedTools = {};
|
|
1609
|
+
try {
|
|
1610
|
+
agentDerivedTools = this.convertAgentsToTools(agentsConfig, definedConvertedTools);
|
|
1611
|
+
workflowDerivedTools = this.convertWorkflowsToTools(workflowsConfig, definedConvertedTools);
|
|
1612
|
+
} catch (e) {
|
|
1613
|
+
const mastraError = new error.MastraError(
|
|
1614
|
+
{
|
|
1615
|
+
id: "MCP_SERVER_AGENT_OR_WORKFLOW_TOOL_CONVERSION_FAILED",
|
|
1616
|
+
domain: error.ErrorDomain.MCP,
|
|
1617
|
+
category: error.ErrorCategory.USER
|
|
1618
|
+
},
|
|
1619
|
+
e
|
|
1620
|
+
);
|
|
1621
|
+
this.logger.trackException(mastraError);
|
|
1622
|
+
this.logger.error("Failed to convert tools:", {
|
|
1623
|
+
error: mastraError.toString()
|
|
1624
|
+
});
|
|
1625
|
+
throw mastraError;
|
|
1626
|
+
}
|
|
1245
1627
|
const allConvertedTools = { ...definedConvertedTools, ...agentDerivedTools, ...workflowDerivedTools };
|
|
1246
1628
|
const finalToolCount = Object.keys(allConvertedTools).length;
|
|
1247
1629
|
const definedCount = Object.keys(definedConvertedTools).length;
|
|
@@ -1263,11 +1645,17 @@ var MCPServer = class extends mcp.MCPServerBase {
|
|
|
1263
1645
|
this.server.setRequestHandler(types_js.ListToolsRequestSchema, async () => {
|
|
1264
1646
|
this.logger.debug("Handling ListTools request");
|
|
1265
1647
|
return {
|
|
1266
|
-
tools: Object.values(this.convertedTools).map((tool) =>
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1648
|
+
tools: Object.values(this.convertedTools).map((tool) => {
|
|
1649
|
+
const toolSpec = {
|
|
1650
|
+
name: tool.name,
|
|
1651
|
+
description: tool.description,
|
|
1652
|
+
inputSchema: tool.parameters.jsonSchema
|
|
1653
|
+
};
|
|
1654
|
+
if (tool.outputSchema) {
|
|
1655
|
+
toolSpec.outputSchema = tool.outputSchema.jsonSchema;
|
|
1656
|
+
}
|
|
1657
|
+
return toolSpec;
|
|
1658
|
+
})
|
|
1271
1659
|
};
|
|
1272
1660
|
});
|
|
1273
1661
|
}
|
|
@@ -1290,7 +1678,6 @@ var MCPServer = class extends mcp.MCPServerBase {
|
|
|
1290
1678
|
isError: true
|
|
1291
1679
|
};
|
|
1292
1680
|
}
|
|
1293
|
-
this.logger.debug(`CallTool: Invoking '${request.params.name}' with arguments:`, request.params.arguments);
|
|
1294
1681
|
const validation = tool.parameters.validate?.(request.params.arguments ?? {});
|
|
1295
1682
|
if (validation && !validation.success) {
|
|
1296
1683
|
this.logger.warn(`CallTool: Invalid tool arguments for '${request.params.name}'`, {
|
|
@@ -1309,17 +1696,38 @@ var MCPServer = class extends mcp.MCPServerBase {
|
|
|
1309
1696
|
};
|
|
1310
1697
|
}
|
|
1311
1698
|
const result = await tool.execute(validation?.value, { messages: [], toolCallId: "" });
|
|
1699
|
+
this.logger.debug(`CallTool: Tool '${request.params.name}' executed successfully with result:`, result);
|
|
1312
1700
|
const duration = Date.now() - startTime;
|
|
1313
1701
|
this.logger.info(`Tool '${request.params.name}' executed successfully in ${duration}ms.`);
|
|
1314
|
-
|
|
1315
|
-
|
|
1702
|
+
const response = { isError: false, content: [] };
|
|
1703
|
+
if (tool.outputSchema) {
|
|
1704
|
+
if (!result.structuredContent) {
|
|
1705
|
+
throw new Error(`Tool ${request.params.name} has an output schema but no structured content was provided.`);
|
|
1706
|
+
}
|
|
1707
|
+
const outputValidation = tool.outputSchema.validate?.(result.structuredContent ?? {});
|
|
1708
|
+
if (outputValidation && !outputValidation.success) {
|
|
1709
|
+
this.logger.warn(`CallTool: Invalid structured content for '${request.params.name}'`, {
|
|
1710
|
+
errors: outputValidation.error
|
|
1711
|
+
});
|
|
1712
|
+
throw new Error(
|
|
1713
|
+
`Invalid structured content for tool ${request.params.name}: ${JSON.stringify(outputValidation.error)}`
|
|
1714
|
+
);
|
|
1715
|
+
}
|
|
1716
|
+
response.structuredContent = result.structuredContent;
|
|
1717
|
+
}
|
|
1718
|
+
if (result.content) {
|
|
1719
|
+
response.content = result.content;
|
|
1720
|
+
} else if (response.structuredContent) {
|
|
1721
|
+
response.content = [{ type: "text", text: JSON.stringify(response.structuredContent) }];
|
|
1722
|
+
} else {
|
|
1723
|
+
response.content = [
|
|
1316
1724
|
{
|
|
1317
1725
|
type: "text",
|
|
1318
1726
|
text: typeof result === "string" ? result : JSON.stringify(result)
|
|
1319
1727
|
}
|
|
1320
|
-
]
|
|
1321
|
-
|
|
1322
|
-
|
|
1728
|
+
];
|
|
1729
|
+
}
|
|
1730
|
+
return response;
|
|
1323
1731
|
} catch (error) {
|
|
1324
1732
|
const duration = Date.now() - startTime;
|
|
1325
1733
|
if (error instanceof zod.z.ZodError) {
|
|
@@ -1593,7 +2001,23 @@ var MCPServer = class extends mcp.MCPServerBase {
|
|
|
1593
2001
|
*/
|
|
1594
2002
|
async startStdio() {
|
|
1595
2003
|
this.stdioTransport = new stdio_js.StdioServerTransport();
|
|
1596
|
-
|
|
2004
|
+
try {
|
|
2005
|
+
await this.server.connect(this.stdioTransport);
|
|
2006
|
+
} catch (error$1) {
|
|
2007
|
+
const mastraError = new error.MastraError(
|
|
2008
|
+
{
|
|
2009
|
+
id: "MCP_SERVER_STDIO_CONNECTION_FAILED",
|
|
2010
|
+
domain: error.ErrorDomain.MCP,
|
|
2011
|
+
category: error.ErrorCategory.THIRD_PARTY
|
|
2012
|
+
},
|
|
2013
|
+
error$1
|
|
2014
|
+
);
|
|
2015
|
+
this.logger.trackException(mastraError);
|
|
2016
|
+
this.logger.error("Failed to connect MCP server using stdio transport:", {
|
|
2017
|
+
error: mastraError.toString()
|
|
2018
|
+
});
|
|
2019
|
+
throw mastraError;
|
|
2020
|
+
}
|
|
1597
2021
|
this.logger.info("Started MCP Server (stdio)");
|
|
1598
2022
|
}
|
|
1599
2023
|
/**
|
|
@@ -1607,23 +2031,42 @@ var MCPServer = class extends mcp.MCPServerBase {
|
|
|
1607
2031
|
* @param res HTTP response (must support .write/.end)
|
|
1608
2032
|
*/
|
|
1609
2033
|
async startSSE({ url, ssePath, messagePath, req, res }) {
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
2034
|
+
try {
|
|
2035
|
+
if (url.pathname === ssePath) {
|
|
2036
|
+
await this.connectSSE({
|
|
2037
|
+
messagePath,
|
|
2038
|
+
res
|
|
2039
|
+
});
|
|
2040
|
+
} else if (url.pathname === messagePath) {
|
|
2041
|
+
this.logger.debug("Received message");
|
|
2042
|
+
if (!this.sseTransport) {
|
|
2043
|
+
res.writeHead(503);
|
|
2044
|
+
res.end("SSE connection not established");
|
|
2045
|
+
return;
|
|
2046
|
+
}
|
|
2047
|
+
await this.sseTransport.handlePostMessage(req, res);
|
|
2048
|
+
} else {
|
|
2049
|
+
this.logger.debug("Unknown path:", { path: url.pathname });
|
|
2050
|
+
res.writeHead(404);
|
|
2051
|
+
res.end();
|
|
1621
2052
|
}
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
2053
|
+
} catch (e) {
|
|
2054
|
+
const mastraError = new error.MastraError(
|
|
2055
|
+
{
|
|
2056
|
+
id: "MCP_SERVER_SSE_START_FAILED",
|
|
2057
|
+
domain: error.ErrorDomain.MCP,
|
|
2058
|
+
category: error.ErrorCategory.USER,
|
|
2059
|
+
details: {
|
|
2060
|
+
url: url.toString(),
|
|
2061
|
+
ssePath,
|
|
2062
|
+
messagePath
|
|
2063
|
+
}
|
|
2064
|
+
},
|
|
2065
|
+
e
|
|
2066
|
+
);
|
|
2067
|
+
this.logger.trackException(mastraError);
|
|
2068
|
+
this.logger.error("Failed to start MCP Server (SSE):", { error: mastraError.toString() });
|
|
2069
|
+
throw mastraError;
|
|
1627
2070
|
}
|
|
1628
2071
|
}
|
|
1629
2072
|
/**
|
|
@@ -1636,31 +2079,50 @@ var MCPServer = class extends mcp.MCPServerBase {
|
|
|
1636
2079
|
* @param context Incoming Hono context
|
|
1637
2080
|
*/
|
|
1638
2081
|
async startHonoSSE({ url, ssePath, messagePath, context }) {
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
2082
|
+
try {
|
|
2083
|
+
if (url.pathname === ssePath) {
|
|
2084
|
+
return streamSSE(context, async (stream2) => {
|
|
2085
|
+
await this.connectHonoSSE({
|
|
2086
|
+
messagePath,
|
|
2087
|
+
stream: stream2
|
|
2088
|
+
});
|
|
1644
2089
|
});
|
|
1645
|
-
})
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
2090
|
+
} else if (url.pathname === messagePath) {
|
|
2091
|
+
this.logger.debug("Received message");
|
|
2092
|
+
const sessionId = context.req.query("sessionId");
|
|
2093
|
+
this.logger.debug("Received message for sessionId", { sessionId });
|
|
2094
|
+
if (!sessionId) {
|
|
2095
|
+
return context.text("No sessionId provided", 400);
|
|
2096
|
+
}
|
|
2097
|
+
if (!this.sseHonoTransports.has(sessionId)) {
|
|
2098
|
+
return context.text(`No transport found for sessionId ${sessionId}`, 400);
|
|
2099
|
+
}
|
|
2100
|
+
const message = await this.sseHonoTransports.get(sessionId)?.handlePostMessage(context);
|
|
2101
|
+
if (!message) {
|
|
2102
|
+
return context.text("Transport not found", 400);
|
|
2103
|
+
}
|
|
2104
|
+
return message;
|
|
2105
|
+
} else {
|
|
2106
|
+
this.logger.debug("Unknown path:", { path: url.pathname });
|
|
2107
|
+
return context.text("Unknown path", 404);
|
|
1659
2108
|
}
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
2109
|
+
} catch (e) {
|
|
2110
|
+
const mastraError = new error.MastraError(
|
|
2111
|
+
{
|
|
2112
|
+
id: "MCP_SERVER_HONO_SSE_START_FAILED",
|
|
2113
|
+
domain: error.ErrorDomain.MCP,
|
|
2114
|
+
category: error.ErrorCategory.USER,
|
|
2115
|
+
details: {
|
|
2116
|
+
url: url.toString(),
|
|
2117
|
+
ssePath,
|
|
2118
|
+
messagePath
|
|
2119
|
+
}
|
|
2120
|
+
},
|
|
2121
|
+
e
|
|
2122
|
+
);
|
|
2123
|
+
this.logger.trackException(mastraError);
|
|
2124
|
+
this.logger.error("Failed to start MCP Server (Hono SSE):", { error: mastraError.toString() });
|
|
2125
|
+
throw mastraError;
|
|
1664
2126
|
}
|
|
1665
2127
|
}
|
|
1666
2128
|
/**
|
|
@@ -1788,8 +2250,18 @@ var MCPServer = class extends mcp.MCPServerBase {
|
|
|
1788
2250
|
);
|
|
1789
2251
|
}
|
|
1790
2252
|
}
|
|
1791
|
-
} catch (error) {
|
|
1792
|
-
|
|
2253
|
+
} catch (error$1) {
|
|
2254
|
+
const mastraError = new error.MastraError(
|
|
2255
|
+
{
|
|
2256
|
+
id: "MCP_SERVER_HTTP_CONNECTION_FAILED",
|
|
2257
|
+
domain: error.ErrorDomain.MCP,
|
|
2258
|
+
category: error.ErrorCategory.USER,
|
|
2259
|
+
text: "Failed to connect MCP server using HTTP transport"
|
|
2260
|
+
},
|
|
2261
|
+
error$1
|
|
2262
|
+
);
|
|
2263
|
+
this.logger.trackException(mastraError);
|
|
2264
|
+
this.logger.error("startHTTP: Error handling Streamable HTTP request:", { error: mastraError });
|
|
1793
2265
|
if (!res.headersSent) {
|
|
1794
2266
|
res.writeHead(500, { "Content-Type": "application/json" });
|
|
1795
2267
|
res.end(
|
|
@@ -1803,8 +2275,6 @@ var MCPServer = class extends mcp.MCPServerBase {
|
|
|
1803
2275
|
// Cannot determine original request ID in catch
|
|
1804
2276
|
})
|
|
1805
2277
|
);
|
|
1806
|
-
} else {
|
|
1807
|
-
this.logger.error("startHTTP: Error after headers sent:", error);
|
|
1808
2278
|
}
|
|
1809
2279
|
}
|
|
1810
2280
|
}
|
|
@@ -1812,38 +2282,72 @@ var MCPServer = class extends mcp.MCPServerBase {
|
|
|
1812
2282
|
messagePath,
|
|
1813
2283
|
res
|
|
1814
2284
|
}) {
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
this.
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
2285
|
+
try {
|
|
2286
|
+
this.logger.debug("Received SSE connection");
|
|
2287
|
+
this.sseTransport = new sse_js.SSEServerTransport(messagePath, res);
|
|
2288
|
+
await this.server.connect(this.sseTransport);
|
|
2289
|
+
this.server.onclose = async () => {
|
|
2290
|
+
this.sseTransport = void 0;
|
|
2291
|
+
await this.server.close();
|
|
2292
|
+
};
|
|
2293
|
+
res.on("close", () => {
|
|
2294
|
+
this.sseTransport = void 0;
|
|
2295
|
+
});
|
|
2296
|
+
} catch (e) {
|
|
2297
|
+
const mastraError = new error.MastraError(
|
|
2298
|
+
{
|
|
2299
|
+
id: "MCP_SERVER_SSE_CONNECT_FAILED",
|
|
2300
|
+
domain: error.ErrorDomain.MCP,
|
|
2301
|
+
category: error.ErrorCategory.USER,
|
|
2302
|
+
details: {
|
|
2303
|
+
messagePath
|
|
2304
|
+
}
|
|
2305
|
+
},
|
|
2306
|
+
e
|
|
2307
|
+
);
|
|
2308
|
+
this.logger.trackException(mastraError);
|
|
2309
|
+
this.logger.error("Failed to connect to MCP Server (SSE):", { error: mastraError });
|
|
2310
|
+
throw mastraError;
|
|
2311
|
+
}
|
|
1825
2312
|
}
|
|
1826
|
-
async connectHonoSSE({ messagePath, stream }) {
|
|
2313
|
+
async connectHonoSSE({ messagePath, stream: stream2 }) {
|
|
1827
2314
|
this.logger.debug("Received SSE connection");
|
|
1828
|
-
const sseTransport = new SSETransport(messagePath,
|
|
2315
|
+
const sseTransport = new SSETransport(messagePath, stream2);
|
|
1829
2316
|
const sessionId = sseTransport.sessionId;
|
|
1830
2317
|
this.logger.debug("SSE Transport created with sessionId:", { sessionId });
|
|
1831
2318
|
this.sseHonoTransports.set(sessionId, sseTransport);
|
|
1832
|
-
|
|
2319
|
+
stream2.onAbort(() => {
|
|
1833
2320
|
this.logger.debug("SSE Transport aborted with sessionId:", { sessionId });
|
|
1834
2321
|
this.sseHonoTransports.delete(sessionId);
|
|
1835
2322
|
});
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
this.
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
2323
|
+
try {
|
|
2324
|
+
await this.server.connect(sseTransport);
|
|
2325
|
+
this.server.onclose = async () => {
|
|
2326
|
+
this.logger.debug("SSE Transport closed with sessionId:", { sessionId });
|
|
2327
|
+
this.sseHonoTransports.delete(sessionId);
|
|
2328
|
+
await this.server.close();
|
|
2329
|
+
};
|
|
2330
|
+
while (true) {
|
|
2331
|
+
const sessionIds = Array.from(this.sseHonoTransports.keys() || []);
|
|
2332
|
+
this.logger.debug("Active Hono SSE sessions:", { sessionIds });
|
|
2333
|
+
await stream2.write(":keep-alive\n\n");
|
|
2334
|
+
await stream2.sleep(6e4);
|
|
2335
|
+
}
|
|
2336
|
+
} catch (e) {
|
|
2337
|
+
const mastraError = new error.MastraError(
|
|
2338
|
+
{
|
|
2339
|
+
id: "MCP_SERVER_HONO_SSE_CONNECT_FAILED",
|
|
2340
|
+
domain: error.ErrorDomain.MCP,
|
|
2341
|
+
category: error.ErrorCategory.USER,
|
|
2342
|
+
details: {
|
|
2343
|
+
messagePath
|
|
2344
|
+
}
|
|
2345
|
+
},
|
|
2346
|
+
e
|
|
2347
|
+
);
|
|
2348
|
+
this.logger.trackException(mastraError);
|
|
2349
|
+
this.logger.error("Failed to connect to MCP Server (Hono SSE):", { error: mastraError });
|
|
2350
|
+
throw mastraError;
|
|
1847
2351
|
}
|
|
1848
2352
|
}
|
|
1849
2353
|
/**
|
|
@@ -1880,8 +2384,18 @@ var MCPServer = class extends mcp.MCPServerBase {
|
|
|
1880
2384
|
}
|
|
1881
2385
|
await this.server.close();
|
|
1882
2386
|
this.logger.info("MCP server closed.");
|
|
1883
|
-
} catch (error) {
|
|
1884
|
-
|
|
2387
|
+
} catch (error$1) {
|
|
2388
|
+
const mastraError = new error.MastraError(
|
|
2389
|
+
{
|
|
2390
|
+
id: "MCP_SERVER_CLOSE_FAILED",
|
|
2391
|
+
domain: error.ErrorDomain.MCP,
|
|
2392
|
+
category: error.ErrorCategory.THIRD_PARTY
|
|
2393
|
+
},
|
|
2394
|
+
error$1
|
|
2395
|
+
);
|
|
2396
|
+
this.logger.trackException(mastraError);
|
|
2397
|
+
this.logger.error("Error closing MCP server:", { error: mastraError });
|
|
2398
|
+
throw mastraError;
|
|
1885
2399
|
}
|
|
1886
2400
|
}
|
|
1887
2401
|
/**
|
|
@@ -1926,6 +2440,7 @@ var MCPServer = class extends mcp.MCPServerBase {
|
|
|
1926
2440
|
name: tool.name,
|
|
1927
2441
|
description: tool.description,
|
|
1928
2442
|
inputSchema: tool.parameters?.jsonSchema || tool.parameters,
|
|
2443
|
+
outputSchema: tool.outputSchema?.jsonSchema || tool.outputSchema,
|
|
1929
2444
|
toolType: tool.toolType
|
|
1930
2445
|
}))
|
|
1931
2446
|
};
|
|
@@ -1946,6 +2461,7 @@ var MCPServer = class extends mcp.MCPServerBase {
|
|
|
1946
2461
|
name: tool.name,
|
|
1947
2462
|
description: tool.description,
|
|
1948
2463
|
inputSchema: tool.parameters?.jsonSchema || tool.parameters,
|
|
2464
|
+
outputSchema: tool.outputSchema?.jsonSchema || tool.outputSchema,
|
|
1949
2465
|
toolType: tool.toolType
|
|
1950
2466
|
};
|
|
1951
2467
|
}
|
|
@@ -1959,30 +2475,47 @@ var MCPServer = class extends mcp.MCPServerBase {
|
|
|
1959
2475
|
*/
|
|
1960
2476
|
async executeTool(toolId, args, executionContext) {
|
|
1961
2477
|
const tool = this.convertedTools[toolId];
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
let validatedArgs = args;
|
|
1968
|
-
if (tool.parameters instanceof zod.z.ZodType && typeof tool.parameters.safeParse === "function") {
|
|
1969
|
-
const validation = tool.parameters.safeParse(args ?? {});
|
|
1970
|
-
if (!validation.success) {
|
|
1971
|
-
const errorMessages = validation.error.errors.map((e) => `${e.path.join(".")}: ${e.message}`).join(", ");
|
|
1972
|
-
this.logger.warn(`ExecuteTool: Invalid tool arguments for '${toolId}': ${errorMessages}`, {
|
|
1973
|
-
errors: validation.error.format()
|
|
1974
|
-
});
|
|
1975
|
-
throw new zod.z.ZodError(validation.error.issues);
|
|
2478
|
+
let validatedArgs;
|
|
2479
|
+
try {
|
|
2480
|
+
if (!tool) {
|
|
2481
|
+
this.logger.warn(`ExecuteTool: Unknown tool '${toolId}' requested on MCPServer '${this.name}'.`);
|
|
2482
|
+
throw new Error(`Unknown tool: ${toolId}`);
|
|
1976
2483
|
}
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
2484
|
+
this.logger.debug(`ExecuteTool: Invoking '${toolId}' with arguments:`, args);
|
|
2485
|
+
if (tool.parameters instanceof zod.z.ZodType && typeof tool.parameters.safeParse === "function") {
|
|
2486
|
+
const validation = tool.parameters.safeParse(args ?? {});
|
|
2487
|
+
if (!validation.success) {
|
|
2488
|
+
const errorMessages = validation.error.errors.map((e) => `${e.path.join(".")}: ${e.message}`).join(", ");
|
|
2489
|
+
this.logger.warn(`ExecuteTool: Invalid tool arguments for '${toolId}': ${errorMessages}`, {
|
|
2490
|
+
errors: validation.error.format()
|
|
2491
|
+
});
|
|
2492
|
+
throw new zod.z.ZodError(validation.error.issues);
|
|
2493
|
+
}
|
|
2494
|
+
validatedArgs = validation.data;
|
|
2495
|
+
} else {
|
|
2496
|
+
this.logger.debug(
|
|
2497
|
+
`ExecuteTool: Tool '${toolId}' parameters is not a Zod schema with safeParse or is undefined. Skipping validation.`
|
|
2498
|
+
);
|
|
2499
|
+
}
|
|
2500
|
+
if (!tool.execute) {
|
|
2501
|
+
this.logger.error(`ExecuteTool: Tool '${toolId}' does not have an execute function.`);
|
|
2502
|
+
throw new Error(`Tool '${toolId}' cannot be executed.`);
|
|
2503
|
+
}
|
|
2504
|
+
} catch (error$1) {
|
|
2505
|
+
const mastraError = new error.MastraError(
|
|
2506
|
+
{
|
|
2507
|
+
id: "MCP_SERVER_TOOL_EXECUTE_PREPARATION_FAILED",
|
|
2508
|
+
domain: error.ErrorDomain.MCP,
|
|
2509
|
+
category: error.ErrorCategory.USER,
|
|
2510
|
+
details: {
|
|
2511
|
+
toolId,
|
|
2512
|
+
args
|
|
2513
|
+
}
|
|
2514
|
+
},
|
|
2515
|
+
error$1
|
|
1981
2516
|
);
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
this.logger.error(`ExecuteTool: Tool '${toolId}' does not have an execute function.`);
|
|
1985
|
-
throw new Error(`Tool '${toolId}' cannot be executed.`);
|
|
2517
|
+
this.logger.trackException(mastraError);
|
|
2518
|
+
throw mastraError;
|
|
1986
2519
|
}
|
|
1987
2520
|
try {
|
|
1988
2521
|
const finalExecutionContext = {
|
|
@@ -1992,9 +2525,22 @@ var MCPServer = class extends mcp.MCPServerBase {
|
|
|
1992
2525
|
const result = await tool.execute(validatedArgs, finalExecutionContext);
|
|
1993
2526
|
this.logger.info(`ExecuteTool: Tool '${toolId}' executed successfully.`);
|
|
1994
2527
|
return result;
|
|
1995
|
-
} catch (error) {
|
|
1996
|
-
|
|
1997
|
-
|
|
2528
|
+
} catch (error$1) {
|
|
2529
|
+
const mastraError = new error.MastraError(
|
|
2530
|
+
{
|
|
2531
|
+
id: "MCP_SERVER_TOOL_EXECUTE_FAILED",
|
|
2532
|
+
domain: error.ErrorDomain.MCP,
|
|
2533
|
+
category: error.ErrorCategory.USER,
|
|
2534
|
+
details: {
|
|
2535
|
+
toolId,
|
|
2536
|
+
validatedArgs
|
|
2537
|
+
}
|
|
2538
|
+
},
|
|
2539
|
+
error$1
|
|
2540
|
+
);
|
|
2541
|
+
this.logger.trackException(mastraError);
|
|
2542
|
+
this.logger.error(`ExecuteTool: Tool execution failed for '${toolId}':`, { error: error$1 });
|
|
2543
|
+
throw mastraError;
|
|
1998
2544
|
}
|
|
1999
2545
|
}
|
|
2000
2546
|
};
|