mcp-use 0.2.0 โ†’ 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/dist/chunk-2HFIPY7C.js +429 -0
  2. package/dist/chunk-4DEFXVWT.js +680 -0
  3. package/dist/chunk-JXLQRAW2.js +532 -0
  4. package/dist/chunk-SHUYVCID.js +6 -0
  5. package/dist/chunk-YUSC6R6V.js +299 -0
  6. package/dist/index.cjs +5762 -0
  7. package/dist/index.d.ts +7 -0
  8. package/dist/index.d.ts.map +1 -1
  9. package/dist/index.js +3767 -22
  10. package/dist/langfuse-YA2S23SM.js +13 -0
  11. package/dist/src/agents/remote.d.ts.map +1 -1
  12. package/dist/src/agents/utils/ai_sdk.d.ts.map +1 -1
  13. package/dist/src/auth/browser-provider.d.ts +52 -0
  14. package/dist/src/auth/browser-provider.d.ts.map +1 -0
  15. package/dist/src/auth/callback.d.ts +6 -0
  16. package/dist/src/auth/callback.d.ts.map +1 -0
  17. package/dist/src/auth/index.d.ts +7 -0
  18. package/dist/src/auth/index.d.ts.map +1 -0
  19. package/dist/src/auth/types.d.ts +18 -0
  20. package/dist/src/auth/types.d.ts.map +1 -0
  21. package/dist/src/browser.cjs +323 -0
  22. package/dist/src/browser.d.ts +5 -46
  23. package/dist/src/browser.d.ts.map +1 -1
  24. package/dist/src/browser.js +9 -75
  25. package/dist/src/oauth-helper.d.ts +2 -12
  26. package/dist/src/oauth-helper.d.ts.map +1 -1
  27. package/dist/src/react/index.cjs +986 -0
  28. package/dist/src/react/index.d.ts +9 -0
  29. package/dist/src/react/index.d.ts.map +1 -0
  30. package/dist/src/react/index.js +11 -0
  31. package/dist/src/react/types.d.ts +139 -0
  32. package/dist/src/react/types.d.ts.map +1 -0
  33. package/dist/src/react/useMcp.d.ts +3 -0
  34. package/dist/src/react/useMcp.d.ts.map +1 -0
  35. package/dist/src/server/index.cjs +566 -0
  36. package/dist/src/server/index.d.ts +3 -0
  37. package/dist/src/server/index.d.ts.map +1 -0
  38. package/dist/src/server/index.js +9 -0
  39. package/dist/src/server/logging.d.ts +16 -0
  40. package/dist/src/server/logging.d.ts.map +1 -0
  41. package/dist/src/server/mcp-server.d.ts +282 -0
  42. package/dist/src/server/mcp-server.d.ts.map +1 -0
  43. package/dist/src/server/types.d.ts +47 -0
  44. package/dist/src/server/types.d.ts.map +1 -0
  45. package/dist/src/utils/assert.d.ts +8 -0
  46. package/dist/src/utils/assert.d.ts.map +1 -0
  47. package/dist/tsconfig.tsbuildinfo +1 -0
  48. package/package.json +67 -40
  49. package/dist/src/adapters/base.js +0 -124
  50. package/dist/src/adapters/index.js +0 -2
  51. package/dist/src/adapters/langchain_adapter.js +0 -49
  52. package/dist/src/agents/base.js +0 -9
  53. package/dist/src/agents/index.js +0 -3
  54. package/dist/src/agents/mcp_agent.js +0 -1002
  55. package/dist/src/agents/prompts/system_prompt_builder.js +0 -40
  56. package/dist/src/agents/prompts/templates.js +0 -39
  57. package/dist/src/agents/remote.js +0 -264
  58. package/dist/src/agents/utils/ai_sdk.js +0 -62
  59. package/dist/src/agents/utils/index.js +0 -1
  60. package/dist/src/client/base.js +0 -119
  61. package/dist/src/client.js +0 -50
  62. package/dist/src/config.js +0 -34
  63. package/dist/src/connectors/base.js +0 -143
  64. package/dist/src/connectors/http.js +0 -150
  65. package/dist/src/connectors/index.js +0 -4
  66. package/dist/src/connectors/stdio.js +0 -68
  67. package/dist/src/connectors/websocket.js +0 -157
  68. package/dist/src/logging.js +0 -232
  69. package/dist/src/managers/index.js +0 -2
  70. package/dist/src/managers/server_manager.js +0 -106
  71. package/dist/src/managers/tools/acquire_active_mcp_server.js +0 -17
  72. package/dist/src/managers/tools/add_server_from_config.js +0 -40
  73. package/dist/src/managers/tools/base.js +0 -17
  74. package/dist/src/managers/tools/connect_mcp_server.js +0 -46
  75. package/dist/src/managers/tools/index.js +0 -5
  76. package/dist/src/managers/tools/list_mcp_servers.js +0 -33
  77. package/dist/src/managers/tools/release_mcp_server_connection.js +0 -19
  78. package/dist/src/oauth-helper.js +0 -427
  79. package/dist/src/observability/index.js +0 -12
  80. package/dist/src/observability/langfuse.js +0 -211
  81. package/dist/src/observability/manager.js +0 -199
  82. package/dist/src/observability/types.js +0 -4
  83. package/dist/src/session.js +0 -23
  84. package/dist/src/task_managers/base.js +0 -127
  85. package/dist/src/task_managers/index.js +0 -5
  86. package/dist/src/task_managers/sse.js +0 -43
  87. package/dist/src/task_managers/stdio.js +0 -51
  88. package/dist/src/task_managers/streamable_http.js +0 -50
  89. package/dist/src/task_managers/websocket.js +0 -67
  90. package/dist/src/telemetry/events.js +0 -44
  91. package/dist/src/telemetry/index.js +0 -8
  92. package/dist/src/telemetry/telemetry.js +0 -324
  93. package/dist/src/telemetry/utils.js +0 -39
  94. package/dist/tests/ai_sdk_compatibility.test.js +0 -214
  95. package/dist/tests/stream_events.test.js +0 -307
  96. package/dist/tests/stream_events_simple.test.js +0 -179
  97. package/dist/vitest.config.js +0 -21
@@ -1,1002 +0,0 @@
1
- import { CallbackManager } from '@langchain/core/callbacks/manager';
2
- import { AIMessage, HumanMessage, SystemMessage, ToolMessage, } from '@langchain/core/messages';
3
- import { OutputParserException } from '@langchain/core/output_parsers';
4
- import { ChatPromptTemplate, MessagesPlaceholder, } from '@langchain/core/prompts';
5
- import { AgentExecutor, createToolCallingAgent } from 'langchain/agents';
6
- import { zodToJsonSchema } from 'zod-to-json-schema';
7
- import { LangChainAdapter } from '../adapters/langchain_adapter.js';
8
- import { logger } from '../logging.js';
9
- import { ServerManager } from '../managers/server_manager.js';
10
- import { ObservabilityManager } from '../observability/index.js';
11
- import { extractModelInfo, Telemetry } from '../telemetry/index.js';
12
- import { createSystemMessage } from './prompts/system_prompt_builder.js';
13
- import { DEFAULT_SYSTEM_PROMPT_TEMPLATE, SERVER_MANAGER_SYSTEM_PROMPT_TEMPLATE } from './prompts/templates.js';
14
- import { RemoteAgent } from './remote.js';
15
- export class MCPAgent {
16
- llm;
17
- client;
18
- connectors;
19
- maxSteps;
20
- autoInitialize;
21
- memoryEnabled;
22
- disallowedTools;
23
- additionalTools;
24
- useServerManager;
25
- verbose;
26
- observe;
27
- systemPrompt;
28
- systemPromptTemplateOverride;
29
- additionalInstructions;
30
- _initialized = false;
31
- conversationHistory = [];
32
- _agentExecutor = null;
33
- sessions = {};
34
- systemMessage = null;
35
- _tools = [];
36
- adapter;
37
- serverManager = null;
38
- telemetry;
39
- modelProvider;
40
- modelName;
41
- // Observability support
42
- observabilityManager;
43
- callbacks = [];
44
- metadata = {};
45
- tags = [];
46
- // Remote agent support
47
- isRemote = false;
48
- remoteAgent = null;
49
- constructor(options) {
50
- // Handle remote execution
51
- if (options.agentId) {
52
- this.isRemote = true;
53
- this.remoteAgent = new RemoteAgent({
54
- agentId: options.agentId,
55
- apiKey: options.apiKey,
56
- baseUrl: options.baseUrl,
57
- });
58
- // Set default values for remote agent
59
- this.maxSteps = options.maxSteps ?? 5;
60
- this.memoryEnabled = options.memoryEnabled ?? true;
61
- this.autoInitialize = options.autoInitialize ?? false;
62
- this.verbose = options.verbose ?? false;
63
- this.observe = options.observe ?? true;
64
- this.connectors = [];
65
- this.disallowedTools = [];
66
- this.additionalTools = [];
67
- this.useServerManager = false;
68
- this.adapter = new LangChainAdapter();
69
- this.telemetry = Telemetry.getInstance();
70
- this.modelProvider = 'remote';
71
- this.modelName = 'remote-agent';
72
- this.observabilityManager = new ObservabilityManager({
73
- customCallbacks: options.callbacks,
74
- agentId: options.agentId,
75
- });
76
- this.callbacks = [];
77
- return;
78
- }
79
- // Validate requirements for local execution
80
- if (!options.llm) {
81
- throw new Error('llm is required for local execution. For remote execution, provide agentId instead.');
82
- }
83
- this.llm = options.llm;
84
- this.client = options.client;
85
- this.connectors = options.connectors ?? [];
86
- this.maxSteps = options.maxSteps ?? 5;
87
- this.autoInitialize = options.autoInitialize ?? false;
88
- this.memoryEnabled = options.memoryEnabled ?? true;
89
- this.systemPrompt = options.systemPrompt ?? null;
90
- this.systemPromptTemplateOverride = options.systemPromptTemplate ?? null;
91
- this.additionalInstructions = options.additionalInstructions ?? null;
92
- this.disallowedTools = options.disallowedTools ?? [];
93
- this.additionalTools = options.additionalTools ?? [];
94
- this.useServerManager = options.useServerManager ?? false;
95
- this.verbose = options.verbose ?? false;
96
- this.observe = options.observe ?? true;
97
- if (!this.client && this.connectors.length === 0) {
98
- throw new Error('Either \'client\' or at least one \'connector\' must be provided.');
99
- }
100
- if (this.useServerManager) {
101
- if (!this.client) {
102
- throw new Error('\'client\' must be provided when \'useServerManager\' is true.');
103
- }
104
- this.adapter = options.adapter ?? new LangChainAdapter(this.disallowedTools);
105
- this.serverManager = options.serverManagerFactory?.(this.client) ?? new ServerManager(this.client, this.adapter);
106
- }
107
- // Let consumers swap allowed tools dynamically
108
- else {
109
- this.adapter = options.adapter ?? new LangChainAdapter(this.disallowedTools);
110
- }
111
- // Initialize telemetry
112
- this.telemetry = Telemetry.getInstance();
113
- // Track model info for telemetry
114
- if (this.llm) {
115
- const [provider, name] = extractModelInfo(this.llm);
116
- this.modelProvider = provider;
117
- this.modelName = name;
118
- }
119
- else {
120
- this.modelProvider = 'unknown';
121
- this.modelName = 'unknown';
122
- }
123
- // Set up observability callbacks using the ObservabilityManager
124
- this.observabilityManager = new ObservabilityManager({
125
- customCallbacks: options.callbacks,
126
- verbose: this.verbose,
127
- observe: this.observe,
128
- agentId: options.agentId,
129
- metadataProvider: () => this.getMetadata(),
130
- tagsProvider: () => this.getTags(),
131
- });
132
- // Make getters configurable for test mocking
133
- Object.defineProperty(this, 'agentExecutor', {
134
- get: () => this._agentExecutor,
135
- configurable: true,
136
- });
137
- Object.defineProperty(this, 'tools', {
138
- get: () => this._tools,
139
- configurable: true,
140
- });
141
- Object.defineProperty(this, 'initialized', {
142
- get: () => this._initialized,
143
- configurable: true,
144
- });
145
- }
146
- async initialize() {
147
- // Skip initialization for remote agents
148
- if (this.isRemote) {
149
- this._initialized = true;
150
- return;
151
- }
152
- logger.info('๐Ÿš€ Initializing MCP agent and connecting to services...');
153
- // Initialize observability callbacks
154
- this.callbacks = await this.observabilityManager.getCallbacks();
155
- const handlerNames = await this.observabilityManager.getHandlerNames();
156
- if (handlerNames.length > 0) {
157
- logger.info(`๐Ÿ“Š Observability enabled with: ${handlerNames.join(', ')}`);
158
- }
159
- // If using server manager, initialize it
160
- if (this.useServerManager && this.serverManager) {
161
- await this.serverManager.initialize();
162
- // Get server management tools
163
- const managementTools = this.serverManager.tools;
164
- this._tools = managementTools;
165
- this._tools.push(...this.additionalTools);
166
- logger.info(`๐Ÿ”ง Server manager mode active with ${managementTools.length} management tools`);
167
- // Create the system message based on available tools
168
- await this.createSystemMessageFromTools(this._tools);
169
- }
170
- else {
171
- // Standard initialization - if using client, get or create sessions
172
- if (this.client) {
173
- // First try to get existing sessions
174
- this.sessions = this.client.getAllActiveSessions();
175
- logger.info(`๐Ÿ”Œ Found ${Object.keys(this.sessions).length} existing sessions`);
176
- // If no active sessions exist, create new ones
177
- if (Object.keys(this.sessions).length === 0) {
178
- logger.info('๐Ÿ”„ No active sessions found, creating new ones...');
179
- this.sessions = await this.client.createAllSessions();
180
- logger.info(`โœ… Created ${Object.keys(this.sessions).length} new sessions`);
181
- }
182
- // Create LangChain tools directly from the client using the adapter
183
- this._tools = await LangChainAdapter.createTools(this.client);
184
- this._tools.push(...this.additionalTools);
185
- logger.info(`๐Ÿ› ๏ธ Created ${this._tools.length} LangChain tools from client`);
186
- }
187
- else {
188
- // Using direct connector - only establish connection
189
- logger.info(`๐Ÿ”— Connecting to ${this.connectors.length} direct connectors...`);
190
- for (const connector of this.connectors) {
191
- if (!connector.isClientConnected) {
192
- await connector.connect();
193
- }
194
- }
195
- // Create LangChain tools using the adapter with connectors
196
- this._tools = await this.adapter.createToolsFromConnectors(this.connectors);
197
- this._tools.push(...this.additionalTools);
198
- logger.info(`๐Ÿ› ๏ธ Created ${this._tools.length} LangChain tools from connectors`);
199
- }
200
- // Get all tools for system message generation
201
- logger.info(`๐Ÿงฐ Found ${this._tools.length} tools across all connectors`);
202
- // Create the system message based on available tools
203
- await this.createSystemMessageFromTools(this._tools);
204
- }
205
- // Create the agent executor and mark initialized
206
- this._agentExecutor = this.createAgent();
207
- this._initialized = true;
208
- // Add MCP server information to observability metadata
209
- const mcpServerInfo = this.getMCPServerInfo();
210
- if (Object.keys(mcpServerInfo).length > 0) {
211
- this.setMetadata(mcpServerInfo);
212
- logger.debug(`MCP server info added to metadata: ${JSON.stringify(mcpServerInfo)}`);
213
- }
214
- logger.info('โœจ Agent initialization complete');
215
- }
216
- async createSystemMessageFromTools(tools) {
217
- const systemPromptTemplate = this.systemPromptTemplateOverride
218
- ?? DEFAULT_SYSTEM_PROMPT_TEMPLATE;
219
- this.systemMessage = createSystemMessage(tools, systemPromptTemplate, SERVER_MANAGER_SYSTEM_PROMPT_TEMPLATE, this.useServerManager, this.disallowedTools, this.systemPrompt ?? undefined, this.additionalInstructions ?? undefined);
220
- if (this.memoryEnabled) {
221
- this.conversationHistory = [
222
- this.systemMessage,
223
- ...this.conversationHistory.filter(m => !(m instanceof SystemMessage)),
224
- ];
225
- }
226
- }
227
- createAgent() {
228
- if (!this.llm) {
229
- throw new Error('LLM is required to create agent');
230
- }
231
- const systemContent = this.systemMessage?.content ?? 'You are a helpful assistant.';
232
- const prompt = ChatPromptTemplate.fromMessages([
233
- ['system', systemContent],
234
- new MessagesPlaceholder('chat_history'),
235
- ['human', '{input}'],
236
- new MessagesPlaceholder('agent_scratchpad'),
237
- ]);
238
- const agent = createToolCallingAgent({
239
- llm: this.llm,
240
- tools: this._tools,
241
- prompt,
242
- });
243
- return new AgentExecutor({
244
- agent,
245
- tools: this._tools,
246
- maxIterations: this.maxSteps,
247
- verbose: this.verbose,
248
- returnIntermediateSteps: true,
249
- callbacks: this.callbacks,
250
- });
251
- }
252
- getConversationHistory() {
253
- return [...this.conversationHistory];
254
- }
255
- clearConversationHistory() {
256
- this.conversationHistory = this.memoryEnabled && this.systemMessage ? [this.systemMessage] : [];
257
- }
258
- addToHistory(message) {
259
- if (this.memoryEnabled)
260
- this.conversationHistory.push(message);
261
- }
262
- getSystemMessage() {
263
- return this.systemMessage;
264
- }
265
- setSystemMessage(message) {
266
- this.systemMessage = new SystemMessage(message);
267
- if (this.memoryEnabled) {
268
- this.conversationHistory = this.conversationHistory.filter(m => !(m instanceof SystemMessage));
269
- this.conversationHistory.unshift(this.systemMessage);
270
- }
271
- if (this._initialized && this._tools.length) {
272
- this._agentExecutor = this.createAgent();
273
- logger.debug('Agent recreated with new system message');
274
- }
275
- }
276
- setDisallowedTools(disallowedTools) {
277
- this.disallowedTools = disallowedTools;
278
- this.adapter = new LangChainAdapter(this.disallowedTools);
279
- if (this._initialized) {
280
- logger.debug('Agent already initialized. Changes will take effect on next initialization.');
281
- }
282
- }
283
- getDisallowedTools() {
284
- return this.disallowedTools;
285
- }
286
- /**
287
- * Set metadata for observability traces
288
- * @param newMetadata - Key-value pairs to add to metadata. Keys should be strings, values should be serializable.
289
- */
290
- setMetadata(newMetadata) {
291
- // Validate and sanitize metadata
292
- const sanitizedMetadata = this.sanitizeMetadata(newMetadata);
293
- // Merge with existing metadata instead of replacing it
294
- this.metadata = { ...this.metadata, ...sanitizedMetadata };
295
- logger.debug(`Metadata set: ${JSON.stringify(this.metadata)}`);
296
- }
297
- /**
298
- * Get current metadata
299
- * @returns A copy of the current metadata object
300
- */
301
- getMetadata() {
302
- return { ...this.metadata };
303
- }
304
- /**
305
- * Set tags for observability traces
306
- * @param newTags - Array of tag strings to add. Duplicates will be automatically removed.
307
- */
308
- setTags(newTags) {
309
- // Validate and sanitize tags
310
- const sanitizedTags = this.sanitizeTags(newTags);
311
- this.tags = [...new Set([...this.tags, ...sanitizedTags])]; // Remove duplicates
312
- logger.debug(`Tags set: ${JSON.stringify(this.tags)}`);
313
- }
314
- /**
315
- * Get current tags
316
- * @returns A copy of the current tags array
317
- */
318
- getTags() {
319
- return [...this.tags];
320
- }
321
- /**
322
- * Sanitize metadata to ensure compatibility with observability platforms
323
- * @param metadata - Raw metadata object
324
- * @returns Sanitized metadata object
325
- */
326
- sanitizeMetadata(metadata) {
327
- const sanitized = {};
328
- for (const [key, value] of Object.entries(metadata)) {
329
- // Validate key
330
- if (typeof key !== 'string' || key.length === 0) {
331
- logger.warn(`Invalid metadata key: ${key}. Skipping.`);
332
- continue;
333
- }
334
- // Sanitize key (remove special characters that might cause issues)
335
- const sanitizedKey = key.replace(/[^\w-]/g, '_');
336
- // Validate and sanitize value
337
- if (value === null || value === undefined) {
338
- sanitized[sanitizedKey] = value;
339
- }
340
- else if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
341
- sanitized[sanitizedKey] = value;
342
- }
343
- else if (Array.isArray(value)) {
344
- // Only allow arrays of primitives
345
- const sanitizedArray = value.filter(item => typeof item === 'string' || typeof item === 'number' || typeof item === 'boolean');
346
- if (sanitizedArray.length > 0) {
347
- sanitized[sanitizedKey] = sanitizedArray;
348
- }
349
- }
350
- else if (typeof value === 'object') {
351
- // Try to serialize objects, but limit depth to prevent circular references
352
- try {
353
- const serialized = JSON.stringify(value);
354
- if (serialized.length > 1000) {
355
- logger.warn(`Metadata value for key '${sanitizedKey}' is too large. Truncating.`);
356
- sanitized[sanitizedKey] = `${serialized.substring(0, 1000)}...`;
357
- }
358
- else {
359
- sanitized[sanitizedKey] = value;
360
- }
361
- }
362
- catch (error) {
363
- logger.warn(`Failed to serialize metadata value for key '${sanitizedKey}': ${error}. Skipping.`);
364
- }
365
- }
366
- else {
367
- logger.warn(`Unsupported metadata value type for key '${sanitizedKey}': ${typeof value}. Skipping.`);
368
- }
369
- }
370
- return sanitized;
371
- }
372
- /**
373
- * Sanitize tags to ensure compatibility with observability platforms
374
- * @param tags - Array of tag strings
375
- * @returns Array of sanitized tag strings
376
- */
377
- sanitizeTags(tags) {
378
- return tags
379
- .filter(tag => typeof tag === 'string' && tag.length > 0)
380
- .map(tag => tag.replace(/[^\w:-]/g, '_'))
381
- .filter(tag => tag.length <= 50); // Limit tag length
382
- }
383
- /**
384
- * Get MCP server information for observability metadata
385
- */
386
- getMCPServerInfo() {
387
- const serverInfo = {};
388
- try {
389
- if (this.client) {
390
- const serverNames = this.client.getServerNames();
391
- serverInfo.mcp_servers_count = serverNames.length;
392
- serverInfo.mcp_server_names = serverNames;
393
- // Get server types and configurations
394
- const serverConfigs = {};
395
- for (const serverName of serverNames) {
396
- try {
397
- const config = this.client.getServerConfig(serverName);
398
- if (config) {
399
- // Determine server type based on configuration
400
- let serverType = 'unknown';
401
- if (config.command) {
402
- serverType = 'command';
403
- }
404
- else if (config.url) {
405
- serverType = 'http';
406
- }
407
- else if (config.ws_url) {
408
- serverType = 'websocket';
409
- }
410
- serverConfigs[serverName] = {
411
- type: serverType,
412
- // Include safe configuration details (avoid sensitive data)
413
- has_args: !!config.args,
414
- has_env: !!config.env,
415
- has_headers: !!config.headers,
416
- url: config.url || null,
417
- command: config.command || null,
418
- };
419
- }
420
- }
421
- catch (error) {
422
- logger.warn(`Failed to get config for server '${serverName}': ${error}`);
423
- serverConfigs[serverName] = { type: 'error', error: 'config_unavailable' };
424
- }
425
- }
426
- serverInfo.mcp_server_configs = serverConfigs;
427
- }
428
- else if (this.connectors && this.connectors.length > 0) {
429
- // Handle direct connectors
430
- serverInfo.mcp_servers_count = this.connectors.length;
431
- serverInfo.mcp_server_names = this.connectors.map(c => c.publicIdentifier);
432
- serverInfo.mcp_server_types = this.connectors.map(c => c.constructor.name);
433
- }
434
- }
435
- catch (error) {
436
- logger.warn(`Failed to collect MCP server info: ${error}`);
437
- serverInfo.error = 'collection_failed';
438
- }
439
- return serverInfo;
440
- }
441
- async _consumeAndReturn(generator) {
442
- // Manually iterate through the generator to consume the steps.
443
- // The for-await-of loop is not used because it discards the generator's
444
- // final return value. We need to capture that value when `done` is true.
445
- while (true) {
446
- const { done, value } = await generator.next();
447
- if (done) {
448
- return value;
449
- }
450
- }
451
- }
452
- async run(query, maxSteps, manageConnector, externalHistory, outputSchema) {
453
- // Delegate to remote agent if in remote mode
454
- if (this.isRemote && this.remoteAgent) {
455
- return this.remoteAgent.run(query, maxSteps, manageConnector, externalHistory, outputSchema);
456
- }
457
- const generator = this.stream(query, maxSteps, manageConnector, externalHistory, outputSchema);
458
- return this._consumeAndReturn(generator);
459
- }
460
- /**
461
- * Runs the agent and yields intermediate steps as an async generator.
462
- * If outputSchema is provided, returns structured output of type T.
463
- */
464
- async *stream(query, maxSteps, manageConnector = true, externalHistory, outputSchema) {
465
- // Delegate to remote agent if in remote mode
466
- if (this.isRemote && this.remoteAgent) {
467
- const result = await this.remoteAgent.run(query, maxSteps, manageConnector, externalHistory, outputSchema);
468
- return result;
469
- }
470
- let result = '';
471
- let initializedHere = false;
472
- const startTime = Date.now();
473
- const toolsUsedNames = [];
474
- let stepsTaken = 0;
475
- let success = false;
476
- // Schema-aware setup for structured output
477
- let structuredLlm = null;
478
- let schemaDescription = '';
479
- if (outputSchema) {
480
- query = this._enhanceQueryWithSchema(query, outputSchema);
481
- logger.debug(`๐Ÿ”„ Structured output requested, schema: ${JSON.stringify(zodToJsonSchema(outputSchema), null, 2)}`);
482
- // Check if withStructuredOutput method exists
483
- if (this.llm && 'withStructuredOutput' in this.llm && typeof this.llm.withStructuredOutput === 'function') {
484
- structuredLlm = this.llm.withStructuredOutput(outputSchema);
485
- }
486
- else if (this.llm) {
487
- // Fallback: use the same LLM but we'll handle structure in our helper method
488
- structuredLlm = this.llm;
489
- }
490
- else {
491
- throw new Error('LLM is required for structured output');
492
- }
493
- schemaDescription = JSON.stringify(zodToJsonSchema(outputSchema), null, 2);
494
- }
495
- try {
496
- if (manageConnector && !this._initialized) {
497
- await this.initialize();
498
- initializedHere = true;
499
- }
500
- else if (!this._initialized && this.autoInitialize) {
501
- await this.initialize();
502
- initializedHere = true;
503
- }
504
- if (!this._agentExecutor) {
505
- throw new Error('MCP agent failed to initialize');
506
- }
507
- const steps = maxSteps ?? this.maxSteps;
508
- this._agentExecutor.maxIterations = steps;
509
- const display_query = query.length > 50 ? `${query.slice(0, 50).replace(/\n/g, ' ')}...` : query.replace(/\n/g, ' ');
510
- logger.info(`๐Ÿ’ฌ Received query: '${display_query}'`);
511
- // โ€”โ€“โ€“ Record user message
512
- if (this.memoryEnabled) {
513
- this.addToHistory(new HumanMessage(query));
514
- }
515
- const historyToUse = externalHistory ?? this.conversationHistory;
516
- const langchainHistory = [];
517
- for (const msg of historyToUse) {
518
- if (msg instanceof HumanMessage || msg instanceof AIMessage) {
519
- langchainHistory.push(msg);
520
- }
521
- }
522
- const intermediateSteps = [];
523
- const inputs = { input: query, chat_history: langchainHistory };
524
- let nameToToolMap = Object.fromEntries(this._tools.map(t => [t.name, t]));
525
- logger.info(`๐Ÿ Starting agent execution with max_steps=${steps}`);
526
- // Create a run manager with our callbacks if we have any - ONCE for the entire execution
527
- let runManager;
528
- if (this.callbacks?.length > 0) {
529
- // Create an async callback manager with our callbacks
530
- const callbackManager = new CallbackManager(undefined, {
531
- handlers: this.callbacks,
532
- inheritableHandlers: this.callbacks,
533
- });
534
- // Create a run manager for this chain execution
535
- runManager = await callbackManager.handleChainStart({
536
- name: 'MCPAgent (mcp-use)',
537
- id: ['MCPAgent (mcp-use)'],
538
- lc: 1,
539
- type: 'not_implemented',
540
- }, inputs);
541
- }
542
- for (let stepNum = 0; stepNum < steps; stepNum++) {
543
- stepsTaken = stepNum + 1;
544
- if (this.useServerManager && this.serverManager) {
545
- const currentTools = this.serverManager.tools;
546
- const currentToolNames = new Set(currentTools.map(t => t.name));
547
- const existingToolNames = new Set(this._tools.map(t => t.name));
548
- const changed = currentTools.length !== this._tools.length
549
- || [...currentToolNames].some(n => !existingToolNames.has(n));
550
- if (changed) {
551
- logger.info(`๐Ÿ”„ Tools changed before step ${stepNum + 1}, updating agent. New tools: ${[...currentToolNames].join(', ')}`);
552
- this._tools = currentTools;
553
- this._tools.push(...this.additionalTools);
554
- await this.createSystemMessageFromTools(this._tools);
555
- this._agentExecutor = this.createAgent();
556
- this._agentExecutor.maxIterations = steps;
557
- nameToToolMap = Object.fromEntries(this._tools.map(t => [t.name, t]));
558
- }
559
- }
560
- logger.info(`๐Ÿ‘ฃ Step ${stepNum + 1}/${steps}`);
561
- try {
562
- logger.debug('Starting agent step execution');
563
- const nextStepOutput = await this._agentExecutor._takeNextStep(nameToToolMap, inputs, intermediateSteps, runManager);
564
- // Agent finish handling (AgentFinish contains returnValues property)
565
- if ('returnValues' in nextStepOutput) {
566
- logger.info(`โœ… Agent finished at step ${stepNum + 1}`);
567
- result = nextStepOutput.returnValues?.output ?? 'No output generated';
568
- runManager?.handleChainEnd({ output: result });
569
- // If structured output is requested, attempt to create it
570
- if (outputSchema && structuredLlm) {
571
- try {
572
- logger.info('๐Ÿ”ง Attempting structured output...');
573
- const structuredResult = await this._attemptStructuredOutput(result, structuredLlm, outputSchema, schemaDescription);
574
- logger.debug(`๐Ÿ”„ Structured result: ${JSON.stringify(structuredResult)}`);
575
- // Add the final response to conversation history if memory is enabled
576
- if (this.memoryEnabled) {
577
- this.addToHistory(new AIMessage(`Structured result: ${JSON.stringify(structuredResult)}`));
578
- }
579
- logger.info('โœ… Structured output successful');
580
- success = true;
581
- return structuredResult;
582
- }
583
- catch (e) {
584
- logger.warn(`โš ๏ธ Structured output failed: ${e}`);
585
- // Continue execution to gather missing information
586
- const failedStructuredOutputPrompt = `
587
- The current result cannot be formatted into the required structure.
588
- Error: ${String(e)}
589
-
590
- Current information: ${result}
591
-
592
- If information is missing, please continue working to gather the missing information needed for:
593
- ${schemaDescription}
594
-
595
- If the information is complete, please return the result in the required structure.
596
- `;
597
- // Add this as feedback and continue the loop
598
- inputs.input = failedStructuredOutputPrompt;
599
- if (this.memoryEnabled) {
600
- this.addToHistory(new HumanMessage(failedStructuredOutputPrompt));
601
- }
602
- logger.info('๐Ÿ”„ Continuing execution to gather missing information...');
603
- continue;
604
- }
605
- }
606
- else {
607
- // Regular execution without structured output
608
- break;
609
- }
610
- }
611
- const stepArray = nextStepOutput;
612
- intermediateSteps.push(...stepArray);
613
- for (const step of stepArray) {
614
- yield step;
615
- const { action, observation } = step;
616
- const toolName = action.tool;
617
- toolsUsedNames.push(toolName);
618
- let toolInputStr = typeof action.toolInput === 'string'
619
- ? action.toolInput
620
- : JSON.stringify(action.toolInput, null, 2);
621
- if (toolInputStr.length > 100)
622
- toolInputStr = `${toolInputStr.slice(0, 97)}...`;
623
- logger.info(`๐Ÿ”ง Tool call: ${toolName} with input: ${toolInputStr}`);
624
- let outputStr = String(observation);
625
- if (outputStr.length > 100)
626
- outputStr = `${outputStr.slice(0, 97)}...`;
627
- outputStr = outputStr.replace(/\n/g, ' ');
628
- logger.info(`๐Ÿ“„ Tool result: ${outputStr}`);
629
- }
630
- // Detect direct return
631
- if (stepArray.length) {
632
- const lastStep = stepArray[stepArray.length - 1];
633
- const toolReturn = await this._agentExecutor._getToolReturn(lastStep);
634
- if (toolReturn) {
635
- logger.info(`๐Ÿ† Tool returned directly at step ${stepNum + 1}`);
636
- result = toolReturn.returnValues?.output ?? 'No output generated';
637
- break;
638
- }
639
- }
640
- }
641
- catch (e) {
642
- if (e instanceof OutputParserException) {
643
- logger.error(`โŒ Output parsing error during step ${stepNum + 1}: ${e}`);
644
- result = `Agent stopped due to a parsing error: ${e}`;
645
- runManager?.handleChainError(result);
646
- break;
647
- }
648
- logger.error(`โŒ Error during agent execution step ${stepNum + 1}: ${e}`);
649
- console.error(e);
650
- result = `Agent stopped due to an error: ${e}`;
651
- runManager?.handleChainError(result);
652
- break;
653
- }
654
- }
655
- // โ€”โ€“โ€“ Postโ€‘loop handling
656
- if (!result) {
657
- logger.warn(`โš ๏ธ Agent stopped after reaching max iterations (${steps})`);
658
- result = `Agent stopped after reaching the maximum number of steps (${steps}).`;
659
- runManager?.handleChainEnd({ output: result });
660
- }
661
- logger.info('๐ŸŽ‰ Agent execution complete');
662
- success = true;
663
- // Return regular result
664
- return result;
665
- }
666
- catch (e) {
667
- logger.error(`โŒ Error running query: ${e}`);
668
- if (initializedHere && manageConnector) {
669
- logger.info('๐Ÿงน Cleaning up resources after initialization error in run');
670
- await this.close();
671
- }
672
- throw e;
673
- }
674
- finally {
675
- // Track comprehensive execution data
676
- const executionTimeMs = Date.now() - startTime;
677
- let serverCount = 0;
678
- if (this.client) {
679
- serverCount = Object.keys(this.client.getAllActiveSessions()).length;
680
- }
681
- else if (this.connectors) {
682
- serverCount = this.connectors.length;
683
- }
684
- const conversationHistoryLength = this.memoryEnabled ? this.conversationHistory.length : 0;
685
- await this.telemetry.trackAgentExecution({
686
- executionMethod: 'stream',
687
- query,
688
- success,
689
- modelProvider: this.modelProvider,
690
- modelName: this.modelName,
691
- serverCount,
692
- serverIdentifiers: this.connectors.map(connector => connector.publicIdentifier),
693
- totalToolsAvailable: this._tools.length,
694
- toolsAvailableNames: this._tools.map(t => t.name),
695
- maxStepsConfigured: this.maxSteps,
696
- memoryEnabled: this.memoryEnabled,
697
- useServerManager: this.useServerManager,
698
- maxStepsUsed: maxSteps ?? null,
699
- manageConnector,
700
- externalHistoryUsed: externalHistory !== undefined,
701
- stepsTaken,
702
- toolsUsedCount: toolsUsedNames.length,
703
- toolsUsedNames,
704
- response: result,
705
- executionTimeMs,
706
- errorType: success ? null : 'execution_error',
707
- conversationHistoryLength,
708
- });
709
- if (manageConnector && !this.client && initializedHere) {
710
- logger.info('๐Ÿงน Closing agent after query completion');
711
- await this.close();
712
- }
713
- }
714
- }
715
- async close() {
716
- // Delegate to remote agent if in remote mode
717
- if (this.isRemote && this.remoteAgent) {
718
- await this.remoteAgent.close();
719
- return;
720
- }
721
- logger.info('๐Ÿ”Œ Closing MCPAgent resourcesโ€ฆ');
722
- // Shutdown observability handlers (important for serverless)
723
- await this.observabilityManager.shutdown();
724
- try {
725
- this._agentExecutor = null;
726
- this._tools = [];
727
- if (this.client) {
728
- logger.info('๐Ÿ”„ Closing sessions through client');
729
- await this.client.closeAllSessions();
730
- this.sessions = {};
731
- }
732
- else {
733
- for (const connector of this.connectors) {
734
- logger.info('๐Ÿ”„ Disconnecting connector');
735
- await connector.disconnect();
736
- }
737
- }
738
- if ('connectorToolMap' in this.adapter) {
739
- this.adapter = new LangChainAdapter();
740
- }
741
- }
742
- finally {
743
- this._initialized = false;
744
- logger.info('๐Ÿ‘‹ Agent closed successfully');
745
- }
746
- }
747
- /**
748
- * Yields LangChain StreamEvent objects from the underlying streamEvents() method.
749
- * This provides token-level streaming and fine-grained event updates.
750
- */
751
- async *streamEvents(query, maxSteps, manageConnector = true, externalHistory) {
752
- let initializedHere = false;
753
- const startTime = Date.now();
754
- let success = false;
755
- let eventCount = 0;
756
- let totalResponseLength = 0;
757
- let finalResponse = '';
758
- try {
759
- // Initialize if needed
760
- if (manageConnector && !this._initialized) {
761
- await this.initialize();
762
- initializedHere = true;
763
- }
764
- else if (!this._initialized && this.autoInitialize) {
765
- await this.initialize();
766
- initializedHere = true;
767
- }
768
- const agentExecutor = this.agentExecutor;
769
- if (!agentExecutor) {
770
- throw new Error('MCP agent failed to initialize');
771
- }
772
- // Set max iterations
773
- const steps = maxSteps ?? this.maxSteps;
774
- agentExecutor.maxIterations = steps;
775
- const display_query = query.length > 50 ? `${query.slice(0, 50).replace(/\n/g, ' ')}...` : query.replace(/\n/g, ' ');
776
- logger.info(`๐Ÿ’ฌ Received query for streamEvents: '${display_query}'`);
777
- // Add user message to history if memory enabled
778
- if (this.memoryEnabled) {
779
- logger.info(`๐Ÿ”„ Adding user message to history: ${query}`);
780
- this.addToHistory(new HumanMessage(query));
781
- }
782
- // Prepare history
783
- const historyToUse = externalHistory ?? this.conversationHistory;
784
- const langchainHistory = [];
785
- for (const msg of historyToUse) {
786
- if (msg instanceof HumanMessage || msg instanceof AIMessage || msg instanceof ToolMessage) {
787
- langchainHistory.push(msg);
788
- }
789
- else {
790
- logger.info(`โš ๏ธ Skipped message of type: ${msg.constructor.name}`);
791
- }
792
- }
793
- // Prepare inputs
794
- const inputs = { input: query, chat_history: langchainHistory };
795
- logger.info('callbacks', this.callbacks);
796
- // Stream events from the agent executor
797
- const eventStream = agentExecutor.streamEvents(inputs, {
798
- version: 'v2',
799
- callbacks: this.callbacks.length > 0 ? this.callbacks : undefined,
800
- });
801
- // Yield each event
802
- for await (const event of eventStream) {
803
- eventCount++;
804
- // Skip null or invalid events
805
- if (!event || typeof event !== 'object') {
806
- continue;
807
- }
808
- // Track response length for telemetry
809
- if (event.event === 'on_chat_model_stream' && event.data?.chunk?.content) {
810
- totalResponseLength += event.data.chunk.content.length;
811
- }
812
- yield event;
813
- // Capture final response from chain end event
814
- if (event.event === 'on_chain_end' && event.data?.output) {
815
- const output = event.data.output;
816
- if (Array.isArray(output) && output.length > 0 && output[0]?.text) {
817
- finalResponse = output[0].text;
818
- }
819
- }
820
- }
821
- // Add the final AI response to conversation history if memory is enabled
822
- if (this.memoryEnabled && finalResponse) {
823
- this.addToHistory(new AIMessage(finalResponse));
824
- }
825
- logger.info(`๐ŸŽ‰ StreamEvents complete - ${eventCount} events emitted`);
826
- success = true;
827
- }
828
- catch (e) {
829
- logger.error(`โŒ Error during streamEvents: ${e}`);
830
- if (initializedHere && manageConnector) {
831
- logger.info('๐Ÿงน Cleaning up resources after initialization error in streamEvents');
832
- await this.close();
833
- }
834
- throw e;
835
- }
836
- finally {
837
- // Track telemetry
838
- const executionTimeMs = Date.now() - startTime;
839
- let serverCount = 0;
840
- if (this.client) {
841
- serverCount = Object.keys(this.client.getAllActiveSessions()).length;
842
- }
843
- else if (this.connectors) {
844
- serverCount = this.connectors.length;
845
- }
846
- const conversationHistoryLength = this.memoryEnabled ? this.conversationHistory.length : 0;
847
- await this.telemetry.trackAgentExecution({
848
- executionMethod: 'streamEvents',
849
- query,
850
- success,
851
- modelProvider: this.modelProvider,
852
- modelName: this.modelName,
853
- serverCount,
854
- serverIdentifiers: this.connectors.map(connector => connector.publicIdentifier),
855
- totalToolsAvailable: this._tools.length,
856
- toolsAvailableNames: this._tools.map(t => t.name),
857
- maxStepsConfigured: this.maxSteps,
858
- memoryEnabled: this.memoryEnabled,
859
- useServerManager: this.useServerManager,
860
- maxStepsUsed: maxSteps ?? null,
861
- manageConnector,
862
- externalHistoryUsed: externalHistory !== undefined,
863
- response: `[STREAMED RESPONSE - ${totalResponseLength} chars]`,
864
- executionTimeMs,
865
- errorType: success ? null : 'streaming_error',
866
- conversationHistoryLength,
867
- });
868
- // Clean up if needed
869
- if (manageConnector && !this.client && initializedHere) {
870
- logger.info('๐Ÿงน Closing agent after streamEvents completion');
871
- await this.close();
872
- }
873
- }
874
- }
875
- /**
876
- * Attempt to create structured output from raw result with validation and retry logic.
877
- */
878
- async _attemptStructuredOutput(rawResult, structuredLlm, outputSchema, schemaDescription) {
879
- logger.info(`๐Ÿ”„ Attempting structured output with schema: ${outputSchema}`);
880
- logger.info(`๐Ÿ”„ Schema description: ${schemaDescription}`);
881
- logger.info(`๐Ÿ”„ Raw result: ${JSON.stringify(rawResult, null, 2)}`);
882
- // Handle different input formats - rawResult might be an array or object from the agent
883
- let textContent = '';
884
- if (typeof rawResult === 'string') {
885
- textContent = rawResult;
886
- }
887
- else if (rawResult && typeof rawResult === 'object') {
888
- // Handle object format
889
- textContent = JSON.stringify(rawResult);
890
- }
891
- // If we couldn't extract text, use the stringified version
892
- if (!textContent) {
893
- textContent = JSON.stringify(rawResult);
894
- }
895
- // Get detailed schema information for better prompting
896
- const maxRetries = 3;
897
- let lastError = '';
898
- for (let attempt = 1; attempt <= maxRetries; attempt++) {
899
- logger.info(`๐Ÿ”„ Structured output attempt ${attempt}/${maxRetries}`);
900
- let formatPrompt = `
901
- Please format the following information according to the EXACT schema specified below.
902
- You must use the exact field names and types as shown in the schema.
903
-
904
- Required schema format:
905
- ${schemaDescription}
906
-
907
- Content to extract from:
908
- ${textContent}
909
-
910
- IMPORTANT:
911
- - Use ONLY the field names specified in the schema
912
- - Match the data types exactly (string, number, boolean, array, etc.)
913
- - Include ALL required fields
914
- - Return valid JSON that matches the schema structure exactly
915
- `;
916
- // Add specific error feedback for retry attempts
917
- if (attempt > 1) {
918
- formatPrompt += `
919
-
920
- PREVIOUS ATTEMPT FAILED with error: ${lastError}
921
- Please fix the issues mentioned above and ensure the output matches the schema exactly.
922
- `;
923
- }
924
- try {
925
- const structuredResult = await structuredLlm.invoke(formatPrompt);
926
- logger.info(`๐Ÿ”„ Structured result attempt ${attempt}: ${JSON.stringify(structuredResult, null, 2)}`);
927
- // Validate the structured result
928
- const validatedResult = this._validateStructuredResult(structuredResult, outputSchema);
929
- logger.info(`โœ… Structured output successful on attempt ${attempt}`);
930
- return validatedResult;
931
- }
932
- catch (e) {
933
- lastError = e instanceof Error ? e.message : String(e);
934
- logger.warn(`โš ๏ธ Structured output attempt ${attempt} failed: ${lastError}`);
935
- if (attempt === maxRetries) {
936
- logger.error(`โŒ All ${maxRetries} structured output attempts failed`);
937
- throw new Error(`Failed to generate valid structured output after ${maxRetries} attempts. Last error: ${lastError}`);
938
- }
939
- // Continue to next attempt
940
- continue;
941
- }
942
- }
943
- // This should never be reached, but TypeScript requires it
944
- throw new Error('Unexpected error in structured output generation');
945
- }
946
- /**
947
- * Validate the structured result against the schema with detailed error reporting
948
- */
949
- _validateStructuredResult(structuredResult, outputSchema) {
950
- // Use Zod to validate the structured result
951
- try {
952
- // Use Zod to validate the structured result
953
- const validatedResult = outputSchema.parse(structuredResult);
954
- // Additional validation for required fields
955
- const schemaType = outputSchema;
956
- if (schemaType._def && schemaType._def.shape) {
957
- for (const [fieldName, fieldSchema] of Object.entries(schemaType._def.shape)) {
958
- const field = fieldSchema;
959
- const isOptional = field.isOptional?.() ?? field._def?.typeName === 'ZodOptional';
960
- const isNullable = field.isNullable?.() ?? field._def?.typeName === 'ZodNullable';
961
- if (!isOptional && !isNullable) {
962
- const value = validatedResult[fieldName];
963
- if (value === null || value === undefined
964
- || (typeof value === 'string' && !value.trim())
965
- || (Array.isArray(value) && value.length === 0)) {
966
- throw new Error(`Required field '${fieldName}' is missing or empty`);
967
- }
968
- }
969
- }
970
- }
971
- return validatedResult;
972
- }
973
- catch (e) {
974
- logger.debug(`Validation details: ${e}`);
975
- throw e; // Re-raise to trigger retry logic
976
- }
977
- }
978
- /**
979
- * Enhance the query with schema information to make the agent aware of required fields.
980
- */
981
- _enhanceQueryWithSchema(query, outputSchema) {
982
- try {
983
- const schemaDescription = JSON.stringify(zodToJsonSchema(outputSchema), null, 2);
984
- // Enhance the query with schema awareness
985
- const enhancedQuery = `
986
- ${query}
987
-
988
- IMPORTANT: Your response must include sufficient information to populate the following structured output:
989
-
990
- ${schemaDescription}
991
-
992
- Make sure you gather ALL the required information during your task execution.
993
- If any required information is missing, continue working to find it.
994
- `;
995
- return enhancedQuery;
996
- }
997
- catch (e) {
998
- logger.warn(`Could not extract schema details: ${e}`);
999
- return query;
1000
- }
1001
- }
1002
- }