mcp-use 1.2.2 → 1.2.3-canary.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,3158 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
9
+ var __esm = (fn, res) => function __init() {
10
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
11
+ };
12
+ var __export = (target, all) => {
13
+ for (var name in all)
14
+ __defProp(target, name, { get: all[name], enumerable: true });
15
+ };
16
+ var __copyProps = (to, from, except, desc) => {
17
+ if (from && typeof from === "object" || typeof from === "function") {
18
+ for (let key of __getOwnPropNames(from))
19
+ if (!__hasOwnProp.call(to, key) && key !== except)
20
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
21
+ }
22
+ return to;
23
+ };
24
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
25
+ // If the importer is in node compatibility mode or this is not an ESM
26
+ // file that has been converted to a CommonJS file using a Babel-
27
+ // compatible transform (i.e. "__esModule" has not been set), then set
28
+ // "default" to the CommonJS "module.exports" for node compatibility.
29
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
30
+ mod
31
+ ));
32
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
33
+
34
+ // src/logging.ts
35
+ async function getNodeModules() {
36
+ if (typeof process !== "undefined" && process.platform) {
37
+ try {
38
+ const fs3 = await import("fs");
39
+ const path3 = await import("path");
40
+ return { fs: fs3.default, path: path3.default };
41
+ } catch {
42
+ return { fs: null, path: null };
43
+ }
44
+ }
45
+ return { fs: null, path: null };
46
+ }
47
+ function isNodeJSEnvironment() {
48
+ try {
49
+ if (typeof navigator !== "undefined" && navigator.userAgent?.includes("Cloudflare-Workers")) {
50
+ return false;
51
+ }
52
+ if (typeof globalThis.EdgeRuntime !== "undefined" || typeof globalThis.Deno !== "undefined") {
53
+ return false;
54
+ }
55
+ const hasNodeGlobals = typeof process !== "undefined" && typeof process.platform !== "undefined" && typeof __dirname !== "undefined";
56
+ const hasNodeModules = typeof import_winston.createLogger === "function";
57
+ return hasNodeGlobals && hasNodeModules;
58
+ } catch {
59
+ return false;
60
+ }
61
+ }
62
+ function resolveLevel(env) {
63
+ const envValue = typeof process !== "undefined" && process.env ? env : void 0;
64
+ switch (envValue?.trim()) {
65
+ case "2":
66
+ return "debug";
67
+ case "1":
68
+ return "info";
69
+ default:
70
+ return "info";
71
+ }
72
+ }
73
+ var import_winston, combine, timestamp, label, printf, colorize, splat, DEFAULT_LOGGER_NAME, SimpleConsoleLogger, minimalFormatter, detailedFormatter, emojiFormatter, Logger, logger;
74
+ var init_logging = __esm({
75
+ "src/logging.ts"() {
76
+ "use strict";
77
+ import_winston = require("winston");
78
+ __name(getNodeModules, "getNodeModules");
79
+ ({ combine, timestamp, label, printf, colorize, splat } = import_winston.format);
80
+ DEFAULT_LOGGER_NAME = "mcp-use";
81
+ __name(isNodeJSEnvironment, "isNodeJSEnvironment");
82
+ SimpleConsoleLogger = class {
83
+ static {
84
+ __name(this, "SimpleConsoleLogger");
85
+ }
86
+ _level;
87
+ name;
88
+ constructor(name = DEFAULT_LOGGER_NAME, level = "info") {
89
+ this.name = name;
90
+ this._level = level;
91
+ }
92
+ shouldLog(level) {
93
+ const levels = [
94
+ "error",
95
+ "warn",
96
+ "info",
97
+ "http",
98
+ "verbose",
99
+ "debug",
100
+ "silly"
101
+ ];
102
+ const currentIndex = levels.indexOf(this._level);
103
+ const messageIndex = levels.indexOf(level);
104
+ return messageIndex <= currentIndex;
105
+ }
106
+ formatMessage(level, message) {
107
+ const timestamp2 = (/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", { hour12: false });
108
+ return `${timestamp2} [${this.name}] ${level}: ${message}`;
109
+ }
110
+ error(message) {
111
+ if (this.shouldLog("error")) {
112
+ console.error(this.formatMessage("error", message));
113
+ }
114
+ }
115
+ warn(message) {
116
+ if (this.shouldLog("warn")) {
117
+ console.warn(this.formatMessage("warn", message));
118
+ }
119
+ }
120
+ info(message) {
121
+ if (this.shouldLog("info")) {
122
+ console.info(this.formatMessage("info", message));
123
+ }
124
+ }
125
+ debug(message) {
126
+ if (this.shouldLog("debug")) {
127
+ console.debug(this.formatMessage("debug", message));
128
+ }
129
+ }
130
+ http(message) {
131
+ if (this.shouldLog("http")) {
132
+ console.log(this.formatMessage("http", message));
133
+ }
134
+ }
135
+ verbose(message) {
136
+ if (this.shouldLog("verbose")) {
137
+ console.log(this.formatMessage("verbose", message));
138
+ }
139
+ }
140
+ silly(message) {
141
+ if (this.shouldLog("silly")) {
142
+ console.log(this.formatMessage("silly", message));
143
+ }
144
+ }
145
+ // Make it compatible with Winston interface
146
+ get level() {
147
+ return this._level;
148
+ }
149
+ set level(newLevel) {
150
+ this._level = newLevel;
151
+ }
152
+ };
153
+ __name(resolveLevel, "resolveLevel");
154
+ minimalFormatter = printf(({ level, message, label: label2, timestamp: timestamp2 }) => {
155
+ return `${timestamp2} [${label2}] ${level}: ${message}`;
156
+ });
157
+ detailedFormatter = printf(({ level, message, label: label2, timestamp: timestamp2 }) => {
158
+ return `${timestamp2} [${label2}] ${level.toUpperCase()}: ${message}`;
159
+ });
160
+ emojiFormatter = printf(({ level, message, label: label2, timestamp: timestamp2 }) => {
161
+ return `${timestamp2} [${label2}] ${level.toUpperCase()}: ${message}`;
162
+ });
163
+ Logger = class {
164
+ static {
165
+ __name(this, "Logger");
166
+ }
167
+ static instances = {};
168
+ static simpleInstances = {};
169
+ static currentFormat = "minimal";
170
+ static get(name = DEFAULT_LOGGER_NAME) {
171
+ if (!isNodeJSEnvironment()) {
172
+ if (!this.simpleInstances[name]) {
173
+ const debugEnv = typeof process !== "undefined" && process.env?.DEBUG || void 0;
174
+ this.simpleInstances[name] = new SimpleConsoleLogger(
175
+ name,
176
+ resolveLevel(debugEnv)
177
+ );
178
+ }
179
+ return this.simpleInstances[name];
180
+ }
181
+ if (!this.instances[name]) {
182
+ this.instances[name] = (0, import_winston.createLogger)({
183
+ level: resolveLevel(process.env.DEBUG),
184
+ format: combine(
185
+ colorize(),
186
+ splat(),
187
+ label({ label: name }),
188
+ timestamp({ format: "HH:mm:ss" }),
189
+ this.getFormatter()
190
+ ),
191
+ transports: []
192
+ });
193
+ }
194
+ return this.instances[name];
195
+ }
196
+ static getFormatter() {
197
+ switch (this.currentFormat) {
198
+ case "minimal":
199
+ return minimalFormatter;
200
+ case "detailed":
201
+ return detailedFormatter;
202
+ case "emoji":
203
+ return emojiFormatter;
204
+ default:
205
+ return minimalFormatter;
206
+ }
207
+ }
208
+ static async configure(options = {}) {
209
+ const { level, console: console2 = true, file, format: format2 = "minimal" } = options;
210
+ const debugEnv = typeof process !== "undefined" && process.env?.DEBUG || void 0;
211
+ const resolvedLevel = level ?? resolveLevel(debugEnv);
212
+ this.currentFormat = format2;
213
+ const root = this.get();
214
+ root.level = resolvedLevel;
215
+ const winstonRoot = root;
216
+ if (!isNodeJSEnvironment()) {
217
+ Object.values(this.simpleInstances).forEach((logger2) => {
218
+ logger2.level = resolvedLevel;
219
+ });
220
+ return;
221
+ }
222
+ winstonRoot.clear();
223
+ if (console2) {
224
+ winstonRoot.add(new import_winston.transports.Console());
225
+ }
226
+ if (file) {
227
+ const { fs: nodeFs, path: nodePath } = await getNodeModules();
228
+ if (nodeFs && nodePath) {
229
+ const dir = nodePath.dirname(nodePath.resolve(file));
230
+ if (!nodeFs.existsSync(dir)) {
231
+ nodeFs.mkdirSync(dir, { recursive: true });
232
+ }
233
+ winstonRoot.add(new import_winston.transports.File({ filename: file }));
234
+ }
235
+ }
236
+ Object.values(this.instances).forEach((logger2) => {
237
+ if (logger2 && "format" in logger2) {
238
+ logger2.level = resolvedLevel;
239
+ logger2.format = combine(
240
+ colorize(),
241
+ splat(),
242
+ label({ label: DEFAULT_LOGGER_NAME }),
243
+ timestamp({ format: "HH:mm:ss" }),
244
+ this.getFormatter()
245
+ );
246
+ }
247
+ });
248
+ }
249
+ static setDebug(enabled) {
250
+ let level;
251
+ if (enabled === 2 || enabled === true) level = "debug";
252
+ else if (enabled === 1) level = "info";
253
+ else level = "info";
254
+ Object.values(this.simpleInstances).forEach((logger2) => {
255
+ logger2.level = level;
256
+ });
257
+ Object.values(this.instances).forEach((logger2) => {
258
+ if (logger2) {
259
+ logger2.level = level;
260
+ }
261
+ });
262
+ if (typeof process !== "undefined" && process.env) {
263
+ process.env.DEBUG = enabled ? enabled === true ? "2" : String(enabled) : "0";
264
+ }
265
+ }
266
+ static setFormat(format2) {
267
+ this.currentFormat = format2;
268
+ this.configure({ format: format2 });
269
+ }
270
+ };
271
+ if (isNodeJSEnvironment()) {
272
+ Logger.configure();
273
+ } else {
274
+ Logger.configure({ console: true });
275
+ }
276
+ logger = Logger.get();
277
+ }
278
+ });
279
+
280
+ // src/observability/langfuse.ts
281
+ var langfuse_exports = {};
282
+ __export(langfuse_exports, {
283
+ initializeLangfuse: () => initializeLangfuse,
284
+ langfuseClient: () => langfuseClient,
285
+ langfuseHandler: () => langfuseHandler,
286
+ langfuseInitPromise: () => langfuseInitPromise
287
+ });
288
+ async function initializeLangfuse(agentId, metadata, metadataProvider, tagsProvider) {
289
+ try {
290
+ const langfuseModule = await import("langfuse-langchain").catch(() => null);
291
+ if (!langfuseModule) {
292
+ logger.debug(
293
+ "Langfuse package not installed - tracing disabled. Install with: npm install @langfuse/langchain"
294
+ );
295
+ return;
296
+ }
297
+ const { CallbackHandler } = langfuseModule;
298
+ class LoggingCallbackHandler extends CallbackHandler {
299
+ static {
300
+ __name(this, "LoggingCallbackHandler");
301
+ }
302
+ agentId;
303
+ metadata;
304
+ metadataProvider;
305
+ tagsProvider;
306
+ verbose;
307
+ constructor(config3, agentId2, metadata2, metadataProvider2, tagsProvider2) {
308
+ super(config3);
309
+ this.agentId = agentId2;
310
+ this.metadata = metadata2;
311
+ this.metadataProvider = metadataProvider2;
312
+ this.tagsProvider = tagsProvider2;
313
+ this.verbose = config3?.verbose ?? false;
314
+ }
315
+ // Override to add custom metadata to traces
316
+ async handleChainStart(chain, inputs, runId, parentRunId, tags, metadata2, name, kwargs) {
317
+ logger.debug("Langfuse: Chain start intercepted");
318
+ const customTags = this.getCustomTags();
319
+ const metadataToAdd = this.getMetadata();
320
+ const enhancedTags = [...tags || [], ...customTags];
321
+ const enhancedMetadata = { ...metadata2 || {}, ...metadataToAdd };
322
+ if (this.verbose) {
323
+ logger.debug(
324
+ `Langfuse: Chain start with custom tags: ${JSON.stringify(enhancedTags)}`
325
+ );
326
+ logger.debug(
327
+ `Langfuse: Chain start with metadata: ${JSON.stringify(enhancedMetadata)}`
328
+ );
329
+ }
330
+ return super.handleChainStart(
331
+ chain,
332
+ inputs,
333
+ runId,
334
+ parentRunId,
335
+ enhancedTags,
336
+ enhancedMetadata,
337
+ name,
338
+ kwargs
339
+ );
340
+ }
341
+ // Get custom tags based on environment and agent configuration
342
+ getCustomTags() {
343
+ const tags = [];
344
+ const env = this.getEnvironmentTag();
345
+ if (env) {
346
+ tags.push(`env:${env}`);
347
+ }
348
+ if (this.agentId) {
349
+ tags.push(`agent_id:${this.agentId}`);
350
+ }
351
+ if (this.tagsProvider) {
352
+ const providerTags = this.tagsProvider();
353
+ if (providerTags && providerTags.length > 0) {
354
+ tags.push(...providerTags);
355
+ }
356
+ }
357
+ return tags;
358
+ }
359
+ // Get metadata
360
+ getMetadata() {
361
+ const metadata2 = {};
362
+ const env = this.getEnvironmentTag();
363
+ if (env) {
364
+ metadata2.env = env;
365
+ }
366
+ if (this.agentId) {
367
+ metadata2.agent_id = this.agentId;
368
+ }
369
+ if (this.metadata) {
370
+ Object.assign(metadata2, this.metadata);
371
+ }
372
+ if (this.metadataProvider) {
373
+ const dynamicMetadata = this.metadataProvider();
374
+ if (dynamicMetadata) {
375
+ Object.assign(metadata2, dynamicMetadata);
376
+ }
377
+ }
378
+ return metadata2;
379
+ }
380
+ // Determine environment tag based on MCP_USE_AGENT_ENV
381
+ getEnvironmentTag() {
382
+ const agentEnv = process.env.MCP_USE_AGENT_ENV;
383
+ if (!agentEnv) {
384
+ return "unknown";
385
+ }
386
+ const envLower = agentEnv.toLowerCase();
387
+ if (envLower === "local" || envLower === "development") {
388
+ return "local";
389
+ } else if (envLower === "production" || envLower === "prod") {
390
+ return "production";
391
+ } else if (envLower === "staging" || envLower === "stage") {
392
+ return "staging";
393
+ } else if (envLower === "hosted" || envLower === "cloud") {
394
+ return "hosted";
395
+ }
396
+ return envLower.replace(/[^a-z0-9_-]/g, "_");
397
+ }
398
+ async handleLLMStart(...args) {
399
+ logger.debug("Langfuse: LLM start intercepted");
400
+ if (this.verbose) {
401
+ logger.debug(`Langfuse: LLM start args: ${JSON.stringify(args)}`);
402
+ }
403
+ return super.handleLLMStart(...args);
404
+ }
405
+ async handleToolStart(...args) {
406
+ logger.debug("Langfuse: Tool start intercepted");
407
+ if (this.verbose) {
408
+ logger.debug(`Langfuse: Tool start args: ${JSON.stringify(args)}`);
409
+ }
410
+ return super.handleToolStart(...args);
411
+ }
412
+ async handleRetrieverStart(...args) {
413
+ logger.debug("Langfuse: Retriever start intercepted");
414
+ if (this.verbose) {
415
+ logger.debug(
416
+ `Langfuse: Retriever start args: ${JSON.stringify(args)}`
417
+ );
418
+ }
419
+ return super.handleRetrieverStart(...args);
420
+ }
421
+ async handleAgentAction(...args) {
422
+ logger.debug("Langfuse: Agent action intercepted");
423
+ if (this.verbose) {
424
+ logger.debug(`Langfuse: Agent action args: ${JSON.stringify(args)}`);
425
+ }
426
+ return super.handleAgentAction(...args);
427
+ }
428
+ async handleAgentEnd(...args) {
429
+ logger.debug("Langfuse: Agent end intercepted");
430
+ if (this.verbose) {
431
+ logger.debug(`Langfuse: Agent end args: ${JSON.stringify(args)}`);
432
+ }
433
+ return super.handleAgentEnd(...args);
434
+ }
435
+ }
436
+ const initialMetadata = metadata || (metadataProvider ? metadataProvider() : {});
437
+ const initialTags = tagsProvider ? tagsProvider() : [];
438
+ const config2 = {
439
+ publicKey: process.env.LANGFUSE_PUBLIC_KEY,
440
+ secretKey: process.env.LANGFUSE_SECRET_KEY,
441
+ baseUrl: process.env.LANGFUSE_HOST || process.env.LANGFUSE_BASEURL || "https://cloud.langfuse.com",
442
+ flushAt: Number.parseInt(process.env.LANGFUSE_FLUSH_AT || "15"),
443
+ flushInterval: Number.parseInt(
444
+ process.env.LANGFUSE_FLUSH_INTERVAL || "10000"
445
+ ),
446
+ release: process.env.LANGFUSE_RELEASE,
447
+ requestTimeout: Number.parseInt(
448
+ process.env.LANGFUSE_REQUEST_TIMEOUT || "10000"
449
+ ),
450
+ enabled: process.env.LANGFUSE_ENABLED !== "false",
451
+ // Set trace name - can be customized via metadata.trace_name or defaults to 'mcp-use-agent'
452
+ traceName: initialMetadata.trace_name || process.env.LANGFUSE_TRACE_NAME || "mcp-use-agent",
453
+ // Pass sessionId, userId, and tags to the handler
454
+ sessionId: initialMetadata.session_id || void 0,
455
+ userId: initialMetadata.user_id || void 0,
456
+ tags: initialTags.length > 0 ? initialTags : void 0,
457
+ metadata: initialMetadata || void 0
458
+ };
459
+ logger.debug(
460
+ "Langfuse handler config:",
461
+ JSON.stringify(
462
+ {
463
+ traceName: config2.traceName,
464
+ sessionId: config2.sessionId,
465
+ userId: config2.userId,
466
+ tags: config2.tags
467
+ },
468
+ null,
469
+ 2
470
+ )
471
+ );
472
+ langfuseState.handler = new LoggingCallbackHandler(
473
+ config2,
474
+ agentId,
475
+ metadata,
476
+ metadataProvider,
477
+ tagsProvider
478
+ );
479
+ logger.debug(
480
+ "Langfuse observability initialized successfully with logging enabled"
481
+ );
482
+ try {
483
+ const langfuseCore = await import("langfuse").catch(() => null);
484
+ if (langfuseCore) {
485
+ const { Langfuse } = langfuseCore;
486
+ langfuseState.client = new Langfuse({
487
+ publicKey: process.env.LANGFUSE_PUBLIC_KEY,
488
+ secretKey: process.env.LANGFUSE_SECRET_KEY,
489
+ baseUrl: process.env.LANGFUSE_HOST || "https://cloud.langfuse.com"
490
+ });
491
+ logger.debug("Langfuse client initialized");
492
+ }
493
+ } catch (error) {
494
+ logger.debug(`Langfuse client initialization failed: ${error}`);
495
+ }
496
+ } catch (error) {
497
+ logger.debug(`Langfuse initialization error: ${error}`);
498
+ }
499
+ }
500
+ var import_dotenv, langfuseDisabled, langfuseState, langfuseHandler, langfuseClient, langfuseInitPromise;
501
+ var init_langfuse = __esm({
502
+ "src/observability/langfuse.ts"() {
503
+ "use strict";
504
+ import_dotenv = require("dotenv");
505
+ init_logging();
506
+ (0, import_dotenv.config)();
507
+ langfuseDisabled = process.env.MCP_USE_LANGFUSE?.toLowerCase() === "false";
508
+ langfuseState = {
509
+ handler: null,
510
+ client: null,
511
+ initPromise: null
512
+ };
513
+ __name(initializeLangfuse, "initializeLangfuse");
514
+ if (langfuseDisabled) {
515
+ logger.debug(
516
+ "Langfuse tracing disabled via MCP_USE_LANGFUSE environment variable"
517
+ );
518
+ } else if (!process.env.LANGFUSE_PUBLIC_KEY || !process.env.LANGFUSE_SECRET_KEY) {
519
+ logger.debug(
520
+ "Langfuse API keys not found - tracing disabled. Set LANGFUSE_PUBLIC_KEY and LANGFUSE_SECRET_KEY to enable"
521
+ );
522
+ } else {
523
+ langfuseState.initPromise = initializeLangfuse();
524
+ }
525
+ langfuseHandler = /* @__PURE__ */ __name(() => langfuseState.handler, "langfuseHandler");
526
+ langfuseClient = /* @__PURE__ */ __name(() => langfuseState.client, "langfuseClient");
527
+ langfuseInitPromise = /* @__PURE__ */ __name(() => langfuseState.initPromise, "langfuseInitPromise");
528
+ }
529
+ });
530
+
531
+ // src/agents/index.ts
532
+ var agents_exports = {};
533
+ __export(agents_exports, {
534
+ BaseAgent: () => BaseAgent,
535
+ MCPAgent: () => MCPAgent,
536
+ RemoteAgent: () => RemoteAgent
537
+ });
538
+ module.exports = __toCommonJS(agents_exports);
539
+
540
+ // src/agents/base.ts
541
+ var BaseAgent = class {
542
+ static {
543
+ __name(this, "BaseAgent");
544
+ }
545
+ session;
546
+ /**
547
+ * @param session MCP session used for tool invocation
548
+ */
549
+ constructor(session) {
550
+ this.session = session;
551
+ }
552
+ };
553
+
554
+ // src/agents/mcp_agent.ts
555
+ var import_langchain2 = require("langchain");
556
+ var import_zod_to_json_schema2 = require("zod-to-json-schema");
557
+
558
+ // src/adapters/langchain_adapter.ts
559
+ var import_json_schema_to_zod = require("@dmitryrechkin/json-schema-to-zod");
560
+ var import_tools = require("@langchain/core/tools");
561
+ var import_zod = require("zod");
562
+ init_logging();
563
+
564
+ // src/adapters/base.ts
565
+ init_logging();
566
+ var BaseAdapter = class {
567
+ static {
568
+ __name(this, "BaseAdapter");
569
+ }
570
+ /**
571
+ * List of tool names that should not be available.
572
+ */
573
+ disallowedTools;
574
+ /**
575
+ * Internal cache that maps a connector instance to the list of tools
576
+ * generated for it.
577
+ */
578
+ connectorToolMap = /* @__PURE__ */ new Map();
579
+ constructor(disallowedTools) {
580
+ this.disallowedTools = disallowedTools ?? [];
581
+ }
582
+ /**
583
+ * Create tools from an MCPClient instance.
584
+ *
585
+ * This is the recommended way to create tools from an MCPClient, as it handles
586
+ * session creation and connector extraction automatically.
587
+ *
588
+ * @param client The MCPClient to extract tools from.
589
+ * @param disallowedTools Optional list of tool names to exclude.
590
+ * @returns A promise that resolves with a list of converted tools.
591
+ */
592
+ static async createTools(client, disallowedTools) {
593
+ const adapter = new this(disallowedTools);
594
+ if (!client.activeSessions || Object.keys(client.activeSessions).length === 0) {
595
+ logger.info("No active sessions found, creating new ones...");
596
+ await client.createAllSessions();
597
+ }
598
+ const sessions = client.getAllActiveSessions();
599
+ const connectors = Object.values(sessions).map(
600
+ (session) => session.connector
601
+ );
602
+ return adapter.createToolsFromConnectors(connectors);
603
+ }
604
+ /**
605
+ * Dynamically load tools for a specific connector.
606
+ *
607
+ * @param connector The connector to load tools for.
608
+ * @returns The list of tools that were loaded in the target framework's format.
609
+ */
610
+ async loadToolsForConnector(connector) {
611
+ if (this.connectorToolMap.has(connector)) {
612
+ const cached = this.connectorToolMap.get(connector);
613
+ logger.debug(`Returning ${cached.length} existing tools for connector`);
614
+ return cached;
615
+ }
616
+ const connectorTools = [];
617
+ const success = await this.ensureConnectorInitialized(connector);
618
+ if (!success) {
619
+ return [];
620
+ }
621
+ for (const tool of connector.tools) {
622
+ const converted = this.convertTool(tool, connector);
623
+ if (converted) {
624
+ connectorTools.push(converted);
625
+ }
626
+ }
627
+ this.connectorToolMap.set(connector, connectorTools);
628
+ logger.debug(
629
+ `Loaded ${connectorTools.length} new tools for connector: ${connectorTools.map((t) => t?.name ?? String(t)).join(", ")}`
630
+ );
631
+ return connectorTools;
632
+ }
633
+ /**
634
+ * Create tools from MCP tools in all provided connectors.
635
+ *
636
+ * @param connectors List of MCP connectors to create tools from.
637
+ * @returns A promise that resolves with all converted tools.
638
+ */
639
+ async createToolsFromConnectors(connectors) {
640
+ const tools = [];
641
+ for (const connector of connectors) {
642
+ const connectorTools = await this.loadToolsForConnector(connector);
643
+ tools.push(...connectorTools);
644
+ }
645
+ logger.debug(`Available tools: ${tools.length}`);
646
+ return tools;
647
+ }
648
+ /**
649
+ * Check if a connector is initialized and has tools.
650
+ *
651
+ * @param connector The connector to check.
652
+ * @returns True if the connector is initialized and has tools, false otherwise.
653
+ */
654
+ checkConnectorInitialized(connector) {
655
+ return Boolean(connector.tools && connector.tools.length);
656
+ }
657
+ /**
658
+ * Ensure a connector is initialized.
659
+ *
660
+ * @param connector The connector to initialize.
661
+ * @returns True if initialization succeeded, false otherwise.
662
+ */
663
+ async ensureConnectorInitialized(connector) {
664
+ if (!this.checkConnectorInitialized(connector)) {
665
+ logger.debug("Connector doesn't have tools, initializing it");
666
+ try {
667
+ await connector.initialize();
668
+ return true;
669
+ } catch (err) {
670
+ logger.error(`Error initializing connector: ${err}`);
671
+ return false;
672
+ }
673
+ }
674
+ return true;
675
+ }
676
+ };
677
+
678
+ // src/adapters/langchain_adapter.ts
679
+ function schemaToZod(schema) {
680
+ try {
681
+ return import_json_schema_to_zod.JSONSchemaToZod.convert(schema);
682
+ } catch (err) {
683
+ logger.warn(`Failed to convert JSON schema to Zod: ${err}`);
684
+ return import_zod.z.any();
685
+ }
686
+ }
687
+ __name(schemaToZod, "schemaToZod");
688
+ var LangChainAdapter = class extends BaseAdapter {
689
+ static {
690
+ __name(this, "LangChainAdapter");
691
+ }
692
+ constructor(disallowedTools = []) {
693
+ super(disallowedTools);
694
+ }
695
+ /**
696
+ * Convert a single MCP tool specification into a LangChainJS structured tool.
697
+ */
698
+ convertTool(mcpTool, connector) {
699
+ if (this.disallowedTools.includes(mcpTool.name)) {
700
+ return null;
701
+ }
702
+ const argsSchema = mcpTool.inputSchema ? schemaToZod(mcpTool.inputSchema) : import_zod.z.object({}).optional();
703
+ const tool = new import_tools.DynamicStructuredTool({
704
+ name: mcpTool.name ?? "NO NAME",
705
+ description: mcpTool.description ?? "",
706
+ // Blank is acceptable but discouraged.
707
+ schema: argsSchema,
708
+ func: /* @__PURE__ */ __name(async (input) => {
709
+ logger.debug(
710
+ `MCP tool "${mcpTool.name}" received input: ${JSON.stringify(input)}`
711
+ );
712
+ try {
713
+ const result = await connector.callTool(
714
+ mcpTool.name,
715
+ input
716
+ );
717
+ return JSON.stringify(result);
718
+ } catch (err) {
719
+ logger.error(`Error executing MCP tool: ${err.message}`);
720
+ return `Error executing MCP tool: ${String(err)}`;
721
+ }
722
+ }, "func")
723
+ });
724
+ return tool;
725
+ }
726
+ };
727
+
728
+ // src/agents/mcp_agent.ts
729
+ init_logging();
730
+
731
+ // src/managers/server_manager.ts
732
+ var import_lodash_es = require("lodash-es");
733
+ init_logging();
734
+
735
+ // src/managers/tools/acquire_active_mcp_server.ts
736
+ var import_zod2 = require("zod");
737
+
738
+ // src/managers/tools/base.ts
739
+ var import_tools2 = require("@langchain/core/tools");
740
+ var MCPServerTool = class extends import_tools2.StructuredTool {
741
+ static {
742
+ __name(this, "MCPServerTool");
743
+ }
744
+ name = "mcp_server_tool";
745
+ description = "Base tool for MCP server operations.";
746
+ schema;
747
+ _manager;
748
+ constructor(manager) {
749
+ super();
750
+ this._manager = manager;
751
+ }
752
+ async _call(_arg, _runManager, _parentConfig) {
753
+ throw new Error("Method not implemented.");
754
+ }
755
+ get manager() {
756
+ return this._manager;
757
+ }
758
+ };
759
+
760
+ // src/managers/tools/acquire_active_mcp_server.ts
761
+ var PresentActiveServerSchema = import_zod2.z.object({});
762
+ var AcquireActiveMCPServerTool = class extends MCPServerTool {
763
+ static {
764
+ __name(this, "AcquireActiveMCPServerTool");
765
+ }
766
+ name = "get_active_mcp_server";
767
+ description = "Get the currently active MCP (Model Context Protocol) server";
768
+ schema = PresentActiveServerSchema;
769
+ constructor(manager) {
770
+ super(manager);
771
+ }
772
+ async _call() {
773
+ if (!this.manager.activeServer) {
774
+ return `No MCP server is currently active. Use connect_to_mcp_server to connect to a server.`;
775
+ }
776
+ return `Currently active MCP server: ${this.manager.activeServer}`;
777
+ }
778
+ };
779
+
780
+ // src/managers/tools/add_server_from_config.ts
781
+ var import_tools3 = require("@langchain/core/tools");
782
+ var import_zod3 = require("zod");
783
+ init_logging();
784
+ var AddMCPServerFromConfigTool = class extends import_tools3.StructuredTool {
785
+ static {
786
+ __name(this, "AddMCPServerFromConfigTool");
787
+ }
788
+ name = "add_mcp_server_from_config";
789
+ description = "Adds a new MCP server to the client from a configuration object and connects to it, making its tools available.";
790
+ schema = import_zod3.z.object({
791
+ serverName: import_zod3.z.string().describe("The name for the new MCP server."),
792
+ serverConfig: import_zod3.z.any().describe(
793
+ 'The configuration object for the server. This should not include the top-level "mcpServers" key.'
794
+ )
795
+ });
796
+ manager;
797
+ constructor(manager) {
798
+ super();
799
+ this.manager = manager;
800
+ }
801
+ async _call({
802
+ serverName,
803
+ serverConfig
804
+ }) {
805
+ try {
806
+ this.manager.client.addServer(serverName, serverConfig);
807
+ let result = `Server '${serverName}' added to the client.`;
808
+ logger.debug(
809
+ `Connecting to new server '${serverName}' and discovering tools.`
810
+ );
811
+ const session = await this.manager.client.createSession(serverName);
812
+ const connector = session.connector;
813
+ const tools = await this.manager.adapter.createToolsFromConnectors([connector]);
814
+ this.manager.serverTools[serverName] = tools;
815
+ this.manager.initializedServers[serverName] = true;
816
+ this.manager.activeServer = serverName;
817
+ const numTools = tools.length;
818
+ result += ` Session created and connected. '${serverName}' is now the active server with ${numTools} tools available.`;
819
+ result += `
820
+
821
+ ${tools.map((t) => t.name).join("\n")}`;
822
+ logger.info(result);
823
+ return result;
824
+ } catch (e) {
825
+ logger.error(
826
+ `Failed to add or connect to server '${serverName}': ${e.message}`
827
+ );
828
+ return `Failed to add or connect to server '${serverName}': ${e.message}`;
829
+ }
830
+ }
831
+ };
832
+
833
+ // src/managers/tools/connect_mcp_server.ts
834
+ var import_zod4 = require("zod");
835
+ init_logging();
836
+ var ConnectMCPServerSchema = import_zod4.z.object({
837
+ serverName: import_zod4.z.string().describe("The name of the MCP server.")
838
+ });
839
+ var ConnectMCPServerTool = class extends MCPServerTool {
840
+ static {
841
+ __name(this, "ConnectMCPServerTool");
842
+ }
843
+ name = "connect_to_mcp_server";
844
+ description = "Connect to a specific MCP (Model Context Protocol) server to use its tools. Use this tool to connect to a specific server and use its tools.";
845
+ schema = ConnectMCPServerSchema;
846
+ constructor(manager) {
847
+ super(manager);
848
+ }
849
+ async _call({ serverName }) {
850
+ const serverNames = this.manager.client.getServerNames();
851
+ if (!serverNames.includes(serverName)) {
852
+ const available = serverNames.length > 0 ? serverNames.join(", ") : "none";
853
+ return `Server '${serverName}' not found. Available servers: ${available}`;
854
+ }
855
+ if (this.manager.activeServer === serverName) {
856
+ return `Already connected to MCP server '${serverName}'`;
857
+ }
858
+ try {
859
+ let session = this.manager.client.getSession(serverName);
860
+ logger.debug(`Using existing session for server '${serverName}'`);
861
+ if (!session) {
862
+ logger.debug(`Creating new session for server '${serverName}'`);
863
+ session = await this.manager.client.createSession(serverName);
864
+ }
865
+ this.manager.activeServer = serverName;
866
+ if (this.manager.serverTools[serverName]) {
867
+ const connector = session.connector;
868
+ const tools = await this.manager.adapter.createToolsFromConnectors([connector]);
869
+ this.manager.serverTools[serverName] = tools;
870
+ this.manager.initializedServers[serverName] = true;
871
+ }
872
+ const serverTools = this.manager.serverTools[serverName] || [];
873
+ const numTools = serverTools.length;
874
+ return `Connected to MCP server '${serverName}'. ${numTools} tools are now available.`;
875
+ } catch (error) {
876
+ logger.error(
877
+ `Error connecting to server '${serverName}': ${String(error)}`
878
+ );
879
+ return `Failed to connect to server '${serverName}': ${String(error)}`;
880
+ }
881
+ }
882
+ };
883
+
884
+ // src/managers/tools/list_mcp_servers.ts
885
+ var import_zod5 = require("zod");
886
+ init_logging();
887
+ var EnumerateServersSchema = import_zod5.z.object({});
888
+ var ListMCPServersTool = class extends MCPServerTool {
889
+ static {
890
+ __name(this, "ListMCPServersTool");
891
+ }
892
+ name = "list_mcp_servers";
893
+ description = `Lists all available MCP (Model Context Protocol) servers that can be connected to, along with the tools available on each server. Use this tool to discover servers and see what functionalities they offer.`;
894
+ schema = EnumerateServersSchema;
895
+ constructor(manager) {
896
+ super(manager);
897
+ }
898
+ async _call() {
899
+ const serverNames = this.manager.client.getServerNames();
900
+ if (serverNames.length === 0) {
901
+ return `No MCP servers are currently defined.`;
902
+ }
903
+ const outputLines = ["Available MCP servers:"];
904
+ for (const serverName of serverNames) {
905
+ const isActiveServer = serverName === this.manager.activeServer;
906
+ const activeFlag = isActiveServer ? " (ACTIVE)" : "";
907
+ outputLines.push(`- ${serverName}${activeFlag}`);
908
+ try {
909
+ const serverTools = this.manager.serverTools?.[serverName] ?? [];
910
+ const numberOfTools = Array.isArray(serverTools) ? serverTools.length : 0;
911
+ outputLines.push(`${numberOfTools} tools available for this server
912
+ `);
913
+ } catch (error) {
914
+ logger.error(
915
+ `Unexpected error listing tools for server '${serverName}': ${String(error)}`
916
+ );
917
+ }
918
+ }
919
+ return outputLines.join("\n");
920
+ }
921
+ };
922
+
923
+ // src/managers/tools/release_mcp_server_connection.ts
924
+ var import_zod6 = require("zod");
925
+ var ReleaseConnectionSchema = import_zod6.z.object({});
926
+ var ReleaseMCPServerConnectionTool = class extends MCPServerTool {
927
+ static {
928
+ __name(this, "ReleaseMCPServerConnectionTool");
929
+ }
930
+ name = "disconnect_from_mcp_server";
931
+ description = "Disconnect from the currently active MCP (Model Context Protocol) server";
932
+ schema = ReleaseConnectionSchema;
933
+ constructor(manager) {
934
+ super(manager);
935
+ }
936
+ async _call() {
937
+ if (!this.manager.activeServer) {
938
+ return `No MCP server is currently active, so there's nothing to disconnect from.`;
939
+ }
940
+ const serverName = this.manager.activeServer;
941
+ this.manager.activeServer = null;
942
+ return `Successfully disconnected from MCP server '${serverName}'.`;
943
+ }
944
+ };
945
+
946
+ // src/managers/server_manager.ts
947
+ var ServerManager = class {
948
+ static {
949
+ __name(this, "ServerManager");
950
+ }
951
+ initializedServers = {};
952
+ serverTools = {};
953
+ client;
954
+ adapter;
955
+ activeServer = null;
956
+ overrideManagementTools;
957
+ constructor(client, adapter, managementTools) {
958
+ this.client = client;
959
+ this.adapter = adapter;
960
+ this.overrideManagementTools = managementTools;
961
+ }
962
+ setManagementTools(tools) {
963
+ this.overrideManagementTools = tools;
964
+ logger.info(
965
+ `Overriding default management tools with a new set of ${tools.length} tools.`
966
+ );
967
+ }
968
+ logState(context) {
969
+ const allServerNames = this.client.getServerNames();
970
+ const activeSessionNames = Object.keys(this.client.getAllActiveSessions());
971
+ if (allServerNames.length === 0) {
972
+ logger.info("Server Manager State: No servers configured.");
973
+ return;
974
+ }
975
+ const tableData = allServerNames.map((name) => ({
976
+ "Server Name": name,
977
+ Connected: activeSessionNames.includes(name) ? "\u2705" : "\u274C",
978
+ Initialized: this.initializedServers[name] ? "\u2705" : "\u274C",
979
+ "Tool Count": this.serverTools[name]?.length ?? 0,
980
+ Active: this.activeServer === name ? "\u2705" : "\u274C"
981
+ }));
982
+ logger.info(`Server Manager State: [${context}]`);
983
+ console.table(tableData);
984
+ }
985
+ initialize() {
986
+ const serverNames = this.client.getServerNames?.();
987
+ if (serverNames.length === 0) {
988
+ logger.warn("No MCP servers defined in client configuration");
989
+ }
990
+ }
991
+ async prefetchServerTools() {
992
+ const servers = this.client.getServerNames();
993
+ for (const serverName of servers) {
994
+ try {
995
+ let session = null;
996
+ session = this.client.getSession(serverName);
997
+ logger.debug(
998
+ `Using existing session for server '${serverName}' to prefetch tools.`
999
+ );
1000
+ if (!session) {
1001
+ session = await this.client.createSession(serverName).catch((createSessionError) => {
1002
+ logger.warn(
1003
+ `Could not create session for '${serverName}' during prefetch: ${createSessionError}`
1004
+ );
1005
+ return null;
1006
+ });
1007
+ logger.debug(
1008
+ `Temporarily created session for '${serverName}' to prefetch tools.`
1009
+ );
1010
+ }
1011
+ if (session) {
1012
+ const connector = session.connector;
1013
+ let tools = [];
1014
+ try {
1015
+ tools = await this.adapter.createToolsFromConnectors([connector]);
1016
+ } catch (toolFetchError) {
1017
+ logger.error(
1018
+ `Failed to create tools from connector for server '${serverName}': ${toolFetchError}`
1019
+ );
1020
+ continue;
1021
+ }
1022
+ const cachedTools = this.serverTools[serverName];
1023
+ const toolsChanged = !cachedTools || !(0, import_lodash_es.isEqual)(cachedTools, tools);
1024
+ if (toolsChanged) {
1025
+ this.serverTools[serverName] = tools;
1026
+ this.initializedServers[serverName] = true;
1027
+ logger.debug(
1028
+ `Prefetched ${tools.length} tools for server '${serverName}'.`
1029
+ );
1030
+ } else {
1031
+ logger.debug(
1032
+ `Tools for server '${serverName}' unchanged, using cached version.`
1033
+ );
1034
+ }
1035
+ }
1036
+ } catch (outerError) {
1037
+ logger.error(
1038
+ `Error prefetching tools for server '${serverName}': ${outerError}`
1039
+ );
1040
+ }
1041
+ }
1042
+ }
1043
+ get tools() {
1044
+ if (logger.level === "debug") {
1045
+ this.logState("Providing tools to agent");
1046
+ }
1047
+ const managementTools = this.overrideManagementTools ?? [
1048
+ new AddMCPServerFromConfigTool(this),
1049
+ new ListMCPServersTool(this),
1050
+ new ConnectMCPServerTool(this),
1051
+ new AcquireActiveMCPServerTool(this),
1052
+ new ReleaseMCPServerConnectionTool(this)
1053
+ ];
1054
+ if (this.activeServer && this.serverTools[this.activeServer]) {
1055
+ const activeTools = this.serverTools[this.activeServer];
1056
+ logger.debug(
1057
+ `Adding ${activeTools.length} tools from active server '${this.activeServer}'`
1058
+ );
1059
+ return [...managementTools, ...activeTools];
1060
+ }
1061
+ return managementTools;
1062
+ }
1063
+ };
1064
+
1065
+ // src/observability/index.ts
1066
+ init_langfuse();
1067
+ init_langfuse();
1068
+
1069
+ // src/observability/manager.ts
1070
+ init_logging();
1071
+ var ObservabilityManager = class {
1072
+ static {
1073
+ __name(this, "ObservabilityManager");
1074
+ }
1075
+ customCallbacks;
1076
+ availableHandlers = [];
1077
+ handlerNames = [];
1078
+ initialized = false;
1079
+ verbose;
1080
+ observe;
1081
+ agentId;
1082
+ metadata;
1083
+ metadataProvider;
1084
+ tagsProvider;
1085
+ constructor(config2 = {}) {
1086
+ this.customCallbacks = config2.customCallbacks;
1087
+ this.verbose = config2.verbose ?? false;
1088
+ this.observe = config2.observe ?? true;
1089
+ this.agentId = config2.agentId;
1090
+ this.metadata = config2.metadata;
1091
+ this.metadataProvider = config2.metadataProvider;
1092
+ this.tagsProvider = config2.tagsProvider;
1093
+ }
1094
+ /**
1095
+ * Collect all available observability handlers from configured platforms.
1096
+ */
1097
+ async collectAvailableHandlers() {
1098
+ if (this.initialized) {
1099
+ return;
1100
+ }
1101
+ try {
1102
+ const { langfuseHandler: langfuseHandler2, langfuseInitPromise: langfuseInitPromise2 } = await Promise.resolve().then(() => (init_langfuse(), langfuse_exports));
1103
+ if (this.agentId || this.metadata || this.metadataProvider || this.tagsProvider) {
1104
+ const { initializeLangfuse: initializeLangfuse2 } = await Promise.resolve().then(() => (init_langfuse(), langfuse_exports));
1105
+ await initializeLangfuse2(
1106
+ this.agentId,
1107
+ this.metadata,
1108
+ this.metadataProvider,
1109
+ this.tagsProvider
1110
+ );
1111
+ logger.debug(
1112
+ `ObservabilityManager: Reinitialized Langfuse with agent ID: ${this.agentId}, metadata: ${JSON.stringify(this.metadata)}`
1113
+ );
1114
+ } else {
1115
+ const initPromise = langfuseInitPromise2();
1116
+ if (initPromise) {
1117
+ await initPromise;
1118
+ }
1119
+ }
1120
+ const handler = langfuseHandler2();
1121
+ if (handler) {
1122
+ this.availableHandlers.push(handler);
1123
+ this.handlerNames.push("Langfuse");
1124
+ logger.debug("ObservabilityManager: Langfuse handler available");
1125
+ }
1126
+ } catch {
1127
+ logger.debug("ObservabilityManager: Langfuse module not available");
1128
+ }
1129
+ this.initialized = true;
1130
+ }
1131
+ /**
1132
+ * Get the list of callbacks to use.
1133
+ * @returns List of callbacks - either custom callbacks if provided, or all available observability handlers.
1134
+ */
1135
+ async getCallbacks() {
1136
+ if (!this.observe) {
1137
+ logger.debug(
1138
+ "ObservabilityManager: Observability disabled via observe=false"
1139
+ );
1140
+ return [];
1141
+ }
1142
+ if (this.customCallbacks) {
1143
+ logger.debug(
1144
+ `ObservabilityManager: Using ${this.customCallbacks.length} custom callbacks`
1145
+ );
1146
+ return this.customCallbacks;
1147
+ }
1148
+ await this.collectAvailableHandlers();
1149
+ if (this.availableHandlers.length > 0) {
1150
+ logger.debug(
1151
+ `ObservabilityManager: Using ${this.availableHandlers.length} handlers`
1152
+ );
1153
+ } else {
1154
+ logger.debug("ObservabilityManager: No callbacks configured");
1155
+ }
1156
+ return this.availableHandlers;
1157
+ }
1158
+ /**
1159
+ * Get the names of available handlers.
1160
+ * @returns List of handler names (e.g., ["Langfuse", "Laminar"])
1161
+ */
1162
+ async getHandlerNames() {
1163
+ if (!this.observe) {
1164
+ return [];
1165
+ }
1166
+ if (this.customCallbacks) {
1167
+ return this.customCallbacks.map((cb) => cb.constructor.name);
1168
+ }
1169
+ await this.collectAvailableHandlers();
1170
+ return this.handlerNames;
1171
+ }
1172
+ /**
1173
+ * Check if any callbacks are available.
1174
+ * @returns True if callbacks are available, False otherwise.
1175
+ */
1176
+ async hasCallbacks() {
1177
+ if (!this.observe) {
1178
+ return false;
1179
+ }
1180
+ const callbacks = await this.getCallbacks();
1181
+ return callbacks.length > 0;
1182
+ }
1183
+ /**
1184
+ * Get the current observability status including metadata and tags.
1185
+ * @returns Object containing enabled status, callback count, handler names, metadata, and tags.
1186
+ */
1187
+ async getStatus() {
1188
+ const callbacks = await this.getCallbacks();
1189
+ const handlerNames = await this.getHandlerNames();
1190
+ const currentMetadata = this.metadataProvider ? this.metadataProvider() : this.metadata || {};
1191
+ const currentTags = this.tagsProvider ? this.tagsProvider() : [];
1192
+ return {
1193
+ enabled: this.observe && callbacks.length > 0,
1194
+ callbackCount: callbacks.length,
1195
+ handlerNames,
1196
+ metadata: currentMetadata,
1197
+ tags: currentTags
1198
+ };
1199
+ }
1200
+ /**
1201
+ * Add a callback to the custom callbacks list.
1202
+ * @param callback The callback to add.
1203
+ */
1204
+ addCallback(callback) {
1205
+ if (!this.customCallbacks) {
1206
+ this.customCallbacks = [];
1207
+ }
1208
+ this.customCallbacks.push(callback);
1209
+ logger.debug(
1210
+ `ObservabilityManager: Added custom callback: ${callback.constructor.name}`
1211
+ );
1212
+ }
1213
+ /**
1214
+ * Clear all custom callbacks.
1215
+ */
1216
+ clearCallbacks() {
1217
+ this.customCallbacks = [];
1218
+ logger.debug("ObservabilityManager: Cleared all custom callbacks");
1219
+ }
1220
+ /**
1221
+ * Flush all pending traces to observability platforms.
1222
+ * Important for serverless environments and short-lived processes.
1223
+ */
1224
+ async flush() {
1225
+ const callbacks = await this.getCallbacks();
1226
+ for (const callback of callbacks) {
1227
+ if ("flushAsync" in callback && typeof callback.flushAsync === "function") {
1228
+ await callback.flushAsync();
1229
+ }
1230
+ }
1231
+ logger.debug("ObservabilityManager: All traces flushed");
1232
+ }
1233
+ /**
1234
+ * Shutdown all handlers gracefully (for serverless environments).
1235
+ */
1236
+ async shutdown() {
1237
+ await this.flush();
1238
+ const callbacks = await this.getCallbacks();
1239
+ for (const callback of callbacks) {
1240
+ if ("shutdownAsync" in callback && typeof callback.shutdownAsync === "function") {
1241
+ await callback.shutdownAsync();
1242
+ } else if ("shutdown" in callback && typeof callback.shutdown === "function") {
1243
+ await callback.shutdown();
1244
+ }
1245
+ }
1246
+ logger.debug("ObservabilityManager: All handlers shutdown");
1247
+ }
1248
+ /**
1249
+ * String representation of the ObservabilityManager.
1250
+ */
1251
+ toString() {
1252
+ const names = this.handlerNames;
1253
+ if (names.length > 0) {
1254
+ return `ObservabilityManager(handlers=${names.join(", ")})`;
1255
+ }
1256
+ return "ObservabilityManager(no handlers)";
1257
+ }
1258
+ };
1259
+
1260
+ // src/telemetry/telemetry.ts
1261
+ var fs2 = __toESM(require("fs"), 1);
1262
+ var os = __toESM(require("os"), 1);
1263
+ var path2 = __toESM(require("path"), 1);
1264
+ var import_posthog_node = require("posthog-node");
1265
+ var import_uuid = require("uuid");
1266
+ init_logging();
1267
+
1268
+ // src/telemetry/events.ts
1269
+ var BaseTelemetryEvent = class {
1270
+ static {
1271
+ __name(this, "BaseTelemetryEvent");
1272
+ }
1273
+ };
1274
+ var MCPAgentExecutionEvent = class extends BaseTelemetryEvent {
1275
+ constructor(data) {
1276
+ super();
1277
+ this.data = data;
1278
+ }
1279
+ static {
1280
+ __name(this, "MCPAgentExecutionEvent");
1281
+ }
1282
+ get name() {
1283
+ return "mcp_agent_execution";
1284
+ }
1285
+ get properties() {
1286
+ return {
1287
+ // Core execution info
1288
+ execution_method: this.data.executionMethod,
1289
+ query: this.data.query,
1290
+ query_length: this.data.query.length,
1291
+ success: this.data.success,
1292
+ // Agent configuration
1293
+ model_provider: this.data.modelProvider,
1294
+ model_name: this.data.modelName,
1295
+ server_count: this.data.serverCount,
1296
+ server_identifiers: this.data.serverIdentifiers,
1297
+ total_tools_available: this.data.totalToolsAvailable,
1298
+ tools_available_names: this.data.toolsAvailableNames,
1299
+ max_steps_configured: this.data.maxStepsConfigured,
1300
+ memory_enabled: this.data.memoryEnabled,
1301
+ use_server_manager: this.data.useServerManager,
1302
+ // Execution parameters (always include, even if null)
1303
+ max_steps_used: this.data.maxStepsUsed,
1304
+ manage_connector: this.data.manageConnector,
1305
+ external_history_used: this.data.externalHistoryUsed,
1306
+ // Execution results (always include, even if null)
1307
+ steps_taken: this.data.stepsTaken ?? null,
1308
+ tools_used_count: this.data.toolsUsedCount ?? null,
1309
+ tools_used_names: this.data.toolsUsedNames ?? null,
1310
+ response: this.data.response ?? null,
1311
+ response_length: this.data.response ? this.data.response.length : null,
1312
+ execution_time_ms: this.data.executionTimeMs ?? null,
1313
+ error_type: this.data.errorType ?? null,
1314
+ conversation_history_length: this.data.conversationHistoryLength ?? null
1315
+ };
1316
+ }
1317
+ };
1318
+
1319
+ // src/telemetry/utils.ts
1320
+ var fs = __toESM(require("fs"), 1);
1321
+ var path = __toESM(require("path"), 1);
1322
+ function getPackageVersion() {
1323
+ try {
1324
+ if (typeof __dirname === "undefined" || typeof fs === "undefined") {
1325
+ return "unknown";
1326
+ }
1327
+ const packagePath = path.join(__dirname, "../../package.json");
1328
+ const packageJson = JSON.parse(fs.readFileSync(packagePath, "utf-8"));
1329
+ return packageJson.version || "unknown";
1330
+ } catch {
1331
+ return "unknown";
1332
+ }
1333
+ }
1334
+ __name(getPackageVersion, "getPackageVersion");
1335
+ function getModelProvider(llm) {
1336
+ return llm._llm_type || llm.constructor.name.toLowerCase();
1337
+ }
1338
+ __name(getModelProvider, "getModelProvider");
1339
+ function getModelName(llm) {
1340
+ if ("_identifyingParams" in llm) {
1341
+ const identifyingParams = llm._identifyingParams;
1342
+ if (typeof identifyingParams === "object" && identifyingParams !== null) {
1343
+ for (const key of [
1344
+ "model",
1345
+ "modelName",
1346
+ "model_name",
1347
+ "modelId",
1348
+ "model_id",
1349
+ "deploymentName",
1350
+ "deployment_name"
1351
+ ]) {
1352
+ if (key in identifyingParams) {
1353
+ return String(identifyingParams[key]);
1354
+ }
1355
+ }
1356
+ }
1357
+ }
1358
+ return llm.model || llm.modelName || llm.constructor.name;
1359
+ }
1360
+ __name(getModelName, "getModelName");
1361
+ function extractModelInfo(llm) {
1362
+ return [getModelProvider(llm), getModelName(llm)];
1363
+ }
1364
+ __name(extractModelInfo, "extractModelInfo");
1365
+
1366
+ // src/telemetry/telemetry.ts
1367
+ function isNodeJSEnvironment2() {
1368
+ try {
1369
+ if (typeof navigator !== "undefined" && navigator.userAgent?.includes("Cloudflare-Workers")) {
1370
+ return false;
1371
+ }
1372
+ if (typeof globalThis.EdgeRuntime !== "undefined" || typeof globalThis.Deno !== "undefined") {
1373
+ return false;
1374
+ }
1375
+ const hasNodeGlobals = typeof process !== "undefined" && typeof process.platform !== "undefined" && typeof __dirname !== "undefined";
1376
+ const hasNodeModules = typeof fs2 !== "undefined" && typeof os !== "undefined" && typeof fs2.existsSync === "function";
1377
+ return hasNodeGlobals && hasNodeModules;
1378
+ } catch {
1379
+ return false;
1380
+ }
1381
+ }
1382
+ __name(isNodeJSEnvironment2, "isNodeJSEnvironment");
1383
+ var ScarfEventLogger = class {
1384
+ static {
1385
+ __name(this, "ScarfEventLogger");
1386
+ }
1387
+ endpoint;
1388
+ timeout;
1389
+ constructor(endpoint, timeout = 3e3) {
1390
+ this.endpoint = endpoint;
1391
+ this.timeout = timeout;
1392
+ }
1393
+ async logEvent(properties) {
1394
+ try {
1395
+ const controller = new AbortController();
1396
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
1397
+ const response = await fetch(this.endpoint, {
1398
+ method: "POST",
1399
+ headers: {
1400
+ "Content-Type": "application/json"
1401
+ },
1402
+ body: JSON.stringify(properties),
1403
+ signal: controller.signal
1404
+ });
1405
+ clearTimeout(timeoutId);
1406
+ if (!response.ok) {
1407
+ throw new Error(`HTTP error! status: ${response.status}`);
1408
+ }
1409
+ } catch (error) {
1410
+ logger.debug(`Failed to send Scarf event: ${error}`);
1411
+ }
1412
+ }
1413
+ };
1414
+ function getCacheHome() {
1415
+ if (!isNodeJSEnvironment2()) {
1416
+ return "/tmp/mcp_use_cache";
1417
+ }
1418
+ const envVar = process.env.XDG_CACHE_HOME;
1419
+ if (envVar && path2.isAbsolute(envVar)) {
1420
+ return envVar;
1421
+ }
1422
+ const platform = process.platform;
1423
+ const homeDir = os.homedir();
1424
+ if (platform === "win32") {
1425
+ const appdata = process.env.LOCALAPPDATA || process.env.APPDATA;
1426
+ if (appdata) {
1427
+ return appdata;
1428
+ }
1429
+ return path2.join(homeDir, "AppData", "Local");
1430
+ } else if (platform === "darwin") {
1431
+ return path2.join(homeDir, "Library", "Caches");
1432
+ } else {
1433
+ return path2.join(homeDir, ".cache");
1434
+ }
1435
+ }
1436
+ __name(getCacheHome, "getCacheHome");
1437
+ var Telemetry = class _Telemetry {
1438
+ static {
1439
+ __name(this, "Telemetry");
1440
+ }
1441
+ static instance = null;
1442
+ USER_ID_PATH = path2.join(
1443
+ getCacheHome(),
1444
+ "mcp_use_3",
1445
+ "telemetry_user_id"
1446
+ );
1447
+ VERSION_DOWNLOAD_PATH = path2.join(
1448
+ getCacheHome(),
1449
+ "mcp_use",
1450
+ "download_version"
1451
+ );
1452
+ PROJECT_API_KEY = "phc_lyTtbYwvkdSbrcMQNPiKiiRWrrM1seyKIMjycSvItEI";
1453
+ HOST = "https://eu.i.posthog.com";
1454
+ SCARF_GATEWAY_URL = "https://mcpuse.gateway.scarf.sh/events-ts";
1455
+ UNKNOWN_USER_ID = "UNKNOWN_USER_ID";
1456
+ _currUserId = null;
1457
+ _posthogClient = null;
1458
+ _scarfClient = null;
1459
+ _source = "typescript";
1460
+ constructor() {
1461
+ const isNodeJS = isNodeJSEnvironment2();
1462
+ const telemetryDisabled = typeof process !== "undefined" && process.env?.MCP_USE_ANONYMIZED_TELEMETRY?.toLowerCase() === "false" || false;
1463
+ this._source = typeof process !== "undefined" && process.env?.MCP_USE_TELEMETRY_SOURCE || "typescript";
1464
+ if (telemetryDisabled) {
1465
+ this._posthogClient = null;
1466
+ this._scarfClient = null;
1467
+ logger.debug("Telemetry disabled via environment variable");
1468
+ } else if (!isNodeJS) {
1469
+ this._posthogClient = null;
1470
+ this._scarfClient = null;
1471
+ logger.debug(
1472
+ "Telemetry disabled - non-Node.js environment detected (e.g., Cloudflare Workers)"
1473
+ );
1474
+ } else {
1475
+ logger.info(
1476
+ "Anonymized telemetry enabled. Set MCP_USE_ANONYMIZED_TELEMETRY=false to disable."
1477
+ );
1478
+ try {
1479
+ this._posthogClient = new import_posthog_node.PostHog(this.PROJECT_API_KEY, {
1480
+ host: this.HOST,
1481
+ disableGeoip: false
1482
+ });
1483
+ } catch (e) {
1484
+ logger.warn(`Failed to initialize PostHog telemetry: ${e}`);
1485
+ this._posthogClient = null;
1486
+ }
1487
+ try {
1488
+ this._scarfClient = new ScarfEventLogger(this.SCARF_GATEWAY_URL, 3e3);
1489
+ } catch (e) {
1490
+ logger.warn(`Failed to initialize Scarf telemetry: ${e}`);
1491
+ this._scarfClient = null;
1492
+ }
1493
+ }
1494
+ }
1495
+ static getInstance() {
1496
+ if (!_Telemetry.instance) {
1497
+ _Telemetry.instance = new _Telemetry();
1498
+ }
1499
+ return _Telemetry.instance;
1500
+ }
1501
+ /**
1502
+ * Set the source identifier for telemetry events.
1503
+ * This allows tracking usage from different applications.
1504
+ * @param source - The source identifier (e.g., "my-app", "cli", "vs-code-extension")
1505
+ */
1506
+ setSource(source) {
1507
+ this._source = source;
1508
+ logger.debug(`Telemetry source set to: ${source}`);
1509
+ }
1510
+ /**
1511
+ * Get the current source identifier.
1512
+ */
1513
+ getSource() {
1514
+ return this._source;
1515
+ }
1516
+ get userId() {
1517
+ if (this._currUserId) {
1518
+ return this._currUserId;
1519
+ }
1520
+ if (!isNodeJSEnvironment2()) {
1521
+ this._currUserId = this.UNKNOWN_USER_ID;
1522
+ return this._currUserId;
1523
+ }
1524
+ try {
1525
+ const isFirstTime = !fs2.existsSync(this.USER_ID_PATH);
1526
+ if (isFirstTime) {
1527
+ logger.debug(`Creating user ID path: ${this.USER_ID_PATH}`);
1528
+ fs2.mkdirSync(path2.dirname(this.USER_ID_PATH), { recursive: true });
1529
+ const newUserId = (0, import_uuid.v4)();
1530
+ fs2.writeFileSync(this.USER_ID_PATH, newUserId);
1531
+ this._currUserId = newUserId;
1532
+ logger.debug(`User ID path created: ${this.USER_ID_PATH}`);
1533
+ } else {
1534
+ this._currUserId = fs2.readFileSync(this.USER_ID_PATH, "utf-8").trim();
1535
+ }
1536
+ this.trackPackageDownload({
1537
+ triggered_by: "user_id_property"
1538
+ }).catch((e) => logger.debug(`Failed to track package download: ${e}`));
1539
+ } catch (e) {
1540
+ logger.debug(`Failed to get/create user ID: ${e}`);
1541
+ this._currUserId = this.UNKNOWN_USER_ID;
1542
+ }
1543
+ return this._currUserId;
1544
+ }
1545
+ async capture(event) {
1546
+ if (!this._posthogClient && !this._scarfClient) {
1547
+ return;
1548
+ }
1549
+ if (this._posthogClient) {
1550
+ try {
1551
+ const properties = { ...event.properties };
1552
+ properties.mcp_use_version = getPackageVersion();
1553
+ properties.language = "typescript";
1554
+ properties.source = this._source;
1555
+ this._posthogClient.capture({
1556
+ distinctId: this.userId,
1557
+ event: event.name,
1558
+ properties
1559
+ });
1560
+ } catch (e) {
1561
+ logger.debug(`Failed to track PostHog event ${event.name}: ${e}`);
1562
+ }
1563
+ }
1564
+ if (this._scarfClient) {
1565
+ try {
1566
+ const properties = {};
1567
+ properties.mcp_use_version = getPackageVersion();
1568
+ properties.user_id = this.userId;
1569
+ properties.event = event.name;
1570
+ properties.language = "typescript";
1571
+ properties.source = this._source;
1572
+ await this._scarfClient.logEvent(properties);
1573
+ } catch (e) {
1574
+ logger.debug(`Failed to track Scarf event ${event.name}: ${e}`);
1575
+ }
1576
+ }
1577
+ }
1578
+ async trackPackageDownload(properties) {
1579
+ if (!this._scarfClient) {
1580
+ return;
1581
+ }
1582
+ if (!isNodeJSEnvironment2()) {
1583
+ return;
1584
+ }
1585
+ try {
1586
+ const currentVersion = getPackageVersion();
1587
+ let shouldTrack = false;
1588
+ let firstDownload = false;
1589
+ if (!fs2.existsSync(this.VERSION_DOWNLOAD_PATH)) {
1590
+ shouldTrack = true;
1591
+ firstDownload = true;
1592
+ fs2.mkdirSync(path2.dirname(this.VERSION_DOWNLOAD_PATH), {
1593
+ recursive: true
1594
+ });
1595
+ fs2.writeFileSync(this.VERSION_DOWNLOAD_PATH, currentVersion);
1596
+ } else {
1597
+ const savedVersion = fs2.readFileSync(this.VERSION_DOWNLOAD_PATH, "utf-8").trim();
1598
+ if (currentVersion > savedVersion) {
1599
+ shouldTrack = true;
1600
+ firstDownload = false;
1601
+ fs2.writeFileSync(this.VERSION_DOWNLOAD_PATH, currentVersion);
1602
+ }
1603
+ }
1604
+ if (shouldTrack) {
1605
+ logger.debug(
1606
+ `Tracking package download event with properties: ${JSON.stringify(properties)}`
1607
+ );
1608
+ const eventProperties = { ...properties || {} };
1609
+ eventProperties.mcp_use_version = currentVersion;
1610
+ eventProperties.user_id = this.userId;
1611
+ eventProperties.event = "package_download";
1612
+ eventProperties.first_download = firstDownload;
1613
+ eventProperties.language = "typescript";
1614
+ eventProperties.source = this._source;
1615
+ await this._scarfClient.logEvent(eventProperties);
1616
+ }
1617
+ } catch (e) {
1618
+ logger.debug(`Failed to track Scarf package_download event: ${e}`);
1619
+ }
1620
+ }
1621
+ async trackAgentExecution(data) {
1622
+ const event = new MCPAgentExecutionEvent(data);
1623
+ await this.capture(event);
1624
+ }
1625
+ flush() {
1626
+ if (this._posthogClient) {
1627
+ try {
1628
+ this._posthogClient.flush();
1629
+ logger.debug("PostHog client telemetry queue flushed");
1630
+ } catch (e) {
1631
+ logger.debug(`Failed to flush PostHog client: ${e}`);
1632
+ }
1633
+ }
1634
+ if (this._scarfClient) {
1635
+ logger.debug("Scarf telemetry events sent immediately (no flush needed)");
1636
+ }
1637
+ }
1638
+ shutdown() {
1639
+ if (this._posthogClient) {
1640
+ try {
1641
+ this._posthogClient.shutdown();
1642
+ logger.debug("PostHog client shutdown successfully");
1643
+ } catch (e) {
1644
+ logger.debug(`Error shutting down PostHog client: ${e}`);
1645
+ }
1646
+ }
1647
+ if (this._scarfClient) {
1648
+ logger.debug("Scarf telemetry client shutdown (no action needed)");
1649
+ }
1650
+ }
1651
+ };
1652
+
1653
+ // src/agents/prompts/system_prompt_builder.ts
1654
+ var import_langchain = require("langchain");
1655
+ function generateToolDescriptions(tools, disallowedTools) {
1656
+ const disallowedSet = new Set(disallowedTools ?? []);
1657
+ const descriptions = [];
1658
+ for (const tool of tools) {
1659
+ if (disallowedSet.has(tool.name)) continue;
1660
+ const escaped = tool.description.replace(/\{/g, "{{").replace(/\}/g, "}}");
1661
+ descriptions.push(`- ${tool.name}: ${escaped}`);
1662
+ }
1663
+ return descriptions;
1664
+ }
1665
+ __name(generateToolDescriptions, "generateToolDescriptions");
1666
+ function buildSystemPromptContent(template, toolDescriptionLines, additionalInstructions) {
1667
+ const block = toolDescriptionLines.join("\n");
1668
+ let content;
1669
+ if (template.includes("{tool_descriptions}")) {
1670
+ content = template.replace("{tool_descriptions}", block);
1671
+ } else {
1672
+ console.warn(
1673
+ "`{tool_descriptions}` placeholder not found; appending at end."
1674
+ );
1675
+ content = `${template}
1676
+
1677
+ Available tools:
1678
+ ${block}`;
1679
+ }
1680
+ if (additionalInstructions) {
1681
+ content += `
1682
+
1683
+ ${additionalInstructions}`;
1684
+ }
1685
+ return content;
1686
+ }
1687
+ __name(buildSystemPromptContent, "buildSystemPromptContent");
1688
+ function createSystemMessage(tools, systemPromptTemplate, serverManagerTemplate, useServerManager, disallowedTools, userProvidedPrompt, additionalInstructions) {
1689
+ if (userProvidedPrompt) {
1690
+ return new import_langchain.SystemMessage({ content: userProvidedPrompt });
1691
+ }
1692
+ const template = useServerManager ? serverManagerTemplate : systemPromptTemplate;
1693
+ const toolLines = generateToolDescriptions(tools, disallowedTools);
1694
+ const finalContent = buildSystemPromptContent(
1695
+ template,
1696
+ toolLines,
1697
+ additionalInstructions
1698
+ );
1699
+ return new import_langchain.SystemMessage({ content: finalContent });
1700
+ }
1701
+ __name(createSystemMessage, "createSystemMessage");
1702
+
1703
+ // src/agents/prompts/templates.ts
1704
+ var DEFAULT_SYSTEM_PROMPT_TEMPLATE = `You are a helpful AI assistant.
1705
+ You have access to the following tools:
1706
+
1707
+ {tool_descriptions}
1708
+
1709
+ Use the following format:
1710
+
1711
+ Question: the input question you must answer
1712
+ Thought: you should always think about what to do
1713
+ Action: the action to take, should be one of the available tools
1714
+ Action Input: the input to the action
1715
+ Observation: the result of the action
1716
+ ... (this Thought/Action/Action Input/Observation can repeat N times)
1717
+ Thought: I now know the final answer
1718
+ Final Answer: the final answer to the original input question`;
1719
+ var SERVER_MANAGER_SYSTEM_PROMPT_TEMPLATE = `You are a helpful assistant designed to interact with MCP
1720
+ (Model Context Protocol) servers. You can manage connections to different servers and use the tools
1721
+ provided by the currently active server.
1722
+
1723
+ Important: The available tools change depending on which server is active.
1724
+ If a request requires tools not listed below (e.g., file operations, web browsing,
1725
+ image manipulation), you MUST first connect to the appropriate server using
1726
+ 'connect_to_mcp_server'.
1727
+ Use 'list_mcp_servers' to find the relevant server if you are unsure.
1728
+ Only after successfully connecting and seeing the new tools listed in
1729
+ the response should you attempt to use those server-specific tools.
1730
+ Before attempting a task that requires specific tools, you should
1731
+ ensure you are connected to the correct server and aware of its
1732
+ available tools. If unsure, use 'list_mcp_servers' to see options
1733
+ or 'get_active_mcp_server' to check the current connection.
1734
+
1735
+ When you connect to a server using 'connect_to_mcp_server',
1736
+ you will be informed about the new tools that become available.
1737
+ You can then use these server-specific tools in subsequent steps.
1738
+
1739
+ Here are the tools *currently* available to you (this list includes server management tools and will
1740
+ change when you connect to a server):
1741
+ {tool_descriptions}
1742
+ `;
1743
+
1744
+ // src/agents/remote.ts
1745
+ var import_zod_to_json_schema = require("zod-to-json-schema");
1746
+ init_logging();
1747
+ var API_CHATS_ENDPOINT = "/api/v1/chats";
1748
+ var API_CHAT_EXECUTE_ENDPOINT = "/api/v1/chats/{chat_id}/execute";
1749
+ var RemoteAgent = class {
1750
+ static {
1751
+ __name(this, "RemoteAgent");
1752
+ }
1753
+ agentId;
1754
+ apiKey;
1755
+ baseUrl;
1756
+ chatId = null;
1757
+ constructor(options) {
1758
+ this.agentId = options.agentId;
1759
+ this.baseUrl = options.baseUrl ?? "https://cloud.mcp-use.com";
1760
+ const apiKey = options.apiKey ?? process.env.MCP_USE_API_KEY;
1761
+ if (!apiKey) {
1762
+ throw new Error(
1763
+ "API key is required for remote execution. Please provide it as a parameter or set the MCP_USE_API_KEY environment variable. You can get an API key from https://cloud.mcp-use.com"
1764
+ );
1765
+ }
1766
+ this.apiKey = apiKey;
1767
+ }
1768
+ pydanticToJsonSchema(schema) {
1769
+ return (0, import_zod_to_json_schema.zodToJsonSchema)(schema);
1770
+ }
1771
+ parseStructuredResponse(responseData, outputSchema) {
1772
+ let resultData;
1773
+ if (typeof responseData === "object" && responseData !== null) {
1774
+ if ("result" in responseData) {
1775
+ const outerResult = responseData.result;
1776
+ if (typeof outerResult === "object" && outerResult !== null && "result" in outerResult) {
1777
+ resultData = outerResult.result;
1778
+ } else {
1779
+ resultData = outerResult;
1780
+ }
1781
+ } else {
1782
+ resultData = responseData;
1783
+ }
1784
+ } else if (typeof responseData === "string") {
1785
+ try {
1786
+ resultData = JSON.parse(responseData);
1787
+ } catch {
1788
+ resultData = { content: responseData };
1789
+ }
1790
+ } else {
1791
+ resultData = responseData;
1792
+ }
1793
+ try {
1794
+ return outputSchema.parse(resultData);
1795
+ } catch (e) {
1796
+ logger.warn(`Failed to parse structured output: ${e}`);
1797
+ const schemaShape = outputSchema._def?.shape();
1798
+ if (schemaShape && "content" in schemaShape) {
1799
+ return outputSchema.parse({ content: String(resultData) });
1800
+ }
1801
+ throw e;
1802
+ }
1803
+ }
1804
+ async createChatSession() {
1805
+ const chatPayload = {
1806
+ title: `Remote Agent Session - ${this.agentId}`,
1807
+ agent_id: this.agentId,
1808
+ type: "agent_execution"
1809
+ };
1810
+ const headers = {
1811
+ "Content-Type": "application/json",
1812
+ "x-api-key": this.apiKey
1813
+ };
1814
+ const chatUrl = `${this.baseUrl}${API_CHATS_ENDPOINT}`;
1815
+ logger.info(`\u{1F4DD} Creating chat session for agent ${this.agentId}`);
1816
+ try {
1817
+ const response = await fetch(chatUrl, {
1818
+ method: "POST",
1819
+ headers,
1820
+ body: JSON.stringify(chatPayload)
1821
+ });
1822
+ if (!response.ok) {
1823
+ const responseText = await response.text();
1824
+ const statusCode = response.status;
1825
+ if (statusCode === 404) {
1826
+ throw new Error(
1827
+ `Agent not found: Agent '${this.agentId}' does not exist or you don't have access to it. Please verify the agent ID and ensure it exists in your account.`
1828
+ );
1829
+ }
1830
+ throw new Error(
1831
+ `Failed to create chat session: ${statusCode} - ${responseText}`
1832
+ );
1833
+ }
1834
+ const chatData = await response.json();
1835
+ const chatId = chatData.id;
1836
+ logger.info(`\u2705 Chat session created: ${chatId}`);
1837
+ return chatId;
1838
+ } catch (e) {
1839
+ if (e instanceof Error) {
1840
+ throw new TypeError(`Failed to create chat session: ${e.message}`);
1841
+ }
1842
+ throw new Error(`Failed to create chat session: ${String(e)}`);
1843
+ }
1844
+ }
1845
+ async run(query, maxSteps, manageConnector, externalHistory, outputSchema) {
1846
+ if (externalHistory !== void 0) {
1847
+ logger.warn("External history is not yet supported for remote execution");
1848
+ }
1849
+ try {
1850
+ logger.info(`\u{1F310} Executing query on remote agent ${this.agentId}`);
1851
+ if (this.chatId === null) {
1852
+ this.chatId = await this.createChatSession();
1853
+ }
1854
+ const chatId = this.chatId;
1855
+ const executionPayload = {
1856
+ query,
1857
+ max_steps: maxSteps ?? 10
1858
+ };
1859
+ if (outputSchema) {
1860
+ executionPayload.output_schema = this.pydanticToJsonSchema(outputSchema);
1861
+ logger.info(`\u{1F527} Using structured output with schema`);
1862
+ }
1863
+ const headers = {
1864
+ "Content-Type": "application/json",
1865
+ "x-api-key": this.apiKey
1866
+ };
1867
+ const executionUrl = `${this.baseUrl}${API_CHAT_EXECUTE_ENDPOINT.replace("{chat_id}", chatId)}`;
1868
+ logger.info(`\u{1F680} Executing agent in chat ${chatId}`);
1869
+ const response = await fetch(executionUrl, {
1870
+ method: "POST",
1871
+ headers,
1872
+ body: JSON.stringify(executionPayload),
1873
+ signal: AbortSignal.timeout(3e5)
1874
+ // 5 minute timeout
1875
+ });
1876
+ if (!response.ok) {
1877
+ const responseText = await response.text();
1878
+ const statusCode = response.status;
1879
+ if (statusCode === 401) {
1880
+ logger.error(`\u274C Authentication failed: ${responseText}`);
1881
+ throw new Error(
1882
+ "Authentication failed: Invalid or missing API key. Please check your API key and ensure the MCP_USE_API_KEY environment variable is set correctly."
1883
+ );
1884
+ } else if (statusCode === 403) {
1885
+ logger.error(`\u274C Access forbidden: ${responseText}`);
1886
+ throw new Error(
1887
+ `Access denied: You don't have permission to execute agent '${this.agentId}'. Check if the agent exists and you have the necessary permissions.`
1888
+ );
1889
+ } else if (statusCode === 404) {
1890
+ logger.error(`\u274C Agent not found: ${responseText}`);
1891
+ throw new Error(
1892
+ `Agent not found: Agent '${this.agentId}' does not exist or you don't have access to it. Please verify the agent ID and ensure it exists in your account.`
1893
+ );
1894
+ } else if (statusCode === 422) {
1895
+ logger.error(`\u274C Validation error: ${responseText}`);
1896
+ throw new Error(
1897
+ `Request validation failed: ${responseText}. Please check your query parameters and output schema format.`
1898
+ );
1899
+ } else if (statusCode === 500) {
1900
+ logger.error(`\u274C Server error: ${responseText}`);
1901
+ throw new Error(
1902
+ "Internal server error occurred during agent execution. Please try again later or contact support if the issue persists."
1903
+ );
1904
+ } else {
1905
+ logger.error(
1906
+ `\u274C Remote execution failed with status ${statusCode}: ${responseText}`
1907
+ );
1908
+ throw new Error(
1909
+ `Remote agent execution failed: ${statusCode} - ${responseText}`
1910
+ );
1911
+ }
1912
+ }
1913
+ const result = await response.json();
1914
+ logger.info(`\u{1F527} Response: ${JSON.stringify(result)}`);
1915
+ logger.info("\u2705 Remote execution completed successfully");
1916
+ if (typeof result === "object" && result !== null) {
1917
+ if (result.status === "error" || result.error !== null) {
1918
+ const errorMsg = result.error ?? String(result);
1919
+ logger.error(`\u274C Remote agent execution failed: ${errorMsg}`);
1920
+ throw new Error(`Remote agent execution failed: ${errorMsg}`);
1921
+ }
1922
+ if (String(result).includes("failed to initialize")) {
1923
+ logger.error(`\u274C Agent initialization failed: ${result}`);
1924
+ throw new Error(
1925
+ `Agent initialization failed on remote server. This usually indicates:
1926
+ \u2022 Invalid agent configuration (LLM model, system prompt)
1927
+ \u2022 Missing or invalid MCP server configurations
1928
+ \u2022 Network connectivity issues with MCP servers
1929
+ \u2022 Missing environment variables or credentials
1930
+ Raw error: ${result}`
1931
+ );
1932
+ }
1933
+ }
1934
+ if (outputSchema) {
1935
+ return this.parseStructuredResponse(result, outputSchema);
1936
+ }
1937
+ if (typeof result === "object" && result !== null && "result" in result) {
1938
+ return result.result;
1939
+ } else if (typeof result === "string") {
1940
+ return result;
1941
+ } else {
1942
+ return String(result);
1943
+ }
1944
+ } catch (e) {
1945
+ if (e instanceof Error) {
1946
+ if (e.name === "AbortError") {
1947
+ logger.error(`\u274C Remote execution timed out: ${e}`);
1948
+ throw new Error(
1949
+ "Remote agent execution timed out. The server may be overloaded or the query is taking too long to process. Try again or use a simpler query."
1950
+ );
1951
+ }
1952
+ logger.error(`\u274C Remote execution error: ${e}`);
1953
+ throw new Error(`Remote agent execution failed: ${e.message}`);
1954
+ }
1955
+ logger.error(`\u274C Remote execution error: ${e}`);
1956
+ throw new Error(`Remote agent execution failed: ${String(e)}`);
1957
+ }
1958
+ }
1959
+ // eslint-disable-next-line require-yield
1960
+ async *stream(query, maxSteps, manageConnector, externalHistory, outputSchema) {
1961
+ const result = await this.run(
1962
+ query,
1963
+ maxSteps,
1964
+ manageConnector,
1965
+ externalHistory,
1966
+ outputSchema
1967
+ );
1968
+ return result;
1969
+ }
1970
+ async close() {
1971
+ logger.info("\u{1F50C} Remote agent client closed");
1972
+ }
1973
+ };
1974
+
1975
+ // src/agents/mcp_agent.ts
1976
+ var MCPAgent = class {
1977
+ static {
1978
+ __name(this, "MCPAgent");
1979
+ }
1980
+ llm;
1981
+ client;
1982
+ connectors;
1983
+ maxSteps;
1984
+ autoInitialize;
1985
+ memoryEnabled;
1986
+ disallowedTools;
1987
+ additionalTools;
1988
+ toolsUsedNames = [];
1989
+ useServerManager;
1990
+ verbose;
1991
+ observe;
1992
+ systemPrompt;
1993
+ systemPromptTemplateOverride;
1994
+ additionalInstructions;
1995
+ _initialized = false;
1996
+ conversationHistory = [];
1997
+ _agentExecutor = null;
1998
+ sessions = {};
1999
+ systemMessage = null;
2000
+ _tools = [];
2001
+ adapter;
2002
+ serverManager = null;
2003
+ telemetry;
2004
+ modelProvider;
2005
+ modelName;
2006
+ // Observability support
2007
+ observabilityManager;
2008
+ callbacks = [];
2009
+ metadata = {};
2010
+ tags = [];
2011
+ // Remote agent support
2012
+ isRemote = false;
2013
+ remoteAgent = null;
2014
+ constructor(options) {
2015
+ if (options.agentId) {
2016
+ this.isRemote = true;
2017
+ this.remoteAgent = new RemoteAgent({
2018
+ agentId: options.agentId,
2019
+ apiKey: options.apiKey,
2020
+ baseUrl: options.baseUrl
2021
+ });
2022
+ this.maxSteps = options.maxSteps ?? 5;
2023
+ this.memoryEnabled = options.memoryEnabled ?? true;
2024
+ this.autoInitialize = options.autoInitialize ?? false;
2025
+ this.verbose = options.verbose ?? false;
2026
+ this.observe = options.observe ?? true;
2027
+ this.connectors = [];
2028
+ this.disallowedTools = [];
2029
+ this.additionalTools = [];
2030
+ this.useServerManager = false;
2031
+ this.adapter = new LangChainAdapter();
2032
+ this.telemetry = Telemetry.getInstance();
2033
+ this.modelProvider = "remote";
2034
+ this.modelName = "remote-agent";
2035
+ this.observabilityManager = new ObservabilityManager({
2036
+ customCallbacks: options.callbacks,
2037
+ agentId: options.agentId
2038
+ });
2039
+ this.callbacks = [];
2040
+ return;
2041
+ }
2042
+ if (!options.llm) {
2043
+ throw new Error(
2044
+ "llm is required for local execution. For remote execution, provide agentId instead."
2045
+ );
2046
+ }
2047
+ this.llm = options.llm;
2048
+ this.client = options.client;
2049
+ this.connectors = options.connectors ?? [];
2050
+ this.maxSteps = options.maxSteps ?? 5;
2051
+ this.autoInitialize = options.autoInitialize ?? false;
2052
+ this.memoryEnabled = options.memoryEnabled ?? true;
2053
+ this.systemPrompt = options.systemPrompt ?? null;
2054
+ this.systemPromptTemplateOverride = options.systemPromptTemplate ?? null;
2055
+ this.additionalInstructions = options.additionalInstructions ?? null;
2056
+ this.disallowedTools = options.disallowedTools ?? [];
2057
+ this.additionalTools = options.additionalTools ?? [];
2058
+ this.toolsUsedNames = options.toolsUsedNames ?? [];
2059
+ this.useServerManager = options.useServerManager ?? false;
2060
+ this.verbose = options.verbose ?? false;
2061
+ this.observe = options.observe ?? true;
2062
+ if (!this.client && this.connectors.length === 0) {
2063
+ throw new Error(
2064
+ "Either 'client' or at least one 'connector' must be provided."
2065
+ );
2066
+ }
2067
+ if (this.useServerManager) {
2068
+ if (!this.client) {
2069
+ throw new Error(
2070
+ "'client' must be provided when 'useServerManager' is true."
2071
+ );
2072
+ }
2073
+ this.adapter = options.adapter ?? new LangChainAdapter(this.disallowedTools);
2074
+ this.serverManager = options.serverManagerFactory?.(this.client) ?? new ServerManager(this.client, this.adapter);
2075
+ } else {
2076
+ this.adapter = options.adapter ?? new LangChainAdapter(this.disallowedTools);
2077
+ }
2078
+ this.telemetry = Telemetry.getInstance();
2079
+ if (this.llm) {
2080
+ const [provider, name] = extractModelInfo(this.llm);
2081
+ this.modelProvider = provider;
2082
+ this.modelName = name;
2083
+ } else {
2084
+ this.modelProvider = "unknown";
2085
+ this.modelName = "unknown";
2086
+ }
2087
+ this.observabilityManager = new ObservabilityManager({
2088
+ customCallbacks: options.callbacks,
2089
+ verbose: this.verbose,
2090
+ observe: this.observe,
2091
+ agentId: options.agentId,
2092
+ metadataProvider: /* @__PURE__ */ __name(() => this.getMetadata(), "metadataProvider"),
2093
+ tagsProvider: /* @__PURE__ */ __name(() => this.getTags(), "tagsProvider")
2094
+ });
2095
+ Object.defineProperty(this, "agentExecutor", {
2096
+ get: /* @__PURE__ */ __name(() => this._agentExecutor, "get"),
2097
+ configurable: true
2098
+ });
2099
+ Object.defineProperty(this, "tools", {
2100
+ get: /* @__PURE__ */ __name(() => this._tools, "get"),
2101
+ configurable: true
2102
+ });
2103
+ Object.defineProperty(this, "initialized", {
2104
+ get: /* @__PURE__ */ __name(() => this._initialized, "get"),
2105
+ configurable: true
2106
+ });
2107
+ }
2108
+ async initialize() {
2109
+ if (this.isRemote) {
2110
+ this._initialized = true;
2111
+ return;
2112
+ }
2113
+ logger.info("\u{1F680} Initializing MCP agent and connecting to services...");
2114
+ this.callbacks = await this.observabilityManager.getCallbacks();
2115
+ const handlerNames = await this.observabilityManager.getHandlerNames();
2116
+ if (handlerNames.length > 0) {
2117
+ logger.info(`\u{1F4CA} Observability enabled with: ${handlerNames.join(", ")}`);
2118
+ }
2119
+ if (this.useServerManager && this.serverManager) {
2120
+ await this.serverManager.initialize();
2121
+ const managementTools = this.serverManager.tools;
2122
+ this._tools = managementTools;
2123
+ this._tools.push(...this.additionalTools);
2124
+ logger.info(
2125
+ `\u{1F527} Server manager mode active with ${managementTools.length} management tools`
2126
+ );
2127
+ await this.createSystemMessageFromTools(this._tools);
2128
+ } else {
2129
+ if (this.client) {
2130
+ this.sessions = this.client.getAllActiveSessions();
2131
+ logger.info(
2132
+ `\u{1F50C} Found ${Object.keys(this.sessions).length} existing sessions`
2133
+ );
2134
+ if (Object.keys(this.sessions).length === 0) {
2135
+ logger.info("\u{1F504} No active sessions found, creating new ones...");
2136
+ this.sessions = await this.client.createAllSessions();
2137
+ logger.info(
2138
+ `\u2705 Created ${Object.keys(this.sessions).length} new sessions`
2139
+ );
2140
+ }
2141
+ this._tools = await LangChainAdapter.createTools(this.client);
2142
+ this._tools.push(...this.additionalTools);
2143
+ logger.info(
2144
+ `\u{1F6E0}\uFE0F Created ${this._tools.length} LangChain tools from client`
2145
+ );
2146
+ } else {
2147
+ logger.info(
2148
+ `\u{1F517} Connecting to ${this.connectors.length} direct connectors...`
2149
+ );
2150
+ for (const connector of this.connectors) {
2151
+ if (!connector.isClientConnected) {
2152
+ await connector.connect();
2153
+ }
2154
+ }
2155
+ this._tools = await this.adapter.createToolsFromConnectors(
2156
+ this.connectors
2157
+ );
2158
+ this._tools.push(...this.additionalTools);
2159
+ logger.info(
2160
+ `\u{1F6E0}\uFE0F Created ${this._tools.length} LangChain tools from connectors`
2161
+ );
2162
+ }
2163
+ logger.info(`\u{1F9F0} Found ${this._tools.length} tools across all connectors`);
2164
+ await this.createSystemMessageFromTools(this._tools);
2165
+ }
2166
+ this._agentExecutor = this.createAgent();
2167
+ this._initialized = true;
2168
+ const mcpServerInfo = this.getMCPServerInfo();
2169
+ if (Object.keys(mcpServerInfo).length > 0) {
2170
+ this.setMetadata(mcpServerInfo);
2171
+ logger.debug(
2172
+ `MCP server info added to metadata: ${JSON.stringify(mcpServerInfo)}`
2173
+ );
2174
+ }
2175
+ logger.info("\u2728 Agent initialization complete");
2176
+ }
2177
+ async createSystemMessageFromTools(tools) {
2178
+ const systemPromptTemplate = this.systemPromptTemplateOverride ?? DEFAULT_SYSTEM_PROMPT_TEMPLATE;
2179
+ this.systemMessage = createSystemMessage(
2180
+ tools,
2181
+ systemPromptTemplate,
2182
+ SERVER_MANAGER_SYSTEM_PROMPT_TEMPLATE,
2183
+ this.useServerManager,
2184
+ this.disallowedTools,
2185
+ this.systemPrompt ?? void 0,
2186
+ this.additionalInstructions ?? void 0
2187
+ );
2188
+ if (this.memoryEnabled) {
2189
+ this.conversationHistory = [
2190
+ this.systemMessage,
2191
+ ...this.conversationHistory.filter(
2192
+ (m) => !(m instanceof import_langchain2.SystemMessage)
2193
+ )
2194
+ ];
2195
+ }
2196
+ }
2197
+ createAgent() {
2198
+ if (!this.llm) {
2199
+ throw new Error("LLM is required to create agent");
2200
+ }
2201
+ const systemContent = this.systemMessage?.content ?? "You are a helpful assistant.";
2202
+ const toolNames = this._tools.map((tool) => tool.name);
2203
+ logger.info(`\u{1F9E0} Agent ready with tools: ${toolNames.join(", ")}`);
2204
+ const middleware = [(0, import_langchain2.modelCallLimitMiddleware)({ runLimit: this.maxSteps })];
2205
+ const agent = (0, import_langchain2.createAgent)({
2206
+ model: this.llm,
2207
+ tools: this._tools,
2208
+ systemPrompt: systemContent,
2209
+ middleware
2210
+ });
2211
+ logger.debug(
2212
+ `Created agent with max_steps=${this.maxSteps} (via ModelCallLimitMiddleware) and ${this.callbacks.length} callbacks`
2213
+ );
2214
+ return agent;
2215
+ }
2216
+ getConversationHistory() {
2217
+ return [...this.conversationHistory];
2218
+ }
2219
+ clearConversationHistory() {
2220
+ this.conversationHistory = this.memoryEnabled && this.systemMessage ? [this.systemMessage] : [];
2221
+ }
2222
+ addToHistory(message) {
2223
+ if (this.memoryEnabled) this.conversationHistory.push(message);
2224
+ }
2225
+ getSystemMessage() {
2226
+ return this.systemMessage;
2227
+ }
2228
+ setSystemMessage(message) {
2229
+ this.systemMessage = new import_langchain2.SystemMessage(message);
2230
+ if (this.memoryEnabled) {
2231
+ this.conversationHistory = this.conversationHistory.filter(
2232
+ (m) => !(m instanceof import_langchain2.SystemMessage)
2233
+ );
2234
+ this.conversationHistory.unshift(this.systemMessage);
2235
+ }
2236
+ if (this._initialized && this._tools.length) {
2237
+ this._agentExecutor = this.createAgent();
2238
+ logger.debug("Agent recreated with new system message");
2239
+ }
2240
+ }
2241
+ setDisallowedTools(disallowedTools) {
2242
+ this.disallowedTools = disallowedTools;
2243
+ this.adapter = new LangChainAdapter(this.disallowedTools);
2244
+ if (this._initialized) {
2245
+ logger.debug(
2246
+ "Agent already initialized. Changes will take effect on next initialization."
2247
+ );
2248
+ }
2249
+ }
2250
+ getDisallowedTools() {
2251
+ return this.disallowedTools;
2252
+ }
2253
+ /**
2254
+ * Set metadata for observability traces
2255
+ * @param newMetadata - Key-value pairs to add to metadata. Keys should be strings, values should be serializable.
2256
+ */
2257
+ setMetadata(newMetadata) {
2258
+ const sanitizedMetadata = this.sanitizeMetadata(newMetadata);
2259
+ this.metadata = { ...this.metadata, ...sanitizedMetadata };
2260
+ logger.debug(`Metadata set: ${JSON.stringify(this.metadata)}`);
2261
+ }
2262
+ /**
2263
+ * Get current metadata
2264
+ * @returns A copy of the current metadata object
2265
+ */
2266
+ getMetadata() {
2267
+ return { ...this.metadata };
2268
+ }
2269
+ /**
2270
+ * Set tags for observability traces
2271
+ * @param newTags - Array of tag strings to add. Duplicates will be automatically removed.
2272
+ */
2273
+ setTags(newTags) {
2274
+ const sanitizedTags = this.sanitizeTags(newTags);
2275
+ this.tags = [.../* @__PURE__ */ new Set([...this.tags, ...sanitizedTags])];
2276
+ logger.debug(`Tags set: ${JSON.stringify(this.tags)}`);
2277
+ }
2278
+ /**
2279
+ * Get current tags
2280
+ * @returns A copy of the current tags array
2281
+ */
2282
+ getTags() {
2283
+ return [...this.tags];
2284
+ }
2285
+ /**
2286
+ * Sanitize metadata to ensure compatibility with observability platforms
2287
+ * @param metadata - Raw metadata object
2288
+ * @returns Sanitized metadata object
2289
+ */
2290
+ sanitizeMetadata(metadata) {
2291
+ const sanitized = {};
2292
+ for (const [key, value] of Object.entries(metadata)) {
2293
+ if (typeof key !== "string" || key.length === 0) {
2294
+ logger.warn(`Invalid metadata key: ${key}. Skipping.`);
2295
+ continue;
2296
+ }
2297
+ const sanitizedKey = key.replace(/[^\w-]/g, "_");
2298
+ if (value === null || value === void 0) {
2299
+ sanitized[sanitizedKey] = value;
2300
+ } else if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
2301
+ sanitized[sanitizedKey] = value;
2302
+ } else if (Array.isArray(value)) {
2303
+ const sanitizedArray = value.filter(
2304
+ (item) => typeof item === "string" || typeof item === "number" || typeof item === "boolean"
2305
+ );
2306
+ if (sanitizedArray.length > 0) {
2307
+ sanitized[sanitizedKey] = sanitizedArray;
2308
+ }
2309
+ } else if (typeof value === "object") {
2310
+ try {
2311
+ const serialized = JSON.stringify(value);
2312
+ if (serialized.length > 1e3) {
2313
+ logger.warn(
2314
+ `Metadata value for key '${sanitizedKey}' is too large. Truncating.`
2315
+ );
2316
+ sanitized[sanitizedKey] = `${serialized.substring(0, 1e3)}...`;
2317
+ } else {
2318
+ sanitized[sanitizedKey] = value;
2319
+ }
2320
+ } catch (error) {
2321
+ logger.warn(
2322
+ `Failed to serialize metadata value for key '${sanitizedKey}': ${error}. Skipping.`
2323
+ );
2324
+ }
2325
+ } else {
2326
+ logger.warn(
2327
+ `Unsupported metadata value type for key '${sanitizedKey}': ${typeof value}. Skipping.`
2328
+ );
2329
+ }
2330
+ }
2331
+ return sanitized;
2332
+ }
2333
+ /**
2334
+ * Sanitize tags to ensure compatibility with observability platforms
2335
+ * @param tags - Array of tag strings
2336
+ * @returns Array of sanitized tag strings
2337
+ */
2338
+ sanitizeTags(tags) {
2339
+ return tags.filter((tag) => typeof tag === "string" && tag.length > 0).map((tag) => tag.replace(/[^\w:-]/g, "_")).filter((tag) => tag.length <= 50);
2340
+ }
2341
+ /**
2342
+ * Get MCP server information for observability metadata
2343
+ */
2344
+ getMCPServerInfo() {
2345
+ const serverInfo = {};
2346
+ try {
2347
+ if (this.client) {
2348
+ const serverNames = this.client.getServerNames();
2349
+ serverInfo.mcp_servers_count = serverNames.length;
2350
+ serverInfo.mcp_server_names = serverNames;
2351
+ const serverConfigs = {};
2352
+ for (const serverName of serverNames) {
2353
+ try {
2354
+ const config2 = this.client.getServerConfig(serverName);
2355
+ if (config2) {
2356
+ let serverType = "unknown";
2357
+ if (config2.command) {
2358
+ serverType = "command";
2359
+ } else if (config2.url) {
2360
+ serverType = "http";
2361
+ } else if (config2.ws_url) {
2362
+ serverType = "websocket";
2363
+ }
2364
+ serverConfigs[serverName] = {
2365
+ type: serverType,
2366
+ // Include safe configuration details (avoid sensitive data)
2367
+ has_args: !!config2.args,
2368
+ has_env: !!config2.env,
2369
+ has_headers: !!config2.headers,
2370
+ url: config2.url || null,
2371
+ command: config2.command || null
2372
+ };
2373
+ }
2374
+ } catch (error) {
2375
+ logger.warn(
2376
+ `Failed to get config for server '${serverName}': ${error}`
2377
+ );
2378
+ serverConfigs[serverName] = {
2379
+ type: "error",
2380
+ error: "config_unavailable"
2381
+ };
2382
+ }
2383
+ }
2384
+ serverInfo.mcp_server_configs = serverConfigs;
2385
+ } else if (this.connectors && this.connectors.length > 0) {
2386
+ serverInfo.mcp_servers_count = this.connectors.length;
2387
+ serverInfo.mcp_server_names = this.connectors.map(
2388
+ (c) => c.publicIdentifier
2389
+ );
2390
+ serverInfo.mcp_server_types = this.connectors.map(
2391
+ (c) => c.constructor.name
2392
+ );
2393
+ }
2394
+ } catch (error) {
2395
+ logger.warn(`Failed to collect MCP server info: ${error}`);
2396
+ serverInfo.error = "collection_failed";
2397
+ }
2398
+ return serverInfo;
2399
+ }
2400
+ _normalizeOutput(value) {
2401
+ try {
2402
+ if (typeof value === "string") {
2403
+ return value;
2404
+ }
2405
+ if (value && typeof value === "object" && "content" in value) {
2406
+ return this._normalizeOutput(value.content);
2407
+ }
2408
+ if (Array.isArray(value)) {
2409
+ const parts = [];
2410
+ for (const item of value) {
2411
+ if (typeof item === "object" && item !== null) {
2412
+ if ("text" in item && typeof item.text === "string") {
2413
+ parts.push(item.text);
2414
+ } else if ("content" in item) {
2415
+ parts.push(this._normalizeOutput(item.content));
2416
+ } else {
2417
+ parts.push(String(item));
2418
+ }
2419
+ } else {
2420
+ const partText = item && typeof item === "object" && "text" in item ? item.text : null;
2421
+ if (typeof partText === "string") {
2422
+ parts.push(partText);
2423
+ } else {
2424
+ const partContent = item && typeof item === "object" && "content" in item ? item.content : item;
2425
+ parts.push(this._normalizeOutput(partContent));
2426
+ }
2427
+ }
2428
+ }
2429
+ return parts.join("");
2430
+ }
2431
+ return String(value);
2432
+ } catch (error) {
2433
+ return String(value);
2434
+ }
2435
+ }
2436
+ async _consumeAndReturn(generator) {
2437
+ while (true) {
2438
+ const { done, value } = await generator.next();
2439
+ if (done) {
2440
+ return value;
2441
+ }
2442
+ }
2443
+ }
2444
+ async run(query, maxSteps, manageConnector, externalHistory, outputSchema) {
2445
+ if (this.isRemote && this.remoteAgent) {
2446
+ return this.remoteAgent.run(
2447
+ query,
2448
+ maxSteps,
2449
+ manageConnector,
2450
+ externalHistory,
2451
+ outputSchema
2452
+ );
2453
+ }
2454
+ const generator = this.stream(
2455
+ query,
2456
+ maxSteps,
2457
+ manageConnector,
2458
+ externalHistory,
2459
+ outputSchema
2460
+ );
2461
+ return this._consumeAndReturn(generator);
2462
+ }
2463
+ async *stream(query, maxSteps, manageConnector = true, externalHistory, outputSchema) {
2464
+ if (this.isRemote && this.remoteAgent) {
2465
+ const result = await this.remoteAgent.run(
2466
+ query,
2467
+ maxSteps,
2468
+ manageConnector,
2469
+ externalHistory,
2470
+ outputSchema
2471
+ );
2472
+ return result;
2473
+ }
2474
+ let initializedHere = false;
2475
+ const startTime = Date.now();
2476
+ let success = false;
2477
+ let finalOutput = null;
2478
+ let stepsTaken = 0;
2479
+ try {
2480
+ if (manageConnector && !this._initialized) {
2481
+ await this.initialize();
2482
+ initializedHere = true;
2483
+ } else if (!this._initialized && this.autoInitialize) {
2484
+ await this.initialize();
2485
+ initializedHere = true;
2486
+ }
2487
+ if (!this._agentExecutor) {
2488
+ throw new Error("MCP agent failed to initialize");
2489
+ }
2490
+ if (this.useServerManager && this.serverManager) {
2491
+ const currentTools = this.serverManager.tools;
2492
+ const currentToolNames = new Set(currentTools.map((t) => t.name));
2493
+ const existingToolNames = new Set(this._tools.map((t) => t.name));
2494
+ if (currentToolNames.size !== existingToolNames.size || [...currentToolNames].some((n) => !existingToolNames.has(n))) {
2495
+ logger.info(
2496
+ `\u{1F504} Tools changed before execution, updating agent. New tools: ${[...currentToolNames].join(", ")}`
2497
+ );
2498
+ this._tools = currentTools;
2499
+ this._tools.push(...this.additionalTools);
2500
+ await this.createSystemMessageFromTools(this._tools);
2501
+ this._agentExecutor = this.createAgent();
2502
+ }
2503
+ }
2504
+ const historyToUse = externalHistory ?? this.conversationHistory;
2505
+ const langchainHistory = [];
2506
+ for (const msg of historyToUse) {
2507
+ if (msg instanceof import_langchain2.HumanMessage || msg instanceof import_langchain2.AIMessage) {
2508
+ langchainHistory.push(msg);
2509
+ }
2510
+ }
2511
+ const displayQuery = query.length > 50 ? `${query.slice(0, 50).replace(/\n/g, " ")}...` : query.replace(/\n/g, " ");
2512
+ logger.info(`\u{1F4AC} Received query: '${displayQuery}'`);
2513
+ logger.info("\u{1F3C1} Starting agent execution");
2514
+ const maxRestarts = 3;
2515
+ let restartCount = 0;
2516
+ const accumulatedMessages = [
2517
+ ...langchainHistory,
2518
+ new import_langchain2.HumanMessage(query)
2519
+ ];
2520
+ while (restartCount <= maxRestarts) {
2521
+ const inputs = { messages: accumulatedMessages };
2522
+ let shouldRestart = false;
2523
+ const stream = await this._agentExecutor.stream(inputs, {
2524
+ streamMode: "updates",
2525
+ // Get updates as they happen
2526
+ callbacks: this.callbacks,
2527
+ metadata: this.getMetadata(),
2528
+ tags: this.getTags(),
2529
+ // Set trace name for LangChain/Langfuse
2530
+ runName: this.metadata.trace_name || "mcp-use-agent",
2531
+ // Pass sessionId for Langfuse if present in metadata
2532
+ ...this.metadata.session_id && {
2533
+ sessionId: this.metadata.session_id
2534
+ }
2535
+ });
2536
+ for await (const chunk of stream) {
2537
+ for (const [nodeName, nodeOutput] of Object.entries(chunk)) {
2538
+ logger.debug(
2539
+ `\u{1F4E6} Node '${nodeName}' output: ${JSON.stringify(nodeOutput)}`
2540
+ );
2541
+ if (nodeOutput && typeof nodeOutput === "object" && "messages" in nodeOutput) {
2542
+ let messages = nodeOutput.messages;
2543
+ if (!Array.isArray(messages)) {
2544
+ messages = [messages];
2545
+ }
2546
+ for (const msg of messages) {
2547
+ if (!accumulatedMessages.includes(msg)) {
2548
+ accumulatedMessages.push(msg);
2549
+ }
2550
+ }
2551
+ for (const message of messages) {
2552
+ if ("tool_calls" in message && Array.isArray(message.tool_calls) && message.tool_calls.length > 0) {
2553
+ for (const toolCall of message.tool_calls) {
2554
+ const toolName = toolCall.name || "unknown";
2555
+ const toolInput = toolCall.args || {};
2556
+ this.toolsUsedNames.push(toolName);
2557
+ stepsTaken++;
2558
+ let toolInputStr = JSON.stringify(toolInput);
2559
+ if (toolInputStr.length > 100) {
2560
+ toolInputStr = `${toolInputStr.slice(0, 97)}...`;
2561
+ }
2562
+ logger.info(
2563
+ `\u{1F527} Tool call: ${toolName} with input: ${toolInputStr}`
2564
+ );
2565
+ yield {
2566
+ action: {
2567
+ tool: toolName,
2568
+ toolInput,
2569
+ log: `Calling tool ${toolName}`
2570
+ },
2571
+ observation: ""
2572
+ // Will be filled in by tool result
2573
+ };
2574
+ }
2575
+ }
2576
+ if (message instanceof import_langchain2.ToolMessage || message && "type" in message && message.type === "tool") {
2577
+ const observation = message.content;
2578
+ let observationStr = String(observation);
2579
+ if (observationStr.length > 100) {
2580
+ observationStr = `${observationStr.slice(0, 97)}...`;
2581
+ }
2582
+ observationStr = observationStr.replace(/\n/g, " ");
2583
+ logger.info(`\u{1F4C4} Tool result: ${observationStr}`);
2584
+ if (this.useServerManager && this.serverManager) {
2585
+ const currentTools = this.serverManager.tools;
2586
+ const currentToolNames = new Set(
2587
+ currentTools.map((t) => t.name)
2588
+ );
2589
+ const existingToolNames = new Set(
2590
+ this._tools.map((t) => t.name)
2591
+ );
2592
+ if (currentToolNames.size !== existingToolNames.size || [...currentToolNames].some(
2593
+ (n) => !existingToolNames.has(n)
2594
+ )) {
2595
+ logger.info(
2596
+ `\u{1F504} Tools changed during execution. New tools: ${[...currentToolNames].join(", ")}`
2597
+ );
2598
+ this._tools = currentTools;
2599
+ this._tools.push(...this.additionalTools);
2600
+ await this.createSystemMessageFromTools(this._tools);
2601
+ this._agentExecutor = this.createAgent();
2602
+ shouldRestart = true;
2603
+ restartCount++;
2604
+ logger.info(
2605
+ `\u{1F503} Restarting execution with updated tools (restart ${restartCount}/${maxRestarts})`
2606
+ );
2607
+ break;
2608
+ }
2609
+ }
2610
+ }
2611
+ if (message instanceof import_langchain2.AIMessage && !("tool_calls" in message && Array.isArray(message.tool_calls) && message.tool_calls.length > 0)) {
2612
+ finalOutput = this._normalizeOutput(message.content);
2613
+ logger.info("\u2705 Agent finished with output");
2614
+ }
2615
+ }
2616
+ if (shouldRestart) {
2617
+ break;
2618
+ }
2619
+ }
2620
+ }
2621
+ if (shouldRestart) {
2622
+ break;
2623
+ }
2624
+ }
2625
+ if (!shouldRestart) {
2626
+ break;
2627
+ }
2628
+ if (restartCount > maxRestarts) {
2629
+ logger.warn(
2630
+ `\u26A0\uFE0F Max restarts (${maxRestarts}) reached. Continuing with current tools.`
2631
+ );
2632
+ break;
2633
+ }
2634
+ }
2635
+ if (this.memoryEnabled) {
2636
+ this.addToHistory(new import_langchain2.HumanMessage(query));
2637
+ if (finalOutput) {
2638
+ this.addToHistory(new import_langchain2.AIMessage(finalOutput));
2639
+ }
2640
+ }
2641
+ if (outputSchema && finalOutput) {
2642
+ try {
2643
+ logger.info("\u{1F527} Attempting structured output...");
2644
+ const structuredResult = await this._attemptStructuredOutput(
2645
+ finalOutput,
2646
+ this.llm,
2647
+ outputSchema
2648
+ );
2649
+ if (this.memoryEnabled) {
2650
+ this.addToHistory(
2651
+ new import_langchain2.AIMessage(
2652
+ `Structured result: ${JSON.stringify(structuredResult)}`
2653
+ )
2654
+ );
2655
+ }
2656
+ logger.info("\u2705 Structured output successful");
2657
+ success = true;
2658
+ return structuredResult;
2659
+ } catch (e) {
2660
+ logger.error(`\u274C Structured output failed: ${e}`);
2661
+ throw new Error(
2662
+ `Failed to generate structured output: ${e instanceof Error ? e.message : String(e)}`
2663
+ );
2664
+ }
2665
+ }
2666
+ logger.info(
2667
+ `\u{1F389} Agent execution complete in ${((Date.now() - startTime) / 1e3).toFixed(2)} seconds`
2668
+ );
2669
+ success = true;
2670
+ return finalOutput || "No output generated";
2671
+ } catch (e) {
2672
+ logger.error(`\u274C Error running query: ${e}`);
2673
+ if (initializedHere && manageConnector) {
2674
+ logger.info("\u{1F9F9} Cleaning up resources after error");
2675
+ await this.close();
2676
+ }
2677
+ throw e;
2678
+ } finally {
2679
+ const executionTimeMs = Date.now() - startTime;
2680
+ let serverCount = 0;
2681
+ if (this.client) {
2682
+ serverCount = Object.keys(this.client.getAllActiveSessions()).length;
2683
+ } else if (this.connectors) {
2684
+ serverCount = this.connectors.length;
2685
+ }
2686
+ const conversationHistoryLength = this.memoryEnabled ? this.conversationHistory.length : 0;
2687
+ const toolsAvailable = this._tools || [];
2688
+ await this.telemetry.trackAgentExecution({
2689
+ executionMethod: "stream",
2690
+ query,
2691
+ success,
2692
+ modelProvider: this.modelProvider,
2693
+ modelName: this.modelName,
2694
+ serverCount,
2695
+ serverIdentifiers: this.connectors.map(
2696
+ (connector) => connector.publicIdentifier
2697
+ ),
2698
+ totalToolsAvailable: toolsAvailable.length,
2699
+ toolsAvailableNames: toolsAvailable.map((t) => t.name),
2700
+ maxStepsConfigured: this.maxSteps,
2701
+ memoryEnabled: this.memoryEnabled,
2702
+ useServerManager: this.useServerManager,
2703
+ maxStepsUsed: maxSteps ?? null,
2704
+ manageConnector,
2705
+ externalHistoryUsed: externalHistory !== void 0,
2706
+ stepsTaken,
2707
+ toolsUsedCount: this.toolsUsedNames.length,
2708
+ toolsUsedNames: this.toolsUsedNames,
2709
+ response: finalOutput || "",
2710
+ executionTimeMs,
2711
+ errorType: success ? null : "execution_error",
2712
+ conversationHistoryLength
2713
+ });
2714
+ if (manageConnector && !this.client && initializedHere) {
2715
+ logger.info("\u{1F9F9} Closing agent after stream completion");
2716
+ await this.close();
2717
+ }
2718
+ }
2719
+ }
2720
+ /**
2721
+ * Flush observability traces to the configured observability platform.
2722
+ * Important for serverless environments where traces need to be sent before function termination.
2723
+ */
2724
+ async flush() {
2725
+ if (this.isRemote && this.remoteAgent) {
2726
+ return;
2727
+ }
2728
+ logger.debug("Flushing observability traces...");
2729
+ await this.observabilityManager.flush();
2730
+ }
2731
+ async close() {
2732
+ if (this.isRemote && this.remoteAgent) {
2733
+ await this.remoteAgent.close();
2734
+ return;
2735
+ }
2736
+ logger.info("\u{1F50C} Closing MCPAgent resources\u2026");
2737
+ await this.observabilityManager.shutdown();
2738
+ try {
2739
+ this._agentExecutor = null;
2740
+ this._tools = [];
2741
+ if (this.client) {
2742
+ logger.info("\u{1F504} Closing sessions through client");
2743
+ await this.client.closeAllSessions();
2744
+ this.sessions = {};
2745
+ } else {
2746
+ for (const connector of this.connectors) {
2747
+ logger.info("\u{1F504} Disconnecting connector");
2748
+ await connector.disconnect();
2749
+ }
2750
+ }
2751
+ if ("connectorToolMap" in this.adapter) {
2752
+ this.adapter = new LangChainAdapter();
2753
+ }
2754
+ } finally {
2755
+ this._initialized = false;
2756
+ logger.info("\u{1F44B} Agent closed successfully");
2757
+ }
2758
+ }
2759
+ /**
2760
+ * Yields LangChain StreamEvent objects from the underlying streamEvents() method.
2761
+ * This provides token-level streaming and fine-grained event updates.
2762
+ */
2763
+ async *streamEvents(query, maxSteps, manageConnector = true, externalHistory, outputSchema) {
2764
+ let initializedHere = false;
2765
+ const startTime = Date.now();
2766
+ let success = false;
2767
+ let eventCount = 0;
2768
+ let totalResponseLength = 0;
2769
+ let finalResponse = "";
2770
+ if (outputSchema) {
2771
+ query = this._enhanceQueryWithSchema(query, outputSchema);
2772
+ }
2773
+ try {
2774
+ if (manageConnector && !this._initialized) {
2775
+ await this.initialize();
2776
+ initializedHere = true;
2777
+ } else if (!this._initialized && this.autoInitialize) {
2778
+ await this.initialize();
2779
+ initializedHere = true;
2780
+ }
2781
+ const agentExecutor = this._agentExecutor;
2782
+ if (!agentExecutor) {
2783
+ throw new Error("MCP agent failed to initialize");
2784
+ }
2785
+ this.maxSteps = maxSteps ?? this.maxSteps;
2786
+ const display_query = query.length > 50 ? `${query.slice(0, 50).replace(/\n/g, " ")}...` : query.replace(/\n/g, " ");
2787
+ logger.info(`\u{1F4AC} Received query for streamEvents: '${display_query}'`);
2788
+ if (this.memoryEnabled) {
2789
+ logger.info(`\u{1F504} Adding user message to history: ${query}`);
2790
+ this.addToHistory(new import_langchain2.HumanMessage(query));
2791
+ }
2792
+ const historyToUse = externalHistory ?? this.conversationHistory;
2793
+ const langchainHistory = [];
2794
+ for (const msg of historyToUse) {
2795
+ if (msg instanceof import_langchain2.HumanMessage || msg instanceof import_langchain2.AIMessage || msg instanceof import_langchain2.ToolMessage) {
2796
+ langchainHistory.push(msg);
2797
+ } else {
2798
+ logger.info(`\u26A0\uFE0F Skipped message of type: ${msg.constructor.name}`);
2799
+ }
2800
+ }
2801
+ const inputs = [
2802
+ ...langchainHistory,
2803
+ new import_langchain2.HumanMessage(query)
2804
+ ];
2805
+ logger.info("callbacks", this.callbacks);
2806
+ const eventStream = agentExecutor.streamEvents(
2807
+ { messages: inputs },
2808
+ {
2809
+ streamMode: "messages",
2810
+ version: "v2",
2811
+ callbacks: this.callbacks,
2812
+ metadata: this.getMetadata(),
2813
+ tags: this.getTags(),
2814
+ // Set trace name for LangChain/Langfuse
2815
+ runName: this.metadata.trace_name || "mcp-use-agent",
2816
+ // Pass sessionId for Langfuse if present in metadata
2817
+ ...this.metadata.session_id && {
2818
+ sessionId: this.metadata.session_id
2819
+ }
2820
+ }
2821
+ );
2822
+ for await (const event of eventStream) {
2823
+ eventCount++;
2824
+ if (!event || typeof event !== "object") {
2825
+ continue;
2826
+ }
2827
+ if (event.event === "on_chat_model_stream" && event.data?.chunk?.content) {
2828
+ totalResponseLength += event.data.chunk.content.length;
2829
+ }
2830
+ if (event.event === "on_chat_model_stream" && event.data?.chunk) {
2831
+ const chunk = event.data.chunk;
2832
+ if (chunk.content) {
2833
+ if (!finalResponse) {
2834
+ finalResponse = "";
2835
+ }
2836
+ const normalizedContent = this._normalizeOutput(chunk.content);
2837
+ finalResponse += normalizedContent;
2838
+ logger.debug(
2839
+ `\u{1F4DD} Accumulated response length: ${finalResponse.length}`
2840
+ );
2841
+ }
2842
+ }
2843
+ yield event;
2844
+ if (event.event === "on_chain_end" && event.data?.output && !finalResponse) {
2845
+ const output = event.data.output;
2846
+ if (Array.isArray(output) && output.length > 0 && output[0]?.text) {
2847
+ finalResponse = output[0].text;
2848
+ } else if (typeof output === "string") {
2849
+ finalResponse = output;
2850
+ } else if (output && typeof output === "object" && "output" in output) {
2851
+ finalResponse = output.output;
2852
+ }
2853
+ }
2854
+ }
2855
+ if (outputSchema && finalResponse) {
2856
+ logger.info("\u{1F527} Attempting structured output conversion...");
2857
+ try {
2858
+ let conversionCompleted = false;
2859
+ let conversionResult = null;
2860
+ let conversionError = null;
2861
+ this._attemptStructuredOutput(
2862
+ finalResponse,
2863
+ this.llm,
2864
+ outputSchema
2865
+ ).then((result) => {
2866
+ conversionCompleted = true;
2867
+ conversionResult = result;
2868
+ return result;
2869
+ }).catch((error) => {
2870
+ conversionCompleted = true;
2871
+ conversionError = error;
2872
+ throw error;
2873
+ });
2874
+ let progressCount = 0;
2875
+ while (!conversionCompleted) {
2876
+ await new Promise((resolve) => setTimeout(resolve, 2e3));
2877
+ if (!conversionCompleted) {
2878
+ progressCount++;
2879
+ yield {
2880
+ event: "on_structured_output_progress",
2881
+ data: {
2882
+ message: `Converting to structured output... (${progressCount * 2}s)`,
2883
+ elapsed: progressCount * 2
2884
+ }
2885
+ };
2886
+ }
2887
+ }
2888
+ if (conversionError) {
2889
+ throw conversionError;
2890
+ }
2891
+ if (conversionResult) {
2892
+ yield {
2893
+ event: "on_structured_output",
2894
+ data: { output: conversionResult }
2895
+ };
2896
+ if (this.memoryEnabled) {
2897
+ this.addToHistory(
2898
+ new import_langchain2.AIMessage(
2899
+ `Structured result: ${JSON.stringify(conversionResult)}`
2900
+ )
2901
+ );
2902
+ }
2903
+ logger.info("\u2705 Structured output successful");
2904
+ }
2905
+ } catch (e) {
2906
+ logger.warn(`\u26A0\uFE0F Structured output failed: ${e}`);
2907
+ yield {
2908
+ event: "on_structured_output_error",
2909
+ data: { error: e instanceof Error ? e.message : String(e) }
2910
+ };
2911
+ }
2912
+ } else if (this.memoryEnabled && finalResponse) {
2913
+ this.addToHistory(new import_langchain2.AIMessage(finalResponse));
2914
+ }
2915
+ logger.info(`\u{1F389} StreamEvents complete - ${eventCount} events emitted`);
2916
+ success = true;
2917
+ } catch (e) {
2918
+ logger.error(`\u274C Error during streamEvents: ${e}`);
2919
+ if (initializedHere && manageConnector) {
2920
+ logger.info(
2921
+ "\u{1F9F9} Cleaning up resources after initialization error in streamEvents"
2922
+ );
2923
+ await this.close();
2924
+ }
2925
+ throw e;
2926
+ } finally {
2927
+ const executionTimeMs = Date.now() - startTime;
2928
+ let serverCount = 0;
2929
+ if (this.client) {
2930
+ serverCount = Object.keys(this.client.getAllActiveSessions()).length;
2931
+ } else if (this.connectors) {
2932
+ serverCount = this.connectors.length;
2933
+ }
2934
+ const conversationHistoryLength = this.memoryEnabled ? this.conversationHistory.length : 0;
2935
+ await this.telemetry.trackAgentExecution({
2936
+ executionMethod: "streamEvents",
2937
+ query,
2938
+ success,
2939
+ modelProvider: this.modelProvider,
2940
+ modelName: this.modelName,
2941
+ serverCount,
2942
+ serverIdentifiers: this.connectors.map(
2943
+ (connector) => connector.publicIdentifier
2944
+ ),
2945
+ totalToolsAvailable: this._tools.length,
2946
+ toolsAvailableNames: this._tools.map((t) => t.name),
2947
+ maxStepsConfigured: this.maxSteps,
2948
+ memoryEnabled: this.memoryEnabled,
2949
+ useServerManager: this.useServerManager,
2950
+ maxStepsUsed: maxSteps ?? null,
2951
+ manageConnector,
2952
+ externalHistoryUsed: externalHistory !== void 0,
2953
+ response: `[STREAMED RESPONSE - ${totalResponseLength} chars]`,
2954
+ executionTimeMs,
2955
+ errorType: success ? null : "streaming_error",
2956
+ conversationHistoryLength
2957
+ });
2958
+ if (manageConnector && !this.client && initializedHere) {
2959
+ logger.info("\u{1F9F9} Closing agent after streamEvents completion");
2960
+ await this.close();
2961
+ }
2962
+ }
2963
+ }
2964
+ /**
2965
+ * Attempt to create structured output from raw result with validation and retry logic.
2966
+ *
2967
+ * @param rawResult - The raw text result from the agent
2968
+ * @param llm - LLM to use for structured output
2969
+ * @param outputSchema - The Zod schema to validate against
2970
+ */
2971
+ async _attemptStructuredOutput(rawResult, llm, outputSchema) {
2972
+ logger.info(
2973
+ `\u{1F504} Attempting structured output with schema: ${JSON.stringify(outputSchema, null, 2)}`
2974
+ );
2975
+ logger.info(`\u{1F504} Raw result: ${JSON.stringify(rawResult, null, 2)}`);
2976
+ let structuredLlm = null;
2977
+ let schemaDescription = "";
2978
+ logger.debug(
2979
+ `\u{1F504} Structured output requested, schema: ${JSON.stringify((0, import_zod_to_json_schema2.zodToJsonSchema)(outputSchema), null, 2)}`
2980
+ );
2981
+ if (llm && "withStructuredOutput" in llm && typeof llm.withStructuredOutput === "function") {
2982
+ structuredLlm = llm.withStructuredOutput(outputSchema);
2983
+ } else if (llm) {
2984
+ structuredLlm = llm;
2985
+ } else {
2986
+ throw new Error("LLM is required for structured output");
2987
+ }
2988
+ const jsonSchema = (0, import_zod_to_json_schema2.zodToJsonSchema)(outputSchema);
2989
+ const { $schema, additionalProperties, ...cleanSchema } = jsonSchema;
2990
+ schemaDescription = JSON.stringify(cleanSchema, null, 2);
2991
+ logger.info(`\u{1F504} Schema description: ${schemaDescription}`);
2992
+ let textContent = "";
2993
+ if (typeof rawResult === "string") {
2994
+ textContent = rawResult;
2995
+ } else if (rawResult && typeof rawResult === "object") {
2996
+ textContent = JSON.stringify(rawResult);
2997
+ }
2998
+ logger.info("rawResult", rawResult);
2999
+ if (!textContent) {
3000
+ textContent = JSON.stringify(rawResult);
3001
+ }
3002
+ const maxRetries = 3;
3003
+ let lastError = "";
3004
+ for (let attempt = 1; attempt <= maxRetries; attempt++) {
3005
+ logger.info(`\u{1F504} Structured output attempt ${attempt}/${maxRetries}`);
3006
+ let formatPrompt = `
3007
+ Please format the following information according to the EXACT schema specified below.
3008
+ You must use the exact field names and types as shown in the schema.
3009
+
3010
+ Required schema format:
3011
+ ${schemaDescription}
3012
+
3013
+ Content to extract from:
3014
+ ${textContent}
3015
+
3016
+ IMPORTANT:
3017
+ - Use ONLY the field names specified in the schema
3018
+ - Match the data types exactly (string, number, boolean, array, etc.)
3019
+ - Include ALL required fields
3020
+ - Return valid JSON that matches the schema structure exactly
3021
+ - For missing data: use null for nullable fields, omit optional fields entirely
3022
+ - Do NOT use empty strings ("") or zero (0) as placeholders for missing data
3023
+ `;
3024
+ if (attempt > 1) {
3025
+ formatPrompt += `
3026
+
3027
+ PREVIOUS ATTEMPT FAILED with error: ${lastError}
3028
+ Please fix the issues mentioned above and ensure the output matches the schema exactly.
3029
+ `;
3030
+ }
3031
+ try {
3032
+ logger.info(
3033
+ `\u{1F504} Structured output attempt ${attempt} - using streaming approach`
3034
+ );
3035
+ const contentPreview = textContent.length > 300 ? `${textContent.slice(0, 300)}...` : textContent;
3036
+ logger.info(
3037
+ `\u{1F504} Content being formatted (${textContent.length} chars): ${contentPreview}`
3038
+ );
3039
+ logger.info(
3040
+ `\u{1F504} Full format prompt (${formatPrompt.length} chars):
3041
+ ${formatPrompt}`
3042
+ );
3043
+ const stream = await structuredLlm.stream(formatPrompt);
3044
+ let structuredResult = null;
3045
+ let chunkCount = 0;
3046
+ for await (const chunk of stream) {
3047
+ chunkCount++;
3048
+ logger.info(`Chunk ${chunkCount}: ${JSON.stringify(chunk, null, 2)}`);
3049
+ if (typeof chunk === "string") {
3050
+ try {
3051
+ structuredResult = JSON.parse(chunk);
3052
+ } catch (e) {
3053
+ logger.warn(`\u{1F504} Failed to parse string chunk as JSON: ${chunk}`);
3054
+ }
3055
+ } else if (chunk && typeof chunk === "object") {
3056
+ structuredResult = chunk;
3057
+ } else {
3058
+ try {
3059
+ structuredResult = JSON.parse(String(chunk));
3060
+ } catch (e) {
3061
+ logger.warn(`\u{1F504} Failed to parse chunk as JSON: ${chunk}`);
3062
+ }
3063
+ }
3064
+ if (chunkCount % 10 === 0) {
3065
+ logger.info(`\u{1F504} Structured output streaming: ${chunkCount} chunks`);
3066
+ }
3067
+ }
3068
+ logger.info(
3069
+ `\u{1F504} Structured result attempt ${attempt}: ${JSON.stringify(structuredResult, null, 2)}`
3070
+ );
3071
+ if (!structuredResult) {
3072
+ throw new Error("No structured result received from stream");
3073
+ }
3074
+ const validatedResult = this._validateStructuredResult(
3075
+ structuredResult,
3076
+ outputSchema
3077
+ );
3078
+ logger.info(`\u2705 Structured output successful on attempt ${attempt}`);
3079
+ return validatedResult;
3080
+ } catch (e) {
3081
+ lastError = e instanceof Error ? e.message : String(e);
3082
+ logger.warn(
3083
+ `\u26A0\uFE0F Structured output attempt ${attempt} failed: ${lastError}`
3084
+ );
3085
+ if (attempt === maxRetries) {
3086
+ logger.error(
3087
+ `\u274C All ${maxRetries} structured output attempts failed`
3088
+ );
3089
+ throw new Error(
3090
+ `Failed to generate valid structured output after ${maxRetries} attempts. Last error: ${lastError}`
3091
+ );
3092
+ }
3093
+ continue;
3094
+ }
3095
+ }
3096
+ throw new Error("Unexpected error in structured output generation");
3097
+ }
3098
+ /**
3099
+ * Validate the structured result against the schema with detailed error reporting
3100
+ */
3101
+ _validateStructuredResult(structuredResult, outputSchema) {
3102
+ try {
3103
+ const validatedResult = outputSchema.parse(structuredResult);
3104
+ const schemaType = outputSchema;
3105
+ if (schemaType._def && schemaType._def.shape) {
3106
+ for (const [fieldName, fieldSchema] of Object.entries(
3107
+ schemaType._def.shape
3108
+ )) {
3109
+ const field = fieldSchema;
3110
+ const isOptional = field.isOptional?.() ?? field._def?.typeName === "ZodOptional";
3111
+ const isNullable = field.isNullable?.() ?? field._def?.typeName === "ZodNullable";
3112
+ if (!isOptional && !isNullable) {
3113
+ const value = validatedResult[fieldName];
3114
+ if (value === null || value === void 0 || typeof value === "string" && !value.trim() || Array.isArray(value) && value.length === 0) {
3115
+ throw new Error(
3116
+ `Required field '${fieldName}' is missing or empty`
3117
+ );
3118
+ }
3119
+ }
3120
+ }
3121
+ }
3122
+ return validatedResult;
3123
+ } catch (e) {
3124
+ logger.debug(`Validation details: ${e}`);
3125
+ throw e;
3126
+ }
3127
+ }
3128
+ /**
3129
+ * Enhance the query with schema information to make the agent aware of required fields.
3130
+ */
3131
+ _enhanceQueryWithSchema(query, outputSchema) {
3132
+ try {
3133
+ const jsonSchema = (0, import_zod_to_json_schema2.zodToJsonSchema)(outputSchema);
3134
+ const { $schema, additionalProperties, ...cleanSchema } = jsonSchema;
3135
+ const schemaDescription = JSON.stringify(cleanSchema, null, 2);
3136
+ const enhancedQuery = `
3137
+ ${query}
3138
+
3139
+ IMPORTANT: Your response must include sufficient information to populate the following structured output:
3140
+
3141
+ ${schemaDescription}
3142
+
3143
+ Make sure you gather ALL the required information during your task execution.
3144
+ If any required information is missing, continue working to find it.
3145
+ `;
3146
+ return enhancedQuery;
3147
+ } catch (e) {
3148
+ logger.warn(`Could not extract schema details: ${e}`);
3149
+ return query;
3150
+ }
3151
+ }
3152
+ };
3153
+ // Annotate the CommonJS export names for ESM import in node:
3154
+ 0 && (module.exports = {
3155
+ BaseAgent,
3156
+ MCPAgent,
3157
+ RemoteAgent
3158
+ });