integrate-sdk 0.6.9 → 0.7.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/adapters/auto-routes.js +35 -0
- package/dist/adapters/base-handler.js +35 -0
- package/dist/adapters/nextjs.js +52 -0
- package/dist/adapters/node.js +35 -0
- package/dist/adapters/solid-start.js +106 -27
- package/dist/adapters/svelte-kit.js +106 -27
- package/dist/index.js +107 -27
- package/dist/oauth.js +35 -0
- package/dist/server.js +107 -27
- package/dist/src/adapters/base-handler.d.ts +34 -0
- package/dist/src/adapters/base-handler.d.ts.map +1 -1
- package/dist/src/adapters/nextjs.d.ts +26 -0
- package/dist/src/adapters/nextjs.d.ts.map +1 -1
- package/dist/src/client.d.ts +6 -0
- package/dist/src/client.d.ts.map +1 -1
- package/dist/src/config/types.d.ts +18 -0
- package/dist/src/config/types.d.ts.map +1 -1
- package/dist/src/server.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -139,6 +139,41 @@ class OAuthHandler {
|
|
|
139
139
|
const data = await response.json();
|
|
140
140
|
return data;
|
|
141
141
|
}
|
|
142
|
+
async handleToolCall(request, authHeader) {
|
|
143
|
+
const url = new URL("/tools/call", this.serverUrl);
|
|
144
|
+
const headers = this.getHeaders({
|
|
145
|
+
"Content-Type": "application/json"
|
|
146
|
+
});
|
|
147
|
+
if (authHeader && authHeader.startsWith("Bearer ")) {
|
|
148
|
+
headers["Authorization"] = authHeader;
|
|
149
|
+
}
|
|
150
|
+
const jsonRpcRequest = {
|
|
151
|
+
jsonrpc: "2.0",
|
|
152
|
+
id: Date.now() + Math.random(),
|
|
153
|
+
method: "tools/call",
|
|
154
|
+
params: {
|
|
155
|
+
name: request.name,
|
|
156
|
+
arguments: request.arguments || {}
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
const response = await fetch(url.toString(), {
|
|
160
|
+
method: "POST",
|
|
161
|
+
headers,
|
|
162
|
+
body: JSON.stringify(jsonRpcRequest)
|
|
163
|
+
});
|
|
164
|
+
if (!response.ok) {
|
|
165
|
+
const error = await response.text();
|
|
166
|
+
throw new Error(`MCP server failed to execute tool call: ${error}`);
|
|
167
|
+
}
|
|
168
|
+
const jsonRpcResponse = await response.json();
|
|
169
|
+
if (jsonRpcResponse.error) {
|
|
170
|
+
const error = new Error(jsonRpcResponse.error.message || "Tool call failed");
|
|
171
|
+
error.code = jsonRpcResponse.error.code;
|
|
172
|
+
error.data = jsonRpcResponse.error.data;
|
|
173
|
+
throw error;
|
|
174
|
+
}
|
|
175
|
+
return jsonRpcResponse.result;
|
|
176
|
+
}
|
|
142
177
|
}
|
|
143
178
|
|
|
144
179
|
// src/adapters/auto-routes.ts
|
|
@@ -139,6 +139,41 @@ class OAuthHandler {
|
|
|
139
139
|
const data = await response.json();
|
|
140
140
|
return data;
|
|
141
141
|
}
|
|
142
|
+
async handleToolCall(request, authHeader) {
|
|
143
|
+
const url = new URL("/tools/call", this.serverUrl);
|
|
144
|
+
const headers = this.getHeaders({
|
|
145
|
+
"Content-Type": "application/json"
|
|
146
|
+
});
|
|
147
|
+
if (authHeader && authHeader.startsWith("Bearer ")) {
|
|
148
|
+
headers["Authorization"] = authHeader;
|
|
149
|
+
}
|
|
150
|
+
const jsonRpcRequest = {
|
|
151
|
+
jsonrpc: "2.0",
|
|
152
|
+
id: Date.now() + Math.random(),
|
|
153
|
+
method: "tools/call",
|
|
154
|
+
params: {
|
|
155
|
+
name: request.name,
|
|
156
|
+
arguments: request.arguments || {}
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
const response = await fetch(url.toString(), {
|
|
160
|
+
method: "POST",
|
|
161
|
+
headers,
|
|
162
|
+
body: JSON.stringify(jsonRpcRequest)
|
|
163
|
+
});
|
|
164
|
+
if (!response.ok) {
|
|
165
|
+
const error = await response.text();
|
|
166
|
+
throw new Error(`MCP server failed to execute tool call: ${error}`);
|
|
167
|
+
}
|
|
168
|
+
const jsonRpcResponse = await response.json();
|
|
169
|
+
if (jsonRpcResponse.error) {
|
|
170
|
+
const error = new Error(jsonRpcResponse.error.message || "Tool call failed");
|
|
171
|
+
error.code = jsonRpcResponse.error.code;
|
|
172
|
+
error.data = jsonRpcResponse.error.data;
|
|
173
|
+
throw error;
|
|
174
|
+
}
|
|
175
|
+
return jsonRpcResponse.result;
|
|
176
|
+
}
|
|
142
177
|
}
|
|
143
178
|
export {
|
|
144
179
|
OAuthHandler
|
package/dist/adapters/nextjs.js
CHANGED
|
@@ -235,6 +235,41 @@ class OAuthHandler {
|
|
|
235
235
|
const data = await response.json();
|
|
236
236
|
return data;
|
|
237
237
|
}
|
|
238
|
+
async handleToolCall(request, authHeader) {
|
|
239
|
+
const url = new URL("/tools/call", this.serverUrl);
|
|
240
|
+
const headers = this.getHeaders({
|
|
241
|
+
"Content-Type": "application/json"
|
|
242
|
+
});
|
|
243
|
+
if (authHeader && authHeader.startsWith("Bearer ")) {
|
|
244
|
+
headers["Authorization"] = authHeader;
|
|
245
|
+
}
|
|
246
|
+
const jsonRpcRequest = {
|
|
247
|
+
jsonrpc: "2.0",
|
|
248
|
+
id: Date.now() + Math.random(),
|
|
249
|
+
method: "tools/call",
|
|
250
|
+
params: {
|
|
251
|
+
name: request.name,
|
|
252
|
+
arguments: request.arguments || {}
|
|
253
|
+
}
|
|
254
|
+
};
|
|
255
|
+
const response = await fetch(url.toString(), {
|
|
256
|
+
method: "POST",
|
|
257
|
+
headers,
|
|
258
|
+
body: JSON.stringify(jsonRpcRequest)
|
|
259
|
+
});
|
|
260
|
+
if (!response.ok) {
|
|
261
|
+
const error = await response.text();
|
|
262
|
+
throw new Error(`MCP server failed to execute tool call: ${error}`);
|
|
263
|
+
}
|
|
264
|
+
const jsonRpcResponse = await response.json();
|
|
265
|
+
if (jsonRpcResponse.error) {
|
|
266
|
+
const error = new Error(jsonRpcResponse.error.message || "Tool call failed");
|
|
267
|
+
error.code = jsonRpcResponse.error.code;
|
|
268
|
+
error.data = jsonRpcResponse.error.data;
|
|
269
|
+
throw error;
|
|
270
|
+
}
|
|
271
|
+
return jsonRpcResponse.result;
|
|
272
|
+
}
|
|
238
273
|
}
|
|
239
274
|
|
|
240
275
|
// src/adapters/nextjs.ts
|
|
@@ -312,6 +347,9 @@ function createNextOAuthHandler(config) {
|
|
|
312
347
|
if (action === "disconnect") {
|
|
313
348
|
return handlers.disconnect(req);
|
|
314
349
|
}
|
|
350
|
+
if (action === "mcp") {
|
|
351
|
+
return handlers.mcp(req);
|
|
352
|
+
}
|
|
315
353
|
return Response.json({ error: `Unknown action: ${action}` }, { status: 404 });
|
|
316
354
|
},
|
|
317
355
|
async GET(req, context) {
|
|
@@ -324,6 +362,17 @@ function createNextOAuthHandler(config) {
|
|
|
324
362
|
}
|
|
325
363
|
};
|
|
326
364
|
},
|
|
365
|
+
async mcp(req) {
|
|
366
|
+
try {
|
|
367
|
+
const body = await req.json();
|
|
368
|
+
const authHeader = req.headers.get("authorization");
|
|
369
|
+
const result = await handler.handleToolCall(body, authHeader);
|
|
370
|
+
return Response.json(result);
|
|
371
|
+
} catch (error) {
|
|
372
|
+
console.error("[MCP Tool Call] Error:", error);
|
|
373
|
+
return Response.json({ error: error.message || "Failed to execute tool call" }, { status: error.statusCode || 500 });
|
|
374
|
+
}
|
|
375
|
+
},
|
|
327
376
|
toNextJsHandler(redirectConfig) {
|
|
328
377
|
const defaultRedirectUrl = redirectConfig?.redirectUrl || "/";
|
|
329
378
|
const errorRedirectUrl = redirectConfig?.errorRedirectUrl || "/auth-error";
|
|
@@ -344,6 +393,9 @@ function createNextOAuthHandler(config) {
|
|
|
344
393
|
}
|
|
345
394
|
return Response.json({ error: `Unknown action: ${action}` }, { status: 404 });
|
|
346
395
|
}
|
|
396
|
+
if (segments.length === 1 && segments[0] === "mcp") {
|
|
397
|
+
return handlers.mcp(req);
|
|
398
|
+
}
|
|
347
399
|
return Response.json({ error: `Invalid route: /${segments.join("/")}` }, { status: 404 });
|
|
348
400
|
},
|
|
349
401
|
async GET(req, context) {
|
package/dist/adapters/node.js
CHANGED
|
@@ -139,6 +139,41 @@ class OAuthHandler {
|
|
|
139
139
|
const data = await response.json();
|
|
140
140
|
return data;
|
|
141
141
|
}
|
|
142
|
+
async handleToolCall(request, authHeader) {
|
|
143
|
+
const url = new URL("/tools/call", this.serverUrl);
|
|
144
|
+
const headers = this.getHeaders({
|
|
145
|
+
"Content-Type": "application/json"
|
|
146
|
+
});
|
|
147
|
+
if (authHeader && authHeader.startsWith("Bearer ")) {
|
|
148
|
+
headers["Authorization"] = authHeader;
|
|
149
|
+
}
|
|
150
|
+
const jsonRpcRequest = {
|
|
151
|
+
jsonrpc: "2.0",
|
|
152
|
+
id: Date.now() + Math.random(),
|
|
153
|
+
method: "tools/call",
|
|
154
|
+
params: {
|
|
155
|
+
name: request.name,
|
|
156
|
+
arguments: request.arguments || {}
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
const response = await fetch(url.toString(), {
|
|
160
|
+
method: "POST",
|
|
161
|
+
headers,
|
|
162
|
+
body: JSON.stringify(jsonRpcRequest)
|
|
163
|
+
});
|
|
164
|
+
if (!response.ok) {
|
|
165
|
+
const error = await response.text();
|
|
166
|
+
throw new Error(`MCP server failed to execute tool call: ${error}`);
|
|
167
|
+
}
|
|
168
|
+
const jsonRpcResponse = await response.json();
|
|
169
|
+
if (jsonRpcResponse.error) {
|
|
170
|
+
const error = new Error(jsonRpcResponse.error.message || "Tool call failed");
|
|
171
|
+
error.code = jsonRpcResponse.error.code;
|
|
172
|
+
error.data = jsonRpcResponse.error.data;
|
|
173
|
+
throw error;
|
|
174
|
+
}
|
|
175
|
+
return jsonRpcResponse.result;
|
|
176
|
+
}
|
|
142
177
|
}
|
|
143
178
|
|
|
144
179
|
// src/adapters/node.ts
|
|
@@ -373,6 +373,41 @@ class OAuthHandler {
|
|
|
373
373
|
const data = await response.json();
|
|
374
374
|
return data;
|
|
375
375
|
}
|
|
376
|
+
async handleToolCall(request, authHeader) {
|
|
377
|
+
const url = new URL("/tools/call", this.serverUrl);
|
|
378
|
+
const headers = this.getHeaders({
|
|
379
|
+
"Content-Type": "application/json"
|
|
380
|
+
});
|
|
381
|
+
if (authHeader && authHeader.startsWith("Bearer ")) {
|
|
382
|
+
headers["Authorization"] = authHeader;
|
|
383
|
+
}
|
|
384
|
+
const jsonRpcRequest = {
|
|
385
|
+
jsonrpc: "2.0",
|
|
386
|
+
id: Date.now() + Math.random(),
|
|
387
|
+
method: "tools/call",
|
|
388
|
+
params: {
|
|
389
|
+
name: request.name,
|
|
390
|
+
arguments: request.arguments || {}
|
|
391
|
+
}
|
|
392
|
+
};
|
|
393
|
+
const response = await fetch(url.toString(), {
|
|
394
|
+
method: "POST",
|
|
395
|
+
headers,
|
|
396
|
+
body: JSON.stringify(jsonRpcRequest)
|
|
397
|
+
});
|
|
398
|
+
if (!response.ok) {
|
|
399
|
+
const error = await response.text();
|
|
400
|
+
throw new Error(`MCP server failed to execute tool call: ${error}`);
|
|
401
|
+
}
|
|
402
|
+
const jsonRpcResponse = await response.json();
|
|
403
|
+
if (jsonRpcResponse.error) {
|
|
404
|
+
const error = new Error(jsonRpcResponse.error.message || "Tool call failed");
|
|
405
|
+
error.code = jsonRpcResponse.error.code;
|
|
406
|
+
error.data = jsonRpcResponse.error.data;
|
|
407
|
+
throw error;
|
|
408
|
+
}
|
|
409
|
+
return jsonRpcResponse.result;
|
|
410
|
+
}
|
|
376
411
|
}
|
|
377
412
|
|
|
378
413
|
// src/adapters/nextjs.ts
|
|
@@ -450,6 +485,9 @@ function createNextOAuthHandler(config) {
|
|
|
450
485
|
if (action === "disconnect") {
|
|
451
486
|
return handlers.disconnect(req);
|
|
452
487
|
}
|
|
488
|
+
if (action === "mcp") {
|
|
489
|
+
return handlers.mcp(req);
|
|
490
|
+
}
|
|
453
491
|
return Response.json({ error: `Unknown action: ${action}` }, { status: 404 });
|
|
454
492
|
},
|
|
455
493
|
async GET(req, context) {
|
|
@@ -462,6 +500,17 @@ function createNextOAuthHandler(config) {
|
|
|
462
500
|
}
|
|
463
501
|
};
|
|
464
502
|
},
|
|
503
|
+
async mcp(req) {
|
|
504
|
+
try {
|
|
505
|
+
const body = await req.json();
|
|
506
|
+
const authHeader = req.headers.get("authorization");
|
|
507
|
+
const result = await handler.handleToolCall(body, authHeader);
|
|
508
|
+
return Response.json(result);
|
|
509
|
+
} catch (error) {
|
|
510
|
+
console.error("[MCP Tool Call] Error:", error);
|
|
511
|
+
return Response.json({ error: error.message || "Failed to execute tool call" }, { status: error.statusCode || 500 });
|
|
512
|
+
}
|
|
513
|
+
},
|
|
465
514
|
toNextJsHandler(redirectConfig) {
|
|
466
515
|
const defaultRedirectUrl = redirectConfig?.redirectUrl || "/";
|
|
467
516
|
const errorRedirectUrl = redirectConfig?.errorRedirectUrl || "/auth-error";
|
|
@@ -482,6 +531,9 @@ function createNextOAuthHandler(config) {
|
|
|
482
531
|
}
|
|
483
532
|
return Response.json({ error: `Unknown action: ${action}` }, { status: 404 });
|
|
484
533
|
}
|
|
534
|
+
if (segments.length === 1 && segments[0] === "mcp") {
|
|
535
|
+
return handlers.mcp(req);
|
|
536
|
+
}
|
|
485
537
|
return Response.json({ error: `Invalid route: /${segments.join("/")}` }, { status: 404 });
|
|
486
538
|
},
|
|
487
539
|
async GET(req, context) {
|
|
@@ -1279,6 +1331,7 @@ class MCPClient {
|
|
|
1279
1331
|
connecting = null;
|
|
1280
1332
|
oauthManager;
|
|
1281
1333
|
eventEmitter = new SimpleEventEmitter;
|
|
1334
|
+
apiRouteBase;
|
|
1282
1335
|
github;
|
|
1283
1336
|
gmail;
|
|
1284
1337
|
server;
|
|
@@ -1290,6 +1343,7 @@ class MCPClient {
|
|
|
1290
1343
|
});
|
|
1291
1344
|
const oauthApiBase = config.oauthApiBase || "/api/integrate/oauth";
|
|
1292
1345
|
const defaultRedirectUri = this.getDefaultRedirectUri(oauthApiBase);
|
|
1346
|
+
this.apiRouteBase = config.apiRouteBase || "/api/integrate";
|
|
1293
1347
|
this.plugins = config.plugins.map((plugin) => {
|
|
1294
1348
|
if (plugin.oauth && !plugin.oauth.redirectUri) {
|
|
1295
1349
|
return {
|
|
@@ -1381,12 +1435,8 @@ class MCPClient {
|
|
|
1381
1435
|
if (!this.availableTools.has(name)) {
|
|
1382
1436
|
throw new Error(`Tool "${name}" is not available on the server. Available tools: ${Array.from(this.availableTools.keys()).join(", ")}`);
|
|
1383
1437
|
}
|
|
1384
|
-
const params = {
|
|
1385
|
-
name,
|
|
1386
|
-
arguments: args
|
|
1387
|
-
};
|
|
1388
1438
|
try {
|
|
1389
|
-
const response = await this.
|
|
1439
|
+
const response = await this.callToolThroughHandler(name, args);
|
|
1390
1440
|
return response;
|
|
1391
1441
|
} catch (error) {
|
|
1392
1442
|
const parsedError = parseServerError(error, { toolName: name });
|
|
@@ -1445,18 +1495,58 @@ class MCPClient {
|
|
|
1445
1495
|
if (!this.availableTools.has(name)) {
|
|
1446
1496
|
throw new Error(`Tool "${name}" is not available on the server. Available tools: ${Array.from(this.availableTools.keys()).join(", ")}`);
|
|
1447
1497
|
}
|
|
1448
|
-
const params = {
|
|
1449
|
-
name,
|
|
1450
|
-
arguments: args
|
|
1451
|
-
};
|
|
1452
1498
|
try {
|
|
1453
|
-
const response = await this.
|
|
1499
|
+
const response = await this.callToolThroughHandler(name, args);
|
|
1454
1500
|
return response;
|
|
1455
1501
|
} catch (error) {
|
|
1456
1502
|
const parsedError = parseServerError(error, { toolName: name });
|
|
1457
1503
|
throw parsedError;
|
|
1458
1504
|
}
|
|
1459
1505
|
}
|
|
1506
|
+
async callToolThroughHandler(name, args, provider) {
|
|
1507
|
+
const url = `${this.apiRouteBase}/mcp`;
|
|
1508
|
+
const headers = {
|
|
1509
|
+
"Content-Type": "application/json"
|
|
1510
|
+
};
|
|
1511
|
+
if (provider) {
|
|
1512
|
+
const tokenData = this.oauthManager.getProviderToken(provider);
|
|
1513
|
+
if (tokenData) {
|
|
1514
|
+
headers["Authorization"] = `Bearer ${tokenData.accessToken}`;
|
|
1515
|
+
}
|
|
1516
|
+
}
|
|
1517
|
+
const response = await fetch(url, {
|
|
1518
|
+
method: "POST",
|
|
1519
|
+
headers,
|
|
1520
|
+
body: JSON.stringify({
|
|
1521
|
+
name,
|
|
1522
|
+
arguments: args
|
|
1523
|
+
})
|
|
1524
|
+
});
|
|
1525
|
+
if (!response.ok) {
|
|
1526
|
+
let errorMessage = `Request failed: ${response.statusText}`;
|
|
1527
|
+
const error = new Error(errorMessage);
|
|
1528
|
+
error.statusCode = response.status;
|
|
1529
|
+
try {
|
|
1530
|
+
const errorData = await response.json();
|
|
1531
|
+
if (errorData.error) {
|
|
1532
|
+
errorMessage = typeof errorData.error === "string" ? errorData.error : errorData.error.message || errorMessage;
|
|
1533
|
+
error.message = errorMessage;
|
|
1534
|
+
}
|
|
1535
|
+
if (errorData.code) {
|
|
1536
|
+
error.code = errorData.code;
|
|
1537
|
+
}
|
|
1538
|
+
if (errorData.data) {
|
|
1539
|
+
error.data = errorData.data;
|
|
1540
|
+
}
|
|
1541
|
+
if (errorData.error && typeof errorData.error === "object") {
|
|
1542
|
+
error.jsonrpcError = errorData.error;
|
|
1543
|
+
}
|
|
1544
|
+
} catch {}
|
|
1545
|
+
throw error;
|
|
1546
|
+
}
|
|
1547
|
+
const result = await response.json();
|
|
1548
|
+
return result;
|
|
1549
|
+
}
|
|
1460
1550
|
async callToolWithRetry(name, args, retryCount = 0) {
|
|
1461
1551
|
if (!this.initialized) {
|
|
1462
1552
|
throw new Error("Client not initialized. Call connect() first.");
|
|
@@ -1468,35 +1558,24 @@ class MCPClient {
|
|
|
1468
1558
|
throw new Error(`Tool "${name}" is not available on the server. Available tools: ${Array.from(this.availableTools.keys()).join(", ")}`);
|
|
1469
1559
|
}
|
|
1470
1560
|
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
1561
|
try {
|
|
1482
|
-
const response = await this.
|
|
1562
|
+
const response = await this.callToolThroughHandler(name, args, provider);
|
|
1483
1563
|
if (provider) {
|
|
1484
1564
|
this.authState.set(provider, { authenticated: true });
|
|
1485
1565
|
}
|
|
1486
1566
|
return response;
|
|
1487
1567
|
} catch (error) {
|
|
1488
|
-
const
|
|
1489
|
-
const parsedError = parseServerError(error, { toolName: name, provider: provider2 });
|
|
1568
|
+
const parsedError = parseServerError(error, { toolName: name, provider });
|
|
1490
1569
|
if (isAuthError(parsedError) && retryCount < this.maxReauthRetries) {
|
|
1491
|
-
if (
|
|
1492
|
-
this.authState.set(
|
|
1570
|
+
if (provider) {
|
|
1571
|
+
this.authState.set(provider, {
|
|
1493
1572
|
authenticated: false,
|
|
1494
1573
|
lastError: parsedError
|
|
1495
1574
|
});
|
|
1496
1575
|
}
|
|
1497
|
-
if (this.onReauthRequired &&
|
|
1576
|
+
if (this.onReauthRequired && provider) {
|
|
1498
1577
|
const reauthSuccess = await this.onReauthRequired({
|
|
1499
|
-
provider
|
|
1578
|
+
provider,
|
|
1500
1579
|
error: parsedError,
|
|
1501
1580
|
toolName: name
|
|
1502
1581
|
});
|
|
@@ -373,6 +373,41 @@ class OAuthHandler {
|
|
|
373
373
|
const data = await response.json();
|
|
374
374
|
return data;
|
|
375
375
|
}
|
|
376
|
+
async handleToolCall(request, authHeader) {
|
|
377
|
+
const url = new URL("/tools/call", this.serverUrl);
|
|
378
|
+
const headers = this.getHeaders({
|
|
379
|
+
"Content-Type": "application/json"
|
|
380
|
+
});
|
|
381
|
+
if (authHeader && authHeader.startsWith("Bearer ")) {
|
|
382
|
+
headers["Authorization"] = authHeader;
|
|
383
|
+
}
|
|
384
|
+
const jsonRpcRequest = {
|
|
385
|
+
jsonrpc: "2.0",
|
|
386
|
+
id: Date.now() + Math.random(),
|
|
387
|
+
method: "tools/call",
|
|
388
|
+
params: {
|
|
389
|
+
name: request.name,
|
|
390
|
+
arguments: request.arguments || {}
|
|
391
|
+
}
|
|
392
|
+
};
|
|
393
|
+
const response = await fetch(url.toString(), {
|
|
394
|
+
method: "POST",
|
|
395
|
+
headers,
|
|
396
|
+
body: JSON.stringify(jsonRpcRequest)
|
|
397
|
+
});
|
|
398
|
+
if (!response.ok) {
|
|
399
|
+
const error = await response.text();
|
|
400
|
+
throw new Error(`MCP server failed to execute tool call: ${error}`);
|
|
401
|
+
}
|
|
402
|
+
const jsonRpcResponse = await response.json();
|
|
403
|
+
if (jsonRpcResponse.error) {
|
|
404
|
+
const error = new Error(jsonRpcResponse.error.message || "Tool call failed");
|
|
405
|
+
error.code = jsonRpcResponse.error.code;
|
|
406
|
+
error.data = jsonRpcResponse.error.data;
|
|
407
|
+
throw error;
|
|
408
|
+
}
|
|
409
|
+
return jsonRpcResponse.result;
|
|
410
|
+
}
|
|
376
411
|
}
|
|
377
412
|
|
|
378
413
|
// src/adapters/nextjs.ts
|
|
@@ -450,6 +485,9 @@ function createNextOAuthHandler(config) {
|
|
|
450
485
|
if (action === "disconnect") {
|
|
451
486
|
return handlers.disconnect(req);
|
|
452
487
|
}
|
|
488
|
+
if (action === "mcp") {
|
|
489
|
+
return handlers.mcp(req);
|
|
490
|
+
}
|
|
453
491
|
return Response.json({ error: `Unknown action: ${action}` }, { status: 404 });
|
|
454
492
|
},
|
|
455
493
|
async GET(req, context) {
|
|
@@ -462,6 +500,17 @@ function createNextOAuthHandler(config) {
|
|
|
462
500
|
}
|
|
463
501
|
};
|
|
464
502
|
},
|
|
503
|
+
async mcp(req) {
|
|
504
|
+
try {
|
|
505
|
+
const body = await req.json();
|
|
506
|
+
const authHeader = req.headers.get("authorization");
|
|
507
|
+
const result = await handler.handleToolCall(body, authHeader);
|
|
508
|
+
return Response.json(result);
|
|
509
|
+
} catch (error) {
|
|
510
|
+
console.error("[MCP Tool Call] Error:", error);
|
|
511
|
+
return Response.json({ error: error.message || "Failed to execute tool call" }, { status: error.statusCode || 500 });
|
|
512
|
+
}
|
|
513
|
+
},
|
|
465
514
|
toNextJsHandler(redirectConfig) {
|
|
466
515
|
const defaultRedirectUrl = redirectConfig?.redirectUrl || "/";
|
|
467
516
|
const errorRedirectUrl = redirectConfig?.errorRedirectUrl || "/auth-error";
|
|
@@ -482,6 +531,9 @@ function createNextOAuthHandler(config) {
|
|
|
482
531
|
}
|
|
483
532
|
return Response.json({ error: `Unknown action: ${action}` }, { status: 404 });
|
|
484
533
|
}
|
|
534
|
+
if (segments.length === 1 && segments[0] === "mcp") {
|
|
535
|
+
return handlers.mcp(req);
|
|
536
|
+
}
|
|
485
537
|
return Response.json({ error: `Invalid route: /${segments.join("/")}` }, { status: 404 });
|
|
486
538
|
},
|
|
487
539
|
async GET(req, context) {
|
|
@@ -1279,6 +1331,7 @@ class MCPClient {
|
|
|
1279
1331
|
connecting = null;
|
|
1280
1332
|
oauthManager;
|
|
1281
1333
|
eventEmitter = new SimpleEventEmitter;
|
|
1334
|
+
apiRouteBase;
|
|
1282
1335
|
github;
|
|
1283
1336
|
gmail;
|
|
1284
1337
|
server;
|
|
@@ -1290,6 +1343,7 @@ class MCPClient {
|
|
|
1290
1343
|
});
|
|
1291
1344
|
const oauthApiBase = config.oauthApiBase || "/api/integrate/oauth";
|
|
1292
1345
|
const defaultRedirectUri = this.getDefaultRedirectUri(oauthApiBase);
|
|
1346
|
+
this.apiRouteBase = config.apiRouteBase || "/api/integrate";
|
|
1293
1347
|
this.plugins = config.plugins.map((plugin) => {
|
|
1294
1348
|
if (plugin.oauth && !plugin.oauth.redirectUri) {
|
|
1295
1349
|
return {
|
|
@@ -1381,12 +1435,8 @@ class MCPClient {
|
|
|
1381
1435
|
if (!this.availableTools.has(name)) {
|
|
1382
1436
|
throw new Error(`Tool "${name}" is not available on the server. Available tools: ${Array.from(this.availableTools.keys()).join(", ")}`);
|
|
1383
1437
|
}
|
|
1384
|
-
const params = {
|
|
1385
|
-
name,
|
|
1386
|
-
arguments: args
|
|
1387
|
-
};
|
|
1388
1438
|
try {
|
|
1389
|
-
const response = await this.
|
|
1439
|
+
const response = await this.callToolThroughHandler(name, args);
|
|
1390
1440
|
return response;
|
|
1391
1441
|
} catch (error) {
|
|
1392
1442
|
const parsedError = parseServerError(error, { toolName: name });
|
|
@@ -1445,18 +1495,58 @@ class MCPClient {
|
|
|
1445
1495
|
if (!this.availableTools.has(name)) {
|
|
1446
1496
|
throw new Error(`Tool "${name}" is not available on the server. Available tools: ${Array.from(this.availableTools.keys()).join(", ")}`);
|
|
1447
1497
|
}
|
|
1448
|
-
const params = {
|
|
1449
|
-
name,
|
|
1450
|
-
arguments: args
|
|
1451
|
-
};
|
|
1452
1498
|
try {
|
|
1453
|
-
const response = await this.
|
|
1499
|
+
const response = await this.callToolThroughHandler(name, args);
|
|
1454
1500
|
return response;
|
|
1455
1501
|
} catch (error) {
|
|
1456
1502
|
const parsedError = parseServerError(error, { toolName: name });
|
|
1457
1503
|
throw parsedError;
|
|
1458
1504
|
}
|
|
1459
1505
|
}
|
|
1506
|
+
async callToolThroughHandler(name, args, provider) {
|
|
1507
|
+
const url = `${this.apiRouteBase}/mcp`;
|
|
1508
|
+
const headers = {
|
|
1509
|
+
"Content-Type": "application/json"
|
|
1510
|
+
};
|
|
1511
|
+
if (provider) {
|
|
1512
|
+
const tokenData = this.oauthManager.getProviderToken(provider);
|
|
1513
|
+
if (tokenData) {
|
|
1514
|
+
headers["Authorization"] = `Bearer ${tokenData.accessToken}`;
|
|
1515
|
+
}
|
|
1516
|
+
}
|
|
1517
|
+
const response = await fetch(url, {
|
|
1518
|
+
method: "POST",
|
|
1519
|
+
headers,
|
|
1520
|
+
body: JSON.stringify({
|
|
1521
|
+
name,
|
|
1522
|
+
arguments: args
|
|
1523
|
+
})
|
|
1524
|
+
});
|
|
1525
|
+
if (!response.ok) {
|
|
1526
|
+
let errorMessage = `Request failed: ${response.statusText}`;
|
|
1527
|
+
const error = new Error(errorMessage);
|
|
1528
|
+
error.statusCode = response.status;
|
|
1529
|
+
try {
|
|
1530
|
+
const errorData = await response.json();
|
|
1531
|
+
if (errorData.error) {
|
|
1532
|
+
errorMessage = typeof errorData.error === "string" ? errorData.error : errorData.error.message || errorMessage;
|
|
1533
|
+
error.message = errorMessage;
|
|
1534
|
+
}
|
|
1535
|
+
if (errorData.code) {
|
|
1536
|
+
error.code = errorData.code;
|
|
1537
|
+
}
|
|
1538
|
+
if (errorData.data) {
|
|
1539
|
+
error.data = errorData.data;
|
|
1540
|
+
}
|
|
1541
|
+
if (errorData.error && typeof errorData.error === "object") {
|
|
1542
|
+
error.jsonrpcError = errorData.error;
|
|
1543
|
+
}
|
|
1544
|
+
} catch {}
|
|
1545
|
+
throw error;
|
|
1546
|
+
}
|
|
1547
|
+
const result = await response.json();
|
|
1548
|
+
return result;
|
|
1549
|
+
}
|
|
1460
1550
|
async callToolWithRetry(name, args, retryCount = 0) {
|
|
1461
1551
|
if (!this.initialized) {
|
|
1462
1552
|
throw new Error("Client not initialized. Call connect() first.");
|
|
@@ -1468,35 +1558,24 @@ class MCPClient {
|
|
|
1468
1558
|
throw new Error(`Tool "${name}" is not available on the server. Available tools: ${Array.from(this.availableTools.keys()).join(", ")}`);
|
|
1469
1559
|
}
|
|
1470
1560
|
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
1561
|
try {
|
|
1482
|
-
const response = await this.
|
|
1562
|
+
const response = await this.callToolThroughHandler(name, args, provider);
|
|
1483
1563
|
if (provider) {
|
|
1484
1564
|
this.authState.set(provider, { authenticated: true });
|
|
1485
1565
|
}
|
|
1486
1566
|
return response;
|
|
1487
1567
|
} catch (error) {
|
|
1488
|
-
const
|
|
1489
|
-
const parsedError = parseServerError(error, { toolName: name, provider: provider2 });
|
|
1568
|
+
const parsedError = parseServerError(error, { toolName: name, provider });
|
|
1490
1569
|
if (isAuthError(parsedError) && retryCount < this.maxReauthRetries) {
|
|
1491
|
-
if (
|
|
1492
|
-
this.authState.set(
|
|
1570
|
+
if (provider) {
|
|
1571
|
+
this.authState.set(provider, {
|
|
1493
1572
|
authenticated: false,
|
|
1494
1573
|
lastError: parsedError
|
|
1495
1574
|
});
|
|
1496
1575
|
}
|
|
1497
|
-
if (this.onReauthRequired &&
|
|
1576
|
+
if (this.onReauthRequired && provider) {
|
|
1498
1577
|
const reauthSuccess = await this.onReauthRequired({
|
|
1499
|
-
provider
|
|
1578
|
+
provider,
|
|
1500
1579
|
error: parsedError,
|
|
1501
1580
|
toolName: name
|
|
1502
1581
|
});
|