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.
- package/dist/chunk-2HFIPY7C.js +429 -0
- package/dist/chunk-4DEFXVWT.js +680 -0
- package/dist/chunk-JXLQRAW2.js +532 -0
- package/dist/chunk-SHUYVCID.js +6 -0
- package/dist/chunk-YUSC6R6V.js +299 -0
- package/dist/index.cjs +5762 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3767 -22
- package/dist/langfuse-YA2S23SM.js +13 -0
- package/dist/src/agents/remote.d.ts.map +1 -1
- package/dist/src/agents/utils/ai_sdk.d.ts.map +1 -1
- package/dist/src/auth/browser-provider.d.ts +52 -0
- package/dist/src/auth/browser-provider.d.ts.map +1 -0
- package/dist/src/auth/callback.d.ts +6 -0
- package/dist/src/auth/callback.d.ts.map +1 -0
- package/dist/src/auth/index.d.ts +7 -0
- package/dist/src/auth/index.d.ts.map +1 -0
- package/dist/src/auth/types.d.ts +18 -0
- package/dist/src/auth/types.d.ts.map +1 -0
- package/dist/src/browser.cjs +323 -0
- package/dist/src/browser.d.ts +5 -46
- package/dist/src/browser.d.ts.map +1 -1
- package/dist/src/browser.js +9 -75
- package/dist/src/oauth-helper.d.ts +2 -12
- package/dist/src/oauth-helper.d.ts.map +1 -1
- package/dist/src/react/index.cjs +986 -0
- package/dist/src/react/index.d.ts +9 -0
- package/dist/src/react/index.d.ts.map +1 -0
- package/dist/src/react/index.js +11 -0
- package/dist/src/react/types.d.ts +139 -0
- package/dist/src/react/types.d.ts.map +1 -0
- package/dist/src/react/useMcp.d.ts +3 -0
- package/dist/src/react/useMcp.d.ts.map +1 -0
- package/dist/src/server/index.cjs +566 -0
- package/dist/src/server/index.d.ts +3 -0
- package/dist/src/server/index.d.ts.map +1 -0
- package/dist/src/server/index.js +9 -0
- package/dist/src/server/logging.d.ts +16 -0
- package/dist/src/server/logging.d.ts.map +1 -0
- package/dist/src/server/mcp-server.d.ts +282 -0
- package/dist/src/server/mcp-server.d.ts.map +1 -0
- package/dist/src/server/types.d.ts +47 -0
- package/dist/src/server/types.d.ts.map +1 -0
- package/dist/src/utils/assert.d.ts +8 -0
- package/dist/src/utils/assert.d.ts.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +67 -40
- package/dist/src/adapters/base.js +0 -124
- package/dist/src/adapters/index.js +0 -2
- package/dist/src/adapters/langchain_adapter.js +0 -49
- package/dist/src/agents/base.js +0 -9
- package/dist/src/agents/index.js +0 -3
- package/dist/src/agents/mcp_agent.js +0 -1002
- package/dist/src/agents/prompts/system_prompt_builder.js +0 -40
- package/dist/src/agents/prompts/templates.js +0 -39
- package/dist/src/agents/remote.js +0 -264
- package/dist/src/agents/utils/ai_sdk.js +0 -62
- package/dist/src/agents/utils/index.js +0 -1
- package/dist/src/client/base.js +0 -119
- package/dist/src/client.js +0 -50
- package/dist/src/config.js +0 -34
- package/dist/src/connectors/base.js +0 -143
- package/dist/src/connectors/http.js +0 -150
- package/dist/src/connectors/index.js +0 -4
- package/dist/src/connectors/stdio.js +0 -68
- package/dist/src/connectors/websocket.js +0 -157
- package/dist/src/logging.js +0 -232
- package/dist/src/managers/index.js +0 -2
- package/dist/src/managers/server_manager.js +0 -106
- package/dist/src/managers/tools/acquire_active_mcp_server.js +0 -17
- package/dist/src/managers/tools/add_server_from_config.js +0 -40
- package/dist/src/managers/tools/base.js +0 -17
- package/dist/src/managers/tools/connect_mcp_server.js +0 -46
- package/dist/src/managers/tools/index.js +0 -5
- package/dist/src/managers/tools/list_mcp_servers.js +0 -33
- package/dist/src/managers/tools/release_mcp_server_connection.js +0 -19
- package/dist/src/oauth-helper.js +0 -427
- package/dist/src/observability/index.js +0 -12
- package/dist/src/observability/langfuse.js +0 -211
- package/dist/src/observability/manager.js +0 -199
- package/dist/src/observability/types.js +0 -4
- package/dist/src/session.js +0 -23
- package/dist/src/task_managers/base.js +0 -127
- package/dist/src/task_managers/index.js +0 -5
- package/dist/src/task_managers/sse.js +0 -43
- package/dist/src/task_managers/stdio.js +0 -51
- package/dist/src/task_managers/streamable_http.js +0 -50
- package/dist/src/task_managers/websocket.js +0 -67
- package/dist/src/telemetry/events.js +0 -44
- package/dist/src/telemetry/index.js +0 -8
- package/dist/src/telemetry/telemetry.js +0 -324
- package/dist/src/telemetry/utils.js +0 -39
- package/dist/tests/ai_sdk_compatibility.test.js +0 -214
- package/dist/tests/stream_events.test.js +0 -307
- package/dist/tests/stream_events_simple.test.js +0 -179
- package/dist/vitest.config.js +0 -21
package/dist/src/oauth-helper.js
DELETED
@@ -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 };
|