@mastra/mcp 0.10.4-alpha.1 → 0.10.5-alpha.0
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 +40 -0
- package/dist/index.cjs +461 -143
- package/dist/index.js +451 -133
- package/package.json +3 -3
- 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.ts +251 -98
package/dist/index.cjs
CHANGED
|
@@ -12,6 +12,7 @@ var types_js = require('@modelcontextprotocol/sdk/types.js');
|
|
|
12
12
|
var exitHook = require('exit-hook');
|
|
13
13
|
var zod = require('zod');
|
|
14
14
|
var zodFromJsonSchema = require('zod-from-json-schema');
|
|
15
|
+
var error = require('@mastra/core/error');
|
|
15
16
|
var equal = require('fast-deep-equal');
|
|
16
17
|
var uuid = require('uuid');
|
|
17
18
|
var crypto$1 = require('crypto');
|
|
@@ -614,8 +615,17 @@ To fix this you have three different options:
|
|
|
614
615
|
try {
|
|
615
616
|
const internalClient = await this.getConnectedClientForServer(serverName);
|
|
616
617
|
allResources[serverName] = await internalClient.resources.list();
|
|
617
|
-
} catch (error) {
|
|
618
|
-
|
|
618
|
+
} catch (error$1) {
|
|
619
|
+
const mastraError = new error.MastraError({
|
|
620
|
+
id: "MCP_CLIENT_LIST_RESOURCES_FAILED",
|
|
621
|
+
domain: error.ErrorDomain.MCP,
|
|
622
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
623
|
+
details: {
|
|
624
|
+
serverName
|
|
625
|
+
}
|
|
626
|
+
}, error$1);
|
|
627
|
+
this.logger.trackException(mastraError);
|
|
628
|
+
this.logger.error("Failed to list resources from server:", { error: mastraError.toString() });
|
|
619
629
|
}
|
|
620
630
|
}
|
|
621
631
|
return allResources;
|
|
@@ -626,31 +636,98 @@ To fix this you have three different options:
|
|
|
626
636
|
try {
|
|
627
637
|
const internalClient = await this.getConnectedClientForServer(serverName);
|
|
628
638
|
allTemplates[serverName] = await internalClient.resources.templates();
|
|
629
|
-
} catch (error) {
|
|
630
|
-
|
|
639
|
+
} catch (error$1) {
|
|
640
|
+
const mastraError = new error.MastraError({
|
|
641
|
+
id: "MCP_CLIENT_LIST_RESOURCE_TEMPLATES_FAILED",
|
|
642
|
+
domain: error.ErrorDomain.MCP,
|
|
643
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
644
|
+
details: {
|
|
645
|
+
serverName
|
|
646
|
+
}
|
|
647
|
+
}, error$1);
|
|
648
|
+
this.logger.trackException(mastraError);
|
|
649
|
+
this.logger.error("Failed to list resource templates from server:", { error: mastraError.toString() });
|
|
631
650
|
}
|
|
632
651
|
}
|
|
633
652
|
return allTemplates;
|
|
634
653
|
},
|
|
635
654
|
read: async (serverName, uri) => {
|
|
636
|
-
|
|
637
|
-
|
|
655
|
+
try {
|
|
656
|
+
const internalClient = await this.getConnectedClientForServer(serverName);
|
|
657
|
+
return internalClient.resources.read(uri);
|
|
658
|
+
} catch (error$1) {
|
|
659
|
+
throw new error.MastraError({
|
|
660
|
+
id: "MCP_CLIENT_READ_RESOURCE_FAILED",
|
|
661
|
+
domain: error.ErrorDomain.MCP,
|
|
662
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
663
|
+
details: {
|
|
664
|
+
serverName,
|
|
665
|
+
uri
|
|
666
|
+
}
|
|
667
|
+
}, error$1);
|
|
668
|
+
}
|
|
638
669
|
},
|
|
639
670
|
subscribe: async (serverName, uri) => {
|
|
640
|
-
|
|
641
|
-
|
|
671
|
+
try {
|
|
672
|
+
const internalClient = await this.getConnectedClientForServer(serverName);
|
|
673
|
+
return internalClient.resources.subscribe(uri);
|
|
674
|
+
} catch (error$1) {
|
|
675
|
+
throw new error.MastraError({
|
|
676
|
+
id: "MCP_CLIENT_SUBSCRIBE_RESOURCE_FAILED",
|
|
677
|
+
domain: error.ErrorDomain.MCP,
|
|
678
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
679
|
+
details: {
|
|
680
|
+
serverName,
|
|
681
|
+
uri
|
|
682
|
+
}
|
|
683
|
+
}, error$1);
|
|
684
|
+
}
|
|
642
685
|
},
|
|
643
686
|
unsubscribe: async (serverName, uri) => {
|
|
644
|
-
|
|
645
|
-
|
|
687
|
+
try {
|
|
688
|
+
const internalClient = await this.getConnectedClientForServer(serverName);
|
|
689
|
+
return internalClient.resources.unsubscribe(uri);
|
|
690
|
+
} catch (err) {
|
|
691
|
+
throw new error.MastraError({
|
|
692
|
+
id: "MCP_CLIENT_UNSUBSCRIBE_RESOURCE_FAILED",
|
|
693
|
+
domain: error.ErrorDomain.MCP,
|
|
694
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
695
|
+
details: {
|
|
696
|
+
serverName,
|
|
697
|
+
uri
|
|
698
|
+
}
|
|
699
|
+
}, err);
|
|
700
|
+
}
|
|
646
701
|
},
|
|
647
702
|
onUpdated: async (serverName, handler) => {
|
|
648
|
-
|
|
649
|
-
|
|
703
|
+
try {
|
|
704
|
+
const internalClient = await this.getConnectedClientForServer(serverName);
|
|
705
|
+
return internalClient.resources.onUpdated(handler);
|
|
706
|
+
} catch (err) {
|
|
707
|
+
throw new error.MastraError({
|
|
708
|
+
id: "MCP_CLIENT_ON_UPDATED_RESOURCE_FAILED",
|
|
709
|
+
domain: error.ErrorDomain.MCP,
|
|
710
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
711
|
+
details: {
|
|
712
|
+
serverName
|
|
713
|
+
}
|
|
714
|
+
}, err);
|
|
715
|
+
}
|
|
650
716
|
},
|
|
651
717
|
onListChanged: async (serverName, handler) => {
|
|
652
|
-
|
|
653
|
-
|
|
718
|
+
try {
|
|
719
|
+
const internalClient = await this.getConnectedClientForServer(serverName);
|
|
720
|
+
return internalClient.resources.onListChanged(handler);
|
|
721
|
+
} catch (err) {
|
|
722
|
+
throw new error.MastraError({
|
|
723
|
+
id: "MCP_CLIENT_ON_LIST_CHANGED_RESOURCE_FAILED",
|
|
724
|
+
domain: error.ErrorDomain.MCP,
|
|
725
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
726
|
+
details: {
|
|
727
|
+
serverName
|
|
728
|
+
}
|
|
729
|
+
}, err);
|
|
730
|
+
}
|
|
654
731
|
}
|
|
655
732
|
};
|
|
656
733
|
}
|
|
@@ -663,19 +740,51 @@ To fix this you have three different options:
|
|
|
663
740
|
try {
|
|
664
741
|
const internalClient = await this.getConnectedClientForServer(serverName);
|
|
665
742
|
allPrompts[serverName] = await internalClient.prompts.list();
|
|
666
|
-
} catch (error) {
|
|
667
|
-
|
|
743
|
+
} catch (error$1) {
|
|
744
|
+
const mastraError = new error.MastraError({
|
|
745
|
+
id: "MCP_CLIENT_LIST_PROMPTS_FAILED",
|
|
746
|
+
domain: error.ErrorDomain.MCP,
|
|
747
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
748
|
+
details: {
|
|
749
|
+
serverName
|
|
750
|
+
}
|
|
751
|
+
}, error$1);
|
|
752
|
+
this.logger.trackException(mastraError);
|
|
753
|
+
this.logger.error("Failed to list prompts from server:", { error: mastraError.toString() });
|
|
668
754
|
}
|
|
669
755
|
}
|
|
670
756
|
return allPrompts;
|
|
671
757
|
},
|
|
672
758
|
get: async ({ serverName, name, args, version }) => {
|
|
673
|
-
|
|
674
|
-
|
|
759
|
+
try {
|
|
760
|
+
const internalClient = await this.getConnectedClientForServer(serverName);
|
|
761
|
+
return internalClient.prompts.get({ name, args, version });
|
|
762
|
+
} catch (error$1) {
|
|
763
|
+
throw new error.MastraError({
|
|
764
|
+
id: "MCP_CLIENT_GET_PROMPT_FAILED",
|
|
765
|
+
domain: error.ErrorDomain.MCP,
|
|
766
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
767
|
+
details: {
|
|
768
|
+
serverName,
|
|
769
|
+
name
|
|
770
|
+
}
|
|
771
|
+
}, error$1);
|
|
772
|
+
}
|
|
675
773
|
},
|
|
676
774
|
onListChanged: async (serverName, handler) => {
|
|
677
|
-
|
|
678
|
-
|
|
775
|
+
try {
|
|
776
|
+
const internalClient = await this.getConnectedClientForServer(serverName);
|
|
777
|
+
return internalClient.prompts.onListChanged(handler);
|
|
778
|
+
} catch (error$1) {
|
|
779
|
+
throw new error.MastraError({
|
|
780
|
+
id: "MCP_CLIENT_ON_LIST_CHANGED_PROMPT_FAILED",
|
|
781
|
+
domain: error.ErrorDomain.MCP,
|
|
782
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
783
|
+
details: {
|
|
784
|
+
serverName
|
|
785
|
+
}
|
|
786
|
+
}, error$1);
|
|
787
|
+
}
|
|
679
788
|
}
|
|
680
789
|
};
|
|
681
790
|
}
|
|
@@ -707,21 +816,37 @@ To fix this you have three different options:
|
|
|
707
816
|
async getTools() {
|
|
708
817
|
this.addToInstanceCache();
|
|
709
818
|
const connectedTools = {};
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
819
|
+
try {
|
|
820
|
+
await this.eachClientTools(async ({ serverName, tools }) => {
|
|
821
|
+
for (const [toolName, toolConfig] of Object.entries(tools)) {
|
|
822
|
+
connectedTools[`${serverName}_${toolName}`] = toolConfig;
|
|
823
|
+
}
|
|
824
|
+
});
|
|
825
|
+
} catch (error$1) {
|
|
826
|
+
throw new error.MastraError({
|
|
827
|
+
id: "MCP_CLIENT_GET_TOOLS_FAILED",
|
|
828
|
+
domain: error.ErrorDomain.MCP,
|
|
829
|
+
category: error.ErrorCategory.THIRD_PARTY
|
|
830
|
+
}, error$1);
|
|
831
|
+
}
|
|
715
832
|
return connectedTools;
|
|
716
833
|
}
|
|
717
834
|
async getToolsets() {
|
|
718
835
|
this.addToInstanceCache();
|
|
719
836
|
const connectedToolsets = {};
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
837
|
+
try {
|
|
838
|
+
await this.eachClientTools(async ({ serverName, tools }) => {
|
|
839
|
+
if (tools) {
|
|
840
|
+
connectedToolsets[serverName] = tools;
|
|
841
|
+
}
|
|
842
|
+
});
|
|
843
|
+
} catch (error$1) {
|
|
844
|
+
throw new error.MastraError({
|
|
845
|
+
id: "MCP_CLIENT_GET_TOOLSETS_FAILED",
|
|
846
|
+
domain: error.ErrorDomain.MCP,
|
|
847
|
+
category: error.ErrorCategory.THIRD_PARTY
|
|
848
|
+
}, error$1);
|
|
849
|
+
}
|
|
725
850
|
return connectedToolsets;
|
|
726
851
|
}
|
|
727
852
|
/**
|
|
@@ -768,13 +893,19 @@ To fix this you have three different options:
|
|
|
768
893
|
try {
|
|
769
894
|
await mcpClient.connect();
|
|
770
895
|
} catch (e) {
|
|
896
|
+
const mastraError = new error.MastraError({
|
|
897
|
+
id: "MCP_CLIENT_CONNECT_FAILED",
|
|
898
|
+
domain: error.ErrorDomain.MCP,
|
|
899
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
900
|
+
text: `Failed to connect to MCP server ${name}: ${e instanceof Error ? e.stack || e.message : String(e)}`,
|
|
901
|
+
details: {
|
|
902
|
+
name
|
|
903
|
+
}
|
|
904
|
+
}, e);
|
|
905
|
+
this.logger.trackException(mastraError);
|
|
906
|
+
this.logger.error("MCPClient errored connecting to MCP server:", { error: mastraError.toString() });
|
|
771
907
|
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
|
-
);
|
|
908
|
+
throw mastraError;
|
|
778
909
|
}
|
|
779
910
|
this.logger.debug(`Connected to ${name} MCP server`);
|
|
780
911
|
return mcpClient;
|
|
@@ -888,8 +1019,6 @@ var SSETransport = class {
|
|
|
888
1019
|
});
|
|
889
1020
|
}
|
|
890
1021
|
};
|
|
891
|
-
|
|
892
|
-
// src/server/promptActions.ts
|
|
893
1022
|
var ServerPromptActions = class {
|
|
894
1023
|
getLogger;
|
|
895
1024
|
getSdkServer;
|
|
@@ -908,16 +1037,24 @@ var ServerPromptActions = class {
|
|
|
908
1037
|
this.clearDefinedPrompts();
|
|
909
1038
|
try {
|
|
910
1039
|
await this.getSdkServer().sendPromptListChanged();
|
|
911
|
-
} catch (error) {
|
|
1040
|
+
} catch (error$1) {
|
|
1041
|
+
const mastraError = new error.MastraError(
|
|
1042
|
+
{
|
|
1043
|
+
id: "MCP_SERVER_PROMPT_LIST_CHANGED_NOTIFICATION_FAILED",
|
|
1044
|
+
domain: error.ErrorDomain.MCP,
|
|
1045
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
1046
|
+
text: "Failed to send prompt list changed notification"
|
|
1047
|
+
},
|
|
1048
|
+
error$1
|
|
1049
|
+
);
|
|
912
1050
|
this.getLogger().error("Failed to send prompt list changed notification:", {
|
|
913
|
-
error:
|
|
1051
|
+
error: mastraError.toString()
|
|
914
1052
|
});
|
|
915
|
-
|
|
1053
|
+
this.getLogger().trackException(mastraError);
|
|
1054
|
+
throw mastraError;
|
|
916
1055
|
}
|
|
917
1056
|
}
|
|
918
1057
|
};
|
|
919
|
-
|
|
920
|
-
// src/server/resourceActions.ts
|
|
921
1058
|
var ServerResourceActions = class {
|
|
922
1059
|
getSubscriptions;
|
|
923
1060
|
getLogger;
|
|
@@ -940,9 +1077,24 @@ var ServerResourceActions = class {
|
|
|
940
1077
|
this.getLogger().info(`Sending notifications/resources/updated for externally notified resource: ${uri}`);
|
|
941
1078
|
try {
|
|
942
1079
|
await this.getSdkServer().sendResourceUpdated({ uri });
|
|
943
|
-
} catch (error) {
|
|
944
|
-
|
|
945
|
-
|
|
1080
|
+
} catch (error$1) {
|
|
1081
|
+
const mastraError = new error.MastraError(
|
|
1082
|
+
{
|
|
1083
|
+
id: "MCP_SERVER_RESOURCE_UPDATED_NOTIFICATION_FAILED",
|
|
1084
|
+
domain: error.ErrorDomain.MCP,
|
|
1085
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
1086
|
+
text: "Failed to send resource updated notification",
|
|
1087
|
+
details: {
|
|
1088
|
+
uri
|
|
1089
|
+
}
|
|
1090
|
+
},
|
|
1091
|
+
error$1
|
|
1092
|
+
);
|
|
1093
|
+
this.getLogger().trackException(mastraError);
|
|
1094
|
+
this.getLogger().error("Failed to send resource updated notification:", {
|
|
1095
|
+
error: mastraError.toString()
|
|
1096
|
+
});
|
|
1097
|
+
throw mastraError;
|
|
946
1098
|
}
|
|
947
1099
|
} else {
|
|
948
1100
|
this.getLogger().debug(`Resource ${uri} was updated, but no active subscriptions for it.`);
|
|
@@ -960,9 +1112,21 @@ var ServerResourceActions = class {
|
|
|
960
1112
|
this.clearDefinedResourceTemplates();
|
|
961
1113
|
try {
|
|
962
1114
|
await this.getSdkServer().sendResourceListChanged();
|
|
963
|
-
} catch (error) {
|
|
964
|
-
|
|
965
|
-
|
|
1115
|
+
} catch (error$1) {
|
|
1116
|
+
const mastraError = new error.MastraError(
|
|
1117
|
+
{
|
|
1118
|
+
id: "MCP_SERVER_RESOURCE_LIST_CHANGED_NOTIFICATION_FAILED",
|
|
1119
|
+
domain: error.ErrorDomain.MCP,
|
|
1120
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
1121
|
+
text: "Failed to send resource list changed notification"
|
|
1122
|
+
},
|
|
1123
|
+
error$1
|
|
1124
|
+
);
|
|
1125
|
+
this.getLogger().trackException(mastraError);
|
|
1126
|
+
this.getLogger().error("Failed to send resource list changed notification:", {
|
|
1127
|
+
error: mastraError.toString()
|
|
1128
|
+
});
|
|
1129
|
+
throw mastraError;
|
|
966
1130
|
}
|
|
967
1131
|
}
|
|
968
1132
|
};
|
|
@@ -1240,8 +1404,26 @@ var MCPServer = class extends mcp.MCPServerBase {
|
|
|
1240
1404
|
this.logger.info(`Registered explicit tool: '${toolName}'`);
|
|
1241
1405
|
}
|
|
1242
1406
|
this.logger.info(`Total defined tools registered: ${Object.keys(definedConvertedTools).length}`);
|
|
1243
|
-
|
|
1244
|
-
|
|
1407
|
+
let agentDerivedTools = {};
|
|
1408
|
+
let workflowDerivedTools = {};
|
|
1409
|
+
try {
|
|
1410
|
+
agentDerivedTools = this.convertAgentsToTools(agentsConfig, definedConvertedTools);
|
|
1411
|
+
workflowDerivedTools = this.convertWorkflowsToTools(workflowsConfig, definedConvertedTools);
|
|
1412
|
+
} catch (e) {
|
|
1413
|
+
const mastraError = new error.MastraError(
|
|
1414
|
+
{
|
|
1415
|
+
id: "MCP_SERVER_AGENT_OR_WORKFLOW_TOOL_CONVERSION_FAILED",
|
|
1416
|
+
domain: error.ErrorDomain.MCP,
|
|
1417
|
+
category: error.ErrorCategory.USER
|
|
1418
|
+
},
|
|
1419
|
+
e
|
|
1420
|
+
);
|
|
1421
|
+
this.logger.trackException(mastraError);
|
|
1422
|
+
this.logger.error("Failed to convert tools:", {
|
|
1423
|
+
error: mastraError.toString()
|
|
1424
|
+
});
|
|
1425
|
+
throw mastraError;
|
|
1426
|
+
}
|
|
1245
1427
|
const allConvertedTools = { ...definedConvertedTools, ...agentDerivedTools, ...workflowDerivedTools };
|
|
1246
1428
|
const finalToolCount = Object.keys(allConvertedTools).length;
|
|
1247
1429
|
const definedCount = Object.keys(definedConvertedTools).length;
|
|
@@ -1593,7 +1775,23 @@ var MCPServer = class extends mcp.MCPServerBase {
|
|
|
1593
1775
|
*/
|
|
1594
1776
|
async startStdio() {
|
|
1595
1777
|
this.stdioTransport = new stdio_js.StdioServerTransport();
|
|
1596
|
-
|
|
1778
|
+
try {
|
|
1779
|
+
await this.server.connect(this.stdioTransport);
|
|
1780
|
+
} catch (error$1) {
|
|
1781
|
+
const mastraError = new error.MastraError(
|
|
1782
|
+
{
|
|
1783
|
+
id: "MCP_SERVER_STDIO_CONNECTION_FAILED",
|
|
1784
|
+
domain: error.ErrorDomain.MCP,
|
|
1785
|
+
category: error.ErrorCategory.THIRD_PARTY
|
|
1786
|
+
},
|
|
1787
|
+
error$1
|
|
1788
|
+
);
|
|
1789
|
+
this.logger.trackException(mastraError);
|
|
1790
|
+
this.logger.error("Failed to connect MCP server using stdio transport:", {
|
|
1791
|
+
error: mastraError.toString()
|
|
1792
|
+
});
|
|
1793
|
+
throw mastraError;
|
|
1794
|
+
}
|
|
1597
1795
|
this.logger.info("Started MCP Server (stdio)");
|
|
1598
1796
|
}
|
|
1599
1797
|
/**
|
|
@@ -1607,23 +1805,42 @@ var MCPServer = class extends mcp.MCPServerBase {
|
|
|
1607
1805
|
* @param res HTTP response (must support .write/.end)
|
|
1608
1806
|
*/
|
|
1609
1807
|
async startSSE({ url, ssePath, messagePath, req, res }) {
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1808
|
+
try {
|
|
1809
|
+
if (url.pathname === ssePath) {
|
|
1810
|
+
await this.connectSSE({
|
|
1811
|
+
messagePath,
|
|
1812
|
+
res
|
|
1813
|
+
});
|
|
1814
|
+
} else if (url.pathname === messagePath) {
|
|
1815
|
+
this.logger.debug("Received message");
|
|
1816
|
+
if (!this.sseTransport) {
|
|
1817
|
+
res.writeHead(503);
|
|
1818
|
+
res.end("SSE connection not established");
|
|
1819
|
+
return;
|
|
1820
|
+
}
|
|
1821
|
+
await this.sseTransport.handlePostMessage(req, res);
|
|
1822
|
+
} else {
|
|
1823
|
+
this.logger.debug("Unknown path:", { path: url.pathname });
|
|
1824
|
+
res.writeHead(404);
|
|
1825
|
+
res.end();
|
|
1621
1826
|
}
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1827
|
+
} catch (e) {
|
|
1828
|
+
const mastraError = new error.MastraError(
|
|
1829
|
+
{
|
|
1830
|
+
id: "MCP_SERVER_SSE_START_FAILED",
|
|
1831
|
+
domain: error.ErrorDomain.MCP,
|
|
1832
|
+
category: error.ErrorCategory.USER,
|
|
1833
|
+
details: {
|
|
1834
|
+
url: url.toString(),
|
|
1835
|
+
ssePath,
|
|
1836
|
+
messagePath
|
|
1837
|
+
}
|
|
1838
|
+
},
|
|
1839
|
+
e
|
|
1840
|
+
);
|
|
1841
|
+
this.logger.trackException(mastraError);
|
|
1842
|
+
this.logger.error("Failed to start MCP Server (SSE):", { error: mastraError.toString() });
|
|
1843
|
+
throw mastraError;
|
|
1627
1844
|
}
|
|
1628
1845
|
}
|
|
1629
1846
|
/**
|
|
@@ -1636,31 +1853,50 @@ var MCPServer = class extends mcp.MCPServerBase {
|
|
|
1636
1853
|
* @param context Incoming Hono context
|
|
1637
1854
|
*/
|
|
1638
1855
|
async startHonoSSE({ url, ssePath, messagePath, context }) {
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1856
|
+
try {
|
|
1857
|
+
if (url.pathname === ssePath) {
|
|
1858
|
+
return streaming.streamSSE(context, async (stream) => {
|
|
1859
|
+
await this.connectHonoSSE({
|
|
1860
|
+
messagePath,
|
|
1861
|
+
stream
|
|
1862
|
+
});
|
|
1644
1863
|
});
|
|
1645
|
-
})
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1864
|
+
} else if (url.pathname === messagePath) {
|
|
1865
|
+
this.logger.debug("Received message");
|
|
1866
|
+
const sessionId = context.req.query("sessionId");
|
|
1867
|
+
this.logger.debug("Received message for sessionId", { sessionId });
|
|
1868
|
+
if (!sessionId) {
|
|
1869
|
+
return context.text("No sessionId provided", 400);
|
|
1870
|
+
}
|
|
1871
|
+
if (!this.sseHonoTransports.has(sessionId)) {
|
|
1872
|
+
return context.text(`No transport found for sessionId ${sessionId}`, 400);
|
|
1873
|
+
}
|
|
1874
|
+
const message = await this.sseHonoTransports.get(sessionId)?.handlePostMessage(context);
|
|
1875
|
+
if (!message) {
|
|
1876
|
+
return context.text("Transport not found", 400);
|
|
1877
|
+
}
|
|
1878
|
+
return message;
|
|
1879
|
+
} else {
|
|
1880
|
+
this.logger.debug("Unknown path:", { path: url.pathname });
|
|
1881
|
+
return context.text("Unknown path", 404);
|
|
1659
1882
|
}
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1883
|
+
} catch (e) {
|
|
1884
|
+
const mastraError = new error.MastraError(
|
|
1885
|
+
{
|
|
1886
|
+
id: "MCP_SERVER_HONO_SSE_START_FAILED",
|
|
1887
|
+
domain: error.ErrorDomain.MCP,
|
|
1888
|
+
category: error.ErrorCategory.USER,
|
|
1889
|
+
details: {
|
|
1890
|
+
url: url.toString(),
|
|
1891
|
+
ssePath,
|
|
1892
|
+
messagePath
|
|
1893
|
+
}
|
|
1894
|
+
},
|
|
1895
|
+
e
|
|
1896
|
+
);
|
|
1897
|
+
this.logger.trackException(mastraError);
|
|
1898
|
+
this.logger.error("Failed to start MCP Server (Hono SSE):", { error: mastraError.toString() });
|
|
1899
|
+
throw mastraError;
|
|
1664
1900
|
}
|
|
1665
1901
|
}
|
|
1666
1902
|
/**
|
|
@@ -1788,8 +2024,18 @@ var MCPServer = class extends mcp.MCPServerBase {
|
|
|
1788
2024
|
);
|
|
1789
2025
|
}
|
|
1790
2026
|
}
|
|
1791
|
-
} catch (error) {
|
|
1792
|
-
|
|
2027
|
+
} catch (error$1) {
|
|
2028
|
+
const mastraError = new error.MastraError(
|
|
2029
|
+
{
|
|
2030
|
+
id: "MCP_SERVER_HTTP_CONNECTION_FAILED",
|
|
2031
|
+
domain: error.ErrorDomain.MCP,
|
|
2032
|
+
category: error.ErrorCategory.USER,
|
|
2033
|
+
text: "Failed to connect MCP server using HTTP transport"
|
|
2034
|
+
},
|
|
2035
|
+
error$1
|
|
2036
|
+
);
|
|
2037
|
+
this.logger.trackException(mastraError);
|
|
2038
|
+
this.logger.error("startHTTP: Error handling Streamable HTTP request:", { error: mastraError });
|
|
1793
2039
|
if (!res.headersSent) {
|
|
1794
2040
|
res.writeHead(500, { "Content-Type": "application/json" });
|
|
1795
2041
|
res.end(
|
|
@@ -1803,8 +2049,6 @@ var MCPServer = class extends mcp.MCPServerBase {
|
|
|
1803
2049
|
// Cannot determine original request ID in catch
|
|
1804
2050
|
})
|
|
1805
2051
|
);
|
|
1806
|
-
} else {
|
|
1807
|
-
this.logger.error("startHTTP: Error after headers sent:", error);
|
|
1808
2052
|
}
|
|
1809
2053
|
}
|
|
1810
2054
|
}
|
|
@@ -1812,16 +2056,33 @@ var MCPServer = class extends mcp.MCPServerBase {
|
|
|
1812
2056
|
messagePath,
|
|
1813
2057
|
res
|
|
1814
2058
|
}) {
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
this.
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
2059
|
+
try {
|
|
2060
|
+
this.logger.debug("Received SSE connection");
|
|
2061
|
+
this.sseTransport = new sse_js.SSEServerTransport(messagePath, res);
|
|
2062
|
+
await this.server.connect(this.sseTransport);
|
|
2063
|
+
this.server.onclose = async () => {
|
|
2064
|
+
this.sseTransport = void 0;
|
|
2065
|
+
await this.server.close();
|
|
2066
|
+
};
|
|
2067
|
+
res.on("close", () => {
|
|
2068
|
+
this.sseTransport = void 0;
|
|
2069
|
+
});
|
|
2070
|
+
} catch (e) {
|
|
2071
|
+
const mastraError = new error.MastraError(
|
|
2072
|
+
{
|
|
2073
|
+
id: "MCP_SERVER_SSE_CONNECT_FAILED",
|
|
2074
|
+
domain: error.ErrorDomain.MCP,
|
|
2075
|
+
category: error.ErrorCategory.USER,
|
|
2076
|
+
details: {
|
|
2077
|
+
messagePath
|
|
2078
|
+
}
|
|
2079
|
+
},
|
|
2080
|
+
e
|
|
2081
|
+
);
|
|
2082
|
+
this.logger.trackException(mastraError);
|
|
2083
|
+
this.logger.error("Failed to connect to MCP Server (SSE):", { error: mastraError });
|
|
2084
|
+
throw mastraError;
|
|
2085
|
+
}
|
|
1825
2086
|
}
|
|
1826
2087
|
async connectHonoSSE({ messagePath, stream }) {
|
|
1827
2088
|
this.logger.debug("Received SSE connection");
|
|
@@ -1833,17 +2094,34 @@ var MCPServer = class extends mcp.MCPServerBase {
|
|
|
1833
2094
|
this.logger.debug("SSE Transport aborted with sessionId:", { sessionId });
|
|
1834
2095
|
this.sseHonoTransports.delete(sessionId);
|
|
1835
2096
|
});
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
this.
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
2097
|
+
try {
|
|
2098
|
+
await this.server.connect(sseTransport);
|
|
2099
|
+
this.server.onclose = async () => {
|
|
2100
|
+
this.logger.debug("SSE Transport closed with sessionId:", { sessionId });
|
|
2101
|
+
this.sseHonoTransports.delete(sessionId);
|
|
2102
|
+
await this.server.close();
|
|
2103
|
+
};
|
|
2104
|
+
while (true) {
|
|
2105
|
+
const sessionIds = Array.from(this.sseHonoTransports.keys() || []);
|
|
2106
|
+
this.logger.debug("Active Hono SSE sessions:", { sessionIds });
|
|
2107
|
+
await stream.write(":keep-alive\n\n");
|
|
2108
|
+
await stream.sleep(6e4);
|
|
2109
|
+
}
|
|
2110
|
+
} catch (e) {
|
|
2111
|
+
const mastraError = new error.MastraError(
|
|
2112
|
+
{
|
|
2113
|
+
id: "MCP_SERVER_HONO_SSE_CONNECT_FAILED",
|
|
2114
|
+
domain: error.ErrorDomain.MCP,
|
|
2115
|
+
category: error.ErrorCategory.USER,
|
|
2116
|
+
details: {
|
|
2117
|
+
messagePath
|
|
2118
|
+
}
|
|
2119
|
+
},
|
|
2120
|
+
e
|
|
2121
|
+
);
|
|
2122
|
+
this.logger.trackException(mastraError);
|
|
2123
|
+
this.logger.error("Failed to connect to MCP Server (Hono SSE):", { error: mastraError });
|
|
2124
|
+
throw mastraError;
|
|
1847
2125
|
}
|
|
1848
2126
|
}
|
|
1849
2127
|
/**
|
|
@@ -1880,8 +2158,18 @@ var MCPServer = class extends mcp.MCPServerBase {
|
|
|
1880
2158
|
}
|
|
1881
2159
|
await this.server.close();
|
|
1882
2160
|
this.logger.info("MCP server closed.");
|
|
1883
|
-
} catch (error) {
|
|
1884
|
-
|
|
2161
|
+
} catch (error$1) {
|
|
2162
|
+
const mastraError = new error.MastraError(
|
|
2163
|
+
{
|
|
2164
|
+
id: "MCP_SERVER_CLOSE_FAILED",
|
|
2165
|
+
domain: error.ErrorDomain.MCP,
|
|
2166
|
+
category: error.ErrorCategory.THIRD_PARTY
|
|
2167
|
+
},
|
|
2168
|
+
error$1
|
|
2169
|
+
);
|
|
2170
|
+
this.logger.trackException(mastraError);
|
|
2171
|
+
this.logger.error("Error closing MCP server:", { error: mastraError });
|
|
2172
|
+
throw mastraError;
|
|
1885
2173
|
}
|
|
1886
2174
|
}
|
|
1887
2175
|
/**
|
|
@@ -1959,30 +2247,47 @@ var MCPServer = class extends mcp.MCPServerBase {
|
|
|
1959
2247
|
*/
|
|
1960
2248
|
async executeTool(toolId, args, executionContext) {
|
|
1961
2249
|
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);
|
|
2250
|
+
let validatedArgs;
|
|
2251
|
+
try {
|
|
2252
|
+
if (!tool) {
|
|
2253
|
+
this.logger.warn(`ExecuteTool: Unknown tool '${toolId}' requested on MCPServer '${this.name}'.`);
|
|
2254
|
+
throw new Error(`Unknown tool: ${toolId}`);
|
|
1976
2255
|
}
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
2256
|
+
this.logger.debug(`ExecuteTool: Invoking '${toolId}' with arguments:`, args);
|
|
2257
|
+
if (tool.parameters instanceof zod.z.ZodType && typeof tool.parameters.safeParse === "function") {
|
|
2258
|
+
const validation = tool.parameters.safeParse(args ?? {});
|
|
2259
|
+
if (!validation.success) {
|
|
2260
|
+
const errorMessages = validation.error.errors.map((e) => `${e.path.join(".")}: ${e.message}`).join(", ");
|
|
2261
|
+
this.logger.warn(`ExecuteTool: Invalid tool arguments for '${toolId}': ${errorMessages}`, {
|
|
2262
|
+
errors: validation.error.format()
|
|
2263
|
+
});
|
|
2264
|
+
throw new zod.z.ZodError(validation.error.issues);
|
|
2265
|
+
}
|
|
2266
|
+
validatedArgs = validation.data;
|
|
2267
|
+
} else {
|
|
2268
|
+
this.logger.debug(
|
|
2269
|
+
`ExecuteTool: Tool '${toolId}' parameters is not a Zod schema with safeParse or is undefined. Skipping validation.`
|
|
2270
|
+
);
|
|
2271
|
+
}
|
|
2272
|
+
if (!tool.execute) {
|
|
2273
|
+
this.logger.error(`ExecuteTool: Tool '${toolId}' does not have an execute function.`);
|
|
2274
|
+
throw new Error(`Tool '${toolId}' cannot be executed.`);
|
|
2275
|
+
}
|
|
2276
|
+
} catch (error$1) {
|
|
2277
|
+
const mastraError = new error.MastraError(
|
|
2278
|
+
{
|
|
2279
|
+
id: "MCP_SERVER_TOOL_EXECUTE_PREPARATION_FAILED",
|
|
2280
|
+
domain: error.ErrorDomain.MCP,
|
|
2281
|
+
category: error.ErrorCategory.USER,
|
|
2282
|
+
details: {
|
|
2283
|
+
toolId,
|
|
2284
|
+
args
|
|
2285
|
+
}
|
|
2286
|
+
},
|
|
2287
|
+
error$1
|
|
1981
2288
|
);
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
this.logger.error(`ExecuteTool: Tool '${toolId}' does not have an execute function.`);
|
|
1985
|
-
throw new Error(`Tool '${toolId}' cannot be executed.`);
|
|
2289
|
+
this.logger.trackException(mastraError);
|
|
2290
|
+
throw mastraError;
|
|
1986
2291
|
}
|
|
1987
2292
|
try {
|
|
1988
2293
|
const finalExecutionContext = {
|
|
@@ -1992,9 +2297,22 @@ var MCPServer = class extends mcp.MCPServerBase {
|
|
|
1992
2297
|
const result = await tool.execute(validatedArgs, finalExecutionContext);
|
|
1993
2298
|
this.logger.info(`ExecuteTool: Tool '${toolId}' executed successfully.`);
|
|
1994
2299
|
return result;
|
|
1995
|
-
} catch (error) {
|
|
1996
|
-
|
|
1997
|
-
|
|
2300
|
+
} catch (error$1) {
|
|
2301
|
+
const mastraError = new error.MastraError(
|
|
2302
|
+
{
|
|
2303
|
+
id: "MCP_SERVER_TOOL_EXECUTE_FAILED",
|
|
2304
|
+
domain: error.ErrorDomain.MCP,
|
|
2305
|
+
category: error.ErrorCategory.USER,
|
|
2306
|
+
details: {
|
|
2307
|
+
toolId,
|
|
2308
|
+
validatedArgs
|
|
2309
|
+
}
|
|
2310
|
+
},
|
|
2311
|
+
error$1
|
|
2312
|
+
);
|
|
2313
|
+
this.logger.trackException(mastraError);
|
|
2314
|
+
this.logger.error(`ExecuteTool: Tool execution failed for '${toolId}':`, { error: error$1 });
|
|
2315
|
+
throw mastraError;
|
|
1998
2316
|
}
|
|
1999
2317
|
}
|
|
2000
2318
|
};
|