mcp-use 0.2.0 → 0.3.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,427 +0,0 @@
1
- /**
2
- * OAuth helper for browser-based MCP authentication
3
- *
4
- * This helper provides OAuth 2.0 authorization code flow support for MCP servers
5
- * that require authentication, such as Linear's MCP server.
6
- */
7
- export class OAuthHelper {
8
- config;
9
- discovery;
10
- state;
11
- clientRegistration;
12
- serverUrl;
13
- storageKey;
14
- constructor(config) {
15
- this.config = config;
16
- this.storageKey = `mcp-oauth-${btoa(config.redirectUri)}`;
17
- this.state = {
18
- isRequired: false,
19
- isAuthenticated: false,
20
- isAuthenticating: false,
21
- isCompletingOAuth: false,
22
- authError: null,
23
- oauthTokens: null,
24
- };
25
- // Load persisted client registration
26
- this.loadClientRegistration();
27
- }
28
- /**
29
- * Get current OAuth state
30
- */
31
- getState() {
32
- return { ...this.state };
33
- }
34
- /**
35
- * Load client registration from localStorage
36
- */
37
- loadClientRegistration() {
38
- try {
39
- const stored = localStorage.getItem(this.storageKey);
40
- if (stored) {
41
- const data = JSON.parse(stored);
42
- this.clientRegistration = data.clientRegistration;
43
- this.serverUrl = data.serverUrl;
44
- console.log('🔄 [OAuthHelper] Loaded persisted client registration:', {
45
- client_id: this.clientRegistration?.client_id,
46
- server: this.serverUrl,
47
- });
48
- }
49
- }
50
- catch (error) {
51
- console.warn('⚠️ [OAuthHelper] Failed to load client registration:', error);
52
- }
53
- }
54
- /**
55
- * Save client registration to localStorage
56
- */
57
- saveClientRegistration() {
58
- try {
59
- const data = {
60
- clientRegistration: this.clientRegistration,
61
- serverUrl: this.serverUrl,
62
- };
63
- localStorage.setItem(this.storageKey, JSON.stringify(data));
64
- console.log('💾 [OAuthHelper] Saved client registration to localStorage');
65
- }
66
- catch (error) {
67
- console.warn('⚠️ [OAuthHelper] Failed to save client registration:', error);
68
- }
69
- }
70
- /**
71
- * Check if a server requires authentication by pinging the URL
72
- */
73
- async checkAuthRequired(serverUrl) {
74
- console.log('🔍 [OAuthHelper] Checking auth requirement for:', serverUrl);
75
- try {
76
- const response = await fetch(serverUrl, {
77
- method: 'GET',
78
- headers: {
79
- 'Accept': 'text/event-stream',
80
- 'Cache-Control': 'no-cache',
81
- },
82
- redirect: 'manual',
83
- signal: AbortSignal.timeout(10000), // 10 second timeout
84
- });
85
- console.log('🔍 [OAuthHelper] Auth check response:', {
86
- status: response.status,
87
- statusText: response.statusText,
88
- url: serverUrl,
89
- });
90
- // 401 Unauthorized, 403 Forbidden, or 400 Bad Request means auth is required
91
- if (response.status === 401 || response.status === 403 || response.status === 400) {
92
- console.log('🔐 [OAuthHelper] Authentication required for:', serverUrl);
93
- return true;
94
- }
95
- // Any other response (200, 404, 500, etc.) means no auth required
96
- console.log('✅ [OAuthHelper] No authentication required for:', serverUrl);
97
- return false;
98
- }
99
- catch (error) {
100
- console.warn('⚠️ [OAuthHelper] Could not check auth requirement for:', serverUrl, error);
101
- // Handle specific error types
102
- if (error.name === 'TypeError'
103
- && (error.message?.includes('CORS') || error.message?.includes('Failed to fetch'))) {
104
- console.log('🔍 [OAuthHelper] CORS blocked direct check, using heuristics for:', serverUrl);
105
- return this.checkAuthByHeuristics(serverUrl);
106
- }
107
- if (error.name === 'AbortError') {
108
- console.log('⏰ [OAuthHelper] Request timeout, assuming no auth required for:', serverUrl);
109
- return false;
110
- }
111
- // If we can't reach the server at all, try heuristics
112
- return this.checkAuthByHeuristics(serverUrl);
113
- }
114
- }
115
- /**
116
- * Fallback heuristics for determining auth requirements when direct checking fails
117
- */
118
- checkAuthByHeuristics(serverUrl) {
119
- console.log('🔍 [OAuthHelper] Using heuristics to determine auth for:', serverUrl);
120
- // Known patterns that typically require auth
121
- const authRequiredPatterns = [
122
- /api\.githubcopilot\.com/i, // GitHub Copilot
123
- /api\.github\.com/i, // GitHub API
124
- /.*\.googleapis\.com/i, // Google APIs
125
- /api\.openai\.com/i, // OpenAI
126
- /api\.anthropic\.com/i, // Anthropic
127
- /.*\.atlassian\.net/i, // Atlassian (Jira, Confluence)
128
- /.*\.slack\.com/i, // Slack
129
- /api\.notion\.com/i, // Notion
130
- /api\.linear\.app/i, // Linear
131
- ];
132
- // Known patterns that typically don't require auth (public MCP servers)
133
- const noAuthPatterns = [
134
- /localhost/i, // Local development
135
- /127\.0\.0\.1/, // Local development
136
- /\.local/i, // Local development
137
- /mcp\..*\.com/i, // Generic MCP server pattern (often public)
138
- ];
139
- // Check no-auth patterns first
140
- for (const pattern of noAuthPatterns) {
141
- if (pattern.test(serverUrl)) {
142
- console.log('✅ [OAuthHelper] Heuristic: No auth required (matches no-auth pattern):', serverUrl);
143
- return false;
144
- }
145
- }
146
- // Check auth-required patterns
147
- for (const pattern of authRequiredPatterns) {
148
- if (pattern.test(serverUrl)) {
149
- console.log('🔐 [OAuthHelper] Heuristic: Auth required (matches auth pattern):', serverUrl);
150
- return true;
151
- }
152
- }
153
- // Default: assume no auth required for unknown patterns
154
- console.log('❓ [OAuthHelper] Heuristic: Unknown pattern, assuming no auth required:', serverUrl);
155
- return false;
156
- }
157
- /**
158
- * Discover OAuth configuration from a server
159
- */
160
- async discoverOAuthConfig(serverUrl) {
161
- try {
162
- const discoveryUrl = `${serverUrl}/.well-known/oauth-authorization-server`;
163
- const response = await fetch(discoveryUrl);
164
- if (!response.ok) {
165
- throw new Error(`OAuth discovery failed: ${response.status} ${response.statusText}`);
166
- }
167
- this.discovery = await response.json();
168
- return this.discovery;
169
- }
170
- catch (error) {
171
- throw new Error(`Failed to discover OAuth configuration: ${error}`);
172
- }
173
- }
174
- /**
175
- * Register a new OAuth client dynamically
176
- */
177
- async registerClient(serverUrl) {
178
- if (!this.discovery) {
179
- throw new Error('OAuth discovery not performed. Call discoverOAuthConfig first.');
180
- }
181
- if (!this.discovery.registration_endpoint) {
182
- throw new Error('Server does not support dynamic client registration');
183
- }
184
- try {
185
- const registrationData = {
186
- client_name: this.config.clientName || 'MCP Use Example',
187
- redirect_uris: [this.config.redirectUri],
188
- grant_types: ['authorization_code'],
189
- response_types: ['code'],
190
- token_endpoint_auth_method: 'none', // Use public client (no secret)
191
- scope: this.config.scope || 'read write',
192
- };
193
- console.log('🔐 [OAuthHelper] Registering OAuth client dynamically:', {
194
- registration_endpoint: this.discovery.registration_endpoint,
195
- client_name: registrationData.client_name,
196
- redirect_uri: this.config.redirectUri,
197
- });
198
- const response = await fetch(this.discovery.registration_endpoint, {
199
- method: 'POST',
200
- headers: {
201
- 'Content-Type': 'application/json',
202
- },
203
- body: JSON.stringify(registrationData),
204
- });
205
- if (!response.ok) {
206
- const errorText = await response.text();
207
- throw new Error(`Client registration failed: ${response.status} ${response.statusText} - ${errorText}`);
208
- }
209
- this.clientRegistration = await response.json();
210
- this.serverUrl = serverUrl;
211
- this.saveClientRegistration();
212
- console.log('✅ [OAuthHelper] Client registered successfully:', {
213
- client_id: this.clientRegistration.client_id,
214
- client_secret: this.clientRegistration.client_secret ? '***' : 'none',
215
- });
216
- return this.clientRegistration;
217
- }
218
- catch (error) {
219
- console.error('❌ [OAuthHelper] Client registration failed:', error);
220
- throw new Error(`Failed to register OAuth client: ${error}`);
221
- }
222
- }
223
- /**
224
- * Generate authorization URL for OAuth flow
225
- */
226
- generateAuthUrl(serverUrl, additionalParams) {
227
- if (!this.discovery) {
228
- throw new Error('OAuth discovery not performed. Call discoverOAuthConfig first.');
229
- }
230
- if (!this.clientRegistration) {
231
- throw new Error('Client not registered. Call registerClient first.');
232
- }
233
- const params = new URLSearchParams({
234
- client_id: this.clientRegistration.client_id,
235
- redirect_uri: this.config.redirectUri,
236
- response_type: 'code',
237
- scope: this.config.scope || 'read',
238
- state: this.config.state || this.generateState(),
239
- ...additionalParams,
240
- });
241
- return `${this.discovery.authorization_endpoint}?${params.toString()}`;
242
- }
243
- /**
244
- * Exchange authorization code for access token
245
- */
246
- async exchangeCodeForToken(serverUrl, code, codeVerifier) {
247
- if (!this.discovery) {
248
- throw new Error('OAuth discovery not performed. Call discoverOAuthConfig first.');
249
- }
250
- if (!this.clientRegistration) {
251
- throw new Error('Client not registered. Call registerClient first.');
252
- }
253
- const body = new URLSearchParams({
254
- grant_type: 'authorization_code',
255
- client_id: this.clientRegistration.client_id,
256
- code,
257
- redirect_uri: this.config.redirectUri,
258
- });
259
- if (codeVerifier) {
260
- body.append('code_verifier', codeVerifier);
261
- }
262
- const response = await fetch(this.discovery.token_endpoint, {
263
- method: 'POST',
264
- headers: {
265
- 'Content-Type': 'application/x-www-form-urlencoded',
266
- },
267
- body: body.toString(),
268
- });
269
- if (!response.ok) {
270
- const error = await response.text();
271
- throw new Error(`Token exchange failed: ${response.status} ${response.statusText} - ${error}`);
272
- }
273
- return await response.json();
274
- }
275
- /**
276
- * Handle OAuth callback and extract authorization code
277
- */
278
- handleCallback() {
279
- const urlParams = new URLSearchParams(window.location.search);
280
- const code = urlParams.get('code');
281
- const state = urlParams.get('state');
282
- if (!code || !state) {
283
- return null;
284
- }
285
- // Clean up URL
286
- const url = new URL(window.location.href);
287
- url.searchParams.delete('code');
288
- url.searchParams.delete('state');
289
- window.history.replaceState({}, '', url.toString());
290
- return { code, state };
291
- }
292
- /**
293
- * Start OAuth flow by opening popup window (similar to your implementation)
294
- */
295
- async startOAuthFlow(serverUrl) {
296
- this.setState({
297
- isAuthenticating: true,
298
- authError: null,
299
- });
300
- try {
301
- // Step 1: Discover OAuth configuration
302
- await this.discoverOAuthConfig(serverUrl);
303
- // Step 2: Register client dynamically (if not already registered)
304
- if (!this.clientRegistration) {
305
- await this.registerClient(serverUrl);
306
- }
307
- // Step 3: Generate authorization URL
308
- const authUrl = this.generateAuthUrl(serverUrl);
309
- // Step 4: Open popup window for authentication
310
- const authWindow = window.open(authUrl, 'mcp-oauth', 'width=500,height=600,scrollbars=yes,resizable=yes,status=yes,location=yes');
311
- if (!authWindow) {
312
- throw new Error('Failed to open authentication window. Please allow popups for this site and try again.');
313
- }
314
- console.log('✅ [OAuthHelper] OAuth popup opened successfully');
315
- }
316
- catch (error) {
317
- console.error('❌ [OAuthHelper] Failed to start OAuth flow:', error);
318
- this.setState({
319
- isAuthenticating: false,
320
- authError: error instanceof Error ? error.message : 'Failed to start authentication',
321
- });
322
- throw error;
323
- }
324
- }
325
- /**
326
- * Complete OAuth flow by exchanging code for token
327
- */
328
- async completeOAuthFlow(serverUrl, code) {
329
- this.setState({
330
- isCompletingOAuth: true,
331
- authError: null,
332
- });
333
- try {
334
- // If we don't have discovery data, re-discover it
335
- if (!this.discovery) {
336
- console.log('🔍 [OAuthHelper] Re-discovering OAuth configuration for callback');
337
- await this.discoverOAuthConfig(serverUrl);
338
- }
339
- // Only re-register if we don't have a client registration for this server
340
- if (!this.clientRegistration || this.serverUrl !== serverUrl) {
341
- console.log('🔐 [OAuthHelper] Re-registering client for callback');
342
- await this.registerClient(serverUrl);
343
- }
344
- else {
345
- console.log('🔄 [OAuthHelper] Using existing client registration for callback');
346
- }
347
- const tokenResponse = await this.exchangeCodeForToken(serverUrl, code);
348
- this.setState({
349
- isAuthenticating: false,
350
- isAuthenticated: true,
351
- isCompletingOAuth: false,
352
- authError: null,
353
- oauthTokens: tokenResponse,
354
- });
355
- console.log('✅ [OAuthHelper] OAuth flow completed successfully');
356
- return tokenResponse;
357
- }
358
- catch (error) {
359
- console.error('❌ [OAuthHelper] Failed to complete OAuth flow:', error);
360
- this.setState({
361
- isAuthenticating: false,
362
- isCompletingOAuth: false,
363
- authError: error instanceof Error ? error.message : 'Failed to complete authentication',
364
- });
365
- throw error;
366
- }
367
- }
368
- /**
369
- * Reset authentication state
370
- */
371
- resetAuth() {
372
- this.setState({
373
- isRequired: false,
374
- isAuthenticated: false,
375
- isAuthenticating: false,
376
- isCompletingOAuth: false,
377
- authError: null,
378
- oauthTokens: null,
379
- });
380
- // Clear stored client registration
381
- this.clientRegistration = undefined;
382
- this.serverUrl = undefined;
383
- try {
384
- localStorage.removeItem(this.storageKey);
385
- console.log('🗑️ [OAuthHelper] Cleared stored client registration');
386
- }
387
- catch (error) {
388
- console.warn('⚠️ [OAuthHelper] Failed to clear client registration:', error);
389
- }
390
- }
391
- /**
392
- * Set OAuth state (internal method)
393
- */
394
- setState(newState) {
395
- this.state = { ...this.state, ...newState };
396
- }
397
- /**
398
- * Generate a random state parameter for CSRF protection
399
- */
400
- generateState() {
401
- return Math.random().toString(36).substring(2, 15)
402
- + Math.random().toString(36).substring(2, 15);
403
- }
404
- }
405
- /**
406
- * Linear-specific OAuth configuration
407
- */
408
- export const LINEAR_OAUTH_CONFIG = {
409
- // No clientId needed - will use dynamic client registration
410
- redirectUri: typeof window !== 'undefined' ? window.location.origin + window.location.pathname : 'http://localhost:5174',
411
- scope: 'read write',
412
- clientName: 'MCP Use Example',
413
- };
414
- /**
415
- * Helper function to create OAuth-enabled MCP configuration
416
- */
417
- export function createOAuthMCPConfig(serverUrl, accessToken) {
418
- return {
419
- mcpServers: {
420
- linear: {
421
- url: serverUrl,
422
- authToken: accessToken,
423
- transport: 'sse',
424
- },
425
- },
426
- };
427
- }
@@ -1,12 +0,0 @@
1
- /**
2
- * Observability module for MCP-use.
3
- *
4
- * This module provides centralized observability management for LangChain agents,
5
- * supporting multiple platforms like Langfuse and Laminar.
6
- */
7
- // Import observability providers - order matters for initialization
8
- import './langfuse.js';
9
- // Re-export individual handlers for direct usage if needed
10
- export { langfuseClient, langfuseHandler, langfuseInitPromise, } from './langfuse.js';
11
- // Export the manager and its utilities
12
- export { createManager, getDefaultManager, ObservabilityManager, } from './manager.js';
@@ -1,211 +0,0 @@
1
- /**
2
- * Langfuse observability integration for MCP-use.
3
- *
4
- * This module provides automatic instrumentation and callback handler
5
- * for Langfuse observability platform.
6
- */
7
- import { config } from 'dotenv';
8
- import { logger } from '../logging.js';
9
- config();
10
- // Check if Langfuse is disabled via environment variable
11
- const langfuseDisabled = process.env.MCP_USE_LANGFUSE?.toLowerCase() === 'false';
12
- // Initialize variables - using const with object to avoid linter issues with mutable exports
13
- const langfuseState = {
14
- handler: null,
15
- client: null,
16
- initPromise: null,
17
- };
18
- async function initializeLangfuse(agentId, metadata, metadataProvider, tagsProvider) {
19
- try {
20
- // Dynamically import to avoid errors if package not installed
21
- const langfuseModule = await import('langfuse-langchain').catch(() => null);
22
- if (!langfuseModule) {
23
- logger.debug('Langfuse package not installed - tracing disabled. Install with: npm install langfuse-langchain');
24
- return;
25
- }
26
- const { CallbackHandler } = langfuseModule;
27
- // Create a custom CallbackHandler wrapper to add logging and custom metadata
28
- class LoggingCallbackHandler extends CallbackHandler {
29
- agentId;
30
- metadata;
31
- metadataProvider;
32
- tagsProvider;
33
- verbose;
34
- constructor(config, agentId, metadata, metadataProvider, tagsProvider) {
35
- super(config);
36
- this.agentId = agentId;
37
- this.metadata = metadata;
38
- this.metadataProvider = metadataProvider;
39
- this.tagsProvider = tagsProvider;
40
- this.verbose = config?.verbose ?? false;
41
- }
42
- // Override to add custom metadata to traces
43
- async handleChainStart(chain, inputs, runId, parentRunId, tags, metadata, name, kwargs) {
44
- logger.debug('Langfuse: Chain start intercepted');
45
- // Add custom tags and metadata
46
- const customTags = this.getCustomTags();
47
- const metadataToAdd = this.getMetadata();
48
- // Merge with existing tags and metadata
49
- const enhancedTags = [...(tags || []), ...customTags];
50
- const enhancedMetadata = { ...(metadata || {}), ...metadataToAdd };
51
- if (this.verbose) {
52
- logger.debug(`Langfuse: Chain start with custom tags: ${JSON.stringify(enhancedTags)}`);
53
- logger.debug(`Langfuse: Chain start with metadata: ${JSON.stringify(enhancedMetadata)}`);
54
- }
55
- return super.handleChainStart(chain, inputs, runId, parentRunId, enhancedTags, enhancedMetadata, name, kwargs);
56
- }
57
- // Get custom tags based on environment and agent configuration
58
- getCustomTags() {
59
- const tags = [];
60
- // Add environment tag
61
- const env = this.getEnvironmentTag();
62
- if (env) {
63
- tags.push(`env:${env}`);
64
- }
65
- // Add agent ID tag if available
66
- if (this.agentId) {
67
- tags.push(`agent_id:${this.agentId}`);
68
- }
69
- // Add tags from provider if available
70
- if (this.tagsProvider) {
71
- const providerTags = this.tagsProvider();
72
- if (providerTags && providerTags.length > 0) {
73
- tags.push(...providerTags);
74
- }
75
- }
76
- return tags;
77
- }
78
- // Get metadata
79
- getMetadata() {
80
- const metadata = {};
81
- // Add environment metadata
82
- const env = this.getEnvironmentTag();
83
- if (env) {
84
- metadata.env = env;
85
- }
86
- // Add agent ID metadata if available
87
- if (this.agentId) {
88
- metadata.agent_id = this.agentId;
89
- }
90
- // Add static metadata if provided
91
- if (this.metadata) {
92
- Object.assign(metadata, this.metadata);
93
- }
94
- // Add dynamic metadata from provider if available
95
- if (this.metadataProvider) {
96
- const dynamicMetadata = this.metadataProvider();
97
- if (dynamicMetadata) {
98
- Object.assign(metadata, dynamicMetadata);
99
- }
100
- }
101
- return metadata;
102
- }
103
- // Determine environment tag based on MCP_USE_AGENT_ENV
104
- getEnvironmentTag() {
105
- const agentEnv = process.env.MCP_USE_AGENT_ENV;
106
- if (!agentEnv) {
107
- // Default to 'unknown' if environment is not explicitly set
108
- return 'unknown';
109
- }
110
- const envLower = agentEnv.toLowerCase();
111
- if (envLower === 'local' || envLower === 'development') {
112
- return 'local';
113
- }
114
- else if (envLower === 'production' || envLower === 'prod') {
115
- return 'production';
116
- }
117
- else if (envLower === 'staging' || envLower === 'stage') {
118
- return 'staging';
119
- }
120
- else if (envLower === 'hosted' || envLower === 'cloud') {
121
- return 'hosted';
122
- }
123
- // For any other values, use the value as-is but sanitized
124
- return envLower.replace(/[^a-z0-9_-]/g, '_');
125
- }
126
- async handleLLMStart(...args) {
127
- logger.debug('Langfuse: LLM start intercepted');
128
- if (this.verbose) {
129
- logger.debug(`Langfuse: LLM start args: ${JSON.stringify(args)}`);
130
- }
131
- return super.handleLLMStart(...args);
132
- }
133
- async handleToolStart(...args) {
134
- logger.debug('Langfuse: Tool start intercepted');
135
- if (this.verbose) {
136
- logger.debug(`Langfuse: Tool start args: ${JSON.stringify(args)}`);
137
- }
138
- return super.handleToolStart(...args);
139
- }
140
- async handleRetrieverStart(...args) {
141
- logger.debug('Langfuse: Retriever start intercepted');
142
- if (this.verbose) {
143
- logger.debug(`Langfuse: Retriever start args: ${JSON.stringify(args)}`);
144
- }
145
- return super.handleRetrieverStart(...args);
146
- }
147
- async handleAgentAction(...args) {
148
- logger.debug('Langfuse: Agent action intercepted');
149
- if (this.verbose) {
150
- logger.debug(`Langfuse: Agent action args: ${JSON.stringify(args)}`);
151
- }
152
- return super.handleAgentAction(...args);
153
- }
154
- async handleAgentEnd(...args) {
155
- logger.debug('Langfuse: Agent end intercepted');
156
- if (this.verbose) {
157
- logger.debug(`Langfuse: Agent end args: ${JSON.stringify(args)}`);
158
- }
159
- return super.handleAgentEnd(...args);
160
- }
161
- }
162
- // Create the handler with configuration
163
- const config = {
164
- publicKey: process.env.LANGFUSE_PUBLIC_KEY,
165
- secretKey: process.env.LANGFUSE_SECRET_KEY,
166
- baseUrl: process.env.LANGFUSE_HOST || process.env.LANGFUSE_BASEURL || 'https://cloud.langfuse.com',
167
- flushAt: Number.parseInt(process.env.LANGFUSE_FLUSH_AT || '15'),
168
- flushInterval: Number.parseInt(process.env.LANGFUSE_FLUSH_INTERVAL || '10000'),
169
- release: process.env.LANGFUSE_RELEASE,
170
- requestTimeout: Number.parseInt(process.env.LANGFUSE_REQUEST_TIMEOUT || '10000'),
171
- enabled: process.env.LANGFUSE_ENABLED !== 'false',
172
- };
173
- langfuseState.handler = new LoggingCallbackHandler(config, agentId, metadata, metadataProvider, tagsProvider);
174
- logger.debug('Langfuse observability initialized successfully with logging enabled');
175
- // Also initialize the client for direct usage if needed
176
- try {
177
- const langfuseCore = await import('langfuse').catch(() => null);
178
- if (langfuseCore) {
179
- const { Langfuse } = langfuseCore;
180
- langfuseState.client = new Langfuse({
181
- publicKey: process.env.LANGFUSE_PUBLIC_KEY,
182
- secretKey: process.env.LANGFUSE_SECRET_KEY,
183
- baseUrl: process.env.LANGFUSE_HOST || 'https://cloud.langfuse.com',
184
- });
185
- logger.debug('Langfuse client initialized');
186
- }
187
- }
188
- catch (error) {
189
- logger.debug(`Langfuse client initialization failed: ${error}`);
190
- }
191
- }
192
- catch (error) {
193
- logger.debug(`Langfuse initialization error: ${error}`);
194
- }
195
- }
196
- // Only initialize if not disabled and required keys are present
197
- if (langfuseDisabled) {
198
- logger.debug('Langfuse tracing disabled via MCP_USE_LANGFUSE environment variable');
199
- }
200
- else if (!process.env.LANGFUSE_PUBLIC_KEY || !process.env.LANGFUSE_SECRET_KEY) {
201
- logger.debug('Langfuse API keys not found - tracing disabled. Set LANGFUSE_PUBLIC_KEY and LANGFUSE_SECRET_KEY to enable');
202
- }
203
- else {
204
- // Create initialization promise to ensure handlers are ready when needed
205
- langfuseState.initPromise = initializeLangfuse();
206
- }
207
- // Export getters to access the state
208
- export const langfuseHandler = () => langfuseState.handler;
209
- export const langfuseClient = () => langfuseState.client;
210
- export const langfuseInitPromise = () => langfuseState.initPromise;
211
- export { initializeLangfuse };