mcp-use 1.3.4-canary.2 → 1.4.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.
Files changed (41) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/{chunk-6EHM3S3M.js → chunk-35A6O3YH.js} +52 -10
  3. package/dist/chunk-DSBKVAWD.js +263 -0
  4. package/dist/{chunk-TIUSJAAE.js → chunk-GRLCLVAK.js} +3 -254
  5. package/dist/{chunk-QKPVHYJU.js → chunk-RE7EYFDV.js} +1 -1
  6. package/dist/chunk-WERYJ6PF.js +209 -0
  7. package/dist/chunk-ZFZPZ4GE.js +21 -0
  8. package/dist/display-LIYVTGEU.js +350 -0
  9. package/dist/index.cjs +1539 -284
  10. package/dist/index.d.ts +5 -3
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +686 -22
  13. package/dist/src/agents/display.d.ts +54 -0
  14. package/dist/src/agents/display.d.ts.map +1 -0
  15. package/dist/src/agents/index.cjs +504 -10
  16. package/dist/src/agents/index.d.ts +1 -0
  17. package/dist/src/agents/index.d.ts.map +1 -1
  18. package/dist/src/agents/index.js +10 -18
  19. package/dist/src/agents/mcp_agent.d.ts +5 -0
  20. package/dist/src/agents/mcp_agent.d.ts.map +1 -1
  21. package/dist/src/browser.cjs +406 -10
  22. package/dist/src/browser.js +10 -8
  23. package/dist/src/client/codeExecutor.d.ts +6 -0
  24. package/dist/src/client/codeExecutor.d.ts.map +1 -0
  25. package/dist/src/client/connectors/codeMode.d.ts +27 -0
  26. package/dist/src/client/connectors/codeMode.d.ts.map +1 -0
  27. package/dist/src/client/executors/base.d.ts +56 -0
  28. package/dist/src/client/executors/base.d.ts.map +1 -0
  29. package/dist/src/client/executors/e2b.d.ts +46 -0
  30. package/dist/src/client/executors/e2b.d.ts.map +1 -0
  31. package/dist/src/client/executors/vm.d.ts +30 -0
  32. package/dist/src/client/executors/vm.d.ts.map +1 -0
  33. package/dist/src/client/prompts.cjs +401 -0
  34. package/dist/src/client/prompts.d.ts +13 -0
  35. package/dist/src/client/prompts.d.ts.map +1 -0
  36. package/dist/src/client/prompts.js +9 -0
  37. package/dist/src/client.d.ts +51 -4
  38. package/dist/src/client.d.ts.map +1 -1
  39. package/dist/src/react/index.js +3 -2
  40. package/dist/tsup.config.d.ts.map +1 -1
  41. 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
- if (Object.keys(this.sessions).length === 0) {
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
- this._tools = await LangChainAdapter.createTools(this.client);
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 sessions through client");
2981
- await this.client.closeAllSessions();
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: ${query}`);
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/config.ts
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 ConnectionManager = class {
3945
+ var BaseCodeExecutor = class {
3561
3946
  static {
3562
- __name(this, "ConnectionManager");
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
- * Start the connection manager and establish a connection.
3577
- *
3578
- * @returns The established connection.
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
- * Stop the connection manager and close the connection.
3955
+ * Ensure all configured MCP servers are connected before execution.
3956
+ * Prevents race conditions with a connection lock.
3596
3957
  */
3597
- async stop() {
3598
- if (this._task && this._abortController) {
3599
- logger.debug(`Cancelling ${this.constructor.name} task`);
3600
- this._abortController.abort();
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
- await this._task;
3603
- } catch (e) {
3604
- if (e instanceof Error && e.name === "AbortError") {
3605
- logger.debug(`${this.constructor.name} task aborted successfully`);
3606
- } else {
3607
- logger.warn(`Error stopping ${this.constructor.name} task: ${e}`);
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
- * The background task responsible for establishing and maintaining the
3627
- * connection until it is cancelled.
3983
+ * Get tool namespace information from all active MCP sessions.
3984
+ * Filters out the internal code_mode server.
3628
3985
  */
3629
- async connectionTask() {
3630
- logger.debug(`Running ${this.constructor.name} task`);
3631
- try {
3632
- this._connection = await this.establishConnection();
3633
- logger.debug(`${this.constructor.name} connected successfully`);
3634
- this._readyResolver();
3635
- await this.waitForAbort();
3636
- } catch (err) {
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
- await this.closeConnection(this._connection);
3644
- } catch (closeErr) {
3645
- logger.warn(
3646
- `Error closing connection in ${this.constructor.name}: ${closeErr}`
3647
- );
3995
+ tools = connector.tools;
3996
+ } catch (e) {
3997
+ logger.warn(`Tools not available for server ${serverName}: ${e}`);
3998
+ continue;
3648
3999
  }
3649
- this._connection = null;
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
- * Helper that returns a promise which resolves when the abort signal fires.
4009
+ * Create a search function for discovering available MCP tools.
4010
+ * Used by code execution environments to find tools at runtime.
3656
4011
  */
3657
- async waitForAbort() {
3658
- return new Promise((_resolve, _reject) => {
3659
- if (!this._abortController) {
3660
- return;
3661
- }
3662
- const signal = this._abortController.signal;
3663
- if (signal.aborted) {
3664
- _resolve();
3665
- return;
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
- const onAbort = /* @__PURE__ */ __name(() => {
3668
- signal.removeEventListener("abort", onAbort);
3669
- _resolve();
3670
- }, "onAbort");
3671
- signal.addEventListener("abort", onAbort);
3672
- });
4048
+ return allTools;
4049
+ };
3673
4050
  }
3674
4051
  };
3675
4052
 
3676
- // src/task_managers/sse.ts
3677
- var SseConnectionManager = class extends ConnectionManager {
4053
+ // src/client/executors/e2b.ts
4054
+ init_logging();
4055
+ var E2BCodeExecutor = class extends BaseCodeExecutor {
3678
4056
  static {
3679
- __name(this, "SseConnectionManager");
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
- * Create an SSE connection manager.
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
- constructor(url, opts) {
3691
- super();
3692
- this.url = typeof url === "string" ? new URL(url) : url;
3693
- this.opts = opts;
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
- * Spawn a new `SSEClientTransport` and start the connection.
4084
+ * Get or create a dedicated sandbox for code execution.
3697
4085
  */
3698
- async establishConnection() {
3699
- this._transport = new import_sse.SSEClientTransport(this.url, this.opts);
3700
- logger.debug(`${this.constructor.name} connected successfully`);
3701
- return this._transport;
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
- * Close the underlying transport and clean up resources.
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
- async closeConnection(_connection) {
3707
- if (this._transport) {
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._transport.close();
3710
- } catch (e) {
3711
- logger.warn(`Error closing SSE transport: ${e}`);
3712
- } finally {
3713
- this._transport = null;
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/task_managers/streamable_http.ts
3720
- var import_streamableHttp = require("@modelcontextprotocol/sdk/client/streamableHttp.js");
4347
+ // src/client/executors/vm.ts
4348
+ var import_node_vm = __toESM(require("vm"), 1);
3721
4349
  init_logging();
3722
- var StreamableHttpConnectionManager = class extends ConnectionManager {
4350
+ var VMCodeExecutor = class extends BaseCodeExecutor {
3723
4351
  static {
3724
- __name(this, "StreamableHttpConnectionManager");
4352
+ __name(this, "VMCodeExecutor");
3725
4353
  }
3726
- url;
3727
- opts;
3728
- _transport = null;
3729
- /**
3730
- * Create a Streamable HTTP connection manager.
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
- * Spawn a new `StreamableHTTPClientTransport` and return it.
3742
- * The Client.connect() method will handle starting the transport.
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 establishConnection() {
3745
- this._transport = new import_streamableHttp.StreamableHTTPClientTransport(this.url, this.opts);
3746
- logger.debug(`${this.constructor.name} created successfully`);
3747
- return this._transport;
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
- * Close the underlying transport and clean up resources.
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 closeConnection(_connection) {
3753
- if (this._transport) {
3754
- try {
3755
- await this._transport.close();
3756
- } catch (e) {
3757
- logger.warn(`Error closing Streamable HTTP transport: ${e}`);
3758
- } finally {
3759
- this._transport = null;
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
- * Get the session ID from the transport if available.
4491
+ * Clean up resources.
4492
+ * VM executor doesn't need cleanup, but method kept for interface consistency.
3765
4493
  */
3766
- get sessionId() {
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
- throw err;
5050
+ this._doneResolver();
3901
5051
  }
3902
5052
  }
3903
5053
  /**
3904
- * List resource templates from the server
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 listResourceTemplates(options) {
3910
- if (!this.client) {
3911
- throw new Error("MCP client is not connected");
3912
- }
3913
- logger.debug("Listing resource templates");
3914
- return await this.client.listResourceTemplates(void 0, options);
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
- /** Read a resource by URI. */
3917
- async readResource(uri, options) {
3918
- if (!this.client) {
3919
- throw new Error("MCP client is not connected");
3920
- }
3921
- logger.debug(`Reading resource ${uri}`);
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
- * Subscribe to resource updates
5084
+ * Create an SSE connection manager.
3927
5085
  *
3928
- * @param uri - URI of the resource to subscribe to
3929
- * @param options - Request options
5086
+ * @param url The SSE endpoint URL.
5087
+ * @param opts Optional transport options (auth, headers, etc.).
3930
5088
  */
3931
- async subscribeToResource(uri, options) {
3932
- if (!this.client) {
3933
- throw new Error("MCP client is not connected");
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
- * Unsubscribe from resource updates
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 unsubscribeFromResource(uri, options) {
3945
- if (!this.client) {
3946
- throw new Error("MCP client is not connected");
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
- * Helper to tear down the client & connection manager safely.
5103
+ * Close the underlying transport and clean up resources.
3991
5104
  */
3992
- async cleanupResources() {
3993
- const issues = [];
3994
- if (this.client) {
5105
+ async closeConnection(_connection) {
5106
+ if (this._transport) {
3995
5107
  try {
3996
- if (typeof this.client.close === "function") {
3997
- await this.client.close();
3998
- }
5108
+ await this._transport.close();
3999
5109
  } catch (e) {
4000
- const msg = `Error closing client: ${e}`;
4001
- logger.warn(msg);
4002
- issues.push(msg);
5110
+ logger.warn(`Error closing SSE transport: ${e}`);
4003
5111
  } finally {
4004
- this.client = null;
5112
+ this._transport = null;
4005
5113
  }
4006
5114
  }
4007
- if (this.connectionManager) {
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.connectionManager.stop();
5154
+ await this._transport.close();
4010
5155
  } catch (e) {
4011
- const msg = `Error stopping connection manager: ${e}`;
4012
- logger.warn(msg);
4013
- issues.push(msg);
5156
+ logger.warn(`Error closing Streamable HTTP transport: ${e}`);
4014
5157
  } finally {
4015
- this.connectionManager = null;
5158
+ this._transport = null;
4016
5159
  }
4017
5160
  }
4018
- this.toolsCache = null;
4019
- if (issues.length) {
4020
- logger.warn(`Resource cleanup finished with ${issues.length} issue(s)`);
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
- constructor(config2) {
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
+ };