mcp-use 1.10.6 → 1.11.0-canary.11
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/README.md +1 -1
- package/dist/.tsbuildinfo +1 -1
- package/dist/{chunk-KIWNNI6F.js → chunk-2NE5H4KG.js} +16 -2
- package/dist/{chunk-D5WOXLJ2.js → chunk-4QWS5ME6.js} +171 -11
- package/dist/chunk-7P2EMREO.js +101 -0
- package/dist/chunk-7PSUUT4A.js +1055 -0
- package/dist/{chunk-44DFBJUL.js → chunk-BOCIQYWG.js} +196 -496
- package/dist/chunk-BPZJIV4V.js +1873 -0
- package/dist/{chunk-EEUJZMOP.js → chunk-CVKKDXI3.js} +1 -1
- package/dist/chunk-DPK5NHDR.js +12 -0
- package/dist/{chunk-FDKY2O5P.js → chunk-EHCLF3JO.js} +443 -969
- package/dist/{chunk-34R6SIER.js → chunk-FRUZDWXH.js} +1 -1
- package/dist/chunk-GXNAXUDI.js +0 -0
- package/dist/{chunk-JH3ZOGLI.js → chunk-J3WTIYVV.js} +2 -2
- package/dist/{chunk-CPG2WZUL.js → chunk-JRGQRPTN.js} +1 -1
- package/dist/chunk-MFSO5PUW.js +1049 -0
- package/dist/chunk-SQSJ5NKY.js +1055 -0
- package/dist/chunk-T4EDAWDS.js +2638 -0
- package/dist/chunk-UWWLWLS2.js +62 -0
- package/dist/{chunk-BLWPCOUZ.js → chunk-V4YUDB7N.js} +3 -8
- package/dist/index.cjs +5065 -4608
- package/dist/index.d.ts +2 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +46 -1061
- package/dist/{langfuse-N5Y5BSXK.js → langfuse-74RGPTAH.js} +2 -2
- package/dist/notifications-FLGIFS56.js +9 -0
- package/dist/src/adapters/base.d.ts +44 -0
- package/dist/src/adapters/base.d.ts.map +1 -1
- package/dist/src/adapters/index.cjs +1346 -0
- package/dist/src/adapters/index.js +11 -0
- package/dist/src/adapters/langchain_adapter.d.ts +12 -1
- package/dist/src/adapters/langchain_adapter.d.ts.map +1 -1
- package/dist/src/agents/index.cjs +3141 -159
- 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 +12 -8
- 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 +1856 -423
- package/dist/src/browser.d.ts +1 -2
- package/dist/src/browser.d.ts.map +1 -1
- package/dist/src/browser.js +30 -19
- package/dist/src/client/base.d.ts +1 -0
- package/dist/src/client/base.d.ts.map +1 -1
- package/dist/src/client/browser.d.ts +2 -2
- package/dist/src/client/browser.d.ts.map +1 -1
- package/dist/src/client/prompts.cjs +1 -1
- package/dist/src/client/prompts.js +5 -4
- package/dist/src/client.cjs +3788 -0
- package/dist/src/client.d.ts +2 -0
- package/dist/src/client.d.ts.map +1 -1
- package/dist/src/client.js +23 -0
- package/dist/src/config.d.ts.map +1 -1
- package/dist/src/connectors/base.d.ts +8 -0
- package/dist/src/connectors/base.d.ts.map +1 -1
- package/dist/src/connectors/index.d.ts +0 -1
- package/dist/src/connectors/index.d.ts.map +1 -1
- package/dist/src/managers/server_manager.d.ts.map +1 -1
- package/dist/src/managers/tools/connect_mcp_server.d.ts.map +1 -1
- package/dist/src/react/index.cjs +259 -298
- package/dist/src/react/index.js +9 -8
- package/dist/src/react/types.d.ts +42 -4
- package/dist/src/react/types.d.ts.map +1 -1
- package/dist/src/react/useMcp.d.ts.map +1 -1
- package/dist/src/react/useWidget.d.ts +11 -7
- package/dist/src/react/useWidget.d.ts.map +1 -1
- package/dist/src/react/widget-types.d.ts +6 -2
- package/dist/src/react/widget-types.d.ts.map +1 -1
- package/dist/src/server/endpoints/mount-mcp.d.ts.map +1 -1
- package/dist/src/server/index.cjs +1288 -140
- package/dist/src/server/index.d.ts +2 -0
- package/dist/src/server/index.d.ts.map +1 -1
- package/dist/src/server/index.js +1183 -102
- package/dist/src/server/mcp-server.d.ts +5 -1
- package/dist/src/server/mcp-server.d.ts.map +1 -1
- package/dist/src/server/notifications/index.d.ts +1 -1
- package/dist/src/server/notifications/index.d.ts.map +1 -1
- package/dist/src/server/notifications/notification-registration.d.ts +51 -0
- package/dist/src/server/notifications/notification-registration.d.ts.map +1 -1
- package/dist/src/server/sessions/index.d.ts +3 -1
- package/dist/src/server/sessions/index.d.ts.map +1 -1
- package/dist/src/server/sessions/session-manager.d.ts +36 -19
- package/dist/src/server/sessions/session-manager.d.ts.map +1 -1
- package/dist/src/server/sessions/stores/filesystem.d.ts +121 -0
- package/dist/src/server/sessions/stores/filesystem.d.ts.map +1 -0
- package/dist/src/server/sessions/stores/index.d.ts +94 -0
- package/dist/src/server/sessions/stores/index.d.ts.map +1 -0
- package/dist/src/server/sessions/stores/memory.d.ts +82 -0
- package/dist/src/server/sessions/stores/memory.d.ts.map +1 -0
- package/dist/src/server/sessions/stores/redis.d.ts +164 -0
- package/dist/src/server/sessions/stores/redis.d.ts.map +1 -0
- package/dist/src/server/sessions/streams/index.d.ts +77 -0
- package/dist/src/server/sessions/streams/index.d.ts.map +1 -0
- package/dist/src/server/sessions/streams/memory.d.ts +76 -0
- package/dist/src/server/sessions/streams/memory.d.ts.map +1 -0
- package/dist/src/server/sessions/streams/redis.d.ts +146 -0
- package/dist/src/server/sessions/streams/redis.d.ts.map +1 -0
- package/dist/src/server/types/common.d.ts +105 -28
- package/dist/src/server/types/common.d.ts.map +1 -1
- package/dist/src/server/types/resource.d.ts +16 -0
- package/dist/src/server/types/resource.d.ts.map +1 -1
- package/dist/src/server/types/widget.d.ts +21 -2
- package/dist/src/server/types/widget.d.ts.map +1 -1
- package/dist/src/server/utils/response-helpers.d.ts +12 -6
- package/dist/src/server/utils/response-helpers.d.ts.map +1 -1
- package/dist/src/server/widgets/index.d.ts +1 -1
- package/dist/src/server/widgets/index.d.ts.map +1 -1
- package/dist/src/server/widgets/mount-widgets-dev.d.ts.map +1 -1
- package/dist/src/server/widgets/setup-widget-routes.d.ts.map +1 -1
- package/dist/src/server/widgets/ui-resource-registration.d.ts.map +1 -1
- package/dist/src/server/widgets/widget-helpers.d.ts +22 -0
- package/dist/src/server/widgets/widget-helpers.d.ts.map +1 -1
- package/dist/src/server/widgets/widget-types.d.ts +2 -0
- package/dist/src/server/widgets/widget-types.d.ts.map +1 -1
- package/dist/src/session.d.ts +16 -2
- package/dist/src/session.d.ts.map +1 -1
- package/dist/src/task_managers/index.d.ts +10 -1
- package/dist/src/task_managers/index.d.ts.map +1 -1
- package/dist/src/task_managers/sse.d.ts +34 -1
- package/dist/src/task_managers/sse.d.ts.map +1 -1
- package/dist/src/task_managers/streamable_http.d.ts +8 -2
- package/dist/src/task_managers/streamable_http.d.ts.map +1 -1
- package/dist/src/version.d.ts +1 -1
- package/dist/src/version.d.ts.map +1 -1
- package/dist/{tool-execution-helpers-4X6A63AS.js → tool-execution-helpers-3BYYGIA5.js} +3 -3
- package/dist/tsup.config.d.ts.map +1 -1
- package/package.json +47 -14
- package/dist/src/connectors/websocket.d.ts +0 -38
- package/dist/src/connectors/websocket.d.ts.map +0 -1
- package/dist/src/task_managers/websocket.d.ts +0 -18
- package/dist/src/task_managers/websocket.d.ts.map +0 -1
- /package/dist/{chunk-EW4MJSHA.js → chunk-LGDFGYRL.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
|
}
|
|
@@ -198,7 +198,7 @@ var init_logging = __esm({
|
|
|
198
198
|
timestamp({ format: "HH:mm:ss" }),
|
|
199
199
|
this.getFormatter()
|
|
200
200
|
),
|
|
201
|
-
transports: []
|
|
201
|
+
transports: [new winston.transports.Console()]
|
|
202
202
|
});
|
|
203
203
|
}
|
|
204
204
|
return this.instances[name];
|
|
@@ -1052,7 +1052,6 @@ __export(browser_exports, {
|
|
|
1052
1052
|
BrowserOAuthClientProvider: () => BrowserOAuthClientProvider,
|
|
1053
1053
|
BrowserTelemetry: () => Tel,
|
|
1054
1054
|
HttpConnector: () => HttpConnector,
|
|
1055
|
-
LangChainAdapter: () => LangChainAdapter,
|
|
1056
1055
|
Logger: () => Logger,
|
|
1057
1056
|
MCPAgent: () => MCPAgent,
|
|
1058
1057
|
MCPClient: () => BrowserMCPClient,
|
|
@@ -1062,11 +1061,14 @@ __export(browser_exports, {
|
|
|
1062
1061
|
Tel: () => Tel,
|
|
1063
1062
|
Telemetry: () => Telemetry,
|
|
1064
1063
|
VERSION: () => VERSION,
|
|
1065
|
-
|
|
1064
|
+
createLLMFromString: () => createLLMFromString,
|
|
1066
1065
|
createReadableStreamFromGenerator: () => createReadableStreamFromGenerator,
|
|
1067
1066
|
getPackageVersion: () => getPackageVersion,
|
|
1067
|
+
getSupportedProviders: () => getSupportedProviders,
|
|
1068
|
+
isValidLLMString: () => isValidLLMString,
|
|
1068
1069
|
logger: () => logger,
|
|
1069
1070
|
onMcpAuthorization: () => onMcpAuthorization,
|
|
1071
|
+
parseLLMString: () => parseLLMString,
|
|
1070
1072
|
setBrowserTelemetrySource: () => setTelemetrySource,
|
|
1071
1073
|
setTelemetrySource: () => setTelemetrySource,
|
|
1072
1074
|
streamEventsToAISDK: () => streamEventsToAISDK,
|
|
@@ -1209,6 +1211,7 @@ var SseConnectionManager = class extends ConnectionManager {
|
|
|
1209
1211
|
url;
|
|
1210
1212
|
opts;
|
|
1211
1213
|
_transport = null;
|
|
1214
|
+
reinitializing = false;
|
|
1212
1215
|
/**
|
|
1213
1216
|
* Create an SSE connection manager.
|
|
1214
1217
|
*
|
|
@@ -1221,12 +1224,53 @@ var SseConnectionManager = class extends ConnectionManager {
|
|
|
1221
1224
|
this.opts = opts;
|
|
1222
1225
|
}
|
|
1223
1226
|
/**
|
|
1224
|
-
* Spawn a new `SSEClientTransport` and
|
|
1227
|
+
* Spawn a new `SSEClientTransport` and wrap it with 404 handling.
|
|
1228
|
+
* Per MCP spec, clients MUST re-initialize when receiving 404 for stale sessions.
|
|
1225
1229
|
*/
|
|
1226
1230
|
async establishConnection() {
|
|
1227
|
-
|
|
1231
|
+
const transport = new import_sse.SSEClientTransport(this.url, this.opts);
|
|
1232
|
+
const originalSend = transport.send.bind(transport);
|
|
1233
|
+
transport.send = async (message) => {
|
|
1234
|
+
const sendMessage = /* @__PURE__ */ __name(async (msg) => {
|
|
1235
|
+
if (Array.isArray(msg)) {
|
|
1236
|
+
for (const singleMsg of msg) {
|
|
1237
|
+
await originalSend(singleMsg);
|
|
1238
|
+
}
|
|
1239
|
+
} else {
|
|
1240
|
+
await originalSend(msg);
|
|
1241
|
+
}
|
|
1242
|
+
}, "sendMessage");
|
|
1243
|
+
try {
|
|
1244
|
+
await sendMessage(message);
|
|
1245
|
+
} catch (error) {
|
|
1246
|
+
if (error?.code === 404 && transport.sessionId && !this.reinitializing) {
|
|
1247
|
+
logger.warn(
|
|
1248
|
+
`[SSE] Session not found (404), re-initializing per MCP spec...`
|
|
1249
|
+
);
|
|
1250
|
+
this.reinitializing = true;
|
|
1251
|
+
try {
|
|
1252
|
+
transport.sessionId = void 0;
|
|
1253
|
+
await this.reinitialize(transport);
|
|
1254
|
+
logger.info(`[SSE] Re-initialization successful, retrying request`);
|
|
1255
|
+
await sendMessage(message);
|
|
1256
|
+
} finally {
|
|
1257
|
+
this.reinitializing = false;
|
|
1258
|
+
}
|
|
1259
|
+
} else {
|
|
1260
|
+
throw error;
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
};
|
|
1264
|
+
this._transport = transport;
|
|
1228
1265
|
logger.debug(`${this.constructor.name} connected successfully`);
|
|
1229
|
-
return
|
|
1266
|
+
return transport;
|
|
1267
|
+
}
|
|
1268
|
+
/**
|
|
1269
|
+
* Re-initialize the transport with a new session
|
|
1270
|
+
* This is called when the server returns 404 for a stale session
|
|
1271
|
+
*/
|
|
1272
|
+
async reinitialize(transport) {
|
|
1273
|
+
logger.debug(`[SSE] Re-initialization triggered`);
|
|
1230
1274
|
}
|
|
1231
1275
|
/**
|
|
1232
1276
|
* Close the underlying transport and clean up resources.
|
|
@@ -1607,7 +1651,7 @@ __name(generateUUID, "generateUUID");
|
|
|
1607
1651
|
init_logging();
|
|
1608
1652
|
|
|
1609
1653
|
// src/version.ts
|
|
1610
|
-
var VERSION = "1.
|
|
1654
|
+
var VERSION = "1.11.0-canary.11";
|
|
1611
1655
|
function getPackageVersion() {
|
|
1612
1656
|
return VERSION;
|
|
1613
1657
|
}
|
|
@@ -1928,26 +1972,26 @@ var Telemetry = class _Telemetry {
|
|
|
1928
1972
|
* Get or create user ID from filesystem (Node.js/Bun)
|
|
1929
1973
|
*/
|
|
1930
1974
|
_getUserIdFromFilesystem() {
|
|
1931
|
-
const
|
|
1975
|
+
const fs2 = require("fs");
|
|
1932
1976
|
const os = require("os");
|
|
1933
|
-
const
|
|
1977
|
+
const path2 = require("path");
|
|
1934
1978
|
if (!this._userIdPath) {
|
|
1935
|
-
this._userIdPath =
|
|
1936
|
-
this._getCacheHome(os,
|
|
1979
|
+
this._userIdPath = path2.join(
|
|
1980
|
+
this._getCacheHome(os, path2),
|
|
1937
1981
|
"mcp_use_3",
|
|
1938
1982
|
"telemetry_user_id"
|
|
1939
1983
|
);
|
|
1940
1984
|
}
|
|
1941
|
-
const isFirstTime = !
|
|
1985
|
+
const isFirstTime = !fs2.existsSync(this._userIdPath);
|
|
1942
1986
|
if (isFirstTime) {
|
|
1943
1987
|
logger.debug(`Creating user ID path: ${this._userIdPath}`);
|
|
1944
|
-
|
|
1988
|
+
fs2.mkdirSync(path2.dirname(this._userIdPath), { recursive: true });
|
|
1945
1989
|
const newUserId = generateUUID();
|
|
1946
|
-
|
|
1990
|
+
fs2.writeFileSync(this._userIdPath, newUserId);
|
|
1947
1991
|
logger.debug(`User ID path created: ${this._userIdPath}`);
|
|
1948
1992
|
return newUserId;
|
|
1949
1993
|
}
|
|
1950
|
-
return
|
|
1994
|
+
return fs2.readFileSync(this._userIdPath, "utf-8").trim();
|
|
1951
1995
|
}
|
|
1952
1996
|
/**
|
|
1953
1997
|
* Get or create user ID from localStorage (Browser)
|
|
@@ -1966,9 +2010,9 @@ var Telemetry = class _Telemetry {
|
|
|
1966
2010
|
return `session-${generateUUID()}`;
|
|
1967
2011
|
}
|
|
1968
2012
|
}
|
|
1969
|
-
_getCacheHome(os,
|
|
2013
|
+
_getCacheHome(os, path2) {
|
|
1970
2014
|
const envVar = process.env.XDG_CACHE_HOME;
|
|
1971
|
-
if (envVar &&
|
|
2015
|
+
if (envVar && path2.isAbsolute(envVar)) {
|
|
1972
2016
|
return envVar;
|
|
1973
2017
|
}
|
|
1974
2018
|
const platform = process.platform;
|
|
@@ -1978,11 +2022,11 @@ var Telemetry = class _Telemetry {
|
|
|
1978
2022
|
if (appdata) {
|
|
1979
2023
|
return appdata;
|
|
1980
2024
|
}
|
|
1981
|
-
return
|
|
2025
|
+
return path2.join(homeDir, "AppData", "Local");
|
|
1982
2026
|
} else if (platform === "darwin") {
|
|
1983
|
-
return
|
|
2027
|
+
return path2.join(homeDir, "Library", "Caches");
|
|
1984
2028
|
} else {
|
|
1985
|
-
return
|
|
2029
|
+
return path2.join(homeDir, ".cache");
|
|
1986
2030
|
}
|
|
1987
2031
|
}
|
|
1988
2032
|
async capture(event) {
|
|
@@ -2056,12 +2100,12 @@ var Telemetry = class _Telemetry {
|
|
|
2056
2100
|
return;
|
|
2057
2101
|
}
|
|
2058
2102
|
try {
|
|
2059
|
-
const
|
|
2060
|
-
const
|
|
2103
|
+
const fs2 = require("fs");
|
|
2104
|
+
const path2 = require("path");
|
|
2061
2105
|
const os = require("os");
|
|
2062
2106
|
if (!this._versionDownloadPath) {
|
|
2063
|
-
this._versionDownloadPath =
|
|
2064
|
-
this._getCacheHome(os,
|
|
2107
|
+
this._versionDownloadPath = path2.join(
|
|
2108
|
+
this._getCacheHome(os, path2),
|
|
2065
2109
|
"mcp_use",
|
|
2066
2110
|
"download_version"
|
|
2067
2111
|
);
|
|
@@ -2069,19 +2113,19 @@ var Telemetry = class _Telemetry {
|
|
|
2069
2113
|
const currentVersion = getPackageVersion();
|
|
2070
2114
|
let shouldTrack = false;
|
|
2071
2115
|
let firstDownload = false;
|
|
2072
|
-
if (!
|
|
2116
|
+
if (!fs2.existsSync(this._versionDownloadPath)) {
|
|
2073
2117
|
shouldTrack = true;
|
|
2074
2118
|
firstDownload = true;
|
|
2075
|
-
|
|
2119
|
+
fs2.mkdirSync(path2.dirname(this._versionDownloadPath), {
|
|
2076
2120
|
recursive: true
|
|
2077
2121
|
});
|
|
2078
|
-
|
|
2122
|
+
fs2.writeFileSync(this._versionDownloadPath, currentVersion);
|
|
2079
2123
|
} else {
|
|
2080
|
-
const savedVersion =
|
|
2124
|
+
const savedVersion = fs2.readFileSync(this._versionDownloadPath, "utf-8").trim();
|
|
2081
2125
|
if (currentVersion > savedVersion) {
|
|
2082
2126
|
shouldTrack = true;
|
|
2083
2127
|
firstDownload = false;
|
|
2084
|
-
|
|
2128
|
+
fs2.writeFileSync(this._versionDownloadPath, currentVersion);
|
|
2085
2129
|
}
|
|
2086
2130
|
}
|
|
2087
2131
|
if (shouldTrack) {
|
|
@@ -2569,6 +2613,20 @@ var BaseConnector = class {
|
|
|
2569
2613
|
logger.debug(`Tool '${name}' returned`, res);
|
|
2570
2614
|
return res;
|
|
2571
2615
|
}
|
|
2616
|
+
/**
|
|
2617
|
+
* List all available tools from the MCP server.
|
|
2618
|
+
* This method fetches fresh tools from the server, unlike the `tools` getter which returns cached tools.
|
|
2619
|
+
*
|
|
2620
|
+
* @param options - Optional request options
|
|
2621
|
+
* @returns Array of available tools
|
|
2622
|
+
*/
|
|
2623
|
+
async listTools(options) {
|
|
2624
|
+
if (!this.client) {
|
|
2625
|
+
throw new Error("MCP client is not connected");
|
|
2626
|
+
}
|
|
2627
|
+
const result = await this.client.listTools(void 0, options);
|
|
2628
|
+
return result.tools ?? [];
|
|
2629
|
+
}
|
|
2572
2630
|
/**
|
|
2573
2631
|
* List resources from the server with optional pagination
|
|
2574
2632
|
*
|
|
@@ -3012,283 +3070,6 @@ var HttpConnector = class extends BaseConnector {
|
|
|
3012
3070
|
}
|
|
3013
3071
|
};
|
|
3014
3072
|
|
|
3015
|
-
// src/connectors/websocket.ts
|
|
3016
|
-
init_logging();
|
|
3017
|
-
|
|
3018
|
-
// src/task_managers/websocket.ts
|
|
3019
|
-
var import_ws = __toESM(require("ws"), 1);
|
|
3020
|
-
init_logging();
|
|
3021
|
-
var WebSocketConnectionManager = class extends ConnectionManager {
|
|
3022
|
-
static {
|
|
3023
|
-
__name(this, "WebSocketConnectionManager");
|
|
3024
|
-
}
|
|
3025
|
-
url;
|
|
3026
|
-
headers;
|
|
3027
|
-
_ws = null;
|
|
3028
|
-
/**
|
|
3029
|
-
* @param url The WebSocket URL to connect to.
|
|
3030
|
-
* @param headers Optional headers to include in the connection handshake.
|
|
3031
|
-
*/
|
|
3032
|
-
constructor(url, headers = {}) {
|
|
3033
|
-
super();
|
|
3034
|
-
this.url = url;
|
|
3035
|
-
this.headers = headers;
|
|
3036
|
-
}
|
|
3037
|
-
/** Establish a WebSocket connection and wait until it is open. */
|
|
3038
|
-
async establishConnection() {
|
|
3039
|
-
logger.debug(`Connecting to WebSocket: ${this.url}`);
|
|
3040
|
-
return new Promise((resolve, reject) => {
|
|
3041
|
-
const ws = new import_ws.default(this.url, {
|
|
3042
|
-
headers: this.headers
|
|
3043
|
-
});
|
|
3044
|
-
this._ws = ws;
|
|
3045
|
-
const onOpen = /* @__PURE__ */ __name(() => {
|
|
3046
|
-
cleanup();
|
|
3047
|
-
logger.debug("WebSocket connected successfully");
|
|
3048
|
-
resolve(ws);
|
|
3049
|
-
}, "onOpen");
|
|
3050
|
-
const onError = /* @__PURE__ */ __name((err) => {
|
|
3051
|
-
cleanup();
|
|
3052
|
-
logger.error(`Failed to connect to WebSocket: ${err}`);
|
|
3053
|
-
reject(err);
|
|
3054
|
-
}, "onError");
|
|
3055
|
-
const cleanup = /* @__PURE__ */ __name(() => {
|
|
3056
|
-
ws.off("open", onOpen);
|
|
3057
|
-
ws.off("error", onError);
|
|
3058
|
-
}, "cleanup");
|
|
3059
|
-
ws.on("open", onOpen);
|
|
3060
|
-
ws.on("error", onError);
|
|
3061
|
-
});
|
|
3062
|
-
}
|
|
3063
|
-
/** Cleanly close the WebSocket connection. */
|
|
3064
|
-
async closeConnection(connection) {
|
|
3065
|
-
logger.debug("Closing WebSocket connection");
|
|
3066
|
-
return new Promise((resolve) => {
|
|
3067
|
-
const onClose = /* @__PURE__ */ __name(() => {
|
|
3068
|
-
connection.off("close", onClose);
|
|
3069
|
-
this._ws = null;
|
|
3070
|
-
resolve();
|
|
3071
|
-
}, "onClose");
|
|
3072
|
-
if (connection.readyState === import_ws.default.CLOSED) {
|
|
3073
|
-
onClose();
|
|
3074
|
-
return;
|
|
3075
|
-
}
|
|
3076
|
-
connection.on("close", onClose);
|
|
3077
|
-
try {
|
|
3078
|
-
connection.close();
|
|
3079
|
-
} catch (e) {
|
|
3080
|
-
logger.warn(`Error closing WebSocket connection: ${e}`);
|
|
3081
|
-
onClose();
|
|
3082
|
-
}
|
|
3083
|
-
});
|
|
3084
|
-
}
|
|
3085
|
-
};
|
|
3086
|
-
|
|
3087
|
-
// src/connectors/websocket.ts
|
|
3088
|
-
var WebSocketConnector = class extends BaseConnector {
|
|
3089
|
-
static {
|
|
3090
|
-
__name(this, "WebSocketConnector");
|
|
3091
|
-
}
|
|
3092
|
-
url;
|
|
3093
|
-
headers;
|
|
3094
|
-
connectionManager = null;
|
|
3095
|
-
ws = null;
|
|
3096
|
-
receiverTask = null;
|
|
3097
|
-
pending = /* @__PURE__ */ new Map();
|
|
3098
|
-
toolsCache = null;
|
|
3099
|
-
constructor(url, opts = {}) {
|
|
3100
|
-
super();
|
|
3101
|
-
this.url = url;
|
|
3102
|
-
this.headers = { ...opts.headers ?? {} };
|
|
3103
|
-
if (opts.authToken) this.headers.Authorization = `Bearer ${opts.authToken}`;
|
|
3104
|
-
}
|
|
3105
|
-
async connect() {
|
|
3106
|
-
if (this.connected) {
|
|
3107
|
-
logger.debug("Already connected to MCP implementation");
|
|
3108
|
-
return;
|
|
3109
|
-
}
|
|
3110
|
-
logger.debug(`Connecting via WebSocket: ${this.url}`);
|
|
3111
|
-
try {
|
|
3112
|
-
this.connectionManager = new WebSocketConnectionManager(
|
|
3113
|
-
this.url,
|
|
3114
|
-
this.headers
|
|
3115
|
-
);
|
|
3116
|
-
this.ws = await this.connectionManager.start();
|
|
3117
|
-
this.receiverTask = this.receiveLoop();
|
|
3118
|
-
this.connected = true;
|
|
3119
|
-
logger.debug("WebSocket connected successfully");
|
|
3120
|
-
} catch (e) {
|
|
3121
|
-
logger.error(`Failed to connect: ${e}`);
|
|
3122
|
-
await this.cleanupResources();
|
|
3123
|
-
throw e;
|
|
3124
|
-
}
|
|
3125
|
-
}
|
|
3126
|
-
async disconnect() {
|
|
3127
|
-
if (!this.connected) {
|
|
3128
|
-
logger.debug("Not connected to MCP implementation");
|
|
3129
|
-
return;
|
|
3130
|
-
}
|
|
3131
|
-
logger.debug("Disconnecting \u2026");
|
|
3132
|
-
await this.cleanupResources();
|
|
3133
|
-
this.connected = false;
|
|
3134
|
-
}
|
|
3135
|
-
sendRequest(method, params = null) {
|
|
3136
|
-
if (!this.ws) throw new Error("WebSocket is not connected");
|
|
3137
|
-
const id = generateUUID();
|
|
3138
|
-
const payload = JSON.stringify({ id, method, params: params ?? {} });
|
|
3139
|
-
return new Promise((resolve, reject) => {
|
|
3140
|
-
this.pending.set(id, { resolve, reject });
|
|
3141
|
-
this.ws.send(payload, (err) => {
|
|
3142
|
-
if (err) {
|
|
3143
|
-
this.pending.delete(id);
|
|
3144
|
-
reject(err);
|
|
3145
|
-
}
|
|
3146
|
-
});
|
|
3147
|
-
});
|
|
3148
|
-
}
|
|
3149
|
-
async receiveLoop() {
|
|
3150
|
-
if (!this.ws) return;
|
|
3151
|
-
const socket = this.ws;
|
|
3152
|
-
const onMessage = /* @__PURE__ */ __name((msg) => {
|
|
3153
|
-
let data;
|
|
3154
|
-
try {
|
|
3155
|
-
data = JSON.parse(msg.data ?? msg);
|
|
3156
|
-
} catch (e) {
|
|
3157
|
-
logger.warn("Received non\u2011JSON frame", e);
|
|
3158
|
-
return;
|
|
3159
|
-
}
|
|
3160
|
-
const id = data.id;
|
|
3161
|
-
if (id && this.pending.has(id)) {
|
|
3162
|
-
const { resolve, reject } = this.pending.get(id);
|
|
3163
|
-
this.pending.delete(id);
|
|
3164
|
-
if ("result" in data) resolve(data.result);
|
|
3165
|
-
else if ("error" in data) reject(data.error);
|
|
3166
|
-
} else if (data.method && !data.id) {
|
|
3167
|
-
logger.debug("Received notification", data.method, data.params);
|
|
3168
|
-
this.handleNotification(data);
|
|
3169
|
-
} else {
|
|
3170
|
-
logger.debug("Received unsolicited message", data);
|
|
3171
|
-
}
|
|
3172
|
-
}, "onMessage");
|
|
3173
|
-
if (socket.addEventListener) {
|
|
3174
|
-
socket.addEventListener("message", onMessage);
|
|
3175
|
-
} else {
|
|
3176
|
-
socket.on("message", onMessage);
|
|
3177
|
-
}
|
|
3178
|
-
return new Promise((resolve) => {
|
|
3179
|
-
const onClose = /* @__PURE__ */ __name(() => {
|
|
3180
|
-
if (socket.removeEventListener) {
|
|
3181
|
-
socket.removeEventListener("message", onMessage);
|
|
3182
|
-
} else {
|
|
3183
|
-
socket.off("message", onMessage);
|
|
3184
|
-
}
|
|
3185
|
-
this.rejectAll(new Error("WebSocket closed"));
|
|
3186
|
-
resolve();
|
|
3187
|
-
}, "onClose");
|
|
3188
|
-
if (socket.addEventListener) {
|
|
3189
|
-
socket.addEventListener("close", onClose);
|
|
3190
|
-
} else {
|
|
3191
|
-
socket.on("close", onClose);
|
|
3192
|
-
}
|
|
3193
|
-
});
|
|
3194
|
-
}
|
|
3195
|
-
rejectAll(err) {
|
|
3196
|
-
for (const { reject } of this.pending.values()) reject(err);
|
|
3197
|
-
this.pending.clear();
|
|
3198
|
-
}
|
|
3199
|
-
async handleNotification(data) {
|
|
3200
|
-
switch (data.method) {
|
|
3201
|
-
case "notifications/tools/list_changed":
|
|
3202
|
-
await this.refreshToolsCache();
|
|
3203
|
-
break;
|
|
3204
|
-
case "notifications/resources/list_changed":
|
|
3205
|
-
await this.onResourcesListChanged();
|
|
3206
|
-
break;
|
|
3207
|
-
case "notifications/prompts/list_changed":
|
|
3208
|
-
await this.onPromptsListChanged();
|
|
3209
|
-
break;
|
|
3210
|
-
default:
|
|
3211
|
-
break;
|
|
3212
|
-
}
|
|
3213
|
-
for (const handler of this.notificationHandlers) {
|
|
3214
|
-
try {
|
|
3215
|
-
await handler({
|
|
3216
|
-
method: data.method,
|
|
3217
|
-
params: data.params
|
|
3218
|
-
});
|
|
3219
|
-
} catch (err) {
|
|
3220
|
-
logger.error("Error in notification handler:", err);
|
|
3221
|
-
}
|
|
3222
|
-
}
|
|
3223
|
-
}
|
|
3224
|
-
/**
|
|
3225
|
-
* Auto-refresh tools cache when server sends tools/list_changed notification
|
|
3226
|
-
* Override to use WebSocket-specific listTools method
|
|
3227
|
-
*/
|
|
3228
|
-
async refreshToolsCache() {
|
|
3229
|
-
try {
|
|
3230
|
-
logger.debug(
|
|
3231
|
-
"[Auto] Refreshing tools cache due to list_changed notification"
|
|
3232
|
-
);
|
|
3233
|
-
const tools = await this.listTools();
|
|
3234
|
-
this.toolsCache = tools.map((t) => t);
|
|
3235
|
-
logger.debug(
|
|
3236
|
-
`[Auto] Refreshed tools cache: ${this.toolsCache.length} tools`
|
|
3237
|
-
);
|
|
3238
|
-
} catch (err) {
|
|
3239
|
-
logger.warn("[Auto] Failed to refresh tools cache:", err);
|
|
3240
|
-
}
|
|
3241
|
-
}
|
|
3242
|
-
async initialize() {
|
|
3243
|
-
logger.debug("Initializing MCP session over WebSocket");
|
|
3244
|
-
const result = await this.sendRequest("initialize");
|
|
3245
|
-
const toolsList = await this.listTools();
|
|
3246
|
-
this.toolsCache = toolsList.map((t) => t);
|
|
3247
|
-
logger.debug(`Initialized with ${this.toolsCache.length} tools`);
|
|
3248
|
-
return result;
|
|
3249
|
-
}
|
|
3250
|
-
async listTools() {
|
|
3251
|
-
const res = await this.sendRequest("tools/list");
|
|
3252
|
-
return res.tools ?? [];
|
|
3253
|
-
}
|
|
3254
|
-
async callTool(name, args) {
|
|
3255
|
-
return await this.sendRequest("tools/call", { name, arguments: args });
|
|
3256
|
-
}
|
|
3257
|
-
async listResources() {
|
|
3258
|
-
const resources = await this.sendRequest("resources/list");
|
|
3259
|
-
return { resources: Array.isArray(resources) ? resources : [] };
|
|
3260
|
-
}
|
|
3261
|
-
async readResource(uri) {
|
|
3262
|
-
const res = await this.sendRequest("resources/read", { uri });
|
|
3263
|
-
return res;
|
|
3264
|
-
}
|
|
3265
|
-
async request(method, params = null) {
|
|
3266
|
-
return await this.sendRequest(method, params);
|
|
3267
|
-
}
|
|
3268
|
-
get tools() {
|
|
3269
|
-
if (!this.toolsCache) throw new Error("MCP client is not initialized");
|
|
3270
|
-
return this.toolsCache;
|
|
3271
|
-
}
|
|
3272
|
-
async cleanupResources() {
|
|
3273
|
-
if (this.receiverTask) await this.receiverTask.catch(() => {
|
|
3274
|
-
});
|
|
3275
|
-
this.receiverTask = null;
|
|
3276
|
-
this.rejectAll(new Error("WebSocket disconnected"));
|
|
3277
|
-
if (this.connectionManager) {
|
|
3278
|
-
await this.connectionManager.stop();
|
|
3279
|
-
this.connectionManager = null;
|
|
3280
|
-
this.ws = null;
|
|
3281
|
-
}
|
|
3282
|
-
this.toolsCache = null;
|
|
3283
|
-
}
|
|
3284
|
-
get publicIdentifier() {
|
|
3285
|
-
return {
|
|
3286
|
-
type: "websocket",
|
|
3287
|
-
url: this.url
|
|
3288
|
-
};
|
|
3289
|
-
}
|
|
3290
|
-
};
|
|
3291
|
-
|
|
3292
3073
|
// src/client/browser.ts
|
|
3293
3074
|
init_logging();
|
|
3294
3075
|
|
|
@@ -3380,6 +3161,22 @@ var MCPSession = class {
|
|
|
3380
3161
|
get tools() {
|
|
3381
3162
|
return this.connector.tools;
|
|
3382
3163
|
}
|
|
3164
|
+
/**
|
|
3165
|
+
* List all available tools from the MCP server.
|
|
3166
|
+
* This method fetches fresh tools from the server, unlike the `tools` getter which returns cached tools.
|
|
3167
|
+
*
|
|
3168
|
+
* @param options - Optional request options
|
|
3169
|
+
* @returns Array of available tools
|
|
3170
|
+
*
|
|
3171
|
+
* @example
|
|
3172
|
+
* ```typescript
|
|
3173
|
+
* const tools = await session.listTools();
|
|
3174
|
+
* console.log(`Available tools: ${tools.map(t => t.name).join(", ")}`);
|
|
3175
|
+
* ```
|
|
3176
|
+
*/
|
|
3177
|
+
async listTools(options) {
|
|
3178
|
+
return this.connector.listTools(options);
|
|
3179
|
+
}
|
|
3383
3180
|
/**
|
|
3384
3181
|
* Get the server capabilities advertised during initialization.
|
|
3385
3182
|
*
|
|
@@ -3400,7 +3197,7 @@ var MCPSession = class {
|
|
|
3400
3197
|
* Call a tool on the server.
|
|
3401
3198
|
*
|
|
3402
3199
|
* @param name - Name of the tool to call
|
|
3403
|
-
* @param args - Arguments to pass to the tool
|
|
3200
|
+
* @param args - Arguments to pass to the tool (defaults to empty object)
|
|
3404
3201
|
* @param options - Optional request options (timeout, progress handlers, etc.)
|
|
3405
3202
|
* @returns Result from the tool execution
|
|
3406
3203
|
*
|
|
@@ -3410,7 +3207,7 @@ var MCPSession = class {
|
|
|
3410
3207
|
* console.log(`Result: ${result.content[0].text}`);
|
|
3411
3208
|
* ```
|
|
3412
3209
|
*/
|
|
3413
|
-
async callTool(name, args, options) {
|
|
3210
|
+
async callTool(name, args = {}, options) {
|
|
3414
3211
|
return this.connector.callTool(name, args, options);
|
|
3415
3212
|
}
|
|
3416
3213
|
/**
|
|
@@ -3625,6 +3422,15 @@ var BaseMCPClient = class {
|
|
|
3625
3422
|
}
|
|
3626
3423
|
return session;
|
|
3627
3424
|
}
|
|
3425
|
+
requireSession(serverName) {
|
|
3426
|
+
const session = this.sessions[serverName];
|
|
3427
|
+
if (!session) {
|
|
3428
|
+
throw new Error(
|
|
3429
|
+
`Session '${serverName}' not found. Available sessions: ${this.activeSessions.join(", ") || "none"}`
|
|
3430
|
+
);
|
|
3431
|
+
}
|
|
3432
|
+
return session;
|
|
3433
|
+
}
|
|
3628
3434
|
getAllActiveSessions() {
|
|
3629
3435
|
return Object.fromEntries(
|
|
3630
3436
|
this.activeSessions.map((n) => [n, this.sessions[n]])
|
|
@@ -3710,12 +3516,11 @@ var BrowserMCPClient = class _BrowserMCPClient extends BaseMCPClient {
|
|
|
3710
3516
|
}
|
|
3711
3517
|
/**
|
|
3712
3518
|
* Create a connector from server configuration (Browser version)
|
|
3713
|
-
* Supports HTTP
|
|
3519
|
+
* Supports HTTP connector only
|
|
3714
3520
|
*/
|
|
3715
3521
|
createConnectorFromConfig(serverConfig) {
|
|
3716
3522
|
const {
|
|
3717
3523
|
url,
|
|
3718
|
-
transport,
|
|
3719
3524
|
headers,
|
|
3720
3525
|
authToken,
|
|
3721
3526
|
authProvider,
|
|
@@ -3751,13 +3556,7 @@ var BrowserMCPClient = class _BrowserMCPClient extends BaseMCPClient {
|
|
|
3751
3556
|
"[BrowserMCPClient] No clientOptions provided to connector!"
|
|
3752
3557
|
);
|
|
3753
3558
|
}
|
|
3754
|
-
|
|
3755
|
-
return new WebSocketConnector(url, connectorOptions);
|
|
3756
|
-
} else if (transport === "http" || url.startsWith("http://") || url.startsWith("https://")) {
|
|
3757
|
-
return new HttpConnector(url, connectorOptions);
|
|
3758
|
-
} else {
|
|
3759
|
-
return new HttpConnector(url, connectorOptions);
|
|
3760
|
-
}
|
|
3559
|
+
return new HttpConnector(url, connectorOptions);
|
|
3761
3560
|
}
|
|
3762
3561
|
};
|
|
3763
3562
|
|
|
@@ -4542,6 +4341,98 @@ var BaseAdapter = class {
|
|
|
4542
4341
|
logger.debug(`Available tools: ${tools.length}`);
|
|
4543
4342
|
return tools;
|
|
4544
4343
|
}
|
|
4344
|
+
/**
|
|
4345
|
+
* Dynamically load resources for a specific connector.
|
|
4346
|
+
*
|
|
4347
|
+
* @param connector The connector to load resources for.
|
|
4348
|
+
* @returns The list of resources that were loaded in the target framework's format.
|
|
4349
|
+
*/
|
|
4350
|
+
async loadResourcesForConnector(connector) {
|
|
4351
|
+
const connectorResources = [];
|
|
4352
|
+
const success = await this.ensureConnectorInitialized(connector);
|
|
4353
|
+
if (!success) {
|
|
4354
|
+
return [];
|
|
4355
|
+
}
|
|
4356
|
+
try {
|
|
4357
|
+
const resourcesResult = await connector.listAllResources();
|
|
4358
|
+
const resources = resourcesResult?.resources || [];
|
|
4359
|
+
if (this.convertResource) {
|
|
4360
|
+
for (const resource of resources) {
|
|
4361
|
+
const converted = this.convertResource(resource, connector);
|
|
4362
|
+
if (converted) {
|
|
4363
|
+
connectorResources.push(converted);
|
|
4364
|
+
}
|
|
4365
|
+
}
|
|
4366
|
+
}
|
|
4367
|
+
logger.debug(
|
|
4368
|
+
`Loaded ${connectorResources.length} new resources for connector: ${connectorResources.map((r) => r?.name ?? String(r)).join(", ")}`
|
|
4369
|
+
);
|
|
4370
|
+
} catch (err) {
|
|
4371
|
+
logger.warn(`Error loading resources for connector: ${err}`);
|
|
4372
|
+
}
|
|
4373
|
+
return connectorResources;
|
|
4374
|
+
}
|
|
4375
|
+
/**
|
|
4376
|
+
* Dynamically load prompts for a specific connector.
|
|
4377
|
+
*
|
|
4378
|
+
* @param connector The connector to load prompts for.
|
|
4379
|
+
* @returns The list of prompts that were loaded in the target framework's format.
|
|
4380
|
+
*/
|
|
4381
|
+
async loadPromptsForConnector(connector) {
|
|
4382
|
+
const connectorPrompts = [];
|
|
4383
|
+
const success = await this.ensureConnectorInitialized(connector);
|
|
4384
|
+
if (!success) {
|
|
4385
|
+
return [];
|
|
4386
|
+
}
|
|
4387
|
+
try {
|
|
4388
|
+
const promptsResult = await connector.listPrompts();
|
|
4389
|
+
const prompts = promptsResult?.prompts || [];
|
|
4390
|
+
if (this.convertPrompt) {
|
|
4391
|
+
for (const prompt of prompts) {
|
|
4392
|
+
const converted = this.convertPrompt(prompt, connector);
|
|
4393
|
+
if (converted) {
|
|
4394
|
+
connectorPrompts.push(converted);
|
|
4395
|
+
}
|
|
4396
|
+
}
|
|
4397
|
+
}
|
|
4398
|
+
logger.debug(
|
|
4399
|
+
`Loaded ${connectorPrompts.length} new prompts for connector: ${connectorPrompts.map((p) => p?.name ?? String(p)).join(", ")}`
|
|
4400
|
+
);
|
|
4401
|
+
} catch (err) {
|
|
4402
|
+
logger.warn(`Error loading prompts for connector: ${err}`);
|
|
4403
|
+
}
|
|
4404
|
+
return connectorPrompts;
|
|
4405
|
+
}
|
|
4406
|
+
/**
|
|
4407
|
+
* Create resources from MCP resources in all provided connectors.
|
|
4408
|
+
*
|
|
4409
|
+
* @param connectors List of MCP connectors to create resources from.
|
|
4410
|
+
* @returns A promise that resolves with all converted resources.
|
|
4411
|
+
*/
|
|
4412
|
+
async createResourcesFromConnectors(connectors) {
|
|
4413
|
+
const resources = [];
|
|
4414
|
+
for (const connector of connectors) {
|
|
4415
|
+
const connectorResources = await this.loadResourcesForConnector(connector);
|
|
4416
|
+
resources.push(...connectorResources);
|
|
4417
|
+
}
|
|
4418
|
+
logger.debug(`Available resources: ${resources.length}`);
|
|
4419
|
+
return resources;
|
|
4420
|
+
}
|
|
4421
|
+
/**
|
|
4422
|
+
* Create prompts from MCP prompts in all provided connectors.
|
|
4423
|
+
*
|
|
4424
|
+
* @param connectors List of MCP connectors to create prompts from.
|
|
4425
|
+
* @returns A promise that resolves with all converted prompts.
|
|
4426
|
+
*/
|
|
4427
|
+
async createPromptsFromConnectors(connectors) {
|
|
4428
|
+
const prompts = [];
|
|
4429
|
+
for (const connector of connectors) {
|
|
4430
|
+
const connectorPrompts = await this.loadPromptsForConnector(connector);
|
|
4431
|
+
prompts.push(...connectorPrompts);
|
|
4432
|
+
}
|
|
4433
|
+
logger.debug(`Available prompts: ${prompts.length}`);
|
|
4434
|
+
return prompts;
|
|
4435
|
+
}
|
|
4545
4436
|
/**
|
|
4546
4437
|
* Check if a connector is initialized and has tools.
|
|
4547
4438
|
*
|
|
@@ -4620,16 +4511,1238 @@ var LangChainAdapter = class extends BaseAdapter {
|
|
|
4620
4511
|
});
|
|
4621
4512
|
return tool;
|
|
4622
4513
|
}
|
|
4514
|
+
/**
|
|
4515
|
+
* Convert a single MCP resource into a LangChainJS structured tool.
|
|
4516
|
+
* Each resource becomes an async tool that returns its content when called.
|
|
4517
|
+
*/
|
|
4518
|
+
convertResource(mcpResource, connector) {
|
|
4519
|
+
const sanitizeName = /* @__PURE__ */ __name((name) => {
|
|
4520
|
+
return name.replace(/[^A-Za-z0-9_]+/g, "_").toLowerCase().replace(/^_+|_+$/g, "");
|
|
4521
|
+
}, "sanitizeName");
|
|
4522
|
+
const resourceName = sanitizeName(
|
|
4523
|
+
mcpResource.name || `resource_${mcpResource.uri}`
|
|
4524
|
+
);
|
|
4525
|
+
const resourceUri = mcpResource.uri;
|
|
4526
|
+
const tool = new import_tools.DynamicStructuredTool({
|
|
4527
|
+
name: resourceName,
|
|
4528
|
+
description: mcpResource.description || `Return the content of the resource located at URI ${resourceUri}.`,
|
|
4529
|
+
schema: import_zod2.z.object({}).optional(),
|
|
4530
|
+
// Resources take no arguments
|
|
4531
|
+
func: /* @__PURE__ */ __name(async () => {
|
|
4532
|
+
logger.debug(`Resource tool: "${resourceName}" called`);
|
|
4533
|
+
try {
|
|
4534
|
+
const result = await connector.readResource(resourceUri);
|
|
4535
|
+
if (result.contents && result.contents.length > 0) {
|
|
4536
|
+
return result.contents.map((content) => {
|
|
4537
|
+
if (typeof content === "string") {
|
|
4538
|
+
return content;
|
|
4539
|
+
}
|
|
4540
|
+
if (content.text) {
|
|
4541
|
+
return content.text;
|
|
4542
|
+
}
|
|
4543
|
+
if (content.uri) {
|
|
4544
|
+
return content.uri;
|
|
4545
|
+
}
|
|
4546
|
+
return JSON.stringify(content);
|
|
4547
|
+
}).join("\n");
|
|
4548
|
+
}
|
|
4549
|
+
return "Resource is empty or unavailable";
|
|
4550
|
+
} catch (err) {
|
|
4551
|
+
logger.error(`Error reading resource: ${err.message}`);
|
|
4552
|
+
return `Error reading resource: ${String(err)}`;
|
|
4553
|
+
}
|
|
4554
|
+
}, "func")
|
|
4555
|
+
});
|
|
4556
|
+
return tool;
|
|
4557
|
+
}
|
|
4558
|
+
/**
|
|
4559
|
+
* Convert a single MCP prompt into a LangChainJS structured tool.
|
|
4560
|
+
* The resulting tool executes getPrompt on the connector with the prompt's name
|
|
4561
|
+
* and the user-provided arguments (if any).
|
|
4562
|
+
*/
|
|
4563
|
+
convertPrompt(mcpPrompt, connector) {
|
|
4564
|
+
let argsSchema = import_zod2.z.object({}).optional();
|
|
4565
|
+
if (mcpPrompt.arguments && mcpPrompt.arguments.length > 0) {
|
|
4566
|
+
const schemaFields = {};
|
|
4567
|
+
for (const arg of mcpPrompt.arguments) {
|
|
4568
|
+
const zodType = import_zod2.z.string();
|
|
4569
|
+
if (arg.required !== false) {
|
|
4570
|
+
schemaFields[arg.name] = zodType;
|
|
4571
|
+
} else {
|
|
4572
|
+
schemaFields[arg.name] = zodType.optional();
|
|
4573
|
+
}
|
|
4574
|
+
}
|
|
4575
|
+
argsSchema = Object.keys(schemaFields).length > 0 ? import_zod2.z.object(schemaFields) : import_zod2.z.object({}).optional();
|
|
4576
|
+
}
|
|
4577
|
+
const tool = new import_tools.DynamicStructuredTool({
|
|
4578
|
+
name: mcpPrompt.name,
|
|
4579
|
+
description: mcpPrompt.description || "",
|
|
4580
|
+
schema: argsSchema,
|
|
4581
|
+
func: /* @__PURE__ */ __name(async (input) => {
|
|
4582
|
+
logger.debug(
|
|
4583
|
+
`Prompt tool: "${mcpPrompt.name}" called with args: ${JSON.stringify(input)}`
|
|
4584
|
+
);
|
|
4585
|
+
try {
|
|
4586
|
+
const result = await connector.getPrompt(mcpPrompt.name, input);
|
|
4587
|
+
if (result.messages && result.messages.length > 0) {
|
|
4588
|
+
return result.messages.map((msg) => {
|
|
4589
|
+
if (typeof msg === "string") {
|
|
4590
|
+
return msg;
|
|
4591
|
+
}
|
|
4592
|
+
if (msg.content) {
|
|
4593
|
+
return typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content);
|
|
4594
|
+
}
|
|
4595
|
+
return JSON.stringify(msg);
|
|
4596
|
+
}).join("\n");
|
|
4597
|
+
}
|
|
4598
|
+
return "Prompt returned no messages";
|
|
4599
|
+
} catch (err) {
|
|
4600
|
+
logger.error(`Error getting prompt: ${err.message}`);
|
|
4601
|
+
return `Error getting prompt: ${String(err)}`;
|
|
4602
|
+
}
|
|
4603
|
+
}, "func")
|
|
4604
|
+
});
|
|
4605
|
+
return tool;
|
|
4606
|
+
}
|
|
4623
4607
|
};
|
|
4624
4608
|
|
|
4625
|
-
// src/
|
|
4626
|
-
|
|
4609
|
+
// src/client.ts
|
|
4610
|
+
var import_node_fs2 = __toESM(require("fs"), 1);
|
|
4611
|
+
var import_node_path = __toESM(require("path"), 1);
|
|
4627
4612
|
|
|
4628
|
-
// src/
|
|
4613
|
+
// src/client/executors/base.ts
|
|
4629
4614
|
init_logging();
|
|
4630
|
-
|
|
4631
|
-
|
|
4632
|
-
|
|
4615
|
+
var BaseCodeExecutor = class {
|
|
4616
|
+
static {
|
|
4617
|
+
__name(this, "BaseCodeExecutor");
|
|
4618
|
+
}
|
|
4619
|
+
client;
|
|
4620
|
+
_connecting = false;
|
|
4621
|
+
constructor(client) {
|
|
4622
|
+
this.client = client;
|
|
4623
|
+
}
|
|
4624
|
+
/**
|
|
4625
|
+
* Ensure all configured MCP servers are connected before execution.
|
|
4626
|
+
* Prevents race conditions with a connection lock.
|
|
4627
|
+
*/
|
|
4628
|
+
async ensureServersConnected() {
|
|
4629
|
+
const configuredServers = this.client.getServerNames();
|
|
4630
|
+
const activeSessions = Object.keys(this.client.getAllActiveSessions());
|
|
4631
|
+
const missingServers = configuredServers.filter(
|
|
4632
|
+
(s) => !activeSessions.includes(s)
|
|
4633
|
+
);
|
|
4634
|
+
if (missingServers.length > 0 && !this._connecting) {
|
|
4635
|
+
this._connecting = true;
|
|
4636
|
+
try {
|
|
4637
|
+
logger.debug(
|
|
4638
|
+
`Connecting to configured servers for code execution: ${missingServers.join(", ")}`
|
|
4639
|
+
);
|
|
4640
|
+
await this.client.createAllSessions();
|
|
4641
|
+
} finally {
|
|
4642
|
+
this._connecting = false;
|
|
4643
|
+
}
|
|
4644
|
+
} else if (missingServers.length > 0 && this._connecting) {
|
|
4645
|
+
logger.debug("Waiting for ongoing server connection...");
|
|
4646
|
+
const startWait = Date.now();
|
|
4647
|
+
while (this._connecting && Date.now() - startWait < 5e3) {
|
|
4648
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
4649
|
+
}
|
|
4650
|
+
}
|
|
4651
|
+
}
|
|
4652
|
+
/**
|
|
4653
|
+
* Get tool namespace information from all active MCP sessions.
|
|
4654
|
+
* Filters out the internal code_mode server.
|
|
4655
|
+
*/
|
|
4656
|
+
getToolNamespaces() {
|
|
4657
|
+
const namespaces = [];
|
|
4658
|
+
const activeSessions = this.client.getAllActiveSessions();
|
|
4659
|
+
for (const [serverName, session] of Object.entries(activeSessions)) {
|
|
4660
|
+
if (serverName === "code_mode") continue;
|
|
4661
|
+
try {
|
|
4662
|
+
const connector = session.connector;
|
|
4663
|
+
let tools;
|
|
4664
|
+
try {
|
|
4665
|
+
tools = connector.tools;
|
|
4666
|
+
} catch (e) {
|
|
4667
|
+
logger.warn(`Tools not available for server ${serverName}: ${e}`);
|
|
4668
|
+
continue;
|
|
4669
|
+
}
|
|
4670
|
+
if (!tools || tools.length === 0) continue;
|
|
4671
|
+
namespaces.push({ serverName, tools, session });
|
|
4672
|
+
} catch (e) {
|
|
4673
|
+
logger.warn(`Failed to load tools for server ${serverName}: ${e}`);
|
|
4674
|
+
}
|
|
4675
|
+
}
|
|
4676
|
+
return namespaces;
|
|
4677
|
+
}
|
|
4678
|
+
/**
|
|
4679
|
+
* Create a search function for discovering available MCP tools.
|
|
4680
|
+
* Used by code execution environments to find tools at runtime.
|
|
4681
|
+
*/
|
|
4682
|
+
createSearchToolsFunction() {
|
|
4683
|
+
return async (query = "", detailLevel = "full") => {
|
|
4684
|
+
const allTools = [];
|
|
4685
|
+
const allNamespaces = /* @__PURE__ */ new Set();
|
|
4686
|
+
const queryLower = query.toLowerCase();
|
|
4687
|
+
const activeSessions = this.client.getAllActiveSessions();
|
|
4688
|
+
for (const [serverName, session] of Object.entries(activeSessions)) {
|
|
4689
|
+
if (serverName === "code_mode") continue;
|
|
4690
|
+
try {
|
|
4691
|
+
const tools = session.connector.tools;
|
|
4692
|
+
if (tools && tools.length > 0) {
|
|
4693
|
+
allNamespaces.add(serverName);
|
|
4694
|
+
}
|
|
4695
|
+
for (const tool of tools) {
|
|
4696
|
+
if (detailLevel === "names") {
|
|
4697
|
+
allTools.push({ name: tool.name, server: serverName });
|
|
4698
|
+
} else if (detailLevel === "descriptions") {
|
|
4699
|
+
allTools.push({
|
|
4700
|
+
name: tool.name,
|
|
4701
|
+
server: serverName,
|
|
4702
|
+
description: tool.description
|
|
4703
|
+
});
|
|
4704
|
+
} else {
|
|
4705
|
+
allTools.push({
|
|
4706
|
+
name: tool.name,
|
|
4707
|
+
server: serverName,
|
|
4708
|
+
description: tool.description,
|
|
4709
|
+
input_schema: tool.inputSchema
|
|
4710
|
+
});
|
|
4711
|
+
}
|
|
4712
|
+
}
|
|
4713
|
+
} catch (e) {
|
|
4714
|
+
logger.warn(`Failed to search tools in server ${serverName}: ${e}`);
|
|
4715
|
+
}
|
|
4716
|
+
}
|
|
4717
|
+
let filteredTools = allTools;
|
|
4718
|
+
if (query) {
|
|
4719
|
+
filteredTools = allTools.filter((tool) => {
|
|
4720
|
+
const nameMatch = tool.name.toLowerCase().includes(queryLower);
|
|
4721
|
+
const descMatch = tool.description?.toLowerCase().includes(queryLower);
|
|
4722
|
+
const serverMatch = tool.server.toLowerCase().includes(queryLower);
|
|
4723
|
+
return nameMatch || descMatch || serverMatch;
|
|
4724
|
+
});
|
|
4725
|
+
}
|
|
4726
|
+
return {
|
|
4727
|
+
meta: {
|
|
4728
|
+
total_tools: allTools.length,
|
|
4729
|
+
namespaces: Array.from(allNamespaces).sort(),
|
|
4730
|
+
result_count: filteredTools.length
|
|
4731
|
+
},
|
|
4732
|
+
results: filteredTools
|
|
4733
|
+
};
|
|
4734
|
+
};
|
|
4735
|
+
}
|
|
4736
|
+
};
|
|
4737
|
+
|
|
4738
|
+
// src/client/executors/e2b.ts
|
|
4739
|
+
init_logging();
|
|
4740
|
+
var E2BCodeExecutor = class extends BaseCodeExecutor {
|
|
4741
|
+
static {
|
|
4742
|
+
__name(this, "E2BCodeExecutor");
|
|
4743
|
+
}
|
|
4744
|
+
e2bApiKey;
|
|
4745
|
+
codeExecSandbox = null;
|
|
4746
|
+
SandboxClass = null;
|
|
4747
|
+
timeoutMs;
|
|
4748
|
+
constructor(client, options) {
|
|
4749
|
+
super(client);
|
|
4750
|
+
this.e2bApiKey = options.apiKey;
|
|
4751
|
+
this.timeoutMs = options.timeoutMs ?? 3e5;
|
|
4752
|
+
}
|
|
4753
|
+
/**
|
|
4754
|
+
* Lazy load E2B Sandbox class.
|
|
4755
|
+
* This allows the library to work without E2B installed.
|
|
4756
|
+
*/
|
|
4757
|
+
async ensureSandboxClass() {
|
|
4758
|
+
if (this.SandboxClass) return;
|
|
4759
|
+
try {
|
|
4760
|
+
const e2b = await import("@e2b/code-interpreter");
|
|
4761
|
+
this.SandboxClass = e2b.Sandbox;
|
|
4762
|
+
} catch (error) {
|
|
4763
|
+
throw new Error(
|
|
4764
|
+
"@e2b/code-interpreter is not installed. The E2B code executor requires this optional dependency. Install it with: yarn add @e2b/code-interpreter"
|
|
4765
|
+
);
|
|
4766
|
+
}
|
|
4767
|
+
}
|
|
4768
|
+
/**
|
|
4769
|
+
* Get or create a dedicated sandbox for code execution.
|
|
4770
|
+
*/
|
|
4771
|
+
async getOrCreateCodeExecSandbox() {
|
|
4772
|
+
if (this.codeExecSandbox) return this.codeExecSandbox;
|
|
4773
|
+
await this.ensureSandboxClass();
|
|
4774
|
+
logger.debug("Starting E2B sandbox for code execution...");
|
|
4775
|
+
this.codeExecSandbox = await this.SandboxClass.create("base", {
|
|
4776
|
+
apiKey: this.e2bApiKey,
|
|
4777
|
+
timeoutMs: this.timeoutMs
|
|
4778
|
+
});
|
|
4779
|
+
return this.codeExecSandbox;
|
|
4780
|
+
}
|
|
4781
|
+
/**
|
|
4782
|
+
* Generate the shim code that exposes tools to the sandbox environment.
|
|
4783
|
+
* Creates a bridge that intercepts tool calls and sends them back to host.
|
|
4784
|
+
*/
|
|
4785
|
+
generateShim(tools) {
|
|
4786
|
+
let shim = `
|
|
4787
|
+
// MCP Bridge Shim
|
|
4788
|
+
global.__callMcpTool = async (server, tool, args) => {
|
|
4789
|
+
const id = Math.random().toString(36).substring(7);
|
|
4790
|
+
console.log(JSON.stringify({
|
|
4791
|
+
type: '__MCP_TOOL_CALL__',
|
|
4792
|
+
id,
|
|
4793
|
+
server,
|
|
4794
|
+
tool,
|
|
4795
|
+
args
|
|
4796
|
+
}));
|
|
4797
|
+
|
|
4798
|
+
const resultPath = \`/tmp/mcp_result_\${id}.json\`;
|
|
4799
|
+
const fs = require('fs');
|
|
4800
|
+
|
|
4801
|
+
// Poll for result file
|
|
4802
|
+
let attempts = 0;
|
|
4803
|
+
while (attempts < 300) { // 30 seconds timeout
|
|
4804
|
+
if (fs.existsSync(resultPath)) {
|
|
4805
|
+
const content = fs.readFileSync(resultPath, 'utf8');
|
|
4806
|
+
const result = JSON.parse(content);
|
|
4807
|
+
fs.unlinkSync(resultPath); // Clean up
|
|
4808
|
+
|
|
4809
|
+
if (result.error) {
|
|
4810
|
+
throw new Error(result.error);
|
|
4811
|
+
}
|
|
4812
|
+
return result.data;
|
|
4813
|
+
}
|
|
4814
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
4815
|
+
attempts++;
|
|
4816
|
+
}
|
|
4817
|
+
throw new Error('Tool execution timed out');
|
|
4818
|
+
};
|
|
4819
|
+
|
|
4820
|
+
// Global search_tools helper
|
|
4821
|
+
global.search_tools = async (query, detailLevel = 'full') => {
|
|
4822
|
+
const allTools = ${JSON.stringify(
|
|
4823
|
+
Object.entries(tools).flatMap(
|
|
4824
|
+
([server, serverTools]) => serverTools.map((tool) => ({
|
|
4825
|
+
name: tool.name,
|
|
4826
|
+
description: tool.description,
|
|
4827
|
+
server,
|
|
4828
|
+
input_schema: tool.inputSchema
|
|
4829
|
+
}))
|
|
4830
|
+
)
|
|
4831
|
+
)};
|
|
4832
|
+
|
|
4833
|
+
const filtered = allTools.filter(tool => {
|
|
4834
|
+
if (!query) return true;
|
|
4835
|
+
const q = query.toLowerCase();
|
|
4836
|
+
return tool.name.toLowerCase().includes(q) ||
|
|
4837
|
+
(tool.description && tool.description.toLowerCase().includes(q));
|
|
4838
|
+
});
|
|
4839
|
+
|
|
4840
|
+
if (detailLevel === 'names') {
|
|
4841
|
+
return filtered.map(t => ({ name: t.name, server: t.server }));
|
|
4842
|
+
} else if (detailLevel === 'descriptions') {
|
|
4843
|
+
return filtered.map(t => ({ name: t.name, server: t.server, description: t.description }));
|
|
4844
|
+
}
|
|
4845
|
+
return filtered;
|
|
4846
|
+
};
|
|
4847
|
+
`;
|
|
4848
|
+
for (const [serverName, serverTools] of Object.entries(tools)) {
|
|
4849
|
+
if (!serverTools || serverTools.length === 0) continue;
|
|
4850
|
+
const safeServerName = serverName.replace(/[^a-zA-Z0-9_]/g, "_");
|
|
4851
|
+
shim += `
|
|
4852
|
+
global['${serverName}'] = {`;
|
|
4853
|
+
for (const tool of serverTools) {
|
|
4854
|
+
shim += `
|
|
4855
|
+
'${tool.name}': async (args) => await global.__callMcpTool('${serverName}', '${tool.name}', args),`;
|
|
4856
|
+
}
|
|
4857
|
+
shim += `
|
|
4858
|
+
};
|
|
4859
|
+
|
|
4860
|
+
// Also expose as safe name if different
|
|
4861
|
+
if ('${safeServerName}' !== '${serverName}') {
|
|
4862
|
+
global['${safeServerName}'] = global['${serverName}'];
|
|
4863
|
+
}
|
|
4864
|
+
`;
|
|
4865
|
+
}
|
|
4866
|
+
return shim;
|
|
4867
|
+
}
|
|
4868
|
+
/**
|
|
4869
|
+
* Build the tool catalog for the shim.
|
|
4870
|
+
* Returns a map of server names to their available tools.
|
|
4871
|
+
*/
|
|
4872
|
+
buildToolCatalog() {
|
|
4873
|
+
const catalog = {};
|
|
4874
|
+
const namespaces = this.getToolNamespaces();
|
|
4875
|
+
for (const { serverName, tools } of namespaces) {
|
|
4876
|
+
catalog[serverName] = tools;
|
|
4877
|
+
}
|
|
4878
|
+
return catalog;
|
|
4879
|
+
}
|
|
4880
|
+
/**
|
|
4881
|
+
* Execute JavaScript/TypeScript code in an E2B sandbox with MCP tool access.
|
|
4882
|
+
* Tool calls are proxied back to the host via the bridge pattern.
|
|
4883
|
+
*
|
|
4884
|
+
* @param code - Code to execute
|
|
4885
|
+
* @param timeout - Execution timeout in milliseconds (default: 30000)
|
|
4886
|
+
*/
|
|
4887
|
+
async execute(code, timeout = 3e4) {
|
|
4888
|
+
const startTime = Date.now();
|
|
4889
|
+
let result = null;
|
|
4890
|
+
let error = null;
|
|
4891
|
+
let logs = [];
|
|
4892
|
+
try {
|
|
4893
|
+
await this.ensureServersConnected();
|
|
4894
|
+
const sandbox = await this.getOrCreateCodeExecSandbox();
|
|
4895
|
+
const toolCatalog = this.buildToolCatalog();
|
|
4896
|
+
const shim = this.generateShim(toolCatalog);
|
|
4897
|
+
const wrappedCode = `
|
|
4898
|
+
${shim}
|
|
4899
|
+
|
|
4900
|
+
(async () => {
|
|
4901
|
+
try {
|
|
4902
|
+
const func = async () => {
|
|
4903
|
+
${code}
|
|
4904
|
+
};
|
|
4905
|
+
const result = await func();
|
|
4906
|
+
console.log('__MCP_RESULT_START__');
|
|
4907
|
+
console.log(JSON.stringify(result));
|
|
4908
|
+
console.log('__MCP_RESULT_END__');
|
|
4909
|
+
} catch (e) {
|
|
4910
|
+
console.error(e);
|
|
4911
|
+
process.exit(1);
|
|
4912
|
+
}
|
|
4913
|
+
})();
|
|
4914
|
+
`;
|
|
4915
|
+
const filename = `exec_${Date.now()}.js`;
|
|
4916
|
+
await sandbox.files.write(filename, wrappedCode);
|
|
4917
|
+
const execution = await sandbox.commands.run(`node ${filename}`, {
|
|
4918
|
+
timeoutMs: timeout,
|
|
4919
|
+
onStdout: /* @__PURE__ */ __name(async (data) => {
|
|
4920
|
+
try {
|
|
4921
|
+
const lines = data.split("\n");
|
|
4922
|
+
for (const line of lines) {
|
|
4923
|
+
if (line.trim().startsWith('{"type":"__MCP_TOOL_CALL__"')) {
|
|
4924
|
+
const call = JSON.parse(line);
|
|
4925
|
+
if (call.type === "__MCP_TOOL_CALL__") {
|
|
4926
|
+
try {
|
|
4927
|
+
logger.debug(
|
|
4928
|
+
`[E2B Bridge] Calling tool ${call.server}.${call.tool}`
|
|
4929
|
+
);
|
|
4930
|
+
const activeSessions = this.client.getAllActiveSessions();
|
|
4931
|
+
const session = activeSessions[call.server];
|
|
4932
|
+
if (!session) {
|
|
4933
|
+
throw new Error(`Server ${call.server} not found`);
|
|
4934
|
+
}
|
|
4935
|
+
const toolResult = await session.connector.callTool(
|
|
4936
|
+
call.tool,
|
|
4937
|
+
call.args
|
|
4938
|
+
);
|
|
4939
|
+
let extractedResult = toolResult;
|
|
4940
|
+
if (toolResult.content && toolResult.content.length > 0) {
|
|
4941
|
+
const item = toolResult.content[0];
|
|
4942
|
+
if (item.type === "text") {
|
|
4943
|
+
try {
|
|
4944
|
+
extractedResult = JSON.parse(item.text);
|
|
4945
|
+
} catch {
|
|
4946
|
+
extractedResult = item.text;
|
|
4947
|
+
}
|
|
4948
|
+
} else {
|
|
4949
|
+
extractedResult = item;
|
|
4950
|
+
}
|
|
4951
|
+
}
|
|
4952
|
+
const resultPath = `/tmp/mcp_result_${call.id}.json`;
|
|
4953
|
+
await sandbox.files.write(
|
|
4954
|
+
resultPath,
|
|
4955
|
+
JSON.stringify({ data: extractedResult })
|
|
4956
|
+
);
|
|
4957
|
+
} catch (err) {
|
|
4958
|
+
logger.error(
|
|
4959
|
+
`[E2B Bridge] Tool execution failed: ${err.message}`
|
|
4960
|
+
);
|
|
4961
|
+
const resultPath = `/tmp/mcp_result_${call.id}.json`;
|
|
4962
|
+
await sandbox.files.write(
|
|
4963
|
+
resultPath,
|
|
4964
|
+
JSON.stringify({
|
|
4965
|
+
error: err.message || String(err)
|
|
4966
|
+
})
|
|
4967
|
+
);
|
|
4968
|
+
}
|
|
4969
|
+
}
|
|
4970
|
+
}
|
|
4971
|
+
}
|
|
4972
|
+
} catch (e) {
|
|
4973
|
+
}
|
|
4974
|
+
}, "onStdout")
|
|
4975
|
+
});
|
|
4976
|
+
logs = [execution.stdout, execution.stderr].filter(Boolean);
|
|
4977
|
+
if (execution.exitCode !== 0) {
|
|
4978
|
+
error = execution.stderr || "Execution failed";
|
|
4979
|
+
} else {
|
|
4980
|
+
const stdout = execution.stdout;
|
|
4981
|
+
const startMarker = "__MCP_RESULT_START__";
|
|
4982
|
+
const endMarker = "__MCP_RESULT_END__";
|
|
4983
|
+
const startIndex = stdout.indexOf(startMarker);
|
|
4984
|
+
const endIndex = stdout.indexOf(endMarker);
|
|
4985
|
+
if (startIndex !== -1 && endIndex !== -1) {
|
|
4986
|
+
const jsonStr = stdout.substring(startIndex + startMarker.length, endIndex).trim();
|
|
4987
|
+
try {
|
|
4988
|
+
result = JSON.parse(jsonStr);
|
|
4989
|
+
} catch (e) {
|
|
4990
|
+
result = jsonStr;
|
|
4991
|
+
}
|
|
4992
|
+
logs = logs.map((log) => {
|
|
4993
|
+
let cleaned = log.replace(
|
|
4994
|
+
new RegExp(startMarker + "[\\s\\S]*?" + endMarker),
|
|
4995
|
+
"[Result captured]"
|
|
4996
|
+
);
|
|
4997
|
+
cleaned = cleaned.split("\n").filter((l) => !l.includes("__MCP_TOOL_CALL__")).join("\n");
|
|
4998
|
+
return cleaned;
|
|
4999
|
+
});
|
|
5000
|
+
}
|
|
5001
|
+
}
|
|
5002
|
+
} catch (e) {
|
|
5003
|
+
error = e.message || String(e);
|
|
5004
|
+
if (error && (error.includes("timeout") || error.includes("timed out"))) {
|
|
5005
|
+
error = "Script execution timed out";
|
|
5006
|
+
}
|
|
5007
|
+
}
|
|
5008
|
+
return {
|
|
5009
|
+
result,
|
|
5010
|
+
logs,
|
|
5011
|
+
error,
|
|
5012
|
+
execution_time: (Date.now() - startTime) / 1e3
|
|
5013
|
+
};
|
|
5014
|
+
}
|
|
5015
|
+
/**
|
|
5016
|
+
* Clean up the E2B sandbox.
|
|
5017
|
+
* Should be called when the executor is no longer needed.
|
|
5018
|
+
*/
|
|
5019
|
+
async cleanup() {
|
|
5020
|
+
if (this.codeExecSandbox) {
|
|
5021
|
+
try {
|
|
5022
|
+
await this.codeExecSandbox.kill();
|
|
5023
|
+
this.codeExecSandbox = null;
|
|
5024
|
+
logger.debug("E2B code execution sandbox stopped");
|
|
5025
|
+
} catch (error) {
|
|
5026
|
+
logger.error("Failed to stop E2B code execution sandbox:", error);
|
|
5027
|
+
}
|
|
5028
|
+
}
|
|
5029
|
+
}
|
|
5030
|
+
};
|
|
5031
|
+
|
|
5032
|
+
// src/client/executors/vm.ts
|
|
5033
|
+
init_logging();
|
|
5034
|
+
var vm = null;
|
|
5035
|
+
var vmCheckAttempted = false;
|
|
5036
|
+
function getVMModuleName() {
|
|
5037
|
+
return ["node", "vm"].join(":");
|
|
5038
|
+
}
|
|
5039
|
+
__name(getVMModuleName, "getVMModuleName");
|
|
5040
|
+
function tryLoadVM() {
|
|
5041
|
+
if (vmCheckAttempted) {
|
|
5042
|
+
return vm !== null;
|
|
5043
|
+
}
|
|
5044
|
+
vmCheckAttempted = true;
|
|
5045
|
+
try {
|
|
5046
|
+
const nodeRequire = typeof require !== "undefined" ? require : null;
|
|
5047
|
+
if (nodeRequire) {
|
|
5048
|
+
vm = nodeRequire(getVMModuleName());
|
|
5049
|
+
return true;
|
|
5050
|
+
}
|
|
5051
|
+
} catch (error) {
|
|
5052
|
+
logger.debug("node:vm module not available via require");
|
|
5053
|
+
}
|
|
5054
|
+
return false;
|
|
5055
|
+
}
|
|
5056
|
+
__name(tryLoadVM, "tryLoadVM");
|
|
5057
|
+
async function tryLoadVMAsync() {
|
|
5058
|
+
if (vm !== null) {
|
|
5059
|
+
return true;
|
|
5060
|
+
}
|
|
5061
|
+
if (!vmCheckAttempted) {
|
|
5062
|
+
if (tryLoadVM()) {
|
|
5063
|
+
return true;
|
|
5064
|
+
}
|
|
5065
|
+
}
|
|
5066
|
+
try {
|
|
5067
|
+
vm = await import(
|
|
5068
|
+
/* @vite-ignore */
|
|
5069
|
+
getVMModuleName()
|
|
5070
|
+
);
|
|
5071
|
+
return true;
|
|
5072
|
+
} catch (error) {
|
|
5073
|
+
logger.debug(
|
|
5074
|
+
"node:vm module not available in this environment (e.g., Deno)"
|
|
5075
|
+
);
|
|
5076
|
+
return false;
|
|
5077
|
+
}
|
|
5078
|
+
}
|
|
5079
|
+
__name(tryLoadVMAsync, "tryLoadVMAsync");
|
|
5080
|
+
var VMCodeExecutor = class extends BaseCodeExecutor {
|
|
5081
|
+
static {
|
|
5082
|
+
__name(this, "VMCodeExecutor");
|
|
5083
|
+
}
|
|
5084
|
+
defaultTimeout;
|
|
5085
|
+
memoryLimitMb;
|
|
5086
|
+
constructor(client, options) {
|
|
5087
|
+
super(client);
|
|
5088
|
+
this.defaultTimeout = options?.timeoutMs ?? 3e4;
|
|
5089
|
+
this.memoryLimitMb = options?.memoryLimitMb;
|
|
5090
|
+
tryLoadVM();
|
|
5091
|
+
}
|
|
5092
|
+
/**
|
|
5093
|
+
* Ensure VM module is loaded before execution
|
|
5094
|
+
*/
|
|
5095
|
+
async ensureVMLoaded() {
|
|
5096
|
+
if (vm !== null) {
|
|
5097
|
+
return;
|
|
5098
|
+
}
|
|
5099
|
+
const loaded = await tryLoadVMAsync();
|
|
5100
|
+
if (!loaded) {
|
|
5101
|
+
throw new Error(
|
|
5102
|
+
"node:vm module is not available in this environment. Please use E2B executor instead or run in a Node.js environment."
|
|
5103
|
+
);
|
|
5104
|
+
}
|
|
5105
|
+
}
|
|
5106
|
+
/**
|
|
5107
|
+
* Execute JavaScript/TypeScript code with access to MCP tools.
|
|
5108
|
+
*
|
|
5109
|
+
* @param code - Code to execute
|
|
5110
|
+
* @param timeout - Execution timeout in milliseconds (default: configured timeout or 30000)
|
|
5111
|
+
*/
|
|
5112
|
+
async execute(code, timeout) {
|
|
5113
|
+
const effectiveTimeout = timeout ?? this.defaultTimeout;
|
|
5114
|
+
await this.ensureVMLoaded();
|
|
5115
|
+
await this.ensureServersConnected();
|
|
5116
|
+
const logs = [];
|
|
5117
|
+
const startTime = Date.now();
|
|
5118
|
+
let result = null;
|
|
5119
|
+
let error = null;
|
|
5120
|
+
try {
|
|
5121
|
+
const context = await this._buildContext(logs);
|
|
5122
|
+
const wrappedCode = `
|
|
5123
|
+
(async () => {
|
|
5124
|
+
try {
|
|
5125
|
+
${code}
|
|
5126
|
+
} catch (e) {
|
|
5127
|
+
throw e;
|
|
5128
|
+
}
|
|
5129
|
+
})()
|
|
5130
|
+
`;
|
|
5131
|
+
const script = new vm.Script(wrappedCode, {
|
|
5132
|
+
filename: "agent_code.js"
|
|
5133
|
+
});
|
|
5134
|
+
const promise = script.runInNewContext(context, {
|
|
5135
|
+
timeout: effectiveTimeout,
|
|
5136
|
+
displayErrors: true
|
|
5137
|
+
});
|
|
5138
|
+
result = await promise;
|
|
5139
|
+
} catch (e) {
|
|
5140
|
+
error = e.message || String(e);
|
|
5141
|
+
if (e.code === "ERR_SCRIPT_EXECUTION_TIMEOUT" || e.message === "Script execution timed out." || typeof error === "string" && (error.includes("timed out") || error.includes("timeout"))) {
|
|
5142
|
+
error = "Script execution timed out";
|
|
5143
|
+
}
|
|
5144
|
+
if (e.stack) {
|
|
5145
|
+
logger.debug(`Code execution error stack: ${e.stack}`);
|
|
5146
|
+
}
|
|
5147
|
+
}
|
|
5148
|
+
const executionTime = (Date.now() - startTime) / 1e3;
|
|
5149
|
+
return {
|
|
5150
|
+
result,
|
|
5151
|
+
logs,
|
|
5152
|
+
error,
|
|
5153
|
+
execution_time: executionTime
|
|
5154
|
+
};
|
|
5155
|
+
}
|
|
5156
|
+
/**
|
|
5157
|
+
* Build the VM execution context with MCP tools and standard globals.
|
|
5158
|
+
*
|
|
5159
|
+
* @param logs - Array to capture console output
|
|
5160
|
+
*/
|
|
5161
|
+
async _buildContext(logs) {
|
|
5162
|
+
const logHandler = /* @__PURE__ */ __name((...args) => {
|
|
5163
|
+
logs.push(
|
|
5164
|
+
args.map(
|
|
5165
|
+
(arg) => typeof arg === "object" ? JSON.stringify(arg, null, 2) : String(arg)
|
|
5166
|
+
).join(" ")
|
|
5167
|
+
);
|
|
5168
|
+
}, "logHandler");
|
|
5169
|
+
const sandbox = {
|
|
5170
|
+
console: {
|
|
5171
|
+
log: logHandler,
|
|
5172
|
+
error: /* @__PURE__ */ __name((...args) => {
|
|
5173
|
+
logHandler("[ERROR]", ...args);
|
|
5174
|
+
}, "error"),
|
|
5175
|
+
warn: /* @__PURE__ */ __name((...args) => {
|
|
5176
|
+
logHandler("[WARN]", ...args);
|
|
5177
|
+
}, "warn"),
|
|
5178
|
+
info: logHandler,
|
|
5179
|
+
debug: logHandler
|
|
5180
|
+
},
|
|
5181
|
+
// Standard globals
|
|
5182
|
+
Object,
|
|
5183
|
+
Array,
|
|
5184
|
+
String,
|
|
5185
|
+
Number,
|
|
5186
|
+
Boolean,
|
|
5187
|
+
Date,
|
|
5188
|
+
Math,
|
|
5189
|
+
JSON,
|
|
5190
|
+
RegExp,
|
|
5191
|
+
Map,
|
|
5192
|
+
Set,
|
|
5193
|
+
Promise,
|
|
5194
|
+
parseInt,
|
|
5195
|
+
parseFloat,
|
|
5196
|
+
isNaN,
|
|
5197
|
+
isFinite,
|
|
5198
|
+
encodeURI,
|
|
5199
|
+
decodeURI,
|
|
5200
|
+
encodeURIComponent,
|
|
5201
|
+
decodeURIComponent,
|
|
5202
|
+
setTimeout,
|
|
5203
|
+
clearTimeout,
|
|
5204
|
+
// Helper for tools
|
|
5205
|
+
search_tools: this.createSearchToolsFunction(),
|
|
5206
|
+
__tool_namespaces: []
|
|
5207
|
+
};
|
|
5208
|
+
const toolNamespaces = {};
|
|
5209
|
+
const namespaceInfos = this.getToolNamespaces();
|
|
5210
|
+
for (const { serverName, tools, session } of namespaceInfos) {
|
|
5211
|
+
const serverNamespace = {};
|
|
5212
|
+
for (const tool of tools) {
|
|
5213
|
+
const toolName = tool.name;
|
|
5214
|
+
serverNamespace[toolName] = async (args) => {
|
|
5215
|
+
const result = await session.connector.callTool(toolName, args || {});
|
|
5216
|
+
if (result.content && result.content.length > 0) {
|
|
5217
|
+
const item = result.content[0];
|
|
5218
|
+
if (item.type === "text") {
|
|
5219
|
+
try {
|
|
5220
|
+
return JSON.parse(item.text);
|
|
5221
|
+
} catch {
|
|
5222
|
+
return item.text;
|
|
5223
|
+
}
|
|
5224
|
+
}
|
|
5225
|
+
return item;
|
|
5226
|
+
}
|
|
5227
|
+
return result;
|
|
5228
|
+
};
|
|
5229
|
+
}
|
|
5230
|
+
sandbox[serverName] = serverNamespace;
|
|
5231
|
+
toolNamespaces[serverName] = true;
|
|
5232
|
+
}
|
|
5233
|
+
sandbox.__tool_namespaces = Object.keys(toolNamespaces);
|
|
5234
|
+
return vm.createContext(sandbox);
|
|
5235
|
+
}
|
|
5236
|
+
/**
|
|
5237
|
+
* Clean up resources.
|
|
5238
|
+
* VM executor doesn't need cleanup, but method kept for interface consistency.
|
|
5239
|
+
*/
|
|
5240
|
+
async cleanup() {
|
|
5241
|
+
}
|
|
5242
|
+
};
|
|
5243
|
+
|
|
5244
|
+
// src/client/connectors/codeMode.ts
|
|
5245
|
+
var CodeModeConnector = class extends BaseConnector {
|
|
5246
|
+
static {
|
|
5247
|
+
__name(this, "CodeModeConnector");
|
|
5248
|
+
}
|
|
5249
|
+
mcpClient;
|
|
5250
|
+
_tools;
|
|
5251
|
+
constructor(client) {
|
|
5252
|
+
super();
|
|
5253
|
+
this.mcpClient = client;
|
|
5254
|
+
this.connected = true;
|
|
5255
|
+
this._tools = this._createToolsList();
|
|
5256
|
+
}
|
|
5257
|
+
async connect() {
|
|
5258
|
+
this.connected = true;
|
|
5259
|
+
}
|
|
5260
|
+
async disconnect() {
|
|
5261
|
+
this.connected = false;
|
|
5262
|
+
}
|
|
5263
|
+
get publicIdentifier() {
|
|
5264
|
+
return { name: "code_mode", version: "1.0.0" };
|
|
5265
|
+
}
|
|
5266
|
+
_createToolsList() {
|
|
5267
|
+
return [
|
|
5268
|
+
{
|
|
5269
|
+
name: "execute_code",
|
|
5270
|
+
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.",
|
|
5271
|
+
inputSchema: {
|
|
5272
|
+
type: "object",
|
|
5273
|
+
properties: {
|
|
5274
|
+
code: {
|
|
5275
|
+
type: "string",
|
|
5276
|
+
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"
|
|
5277
|
+
},
|
|
5278
|
+
timeout: {
|
|
5279
|
+
type: "number",
|
|
5280
|
+
description: "Execution timeout in milliseconds",
|
|
5281
|
+
default: 3e4
|
|
5282
|
+
}
|
|
5283
|
+
},
|
|
5284
|
+
required: ["code"]
|
|
5285
|
+
}
|
|
5286
|
+
},
|
|
5287
|
+
{
|
|
5288
|
+
name: "search_tools",
|
|
5289
|
+
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.",
|
|
5290
|
+
inputSchema: {
|
|
5291
|
+
type: "object",
|
|
5292
|
+
properties: {
|
|
5293
|
+
query: {
|
|
5294
|
+
type: "string",
|
|
5295
|
+
description: "Search query to filter tools by name or description",
|
|
5296
|
+
default: ""
|
|
5297
|
+
},
|
|
5298
|
+
detail_level: {
|
|
5299
|
+
type: "string",
|
|
5300
|
+
description: "Detail level: 'names', 'descriptions', or 'full'",
|
|
5301
|
+
enum: ["names", "descriptions", "full"],
|
|
5302
|
+
default: "full"
|
|
5303
|
+
}
|
|
5304
|
+
}
|
|
5305
|
+
}
|
|
5306
|
+
}
|
|
5307
|
+
];
|
|
5308
|
+
}
|
|
5309
|
+
// Override tools getter to return static list immediately
|
|
5310
|
+
get tools() {
|
|
5311
|
+
return this._tools;
|
|
5312
|
+
}
|
|
5313
|
+
async initialize() {
|
|
5314
|
+
this.toolsCache = this._tools;
|
|
5315
|
+
return { capabilities: {}, version: "1.0.0" };
|
|
5316
|
+
}
|
|
5317
|
+
async callTool(name, args) {
|
|
5318
|
+
if (name === "execute_code") {
|
|
5319
|
+
const code = args.code;
|
|
5320
|
+
const timeout = args.timeout || 3e4;
|
|
5321
|
+
const result = await this.mcpClient.executeCode(code, timeout);
|
|
5322
|
+
return {
|
|
5323
|
+
content: [
|
|
5324
|
+
{
|
|
5325
|
+
type: "text",
|
|
5326
|
+
text: JSON.stringify(result)
|
|
5327
|
+
}
|
|
5328
|
+
]
|
|
5329
|
+
};
|
|
5330
|
+
} else if (name === "search_tools") {
|
|
5331
|
+
const query = args.query || "";
|
|
5332
|
+
const detailLevel = args.detail_level;
|
|
5333
|
+
const result = await this.mcpClient.searchTools(
|
|
5334
|
+
query,
|
|
5335
|
+
detailLevel && detailLevel in ["names", "descriptions", "full"] ? detailLevel : "full"
|
|
5336
|
+
);
|
|
5337
|
+
return {
|
|
5338
|
+
content: [
|
|
5339
|
+
{
|
|
5340
|
+
type: "text",
|
|
5341
|
+
text: JSON.stringify(result)
|
|
5342
|
+
}
|
|
5343
|
+
]
|
|
5344
|
+
};
|
|
5345
|
+
}
|
|
5346
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
5347
|
+
}
|
|
5348
|
+
};
|
|
5349
|
+
|
|
5350
|
+
// src/config.ts
|
|
5351
|
+
var import_node_fs = require("fs");
|
|
5352
|
+
|
|
5353
|
+
// src/connectors/stdio.ts
|
|
5354
|
+
var import_node_process = __toESM(require("process"), 1);
|
|
5355
|
+
var import_client2 = require("@mcp-use/modelcontextprotocol-sdk/client/index.js");
|
|
5356
|
+
init_logging();
|
|
5357
|
+
|
|
5358
|
+
// src/task_managers/stdio.ts
|
|
5359
|
+
var import_stdio = require("@mcp-use/modelcontextprotocol-sdk/client/stdio.js");
|
|
5360
|
+
init_logging();
|
|
5361
|
+
var StdioConnectionManager = class extends ConnectionManager {
|
|
5362
|
+
static {
|
|
5363
|
+
__name(this, "StdioConnectionManager");
|
|
5364
|
+
}
|
|
5365
|
+
serverParams;
|
|
5366
|
+
errlog;
|
|
5367
|
+
_transport = null;
|
|
5368
|
+
/**
|
|
5369
|
+
* Create a new stdio connection manager.
|
|
5370
|
+
*
|
|
5371
|
+
* @param serverParams Parameters for the stdio server process.
|
|
5372
|
+
* @param errlog Stream to which the server's stderr should be piped.
|
|
5373
|
+
* Defaults to `process.stderr`.
|
|
5374
|
+
*/
|
|
5375
|
+
constructor(serverParams, errlog = process.stderr) {
|
|
5376
|
+
super();
|
|
5377
|
+
this.serverParams = serverParams;
|
|
5378
|
+
this.errlog = errlog;
|
|
5379
|
+
}
|
|
5380
|
+
/**
|
|
5381
|
+
* Establish the stdio connection by spawning the server process and starting
|
|
5382
|
+
* the SDK's transport. Returns the live `StdioClientTransport` instance.
|
|
5383
|
+
*/
|
|
5384
|
+
async establishConnection() {
|
|
5385
|
+
this._transport = new import_stdio.StdioClientTransport(this.serverParams);
|
|
5386
|
+
if (this._transport.stderr && typeof this._transport.stderr.pipe === "function") {
|
|
5387
|
+
this._transport.stderr.pipe(
|
|
5388
|
+
this.errlog
|
|
5389
|
+
);
|
|
5390
|
+
}
|
|
5391
|
+
logger.debug(`${this.constructor.name} connected successfully`);
|
|
5392
|
+
return this._transport;
|
|
5393
|
+
}
|
|
5394
|
+
/**
|
|
5395
|
+
* Close the stdio connection, making sure the transport cleans up the child
|
|
5396
|
+
* process and associated resources.
|
|
5397
|
+
*/
|
|
5398
|
+
async closeConnection(_connection) {
|
|
5399
|
+
if (this._transport) {
|
|
5400
|
+
try {
|
|
5401
|
+
await this._transport.close();
|
|
5402
|
+
} catch (e) {
|
|
5403
|
+
logger.warn(`Error closing stdio transport: ${e}`);
|
|
5404
|
+
} finally {
|
|
5405
|
+
this._transport = null;
|
|
5406
|
+
}
|
|
5407
|
+
}
|
|
5408
|
+
}
|
|
5409
|
+
};
|
|
5410
|
+
|
|
5411
|
+
// src/connectors/stdio.ts
|
|
5412
|
+
var StdioConnector = class extends BaseConnector {
|
|
5413
|
+
static {
|
|
5414
|
+
__name(this, "StdioConnector");
|
|
5415
|
+
}
|
|
5416
|
+
command;
|
|
5417
|
+
args;
|
|
5418
|
+
env;
|
|
5419
|
+
errlog;
|
|
5420
|
+
clientInfo;
|
|
5421
|
+
constructor({
|
|
5422
|
+
command = "npx",
|
|
5423
|
+
args = [],
|
|
5424
|
+
env,
|
|
5425
|
+
errlog = import_node_process.default.stderr,
|
|
5426
|
+
...rest
|
|
5427
|
+
} = {}) {
|
|
5428
|
+
super(rest);
|
|
5429
|
+
this.command = command;
|
|
5430
|
+
this.args = args;
|
|
5431
|
+
this.env = env;
|
|
5432
|
+
this.errlog = errlog;
|
|
5433
|
+
this.clientInfo = rest.clientInfo ?? {
|
|
5434
|
+
name: "stdio-connector",
|
|
5435
|
+
version: "1.0.0"
|
|
5436
|
+
};
|
|
5437
|
+
}
|
|
5438
|
+
/** Establish connection to the MCP implementation. */
|
|
5439
|
+
async connect() {
|
|
5440
|
+
if (this.connected) {
|
|
5441
|
+
logger.debug("Already connected to MCP implementation");
|
|
5442
|
+
return;
|
|
5443
|
+
}
|
|
5444
|
+
logger.debug(`Connecting to MCP implementation via stdio: ${this.command}`);
|
|
5445
|
+
try {
|
|
5446
|
+
let mergedEnv;
|
|
5447
|
+
if (this.env) {
|
|
5448
|
+
mergedEnv = {};
|
|
5449
|
+
for (const [key, value] of Object.entries(import_node_process.default.env)) {
|
|
5450
|
+
if (value !== void 0) {
|
|
5451
|
+
mergedEnv[key] = value;
|
|
5452
|
+
}
|
|
5453
|
+
}
|
|
5454
|
+
Object.assign(mergedEnv, this.env);
|
|
5455
|
+
}
|
|
5456
|
+
const serverParams = {
|
|
5457
|
+
command: this.command,
|
|
5458
|
+
args: this.args,
|
|
5459
|
+
env: mergedEnv
|
|
5460
|
+
};
|
|
5461
|
+
this.connectionManager = new StdioConnectionManager(
|
|
5462
|
+
serverParams,
|
|
5463
|
+
this.errlog
|
|
5464
|
+
);
|
|
5465
|
+
const transport = await this.connectionManager.start();
|
|
5466
|
+
const clientOptions = {
|
|
5467
|
+
...this.opts.clientOptions || {},
|
|
5468
|
+
capabilities: {
|
|
5469
|
+
...this.opts.clientOptions?.capabilities || {},
|
|
5470
|
+
roots: { listChanged: true },
|
|
5471
|
+
// Always advertise roots capability
|
|
5472
|
+
// Add sampling capability if callback is provided
|
|
5473
|
+
...this.opts.samplingCallback ? { sampling: {} } : {},
|
|
5474
|
+
// Add elicitation capability if callback is provided
|
|
5475
|
+
...this.opts.elicitationCallback ? { elicitation: { form: {}, url: {} } } : {}
|
|
5476
|
+
}
|
|
5477
|
+
};
|
|
5478
|
+
this.client = new import_client2.Client(this.clientInfo, clientOptions);
|
|
5479
|
+
await this.client.connect(transport);
|
|
5480
|
+
this.connected = true;
|
|
5481
|
+
this.setupNotificationHandler();
|
|
5482
|
+
this.setupRootsHandler();
|
|
5483
|
+
this.setupSamplingHandler();
|
|
5484
|
+
this.setupElicitationHandler();
|
|
5485
|
+
logger.debug(
|
|
5486
|
+
`Successfully connected to MCP implementation: ${this.command}`
|
|
5487
|
+
);
|
|
5488
|
+
this.trackConnectorInit({
|
|
5489
|
+
serverCommand: this.command,
|
|
5490
|
+
serverArgs: this.args,
|
|
5491
|
+
publicIdentifier: `${this.command} ${this.args.join(" ")}`
|
|
5492
|
+
});
|
|
5493
|
+
} catch (err) {
|
|
5494
|
+
logger.error(`Failed to connect to MCP implementation: ${err}`);
|
|
5495
|
+
await this.cleanupResources();
|
|
5496
|
+
throw err;
|
|
5497
|
+
}
|
|
5498
|
+
}
|
|
5499
|
+
get publicIdentifier() {
|
|
5500
|
+
return {
|
|
5501
|
+
type: "stdio",
|
|
5502
|
+
"command&args": `${this.command} ${this.args.join(" ")}`
|
|
5503
|
+
};
|
|
5504
|
+
}
|
|
5505
|
+
};
|
|
5506
|
+
|
|
5507
|
+
// src/config.ts
|
|
5508
|
+
function loadConfigFile(filepath) {
|
|
5509
|
+
const raw = (0, import_node_fs.readFileSync)(filepath, "utf-8");
|
|
5510
|
+
return JSON.parse(raw);
|
|
5511
|
+
}
|
|
5512
|
+
__name(loadConfigFile, "loadConfigFile");
|
|
5513
|
+
function createConnectorFromConfig(serverConfig, connectorOptions) {
|
|
5514
|
+
if ("command" in serverConfig && "args" in serverConfig) {
|
|
5515
|
+
return new StdioConnector({
|
|
5516
|
+
command: serverConfig.command,
|
|
5517
|
+
args: serverConfig.args,
|
|
5518
|
+
env: serverConfig.env,
|
|
5519
|
+
...connectorOptions
|
|
5520
|
+
});
|
|
5521
|
+
}
|
|
5522
|
+
if ("url" in serverConfig) {
|
|
5523
|
+
const transport = serverConfig.transport || "http";
|
|
5524
|
+
return new HttpConnector(serverConfig.url, {
|
|
5525
|
+
headers: serverConfig.headers,
|
|
5526
|
+
authToken: serverConfig.auth_token || serverConfig.authToken,
|
|
5527
|
+
// Only force SSE if explicitly requested
|
|
5528
|
+
preferSse: serverConfig.preferSse || transport === "sse",
|
|
5529
|
+
...connectorOptions
|
|
5530
|
+
});
|
|
5531
|
+
}
|
|
5532
|
+
throw new Error("Cannot determine connector type from config");
|
|
5533
|
+
}
|
|
5534
|
+
__name(createConnectorFromConfig, "createConnectorFromConfig");
|
|
5535
|
+
|
|
5536
|
+
// src/client.ts
|
|
5537
|
+
init_logging();
|
|
5538
|
+
var MCPClient = class _MCPClient extends BaseMCPClient {
|
|
5539
|
+
static {
|
|
5540
|
+
__name(this, "MCPClient");
|
|
5541
|
+
}
|
|
5542
|
+
/**
|
|
5543
|
+
* Get the mcp-use package version.
|
|
5544
|
+
* Works in all environments (Node.js, browser, Cloudflare Workers, Deno, etc.)
|
|
5545
|
+
*/
|
|
5546
|
+
static getPackageVersion() {
|
|
5547
|
+
return getPackageVersion();
|
|
5548
|
+
}
|
|
5549
|
+
codeMode = false;
|
|
5550
|
+
_codeExecutor = null;
|
|
5551
|
+
_customCodeExecutor = null;
|
|
5552
|
+
_codeExecutorConfig = "vm";
|
|
5553
|
+
_executorOptions;
|
|
5554
|
+
_samplingCallback;
|
|
5555
|
+
_elicitationCallback;
|
|
5556
|
+
constructor(config, options) {
|
|
5557
|
+
if (config) {
|
|
5558
|
+
if (typeof config === "string") {
|
|
5559
|
+
super(loadConfigFile(config));
|
|
5560
|
+
} else {
|
|
5561
|
+
super(config);
|
|
5562
|
+
}
|
|
5563
|
+
} else {
|
|
5564
|
+
super();
|
|
5565
|
+
}
|
|
5566
|
+
let codeModeEnabled = false;
|
|
5567
|
+
let executorConfig = "vm";
|
|
5568
|
+
let executorOptions;
|
|
5569
|
+
if (options?.codeMode) {
|
|
5570
|
+
if (typeof options.codeMode === "boolean") {
|
|
5571
|
+
codeModeEnabled = options.codeMode;
|
|
5572
|
+
} else {
|
|
5573
|
+
codeModeEnabled = options.codeMode.enabled;
|
|
5574
|
+
executorConfig = options.codeMode.executor ?? "vm";
|
|
5575
|
+
executorOptions = options.codeMode.executorOptions;
|
|
5576
|
+
}
|
|
5577
|
+
}
|
|
5578
|
+
this.codeMode = codeModeEnabled;
|
|
5579
|
+
this._codeExecutorConfig = executorConfig;
|
|
5580
|
+
this._executorOptions = executorOptions;
|
|
5581
|
+
this._samplingCallback = options?.samplingCallback;
|
|
5582
|
+
this._elicitationCallback = options?.elicitationCallback;
|
|
5583
|
+
if (this.codeMode) {
|
|
5584
|
+
this._setupCodeModeConnector();
|
|
5585
|
+
}
|
|
5586
|
+
this._trackClientInit();
|
|
5587
|
+
}
|
|
5588
|
+
_trackClientInit() {
|
|
5589
|
+
const servers = Object.keys(this.config.mcpServers ?? {});
|
|
5590
|
+
const hasSamplingCallback = !!this._samplingCallback;
|
|
5591
|
+
const hasElicitationCallback = !!this._elicitationCallback;
|
|
5592
|
+
Tel.getInstance().trackMCPClientInit({
|
|
5593
|
+
codeMode: this.codeMode,
|
|
5594
|
+
sandbox: false,
|
|
5595
|
+
// Sandbox not supported in TS yet
|
|
5596
|
+
allCallbacks: hasSamplingCallback && hasElicitationCallback,
|
|
5597
|
+
verify: false,
|
|
5598
|
+
// No verify option in TS client
|
|
5599
|
+
servers,
|
|
5600
|
+
numServers: servers.length,
|
|
5601
|
+
isBrowser: false
|
|
5602
|
+
// Node.js MCPClient
|
|
5603
|
+
}).catch((e) => logger.debug(`Failed to track MCPClient init: ${e}`));
|
|
5604
|
+
}
|
|
5605
|
+
static fromDict(cfg, options) {
|
|
5606
|
+
return new _MCPClient(cfg, options);
|
|
5607
|
+
}
|
|
5608
|
+
static fromConfigFile(path2, options) {
|
|
5609
|
+
return new _MCPClient(loadConfigFile(path2), options);
|
|
5610
|
+
}
|
|
5611
|
+
/**
|
|
5612
|
+
* Save configuration to a file (Node.js only)
|
|
5613
|
+
*/
|
|
5614
|
+
saveConfig(filepath) {
|
|
5615
|
+
const dir = import_node_path.default.dirname(filepath);
|
|
5616
|
+
if (!import_node_fs2.default.existsSync(dir)) {
|
|
5617
|
+
import_node_fs2.default.mkdirSync(dir, { recursive: true });
|
|
5618
|
+
}
|
|
5619
|
+
import_node_fs2.default.writeFileSync(filepath, JSON.stringify(this.config, null, 2), "utf-8");
|
|
5620
|
+
}
|
|
5621
|
+
/**
|
|
5622
|
+
* Create a connector from server configuration (Node.js version)
|
|
5623
|
+
* Supports all connector types including StdioConnector
|
|
5624
|
+
*/
|
|
5625
|
+
createConnectorFromConfig(serverConfig) {
|
|
5626
|
+
return createConnectorFromConfig(serverConfig, {
|
|
5627
|
+
samplingCallback: this._samplingCallback,
|
|
5628
|
+
elicitationCallback: this._elicitationCallback
|
|
5629
|
+
});
|
|
5630
|
+
}
|
|
5631
|
+
_setupCodeModeConnector() {
|
|
5632
|
+
logger.debug("Code mode connector initialized as internal meta server");
|
|
5633
|
+
const connector = new CodeModeConnector(this);
|
|
5634
|
+
const session = new MCPSession(connector);
|
|
5635
|
+
this.sessions["code_mode"] = session;
|
|
5636
|
+
this.activeSessions.push("code_mode");
|
|
5637
|
+
}
|
|
5638
|
+
_ensureCodeExecutor() {
|
|
5639
|
+
if (!this._codeExecutor) {
|
|
5640
|
+
const config = this._codeExecutorConfig;
|
|
5641
|
+
if (config instanceof BaseCodeExecutor) {
|
|
5642
|
+
this._codeExecutor = config;
|
|
5643
|
+
} else if (typeof config === "function") {
|
|
5644
|
+
this._customCodeExecutor = config;
|
|
5645
|
+
throw new Error(
|
|
5646
|
+
"Custom executor function should be handled in executeCode"
|
|
5647
|
+
);
|
|
5648
|
+
} else if (config === "e2b") {
|
|
5649
|
+
const opts = this._executorOptions;
|
|
5650
|
+
if (!opts?.apiKey) {
|
|
5651
|
+
logger.warn("E2B executor requires apiKey. Falling back to VM.");
|
|
5652
|
+
try {
|
|
5653
|
+
this._codeExecutor = new VMCodeExecutor(
|
|
5654
|
+
this,
|
|
5655
|
+
this._executorOptions
|
|
5656
|
+
);
|
|
5657
|
+
} catch (error) {
|
|
5658
|
+
throw new Error(
|
|
5659
|
+
"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."
|
|
5660
|
+
);
|
|
5661
|
+
}
|
|
5662
|
+
} else {
|
|
5663
|
+
this._codeExecutor = new E2BCodeExecutor(this, opts);
|
|
5664
|
+
}
|
|
5665
|
+
} else {
|
|
5666
|
+
try {
|
|
5667
|
+
this._codeExecutor = new VMCodeExecutor(
|
|
5668
|
+
this,
|
|
5669
|
+
this._executorOptions
|
|
5670
|
+
);
|
|
5671
|
+
} catch (error) {
|
|
5672
|
+
const e2bOpts = this._executorOptions;
|
|
5673
|
+
const e2bApiKey = e2bOpts?.apiKey || process.env.E2B_API_KEY;
|
|
5674
|
+
if (e2bApiKey) {
|
|
5675
|
+
logger.info(
|
|
5676
|
+
"VM executor not available in this environment. Falling back to E2B."
|
|
5677
|
+
);
|
|
5678
|
+
this._codeExecutor = new E2BCodeExecutor(this, {
|
|
5679
|
+
...e2bOpts,
|
|
5680
|
+
apiKey: e2bApiKey
|
|
5681
|
+
});
|
|
5682
|
+
} else {
|
|
5683
|
+
throw new Error(
|
|
5684
|
+
"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."
|
|
5685
|
+
);
|
|
5686
|
+
}
|
|
5687
|
+
}
|
|
5688
|
+
}
|
|
5689
|
+
}
|
|
5690
|
+
return this._codeExecutor;
|
|
5691
|
+
}
|
|
5692
|
+
/**
|
|
5693
|
+
* Execute code in code mode
|
|
5694
|
+
*/
|
|
5695
|
+
async executeCode(code, timeout) {
|
|
5696
|
+
if (!this.codeMode) {
|
|
5697
|
+
throw new Error("Code execution mode is not enabled");
|
|
5698
|
+
}
|
|
5699
|
+
if (this._customCodeExecutor) {
|
|
5700
|
+
return this._customCodeExecutor(code, timeout);
|
|
5701
|
+
}
|
|
5702
|
+
return this._ensureCodeExecutor().execute(code, timeout);
|
|
5703
|
+
}
|
|
5704
|
+
/**
|
|
5705
|
+
* Search available tools (used by code mode)
|
|
5706
|
+
*/
|
|
5707
|
+
async searchTools(query = "", detailLevel = "full") {
|
|
5708
|
+
if (!this.codeMode) {
|
|
5709
|
+
throw new Error("Code execution mode is not enabled");
|
|
5710
|
+
}
|
|
5711
|
+
return this._ensureCodeExecutor().createSearchToolsFunction()(
|
|
5712
|
+
query,
|
|
5713
|
+
detailLevel
|
|
5714
|
+
);
|
|
5715
|
+
}
|
|
5716
|
+
/**
|
|
5717
|
+
* Override getServerNames to exclude internal code_mode server
|
|
5718
|
+
*/
|
|
5719
|
+
getServerNames() {
|
|
5720
|
+
const isCodeModeEnabled = this.codeMode;
|
|
5721
|
+
return super.getServerNames().filter((name) => {
|
|
5722
|
+
return !isCodeModeEnabled || name !== "code_mode";
|
|
5723
|
+
});
|
|
5724
|
+
}
|
|
5725
|
+
/**
|
|
5726
|
+
* Close the client and clean up resources including code executors.
|
|
5727
|
+
* This ensures E2B sandboxes and other resources are properly released.
|
|
5728
|
+
*/
|
|
5729
|
+
async close() {
|
|
5730
|
+
if (this._codeExecutor) {
|
|
5731
|
+
await this._codeExecutor.cleanup();
|
|
5732
|
+
this._codeExecutor = null;
|
|
5733
|
+
}
|
|
5734
|
+
await this.closeAllSessions();
|
|
5735
|
+
}
|
|
5736
|
+
};
|
|
5737
|
+
|
|
5738
|
+
// src/agents/mcp_agent.ts
|
|
5739
|
+
init_logging();
|
|
5740
|
+
|
|
5741
|
+
// src/managers/server_manager.ts
|
|
5742
|
+
init_logging();
|
|
5743
|
+
|
|
5744
|
+
// src/managers/tools/acquire_active_mcp_server.ts
|
|
5745
|
+
var import_zod3 = require("zod");
|
|
4633
5746
|
|
|
4634
5747
|
// src/managers/tools/base.ts
|
|
4635
5748
|
var import_tools2 = require("@langchain/core/tools");
|
|
@@ -4759,15 +5872,21 @@ var ConnectMCPServerTool = class extends MCPServerTool {
|
|
|
4759
5872
|
session = await this.manager.client.createSession(serverName);
|
|
4760
5873
|
}
|
|
4761
5874
|
this.manager.activeServer = serverName;
|
|
4762
|
-
if (this.manager.serverTools[serverName]) {
|
|
5875
|
+
if (!this.manager.serverTools[serverName]) {
|
|
4763
5876
|
const connector = session.connector;
|
|
4764
5877
|
const tools = await this.manager.adapter.createToolsFromConnectors([connector]);
|
|
4765
|
-
this.manager.
|
|
5878
|
+
const resources = await this.manager.adapter.createResourcesFromConnectors([connector]);
|
|
5879
|
+
const prompts = await this.manager.adapter.createPromptsFromConnectors([connector]);
|
|
5880
|
+
const allItems = [...tools, ...resources, ...prompts];
|
|
5881
|
+
this.manager.serverTools[serverName] = allItems;
|
|
4766
5882
|
this.manager.initializedServers[serverName] = true;
|
|
5883
|
+
logger.debug(
|
|
5884
|
+
`Loaded ${allItems.length} items for server '${serverName}': ${tools.length} tools, ${resources.length} resources, ${prompts.length} prompts`
|
|
5885
|
+
);
|
|
4767
5886
|
}
|
|
4768
5887
|
const serverTools = this.manager.serverTools[serverName] || [];
|
|
4769
5888
|
const numTools = serverTools.length;
|
|
4770
|
-
return `Connected to MCP server '${serverName}'. ${numTools} tools are now available.`;
|
|
5889
|
+
return `Connected to MCP server '${serverName}'. ${numTools} tools, resources, and prompts are now available.`;
|
|
4771
5890
|
} catch (error) {
|
|
4772
5891
|
logger.error(
|
|
4773
5892
|
`Error connecting to server '${serverName}': ${String(error)}`
|
|
@@ -4929,21 +6048,30 @@ var ServerManager = class {
|
|
|
4929
6048
|
if (session) {
|
|
4930
6049
|
const connector = session.connector;
|
|
4931
6050
|
let tools = [];
|
|
6051
|
+
let resources = [];
|
|
6052
|
+
let prompts = [];
|
|
4932
6053
|
try {
|
|
4933
6054
|
tools = await this.adapter.createToolsFromConnectors([connector]);
|
|
6055
|
+
resources = await this.adapter.createResourcesFromConnectors([
|
|
6056
|
+
connector
|
|
6057
|
+
]);
|
|
6058
|
+
prompts = await this.adapter.createPromptsFromConnectors([
|
|
6059
|
+
connector
|
|
6060
|
+
]);
|
|
4934
6061
|
} catch (toolFetchError) {
|
|
4935
6062
|
logger.error(
|
|
4936
|
-
`Failed to create tools from connector for server '${serverName}': ${toolFetchError}`
|
|
6063
|
+
`Failed to create tools/resources/prompts from connector for server '${serverName}': ${toolFetchError}`
|
|
4937
6064
|
);
|
|
4938
6065
|
continue;
|
|
4939
6066
|
}
|
|
6067
|
+
const allItems = [...tools, ...resources, ...prompts];
|
|
4940
6068
|
const cachedTools = this.serverTools[serverName];
|
|
4941
|
-
const toolsChanged = !cachedTools || !isEqual(cachedTools,
|
|
6069
|
+
const toolsChanged = !cachedTools || !isEqual(cachedTools, allItems);
|
|
4942
6070
|
if (toolsChanged) {
|
|
4943
|
-
this.serverTools[serverName] =
|
|
6071
|
+
this.serverTools[serverName] = allItems;
|
|
4944
6072
|
this.initializedServers[serverName] = true;
|
|
4945
6073
|
logger.debug(
|
|
4946
|
-
`Prefetched ${
|
|
6074
|
+
`Prefetched ${allItems.length} items for server '${serverName}': ${tools.length} tools, ${resources.length} resources, ${prompts.length} prompts.`
|
|
4947
6075
|
);
|
|
4948
6076
|
} else {
|
|
4949
6077
|
logger.debug(
|
|
@@ -5271,6 +6399,26 @@ var import_zod8 = require("zod");
|
|
|
5271
6399
|
init_logging();
|
|
5272
6400
|
var API_CHATS_ENDPOINT = "/api/v1/chats";
|
|
5273
6401
|
var API_CHAT_EXECUTE_ENDPOINT = "/api/v1/chats/{chat_id}/execute";
|
|
6402
|
+
function normalizeRemoteRunOptions(queryOrOptions, maxSteps, manageConnector, externalHistory, outputSchema) {
|
|
6403
|
+
if (typeof queryOrOptions === "object" && queryOrOptions !== null) {
|
|
6404
|
+
const options = queryOrOptions;
|
|
6405
|
+
return {
|
|
6406
|
+
query: options.prompt,
|
|
6407
|
+
maxSteps: options.maxSteps,
|
|
6408
|
+
manageConnector: options.manageConnector,
|
|
6409
|
+
externalHistory: options.externalHistory,
|
|
6410
|
+
outputSchema: options.schema
|
|
6411
|
+
};
|
|
6412
|
+
}
|
|
6413
|
+
return {
|
|
6414
|
+
query: queryOrOptions,
|
|
6415
|
+
maxSteps,
|
|
6416
|
+
manageConnector,
|
|
6417
|
+
externalHistory,
|
|
6418
|
+
outputSchema
|
|
6419
|
+
};
|
|
6420
|
+
}
|
|
6421
|
+
__name(normalizeRemoteRunOptions, "normalizeRemoteRunOptions");
|
|
5274
6422
|
var RemoteAgent = class {
|
|
5275
6423
|
static {
|
|
5276
6424
|
__name(this, "RemoteAgent");
|
|
@@ -5367,8 +6515,20 @@ var RemoteAgent = class {
|
|
|
5367
6515
|
throw new Error(`Failed to create chat session: ${String(e)}`);
|
|
5368
6516
|
}
|
|
5369
6517
|
}
|
|
5370
|
-
async run(
|
|
5371
|
-
|
|
6518
|
+
async run(queryOrOptions, maxSteps, manageConnector, externalHistory, outputSchema) {
|
|
6519
|
+
const {
|
|
6520
|
+
query,
|
|
6521
|
+
maxSteps: steps,
|
|
6522
|
+
externalHistory: history,
|
|
6523
|
+
outputSchema: schema
|
|
6524
|
+
} = normalizeRemoteRunOptions(
|
|
6525
|
+
queryOrOptions,
|
|
6526
|
+
maxSteps,
|
|
6527
|
+
manageConnector,
|
|
6528
|
+
externalHistory,
|
|
6529
|
+
outputSchema
|
|
6530
|
+
);
|
|
6531
|
+
if (history !== void 0) {
|
|
5372
6532
|
logger.warn("External history is not yet supported for remote execution");
|
|
5373
6533
|
}
|
|
5374
6534
|
try {
|
|
@@ -5379,10 +6539,10 @@ var RemoteAgent = class {
|
|
|
5379
6539
|
const chatId = this.chatId;
|
|
5380
6540
|
const executionPayload = {
|
|
5381
6541
|
query,
|
|
5382
|
-
max_steps:
|
|
6542
|
+
max_steps: steps ?? 10
|
|
5383
6543
|
};
|
|
5384
|
-
if (
|
|
5385
|
-
executionPayload.output_schema = this.pydanticToJsonSchema(
|
|
6544
|
+
if (schema) {
|
|
6545
|
+
executionPayload.output_schema = this.pydanticToJsonSchema(schema);
|
|
5386
6546
|
logger.info(`\u{1F527} Using structured output with schema`);
|
|
5387
6547
|
}
|
|
5388
6548
|
const headers = {
|
|
@@ -5456,8 +6616,8 @@ Raw error: ${result}`
|
|
|
5456
6616
|
);
|
|
5457
6617
|
}
|
|
5458
6618
|
}
|
|
5459
|
-
if (
|
|
5460
|
-
return this.parseStructuredResponse(result,
|
|
6619
|
+
if (schema) {
|
|
6620
|
+
return this.parseStructuredResponse(result, schema);
|
|
5461
6621
|
}
|
|
5462
6622
|
if (typeof result === "object" && result !== null && "result" in result) {
|
|
5463
6623
|
return result.result;
|
|
@@ -5482,9 +6642,9 @@ Raw error: ${result}`
|
|
|
5482
6642
|
}
|
|
5483
6643
|
}
|
|
5484
6644
|
// eslint-disable-next-line require-yield
|
|
5485
|
-
async *stream(
|
|
6645
|
+
async *stream(queryOrOptions, maxSteps, manageConnector, externalHistory, outputSchema) {
|
|
5486
6646
|
const result = await this.run(
|
|
5487
|
-
|
|
6647
|
+
queryOrOptions,
|
|
5488
6648
|
maxSteps,
|
|
5489
6649
|
manageConnector,
|
|
5490
6650
|
externalHistory,
|
|
@@ -5497,7 +6657,166 @@ Raw error: ${result}`
|
|
|
5497
6657
|
}
|
|
5498
6658
|
};
|
|
5499
6659
|
|
|
6660
|
+
// src/agents/utils/llm_provider.ts
|
|
6661
|
+
init_logging();
|
|
6662
|
+
var PROVIDER_CONFIG = {
|
|
6663
|
+
openai: {
|
|
6664
|
+
package: "@langchain/openai",
|
|
6665
|
+
className: "ChatOpenAI",
|
|
6666
|
+
envVars: ["OPENAI_API_KEY"],
|
|
6667
|
+
defaultModel: "gpt-4o"
|
|
6668
|
+
},
|
|
6669
|
+
anthropic: {
|
|
6670
|
+
package: "@langchain/anthropic",
|
|
6671
|
+
className: "ChatAnthropic",
|
|
6672
|
+
envVars: ["ANTHROPIC_API_KEY"],
|
|
6673
|
+
defaultModel: "claude-3-5-sonnet-20241022"
|
|
6674
|
+
},
|
|
6675
|
+
google: {
|
|
6676
|
+
package: "@langchain/google-genai",
|
|
6677
|
+
className: "ChatGoogleGenerativeAI",
|
|
6678
|
+
envVars: ["GOOGLE_API_KEY", "GOOGLE_GENERATIVE_AI_API_KEY"],
|
|
6679
|
+
defaultModel: "gemini-pro"
|
|
6680
|
+
},
|
|
6681
|
+
groq: {
|
|
6682
|
+
package: "@langchain/groq",
|
|
6683
|
+
className: "ChatGroq",
|
|
6684
|
+
envVars: ["GROQ_API_KEY"],
|
|
6685
|
+
defaultModel: "llama-3.1-70b-versatile"
|
|
6686
|
+
}
|
|
6687
|
+
};
|
|
6688
|
+
function parseLLMString(llmString) {
|
|
6689
|
+
const parts = llmString.split("/");
|
|
6690
|
+
if (parts.length !== 2) {
|
|
6691
|
+
throw new Error(
|
|
6692
|
+
`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'`
|
|
6693
|
+
);
|
|
6694
|
+
}
|
|
6695
|
+
const [provider, model] = parts;
|
|
6696
|
+
if (!provider || !model) {
|
|
6697
|
+
throw new Error(
|
|
6698
|
+
`Invalid LLM string format. Both provider and model must be non-empty. Got '${llmString}'`
|
|
6699
|
+
);
|
|
6700
|
+
}
|
|
6701
|
+
const normalizedProvider = provider.toLowerCase();
|
|
6702
|
+
if (!(normalizedProvider in PROVIDER_CONFIG)) {
|
|
6703
|
+
const supportedProviders = Object.keys(PROVIDER_CONFIG).join(", ");
|
|
6704
|
+
throw new Error(
|
|
6705
|
+
`Unsupported LLM provider '${provider}'. Supported providers: ${supportedProviders}`
|
|
6706
|
+
);
|
|
6707
|
+
}
|
|
6708
|
+
return { provider: normalizedProvider, model };
|
|
6709
|
+
}
|
|
6710
|
+
__name(parseLLMString, "parseLLMString");
|
|
6711
|
+
function getAPIKey(provider, config) {
|
|
6712
|
+
if (config?.apiKey) {
|
|
6713
|
+
return config.apiKey;
|
|
6714
|
+
}
|
|
6715
|
+
const providerConfig = PROVIDER_CONFIG[provider];
|
|
6716
|
+
for (const envVar of providerConfig.envVars) {
|
|
6717
|
+
const apiKey = process.env[envVar];
|
|
6718
|
+
if (apiKey) {
|
|
6719
|
+
logger.debug(
|
|
6720
|
+
`Using API key from environment variable ${envVar} for provider ${provider}`
|
|
6721
|
+
);
|
|
6722
|
+
return apiKey;
|
|
6723
|
+
}
|
|
6724
|
+
}
|
|
6725
|
+
const envVarsStr = providerConfig.envVars.join(" or ");
|
|
6726
|
+
throw new Error(
|
|
6727
|
+
`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' } })`
|
|
6728
|
+
);
|
|
6729
|
+
}
|
|
6730
|
+
__name(getAPIKey, "getAPIKey");
|
|
6731
|
+
async function createLLMFromString(llmString, config) {
|
|
6732
|
+
logger.info(`Creating LLM from string: ${llmString}`);
|
|
6733
|
+
const { provider, model } = parseLLMString(llmString);
|
|
6734
|
+
const providerConfig = PROVIDER_CONFIG[provider];
|
|
6735
|
+
const apiKey = getAPIKey(provider, config);
|
|
6736
|
+
let providerModule;
|
|
6737
|
+
try {
|
|
6738
|
+
logger.debug(`Importing package ${providerConfig.package}...`);
|
|
6739
|
+
providerModule = await import(providerConfig.package);
|
|
6740
|
+
} catch (error) {
|
|
6741
|
+
if (error?.code === "MODULE_NOT_FOUND" || error?.message?.includes("Cannot find module") || error?.message?.includes("Cannot find package")) {
|
|
6742
|
+
throw new Error(
|
|
6743
|
+
`Package '${providerConfig.package}' is not installed. Install it with: npm install ${providerConfig.package} or yarn add ${providerConfig.package}`
|
|
6744
|
+
);
|
|
6745
|
+
}
|
|
6746
|
+
throw new Error(
|
|
6747
|
+
`Failed to import ${providerConfig.package}: ${error?.message || error}`
|
|
6748
|
+
);
|
|
6749
|
+
}
|
|
6750
|
+
const LLMClass = providerModule[providerConfig.className];
|
|
6751
|
+
if (!LLMClass) {
|
|
6752
|
+
throw new Error(
|
|
6753
|
+
`Could not find ${providerConfig.className} in package ${providerConfig.package}. This might be a version compatibility issue.`
|
|
6754
|
+
);
|
|
6755
|
+
}
|
|
6756
|
+
const llmConfig = {
|
|
6757
|
+
model,
|
|
6758
|
+
apiKey,
|
|
6759
|
+
...config
|
|
6760
|
+
};
|
|
6761
|
+
if (config?.apiKey) {
|
|
6762
|
+
delete llmConfig.apiKey;
|
|
6763
|
+
llmConfig.apiKey = apiKey;
|
|
6764
|
+
}
|
|
6765
|
+
if (provider === "anthropic") {
|
|
6766
|
+
llmConfig.model = model;
|
|
6767
|
+
} else if (provider === "google") {
|
|
6768
|
+
llmConfig.model = model;
|
|
6769
|
+
} else if (provider === "openai") {
|
|
6770
|
+
llmConfig.model = model;
|
|
6771
|
+
} else if (provider === "groq") {
|
|
6772
|
+
llmConfig.model = model;
|
|
6773
|
+
}
|
|
6774
|
+
try {
|
|
6775
|
+
const llmInstance = new LLMClass(llmConfig);
|
|
6776
|
+
logger.info(`Successfully created ${provider} LLM with model ${model}`);
|
|
6777
|
+
return llmInstance;
|
|
6778
|
+
} catch (error) {
|
|
6779
|
+
throw new Error(
|
|
6780
|
+
`Failed to instantiate ${providerConfig.className} with model '${model}': ${error?.message || error}`
|
|
6781
|
+
);
|
|
6782
|
+
}
|
|
6783
|
+
}
|
|
6784
|
+
__name(createLLMFromString, "createLLMFromString");
|
|
6785
|
+
function isValidLLMString(llmString) {
|
|
6786
|
+
try {
|
|
6787
|
+
parseLLMString(llmString);
|
|
6788
|
+
return true;
|
|
6789
|
+
} catch {
|
|
6790
|
+
return false;
|
|
6791
|
+
}
|
|
6792
|
+
}
|
|
6793
|
+
__name(isValidLLMString, "isValidLLMString");
|
|
6794
|
+
function getSupportedProviders() {
|
|
6795
|
+
return Object.keys(PROVIDER_CONFIG);
|
|
6796
|
+
}
|
|
6797
|
+
__name(getSupportedProviders, "getSupportedProviders");
|
|
6798
|
+
|
|
5500
6799
|
// src/agents/mcp_agent.ts
|
|
6800
|
+
function normalizeRunOptions(queryOrOptions, maxSteps, manageConnector, externalHistory, outputSchema) {
|
|
6801
|
+
if (typeof queryOrOptions === "object" && queryOrOptions !== null) {
|
|
6802
|
+
const options = queryOrOptions;
|
|
6803
|
+
return {
|
|
6804
|
+
query: options.prompt,
|
|
6805
|
+
maxSteps: options.maxSteps,
|
|
6806
|
+
manageConnector: options.manageConnector,
|
|
6807
|
+
externalHistory: options.externalHistory,
|
|
6808
|
+
outputSchema: options.schema
|
|
6809
|
+
};
|
|
6810
|
+
}
|
|
6811
|
+
return {
|
|
6812
|
+
query: queryOrOptions,
|
|
6813
|
+
maxSteps,
|
|
6814
|
+
manageConnector,
|
|
6815
|
+
externalHistory,
|
|
6816
|
+
outputSchema
|
|
6817
|
+
};
|
|
6818
|
+
}
|
|
6819
|
+
__name(normalizeRunOptions, "normalizeRunOptions");
|
|
5501
6820
|
var MCPAgent = class {
|
|
5502
6821
|
static {
|
|
5503
6822
|
__name(this, "MCPAgent");
|
|
@@ -5543,6 +6862,12 @@ var MCPAgent = class {
|
|
|
5543
6862
|
// Remote agent support
|
|
5544
6863
|
isRemote = false;
|
|
5545
6864
|
remoteAgent = null;
|
|
6865
|
+
// Simplified mode support
|
|
6866
|
+
isSimplifiedMode = false;
|
|
6867
|
+
llmString;
|
|
6868
|
+
llmConfig;
|
|
6869
|
+
mcpServersConfig;
|
|
6870
|
+
clientOwnedByAgent = false;
|
|
5546
6871
|
constructor(options) {
|
|
5547
6872
|
if (options.agentId) {
|
|
5548
6873
|
this.isRemote = true;
|
|
@@ -5576,9 +6901,36 @@ var MCPAgent = class {
|
|
|
5576
6901
|
"llm is required for local execution. For remote execution, provide agentId instead."
|
|
5577
6902
|
);
|
|
5578
6903
|
}
|
|
5579
|
-
|
|
5580
|
-
|
|
5581
|
-
|
|
6904
|
+
const isSimplifiedMode = typeof options.llm === "string";
|
|
6905
|
+
if (isSimplifiedMode) {
|
|
6906
|
+
this.isSimplifiedMode = true;
|
|
6907
|
+
this.llmString = options.llm;
|
|
6908
|
+
this.llmConfig = options.llmConfig;
|
|
6909
|
+
this.mcpServersConfig = options.mcpServers;
|
|
6910
|
+
if (!this.mcpServersConfig || Object.keys(this.mcpServersConfig).length === 0) {
|
|
6911
|
+
throw new Error(
|
|
6912
|
+
"Simplified mode requires 'mcpServers' configuration. Provide an object with server configurations, e.g., { filesystem: { command: 'npx', args: [...] } }"
|
|
6913
|
+
);
|
|
6914
|
+
}
|
|
6915
|
+
this.llm = void 0;
|
|
6916
|
+
this.client = void 0;
|
|
6917
|
+
this.clientOwnedByAgent = true;
|
|
6918
|
+
this.connectors = [];
|
|
6919
|
+
logger.info(
|
|
6920
|
+
`\u{1F3AF} Simplified mode enabled: LLM will be created from '${this.llmString}'`
|
|
6921
|
+
);
|
|
6922
|
+
} else {
|
|
6923
|
+
this.isSimplifiedMode = false;
|
|
6924
|
+
this.llm = options.llm;
|
|
6925
|
+
this.client = options.client;
|
|
6926
|
+
this.connectors = options.connectors ?? [];
|
|
6927
|
+
this.clientOwnedByAgent = false;
|
|
6928
|
+
if (!this.client && this.connectors.length === 0) {
|
|
6929
|
+
throw new Error(
|
|
6930
|
+
"Explicit mode requires either 'client' or at least one 'connector'. Alternatively, use simplified mode with 'llm' as a string and 'mcpServers' config."
|
|
6931
|
+
);
|
|
6932
|
+
}
|
|
6933
|
+
}
|
|
5582
6934
|
this.maxSteps = options.maxSteps ?? 5;
|
|
5583
6935
|
this.autoInitialize = options.autoInitialize ?? false;
|
|
5584
6936
|
this.memoryEnabled = options.memoryEnabled ?? true;
|
|
@@ -5591,28 +6943,30 @@ var MCPAgent = class {
|
|
|
5591
6943
|
this.useServerManager = options.useServerManager ?? false;
|
|
5592
6944
|
this.verbose = options.verbose ?? false;
|
|
5593
6945
|
this.observe = options.observe ?? true;
|
|
5594
|
-
if (!this.
|
|
5595
|
-
|
|
5596
|
-
|
|
5597
|
-
|
|
5598
|
-
|
|
5599
|
-
|
|
5600
|
-
|
|
5601
|
-
|
|
5602
|
-
|
|
5603
|
-
|
|
6946
|
+
if (!this.isSimplifiedMode) {
|
|
6947
|
+
if (this.useServerManager) {
|
|
6948
|
+
if (!this.client) {
|
|
6949
|
+
throw new Error(
|
|
6950
|
+
"'client' must be provided when 'useServerManager' is true."
|
|
6951
|
+
);
|
|
6952
|
+
}
|
|
6953
|
+
this.adapter = options.adapter ?? new LangChainAdapter(this.disallowedTools);
|
|
6954
|
+
this.serverManager = options.serverManagerFactory?.(this.client) ?? new ServerManager(this.client, this.adapter);
|
|
6955
|
+
} else {
|
|
6956
|
+
this.adapter = options.adapter ?? new LangChainAdapter(this.disallowedTools);
|
|
6957
|
+
}
|
|
6958
|
+
this.telemetry = Telemetry.getInstance();
|
|
6959
|
+
if (this.llm) {
|
|
6960
|
+
const [provider, name] = extractModelInfo(this.llm);
|
|
6961
|
+
this.modelProvider = provider;
|
|
6962
|
+
this.modelName = name;
|
|
6963
|
+
} else {
|
|
6964
|
+
this.modelProvider = "unknown";
|
|
6965
|
+
this.modelName = "unknown";
|
|
5604
6966
|
}
|
|
5605
|
-
this.adapter = options.adapter ?? new LangChainAdapter(this.disallowedTools);
|
|
5606
|
-
this.serverManager = options.serverManagerFactory?.(this.client) ?? new ServerManager(this.client, this.adapter);
|
|
5607
6967
|
} else {
|
|
5608
6968
|
this.adapter = options.adapter ?? new LangChainAdapter(this.disallowedTools);
|
|
5609
|
-
|
|
5610
|
-
this.telemetry = Telemetry.getInstance();
|
|
5611
|
-
if (this.llm) {
|
|
5612
|
-
const [provider, name] = extractModelInfo(this.llm);
|
|
5613
|
-
this.modelProvider = provider;
|
|
5614
|
-
this.modelName = name;
|
|
5615
|
-
} else {
|
|
6969
|
+
this.telemetry = Telemetry.getInstance();
|
|
5616
6970
|
this.modelProvider = "unknown";
|
|
5617
6971
|
this.modelName = "unknown";
|
|
5618
6972
|
}
|
|
@@ -5643,6 +6997,40 @@ var MCPAgent = class {
|
|
|
5643
6997
|
return;
|
|
5644
6998
|
}
|
|
5645
6999
|
logger.info("\u{1F680} Initializing MCP agent and connecting to services...");
|
|
7000
|
+
if (this.isSimplifiedMode) {
|
|
7001
|
+
logger.info(
|
|
7002
|
+
"\u{1F3AF} Simplified mode: Creating client and LLM from configuration..."
|
|
7003
|
+
);
|
|
7004
|
+
if (this.mcpServersConfig) {
|
|
7005
|
+
logger.info(
|
|
7006
|
+
`Creating MCPClient with ${Object.keys(this.mcpServersConfig).length} server(s)...`
|
|
7007
|
+
);
|
|
7008
|
+
this.client = new MCPClient({ mcpServers: this.mcpServersConfig });
|
|
7009
|
+
logger.info("\u2705 MCPClient created successfully");
|
|
7010
|
+
}
|
|
7011
|
+
if (this.llmString) {
|
|
7012
|
+
logger.info(`Creating LLM from string: ${this.llmString}...`);
|
|
7013
|
+
try {
|
|
7014
|
+
this.llm = await createLLMFromString(this.llmString, this.llmConfig);
|
|
7015
|
+
logger.info("\u2705 LLM created successfully");
|
|
7016
|
+
const [provider, name] = extractModelInfo(this.llm);
|
|
7017
|
+
this.modelProvider = provider;
|
|
7018
|
+
this.modelName = name;
|
|
7019
|
+
} catch (error) {
|
|
7020
|
+
throw new Error(
|
|
7021
|
+
`Failed to create LLM from string '${this.llmString}': ${error?.message || error}`
|
|
7022
|
+
);
|
|
7023
|
+
}
|
|
7024
|
+
}
|
|
7025
|
+
if (this.useServerManager) {
|
|
7026
|
+
if (!this.client) {
|
|
7027
|
+
throw new Error(
|
|
7028
|
+
"'client' must be available when 'useServerManager' is true."
|
|
7029
|
+
);
|
|
7030
|
+
}
|
|
7031
|
+
this.serverManager = new ServerManager(this.client, this.adapter);
|
|
7032
|
+
}
|
|
7033
|
+
}
|
|
5646
7034
|
this.callbacks = await this.observabilityManager.getCallbacks();
|
|
5647
7035
|
const handlerNames = await this.observabilityManager.getHandlerNames();
|
|
5648
7036
|
if (handlerNames.length > 0) {
|
|
@@ -5686,9 +7074,18 @@ var MCPAgent = class {
|
|
|
5686
7074
|
);
|
|
5687
7075
|
}
|
|
5688
7076
|
} else {
|
|
5689
|
-
|
|
7077
|
+
const tools = await this.adapter.createToolsFromConnectors(
|
|
7078
|
+
Object.values(this.sessions).map((session) => session.connector)
|
|
7079
|
+
);
|
|
7080
|
+
const resources = await this.adapter.createResourcesFromConnectors(
|
|
7081
|
+
Object.values(this.sessions).map((session) => session.connector)
|
|
7082
|
+
);
|
|
7083
|
+
const prompts = await this.adapter.createPromptsFromConnectors(
|
|
7084
|
+
Object.values(this.sessions).map((session) => session.connector)
|
|
7085
|
+
);
|
|
7086
|
+
this._tools = [...tools, ...resources, ...prompts];
|
|
5690
7087
|
logger.info(
|
|
5691
|
-
`\u{1F6E0}\uFE0F Created ${this._tools.length} LangChain
|
|
7088
|
+
`\u{1F6E0}\uFE0F Created ${this._tools.length} LangChain items from client: ${tools.length} tools, ${resources.length} resources, ${prompts.length} prompts`
|
|
5692
7089
|
);
|
|
5693
7090
|
}
|
|
5694
7091
|
this._tools.push(...this.additionalTools);
|
|
@@ -5701,12 +7098,19 @@ var MCPAgent = class {
|
|
|
5701
7098
|
await connector.connect();
|
|
5702
7099
|
}
|
|
5703
7100
|
}
|
|
5704
|
-
|
|
7101
|
+
const tools = await this.adapter.createToolsFromConnectors(
|
|
5705
7102
|
this.connectors
|
|
5706
7103
|
);
|
|
7104
|
+
const resources = await this.adapter.createResourcesFromConnectors(
|
|
7105
|
+
this.connectors
|
|
7106
|
+
);
|
|
7107
|
+
const prompts = await this.adapter.createPromptsFromConnectors(
|
|
7108
|
+
this.connectors
|
|
7109
|
+
);
|
|
7110
|
+
this._tools = [...tools, ...resources, ...prompts];
|
|
5707
7111
|
this._tools.push(...this.additionalTools);
|
|
5708
7112
|
logger.info(
|
|
5709
|
-
`\u{1F6E0}\uFE0F Created ${this._tools.length} LangChain
|
|
7113
|
+
`\u{1F6E0}\uFE0F Created ${this._tools.length} LangChain items from connectors: ${tools.length} tools, ${resources.length} resources, ${prompts.length} prompts`
|
|
5710
7114
|
);
|
|
5711
7115
|
}
|
|
5712
7116
|
logger.info(`\u{1F9F0} Found ${this._tools.length} tools across all connectors`);
|
|
@@ -6169,33 +7573,47 @@ var MCPAgent = class {
|
|
|
6169
7573
|
}
|
|
6170
7574
|
}
|
|
6171
7575
|
}
|
|
6172
|
-
async run(
|
|
6173
|
-
|
|
6174
|
-
return this.remoteAgent.run(
|
|
6175
|
-
query,
|
|
6176
|
-
maxSteps,
|
|
6177
|
-
manageConnector,
|
|
6178
|
-
externalHistory,
|
|
6179
|
-
outputSchema
|
|
6180
|
-
);
|
|
6181
|
-
}
|
|
6182
|
-
const generator = this.stream(
|
|
7576
|
+
async run(queryOrOptions, maxSteps, manageConnector, externalHistory, outputSchema) {
|
|
7577
|
+
const {
|
|
6183
7578
|
query,
|
|
7579
|
+
maxSteps: steps,
|
|
7580
|
+
manageConnector: manage,
|
|
7581
|
+
externalHistory: history,
|
|
7582
|
+
outputSchema: schema
|
|
7583
|
+
} = normalizeRunOptions(
|
|
7584
|
+
queryOrOptions,
|
|
6184
7585
|
maxSteps,
|
|
6185
7586
|
manageConnector,
|
|
6186
7587
|
externalHistory,
|
|
6187
7588
|
outputSchema
|
|
6188
7589
|
);
|
|
7590
|
+
if (this.isRemote && this.remoteAgent) {
|
|
7591
|
+
return this.remoteAgent.run(query, steps, manage, history, schema);
|
|
7592
|
+
}
|
|
7593
|
+
const generator = this.stream(query, steps, manage, history, schema);
|
|
6189
7594
|
return this._consumeAndReturn(generator);
|
|
6190
7595
|
}
|
|
6191
|
-
async *stream(
|
|
7596
|
+
async *stream(queryOrOptions, maxSteps, manageConnector = true, externalHistory, outputSchema) {
|
|
7597
|
+
const {
|
|
7598
|
+
query,
|
|
7599
|
+
maxSteps: steps,
|
|
7600
|
+
manageConnector: manage,
|
|
7601
|
+
externalHistory: history,
|
|
7602
|
+
outputSchema: schema
|
|
7603
|
+
} = normalizeRunOptions(
|
|
7604
|
+
queryOrOptions,
|
|
7605
|
+
maxSteps,
|
|
7606
|
+
manageConnector,
|
|
7607
|
+
externalHistory,
|
|
7608
|
+
outputSchema
|
|
7609
|
+
);
|
|
6192
7610
|
if (this.isRemote && this.remoteAgent) {
|
|
6193
7611
|
const result = await this.remoteAgent.run(
|
|
6194
7612
|
query,
|
|
6195
|
-
|
|
6196
|
-
|
|
6197
|
-
|
|
6198
|
-
|
|
7613
|
+
steps,
|
|
7614
|
+
manage,
|
|
7615
|
+
history,
|
|
7616
|
+
schema
|
|
6199
7617
|
);
|
|
6200
7618
|
return result;
|
|
6201
7619
|
}
|
|
@@ -6205,7 +7623,7 @@ var MCPAgent = class {
|
|
|
6205
7623
|
let finalOutput = null;
|
|
6206
7624
|
let stepsTaken = 0;
|
|
6207
7625
|
try {
|
|
6208
|
-
if (
|
|
7626
|
+
if (manage && !this._initialized) {
|
|
6209
7627
|
await this.initialize();
|
|
6210
7628
|
initializedHere = true;
|
|
6211
7629
|
} else if (!this._initialized && this.autoInitialize) {
|
|
@@ -6229,7 +7647,7 @@ var MCPAgent = class {
|
|
|
6229
7647
|
this._agentExecutor = this.createAgent();
|
|
6230
7648
|
}
|
|
6231
7649
|
}
|
|
6232
|
-
const historyToUse =
|
|
7650
|
+
const historyToUse = history ?? this.conversationHistory;
|
|
6233
7651
|
const langchainHistory = [];
|
|
6234
7652
|
for (const msg of historyToUse) {
|
|
6235
7653
|
if (this._isHumanMessageLike(msg) || this._isAIMessageLike(msg) || this._isToolMessageLike(msg)) {
|
|
@@ -6370,13 +7788,13 @@ var MCPAgent = class {
|
|
|
6370
7788
|
this.addToHistory(msg);
|
|
6371
7789
|
}
|
|
6372
7790
|
}
|
|
6373
|
-
if (
|
|
7791
|
+
if (schema && finalOutput) {
|
|
6374
7792
|
try {
|
|
6375
7793
|
logger.info("\u{1F527} Attempting structured output...");
|
|
6376
7794
|
const structuredResult = await this._attemptStructuredOutput(
|
|
6377
7795
|
finalOutput,
|
|
6378
7796
|
this.llm,
|
|
6379
|
-
|
|
7797
|
+
schema
|
|
6380
7798
|
);
|
|
6381
7799
|
if (this.memoryEnabled) {
|
|
6382
7800
|
this.addToHistory(
|
|
@@ -6402,7 +7820,7 @@ var MCPAgent = class {
|
|
|
6402
7820
|
return finalOutput || "No output generated";
|
|
6403
7821
|
} catch (e) {
|
|
6404
7822
|
logger.error(`\u274C Error running query: ${e}`);
|
|
6405
|
-
if (initializedHere &&
|
|
7823
|
+
if (initializedHere && manage) {
|
|
6406
7824
|
logger.info("\u{1F9F9} Cleaning up resources after error");
|
|
6407
7825
|
await this.close();
|
|
6408
7826
|
}
|
|
@@ -6432,9 +7850,9 @@ var MCPAgent = class {
|
|
|
6432
7850
|
maxStepsConfigured: this.maxSteps,
|
|
6433
7851
|
memoryEnabled: this.memoryEnabled,
|
|
6434
7852
|
useServerManager: this.useServerManager,
|
|
6435
|
-
maxStepsUsed:
|
|
6436
|
-
manageConnector,
|
|
6437
|
-
externalHistoryUsed:
|
|
7853
|
+
maxStepsUsed: steps ?? null,
|
|
7854
|
+
manageConnector: manage ?? true,
|
|
7855
|
+
externalHistoryUsed: history !== void 0,
|
|
6438
7856
|
stepsTaken,
|
|
6439
7857
|
toolsUsedCount: this.toolsUsedNames.length,
|
|
6440
7858
|
toolsUsedNames: this.toolsUsedNames,
|
|
@@ -6443,7 +7861,7 @@ var MCPAgent = class {
|
|
|
6443
7861
|
errorType: success ? null : "execution_error",
|
|
6444
7862
|
conversationHistoryLength
|
|
6445
7863
|
});
|
|
6446
|
-
if (
|
|
7864
|
+
if (manage && !this.client && initializedHere) {
|
|
6447
7865
|
logger.info("\u{1F9F9} Closing agent after stream completion");
|
|
6448
7866
|
await this.close();
|
|
6449
7867
|
}
|
|
@@ -6471,15 +7889,28 @@ var MCPAgent = class {
|
|
|
6471
7889
|
this._agentExecutor = null;
|
|
6472
7890
|
this._tools = [];
|
|
6473
7891
|
if (this.client) {
|
|
6474
|
-
|
|
6475
|
-
|
|
6476
|
-
|
|
7892
|
+
if (this.clientOwnedByAgent) {
|
|
7893
|
+
logger.info(
|
|
7894
|
+
"\u{1F504} Closing internally-created client (simplified mode) and cleaning up resources"
|
|
7895
|
+
);
|
|
7896
|
+
await this.client.close();
|
|
7897
|
+
this.sessions = {};
|
|
7898
|
+
this.client = void 0;
|
|
7899
|
+
} else {
|
|
7900
|
+
logger.info("\u{1F504} Closing client and cleaning up resources");
|
|
7901
|
+
await this.client.close();
|
|
7902
|
+
this.sessions = {};
|
|
7903
|
+
}
|
|
6477
7904
|
} else {
|
|
6478
7905
|
for (const connector of this.connectors) {
|
|
6479
7906
|
logger.info("\u{1F504} Disconnecting connector");
|
|
6480
7907
|
await connector.disconnect();
|
|
6481
7908
|
}
|
|
6482
7909
|
}
|
|
7910
|
+
if (this.isSimplifiedMode && this.llm) {
|
|
7911
|
+
logger.debug("\u{1F504} Clearing LLM reference (simplified mode)");
|
|
7912
|
+
this.llm = void 0;
|
|
7913
|
+
}
|
|
6483
7914
|
if ("connectorToolMap" in this.adapter) {
|
|
6484
7915
|
this.adapter = new LangChainAdapter();
|
|
6485
7916
|
}
|
|
@@ -6488,16 +7919,12 @@ var MCPAgent = class {
|
|
|
6488
7919
|
logger.info("\u{1F44B} Agent closed successfully");
|
|
6489
7920
|
}
|
|
6490
7921
|
}
|
|
6491
|
-
|
|
6492
|
-
* Yields with pretty-printed output for code mode.
|
|
6493
|
-
* This method formats and displays tool executions in a user-friendly way with syntax highlighting.
|
|
6494
|
-
*/
|
|
6495
|
-
async *prettyStreamEvents(query, maxSteps, manageConnector = true, externalHistory, outputSchema) {
|
|
7922
|
+
async *prettyStreamEvents(queryOrOptions, maxSteps, manageConnector = true, externalHistory, outputSchema) {
|
|
6496
7923
|
const { prettyStreamEvents: prettyStream } = await Promise.resolve().then(() => (init_display(), display_exports));
|
|
6497
7924
|
const finalResponse = "";
|
|
6498
7925
|
for await (const _ of prettyStream(
|
|
6499
7926
|
this.streamEvents(
|
|
6500
|
-
|
|
7927
|
+
queryOrOptions,
|
|
6501
7928
|
maxSteps,
|
|
6502
7929
|
manageConnector,
|
|
6503
7930
|
externalHistory,
|
|
@@ -6508,22 +7935,32 @@ var MCPAgent = class {
|
|
|
6508
7935
|
}
|
|
6509
7936
|
return finalResponse;
|
|
6510
7937
|
}
|
|
6511
|
-
|
|
6512
|
-
|
|
6513
|
-
|
|
6514
|
-
|
|
6515
|
-
|
|
7938
|
+
async *streamEvents(queryOrOptions, maxSteps, manageConnector = true, externalHistory, outputSchema) {
|
|
7939
|
+
const normalized = normalizeRunOptions(
|
|
7940
|
+
queryOrOptions,
|
|
7941
|
+
maxSteps,
|
|
7942
|
+
manageConnector,
|
|
7943
|
+
externalHistory,
|
|
7944
|
+
outputSchema
|
|
7945
|
+
);
|
|
7946
|
+
let { query } = normalized;
|
|
7947
|
+
const {
|
|
7948
|
+
maxSteps: steps,
|
|
7949
|
+
manageConnector: manage,
|
|
7950
|
+
externalHistory: history,
|
|
7951
|
+
outputSchema: schema
|
|
7952
|
+
} = normalized;
|
|
6516
7953
|
let initializedHere = false;
|
|
6517
7954
|
const startTime = Date.now();
|
|
6518
7955
|
let success = false;
|
|
6519
7956
|
let eventCount = 0;
|
|
6520
7957
|
let totalResponseLength = 0;
|
|
6521
7958
|
let finalResponse = "";
|
|
6522
|
-
if (
|
|
6523
|
-
query = this._enhanceQueryWithSchema(query,
|
|
7959
|
+
if (schema) {
|
|
7960
|
+
query = this._enhanceQueryWithSchema(query, schema);
|
|
6524
7961
|
}
|
|
6525
7962
|
try {
|
|
6526
|
-
if (
|
|
7963
|
+
if (manage && !this._initialized) {
|
|
6527
7964
|
await this.initialize();
|
|
6528
7965
|
initializedHere = true;
|
|
6529
7966
|
} else if (!this._initialized && this.autoInitialize) {
|
|
@@ -6534,14 +7971,14 @@ var MCPAgent = class {
|
|
|
6534
7971
|
if (!agentExecutor) {
|
|
6535
7972
|
throw new Error("MCP agent failed to initialize");
|
|
6536
7973
|
}
|
|
6537
|
-
this.maxSteps =
|
|
7974
|
+
this.maxSteps = steps ?? this.maxSteps;
|
|
6538
7975
|
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);
|
|
6539
7976
|
logger.info(`\u{1F4AC} Received query for streamEvents: '${display_query}'`);
|
|
6540
7977
|
if (this.memoryEnabled) {
|
|
6541
7978
|
logger.info(`\u{1F504} Adding user message to history: ${display_query}`);
|
|
6542
7979
|
this.addToHistory(new import_langchain2.HumanMessage({ content: query }));
|
|
6543
7980
|
}
|
|
6544
|
-
const historyToUse =
|
|
7981
|
+
const historyToUse = history ?? this.conversationHistory;
|
|
6545
7982
|
const langchainHistory = [];
|
|
6546
7983
|
for (const msg of historyToUse) {
|
|
6547
7984
|
if (this._isHumanMessageLike(msg) || this._isAIMessageLike(msg) || this._isToolMessageLike(msg)) {
|
|
@@ -6608,17 +8045,13 @@ var MCPAgent = class {
|
|
|
6608
8045
|
}
|
|
6609
8046
|
}
|
|
6610
8047
|
}
|
|
6611
|
-
if (
|
|
8048
|
+
if (schema && finalResponse) {
|
|
6612
8049
|
logger.info("\u{1F527} Attempting structured output conversion...");
|
|
6613
8050
|
try {
|
|
6614
8051
|
let conversionCompleted = false;
|
|
6615
8052
|
let conversionResult = null;
|
|
6616
8053
|
let conversionError = null;
|
|
6617
|
-
this._attemptStructuredOutput(
|
|
6618
|
-
finalResponse,
|
|
6619
|
-
this.llm,
|
|
6620
|
-
outputSchema
|
|
6621
|
-
).then((result) => {
|
|
8054
|
+
this._attemptStructuredOutput(finalResponse, this.llm, schema).then((result) => {
|
|
6622
8055
|
conversionCompleted = true;
|
|
6623
8056
|
conversionResult = result;
|
|
6624
8057
|
return result;
|
|
@@ -6673,7 +8106,7 @@ var MCPAgent = class {
|
|
|
6673
8106
|
success = true;
|
|
6674
8107
|
} catch (e) {
|
|
6675
8108
|
logger.error(`\u274C Error during streamEvents: ${e}`);
|
|
6676
|
-
if (initializedHere &&
|
|
8109
|
+
if (initializedHere && manage) {
|
|
6677
8110
|
logger.info(
|
|
6678
8111
|
"\u{1F9F9} Cleaning up resources after initialization error in streamEvents"
|
|
6679
8112
|
);
|
|
@@ -6704,15 +8137,15 @@ var MCPAgent = class {
|
|
|
6704
8137
|
maxStepsConfigured: this.maxSteps,
|
|
6705
8138
|
memoryEnabled: this.memoryEnabled,
|
|
6706
8139
|
useServerManager: this.useServerManager,
|
|
6707
|
-
maxStepsUsed:
|
|
6708
|
-
manageConnector,
|
|
6709
|
-
externalHistoryUsed:
|
|
8140
|
+
maxStepsUsed: steps ?? null,
|
|
8141
|
+
manageConnector: manage ?? true,
|
|
8142
|
+
externalHistoryUsed: history !== void 0,
|
|
6710
8143
|
response: `[STREAMED RESPONSE - ${totalResponseLength} chars]`,
|
|
6711
8144
|
executionTimeMs,
|
|
6712
8145
|
errorType: success ? null : "streaming_error",
|
|
6713
8146
|
conversationHistoryLength
|
|
6714
8147
|
});
|
|
6715
|
-
if (
|
|
8148
|
+
if (manage && !this.client && initializedHere) {
|
|
6716
8149
|
logger.info("\u{1F9F9} Closing agent after streamEvents completion");
|
|
6717
8150
|
await this.close();
|
|
6718
8151
|
}
|