mcp-use 1.3.4-canary.2 → 1.4.0-canary.3
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/dist/.tsbuildinfo +1 -1
- package/dist/{chunk-6EHM3S3M.js → chunk-35A6O3YH.js} +52 -10
- package/dist/chunk-DSBKVAWD.js +263 -0
- package/dist/{chunk-TIUSJAAE.js → chunk-GRLCLVAK.js} +3 -254
- package/dist/{chunk-QKPVHYJU.js → chunk-RE7EYFDV.js} +1 -1
- package/dist/chunk-WERYJ6PF.js +209 -0
- package/dist/chunk-ZFZPZ4GE.js +21 -0
- package/dist/display-LIYVTGEU.js +350 -0
- package/dist/index.cjs +1539 -284
- package/dist/index.d.ts +5 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +686 -22
- package/dist/src/agents/display.d.ts +54 -0
- package/dist/src/agents/display.d.ts.map +1 -0
- package/dist/src/agents/index.cjs +504 -10
- package/dist/src/agents/index.d.ts +1 -0
- package/dist/src/agents/index.d.ts.map +1 -1
- package/dist/src/agents/index.js +10 -18
- package/dist/src/agents/mcp_agent.d.ts +5 -0
- package/dist/src/agents/mcp_agent.d.ts.map +1 -1
- package/dist/src/browser.cjs +406 -10
- package/dist/src/browser.js +10 -8
- package/dist/src/client/codeExecutor.d.ts +6 -0
- package/dist/src/client/codeExecutor.d.ts.map +1 -0
- package/dist/src/client/connectors/codeMode.d.ts +27 -0
- package/dist/src/client/connectors/codeMode.d.ts.map +1 -0
- package/dist/src/client/executors/base.d.ts +56 -0
- package/dist/src/client/executors/base.d.ts.map +1 -0
- package/dist/src/client/executors/e2b.d.ts +46 -0
- package/dist/src/client/executors/e2b.d.ts.map +1 -0
- package/dist/src/client/executors/vm.d.ts +30 -0
- package/dist/src/client/executors/vm.d.ts.map +1 -0
- package/dist/src/client/prompts.cjs +401 -0
- package/dist/src/client/prompts.d.ts +13 -0
- package/dist/src/client/prompts.d.ts.map +1 -0
- package/dist/src/client/prompts.js +9 -0
- package/dist/src/client.d.ts +51 -4
- package/dist/src/client.d.ts.map +1 -1
- package/dist/src/react/index.js +3 -2
- package/dist/tsup.config.d.ts.map +1 -1
- package/package.json +14 -4
package/dist/index.cjs
CHANGED
|
@@ -559,6 +559,360 @@ var init_langfuse = __esm({
|
|
|
559
559
|
}
|
|
560
560
|
});
|
|
561
561
|
|
|
562
|
+
// src/agents/display.ts
|
|
563
|
+
var display_exports = {};
|
|
564
|
+
__export(display_exports, {
|
|
565
|
+
extractCodeFromToolInput: () => extractCodeFromToolInput,
|
|
566
|
+
extractToolMessageContent: () => extractToolMessageContent,
|
|
567
|
+
formatSearchToolsAsTree: () => formatSearchToolsAsTree,
|
|
568
|
+
handleToolEnd: () => handleToolEnd,
|
|
569
|
+
handleToolStart: () => handleToolStart,
|
|
570
|
+
parseExecuteCodeResult: () => parseExecuteCodeResult,
|
|
571
|
+
prettyStreamEvents: () => prettyStreamEvents,
|
|
572
|
+
printBox: () => printBox,
|
|
573
|
+
renderContent: () => renderContent,
|
|
574
|
+
unwrapToolInput: () => unwrapToolInput
|
|
575
|
+
});
|
|
576
|
+
function stripAnsi(str) {
|
|
577
|
+
return (0, import_strip_ansi.default)(str);
|
|
578
|
+
}
|
|
579
|
+
function wrapAnsiLine(line, maxWidth) {
|
|
580
|
+
const stripped = stripAnsi(line);
|
|
581
|
+
if (stripped.length <= maxWidth) return [line];
|
|
582
|
+
const result = [];
|
|
583
|
+
let visibleCount = 0;
|
|
584
|
+
let current = "";
|
|
585
|
+
let i = 0;
|
|
586
|
+
while (i < line.length) {
|
|
587
|
+
const char = line[i];
|
|
588
|
+
if (char === "\x1B") {
|
|
589
|
+
let sequence = char;
|
|
590
|
+
i++;
|
|
591
|
+
while (i < line.length) {
|
|
592
|
+
const nextChar = line[i];
|
|
593
|
+
sequence += nextChar;
|
|
594
|
+
i++;
|
|
595
|
+
if (nextChar === "m") break;
|
|
596
|
+
}
|
|
597
|
+
current += sequence;
|
|
598
|
+
continue;
|
|
599
|
+
}
|
|
600
|
+
current += char;
|
|
601
|
+
visibleCount++;
|
|
602
|
+
i++;
|
|
603
|
+
if (visibleCount >= maxWidth) {
|
|
604
|
+
result.push(current);
|
|
605
|
+
current = "";
|
|
606
|
+
visibleCount = 0;
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
if (current) result.push(current);
|
|
610
|
+
return result;
|
|
611
|
+
}
|
|
612
|
+
function printBox(content, title, language, bgColor = false) {
|
|
613
|
+
const width = TERMINAL_WIDTH;
|
|
614
|
+
let displayContent = content;
|
|
615
|
+
if (language) {
|
|
616
|
+
try {
|
|
617
|
+
displayContent = (0, import_cli_highlight.highlight)(content, { language, ignoreIllegals: true });
|
|
618
|
+
} catch {
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
const lines = displayContent.split("\n").flatMap((line) => wrapAnsiLine(line, width - 4));
|
|
622
|
+
console.log(import_chalk.default.gray("\u250C" + "\u2500".repeat(width - 2) + "\u2510"));
|
|
623
|
+
if (title) {
|
|
624
|
+
const stripped = stripAnsi(title);
|
|
625
|
+
const lineText = `${title} `;
|
|
626
|
+
const padding = Math.max(0, width - 4 - stripped.length - 2);
|
|
627
|
+
console.log(
|
|
628
|
+
import_chalk.default.gray("\u2502 ") + import_chalk.default.bold.white(lineText) + " ".repeat(padding) + import_chalk.default.gray(" \u2502")
|
|
629
|
+
);
|
|
630
|
+
console.log(import_chalk.default.gray("\u251C" + "\u2500".repeat(width - 2) + "\u2524"));
|
|
631
|
+
}
|
|
632
|
+
lines.forEach((line) => {
|
|
633
|
+
const stripped = stripAnsi(line);
|
|
634
|
+
const padding = Math.max(0, width - 4 - stripped.length);
|
|
635
|
+
const finalLine = bgColor ? import_chalk.default.bgGray(line + " ".repeat(padding)) : line + " ".repeat(padding);
|
|
636
|
+
console.log(import_chalk.default.gray("\u2502 ") + finalLine + import_chalk.default.gray(" \u2502"));
|
|
637
|
+
});
|
|
638
|
+
console.log(import_chalk.default.gray("\u2514" + "\u2500".repeat(width - 2) + "\u2518"));
|
|
639
|
+
}
|
|
640
|
+
function extractCodeFromToolInput(input) {
|
|
641
|
+
if (typeof input === "object" && input !== null && "code" in input) {
|
|
642
|
+
const inputObj = input;
|
|
643
|
+
return typeof inputObj.code === "string" ? inputObj.code : null;
|
|
644
|
+
}
|
|
645
|
+
return null;
|
|
646
|
+
}
|
|
647
|
+
function isExecuteCodeResult(obj) {
|
|
648
|
+
if (typeof obj !== "object" || obj === null) return false;
|
|
649
|
+
const result = obj;
|
|
650
|
+
return "result" in result && "logs" in result && Array.isArray(result.logs) && "execution_time" in result && typeof result.execution_time === "number" && "error" in result && (typeof result.error === "string" || result.error === null);
|
|
651
|
+
}
|
|
652
|
+
function parseExecuteCodeResult(output) {
|
|
653
|
+
try {
|
|
654
|
+
if (typeof output === "string") {
|
|
655
|
+
const parsed = JSON.parse(output);
|
|
656
|
+
if (isExecuteCodeResult(parsed)) {
|
|
657
|
+
return parsed;
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
if (isExecuteCodeResult(output)) {
|
|
661
|
+
return output;
|
|
662
|
+
}
|
|
663
|
+
} catch (e) {
|
|
664
|
+
}
|
|
665
|
+
return null;
|
|
666
|
+
}
|
|
667
|
+
function renderContent(content) {
|
|
668
|
+
if (content === null || content === void 0) {
|
|
669
|
+
return "null";
|
|
670
|
+
}
|
|
671
|
+
if (typeof content === "object") {
|
|
672
|
+
return JSON.stringify(content, null, 2);
|
|
673
|
+
}
|
|
674
|
+
return String(content);
|
|
675
|
+
}
|
|
676
|
+
function unwrapToolInput(input) {
|
|
677
|
+
if (typeof input === "object" && input !== null && "input" in input) {
|
|
678
|
+
const inputObj = input;
|
|
679
|
+
if (typeof inputObj.input === "string") {
|
|
680
|
+
try {
|
|
681
|
+
return JSON.parse(inputObj.input);
|
|
682
|
+
} catch (e) {
|
|
683
|
+
return inputObj.input;
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
return input;
|
|
688
|
+
}
|
|
689
|
+
function handleToolStart(event) {
|
|
690
|
+
const toolName = event.name || "unknown";
|
|
691
|
+
let input = event.data?.input || {};
|
|
692
|
+
input = unwrapToolInput(input);
|
|
693
|
+
const code = extractCodeFromToolInput(input);
|
|
694
|
+
if (code) {
|
|
695
|
+
printBox(code, `${toolName} - input`, "javascript", false);
|
|
696
|
+
const otherParams = { ...input };
|
|
697
|
+
delete otherParams.code;
|
|
698
|
+
if (Object.keys(otherParams).length > 0) {
|
|
699
|
+
printBox(renderContent(otherParams), "Other Parameters", "json", false);
|
|
700
|
+
}
|
|
701
|
+
} else {
|
|
702
|
+
printBox(renderContent(input), `${toolName} - input`, "json", false);
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
function extractToolMessageContent(output) {
|
|
706
|
+
try {
|
|
707
|
+
if (typeof output === "object" && output !== null && "name" in output && "content" in output) {
|
|
708
|
+
const outputObj = output;
|
|
709
|
+
const toolName = (typeof outputObj.name === "string" ? outputObj.name : null) || "unknown";
|
|
710
|
+
const lcKwargs = outputObj.lc_kwargs;
|
|
711
|
+
const status = lcKwargs?.status || outputObj.status || "unknown";
|
|
712
|
+
let content = outputObj.content;
|
|
713
|
+
if (typeof content === "string") {
|
|
714
|
+
try {
|
|
715
|
+
content = JSON.parse(content);
|
|
716
|
+
} catch (e) {
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
return { toolName, status, content };
|
|
720
|
+
}
|
|
721
|
+
} catch (e) {
|
|
722
|
+
}
|
|
723
|
+
return null;
|
|
724
|
+
}
|
|
725
|
+
function formatSearchToolsAsTree(tools) {
|
|
726
|
+
if (!Array.isArray(tools) || tools.length === 0) {
|
|
727
|
+
return "(no tools found)";
|
|
728
|
+
}
|
|
729
|
+
const toolsByServer = {};
|
|
730
|
+
for (const tool of tools) {
|
|
731
|
+
const server = tool.server || "unknown";
|
|
732
|
+
if (!toolsByServer[server]) {
|
|
733
|
+
toolsByServer[server] = [];
|
|
734
|
+
}
|
|
735
|
+
toolsByServer[server].push(tool);
|
|
736
|
+
}
|
|
737
|
+
const lines = [];
|
|
738
|
+
const servers = Object.keys(toolsByServer).sort();
|
|
739
|
+
for (let i = 0; i < servers.length; i++) {
|
|
740
|
+
const server = servers[i];
|
|
741
|
+
const serverTools = toolsByServer[server];
|
|
742
|
+
const isLastServer = i === servers.length - 1;
|
|
743
|
+
const serverPrefix = isLastServer ? "\u2514\u2500" : "\u251C\u2500";
|
|
744
|
+
lines.push(
|
|
745
|
+
`${serverPrefix} ${import_chalk.default.cyan(server)} (${serverTools.length} tools)`
|
|
746
|
+
);
|
|
747
|
+
for (let j = 0; j < serverTools.length; j++) {
|
|
748
|
+
const tool = serverTools[j];
|
|
749
|
+
const isLastTool = j === serverTools.length - 1;
|
|
750
|
+
const indent = isLastServer ? " " : "\u2502 ";
|
|
751
|
+
const toolPrefix = isLastTool ? "\u2514\u2500" : "\u251C\u2500";
|
|
752
|
+
let toolLine = `${indent}${toolPrefix} ${tool.name}`;
|
|
753
|
+
if (tool.description) {
|
|
754
|
+
toolLine += import_chalk.default.dim(` - ${tool.description}`);
|
|
755
|
+
}
|
|
756
|
+
lines.push(toolLine);
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
return lines.join("\n");
|
|
760
|
+
}
|
|
761
|
+
function handleToolEnd(event) {
|
|
762
|
+
const output = event.data?.output;
|
|
763
|
+
const toolMessage = extractToolMessageContent(output);
|
|
764
|
+
if (toolMessage) {
|
|
765
|
+
const { toolName, status, content } = toolMessage;
|
|
766
|
+
if (toolName === "execute_code") {
|
|
767
|
+
let actualContent = content;
|
|
768
|
+
if (typeof content === "object" && content !== null && "content" in content) {
|
|
769
|
+
const innerContent = content.content;
|
|
770
|
+
if (Array.isArray(innerContent) && innerContent.length > 0) {
|
|
771
|
+
if (innerContent[0].type === "text" && innerContent[0].text) {
|
|
772
|
+
actualContent = innerContent[0].text;
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
const execResult2 = parseExecuteCodeResult(actualContent);
|
|
777
|
+
if (execResult2) {
|
|
778
|
+
const timeMs = execResult2.execution_time ? Math.round(execResult2.execution_time * 1e3) : 0;
|
|
779
|
+
const timeStr = `${timeMs}ms`;
|
|
780
|
+
const isError2 = execResult2.error !== null && execResult2.error !== void 0 && execResult2.error !== "";
|
|
781
|
+
const statusText = isError2 ? import_chalk.default.red("error") : import_chalk.default.green("success");
|
|
782
|
+
const title2 = `${toolName} - ${statusText} - ${timeStr}`;
|
|
783
|
+
if (execResult2.result !== null && execResult2.result !== void 0) {
|
|
784
|
+
const resultStr = renderContent(execResult2.result);
|
|
785
|
+
const language3 = typeof execResult2.result === "object" ? "json" : void 0;
|
|
786
|
+
printBox(resultStr, title2, language3, false);
|
|
787
|
+
} else {
|
|
788
|
+
printBox("(no result)", title2, void 0, false);
|
|
789
|
+
}
|
|
790
|
+
if (execResult2.logs && execResult2.logs.length > 0) {
|
|
791
|
+
printBox(execResult2.logs.join("\n"), `Logs`, void 0, false);
|
|
792
|
+
}
|
|
793
|
+
if (execResult2.error) {
|
|
794
|
+
printBox(execResult2.error, import_chalk.default.red("Error"), void 0, false);
|
|
795
|
+
}
|
|
796
|
+
return;
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
if (toolName === "search_tools") {
|
|
800
|
+
let actualContent = content;
|
|
801
|
+
if (typeof content === "object" && content !== null && !Array.isArray(content) && "content" in content) {
|
|
802
|
+
const innerContent = content.content;
|
|
803
|
+
if (Array.isArray(innerContent) && innerContent.length > 0) {
|
|
804
|
+
if (innerContent[0].type === "text" && innerContent[0].text) {
|
|
805
|
+
try {
|
|
806
|
+
actualContent = JSON.parse(innerContent[0].text);
|
|
807
|
+
} catch (e) {
|
|
808
|
+
actualContent = innerContent[0].text;
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
if (Array.isArray(actualContent)) {
|
|
814
|
+
const treeStr = formatSearchToolsAsTree(actualContent);
|
|
815
|
+
const statusText = status === "success" ? import_chalk.default.green("Success") : import_chalk.default.red("Error");
|
|
816
|
+
const title2 = `${statusText}: ${toolName} - Result`;
|
|
817
|
+
printBox(treeStr, title2, void 0, false);
|
|
818
|
+
return;
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
const contentObj = typeof content === "object" && content !== null ? content : null;
|
|
822
|
+
const isError = contentObj && "isError" in contentObj && contentObj.isError === true || status === "error";
|
|
823
|
+
let displayContent = content;
|
|
824
|
+
if (typeof content === "object" && content !== null && "content" in content) {
|
|
825
|
+
displayContent = content.content;
|
|
826
|
+
if (Array.isArray(displayContent) && displayContent.length > 0) {
|
|
827
|
+
if (displayContent[0].type === "text" && displayContent[0].text) {
|
|
828
|
+
displayContent = displayContent[0].text;
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
const contentStr = renderContent(displayContent);
|
|
833
|
+
const language2 = typeof displayContent === "object" ? "json" : void 0;
|
|
834
|
+
const statusLabel = status === "success" ? import_chalk.default.green("Success") : isError ? import_chalk.default.red("Error") : "Result";
|
|
835
|
+
const title = `${statusLabel}: ${toolName} - Result`;
|
|
836
|
+
printBox(contentStr, title, language2, false);
|
|
837
|
+
return;
|
|
838
|
+
}
|
|
839
|
+
const execResult = parseExecuteCodeResult(output);
|
|
840
|
+
if (execResult) {
|
|
841
|
+
const timeMs = execResult.execution_time ? Math.round(execResult.execution_time * 1e3) : 0;
|
|
842
|
+
const timeStr = `${timeMs}ms`;
|
|
843
|
+
if (execResult.result !== null && execResult.result !== void 0) {
|
|
844
|
+
const resultStr = renderContent(execResult.result);
|
|
845
|
+
const language2 = typeof execResult.result === "object" ? "json" : void 0;
|
|
846
|
+
printBox(resultStr, `Result - ${timeStr}`, language2, false);
|
|
847
|
+
}
|
|
848
|
+
if (execResult.logs && execResult.logs.length > 0) {
|
|
849
|
+
printBox(execResult.logs.join("\n"), `Logs`, void 0, false);
|
|
850
|
+
}
|
|
851
|
+
if (execResult.error) {
|
|
852
|
+
printBox(execResult.error, import_chalk.default.red("Error"), void 0, false);
|
|
853
|
+
}
|
|
854
|
+
return;
|
|
855
|
+
}
|
|
856
|
+
const outputStr = renderContent(output);
|
|
857
|
+
const language = typeof output === "object" ? "json" : void 0;
|
|
858
|
+
printBox(outputStr, "Result", language, false);
|
|
859
|
+
}
|
|
860
|
+
async function* prettyStreamEvents(streamEventsGenerator) {
|
|
861
|
+
let finalResponse = "";
|
|
862
|
+
let isFirstTextChunk = true;
|
|
863
|
+
let hasStreamedText = false;
|
|
864
|
+
for await (const event of streamEventsGenerator) {
|
|
865
|
+
if (event.event === "on_tool_start") {
|
|
866
|
+
if (hasStreamedText) {
|
|
867
|
+
process.stdout.write("\n");
|
|
868
|
+
hasStreamedText = false;
|
|
869
|
+
isFirstTextChunk = true;
|
|
870
|
+
}
|
|
871
|
+
handleToolStart(event);
|
|
872
|
+
} else if (event.event === "on_tool_end") {
|
|
873
|
+
handleToolEnd(event);
|
|
874
|
+
} else if (event.event === "on_chat_model_stream") {
|
|
875
|
+
if (event.data?.chunk?.text) {
|
|
876
|
+
const text = event.data.chunk.text;
|
|
877
|
+
if (typeof text === "string" && text.length > 0) {
|
|
878
|
+
if (isFirstTextChunk) {
|
|
879
|
+
process.stdout.write("\n\u{1F916} ");
|
|
880
|
+
isFirstTextChunk = false;
|
|
881
|
+
}
|
|
882
|
+
process.stdout.write(text);
|
|
883
|
+
finalResponse += text;
|
|
884
|
+
hasStreamedText = true;
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
}
|
|
888
|
+
yield;
|
|
889
|
+
}
|
|
890
|
+
return finalResponse;
|
|
891
|
+
}
|
|
892
|
+
var import_chalk, import_cli_highlight, import_strip_ansi, TERMINAL_WIDTH;
|
|
893
|
+
var init_display = __esm({
|
|
894
|
+
"src/agents/display.ts"() {
|
|
895
|
+
"use strict";
|
|
896
|
+
import_chalk = __toESM(require("chalk"), 1);
|
|
897
|
+
import_cli_highlight = require("cli-highlight");
|
|
898
|
+
import_strip_ansi = __toESM(require("strip-ansi"), 1);
|
|
899
|
+
TERMINAL_WIDTH = process.stdout.columns || 120;
|
|
900
|
+
__name(stripAnsi, "stripAnsi");
|
|
901
|
+
__name(wrapAnsiLine, "wrapAnsiLine");
|
|
902
|
+
__name(printBox, "printBox");
|
|
903
|
+
__name(extractCodeFromToolInput, "extractCodeFromToolInput");
|
|
904
|
+
__name(isExecuteCodeResult, "isExecuteCodeResult");
|
|
905
|
+
__name(parseExecuteCodeResult, "parseExecuteCodeResult");
|
|
906
|
+
__name(renderContent, "renderContent");
|
|
907
|
+
__name(unwrapToolInput, "unwrapToolInput");
|
|
908
|
+
__name(handleToolStart, "handleToolStart");
|
|
909
|
+
__name(extractToolMessageContent, "extractToolMessageContent");
|
|
910
|
+
__name(formatSearchToolsAsTree, "formatSearchToolsAsTree");
|
|
911
|
+
__name(handleToolEnd, "handleToolEnd");
|
|
912
|
+
__name(prettyStreamEvents, "prettyStreamEvents");
|
|
913
|
+
}
|
|
914
|
+
});
|
|
915
|
+
|
|
562
916
|
// index.ts
|
|
563
917
|
var index_exports = {};
|
|
564
918
|
__export(index_exports, {
|
|
@@ -578,6 +932,7 @@ __export(index_exports, {
|
|
|
578
932
|
MCPSession: () => MCPSession,
|
|
579
933
|
OAuthHelper: () => OAuthHelper,
|
|
580
934
|
ObservabilityManager: () => ObservabilityManager,
|
|
935
|
+
PROMPTS: () => PROMPTS,
|
|
581
936
|
ReleaseMCPServerConnectionTool: () => ReleaseMCPServerConnectionTool,
|
|
582
937
|
RemoteAgent: () => RemoteAgent,
|
|
583
938
|
ServerManager: () => ServerManager,
|
|
@@ -2188,18 +2543,35 @@ var MCPAgent = class {
|
|
|
2188
2543
|
logger.info(
|
|
2189
2544
|
`\u{1F50C} Found ${Object.keys(this.sessions).length} existing sessions`
|
|
2190
2545
|
);
|
|
2191
|
-
|
|
2546
|
+
const nonCodeModeSessions = Object.keys(this.sessions).filter(
|
|
2547
|
+
(name) => name !== "code_mode"
|
|
2548
|
+
);
|
|
2549
|
+
if (nonCodeModeSessions.length === 0) {
|
|
2192
2550
|
logger.info("\u{1F504} No active sessions found, creating new ones...");
|
|
2193
2551
|
this.sessions = await this.client.createAllSessions();
|
|
2194
2552
|
logger.info(
|
|
2195
2553
|
`\u2705 Created ${Object.keys(this.sessions).length} new sessions`
|
|
2196
2554
|
);
|
|
2197
2555
|
}
|
|
2198
|
-
|
|
2556
|
+
if (this.client.codeMode) {
|
|
2557
|
+
const codeModeSession = this.sessions["code_mode"];
|
|
2558
|
+
if (codeModeSession) {
|
|
2559
|
+
this._tools = await this.adapter.createToolsFromConnectors([
|
|
2560
|
+
codeModeSession.connector
|
|
2561
|
+
]);
|
|
2562
|
+
logger.info(`\u{1F6E0}\uFE0F Created ${this._tools.length} code mode tools`);
|
|
2563
|
+
} else {
|
|
2564
|
+
throw new Error(
|
|
2565
|
+
"Code mode enabled but code_mode session not found"
|
|
2566
|
+
);
|
|
2567
|
+
}
|
|
2568
|
+
} else {
|
|
2569
|
+
this._tools = await LangChainAdapter.createTools(this.client);
|
|
2570
|
+
logger.info(
|
|
2571
|
+
`\u{1F6E0}\uFE0F Created ${this._tools.length} LangChain tools from client`
|
|
2572
|
+
);
|
|
2573
|
+
}
|
|
2199
2574
|
this._tools.push(...this.additionalTools);
|
|
2200
|
-
logger.info(
|
|
2201
|
-
`\u{1F6E0}\uFE0F Created ${this._tools.length} LangChain tools from client`
|
|
2202
|
-
);
|
|
2203
2575
|
} else {
|
|
2204
2576
|
logger.info(
|
|
2205
2577
|
`\u{1F517} Connecting to ${this.connectors.length} direct connectors...`
|
|
@@ -2764,6 +3136,8 @@ var MCPAgent = class {
|
|
|
2764
3136
|
tags: this.getTags(),
|
|
2765
3137
|
// Set trace name for LangChain/Langfuse
|
|
2766
3138
|
runName: this.metadata.trace_name || "mcp-use-agent",
|
|
3139
|
+
// Set recursion limit to 3x maxSteps to account for model calls + tool executions
|
|
3140
|
+
recursionLimit: this.maxSteps * 3,
|
|
2767
3141
|
// Pass sessionId for Langfuse if present in metadata
|
|
2768
3142
|
...this.metadata.session_id && {
|
|
2769
3143
|
sessionId: this.metadata.session_id
|
|
@@ -2977,8 +3351,8 @@ var MCPAgent = class {
|
|
|
2977
3351
|
this._agentExecutor = null;
|
|
2978
3352
|
this._tools = [];
|
|
2979
3353
|
if (this.client) {
|
|
2980
|
-
logger.info("\u{1F504} Closing
|
|
2981
|
-
await this.client.
|
|
3354
|
+
logger.info("\u{1F504} Closing client and cleaning up resources");
|
|
3355
|
+
await this.client.close();
|
|
2982
3356
|
this.sessions = {};
|
|
2983
3357
|
} else {
|
|
2984
3358
|
for (const connector of this.connectors) {
|
|
@@ -2994,6 +3368,26 @@ var MCPAgent = class {
|
|
|
2994
3368
|
logger.info("\u{1F44B} Agent closed successfully");
|
|
2995
3369
|
}
|
|
2996
3370
|
}
|
|
3371
|
+
/**
|
|
3372
|
+
* Yields with pretty-printed output for code mode.
|
|
3373
|
+
* This method formats and displays tool executions in a user-friendly way with syntax highlighting.
|
|
3374
|
+
*/
|
|
3375
|
+
async *prettyStreamEvents(query, maxSteps, manageConnector = true, externalHistory, outputSchema) {
|
|
3376
|
+
const { prettyStreamEvents: prettyStream } = await Promise.resolve().then(() => (init_display(), display_exports));
|
|
3377
|
+
const finalResponse = "";
|
|
3378
|
+
for await (const _ of prettyStream(
|
|
3379
|
+
this.streamEvents(
|
|
3380
|
+
query,
|
|
3381
|
+
maxSteps,
|
|
3382
|
+
manageConnector,
|
|
3383
|
+
externalHistory,
|
|
3384
|
+
outputSchema
|
|
3385
|
+
)
|
|
3386
|
+
)) {
|
|
3387
|
+
yield;
|
|
3388
|
+
}
|
|
3389
|
+
return finalResponse;
|
|
3390
|
+
}
|
|
2997
3391
|
/**
|
|
2998
3392
|
* Yields LangChain StreamEvent objects from the underlying streamEvents() method.
|
|
2999
3393
|
* This provides token-level streaming and fine-grained event updates.
|
|
@@ -3021,11 +3415,11 @@ var MCPAgent = class {
|
|
|
3021
3415
|
throw new Error("MCP agent failed to initialize");
|
|
3022
3416
|
}
|
|
3023
3417
|
this.maxSteps = maxSteps ?? this.maxSteps;
|
|
3024
|
-
const display_query = query.length > 50 ? `${query.slice(0, 50).replace(/\n/g, " ")}...` : query.replace(/\n/g, " ");
|
|
3418
|
+
const display_query = typeof query === "string" && query.length > 50 ? `${query.slice(0, 50).replace(/\n/g, " ")}...` : typeof query === "string" ? query.replace(/\n/g, " ") : String(query);
|
|
3025
3419
|
logger.info(`\u{1F4AC} Received query for streamEvents: '${display_query}'`);
|
|
3026
3420
|
if (this.memoryEnabled) {
|
|
3027
|
-
logger.info(`\u{1F504} Adding user message to history: ${
|
|
3028
|
-
this.addToHistory(new import_langchain2.HumanMessage(query));
|
|
3421
|
+
logger.info(`\u{1F504} Adding user message to history: ${display_query}`);
|
|
3422
|
+
this.addToHistory(new import_langchain2.HumanMessage({ content: query }));
|
|
3029
3423
|
}
|
|
3030
3424
|
const historyToUse = externalHistory ?? this.conversationHistory;
|
|
3031
3425
|
const langchainHistory = [];
|
|
@@ -3053,6 +3447,8 @@ var MCPAgent = class {
|
|
|
3053
3447
|
tags: this.getTags(),
|
|
3054
3448
|
// Set trace name for LangChain/Langfuse
|
|
3055
3449
|
runName: this.metadata.trace_name || "mcp-use-agent",
|
|
3450
|
+
// Set recursion limit to 3x maxSteps to account for model calls + tool executions
|
|
3451
|
+
recursionLimit: this.maxSteps * 3,
|
|
3056
3452
|
// Pass sessionId for Langfuse if present in metadata
|
|
3057
3453
|
...this.metadata.session_id && {
|
|
3058
3454
|
sessionId: this.metadata.session_id
|
|
@@ -3152,6 +3548,7 @@ var MCPAgent = class {
|
|
|
3152
3548
|
} else if (this.memoryEnabled && finalResponse) {
|
|
3153
3549
|
this.addToHistory(new import_langchain2.AIMessage(finalResponse));
|
|
3154
3550
|
}
|
|
3551
|
+
console.log("\n\n");
|
|
3155
3552
|
logger.info(`\u{1F389} StreamEvents complete - ${eventCount} events emitted`);
|
|
3156
3553
|
success = true;
|
|
3157
3554
|
} catch (e) {
|
|
@@ -3543,228 +3940,558 @@ var BaseMCPClient = class {
|
|
|
3543
3940
|
}
|
|
3544
3941
|
};
|
|
3545
3942
|
|
|
3546
|
-
// src/
|
|
3547
|
-
var import_node_fs = require("fs");
|
|
3548
|
-
|
|
3549
|
-
// src/connectors/http.ts
|
|
3550
|
-
var import_client = require("@modelcontextprotocol/sdk/client/index.js");
|
|
3551
|
-
var import_streamableHttp2 = require("@modelcontextprotocol/sdk/client/streamableHttp.js");
|
|
3552
|
-
init_logging();
|
|
3553
|
-
|
|
3554
|
-
// src/task_managers/sse.ts
|
|
3555
|
-
var import_sse = require("@modelcontextprotocol/sdk/client/sse.js");
|
|
3556
|
-
init_logging();
|
|
3557
|
-
|
|
3558
|
-
// src/task_managers/base.ts
|
|
3943
|
+
// src/client/executors/base.ts
|
|
3559
3944
|
init_logging();
|
|
3560
|
-
var
|
|
3945
|
+
var BaseCodeExecutor = class {
|
|
3561
3946
|
static {
|
|
3562
|
-
__name(this, "
|
|
3563
|
-
}
|
|
3564
|
-
_readyPromise;
|
|
3565
|
-
_readyResolver;
|
|
3566
|
-
_donePromise;
|
|
3567
|
-
_doneResolver;
|
|
3568
|
-
_exception = null;
|
|
3569
|
-
_connection = null;
|
|
3570
|
-
_task = null;
|
|
3571
|
-
_abortController = null;
|
|
3572
|
-
constructor() {
|
|
3573
|
-
this.reset();
|
|
3947
|
+
__name(this, "BaseCodeExecutor");
|
|
3574
3948
|
}
|
|
3575
|
-
|
|
3576
|
-
|
|
3577
|
-
|
|
3578
|
-
|
|
3579
|
-
* @throws If the connection cannot be established.
|
|
3580
|
-
*/
|
|
3581
|
-
async start() {
|
|
3582
|
-
this.reset();
|
|
3583
|
-
logger.debug(`Starting ${this.constructor.name}`);
|
|
3584
|
-
this._task = this.connectionTask();
|
|
3585
|
-
await this._readyPromise;
|
|
3586
|
-
if (this._exception) {
|
|
3587
|
-
throw this._exception;
|
|
3588
|
-
}
|
|
3589
|
-
if (this._connection === null) {
|
|
3590
|
-
throw new Error("Connection was not established");
|
|
3591
|
-
}
|
|
3592
|
-
return this._connection;
|
|
3949
|
+
client;
|
|
3950
|
+
_connecting = false;
|
|
3951
|
+
constructor(client) {
|
|
3952
|
+
this.client = client;
|
|
3593
3953
|
}
|
|
3594
3954
|
/**
|
|
3595
|
-
*
|
|
3955
|
+
* Ensure all configured MCP servers are connected before execution.
|
|
3956
|
+
* Prevents race conditions with a connection lock.
|
|
3596
3957
|
*/
|
|
3597
|
-
async
|
|
3598
|
-
|
|
3599
|
-
|
|
3600
|
-
|
|
3958
|
+
async ensureServersConnected() {
|
|
3959
|
+
const configuredServers = this.client.getServerNames();
|
|
3960
|
+
const activeSessions = Object.keys(this.client.getAllActiveSessions());
|
|
3961
|
+
const missingServers = configuredServers.filter(
|
|
3962
|
+
(s) => !activeSessions.includes(s)
|
|
3963
|
+
);
|
|
3964
|
+
if (missingServers.length > 0 && !this._connecting) {
|
|
3965
|
+
this._connecting = true;
|
|
3601
3966
|
try {
|
|
3602
|
-
|
|
3603
|
-
|
|
3604
|
-
|
|
3605
|
-
|
|
3606
|
-
|
|
3607
|
-
|
|
3608
|
-
|
|
3967
|
+
logger.debug(
|
|
3968
|
+
`Connecting to configured servers for code execution: ${missingServers.join(", ")}`
|
|
3969
|
+
);
|
|
3970
|
+
await this.client.createAllSessions();
|
|
3971
|
+
} finally {
|
|
3972
|
+
this._connecting = false;
|
|
3973
|
+
}
|
|
3974
|
+
} else if (missingServers.length > 0 && this._connecting) {
|
|
3975
|
+
logger.debug("Waiting for ongoing server connection...");
|
|
3976
|
+
const startWait = Date.now();
|
|
3977
|
+
while (this._connecting && Date.now() - startWait < 5e3) {
|
|
3978
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
3609
3979
|
}
|
|
3610
3980
|
}
|
|
3611
|
-
await this._donePromise;
|
|
3612
|
-
logger.debug(`${this.constructor.name} task completed`);
|
|
3613
|
-
}
|
|
3614
|
-
/**
|
|
3615
|
-
* Reset all internal state.
|
|
3616
|
-
*/
|
|
3617
|
-
reset() {
|
|
3618
|
-
this._readyPromise = new Promise((res) => this._readyResolver = res);
|
|
3619
|
-
this._donePromise = new Promise((res) => this._doneResolver = res);
|
|
3620
|
-
this._exception = null;
|
|
3621
|
-
this._connection = null;
|
|
3622
|
-
this._task = null;
|
|
3623
|
-
this._abortController = new AbortController();
|
|
3624
3981
|
}
|
|
3625
3982
|
/**
|
|
3626
|
-
*
|
|
3627
|
-
*
|
|
3983
|
+
* Get tool namespace information from all active MCP sessions.
|
|
3984
|
+
* Filters out the internal code_mode server.
|
|
3628
3985
|
*/
|
|
3629
|
-
|
|
3630
|
-
|
|
3631
|
-
|
|
3632
|
-
|
|
3633
|
-
|
|
3634
|
-
|
|
3635
|
-
|
|
3636
|
-
|
|
3637
|
-
this._exception = err;
|
|
3638
|
-
logger.error(`Error in ${this.constructor.name} task: ${err}`);
|
|
3639
|
-
this._readyResolver();
|
|
3640
|
-
} finally {
|
|
3641
|
-
if (this._connection !== null) {
|
|
3986
|
+
getToolNamespaces() {
|
|
3987
|
+
const namespaces = [];
|
|
3988
|
+
const activeSessions = this.client.getAllActiveSessions();
|
|
3989
|
+
for (const [serverName, session] of Object.entries(activeSessions)) {
|
|
3990
|
+
if (serverName === "code_mode") continue;
|
|
3991
|
+
try {
|
|
3992
|
+
const connector = session.connector;
|
|
3993
|
+
let tools;
|
|
3642
3994
|
try {
|
|
3643
|
-
|
|
3644
|
-
} catch (
|
|
3645
|
-
logger.warn(
|
|
3646
|
-
|
|
3647
|
-
);
|
|
3995
|
+
tools = connector.tools;
|
|
3996
|
+
} catch (e) {
|
|
3997
|
+
logger.warn(`Tools not available for server ${serverName}: ${e}`);
|
|
3998
|
+
continue;
|
|
3648
3999
|
}
|
|
3649
|
-
|
|
4000
|
+
if (!tools || tools.length === 0) continue;
|
|
4001
|
+
namespaces.push({ serverName, tools, session });
|
|
4002
|
+
} catch (e) {
|
|
4003
|
+
logger.warn(`Failed to load tools for server ${serverName}: ${e}`);
|
|
3650
4004
|
}
|
|
3651
|
-
this._doneResolver();
|
|
3652
4005
|
}
|
|
4006
|
+
return namespaces;
|
|
3653
4007
|
}
|
|
3654
4008
|
/**
|
|
3655
|
-
*
|
|
4009
|
+
* Create a search function for discovering available MCP tools.
|
|
4010
|
+
* Used by code execution environments to find tools at runtime.
|
|
3656
4011
|
*/
|
|
3657
|
-
|
|
3658
|
-
return
|
|
3659
|
-
|
|
3660
|
-
|
|
3661
|
-
|
|
3662
|
-
const
|
|
3663
|
-
|
|
3664
|
-
|
|
3665
|
-
|
|
4012
|
+
createSearchToolsFunction() {
|
|
4013
|
+
return async (query = "", detailLevel = "full") => {
|
|
4014
|
+
const allTools = [];
|
|
4015
|
+
const queryLower = query.toLowerCase();
|
|
4016
|
+
const activeSessions = this.client.getAllActiveSessions();
|
|
4017
|
+
for (const [serverName, session] of Object.entries(activeSessions)) {
|
|
4018
|
+
if (serverName === "code_mode") continue;
|
|
4019
|
+
try {
|
|
4020
|
+
const tools = session.connector.tools;
|
|
4021
|
+
for (const tool of tools) {
|
|
4022
|
+
if (query) {
|
|
4023
|
+
const nameMatch = tool.name.toLowerCase().includes(queryLower);
|
|
4024
|
+
const descMatch = tool.description?.toLowerCase().includes(queryLower);
|
|
4025
|
+
if (!nameMatch && !descMatch) continue;
|
|
4026
|
+
}
|
|
4027
|
+
if (detailLevel === "names") {
|
|
4028
|
+
allTools.push({ name: tool.name, server: serverName });
|
|
4029
|
+
} else if (detailLevel === "descriptions") {
|
|
4030
|
+
allTools.push({
|
|
4031
|
+
name: tool.name,
|
|
4032
|
+
server: serverName,
|
|
4033
|
+
description: tool.description
|
|
4034
|
+
});
|
|
4035
|
+
} else {
|
|
4036
|
+
allTools.push({
|
|
4037
|
+
name: tool.name,
|
|
4038
|
+
server: serverName,
|
|
4039
|
+
description: tool.description,
|
|
4040
|
+
input_schema: tool.inputSchema
|
|
4041
|
+
});
|
|
4042
|
+
}
|
|
4043
|
+
}
|
|
4044
|
+
} catch (e) {
|
|
4045
|
+
logger.warn(`Failed to search tools in server ${serverName}: ${e}`);
|
|
4046
|
+
}
|
|
3666
4047
|
}
|
|
3667
|
-
|
|
3668
|
-
|
|
3669
|
-
_resolve();
|
|
3670
|
-
}, "onAbort");
|
|
3671
|
-
signal.addEventListener("abort", onAbort);
|
|
3672
|
-
});
|
|
4048
|
+
return allTools;
|
|
4049
|
+
};
|
|
3673
4050
|
}
|
|
3674
4051
|
};
|
|
3675
4052
|
|
|
3676
|
-
// src/
|
|
3677
|
-
|
|
4053
|
+
// src/client/executors/e2b.ts
|
|
4054
|
+
init_logging();
|
|
4055
|
+
var E2BCodeExecutor = class extends BaseCodeExecutor {
|
|
3678
4056
|
static {
|
|
3679
|
-
__name(this, "
|
|
4057
|
+
__name(this, "E2BCodeExecutor");
|
|
4058
|
+
}
|
|
4059
|
+
e2bApiKey;
|
|
4060
|
+
codeExecSandbox = null;
|
|
4061
|
+
SandboxClass = null;
|
|
4062
|
+
timeoutMs;
|
|
4063
|
+
constructor(client, options) {
|
|
4064
|
+
super(client);
|
|
4065
|
+
this.e2bApiKey = options.apiKey;
|
|
4066
|
+
this.timeoutMs = options.timeoutMs ?? 3e5;
|
|
3680
4067
|
}
|
|
3681
|
-
url;
|
|
3682
|
-
opts;
|
|
3683
|
-
_transport = null;
|
|
3684
4068
|
/**
|
|
3685
|
-
*
|
|
3686
|
-
*
|
|
3687
|
-
* @param url The SSE endpoint URL.
|
|
3688
|
-
* @param opts Optional transport options (auth, headers, etc.).
|
|
4069
|
+
* Lazy load E2B Sandbox class.
|
|
4070
|
+
* This allows the library to work without E2B installed.
|
|
3689
4071
|
*/
|
|
3690
|
-
|
|
3691
|
-
|
|
3692
|
-
|
|
3693
|
-
|
|
4072
|
+
async ensureSandboxClass() {
|
|
4073
|
+
if (this.SandboxClass) return;
|
|
4074
|
+
try {
|
|
4075
|
+
const e2b = await import("@e2b/code-interpreter");
|
|
4076
|
+
this.SandboxClass = e2b.Sandbox;
|
|
4077
|
+
} catch (error) {
|
|
4078
|
+
throw new Error(
|
|
4079
|
+
"@e2b/code-interpreter is not installed. The E2B code executor requires this optional dependency. Install it with: yarn add @e2b/code-interpreter"
|
|
4080
|
+
);
|
|
4081
|
+
}
|
|
3694
4082
|
}
|
|
3695
4083
|
/**
|
|
3696
|
-
*
|
|
4084
|
+
* Get or create a dedicated sandbox for code execution.
|
|
3697
4085
|
*/
|
|
3698
|
-
async
|
|
3699
|
-
|
|
3700
|
-
|
|
3701
|
-
|
|
4086
|
+
async getOrCreateCodeExecSandbox() {
|
|
4087
|
+
if (this.codeExecSandbox) return this.codeExecSandbox;
|
|
4088
|
+
await this.ensureSandboxClass();
|
|
4089
|
+
logger.debug("Starting E2B sandbox for code execution...");
|
|
4090
|
+
this.codeExecSandbox = await this.SandboxClass.create("base", {
|
|
4091
|
+
apiKey: this.e2bApiKey,
|
|
4092
|
+
timeoutMs: this.timeoutMs
|
|
4093
|
+
});
|
|
4094
|
+
return this.codeExecSandbox;
|
|
3702
4095
|
}
|
|
3703
4096
|
/**
|
|
3704
|
-
*
|
|
4097
|
+
* Generate the shim code that exposes tools to the sandbox environment.
|
|
4098
|
+
* Creates a bridge that intercepts tool calls and sends them back to host.
|
|
3705
4099
|
*/
|
|
3706
|
-
|
|
3707
|
-
|
|
4100
|
+
generateShim(tools) {
|
|
4101
|
+
let shim = `
|
|
4102
|
+
// MCP Bridge Shim
|
|
4103
|
+
global.__callMcpTool = async (server, tool, args) => {
|
|
4104
|
+
const id = Math.random().toString(36).substring(7);
|
|
4105
|
+
console.log(JSON.stringify({
|
|
4106
|
+
type: '__MCP_TOOL_CALL__',
|
|
4107
|
+
id,
|
|
4108
|
+
server,
|
|
4109
|
+
tool,
|
|
4110
|
+
args
|
|
4111
|
+
}));
|
|
4112
|
+
|
|
4113
|
+
const resultPath = \`/tmp/mcp_result_\${id}.json\`;
|
|
4114
|
+
const fs = require('fs');
|
|
4115
|
+
|
|
4116
|
+
// Poll for result file
|
|
4117
|
+
let attempts = 0;
|
|
4118
|
+
while (attempts < 300) { // 30 seconds timeout
|
|
4119
|
+
if (fs.existsSync(resultPath)) {
|
|
4120
|
+
const content = fs.readFileSync(resultPath, 'utf8');
|
|
4121
|
+
const result = JSON.parse(content);
|
|
4122
|
+
fs.unlinkSync(resultPath); // Clean up
|
|
4123
|
+
|
|
4124
|
+
if (result.error) {
|
|
4125
|
+
throw new Error(result.error);
|
|
4126
|
+
}
|
|
4127
|
+
return result.data;
|
|
4128
|
+
}
|
|
4129
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
4130
|
+
attempts++;
|
|
4131
|
+
}
|
|
4132
|
+
throw new Error('Tool execution timed out');
|
|
4133
|
+
};
|
|
4134
|
+
|
|
4135
|
+
// Global search_tools helper
|
|
4136
|
+
global.search_tools = async (query, detailLevel = 'full') => {
|
|
4137
|
+
const allTools = ${JSON.stringify(
|
|
4138
|
+
Object.entries(tools).flatMap(
|
|
4139
|
+
([server, serverTools]) => serverTools.map((tool) => ({
|
|
4140
|
+
name: tool.name,
|
|
4141
|
+
description: tool.description,
|
|
4142
|
+
server,
|
|
4143
|
+
input_schema: tool.inputSchema
|
|
4144
|
+
}))
|
|
4145
|
+
)
|
|
4146
|
+
)};
|
|
4147
|
+
|
|
4148
|
+
const filtered = allTools.filter(tool => {
|
|
4149
|
+
if (!query) return true;
|
|
4150
|
+
const q = query.toLowerCase();
|
|
4151
|
+
return tool.name.toLowerCase().includes(q) ||
|
|
4152
|
+
(tool.description && tool.description.toLowerCase().includes(q));
|
|
4153
|
+
});
|
|
4154
|
+
|
|
4155
|
+
if (detailLevel === 'names') {
|
|
4156
|
+
return filtered.map(t => ({ name: t.name, server: t.server }));
|
|
4157
|
+
} else if (detailLevel === 'descriptions') {
|
|
4158
|
+
return filtered.map(t => ({ name: t.name, server: t.server, description: t.description }));
|
|
4159
|
+
}
|
|
4160
|
+
return filtered;
|
|
4161
|
+
};
|
|
4162
|
+
`;
|
|
4163
|
+
for (const [serverName, serverTools] of Object.entries(tools)) {
|
|
4164
|
+
if (!serverTools || serverTools.length === 0) continue;
|
|
4165
|
+
const safeServerName = serverName.replace(/[^a-zA-Z0-9_]/g, "_");
|
|
4166
|
+
shim += `
|
|
4167
|
+
global['${serverName}'] = {`;
|
|
4168
|
+
for (const tool of serverTools) {
|
|
4169
|
+
shim += `
|
|
4170
|
+
'${tool.name}': async (args) => await global.__callMcpTool('${serverName}', '${tool.name}', args),`;
|
|
4171
|
+
}
|
|
4172
|
+
shim += `
|
|
4173
|
+
};
|
|
4174
|
+
|
|
4175
|
+
// Also expose as safe name if different
|
|
4176
|
+
if ('${safeServerName}' !== '${serverName}') {
|
|
4177
|
+
global['${safeServerName}'] = global['${serverName}'];
|
|
4178
|
+
}
|
|
4179
|
+
`;
|
|
4180
|
+
}
|
|
4181
|
+
return shim;
|
|
4182
|
+
}
|
|
4183
|
+
/**
|
|
4184
|
+
* Build the tool catalog for the shim.
|
|
4185
|
+
* Returns a map of server names to their available tools.
|
|
4186
|
+
*/
|
|
4187
|
+
buildToolCatalog() {
|
|
4188
|
+
const catalog = {};
|
|
4189
|
+
const namespaces = this.getToolNamespaces();
|
|
4190
|
+
for (const { serverName, tools } of namespaces) {
|
|
4191
|
+
catalog[serverName] = tools;
|
|
4192
|
+
}
|
|
4193
|
+
return catalog;
|
|
4194
|
+
}
|
|
4195
|
+
/**
|
|
4196
|
+
* Execute JavaScript/TypeScript code in an E2B sandbox with MCP tool access.
|
|
4197
|
+
* Tool calls are proxied back to the host via the bridge pattern.
|
|
4198
|
+
*
|
|
4199
|
+
* @param code - Code to execute
|
|
4200
|
+
* @param timeout - Execution timeout in milliseconds (default: 30000)
|
|
4201
|
+
*/
|
|
4202
|
+
async execute(code, timeout = 3e4) {
|
|
4203
|
+
const startTime = Date.now();
|
|
4204
|
+
let result = null;
|
|
4205
|
+
let error = null;
|
|
4206
|
+
let logs = [];
|
|
4207
|
+
try {
|
|
4208
|
+
await this.ensureServersConnected();
|
|
4209
|
+
const sandbox = await this.getOrCreateCodeExecSandbox();
|
|
4210
|
+
const toolCatalog = this.buildToolCatalog();
|
|
4211
|
+
const shim = this.generateShim(toolCatalog);
|
|
4212
|
+
const wrappedCode = `
|
|
4213
|
+
${shim}
|
|
4214
|
+
|
|
4215
|
+
(async () => {
|
|
4216
|
+
try {
|
|
4217
|
+
const func = async () => {
|
|
4218
|
+
${code}
|
|
4219
|
+
};
|
|
4220
|
+
const result = await func();
|
|
4221
|
+
console.log('__MCP_RESULT_START__');
|
|
4222
|
+
console.log(JSON.stringify(result));
|
|
4223
|
+
console.log('__MCP_RESULT_END__');
|
|
4224
|
+
} catch (e) {
|
|
4225
|
+
console.error(e);
|
|
4226
|
+
process.exit(1);
|
|
4227
|
+
}
|
|
4228
|
+
})();
|
|
4229
|
+
`;
|
|
4230
|
+
const filename = `exec_${Date.now()}.js`;
|
|
4231
|
+
await sandbox.files.write(filename, wrappedCode);
|
|
4232
|
+
const execution = await sandbox.commands.run(`node ${filename}`, {
|
|
4233
|
+
timeoutMs: timeout,
|
|
4234
|
+
onStdout: /* @__PURE__ */ __name(async (data) => {
|
|
4235
|
+
try {
|
|
4236
|
+
const lines = data.split("\n");
|
|
4237
|
+
for (const line of lines) {
|
|
4238
|
+
if (line.trim().startsWith('{"type":"__MCP_TOOL_CALL__"')) {
|
|
4239
|
+
const call = JSON.parse(line);
|
|
4240
|
+
if (call.type === "__MCP_TOOL_CALL__") {
|
|
4241
|
+
try {
|
|
4242
|
+
logger.debug(
|
|
4243
|
+
`[E2B Bridge] Calling tool ${call.server}.${call.tool}`
|
|
4244
|
+
);
|
|
4245
|
+
const activeSessions = this.client.getAllActiveSessions();
|
|
4246
|
+
const session = activeSessions[call.server];
|
|
4247
|
+
if (!session) {
|
|
4248
|
+
throw new Error(`Server ${call.server} not found`);
|
|
4249
|
+
}
|
|
4250
|
+
const toolResult = await session.connector.callTool(
|
|
4251
|
+
call.tool,
|
|
4252
|
+
call.args
|
|
4253
|
+
);
|
|
4254
|
+
let extractedResult = toolResult;
|
|
4255
|
+
if (toolResult.content && toolResult.content.length > 0) {
|
|
4256
|
+
const item = toolResult.content[0];
|
|
4257
|
+
if (item.type === "text") {
|
|
4258
|
+
try {
|
|
4259
|
+
extractedResult = JSON.parse(item.text);
|
|
4260
|
+
} catch {
|
|
4261
|
+
extractedResult = item.text;
|
|
4262
|
+
}
|
|
4263
|
+
} else {
|
|
4264
|
+
extractedResult = item;
|
|
4265
|
+
}
|
|
4266
|
+
}
|
|
4267
|
+
const resultPath = `/tmp/mcp_result_${call.id}.json`;
|
|
4268
|
+
await sandbox.files.write(
|
|
4269
|
+
resultPath,
|
|
4270
|
+
JSON.stringify({ data: extractedResult })
|
|
4271
|
+
);
|
|
4272
|
+
} catch (err) {
|
|
4273
|
+
logger.error(
|
|
4274
|
+
`[E2B Bridge] Tool execution failed: ${err.message}`
|
|
4275
|
+
);
|
|
4276
|
+
const resultPath = `/tmp/mcp_result_${call.id}.json`;
|
|
4277
|
+
await sandbox.files.write(
|
|
4278
|
+
resultPath,
|
|
4279
|
+
JSON.stringify({
|
|
4280
|
+
error: err.message || String(err)
|
|
4281
|
+
})
|
|
4282
|
+
);
|
|
4283
|
+
}
|
|
4284
|
+
}
|
|
4285
|
+
}
|
|
4286
|
+
}
|
|
4287
|
+
} catch (e) {
|
|
4288
|
+
}
|
|
4289
|
+
}, "onStdout")
|
|
4290
|
+
});
|
|
4291
|
+
logs = [execution.stdout, execution.stderr].filter(Boolean);
|
|
4292
|
+
if (execution.exitCode !== 0) {
|
|
4293
|
+
error = execution.stderr || "Execution failed";
|
|
4294
|
+
} else {
|
|
4295
|
+
const stdout = execution.stdout;
|
|
4296
|
+
const startMarker = "__MCP_RESULT_START__";
|
|
4297
|
+
const endMarker = "__MCP_RESULT_END__";
|
|
4298
|
+
const startIndex = stdout.indexOf(startMarker);
|
|
4299
|
+
const endIndex = stdout.indexOf(endMarker);
|
|
4300
|
+
if (startIndex !== -1 && endIndex !== -1) {
|
|
4301
|
+
const jsonStr = stdout.substring(startIndex + startMarker.length, endIndex).trim();
|
|
4302
|
+
try {
|
|
4303
|
+
result = JSON.parse(jsonStr);
|
|
4304
|
+
} catch (e) {
|
|
4305
|
+
result = jsonStr;
|
|
4306
|
+
}
|
|
4307
|
+
logs = logs.map((log) => {
|
|
4308
|
+
let cleaned = log.replace(
|
|
4309
|
+
new RegExp(startMarker + "[\\s\\S]*?" + endMarker),
|
|
4310
|
+
"[Result captured]"
|
|
4311
|
+
);
|
|
4312
|
+
cleaned = cleaned.split("\n").filter((l) => !l.includes("__MCP_TOOL_CALL__")).join("\n");
|
|
4313
|
+
return cleaned;
|
|
4314
|
+
});
|
|
4315
|
+
}
|
|
4316
|
+
}
|
|
4317
|
+
} catch (e) {
|
|
4318
|
+
error = e.message || String(e);
|
|
4319
|
+
if (error && (error.includes("timeout") || error.includes("timed out"))) {
|
|
4320
|
+
error = "Script execution timed out";
|
|
4321
|
+
}
|
|
4322
|
+
}
|
|
4323
|
+
return {
|
|
4324
|
+
result,
|
|
4325
|
+
logs,
|
|
4326
|
+
error,
|
|
4327
|
+
execution_time: (Date.now() - startTime) / 1e3
|
|
4328
|
+
};
|
|
4329
|
+
}
|
|
4330
|
+
/**
|
|
4331
|
+
* Clean up the E2B sandbox.
|
|
4332
|
+
* Should be called when the executor is no longer needed.
|
|
4333
|
+
*/
|
|
4334
|
+
async cleanup() {
|
|
4335
|
+
if (this.codeExecSandbox) {
|
|
3708
4336
|
try {
|
|
3709
|
-
await this.
|
|
3710
|
-
|
|
3711
|
-
logger.
|
|
3712
|
-
}
|
|
3713
|
-
|
|
4337
|
+
await this.codeExecSandbox.kill();
|
|
4338
|
+
this.codeExecSandbox = null;
|
|
4339
|
+
logger.debug("E2B code execution sandbox stopped");
|
|
4340
|
+
} catch (error) {
|
|
4341
|
+
logger.error("Failed to stop E2B code execution sandbox:", error);
|
|
3714
4342
|
}
|
|
3715
4343
|
}
|
|
3716
4344
|
}
|
|
3717
4345
|
};
|
|
3718
4346
|
|
|
3719
|
-
// src/
|
|
3720
|
-
var
|
|
4347
|
+
// src/client/executors/vm.ts
|
|
4348
|
+
var import_node_vm = __toESM(require("vm"), 1);
|
|
3721
4349
|
init_logging();
|
|
3722
|
-
var
|
|
4350
|
+
var VMCodeExecutor = class extends BaseCodeExecutor {
|
|
3723
4351
|
static {
|
|
3724
|
-
__name(this, "
|
|
4352
|
+
__name(this, "VMCodeExecutor");
|
|
3725
4353
|
}
|
|
3726
|
-
|
|
3727
|
-
|
|
3728
|
-
|
|
3729
|
-
|
|
3730
|
-
|
|
3731
|
-
|
|
3732
|
-
* @param url The HTTP endpoint URL.
|
|
3733
|
-
* @param opts Optional transport options (auth, headers, etc.).
|
|
3734
|
-
*/
|
|
3735
|
-
constructor(url, opts) {
|
|
3736
|
-
super();
|
|
3737
|
-
this.url = typeof url === "string" ? new URL(url) : url;
|
|
3738
|
-
this.opts = opts;
|
|
4354
|
+
defaultTimeout;
|
|
4355
|
+
memoryLimitMb;
|
|
4356
|
+
constructor(client, options) {
|
|
4357
|
+
super(client);
|
|
4358
|
+
this.defaultTimeout = options?.timeoutMs ?? 3e4;
|
|
4359
|
+
this.memoryLimitMb = options?.memoryLimitMb;
|
|
3739
4360
|
}
|
|
3740
4361
|
/**
|
|
3741
|
-
*
|
|
3742
|
-
*
|
|
4362
|
+
* Execute JavaScript/TypeScript code with access to MCP tools.
|
|
4363
|
+
*
|
|
4364
|
+
* @param code - Code to execute
|
|
4365
|
+
* @param timeout - Execution timeout in milliseconds (default: configured timeout or 30000)
|
|
3743
4366
|
*/
|
|
3744
|
-
async
|
|
3745
|
-
|
|
3746
|
-
|
|
3747
|
-
|
|
4367
|
+
async execute(code, timeout) {
|
|
4368
|
+
const effectiveTimeout = timeout ?? this.defaultTimeout;
|
|
4369
|
+
await this.ensureServersConnected();
|
|
4370
|
+
const logs = [];
|
|
4371
|
+
const startTime = Date.now();
|
|
4372
|
+
let result = null;
|
|
4373
|
+
let error = null;
|
|
4374
|
+
try {
|
|
4375
|
+
const context = await this._buildContext(logs);
|
|
4376
|
+
const wrappedCode = `
|
|
4377
|
+
(async () => {
|
|
4378
|
+
try {
|
|
4379
|
+
${code}
|
|
4380
|
+
} catch (e) {
|
|
4381
|
+
throw e;
|
|
4382
|
+
}
|
|
4383
|
+
})()
|
|
4384
|
+
`;
|
|
4385
|
+
const script = new import_node_vm.default.Script(wrappedCode, {
|
|
4386
|
+
filename: "agent_code.js"
|
|
4387
|
+
});
|
|
4388
|
+
const promise = script.runInNewContext(context, {
|
|
4389
|
+
timeout: effectiveTimeout,
|
|
4390
|
+
displayErrors: true
|
|
4391
|
+
});
|
|
4392
|
+
result = await promise;
|
|
4393
|
+
} catch (e) {
|
|
4394
|
+
error = e.message || String(e);
|
|
4395
|
+
if (e.code === "ERR_SCRIPT_EXECUTION_TIMEOUT" || e.message === "Script execution timed out." || typeof error === "string" && (error.includes("timed out") || error.includes("timeout"))) {
|
|
4396
|
+
error = "Script execution timed out";
|
|
4397
|
+
}
|
|
4398
|
+
if (e.stack) {
|
|
4399
|
+
logger.debug(`Code execution error stack: ${e.stack}`);
|
|
4400
|
+
}
|
|
4401
|
+
}
|
|
4402
|
+
const executionTime = (Date.now() - startTime) / 1e3;
|
|
4403
|
+
return {
|
|
4404
|
+
result,
|
|
4405
|
+
logs,
|
|
4406
|
+
error,
|
|
4407
|
+
execution_time: executionTime
|
|
4408
|
+
};
|
|
3748
4409
|
}
|
|
3749
4410
|
/**
|
|
3750
|
-
*
|
|
4411
|
+
* Build the VM execution context with MCP tools and standard globals.
|
|
4412
|
+
*
|
|
4413
|
+
* @param logs - Array to capture console output
|
|
3751
4414
|
*/
|
|
3752
|
-
async
|
|
3753
|
-
|
|
3754
|
-
|
|
3755
|
-
|
|
3756
|
-
|
|
3757
|
-
|
|
3758
|
-
|
|
3759
|
-
|
|
4415
|
+
async _buildContext(logs) {
|
|
4416
|
+
const logHandler = /* @__PURE__ */ __name((...args) => {
|
|
4417
|
+
logs.push(
|
|
4418
|
+
args.map(
|
|
4419
|
+
(arg) => typeof arg === "object" ? JSON.stringify(arg, null, 2) : String(arg)
|
|
4420
|
+
).join(" ")
|
|
4421
|
+
);
|
|
4422
|
+
}, "logHandler");
|
|
4423
|
+
const sandbox = {
|
|
4424
|
+
console: {
|
|
4425
|
+
log: logHandler,
|
|
4426
|
+
error: /* @__PURE__ */ __name((...args) => {
|
|
4427
|
+
logHandler("[ERROR]", ...args);
|
|
4428
|
+
}, "error"),
|
|
4429
|
+
warn: /* @__PURE__ */ __name((...args) => {
|
|
4430
|
+
logHandler("[WARN]", ...args);
|
|
4431
|
+
}, "warn"),
|
|
4432
|
+
info: logHandler,
|
|
4433
|
+
debug: logHandler
|
|
4434
|
+
},
|
|
4435
|
+
// Standard globals
|
|
4436
|
+
Object,
|
|
4437
|
+
Array,
|
|
4438
|
+
String,
|
|
4439
|
+
Number,
|
|
4440
|
+
Boolean,
|
|
4441
|
+
Date,
|
|
4442
|
+
Math,
|
|
4443
|
+
JSON,
|
|
4444
|
+
RegExp,
|
|
4445
|
+
Map,
|
|
4446
|
+
Set,
|
|
4447
|
+
Promise,
|
|
4448
|
+
parseInt,
|
|
4449
|
+
parseFloat,
|
|
4450
|
+
isNaN,
|
|
4451
|
+
isFinite,
|
|
4452
|
+
encodeURI,
|
|
4453
|
+
decodeURI,
|
|
4454
|
+
encodeURIComponent,
|
|
4455
|
+
decodeURIComponent,
|
|
4456
|
+
setTimeout,
|
|
4457
|
+
clearTimeout,
|
|
4458
|
+
// Helper for tools
|
|
4459
|
+
search_tools: this.createSearchToolsFunction(),
|
|
4460
|
+
__tool_namespaces: []
|
|
4461
|
+
};
|
|
4462
|
+
const toolNamespaces = {};
|
|
4463
|
+
const namespaceInfos = this.getToolNamespaces();
|
|
4464
|
+
for (const { serverName, tools, session } of namespaceInfos) {
|
|
4465
|
+
const serverNamespace = {};
|
|
4466
|
+
for (const tool of tools) {
|
|
4467
|
+
const toolName = tool.name;
|
|
4468
|
+
serverNamespace[toolName] = async (args) => {
|
|
4469
|
+
const result = await session.connector.callTool(toolName, args || {});
|
|
4470
|
+
if (result.content && result.content.length > 0) {
|
|
4471
|
+
const item = result.content[0];
|
|
4472
|
+
if (item.type === "text") {
|
|
4473
|
+
try {
|
|
4474
|
+
return JSON.parse(item.text);
|
|
4475
|
+
} catch {
|
|
4476
|
+
return item.text;
|
|
4477
|
+
}
|
|
4478
|
+
}
|
|
4479
|
+
return item;
|
|
4480
|
+
}
|
|
4481
|
+
return result;
|
|
4482
|
+
};
|
|
3760
4483
|
}
|
|
4484
|
+
sandbox[serverName] = serverNamespace;
|
|
4485
|
+
toolNamespaces[serverName] = true;
|
|
3761
4486
|
}
|
|
4487
|
+
sandbox.__tool_namespaces = Object.keys(toolNamespaces);
|
|
4488
|
+
return import_node_vm.default.createContext(sandbox);
|
|
3762
4489
|
}
|
|
3763
4490
|
/**
|
|
3764
|
-
*
|
|
4491
|
+
* Clean up resources.
|
|
4492
|
+
* VM executor doesn't need cleanup, but method kept for interface consistency.
|
|
3765
4493
|
*/
|
|
3766
|
-
|
|
3767
|
-
return this._transport?.sessionId;
|
|
4494
|
+
async cleanup() {
|
|
3768
4495
|
}
|
|
3769
4496
|
};
|
|
3770
4497
|
|
|
@@ -3893,132 +4620,550 @@ var BaseConnector = class {
|
|
|
3893
4620
|
} while (cursor);
|
|
3894
4621
|
return { resources: allResources };
|
|
3895
4622
|
} catch (err) {
|
|
3896
|
-
if (err.code === -32601) {
|
|
3897
|
-
logger.debug("Server advertised resources but method not found");
|
|
3898
|
-
return { resources: [] };
|
|
4623
|
+
if (err.code === -32601) {
|
|
4624
|
+
logger.debug("Server advertised resources but method not found");
|
|
4625
|
+
return { resources: [] };
|
|
4626
|
+
}
|
|
4627
|
+
throw err;
|
|
4628
|
+
}
|
|
4629
|
+
}
|
|
4630
|
+
/**
|
|
4631
|
+
* List resource templates from the server
|
|
4632
|
+
*
|
|
4633
|
+
* @param options - Request options
|
|
4634
|
+
* @returns List of available resource templates
|
|
4635
|
+
*/
|
|
4636
|
+
async listResourceTemplates(options) {
|
|
4637
|
+
if (!this.client) {
|
|
4638
|
+
throw new Error("MCP client is not connected");
|
|
4639
|
+
}
|
|
4640
|
+
logger.debug("Listing resource templates");
|
|
4641
|
+
return await this.client.listResourceTemplates(void 0, options);
|
|
4642
|
+
}
|
|
4643
|
+
/** Read a resource by URI. */
|
|
4644
|
+
async readResource(uri, options) {
|
|
4645
|
+
if (!this.client) {
|
|
4646
|
+
throw new Error("MCP client is not connected");
|
|
4647
|
+
}
|
|
4648
|
+
logger.debug(`Reading resource ${uri}`);
|
|
4649
|
+
const res = await this.client.readResource({ uri }, options);
|
|
4650
|
+
return res;
|
|
4651
|
+
}
|
|
4652
|
+
/**
|
|
4653
|
+
* Subscribe to resource updates
|
|
4654
|
+
*
|
|
4655
|
+
* @param uri - URI of the resource to subscribe to
|
|
4656
|
+
* @param options - Request options
|
|
4657
|
+
*/
|
|
4658
|
+
async subscribeToResource(uri, options) {
|
|
4659
|
+
if (!this.client) {
|
|
4660
|
+
throw new Error("MCP client is not connected");
|
|
4661
|
+
}
|
|
4662
|
+
logger.debug(`Subscribing to resource: ${uri}`);
|
|
4663
|
+
return await this.client.subscribeResource({ uri }, options);
|
|
4664
|
+
}
|
|
4665
|
+
/**
|
|
4666
|
+
* Unsubscribe from resource updates
|
|
4667
|
+
*
|
|
4668
|
+
* @param uri - URI of the resource to unsubscribe from
|
|
4669
|
+
* @param options - Request options
|
|
4670
|
+
*/
|
|
4671
|
+
async unsubscribeFromResource(uri, options) {
|
|
4672
|
+
if (!this.client) {
|
|
4673
|
+
throw new Error("MCP client is not connected");
|
|
4674
|
+
}
|
|
4675
|
+
logger.debug(`Unsubscribing from resource: ${uri}`);
|
|
4676
|
+
return await this.client.unsubscribeResource({ uri }, options);
|
|
4677
|
+
}
|
|
4678
|
+
async listPrompts() {
|
|
4679
|
+
if (!this.client) {
|
|
4680
|
+
throw new Error("MCP client is not connected");
|
|
4681
|
+
}
|
|
4682
|
+
if (!this.capabilitiesCache?.prompts) {
|
|
4683
|
+
logger.debug("Server does not advertise prompts capability, skipping");
|
|
4684
|
+
return { prompts: [] };
|
|
4685
|
+
}
|
|
4686
|
+
try {
|
|
4687
|
+
logger.debug("Listing prompts");
|
|
4688
|
+
return await this.client.listPrompts();
|
|
4689
|
+
} catch (err) {
|
|
4690
|
+
if (err.code === -32601) {
|
|
4691
|
+
logger.debug("Server advertised prompts but method not found");
|
|
4692
|
+
return { prompts: [] };
|
|
4693
|
+
}
|
|
4694
|
+
throw err;
|
|
4695
|
+
}
|
|
4696
|
+
}
|
|
4697
|
+
async getPrompt(name, args) {
|
|
4698
|
+
if (!this.client) {
|
|
4699
|
+
throw new Error("MCP client is not connected");
|
|
4700
|
+
}
|
|
4701
|
+
logger.debug(`Getting prompt ${name}`);
|
|
4702
|
+
return await this.client.getPrompt({ name, arguments: args });
|
|
4703
|
+
}
|
|
4704
|
+
/** Send a raw request through the client. */
|
|
4705
|
+
async request(method, params = null, options) {
|
|
4706
|
+
if (!this.client) {
|
|
4707
|
+
throw new Error("MCP client is not connected");
|
|
4708
|
+
}
|
|
4709
|
+
logger.debug(`Sending raw request '${method}' with params`, params);
|
|
4710
|
+
return await this.client.request(
|
|
4711
|
+
{ method, params: params ?? {} },
|
|
4712
|
+
void 0,
|
|
4713
|
+
options
|
|
4714
|
+
);
|
|
4715
|
+
}
|
|
4716
|
+
/**
|
|
4717
|
+
* Helper to tear down the client & connection manager safely.
|
|
4718
|
+
*/
|
|
4719
|
+
async cleanupResources() {
|
|
4720
|
+
const issues = [];
|
|
4721
|
+
if (this.client) {
|
|
4722
|
+
try {
|
|
4723
|
+
if (typeof this.client.close === "function") {
|
|
4724
|
+
await this.client.close();
|
|
4725
|
+
}
|
|
4726
|
+
} catch (e) {
|
|
4727
|
+
const msg = `Error closing client: ${e}`;
|
|
4728
|
+
logger.warn(msg);
|
|
4729
|
+
issues.push(msg);
|
|
4730
|
+
} finally {
|
|
4731
|
+
this.client = null;
|
|
4732
|
+
}
|
|
4733
|
+
}
|
|
4734
|
+
if (this.connectionManager) {
|
|
4735
|
+
try {
|
|
4736
|
+
await this.connectionManager.stop();
|
|
4737
|
+
} catch (e) {
|
|
4738
|
+
const msg = `Error stopping connection manager: ${e}`;
|
|
4739
|
+
logger.warn(msg);
|
|
4740
|
+
issues.push(msg);
|
|
4741
|
+
} finally {
|
|
4742
|
+
this.connectionManager = null;
|
|
4743
|
+
}
|
|
4744
|
+
}
|
|
4745
|
+
this.toolsCache = null;
|
|
4746
|
+
if (issues.length) {
|
|
4747
|
+
logger.warn(`Resource cleanup finished with ${issues.length} issue(s)`);
|
|
4748
|
+
}
|
|
4749
|
+
}
|
|
4750
|
+
};
|
|
4751
|
+
|
|
4752
|
+
// src/client/connectors/codeMode.ts
|
|
4753
|
+
var CODE_MODE_AGENT_PROMPT = `
|
|
4754
|
+
## MCP Code Mode Tool Usage Guide
|
|
4755
|
+
|
|
4756
|
+
You have access to an MCP Code Mode Client that allows you to execute JavaScript/TypeScript code with access to registered tools. Follow this workflow:
|
|
4757
|
+
|
|
4758
|
+
### 1. Tool Discovery Phase
|
|
4759
|
+
**Always start by discovering available tools:**
|
|
4760
|
+
- Tools are organized by server namespace (e.g., \`server_name.tool_name\`)
|
|
4761
|
+
- Use the \`search_tools(query, detail_level)\` function to find available tools
|
|
4762
|
+
- You can access \`__tool_namespaces\` to see all available server namespaces
|
|
4763
|
+
|
|
4764
|
+
\`\`\`javascript
|
|
4765
|
+
// Find all GitHub-related tools
|
|
4766
|
+
const tools = await search_tools("github");
|
|
4767
|
+
for (const tool of tools) {
|
|
4768
|
+
console.log(\`\${tool.server}.\${tool.name}: \${tool.description}\`);
|
|
4769
|
+
}
|
|
4770
|
+
|
|
4771
|
+
// Get only tool names for quick overview
|
|
4772
|
+
const tools = await search_tools("", "names");
|
|
4773
|
+
\`\`\`
|
|
4774
|
+
|
|
4775
|
+
### 2. Interface Introspection
|
|
4776
|
+
**Understand tool contracts before using them:**
|
|
4777
|
+
- Use \`search_tools\` to get tool descriptions and input schemas
|
|
4778
|
+
- Look for "Access as: server.tool(args)" patterns in descriptions
|
|
4779
|
+
|
|
4780
|
+
### 3. Code Execution Guidelines
|
|
4781
|
+
**When writing code:**
|
|
4782
|
+
- Use \`await server.tool({ param: value })\` syntax for all tool calls
|
|
4783
|
+
- Tools are async functions that return promises
|
|
4784
|
+
- You have access to standard JavaScript globals: \`console\`, \`JSON\`, \`Math\`, \`Date\`, etc.
|
|
4785
|
+
- All console output (\`console.log\`, \`console.error\`, etc.) is automatically captured and returned
|
|
4786
|
+
- Build properly structured input objects based on interface definitions
|
|
4787
|
+
- Handle errors appropriately with try/catch blocks
|
|
4788
|
+
- Chain tool calls by using results from previous calls
|
|
4789
|
+
|
|
4790
|
+
### 4. Best Practices
|
|
4791
|
+
- **Discover first, code second**: Always explore available tools before writing execution code
|
|
4792
|
+
- **Respect namespaces**: Use full \`server.tool\` names to avoid conflicts
|
|
4793
|
+
- **Minimize Context**: Process large data in code, return only essential results
|
|
4794
|
+
- **Error handling**: Wrap tool calls in try/catch for robustness
|
|
4795
|
+
- **Data flow**: Chain tools by passing outputs as inputs to subsequent tools
|
|
4796
|
+
|
|
4797
|
+
### 5. Available Runtime Context
|
|
4798
|
+
- \`search_tools(query, detail_level)\`: Function to discover tools
|
|
4799
|
+
- \`__tool_namespaces\`: Array of available server namespaces
|
|
4800
|
+
- All registered tools as \`server.tool\` functions
|
|
4801
|
+
- Standard JavaScript built-ins for data processing
|
|
4802
|
+
|
|
4803
|
+
### Example Workflow
|
|
4804
|
+
|
|
4805
|
+
\`\`\`javascript
|
|
4806
|
+
// 1. Discover available tools
|
|
4807
|
+
const github_tools = await search_tools("github pull request");
|
|
4808
|
+
console.log(\`Available GitHub PR tools: \${github_tools.map(t => t.name)}\`);
|
|
4809
|
+
|
|
4810
|
+
// 2. Call tools with proper parameters
|
|
4811
|
+
const pr = await github.get_pull_request({
|
|
4812
|
+
owner: "facebook",
|
|
4813
|
+
repo: "react",
|
|
4814
|
+
number: 12345
|
|
4815
|
+
});
|
|
4816
|
+
|
|
4817
|
+
// 3. Process results
|
|
4818
|
+
let result;
|
|
4819
|
+
if (pr.state === 'open' && pr.labels.some(l => l.name === 'bug')) {
|
|
4820
|
+
// 4. Chain with other tools
|
|
4821
|
+
await slack.post_message({
|
|
4822
|
+
channel: "#bugs",
|
|
4823
|
+
text: \`\u{1F41B} Bug PR needs review: \${pr.title}\`
|
|
4824
|
+
});
|
|
4825
|
+
result = "Notification sent";
|
|
4826
|
+
} else {
|
|
4827
|
+
result = "No action needed";
|
|
4828
|
+
}
|
|
4829
|
+
|
|
4830
|
+
// 5. Return structured results
|
|
4831
|
+
return {
|
|
4832
|
+
pr_number: pr.number,
|
|
4833
|
+
pr_title: pr.title,
|
|
4834
|
+
action_taken: result
|
|
4835
|
+
};
|
|
4836
|
+
\`\`\`
|
|
4837
|
+
|
|
4838
|
+
Remember: Always discover and understand available tools before attempting to use them in code execution.
|
|
4839
|
+
`;
|
|
4840
|
+
var CodeModeConnector = class extends BaseConnector {
|
|
4841
|
+
static {
|
|
4842
|
+
__name(this, "CodeModeConnector");
|
|
4843
|
+
}
|
|
4844
|
+
mcpClient;
|
|
4845
|
+
_tools;
|
|
4846
|
+
constructor(client) {
|
|
4847
|
+
super();
|
|
4848
|
+
this.mcpClient = client;
|
|
4849
|
+
this.connected = true;
|
|
4850
|
+
this._tools = this._createToolsList();
|
|
4851
|
+
}
|
|
4852
|
+
async connect() {
|
|
4853
|
+
this.connected = true;
|
|
4854
|
+
}
|
|
4855
|
+
async disconnect() {
|
|
4856
|
+
this.connected = false;
|
|
4857
|
+
}
|
|
4858
|
+
get publicIdentifier() {
|
|
4859
|
+
return { name: "code_mode", version: "1.0.0" };
|
|
4860
|
+
}
|
|
4861
|
+
_createToolsList() {
|
|
4862
|
+
return [
|
|
4863
|
+
{
|
|
4864
|
+
name: "execute_code",
|
|
4865
|
+
description: "Execute JavaScript/TypeScript code with access to MCP tools. This is the PRIMARY way to interact with MCP servers in code mode. Write code that discovers tools using search_tools(), calls tools as async functions (e.g., await github.get_pull_request(...)), processes data efficiently, and returns results. Use 'await' for async operations and 'return' to return values. Available in code: search_tools(), __tool_namespaces, and server.tool_name() functions.",
|
|
4866
|
+
inputSchema: {
|
|
4867
|
+
type: "object",
|
|
4868
|
+
properties: {
|
|
4869
|
+
code: {
|
|
4870
|
+
type: "string",
|
|
4871
|
+
description: "JavaScript/TypeScript code to execute. Use 'await' for async operations. Use 'return' to return a value. Available: search_tools(), server.tool_name(), __tool_namespaces"
|
|
4872
|
+
},
|
|
4873
|
+
timeout: {
|
|
4874
|
+
type: "number",
|
|
4875
|
+
description: "Execution timeout in milliseconds",
|
|
4876
|
+
default: 3e4
|
|
4877
|
+
}
|
|
4878
|
+
},
|
|
4879
|
+
required: ["code"]
|
|
4880
|
+
}
|
|
4881
|
+
},
|
|
4882
|
+
{
|
|
4883
|
+
name: "search_tools",
|
|
4884
|
+
description: "Search and discover available MCP tools across all servers. Use this to find out what tools are available before writing code. Returns tool information including names, descriptions, and schemas. Can filter by query and control detail level.",
|
|
4885
|
+
inputSchema: {
|
|
4886
|
+
type: "object",
|
|
4887
|
+
properties: {
|
|
4888
|
+
query: {
|
|
4889
|
+
type: "string",
|
|
4890
|
+
description: "Search query to filter tools by name or description",
|
|
4891
|
+
default: ""
|
|
4892
|
+
},
|
|
4893
|
+
detail_level: {
|
|
4894
|
+
type: "string",
|
|
4895
|
+
description: "Detail level: 'names', 'descriptions', or 'full'",
|
|
4896
|
+
enum: ["names", "descriptions", "full"],
|
|
4897
|
+
default: "full"
|
|
4898
|
+
}
|
|
4899
|
+
}
|
|
4900
|
+
}
|
|
4901
|
+
}
|
|
4902
|
+
];
|
|
4903
|
+
}
|
|
4904
|
+
// Override tools getter to return static list immediately
|
|
4905
|
+
get tools() {
|
|
4906
|
+
return this._tools;
|
|
4907
|
+
}
|
|
4908
|
+
async initialize() {
|
|
4909
|
+
this.toolsCache = this._tools;
|
|
4910
|
+
return { capabilities: {}, version: "1.0.0" };
|
|
4911
|
+
}
|
|
4912
|
+
async callTool(name, args) {
|
|
4913
|
+
if (name === "execute_code") {
|
|
4914
|
+
const code = args.code;
|
|
4915
|
+
const timeout = args.timeout || 3e4;
|
|
4916
|
+
const result = await this.mcpClient.executeCode(code, timeout);
|
|
4917
|
+
return {
|
|
4918
|
+
content: [
|
|
4919
|
+
{
|
|
4920
|
+
type: "text",
|
|
4921
|
+
text: JSON.stringify(result)
|
|
4922
|
+
}
|
|
4923
|
+
]
|
|
4924
|
+
};
|
|
4925
|
+
} else if (name === "search_tools") {
|
|
4926
|
+
const query = args.query || "";
|
|
4927
|
+
const detailLevel = args.detail_level;
|
|
4928
|
+
const result = await this.mcpClient.searchTools(
|
|
4929
|
+
query,
|
|
4930
|
+
detailLevel && detailLevel in ["names", "descriptions", "full"] ? detailLevel : "full"
|
|
4931
|
+
);
|
|
4932
|
+
return {
|
|
4933
|
+
content: [
|
|
4934
|
+
{
|
|
4935
|
+
type: "text",
|
|
4936
|
+
text: JSON.stringify(result)
|
|
4937
|
+
}
|
|
4938
|
+
]
|
|
4939
|
+
};
|
|
4940
|
+
}
|
|
4941
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
4942
|
+
}
|
|
4943
|
+
};
|
|
4944
|
+
|
|
4945
|
+
// src/config.ts
|
|
4946
|
+
var import_node_fs = require("fs");
|
|
4947
|
+
|
|
4948
|
+
// src/connectors/http.ts
|
|
4949
|
+
var import_client = require("@modelcontextprotocol/sdk/client/index.js");
|
|
4950
|
+
var import_streamableHttp2 = require("@modelcontextprotocol/sdk/client/streamableHttp.js");
|
|
4951
|
+
init_logging();
|
|
4952
|
+
|
|
4953
|
+
// src/task_managers/sse.ts
|
|
4954
|
+
var import_sse = require("@modelcontextprotocol/sdk/client/sse.js");
|
|
4955
|
+
init_logging();
|
|
4956
|
+
|
|
4957
|
+
// src/task_managers/base.ts
|
|
4958
|
+
init_logging();
|
|
4959
|
+
var ConnectionManager = class {
|
|
4960
|
+
static {
|
|
4961
|
+
__name(this, "ConnectionManager");
|
|
4962
|
+
}
|
|
4963
|
+
_readyPromise;
|
|
4964
|
+
_readyResolver;
|
|
4965
|
+
_donePromise;
|
|
4966
|
+
_doneResolver;
|
|
4967
|
+
_exception = null;
|
|
4968
|
+
_connection = null;
|
|
4969
|
+
_task = null;
|
|
4970
|
+
_abortController = null;
|
|
4971
|
+
constructor() {
|
|
4972
|
+
this.reset();
|
|
4973
|
+
}
|
|
4974
|
+
/**
|
|
4975
|
+
* Start the connection manager and establish a connection.
|
|
4976
|
+
*
|
|
4977
|
+
* @returns The established connection.
|
|
4978
|
+
* @throws If the connection cannot be established.
|
|
4979
|
+
*/
|
|
4980
|
+
async start() {
|
|
4981
|
+
this.reset();
|
|
4982
|
+
logger.debug(`Starting ${this.constructor.name}`);
|
|
4983
|
+
this._task = this.connectionTask();
|
|
4984
|
+
await this._readyPromise;
|
|
4985
|
+
if (this._exception) {
|
|
4986
|
+
throw this._exception;
|
|
4987
|
+
}
|
|
4988
|
+
if (this._connection === null) {
|
|
4989
|
+
throw new Error("Connection was not established");
|
|
4990
|
+
}
|
|
4991
|
+
return this._connection;
|
|
4992
|
+
}
|
|
4993
|
+
/**
|
|
4994
|
+
* Stop the connection manager and close the connection.
|
|
4995
|
+
*/
|
|
4996
|
+
async stop() {
|
|
4997
|
+
if (this._task && this._abortController) {
|
|
4998
|
+
logger.debug(`Cancelling ${this.constructor.name} task`);
|
|
4999
|
+
this._abortController.abort();
|
|
5000
|
+
try {
|
|
5001
|
+
await this._task;
|
|
5002
|
+
} catch (e) {
|
|
5003
|
+
if (e instanceof Error && e.name === "AbortError") {
|
|
5004
|
+
logger.debug(`${this.constructor.name} task aborted successfully`);
|
|
5005
|
+
} else {
|
|
5006
|
+
logger.warn(`Error stopping ${this.constructor.name} task: ${e}`);
|
|
5007
|
+
}
|
|
5008
|
+
}
|
|
5009
|
+
}
|
|
5010
|
+
await this._donePromise;
|
|
5011
|
+
logger.debug(`${this.constructor.name} task completed`);
|
|
5012
|
+
}
|
|
5013
|
+
/**
|
|
5014
|
+
* Reset all internal state.
|
|
5015
|
+
*/
|
|
5016
|
+
reset() {
|
|
5017
|
+
this._readyPromise = new Promise((res) => this._readyResolver = res);
|
|
5018
|
+
this._donePromise = new Promise((res) => this._doneResolver = res);
|
|
5019
|
+
this._exception = null;
|
|
5020
|
+
this._connection = null;
|
|
5021
|
+
this._task = null;
|
|
5022
|
+
this._abortController = new AbortController();
|
|
5023
|
+
}
|
|
5024
|
+
/**
|
|
5025
|
+
* The background task responsible for establishing and maintaining the
|
|
5026
|
+
* connection until it is cancelled.
|
|
5027
|
+
*/
|
|
5028
|
+
async connectionTask() {
|
|
5029
|
+
logger.debug(`Running ${this.constructor.name} task`);
|
|
5030
|
+
try {
|
|
5031
|
+
this._connection = await this.establishConnection();
|
|
5032
|
+
logger.debug(`${this.constructor.name} connected successfully`);
|
|
5033
|
+
this._readyResolver();
|
|
5034
|
+
await this.waitForAbort();
|
|
5035
|
+
} catch (err) {
|
|
5036
|
+
this._exception = err;
|
|
5037
|
+
logger.error(`Error in ${this.constructor.name} task: ${err}`);
|
|
5038
|
+
this._readyResolver();
|
|
5039
|
+
} finally {
|
|
5040
|
+
if (this._connection !== null) {
|
|
5041
|
+
try {
|
|
5042
|
+
await this.closeConnection(this._connection);
|
|
5043
|
+
} catch (closeErr) {
|
|
5044
|
+
logger.warn(
|
|
5045
|
+
`Error closing connection in ${this.constructor.name}: ${closeErr}`
|
|
5046
|
+
);
|
|
5047
|
+
}
|
|
5048
|
+
this._connection = null;
|
|
3899
5049
|
}
|
|
3900
|
-
|
|
5050
|
+
this._doneResolver();
|
|
3901
5051
|
}
|
|
3902
5052
|
}
|
|
3903
5053
|
/**
|
|
3904
|
-
*
|
|
3905
|
-
*
|
|
3906
|
-
* @param options - Request options
|
|
3907
|
-
* @returns List of available resource templates
|
|
5054
|
+
* Helper that returns a promise which resolves when the abort signal fires.
|
|
3908
5055
|
*/
|
|
3909
|
-
async
|
|
3910
|
-
|
|
3911
|
-
|
|
3912
|
-
|
|
3913
|
-
|
|
3914
|
-
|
|
5056
|
+
async waitForAbort() {
|
|
5057
|
+
return new Promise((_resolve, _reject) => {
|
|
5058
|
+
if (!this._abortController) {
|
|
5059
|
+
return;
|
|
5060
|
+
}
|
|
5061
|
+
const signal = this._abortController.signal;
|
|
5062
|
+
if (signal.aborted) {
|
|
5063
|
+
_resolve();
|
|
5064
|
+
return;
|
|
5065
|
+
}
|
|
5066
|
+
const onAbort = /* @__PURE__ */ __name(() => {
|
|
5067
|
+
signal.removeEventListener("abort", onAbort);
|
|
5068
|
+
_resolve();
|
|
5069
|
+
}, "onAbort");
|
|
5070
|
+
signal.addEventListener("abort", onAbort);
|
|
5071
|
+
});
|
|
3915
5072
|
}
|
|
3916
|
-
|
|
3917
|
-
|
|
3918
|
-
|
|
3919
|
-
|
|
3920
|
-
|
|
3921
|
-
|
|
3922
|
-
const res = await this.client.readResource({ uri }, options);
|
|
3923
|
-
return res;
|
|
5073
|
+
};
|
|
5074
|
+
|
|
5075
|
+
// src/task_managers/sse.ts
|
|
5076
|
+
var SseConnectionManager = class extends ConnectionManager {
|
|
5077
|
+
static {
|
|
5078
|
+
__name(this, "SseConnectionManager");
|
|
3924
5079
|
}
|
|
5080
|
+
url;
|
|
5081
|
+
opts;
|
|
5082
|
+
_transport = null;
|
|
3925
5083
|
/**
|
|
3926
|
-
*
|
|
5084
|
+
* Create an SSE connection manager.
|
|
3927
5085
|
*
|
|
3928
|
-
* @param
|
|
3929
|
-
* @param options
|
|
5086
|
+
* @param url The SSE endpoint URL.
|
|
5087
|
+
* @param opts Optional transport options (auth, headers, etc.).
|
|
3930
5088
|
*/
|
|
3931
|
-
|
|
3932
|
-
|
|
3933
|
-
|
|
3934
|
-
|
|
3935
|
-
logger.debug(`Subscribing to resource: ${uri}`);
|
|
3936
|
-
return await this.client.subscribeResource({ uri }, options);
|
|
5089
|
+
constructor(url, opts) {
|
|
5090
|
+
super();
|
|
5091
|
+
this.url = typeof url === "string" ? new URL(url) : url;
|
|
5092
|
+
this.opts = opts;
|
|
3937
5093
|
}
|
|
3938
5094
|
/**
|
|
3939
|
-
*
|
|
3940
|
-
*
|
|
3941
|
-
* @param uri - URI of the resource to unsubscribe from
|
|
3942
|
-
* @param options - Request options
|
|
5095
|
+
* Spawn a new `SSEClientTransport` and start the connection.
|
|
3943
5096
|
*/
|
|
3944
|
-
async
|
|
3945
|
-
|
|
3946
|
-
|
|
3947
|
-
|
|
3948
|
-
logger.debug(`Unsubscribing from resource: ${uri}`);
|
|
3949
|
-
return await this.client.unsubscribeResource({ uri }, options);
|
|
3950
|
-
}
|
|
3951
|
-
async listPrompts() {
|
|
3952
|
-
if (!this.client) {
|
|
3953
|
-
throw new Error("MCP client is not connected");
|
|
3954
|
-
}
|
|
3955
|
-
if (!this.capabilitiesCache?.prompts) {
|
|
3956
|
-
logger.debug("Server does not advertise prompts capability, skipping");
|
|
3957
|
-
return { prompts: [] };
|
|
3958
|
-
}
|
|
3959
|
-
try {
|
|
3960
|
-
logger.debug("Listing prompts");
|
|
3961
|
-
return await this.client.listPrompts();
|
|
3962
|
-
} catch (err) {
|
|
3963
|
-
if (err.code === -32601) {
|
|
3964
|
-
logger.debug("Server advertised prompts but method not found");
|
|
3965
|
-
return { prompts: [] };
|
|
3966
|
-
}
|
|
3967
|
-
throw err;
|
|
3968
|
-
}
|
|
3969
|
-
}
|
|
3970
|
-
async getPrompt(name, args) {
|
|
3971
|
-
if (!this.client) {
|
|
3972
|
-
throw new Error("MCP client is not connected");
|
|
3973
|
-
}
|
|
3974
|
-
logger.debug(`Getting prompt ${name}`);
|
|
3975
|
-
return await this.client.getPrompt({ name, arguments: args });
|
|
3976
|
-
}
|
|
3977
|
-
/** Send a raw request through the client. */
|
|
3978
|
-
async request(method, params = null, options) {
|
|
3979
|
-
if (!this.client) {
|
|
3980
|
-
throw new Error("MCP client is not connected");
|
|
3981
|
-
}
|
|
3982
|
-
logger.debug(`Sending raw request '${method}' with params`, params);
|
|
3983
|
-
return await this.client.request(
|
|
3984
|
-
{ method, params: params ?? {} },
|
|
3985
|
-
void 0,
|
|
3986
|
-
options
|
|
3987
|
-
);
|
|
5097
|
+
async establishConnection() {
|
|
5098
|
+
this._transport = new import_sse.SSEClientTransport(this.url, this.opts);
|
|
5099
|
+
logger.debug(`${this.constructor.name} connected successfully`);
|
|
5100
|
+
return this._transport;
|
|
3988
5101
|
}
|
|
3989
5102
|
/**
|
|
3990
|
-
*
|
|
5103
|
+
* Close the underlying transport and clean up resources.
|
|
3991
5104
|
*/
|
|
3992
|
-
async
|
|
3993
|
-
|
|
3994
|
-
if (this.client) {
|
|
5105
|
+
async closeConnection(_connection) {
|
|
5106
|
+
if (this._transport) {
|
|
3995
5107
|
try {
|
|
3996
|
-
|
|
3997
|
-
await this.client.close();
|
|
3998
|
-
}
|
|
5108
|
+
await this._transport.close();
|
|
3999
5109
|
} catch (e) {
|
|
4000
|
-
|
|
4001
|
-
logger.warn(msg);
|
|
4002
|
-
issues.push(msg);
|
|
5110
|
+
logger.warn(`Error closing SSE transport: ${e}`);
|
|
4003
5111
|
} finally {
|
|
4004
|
-
this.
|
|
5112
|
+
this._transport = null;
|
|
4005
5113
|
}
|
|
4006
5114
|
}
|
|
4007
|
-
|
|
5115
|
+
}
|
|
5116
|
+
};
|
|
5117
|
+
|
|
5118
|
+
// src/task_managers/streamable_http.ts
|
|
5119
|
+
var import_streamableHttp = require("@modelcontextprotocol/sdk/client/streamableHttp.js");
|
|
5120
|
+
init_logging();
|
|
5121
|
+
var StreamableHttpConnectionManager = class extends ConnectionManager {
|
|
5122
|
+
static {
|
|
5123
|
+
__name(this, "StreamableHttpConnectionManager");
|
|
5124
|
+
}
|
|
5125
|
+
url;
|
|
5126
|
+
opts;
|
|
5127
|
+
_transport = null;
|
|
5128
|
+
/**
|
|
5129
|
+
* Create a Streamable HTTP connection manager.
|
|
5130
|
+
*
|
|
5131
|
+
* @param url The HTTP endpoint URL.
|
|
5132
|
+
* @param opts Optional transport options (auth, headers, etc.).
|
|
5133
|
+
*/
|
|
5134
|
+
constructor(url, opts) {
|
|
5135
|
+
super();
|
|
5136
|
+
this.url = typeof url === "string" ? new URL(url) : url;
|
|
5137
|
+
this.opts = opts;
|
|
5138
|
+
}
|
|
5139
|
+
/**
|
|
5140
|
+
* Spawn a new `StreamableHTTPClientTransport` and return it.
|
|
5141
|
+
* The Client.connect() method will handle starting the transport.
|
|
5142
|
+
*/
|
|
5143
|
+
async establishConnection() {
|
|
5144
|
+
this._transport = new import_streamableHttp.StreamableHTTPClientTransport(this.url, this.opts);
|
|
5145
|
+
logger.debug(`${this.constructor.name} created successfully`);
|
|
5146
|
+
return this._transport;
|
|
5147
|
+
}
|
|
5148
|
+
/**
|
|
5149
|
+
* Close the underlying transport and clean up resources.
|
|
5150
|
+
*/
|
|
5151
|
+
async closeConnection(_connection) {
|
|
5152
|
+
if (this._transport) {
|
|
4008
5153
|
try {
|
|
4009
|
-
await this.
|
|
5154
|
+
await this._transport.close();
|
|
4010
5155
|
} catch (e) {
|
|
4011
|
-
|
|
4012
|
-
logger.warn(msg);
|
|
4013
|
-
issues.push(msg);
|
|
5156
|
+
logger.warn(`Error closing Streamable HTTP transport: ${e}`);
|
|
4014
5157
|
} finally {
|
|
4015
|
-
this.
|
|
5158
|
+
this._transport = null;
|
|
4016
5159
|
}
|
|
4017
5160
|
}
|
|
4018
|
-
|
|
4019
|
-
|
|
4020
|
-
|
|
4021
|
-
|
|
5161
|
+
}
|
|
5162
|
+
/**
|
|
5163
|
+
* Get the session ID from the transport if available.
|
|
5164
|
+
*/
|
|
5165
|
+
get sessionId() {
|
|
5166
|
+
return this._transport?.sessionId;
|
|
4022
5167
|
}
|
|
4023
5168
|
};
|
|
4024
5169
|
|
|
@@ -4600,11 +5745,17 @@ function createConnectorFromConfig(serverConfig) {
|
|
|
4600
5745
|
__name(createConnectorFromConfig, "createConnectorFromConfig");
|
|
4601
5746
|
|
|
4602
5747
|
// src/client.ts
|
|
5748
|
+
init_logging();
|
|
4603
5749
|
var MCPClient = class _MCPClient extends BaseMCPClient {
|
|
4604
5750
|
static {
|
|
4605
5751
|
__name(this, "MCPClient");
|
|
4606
5752
|
}
|
|
4607
|
-
|
|
5753
|
+
codeMode = false;
|
|
5754
|
+
_codeExecutor = null;
|
|
5755
|
+
_customCodeExecutor = null;
|
|
5756
|
+
_codeExecutorConfig = "vm";
|
|
5757
|
+
_executorOptions;
|
|
5758
|
+
constructor(config2, options) {
|
|
4608
5759
|
if (config2) {
|
|
4609
5760
|
if (typeof config2 === "string") {
|
|
4610
5761
|
super(loadConfigFile(config2));
|
|
@@ -4614,12 +5765,30 @@ var MCPClient = class _MCPClient extends BaseMCPClient {
|
|
|
4614
5765
|
} else {
|
|
4615
5766
|
super();
|
|
4616
5767
|
}
|
|
5768
|
+
let codeModeEnabled = false;
|
|
5769
|
+
let executorConfig = "vm";
|
|
5770
|
+
let executorOptions;
|
|
5771
|
+
if (options?.codeMode) {
|
|
5772
|
+
if (typeof options.codeMode === "boolean") {
|
|
5773
|
+
codeModeEnabled = options.codeMode;
|
|
5774
|
+
} else {
|
|
5775
|
+
codeModeEnabled = options.codeMode.enabled;
|
|
5776
|
+
executorConfig = options.codeMode.executor ?? "vm";
|
|
5777
|
+
executorOptions = options.codeMode.executorOptions;
|
|
5778
|
+
}
|
|
5779
|
+
}
|
|
5780
|
+
this.codeMode = codeModeEnabled;
|
|
5781
|
+
this._codeExecutorConfig = executorConfig;
|
|
5782
|
+
this._executorOptions = executorOptions;
|
|
5783
|
+
if (this.codeMode) {
|
|
5784
|
+
this._setupCodeModeConnector();
|
|
5785
|
+
}
|
|
4617
5786
|
}
|
|
4618
|
-
static fromDict(cfg) {
|
|
4619
|
-
return new _MCPClient(cfg);
|
|
5787
|
+
static fromDict(cfg, options) {
|
|
5788
|
+
return new _MCPClient(cfg, options);
|
|
4620
5789
|
}
|
|
4621
|
-
static fromConfigFile(path4) {
|
|
4622
|
-
return new _MCPClient(loadConfigFile(path4));
|
|
5790
|
+
static fromConfigFile(path4, options) {
|
|
5791
|
+
return new _MCPClient(loadConfigFile(path4), options);
|
|
4623
5792
|
}
|
|
4624
5793
|
/**
|
|
4625
5794
|
* Save configuration to a file (Node.js only)
|
|
@@ -4638,6 +5807,87 @@ var MCPClient = class _MCPClient extends BaseMCPClient {
|
|
|
4638
5807
|
createConnectorFromConfig(serverConfig) {
|
|
4639
5808
|
return createConnectorFromConfig(serverConfig);
|
|
4640
5809
|
}
|
|
5810
|
+
_setupCodeModeConnector() {
|
|
5811
|
+
logger.debug("Code mode connector initialized as internal meta server");
|
|
5812
|
+
const connector = new CodeModeConnector(this);
|
|
5813
|
+
const session = new MCPSession(connector);
|
|
5814
|
+
this.sessions["code_mode"] = session;
|
|
5815
|
+
this.activeSessions.push("code_mode");
|
|
5816
|
+
}
|
|
5817
|
+
_ensureCodeExecutor() {
|
|
5818
|
+
if (!this._codeExecutor) {
|
|
5819
|
+
const config2 = this._codeExecutorConfig;
|
|
5820
|
+
if (config2 instanceof BaseCodeExecutor) {
|
|
5821
|
+
this._codeExecutor = config2;
|
|
5822
|
+
} else if (typeof config2 === "function") {
|
|
5823
|
+
this._customCodeExecutor = config2;
|
|
5824
|
+
throw new Error(
|
|
5825
|
+
"Custom executor function should be handled in executeCode"
|
|
5826
|
+
);
|
|
5827
|
+
} else if (config2 === "e2b") {
|
|
5828
|
+
const opts = this._executorOptions;
|
|
5829
|
+
if (!opts?.apiKey) {
|
|
5830
|
+
logger.warn("E2B executor requires apiKey. Falling back to VM.");
|
|
5831
|
+
this._codeExecutor = new VMCodeExecutor(
|
|
5832
|
+
this,
|
|
5833
|
+
this._executorOptions
|
|
5834
|
+
);
|
|
5835
|
+
} else {
|
|
5836
|
+
this._codeExecutor = new E2BCodeExecutor(this, opts);
|
|
5837
|
+
}
|
|
5838
|
+
} else {
|
|
5839
|
+
this._codeExecutor = new VMCodeExecutor(
|
|
5840
|
+
this,
|
|
5841
|
+
this._executorOptions
|
|
5842
|
+
);
|
|
5843
|
+
}
|
|
5844
|
+
}
|
|
5845
|
+
return this._codeExecutor;
|
|
5846
|
+
}
|
|
5847
|
+
/**
|
|
5848
|
+
* Execute code in code mode
|
|
5849
|
+
*/
|
|
5850
|
+
async executeCode(code, timeout) {
|
|
5851
|
+
if (!this.codeMode) {
|
|
5852
|
+
throw new Error("Code execution mode is not enabled");
|
|
5853
|
+
}
|
|
5854
|
+
if (this._customCodeExecutor) {
|
|
5855
|
+
return this._customCodeExecutor(code, timeout);
|
|
5856
|
+
}
|
|
5857
|
+
return this._ensureCodeExecutor().execute(code, timeout);
|
|
5858
|
+
}
|
|
5859
|
+
/**
|
|
5860
|
+
* Search available tools (used by code mode)
|
|
5861
|
+
*/
|
|
5862
|
+
async searchTools(query = "", detailLevel = "full") {
|
|
5863
|
+
if (!this.codeMode) {
|
|
5864
|
+
throw new Error("Code execution mode is not enabled");
|
|
5865
|
+
}
|
|
5866
|
+
return this._ensureCodeExecutor().createSearchToolsFunction()(
|
|
5867
|
+
query,
|
|
5868
|
+
detailLevel
|
|
5869
|
+
);
|
|
5870
|
+
}
|
|
5871
|
+
/**
|
|
5872
|
+
* Override getServerNames to exclude internal code_mode server
|
|
5873
|
+
*/
|
|
5874
|
+
getServerNames() {
|
|
5875
|
+
const isCodeModeEnabled = this.codeMode;
|
|
5876
|
+
return super.getServerNames().filter((name) => {
|
|
5877
|
+
return !isCodeModeEnabled || name !== "code_mode";
|
|
5878
|
+
});
|
|
5879
|
+
}
|
|
5880
|
+
/**
|
|
5881
|
+
* Close the client and clean up resources including code executors.
|
|
5882
|
+
* This ensures E2B sandboxes and other resources are properly released.
|
|
5883
|
+
*/
|
|
5884
|
+
async close() {
|
|
5885
|
+
if (this._codeExecutor) {
|
|
5886
|
+
await this._codeExecutor.cleanup();
|
|
5887
|
+
this._codeExecutor = null;
|
|
5888
|
+
}
|
|
5889
|
+
await this.closeAllSessions();
|
|
5890
|
+
}
|
|
4641
5891
|
};
|
|
4642
5892
|
|
|
4643
5893
|
// index.ts
|
|
@@ -7486,3 +8736,8 @@ function WidgetDebugger({
|
|
|
7486
8736
|
));
|
|
7487
8737
|
}
|
|
7488
8738
|
__name(WidgetDebugger, "WidgetDebugger");
|
|
8739
|
+
|
|
8740
|
+
// src/client/prompts.ts
|
|
8741
|
+
var PROMPTS = {
|
|
8742
|
+
CODE_MODE: CODE_MODE_AGENT_PROMPT
|
|
8743
|
+
};
|