integrate-sdk 0.6.9 → 0.7.1

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.
@@ -10,6 +10,171 @@ var __export = (target, all) => {
10
10
  };
11
11
  var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
12
12
 
13
+ // src/adapters/base-handler.ts
14
+ class OAuthHandler {
15
+ config;
16
+ serverUrl;
17
+ apiKey;
18
+ constructor(config) {
19
+ this.config = config;
20
+ if (!config || !config.providers) {
21
+ throw new Error("OAuthHandler requires a valid config with providers");
22
+ }
23
+ this.serverUrl = config.serverUrl || MCP_SERVER_URL;
24
+ this.apiKey = config.apiKey;
25
+ }
26
+ getHeaders(additionalHeaders) {
27
+ const headers = {
28
+ ...additionalHeaders
29
+ };
30
+ if (this.apiKey) {
31
+ headers["X-API-KEY"] = this.apiKey;
32
+ }
33
+ return headers;
34
+ }
35
+ async handleAuthorize(request) {
36
+ const providerConfig = this.config.providers[request.provider];
37
+ if (!providerConfig) {
38
+ throw new Error(`Provider ${request.provider} not configured. Add OAuth credentials to your API route configuration.`);
39
+ }
40
+ if (!providerConfig.clientId || !providerConfig.clientSecret) {
41
+ throw new Error(`Missing OAuth credentials for ${request.provider}. Check your environment variables.`);
42
+ }
43
+ const url = new URL("/oauth/authorize", this.serverUrl);
44
+ url.searchParams.set("provider", request.provider);
45
+ url.searchParams.set("client_id", providerConfig.clientId);
46
+ url.searchParams.set("client_secret", providerConfig.clientSecret);
47
+ url.searchParams.set("scope", request.scopes.join(","));
48
+ url.searchParams.set("state", request.state);
49
+ url.searchParams.set("code_challenge", request.codeChallenge);
50
+ url.searchParams.set("code_challenge_method", request.codeChallengeMethod);
51
+ const redirectUri = request.redirectUri || providerConfig.redirectUri;
52
+ if (redirectUri) {
53
+ url.searchParams.set("redirect_uri", redirectUri);
54
+ }
55
+ const response = await fetch(url.toString(), {
56
+ method: "GET",
57
+ headers: this.getHeaders()
58
+ });
59
+ if (!response.ok) {
60
+ const error = await response.text();
61
+ throw new Error(`MCP server failed to generate authorization URL: ${error}`);
62
+ }
63
+ const data = await response.json();
64
+ return data;
65
+ }
66
+ async handleCallback(request) {
67
+ const providerConfig = this.config.providers[request.provider];
68
+ if (!providerConfig) {
69
+ throw new Error(`Provider ${request.provider} not configured. Add OAuth credentials to your API route configuration.`);
70
+ }
71
+ if (!providerConfig.clientId || !providerConfig.clientSecret) {
72
+ throw new Error(`Missing OAuth credentials for ${request.provider}. Check your environment variables.`);
73
+ }
74
+ const url = new URL("/oauth/callback", this.serverUrl);
75
+ const response = await fetch(url.toString(), {
76
+ method: "POST",
77
+ headers: this.getHeaders({
78
+ "Content-Type": "application/json"
79
+ }),
80
+ body: JSON.stringify({
81
+ provider: request.provider,
82
+ code: request.code,
83
+ code_verifier: request.codeVerifier,
84
+ state: request.state,
85
+ client_id: providerConfig.clientId,
86
+ client_secret: providerConfig.clientSecret,
87
+ redirect_uri: providerConfig.redirectUri
88
+ })
89
+ });
90
+ if (!response.ok) {
91
+ const error = await response.text();
92
+ throw new Error(`MCP server failed to exchange authorization code: ${error}`);
93
+ }
94
+ const data = await response.json();
95
+ return data;
96
+ }
97
+ async handleStatus(provider, accessToken) {
98
+ const url = new URL("/oauth/status", this.serverUrl);
99
+ url.searchParams.set("provider", provider);
100
+ const response = await fetch(url.toString(), {
101
+ method: "GET",
102
+ headers: this.getHeaders({
103
+ Authorization: `Bearer ${accessToken}`
104
+ })
105
+ });
106
+ if (!response.ok) {
107
+ if (response.status === 401) {
108
+ return {
109
+ authorized: false
110
+ };
111
+ }
112
+ const error = await response.text();
113
+ throw new Error(`MCP server failed to check authorization status: ${error}`);
114
+ }
115
+ const data = await response.json();
116
+ return data;
117
+ }
118
+ async handleDisconnect(request, accessToken) {
119
+ if (!accessToken) {
120
+ throw new Error("No access token provided. Cannot disconnect provider.");
121
+ }
122
+ const url = new URL("/oauth/disconnect", this.serverUrl);
123
+ const response = await fetch(url.toString(), {
124
+ method: "POST",
125
+ headers: this.getHeaders({
126
+ "Content-Type": "application/json",
127
+ Authorization: `Bearer ${accessToken}`
128
+ }),
129
+ body: JSON.stringify({
130
+ provider: request.provider
131
+ })
132
+ });
133
+ if (!response.ok) {
134
+ const error = await response.text();
135
+ throw new Error(`MCP server failed to disconnect provider: ${error}`);
136
+ }
137
+ const data = await response.json();
138
+ return data;
139
+ }
140
+ async handleToolCall(request, authHeader) {
141
+ const url = new URL("/tools/call", this.serverUrl);
142
+ const headers = this.getHeaders({
143
+ "Content-Type": "application/json"
144
+ });
145
+ if (authHeader && authHeader.startsWith("Bearer ")) {
146
+ headers["Authorization"] = authHeader;
147
+ }
148
+ const jsonRpcRequest = {
149
+ jsonrpc: "2.0",
150
+ id: Date.now() + Math.random(),
151
+ method: "tools/call",
152
+ params: {
153
+ name: request.name,
154
+ arguments: request.arguments || {}
155
+ }
156
+ };
157
+ const response = await fetch(url.toString(), {
158
+ method: "POST",
159
+ headers,
160
+ body: JSON.stringify(jsonRpcRequest)
161
+ });
162
+ if (!response.ok) {
163
+ const error = await response.text();
164
+ throw new Error(`MCP server failed to execute tool call: ${error}`);
165
+ }
166
+ const jsonRpcResponse = await response.json();
167
+ if (jsonRpcResponse.error) {
168
+ const error = new Error(jsonRpcResponse.error.message || "Tool call failed");
169
+ error.code = jsonRpcResponse.error.code;
170
+ error.data = jsonRpcResponse.error.data;
171
+ throw error;
172
+ }
173
+ return jsonRpcResponse.result;
174
+ }
175
+ }
176
+ var MCP_SERVER_URL = "https://mcp.integrate.dev/api/v1/mcp";
177
+
13
178
  // src/oauth/pkce.ts
14
179
  var exports_pkce = {};
15
180
  __export(exports_pkce, {
@@ -244,137 +409,6 @@ var init_errors = __esm(() => {
244
409
  };
245
410
  });
246
411
 
247
- // src/adapters/base-handler.ts
248
- var MCP_SERVER_URL = "https://mcp.integrate.dev/api/v1/mcp";
249
-
250
- class OAuthHandler {
251
- config;
252
- serverUrl;
253
- apiKey;
254
- constructor(config) {
255
- this.config = config;
256
- if (!config || !config.providers) {
257
- throw new Error("OAuthHandler requires a valid config with providers");
258
- }
259
- this.serverUrl = config.serverUrl || MCP_SERVER_URL;
260
- this.apiKey = config.apiKey;
261
- }
262
- getHeaders(additionalHeaders) {
263
- const headers = {
264
- ...additionalHeaders
265
- };
266
- if (this.apiKey) {
267
- headers["X-API-KEY"] = this.apiKey;
268
- }
269
- return headers;
270
- }
271
- async handleAuthorize(request) {
272
- const providerConfig = this.config.providers[request.provider];
273
- if (!providerConfig) {
274
- throw new Error(`Provider ${request.provider} not configured. Add OAuth credentials to your API route configuration.`);
275
- }
276
- if (!providerConfig.clientId || !providerConfig.clientSecret) {
277
- throw new Error(`Missing OAuth credentials for ${request.provider}. Check your environment variables.`);
278
- }
279
- const url = new URL("/oauth/authorize", this.serverUrl);
280
- url.searchParams.set("provider", request.provider);
281
- url.searchParams.set("client_id", providerConfig.clientId);
282
- url.searchParams.set("client_secret", providerConfig.clientSecret);
283
- url.searchParams.set("scope", request.scopes.join(","));
284
- url.searchParams.set("state", request.state);
285
- url.searchParams.set("code_challenge", request.codeChallenge);
286
- url.searchParams.set("code_challenge_method", request.codeChallengeMethod);
287
- const redirectUri = request.redirectUri || providerConfig.redirectUri;
288
- if (redirectUri) {
289
- url.searchParams.set("redirect_uri", redirectUri);
290
- }
291
- const response = await fetch(url.toString(), {
292
- method: "GET",
293
- headers: this.getHeaders()
294
- });
295
- if (!response.ok) {
296
- const error = await response.text();
297
- throw new Error(`MCP server failed to generate authorization URL: ${error}`);
298
- }
299
- const data = await response.json();
300
- return data;
301
- }
302
- async handleCallback(request) {
303
- const providerConfig = this.config.providers[request.provider];
304
- if (!providerConfig) {
305
- throw new Error(`Provider ${request.provider} not configured. Add OAuth credentials to your API route configuration.`);
306
- }
307
- if (!providerConfig.clientId || !providerConfig.clientSecret) {
308
- throw new Error(`Missing OAuth credentials for ${request.provider}. Check your environment variables.`);
309
- }
310
- const url = new URL("/oauth/callback", this.serverUrl);
311
- const response = await fetch(url.toString(), {
312
- method: "POST",
313
- headers: this.getHeaders({
314
- "Content-Type": "application/json"
315
- }),
316
- body: JSON.stringify({
317
- provider: request.provider,
318
- code: request.code,
319
- code_verifier: request.codeVerifier,
320
- state: request.state,
321
- client_id: providerConfig.clientId,
322
- client_secret: providerConfig.clientSecret,
323
- redirect_uri: providerConfig.redirectUri
324
- })
325
- });
326
- if (!response.ok) {
327
- const error = await response.text();
328
- throw new Error(`MCP server failed to exchange authorization code: ${error}`);
329
- }
330
- const data = await response.json();
331
- return data;
332
- }
333
- async handleStatus(provider, accessToken) {
334
- const url = new URL("/oauth/status", this.serverUrl);
335
- url.searchParams.set("provider", provider);
336
- const response = await fetch(url.toString(), {
337
- method: "GET",
338
- headers: this.getHeaders({
339
- Authorization: `Bearer ${accessToken}`
340
- })
341
- });
342
- if (!response.ok) {
343
- if (response.status === 401) {
344
- return {
345
- authorized: false
346
- };
347
- }
348
- const error = await response.text();
349
- throw new Error(`MCP server failed to check authorization status: ${error}`);
350
- }
351
- const data = await response.json();
352
- return data;
353
- }
354
- async handleDisconnect(request, accessToken) {
355
- if (!accessToken) {
356
- throw new Error("No access token provided. Cannot disconnect provider.");
357
- }
358
- const url = new URL("/oauth/disconnect", this.serverUrl);
359
- const response = await fetch(url.toString(), {
360
- method: "POST",
361
- headers: this.getHeaders({
362
- "Content-Type": "application/json",
363
- Authorization: `Bearer ${accessToken}`
364
- }),
365
- body: JSON.stringify({
366
- provider: request.provider
367
- })
368
- });
369
- if (!response.ok) {
370
- const error = await response.text();
371
- throw new Error(`MCP server failed to disconnect provider: ${error}`);
372
- }
373
- const data = await response.json();
374
- return data;
375
- }
376
- }
377
-
378
412
  // src/adapters/nextjs.ts
379
413
  function createNextOAuthHandler(config) {
380
414
  const handler = new OAuthHandler(config);
@@ -450,6 +484,9 @@ function createNextOAuthHandler(config) {
450
484
  if (action === "disconnect") {
451
485
  return handlers.disconnect(req);
452
486
  }
487
+ if (action === "mcp") {
488
+ return handlers.mcp(req);
489
+ }
453
490
  return Response.json({ error: `Unknown action: ${action}` }, { status: 404 });
454
491
  },
455
492
  async GET(req, context) {
@@ -462,6 +499,17 @@ function createNextOAuthHandler(config) {
462
499
  }
463
500
  };
464
501
  },
502
+ async mcp(req) {
503
+ try {
504
+ const body = await req.json();
505
+ const authHeader = req.headers.get("authorization");
506
+ const result = await handler.handleToolCall(body, authHeader);
507
+ return Response.json(result);
508
+ } catch (error) {
509
+ console.error("[MCP Tool Call] Error:", error);
510
+ return Response.json({ error: error.message || "Failed to execute tool call" }, { status: error.statusCode || 500 });
511
+ }
512
+ },
465
513
  toNextJsHandler(redirectConfig) {
466
514
  const defaultRedirectUrl = redirectConfig?.redirectUrl || "/";
467
515
  const errorRedirectUrl = redirectConfig?.errorRedirectUrl || "/auth-error";
@@ -482,6 +530,9 @@ function createNextOAuthHandler(config) {
482
530
  }
483
531
  return Response.json({ error: `Unknown action: ${action}` }, { status: 404 });
484
532
  }
533
+ if (segments.length === 1 && segments[0] === "mcp") {
534
+ return handlers.mcp(req);
535
+ }
485
536
  return Response.json({ error: `Invalid route: /${segments.join("/")}` }, { status: 404 });
486
537
  },
487
538
  async GET(req, context) {
@@ -1279,6 +1330,7 @@ class MCPClient {
1279
1330
  connecting = null;
1280
1331
  oauthManager;
1281
1332
  eventEmitter = new SimpleEventEmitter;
1333
+ apiRouteBase;
1282
1334
  github;
1283
1335
  gmail;
1284
1336
  server;
@@ -1290,6 +1342,7 @@ class MCPClient {
1290
1342
  });
1291
1343
  const oauthApiBase = config.oauthApiBase || "/api/integrate/oauth";
1292
1344
  const defaultRedirectUri = this.getDefaultRedirectUri(oauthApiBase);
1345
+ this.apiRouteBase = config.apiRouteBase || "/api/integrate";
1293
1346
  this.plugins = config.plugins.map((plugin) => {
1294
1347
  if (plugin.oauth && !plugin.oauth.redirectUri) {
1295
1348
  return {
@@ -1381,12 +1434,8 @@ class MCPClient {
1381
1434
  if (!this.availableTools.has(name)) {
1382
1435
  throw new Error(`Tool "${name}" is not available on the server. Available tools: ${Array.from(this.availableTools.keys()).join(", ")}`);
1383
1436
  }
1384
- const params = {
1385
- name,
1386
- arguments: args
1387
- };
1388
1437
  try {
1389
- const response = await this.transport.sendRequest("tools/call" /* TOOLS_CALL */, params);
1438
+ const response = await this.callToolThroughHandler(name, args);
1390
1439
  return response;
1391
1440
  } catch (error) {
1392
1441
  const parsedError = parseServerError(error, { toolName: name });
@@ -1445,18 +1494,58 @@ class MCPClient {
1445
1494
  if (!this.availableTools.has(name)) {
1446
1495
  throw new Error(`Tool "${name}" is not available on the server. Available tools: ${Array.from(this.availableTools.keys()).join(", ")}`);
1447
1496
  }
1448
- const params = {
1449
- name,
1450
- arguments: args
1451
- };
1452
1497
  try {
1453
- const response = await this.transport.sendRequest("tools/call" /* TOOLS_CALL */, params);
1498
+ const response = await this.callToolThroughHandler(name, args);
1454
1499
  return response;
1455
1500
  } catch (error) {
1456
1501
  const parsedError = parseServerError(error, { toolName: name });
1457
1502
  throw parsedError;
1458
1503
  }
1459
1504
  }
1505
+ async callToolThroughHandler(name, args, provider) {
1506
+ const url = `${this.apiRouteBase}/mcp`;
1507
+ const headers = {
1508
+ "Content-Type": "application/json"
1509
+ };
1510
+ if (provider) {
1511
+ const tokenData = this.oauthManager.getProviderToken(provider);
1512
+ if (tokenData) {
1513
+ headers["Authorization"] = `Bearer ${tokenData.accessToken}`;
1514
+ }
1515
+ }
1516
+ const response = await fetch(url, {
1517
+ method: "POST",
1518
+ headers,
1519
+ body: JSON.stringify({
1520
+ name,
1521
+ arguments: args
1522
+ })
1523
+ });
1524
+ if (!response.ok) {
1525
+ let errorMessage = `Request failed: ${response.statusText}`;
1526
+ const error = new Error(errorMessage);
1527
+ error.statusCode = response.status;
1528
+ try {
1529
+ const errorData = await response.json();
1530
+ if (errorData.error) {
1531
+ errorMessage = typeof errorData.error === "string" ? errorData.error : errorData.error.message || errorMessage;
1532
+ error.message = errorMessage;
1533
+ }
1534
+ if (errorData.code) {
1535
+ error.code = errorData.code;
1536
+ }
1537
+ if (errorData.data) {
1538
+ error.data = errorData.data;
1539
+ }
1540
+ if (errorData.error && typeof errorData.error === "object") {
1541
+ error.jsonrpcError = errorData.error;
1542
+ }
1543
+ } catch {}
1544
+ throw error;
1545
+ }
1546
+ const result = await response.json();
1547
+ return result;
1548
+ }
1460
1549
  async callToolWithRetry(name, args, retryCount = 0) {
1461
1550
  if (!this.initialized) {
1462
1551
  throw new Error("Client not initialized. Call connect() first.");
@@ -1468,35 +1557,24 @@ class MCPClient {
1468
1557
  throw new Error(`Tool "${name}" is not available on the server. Available tools: ${Array.from(this.availableTools.keys()).join(", ")}`);
1469
1558
  }
1470
1559
  const provider = this.getProviderForTool(name);
1471
- if (provider) {
1472
- const tokenData = this.oauthManager.getProviderToken(provider);
1473
- if (tokenData) {
1474
- this.transport.setHeader("Authorization", `Bearer ${tokenData.accessToken}`);
1475
- }
1476
- }
1477
- const params = {
1478
- name,
1479
- arguments: args
1480
- };
1481
1560
  try {
1482
- const response = await this.transport.sendRequest("tools/call" /* TOOLS_CALL */, params);
1561
+ const response = await this.callToolThroughHandler(name, args, provider);
1483
1562
  if (provider) {
1484
1563
  this.authState.set(provider, { authenticated: true });
1485
1564
  }
1486
1565
  return response;
1487
1566
  } catch (error) {
1488
- const provider2 = this.getProviderForTool(name);
1489
- const parsedError = parseServerError(error, { toolName: name, provider: provider2 });
1567
+ const parsedError = parseServerError(error, { toolName: name, provider });
1490
1568
  if (isAuthError(parsedError) && retryCount < this.maxReauthRetries) {
1491
- if (provider2) {
1492
- this.authState.set(provider2, {
1569
+ if (provider) {
1570
+ this.authState.set(provider, {
1493
1571
  authenticated: false,
1494
1572
  lastError: parsedError
1495
1573
  });
1496
1574
  }
1497
- if (this.onReauthRequired && provider2) {
1575
+ if (this.onReauthRequired && provider) {
1498
1576
  const reauthSuccess = await this.onReauthRequired({
1499
- provider: provider2,
1577
+ provider,
1500
1578
  error: parsedError,
1501
1579
  toolName: name
1502
1580
  });