@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.js
CHANGED
|
@@ -10,6 +10,7 @@ import { ListToolsRequestSchema, CallToolRequestSchema, ListResourcesRequestSche
|
|
|
10
10
|
import { asyncExitHook, gracefulExit } from 'exit-hook';
|
|
11
11
|
import { z } from 'zod';
|
|
12
12
|
import { convertJsonSchemaToZod } from 'zod-from-json-schema';
|
|
13
|
+
import { MastraError, ErrorCategory, ErrorDomain } from '@mastra/core/error';
|
|
13
14
|
import equal from 'fast-deep-equal';
|
|
14
15
|
import { v5 } from 'uuid';
|
|
15
16
|
import { randomUUID } from 'crypto';
|
|
@@ -609,7 +610,16 @@ To fix this you have three different options:
|
|
|
609
610
|
const internalClient = await this.getConnectedClientForServer(serverName);
|
|
610
611
|
allResources[serverName] = await internalClient.resources.list();
|
|
611
612
|
} catch (error) {
|
|
612
|
-
|
|
613
|
+
const mastraError = new MastraError({
|
|
614
|
+
id: "MCP_CLIENT_LIST_RESOURCES_FAILED",
|
|
615
|
+
domain: ErrorDomain.MCP,
|
|
616
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
617
|
+
details: {
|
|
618
|
+
serverName
|
|
619
|
+
}
|
|
620
|
+
}, error);
|
|
621
|
+
this.logger.trackException(mastraError);
|
|
622
|
+
this.logger.error("Failed to list resources from server:", { error: mastraError.toString() });
|
|
613
623
|
}
|
|
614
624
|
}
|
|
615
625
|
return allResources;
|
|
@@ -621,30 +631,97 @@ To fix this you have three different options:
|
|
|
621
631
|
const internalClient = await this.getConnectedClientForServer(serverName);
|
|
622
632
|
allTemplates[serverName] = await internalClient.resources.templates();
|
|
623
633
|
} catch (error) {
|
|
624
|
-
|
|
634
|
+
const mastraError = new MastraError({
|
|
635
|
+
id: "MCP_CLIENT_LIST_RESOURCE_TEMPLATES_FAILED",
|
|
636
|
+
domain: ErrorDomain.MCP,
|
|
637
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
638
|
+
details: {
|
|
639
|
+
serverName
|
|
640
|
+
}
|
|
641
|
+
}, error);
|
|
642
|
+
this.logger.trackException(mastraError);
|
|
643
|
+
this.logger.error("Failed to list resource templates from server:", { error: mastraError.toString() });
|
|
625
644
|
}
|
|
626
645
|
}
|
|
627
646
|
return allTemplates;
|
|
628
647
|
},
|
|
629
648
|
read: async (serverName, uri) => {
|
|
630
|
-
|
|
631
|
-
|
|
649
|
+
try {
|
|
650
|
+
const internalClient = await this.getConnectedClientForServer(serverName);
|
|
651
|
+
return internalClient.resources.read(uri);
|
|
652
|
+
} catch (error) {
|
|
653
|
+
throw new MastraError({
|
|
654
|
+
id: "MCP_CLIENT_READ_RESOURCE_FAILED",
|
|
655
|
+
domain: ErrorDomain.MCP,
|
|
656
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
657
|
+
details: {
|
|
658
|
+
serverName,
|
|
659
|
+
uri
|
|
660
|
+
}
|
|
661
|
+
}, error);
|
|
662
|
+
}
|
|
632
663
|
},
|
|
633
664
|
subscribe: async (serverName, uri) => {
|
|
634
|
-
|
|
635
|
-
|
|
665
|
+
try {
|
|
666
|
+
const internalClient = await this.getConnectedClientForServer(serverName);
|
|
667
|
+
return internalClient.resources.subscribe(uri);
|
|
668
|
+
} catch (error) {
|
|
669
|
+
throw new MastraError({
|
|
670
|
+
id: "MCP_CLIENT_SUBSCRIBE_RESOURCE_FAILED",
|
|
671
|
+
domain: ErrorDomain.MCP,
|
|
672
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
673
|
+
details: {
|
|
674
|
+
serverName,
|
|
675
|
+
uri
|
|
676
|
+
}
|
|
677
|
+
}, error);
|
|
678
|
+
}
|
|
636
679
|
},
|
|
637
680
|
unsubscribe: async (serverName, uri) => {
|
|
638
|
-
|
|
639
|
-
|
|
681
|
+
try {
|
|
682
|
+
const internalClient = await this.getConnectedClientForServer(serverName);
|
|
683
|
+
return internalClient.resources.unsubscribe(uri);
|
|
684
|
+
} catch (err) {
|
|
685
|
+
throw new MastraError({
|
|
686
|
+
id: "MCP_CLIENT_UNSUBSCRIBE_RESOURCE_FAILED",
|
|
687
|
+
domain: ErrorDomain.MCP,
|
|
688
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
689
|
+
details: {
|
|
690
|
+
serverName,
|
|
691
|
+
uri
|
|
692
|
+
}
|
|
693
|
+
}, err);
|
|
694
|
+
}
|
|
640
695
|
},
|
|
641
696
|
onUpdated: async (serverName, handler) => {
|
|
642
|
-
|
|
643
|
-
|
|
697
|
+
try {
|
|
698
|
+
const internalClient = await this.getConnectedClientForServer(serverName);
|
|
699
|
+
return internalClient.resources.onUpdated(handler);
|
|
700
|
+
} catch (err) {
|
|
701
|
+
throw new MastraError({
|
|
702
|
+
id: "MCP_CLIENT_ON_UPDATED_RESOURCE_FAILED",
|
|
703
|
+
domain: ErrorDomain.MCP,
|
|
704
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
705
|
+
details: {
|
|
706
|
+
serverName
|
|
707
|
+
}
|
|
708
|
+
}, err);
|
|
709
|
+
}
|
|
644
710
|
},
|
|
645
711
|
onListChanged: async (serverName, handler) => {
|
|
646
|
-
|
|
647
|
-
|
|
712
|
+
try {
|
|
713
|
+
const internalClient = await this.getConnectedClientForServer(serverName);
|
|
714
|
+
return internalClient.resources.onListChanged(handler);
|
|
715
|
+
} catch (err) {
|
|
716
|
+
throw new MastraError({
|
|
717
|
+
id: "MCP_CLIENT_ON_LIST_CHANGED_RESOURCE_FAILED",
|
|
718
|
+
domain: ErrorDomain.MCP,
|
|
719
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
720
|
+
details: {
|
|
721
|
+
serverName
|
|
722
|
+
}
|
|
723
|
+
}, err);
|
|
724
|
+
}
|
|
648
725
|
}
|
|
649
726
|
};
|
|
650
727
|
}
|
|
@@ -658,18 +735,50 @@ To fix this you have three different options:
|
|
|
658
735
|
const internalClient = await this.getConnectedClientForServer(serverName);
|
|
659
736
|
allPrompts[serverName] = await internalClient.prompts.list();
|
|
660
737
|
} catch (error) {
|
|
661
|
-
|
|
738
|
+
const mastraError = new MastraError({
|
|
739
|
+
id: "MCP_CLIENT_LIST_PROMPTS_FAILED",
|
|
740
|
+
domain: ErrorDomain.MCP,
|
|
741
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
742
|
+
details: {
|
|
743
|
+
serverName
|
|
744
|
+
}
|
|
745
|
+
}, error);
|
|
746
|
+
this.logger.trackException(mastraError);
|
|
747
|
+
this.logger.error("Failed to list prompts from server:", { error: mastraError.toString() });
|
|
662
748
|
}
|
|
663
749
|
}
|
|
664
750
|
return allPrompts;
|
|
665
751
|
},
|
|
666
752
|
get: async ({ serverName, name, args, version }) => {
|
|
667
|
-
|
|
668
|
-
|
|
753
|
+
try {
|
|
754
|
+
const internalClient = await this.getConnectedClientForServer(serverName);
|
|
755
|
+
return internalClient.prompts.get({ name, args, version });
|
|
756
|
+
} catch (error) {
|
|
757
|
+
throw new MastraError({
|
|
758
|
+
id: "MCP_CLIENT_GET_PROMPT_FAILED",
|
|
759
|
+
domain: ErrorDomain.MCP,
|
|
760
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
761
|
+
details: {
|
|
762
|
+
serverName,
|
|
763
|
+
name
|
|
764
|
+
}
|
|
765
|
+
}, error);
|
|
766
|
+
}
|
|
669
767
|
},
|
|
670
768
|
onListChanged: async (serverName, handler) => {
|
|
671
|
-
|
|
672
|
-
|
|
769
|
+
try {
|
|
770
|
+
const internalClient = await this.getConnectedClientForServer(serverName);
|
|
771
|
+
return internalClient.prompts.onListChanged(handler);
|
|
772
|
+
} catch (error) {
|
|
773
|
+
throw new MastraError({
|
|
774
|
+
id: "MCP_CLIENT_ON_LIST_CHANGED_PROMPT_FAILED",
|
|
775
|
+
domain: ErrorDomain.MCP,
|
|
776
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
777
|
+
details: {
|
|
778
|
+
serverName
|
|
779
|
+
}
|
|
780
|
+
}, error);
|
|
781
|
+
}
|
|
673
782
|
}
|
|
674
783
|
};
|
|
675
784
|
}
|
|
@@ -701,21 +810,37 @@ To fix this you have three different options:
|
|
|
701
810
|
async getTools() {
|
|
702
811
|
this.addToInstanceCache();
|
|
703
812
|
const connectedTools = {};
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
813
|
+
try {
|
|
814
|
+
await this.eachClientTools(async ({ serverName, tools }) => {
|
|
815
|
+
for (const [toolName, toolConfig] of Object.entries(tools)) {
|
|
816
|
+
connectedTools[`${serverName}_${toolName}`] = toolConfig;
|
|
817
|
+
}
|
|
818
|
+
});
|
|
819
|
+
} catch (error) {
|
|
820
|
+
throw new MastraError({
|
|
821
|
+
id: "MCP_CLIENT_GET_TOOLS_FAILED",
|
|
822
|
+
domain: ErrorDomain.MCP,
|
|
823
|
+
category: ErrorCategory.THIRD_PARTY
|
|
824
|
+
}, error);
|
|
825
|
+
}
|
|
709
826
|
return connectedTools;
|
|
710
827
|
}
|
|
711
828
|
async getToolsets() {
|
|
712
829
|
this.addToInstanceCache();
|
|
713
830
|
const connectedToolsets = {};
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
831
|
+
try {
|
|
832
|
+
await this.eachClientTools(async ({ serverName, tools }) => {
|
|
833
|
+
if (tools) {
|
|
834
|
+
connectedToolsets[serverName] = tools;
|
|
835
|
+
}
|
|
836
|
+
});
|
|
837
|
+
} catch (error) {
|
|
838
|
+
throw new MastraError({
|
|
839
|
+
id: "MCP_CLIENT_GET_TOOLSETS_FAILED",
|
|
840
|
+
domain: ErrorDomain.MCP,
|
|
841
|
+
category: ErrorCategory.THIRD_PARTY
|
|
842
|
+
}, error);
|
|
843
|
+
}
|
|
719
844
|
return connectedToolsets;
|
|
720
845
|
}
|
|
721
846
|
/**
|
|
@@ -762,13 +887,19 @@ To fix this you have three different options:
|
|
|
762
887
|
try {
|
|
763
888
|
await mcpClient.connect();
|
|
764
889
|
} catch (e) {
|
|
890
|
+
const mastraError = new MastraError({
|
|
891
|
+
id: "MCP_CLIENT_CONNECT_FAILED",
|
|
892
|
+
domain: ErrorDomain.MCP,
|
|
893
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
894
|
+
text: `Failed to connect to MCP server ${name}: ${e instanceof Error ? e.stack || e.message : String(e)}`,
|
|
895
|
+
details: {
|
|
896
|
+
name
|
|
897
|
+
}
|
|
898
|
+
}, e);
|
|
899
|
+
this.logger.trackException(mastraError);
|
|
900
|
+
this.logger.error("MCPClient errored connecting to MCP server:", { error: mastraError.toString() });
|
|
765
901
|
this.mcpClientsById.delete(name);
|
|
766
|
-
|
|
767
|
-
error: e instanceof Error ? e.message : String(e)
|
|
768
|
-
});
|
|
769
|
-
throw new Error(
|
|
770
|
-
`Failed to connect to MCP server ${name}: ${e instanceof Error ? e.stack || e.message : String(e)}`
|
|
771
|
-
);
|
|
902
|
+
throw mastraError;
|
|
772
903
|
}
|
|
773
904
|
this.logger.debug(`Connected to ${name} MCP server`);
|
|
774
905
|
return mcpClient;
|
|
@@ -882,8 +1013,6 @@ var SSETransport = class {
|
|
|
882
1013
|
});
|
|
883
1014
|
}
|
|
884
1015
|
};
|
|
885
|
-
|
|
886
|
-
// src/server/promptActions.ts
|
|
887
1016
|
var ServerPromptActions = class {
|
|
888
1017
|
getLogger;
|
|
889
1018
|
getSdkServer;
|
|
@@ -903,15 +1032,23 @@ var ServerPromptActions = class {
|
|
|
903
1032
|
try {
|
|
904
1033
|
await this.getSdkServer().sendPromptListChanged();
|
|
905
1034
|
} catch (error) {
|
|
1035
|
+
const mastraError = new MastraError(
|
|
1036
|
+
{
|
|
1037
|
+
id: "MCP_SERVER_PROMPT_LIST_CHANGED_NOTIFICATION_FAILED",
|
|
1038
|
+
domain: ErrorDomain.MCP,
|
|
1039
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1040
|
+
text: "Failed to send prompt list changed notification"
|
|
1041
|
+
},
|
|
1042
|
+
error
|
|
1043
|
+
);
|
|
906
1044
|
this.getLogger().error("Failed to send prompt list changed notification:", {
|
|
907
|
-
error:
|
|
1045
|
+
error: mastraError.toString()
|
|
908
1046
|
});
|
|
909
|
-
|
|
1047
|
+
this.getLogger().trackException(mastraError);
|
|
1048
|
+
throw mastraError;
|
|
910
1049
|
}
|
|
911
1050
|
}
|
|
912
1051
|
};
|
|
913
|
-
|
|
914
|
-
// src/server/resourceActions.ts
|
|
915
1052
|
var ServerResourceActions = class {
|
|
916
1053
|
getSubscriptions;
|
|
917
1054
|
getLogger;
|
|
@@ -935,8 +1072,23 @@ var ServerResourceActions = class {
|
|
|
935
1072
|
try {
|
|
936
1073
|
await this.getSdkServer().sendResourceUpdated({ uri });
|
|
937
1074
|
} catch (error) {
|
|
938
|
-
|
|
939
|
-
|
|
1075
|
+
const mastraError = new MastraError(
|
|
1076
|
+
{
|
|
1077
|
+
id: "MCP_SERVER_RESOURCE_UPDATED_NOTIFICATION_FAILED",
|
|
1078
|
+
domain: ErrorDomain.MCP,
|
|
1079
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1080
|
+
text: "Failed to send resource updated notification",
|
|
1081
|
+
details: {
|
|
1082
|
+
uri
|
|
1083
|
+
}
|
|
1084
|
+
},
|
|
1085
|
+
error
|
|
1086
|
+
);
|
|
1087
|
+
this.getLogger().trackException(mastraError);
|
|
1088
|
+
this.getLogger().error("Failed to send resource updated notification:", {
|
|
1089
|
+
error: mastraError.toString()
|
|
1090
|
+
});
|
|
1091
|
+
throw mastraError;
|
|
940
1092
|
}
|
|
941
1093
|
} else {
|
|
942
1094
|
this.getLogger().debug(`Resource ${uri} was updated, but no active subscriptions for it.`);
|
|
@@ -955,8 +1107,20 @@ var ServerResourceActions = class {
|
|
|
955
1107
|
try {
|
|
956
1108
|
await this.getSdkServer().sendResourceListChanged();
|
|
957
1109
|
} catch (error) {
|
|
958
|
-
|
|
959
|
-
|
|
1110
|
+
const mastraError = new MastraError(
|
|
1111
|
+
{
|
|
1112
|
+
id: "MCP_SERVER_RESOURCE_LIST_CHANGED_NOTIFICATION_FAILED",
|
|
1113
|
+
domain: ErrorDomain.MCP,
|
|
1114
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
1115
|
+
text: "Failed to send resource list changed notification"
|
|
1116
|
+
},
|
|
1117
|
+
error
|
|
1118
|
+
);
|
|
1119
|
+
this.getLogger().trackException(mastraError);
|
|
1120
|
+
this.getLogger().error("Failed to send resource list changed notification:", {
|
|
1121
|
+
error: mastraError.toString()
|
|
1122
|
+
});
|
|
1123
|
+
throw mastraError;
|
|
960
1124
|
}
|
|
961
1125
|
}
|
|
962
1126
|
};
|
|
@@ -1234,8 +1398,26 @@ var MCPServer = class extends MCPServerBase {
|
|
|
1234
1398
|
this.logger.info(`Registered explicit tool: '${toolName}'`);
|
|
1235
1399
|
}
|
|
1236
1400
|
this.logger.info(`Total defined tools registered: ${Object.keys(definedConvertedTools).length}`);
|
|
1237
|
-
|
|
1238
|
-
|
|
1401
|
+
let agentDerivedTools = {};
|
|
1402
|
+
let workflowDerivedTools = {};
|
|
1403
|
+
try {
|
|
1404
|
+
agentDerivedTools = this.convertAgentsToTools(agentsConfig, definedConvertedTools);
|
|
1405
|
+
workflowDerivedTools = this.convertWorkflowsToTools(workflowsConfig, definedConvertedTools);
|
|
1406
|
+
} catch (e) {
|
|
1407
|
+
const mastraError = new MastraError(
|
|
1408
|
+
{
|
|
1409
|
+
id: "MCP_SERVER_AGENT_OR_WORKFLOW_TOOL_CONVERSION_FAILED",
|
|
1410
|
+
domain: ErrorDomain.MCP,
|
|
1411
|
+
category: ErrorCategory.USER
|
|
1412
|
+
},
|
|
1413
|
+
e
|
|
1414
|
+
);
|
|
1415
|
+
this.logger.trackException(mastraError);
|
|
1416
|
+
this.logger.error("Failed to convert tools:", {
|
|
1417
|
+
error: mastraError.toString()
|
|
1418
|
+
});
|
|
1419
|
+
throw mastraError;
|
|
1420
|
+
}
|
|
1239
1421
|
const allConvertedTools = { ...definedConvertedTools, ...agentDerivedTools, ...workflowDerivedTools };
|
|
1240
1422
|
const finalToolCount = Object.keys(allConvertedTools).length;
|
|
1241
1423
|
const definedCount = Object.keys(definedConvertedTools).length;
|
|
@@ -1587,7 +1769,23 @@ var MCPServer = class extends MCPServerBase {
|
|
|
1587
1769
|
*/
|
|
1588
1770
|
async startStdio() {
|
|
1589
1771
|
this.stdioTransport = new StdioServerTransport();
|
|
1590
|
-
|
|
1772
|
+
try {
|
|
1773
|
+
await this.server.connect(this.stdioTransport);
|
|
1774
|
+
} catch (error) {
|
|
1775
|
+
const mastraError = new MastraError(
|
|
1776
|
+
{
|
|
1777
|
+
id: "MCP_SERVER_STDIO_CONNECTION_FAILED",
|
|
1778
|
+
domain: ErrorDomain.MCP,
|
|
1779
|
+
category: ErrorCategory.THIRD_PARTY
|
|
1780
|
+
},
|
|
1781
|
+
error
|
|
1782
|
+
);
|
|
1783
|
+
this.logger.trackException(mastraError);
|
|
1784
|
+
this.logger.error("Failed to connect MCP server using stdio transport:", {
|
|
1785
|
+
error: mastraError.toString()
|
|
1786
|
+
});
|
|
1787
|
+
throw mastraError;
|
|
1788
|
+
}
|
|
1591
1789
|
this.logger.info("Started MCP Server (stdio)");
|
|
1592
1790
|
}
|
|
1593
1791
|
/**
|
|
@@ -1601,23 +1799,42 @@ var MCPServer = class extends MCPServerBase {
|
|
|
1601
1799
|
* @param res HTTP response (must support .write/.end)
|
|
1602
1800
|
*/
|
|
1603
1801
|
async startSSE({ url, ssePath, messagePath, req, res }) {
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1802
|
+
try {
|
|
1803
|
+
if (url.pathname === ssePath) {
|
|
1804
|
+
await this.connectSSE({
|
|
1805
|
+
messagePath,
|
|
1806
|
+
res
|
|
1807
|
+
});
|
|
1808
|
+
} else if (url.pathname === messagePath) {
|
|
1809
|
+
this.logger.debug("Received message");
|
|
1810
|
+
if (!this.sseTransport) {
|
|
1811
|
+
res.writeHead(503);
|
|
1812
|
+
res.end("SSE connection not established");
|
|
1813
|
+
return;
|
|
1814
|
+
}
|
|
1815
|
+
await this.sseTransport.handlePostMessage(req, res);
|
|
1816
|
+
} else {
|
|
1817
|
+
this.logger.debug("Unknown path:", { path: url.pathname });
|
|
1818
|
+
res.writeHead(404);
|
|
1819
|
+
res.end();
|
|
1615
1820
|
}
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1821
|
+
} catch (e) {
|
|
1822
|
+
const mastraError = new MastraError(
|
|
1823
|
+
{
|
|
1824
|
+
id: "MCP_SERVER_SSE_START_FAILED",
|
|
1825
|
+
domain: ErrorDomain.MCP,
|
|
1826
|
+
category: ErrorCategory.USER,
|
|
1827
|
+
details: {
|
|
1828
|
+
url: url.toString(),
|
|
1829
|
+
ssePath,
|
|
1830
|
+
messagePath
|
|
1831
|
+
}
|
|
1832
|
+
},
|
|
1833
|
+
e
|
|
1834
|
+
);
|
|
1835
|
+
this.logger.trackException(mastraError);
|
|
1836
|
+
this.logger.error("Failed to start MCP Server (SSE):", { error: mastraError.toString() });
|
|
1837
|
+
throw mastraError;
|
|
1621
1838
|
}
|
|
1622
1839
|
}
|
|
1623
1840
|
/**
|
|
@@ -1630,31 +1847,50 @@ var MCPServer = class extends MCPServerBase {
|
|
|
1630
1847
|
* @param context Incoming Hono context
|
|
1631
1848
|
*/
|
|
1632
1849
|
async startHonoSSE({ url, ssePath, messagePath, context }) {
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1850
|
+
try {
|
|
1851
|
+
if (url.pathname === ssePath) {
|
|
1852
|
+
return streamSSE(context, async (stream) => {
|
|
1853
|
+
await this.connectHonoSSE({
|
|
1854
|
+
messagePath,
|
|
1855
|
+
stream
|
|
1856
|
+
});
|
|
1638
1857
|
});
|
|
1639
|
-
})
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1858
|
+
} else if (url.pathname === messagePath) {
|
|
1859
|
+
this.logger.debug("Received message");
|
|
1860
|
+
const sessionId = context.req.query("sessionId");
|
|
1861
|
+
this.logger.debug("Received message for sessionId", { sessionId });
|
|
1862
|
+
if (!sessionId) {
|
|
1863
|
+
return context.text("No sessionId provided", 400);
|
|
1864
|
+
}
|
|
1865
|
+
if (!this.sseHonoTransports.has(sessionId)) {
|
|
1866
|
+
return context.text(`No transport found for sessionId ${sessionId}`, 400);
|
|
1867
|
+
}
|
|
1868
|
+
const message = await this.sseHonoTransports.get(sessionId)?.handlePostMessage(context);
|
|
1869
|
+
if (!message) {
|
|
1870
|
+
return context.text("Transport not found", 400);
|
|
1871
|
+
}
|
|
1872
|
+
return message;
|
|
1873
|
+
} else {
|
|
1874
|
+
this.logger.debug("Unknown path:", { path: url.pathname });
|
|
1875
|
+
return context.text("Unknown path", 404);
|
|
1653
1876
|
}
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1877
|
+
} catch (e) {
|
|
1878
|
+
const mastraError = new MastraError(
|
|
1879
|
+
{
|
|
1880
|
+
id: "MCP_SERVER_HONO_SSE_START_FAILED",
|
|
1881
|
+
domain: ErrorDomain.MCP,
|
|
1882
|
+
category: ErrorCategory.USER,
|
|
1883
|
+
details: {
|
|
1884
|
+
url: url.toString(),
|
|
1885
|
+
ssePath,
|
|
1886
|
+
messagePath
|
|
1887
|
+
}
|
|
1888
|
+
},
|
|
1889
|
+
e
|
|
1890
|
+
);
|
|
1891
|
+
this.logger.trackException(mastraError);
|
|
1892
|
+
this.logger.error("Failed to start MCP Server (Hono SSE):", { error: mastraError.toString() });
|
|
1893
|
+
throw mastraError;
|
|
1658
1894
|
}
|
|
1659
1895
|
}
|
|
1660
1896
|
/**
|
|
@@ -1783,7 +2019,17 @@ var MCPServer = class extends MCPServerBase {
|
|
|
1783
2019
|
}
|
|
1784
2020
|
}
|
|
1785
2021
|
} catch (error) {
|
|
1786
|
-
|
|
2022
|
+
const mastraError = new MastraError(
|
|
2023
|
+
{
|
|
2024
|
+
id: "MCP_SERVER_HTTP_CONNECTION_FAILED",
|
|
2025
|
+
domain: ErrorDomain.MCP,
|
|
2026
|
+
category: ErrorCategory.USER,
|
|
2027
|
+
text: "Failed to connect MCP server using HTTP transport"
|
|
2028
|
+
},
|
|
2029
|
+
error
|
|
2030
|
+
);
|
|
2031
|
+
this.logger.trackException(mastraError);
|
|
2032
|
+
this.logger.error("startHTTP: Error handling Streamable HTTP request:", { error: mastraError });
|
|
1787
2033
|
if (!res.headersSent) {
|
|
1788
2034
|
res.writeHead(500, { "Content-Type": "application/json" });
|
|
1789
2035
|
res.end(
|
|
@@ -1797,8 +2043,6 @@ var MCPServer = class extends MCPServerBase {
|
|
|
1797
2043
|
// Cannot determine original request ID in catch
|
|
1798
2044
|
})
|
|
1799
2045
|
);
|
|
1800
|
-
} else {
|
|
1801
|
-
this.logger.error("startHTTP: Error after headers sent:", error);
|
|
1802
2046
|
}
|
|
1803
2047
|
}
|
|
1804
2048
|
}
|
|
@@ -1806,16 +2050,33 @@ var MCPServer = class extends MCPServerBase {
|
|
|
1806
2050
|
messagePath,
|
|
1807
2051
|
res
|
|
1808
2052
|
}) {
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
this.
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
2053
|
+
try {
|
|
2054
|
+
this.logger.debug("Received SSE connection");
|
|
2055
|
+
this.sseTransport = new SSEServerTransport(messagePath, res);
|
|
2056
|
+
await this.server.connect(this.sseTransport);
|
|
2057
|
+
this.server.onclose = async () => {
|
|
2058
|
+
this.sseTransport = void 0;
|
|
2059
|
+
await this.server.close();
|
|
2060
|
+
};
|
|
2061
|
+
res.on("close", () => {
|
|
2062
|
+
this.sseTransport = void 0;
|
|
2063
|
+
});
|
|
2064
|
+
} catch (e) {
|
|
2065
|
+
const mastraError = new MastraError(
|
|
2066
|
+
{
|
|
2067
|
+
id: "MCP_SERVER_SSE_CONNECT_FAILED",
|
|
2068
|
+
domain: ErrorDomain.MCP,
|
|
2069
|
+
category: ErrorCategory.USER,
|
|
2070
|
+
details: {
|
|
2071
|
+
messagePath
|
|
2072
|
+
}
|
|
2073
|
+
},
|
|
2074
|
+
e
|
|
2075
|
+
);
|
|
2076
|
+
this.logger.trackException(mastraError);
|
|
2077
|
+
this.logger.error("Failed to connect to MCP Server (SSE):", { error: mastraError });
|
|
2078
|
+
throw mastraError;
|
|
2079
|
+
}
|
|
1819
2080
|
}
|
|
1820
2081
|
async connectHonoSSE({ messagePath, stream }) {
|
|
1821
2082
|
this.logger.debug("Received SSE connection");
|
|
@@ -1827,17 +2088,34 @@ var MCPServer = class extends MCPServerBase {
|
|
|
1827
2088
|
this.logger.debug("SSE Transport aborted with sessionId:", { sessionId });
|
|
1828
2089
|
this.sseHonoTransports.delete(sessionId);
|
|
1829
2090
|
});
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
this.
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
2091
|
+
try {
|
|
2092
|
+
await this.server.connect(sseTransport);
|
|
2093
|
+
this.server.onclose = async () => {
|
|
2094
|
+
this.logger.debug("SSE Transport closed with sessionId:", { sessionId });
|
|
2095
|
+
this.sseHonoTransports.delete(sessionId);
|
|
2096
|
+
await this.server.close();
|
|
2097
|
+
};
|
|
2098
|
+
while (true) {
|
|
2099
|
+
const sessionIds = Array.from(this.sseHonoTransports.keys() || []);
|
|
2100
|
+
this.logger.debug("Active Hono SSE sessions:", { sessionIds });
|
|
2101
|
+
await stream.write(":keep-alive\n\n");
|
|
2102
|
+
await stream.sleep(6e4);
|
|
2103
|
+
}
|
|
2104
|
+
} catch (e) {
|
|
2105
|
+
const mastraError = new MastraError(
|
|
2106
|
+
{
|
|
2107
|
+
id: "MCP_SERVER_HONO_SSE_CONNECT_FAILED",
|
|
2108
|
+
domain: ErrorDomain.MCP,
|
|
2109
|
+
category: ErrorCategory.USER,
|
|
2110
|
+
details: {
|
|
2111
|
+
messagePath
|
|
2112
|
+
}
|
|
2113
|
+
},
|
|
2114
|
+
e
|
|
2115
|
+
);
|
|
2116
|
+
this.logger.trackException(mastraError);
|
|
2117
|
+
this.logger.error("Failed to connect to MCP Server (Hono SSE):", { error: mastraError });
|
|
2118
|
+
throw mastraError;
|
|
1841
2119
|
}
|
|
1842
2120
|
}
|
|
1843
2121
|
/**
|
|
@@ -1875,7 +2153,17 @@ var MCPServer = class extends MCPServerBase {
|
|
|
1875
2153
|
await this.server.close();
|
|
1876
2154
|
this.logger.info("MCP server closed.");
|
|
1877
2155
|
} catch (error) {
|
|
1878
|
-
|
|
2156
|
+
const mastraError = new MastraError(
|
|
2157
|
+
{
|
|
2158
|
+
id: "MCP_SERVER_CLOSE_FAILED",
|
|
2159
|
+
domain: ErrorDomain.MCP,
|
|
2160
|
+
category: ErrorCategory.THIRD_PARTY
|
|
2161
|
+
},
|
|
2162
|
+
error
|
|
2163
|
+
);
|
|
2164
|
+
this.logger.trackException(mastraError);
|
|
2165
|
+
this.logger.error("Error closing MCP server:", { error: mastraError });
|
|
2166
|
+
throw mastraError;
|
|
1879
2167
|
}
|
|
1880
2168
|
}
|
|
1881
2169
|
/**
|
|
@@ -1953,30 +2241,47 @@ var MCPServer = class extends MCPServerBase {
|
|
|
1953
2241
|
*/
|
|
1954
2242
|
async executeTool(toolId, args, executionContext) {
|
|
1955
2243
|
const tool = this.convertedTools[toolId];
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
let validatedArgs = args;
|
|
1962
|
-
if (tool.parameters instanceof z.ZodType && typeof tool.parameters.safeParse === "function") {
|
|
1963
|
-
const validation = tool.parameters.safeParse(args ?? {});
|
|
1964
|
-
if (!validation.success) {
|
|
1965
|
-
const errorMessages = validation.error.errors.map((e) => `${e.path.join(".")}: ${e.message}`).join(", ");
|
|
1966
|
-
this.logger.warn(`ExecuteTool: Invalid tool arguments for '${toolId}': ${errorMessages}`, {
|
|
1967
|
-
errors: validation.error.format()
|
|
1968
|
-
});
|
|
1969
|
-
throw new z.ZodError(validation.error.issues);
|
|
2244
|
+
let validatedArgs;
|
|
2245
|
+
try {
|
|
2246
|
+
if (!tool) {
|
|
2247
|
+
this.logger.warn(`ExecuteTool: Unknown tool '${toolId}' requested on MCPServer '${this.name}'.`);
|
|
2248
|
+
throw new Error(`Unknown tool: ${toolId}`);
|
|
1970
2249
|
}
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
2250
|
+
this.logger.debug(`ExecuteTool: Invoking '${toolId}' with arguments:`, args);
|
|
2251
|
+
if (tool.parameters instanceof z.ZodType && typeof tool.parameters.safeParse === "function") {
|
|
2252
|
+
const validation = tool.parameters.safeParse(args ?? {});
|
|
2253
|
+
if (!validation.success) {
|
|
2254
|
+
const errorMessages = validation.error.errors.map((e) => `${e.path.join(".")}: ${e.message}`).join(", ");
|
|
2255
|
+
this.logger.warn(`ExecuteTool: Invalid tool arguments for '${toolId}': ${errorMessages}`, {
|
|
2256
|
+
errors: validation.error.format()
|
|
2257
|
+
});
|
|
2258
|
+
throw new z.ZodError(validation.error.issues);
|
|
2259
|
+
}
|
|
2260
|
+
validatedArgs = validation.data;
|
|
2261
|
+
} else {
|
|
2262
|
+
this.logger.debug(
|
|
2263
|
+
`ExecuteTool: Tool '${toolId}' parameters is not a Zod schema with safeParse or is undefined. Skipping validation.`
|
|
2264
|
+
);
|
|
2265
|
+
}
|
|
2266
|
+
if (!tool.execute) {
|
|
2267
|
+
this.logger.error(`ExecuteTool: Tool '${toolId}' does not have an execute function.`);
|
|
2268
|
+
throw new Error(`Tool '${toolId}' cannot be executed.`);
|
|
2269
|
+
}
|
|
2270
|
+
} catch (error) {
|
|
2271
|
+
const mastraError = new MastraError(
|
|
2272
|
+
{
|
|
2273
|
+
id: "MCP_SERVER_TOOL_EXECUTE_PREPARATION_FAILED",
|
|
2274
|
+
domain: ErrorDomain.MCP,
|
|
2275
|
+
category: ErrorCategory.USER,
|
|
2276
|
+
details: {
|
|
2277
|
+
toolId,
|
|
2278
|
+
args
|
|
2279
|
+
}
|
|
2280
|
+
},
|
|
2281
|
+
error
|
|
1975
2282
|
);
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
this.logger.error(`ExecuteTool: Tool '${toolId}' does not have an execute function.`);
|
|
1979
|
-
throw new Error(`Tool '${toolId}' cannot be executed.`);
|
|
2283
|
+
this.logger.trackException(mastraError);
|
|
2284
|
+
throw mastraError;
|
|
1980
2285
|
}
|
|
1981
2286
|
try {
|
|
1982
2287
|
const finalExecutionContext = {
|
|
@@ -1987,8 +2292,21 @@ var MCPServer = class extends MCPServerBase {
|
|
|
1987
2292
|
this.logger.info(`ExecuteTool: Tool '${toolId}' executed successfully.`);
|
|
1988
2293
|
return result;
|
|
1989
2294
|
} catch (error) {
|
|
2295
|
+
const mastraError = new MastraError(
|
|
2296
|
+
{
|
|
2297
|
+
id: "MCP_SERVER_TOOL_EXECUTE_FAILED",
|
|
2298
|
+
domain: ErrorDomain.MCP,
|
|
2299
|
+
category: ErrorCategory.USER,
|
|
2300
|
+
details: {
|
|
2301
|
+
toolId,
|
|
2302
|
+
validatedArgs
|
|
2303
|
+
}
|
|
2304
|
+
},
|
|
2305
|
+
error
|
|
2306
|
+
);
|
|
2307
|
+
this.logger.trackException(mastraError);
|
|
1990
2308
|
this.logger.error(`ExecuteTool: Tool execution failed for '${toolId}':`, { error });
|
|
1991
|
-
throw
|
|
2309
|
+
throw mastraError;
|
|
1992
2310
|
}
|
|
1993
2311
|
}
|
|
1994
2312
|
};
|