mcp-use 1.11.0-canary.3 → 1.11.0-canary.5
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-FDWI2WVM.js → chunk-454ZT2R7.js} +15 -91
- package/dist/{chunk-BONN23WU.js → chunk-52OY3IIW.js} +2 -2
- package/dist/chunk-6RVQ5RGR.js +12 -0
- package/dist/chunk-BAFXO6MT.js +101 -0
- package/dist/{chunk-TZ7SHSRY.js → chunk-FONZ4CWK.js} +1 -1
- package/dist/{chunk-WFPXUU4A.js → chunk-FQJ6Z3U6.js} +1 -1
- package/dist/{chunk-YIZWQ5PM.js → chunk-JRFJXT2T.js} +1 -1
- package/dist/{chunk-DKLRVWPJ.js → chunk-WK34REFK.js} +3 -8
- package/dist/{chunk-KZL3RCT6.js → chunk-ZP4QTLQC.js} +1419 -88
- package/dist/index.cjs +4745 -4443
- package/dist/index.js +26 -1035
- package/dist/src/agents/index.cjs +2881 -157
- package/dist/src/agents/index.d.ts +2 -0
- package/dist/src/agents/index.d.ts.map +1 -1
- package/dist/src/agents/index.js +6 -4
- package/dist/src/agents/mcp_agent.d.ts +59 -37
- package/dist/src/agents/mcp_agent.d.ts.map +1 -1
- package/dist/src/agents/remote.d.ts +25 -0
- package/dist/src/agents/remote.d.ts.map +1 -1
- package/dist/src/agents/types.d.ts +76 -0
- package/dist/src/agents/types.d.ts.map +1 -1
- package/dist/src/agents/utils/index.d.ts +1 -0
- package/dist/src/agents/utils/index.d.ts.map +1 -1
- package/dist/src/agents/utils/llm_provider.d.ts +53 -0
- package/dist/src/agents/utils/llm_provider.d.ts.map +1 -0
- package/dist/src/browser.cjs +1632 -201
- package/dist/src/browser.js +18 -7
- package/dist/src/client/base.d.ts +1 -0
- package/dist/src/client/base.d.ts.map +1 -1
- package/dist/src/client/prompts.js +4 -3
- package/dist/src/react/index.cjs +12 -3
- package/dist/src/react/index.js +5 -4
- package/dist/src/server/endpoints/mount-mcp.d.ts.map +1 -1
- package/dist/src/server/index.cjs +91 -64
- package/dist/src/server/index.js +93 -66
- package/dist/src/server/mcp-server.d.ts.map +1 -1
- package/dist/src/server/types/common.d.ts +26 -0
- package/dist/src/server/types/common.d.ts.map +1 -1
- package/dist/src/session.d.ts +2 -2
- package/dist/src/session.d.ts.map +1 -1
- package/dist/src/version.d.ts +1 -1
- package/dist/{tool-execution-helpers-HNASWGXY.js → tool-execution-helpers-3RAOCSJ4.js} +2 -2
- package/package.json +5 -4
- /package/dist/{chunk-EW4MJSHA.js → chunk-H4BZVTGK.js} +0 -0
package/dist/src/browser.cjs
CHANGED
|
@@ -35,9 +35,9 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
35
35
|
async function getNodeModules() {
|
|
36
36
|
if (typeof process !== "undefined" && process.platform) {
|
|
37
37
|
try {
|
|
38
|
-
const
|
|
39
|
-
const
|
|
40
|
-
return { fs:
|
|
38
|
+
const fs2 = await import("fs");
|
|
39
|
+
const path2 = await import("path");
|
|
40
|
+
return { fs: fs2.default, path: path2.default };
|
|
41
41
|
} catch {
|
|
42
42
|
return { fs: null, path: null };
|
|
43
43
|
}
|
|
@@ -1062,10 +1062,14 @@ __export(browser_exports, {
|
|
|
1062
1062
|
Tel: () => Tel,
|
|
1063
1063
|
Telemetry: () => Telemetry,
|
|
1064
1064
|
VERSION: () => VERSION,
|
|
1065
|
+
createLLMFromString: () => createLLMFromString,
|
|
1065
1066
|
createReadableStreamFromGenerator: () => createReadableStreamFromGenerator,
|
|
1066
1067
|
getPackageVersion: () => getPackageVersion,
|
|
1068
|
+
getSupportedProviders: () => getSupportedProviders,
|
|
1069
|
+
isValidLLMString: () => isValidLLMString,
|
|
1067
1070
|
logger: () => logger,
|
|
1068
1071
|
onMcpAuthorization: () => onMcpAuthorization,
|
|
1072
|
+
parseLLMString: () => parseLLMString,
|
|
1069
1073
|
setBrowserTelemetrySource: () => setTelemetrySource,
|
|
1070
1074
|
setTelemetrySource: () => setTelemetrySource,
|
|
1071
1075
|
streamEventsToAISDK: () => streamEventsToAISDK,
|
|
@@ -1606,7 +1610,7 @@ __name(generateUUID, "generateUUID");
|
|
|
1606
1610
|
init_logging();
|
|
1607
1611
|
|
|
1608
1612
|
// src/version.ts
|
|
1609
|
-
var VERSION = "1.11.0-canary.
|
|
1613
|
+
var VERSION = "1.11.0-canary.5";
|
|
1610
1614
|
function getPackageVersion() {
|
|
1611
1615
|
return VERSION;
|
|
1612
1616
|
}
|
|
@@ -1927,26 +1931,26 @@ var Telemetry = class _Telemetry {
|
|
|
1927
1931
|
* Get or create user ID from filesystem (Node.js/Bun)
|
|
1928
1932
|
*/
|
|
1929
1933
|
_getUserIdFromFilesystem() {
|
|
1930
|
-
const
|
|
1934
|
+
const fs2 = require("fs");
|
|
1931
1935
|
const os = require("os");
|
|
1932
|
-
const
|
|
1936
|
+
const path2 = require("path");
|
|
1933
1937
|
if (!this._userIdPath) {
|
|
1934
|
-
this._userIdPath =
|
|
1935
|
-
this._getCacheHome(os,
|
|
1938
|
+
this._userIdPath = path2.join(
|
|
1939
|
+
this._getCacheHome(os, path2),
|
|
1936
1940
|
"mcp_use_3",
|
|
1937
1941
|
"telemetry_user_id"
|
|
1938
1942
|
);
|
|
1939
1943
|
}
|
|
1940
|
-
const isFirstTime = !
|
|
1944
|
+
const isFirstTime = !fs2.existsSync(this._userIdPath);
|
|
1941
1945
|
if (isFirstTime) {
|
|
1942
1946
|
logger.debug(`Creating user ID path: ${this._userIdPath}`);
|
|
1943
|
-
|
|
1947
|
+
fs2.mkdirSync(path2.dirname(this._userIdPath), { recursive: true });
|
|
1944
1948
|
const newUserId = generateUUID();
|
|
1945
|
-
|
|
1949
|
+
fs2.writeFileSync(this._userIdPath, newUserId);
|
|
1946
1950
|
logger.debug(`User ID path created: ${this._userIdPath}`);
|
|
1947
1951
|
return newUserId;
|
|
1948
1952
|
}
|
|
1949
|
-
return
|
|
1953
|
+
return fs2.readFileSync(this._userIdPath, "utf-8").trim();
|
|
1950
1954
|
}
|
|
1951
1955
|
/**
|
|
1952
1956
|
* Get or create user ID from localStorage (Browser)
|
|
@@ -1965,9 +1969,9 @@ var Telemetry = class _Telemetry {
|
|
|
1965
1969
|
return `session-${generateUUID()}`;
|
|
1966
1970
|
}
|
|
1967
1971
|
}
|
|
1968
|
-
_getCacheHome(os,
|
|
1972
|
+
_getCacheHome(os, path2) {
|
|
1969
1973
|
const envVar = process.env.XDG_CACHE_HOME;
|
|
1970
|
-
if (envVar &&
|
|
1974
|
+
if (envVar && path2.isAbsolute(envVar)) {
|
|
1971
1975
|
return envVar;
|
|
1972
1976
|
}
|
|
1973
1977
|
const platform = process.platform;
|
|
@@ -1977,11 +1981,11 @@ var Telemetry = class _Telemetry {
|
|
|
1977
1981
|
if (appdata) {
|
|
1978
1982
|
return appdata;
|
|
1979
1983
|
}
|
|
1980
|
-
return
|
|
1984
|
+
return path2.join(homeDir, "AppData", "Local");
|
|
1981
1985
|
} else if (platform === "darwin") {
|
|
1982
|
-
return
|
|
1986
|
+
return path2.join(homeDir, "Library", "Caches");
|
|
1983
1987
|
} else {
|
|
1984
|
-
return
|
|
1988
|
+
return path2.join(homeDir, ".cache");
|
|
1985
1989
|
}
|
|
1986
1990
|
}
|
|
1987
1991
|
async capture(event) {
|
|
@@ -2055,12 +2059,12 @@ var Telemetry = class _Telemetry {
|
|
|
2055
2059
|
return;
|
|
2056
2060
|
}
|
|
2057
2061
|
try {
|
|
2058
|
-
const
|
|
2059
|
-
const
|
|
2062
|
+
const fs2 = require("fs");
|
|
2063
|
+
const path2 = require("path");
|
|
2060
2064
|
const os = require("os");
|
|
2061
2065
|
if (!this._versionDownloadPath) {
|
|
2062
|
-
this._versionDownloadPath =
|
|
2063
|
-
this._getCacheHome(os,
|
|
2066
|
+
this._versionDownloadPath = path2.join(
|
|
2067
|
+
this._getCacheHome(os, path2),
|
|
2064
2068
|
"mcp_use",
|
|
2065
2069
|
"download_version"
|
|
2066
2070
|
);
|
|
@@ -2068,19 +2072,19 @@ var Telemetry = class _Telemetry {
|
|
|
2068
2072
|
const currentVersion = getPackageVersion();
|
|
2069
2073
|
let shouldTrack = false;
|
|
2070
2074
|
let firstDownload = false;
|
|
2071
|
-
if (!
|
|
2075
|
+
if (!fs2.existsSync(this._versionDownloadPath)) {
|
|
2072
2076
|
shouldTrack = true;
|
|
2073
2077
|
firstDownload = true;
|
|
2074
|
-
|
|
2078
|
+
fs2.mkdirSync(path2.dirname(this._versionDownloadPath), {
|
|
2075
2079
|
recursive: true
|
|
2076
2080
|
});
|
|
2077
|
-
|
|
2081
|
+
fs2.writeFileSync(this._versionDownloadPath, currentVersion);
|
|
2078
2082
|
} else {
|
|
2079
|
-
const savedVersion =
|
|
2083
|
+
const savedVersion = fs2.readFileSync(this._versionDownloadPath, "utf-8").trim();
|
|
2080
2084
|
if (currentVersion > savedVersion) {
|
|
2081
2085
|
shouldTrack = true;
|
|
2082
2086
|
firstDownload = false;
|
|
2083
|
-
|
|
2087
|
+
fs2.writeFileSync(this._versionDownloadPath, currentVersion);
|
|
2084
2088
|
}
|
|
2085
2089
|
}
|
|
2086
2090
|
if (shouldTrack) {
|
|
@@ -3152,7 +3156,7 @@ var MCPSession = class {
|
|
|
3152
3156
|
* Call a tool on the server.
|
|
3153
3157
|
*
|
|
3154
3158
|
* @param name - Name of the tool to call
|
|
3155
|
-
* @param args - Arguments to pass to the tool
|
|
3159
|
+
* @param args - Arguments to pass to the tool (defaults to empty object)
|
|
3156
3160
|
* @param options - Optional request options (timeout, progress handlers, etc.)
|
|
3157
3161
|
* @returns Result from the tool execution
|
|
3158
3162
|
*
|
|
@@ -3162,7 +3166,7 @@ var MCPSession = class {
|
|
|
3162
3166
|
* console.log(`Result: ${result.content[0].text}`);
|
|
3163
3167
|
* ```
|
|
3164
3168
|
*/
|
|
3165
|
-
async callTool(name, args, options) {
|
|
3169
|
+
async callTool(name, args = {}, options) {
|
|
3166
3170
|
return this.connector.callTool(name, args, options);
|
|
3167
3171
|
}
|
|
3168
3172
|
/**
|
|
@@ -3377,6 +3381,15 @@ var BaseMCPClient = class {
|
|
|
3377
3381
|
}
|
|
3378
3382
|
return session;
|
|
3379
3383
|
}
|
|
3384
|
+
requireSession(serverName) {
|
|
3385
|
+
const session = this.sessions[serverName];
|
|
3386
|
+
if (!session) {
|
|
3387
|
+
throw new Error(
|
|
3388
|
+
`Session '${serverName}' not found. Available sessions: ${this.activeSessions.join(", ") || "none"}`
|
|
3389
|
+
);
|
|
3390
|
+
}
|
|
3391
|
+
return session;
|
|
3392
|
+
}
|
|
3380
3393
|
getAllActiveSessions() {
|
|
3381
3394
|
return Object.fromEntries(
|
|
3382
3395
|
this.activeSessions.map((n) => [n, this.sessions[n]])
|
|
@@ -4453,102 +4466,1231 @@ var LangChainAdapter = class extends BaseAdapter {
|
|
|
4453
4466
|
logger.error(`Error executing MCP tool: ${err.message}`);
|
|
4454
4467
|
return `Error executing MCP tool: ${String(err)}`;
|
|
4455
4468
|
}
|
|
4456
|
-
}, "func")
|
|
4457
|
-
});
|
|
4458
|
-
return tool;
|
|
4469
|
+
}, "func")
|
|
4470
|
+
});
|
|
4471
|
+
return tool;
|
|
4472
|
+
}
|
|
4473
|
+
/**
|
|
4474
|
+
* Convert a single MCP resource into a LangChainJS structured tool.
|
|
4475
|
+
* Each resource becomes an async tool that returns its content when called.
|
|
4476
|
+
*/
|
|
4477
|
+
convertResource(mcpResource, connector) {
|
|
4478
|
+
const sanitizeName = /* @__PURE__ */ __name((name) => {
|
|
4479
|
+
return name.replace(/[^A-Za-z0-9_]+/g, "_").toLowerCase().replace(/^_+|_+$/g, "");
|
|
4480
|
+
}, "sanitizeName");
|
|
4481
|
+
const resourceName = sanitizeName(
|
|
4482
|
+
mcpResource.name || `resource_${mcpResource.uri}`
|
|
4483
|
+
);
|
|
4484
|
+
const resourceUri = mcpResource.uri;
|
|
4485
|
+
const tool = new import_tools.DynamicStructuredTool({
|
|
4486
|
+
name: resourceName,
|
|
4487
|
+
description: mcpResource.description || `Return the content of the resource located at URI ${resourceUri}.`,
|
|
4488
|
+
schema: import_zod2.z.object({}).optional(),
|
|
4489
|
+
// Resources take no arguments
|
|
4490
|
+
func: /* @__PURE__ */ __name(async () => {
|
|
4491
|
+
logger.debug(`Resource tool: "${resourceName}" called`);
|
|
4492
|
+
try {
|
|
4493
|
+
const result = await connector.readResource(resourceUri);
|
|
4494
|
+
if (result.contents && result.contents.length > 0) {
|
|
4495
|
+
return result.contents.map((content) => {
|
|
4496
|
+
if (typeof content === "string") {
|
|
4497
|
+
return content;
|
|
4498
|
+
}
|
|
4499
|
+
if (content.text) {
|
|
4500
|
+
return content.text;
|
|
4501
|
+
}
|
|
4502
|
+
if (content.uri) {
|
|
4503
|
+
return content.uri;
|
|
4504
|
+
}
|
|
4505
|
+
return JSON.stringify(content);
|
|
4506
|
+
}).join("\n");
|
|
4507
|
+
}
|
|
4508
|
+
return "Resource is empty or unavailable";
|
|
4509
|
+
} catch (err) {
|
|
4510
|
+
logger.error(`Error reading resource: ${err.message}`);
|
|
4511
|
+
return `Error reading resource: ${String(err)}`;
|
|
4512
|
+
}
|
|
4513
|
+
}, "func")
|
|
4514
|
+
});
|
|
4515
|
+
return tool;
|
|
4516
|
+
}
|
|
4517
|
+
/**
|
|
4518
|
+
* Convert a single MCP prompt into a LangChainJS structured tool.
|
|
4519
|
+
* The resulting tool executes getPrompt on the connector with the prompt's name
|
|
4520
|
+
* and the user-provided arguments (if any).
|
|
4521
|
+
*/
|
|
4522
|
+
convertPrompt(mcpPrompt, connector) {
|
|
4523
|
+
let argsSchema = import_zod2.z.object({}).optional();
|
|
4524
|
+
if (mcpPrompt.arguments && mcpPrompt.arguments.length > 0) {
|
|
4525
|
+
const schemaFields = {};
|
|
4526
|
+
for (const arg of mcpPrompt.arguments) {
|
|
4527
|
+
const zodType = import_zod2.z.string();
|
|
4528
|
+
if (arg.required !== false) {
|
|
4529
|
+
schemaFields[arg.name] = zodType;
|
|
4530
|
+
} else {
|
|
4531
|
+
schemaFields[arg.name] = zodType.optional();
|
|
4532
|
+
}
|
|
4533
|
+
}
|
|
4534
|
+
argsSchema = Object.keys(schemaFields).length > 0 ? import_zod2.z.object(schemaFields) : import_zod2.z.object({}).optional();
|
|
4535
|
+
}
|
|
4536
|
+
const tool = new import_tools.DynamicStructuredTool({
|
|
4537
|
+
name: mcpPrompt.name,
|
|
4538
|
+
description: mcpPrompt.description || "",
|
|
4539
|
+
schema: argsSchema,
|
|
4540
|
+
func: /* @__PURE__ */ __name(async (input) => {
|
|
4541
|
+
logger.debug(
|
|
4542
|
+
`Prompt tool: "${mcpPrompt.name}" called with args: ${JSON.stringify(input)}`
|
|
4543
|
+
);
|
|
4544
|
+
try {
|
|
4545
|
+
const result = await connector.getPrompt(mcpPrompt.name, input);
|
|
4546
|
+
if (result.messages && result.messages.length > 0) {
|
|
4547
|
+
return result.messages.map((msg) => {
|
|
4548
|
+
if (typeof msg === "string") {
|
|
4549
|
+
return msg;
|
|
4550
|
+
}
|
|
4551
|
+
if (msg.content) {
|
|
4552
|
+
return typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content);
|
|
4553
|
+
}
|
|
4554
|
+
return JSON.stringify(msg);
|
|
4555
|
+
}).join("\n");
|
|
4556
|
+
}
|
|
4557
|
+
return "Prompt returned no messages";
|
|
4558
|
+
} catch (err) {
|
|
4559
|
+
logger.error(`Error getting prompt: ${err.message}`);
|
|
4560
|
+
return `Error getting prompt: ${String(err)}`;
|
|
4561
|
+
}
|
|
4562
|
+
}, "func")
|
|
4563
|
+
});
|
|
4564
|
+
return tool;
|
|
4565
|
+
}
|
|
4566
|
+
};
|
|
4567
|
+
|
|
4568
|
+
// src/client.ts
|
|
4569
|
+
var import_node_fs2 = __toESM(require("fs"), 1);
|
|
4570
|
+
var import_node_path = __toESM(require("path"), 1);
|
|
4571
|
+
|
|
4572
|
+
// src/client/executors/base.ts
|
|
4573
|
+
init_logging();
|
|
4574
|
+
var BaseCodeExecutor = class {
|
|
4575
|
+
static {
|
|
4576
|
+
__name(this, "BaseCodeExecutor");
|
|
4577
|
+
}
|
|
4578
|
+
client;
|
|
4579
|
+
_connecting = false;
|
|
4580
|
+
constructor(client) {
|
|
4581
|
+
this.client = client;
|
|
4582
|
+
}
|
|
4583
|
+
/**
|
|
4584
|
+
* Ensure all configured MCP servers are connected before execution.
|
|
4585
|
+
* Prevents race conditions with a connection lock.
|
|
4586
|
+
*/
|
|
4587
|
+
async ensureServersConnected() {
|
|
4588
|
+
const configuredServers = this.client.getServerNames();
|
|
4589
|
+
const activeSessions = Object.keys(this.client.getAllActiveSessions());
|
|
4590
|
+
const missingServers = configuredServers.filter(
|
|
4591
|
+
(s) => !activeSessions.includes(s)
|
|
4592
|
+
);
|
|
4593
|
+
if (missingServers.length > 0 && !this._connecting) {
|
|
4594
|
+
this._connecting = true;
|
|
4595
|
+
try {
|
|
4596
|
+
logger.debug(
|
|
4597
|
+
`Connecting to configured servers for code execution: ${missingServers.join(", ")}`
|
|
4598
|
+
);
|
|
4599
|
+
await this.client.createAllSessions();
|
|
4600
|
+
} finally {
|
|
4601
|
+
this._connecting = false;
|
|
4602
|
+
}
|
|
4603
|
+
} else if (missingServers.length > 0 && this._connecting) {
|
|
4604
|
+
logger.debug("Waiting for ongoing server connection...");
|
|
4605
|
+
const startWait = Date.now();
|
|
4606
|
+
while (this._connecting && Date.now() - startWait < 5e3) {
|
|
4607
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
4608
|
+
}
|
|
4609
|
+
}
|
|
4610
|
+
}
|
|
4611
|
+
/**
|
|
4612
|
+
* Get tool namespace information from all active MCP sessions.
|
|
4613
|
+
* Filters out the internal code_mode server.
|
|
4614
|
+
*/
|
|
4615
|
+
getToolNamespaces() {
|
|
4616
|
+
const namespaces = [];
|
|
4617
|
+
const activeSessions = this.client.getAllActiveSessions();
|
|
4618
|
+
for (const [serverName, session] of Object.entries(activeSessions)) {
|
|
4619
|
+
if (serverName === "code_mode") continue;
|
|
4620
|
+
try {
|
|
4621
|
+
const connector = session.connector;
|
|
4622
|
+
let tools;
|
|
4623
|
+
try {
|
|
4624
|
+
tools = connector.tools;
|
|
4625
|
+
} catch (e) {
|
|
4626
|
+
logger.warn(`Tools not available for server ${serverName}: ${e}`);
|
|
4627
|
+
continue;
|
|
4628
|
+
}
|
|
4629
|
+
if (!tools || tools.length === 0) continue;
|
|
4630
|
+
namespaces.push({ serverName, tools, session });
|
|
4631
|
+
} catch (e) {
|
|
4632
|
+
logger.warn(`Failed to load tools for server ${serverName}: ${e}`);
|
|
4633
|
+
}
|
|
4634
|
+
}
|
|
4635
|
+
return namespaces;
|
|
4636
|
+
}
|
|
4637
|
+
/**
|
|
4638
|
+
* Create a search function for discovering available MCP tools.
|
|
4639
|
+
* Used by code execution environments to find tools at runtime.
|
|
4640
|
+
*/
|
|
4641
|
+
createSearchToolsFunction() {
|
|
4642
|
+
return async (query = "", detailLevel = "full") => {
|
|
4643
|
+
const allTools = [];
|
|
4644
|
+
const allNamespaces = /* @__PURE__ */ new Set();
|
|
4645
|
+
const queryLower = query.toLowerCase();
|
|
4646
|
+
const activeSessions = this.client.getAllActiveSessions();
|
|
4647
|
+
for (const [serverName, session] of Object.entries(activeSessions)) {
|
|
4648
|
+
if (serverName === "code_mode") continue;
|
|
4649
|
+
try {
|
|
4650
|
+
const tools = session.connector.tools;
|
|
4651
|
+
if (tools && tools.length > 0) {
|
|
4652
|
+
allNamespaces.add(serverName);
|
|
4653
|
+
}
|
|
4654
|
+
for (const tool of tools) {
|
|
4655
|
+
if (detailLevel === "names") {
|
|
4656
|
+
allTools.push({ name: tool.name, server: serverName });
|
|
4657
|
+
} else if (detailLevel === "descriptions") {
|
|
4658
|
+
allTools.push({
|
|
4659
|
+
name: tool.name,
|
|
4660
|
+
server: serverName,
|
|
4661
|
+
description: tool.description
|
|
4662
|
+
});
|
|
4663
|
+
} else {
|
|
4664
|
+
allTools.push({
|
|
4665
|
+
name: tool.name,
|
|
4666
|
+
server: serverName,
|
|
4667
|
+
description: tool.description,
|
|
4668
|
+
input_schema: tool.inputSchema
|
|
4669
|
+
});
|
|
4670
|
+
}
|
|
4671
|
+
}
|
|
4672
|
+
} catch (e) {
|
|
4673
|
+
logger.warn(`Failed to search tools in server ${serverName}: ${e}`);
|
|
4674
|
+
}
|
|
4675
|
+
}
|
|
4676
|
+
let filteredTools = allTools;
|
|
4677
|
+
if (query) {
|
|
4678
|
+
filteredTools = allTools.filter((tool) => {
|
|
4679
|
+
const nameMatch = tool.name.toLowerCase().includes(queryLower);
|
|
4680
|
+
const descMatch = tool.description?.toLowerCase().includes(queryLower);
|
|
4681
|
+
const serverMatch = tool.server.toLowerCase().includes(queryLower);
|
|
4682
|
+
return nameMatch || descMatch || serverMatch;
|
|
4683
|
+
});
|
|
4684
|
+
}
|
|
4685
|
+
return {
|
|
4686
|
+
meta: {
|
|
4687
|
+
total_tools: allTools.length,
|
|
4688
|
+
namespaces: Array.from(allNamespaces).sort(),
|
|
4689
|
+
result_count: filteredTools.length
|
|
4690
|
+
},
|
|
4691
|
+
results: filteredTools
|
|
4692
|
+
};
|
|
4693
|
+
};
|
|
4694
|
+
}
|
|
4695
|
+
};
|
|
4696
|
+
|
|
4697
|
+
// src/client/executors/e2b.ts
|
|
4698
|
+
init_logging();
|
|
4699
|
+
var E2BCodeExecutor = class extends BaseCodeExecutor {
|
|
4700
|
+
static {
|
|
4701
|
+
__name(this, "E2BCodeExecutor");
|
|
4702
|
+
}
|
|
4703
|
+
e2bApiKey;
|
|
4704
|
+
codeExecSandbox = null;
|
|
4705
|
+
SandboxClass = null;
|
|
4706
|
+
timeoutMs;
|
|
4707
|
+
constructor(client, options) {
|
|
4708
|
+
super(client);
|
|
4709
|
+
this.e2bApiKey = options.apiKey;
|
|
4710
|
+
this.timeoutMs = options.timeoutMs ?? 3e5;
|
|
4711
|
+
}
|
|
4712
|
+
/**
|
|
4713
|
+
* Lazy load E2B Sandbox class.
|
|
4714
|
+
* This allows the library to work without E2B installed.
|
|
4715
|
+
*/
|
|
4716
|
+
async ensureSandboxClass() {
|
|
4717
|
+
if (this.SandboxClass) return;
|
|
4718
|
+
try {
|
|
4719
|
+
const e2b = await import("@e2b/code-interpreter");
|
|
4720
|
+
this.SandboxClass = e2b.Sandbox;
|
|
4721
|
+
} catch (error) {
|
|
4722
|
+
throw new Error(
|
|
4723
|
+
"@e2b/code-interpreter is not installed. The E2B code executor requires this optional dependency. Install it with: yarn add @e2b/code-interpreter"
|
|
4724
|
+
);
|
|
4725
|
+
}
|
|
4726
|
+
}
|
|
4727
|
+
/**
|
|
4728
|
+
* Get or create a dedicated sandbox for code execution.
|
|
4729
|
+
*/
|
|
4730
|
+
async getOrCreateCodeExecSandbox() {
|
|
4731
|
+
if (this.codeExecSandbox) return this.codeExecSandbox;
|
|
4732
|
+
await this.ensureSandboxClass();
|
|
4733
|
+
logger.debug("Starting E2B sandbox for code execution...");
|
|
4734
|
+
this.codeExecSandbox = await this.SandboxClass.create("base", {
|
|
4735
|
+
apiKey: this.e2bApiKey,
|
|
4736
|
+
timeoutMs: this.timeoutMs
|
|
4737
|
+
});
|
|
4738
|
+
return this.codeExecSandbox;
|
|
4739
|
+
}
|
|
4740
|
+
/**
|
|
4741
|
+
* Generate the shim code that exposes tools to the sandbox environment.
|
|
4742
|
+
* Creates a bridge that intercepts tool calls and sends them back to host.
|
|
4743
|
+
*/
|
|
4744
|
+
generateShim(tools) {
|
|
4745
|
+
let shim = `
|
|
4746
|
+
// MCP Bridge Shim
|
|
4747
|
+
global.__callMcpTool = async (server, tool, args) => {
|
|
4748
|
+
const id = Math.random().toString(36).substring(7);
|
|
4749
|
+
console.log(JSON.stringify({
|
|
4750
|
+
type: '__MCP_TOOL_CALL__',
|
|
4751
|
+
id,
|
|
4752
|
+
server,
|
|
4753
|
+
tool,
|
|
4754
|
+
args
|
|
4755
|
+
}));
|
|
4756
|
+
|
|
4757
|
+
const resultPath = \`/tmp/mcp_result_\${id}.json\`;
|
|
4758
|
+
const fs = require('fs');
|
|
4759
|
+
|
|
4760
|
+
// Poll for result file
|
|
4761
|
+
let attempts = 0;
|
|
4762
|
+
while (attempts < 300) { // 30 seconds timeout
|
|
4763
|
+
if (fs.existsSync(resultPath)) {
|
|
4764
|
+
const content = fs.readFileSync(resultPath, 'utf8');
|
|
4765
|
+
const result = JSON.parse(content);
|
|
4766
|
+
fs.unlinkSync(resultPath); // Clean up
|
|
4767
|
+
|
|
4768
|
+
if (result.error) {
|
|
4769
|
+
throw new Error(result.error);
|
|
4770
|
+
}
|
|
4771
|
+
return result.data;
|
|
4772
|
+
}
|
|
4773
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
4774
|
+
attempts++;
|
|
4775
|
+
}
|
|
4776
|
+
throw new Error('Tool execution timed out');
|
|
4777
|
+
};
|
|
4778
|
+
|
|
4779
|
+
// Global search_tools helper
|
|
4780
|
+
global.search_tools = async (query, detailLevel = 'full') => {
|
|
4781
|
+
const allTools = ${JSON.stringify(
|
|
4782
|
+
Object.entries(tools).flatMap(
|
|
4783
|
+
([server, serverTools]) => serverTools.map((tool) => ({
|
|
4784
|
+
name: tool.name,
|
|
4785
|
+
description: tool.description,
|
|
4786
|
+
server,
|
|
4787
|
+
input_schema: tool.inputSchema
|
|
4788
|
+
}))
|
|
4789
|
+
)
|
|
4790
|
+
)};
|
|
4791
|
+
|
|
4792
|
+
const filtered = allTools.filter(tool => {
|
|
4793
|
+
if (!query) return true;
|
|
4794
|
+
const q = query.toLowerCase();
|
|
4795
|
+
return tool.name.toLowerCase().includes(q) ||
|
|
4796
|
+
(tool.description && tool.description.toLowerCase().includes(q));
|
|
4797
|
+
});
|
|
4798
|
+
|
|
4799
|
+
if (detailLevel === 'names') {
|
|
4800
|
+
return filtered.map(t => ({ name: t.name, server: t.server }));
|
|
4801
|
+
} else if (detailLevel === 'descriptions') {
|
|
4802
|
+
return filtered.map(t => ({ name: t.name, server: t.server, description: t.description }));
|
|
4803
|
+
}
|
|
4804
|
+
return filtered;
|
|
4805
|
+
};
|
|
4806
|
+
`;
|
|
4807
|
+
for (const [serverName, serverTools] of Object.entries(tools)) {
|
|
4808
|
+
if (!serverTools || serverTools.length === 0) continue;
|
|
4809
|
+
const safeServerName = serverName.replace(/[^a-zA-Z0-9_]/g, "_");
|
|
4810
|
+
shim += `
|
|
4811
|
+
global['${serverName}'] = {`;
|
|
4812
|
+
for (const tool of serverTools) {
|
|
4813
|
+
shim += `
|
|
4814
|
+
'${tool.name}': async (args) => await global.__callMcpTool('${serverName}', '${tool.name}', args),`;
|
|
4815
|
+
}
|
|
4816
|
+
shim += `
|
|
4817
|
+
};
|
|
4818
|
+
|
|
4819
|
+
// Also expose as safe name if different
|
|
4820
|
+
if ('${safeServerName}' !== '${serverName}') {
|
|
4821
|
+
global['${safeServerName}'] = global['${serverName}'];
|
|
4822
|
+
}
|
|
4823
|
+
`;
|
|
4824
|
+
}
|
|
4825
|
+
return shim;
|
|
4826
|
+
}
|
|
4827
|
+
/**
|
|
4828
|
+
* Build the tool catalog for the shim.
|
|
4829
|
+
* Returns a map of server names to their available tools.
|
|
4830
|
+
*/
|
|
4831
|
+
buildToolCatalog() {
|
|
4832
|
+
const catalog = {};
|
|
4833
|
+
const namespaces = this.getToolNamespaces();
|
|
4834
|
+
for (const { serverName, tools } of namespaces) {
|
|
4835
|
+
catalog[serverName] = tools;
|
|
4836
|
+
}
|
|
4837
|
+
return catalog;
|
|
4838
|
+
}
|
|
4839
|
+
/**
|
|
4840
|
+
* Execute JavaScript/TypeScript code in an E2B sandbox with MCP tool access.
|
|
4841
|
+
* Tool calls are proxied back to the host via the bridge pattern.
|
|
4842
|
+
*
|
|
4843
|
+
* @param code - Code to execute
|
|
4844
|
+
* @param timeout - Execution timeout in milliseconds (default: 30000)
|
|
4845
|
+
*/
|
|
4846
|
+
async execute(code, timeout = 3e4) {
|
|
4847
|
+
const startTime = Date.now();
|
|
4848
|
+
let result = null;
|
|
4849
|
+
let error = null;
|
|
4850
|
+
let logs = [];
|
|
4851
|
+
try {
|
|
4852
|
+
await this.ensureServersConnected();
|
|
4853
|
+
const sandbox = await this.getOrCreateCodeExecSandbox();
|
|
4854
|
+
const toolCatalog = this.buildToolCatalog();
|
|
4855
|
+
const shim = this.generateShim(toolCatalog);
|
|
4856
|
+
const wrappedCode = `
|
|
4857
|
+
${shim}
|
|
4858
|
+
|
|
4859
|
+
(async () => {
|
|
4860
|
+
try {
|
|
4861
|
+
const func = async () => {
|
|
4862
|
+
${code}
|
|
4863
|
+
};
|
|
4864
|
+
const result = await func();
|
|
4865
|
+
console.log('__MCP_RESULT_START__');
|
|
4866
|
+
console.log(JSON.stringify(result));
|
|
4867
|
+
console.log('__MCP_RESULT_END__');
|
|
4868
|
+
} catch (e) {
|
|
4869
|
+
console.error(e);
|
|
4870
|
+
process.exit(1);
|
|
4871
|
+
}
|
|
4872
|
+
})();
|
|
4873
|
+
`;
|
|
4874
|
+
const filename = `exec_${Date.now()}.js`;
|
|
4875
|
+
await sandbox.files.write(filename, wrappedCode);
|
|
4876
|
+
const execution = await sandbox.commands.run(`node ${filename}`, {
|
|
4877
|
+
timeoutMs: timeout,
|
|
4878
|
+
onStdout: /* @__PURE__ */ __name(async (data) => {
|
|
4879
|
+
try {
|
|
4880
|
+
const lines = data.split("\n");
|
|
4881
|
+
for (const line of lines) {
|
|
4882
|
+
if (line.trim().startsWith('{"type":"__MCP_TOOL_CALL__"')) {
|
|
4883
|
+
const call = JSON.parse(line);
|
|
4884
|
+
if (call.type === "__MCP_TOOL_CALL__") {
|
|
4885
|
+
try {
|
|
4886
|
+
logger.debug(
|
|
4887
|
+
`[E2B Bridge] Calling tool ${call.server}.${call.tool}`
|
|
4888
|
+
);
|
|
4889
|
+
const activeSessions = this.client.getAllActiveSessions();
|
|
4890
|
+
const session = activeSessions[call.server];
|
|
4891
|
+
if (!session) {
|
|
4892
|
+
throw new Error(`Server ${call.server} not found`);
|
|
4893
|
+
}
|
|
4894
|
+
const toolResult = await session.connector.callTool(
|
|
4895
|
+
call.tool,
|
|
4896
|
+
call.args
|
|
4897
|
+
);
|
|
4898
|
+
let extractedResult = toolResult;
|
|
4899
|
+
if (toolResult.content && toolResult.content.length > 0) {
|
|
4900
|
+
const item = toolResult.content[0];
|
|
4901
|
+
if (item.type === "text") {
|
|
4902
|
+
try {
|
|
4903
|
+
extractedResult = JSON.parse(item.text);
|
|
4904
|
+
} catch {
|
|
4905
|
+
extractedResult = item.text;
|
|
4906
|
+
}
|
|
4907
|
+
} else {
|
|
4908
|
+
extractedResult = item;
|
|
4909
|
+
}
|
|
4910
|
+
}
|
|
4911
|
+
const resultPath = `/tmp/mcp_result_${call.id}.json`;
|
|
4912
|
+
await sandbox.files.write(
|
|
4913
|
+
resultPath,
|
|
4914
|
+
JSON.stringify({ data: extractedResult })
|
|
4915
|
+
);
|
|
4916
|
+
} catch (err) {
|
|
4917
|
+
logger.error(
|
|
4918
|
+
`[E2B Bridge] Tool execution failed: ${err.message}`
|
|
4919
|
+
);
|
|
4920
|
+
const resultPath = `/tmp/mcp_result_${call.id}.json`;
|
|
4921
|
+
await sandbox.files.write(
|
|
4922
|
+
resultPath,
|
|
4923
|
+
JSON.stringify({
|
|
4924
|
+
error: err.message || String(err)
|
|
4925
|
+
})
|
|
4926
|
+
);
|
|
4927
|
+
}
|
|
4928
|
+
}
|
|
4929
|
+
}
|
|
4930
|
+
}
|
|
4931
|
+
} catch (e) {
|
|
4932
|
+
}
|
|
4933
|
+
}, "onStdout")
|
|
4934
|
+
});
|
|
4935
|
+
logs = [execution.stdout, execution.stderr].filter(Boolean);
|
|
4936
|
+
if (execution.exitCode !== 0) {
|
|
4937
|
+
error = execution.stderr || "Execution failed";
|
|
4938
|
+
} else {
|
|
4939
|
+
const stdout = execution.stdout;
|
|
4940
|
+
const startMarker = "__MCP_RESULT_START__";
|
|
4941
|
+
const endMarker = "__MCP_RESULT_END__";
|
|
4942
|
+
const startIndex = stdout.indexOf(startMarker);
|
|
4943
|
+
const endIndex = stdout.indexOf(endMarker);
|
|
4944
|
+
if (startIndex !== -1 && endIndex !== -1) {
|
|
4945
|
+
const jsonStr = stdout.substring(startIndex + startMarker.length, endIndex).trim();
|
|
4946
|
+
try {
|
|
4947
|
+
result = JSON.parse(jsonStr);
|
|
4948
|
+
} catch (e) {
|
|
4949
|
+
result = jsonStr;
|
|
4950
|
+
}
|
|
4951
|
+
logs = logs.map((log) => {
|
|
4952
|
+
let cleaned = log.replace(
|
|
4953
|
+
new RegExp(startMarker + "[\\s\\S]*?" + endMarker),
|
|
4954
|
+
"[Result captured]"
|
|
4955
|
+
);
|
|
4956
|
+
cleaned = cleaned.split("\n").filter((l) => !l.includes("__MCP_TOOL_CALL__")).join("\n");
|
|
4957
|
+
return cleaned;
|
|
4958
|
+
});
|
|
4959
|
+
}
|
|
4960
|
+
}
|
|
4961
|
+
} catch (e) {
|
|
4962
|
+
error = e.message || String(e);
|
|
4963
|
+
if (error && (error.includes("timeout") || error.includes("timed out"))) {
|
|
4964
|
+
error = "Script execution timed out";
|
|
4965
|
+
}
|
|
4966
|
+
}
|
|
4967
|
+
return {
|
|
4968
|
+
result,
|
|
4969
|
+
logs,
|
|
4970
|
+
error,
|
|
4971
|
+
execution_time: (Date.now() - startTime) / 1e3
|
|
4972
|
+
};
|
|
4973
|
+
}
|
|
4974
|
+
/**
|
|
4975
|
+
* Clean up the E2B sandbox.
|
|
4976
|
+
* Should be called when the executor is no longer needed.
|
|
4977
|
+
*/
|
|
4978
|
+
async cleanup() {
|
|
4979
|
+
if (this.codeExecSandbox) {
|
|
4980
|
+
try {
|
|
4981
|
+
await this.codeExecSandbox.kill();
|
|
4982
|
+
this.codeExecSandbox = null;
|
|
4983
|
+
logger.debug("E2B code execution sandbox stopped");
|
|
4984
|
+
} catch (error) {
|
|
4985
|
+
logger.error("Failed to stop E2B code execution sandbox:", error);
|
|
4986
|
+
}
|
|
4987
|
+
}
|
|
4988
|
+
}
|
|
4989
|
+
};
|
|
4990
|
+
|
|
4991
|
+
// src/client/executors/vm.ts
|
|
4992
|
+
init_logging();
|
|
4993
|
+
var vm = null;
|
|
4994
|
+
var vmCheckAttempted = false;
|
|
4995
|
+
function getVMModuleName() {
|
|
4996
|
+
return ["node", "vm"].join(":");
|
|
4997
|
+
}
|
|
4998
|
+
__name(getVMModuleName, "getVMModuleName");
|
|
4999
|
+
function tryLoadVM() {
|
|
5000
|
+
if (vmCheckAttempted) {
|
|
5001
|
+
return vm !== null;
|
|
5002
|
+
}
|
|
5003
|
+
vmCheckAttempted = true;
|
|
5004
|
+
try {
|
|
5005
|
+
const nodeRequire = typeof require !== "undefined" ? require : null;
|
|
5006
|
+
if (nodeRequire) {
|
|
5007
|
+
vm = nodeRequire(getVMModuleName());
|
|
5008
|
+
return true;
|
|
5009
|
+
}
|
|
5010
|
+
} catch (error) {
|
|
5011
|
+
logger.debug("node:vm module not available via require");
|
|
5012
|
+
}
|
|
5013
|
+
return false;
|
|
5014
|
+
}
|
|
5015
|
+
__name(tryLoadVM, "tryLoadVM");
|
|
5016
|
+
async function tryLoadVMAsync() {
|
|
5017
|
+
if (vm !== null) {
|
|
5018
|
+
return true;
|
|
5019
|
+
}
|
|
5020
|
+
if (!vmCheckAttempted) {
|
|
5021
|
+
if (tryLoadVM()) {
|
|
5022
|
+
return true;
|
|
5023
|
+
}
|
|
5024
|
+
}
|
|
5025
|
+
try {
|
|
5026
|
+
vm = await import(
|
|
5027
|
+
/* @vite-ignore */
|
|
5028
|
+
getVMModuleName()
|
|
5029
|
+
);
|
|
5030
|
+
return true;
|
|
5031
|
+
} catch (error) {
|
|
5032
|
+
logger.debug(
|
|
5033
|
+
"node:vm module not available in this environment (e.g., Deno)"
|
|
5034
|
+
);
|
|
5035
|
+
return false;
|
|
5036
|
+
}
|
|
5037
|
+
}
|
|
5038
|
+
__name(tryLoadVMAsync, "tryLoadVMAsync");
|
|
5039
|
+
var VMCodeExecutor = class extends BaseCodeExecutor {
|
|
5040
|
+
static {
|
|
5041
|
+
__name(this, "VMCodeExecutor");
|
|
5042
|
+
}
|
|
5043
|
+
defaultTimeout;
|
|
5044
|
+
memoryLimitMb;
|
|
5045
|
+
constructor(client, options) {
|
|
5046
|
+
super(client);
|
|
5047
|
+
this.defaultTimeout = options?.timeoutMs ?? 3e4;
|
|
5048
|
+
this.memoryLimitMb = options?.memoryLimitMb;
|
|
5049
|
+
tryLoadVM();
|
|
5050
|
+
}
|
|
5051
|
+
/**
|
|
5052
|
+
* Ensure VM module is loaded before execution
|
|
5053
|
+
*/
|
|
5054
|
+
async ensureVMLoaded() {
|
|
5055
|
+
if (vm !== null) {
|
|
5056
|
+
return;
|
|
5057
|
+
}
|
|
5058
|
+
const loaded = await tryLoadVMAsync();
|
|
5059
|
+
if (!loaded) {
|
|
5060
|
+
throw new Error(
|
|
5061
|
+
"node:vm module is not available in this environment. Please use E2B executor instead or run in a Node.js environment."
|
|
5062
|
+
);
|
|
5063
|
+
}
|
|
5064
|
+
}
|
|
5065
|
+
/**
|
|
5066
|
+
* Execute JavaScript/TypeScript code with access to MCP tools.
|
|
5067
|
+
*
|
|
5068
|
+
* @param code - Code to execute
|
|
5069
|
+
* @param timeout - Execution timeout in milliseconds (default: configured timeout or 30000)
|
|
5070
|
+
*/
|
|
5071
|
+
async execute(code, timeout) {
|
|
5072
|
+
const effectiveTimeout = timeout ?? this.defaultTimeout;
|
|
5073
|
+
await this.ensureVMLoaded();
|
|
5074
|
+
await this.ensureServersConnected();
|
|
5075
|
+
const logs = [];
|
|
5076
|
+
const startTime = Date.now();
|
|
5077
|
+
let result = null;
|
|
5078
|
+
let error = null;
|
|
5079
|
+
try {
|
|
5080
|
+
const context = await this._buildContext(logs);
|
|
5081
|
+
const wrappedCode = `
|
|
5082
|
+
(async () => {
|
|
5083
|
+
try {
|
|
5084
|
+
${code}
|
|
5085
|
+
} catch (e) {
|
|
5086
|
+
throw e;
|
|
5087
|
+
}
|
|
5088
|
+
})()
|
|
5089
|
+
`;
|
|
5090
|
+
const script = new vm.Script(wrappedCode, {
|
|
5091
|
+
filename: "agent_code.js"
|
|
5092
|
+
});
|
|
5093
|
+
const promise = script.runInNewContext(context, {
|
|
5094
|
+
timeout: effectiveTimeout,
|
|
5095
|
+
displayErrors: true
|
|
5096
|
+
});
|
|
5097
|
+
result = await promise;
|
|
5098
|
+
} catch (e) {
|
|
5099
|
+
error = e.message || String(e);
|
|
5100
|
+
if (e.code === "ERR_SCRIPT_EXECUTION_TIMEOUT" || e.message === "Script execution timed out." || typeof error === "string" && (error.includes("timed out") || error.includes("timeout"))) {
|
|
5101
|
+
error = "Script execution timed out";
|
|
5102
|
+
}
|
|
5103
|
+
if (e.stack) {
|
|
5104
|
+
logger.debug(`Code execution error stack: ${e.stack}`);
|
|
5105
|
+
}
|
|
5106
|
+
}
|
|
5107
|
+
const executionTime = (Date.now() - startTime) / 1e3;
|
|
5108
|
+
return {
|
|
5109
|
+
result,
|
|
5110
|
+
logs,
|
|
5111
|
+
error,
|
|
5112
|
+
execution_time: executionTime
|
|
5113
|
+
};
|
|
5114
|
+
}
|
|
5115
|
+
/**
|
|
5116
|
+
* Build the VM execution context with MCP tools and standard globals.
|
|
5117
|
+
*
|
|
5118
|
+
* @param logs - Array to capture console output
|
|
5119
|
+
*/
|
|
5120
|
+
async _buildContext(logs) {
|
|
5121
|
+
const logHandler = /* @__PURE__ */ __name((...args) => {
|
|
5122
|
+
logs.push(
|
|
5123
|
+
args.map(
|
|
5124
|
+
(arg) => typeof arg === "object" ? JSON.stringify(arg, null, 2) : String(arg)
|
|
5125
|
+
).join(" ")
|
|
5126
|
+
);
|
|
5127
|
+
}, "logHandler");
|
|
5128
|
+
const sandbox = {
|
|
5129
|
+
console: {
|
|
5130
|
+
log: logHandler,
|
|
5131
|
+
error: /* @__PURE__ */ __name((...args) => {
|
|
5132
|
+
logHandler("[ERROR]", ...args);
|
|
5133
|
+
}, "error"),
|
|
5134
|
+
warn: /* @__PURE__ */ __name((...args) => {
|
|
5135
|
+
logHandler("[WARN]", ...args);
|
|
5136
|
+
}, "warn"),
|
|
5137
|
+
info: logHandler,
|
|
5138
|
+
debug: logHandler
|
|
5139
|
+
},
|
|
5140
|
+
// Standard globals
|
|
5141
|
+
Object,
|
|
5142
|
+
Array,
|
|
5143
|
+
String,
|
|
5144
|
+
Number,
|
|
5145
|
+
Boolean,
|
|
5146
|
+
Date,
|
|
5147
|
+
Math,
|
|
5148
|
+
JSON,
|
|
5149
|
+
RegExp,
|
|
5150
|
+
Map,
|
|
5151
|
+
Set,
|
|
5152
|
+
Promise,
|
|
5153
|
+
parseInt,
|
|
5154
|
+
parseFloat,
|
|
5155
|
+
isNaN,
|
|
5156
|
+
isFinite,
|
|
5157
|
+
encodeURI,
|
|
5158
|
+
decodeURI,
|
|
5159
|
+
encodeURIComponent,
|
|
5160
|
+
decodeURIComponent,
|
|
5161
|
+
setTimeout,
|
|
5162
|
+
clearTimeout,
|
|
5163
|
+
// Helper for tools
|
|
5164
|
+
search_tools: this.createSearchToolsFunction(),
|
|
5165
|
+
__tool_namespaces: []
|
|
5166
|
+
};
|
|
5167
|
+
const toolNamespaces = {};
|
|
5168
|
+
const namespaceInfos = this.getToolNamespaces();
|
|
5169
|
+
for (const { serverName, tools, session } of namespaceInfos) {
|
|
5170
|
+
const serverNamespace = {};
|
|
5171
|
+
for (const tool of tools) {
|
|
5172
|
+
const toolName = tool.name;
|
|
5173
|
+
serverNamespace[toolName] = async (args) => {
|
|
5174
|
+
const result = await session.connector.callTool(toolName, args || {});
|
|
5175
|
+
if (result.content && result.content.length > 0) {
|
|
5176
|
+
const item = result.content[0];
|
|
5177
|
+
if (item.type === "text") {
|
|
5178
|
+
try {
|
|
5179
|
+
return JSON.parse(item.text);
|
|
5180
|
+
} catch {
|
|
5181
|
+
return item.text;
|
|
5182
|
+
}
|
|
5183
|
+
}
|
|
5184
|
+
return item;
|
|
5185
|
+
}
|
|
5186
|
+
return result;
|
|
5187
|
+
};
|
|
5188
|
+
}
|
|
5189
|
+
sandbox[serverName] = serverNamespace;
|
|
5190
|
+
toolNamespaces[serverName] = true;
|
|
5191
|
+
}
|
|
5192
|
+
sandbox.__tool_namespaces = Object.keys(toolNamespaces);
|
|
5193
|
+
return vm.createContext(sandbox);
|
|
5194
|
+
}
|
|
5195
|
+
/**
|
|
5196
|
+
* Clean up resources.
|
|
5197
|
+
* VM executor doesn't need cleanup, but method kept for interface consistency.
|
|
5198
|
+
*/
|
|
5199
|
+
async cleanup() {
|
|
5200
|
+
}
|
|
5201
|
+
};
|
|
5202
|
+
|
|
5203
|
+
// src/client/connectors/codeMode.ts
|
|
5204
|
+
var CodeModeConnector = class extends BaseConnector {
|
|
5205
|
+
static {
|
|
5206
|
+
__name(this, "CodeModeConnector");
|
|
5207
|
+
}
|
|
5208
|
+
mcpClient;
|
|
5209
|
+
_tools;
|
|
5210
|
+
constructor(client) {
|
|
5211
|
+
super();
|
|
5212
|
+
this.mcpClient = client;
|
|
5213
|
+
this.connected = true;
|
|
5214
|
+
this._tools = this._createToolsList();
|
|
5215
|
+
}
|
|
5216
|
+
async connect() {
|
|
5217
|
+
this.connected = true;
|
|
5218
|
+
}
|
|
5219
|
+
async disconnect() {
|
|
5220
|
+
this.connected = false;
|
|
5221
|
+
}
|
|
5222
|
+
get publicIdentifier() {
|
|
5223
|
+
return { name: "code_mode", version: "1.0.0" };
|
|
5224
|
+
}
|
|
5225
|
+
_createToolsList() {
|
|
5226
|
+
return [
|
|
5227
|
+
{
|
|
5228
|
+
name: "execute_code",
|
|
5229
|
+
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.",
|
|
5230
|
+
inputSchema: {
|
|
5231
|
+
type: "object",
|
|
5232
|
+
properties: {
|
|
5233
|
+
code: {
|
|
5234
|
+
type: "string",
|
|
5235
|
+
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"
|
|
5236
|
+
},
|
|
5237
|
+
timeout: {
|
|
5238
|
+
type: "number",
|
|
5239
|
+
description: "Execution timeout in milliseconds",
|
|
5240
|
+
default: 3e4
|
|
5241
|
+
}
|
|
5242
|
+
},
|
|
5243
|
+
required: ["code"]
|
|
5244
|
+
}
|
|
5245
|
+
},
|
|
5246
|
+
{
|
|
5247
|
+
name: "search_tools",
|
|
5248
|
+
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.",
|
|
5249
|
+
inputSchema: {
|
|
5250
|
+
type: "object",
|
|
5251
|
+
properties: {
|
|
5252
|
+
query: {
|
|
5253
|
+
type: "string",
|
|
5254
|
+
description: "Search query to filter tools by name or description",
|
|
5255
|
+
default: ""
|
|
5256
|
+
},
|
|
5257
|
+
detail_level: {
|
|
5258
|
+
type: "string",
|
|
5259
|
+
description: "Detail level: 'names', 'descriptions', or 'full'",
|
|
5260
|
+
enum: ["names", "descriptions", "full"],
|
|
5261
|
+
default: "full"
|
|
5262
|
+
}
|
|
5263
|
+
}
|
|
5264
|
+
}
|
|
5265
|
+
}
|
|
5266
|
+
];
|
|
5267
|
+
}
|
|
5268
|
+
// Override tools getter to return static list immediately
|
|
5269
|
+
get tools() {
|
|
5270
|
+
return this._tools;
|
|
5271
|
+
}
|
|
5272
|
+
async initialize() {
|
|
5273
|
+
this.toolsCache = this._tools;
|
|
5274
|
+
return { capabilities: {}, version: "1.0.0" };
|
|
5275
|
+
}
|
|
5276
|
+
async callTool(name, args) {
|
|
5277
|
+
if (name === "execute_code") {
|
|
5278
|
+
const code = args.code;
|
|
5279
|
+
const timeout = args.timeout || 3e4;
|
|
5280
|
+
const result = await this.mcpClient.executeCode(code, timeout);
|
|
5281
|
+
return {
|
|
5282
|
+
content: [
|
|
5283
|
+
{
|
|
5284
|
+
type: "text",
|
|
5285
|
+
text: JSON.stringify(result)
|
|
5286
|
+
}
|
|
5287
|
+
]
|
|
5288
|
+
};
|
|
5289
|
+
} else if (name === "search_tools") {
|
|
5290
|
+
const query = args.query || "";
|
|
5291
|
+
const detailLevel = args.detail_level;
|
|
5292
|
+
const result = await this.mcpClient.searchTools(
|
|
5293
|
+
query,
|
|
5294
|
+
detailLevel && detailLevel in ["names", "descriptions", "full"] ? detailLevel : "full"
|
|
5295
|
+
);
|
|
5296
|
+
return {
|
|
5297
|
+
content: [
|
|
5298
|
+
{
|
|
5299
|
+
type: "text",
|
|
5300
|
+
text: JSON.stringify(result)
|
|
5301
|
+
}
|
|
5302
|
+
]
|
|
5303
|
+
};
|
|
5304
|
+
}
|
|
5305
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
5306
|
+
}
|
|
5307
|
+
};
|
|
5308
|
+
|
|
5309
|
+
// src/config.ts
|
|
5310
|
+
var import_node_fs = require("fs");
|
|
5311
|
+
|
|
5312
|
+
// src/connectors/stdio.ts
|
|
5313
|
+
var import_node_process = __toESM(require("process"), 1);
|
|
5314
|
+
var import_client2 = require("@mcp-use/modelcontextprotocol-sdk/client/index.js");
|
|
5315
|
+
init_logging();
|
|
5316
|
+
|
|
5317
|
+
// src/task_managers/stdio.ts
|
|
5318
|
+
var import_stdio = require("@mcp-use/modelcontextprotocol-sdk/client/stdio.js");
|
|
5319
|
+
init_logging();
|
|
5320
|
+
var StdioConnectionManager = class extends ConnectionManager {
|
|
5321
|
+
static {
|
|
5322
|
+
__name(this, "StdioConnectionManager");
|
|
5323
|
+
}
|
|
5324
|
+
serverParams;
|
|
5325
|
+
errlog;
|
|
5326
|
+
_transport = null;
|
|
5327
|
+
/**
|
|
5328
|
+
* Create a new stdio connection manager.
|
|
5329
|
+
*
|
|
5330
|
+
* @param serverParams Parameters for the stdio server process.
|
|
5331
|
+
* @param errlog Stream to which the server's stderr should be piped.
|
|
5332
|
+
* Defaults to `process.stderr`.
|
|
5333
|
+
*/
|
|
5334
|
+
constructor(serverParams, errlog = process.stderr) {
|
|
5335
|
+
super();
|
|
5336
|
+
this.serverParams = serverParams;
|
|
5337
|
+
this.errlog = errlog;
|
|
5338
|
+
}
|
|
5339
|
+
/**
|
|
5340
|
+
* Establish the stdio connection by spawning the server process and starting
|
|
5341
|
+
* the SDK's transport. Returns the live `StdioClientTransport` instance.
|
|
5342
|
+
*/
|
|
5343
|
+
async establishConnection() {
|
|
5344
|
+
this._transport = new import_stdio.StdioClientTransport(this.serverParams);
|
|
5345
|
+
if (this._transport.stderr && typeof this._transport.stderr.pipe === "function") {
|
|
5346
|
+
this._transport.stderr.pipe(
|
|
5347
|
+
this.errlog
|
|
5348
|
+
);
|
|
5349
|
+
}
|
|
5350
|
+
logger.debug(`${this.constructor.name} connected successfully`);
|
|
5351
|
+
return this._transport;
|
|
5352
|
+
}
|
|
5353
|
+
/**
|
|
5354
|
+
* Close the stdio connection, making sure the transport cleans up the child
|
|
5355
|
+
* process and associated resources.
|
|
5356
|
+
*/
|
|
5357
|
+
async closeConnection(_connection) {
|
|
5358
|
+
if (this._transport) {
|
|
5359
|
+
try {
|
|
5360
|
+
await this._transport.close();
|
|
5361
|
+
} catch (e) {
|
|
5362
|
+
logger.warn(`Error closing stdio transport: ${e}`);
|
|
5363
|
+
} finally {
|
|
5364
|
+
this._transport = null;
|
|
5365
|
+
}
|
|
5366
|
+
}
|
|
5367
|
+
}
|
|
5368
|
+
};
|
|
5369
|
+
|
|
5370
|
+
// src/connectors/stdio.ts
|
|
5371
|
+
var StdioConnector = class extends BaseConnector {
|
|
5372
|
+
static {
|
|
5373
|
+
__name(this, "StdioConnector");
|
|
5374
|
+
}
|
|
5375
|
+
command;
|
|
5376
|
+
args;
|
|
5377
|
+
env;
|
|
5378
|
+
errlog;
|
|
5379
|
+
clientInfo;
|
|
5380
|
+
constructor({
|
|
5381
|
+
command = "npx",
|
|
5382
|
+
args = [],
|
|
5383
|
+
env,
|
|
5384
|
+
errlog = import_node_process.default.stderr,
|
|
5385
|
+
...rest
|
|
5386
|
+
} = {}) {
|
|
5387
|
+
super(rest);
|
|
5388
|
+
this.command = command;
|
|
5389
|
+
this.args = args;
|
|
5390
|
+
this.env = env;
|
|
5391
|
+
this.errlog = errlog;
|
|
5392
|
+
this.clientInfo = rest.clientInfo ?? {
|
|
5393
|
+
name: "stdio-connector",
|
|
5394
|
+
version: "1.0.0"
|
|
5395
|
+
};
|
|
5396
|
+
}
|
|
5397
|
+
/** Establish connection to the MCP implementation. */
|
|
5398
|
+
async connect() {
|
|
5399
|
+
if (this.connected) {
|
|
5400
|
+
logger.debug("Already connected to MCP implementation");
|
|
5401
|
+
return;
|
|
5402
|
+
}
|
|
5403
|
+
logger.debug(`Connecting to MCP implementation via stdio: ${this.command}`);
|
|
5404
|
+
try {
|
|
5405
|
+
let mergedEnv;
|
|
5406
|
+
if (this.env) {
|
|
5407
|
+
mergedEnv = {};
|
|
5408
|
+
for (const [key, value] of Object.entries(import_node_process.default.env)) {
|
|
5409
|
+
if (value !== void 0) {
|
|
5410
|
+
mergedEnv[key] = value;
|
|
5411
|
+
}
|
|
5412
|
+
}
|
|
5413
|
+
Object.assign(mergedEnv, this.env);
|
|
5414
|
+
}
|
|
5415
|
+
const serverParams = {
|
|
5416
|
+
command: this.command,
|
|
5417
|
+
args: this.args,
|
|
5418
|
+
env: mergedEnv
|
|
5419
|
+
};
|
|
5420
|
+
this.connectionManager = new StdioConnectionManager(
|
|
5421
|
+
serverParams,
|
|
5422
|
+
this.errlog
|
|
5423
|
+
);
|
|
5424
|
+
const transport = await this.connectionManager.start();
|
|
5425
|
+
const clientOptions = {
|
|
5426
|
+
...this.opts.clientOptions || {},
|
|
5427
|
+
capabilities: {
|
|
5428
|
+
...this.opts.clientOptions?.capabilities || {},
|
|
5429
|
+
roots: { listChanged: true },
|
|
5430
|
+
// Always advertise roots capability
|
|
5431
|
+
// Add sampling capability if callback is provided
|
|
5432
|
+
...this.opts.samplingCallback ? { sampling: {} } : {},
|
|
5433
|
+
// Add elicitation capability if callback is provided
|
|
5434
|
+
...this.opts.elicitationCallback ? { elicitation: { form: {}, url: {} } } : {}
|
|
5435
|
+
}
|
|
5436
|
+
};
|
|
5437
|
+
this.client = new import_client2.Client(this.clientInfo, clientOptions);
|
|
5438
|
+
await this.client.connect(transport);
|
|
5439
|
+
this.connected = true;
|
|
5440
|
+
this.setupNotificationHandler();
|
|
5441
|
+
this.setupRootsHandler();
|
|
5442
|
+
this.setupSamplingHandler();
|
|
5443
|
+
this.setupElicitationHandler();
|
|
5444
|
+
logger.debug(
|
|
5445
|
+
`Successfully connected to MCP implementation: ${this.command}`
|
|
5446
|
+
);
|
|
5447
|
+
this.trackConnectorInit({
|
|
5448
|
+
serverCommand: this.command,
|
|
5449
|
+
serverArgs: this.args,
|
|
5450
|
+
publicIdentifier: `${this.command} ${this.args.join(" ")}`
|
|
5451
|
+
});
|
|
5452
|
+
} catch (err) {
|
|
5453
|
+
logger.error(`Failed to connect to MCP implementation: ${err}`);
|
|
5454
|
+
await this.cleanupResources();
|
|
5455
|
+
throw err;
|
|
5456
|
+
}
|
|
5457
|
+
}
|
|
5458
|
+
get publicIdentifier() {
|
|
5459
|
+
return {
|
|
5460
|
+
type: "stdio",
|
|
5461
|
+
"command&args": `${this.command} ${this.args.join(" ")}`
|
|
5462
|
+
};
|
|
5463
|
+
}
|
|
5464
|
+
};
|
|
5465
|
+
|
|
5466
|
+
// src/config.ts
|
|
5467
|
+
function loadConfigFile(filepath) {
|
|
5468
|
+
const raw = (0, import_node_fs.readFileSync)(filepath, "utf-8");
|
|
5469
|
+
return JSON.parse(raw);
|
|
5470
|
+
}
|
|
5471
|
+
__name(loadConfigFile, "loadConfigFile");
|
|
5472
|
+
function createConnectorFromConfig(serverConfig, connectorOptions) {
|
|
5473
|
+
if ("command" in serverConfig && "args" in serverConfig) {
|
|
5474
|
+
return new StdioConnector({
|
|
5475
|
+
command: serverConfig.command,
|
|
5476
|
+
args: serverConfig.args,
|
|
5477
|
+
env: serverConfig.env,
|
|
5478
|
+
...connectorOptions
|
|
5479
|
+
});
|
|
5480
|
+
}
|
|
5481
|
+
if ("url" in serverConfig) {
|
|
5482
|
+
const transport = serverConfig.transport || "http";
|
|
5483
|
+
return new HttpConnector(serverConfig.url, {
|
|
5484
|
+
headers: serverConfig.headers,
|
|
5485
|
+
authToken: serverConfig.auth_token || serverConfig.authToken,
|
|
5486
|
+
// Only force SSE if explicitly requested
|
|
5487
|
+
preferSse: serverConfig.preferSse || transport === "sse",
|
|
5488
|
+
...connectorOptions
|
|
5489
|
+
});
|
|
5490
|
+
}
|
|
5491
|
+
throw new Error("Cannot determine connector type from config");
|
|
5492
|
+
}
|
|
5493
|
+
__name(createConnectorFromConfig, "createConnectorFromConfig");
|
|
5494
|
+
|
|
5495
|
+
// src/client.ts
|
|
5496
|
+
init_logging();
|
|
5497
|
+
var MCPClient = class _MCPClient extends BaseMCPClient {
|
|
5498
|
+
static {
|
|
5499
|
+
__name(this, "MCPClient");
|
|
5500
|
+
}
|
|
5501
|
+
/**
|
|
5502
|
+
* Get the mcp-use package version.
|
|
5503
|
+
* Works in all environments (Node.js, browser, Cloudflare Workers, Deno, etc.)
|
|
5504
|
+
*/
|
|
5505
|
+
static getPackageVersion() {
|
|
5506
|
+
return getPackageVersion();
|
|
5507
|
+
}
|
|
5508
|
+
codeMode = false;
|
|
5509
|
+
_codeExecutor = null;
|
|
5510
|
+
_customCodeExecutor = null;
|
|
5511
|
+
_codeExecutorConfig = "vm";
|
|
5512
|
+
_executorOptions;
|
|
5513
|
+
_samplingCallback;
|
|
5514
|
+
_elicitationCallback;
|
|
5515
|
+
constructor(config, options) {
|
|
5516
|
+
if (config) {
|
|
5517
|
+
if (typeof config === "string") {
|
|
5518
|
+
super(loadConfigFile(config));
|
|
5519
|
+
} else {
|
|
5520
|
+
super(config);
|
|
5521
|
+
}
|
|
5522
|
+
} else {
|
|
5523
|
+
super();
|
|
5524
|
+
}
|
|
5525
|
+
let codeModeEnabled = false;
|
|
5526
|
+
let executorConfig = "vm";
|
|
5527
|
+
let executorOptions;
|
|
5528
|
+
if (options?.codeMode) {
|
|
5529
|
+
if (typeof options.codeMode === "boolean") {
|
|
5530
|
+
codeModeEnabled = options.codeMode;
|
|
5531
|
+
} else {
|
|
5532
|
+
codeModeEnabled = options.codeMode.enabled;
|
|
5533
|
+
executorConfig = options.codeMode.executor ?? "vm";
|
|
5534
|
+
executorOptions = options.codeMode.executorOptions;
|
|
5535
|
+
}
|
|
5536
|
+
}
|
|
5537
|
+
this.codeMode = codeModeEnabled;
|
|
5538
|
+
this._codeExecutorConfig = executorConfig;
|
|
5539
|
+
this._executorOptions = executorOptions;
|
|
5540
|
+
this._samplingCallback = options?.samplingCallback;
|
|
5541
|
+
this._elicitationCallback = options?.elicitationCallback;
|
|
5542
|
+
if (this.codeMode) {
|
|
5543
|
+
this._setupCodeModeConnector();
|
|
5544
|
+
}
|
|
5545
|
+
this._trackClientInit();
|
|
5546
|
+
}
|
|
5547
|
+
_trackClientInit() {
|
|
5548
|
+
const servers = Object.keys(this.config.mcpServers ?? {});
|
|
5549
|
+
const hasSamplingCallback = !!this._samplingCallback;
|
|
5550
|
+
const hasElicitationCallback = !!this._elicitationCallback;
|
|
5551
|
+
Tel.getInstance().trackMCPClientInit({
|
|
5552
|
+
codeMode: this.codeMode,
|
|
5553
|
+
sandbox: false,
|
|
5554
|
+
// Sandbox not supported in TS yet
|
|
5555
|
+
allCallbacks: hasSamplingCallback && hasElicitationCallback,
|
|
5556
|
+
verify: false,
|
|
5557
|
+
// No verify option in TS client
|
|
5558
|
+
servers,
|
|
5559
|
+
numServers: servers.length,
|
|
5560
|
+
isBrowser: false
|
|
5561
|
+
// Node.js MCPClient
|
|
5562
|
+
}).catch((e) => logger.debug(`Failed to track MCPClient init: ${e}`));
|
|
5563
|
+
}
|
|
5564
|
+
static fromDict(cfg, options) {
|
|
5565
|
+
return new _MCPClient(cfg, options);
|
|
5566
|
+
}
|
|
5567
|
+
static fromConfigFile(path2, options) {
|
|
5568
|
+
return new _MCPClient(loadConfigFile(path2), options);
|
|
5569
|
+
}
|
|
5570
|
+
/**
|
|
5571
|
+
* Save configuration to a file (Node.js only)
|
|
5572
|
+
*/
|
|
5573
|
+
saveConfig(filepath) {
|
|
5574
|
+
const dir = import_node_path.default.dirname(filepath);
|
|
5575
|
+
if (!import_node_fs2.default.existsSync(dir)) {
|
|
5576
|
+
import_node_fs2.default.mkdirSync(dir, { recursive: true });
|
|
5577
|
+
}
|
|
5578
|
+
import_node_fs2.default.writeFileSync(filepath, JSON.stringify(this.config, null, 2), "utf-8");
|
|
5579
|
+
}
|
|
5580
|
+
/**
|
|
5581
|
+
* Create a connector from server configuration (Node.js version)
|
|
5582
|
+
* Supports all connector types including StdioConnector
|
|
5583
|
+
*/
|
|
5584
|
+
createConnectorFromConfig(serverConfig) {
|
|
5585
|
+
return createConnectorFromConfig(serverConfig, {
|
|
5586
|
+
samplingCallback: this._samplingCallback,
|
|
5587
|
+
elicitationCallback: this._elicitationCallback
|
|
5588
|
+
});
|
|
5589
|
+
}
|
|
5590
|
+
_setupCodeModeConnector() {
|
|
5591
|
+
logger.debug("Code mode connector initialized as internal meta server");
|
|
5592
|
+
const connector = new CodeModeConnector(this);
|
|
5593
|
+
const session = new MCPSession(connector);
|
|
5594
|
+
this.sessions["code_mode"] = session;
|
|
5595
|
+
this.activeSessions.push("code_mode");
|
|
5596
|
+
}
|
|
5597
|
+
_ensureCodeExecutor() {
|
|
5598
|
+
if (!this._codeExecutor) {
|
|
5599
|
+
const config = this._codeExecutorConfig;
|
|
5600
|
+
if (config instanceof BaseCodeExecutor) {
|
|
5601
|
+
this._codeExecutor = config;
|
|
5602
|
+
} else if (typeof config === "function") {
|
|
5603
|
+
this._customCodeExecutor = config;
|
|
5604
|
+
throw new Error(
|
|
5605
|
+
"Custom executor function should be handled in executeCode"
|
|
5606
|
+
);
|
|
5607
|
+
} else if (config === "e2b") {
|
|
5608
|
+
const opts = this._executorOptions;
|
|
5609
|
+
if (!opts?.apiKey) {
|
|
5610
|
+
logger.warn("E2B executor requires apiKey. Falling back to VM.");
|
|
5611
|
+
try {
|
|
5612
|
+
this._codeExecutor = new VMCodeExecutor(
|
|
5613
|
+
this,
|
|
5614
|
+
this._executorOptions
|
|
5615
|
+
);
|
|
5616
|
+
} catch (error) {
|
|
5617
|
+
throw new Error(
|
|
5618
|
+
"VM executor is not available in this environment and E2B API key is not provided. Please provide an E2B API key or run in a Node.js environment."
|
|
5619
|
+
);
|
|
5620
|
+
}
|
|
5621
|
+
} else {
|
|
5622
|
+
this._codeExecutor = new E2BCodeExecutor(this, opts);
|
|
5623
|
+
}
|
|
5624
|
+
} else {
|
|
5625
|
+
try {
|
|
5626
|
+
this._codeExecutor = new VMCodeExecutor(
|
|
5627
|
+
this,
|
|
5628
|
+
this._executorOptions
|
|
5629
|
+
);
|
|
5630
|
+
} catch (error) {
|
|
5631
|
+
const e2bOpts = this._executorOptions;
|
|
5632
|
+
const e2bApiKey = e2bOpts?.apiKey || process.env.E2B_API_KEY;
|
|
5633
|
+
if (e2bApiKey) {
|
|
5634
|
+
logger.info(
|
|
5635
|
+
"VM executor not available in this environment. Falling back to E2B."
|
|
5636
|
+
);
|
|
5637
|
+
this._codeExecutor = new E2BCodeExecutor(this, {
|
|
5638
|
+
...e2bOpts,
|
|
5639
|
+
apiKey: e2bApiKey
|
|
5640
|
+
});
|
|
5641
|
+
} else {
|
|
5642
|
+
throw new Error(
|
|
5643
|
+
"VM executor is not available in this environment. Please provide an E2B API key via executorOptions or E2B_API_KEY environment variable, or run in a Node.js environment."
|
|
5644
|
+
);
|
|
5645
|
+
}
|
|
5646
|
+
}
|
|
5647
|
+
}
|
|
5648
|
+
}
|
|
5649
|
+
return this._codeExecutor;
|
|
4459
5650
|
}
|
|
4460
5651
|
/**
|
|
4461
|
-
*
|
|
4462
|
-
* Each resource becomes an async tool that returns its content when called.
|
|
5652
|
+
* Execute code in code mode
|
|
4463
5653
|
*/
|
|
4464
|
-
|
|
4465
|
-
|
|
4466
|
-
|
|
4467
|
-
}
|
|
4468
|
-
|
|
4469
|
-
|
|
5654
|
+
async executeCode(code, timeout) {
|
|
5655
|
+
if (!this.codeMode) {
|
|
5656
|
+
throw new Error("Code execution mode is not enabled");
|
|
5657
|
+
}
|
|
5658
|
+
if (this._customCodeExecutor) {
|
|
5659
|
+
return this._customCodeExecutor(code, timeout);
|
|
5660
|
+
}
|
|
5661
|
+
return this._ensureCodeExecutor().execute(code, timeout);
|
|
5662
|
+
}
|
|
5663
|
+
/**
|
|
5664
|
+
* Search available tools (used by code mode)
|
|
5665
|
+
*/
|
|
5666
|
+
async searchTools(query = "", detailLevel = "full") {
|
|
5667
|
+
if (!this.codeMode) {
|
|
5668
|
+
throw new Error("Code execution mode is not enabled");
|
|
5669
|
+
}
|
|
5670
|
+
return this._ensureCodeExecutor().createSearchToolsFunction()(
|
|
5671
|
+
query,
|
|
5672
|
+
detailLevel
|
|
4470
5673
|
);
|
|
4471
|
-
|
|
4472
|
-
|
|
4473
|
-
|
|
4474
|
-
|
|
4475
|
-
|
|
4476
|
-
|
|
4477
|
-
|
|
4478
|
-
|
|
4479
|
-
try {
|
|
4480
|
-
const result = await connector.readResource(resourceUri);
|
|
4481
|
-
if (result.contents && result.contents.length > 0) {
|
|
4482
|
-
return result.contents.map((content) => {
|
|
4483
|
-
if (typeof content === "string") {
|
|
4484
|
-
return content;
|
|
4485
|
-
}
|
|
4486
|
-
if (content.text) {
|
|
4487
|
-
return content.text;
|
|
4488
|
-
}
|
|
4489
|
-
if (content.uri) {
|
|
4490
|
-
return content.uri;
|
|
4491
|
-
}
|
|
4492
|
-
return JSON.stringify(content);
|
|
4493
|
-
}).join("\n");
|
|
4494
|
-
}
|
|
4495
|
-
return "Resource is empty or unavailable";
|
|
4496
|
-
} catch (err) {
|
|
4497
|
-
logger.error(`Error reading resource: ${err.message}`);
|
|
4498
|
-
return `Error reading resource: ${String(err)}`;
|
|
4499
|
-
}
|
|
4500
|
-
}, "func")
|
|
5674
|
+
}
|
|
5675
|
+
/**
|
|
5676
|
+
* Override getServerNames to exclude internal code_mode server
|
|
5677
|
+
*/
|
|
5678
|
+
getServerNames() {
|
|
5679
|
+
const isCodeModeEnabled = this.codeMode;
|
|
5680
|
+
return super.getServerNames().filter((name) => {
|
|
5681
|
+
return !isCodeModeEnabled || name !== "code_mode";
|
|
4501
5682
|
});
|
|
4502
|
-
return tool;
|
|
4503
5683
|
}
|
|
4504
5684
|
/**
|
|
4505
|
-
*
|
|
4506
|
-
*
|
|
4507
|
-
* and the user-provided arguments (if any).
|
|
5685
|
+
* Close the client and clean up resources including code executors.
|
|
5686
|
+
* This ensures E2B sandboxes and other resources are properly released.
|
|
4508
5687
|
*/
|
|
4509
|
-
|
|
4510
|
-
|
|
4511
|
-
|
|
4512
|
-
|
|
4513
|
-
for (const arg of mcpPrompt.arguments) {
|
|
4514
|
-
const zodType = import_zod2.z.string();
|
|
4515
|
-
if (arg.required !== false) {
|
|
4516
|
-
schemaFields[arg.name] = zodType;
|
|
4517
|
-
} else {
|
|
4518
|
-
schemaFields[arg.name] = zodType.optional();
|
|
4519
|
-
}
|
|
4520
|
-
}
|
|
4521
|
-
argsSchema = Object.keys(schemaFields).length > 0 ? import_zod2.z.object(schemaFields) : import_zod2.z.object({}).optional();
|
|
5688
|
+
async close() {
|
|
5689
|
+
if (this._codeExecutor) {
|
|
5690
|
+
await this._codeExecutor.cleanup();
|
|
5691
|
+
this._codeExecutor = null;
|
|
4522
5692
|
}
|
|
4523
|
-
|
|
4524
|
-
name: mcpPrompt.name,
|
|
4525
|
-
description: mcpPrompt.description || "",
|
|
4526
|
-
schema: argsSchema,
|
|
4527
|
-
func: /* @__PURE__ */ __name(async (input) => {
|
|
4528
|
-
logger.debug(
|
|
4529
|
-
`Prompt tool: "${mcpPrompt.name}" called with args: ${JSON.stringify(input)}`
|
|
4530
|
-
);
|
|
4531
|
-
try {
|
|
4532
|
-
const result = await connector.getPrompt(mcpPrompt.name, input);
|
|
4533
|
-
if (result.messages && result.messages.length > 0) {
|
|
4534
|
-
return result.messages.map((msg) => {
|
|
4535
|
-
if (typeof msg === "string") {
|
|
4536
|
-
return msg;
|
|
4537
|
-
}
|
|
4538
|
-
if (msg.content) {
|
|
4539
|
-
return typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content);
|
|
4540
|
-
}
|
|
4541
|
-
return JSON.stringify(msg);
|
|
4542
|
-
}).join("\n");
|
|
4543
|
-
}
|
|
4544
|
-
return "Prompt returned no messages";
|
|
4545
|
-
} catch (err) {
|
|
4546
|
-
logger.error(`Error getting prompt: ${err.message}`);
|
|
4547
|
-
return `Error getting prompt: ${String(err)}`;
|
|
4548
|
-
}
|
|
4549
|
-
}, "func")
|
|
4550
|
-
});
|
|
4551
|
-
return tool;
|
|
5693
|
+
await this.closeAllSessions();
|
|
4552
5694
|
}
|
|
4553
5695
|
};
|
|
4554
5696
|
|
|
@@ -5216,6 +6358,26 @@ var import_zod8 = require("zod");
|
|
|
5216
6358
|
init_logging();
|
|
5217
6359
|
var API_CHATS_ENDPOINT = "/api/v1/chats";
|
|
5218
6360
|
var API_CHAT_EXECUTE_ENDPOINT = "/api/v1/chats/{chat_id}/execute";
|
|
6361
|
+
function normalizeRemoteRunOptions(queryOrOptions, maxSteps, manageConnector, externalHistory, outputSchema) {
|
|
6362
|
+
if (typeof queryOrOptions === "object" && queryOrOptions !== null) {
|
|
6363
|
+
const options = queryOrOptions;
|
|
6364
|
+
return {
|
|
6365
|
+
query: options.prompt,
|
|
6366
|
+
maxSteps: options.maxSteps,
|
|
6367
|
+
manageConnector: options.manageConnector,
|
|
6368
|
+
externalHistory: options.externalHistory,
|
|
6369
|
+
outputSchema: options.schema
|
|
6370
|
+
};
|
|
6371
|
+
}
|
|
6372
|
+
return {
|
|
6373
|
+
query: queryOrOptions,
|
|
6374
|
+
maxSteps,
|
|
6375
|
+
manageConnector,
|
|
6376
|
+
externalHistory,
|
|
6377
|
+
outputSchema
|
|
6378
|
+
};
|
|
6379
|
+
}
|
|
6380
|
+
__name(normalizeRemoteRunOptions, "normalizeRemoteRunOptions");
|
|
5219
6381
|
var RemoteAgent = class {
|
|
5220
6382
|
static {
|
|
5221
6383
|
__name(this, "RemoteAgent");
|
|
@@ -5312,8 +6474,20 @@ var RemoteAgent = class {
|
|
|
5312
6474
|
throw new Error(`Failed to create chat session: ${String(e)}`);
|
|
5313
6475
|
}
|
|
5314
6476
|
}
|
|
5315
|
-
async run(
|
|
5316
|
-
|
|
6477
|
+
async run(queryOrOptions, maxSteps, manageConnector, externalHistory, outputSchema) {
|
|
6478
|
+
const {
|
|
6479
|
+
query,
|
|
6480
|
+
maxSteps: steps,
|
|
6481
|
+
externalHistory: history,
|
|
6482
|
+
outputSchema: schema
|
|
6483
|
+
} = normalizeRemoteRunOptions(
|
|
6484
|
+
queryOrOptions,
|
|
6485
|
+
maxSteps,
|
|
6486
|
+
manageConnector,
|
|
6487
|
+
externalHistory,
|
|
6488
|
+
outputSchema
|
|
6489
|
+
);
|
|
6490
|
+
if (history !== void 0) {
|
|
5317
6491
|
logger.warn("External history is not yet supported for remote execution");
|
|
5318
6492
|
}
|
|
5319
6493
|
try {
|
|
@@ -5324,10 +6498,10 @@ var RemoteAgent = class {
|
|
|
5324
6498
|
const chatId = this.chatId;
|
|
5325
6499
|
const executionPayload = {
|
|
5326
6500
|
query,
|
|
5327
|
-
max_steps:
|
|
6501
|
+
max_steps: steps ?? 10
|
|
5328
6502
|
};
|
|
5329
|
-
if (
|
|
5330
|
-
executionPayload.output_schema = this.pydanticToJsonSchema(
|
|
6503
|
+
if (schema) {
|
|
6504
|
+
executionPayload.output_schema = this.pydanticToJsonSchema(schema);
|
|
5331
6505
|
logger.info(`\u{1F527} Using structured output with schema`);
|
|
5332
6506
|
}
|
|
5333
6507
|
const headers = {
|
|
@@ -5401,8 +6575,8 @@ Raw error: ${result}`
|
|
|
5401
6575
|
);
|
|
5402
6576
|
}
|
|
5403
6577
|
}
|
|
5404
|
-
if (
|
|
5405
|
-
return this.parseStructuredResponse(result,
|
|
6578
|
+
if (schema) {
|
|
6579
|
+
return this.parseStructuredResponse(result, schema);
|
|
5406
6580
|
}
|
|
5407
6581
|
if (typeof result === "object" && result !== null && "result" in result) {
|
|
5408
6582
|
return result.result;
|
|
@@ -5427,9 +6601,9 @@ Raw error: ${result}`
|
|
|
5427
6601
|
}
|
|
5428
6602
|
}
|
|
5429
6603
|
// eslint-disable-next-line require-yield
|
|
5430
|
-
async *stream(
|
|
6604
|
+
async *stream(queryOrOptions, maxSteps, manageConnector, externalHistory, outputSchema) {
|
|
5431
6605
|
const result = await this.run(
|
|
5432
|
-
|
|
6606
|
+
queryOrOptions,
|
|
5433
6607
|
maxSteps,
|
|
5434
6608
|
manageConnector,
|
|
5435
6609
|
externalHistory,
|
|
@@ -5442,7 +6616,166 @@ Raw error: ${result}`
|
|
|
5442
6616
|
}
|
|
5443
6617
|
};
|
|
5444
6618
|
|
|
6619
|
+
// src/agents/utils/llm_provider.ts
|
|
6620
|
+
init_logging();
|
|
6621
|
+
var PROVIDER_CONFIG = {
|
|
6622
|
+
openai: {
|
|
6623
|
+
package: "@langchain/openai",
|
|
6624
|
+
className: "ChatOpenAI",
|
|
6625
|
+
envVars: ["OPENAI_API_KEY"],
|
|
6626
|
+
defaultModel: "gpt-4o"
|
|
6627
|
+
},
|
|
6628
|
+
anthropic: {
|
|
6629
|
+
package: "@langchain/anthropic",
|
|
6630
|
+
className: "ChatAnthropic",
|
|
6631
|
+
envVars: ["ANTHROPIC_API_KEY"],
|
|
6632
|
+
defaultModel: "claude-3-5-sonnet-20241022"
|
|
6633
|
+
},
|
|
6634
|
+
google: {
|
|
6635
|
+
package: "@langchain/google-genai",
|
|
6636
|
+
className: "ChatGoogleGenerativeAI",
|
|
6637
|
+
envVars: ["GOOGLE_API_KEY", "GOOGLE_GENERATIVE_AI_API_KEY"],
|
|
6638
|
+
defaultModel: "gemini-pro"
|
|
6639
|
+
},
|
|
6640
|
+
groq: {
|
|
6641
|
+
package: "@langchain/groq",
|
|
6642
|
+
className: "ChatGroq",
|
|
6643
|
+
envVars: ["GROQ_API_KEY"],
|
|
6644
|
+
defaultModel: "llama-3.1-70b-versatile"
|
|
6645
|
+
}
|
|
6646
|
+
};
|
|
6647
|
+
function parseLLMString(llmString) {
|
|
6648
|
+
const parts = llmString.split("/");
|
|
6649
|
+
if (parts.length !== 2) {
|
|
6650
|
+
throw new Error(
|
|
6651
|
+
`Invalid LLM string format. Expected 'provider/model', got '${llmString}'. Examples: 'openai/gpt-4', 'anthropic/claude-3-5-sonnet-20241022', 'google/gemini-pro', 'groq/llama-3.1-70b-versatile'`
|
|
6652
|
+
);
|
|
6653
|
+
}
|
|
6654
|
+
const [provider, model] = parts;
|
|
6655
|
+
if (!provider || !model) {
|
|
6656
|
+
throw new Error(
|
|
6657
|
+
`Invalid LLM string format. Both provider and model must be non-empty. Got '${llmString}'`
|
|
6658
|
+
);
|
|
6659
|
+
}
|
|
6660
|
+
const normalizedProvider = provider.toLowerCase();
|
|
6661
|
+
if (!(normalizedProvider in PROVIDER_CONFIG)) {
|
|
6662
|
+
const supportedProviders = Object.keys(PROVIDER_CONFIG).join(", ");
|
|
6663
|
+
throw new Error(
|
|
6664
|
+
`Unsupported LLM provider '${provider}'. Supported providers: ${supportedProviders}`
|
|
6665
|
+
);
|
|
6666
|
+
}
|
|
6667
|
+
return { provider: normalizedProvider, model };
|
|
6668
|
+
}
|
|
6669
|
+
__name(parseLLMString, "parseLLMString");
|
|
6670
|
+
function getAPIKey(provider, config) {
|
|
6671
|
+
if (config?.apiKey) {
|
|
6672
|
+
return config.apiKey;
|
|
6673
|
+
}
|
|
6674
|
+
const providerConfig = PROVIDER_CONFIG[provider];
|
|
6675
|
+
for (const envVar of providerConfig.envVars) {
|
|
6676
|
+
const apiKey = process.env[envVar];
|
|
6677
|
+
if (apiKey) {
|
|
6678
|
+
logger.debug(
|
|
6679
|
+
`Using API key from environment variable ${envVar} for provider ${provider}`
|
|
6680
|
+
);
|
|
6681
|
+
return apiKey;
|
|
6682
|
+
}
|
|
6683
|
+
}
|
|
6684
|
+
const envVarsStr = providerConfig.envVars.join(" or ");
|
|
6685
|
+
throw new Error(
|
|
6686
|
+
`API key not found for provider '${provider}'. Set ${envVarsStr} environment variable or pass apiKey in llmConfig. Example: new MCPAgent({ llm: '${provider}/model', llmConfig: { apiKey: 'your-key' } })`
|
|
6687
|
+
);
|
|
6688
|
+
}
|
|
6689
|
+
__name(getAPIKey, "getAPIKey");
|
|
6690
|
+
async function createLLMFromString(llmString, config) {
|
|
6691
|
+
logger.info(`Creating LLM from string: ${llmString}`);
|
|
6692
|
+
const { provider, model } = parseLLMString(llmString);
|
|
6693
|
+
const providerConfig = PROVIDER_CONFIG[provider];
|
|
6694
|
+
const apiKey = getAPIKey(provider, config);
|
|
6695
|
+
let providerModule;
|
|
6696
|
+
try {
|
|
6697
|
+
logger.debug(`Importing package ${providerConfig.package}...`);
|
|
6698
|
+
providerModule = await import(providerConfig.package);
|
|
6699
|
+
} catch (error) {
|
|
6700
|
+
if (error?.code === "MODULE_NOT_FOUND" || error?.message?.includes("Cannot find module") || error?.message?.includes("Cannot find package")) {
|
|
6701
|
+
throw new Error(
|
|
6702
|
+
`Package '${providerConfig.package}' is not installed. Install it with: npm install ${providerConfig.package} or yarn add ${providerConfig.package}`
|
|
6703
|
+
);
|
|
6704
|
+
}
|
|
6705
|
+
throw new Error(
|
|
6706
|
+
`Failed to import ${providerConfig.package}: ${error?.message || error}`
|
|
6707
|
+
);
|
|
6708
|
+
}
|
|
6709
|
+
const LLMClass = providerModule[providerConfig.className];
|
|
6710
|
+
if (!LLMClass) {
|
|
6711
|
+
throw new Error(
|
|
6712
|
+
`Could not find ${providerConfig.className} in package ${providerConfig.package}. This might be a version compatibility issue.`
|
|
6713
|
+
);
|
|
6714
|
+
}
|
|
6715
|
+
const llmConfig = {
|
|
6716
|
+
model,
|
|
6717
|
+
apiKey,
|
|
6718
|
+
...config
|
|
6719
|
+
};
|
|
6720
|
+
if (config?.apiKey) {
|
|
6721
|
+
delete llmConfig.apiKey;
|
|
6722
|
+
llmConfig.apiKey = apiKey;
|
|
6723
|
+
}
|
|
6724
|
+
if (provider === "anthropic") {
|
|
6725
|
+
llmConfig.model = model;
|
|
6726
|
+
} else if (provider === "google") {
|
|
6727
|
+
llmConfig.model = model;
|
|
6728
|
+
} else if (provider === "openai") {
|
|
6729
|
+
llmConfig.model = model;
|
|
6730
|
+
} else if (provider === "groq") {
|
|
6731
|
+
llmConfig.model = model;
|
|
6732
|
+
}
|
|
6733
|
+
try {
|
|
6734
|
+
const llmInstance = new LLMClass(llmConfig);
|
|
6735
|
+
logger.info(`Successfully created ${provider} LLM with model ${model}`);
|
|
6736
|
+
return llmInstance;
|
|
6737
|
+
} catch (error) {
|
|
6738
|
+
throw new Error(
|
|
6739
|
+
`Failed to instantiate ${providerConfig.className} with model '${model}': ${error?.message || error}`
|
|
6740
|
+
);
|
|
6741
|
+
}
|
|
6742
|
+
}
|
|
6743
|
+
__name(createLLMFromString, "createLLMFromString");
|
|
6744
|
+
function isValidLLMString(llmString) {
|
|
6745
|
+
try {
|
|
6746
|
+
parseLLMString(llmString);
|
|
6747
|
+
return true;
|
|
6748
|
+
} catch {
|
|
6749
|
+
return false;
|
|
6750
|
+
}
|
|
6751
|
+
}
|
|
6752
|
+
__name(isValidLLMString, "isValidLLMString");
|
|
6753
|
+
function getSupportedProviders() {
|
|
6754
|
+
return Object.keys(PROVIDER_CONFIG);
|
|
6755
|
+
}
|
|
6756
|
+
__name(getSupportedProviders, "getSupportedProviders");
|
|
6757
|
+
|
|
5445
6758
|
// src/agents/mcp_agent.ts
|
|
6759
|
+
function normalizeRunOptions(queryOrOptions, maxSteps, manageConnector, externalHistory, outputSchema) {
|
|
6760
|
+
if (typeof queryOrOptions === "object" && queryOrOptions !== null) {
|
|
6761
|
+
const options = queryOrOptions;
|
|
6762
|
+
return {
|
|
6763
|
+
query: options.prompt,
|
|
6764
|
+
maxSteps: options.maxSteps,
|
|
6765
|
+
manageConnector: options.manageConnector,
|
|
6766
|
+
externalHistory: options.externalHistory,
|
|
6767
|
+
outputSchema: options.schema
|
|
6768
|
+
};
|
|
6769
|
+
}
|
|
6770
|
+
return {
|
|
6771
|
+
query: queryOrOptions,
|
|
6772
|
+
maxSteps,
|
|
6773
|
+
manageConnector,
|
|
6774
|
+
externalHistory,
|
|
6775
|
+
outputSchema
|
|
6776
|
+
};
|
|
6777
|
+
}
|
|
6778
|
+
__name(normalizeRunOptions, "normalizeRunOptions");
|
|
5446
6779
|
var MCPAgent = class {
|
|
5447
6780
|
static {
|
|
5448
6781
|
__name(this, "MCPAgent");
|
|
@@ -5488,6 +6821,12 @@ var MCPAgent = class {
|
|
|
5488
6821
|
// Remote agent support
|
|
5489
6822
|
isRemote = false;
|
|
5490
6823
|
remoteAgent = null;
|
|
6824
|
+
// Simplified mode support
|
|
6825
|
+
isSimplifiedMode = false;
|
|
6826
|
+
llmString;
|
|
6827
|
+
llmConfig;
|
|
6828
|
+
mcpServersConfig;
|
|
6829
|
+
clientOwnedByAgent = false;
|
|
5491
6830
|
constructor(options) {
|
|
5492
6831
|
if (options.agentId) {
|
|
5493
6832
|
this.isRemote = true;
|
|
@@ -5521,9 +6860,36 @@ var MCPAgent = class {
|
|
|
5521
6860
|
"llm is required for local execution. For remote execution, provide agentId instead."
|
|
5522
6861
|
);
|
|
5523
6862
|
}
|
|
5524
|
-
|
|
5525
|
-
|
|
5526
|
-
|
|
6863
|
+
const isSimplifiedMode = typeof options.llm === "string";
|
|
6864
|
+
if (isSimplifiedMode) {
|
|
6865
|
+
this.isSimplifiedMode = true;
|
|
6866
|
+
this.llmString = options.llm;
|
|
6867
|
+
this.llmConfig = options.llmConfig;
|
|
6868
|
+
this.mcpServersConfig = options.mcpServers;
|
|
6869
|
+
if (!this.mcpServersConfig || Object.keys(this.mcpServersConfig).length === 0) {
|
|
6870
|
+
throw new Error(
|
|
6871
|
+
"Simplified mode requires 'mcpServers' configuration. Provide an object with server configurations, e.g., { filesystem: { command: 'npx', args: [...] } }"
|
|
6872
|
+
);
|
|
6873
|
+
}
|
|
6874
|
+
this.llm = void 0;
|
|
6875
|
+
this.client = void 0;
|
|
6876
|
+
this.clientOwnedByAgent = true;
|
|
6877
|
+
this.connectors = [];
|
|
6878
|
+
logger.info(
|
|
6879
|
+
`\u{1F3AF} Simplified mode enabled: LLM will be created from '${this.llmString}'`
|
|
6880
|
+
);
|
|
6881
|
+
} else {
|
|
6882
|
+
this.isSimplifiedMode = false;
|
|
6883
|
+
this.llm = options.llm;
|
|
6884
|
+
this.client = options.client;
|
|
6885
|
+
this.connectors = options.connectors ?? [];
|
|
6886
|
+
this.clientOwnedByAgent = false;
|
|
6887
|
+
if (!this.client && this.connectors.length === 0) {
|
|
6888
|
+
throw new Error(
|
|
6889
|
+
"Explicit mode requires either 'client' or at least one 'connector'. Alternatively, use simplified mode with 'llm' as a string and 'mcpServers' config."
|
|
6890
|
+
);
|
|
6891
|
+
}
|
|
6892
|
+
}
|
|
5527
6893
|
this.maxSteps = options.maxSteps ?? 5;
|
|
5528
6894
|
this.autoInitialize = options.autoInitialize ?? false;
|
|
5529
6895
|
this.memoryEnabled = options.memoryEnabled ?? true;
|
|
@@ -5536,28 +6902,30 @@ var MCPAgent = class {
|
|
|
5536
6902
|
this.useServerManager = options.useServerManager ?? false;
|
|
5537
6903
|
this.verbose = options.verbose ?? false;
|
|
5538
6904
|
this.observe = options.observe ?? true;
|
|
5539
|
-
if (!this.
|
|
5540
|
-
|
|
5541
|
-
|
|
5542
|
-
|
|
5543
|
-
|
|
5544
|
-
|
|
5545
|
-
|
|
5546
|
-
|
|
5547
|
-
|
|
5548
|
-
|
|
6905
|
+
if (!this.isSimplifiedMode) {
|
|
6906
|
+
if (this.useServerManager) {
|
|
6907
|
+
if (!this.client) {
|
|
6908
|
+
throw new Error(
|
|
6909
|
+
"'client' must be provided when 'useServerManager' is true."
|
|
6910
|
+
);
|
|
6911
|
+
}
|
|
6912
|
+
this.adapter = options.adapter ?? new LangChainAdapter(this.disallowedTools);
|
|
6913
|
+
this.serverManager = options.serverManagerFactory?.(this.client) ?? new ServerManager(this.client, this.adapter);
|
|
6914
|
+
} else {
|
|
6915
|
+
this.adapter = options.adapter ?? new LangChainAdapter(this.disallowedTools);
|
|
6916
|
+
}
|
|
6917
|
+
this.telemetry = Telemetry.getInstance();
|
|
6918
|
+
if (this.llm) {
|
|
6919
|
+
const [provider, name] = extractModelInfo(this.llm);
|
|
6920
|
+
this.modelProvider = provider;
|
|
6921
|
+
this.modelName = name;
|
|
6922
|
+
} else {
|
|
6923
|
+
this.modelProvider = "unknown";
|
|
6924
|
+
this.modelName = "unknown";
|
|
5549
6925
|
}
|
|
5550
|
-
this.adapter = options.adapter ?? new LangChainAdapter(this.disallowedTools);
|
|
5551
|
-
this.serverManager = options.serverManagerFactory?.(this.client) ?? new ServerManager(this.client, this.adapter);
|
|
5552
6926
|
} else {
|
|
5553
6927
|
this.adapter = options.adapter ?? new LangChainAdapter(this.disallowedTools);
|
|
5554
|
-
|
|
5555
|
-
this.telemetry = Telemetry.getInstance();
|
|
5556
|
-
if (this.llm) {
|
|
5557
|
-
const [provider, name] = extractModelInfo(this.llm);
|
|
5558
|
-
this.modelProvider = provider;
|
|
5559
|
-
this.modelName = name;
|
|
5560
|
-
} else {
|
|
6928
|
+
this.telemetry = Telemetry.getInstance();
|
|
5561
6929
|
this.modelProvider = "unknown";
|
|
5562
6930
|
this.modelName = "unknown";
|
|
5563
6931
|
}
|
|
@@ -5588,6 +6956,40 @@ var MCPAgent = class {
|
|
|
5588
6956
|
return;
|
|
5589
6957
|
}
|
|
5590
6958
|
logger.info("\u{1F680} Initializing MCP agent and connecting to services...");
|
|
6959
|
+
if (this.isSimplifiedMode) {
|
|
6960
|
+
logger.info(
|
|
6961
|
+
"\u{1F3AF} Simplified mode: Creating client and LLM from configuration..."
|
|
6962
|
+
);
|
|
6963
|
+
if (this.mcpServersConfig) {
|
|
6964
|
+
logger.info(
|
|
6965
|
+
`Creating MCPClient with ${Object.keys(this.mcpServersConfig).length} server(s)...`
|
|
6966
|
+
);
|
|
6967
|
+
this.client = new MCPClient({ mcpServers: this.mcpServersConfig });
|
|
6968
|
+
logger.info("\u2705 MCPClient created successfully");
|
|
6969
|
+
}
|
|
6970
|
+
if (this.llmString) {
|
|
6971
|
+
logger.info(`Creating LLM from string: ${this.llmString}...`);
|
|
6972
|
+
try {
|
|
6973
|
+
this.llm = await createLLMFromString(this.llmString, this.llmConfig);
|
|
6974
|
+
logger.info("\u2705 LLM created successfully");
|
|
6975
|
+
const [provider, name] = extractModelInfo(this.llm);
|
|
6976
|
+
this.modelProvider = provider;
|
|
6977
|
+
this.modelName = name;
|
|
6978
|
+
} catch (error) {
|
|
6979
|
+
throw new Error(
|
|
6980
|
+
`Failed to create LLM from string '${this.llmString}': ${error?.message || error}`
|
|
6981
|
+
);
|
|
6982
|
+
}
|
|
6983
|
+
}
|
|
6984
|
+
if (this.useServerManager) {
|
|
6985
|
+
if (!this.client) {
|
|
6986
|
+
throw new Error(
|
|
6987
|
+
"'client' must be available when 'useServerManager' is true."
|
|
6988
|
+
);
|
|
6989
|
+
}
|
|
6990
|
+
this.serverManager = new ServerManager(this.client, this.adapter);
|
|
6991
|
+
}
|
|
6992
|
+
}
|
|
5591
6993
|
this.callbacks = await this.observabilityManager.getCallbacks();
|
|
5592
6994
|
const handlerNames = await this.observabilityManager.getHandlerNames();
|
|
5593
6995
|
if (handlerNames.length > 0) {
|
|
@@ -6130,33 +7532,47 @@ var MCPAgent = class {
|
|
|
6130
7532
|
}
|
|
6131
7533
|
}
|
|
6132
7534
|
}
|
|
6133
|
-
async run(
|
|
6134
|
-
|
|
6135
|
-
return this.remoteAgent.run(
|
|
6136
|
-
query,
|
|
6137
|
-
maxSteps,
|
|
6138
|
-
manageConnector,
|
|
6139
|
-
externalHistory,
|
|
6140
|
-
outputSchema
|
|
6141
|
-
);
|
|
6142
|
-
}
|
|
6143
|
-
const generator = this.stream(
|
|
7535
|
+
async run(queryOrOptions, maxSteps, manageConnector, externalHistory, outputSchema) {
|
|
7536
|
+
const {
|
|
6144
7537
|
query,
|
|
7538
|
+
maxSteps: steps,
|
|
7539
|
+
manageConnector: manage,
|
|
7540
|
+
externalHistory: history,
|
|
7541
|
+
outputSchema: schema
|
|
7542
|
+
} = normalizeRunOptions(
|
|
7543
|
+
queryOrOptions,
|
|
6145
7544
|
maxSteps,
|
|
6146
7545
|
manageConnector,
|
|
6147
7546
|
externalHistory,
|
|
6148
7547
|
outputSchema
|
|
6149
7548
|
);
|
|
7549
|
+
if (this.isRemote && this.remoteAgent) {
|
|
7550
|
+
return this.remoteAgent.run(query, steps, manage, history, schema);
|
|
7551
|
+
}
|
|
7552
|
+
const generator = this.stream(query, steps, manage, history, schema);
|
|
6150
7553
|
return this._consumeAndReturn(generator);
|
|
6151
7554
|
}
|
|
6152
|
-
async *stream(
|
|
7555
|
+
async *stream(queryOrOptions, maxSteps, manageConnector = true, externalHistory, outputSchema) {
|
|
7556
|
+
const {
|
|
7557
|
+
query,
|
|
7558
|
+
maxSteps: steps,
|
|
7559
|
+
manageConnector: manage,
|
|
7560
|
+
externalHistory: history,
|
|
7561
|
+
outputSchema: schema
|
|
7562
|
+
} = normalizeRunOptions(
|
|
7563
|
+
queryOrOptions,
|
|
7564
|
+
maxSteps,
|
|
7565
|
+
manageConnector,
|
|
7566
|
+
externalHistory,
|
|
7567
|
+
outputSchema
|
|
7568
|
+
);
|
|
6153
7569
|
if (this.isRemote && this.remoteAgent) {
|
|
6154
7570
|
const result = await this.remoteAgent.run(
|
|
6155
7571
|
query,
|
|
6156
|
-
|
|
6157
|
-
|
|
6158
|
-
|
|
6159
|
-
|
|
7572
|
+
steps,
|
|
7573
|
+
manage,
|
|
7574
|
+
history,
|
|
7575
|
+
schema
|
|
6160
7576
|
);
|
|
6161
7577
|
return result;
|
|
6162
7578
|
}
|
|
@@ -6166,7 +7582,7 @@ var MCPAgent = class {
|
|
|
6166
7582
|
let finalOutput = null;
|
|
6167
7583
|
let stepsTaken = 0;
|
|
6168
7584
|
try {
|
|
6169
|
-
if (
|
|
7585
|
+
if (manage && !this._initialized) {
|
|
6170
7586
|
await this.initialize();
|
|
6171
7587
|
initializedHere = true;
|
|
6172
7588
|
} else if (!this._initialized && this.autoInitialize) {
|
|
@@ -6190,7 +7606,7 @@ var MCPAgent = class {
|
|
|
6190
7606
|
this._agentExecutor = this.createAgent();
|
|
6191
7607
|
}
|
|
6192
7608
|
}
|
|
6193
|
-
const historyToUse =
|
|
7609
|
+
const historyToUse = history ?? this.conversationHistory;
|
|
6194
7610
|
const langchainHistory = [];
|
|
6195
7611
|
for (const msg of historyToUse) {
|
|
6196
7612
|
if (this._isHumanMessageLike(msg) || this._isAIMessageLike(msg) || this._isToolMessageLike(msg)) {
|
|
@@ -6331,13 +7747,13 @@ var MCPAgent = class {
|
|
|
6331
7747
|
this.addToHistory(msg);
|
|
6332
7748
|
}
|
|
6333
7749
|
}
|
|
6334
|
-
if (
|
|
7750
|
+
if (schema && finalOutput) {
|
|
6335
7751
|
try {
|
|
6336
7752
|
logger.info("\u{1F527} Attempting structured output...");
|
|
6337
7753
|
const structuredResult = await this._attemptStructuredOutput(
|
|
6338
7754
|
finalOutput,
|
|
6339
7755
|
this.llm,
|
|
6340
|
-
|
|
7756
|
+
schema
|
|
6341
7757
|
);
|
|
6342
7758
|
if (this.memoryEnabled) {
|
|
6343
7759
|
this.addToHistory(
|
|
@@ -6363,7 +7779,7 @@ var MCPAgent = class {
|
|
|
6363
7779
|
return finalOutput || "No output generated";
|
|
6364
7780
|
} catch (e) {
|
|
6365
7781
|
logger.error(`\u274C Error running query: ${e}`);
|
|
6366
|
-
if (initializedHere &&
|
|
7782
|
+
if (initializedHere && manage) {
|
|
6367
7783
|
logger.info("\u{1F9F9} Cleaning up resources after error");
|
|
6368
7784
|
await this.close();
|
|
6369
7785
|
}
|
|
@@ -6393,9 +7809,9 @@ var MCPAgent = class {
|
|
|
6393
7809
|
maxStepsConfigured: this.maxSteps,
|
|
6394
7810
|
memoryEnabled: this.memoryEnabled,
|
|
6395
7811
|
useServerManager: this.useServerManager,
|
|
6396
|
-
maxStepsUsed:
|
|
6397
|
-
manageConnector,
|
|
6398
|
-
externalHistoryUsed:
|
|
7812
|
+
maxStepsUsed: steps ?? null,
|
|
7813
|
+
manageConnector: manage ?? true,
|
|
7814
|
+
externalHistoryUsed: history !== void 0,
|
|
6399
7815
|
stepsTaken,
|
|
6400
7816
|
toolsUsedCount: this.toolsUsedNames.length,
|
|
6401
7817
|
toolsUsedNames: this.toolsUsedNames,
|
|
@@ -6404,7 +7820,7 @@ var MCPAgent = class {
|
|
|
6404
7820
|
errorType: success ? null : "execution_error",
|
|
6405
7821
|
conversationHistoryLength
|
|
6406
7822
|
});
|
|
6407
|
-
if (
|
|
7823
|
+
if (manage && !this.client && initializedHere) {
|
|
6408
7824
|
logger.info("\u{1F9F9} Closing agent after stream completion");
|
|
6409
7825
|
await this.close();
|
|
6410
7826
|
}
|
|
@@ -6432,15 +7848,28 @@ var MCPAgent = class {
|
|
|
6432
7848
|
this._agentExecutor = null;
|
|
6433
7849
|
this._tools = [];
|
|
6434
7850
|
if (this.client) {
|
|
6435
|
-
|
|
6436
|
-
|
|
6437
|
-
|
|
7851
|
+
if (this.clientOwnedByAgent) {
|
|
7852
|
+
logger.info(
|
|
7853
|
+
"\u{1F504} Closing internally-created client (simplified mode) and cleaning up resources"
|
|
7854
|
+
);
|
|
7855
|
+
await this.client.close();
|
|
7856
|
+
this.sessions = {};
|
|
7857
|
+
this.client = void 0;
|
|
7858
|
+
} else {
|
|
7859
|
+
logger.info("\u{1F504} Closing client and cleaning up resources");
|
|
7860
|
+
await this.client.close();
|
|
7861
|
+
this.sessions = {};
|
|
7862
|
+
}
|
|
6438
7863
|
} else {
|
|
6439
7864
|
for (const connector of this.connectors) {
|
|
6440
7865
|
logger.info("\u{1F504} Disconnecting connector");
|
|
6441
7866
|
await connector.disconnect();
|
|
6442
7867
|
}
|
|
6443
7868
|
}
|
|
7869
|
+
if (this.isSimplifiedMode && this.llm) {
|
|
7870
|
+
logger.debug("\u{1F504} Clearing LLM reference (simplified mode)");
|
|
7871
|
+
this.llm = void 0;
|
|
7872
|
+
}
|
|
6444
7873
|
if ("connectorToolMap" in this.adapter) {
|
|
6445
7874
|
this.adapter = new LangChainAdapter();
|
|
6446
7875
|
}
|
|
@@ -6449,16 +7878,12 @@ var MCPAgent = class {
|
|
|
6449
7878
|
logger.info("\u{1F44B} Agent closed successfully");
|
|
6450
7879
|
}
|
|
6451
7880
|
}
|
|
6452
|
-
|
|
6453
|
-
* Yields with pretty-printed output for code mode.
|
|
6454
|
-
* This method formats and displays tool executions in a user-friendly way with syntax highlighting.
|
|
6455
|
-
*/
|
|
6456
|
-
async *prettyStreamEvents(query, maxSteps, manageConnector = true, externalHistory, outputSchema) {
|
|
7881
|
+
async *prettyStreamEvents(queryOrOptions, maxSteps, manageConnector = true, externalHistory, outputSchema) {
|
|
6457
7882
|
const { prettyStreamEvents: prettyStream } = await Promise.resolve().then(() => (init_display(), display_exports));
|
|
6458
7883
|
const finalResponse = "";
|
|
6459
7884
|
for await (const _ of prettyStream(
|
|
6460
7885
|
this.streamEvents(
|
|
6461
|
-
|
|
7886
|
+
queryOrOptions,
|
|
6462
7887
|
maxSteps,
|
|
6463
7888
|
manageConnector,
|
|
6464
7889
|
externalHistory,
|
|
@@ -6469,22 +7894,32 @@ var MCPAgent = class {
|
|
|
6469
7894
|
}
|
|
6470
7895
|
return finalResponse;
|
|
6471
7896
|
}
|
|
6472
|
-
|
|
6473
|
-
|
|
6474
|
-
|
|
6475
|
-
|
|
6476
|
-
|
|
7897
|
+
async *streamEvents(queryOrOptions, maxSteps, manageConnector = true, externalHistory, outputSchema) {
|
|
7898
|
+
const normalized = normalizeRunOptions(
|
|
7899
|
+
queryOrOptions,
|
|
7900
|
+
maxSteps,
|
|
7901
|
+
manageConnector,
|
|
7902
|
+
externalHistory,
|
|
7903
|
+
outputSchema
|
|
7904
|
+
);
|
|
7905
|
+
let { query } = normalized;
|
|
7906
|
+
const {
|
|
7907
|
+
maxSteps: steps,
|
|
7908
|
+
manageConnector: manage,
|
|
7909
|
+
externalHistory: history,
|
|
7910
|
+
outputSchema: schema
|
|
7911
|
+
} = normalized;
|
|
6477
7912
|
let initializedHere = false;
|
|
6478
7913
|
const startTime = Date.now();
|
|
6479
7914
|
let success = false;
|
|
6480
7915
|
let eventCount = 0;
|
|
6481
7916
|
let totalResponseLength = 0;
|
|
6482
7917
|
let finalResponse = "";
|
|
6483
|
-
if (
|
|
6484
|
-
query = this._enhanceQueryWithSchema(query,
|
|
7918
|
+
if (schema) {
|
|
7919
|
+
query = this._enhanceQueryWithSchema(query, schema);
|
|
6485
7920
|
}
|
|
6486
7921
|
try {
|
|
6487
|
-
if (
|
|
7922
|
+
if (manage && !this._initialized) {
|
|
6488
7923
|
await this.initialize();
|
|
6489
7924
|
initializedHere = true;
|
|
6490
7925
|
} else if (!this._initialized && this.autoInitialize) {
|
|
@@ -6495,14 +7930,14 @@ var MCPAgent = class {
|
|
|
6495
7930
|
if (!agentExecutor) {
|
|
6496
7931
|
throw new Error("MCP agent failed to initialize");
|
|
6497
7932
|
}
|
|
6498
|
-
this.maxSteps =
|
|
7933
|
+
this.maxSteps = steps ?? this.maxSteps;
|
|
6499
7934
|
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);
|
|
6500
7935
|
logger.info(`\u{1F4AC} Received query for streamEvents: '${display_query}'`);
|
|
6501
7936
|
if (this.memoryEnabled) {
|
|
6502
7937
|
logger.info(`\u{1F504} Adding user message to history: ${display_query}`);
|
|
6503
7938
|
this.addToHistory(new import_langchain2.HumanMessage({ content: query }));
|
|
6504
7939
|
}
|
|
6505
|
-
const historyToUse =
|
|
7940
|
+
const historyToUse = history ?? this.conversationHistory;
|
|
6506
7941
|
const langchainHistory = [];
|
|
6507
7942
|
for (const msg of historyToUse) {
|
|
6508
7943
|
if (this._isHumanMessageLike(msg) || this._isAIMessageLike(msg) || this._isToolMessageLike(msg)) {
|
|
@@ -6569,17 +8004,13 @@ var MCPAgent = class {
|
|
|
6569
8004
|
}
|
|
6570
8005
|
}
|
|
6571
8006
|
}
|
|
6572
|
-
if (
|
|
8007
|
+
if (schema && finalResponse) {
|
|
6573
8008
|
logger.info("\u{1F527} Attempting structured output conversion...");
|
|
6574
8009
|
try {
|
|
6575
8010
|
let conversionCompleted = false;
|
|
6576
8011
|
let conversionResult = null;
|
|
6577
8012
|
let conversionError = null;
|
|
6578
|
-
this._attemptStructuredOutput(
|
|
6579
|
-
finalResponse,
|
|
6580
|
-
this.llm,
|
|
6581
|
-
outputSchema
|
|
6582
|
-
).then((result) => {
|
|
8013
|
+
this._attemptStructuredOutput(finalResponse, this.llm, schema).then((result) => {
|
|
6583
8014
|
conversionCompleted = true;
|
|
6584
8015
|
conversionResult = result;
|
|
6585
8016
|
return result;
|
|
@@ -6634,7 +8065,7 @@ var MCPAgent = class {
|
|
|
6634
8065
|
success = true;
|
|
6635
8066
|
} catch (e) {
|
|
6636
8067
|
logger.error(`\u274C Error during streamEvents: ${e}`);
|
|
6637
|
-
if (initializedHere &&
|
|
8068
|
+
if (initializedHere && manage) {
|
|
6638
8069
|
logger.info(
|
|
6639
8070
|
"\u{1F9F9} Cleaning up resources after initialization error in streamEvents"
|
|
6640
8071
|
);
|
|
@@ -6665,15 +8096,15 @@ var MCPAgent = class {
|
|
|
6665
8096
|
maxStepsConfigured: this.maxSteps,
|
|
6666
8097
|
memoryEnabled: this.memoryEnabled,
|
|
6667
8098
|
useServerManager: this.useServerManager,
|
|
6668
|
-
maxStepsUsed:
|
|
6669
|
-
manageConnector,
|
|
6670
|
-
externalHistoryUsed:
|
|
8099
|
+
maxStepsUsed: steps ?? null,
|
|
8100
|
+
manageConnector: manage ?? true,
|
|
8101
|
+
externalHistoryUsed: history !== void 0,
|
|
6671
8102
|
response: `[STREAMED RESPONSE - ${totalResponseLength} chars]`,
|
|
6672
8103
|
executionTimeMs,
|
|
6673
8104
|
errorType: success ? null : "streaming_error",
|
|
6674
8105
|
conversationHistoryLength
|
|
6675
8106
|
});
|
|
6676
|
-
if (
|
|
8107
|
+
if (manage && !this.client && initializedHere) {
|
|
6677
8108
|
logger.info("\u{1F9F9} Closing agent after streamEvents completion");
|
|
6678
8109
|
await this.close();
|
|
6679
8110
|
}
|