mcp-use 1.10.5 → 1.11.0-canary.10
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-IY632ZQS.js → chunk-3GB7G5X7.js} +2 -2
- package/dist/{chunk-E42PSMPK.js → chunk-5QAXQTDL.js} +1 -1
- package/dist/{chunk-C7WHRUWQ.js → chunk-BEGEDH6P.js} +196 -496
- package/dist/{chunk-MO5FM5B2.js → chunk-BLGIG2QD.js} +443 -969
- package/dist/{chunk-XG7SR6G4.js → chunk-CBJTHTR4.js} +3 -8
- package/dist/{chunk-34R6SIER.js → chunk-FRUZDWXH.js} +1 -1
- package/dist/chunk-GUB5GQDD.js +101 -0
- package/dist/chunk-GXNAXUDI.js +0 -0
- package/dist/{chunk-CPG2WZUL.js → chunk-JRGQRPTN.js} +1 -1
- package/dist/chunk-MFSO5PUW.js +1049 -0
- package/dist/{chunk-UD5FSFEZ.js → chunk-NXFHUS7A.js} +171 -11
- package/dist/chunk-ULFNVP5Z.js +12 -0
- package/dist/chunk-UWWLWLS2.js +62 -0
- package/dist/chunk-VTEYN43V.js +1055 -0
- package/dist/{chunk-YOHGE3NK.js → chunk-XPTKLSBC.js} +16 -2
- 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 +53 -1068
- 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 +10 -6
- 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 +26 -15
- 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 +3787 -0
- package/dist/src/client.js +20 -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 +6 -5
- 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 +1379 -208
- 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 +1353 -249
- 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 +120 -17
- 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-XTDKRH6N.js → tool-execution-helpers-N7R7YGAW.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
|
@@ -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];
|
|
@@ -1417,7 +1417,7 @@ __name(generateUUID, "generateUUID");
|
|
|
1417
1417
|
init_logging();
|
|
1418
1418
|
|
|
1419
1419
|
// src/version.ts
|
|
1420
|
-
var VERSION = "1.10
|
|
1420
|
+
var VERSION = "1.11.0-canary.10";
|
|
1421
1421
|
function getPackageVersion() {
|
|
1422
1422
|
return VERSION;
|
|
1423
1423
|
}
|
|
@@ -1738,26 +1738,26 @@ var Telemetry = class _Telemetry {
|
|
|
1738
1738
|
* Get or create user ID from filesystem (Node.js/Bun)
|
|
1739
1739
|
*/
|
|
1740
1740
|
_getUserIdFromFilesystem() {
|
|
1741
|
-
const
|
|
1741
|
+
const fs2 = require("fs");
|
|
1742
1742
|
const os = require("os");
|
|
1743
|
-
const
|
|
1743
|
+
const path2 = require("path");
|
|
1744
1744
|
if (!this._userIdPath) {
|
|
1745
|
-
this._userIdPath =
|
|
1746
|
-
this._getCacheHome(os,
|
|
1745
|
+
this._userIdPath = path2.join(
|
|
1746
|
+
this._getCacheHome(os, path2),
|
|
1747
1747
|
"mcp_use_3",
|
|
1748
1748
|
"telemetry_user_id"
|
|
1749
1749
|
);
|
|
1750
1750
|
}
|
|
1751
|
-
const isFirstTime = !
|
|
1751
|
+
const isFirstTime = !fs2.existsSync(this._userIdPath);
|
|
1752
1752
|
if (isFirstTime) {
|
|
1753
1753
|
logger.debug(`Creating user ID path: ${this._userIdPath}`);
|
|
1754
|
-
|
|
1754
|
+
fs2.mkdirSync(path2.dirname(this._userIdPath), { recursive: true });
|
|
1755
1755
|
const newUserId = generateUUID();
|
|
1756
|
-
|
|
1756
|
+
fs2.writeFileSync(this._userIdPath, newUserId);
|
|
1757
1757
|
logger.debug(`User ID path created: ${this._userIdPath}`);
|
|
1758
1758
|
return newUserId;
|
|
1759
1759
|
}
|
|
1760
|
-
return
|
|
1760
|
+
return fs2.readFileSync(this._userIdPath, "utf-8").trim();
|
|
1761
1761
|
}
|
|
1762
1762
|
/**
|
|
1763
1763
|
* Get or create user ID from localStorage (Browser)
|
|
@@ -1776,9 +1776,9 @@ var Telemetry = class _Telemetry {
|
|
|
1776
1776
|
return `session-${generateUUID()}`;
|
|
1777
1777
|
}
|
|
1778
1778
|
}
|
|
1779
|
-
_getCacheHome(os,
|
|
1779
|
+
_getCacheHome(os, path2) {
|
|
1780
1780
|
const envVar = process.env.XDG_CACHE_HOME;
|
|
1781
|
-
if (envVar &&
|
|
1781
|
+
if (envVar && path2.isAbsolute(envVar)) {
|
|
1782
1782
|
return envVar;
|
|
1783
1783
|
}
|
|
1784
1784
|
const platform = process.platform;
|
|
@@ -1788,11 +1788,11 @@ var Telemetry = class _Telemetry {
|
|
|
1788
1788
|
if (appdata) {
|
|
1789
1789
|
return appdata;
|
|
1790
1790
|
}
|
|
1791
|
-
return
|
|
1791
|
+
return path2.join(homeDir, "AppData", "Local");
|
|
1792
1792
|
} else if (platform === "darwin") {
|
|
1793
|
-
return
|
|
1793
|
+
return path2.join(homeDir, "Library", "Caches");
|
|
1794
1794
|
} else {
|
|
1795
|
-
return
|
|
1795
|
+
return path2.join(homeDir, ".cache");
|
|
1796
1796
|
}
|
|
1797
1797
|
}
|
|
1798
1798
|
async capture(event) {
|
|
@@ -1866,12 +1866,12 @@ var Telemetry = class _Telemetry {
|
|
|
1866
1866
|
return;
|
|
1867
1867
|
}
|
|
1868
1868
|
try {
|
|
1869
|
-
const
|
|
1870
|
-
const
|
|
1869
|
+
const fs2 = require("fs");
|
|
1870
|
+
const path2 = require("path");
|
|
1871
1871
|
const os = require("os");
|
|
1872
1872
|
if (!this._versionDownloadPath) {
|
|
1873
|
-
this._versionDownloadPath =
|
|
1874
|
-
this._getCacheHome(os,
|
|
1873
|
+
this._versionDownloadPath = path2.join(
|
|
1874
|
+
this._getCacheHome(os, path2),
|
|
1875
1875
|
"mcp_use",
|
|
1876
1876
|
"download_version"
|
|
1877
1877
|
);
|
|
@@ -1879,19 +1879,19 @@ var Telemetry = class _Telemetry {
|
|
|
1879
1879
|
const currentVersion = getPackageVersion();
|
|
1880
1880
|
let shouldTrack = false;
|
|
1881
1881
|
let firstDownload = false;
|
|
1882
|
-
if (!
|
|
1882
|
+
if (!fs2.existsSync(this._versionDownloadPath)) {
|
|
1883
1883
|
shouldTrack = true;
|
|
1884
1884
|
firstDownload = true;
|
|
1885
|
-
|
|
1885
|
+
fs2.mkdirSync(path2.dirname(this._versionDownloadPath), {
|
|
1886
1886
|
recursive: true
|
|
1887
1887
|
});
|
|
1888
|
-
|
|
1888
|
+
fs2.writeFileSync(this._versionDownloadPath, currentVersion);
|
|
1889
1889
|
} else {
|
|
1890
|
-
const savedVersion =
|
|
1890
|
+
const savedVersion = fs2.readFileSync(this._versionDownloadPath, "utf-8").trim();
|
|
1891
1891
|
if (currentVersion > savedVersion) {
|
|
1892
1892
|
shouldTrack = true;
|
|
1893
1893
|
firstDownload = false;
|
|
1894
|
-
|
|
1894
|
+
fs2.writeFileSync(this._versionDownloadPath, currentVersion);
|
|
1895
1895
|
}
|
|
1896
1896
|
}
|
|
1897
1897
|
if (shouldTrack) {
|
|
@@ -2084,6 +2084,480 @@ var Telemetry = class _Telemetry {
|
|
|
2084
2084
|
}
|
|
2085
2085
|
}
|
|
2086
2086
|
};
|
|
2087
|
+
var Tel = Telemetry;
|
|
2088
|
+
|
|
2089
|
+
// src/connectors/base.ts
|
|
2090
|
+
var BaseConnector = class {
|
|
2091
|
+
static {
|
|
2092
|
+
__name(this, "BaseConnector");
|
|
2093
|
+
}
|
|
2094
|
+
client = null;
|
|
2095
|
+
connectionManager = null;
|
|
2096
|
+
toolsCache = null;
|
|
2097
|
+
capabilitiesCache = null;
|
|
2098
|
+
serverInfoCache = null;
|
|
2099
|
+
connected = false;
|
|
2100
|
+
opts;
|
|
2101
|
+
notificationHandlers = [];
|
|
2102
|
+
rootsCache = [];
|
|
2103
|
+
constructor(opts = {}) {
|
|
2104
|
+
this.opts = opts;
|
|
2105
|
+
if (opts.roots) {
|
|
2106
|
+
this.rootsCache = [...opts.roots];
|
|
2107
|
+
}
|
|
2108
|
+
}
|
|
2109
|
+
/**
|
|
2110
|
+
* Track connector initialization event
|
|
2111
|
+
* Should be called by subclasses after successful connection
|
|
2112
|
+
*/
|
|
2113
|
+
trackConnectorInit(data) {
|
|
2114
|
+
const connectorType = this.constructor.name;
|
|
2115
|
+
Telemetry.getInstance().trackConnectorInit({
|
|
2116
|
+
connectorType,
|
|
2117
|
+
...data
|
|
2118
|
+
}).catch((e) => logger.debug(`Failed to track connector init: ${e}`));
|
|
2119
|
+
}
|
|
2120
|
+
/**
|
|
2121
|
+
* Register a handler for server notifications
|
|
2122
|
+
*
|
|
2123
|
+
* @param handler - Function to call when a notification is received
|
|
2124
|
+
*
|
|
2125
|
+
* @example
|
|
2126
|
+
* ```typescript
|
|
2127
|
+
* connector.onNotification((notification) => {
|
|
2128
|
+
* console.log(`Received: ${notification.method}`, notification.params);
|
|
2129
|
+
* });
|
|
2130
|
+
* ```
|
|
2131
|
+
*/
|
|
2132
|
+
onNotification(handler) {
|
|
2133
|
+
this.notificationHandlers.push(handler);
|
|
2134
|
+
if (this.client) {
|
|
2135
|
+
this.setupNotificationHandler();
|
|
2136
|
+
}
|
|
2137
|
+
}
|
|
2138
|
+
/**
|
|
2139
|
+
* Internal: wire notification handlers to the SDK client
|
|
2140
|
+
* Includes automatic handling for list_changed notifications per MCP spec
|
|
2141
|
+
*/
|
|
2142
|
+
setupNotificationHandler() {
|
|
2143
|
+
if (!this.client) return;
|
|
2144
|
+
this.client.fallbackNotificationHandler = async (notification) => {
|
|
2145
|
+
switch (notification.method) {
|
|
2146
|
+
case "notifications/tools/list_changed":
|
|
2147
|
+
await this.refreshToolsCache();
|
|
2148
|
+
break;
|
|
2149
|
+
case "notifications/resources/list_changed":
|
|
2150
|
+
await this.onResourcesListChanged();
|
|
2151
|
+
break;
|
|
2152
|
+
case "notifications/prompts/list_changed":
|
|
2153
|
+
await this.onPromptsListChanged();
|
|
2154
|
+
break;
|
|
2155
|
+
default:
|
|
2156
|
+
break;
|
|
2157
|
+
}
|
|
2158
|
+
for (const handler of this.notificationHandlers) {
|
|
2159
|
+
try {
|
|
2160
|
+
await handler(notification);
|
|
2161
|
+
} catch (err) {
|
|
2162
|
+
logger.error("Error in notification handler:", err);
|
|
2163
|
+
}
|
|
2164
|
+
}
|
|
2165
|
+
};
|
|
2166
|
+
}
|
|
2167
|
+
/**
|
|
2168
|
+
* Auto-refresh tools cache when server sends tools/list_changed notification
|
|
2169
|
+
*/
|
|
2170
|
+
async refreshToolsCache() {
|
|
2171
|
+
if (!this.client) return;
|
|
2172
|
+
try {
|
|
2173
|
+
logger.debug(
|
|
2174
|
+
"[Auto] Refreshing tools cache due to list_changed notification"
|
|
2175
|
+
);
|
|
2176
|
+
const result = await this.client.listTools();
|
|
2177
|
+
this.toolsCache = result.tools ?? [];
|
|
2178
|
+
logger.debug(
|
|
2179
|
+
`[Auto] Refreshed tools cache: ${this.toolsCache.length} tools`
|
|
2180
|
+
);
|
|
2181
|
+
} catch (err) {
|
|
2182
|
+
logger.warn("[Auto] Failed to refresh tools cache:", err);
|
|
2183
|
+
}
|
|
2184
|
+
}
|
|
2185
|
+
/**
|
|
2186
|
+
* Called when server sends resources/list_changed notification
|
|
2187
|
+
* Resources aren't cached by default, but we log for user awareness
|
|
2188
|
+
*/
|
|
2189
|
+
async onResourcesListChanged() {
|
|
2190
|
+
logger.debug(
|
|
2191
|
+
"[Auto] Resources list changed - clients should re-fetch if needed"
|
|
2192
|
+
);
|
|
2193
|
+
}
|
|
2194
|
+
/**
|
|
2195
|
+
* Called when server sends prompts/list_changed notification
|
|
2196
|
+
* Prompts aren't cached by default, but we log for user awareness
|
|
2197
|
+
*/
|
|
2198
|
+
async onPromptsListChanged() {
|
|
2199
|
+
logger.debug(
|
|
2200
|
+
"[Auto] Prompts list changed - clients should re-fetch if needed"
|
|
2201
|
+
);
|
|
2202
|
+
}
|
|
2203
|
+
/**
|
|
2204
|
+
* Set roots and notify the server.
|
|
2205
|
+
* Roots represent directories or files that the client has access to.
|
|
2206
|
+
*
|
|
2207
|
+
* @param roots - Array of Root objects with `uri` (must start with "file://") and optional `name`
|
|
2208
|
+
*
|
|
2209
|
+
* @example
|
|
2210
|
+
* ```typescript
|
|
2211
|
+
* await connector.setRoots([
|
|
2212
|
+
* { uri: "file:///home/user/project", name: "My Project" },
|
|
2213
|
+
* { uri: "file:///home/user/data" }
|
|
2214
|
+
* ]);
|
|
2215
|
+
* ```
|
|
2216
|
+
*/
|
|
2217
|
+
async setRoots(roots) {
|
|
2218
|
+
this.rootsCache = [...roots];
|
|
2219
|
+
if (this.client) {
|
|
2220
|
+
logger.debug(
|
|
2221
|
+
`Sending roots/list_changed notification with ${roots.length} root(s)`
|
|
2222
|
+
);
|
|
2223
|
+
await this.client.sendRootsListChanged();
|
|
2224
|
+
}
|
|
2225
|
+
}
|
|
2226
|
+
/**
|
|
2227
|
+
* Get the current roots.
|
|
2228
|
+
*/
|
|
2229
|
+
getRoots() {
|
|
2230
|
+
return [...this.rootsCache];
|
|
2231
|
+
}
|
|
2232
|
+
/**
|
|
2233
|
+
* Internal: set up roots/list request handler.
|
|
2234
|
+
* This is called after the client connects to register the handler for server requests.
|
|
2235
|
+
*/
|
|
2236
|
+
setupRootsHandler() {
|
|
2237
|
+
if (!this.client) return;
|
|
2238
|
+
this.client.setRequestHandler(
|
|
2239
|
+
import_types.ListRootsRequestSchema,
|
|
2240
|
+
async (_request, _extra) => {
|
|
2241
|
+
logger.debug(
|
|
2242
|
+
`Server requested roots list, returning ${this.rootsCache.length} root(s)`
|
|
2243
|
+
);
|
|
2244
|
+
return { roots: this.rootsCache };
|
|
2245
|
+
}
|
|
2246
|
+
);
|
|
2247
|
+
}
|
|
2248
|
+
/**
|
|
2249
|
+
* Internal: set up sampling/createMessage request handler.
|
|
2250
|
+
* This is called after the client connects to register the handler for sampling requests.
|
|
2251
|
+
*/
|
|
2252
|
+
setupSamplingHandler() {
|
|
2253
|
+
if (!this.client) {
|
|
2254
|
+
logger.debug("setupSamplingHandler: No client available");
|
|
2255
|
+
return;
|
|
2256
|
+
}
|
|
2257
|
+
if (!this.opts.samplingCallback) {
|
|
2258
|
+
logger.debug("setupSamplingHandler: No sampling callback provided");
|
|
2259
|
+
return;
|
|
2260
|
+
}
|
|
2261
|
+
logger.debug("setupSamplingHandler: Setting up sampling request handler");
|
|
2262
|
+
this.client.setRequestHandler(
|
|
2263
|
+
import_types.CreateMessageRequestSchema,
|
|
2264
|
+
async (request, _extra) => {
|
|
2265
|
+
logger.debug("Server requested sampling, forwarding to callback");
|
|
2266
|
+
return await this.opts.samplingCallback(request.params);
|
|
2267
|
+
}
|
|
2268
|
+
);
|
|
2269
|
+
logger.debug(
|
|
2270
|
+
"setupSamplingHandler: Sampling handler registered successfully"
|
|
2271
|
+
);
|
|
2272
|
+
}
|
|
2273
|
+
/**
|
|
2274
|
+
* Internal: set up elicitation/create request handler.
|
|
2275
|
+
* This is called after the client connects to register the handler for elicitation requests.
|
|
2276
|
+
*/
|
|
2277
|
+
setupElicitationHandler() {
|
|
2278
|
+
if (!this.client) {
|
|
2279
|
+
logger.debug("setupElicitationHandler: No client available");
|
|
2280
|
+
return;
|
|
2281
|
+
}
|
|
2282
|
+
if (!this.opts.elicitationCallback) {
|
|
2283
|
+
logger.debug("setupElicitationHandler: No elicitation callback provided");
|
|
2284
|
+
return;
|
|
2285
|
+
}
|
|
2286
|
+
logger.debug(
|
|
2287
|
+
"setupElicitationHandler: Setting up elicitation request handler"
|
|
2288
|
+
);
|
|
2289
|
+
this.client.setRequestHandler(
|
|
2290
|
+
import_types.ElicitRequestSchema,
|
|
2291
|
+
async (request, _extra) => {
|
|
2292
|
+
logger.debug("Server requested elicitation, forwarding to callback");
|
|
2293
|
+
return await this.opts.elicitationCallback(request.params);
|
|
2294
|
+
}
|
|
2295
|
+
);
|
|
2296
|
+
logger.debug(
|
|
2297
|
+
"setupElicitationHandler: Elicitation handler registered successfully"
|
|
2298
|
+
);
|
|
2299
|
+
}
|
|
2300
|
+
/** Disconnect and release resources. */
|
|
2301
|
+
async disconnect() {
|
|
2302
|
+
if (!this.connected) {
|
|
2303
|
+
logger.debug("Not connected to MCP implementation");
|
|
2304
|
+
return;
|
|
2305
|
+
}
|
|
2306
|
+
logger.debug("Disconnecting from MCP implementation");
|
|
2307
|
+
await this.cleanupResources();
|
|
2308
|
+
this.connected = false;
|
|
2309
|
+
logger.debug("Disconnected from MCP implementation");
|
|
2310
|
+
}
|
|
2311
|
+
/** Check if the client is connected */
|
|
2312
|
+
get isClientConnected() {
|
|
2313
|
+
return this.client != null;
|
|
2314
|
+
}
|
|
2315
|
+
/**
|
|
2316
|
+
* Initialise the MCP session **after** `connect()` has succeeded.
|
|
2317
|
+
*
|
|
2318
|
+
* In the SDK, `Client.connect(transport)` automatically performs the
|
|
2319
|
+
* protocol‑level `initialize` handshake, so we only need to cache the list of
|
|
2320
|
+
* tools and expose some server info.
|
|
2321
|
+
*/
|
|
2322
|
+
async initialize(defaultRequestOptions = this.opts.defaultRequestOptions ?? {}) {
|
|
2323
|
+
if (!this.client) {
|
|
2324
|
+
throw new Error("MCP client is not connected");
|
|
2325
|
+
}
|
|
2326
|
+
logger.debug("Caching server capabilities & tools");
|
|
2327
|
+
const capabilities = this.client.getServerCapabilities();
|
|
2328
|
+
this.capabilitiesCache = capabilities || null;
|
|
2329
|
+
const serverInfo = this.client.getServerVersion();
|
|
2330
|
+
this.serverInfoCache = serverInfo || null;
|
|
2331
|
+
const listToolsRes = await this.client.listTools(
|
|
2332
|
+
void 0,
|
|
2333
|
+
defaultRequestOptions
|
|
2334
|
+
);
|
|
2335
|
+
this.toolsCache = listToolsRes.tools ?? [];
|
|
2336
|
+
logger.debug(`Fetched ${this.toolsCache.length} tools from server`);
|
|
2337
|
+
logger.debug("Server capabilities:", capabilities);
|
|
2338
|
+
logger.debug("Server info:", serverInfo);
|
|
2339
|
+
return capabilities;
|
|
2340
|
+
}
|
|
2341
|
+
/** Lazily expose the cached tools list. */
|
|
2342
|
+
get tools() {
|
|
2343
|
+
if (!this.toolsCache) {
|
|
2344
|
+
throw new Error("MCP client is not initialized; call initialize() first");
|
|
2345
|
+
}
|
|
2346
|
+
return this.toolsCache;
|
|
2347
|
+
}
|
|
2348
|
+
/** Expose cached server capabilities. */
|
|
2349
|
+
get serverCapabilities() {
|
|
2350
|
+
return this.capabilitiesCache || {};
|
|
2351
|
+
}
|
|
2352
|
+
/** Expose cached server info. */
|
|
2353
|
+
get serverInfo() {
|
|
2354
|
+
return this.serverInfoCache;
|
|
2355
|
+
}
|
|
2356
|
+
/** Call a tool on the server. */
|
|
2357
|
+
async callTool(name, args, options) {
|
|
2358
|
+
if (!this.client) {
|
|
2359
|
+
throw new Error("MCP client is not connected");
|
|
2360
|
+
}
|
|
2361
|
+
const enhancedOptions = options ? { ...options } : void 0;
|
|
2362
|
+
if (enhancedOptions?.resetTimeoutOnProgress && !enhancedOptions.onprogress) {
|
|
2363
|
+
enhancedOptions.onprogress = () => {
|
|
2364
|
+
};
|
|
2365
|
+
logger.debug(
|
|
2366
|
+
`[BaseConnector] Added onprogress callback for tool '${name}' to enable progressToken`
|
|
2367
|
+
);
|
|
2368
|
+
}
|
|
2369
|
+
logger.debug(`Calling tool '${name}' with args`, args);
|
|
2370
|
+
const res = await this.client.callTool(
|
|
2371
|
+
{ name, arguments: args },
|
|
2372
|
+
void 0,
|
|
2373
|
+
enhancedOptions
|
|
2374
|
+
);
|
|
2375
|
+
logger.debug(`Tool '${name}' returned`, res);
|
|
2376
|
+
return res;
|
|
2377
|
+
}
|
|
2378
|
+
/**
|
|
2379
|
+
* List all available tools from the MCP server.
|
|
2380
|
+
* This method fetches fresh tools from the server, unlike the `tools` getter which returns cached tools.
|
|
2381
|
+
*
|
|
2382
|
+
* @param options - Optional request options
|
|
2383
|
+
* @returns Array of available tools
|
|
2384
|
+
*/
|
|
2385
|
+
async listTools(options) {
|
|
2386
|
+
if (!this.client) {
|
|
2387
|
+
throw new Error("MCP client is not connected");
|
|
2388
|
+
}
|
|
2389
|
+
const result = await this.client.listTools(void 0, options);
|
|
2390
|
+
return result.tools ?? [];
|
|
2391
|
+
}
|
|
2392
|
+
/**
|
|
2393
|
+
* List resources from the server with optional pagination
|
|
2394
|
+
*
|
|
2395
|
+
* @param cursor - Optional cursor for pagination
|
|
2396
|
+
* @param options - Request options
|
|
2397
|
+
* @returns Resource list with optional nextCursor for pagination
|
|
2398
|
+
*/
|
|
2399
|
+
async listResources(cursor, options) {
|
|
2400
|
+
if (!this.client) {
|
|
2401
|
+
throw new Error("MCP client is not connected");
|
|
2402
|
+
}
|
|
2403
|
+
logger.debug("Listing resources", cursor ? `with cursor: ${cursor}` : "");
|
|
2404
|
+
return await this.client.listResources({ cursor }, options);
|
|
2405
|
+
}
|
|
2406
|
+
/**
|
|
2407
|
+
* List all resources from the server, automatically handling pagination
|
|
2408
|
+
*
|
|
2409
|
+
* @param options - Request options
|
|
2410
|
+
* @returns Complete list of all resources
|
|
2411
|
+
*/
|
|
2412
|
+
async listAllResources(options) {
|
|
2413
|
+
if (!this.client) {
|
|
2414
|
+
throw new Error("MCP client is not connected");
|
|
2415
|
+
}
|
|
2416
|
+
if (!this.capabilitiesCache?.resources) {
|
|
2417
|
+
logger.debug("Server does not advertise resources capability, skipping");
|
|
2418
|
+
return { resources: [] };
|
|
2419
|
+
}
|
|
2420
|
+
try {
|
|
2421
|
+
logger.debug("Listing all resources (with auto-pagination)");
|
|
2422
|
+
const allResources = [];
|
|
2423
|
+
let cursor = void 0;
|
|
2424
|
+
do {
|
|
2425
|
+
const result = await this.client.listResources({ cursor }, options);
|
|
2426
|
+
allResources.push(...result.resources || []);
|
|
2427
|
+
cursor = result.nextCursor;
|
|
2428
|
+
} while (cursor);
|
|
2429
|
+
return { resources: allResources };
|
|
2430
|
+
} catch (err) {
|
|
2431
|
+
const error = err;
|
|
2432
|
+
if (error.code === -32601) {
|
|
2433
|
+
logger.debug("Server advertised resources but method not found");
|
|
2434
|
+
return { resources: [] };
|
|
2435
|
+
}
|
|
2436
|
+
throw err;
|
|
2437
|
+
}
|
|
2438
|
+
}
|
|
2439
|
+
/**
|
|
2440
|
+
* List resource templates from the server
|
|
2441
|
+
*
|
|
2442
|
+
* @param options - Request options
|
|
2443
|
+
* @returns List of available resource templates
|
|
2444
|
+
*/
|
|
2445
|
+
async listResourceTemplates(options) {
|
|
2446
|
+
if (!this.client) {
|
|
2447
|
+
throw new Error("MCP client is not connected");
|
|
2448
|
+
}
|
|
2449
|
+
logger.debug("Listing resource templates");
|
|
2450
|
+
return await this.client.listResourceTemplates(void 0, options);
|
|
2451
|
+
}
|
|
2452
|
+
/** Read a resource by URI. */
|
|
2453
|
+
async readResource(uri, options) {
|
|
2454
|
+
if (!this.client) {
|
|
2455
|
+
throw new Error("MCP client is not connected");
|
|
2456
|
+
}
|
|
2457
|
+
logger.debug(`Reading resource ${uri}`);
|
|
2458
|
+
const res = await this.client.readResource({ uri }, options);
|
|
2459
|
+
return res;
|
|
2460
|
+
}
|
|
2461
|
+
/**
|
|
2462
|
+
* Subscribe to resource updates
|
|
2463
|
+
*
|
|
2464
|
+
* @param uri - URI of the resource to subscribe to
|
|
2465
|
+
* @param options - Request options
|
|
2466
|
+
*/
|
|
2467
|
+
async subscribeToResource(uri, options) {
|
|
2468
|
+
if (!this.client) {
|
|
2469
|
+
throw new Error("MCP client is not connected");
|
|
2470
|
+
}
|
|
2471
|
+
logger.debug(`Subscribing to resource: ${uri}`);
|
|
2472
|
+
return await this.client.subscribeResource({ uri }, options);
|
|
2473
|
+
}
|
|
2474
|
+
/**
|
|
2475
|
+
* Unsubscribe from resource updates
|
|
2476
|
+
*
|
|
2477
|
+
* @param uri - URI of the resource to unsubscribe from
|
|
2478
|
+
* @param options - Request options
|
|
2479
|
+
*/
|
|
2480
|
+
async unsubscribeFromResource(uri, options) {
|
|
2481
|
+
if (!this.client) {
|
|
2482
|
+
throw new Error("MCP client is not connected");
|
|
2483
|
+
}
|
|
2484
|
+
logger.debug(`Unsubscribing from resource: ${uri}`);
|
|
2485
|
+
return await this.client.unsubscribeResource({ uri }, options);
|
|
2486
|
+
}
|
|
2487
|
+
async listPrompts() {
|
|
2488
|
+
if (!this.client) {
|
|
2489
|
+
throw new Error("MCP client is not connected");
|
|
2490
|
+
}
|
|
2491
|
+
if (!this.capabilitiesCache?.prompts) {
|
|
2492
|
+
logger.debug("Server does not advertise prompts capability, skipping");
|
|
2493
|
+
return { prompts: [] };
|
|
2494
|
+
}
|
|
2495
|
+
try {
|
|
2496
|
+
logger.debug("Listing prompts");
|
|
2497
|
+
return await this.client.listPrompts();
|
|
2498
|
+
} catch (err) {
|
|
2499
|
+
const error = err;
|
|
2500
|
+
if (error.code === -32601) {
|
|
2501
|
+
logger.debug("Server advertised prompts but method not found");
|
|
2502
|
+
return { prompts: [] };
|
|
2503
|
+
}
|
|
2504
|
+
throw err;
|
|
2505
|
+
}
|
|
2506
|
+
}
|
|
2507
|
+
async getPrompt(name, args) {
|
|
2508
|
+
if (!this.client) {
|
|
2509
|
+
throw new Error("MCP client is not connected");
|
|
2510
|
+
}
|
|
2511
|
+
logger.debug(`Getting prompt ${name}`);
|
|
2512
|
+
return await this.client.getPrompt({ name, arguments: args });
|
|
2513
|
+
}
|
|
2514
|
+
/** Send a raw request through the client. */
|
|
2515
|
+
async request(method, params = null, options) {
|
|
2516
|
+
if (!this.client) {
|
|
2517
|
+
throw new Error("MCP client is not connected");
|
|
2518
|
+
}
|
|
2519
|
+
logger.debug(`Sending raw request '${method}' with params`, params);
|
|
2520
|
+
return await this.client.request(
|
|
2521
|
+
{ method, params: params ?? {} },
|
|
2522
|
+
void 0,
|
|
2523
|
+
options
|
|
2524
|
+
);
|
|
2525
|
+
}
|
|
2526
|
+
/**
|
|
2527
|
+
* Helper to tear down the client & connection manager safely.
|
|
2528
|
+
*/
|
|
2529
|
+
async cleanupResources() {
|
|
2530
|
+
const issues = [];
|
|
2531
|
+
if (this.client) {
|
|
2532
|
+
try {
|
|
2533
|
+
if (typeof this.client.close === "function") {
|
|
2534
|
+
await this.client.close();
|
|
2535
|
+
}
|
|
2536
|
+
} catch (e) {
|
|
2537
|
+
const msg = `Error closing client: ${e}`;
|
|
2538
|
+
logger.warn(msg);
|
|
2539
|
+
issues.push(msg);
|
|
2540
|
+
} finally {
|
|
2541
|
+
this.client = null;
|
|
2542
|
+
}
|
|
2543
|
+
}
|
|
2544
|
+
if (this.connectionManager) {
|
|
2545
|
+
try {
|
|
2546
|
+
await this.connectionManager.stop();
|
|
2547
|
+
} catch (e) {
|
|
2548
|
+
const msg = `Error stopping connection manager: ${e}`;
|
|
2549
|
+
logger.warn(msg);
|
|
2550
|
+
issues.push(msg);
|
|
2551
|
+
} finally {
|
|
2552
|
+
this.connectionManager = null;
|
|
2553
|
+
}
|
|
2554
|
+
}
|
|
2555
|
+
this.toolsCache = null;
|
|
2556
|
+
if (issues.length) {
|
|
2557
|
+
logger.warn(`Resource cleanup finished with ${issues.length} issue(s)`);
|
|
2558
|
+
}
|
|
2559
|
+
}
|
|
2560
|
+
};
|
|
2087
2561
|
|
|
2088
2562
|
// src/client/connectors/codeMode.ts
|
|
2089
2563
|
var CODE_MODE_AGENT_PROMPT = `
|
|
@@ -2173,6 +2647,110 @@ return {
|
|
|
2173
2647
|
|
|
2174
2648
|
Remember: Always discover and understand available tools before attempting to use them in code execution.
|
|
2175
2649
|
`;
|
|
2650
|
+
var CodeModeConnector = class extends BaseConnector {
|
|
2651
|
+
static {
|
|
2652
|
+
__name(this, "CodeModeConnector");
|
|
2653
|
+
}
|
|
2654
|
+
mcpClient;
|
|
2655
|
+
_tools;
|
|
2656
|
+
constructor(client) {
|
|
2657
|
+
super();
|
|
2658
|
+
this.mcpClient = client;
|
|
2659
|
+
this.connected = true;
|
|
2660
|
+
this._tools = this._createToolsList();
|
|
2661
|
+
}
|
|
2662
|
+
async connect() {
|
|
2663
|
+
this.connected = true;
|
|
2664
|
+
}
|
|
2665
|
+
async disconnect() {
|
|
2666
|
+
this.connected = false;
|
|
2667
|
+
}
|
|
2668
|
+
get publicIdentifier() {
|
|
2669
|
+
return { name: "code_mode", version: "1.0.0" };
|
|
2670
|
+
}
|
|
2671
|
+
_createToolsList() {
|
|
2672
|
+
return [
|
|
2673
|
+
{
|
|
2674
|
+
name: "execute_code",
|
|
2675
|
+
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.",
|
|
2676
|
+
inputSchema: {
|
|
2677
|
+
type: "object",
|
|
2678
|
+
properties: {
|
|
2679
|
+
code: {
|
|
2680
|
+
type: "string",
|
|
2681
|
+
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"
|
|
2682
|
+
},
|
|
2683
|
+
timeout: {
|
|
2684
|
+
type: "number",
|
|
2685
|
+
description: "Execution timeout in milliseconds",
|
|
2686
|
+
default: 3e4
|
|
2687
|
+
}
|
|
2688
|
+
},
|
|
2689
|
+
required: ["code"]
|
|
2690
|
+
}
|
|
2691
|
+
},
|
|
2692
|
+
{
|
|
2693
|
+
name: "search_tools",
|
|
2694
|
+
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.",
|
|
2695
|
+
inputSchema: {
|
|
2696
|
+
type: "object",
|
|
2697
|
+
properties: {
|
|
2698
|
+
query: {
|
|
2699
|
+
type: "string",
|
|
2700
|
+
description: "Search query to filter tools by name or description",
|
|
2701
|
+
default: ""
|
|
2702
|
+
},
|
|
2703
|
+
detail_level: {
|
|
2704
|
+
type: "string",
|
|
2705
|
+
description: "Detail level: 'names', 'descriptions', or 'full'",
|
|
2706
|
+
enum: ["names", "descriptions", "full"],
|
|
2707
|
+
default: "full"
|
|
2708
|
+
}
|
|
2709
|
+
}
|
|
2710
|
+
}
|
|
2711
|
+
}
|
|
2712
|
+
];
|
|
2713
|
+
}
|
|
2714
|
+
// Override tools getter to return static list immediately
|
|
2715
|
+
get tools() {
|
|
2716
|
+
return this._tools;
|
|
2717
|
+
}
|
|
2718
|
+
async initialize() {
|
|
2719
|
+
this.toolsCache = this._tools;
|
|
2720
|
+
return { capabilities: {}, version: "1.0.0" };
|
|
2721
|
+
}
|
|
2722
|
+
async callTool(name, args) {
|
|
2723
|
+
if (name === "execute_code") {
|
|
2724
|
+
const code = args.code;
|
|
2725
|
+
const timeout = args.timeout || 3e4;
|
|
2726
|
+
const result = await this.mcpClient.executeCode(code, timeout);
|
|
2727
|
+
return {
|
|
2728
|
+
content: [
|
|
2729
|
+
{
|
|
2730
|
+
type: "text",
|
|
2731
|
+
text: JSON.stringify(result)
|
|
2732
|
+
}
|
|
2733
|
+
]
|
|
2734
|
+
};
|
|
2735
|
+
} else if (name === "search_tools") {
|
|
2736
|
+
const query = args.query || "";
|
|
2737
|
+
const detailLevel = args.detail_level;
|
|
2738
|
+
const result = await this.mcpClient.searchTools(
|
|
2739
|
+
query,
|
|
2740
|
+
detailLevel && detailLevel in ["names", "descriptions", "full"] ? detailLevel : "full"
|
|
2741
|
+
);
|
|
2742
|
+
return {
|
|
2743
|
+
content: [
|
|
2744
|
+
{
|
|
2745
|
+
type: "text",
|
|
2746
|
+
text: JSON.stringify(result)
|
|
2747
|
+
}
|
|
2748
|
+
]
|
|
2749
|
+
};
|
|
2750
|
+
}
|
|
2751
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
2752
|
+
}
|
|
2753
|
+
};
|
|
2176
2754
|
|
|
2177
2755
|
// src/client/prompts.ts
|
|
2178
2756
|
var PROMPTS = {
|
|
@@ -2974,6 +3552,98 @@ var BaseAdapter = class {
|
|
|
2974
3552
|
logger.debug(`Available tools: ${tools.length}`);
|
|
2975
3553
|
return tools;
|
|
2976
3554
|
}
|
|
3555
|
+
/**
|
|
3556
|
+
* Dynamically load resources for a specific connector.
|
|
3557
|
+
*
|
|
3558
|
+
* @param connector The connector to load resources for.
|
|
3559
|
+
* @returns The list of resources that were loaded in the target framework's format.
|
|
3560
|
+
*/
|
|
3561
|
+
async loadResourcesForConnector(connector) {
|
|
3562
|
+
const connectorResources = [];
|
|
3563
|
+
const success = await this.ensureConnectorInitialized(connector);
|
|
3564
|
+
if (!success) {
|
|
3565
|
+
return [];
|
|
3566
|
+
}
|
|
3567
|
+
try {
|
|
3568
|
+
const resourcesResult = await connector.listAllResources();
|
|
3569
|
+
const resources = resourcesResult?.resources || [];
|
|
3570
|
+
if (this.convertResource) {
|
|
3571
|
+
for (const resource of resources) {
|
|
3572
|
+
const converted = this.convertResource(resource, connector);
|
|
3573
|
+
if (converted) {
|
|
3574
|
+
connectorResources.push(converted);
|
|
3575
|
+
}
|
|
3576
|
+
}
|
|
3577
|
+
}
|
|
3578
|
+
logger.debug(
|
|
3579
|
+
`Loaded ${connectorResources.length} new resources for connector: ${connectorResources.map((r) => r?.name ?? String(r)).join(", ")}`
|
|
3580
|
+
);
|
|
3581
|
+
} catch (err) {
|
|
3582
|
+
logger.warn(`Error loading resources for connector: ${err}`);
|
|
3583
|
+
}
|
|
3584
|
+
return connectorResources;
|
|
3585
|
+
}
|
|
3586
|
+
/**
|
|
3587
|
+
* Dynamically load prompts for a specific connector.
|
|
3588
|
+
*
|
|
3589
|
+
* @param connector The connector to load prompts for.
|
|
3590
|
+
* @returns The list of prompts that were loaded in the target framework's format.
|
|
3591
|
+
*/
|
|
3592
|
+
async loadPromptsForConnector(connector) {
|
|
3593
|
+
const connectorPrompts = [];
|
|
3594
|
+
const success = await this.ensureConnectorInitialized(connector);
|
|
3595
|
+
if (!success) {
|
|
3596
|
+
return [];
|
|
3597
|
+
}
|
|
3598
|
+
try {
|
|
3599
|
+
const promptsResult = await connector.listPrompts();
|
|
3600
|
+
const prompts = promptsResult?.prompts || [];
|
|
3601
|
+
if (this.convertPrompt) {
|
|
3602
|
+
for (const prompt of prompts) {
|
|
3603
|
+
const converted = this.convertPrompt(prompt, connector);
|
|
3604
|
+
if (converted) {
|
|
3605
|
+
connectorPrompts.push(converted);
|
|
3606
|
+
}
|
|
3607
|
+
}
|
|
3608
|
+
}
|
|
3609
|
+
logger.debug(
|
|
3610
|
+
`Loaded ${connectorPrompts.length} new prompts for connector: ${connectorPrompts.map((p) => p?.name ?? String(p)).join(", ")}`
|
|
3611
|
+
);
|
|
3612
|
+
} catch (err) {
|
|
3613
|
+
logger.warn(`Error loading prompts for connector: ${err}`);
|
|
3614
|
+
}
|
|
3615
|
+
return connectorPrompts;
|
|
3616
|
+
}
|
|
3617
|
+
/**
|
|
3618
|
+
* Create resources from MCP resources in all provided connectors.
|
|
3619
|
+
*
|
|
3620
|
+
* @param connectors List of MCP connectors to create resources from.
|
|
3621
|
+
* @returns A promise that resolves with all converted resources.
|
|
3622
|
+
*/
|
|
3623
|
+
async createResourcesFromConnectors(connectors) {
|
|
3624
|
+
const resources = [];
|
|
3625
|
+
for (const connector of connectors) {
|
|
3626
|
+
const connectorResources = await this.loadResourcesForConnector(connector);
|
|
3627
|
+
resources.push(...connectorResources);
|
|
3628
|
+
}
|
|
3629
|
+
logger.debug(`Available resources: ${resources.length}`);
|
|
3630
|
+
return resources;
|
|
3631
|
+
}
|
|
3632
|
+
/**
|
|
3633
|
+
* Create prompts from MCP prompts in all provided connectors.
|
|
3634
|
+
*
|
|
3635
|
+
* @param connectors List of MCP connectors to create prompts from.
|
|
3636
|
+
* @returns A promise that resolves with all converted prompts.
|
|
3637
|
+
*/
|
|
3638
|
+
async createPromptsFromConnectors(connectors) {
|
|
3639
|
+
const prompts = [];
|
|
3640
|
+
for (const connector of connectors) {
|
|
3641
|
+
const connectorPrompts = await this.loadPromptsForConnector(connector);
|
|
3642
|
+
prompts.push(...connectorPrompts);
|
|
3643
|
+
}
|
|
3644
|
+
logger.debug(`Available prompts: ${prompts.length}`);
|
|
3645
|
+
return prompts;
|
|
3646
|
+
}
|
|
2977
3647
|
/**
|
|
2978
3648
|
* Check if a connector is initialized and has tools.
|
|
2979
3649
|
*
|
|
@@ -3000,57 +3670,2062 @@ var BaseAdapter = class {
|
|
|
3000
3670
|
return false;
|
|
3001
3671
|
}
|
|
3002
3672
|
}
|
|
3003
|
-
return true;
|
|
3673
|
+
return true;
|
|
3674
|
+
}
|
|
3675
|
+
};
|
|
3676
|
+
|
|
3677
|
+
// src/adapters/langchain_adapter.ts
|
|
3678
|
+
function schemaToZod(schema) {
|
|
3679
|
+
try {
|
|
3680
|
+
return JSONSchemaToZod.convert(schema);
|
|
3681
|
+
} catch (err) {
|
|
3682
|
+
logger.warn(`Failed to convert JSON schema to Zod: ${err}`);
|
|
3683
|
+
return import_zod2.z.any();
|
|
3684
|
+
}
|
|
3685
|
+
}
|
|
3686
|
+
__name(schemaToZod, "schemaToZod");
|
|
3687
|
+
var LangChainAdapter = class extends BaseAdapter {
|
|
3688
|
+
static {
|
|
3689
|
+
__name(this, "LangChainAdapter");
|
|
3690
|
+
}
|
|
3691
|
+
constructor(disallowedTools = []) {
|
|
3692
|
+
super(disallowedTools);
|
|
3693
|
+
}
|
|
3694
|
+
/**
|
|
3695
|
+
* Convert a single MCP tool specification into a LangChainJS structured tool.
|
|
3696
|
+
*/
|
|
3697
|
+
convertTool(mcpTool, connector) {
|
|
3698
|
+
if (this.disallowedTools.includes(mcpTool.name)) {
|
|
3699
|
+
return null;
|
|
3700
|
+
}
|
|
3701
|
+
const argsSchema = mcpTool.inputSchema ? schemaToZod(mcpTool.inputSchema) : import_zod2.z.object({}).optional();
|
|
3702
|
+
const tool = new import_tools.DynamicStructuredTool({
|
|
3703
|
+
name: mcpTool.name ?? "NO NAME",
|
|
3704
|
+
description: mcpTool.description ?? "",
|
|
3705
|
+
// Blank is acceptable but discouraged.
|
|
3706
|
+
schema: argsSchema,
|
|
3707
|
+
func: /* @__PURE__ */ __name(async (input) => {
|
|
3708
|
+
logger.debug(
|
|
3709
|
+
`MCP tool "${mcpTool.name}" received input: ${JSON.stringify(input)}`
|
|
3710
|
+
);
|
|
3711
|
+
try {
|
|
3712
|
+
const result = await connector.callTool(
|
|
3713
|
+
mcpTool.name,
|
|
3714
|
+
input
|
|
3715
|
+
);
|
|
3716
|
+
return JSON.stringify(result);
|
|
3717
|
+
} catch (err) {
|
|
3718
|
+
logger.error(`Error executing MCP tool: ${err.message}`);
|
|
3719
|
+
return `Error executing MCP tool: ${String(err)}`;
|
|
3720
|
+
}
|
|
3721
|
+
}, "func")
|
|
3722
|
+
});
|
|
3723
|
+
return tool;
|
|
3724
|
+
}
|
|
3725
|
+
/**
|
|
3726
|
+
* Convert a single MCP resource into a LangChainJS structured tool.
|
|
3727
|
+
* Each resource becomes an async tool that returns its content when called.
|
|
3728
|
+
*/
|
|
3729
|
+
convertResource(mcpResource, connector) {
|
|
3730
|
+
const sanitizeName = /* @__PURE__ */ __name((name) => {
|
|
3731
|
+
return name.replace(/[^A-Za-z0-9_]+/g, "_").toLowerCase().replace(/^_+|_+$/g, "");
|
|
3732
|
+
}, "sanitizeName");
|
|
3733
|
+
const resourceName = sanitizeName(
|
|
3734
|
+
mcpResource.name || `resource_${mcpResource.uri}`
|
|
3735
|
+
);
|
|
3736
|
+
const resourceUri = mcpResource.uri;
|
|
3737
|
+
const tool = new import_tools.DynamicStructuredTool({
|
|
3738
|
+
name: resourceName,
|
|
3739
|
+
description: mcpResource.description || `Return the content of the resource located at URI ${resourceUri}.`,
|
|
3740
|
+
schema: import_zod2.z.object({}).optional(),
|
|
3741
|
+
// Resources take no arguments
|
|
3742
|
+
func: /* @__PURE__ */ __name(async () => {
|
|
3743
|
+
logger.debug(`Resource tool: "${resourceName}" called`);
|
|
3744
|
+
try {
|
|
3745
|
+
const result = await connector.readResource(resourceUri);
|
|
3746
|
+
if (result.contents && result.contents.length > 0) {
|
|
3747
|
+
return result.contents.map((content) => {
|
|
3748
|
+
if (typeof content === "string") {
|
|
3749
|
+
return content;
|
|
3750
|
+
}
|
|
3751
|
+
if (content.text) {
|
|
3752
|
+
return content.text;
|
|
3753
|
+
}
|
|
3754
|
+
if (content.uri) {
|
|
3755
|
+
return content.uri;
|
|
3756
|
+
}
|
|
3757
|
+
return JSON.stringify(content);
|
|
3758
|
+
}).join("\n");
|
|
3759
|
+
}
|
|
3760
|
+
return "Resource is empty or unavailable";
|
|
3761
|
+
} catch (err) {
|
|
3762
|
+
logger.error(`Error reading resource: ${err.message}`);
|
|
3763
|
+
return `Error reading resource: ${String(err)}`;
|
|
3764
|
+
}
|
|
3765
|
+
}, "func")
|
|
3766
|
+
});
|
|
3767
|
+
return tool;
|
|
3768
|
+
}
|
|
3769
|
+
/**
|
|
3770
|
+
* Convert a single MCP prompt into a LangChainJS structured tool.
|
|
3771
|
+
* The resulting tool executes getPrompt on the connector with the prompt's name
|
|
3772
|
+
* and the user-provided arguments (if any).
|
|
3773
|
+
*/
|
|
3774
|
+
convertPrompt(mcpPrompt, connector) {
|
|
3775
|
+
let argsSchema = import_zod2.z.object({}).optional();
|
|
3776
|
+
if (mcpPrompt.arguments && mcpPrompt.arguments.length > 0) {
|
|
3777
|
+
const schemaFields = {};
|
|
3778
|
+
for (const arg of mcpPrompt.arguments) {
|
|
3779
|
+
const zodType = import_zod2.z.string();
|
|
3780
|
+
if (arg.required !== false) {
|
|
3781
|
+
schemaFields[arg.name] = zodType;
|
|
3782
|
+
} else {
|
|
3783
|
+
schemaFields[arg.name] = zodType.optional();
|
|
3784
|
+
}
|
|
3785
|
+
}
|
|
3786
|
+
argsSchema = Object.keys(schemaFields).length > 0 ? import_zod2.z.object(schemaFields) : import_zod2.z.object({}).optional();
|
|
3787
|
+
}
|
|
3788
|
+
const tool = new import_tools.DynamicStructuredTool({
|
|
3789
|
+
name: mcpPrompt.name,
|
|
3790
|
+
description: mcpPrompt.description || "",
|
|
3791
|
+
schema: argsSchema,
|
|
3792
|
+
func: /* @__PURE__ */ __name(async (input) => {
|
|
3793
|
+
logger.debug(
|
|
3794
|
+
`Prompt tool: "${mcpPrompt.name}" called with args: ${JSON.stringify(input)}`
|
|
3795
|
+
);
|
|
3796
|
+
try {
|
|
3797
|
+
const result = await connector.getPrompt(mcpPrompt.name, input);
|
|
3798
|
+
if (result.messages && result.messages.length > 0) {
|
|
3799
|
+
return result.messages.map((msg) => {
|
|
3800
|
+
if (typeof msg === "string") {
|
|
3801
|
+
return msg;
|
|
3802
|
+
}
|
|
3803
|
+
if (msg.content) {
|
|
3804
|
+
return typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content);
|
|
3805
|
+
}
|
|
3806
|
+
return JSON.stringify(msg);
|
|
3807
|
+
}).join("\n");
|
|
3808
|
+
}
|
|
3809
|
+
return "Prompt returned no messages";
|
|
3810
|
+
} catch (err) {
|
|
3811
|
+
logger.error(`Error getting prompt: ${err.message}`);
|
|
3812
|
+
return `Error getting prompt: ${String(err)}`;
|
|
3813
|
+
}
|
|
3814
|
+
}, "func")
|
|
3815
|
+
});
|
|
3816
|
+
return tool;
|
|
3817
|
+
}
|
|
3818
|
+
};
|
|
3819
|
+
|
|
3820
|
+
// src/client.ts
|
|
3821
|
+
var import_node_fs2 = __toESM(require("fs"), 1);
|
|
3822
|
+
var import_node_path = __toESM(require("path"), 1);
|
|
3823
|
+
|
|
3824
|
+
// src/client/base.ts
|
|
3825
|
+
init_logging();
|
|
3826
|
+
|
|
3827
|
+
// src/session.ts
|
|
3828
|
+
var MCPSession = class {
|
|
3829
|
+
static {
|
|
3830
|
+
__name(this, "MCPSession");
|
|
3831
|
+
}
|
|
3832
|
+
connector;
|
|
3833
|
+
autoConnect;
|
|
3834
|
+
constructor(connector, autoConnect = true) {
|
|
3835
|
+
this.connector = connector;
|
|
3836
|
+
this.autoConnect = autoConnect;
|
|
3837
|
+
}
|
|
3838
|
+
async connect() {
|
|
3839
|
+
await this.connector.connect();
|
|
3840
|
+
}
|
|
3841
|
+
async disconnect() {
|
|
3842
|
+
await this.connector.disconnect();
|
|
3843
|
+
}
|
|
3844
|
+
async initialize() {
|
|
3845
|
+
if (!this.isConnected && this.autoConnect) {
|
|
3846
|
+
await this.connect();
|
|
3847
|
+
}
|
|
3848
|
+
await this.connector.initialize();
|
|
3849
|
+
}
|
|
3850
|
+
get isConnected() {
|
|
3851
|
+
return this.connector && this.connector.isClientConnected;
|
|
3852
|
+
}
|
|
3853
|
+
/**
|
|
3854
|
+
* Register an event handler for session events
|
|
3855
|
+
*
|
|
3856
|
+
* @param event - The event type to listen for
|
|
3857
|
+
* @param handler - The handler function to call when the event occurs
|
|
3858
|
+
*
|
|
3859
|
+
* @example
|
|
3860
|
+
* ```typescript
|
|
3861
|
+
* session.on("notification", async (notification) => {
|
|
3862
|
+
* console.log(`Received: ${notification.method}`, notification.params);
|
|
3863
|
+
*
|
|
3864
|
+
* if (notification.method === "notifications/tools/list_changed") {
|
|
3865
|
+
* // Refresh tools list
|
|
3866
|
+
* }
|
|
3867
|
+
* });
|
|
3868
|
+
* ```
|
|
3869
|
+
*/
|
|
3870
|
+
on(event, handler) {
|
|
3871
|
+
if (event === "notification") {
|
|
3872
|
+
this.connector.onNotification(handler);
|
|
3873
|
+
}
|
|
3874
|
+
}
|
|
3875
|
+
/**
|
|
3876
|
+
* Set roots and notify the server.
|
|
3877
|
+
* Roots represent directories or files that the client has access to.
|
|
3878
|
+
*
|
|
3879
|
+
* @param roots - Array of Root objects with `uri` (must start with "file://") and optional `name`
|
|
3880
|
+
*
|
|
3881
|
+
* @example
|
|
3882
|
+
* ```typescript
|
|
3883
|
+
* await session.setRoots([
|
|
3884
|
+
* { uri: "file:///home/user/project", name: "My Project" },
|
|
3885
|
+
* { uri: "file:///home/user/data" }
|
|
3886
|
+
* ]);
|
|
3887
|
+
* ```
|
|
3888
|
+
*/
|
|
3889
|
+
async setRoots(roots) {
|
|
3890
|
+
return this.connector.setRoots(roots);
|
|
3891
|
+
}
|
|
3892
|
+
/**
|
|
3893
|
+
* Get the current roots.
|
|
3894
|
+
*/
|
|
3895
|
+
getRoots() {
|
|
3896
|
+
return this.connector.getRoots();
|
|
3897
|
+
}
|
|
3898
|
+
/**
|
|
3899
|
+
* Get the cached list of tools from the server.
|
|
3900
|
+
*
|
|
3901
|
+
* @returns Array of available tools
|
|
3902
|
+
*
|
|
3903
|
+
* @example
|
|
3904
|
+
* ```typescript
|
|
3905
|
+
* const tools = session.tools;
|
|
3906
|
+
* console.log(`Available tools: ${tools.map(t => t.name).join(", ")}`);
|
|
3907
|
+
* ```
|
|
3908
|
+
*/
|
|
3909
|
+
get tools() {
|
|
3910
|
+
return this.connector.tools;
|
|
3911
|
+
}
|
|
3912
|
+
/**
|
|
3913
|
+
* List all available tools from the MCP server.
|
|
3914
|
+
* This method fetches fresh tools from the server, unlike the `tools` getter which returns cached tools.
|
|
3915
|
+
*
|
|
3916
|
+
* @param options - Optional request options
|
|
3917
|
+
* @returns Array of available tools
|
|
3918
|
+
*
|
|
3919
|
+
* @example
|
|
3920
|
+
* ```typescript
|
|
3921
|
+
* const tools = await session.listTools();
|
|
3922
|
+
* console.log(`Available tools: ${tools.map(t => t.name).join(", ")}`);
|
|
3923
|
+
* ```
|
|
3924
|
+
*/
|
|
3925
|
+
async listTools(options) {
|
|
3926
|
+
return this.connector.listTools(options);
|
|
3927
|
+
}
|
|
3928
|
+
/**
|
|
3929
|
+
* Get the server capabilities advertised during initialization.
|
|
3930
|
+
*
|
|
3931
|
+
* @returns Server capabilities object
|
|
3932
|
+
*/
|
|
3933
|
+
get serverCapabilities() {
|
|
3934
|
+
return this.connector.serverCapabilities;
|
|
3935
|
+
}
|
|
3936
|
+
/**
|
|
3937
|
+
* Get the server information (name and version).
|
|
3938
|
+
*
|
|
3939
|
+
* @returns Server info object or null if not available
|
|
3940
|
+
*/
|
|
3941
|
+
get serverInfo() {
|
|
3942
|
+
return this.connector.serverInfo;
|
|
3943
|
+
}
|
|
3944
|
+
/**
|
|
3945
|
+
* Call a tool on the server.
|
|
3946
|
+
*
|
|
3947
|
+
* @param name - Name of the tool to call
|
|
3948
|
+
* @param args - Arguments to pass to the tool (defaults to empty object)
|
|
3949
|
+
* @param options - Optional request options (timeout, progress handlers, etc.)
|
|
3950
|
+
* @returns Result from the tool execution
|
|
3951
|
+
*
|
|
3952
|
+
* @example
|
|
3953
|
+
* ```typescript
|
|
3954
|
+
* const result = await session.callTool("add", { a: 5, b: 3 });
|
|
3955
|
+
* console.log(`Result: ${result.content[0].text}`);
|
|
3956
|
+
* ```
|
|
3957
|
+
*/
|
|
3958
|
+
async callTool(name, args = {}, options) {
|
|
3959
|
+
return this.connector.callTool(name, args, options);
|
|
3960
|
+
}
|
|
3961
|
+
/**
|
|
3962
|
+
* List resources from the server with optional pagination.
|
|
3963
|
+
*
|
|
3964
|
+
* @param cursor - Optional cursor for pagination
|
|
3965
|
+
* @param options - Request options
|
|
3966
|
+
* @returns Resource list with optional nextCursor for pagination
|
|
3967
|
+
*
|
|
3968
|
+
* @example
|
|
3969
|
+
* ```typescript
|
|
3970
|
+
* const result = await session.listResources();
|
|
3971
|
+
* console.log(`Found ${result.resources.length} resources`);
|
|
3972
|
+
* ```
|
|
3973
|
+
*/
|
|
3974
|
+
async listResources(cursor, options) {
|
|
3975
|
+
return this.connector.listResources(cursor, options);
|
|
3976
|
+
}
|
|
3977
|
+
/**
|
|
3978
|
+
* List all resources from the server, automatically handling pagination.
|
|
3979
|
+
*
|
|
3980
|
+
* @param options - Request options
|
|
3981
|
+
* @returns Complete list of all resources
|
|
3982
|
+
*
|
|
3983
|
+
* @example
|
|
3984
|
+
* ```typescript
|
|
3985
|
+
* const result = await session.listAllResources();
|
|
3986
|
+
* console.log(`Total resources: ${result.resources.length}`);
|
|
3987
|
+
* ```
|
|
3988
|
+
*/
|
|
3989
|
+
async listAllResources(options) {
|
|
3990
|
+
return this.connector.listAllResources(options);
|
|
3991
|
+
}
|
|
3992
|
+
/**
|
|
3993
|
+
* List resource templates from the server.
|
|
3994
|
+
*
|
|
3995
|
+
* @param options - Request options
|
|
3996
|
+
* @returns List of available resource templates
|
|
3997
|
+
*
|
|
3998
|
+
* @example
|
|
3999
|
+
* ```typescript
|
|
4000
|
+
* const result = await session.listResourceTemplates();
|
|
4001
|
+
* console.log(`Available templates: ${result.resourceTemplates.length}`);
|
|
4002
|
+
* ```
|
|
4003
|
+
*/
|
|
4004
|
+
async listResourceTemplates(options) {
|
|
4005
|
+
return this.connector.listResourceTemplates(options);
|
|
4006
|
+
}
|
|
4007
|
+
/**
|
|
4008
|
+
* Read a resource by URI.
|
|
4009
|
+
*
|
|
4010
|
+
* @param uri - URI of the resource to read
|
|
4011
|
+
* @param options - Request options
|
|
4012
|
+
* @returns Resource content
|
|
4013
|
+
*
|
|
4014
|
+
* @example
|
|
4015
|
+
* ```typescript
|
|
4016
|
+
* const resource = await session.readResource("file:///path/to/file.txt");
|
|
4017
|
+
* console.log(resource.contents);
|
|
4018
|
+
* ```
|
|
4019
|
+
*/
|
|
4020
|
+
async readResource(uri, options) {
|
|
4021
|
+
return this.connector.readResource(uri, options);
|
|
4022
|
+
}
|
|
4023
|
+
/**
|
|
4024
|
+
* Subscribe to resource updates.
|
|
4025
|
+
*
|
|
4026
|
+
* @param uri - URI of the resource to subscribe to
|
|
4027
|
+
* @param options - Request options
|
|
4028
|
+
*
|
|
4029
|
+
* @example
|
|
4030
|
+
* ```typescript
|
|
4031
|
+
* await session.subscribeToResource("file:///path/to/file.txt");
|
|
4032
|
+
* // Now you'll receive notifications when this resource changes
|
|
4033
|
+
* ```
|
|
4034
|
+
*/
|
|
4035
|
+
async subscribeToResource(uri, options) {
|
|
4036
|
+
return this.connector.subscribeToResource(uri, options);
|
|
4037
|
+
}
|
|
4038
|
+
/**
|
|
4039
|
+
* Unsubscribe from resource updates.
|
|
4040
|
+
*
|
|
4041
|
+
* @param uri - URI of the resource to unsubscribe from
|
|
4042
|
+
* @param options - Request options
|
|
4043
|
+
*
|
|
4044
|
+
* @example
|
|
4045
|
+
* ```typescript
|
|
4046
|
+
* await session.unsubscribeFromResource("file:///path/to/file.txt");
|
|
4047
|
+
* ```
|
|
4048
|
+
*/
|
|
4049
|
+
async unsubscribeFromResource(uri, options) {
|
|
4050
|
+
return this.connector.unsubscribeFromResource(uri, options);
|
|
4051
|
+
}
|
|
4052
|
+
/**
|
|
4053
|
+
* List available prompts from the server.
|
|
4054
|
+
*
|
|
4055
|
+
* @returns List of available prompts
|
|
4056
|
+
*
|
|
4057
|
+
* @example
|
|
4058
|
+
* ```typescript
|
|
4059
|
+
* const result = await session.listPrompts();
|
|
4060
|
+
* console.log(`Available prompts: ${result.prompts.length}`);
|
|
4061
|
+
* ```
|
|
4062
|
+
*/
|
|
4063
|
+
async listPrompts() {
|
|
4064
|
+
return this.connector.listPrompts();
|
|
4065
|
+
}
|
|
4066
|
+
/**
|
|
4067
|
+
* Get a specific prompt with arguments.
|
|
4068
|
+
*
|
|
4069
|
+
* @param name - Name of the prompt to get
|
|
4070
|
+
* @param args - Arguments for the prompt
|
|
4071
|
+
* @returns Prompt result
|
|
4072
|
+
*
|
|
4073
|
+
* @example
|
|
4074
|
+
* ```typescript
|
|
4075
|
+
* const prompt = await session.getPrompt("greeting", { name: "Alice" });
|
|
4076
|
+
* console.log(prompt.messages);
|
|
4077
|
+
* ```
|
|
4078
|
+
*/
|
|
4079
|
+
async getPrompt(name, args) {
|
|
4080
|
+
return this.connector.getPrompt(name, args);
|
|
4081
|
+
}
|
|
4082
|
+
/**
|
|
4083
|
+
* Send a raw request through the client.
|
|
4084
|
+
*
|
|
4085
|
+
* @param method - MCP method name
|
|
4086
|
+
* @param params - Request parameters
|
|
4087
|
+
* @param options - Request options
|
|
4088
|
+
* @returns Response from the server
|
|
4089
|
+
*
|
|
4090
|
+
* @example
|
|
4091
|
+
* ```typescript
|
|
4092
|
+
* const result = await session.request("custom/method", { key: "value" });
|
|
4093
|
+
* ```
|
|
4094
|
+
*/
|
|
4095
|
+
async request(method, params = null, options) {
|
|
4096
|
+
return this.connector.request(method, params, options);
|
|
4097
|
+
}
|
|
4098
|
+
};
|
|
4099
|
+
|
|
4100
|
+
// src/client/base.ts
|
|
4101
|
+
var BaseMCPClient = class {
|
|
4102
|
+
static {
|
|
4103
|
+
__name(this, "BaseMCPClient");
|
|
4104
|
+
}
|
|
4105
|
+
config = {};
|
|
4106
|
+
sessions = {};
|
|
4107
|
+
activeSessions = [];
|
|
4108
|
+
constructor(config) {
|
|
4109
|
+
if (config) {
|
|
4110
|
+
this.config = config;
|
|
4111
|
+
}
|
|
4112
|
+
}
|
|
4113
|
+
static fromDict(_cfg) {
|
|
4114
|
+
throw new Error("fromDict must be implemented by concrete class");
|
|
4115
|
+
}
|
|
4116
|
+
addServer(name, serverConfig) {
|
|
4117
|
+
this.config.mcpServers = this.config.mcpServers || {};
|
|
4118
|
+
this.config.mcpServers[name] = serverConfig;
|
|
4119
|
+
Tel.getInstance().trackClientAddServer(name, serverConfig);
|
|
4120
|
+
}
|
|
4121
|
+
removeServer(name) {
|
|
4122
|
+
if (this.config.mcpServers?.[name]) {
|
|
4123
|
+
delete this.config.mcpServers[name];
|
|
4124
|
+
this.activeSessions = this.activeSessions.filter((n) => n !== name);
|
|
4125
|
+
Tel.getInstance().trackClientRemoveServer(name);
|
|
4126
|
+
}
|
|
4127
|
+
}
|
|
4128
|
+
getServerNames() {
|
|
4129
|
+
return Object.keys(this.config.mcpServers ?? {});
|
|
4130
|
+
}
|
|
4131
|
+
getServerConfig(name) {
|
|
4132
|
+
return this.config.mcpServers?.[name];
|
|
4133
|
+
}
|
|
4134
|
+
getConfig() {
|
|
4135
|
+
return this.config ?? {};
|
|
4136
|
+
}
|
|
4137
|
+
async createSession(serverName, autoInitialize = true) {
|
|
4138
|
+
const servers = this.config.mcpServers ?? {};
|
|
4139
|
+
if (Object.keys(servers).length === 0) {
|
|
4140
|
+
logger.warn("No MCP servers defined in config");
|
|
4141
|
+
}
|
|
4142
|
+
if (!servers[serverName]) {
|
|
4143
|
+
throw new Error(`Server '${serverName}' not found in config`);
|
|
4144
|
+
}
|
|
4145
|
+
const connector = this.createConnectorFromConfig(servers[serverName]);
|
|
4146
|
+
const session = new MCPSession(connector);
|
|
4147
|
+
if (autoInitialize) {
|
|
4148
|
+
await session.initialize();
|
|
4149
|
+
}
|
|
4150
|
+
this.sessions[serverName] = session;
|
|
4151
|
+
if (!this.activeSessions.includes(serverName)) {
|
|
4152
|
+
this.activeSessions.push(serverName);
|
|
4153
|
+
}
|
|
4154
|
+
return session;
|
|
4155
|
+
}
|
|
4156
|
+
async createAllSessions(autoInitialize = true) {
|
|
4157
|
+
const servers = this.config.mcpServers ?? {};
|
|
4158
|
+
if (Object.keys(servers).length === 0) {
|
|
4159
|
+
logger.warn("No MCP servers defined in config");
|
|
4160
|
+
}
|
|
4161
|
+
for (const name of Object.keys(servers)) {
|
|
4162
|
+
await this.createSession(name, autoInitialize);
|
|
4163
|
+
}
|
|
4164
|
+
return this.sessions;
|
|
4165
|
+
}
|
|
4166
|
+
getSession(serverName) {
|
|
4167
|
+
const session = this.sessions[serverName];
|
|
4168
|
+
if (!session) {
|
|
4169
|
+
return null;
|
|
4170
|
+
}
|
|
4171
|
+
return session;
|
|
4172
|
+
}
|
|
4173
|
+
requireSession(serverName) {
|
|
4174
|
+
const session = this.sessions[serverName];
|
|
4175
|
+
if (!session) {
|
|
4176
|
+
throw new Error(
|
|
4177
|
+
`Session '${serverName}' not found. Available sessions: ${this.activeSessions.join(", ") || "none"}`
|
|
4178
|
+
);
|
|
4179
|
+
}
|
|
4180
|
+
return session;
|
|
4181
|
+
}
|
|
4182
|
+
getAllActiveSessions() {
|
|
4183
|
+
return Object.fromEntries(
|
|
4184
|
+
this.activeSessions.map((n) => [n, this.sessions[n]])
|
|
4185
|
+
);
|
|
4186
|
+
}
|
|
4187
|
+
async closeSession(serverName) {
|
|
4188
|
+
const session = this.sessions[serverName];
|
|
4189
|
+
if (!session) {
|
|
4190
|
+
logger.warn(
|
|
4191
|
+
`No session exists for server ${serverName}, nothing to close`
|
|
4192
|
+
);
|
|
4193
|
+
return;
|
|
4194
|
+
}
|
|
4195
|
+
try {
|
|
4196
|
+
logger.debug(`Closing session for server ${serverName}`);
|
|
4197
|
+
await session.disconnect();
|
|
4198
|
+
} catch (e) {
|
|
4199
|
+
logger.error(`Error closing session for server '${serverName}': ${e}`);
|
|
4200
|
+
} finally {
|
|
4201
|
+
delete this.sessions[serverName];
|
|
4202
|
+
this.activeSessions = this.activeSessions.filter((n) => n !== serverName);
|
|
4203
|
+
}
|
|
4204
|
+
}
|
|
4205
|
+
async closeAllSessions() {
|
|
4206
|
+
const serverNames = Object.keys(this.sessions);
|
|
4207
|
+
const errors = [];
|
|
4208
|
+
for (const serverName of serverNames) {
|
|
4209
|
+
try {
|
|
4210
|
+
logger.debug(`Closing session for server ${serverName}`);
|
|
4211
|
+
await this.closeSession(serverName);
|
|
4212
|
+
} catch (e) {
|
|
4213
|
+
const errorMsg = `Failed to close session for server '${serverName}': ${e}`;
|
|
4214
|
+
logger.error(errorMsg);
|
|
4215
|
+
errors.push(errorMsg);
|
|
4216
|
+
}
|
|
4217
|
+
}
|
|
4218
|
+
if (errors.length) {
|
|
4219
|
+
logger.error(
|
|
4220
|
+
`Encountered ${errors.length} errors while closing sessions`
|
|
4221
|
+
);
|
|
4222
|
+
} else {
|
|
4223
|
+
logger.debug("All sessions closed successfully");
|
|
4224
|
+
}
|
|
4225
|
+
}
|
|
4226
|
+
};
|
|
4227
|
+
|
|
4228
|
+
// src/client/executors/base.ts
|
|
4229
|
+
init_logging();
|
|
4230
|
+
var BaseCodeExecutor = class {
|
|
4231
|
+
static {
|
|
4232
|
+
__name(this, "BaseCodeExecutor");
|
|
4233
|
+
}
|
|
4234
|
+
client;
|
|
4235
|
+
_connecting = false;
|
|
4236
|
+
constructor(client) {
|
|
4237
|
+
this.client = client;
|
|
4238
|
+
}
|
|
4239
|
+
/**
|
|
4240
|
+
* Ensure all configured MCP servers are connected before execution.
|
|
4241
|
+
* Prevents race conditions with a connection lock.
|
|
4242
|
+
*/
|
|
4243
|
+
async ensureServersConnected() {
|
|
4244
|
+
const configuredServers = this.client.getServerNames();
|
|
4245
|
+
const activeSessions = Object.keys(this.client.getAllActiveSessions());
|
|
4246
|
+
const missingServers = configuredServers.filter(
|
|
4247
|
+
(s) => !activeSessions.includes(s)
|
|
4248
|
+
);
|
|
4249
|
+
if (missingServers.length > 0 && !this._connecting) {
|
|
4250
|
+
this._connecting = true;
|
|
4251
|
+
try {
|
|
4252
|
+
logger.debug(
|
|
4253
|
+
`Connecting to configured servers for code execution: ${missingServers.join(", ")}`
|
|
4254
|
+
);
|
|
4255
|
+
await this.client.createAllSessions();
|
|
4256
|
+
} finally {
|
|
4257
|
+
this._connecting = false;
|
|
4258
|
+
}
|
|
4259
|
+
} else if (missingServers.length > 0 && this._connecting) {
|
|
4260
|
+
logger.debug("Waiting for ongoing server connection...");
|
|
4261
|
+
const startWait = Date.now();
|
|
4262
|
+
while (this._connecting && Date.now() - startWait < 5e3) {
|
|
4263
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
4264
|
+
}
|
|
4265
|
+
}
|
|
4266
|
+
}
|
|
4267
|
+
/**
|
|
4268
|
+
* Get tool namespace information from all active MCP sessions.
|
|
4269
|
+
* Filters out the internal code_mode server.
|
|
4270
|
+
*/
|
|
4271
|
+
getToolNamespaces() {
|
|
4272
|
+
const namespaces = [];
|
|
4273
|
+
const activeSessions = this.client.getAllActiveSessions();
|
|
4274
|
+
for (const [serverName, session] of Object.entries(activeSessions)) {
|
|
4275
|
+
if (serverName === "code_mode") continue;
|
|
4276
|
+
try {
|
|
4277
|
+
const connector = session.connector;
|
|
4278
|
+
let tools;
|
|
4279
|
+
try {
|
|
4280
|
+
tools = connector.tools;
|
|
4281
|
+
} catch (e) {
|
|
4282
|
+
logger.warn(`Tools not available for server ${serverName}: ${e}`);
|
|
4283
|
+
continue;
|
|
4284
|
+
}
|
|
4285
|
+
if (!tools || tools.length === 0) continue;
|
|
4286
|
+
namespaces.push({ serverName, tools, session });
|
|
4287
|
+
} catch (e) {
|
|
4288
|
+
logger.warn(`Failed to load tools for server ${serverName}: ${e}`);
|
|
4289
|
+
}
|
|
4290
|
+
}
|
|
4291
|
+
return namespaces;
|
|
4292
|
+
}
|
|
4293
|
+
/**
|
|
4294
|
+
* Create a search function for discovering available MCP tools.
|
|
4295
|
+
* Used by code execution environments to find tools at runtime.
|
|
4296
|
+
*/
|
|
4297
|
+
createSearchToolsFunction() {
|
|
4298
|
+
return async (query = "", detailLevel = "full") => {
|
|
4299
|
+
const allTools = [];
|
|
4300
|
+
const allNamespaces = /* @__PURE__ */ new Set();
|
|
4301
|
+
const queryLower = query.toLowerCase();
|
|
4302
|
+
const activeSessions = this.client.getAllActiveSessions();
|
|
4303
|
+
for (const [serverName, session] of Object.entries(activeSessions)) {
|
|
4304
|
+
if (serverName === "code_mode") continue;
|
|
4305
|
+
try {
|
|
4306
|
+
const tools = session.connector.tools;
|
|
4307
|
+
if (tools && tools.length > 0) {
|
|
4308
|
+
allNamespaces.add(serverName);
|
|
4309
|
+
}
|
|
4310
|
+
for (const tool of tools) {
|
|
4311
|
+
if (detailLevel === "names") {
|
|
4312
|
+
allTools.push({ name: tool.name, server: serverName });
|
|
4313
|
+
} else if (detailLevel === "descriptions") {
|
|
4314
|
+
allTools.push({
|
|
4315
|
+
name: tool.name,
|
|
4316
|
+
server: serverName,
|
|
4317
|
+
description: tool.description
|
|
4318
|
+
});
|
|
4319
|
+
} else {
|
|
4320
|
+
allTools.push({
|
|
4321
|
+
name: tool.name,
|
|
4322
|
+
server: serverName,
|
|
4323
|
+
description: tool.description,
|
|
4324
|
+
input_schema: tool.inputSchema
|
|
4325
|
+
});
|
|
4326
|
+
}
|
|
4327
|
+
}
|
|
4328
|
+
} catch (e) {
|
|
4329
|
+
logger.warn(`Failed to search tools in server ${serverName}: ${e}`);
|
|
4330
|
+
}
|
|
4331
|
+
}
|
|
4332
|
+
let filteredTools = allTools;
|
|
4333
|
+
if (query) {
|
|
4334
|
+
filteredTools = allTools.filter((tool) => {
|
|
4335
|
+
const nameMatch = tool.name.toLowerCase().includes(queryLower);
|
|
4336
|
+
const descMatch = tool.description?.toLowerCase().includes(queryLower);
|
|
4337
|
+
const serverMatch = tool.server.toLowerCase().includes(queryLower);
|
|
4338
|
+
return nameMatch || descMatch || serverMatch;
|
|
4339
|
+
});
|
|
4340
|
+
}
|
|
4341
|
+
return {
|
|
4342
|
+
meta: {
|
|
4343
|
+
total_tools: allTools.length,
|
|
4344
|
+
namespaces: Array.from(allNamespaces).sort(),
|
|
4345
|
+
result_count: filteredTools.length
|
|
4346
|
+
},
|
|
4347
|
+
results: filteredTools
|
|
4348
|
+
};
|
|
4349
|
+
};
|
|
4350
|
+
}
|
|
4351
|
+
};
|
|
4352
|
+
|
|
4353
|
+
// src/client/executors/e2b.ts
|
|
4354
|
+
init_logging();
|
|
4355
|
+
var E2BCodeExecutor = class extends BaseCodeExecutor {
|
|
4356
|
+
static {
|
|
4357
|
+
__name(this, "E2BCodeExecutor");
|
|
4358
|
+
}
|
|
4359
|
+
e2bApiKey;
|
|
4360
|
+
codeExecSandbox = null;
|
|
4361
|
+
SandboxClass = null;
|
|
4362
|
+
timeoutMs;
|
|
4363
|
+
constructor(client, options) {
|
|
4364
|
+
super(client);
|
|
4365
|
+
this.e2bApiKey = options.apiKey;
|
|
4366
|
+
this.timeoutMs = options.timeoutMs ?? 3e5;
|
|
4367
|
+
}
|
|
4368
|
+
/**
|
|
4369
|
+
* Lazy load E2B Sandbox class.
|
|
4370
|
+
* This allows the library to work without E2B installed.
|
|
4371
|
+
*/
|
|
4372
|
+
async ensureSandboxClass() {
|
|
4373
|
+
if (this.SandboxClass) return;
|
|
4374
|
+
try {
|
|
4375
|
+
const e2b = await import("@e2b/code-interpreter");
|
|
4376
|
+
this.SandboxClass = e2b.Sandbox;
|
|
4377
|
+
} catch (error) {
|
|
4378
|
+
throw new Error(
|
|
4379
|
+
"@e2b/code-interpreter is not installed. The E2B code executor requires this optional dependency. Install it with: yarn add @e2b/code-interpreter"
|
|
4380
|
+
);
|
|
4381
|
+
}
|
|
4382
|
+
}
|
|
4383
|
+
/**
|
|
4384
|
+
* Get or create a dedicated sandbox for code execution.
|
|
4385
|
+
*/
|
|
4386
|
+
async getOrCreateCodeExecSandbox() {
|
|
4387
|
+
if (this.codeExecSandbox) return this.codeExecSandbox;
|
|
4388
|
+
await this.ensureSandboxClass();
|
|
4389
|
+
logger.debug("Starting E2B sandbox for code execution...");
|
|
4390
|
+
this.codeExecSandbox = await this.SandboxClass.create("base", {
|
|
4391
|
+
apiKey: this.e2bApiKey,
|
|
4392
|
+
timeoutMs: this.timeoutMs
|
|
4393
|
+
});
|
|
4394
|
+
return this.codeExecSandbox;
|
|
4395
|
+
}
|
|
4396
|
+
/**
|
|
4397
|
+
* Generate the shim code that exposes tools to the sandbox environment.
|
|
4398
|
+
* Creates a bridge that intercepts tool calls and sends them back to host.
|
|
4399
|
+
*/
|
|
4400
|
+
generateShim(tools) {
|
|
4401
|
+
let shim = `
|
|
4402
|
+
// MCP Bridge Shim
|
|
4403
|
+
global.__callMcpTool = async (server, tool, args) => {
|
|
4404
|
+
const id = Math.random().toString(36).substring(7);
|
|
4405
|
+
console.log(JSON.stringify({
|
|
4406
|
+
type: '__MCP_TOOL_CALL__',
|
|
4407
|
+
id,
|
|
4408
|
+
server,
|
|
4409
|
+
tool,
|
|
4410
|
+
args
|
|
4411
|
+
}));
|
|
4412
|
+
|
|
4413
|
+
const resultPath = \`/tmp/mcp_result_\${id}.json\`;
|
|
4414
|
+
const fs = require('fs');
|
|
4415
|
+
|
|
4416
|
+
// Poll for result file
|
|
4417
|
+
let attempts = 0;
|
|
4418
|
+
while (attempts < 300) { // 30 seconds timeout
|
|
4419
|
+
if (fs.existsSync(resultPath)) {
|
|
4420
|
+
const content = fs.readFileSync(resultPath, 'utf8');
|
|
4421
|
+
const result = JSON.parse(content);
|
|
4422
|
+
fs.unlinkSync(resultPath); // Clean up
|
|
4423
|
+
|
|
4424
|
+
if (result.error) {
|
|
4425
|
+
throw new Error(result.error);
|
|
4426
|
+
}
|
|
4427
|
+
return result.data;
|
|
4428
|
+
}
|
|
4429
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
4430
|
+
attempts++;
|
|
4431
|
+
}
|
|
4432
|
+
throw new Error('Tool execution timed out');
|
|
4433
|
+
};
|
|
4434
|
+
|
|
4435
|
+
// Global search_tools helper
|
|
4436
|
+
global.search_tools = async (query, detailLevel = 'full') => {
|
|
4437
|
+
const allTools = ${JSON.stringify(
|
|
4438
|
+
Object.entries(tools).flatMap(
|
|
4439
|
+
([server, serverTools]) => serverTools.map((tool) => ({
|
|
4440
|
+
name: tool.name,
|
|
4441
|
+
description: tool.description,
|
|
4442
|
+
server,
|
|
4443
|
+
input_schema: tool.inputSchema
|
|
4444
|
+
}))
|
|
4445
|
+
)
|
|
4446
|
+
)};
|
|
4447
|
+
|
|
4448
|
+
const filtered = allTools.filter(tool => {
|
|
4449
|
+
if (!query) return true;
|
|
4450
|
+
const q = query.toLowerCase();
|
|
4451
|
+
return tool.name.toLowerCase().includes(q) ||
|
|
4452
|
+
(tool.description && tool.description.toLowerCase().includes(q));
|
|
4453
|
+
});
|
|
4454
|
+
|
|
4455
|
+
if (detailLevel === 'names') {
|
|
4456
|
+
return filtered.map(t => ({ name: t.name, server: t.server }));
|
|
4457
|
+
} else if (detailLevel === 'descriptions') {
|
|
4458
|
+
return filtered.map(t => ({ name: t.name, server: t.server, description: t.description }));
|
|
4459
|
+
}
|
|
4460
|
+
return filtered;
|
|
4461
|
+
};
|
|
4462
|
+
`;
|
|
4463
|
+
for (const [serverName, serverTools] of Object.entries(tools)) {
|
|
4464
|
+
if (!serverTools || serverTools.length === 0) continue;
|
|
4465
|
+
const safeServerName = serverName.replace(/[^a-zA-Z0-9_]/g, "_");
|
|
4466
|
+
shim += `
|
|
4467
|
+
global['${serverName}'] = {`;
|
|
4468
|
+
for (const tool of serverTools) {
|
|
4469
|
+
shim += `
|
|
4470
|
+
'${tool.name}': async (args) => await global.__callMcpTool('${serverName}', '${tool.name}', args),`;
|
|
4471
|
+
}
|
|
4472
|
+
shim += `
|
|
4473
|
+
};
|
|
4474
|
+
|
|
4475
|
+
// Also expose as safe name if different
|
|
4476
|
+
if ('${safeServerName}' !== '${serverName}') {
|
|
4477
|
+
global['${safeServerName}'] = global['${serverName}'];
|
|
4478
|
+
}
|
|
4479
|
+
`;
|
|
4480
|
+
}
|
|
4481
|
+
return shim;
|
|
4482
|
+
}
|
|
4483
|
+
/**
|
|
4484
|
+
* Build the tool catalog for the shim.
|
|
4485
|
+
* Returns a map of server names to their available tools.
|
|
4486
|
+
*/
|
|
4487
|
+
buildToolCatalog() {
|
|
4488
|
+
const catalog = {};
|
|
4489
|
+
const namespaces = this.getToolNamespaces();
|
|
4490
|
+
for (const { serverName, tools } of namespaces) {
|
|
4491
|
+
catalog[serverName] = tools;
|
|
4492
|
+
}
|
|
4493
|
+
return catalog;
|
|
4494
|
+
}
|
|
4495
|
+
/**
|
|
4496
|
+
* Execute JavaScript/TypeScript code in an E2B sandbox with MCP tool access.
|
|
4497
|
+
* Tool calls are proxied back to the host via the bridge pattern.
|
|
4498
|
+
*
|
|
4499
|
+
* @param code - Code to execute
|
|
4500
|
+
* @param timeout - Execution timeout in milliseconds (default: 30000)
|
|
4501
|
+
*/
|
|
4502
|
+
async execute(code, timeout = 3e4) {
|
|
4503
|
+
const startTime = Date.now();
|
|
4504
|
+
let result = null;
|
|
4505
|
+
let error = null;
|
|
4506
|
+
let logs = [];
|
|
4507
|
+
try {
|
|
4508
|
+
await this.ensureServersConnected();
|
|
4509
|
+
const sandbox = await this.getOrCreateCodeExecSandbox();
|
|
4510
|
+
const toolCatalog = this.buildToolCatalog();
|
|
4511
|
+
const shim = this.generateShim(toolCatalog);
|
|
4512
|
+
const wrappedCode = `
|
|
4513
|
+
${shim}
|
|
4514
|
+
|
|
4515
|
+
(async () => {
|
|
4516
|
+
try {
|
|
4517
|
+
const func = async () => {
|
|
4518
|
+
${code}
|
|
4519
|
+
};
|
|
4520
|
+
const result = await func();
|
|
4521
|
+
console.log('__MCP_RESULT_START__');
|
|
4522
|
+
console.log(JSON.stringify(result));
|
|
4523
|
+
console.log('__MCP_RESULT_END__');
|
|
4524
|
+
} catch (e) {
|
|
4525
|
+
console.error(e);
|
|
4526
|
+
process.exit(1);
|
|
4527
|
+
}
|
|
4528
|
+
})();
|
|
4529
|
+
`;
|
|
4530
|
+
const filename = `exec_${Date.now()}.js`;
|
|
4531
|
+
await sandbox.files.write(filename, wrappedCode);
|
|
4532
|
+
const execution = await sandbox.commands.run(`node ${filename}`, {
|
|
4533
|
+
timeoutMs: timeout,
|
|
4534
|
+
onStdout: /* @__PURE__ */ __name(async (data) => {
|
|
4535
|
+
try {
|
|
4536
|
+
const lines = data.split("\n");
|
|
4537
|
+
for (const line of lines) {
|
|
4538
|
+
if (line.trim().startsWith('{"type":"__MCP_TOOL_CALL__"')) {
|
|
4539
|
+
const call = JSON.parse(line);
|
|
4540
|
+
if (call.type === "__MCP_TOOL_CALL__") {
|
|
4541
|
+
try {
|
|
4542
|
+
logger.debug(
|
|
4543
|
+
`[E2B Bridge] Calling tool ${call.server}.${call.tool}`
|
|
4544
|
+
);
|
|
4545
|
+
const activeSessions = this.client.getAllActiveSessions();
|
|
4546
|
+
const session = activeSessions[call.server];
|
|
4547
|
+
if (!session) {
|
|
4548
|
+
throw new Error(`Server ${call.server} not found`);
|
|
4549
|
+
}
|
|
4550
|
+
const toolResult = await session.connector.callTool(
|
|
4551
|
+
call.tool,
|
|
4552
|
+
call.args
|
|
4553
|
+
);
|
|
4554
|
+
let extractedResult = toolResult;
|
|
4555
|
+
if (toolResult.content && toolResult.content.length > 0) {
|
|
4556
|
+
const item = toolResult.content[0];
|
|
4557
|
+
if (item.type === "text") {
|
|
4558
|
+
try {
|
|
4559
|
+
extractedResult = JSON.parse(item.text);
|
|
4560
|
+
} catch {
|
|
4561
|
+
extractedResult = item.text;
|
|
4562
|
+
}
|
|
4563
|
+
} else {
|
|
4564
|
+
extractedResult = item;
|
|
4565
|
+
}
|
|
4566
|
+
}
|
|
4567
|
+
const resultPath = `/tmp/mcp_result_${call.id}.json`;
|
|
4568
|
+
await sandbox.files.write(
|
|
4569
|
+
resultPath,
|
|
4570
|
+
JSON.stringify({ data: extractedResult })
|
|
4571
|
+
);
|
|
4572
|
+
} catch (err) {
|
|
4573
|
+
logger.error(
|
|
4574
|
+
`[E2B Bridge] Tool execution failed: ${err.message}`
|
|
4575
|
+
);
|
|
4576
|
+
const resultPath = `/tmp/mcp_result_${call.id}.json`;
|
|
4577
|
+
await sandbox.files.write(
|
|
4578
|
+
resultPath,
|
|
4579
|
+
JSON.stringify({
|
|
4580
|
+
error: err.message || String(err)
|
|
4581
|
+
})
|
|
4582
|
+
);
|
|
4583
|
+
}
|
|
4584
|
+
}
|
|
4585
|
+
}
|
|
4586
|
+
}
|
|
4587
|
+
} catch (e) {
|
|
4588
|
+
}
|
|
4589
|
+
}, "onStdout")
|
|
4590
|
+
});
|
|
4591
|
+
logs = [execution.stdout, execution.stderr].filter(Boolean);
|
|
4592
|
+
if (execution.exitCode !== 0) {
|
|
4593
|
+
error = execution.stderr || "Execution failed";
|
|
4594
|
+
} else {
|
|
4595
|
+
const stdout = execution.stdout;
|
|
4596
|
+
const startMarker = "__MCP_RESULT_START__";
|
|
4597
|
+
const endMarker = "__MCP_RESULT_END__";
|
|
4598
|
+
const startIndex = stdout.indexOf(startMarker);
|
|
4599
|
+
const endIndex = stdout.indexOf(endMarker);
|
|
4600
|
+
if (startIndex !== -1 && endIndex !== -1) {
|
|
4601
|
+
const jsonStr = stdout.substring(startIndex + startMarker.length, endIndex).trim();
|
|
4602
|
+
try {
|
|
4603
|
+
result = JSON.parse(jsonStr);
|
|
4604
|
+
} catch (e) {
|
|
4605
|
+
result = jsonStr;
|
|
4606
|
+
}
|
|
4607
|
+
logs = logs.map((log) => {
|
|
4608
|
+
let cleaned = log.replace(
|
|
4609
|
+
new RegExp(startMarker + "[\\s\\S]*?" + endMarker),
|
|
4610
|
+
"[Result captured]"
|
|
4611
|
+
);
|
|
4612
|
+
cleaned = cleaned.split("\n").filter((l) => !l.includes("__MCP_TOOL_CALL__")).join("\n");
|
|
4613
|
+
return cleaned;
|
|
4614
|
+
});
|
|
4615
|
+
}
|
|
4616
|
+
}
|
|
4617
|
+
} catch (e) {
|
|
4618
|
+
error = e.message || String(e);
|
|
4619
|
+
if (error && (error.includes("timeout") || error.includes("timed out"))) {
|
|
4620
|
+
error = "Script execution timed out";
|
|
4621
|
+
}
|
|
4622
|
+
}
|
|
4623
|
+
return {
|
|
4624
|
+
result,
|
|
4625
|
+
logs,
|
|
4626
|
+
error,
|
|
4627
|
+
execution_time: (Date.now() - startTime) / 1e3
|
|
4628
|
+
};
|
|
4629
|
+
}
|
|
4630
|
+
/**
|
|
4631
|
+
* Clean up the E2B sandbox.
|
|
4632
|
+
* Should be called when the executor is no longer needed.
|
|
4633
|
+
*/
|
|
4634
|
+
async cleanup() {
|
|
4635
|
+
if (this.codeExecSandbox) {
|
|
4636
|
+
try {
|
|
4637
|
+
await this.codeExecSandbox.kill();
|
|
4638
|
+
this.codeExecSandbox = null;
|
|
4639
|
+
logger.debug("E2B code execution sandbox stopped");
|
|
4640
|
+
} catch (error) {
|
|
4641
|
+
logger.error("Failed to stop E2B code execution sandbox:", error);
|
|
4642
|
+
}
|
|
4643
|
+
}
|
|
4644
|
+
}
|
|
4645
|
+
};
|
|
4646
|
+
|
|
4647
|
+
// src/client/executors/vm.ts
|
|
4648
|
+
init_logging();
|
|
4649
|
+
var vm = null;
|
|
4650
|
+
var vmCheckAttempted = false;
|
|
4651
|
+
function getVMModuleName() {
|
|
4652
|
+
return ["node", "vm"].join(":");
|
|
4653
|
+
}
|
|
4654
|
+
__name(getVMModuleName, "getVMModuleName");
|
|
4655
|
+
function tryLoadVM() {
|
|
4656
|
+
if (vmCheckAttempted) {
|
|
4657
|
+
return vm !== null;
|
|
4658
|
+
}
|
|
4659
|
+
vmCheckAttempted = true;
|
|
4660
|
+
try {
|
|
4661
|
+
const nodeRequire = typeof require !== "undefined" ? require : null;
|
|
4662
|
+
if (nodeRequire) {
|
|
4663
|
+
vm = nodeRequire(getVMModuleName());
|
|
4664
|
+
return true;
|
|
4665
|
+
}
|
|
4666
|
+
} catch (error) {
|
|
4667
|
+
logger.debug("node:vm module not available via require");
|
|
4668
|
+
}
|
|
4669
|
+
return false;
|
|
4670
|
+
}
|
|
4671
|
+
__name(tryLoadVM, "tryLoadVM");
|
|
4672
|
+
async function tryLoadVMAsync() {
|
|
4673
|
+
if (vm !== null) {
|
|
4674
|
+
return true;
|
|
4675
|
+
}
|
|
4676
|
+
if (!vmCheckAttempted) {
|
|
4677
|
+
if (tryLoadVM()) {
|
|
4678
|
+
return true;
|
|
4679
|
+
}
|
|
4680
|
+
}
|
|
4681
|
+
try {
|
|
4682
|
+
vm = await import(
|
|
4683
|
+
/* @vite-ignore */
|
|
4684
|
+
getVMModuleName()
|
|
4685
|
+
);
|
|
4686
|
+
return true;
|
|
4687
|
+
} catch (error) {
|
|
4688
|
+
logger.debug(
|
|
4689
|
+
"node:vm module not available in this environment (e.g., Deno)"
|
|
4690
|
+
);
|
|
4691
|
+
return false;
|
|
4692
|
+
}
|
|
4693
|
+
}
|
|
4694
|
+
__name(tryLoadVMAsync, "tryLoadVMAsync");
|
|
4695
|
+
var VMCodeExecutor = class extends BaseCodeExecutor {
|
|
4696
|
+
static {
|
|
4697
|
+
__name(this, "VMCodeExecutor");
|
|
4698
|
+
}
|
|
4699
|
+
defaultTimeout;
|
|
4700
|
+
memoryLimitMb;
|
|
4701
|
+
constructor(client, options) {
|
|
4702
|
+
super(client);
|
|
4703
|
+
this.defaultTimeout = options?.timeoutMs ?? 3e4;
|
|
4704
|
+
this.memoryLimitMb = options?.memoryLimitMb;
|
|
4705
|
+
tryLoadVM();
|
|
4706
|
+
}
|
|
4707
|
+
/**
|
|
4708
|
+
* Ensure VM module is loaded before execution
|
|
4709
|
+
*/
|
|
4710
|
+
async ensureVMLoaded() {
|
|
4711
|
+
if (vm !== null) {
|
|
4712
|
+
return;
|
|
4713
|
+
}
|
|
4714
|
+
const loaded = await tryLoadVMAsync();
|
|
4715
|
+
if (!loaded) {
|
|
4716
|
+
throw new Error(
|
|
4717
|
+
"node:vm module is not available in this environment. Please use E2B executor instead or run in a Node.js environment."
|
|
4718
|
+
);
|
|
4719
|
+
}
|
|
4720
|
+
}
|
|
4721
|
+
/**
|
|
4722
|
+
* Execute JavaScript/TypeScript code with access to MCP tools.
|
|
4723
|
+
*
|
|
4724
|
+
* @param code - Code to execute
|
|
4725
|
+
* @param timeout - Execution timeout in milliseconds (default: configured timeout or 30000)
|
|
4726
|
+
*/
|
|
4727
|
+
async execute(code, timeout) {
|
|
4728
|
+
const effectiveTimeout = timeout ?? this.defaultTimeout;
|
|
4729
|
+
await this.ensureVMLoaded();
|
|
4730
|
+
await this.ensureServersConnected();
|
|
4731
|
+
const logs = [];
|
|
4732
|
+
const startTime = Date.now();
|
|
4733
|
+
let result = null;
|
|
4734
|
+
let error = null;
|
|
4735
|
+
try {
|
|
4736
|
+
const context = await this._buildContext(logs);
|
|
4737
|
+
const wrappedCode = `
|
|
4738
|
+
(async () => {
|
|
4739
|
+
try {
|
|
4740
|
+
${code}
|
|
4741
|
+
} catch (e) {
|
|
4742
|
+
throw e;
|
|
4743
|
+
}
|
|
4744
|
+
})()
|
|
4745
|
+
`;
|
|
4746
|
+
const script = new vm.Script(wrappedCode, {
|
|
4747
|
+
filename: "agent_code.js"
|
|
4748
|
+
});
|
|
4749
|
+
const promise = script.runInNewContext(context, {
|
|
4750
|
+
timeout: effectiveTimeout,
|
|
4751
|
+
displayErrors: true
|
|
4752
|
+
});
|
|
4753
|
+
result = await promise;
|
|
4754
|
+
} catch (e) {
|
|
4755
|
+
error = e.message || String(e);
|
|
4756
|
+
if (e.code === "ERR_SCRIPT_EXECUTION_TIMEOUT" || e.message === "Script execution timed out." || typeof error === "string" && (error.includes("timed out") || error.includes("timeout"))) {
|
|
4757
|
+
error = "Script execution timed out";
|
|
4758
|
+
}
|
|
4759
|
+
if (e.stack) {
|
|
4760
|
+
logger.debug(`Code execution error stack: ${e.stack}`);
|
|
4761
|
+
}
|
|
4762
|
+
}
|
|
4763
|
+
const executionTime = (Date.now() - startTime) / 1e3;
|
|
4764
|
+
return {
|
|
4765
|
+
result,
|
|
4766
|
+
logs,
|
|
4767
|
+
error,
|
|
4768
|
+
execution_time: executionTime
|
|
4769
|
+
};
|
|
4770
|
+
}
|
|
4771
|
+
/**
|
|
4772
|
+
* Build the VM execution context with MCP tools and standard globals.
|
|
4773
|
+
*
|
|
4774
|
+
* @param logs - Array to capture console output
|
|
4775
|
+
*/
|
|
4776
|
+
async _buildContext(logs) {
|
|
4777
|
+
const logHandler = /* @__PURE__ */ __name((...args) => {
|
|
4778
|
+
logs.push(
|
|
4779
|
+
args.map(
|
|
4780
|
+
(arg) => typeof arg === "object" ? JSON.stringify(arg, null, 2) : String(arg)
|
|
4781
|
+
).join(" ")
|
|
4782
|
+
);
|
|
4783
|
+
}, "logHandler");
|
|
4784
|
+
const sandbox = {
|
|
4785
|
+
console: {
|
|
4786
|
+
log: logHandler,
|
|
4787
|
+
error: /* @__PURE__ */ __name((...args) => {
|
|
4788
|
+
logHandler("[ERROR]", ...args);
|
|
4789
|
+
}, "error"),
|
|
4790
|
+
warn: /* @__PURE__ */ __name((...args) => {
|
|
4791
|
+
logHandler("[WARN]", ...args);
|
|
4792
|
+
}, "warn"),
|
|
4793
|
+
info: logHandler,
|
|
4794
|
+
debug: logHandler
|
|
4795
|
+
},
|
|
4796
|
+
// Standard globals
|
|
4797
|
+
Object,
|
|
4798
|
+
Array,
|
|
4799
|
+
String,
|
|
4800
|
+
Number,
|
|
4801
|
+
Boolean,
|
|
4802
|
+
Date,
|
|
4803
|
+
Math,
|
|
4804
|
+
JSON,
|
|
4805
|
+
RegExp,
|
|
4806
|
+
Map,
|
|
4807
|
+
Set,
|
|
4808
|
+
Promise,
|
|
4809
|
+
parseInt,
|
|
4810
|
+
parseFloat,
|
|
4811
|
+
isNaN,
|
|
4812
|
+
isFinite,
|
|
4813
|
+
encodeURI,
|
|
4814
|
+
decodeURI,
|
|
4815
|
+
encodeURIComponent,
|
|
4816
|
+
decodeURIComponent,
|
|
4817
|
+
setTimeout,
|
|
4818
|
+
clearTimeout,
|
|
4819
|
+
// Helper for tools
|
|
4820
|
+
search_tools: this.createSearchToolsFunction(),
|
|
4821
|
+
__tool_namespaces: []
|
|
4822
|
+
};
|
|
4823
|
+
const toolNamespaces = {};
|
|
4824
|
+
const namespaceInfos = this.getToolNamespaces();
|
|
4825
|
+
for (const { serverName, tools, session } of namespaceInfos) {
|
|
4826
|
+
const serverNamespace = {};
|
|
4827
|
+
for (const tool of tools) {
|
|
4828
|
+
const toolName = tool.name;
|
|
4829
|
+
serverNamespace[toolName] = async (args) => {
|
|
4830
|
+
const result = await session.connector.callTool(toolName, args || {});
|
|
4831
|
+
if (result.content && result.content.length > 0) {
|
|
4832
|
+
const item = result.content[0];
|
|
4833
|
+
if (item.type === "text") {
|
|
4834
|
+
try {
|
|
4835
|
+
return JSON.parse(item.text);
|
|
4836
|
+
} catch {
|
|
4837
|
+
return item.text;
|
|
4838
|
+
}
|
|
4839
|
+
}
|
|
4840
|
+
return item;
|
|
4841
|
+
}
|
|
4842
|
+
return result;
|
|
4843
|
+
};
|
|
4844
|
+
}
|
|
4845
|
+
sandbox[serverName] = serverNamespace;
|
|
4846
|
+
toolNamespaces[serverName] = true;
|
|
4847
|
+
}
|
|
4848
|
+
sandbox.__tool_namespaces = Object.keys(toolNamespaces);
|
|
4849
|
+
return vm.createContext(sandbox);
|
|
4850
|
+
}
|
|
4851
|
+
/**
|
|
4852
|
+
* Clean up resources.
|
|
4853
|
+
* VM executor doesn't need cleanup, but method kept for interface consistency.
|
|
4854
|
+
*/
|
|
4855
|
+
async cleanup() {
|
|
4856
|
+
}
|
|
4857
|
+
};
|
|
4858
|
+
|
|
4859
|
+
// src/config.ts
|
|
4860
|
+
var import_node_fs = require("fs");
|
|
4861
|
+
|
|
4862
|
+
// src/connectors/http.ts
|
|
4863
|
+
var import_client = require("@mcp-use/modelcontextprotocol-sdk/client/index.js");
|
|
4864
|
+
var import_streamableHttp = require("@mcp-use/modelcontextprotocol-sdk/client/streamableHttp.js");
|
|
4865
|
+
init_logging();
|
|
4866
|
+
|
|
4867
|
+
// src/task_managers/sse.ts
|
|
4868
|
+
var import_sse = require("@mcp-use/modelcontextprotocol-sdk/client/sse.js");
|
|
4869
|
+
init_logging();
|
|
4870
|
+
|
|
4871
|
+
// src/task_managers/base.ts
|
|
4872
|
+
init_logging();
|
|
4873
|
+
var ConnectionManager = class {
|
|
4874
|
+
static {
|
|
4875
|
+
__name(this, "ConnectionManager");
|
|
4876
|
+
}
|
|
4877
|
+
_readyPromise;
|
|
4878
|
+
_readyResolver;
|
|
4879
|
+
_donePromise;
|
|
4880
|
+
_doneResolver;
|
|
4881
|
+
_exception = null;
|
|
4882
|
+
_connection = null;
|
|
4883
|
+
_task = null;
|
|
4884
|
+
_abortController = null;
|
|
4885
|
+
constructor() {
|
|
4886
|
+
this.reset();
|
|
4887
|
+
}
|
|
4888
|
+
/**
|
|
4889
|
+
* Start the connection manager and establish a connection.
|
|
4890
|
+
*
|
|
4891
|
+
* @returns The established connection.
|
|
4892
|
+
* @throws If the connection cannot be established.
|
|
4893
|
+
*/
|
|
4894
|
+
async start() {
|
|
4895
|
+
this.reset();
|
|
4896
|
+
logger.debug(`Starting ${this.constructor.name}`);
|
|
4897
|
+
this._task = this.connectionTask();
|
|
4898
|
+
await this._readyPromise;
|
|
4899
|
+
if (this._exception) {
|
|
4900
|
+
throw this._exception;
|
|
4901
|
+
}
|
|
4902
|
+
if (this._connection === null) {
|
|
4903
|
+
throw new Error("Connection was not established");
|
|
4904
|
+
}
|
|
4905
|
+
return this._connection;
|
|
4906
|
+
}
|
|
4907
|
+
/**
|
|
4908
|
+
* Stop the connection manager and close the connection.
|
|
4909
|
+
*/
|
|
4910
|
+
async stop() {
|
|
4911
|
+
if (this._task && this._abortController) {
|
|
4912
|
+
logger.debug(`Cancelling ${this.constructor.name} task`);
|
|
4913
|
+
this._abortController.abort();
|
|
4914
|
+
try {
|
|
4915
|
+
await this._task;
|
|
4916
|
+
} catch (e) {
|
|
4917
|
+
if (e instanceof Error && e.name === "AbortError") {
|
|
4918
|
+
logger.debug(`${this.constructor.name} task aborted successfully`);
|
|
4919
|
+
} else {
|
|
4920
|
+
logger.warn(`Error stopping ${this.constructor.name} task: ${e}`);
|
|
4921
|
+
}
|
|
4922
|
+
}
|
|
4923
|
+
}
|
|
4924
|
+
await this._donePromise;
|
|
4925
|
+
logger.debug(`${this.constructor.name} task completed`);
|
|
4926
|
+
}
|
|
4927
|
+
/**
|
|
4928
|
+
* Reset all internal state.
|
|
4929
|
+
*/
|
|
4930
|
+
reset() {
|
|
4931
|
+
this._readyPromise = new Promise((res) => this._readyResolver = res);
|
|
4932
|
+
this._donePromise = new Promise((res) => this._doneResolver = res);
|
|
4933
|
+
this._exception = null;
|
|
4934
|
+
this._connection = null;
|
|
4935
|
+
this._task = null;
|
|
4936
|
+
this._abortController = new AbortController();
|
|
4937
|
+
}
|
|
4938
|
+
/**
|
|
4939
|
+
* The background task responsible for establishing and maintaining the
|
|
4940
|
+
* connection until it is cancelled.
|
|
4941
|
+
*/
|
|
4942
|
+
async connectionTask() {
|
|
4943
|
+
logger.debug(`Running ${this.constructor.name} task`);
|
|
4944
|
+
try {
|
|
4945
|
+
this._connection = await this.establishConnection();
|
|
4946
|
+
logger.debug(`${this.constructor.name} connected successfully`);
|
|
4947
|
+
this._readyResolver();
|
|
4948
|
+
await this.waitForAbort();
|
|
4949
|
+
} catch (err) {
|
|
4950
|
+
this._exception = err;
|
|
4951
|
+
logger.error(`Error in ${this.constructor.name} task: ${err}`);
|
|
4952
|
+
this._readyResolver();
|
|
4953
|
+
} finally {
|
|
4954
|
+
if (this._connection !== null) {
|
|
4955
|
+
try {
|
|
4956
|
+
await this.closeConnection(this._connection);
|
|
4957
|
+
} catch (closeErr) {
|
|
4958
|
+
logger.warn(
|
|
4959
|
+
`Error closing connection in ${this.constructor.name}: ${closeErr}`
|
|
4960
|
+
);
|
|
4961
|
+
}
|
|
4962
|
+
this._connection = null;
|
|
4963
|
+
}
|
|
4964
|
+
this._doneResolver();
|
|
4965
|
+
}
|
|
4966
|
+
}
|
|
4967
|
+
/**
|
|
4968
|
+
* Helper that returns a promise which resolves when the abort signal fires.
|
|
4969
|
+
*/
|
|
4970
|
+
async waitForAbort() {
|
|
4971
|
+
return new Promise((_resolve, _reject) => {
|
|
4972
|
+
if (!this._abortController) {
|
|
4973
|
+
return;
|
|
4974
|
+
}
|
|
4975
|
+
const signal = this._abortController.signal;
|
|
4976
|
+
if (signal.aborted) {
|
|
4977
|
+
_resolve();
|
|
4978
|
+
return;
|
|
4979
|
+
}
|
|
4980
|
+
const onAbort = /* @__PURE__ */ __name(() => {
|
|
4981
|
+
signal.removeEventListener("abort", onAbort);
|
|
4982
|
+
_resolve();
|
|
4983
|
+
}, "onAbort");
|
|
4984
|
+
signal.addEventListener("abort", onAbort);
|
|
4985
|
+
});
|
|
4986
|
+
}
|
|
4987
|
+
};
|
|
4988
|
+
|
|
4989
|
+
// src/task_managers/sse.ts
|
|
4990
|
+
var SseConnectionManager = class extends ConnectionManager {
|
|
4991
|
+
static {
|
|
4992
|
+
__name(this, "SseConnectionManager");
|
|
4993
|
+
}
|
|
4994
|
+
url;
|
|
4995
|
+
opts;
|
|
4996
|
+
_transport = null;
|
|
4997
|
+
reinitializing = false;
|
|
4998
|
+
/**
|
|
4999
|
+
* Create an SSE connection manager.
|
|
5000
|
+
*
|
|
5001
|
+
* @param url The SSE endpoint URL.
|
|
5002
|
+
* @param opts Optional transport options (auth, headers, etc.).
|
|
5003
|
+
*/
|
|
5004
|
+
constructor(url, opts) {
|
|
5005
|
+
super();
|
|
5006
|
+
this.url = typeof url === "string" ? new URL(url) : url;
|
|
5007
|
+
this.opts = opts;
|
|
5008
|
+
}
|
|
5009
|
+
/**
|
|
5010
|
+
* Spawn a new `SSEClientTransport` and wrap it with 404 handling.
|
|
5011
|
+
* Per MCP spec, clients MUST re-initialize when receiving 404 for stale sessions.
|
|
5012
|
+
*/
|
|
5013
|
+
async establishConnection() {
|
|
5014
|
+
const transport = new import_sse.SSEClientTransport(this.url, this.opts);
|
|
5015
|
+
const originalSend = transport.send.bind(transport);
|
|
5016
|
+
transport.send = async (message) => {
|
|
5017
|
+
const sendMessage = /* @__PURE__ */ __name(async (msg) => {
|
|
5018
|
+
if (Array.isArray(msg)) {
|
|
5019
|
+
for (const singleMsg of msg) {
|
|
5020
|
+
await originalSend(singleMsg);
|
|
5021
|
+
}
|
|
5022
|
+
} else {
|
|
5023
|
+
await originalSend(msg);
|
|
5024
|
+
}
|
|
5025
|
+
}, "sendMessage");
|
|
5026
|
+
try {
|
|
5027
|
+
await sendMessage(message);
|
|
5028
|
+
} catch (error) {
|
|
5029
|
+
if (error?.code === 404 && transport.sessionId && !this.reinitializing) {
|
|
5030
|
+
logger.warn(
|
|
5031
|
+
`[SSE] Session not found (404), re-initializing per MCP spec...`
|
|
5032
|
+
);
|
|
5033
|
+
this.reinitializing = true;
|
|
5034
|
+
try {
|
|
5035
|
+
transport.sessionId = void 0;
|
|
5036
|
+
await this.reinitialize(transport);
|
|
5037
|
+
logger.info(`[SSE] Re-initialization successful, retrying request`);
|
|
5038
|
+
await sendMessage(message);
|
|
5039
|
+
} finally {
|
|
5040
|
+
this.reinitializing = false;
|
|
5041
|
+
}
|
|
5042
|
+
} else {
|
|
5043
|
+
throw error;
|
|
5044
|
+
}
|
|
5045
|
+
}
|
|
5046
|
+
};
|
|
5047
|
+
this._transport = transport;
|
|
5048
|
+
logger.debug(`${this.constructor.name} connected successfully`);
|
|
5049
|
+
return transport;
|
|
5050
|
+
}
|
|
5051
|
+
/**
|
|
5052
|
+
* Re-initialize the transport with a new session
|
|
5053
|
+
* This is called when the server returns 404 for a stale session
|
|
5054
|
+
*/
|
|
5055
|
+
async reinitialize(transport) {
|
|
5056
|
+
logger.debug(`[SSE] Re-initialization triggered`);
|
|
5057
|
+
}
|
|
5058
|
+
/**
|
|
5059
|
+
* Close the underlying transport and clean up resources.
|
|
5060
|
+
*/
|
|
5061
|
+
async closeConnection(_connection) {
|
|
5062
|
+
if (this._transport) {
|
|
5063
|
+
try {
|
|
5064
|
+
await this._transport.close();
|
|
5065
|
+
} catch (e) {
|
|
5066
|
+
logger.warn(`Error closing SSE transport: ${e}`);
|
|
5067
|
+
} finally {
|
|
5068
|
+
this._transport = null;
|
|
5069
|
+
}
|
|
5070
|
+
}
|
|
5071
|
+
}
|
|
5072
|
+
};
|
|
5073
|
+
|
|
5074
|
+
// src/connectors/http.ts
|
|
5075
|
+
var HttpConnector = class extends BaseConnector {
|
|
5076
|
+
static {
|
|
5077
|
+
__name(this, "HttpConnector");
|
|
5078
|
+
}
|
|
5079
|
+
baseUrl;
|
|
5080
|
+
headers;
|
|
5081
|
+
timeout;
|
|
5082
|
+
sseReadTimeout;
|
|
5083
|
+
clientInfo;
|
|
5084
|
+
preferSse;
|
|
5085
|
+
transportType = null;
|
|
5086
|
+
streamableTransport = null;
|
|
5087
|
+
constructor(baseUrl, opts = {}) {
|
|
5088
|
+
super(opts);
|
|
5089
|
+
this.baseUrl = baseUrl.replace(/\/$/, "");
|
|
5090
|
+
this.headers = { ...opts.headers ?? {} };
|
|
5091
|
+
if (opts.authToken) {
|
|
5092
|
+
this.headers.Authorization = `Bearer ${opts.authToken}`;
|
|
5093
|
+
}
|
|
5094
|
+
this.timeout = opts.timeout ?? 3e4;
|
|
5095
|
+
this.sseReadTimeout = opts.sseReadTimeout ?? 3e5;
|
|
5096
|
+
this.clientInfo = opts.clientInfo ?? {
|
|
5097
|
+
name: "http-connector",
|
|
5098
|
+
version: "1.0.0"
|
|
5099
|
+
};
|
|
5100
|
+
this.preferSse = opts.preferSse ?? false;
|
|
5101
|
+
}
|
|
5102
|
+
/** Establish connection to the MCP implementation via HTTP (streamable or SSE). */
|
|
5103
|
+
async connect() {
|
|
5104
|
+
if (this.connected) {
|
|
5105
|
+
logger.debug("Already connected to MCP implementation");
|
|
5106
|
+
return;
|
|
5107
|
+
}
|
|
5108
|
+
const baseUrl = this.baseUrl;
|
|
5109
|
+
if (this.preferSse) {
|
|
5110
|
+
logger.debug(`Connecting to MCP implementation via HTTP/SSE: ${baseUrl}`);
|
|
5111
|
+
await this.connectWithSse(baseUrl);
|
|
5112
|
+
return;
|
|
5113
|
+
}
|
|
5114
|
+
logger.debug(`Connecting to MCP implementation via HTTP: ${baseUrl}`);
|
|
5115
|
+
try {
|
|
5116
|
+
logger.info("\u{1F504} Attempting streamable HTTP transport...");
|
|
5117
|
+
await this.connectWithStreamableHttp(baseUrl);
|
|
5118
|
+
logger.info("\u2705 Successfully connected via streamable HTTP");
|
|
5119
|
+
} catch (err) {
|
|
5120
|
+
let fallbackReason = "Unknown error";
|
|
5121
|
+
let is401Error = false;
|
|
5122
|
+
if (err instanceof import_streamableHttp.StreamableHTTPError) {
|
|
5123
|
+
const streamableErr = err;
|
|
5124
|
+
is401Error = streamableErr.code === 401;
|
|
5125
|
+
if (streamableErr.code === 400 && streamableErr.message.includes("Missing session ID")) {
|
|
5126
|
+
fallbackReason = "Server requires session ID (FastMCP compatibility) - using SSE transport";
|
|
5127
|
+
logger.warn(`\u26A0\uFE0F ${fallbackReason}`);
|
|
5128
|
+
} else if (streamableErr.code === 404 || streamableErr.code === 405) {
|
|
5129
|
+
fallbackReason = `Server returned ${streamableErr.code} - server likely doesn't support streamable HTTP`;
|
|
5130
|
+
logger.debug(fallbackReason);
|
|
5131
|
+
} else {
|
|
5132
|
+
fallbackReason = `Server returned ${streamableErr.code}: ${streamableErr.message}`;
|
|
5133
|
+
logger.debug(fallbackReason);
|
|
5134
|
+
}
|
|
5135
|
+
} else if (err instanceof Error) {
|
|
5136
|
+
const errorStr = err.toString();
|
|
5137
|
+
const errorMsg = err.message || "";
|
|
5138
|
+
is401Error = errorStr.includes("401") || errorMsg.includes("Unauthorized");
|
|
5139
|
+
if (errorStr.includes("Missing session ID") || errorStr.includes("Bad Request: Missing session ID") || errorMsg.includes("FastMCP session ID error")) {
|
|
5140
|
+
fallbackReason = "Server requires session ID (FastMCP compatibility) - using SSE transport";
|
|
5141
|
+
logger.warn(`\u26A0\uFE0F ${fallbackReason}`);
|
|
5142
|
+
} else if (errorStr.includes("405 Method Not Allowed") || errorStr.includes("404 Not Found")) {
|
|
5143
|
+
fallbackReason = "Server doesn't support streamable HTTP (405/404)";
|
|
5144
|
+
logger.debug(fallbackReason);
|
|
5145
|
+
} else {
|
|
5146
|
+
fallbackReason = `Streamable HTTP failed: ${err.message}`;
|
|
5147
|
+
logger.debug(fallbackReason);
|
|
5148
|
+
}
|
|
5149
|
+
}
|
|
5150
|
+
if (is401Error) {
|
|
5151
|
+
logger.info("Authentication required - skipping SSE fallback");
|
|
5152
|
+
await this.cleanupResources();
|
|
5153
|
+
const authError = new Error("Authentication required");
|
|
5154
|
+
authError.code = 401;
|
|
5155
|
+
throw authError;
|
|
5156
|
+
}
|
|
5157
|
+
logger.info("\u{1F504} Falling back to SSE transport...");
|
|
5158
|
+
try {
|
|
5159
|
+
await this.connectWithSse(baseUrl);
|
|
5160
|
+
} catch (sseErr) {
|
|
5161
|
+
logger.error(`Failed to connect with both transports:`);
|
|
5162
|
+
logger.error(` Streamable HTTP: ${fallbackReason}`);
|
|
5163
|
+
logger.error(` SSE: ${sseErr}`);
|
|
5164
|
+
await this.cleanupResources();
|
|
5165
|
+
const sseIs401 = sseErr?.message?.includes("401") || sseErr?.message?.includes("Unauthorized");
|
|
5166
|
+
if (sseIs401) {
|
|
5167
|
+
const authError = new Error("Authentication required");
|
|
5168
|
+
authError.code = 401;
|
|
5169
|
+
throw authError;
|
|
5170
|
+
}
|
|
5171
|
+
throw new Error(
|
|
5172
|
+
"Could not connect to server with any available transport"
|
|
5173
|
+
);
|
|
5174
|
+
}
|
|
5175
|
+
}
|
|
5176
|
+
}
|
|
5177
|
+
async connectWithStreamableHttp(baseUrl) {
|
|
5178
|
+
try {
|
|
5179
|
+
const streamableTransport = new import_streamableHttp.StreamableHTTPClientTransport(
|
|
5180
|
+
new URL(baseUrl),
|
|
5181
|
+
{
|
|
5182
|
+
authProvider: this.opts.authProvider,
|
|
5183
|
+
// ← Pass OAuth provider to SDK
|
|
5184
|
+
requestInit: {
|
|
5185
|
+
headers: this.headers
|
|
5186
|
+
},
|
|
5187
|
+
// Pass through reconnection options
|
|
5188
|
+
reconnectionOptions: {
|
|
5189
|
+
maxReconnectionDelay: 3e4,
|
|
5190
|
+
initialReconnectionDelay: 1e3,
|
|
5191
|
+
reconnectionDelayGrowFactor: 1.5,
|
|
5192
|
+
maxRetries: 2
|
|
5193
|
+
}
|
|
5194
|
+
// Don't pass sessionId - let the SDK generate it automatically during connect()
|
|
5195
|
+
}
|
|
5196
|
+
);
|
|
5197
|
+
let transport = streamableTransport;
|
|
5198
|
+
if (this.opts.wrapTransport) {
|
|
5199
|
+
const serverId = this.baseUrl;
|
|
5200
|
+
transport = this.opts.wrapTransport(
|
|
5201
|
+
transport,
|
|
5202
|
+
serverId
|
|
5203
|
+
);
|
|
5204
|
+
}
|
|
5205
|
+
const clientOptions = {
|
|
5206
|
+
...this.opts.clientOptions || {},
|
|
5207
|
+
capabilities: {
|
|
5208
|
+
...this.opts.clientOptions?.capabilities || {},
|
|
5209
|
+
roots: { listChanged: true },
|
|
5210
|
+
// Always advertise roots capability
|
|
5211
|
+
// Add sampling capability if callback is provided
|
|
5212
|
+
...this.opts.samplingCallback ? { sampling: {} } : {},
|
|
5213
|
+
// Add elicitation capability if callback is provided
|
|
5214
|
+
...this.opts.elicitationCallback ? { elicitation: { form: {}, url: {} } } : {}
|
|
5215
|
+
}
|
|
5216
|
+
};
|
|
5217
|
+
logger.debug(
|
|
5218
|
+
`Creating Client with capabilities:`,
|
|
5219
|
+
JSON.stringify(clientOptions.capabilities, null, 2)
|
|
5220
|
+
);
|
|
5221
|
+
this.client = new import_client.Client(this.clientInfo, clientOptions);
|
|
5222
|
+
this.setupRootsHandler();
|
|
5223
|
+
logger.debug("Roots handler registered before connect");
|
|
5224
|
+
try {
|
|
5225
|
+
await this.client.connect(transport, {
|
|
5226
|
+
timeout: Math.min(this.timeout, 3e3)
|
|
5227
|
+
});
|
|
5228
|
+
const sessionId = streamableTransport.sessionId;
|
|
5229
|
+
if (sessionId) {
|
|
5230
|
+
logger.debug(`Session ID obtained: ${sessionId}`);
|
|
5231
|
+
} else {
|
|
5232
|
+
logger.warn(
|
|
5233
|
+
"Session ID not available after connect - this may cause issues with SSE stream"
|
|
5234
|
+
);
|
|
5235
|
+
}
|
|
5236
|
+
} catch (connectErr) {
|
|
5237
|
+
if (connectErr instanceof Error) {
|
|
5238
|
+
const errMsg = connectErr.message || connectErr.toString();
|
|
5239
|
+
if (errMsg.includes("Missing session ID") || errMsg.includes("Bad Request: Missing session ID") || errMsg.includes("Mcp-Session-Id header is required")) {
|
|
5240
|
+
const wrappedError = new Error(
|
|
5241
|
+
`Session ID error: ${errMsg}. The SDK should automatically extract session ID from initialize response.`
|
|
5242
|
+
);
|
|
5243
|
+
wrappedError.cause = connectErr;
|
|
5244
|
+
throw wrappedError;
|
|
5245
|
+
}
|
|
5246
|
+
}
|
|
5247
|
+
throw connectErr;
|
|
5248
|
+
}
|
|
5249
|
+
this.streamableTransport = streamableTransport;
|
|
5250
|
+
this.connectionManager = {
|
|
5251
|
+
stop: /* @__PURE__ */ __name(async () => {
|
|
5252
|
+
if (this.streamableTransport) {
|
|
5253
|
+
try {
|
|
5254
|
+
await this.streamableTransport.terminateSession();
|
|
5255
|
+
await this.streamableTransport.close();
|
|
5256
|
+
} catch (e) {
|
|
5257
|
+
logger.warn(`Error closing Streamable HTTP transport: ${e}`);
|
|
5258
|
+
} finally {
|
|
5259
|
+
this.streamableTransport = null;
|
|
5260
|
+
}
|
|
5261
|
+
}
|
|
5262
|
+
}, "stop")
|
|
5263
|
+
};
|
|
5264
|
+
this.connected = true;
|
|
5265
|
+
this.transportType = "streamable-http";
|
|
5266
|
+
this.setupNotificationHandler();
|
|
5267
|
+
this.setupSamplingHandler();
|
|
5268
|
+
this.setupElicitationHandler();
|
|
5269
|
+
logger.debug(
|
|
5270
|
+
`Successfully connected to MCP implementation via streamable HTTP: ${baseUrl}`
|
|
5271
|
+
);
|
|
5272
|
+
this.trackConnectorInit({
|
|
5273
|
+
serverUrl: this.baseUrl,
|
|
5274
|
+
publicIdentifier: `${this.baseUrl} (streamable-http)`
|
|
5275
|
+
});
|
|
5276
|
+
} catch (err) {
|
|
5277
|
+
await this.cleanupResources();
|
|
5278
|
+
throw err;
|
|
5279
|
+
}
|
|
5280
|
+
}
|
|
5281
|
+
async connectWithSse(baseUrl) {
|
|
5282
|
+
try {
|
|
5283
|
+
this.connectionManager = new SseConnectionManager(baseUrl, {
|
|
5284
|
+
authProvider: this.opts.authProvider,
|
|
5285
|
+
// ← Pass OAuth provider to SDK (same as streamable HTTP)
|
|
5286
|
+
requestInit: {
|
|
5287
|
+
headers: this.headers
|
|
5288
|
+
}
|
|
5289
|
+
});
|
|
5290
|
+
let transport = await this.connectionManager.start();
|
|
5291
|
+
if (this.opts.wrapTransport) {
|
|
5292
|
+
const serverId = this.baseUrl;
|
|
5293
|
+
transport = this.opts.wrapTransport(transport, serverId);
|
|
5294
|
+
}
|
|
5295
|
+
const clientOptions = {
|
|
5296
|
+
...this.opts.clientOptions || {},
|
|
5297
|
+
capabilities: {
|
|
5298
|
+
...this.opts.clientOptions?.capabilities || {},
|
|
5299
|
+
roots: { listChanged: true },
|
|
5300
|
+
// Always advertise roots capability
|
|
5301
|
+
// Add sampling capability if callback is provided
|
|
5302
|
+
...this.opts.samplingCallback ? { sampling: {} } : {},
|
|
5303
|
+
// Add elicitation capability if callback is provided
|
|
5304
|
+
...this.opts.elicitationCallback ? { elicitation: { form: {}, url: {} } } : {}
|
|
5305
|
+
}
|
|
5306
|
+
};
|
|
5307
|
+
logger.debug(
|
|
5308
|
+
`Creating Client with capabilities (SSE):`,
|
|
5309
|
+
JSON.stringify(clientOptions.capabilities, null, 2)
|
|
5310
|
+
);
|
|
5311
|
+
this.client = new import_client.Client(this.clientInfo, clientOptions);
|
|
5312
|
+
this.setupRootsHandler();
|
|
5313
|
+
logger.debug("Roots handler registered before connect (SSE)");
|
|
5314
|
+
await this.client.connect(transport);
|
|
5315
|
+
this.connected = true;
|
|
5316
|
+
this.transportType = "sse";
|
|
5317
|
+
this.setupNotificationHandler();
|
|
5318
|
+
this.setupSamplingHandler();
|
|
5319
|
+
this.setupElicitationHandler();
|
|
5320
|
+
logger.debug(
|
|
5321
|
+
`Successfully connected to MCP implementation via HTTP/SSE: ${baseUrl}`
|
|
5322
|
+
);
|
|
5323
|
+
this.trackConnectorInit({
|
|
5324
|
+
serverUrl: this.baseUrl,
|
|
5325
|
+
publicIdentifier: `${this.baseUrl} (sse)`
|
|
5326
|
+
});
|
|
5327
|
+
} catch (err) {
|
|
5328
|
+
await this.cleanupResources();
|
|
5329
|
+
throw err;
|
|
5330
|
+
}
|
|
5331
|
+
}
|
|
5332
|
+
get publicIdentifier() {
|
|
5333
|
+
return {
|
|
5334
|
+
type: "http",
|
|
5335
|
+
url: this.baseUrl,
|
|
5336
|
+
transport: this.transportType || "unknown"
|
|
5337
|
+
};
|
|
5338
|
+
}
|
|
5339
|
+
/**
|
|
5340
|
+
* Get the transport type being used (streamable-http or sse)
|
|
5341
|
+
*/
|
|
5342
|
+
getTransportType() {
|
|
5343
|
+
return this.transportType;
|
|
5344
|
+
}
|
|
5345
|
+
};
|
|
5346
|
+
|
|
5347
|
+
// src/connectors/stdio.ts
|
|
5348
|
+
var import_node_process = __toESM(require("process"), 1);
|
|
5349
|
+
var import_client2 = require("@mcp-use/modelcontextprotocol-sdk/client/index.js");
|
|
5350
|
+
init_logging();
|
|
5351
|
+
|
|
5352
|
+
// src/task_managers/stdio.ts
|
|
5353
|
+
var import_stdio = require("@mcp-use/modelcontextprotocol-sdk/client/stdio.js");
|
|
5354
|
+
init_logging();
|
|
5355
|
+
var StdioConnectionManager = class extends ConnectionManager {
|
|
5356
|
+
static {
|
|
5357
|
+
__name(this, "StdioConnectionManager");
|
|
5358
|
+
}
|
|
5359
|
+
serverParams;
|
|
5360
|
+
errlog;
|
|
5361
|
+
_transport = null;
|
|
5362
|
+
/**
|
|
5363
|
+
* Create a new stdio connection manager.
|
|
5364
|
+
*
|
|
5365
|
+
* @param serverParams Parameters for the stdio server process.
|
|
5366
|
+
* @param errlog Stream to which the server's stderr should be piped.
|
|
5367
|
+
* Defaults to `process.stderr`.
|
|
5368
|
+
*/
|
|
5369
|
+
constructor(serverParams, errlog = process.stderr) {
|
|
5370
|
+
super();
|
|
5371
|
+
this.serverParams = serverParams;
|
|
5372
|
+
this.errlog = errlog;
|
|
5373
|
+
}
|
|
5374
|
+
/**
|
|
5375
|
+
* Establish the stdio connection by spawning the server process and starting
|
|
5376
|
+
* the SDK's transport. Returns the live `StdioClientTransport` instance.
|
|
5377
|
+
*/
|
|
5378
|
+
async establishConnection() {
|
|
5379
|
+
this._transport = new import_stdio.StdioClientTransport(this.serverParams);
|
|
5380
|
+
if (this._transport.stderr && typeof this._transport.stderr.pipe === "function") {
|
|
5381
|
+
this._transport.stderr.pipe(
|
|
5382
|
+
this.errlog
|
|
5383
|
+
);
|
|
5384
|
+
}
|
|
5385
|
+
logger.debug(`${this.constructor.name} connected successfully`);
|
|
5386
|
+
return this._transport;
|
|
5387
|
+
}
|
|
5388
|
+
/**
|
|
5389
|
+
* Close the stdio connection, making sure the transport cleans up the child
|
|
5390
|
+
* process and associated resources.
|
|
5391
|
+
*/
|
|
5392
|
+
async closeConnection(_connection) {
|
|
5393
|
+
if (this._transport) {
|
|
5394
|
+
try {
|
|
5395
|
+
await this._transport.close();
|
|
5396
|
+
} catch (e) {
|
|
5397
|
+
logger.warn(`Error closing stdio transport: ${e}`);
|
|
5398
|
+
} finally {
|
|
5399
|
+
this._transport = null;
|
|
5400
|
+
}
|
|
5401
|
+
}
|
|
5402
|
+
}
|
|
5403
|
+
};
|
|
5404
|
+
|
|
5405
|
+
// src/connectors/stdio.ts
|
|
5406
|
+
var StdioConnector = class extends BaseConnector {
|
|
5407
|
+
static {
|
|
5408
|
+
__name(this, "StdioConnector");
|
|
5409
|
+
}
|
|
5410
|
+
command;
|
|
5411
|
+
args;
|
|
5412
|
+
env;
|
|
5413
|
+
errlog;
|
|
5414
|
+
clientInfo;
|
|
5415
|
+
constructor({
|
|
5416
|
+
command = "npx",
|
|
5417
|
+
args = [],
|
|
5418
|
+
env,
|
|
5419
|
+
errlog = import_node_process.default.stderr,
|
|
5420
|
+
...rest
|
|
5421
|
+
} = {}) {
|
|
5422
|
+
super(rest);
|
|
5423
|
+
this.command = command;
|
|
5424
|
+
this.args = args;
|
|
5425
|
+
this.env = env;
|
|
5426
|
+
this.errlog = errlog;
|
|
5427
|
+
this.clientInfo = rest.clientInfo ?? {
|
|
5428
|
+
name: "stdio-connector",
|
|
5429
|
+
version: "1.0.0"
|
|
5430
|
+
};
|
|
5431
|
+
}
|
|
5432
|
+
/** Establish connection to the MCP implementation. */
|
|
5433
|
+
async connect() {
|
|
5434
|
+
if (this.connected) {
|
|
5435
|
+
logger.debug("Already connected to MCP implementation");
|
|
5436
|
+
return;
|
|
5437
|
+
}
|
|
5438
|
+
logger.debug(`Connecting to MCP implementation via stdio: ${this.command}`);
|
|
5439
|
+
try {
|
|
5440
|
+
let mergedEnv;
|
|
5441
|
+
if (this.env) {
|
|
5442
|
+
mergedEnv = {};
|
|
5443
|
+
for (const [key, value] of Object.entries(import_node_process.default.env)) {
|
|
5444
|
+
if (value !== void 0) {
|
|
5445
|
+
mergedEnv[key] = value;
|
|
5446
|
+
}
|
|
5447
|
+
}
|
|
5448
|
+
Object.assign(mergedEnv, this.env);
|
|
5449
|
+
}
|
|
5450
|
+
const serverParams = {
|
|
5451
|
+
command: this.command,
|
|
5452
|
+
args: this.args,
|
|
5453
|
+
env: mergedEnv
|
|
5454
|
+
};
|
|
5455
|
+
this.connectionManager = new StdioConnectionManager(
|
|
5456
|
+
serverParams,
|
|
5457
|
+
this.errlog
|
|
5458
|
+
);
|
|
5459
|
+
const transport = await this.connectionManager.start();
|
|
5460
|
+
const clientOptions = {
|
|
5461
|
+
...this.opts.clientOptions || {},
|
|
5462
|
+
capabilities: {
|
|
5463
|
+
...this.opts.clientOptions?.capabilities || {},
|
|
5464
|
+
roots: { listChanged: true },
|
|
5465
|
+
// Always advertise roots capability
|
|
5466
|
+
// Add sampling capability if callback is provided
|
|
5467
|
+
...this.opts.samplingCallback ? { sampling: {} } : {},
|
|
5468
|
+
// Add elicitation capability if callback is provided
|
|
5469
|
+
...this.opts.elicitationCallback ? { elicitation: { form: {}, url: {} } } : {}
|
|
5470
|
+
}
|
|
5471
|
+
};
|
|
5472
|
+
this.client = new import_client2.Client(this.clientInfo, clientOptions);
|
|
5473
|
+
await this.client.connect(transport);
|
|
5474
|
+
this.connected = true;
|
|
5475
|
+
this.setupNotificationHandler();
|
|
5476
|
+
this.setupRootsHandler();
|
|
5477
|
+
this.setupSamplingHandler();
|
|
5478
|
+
this.setupElicitationHandler();
|
|
5479
|
+
logger.debug(
|
|
5480
|
+
`Successfully connected to MCP implementation: ${this.command}`
|
|
5481
|
+
);
|
|
5482
|
+
this.trackConnectorInit({
|
|
5483
|
+
serverCommand: this.command,
|
|
5484
|
+
serverArgs: this.args,
|
|
5485
|
+
publicIdentifier: `${this.command} ${this.args.join(" ")}`
|
|
5486
|
+
});
|
|
5487
|
+
} catch (err) {
|
|
5488
|
+
logger.error(`Failed to connect to MCP implementation: ${err}`);
|
|
5489
|
+
await this.cleanupResources();
|
|
5490
|
+
throw err;
|
|
5491
|
+
}
|
|
5492
|
+
}
|
|
5493
|
+
get publicIdentifier() {
|
|
5494
|
+
return {
|
|
5495
|
+
type: "stdio",
|
|
5496
|
+
"command&args": `${this.command} ${this.args.join(" ")}`
|
|
5497
|
+
};
|
|
3004
5498
|
}
|
|
3005
5499
|
};
|
|
3006
5500
|
|
|
3007
|
-
// src/
|
|
3008
|
-
function
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
5501
|
+
// src/config.ts
|
|
5502
|
+
function loadConfigFile(filepath) {
|
|
5503
|
+
const raw = (0, import_node_fs.readFileSync)(filepath, "utf-8");
|
|
5504
|
+
return JSON.parse(raw);
|
|
5505
|
+
}
|
|
5506
|
+
__name(loadConfigFile, "loadConfigFile");
|
|
5507
|
+
function createConnectorFromConfig(serverConfig, connectorOptions) {
|
|
5508
|
+
if ("command" in serverConfig && "args" in serverConfig) {
|
|
5509
|
+
return new StdioConnector({
|
|
5510
|
+
command: serverConfig.command,
|
|
5511
|
+
args: serverConfig.args,
|
|
5512
|
+
env: serverConfig.env,
|
|
5513
|
+
...connectorOptions
|
|
5514
|
+
});
|
|
5515
|
+
}
|
|
5516
|
+
if ("url" in serverConfig) {
|
|
5517
|
+
const transport = serverConfig.transport || "http";
|
|
5518
|
+
return new HttpConnector(serverConfig.url, {
|
|
5519
|
+
headers: serverConfig.headers,
|
|
5520
|
+
authToken: serverConfig.auth_token || serverConfig.authToken,
|
|
5521
|
+
// Only force SSE if explicitly requested
|
|
5522
|
+
preferSse: serverConfig.preferSse || transport === "sse",
|
|
5523
|
+
...connectorOptions
|
|
5524
|
+
});
|
|
3014
5525
|
}
|
|
5526
|
+
throw new Error("Cannot determine connector type from config");
|
|
3015
5527
|
}
|
|
3016
|
-
__name(
|
|
3017
|
-
|
|
5528
|
+
__name(createConnectorFromConfig, "createConnectorFromConfig");
|
|
5529
|
+
|
|
5530
|
+
// src/client.ts
|
|
5531
|
+
init_logging();
|
|
5532
|
+
var MCPClient = class _MCPClient extends BaseMCPClient {
|
|
3018
5533
|
static {
|
|
3019
|
-
__name(this, "
|
|
5534
|
+
__name(this, "MCPClient");
|
|
3020
5535
|
}
|
|
3021
|
-
|
|
3022
|
-
|
|
5536
|
+
/**
|
|
5537
|
+
* Get the mcp-use package version.
|
|
5538
|
+
* Works in all environments (Node.js, browser, Cloudflare Workers, Deno, etc.)
|
|
5539
|
+
*/
|
|
5540
|
+
static getPackageVersion() {
|
|
5541
|
+
return getPackageVersion();
|
|
5542
|
+
}
|
|
5543
|
+
codeMode = false;
|
|
5544
|
+
_codeExecutor = null;
|
|
5545
|
+
_customCodeExecutor = null;
|
|
5546
|
+
_codeExecutorConfig = "vm";
|
|
5547
|
+
_executorOptions;
|
|
5548
|
+
_samplingCallback;
|
|
5549
|
+
_elicitationCallback;
|
|
5550
|
+
constructor(config, options) {
|
|
5551
|
+
if (config) {
|
|
5552
|
+
if (typeof config === "string") {
|
|
5553
|
+
super(loadConfigFile(config));
|
|
5554
|
+
} else {
|
|
5555
|
+
super(config);
|
|
5556
|
+
}
|
|
5557
|
+
} else {
|
|
5558
|
+
super();
|
|
5559
|
+
}
|
|
5560
|
+
let codeModeEnabled = false;
|
|
5561
|
+
let executorConfig = "vm";
|
|
5562
|
+
let executorOptions;
|
|
5563
|
+
if (options?.codeMode) {
|
|
5564
|
+
if (typeof options.codeMode === "boolean") {
|
|
5565
|
+
codeModeEnabled = options.codeMode;
|
|
5566
|
+
} else {
|
|
5567
|
+
codeModeEnabled = options.codeMode.enabled;
|
|
5568
|
+
executorConfig = options.codeMode.executor ?? "vm";
|
|
5569
|
+
executorOptions = options.codeMode.executorOptions;
|
|
5570
|
+
}
|
|
5571
|
+
}
|
|
5572
|
+
this.codeMode = codeModeEnabled;
|
|
5573
|
+
this._codeExecutorConfig = executorConfig;
|
|
5574
|
+
this._executorOptions = executorOptions;
|
|
5575
|
+
this._samplingCallback = options?.samplingCallback;
|
|
5576
|
+
this._elicitationCallback = options?.elicitationCallback;
|
|
5577
|
+
if (this.codeMode) {
|
|
5578
|
+
this._setupCodeModeConnector();
|
|
5579
|
+
}
|
|
5580
|
+
this._trackClientInit();
|
|
5581
|
+
}
|
|
5582
|
+
_trackClientInit() {
|
|
5583
|
+
const servers = Object.keys(this.config.mcpServers ?? {});
|
|
5584
|
+
const hasSamplingCallback = !!this._samplingCallback;
|
|
5585
|
+
const hasElicitationCallback = !!this._elicitationCallback;
|
|
5586
|
+
Tel.getInstance().trackMCPClientInit({
|
|
5587
|
+
codeMode: this.codeMode,
|
|
5588
|
+
sandbox: false,
|
|
5589
|
+
// Sandbox not supported in TS yet
|
|
5590
|
+
allCallbacks: hasSamplingCallback && hasElicitationCallback,
|
|
5591
|
+
verify: false,
|
|
5592
|
+
// No verify option in TS client
|
|
5593
|
+
servers,
|
|
5594
|
+
numServers: servers.length,
|
|
5595
|
+
isBrowser: false
|
|
5596
|
+
// Node.js MCPClient
|
|
5597
|
+
}).catch((e) => logger.debug(`Failed to track MCPClient init: ${e}`));
|
|
5598
|
+
}
|
|
5599
|
+
static fromDict(cfg, options) {
|
|
5600
|
+
return new _MCPClient(cfg, options);
|
|
5601
|
+
}
|
|
5602
|
+
static fromConfigFile(path2, options) {
|
|
5603
|
+
return new _MCPClient(loadConfigFile(path2), options);
|
|
3023
5604
|
}
|
|
3024
5605
|
/**
|
|
3025
|
-
*
|
|
5606
|
+
* Save configuration to a file (Node.js only)
|
|
3026
5607
|
*/
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
|
|
5608
|
+
saveConfig(filepath) {
|
|
5609
|
+
const dir = import_node_path.default.dirname(filepath);
|
|
5610
|
+
if (!import_node_fs2.default.existsSync(dir)) {
|
|
5611
|
+
import_node_fs2.default.mkdirSync(dir, { recursive: true });
|
|
3030
5612
|
}
|
|
3031
|
-
|
|
3032
|
-
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
-
|
|
5613
|
+
import_node_fs2.default.writeFileSync(filepath, JSON.stringify(this.config, null, 2), "utf-8");
|
|
5614
|
+
}
|
|
5615
|
+
/**
|
|
5616
|
+
* Create a connector from server configuration (Node.js version)
|
|
5617
|
+
* Supports all connector types including StdioConnector
|
|
5618
|
+
*/
|
|
5619
|
+
createConnectorFromConfig(serverConfig) {
|
|
5620
|
+
return createConnectorFromConfig(serverConfig, {
|
|
5621
|
+
samplingCallback: this._samplingCallback,
|
|
5622
|
+
elicitationCallback: this._elicitationCallback
|
|
5623
|
+
});
|
|
5624
|
+
}
|
|
5625
|
+
_setupCodeModeConnector() {
|
|
5626
|
+
logger.debug("Code mode connector initialized as internal meta server");
|
|
5627
|
+
const connector = new CodeModeConnector(this);
|
|
5628
|
+
const session = new MCPSession(connector);
|
|
5629
|
+
this.sessions["code_mode"] = session;
|
|
5630
|
+
this.activeSessions.push("code_mode");
|
|
5631
|
+
}
|
|
5632
|
+
_ensureCodeExecutor() {
|
|
5633
|
+
if (!this._codeExecutor) {
|
|
5634
|
+
const config = this._codeExecutorConfig;
|
|
5635
|
+
if (config instanceof BaseCodeExecutor) {
|
|
5636
|
+
this._codeExecutor = config;
|
|
5637
|
+
} else if (typeof config === "function") {
|
|
5638
|
+
this._customCodeExecutor = config;
|
|
5639
|
+
throw new Error(
|
|
5640
|
+
"Custom executor function should be handled in executeCode"
|
|
3040
5641
|
);
|
|
5642
|
+
} else if (config === "e2b") {
|
|
5643
|
+
const opts = this._executorOptions;
|
|
5644
|
+
if (!opts?.apiKey) {
|
|
5645
|
+
logger.warn("E2B executor requires apiKey. Falling back to VM.");
|
|
5646
|
+
try {
|
|
5647
|
+
this._codeExecutor = new VMCodeExecutor(
|
|
5648
|
+
this,
|
|
5649
|
+
this._executorOptions
|
|
5650
|
+
);
|
|
5651
|
+
} catch (error) {
|
|
5652
|
+
throw new Error(
|
|
5653
|
+
"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."
|
|
5654
|
+
);
|
|
5655
|
+
}
|
|
5656
|
+
} else {
|
|
5657
|
+
this._codeExecutor = new E2BCodeExecutor(this, opts);
|
|
5658
|
+
}
|
|
5659
|
+
} else {
|
|
3041
5660
|
try {
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
|
|
5661
|
+
this._codeExecutor = new VMCodeExecutor(
|
|
5662
|
+
this,
|
|
5663
|
+
this._executorOptions
|
|
3045
5664
|
);
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
|
|
5665
|
+
} catch (error) {
|
|
5666
|
+
const e2bOpts = this._executorOptions;
|
|
5667
|
+
const e2bApiKey = e2bOpts?.apiKey || process.env.E2B_API_KEY;
|
|
5668
|
+
if (e2bApiKey) {
|
|
5669
|
+
logger.info(
|
|
5670
|
+
"VM executor not available in this environment. Falling back to E2B."
|
|
5671
|
+
);
|
|
5672
|
+
this._codeExecutor = new E2BCodeExecutor(this, {
|
|
5673
|
+
...e2bOpts,
|
|
5674
|
+
apiKey: e2bApiKey
|
|
5675
|
+
});
|
|
5676
|
+
} else {
|
|
5677
|
+
throw new Error(
|
|
5678
|
+
"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."
|
|
5679
|
+
);
|
|
5680
|
+
}
|
|
3050
5681
|
}
|
|
3051
|
-
}
|
|
5682
|
+
}
|
|
5683
|
+
}
|
|
5684
|
+
return this._codeExecutor;
|
|
5685
|
+
}
|
|
5686
|
+
/**
|
|
5687
|
+
* Execute code in code mode
|
|
5688
|
+
*/
|
|
5689
|
+
async executeCode(code, timeout) {
|
|
5690
|
+
if (!this.codeMode) {
|
|
5691
|
+
throw new Error("Code execution mode is not enabled");
|
|
5692
|
+
}
|
|
5693
|
+
if (this._customCodeExecutor) {
|
|
5694
|
+
return this._customCodeExecutor(code, timeout);
|
|
5695
|
+
}
|
|
5696
|
+
return this._ensureCodeExecutor().execute(code, timeout);
|
|
5697
|
+
}
|
|
5698
|
+
/**
|
|
5699
|
+
* Search available tools (used by code mode)
|
|
5700
|
+
*/
|
|
5701
|
+
async searchTools(query = "", detailLevel = "full") {
|
|
5702
|
+
if (!this.codeMode) {
|
|
5703
|
+
throw new Error("Code execution mode is not enabled");
|
|
5704
|
+
}
|
|
5705
|
+
return this._ensureCodeExecutor().createSearchToolsFunction()(
|
|
5706
|
+
query,
|
|
5707
|
+
detailLevel
|
|
5708
|
+
);
|
|
5709
|
+
}
|
|
5710
|
+
/**
|
|
5711
|
+
* Override getServerNames to exclude internal code_mode server
|
|
5712
|
+
*/
|
|
5713
|
+
getServerNames() {
|
|
5714
|
+
const isCodeModeEnabled = this.codeMode;
|
|
5715
|
+
return super.getServerNames().filter((name) => {
|
|
5716
|
+
return !isCodeModeEnabled || name !== "code_mode";
|
|
3052
5717
|
});
|
|
3053
|
-
|
|
5718
|
+
}
|
|
5719
|
+
/**
|
|
5720
|
+
* Close the client and clean up resources including code executors.
|
|
5721
|
+
* This ensures E2B sandboxes and other resources are properly released.
|
|
5722
|
+
*/
|
|
5723
|
+
async close() {
|
|
5724
|
+
if (this._codeExecutor) {
|
|
5725
|
+
await this._codeExecutor.cleanup();
|
|
5726
|
+
this._codeExecutor = null;
|
|
5727
|
+
}
|
|
5728
|
+
await this.closeAllSessions();
|
|
3054
5729
|
}
|
|
3055
5730
|
};
|
|
3056
5731
|
|
|
@@ -3191,15 +5866,21 @@ var ConnectMCPServerTool = class extends MCPServerTool {
|
|
|
3191
5866
|
session = await this.manager.client.createSession(serverName);
|
|
3192
5867
|
}
|
|
3193
5868
|
this.manager.activeServer = serverName;
|
|
3194
|
-
if (this.manager.serverTools[serverName]) {
|
|
5869
|
+
if (!this.manager.serverTools[serverName]) {
|
|
3195
5870
|
const connector = session.connector;
|
|
3196
5871
|
const tools = await this.manager.adapter.createToolsFromConnectors([connector]);
|
|
3197
|
-
this.manager.
|
|
5872
|
+
const resources = await this.manager.adapter.createResourcesFromConnectors([connector]);
|
|
5873
|
+
const prompts = await this.manager.adapter.createPromptsFromConnectors([connector]);
|
|
5874
|
+
const allItems = [...tools, ...resources, ...prompts];
|
|
5875
|
+
this.manager.serverTools[serverName] = allItems;
|
|
3198
5876
|
this.manager.initializedServers[serverName] = true;
|
|
5877
|
+
logger.debug(
|
|
5878
|
+
`Loaded ${allItems.length} items for server '${serverName}': ${tools.length} tools, ${resources.length} resources, ${prompts.length} prompts`
|
|
5879
|
+
);
|
|
3199
5880
|
}
|
|
3200
5881
|
const serverTools = this.manager.serverTools[serverName] || [];
|
|
3201
5882
|
const numTools = serverTools.length;
|
|
3202
|
-
return `Connected to MCP server '${serverName}'. ${numTools} tools are now available.`;
|
|
5883
|
+
return `Connected to MCP server '${serverName}'. ${numTools} tools, resources, and prompts are now available.`;
|
|
3203
5884
|
} catch (error) {
|
|
3204
5885
|
logger.error(
|
|
3205
5886
|
`Error connecting to server '${serverName}': ${String(error)}`
|
|
@@ -3361,21 +6042,30 @@ var ServerManager = class {
|
|
|
3361
6042
|
if (session) {
|
|
3362
6043
|
const connector = session.connector;
|
|
3363
6044
|
let tools = [];
|
|
6045
|
+
let resources = [];
|
|
6046
|
+
let prompts = [];
|
|
3364
6047
|
try {
|
|
3365
6048
|
tools = await this.adapter.createToolsFromConnectors([connector]);
|
|
6049
|
+
resources = await this.adapter.createResourcesFromConnectors([
|
|
6050
|
+
connector
|
|
6051
|
+
]);
|
|
6052
|
+
prompts = await this.adapter.createPromptsFromConnectors([
|
|
6053
|
+
connector
|
|
6054
|
+
]);
|
|
3366
6055
|
} catch (toolFetchError) {
|
|
3367
6056
|
logger.error(
|
|
3368
|
-
`Failed to create tools from connector for server '${serverName}': ${toolFetchError}`
|
|
6057
|
+
`Failed to create tools/resources/prompts from connector for server '${serverName}': ${toolFetchError}`
|
|
3369
6058
|
);
|
|
3370
6059
|
continue;
|
|
3371
6060
|
}
|
|
6061
|
+
const allItems = [...tools, ...resources, ...prompts];
|
|
3372
6062
|
const cachedTools = this.serverTools[serverName];
|
|
3373
|
-
const toolsChanged = !cachedTools || !isEqual(cachedTools,
|
|
6063
|
+
const toolsChanged = !cachedTools || !isEqual(cachedTools, allItems);
|
|
3374
6064
|
if (toolsChanged) {
|
|
3375
|
-
this.serverTools[serverName] =
|
|
6065
|
+
this.serverTools[serverName] = allItems;
|
|
3376
6066
|
this.initializedServers[serverName] = true;
|
|
3377
6067
|
logger.debug(
|
|
3378
|
-
`Prefetched ${
|
|
6068
|
+
`Prefetched ${allItems.length} items for server '${serverName}': ${tools.length} tools, ${resources.length} resources, ${prompts.length} prompts.`
|
|
3379
6069
|
);
|
|
3380
6070
|
} else {
|
|
3381
6071
|
logger.debug(
|
|
@@ -3703,6 +6393,26 @@ var import_zod8 = require("zod");
|
|
|
3703
6393
|
init_logging();
|
|
3704
6394
|
var API_CHATS_ENDPOINT = "/api/v1/chats";
|
|
3705
6395
|
var API_CHAT_EXECUTE_ENDPOINT = "/api/v1/chats/{chat_id}/execute";
|
|
6396
|
+
function normalizeRemoteRunOptions(queryOrOptions, maxSteps, manageConnector, externalHistory, outputSchema) {
|
|
6397
|
+
if (typeof queryOrOptions === "object" && queryOrOptions !== null) {
|
|
6398
|
+
const options = queryOrOptions;
|
|
6399
|
+
return {
|
|
6400
|
+
query: options.prompt,
|
|
6401
|
+
maxSteps: options.maxSteps,
|
|
6402
|
+
manageConnector: options.manageConnector,
|
|
6403
|
+
externalHistory: options.externalHistory,
|
|
6404
|
+
outputSchema: options.schema
|
|
6405
|
+
};
|
|
6406
|
+
}
|
|
6407
|
+
return {
|
|
6408
|
+
query: queryOrOptions,
|
|
6409
|
+
maxSteps,
|
|
6410
|
+
manageConnector,
|
|
6411
|
+
externalHistory,
|
|
6412
|
+
outputSchema
|
|
6413
|
+
};
|
|
6414
|
+
}
|
|
6415
|
+
__name(normalizeRemoteRunOptions, "normalizeRemoteRunOptions");
|
|
3706
6416
|
var RemoteAgent = class {
|
|
3707
6417
|
static {
|
|
3708
6418
|
__name(this, "RemoteAgent");
|
|
@@ -3799,8 +6509,20 @@ var RemoteAgent = class {
|
|
|
3799
6509
|
throw new Error(`Failed to create chat session: ${String(e)}`);
|
|
3800
6510
|
}
|
|
3801
6511
|
}
|
|
3802
|
-
async run(
|
|
3803
|
-
|
|
6512
|
+
async run(queryOrOptions, maxSteps, manageConnector, externalHistory, outputSchema) {
|
|
6513
|
+
const {
|
|
6514
|
+
query,
|
|
6515
|
+
maxSteps: steps,
|
|
6516
|
+
externalHistory: history,
|
|
6517
|
+
outputSchema: schema
|
|
6518
|
+
} = normalizeRemoteRunOptions(
|
|
6519
|
+
queryOrOptions,
|
|
6520
|
+
maxSteps,
|
|
6521
|
+
manageConnector,
|
|
6522
|
+
externalHistory,
|
|
6523
|
+
outputSchema
|
|
6524
|
+
);
|
|
6525
|
+
if (history !== void 0) {
|
|
3804
6526
|
logger.warn("External history is not yet supported for remote execution");
|
|
3805
6527
|
}
|
|
3806
6528
|
try {
|
|
@@ -3811,10 +6533,10 @@ var RemoteAgent = class {
|
|
|
3811
6533
|
const chatId = this.chatId;
|
|
3812
6534
|
const executionPayload = {
|
|
3813
6535
|
query,
|
|
3814
|
-
max_steps:
|
|
6536
|
+
max_steps: steps ?? 10
|
|
3815
6537
|
};
|
|
3816
|
-
if (
|
|
3817
|
-
executionPayload.output_schema = this.pydanticToJsonSchema(
|
|
6538
|
+
if (schema) {
|
|
6539
|
+
executionPayload.output_schema = this.pydanticToJsonSchema(schema);
|
|
3818
6540
|
logger.info(`\u{1F527} Using structured output with schema`);
|
|
3819
6541
|
}
|
|
3820
6542
|
const headers = {
|
|
@@ -3888,8 +6610,8 @@ Raw error: ${result}`
|
|
|
3888
6610
|
);
|
|
3889
6611
|
}
|
|
3890
6612
|
}
|
|
3891
|
-
if (
|
|
3892
|
-
return this.parseStructuredResponse(result,
|
|
6613
|
+
if (schema) {
|
|
6614
|
+
return this.parseStructuredResponse(result, schema);
|
|
3893
6615
|
}
|
|
3894
6616
|
if (typeof result === "object" && result !== null && "result" in result) {
|
|
3895
6617
|
return result.result;
|
|
@@ -3914,9 +6636,9 @@ Raw error: ${result}`
|
|
|
3914
6636
|
}
|
|
3915
6637
|
}
|
|
3916
6638
|
// eslint-disable-next-line require-yield
|
|
3917
|
-
async *stream(
|
|
6639
|
+
async *stream(queryOrOptions, maxSteps, manageConnector, externalHistory, outputSchema) {
|
|
3918
6640
|
const result = await this.run(
|
|
3919
|
-
|
|
6641
|
+
queryOrOptions,
|
|
3920
6642
|
maxSteps,
|
|
3921
6643
|
manageConnector,
|
|
3922
6644
|
externalHistory,
|
|
@@ -3929,7 +6651,153 @@ Raw error: ${result}`
|
|
|
3929
6651
|
}
|
|
3930
6652
|
};
|
|
3931
6653
|
|
|
6654
|
+
// src/agents/utils/llm_provider.ts
|
|
6655
|
+
init_logging();
|
|
6656
|
+
var PROVIDER_CONFIG = {
|
|
6657
|
+
openai: {
|
|
6658
|
+
package: "@langchain/openai",
|
|
6659
|
+
className: "ChatOpenAI",
|
|
6660
|
+
envVars: ["OPENAI_API_KEY"],
|
|
6661
|
+
defaultModel: "gpt-4o"
|
|
6662
|
+
},
|
|
6663
|
+
anthropic: {
|
|
6664
|
+
package: "@langchain/anthropic",
|
|
6665
|
+
className: "ChatAnthropic",
|
|
6666
|
+
envVars: ["ANTHROPIC_API_KEY"],
|
|
6667
|
+
defaultModel: "claude-3-5-sonnet-20241022"
|
|
6668
|
+
},
|
|
6669
|
+
google: {
|
|
6670
|
+
package: "@langchain/google-genai",
|
|
6671
|
+
className: "ChatGoogleGenerativeAI",
|
|
6672
|
+
envVars: ["GOOGLE_API_KEY", "GOOGLE_GENERATIVE_AI_API_KEY"],
|
|
6673
|
+
defaultModel: "gemini-pro"
|
|
6674
|
+
},
|
|
6675
|
+
groq: {
|
|
6676
|
+
package: "@langchain/groq",
|
|
6677
|
+
className: "ChatGroq",
|
|
6678
|
+
envVars: ["GROQ_API_KEY"],
|
|
6679
|
+
defaultModel: "llama-3.1-70b-versatile"
|
|
6680
|
+
}
|
|
6681
|
+
};
|
|
6682
|
+
function parseLLMString(llmString) {
|
|
6683
|
+
const parts = llmString.split("/");
|
|
6684
|
+
if (parts.length !== 2) {
|
|
6685
|
+
throw new Error(
|
|
6686
|
+
`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'`
|
|
6687
|
+
);
|
|
6688
|
+
}
|
|
6689
|
+
const [provider, model] = parts;
|
|
6690
|
+
if (!provider || !model) {
|
|
6691
|
+
throw new Error(
|
|
6692
|
+
`Invalid LLM string format. Both provider and model must be non-empty. Got '${llmString}'`
|
|
6693
|
+
);
|
|
6694
|
+
}
|
|
6695
|
+
const normalizedProvider = provider.toLowerCase();
|
|
6696
|
+
if (!(normalizedProvider in PROVIDER_CONFIG)) {
|
|
6697
|
+
const supportedProviders = Object.keys(PROVIDER_CONFIG).join(", ");
|
|
6698
|
+
throw new Error(
|
|
6699
|
+
`Unsupported LLM provider '${provider}'. Supported providers: ${supportedProviders}`
|
|
6700
|
+
);
|
|
6701
|
+
}
|
|
6702
|
+
return { provider: normalizedProvider, model };
|
|
6703
|
+
}
|
|
6704
|
+
__name(parseLLMString, "parseLLMString");
|
|
6705
|
+
function getAPIKey(provider, config) {
|
|
6706
|
+
if (config?.apiKey) {
|
|
6707
|
+
return config.apiKey;
|
|
6708
|
+
}
|
|
6709
|
+
const providerConfig = PROVIDER_CONFIG[provider];
|
|
6710
|
+
for (const envVar of providerConfig.envVars) {
|
|
6711
|
+
const apiKey = process.env[envVar];
|
|
6712
|
+
if (apiKey) {
|
|
6713
|
+
logger.debug(
|
|
6714
|
+
`Using API key from environment variable ${envVar} for provider ${provider}`
|
|
6715
|
+
);
|
|
6716
|
+
return apiKey;
|
|
6717
|
+
}
|
|
6718
|
+
}
|
|
6719
|
+
const envVarsStr = providerConfig.envVars.join(" or ");
|
|
6720
|
+
throw new Error(
|
|
6721
|
+
`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' } })`
|
|
6722
|
+
);
|
|
6723
|
+
}
|
|
6724
|
+
__name(getAPIKey, "getAPIKey");
|
|
6725
|
+
async function createLLMFromString(llmString, config) {
|
|
6726
|
+
logger.info(`Creating LLM from string: ${llmString}`);
|
|
6727
|
+
const { provider, model } = parseLLMString(llmString);
|
|
6728
|
+
const providerConfig = PROVIDER_CONFIG[provider];
|
|
6729
|
+
const apiKey = getAPIKey(provider, config);
|
|
6730
|
+
let providerModule;
|
|
6731
|
+
try {
|
|
6732
|
+
logger.debug(`Importing package ${providerConfig.package}...`);
|
|
6733
|
+
providerModule = await import(providerConfig.package);
|
|
6734
|
+
} catch (error) {
|
|
6735
|
+
if (error?.code === "MODULE_NOT_FOUND" || error?.message?.includes("Cannot find module") || error?.message?.includes("Cannot find package")) {
|
|
6736
|
+
throw new Error(
|
|
6737
|
+
`Package '${providerConfig.package}' is not installed. Install it with: npm install ${providerConfig.package} or yarn add ${providerConfig.package}`
|
|
6738
|
+
);
|
|
6739
|
+
}
|
|
6740
|
+
throw new Error(
|
|
6741
|
+
`Failed to import ${providerConfig.package}: ${error?.message || error}`
|
|
6742
|
+
);
|
|
6743
|
+
}
|
|
6744
|
+
const LLMClass = providerModule[providerConfig.className];
|
|
6745
|
+
if (!LLMClass) {
|
|
6746
|
+
throw new Error(
|
|
6747
|
+
`Could not find ${providerConfig.className} in package ${providerConfig.package}. This might be a version compatibility issue.`
|
|
6748
|
+
);
|
|
6749
|
+
}
|
|
6750
|
+
const llmConfig = {
|
|
6751
|
+
model,
|
|
6752
|
+
apiKey,
|
|
6753
|
+
...config
|
|
6754
|
+
};
|
|
6755
|
+
if (config?.apiKey) {
|
|
6756
|
+
delete llmConfig.apiKey;
|
|
6757
|
+
llmConfig.apiKey = apiKey;
|
|
6758
|
+
}
|
|
6759
|
+
if (provider === "anthropic") {
|
|
6760
|
+
llmConfig.model = model;
|
|
6761
|
+
} else if (provider === "google") {
|
|
6762
|
+
llmConfig.model = model;
|
|
6763
|
+
} else if (provider === "openai") {
|
|
6764
|
+
llmConfig.model = model;
|
|
6765
|
+
} else if (provider === "groq") {
|
|
6766
|
+
llmConfig.model = model;
|
|
6767
|
+
}
|
|
6768
|
+
try {
|
|
6769
|
+
const llmInstance = new LLMClass(llmConfig);
|
|
6770
|
+
logger.info(`Successfully created ${provider} LLM with model ${model}`);
|
|
6771
|
+
return llmInstance;
|
|
6772
|
+
} catch (error) {
|
|
6773
|
+
throw new Error(
|
|
6774
|
+
`Failed to instantiate ${providerConfig.className} with model '${model}': ${error?.message || error}`
|
|
6775
|
+
);
|
|
6776
|
+
}
|
|
6777
|
+
}
|
|
6778
|
+
__name(createLLMFromString, "createLLMFromString");
|
|
6779
|
+
|
|
3932
6780
|
// src/agents/mcp_agent.ts
|
|
6781
|
+
function normalizeRunOptions(queryOrOptions, maxSteps, manageConnector, externalHistory, outputSchema) {
|
|
6782
|
+
if (typeof queryOrOptions === "object" && queryOrOptions !== null) {
|
|
6783
|
+
const options = queryOrOptions;
|
|
6784
|
+
return {
|
|
6785
|
+
query: options.prompt,
|
|
6786
|
+
maxSteps: options.maxSteps,
|
|
6787
|
+
manageConnector: options.manageConnector,
|
|
6788
|
+
externalHistory: options.externalHistory,
|
|
6789
|
+
outputSchema: options.schema
|
|
6790
|
+
};
|
|
6791
|
+
}
|
|
6792
|
+
return {
|
|
6793
|
+
query: queryOrOptions,
|
|
6794
|
+
maxSteps,
|
|
6795
|
+
manageConnector,
|
|
6796
|
+
externalHistory,
|
|
6797
|
+
outputSchema
|
|
6798
|
+
};
|
|
6799
|
+
}
|
|
6800
|
+
__name(normalizeRunOptions, "normalizeRunOptions");
|
|
3933
6801
|
var MCPAgent = class {
|
|
3934
6802
|
static {
|
|
3935
6803
|
__name(this, "MCPAgent");
|
|
@@ -3975,6 +6843,12 @@ var MCPAgent = class {
|
|
|
3975
6843
|
// Remote agent support
|
|
3976
6844
|
isRemote = false;
|
|
3977
6845
|
remoteAgent = null;
|
|
6846
|
+
// Simplified mode support
|
|
6847
|
+
isSimplifiedMode = false;
|
|
6848
|
+
llmString;
|
|
6849
|
+
llmConfig;
|
|
6850
|
+
mcpServersConfig;
|
|
6851
|
+
clientOwnedByAgent = false;
|
|
3978
6852
|
constructor(options) {
|
|
3979
6853
|
if (options.agentId) {
|
|
3980
6854
|
this.isRemote = true;
|
|
@@ -4008,9 +6882,36 @@ var MCPAgent = class {
|
|
|
4008
6882
|
"llm is required for local execution. For remote execution, provide agentId instead."
|
|
4009
6883
|
);
|
|
4010
6884
|
}
|
|
4011
|
-
|
|
4012
|
-
|
|
4013
|
-
|
|
6885
|
+
const isSimplifiedMode = typeof options.llm === "string";
|
|
6886
|
+
if (isSimplifiedMode) {
|
|
6887
|
+
this.isSimplifiedMode = true;
|
|
6888
|
+
this.llmString = options.llm;
|
|
6889
|
+
this.llmConfig = options.llmConfig;
|
|
6890
|
+
this.mcpServersConfig = options.mcpServers;
|
|
6891
|
+
if (!this.mcpServersConfig || Object.keys(this.mcpServersConfig).length === 0) {
|
|
6892
|
+
throw new Error(
|
|
6893
|
+
"Simplified mode requires 'mcpServers' configuration. Provide an object with server configurations, e.g., { filesystem: { command: 'npx', args: [...] } }"
|
|
6894
|
+
);
|
|
6895
|
+
}
|
|
6896
|
+
this.llm = void 0;
|
|
6897
|
+
this.client = void 0;
|
|
6898
|
+
this.clientOwnedByAgent = true;
|
|
6899
|
+
this.connectors = [];
|
|
6900
|
+
logger.info(
|
|
6901
|
+
`\u{1F3AF} Simplified mode enabled: LLM will be created from '${this.llmString}'`
|
|
6902
|
+
);
|
|
6903
|
+
} else {
|
|
6904
|
+
this.isSimplifiedMode = false;
|
|
6905
|
+
this.llm = options.llm;
|
|
6906
|
+
this.client = options.client;
|
|
6907
|
+
this.connectors = options.connectors ?? [];
|
|
6908
|
+
this.clientOwnedByAgent = false;
|
|
6909
|
+
if (!this.client && this.connectors.length === 0) {
|
|
6910
|
+
throw new Error(
|
|
6911
|
+
"Explicit mode requires either 'client' or at least one 'connector'. Alternatively, use simplified mode with 'llm' as a string and 'mcpServers' config."
|
|
6912
|
+
);
|
|
6913
|
+
}
|
|
6914
|
+
}
|
|
4014
6915
|
this.maxSteps = options.maxSteps ?? 5;
|
|
4015
6916
|
this.autoInitialize = options.autoInitialize ?? false;
|
|
4016
6917
|
this.memoryEnabled = options.memoryEnabled ?? true;
|
|
@@ -4023,28 +6924,30 @@ var MCPAgent = class {
|
|
|
4023
6924
|
this.useServerManager = options.useServerManager ?? false;
|
|
4024
6925
|
this.verbose = options.verbose ?? false;
|
|
4025
6926
|
this.observe = options.observe ?? true;
|
|
4026
|
-
if (!this.
|
|
4027
|
-
|
|
4028
|
-
|
|
4029
|
-
|
|
4030
|
-
|
|
4031
|
-
|
|
4032
|
-
|
|
4033
|
-
|
|
4034
|
-
|
|
4035
|
-
|
|
6927
|
+
if (!this.isSimplifiedMode) {
|
|
6928
|
+
if (this.useServerManager) {
|
|
6929
|
+
if (!this.client) {
|
|
6930
|
+
throw new Error(
|
|
6931
|
+
"'client' must be provided when 'useServerManager' is true."
|
|
6932
|
+
);
|
|
6933
|
+
}
|
|
6934
|
+
this.adapter = options.adapter ?? new LangChainAdapter(this.disallowedTools);
|
|
6935
|
+
this.serverManager = options.serverManagerFactory?.(this.client) ?? new ServerManager(this.client, this.adapter);
|
|
6936
|
+
} else {
|
|
6937
|
+
this.adapter = options.adapter ?? new LangChainAdapter(this.disallowedTools);
|
|
6938
|
+
}
|
|
6939
|
+
this.telemetry = Telemetry.getInstance();
|
|
6940
|
+
if (this.llm) {
|
|
6941
|
+
const [provider, name] = extractModelInfo(this.llm);
|
|
6942
|
+
this.modelProvider = provider;
|
|
6943
|
+
this.modelName = name;
|
|
6944
|
+
} else {
|
|
6945
|
+
this.modelProvider = "unknown";
|
|
6946
|
+
this.modelName = "unknown";
|
|
4036
6947
|
}
|
|
4037
|
-
this.adapter = options.adapter ?? new LangChainAdapter(this.disallowedTools);
|
|
4038
|
-
this.serverManager = options.serverManagerFactory?.(this.client) ?? new ServerManager(this.client, this.adapter);
|
|
4039
6948
|
} else {
|
|
4040
6949
|
this.adapter = options.adapter ?? new LangChainAdapter(this.disallowedTools);
|
|
4041
|
-
|
|
4042
|
-
this.telemetry = Telemetry.getInstance();
|
|
4043
|
-
if (this.llm) {
|
|
4044
|
-
const [provider, name] = extractModelInfo(this.llm);
|
|
4045
|
-
this.modelProvider = provider;
|
|
4046
|
-
this.modelName = name;
|
|
4047
|
-
} else {
|
|
6950
|
+
this.telemetry = Telemetry.getInstance();
|
|
4048
6951
|
this.modelProvider = "unknown";
|
|
4049
6952
|
this.modelName = "unknown";
|
|
4050
6953
|
}
|
|
@@ -4075,6 +6978,40 @@ var MCPAgent = class {
|
|
|
4075
6978
|
return;
|
|
4076
6979
|
}
|
|
4077
6980
|
logger.info("\u{1F680} Initializing MCP agent and connecting to services...");
|
|
6981
|
+
if (this.isSimplifiedMode) {
|
|
6982
|
+
logger.info(
|
|
6983
|
+
"\u{1F3AF} Simplified mode: Creating client and LLM from configuration..."
|
|
6984
|
+
);
|
|
6985
|
+
if (this.mcpServersConfig) {
|
|
6986
|
+
logger.info(
|
|
6987
|
+
`Creating MCPClient with ${Object.keys(this.mcpServersConfig).length} server(s)...`
|
|
6988
|
+
);
|
|
6989
|
+
this.client = new MCPClient({ mcpServers: this.mcpServersConfig });
|
|
6990
|
+
logger.info("\u2705 MCPClient created successfully");
|
|
6991
|
+
}
|
|
6992
|
+
if (this.llmString) {
|
|
6993
|
+
logger.info(`Creating LLM from string: ${this.llmString}...`);
|
|
6994
|
+
try {
|
|
6995
|
+
this.llm = await createLLMFromString(this.llmString, this.llmConfig);
|
|
6996
|
+
logger.info("\u2705 LLM created successfully");
|
|
6997
|
+
const [provider, name] = extractModelInfo(this.llm);
|
|
6998
|
+
this.modelProvider = provider;
|
|
6999
|
+
this.modelName = name;
|
|
7000
|
+
} catch (error) {
|
|
7001
|
+
throw new Error(
|
|
7002
|
+
`Failed to create LLM from string '${this.llmString}': ${error?.message || error}`
|
|
7003
|
+
);
|
|
7004
|
+
}
|
|
7005
|
+
}
|
|
7006
|
+
if (this.useServerManager) {
|
|
7007
|
+
if (!this.client) {
|
|
7008
|
+
throw new Error(
|
|
7009
|
+
"'client' must be available when 'useServerManager' is true."
|
|
7010
|
+
);
|
|
7011
|
+
}
|
|
7012
|
+
this.serverManager = new ServerManager(this.client, this.adapter);
|
|
7013
|
+
}
|
|
7014
|
+
}
|
|
4078
7015
|
this.callbacks = await this.observabilityManager.getCallbacks();
|
|
4079
7016
|
const handlerNames = await this.observabilityManager.getHandlerNames();
|
|
4080
7017
|
if (handlerNames.length > 0) {
|
|
@@ -4118,9 +7055,18 @@ var MCPAgent = class {
|
|
|
4118
7055
|
);
|
|
4119
7056
|
}
|
|
4120
7057
|
} else {
|
|
4121
|
-
|
|
7058
|
+
const tools = await this.adapter.createToolsFromConnectors(
|
|
7059
|
+
Object.values(this.sessions).map((session) => session.connector)
|
|
7060
|
+
);
|
|
7061
|
+
const resources = await this.adapter.createResourcesFromConnectors(
|
|
7062
|
+
Object.values(this.sessions).map((session) => session.connector)
|
|
7063
|
+
);
|
|
7064
|
+
const prompts = await this.adapter.createPromptsFromConnectors(
|
|
7065
|
+
Object.values(this.sessions).map((session) => session.connector)
|
|
7066
|
+
);
|
|
7067
|
+
this._tools = [...tools, ...resources, ...prompts];
|
|
4122
7068
|
logger.info(
|
|
4123
|
-
`\u{1F6E0}\uFE0F Created ${this._tools.length} LangChain
|
|
7069
|
+
`\u{1F6E0}\uFE0F Created ${this._tools.length} LangChain items from client: ${tools.length} tools, ${resources.length} resources, ${prompts.length} prompts`
|
|
4124
7070
|
);
|
|
4125
7071
|
}
|
|
4126
7072
|
this._tools.push(...this.additionalTools);
|
|
@@ -4133,12 +7079,19 @@ var MCPAgent = class {
|
|
|
4133
7079
|
await connector.connect();
|
|
4134
7080
|
}
|
|
4135
7081
|
}
|
|
4136
|
-
|
|
7082
|
+
const tools = await this.adapter.createToolsFromConnectors(
|
|
7083
|
+
this.connectors
|
|
7084
|
+
);
|
|
7085
|
+
const resources = await this.adapter.createResourcesFromConnectors(
|
|
7086
|
+
this.connectors
|
|
7087
|
+
);
|
|
7088
|
+
const prompts = await this.adapter.createPromptsFromConnectors(
|
|
4137
7089
|
this.connectors
|
|
4138
7090
|
);
|
|
7091
|
+
this._tools = [...tools, ...resources, ...prompts];
|
|
4139
7092
|
this._tools.push(...this.additionalTools);
|
|
4140
7093
|
logger.info(
|
|
4141
|
-
`\u{1F6E0}\uFE0F Created ${this._tools.length} LangChain
|
|
7094
|
+
`\u{1F6E0}\uFE0F Created ${this._tools.length} LangChain items from connectors: ${tools.length} tools, ${resources.length} resources, ${prompts.length} prompts`
|
|
4142
7095
|
);
|
|
4143
7096
|
}
|
|
4144
7097
|
logger.info(`\u{1F9F0} Found ${this._tools.length} tools across all connectors`);
|
|
@@ -4601,33 +7554,47 @@ var MCPAgent = class {
|
|
|
4601
7554
|
}
|
|
4602
7555
|
}
|
|
4603
7556
|
}
|
|
4604
|
-
async run(
|
|
4605
|
-
|
|
4606
|
-
return this.remoteAgent.run(
|
|
4607
|
-
query,
|
|
4608
|
-
maxSteps,
|
|
4609
|
-
manageConnector,
|
|
4610
|
-
externalHistory,
|
|
4611
|
-
outputSchema
|
|
4612
|
-
);
|
|
4613
|
-
}
|
|
4614
|
-
const generator = this.stream(
|
|
7557
|
+
async run(queryOrOptions, maxSteps, manageConnector, externalHistory, outputSchema) {
|
|
7558
|
+
const {
|
|
4615
7559
|
query,
|
|
7560
|
+
maxSteps: steps,
|
|
7561
|
+
manageConnector: manage,
|
|
7562
|
+
externalHistory: history,
|
|
7563
|
+
outputSchema: schema
|
|
7564
|
+
} = normalizeRunOptions(
|
|
7565
|
+
queryOrOptions,
|
|
4616
7566
|
maxSteps,
|
|
4617
7567
|
manageConnector,
|
|
4618
7568
|
externalHistory,
|
|
4619
7569
|
outputSchema
|
|
4620
7570
|
);
|
|
7571
|
+
if (this.isRemote && this.remoteAgent) {
|
|
7572
|
+
return this.remoteAgent.run(query, steps, manage, history, schema);
|
|
7573
|
+
}
|
|
7574
|
+
const generator = this.stream(query, steps, manage, history, schema);
|
|
4621
7575
|
return this._consumeAndReturn(generator);
|
|
4622
7576
|
}
|
|
4623
|
-
async *stream(
|
|
7577
|
+
async *stream(queryOrOptions, maxSteps, manageConnector = true, externalHistory, outputSchema) {
|
|
7578
|
+
const {
|
|
7579
|
+
query,
|
|
7580
|
+
maxSteps: steps,
|
|
7581
|
+
manageConnector: manage,
|
|
7582
|
+
externalHistory: history,
|
|
7583
|
+
outputSchema: schema
|
|
7584
|
+
} = normalizeRunOptions(
|
|
7585
|
+
queryOrOptions,
|
|
7586
|
+
maxSteps,
|
|
7587
|
+
manageConnector,
|
|
7588
|
+
externalHistory,
|
|
7589
|
+
outputSchema
|
|
7590
|
+
);
|
|
4624
7591
|
if (this.isRemote && this.remoteAgent) {
|
|
4625
7592
|
const result = await this.remoteAgent.run(
|
|
4626
7593
|
query,
|
|
4627
|
-
|
|
4628
|
-
|
|
4629
|
-
|
|
4630
|
-
|
|
7594
|
+
steps,
|
|
7595
|
+
manage,
|
|
7596
|
+
history,
|
|
7597
|
+
schema
|
|
4631
7598
|
);
|
|
4632
7599
|
return result;
|
|
4633
7600
|
}
|
|
@@ -4637,7 +7604,7 @@ var MCPAgent = class {
|
|
|
4637
7604
|
let finalOutput = null;
|
|
4638
7605
|
let stepsTaken = 0;
|
|
4639
7606
|
try {
|
|
4640
|
-
if (
|
|
7607
|
+
if (manage && !this._initialized) {
|
|
4641
7608
|
await this.initialize();
|
|
4642
7609
|
initializedHere = true;
|
|
4643
7610
|
} else if (!this._initialized && this.autoInitialize) {
|
|
@@ -4661,7 +7628,7 @@ var MCPAgent = class {
|
|
|
4661
7628
|
this._agentExecutor = this.createAgent();
|
|
4662
7629
|
}
|
|
4663
7630
|
}
|
|
4664
|
-
const historyToUse =
|
|
7631
|
+
const historyToUse = history ?? this.conversationHistory;
|
|
4665
7632
|
const langchainHistory = [];
|
|
4666
7633
|
for (const msg of historyToUse) {
|
|
4667
7634
|
if (this._isHumanMessageLike(msg) || this._isAIMessageLike(msg) || this._isToolMessageLike(msg)) {
|
|
@@ -4802,13 +7769,13 @@ var MCPAgent = class {
|
|
|
4802
7769
|
this.addToHistory(msg);
|
|
4803
7770
|
}
|
|
4804
7771
|
}
|
|
4805
|
-
if (
|
|
7772
|
+
if (schema && finalOutput) {
|
|
4806
7773
|
try {
|
|
4807
7774
|
logger.info("\u{1F527} Attempting structured output...");
|
|
4808
7775
|
const structuredResult = await this._attemptStructuredOutput(
|
|
4809
7776
|
finalOutput,
|
|
4810
7777
|
this.llm,
|
|
4811
|
-
|
|
7778
|
+
schema
|
|
4812
7779
|
);
|
|
4813
7780
|
if (this.memoryEnabled) {
|
|
4814
7781
|
this.addToHistory(
|
|
@@ -4834,7 +7801,7 @@ var MCPAgent = class {
|
|
|
4834
7801
|
return finalOutput || "No output generated";
|
|
4835
7802
|
} catch (e) {
|
|
4836
7803
|
logger.error(`\u274C Error running query: ${e}`);
|
|
4837
|
-
if (initializedHere &&
|
|
7804
|
+
if (initializedHere && manage) {
|
|
4838
7805
|
logger.info("\u{1F9F9} Cleaning up resources after error");
|
|
4839
7806
|
await this.close();
|
|
4840
7807
|
}
|
|
@@ -4864,9 +7831,9 @@ var MCPAgent = class {
|
|
|
4864
7831
|
maxStepsConfigured: this.maxSteps,
|
|
4865
7832
|
memoryEnabled: this.memoryEnabled,
|
|
4866
7833
|
useServerManager: this.useServerManager,
|
|
4867
|
-
maxStepsUsed:
|
|
4868
|
-
manageConnector,
|
|
4869
|
-
externalHistoryUsed:
|
|
7834
|
+
maxStepsUsed: steps ?? null,
|
|
7835
|
+
manageConnector: manage ?? true,
|
|
7836
|
+
externalHistoryUsed: history !== void 0,
|
|
4870
7837
|
stepsTaken,
|
|
4871
7838
|
toolsUsedCount: this.toolsUsedNames.length,
|
|
4872
7839
|
toolsUsedNames: this.toolsUsedNames,
|
|
@@ -4875,7 +7842,7 @@ var MCPAgent = class {
|
|
|
4875
7842
|
errorType: success ? null : "execution_error",
|
|
4876
7843
|
conversationHistoryLength
|
|
4877
7844
|
});
|
|
4878
|
-
if (
|
|
7845
|
+
if (manage && !this.client && initializedHere) {
|
|
4879
7846
|
logger.info("\u{1F9F9} Closing agent after stream completion");
|
|
4880
7847
|
await this.close();
|
|
4881
7848
|
}
|
|
@@ -4903,15 +7870,28 @@ var MCPAgent = class {
|
|
|
4903
7870
|
this._agentExecutor = null;
|
|
4904
7871
|
this._tools = [];
|
|
4905
7872
|
if (this.client) {
|
|
4906
|
-
|
|
4907
|
-
|
|
4908
|
-
|
|
7873
|
+
if (this.clientOwnedByAgent) {
|
|
7874
|
+
logger.info(
|
|
7875
|
+
"\u{1F504} Closing internally-created client (simplified mode) and cleaning up resources"
|
|
7876
|
+
);
|
|
7877
|
+
await this.client.close();
|
|
7878
|
+
this.sessions = {};
|
|
7879
|
+
this.client = void 0;
|
|
7880
|
+
} else {
|
|
7881
|
+
logger.info("\u{1F504} Closing client and cleaning up resources");
|
|
7882
|
+
await this.client.close();
|
|
7883
|
+
this.sessions = {};
|
|
7884
|
+
}
|
|
4909
7885
|
} else {
|
|
4910
7886
|
for (const connector of this.connectors) {
|
|
4911
7887
|
logger.info("\u{1F504} Disconnecting connector");
|
|
4912
7888
|
await connector.disconnect();
|
|
4913
7889
|
}
|
|
4914
7890
|
}
|
|
7891
|
+
if (this.isSimplifiedMode && this.llm) {
|
|
7892
|
+
logger.debug("\u{1F504} Clearing LLM reference (simplified mode)");
|
|
7893
|
+
this.llm = void 0;
|
|
7894
|
+
}
|
|
4915
7895
|
if ("connectorToolMap" in this.adapter) {
|
|
4916
7896
|
this.adapter = new LangChainAdapter();
|
|
4917
7897
|
}
|
|
@@ -4920,16 +7900,12 @@ var MCPAgent = class {
|
|
|
4920
7900
|
logger.info("\u{1F44B} Agent closed successfully");
|
|
4921
7901
|
}
|
|
4922
7902
|
}
|
|
4923
|
-
|
|
4924
|
-
* Yields with pretty-printed output for code mode.
|
|
4925
|
-
* This method formats and displays tool executions in a user-friendly way with syntax highlighting.
|
|
4926
|
-
*/
|
|
4927
|
-
async *prettyStreamEvents(query, maxSteps, manageConnector = true, externalHistory, outputSchema) {
|
|
7903
|
+
async *prettyStreamEvents(queryOrOptions, maxSteps, manageConnector = true, externalHistory, outputSchema) {
|
|
4928
7904
|
const { prettyStreamEvents: prettyStream } = await Promise.resolve().then(() => (init_display(), display_exports));
|
|
4929
7905
|
const finalResponse = "";
|
|
4930
7906
|
for await (const _ of prettyStream(
|
|
4931
7907
|
this.streamEvents(
|
|
4932
|
-
|
|
7908
|
+
queryOrOptions,
|
|
4933
7909
|
maxSteps,
|
|
4934
7910
|
manageConnector,
|
|
4935
7911
|
externalHistory,
|
|
@@ -4940,22 +7916,32 @@ var MCPAgent = class {
|
|
|
4940
7916
|
}
|
|
4941
7917
|
return finalResponse;
|
|
4942
7918
|
}
|
|
4943
|
-
|
|
4944
|
-
|
|
4945
|
-
|
|
4946
|
-
|
|
4947
|
-
|
|
7919
|
+
async *streamEvents(queryOrOptions, maxSteps, manageConnector = true, externalHistory, outputSchema) {
|
|
7920
|
+
const normalized = normalizeRunOptions(
|
|
7921
|
+
queryOrOptions,
|
|
7922
|
+
maxSteps,
|
|
7923
|
+
manageConnector,
|
|
7924
|
+
externalHistory,
|
|
7925
|
+
outputSchema
|
|
7926
|
+
);
|
|
7927
|
+
let { query } = normalized;
|
|
7928
|
+
const {
|
|
7929
|
+
maxSteps: steps,
|
|
7930
|
+
manageConnector: manage,
|
|
7931
|
+
externalHistory: history,
|
|
7932
|
+
outputSchema: schema
|
|
7933
|
+
} = normalized;
|
|
4948
7934
|
let initializedHere = false;
|
|
4949
7935
|
const startTime = Date.now();
|
|
4950
7936
|
let success = false;
|
|
4951
7937
|
let eventCount = 0;
|
|
4952
7938
|
let totalResponseLength = 0;
|
|
4953
7939
|
let finalResponse = "";
|
|
4954
|
-
if (
|
|
4955
|
-
query = this._enhanceQueryWithSchema(query,
|
|
7940
|
+
if (schema) {
|
|
7941
|
+
query = this._enhanceQueryWithSchema(query, schema);
|
|
4956
7942
|
}
|
|
4957
7943
|
try {
|
|
4958
|
-
if (
|
|
7944
|
+
if (manage && !this._initialized) {
|
|
4959
7945
|
await this.initialize();
|
|
4960
7946
|
initializedHere = true;
|
|
4961
7947
|
} else if (!this._initialized && this.autoInitialize) {
|
|
@@ -4966,14 +7952,14 @@ var MCPAgent = class {
|
|
|
4966
7952
|
if (!agentExecutor) {
|
|
4967
7953
|
throw new Error("MCP agent failed to initialize");
|
|
4968
7954
|
}
|
|
4969
|
-
this.maxSteps =
|
|
7955
|
+
this.maxSteps = steps ?? this.maxSteps;
|
|
4970
7956
|
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);
|
|
4971
7957
|
logger.info(`\u{1F4AC} Received query for streamEvents: '${display_query}'`);
|
|
4972
7958
|
if (this.memoryEnabled) {
|
|
4973
7959
|
logger.info(`\u{1F504} Adding user message to history: ${display_query}`);
|
|
4974
7960
|
this.addToHistory(new import_langchain2.HumanMessage({ content: query }));
|
|
4975
7961
|
}
|
|
4976
|
-
const historyToUse =
|
|
7962
|
+
const historyToUse = history ?? this.conversationHistory;
|
|
4977
7963
|
const langchainHistory = [];
|
|
4978
7964
|
for (const msg of historyToUse) {
|
|
4979
7965
|
if (this._isHumanMessageLike(msg) || this._isAIMessageLike(msg) || this._isToolMessageLike(msg)) {
|
|
@@ -5040,17 +8026,13 @@ var MCPAgent = class {
|
|
|
5040
8026
|
}
|
|
5041
8027
|
}
|
|
5042
8028
|
}
|
|
5043
|
-
if (
|
|
8029
|
+
if (schema && finalResponse) {
|
|
5044
8030
|
logger.info("\u{1F527} Attempting structured output conversion...");
|
|
5045
8031
|
try {
|
|
5046
8032
|
let conversionCompleted = false;
|
|
5047
8033
|
let conversionResult = null;
|
|
5048
8034
|
let conversionError = null;
|
|
5049
|
-
this._attemptStructuredOutput(
|
|
5050
|
-
finalResponse,
|
|
5051
|
-
this.llm,
|
|
5052
|
-
outputSchema
|
|
5053
|
-
).then((result) => {
|
|
8035
|
+
this._attemptStructuredOutput(finalResponse, this.llm, schema).then((result) => {
|
|
5054
8036
|
conversionCompleted = true;
|
|
5055
8037
|
conversionResult = result;
|
|
5056
8038
|
return result;
|
|
@@ -5105,7 +8087,7 @@ var MCPAgent = class {
|
|
|
5105
8087
|
success = true;
|
|
5106
8088
|
} catch (e) {
|
|
5107
8089
|
logger.error(`\u274C Error during streamEvents: ${e}`);
|
|
5108
|
-
if (initializedHere &&
|
|
8090
|
+
if (initializedHere && manage) {
|
|
5109
8091
|
logger.info(
|
|
5110
8092
|
"\u{1F9F9} Cleaning up resources after initialization error in streamEvents"
|
|
5111
8093
|
);
|
|
@@ -5136,15 +8118,15 @@ var MCPAgent = class {
|
|
|
5136
8118
|
maxStepsConfigured: this.maxSteps,
|
|
5137
8119
|
memoryEnabled: this.memoryEnabled,
|
|
5138
8120
|
useServerManager: this.useServerManager,
|
|
5139
|
-
maxStepsUsed:
|
|
5140
|
-
manageConnector,
|
|
5141
|
-
externalHistoryUsed:
|
|
8121
|
+
maxStepsUsed: steps ?? null,
|
|
8122
|
+
manageConnector: manage ?? true,
|
|
8123
|
+
externalHistoryUsed: history !== void 0,
|
|
5142
8124
|
response: `[STREAMED RESPONSE - ${totalResponseLength} chars]`,
|
|
5143
8125
|
executionTimeMs,
|
|
5144
8126
|
errorType: success ? null : "streaming_error",
|
|
5145
8127
|
conversationHistoryLength
|
|
5146
8128
|
});
|
|
5147
|
-
if (
|
|
8129
|
+
if (manage && !this.client && initializedHere) {
|
|
5148
8130
|
logger.info("\u{1F9F9} Closing agent after streamEvents completion");
|
|
5149
8131
|
await this.close();
|
|
5150
8132
|
}
|