@mcp-ts/sdk 2.4.4 → 2.5.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/agui-adapter.d.mts +3 -3
- package/dist/adapters/agui-adapter.d.ts +3 -3
- package/dist/adapters/agui-adapter.js.map +1 -1
- package/dist/adapters/agui-adapter.mjs.map +1 -1
- package/dist/adapters/agui-middleware.d.mts +3 -3
- package/dist/adapters/agui-middleware.d.ts +3 -3
- package/dist/adapters/agui-middleware.js.map +1 -1
- package/dist/adapters/agui-middleware.mjs.map +1 -1
- package/dist/adapters/ai-adapter.d.mts +3 -3
- package/dist/adapters/ai-adapter.d.ts +3 -3
- package/dist/adapters/ai-adapter.js.map +1 -1
- package/dist/adapters/ai-adapter.mjs.map +1 -1
- package/dist/adapters/langchain-adapter.d.mts +3 -3
- package/dist/adapters/langchain-adapter.d.ts +3 -3
- package/dist/adapters/langchain-adapter.js +2 -2
- package/dist/adapters/langchain-adapter.js.map +1 -1
- package/dist/adapters/langchain-adapter.mjs +2 -2
- package/dist/adapters/langchain-adapter.mjs.map +1 -1
- package/dist/adapters/mastra-adapter.d.mts +2 -2
- package/dist/adapters/mastra-adapter.d.ts +2 -2
- package/dist/adapters/mastra-adapter.js +2 -2
- package/dist/adapters/mastra-adapter.js.map +1 -1
- package/dist/adapters/mastra-adapter.mjs +2 -2
- package/dist/adapters/mastra-adapter.mjs.map +1 -1
- package/dist/client/index.d.mts +2 -2
- package/dist/client/index.d.ts +2 -2
- package/dist/client/index.js +6 -0
- package/dist/client/index.js.map +1 -1
- package/dist/client/index.mjs +6 -0
- package/dist/client/index.mjs.map +1 -1
- package/dist/client/react.d.mts +15 -4
- package/dist/client/react.d.ts +15 -4
- package/dist/client/react.js +36 -6
- package/dist/client/react.js.map +1 -1
- package/dist/client/react.mjs +36 -6
- package/dist/client/react.mjs.map +1 -1
- package/dist/client/vue.d.mts +4 -4
- package/dist/client/vue.d.ts +4 -4
- package/dist/client/vue.js +6 -0
- package/dist/client/vue.js.map +1 -1
- package/dist/client/vue.mjs +6 -0
- package/dist/client/vue.mjs.map +1 -1
- package/dist/{index-CkM3p0eE.d.mts → index-CTURVnom.d.mts} +5 -1
- package/dist/{index-CZk2gu2E.d.ts → index-sVcqrhf7.d.ts} +5 -1
- package/dist/index.d.mts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +374 -130
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +370 -130
- package/dist/index.mjs.map +1 -1
- package/dist/{multi-session-client-ChQrBZhF.d.mts → multi-session-client-CSPSHHla.d.ts} +14 -2
- package/dist/{multi-session-client-QOOPdEVp.d.ts → multi-session-client-DMZGVABI.d.mts} +14 -2
- package/dist/server/index.d.mts +13 -4
- package/dist/server/index.d.ts +13 -4
- package/dist/server/index.js +368 -130
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +364 -130
- package/dist/server/index.mjs.map +1 -1
- package/dist/shared/index.d.mts +4 -4
- package/dist/shared/index.d.ts +4 -4
- package/dist/shared/index.js +2 -6
- package/dist/shared/index.js.map +1 -1
- package/dist/shared/index.mjs +2 -6
- package/dist/shared/index.mjs.map +1 -1
- package/dist/{tool-router-DQ-HrD7W.d.ts → tool-router-CS9l0w4a.d.ts} +1 -1
- package/dist/{tool-router-CGs3IDOJ.d.mts → tool-router-CVLBaCwH.d.mts} +1 -1
- package/dist/{types-Bf-7GOLW.d.mts → types-DK_NGWd4.d.mts} +37 -3
- package/dist/{types-Bf-7GOLW.d.ts → types-DK_NGWd4.d.ts} +37 -3
- package/migrations/neon/20260513010000_install_mcp_sessions.sql +1 -0
- package/migrations/supabase/20260330195700_install_mcp_sessions.sql +1 -0
- package/package.json +1 -1
- package/src/adapters/agui-adapter.ts +6 -2
- package/src/adapters/ai-adapter.ts +3 -1
- package/src/adapters/langchain-adapter.ts +5 -3
- package/src/adapters/mastra-adapter.ts +5 -3
- package/src/client/core/sse-client.ts +17 -0
- package/src/client/react/use-mcp.ts +63 -0
- package/src/server/handlers/sse-handler.ts +117 -10
- package/src/server/mcp/multi-session-client.ts +7 -3
- package/src/server/mcp/oauth-client.ts +78 -55
- package/src/server/mcp/tool-policy-gateway.ts +90 -0
- package/src/server/storage/index.ts +1 -1
- package/src/server/storage/neon-backend.ts +65 -60
- package/src/server/storage/session-lifecycle.ts +5 -0
- package/src/server/storage/supabase-backend.ts +27 -15
- package/src/server/storage/tool-policy.ts +89 -0
- package/src/server/storage/types.ts +11 -0
- package/src/shared/types.ts +48 -1
- package/src/shared/utils.ts +16 -14
package/dist/server/index.js
CHANGED
|
@@ -159,13 +159,9 @@ init_cjs_shims();
|
|
|
159
159
|
// src/shared/utils.ts
|
|
160
160
|
init_cjs_shims();
|
|
161
161
|
var OAUTH_STATE_SEPARATOR = ".";
|
|
162
|
-
var
|
|
163
|
-
"
|
|
164
|
-
|
|
165
|
-
);
|
|
166
|
-
var rest = nanoid.customAlphabet(
|
|
167
|
-
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
|
|
168
|
-
11
|
|
162
|
+
var serverIdAlphabet = nanoid.customAlphabet(
|
|
163
|
+
"abcdefghijklmnopqrstuvwxyz0123456789",
|
|
164
|
+
12
|
|
169
165
|
);
|
|
170
166
|
function sanitizeServerLabel(name) {
|
|
171
167
|
let sanitized = name.replace(/[^a-zA-Z0-9-_]/g, "_").replace(/_{2,}/g, "_").toLowerCase();
|
|
@@ -175,7 +171,10 @@ function sanitizeServerLabel(name) {
|
|
|
175
171
|
return sanitized;
|
|
176
172
|
}
|
|
177
173
|
function generateSessionId() {
|
|
178
|
-
return
|
|
174
|
+
return "sess_" + nanoid.nanoid(21);
|
|
175
|
+
}
|
|
176
|
+
function generateServerId() {
|
|
177
|
+
return serverIdAlphabet();
|
|
179
178
|
}
|
|
180
179
|
function formatOAuthState(nonce, sessionId) {
|
|
181
180
|
return `${nonce}${OAUTH_STATE_SEPARATOR}${sessionId}`;
|
|
@@ -210,6 +209,60 @@ var SOFTWARE_VERSION = "2.3.4";
|
|
|
210
209
|
var MCP_CLIENT_NAME = "mcp-ts-oauth-client";
|
|
211
210
|
var MCP_CLIENT_VERSION = "2.0";
|
|
212
211
|
|
|
212
|
+
// src/server/storage/tool-policy.ts
|
|
213
|
+
init_cjs_shims();
|
|
214
|
+
function createToolId(serverId, toolName) {
|
|
215
|
+
return `${serverId}::${toolName}`;
|
|
216
|
+
}
|
|
217
|
+
function normalizeToolIds(input) {
|
|
218
|
+
if (!Array.isArray(input)) return [];
|
|
219
|
+
return Array.from(new Set(
|
|
220
|
+
input.filter((id) => typeof id === "string").map((id) => id.trim()).filter(Boolean)
|
|
221
|
+
));
|
|
222
|
+
}
|
|
223
|
+
function normalizeToolPolicy(input, now = Date.now()) {
|
|
224
|
+
if (!input || typeof input !== "object") {
|
|
225
|
+
return void 0;
|
|
226
|
+
}
|
|
227
|
+
const mode = input.mode === "allowlist" || input.mode === "denylist" ? input.mode : "all";
|
|
228
|
+
const updatedAt = typeof input.updatedAt === "number" && Number.isFinite(input.updatedAt) ? input.updatedAt : now;
|
|
229
|
+
if (mode === "all") {
|
|
230
|
+
return { mode: "all", toolIds: [], updatedAt };
|
|
231
|
+
}
|
|
232
|
+
return { mode, toolIds: normalizeToolIds(input.toolIds), updatedAt };
|
|
233
|
+
}
|
|
234
|
+
function normalizeToolPolicyForUpdate(input, now = Date.now()) {
|
|
235
|
+
return normalizeToolPolicy(input, now) ?? { mode: "all", toolIds: [], updatedAt: now };
|
|
236
|
+
}
|
|
237
|
+
function isToolAllowed(policy, toolName, serverId) {
|
|
238
|
+
if (!policy || policy.mode === "all") return true;
|
|
239
|
+
if (!serverId) return false;
|
|
240
|
+
const toolId = createToolId(serverId, toolName);
|
|
241
|
+
if (policy.mode === "allowlist") {
|
|
242
|
+
return policy.toolIds.includes(toolId);
|
|
243
|
+
}
|
|
244
|
+
return !policy.toolIds.includes(toolId);
|
|
245
|
+
}
|
|
246
|
+
function assertToolAllowed(policy, toolName, serverId) {
|
|
247
|
+
if (isToolAllowed(policy, toolName, serverId)) return;
|
|
248
|
+
throw new Error(`Tool "${toolName}" is not allowed for this MCP session`);
|
|
249
|
+
}
|
|
250
|
+
function filterToolsByPolicy(tools, policy, serverId) {
|
|
251
|
+
if (!policy || policy.mode === "all") return tools;
|
|
252
|
+
return tools.filter((tool) => isToolAllowed(policy, tool.name, serverId));
|
|
253
|
+
}
|
|
254
|
+
function validateToolPolicyAgainstTools(policy, tools, serverId) {
|
|
255
|
+
if (policy.mode === "all") return;
|
|
256
|
+
if (!serverId) {
|
|
257
|
+
throw new Error("Cannot validate MCP tool policy without a serverId");
|
|
258
|
+
}
|
|
259
|
+
const availableIds = new Set(tools.map((tool) => createToolId(serverId, tool.name)));
|
|
260
|
+
const unknownIds = policy.toolIds.filter((id) => !availableIds.has(id));
|
|
261
|
+
if (unknownIds.length > 0) {
|
|
262
|
+
throw new Error(`Unknown tool id(s) for this MCP session: ${unknownIds.join(", ")}`);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
213
266
|
// src/server/storage/session-lifecycle.ts
|
|
214
267
|
function resolveSessionExpiresAt(status = "pending", referenceTime = Date.now()) {
|
|
215
268
|
return status === "active" ? null : referenceTime + STATE_EXPIRATION_MS;
|
|
@@ -226,7 +279,8 @@ function normalizeNewSession(session, now = Date.now()) {
|
|
|
226
279
|
status,
|
|
227
280
|
createdAt,
|
|
228
281
|
updatedAt,
|
|
229
|
-
expiresAt: resolveSessionExpiresAt(status, status === "active" ? updatedAt : createdAt)
|
|
282
|
+
expiresAt: resolveSessionExpiresAt(status, status === "active" ? updatedAt : createdAt),
|
|
283
|
+
toolPolicy: normalizeToolPolicy(session.toolPolicy, updatedAt)
|
|
230
284
|
};
|
|
231
285
|
}
|
|
232
286
|
function mergeSessionUpdate(current, data, now = Date.now()) {
|
|
@@ -240,7 +294,8 @@ function mergeSessionUpdate(current, data, now = Date.now()) {
|
|
|
240
294
|
return {
|
|
241
295
|
...updated,
|
|
242
296
|
status,
|
|
243
|
-
expiresAt: resolveSessionExpiresAt(status, updatedAt)
|
|
297
|
+
expiresAt: resolveSessionExpiresAt(status, updatedAt),
|
|
298
|
+
toolPolicy: normalizeToolPolicy(updated.toolPolicy, updatedAt)
|
|
244
299
|
};
|
|
245
300
|
}
|
|
246
301
|
function normalizeStoredSession(session) {
|
|
@@ -253,7 +308,8 @@ function normalizeStoredSession(session) {
|
|
|
253
308
|
status,
|
|
254
309
|
createdAt,
|
|
255
310
|
updatedAt,
|
|
256
|
-
expiresAt
|
|
311
|
+
expiresAt,
|
|
312
|
+
toolPolicy: normalizeToolPolicy(session.toolPolicy, updatedAt)
|
|
257
313
|
};
|
|
258
314
|
}
|
|
259
315
|
function isSessionExpired(session, now = Date.now()) {
|
|
@@ -1124,7 +1180,8 @@ var SupabaseStorageBackend = class {
|
|
|
1124
1180
|
userId: row.user_id,
|
|
1125
1181
|
headers: decryptObject(row.headers),
|
|
1126
1182
|
authUrl: row.auth_url,
|
|
1127
|
-
status: row.status ?? "pending"
|
|
1183
|
+
status: row.status ?? "pending",
|
|
1184
|
+
toolPolicy: normalizeToolPolicy(row.tool_policy)
|
|
1128
1185
|
};
|
|
1129
1186
|
}
|
|
1130
1187
|
mapRowToCredentials(row, userId, sessionId) {
|
|
@@ -1148,7 +1205,7 @@ var SupabaseStorageBackend = class {
|
|
|
1148
1205
|
const createdAt = new Date(session.createdAt || Date.now()).toISOString();
|
|
1149
1206
|
const updatedAt = new Date(session.updatedAt ?? session.createdAt ?? Date.now()).toISOString();
|
|
1150
1207
|
const expiresAt = resolveSessionExpiresAt(status, new Date(createdAt).getTime());
|
|
1151
|
-
const
|
|
1208
|
+
const insertData = {
|
|
1152
1209
|
session_id: sessionId,
|
|
1153
1210
|
user_id: userId,
|
|
1154
1211
|
server_id: session.serverId,
|
|
@@ -1162,7 +1219,12 @@ var SupabaseStorageBackend = class {
|
|
|
1162
1219
|
auth_url: session.authUrl ?? null,
|
|
1163
1220
|
status,
|
|
1164
1221
|
expires_at: expiresAt === null ? null : new Date(expiresAt).toISOString()
|
|
1165
|
-
}
|
|
1222
|
+
};
|
|
1223
|
+
const toolPolicy = normalizeToolPolicy(session.toolPolicy);
|
|
1224
|
+
if (toolPolicy) {
|
|
1225
|
+
insertData.tool_policy = toolPolicy;
|
|
1226
|
+
}
|
|
1227
|
+
const { error } = await this.supabase.from("mcp_sessions").insert(insertData);
|
|
1166
1228
|
if (error) {
|
|
1167
1229
|
if (error.code === "23505") {
|
|
1168
1230
|
throw new Error(`Session ${sessionId} already exists`);
|
|
@@ -1187,6 +1249,7 @@ var SupabaseStorageBackend = class {
|
|
|
1187
1249
|
}
|
|
1188
1250
|
if ("headers" in data) updateData.headers = encryptObject(data.headers);
|
|
1189
1251
|
if ("authUrl" in data) updateData.auth_url = data.authUrl ?? null;
|
|
1252
|
+
if ("toolPolicy" in data) updateData.tool_policy = normalizeToolPolicy(data.toolPolicy);
|
|
1190
1253
|
const shouldUpdateSession = Object.keys(updateData).some((key) => key !== "updated_at");
|
|
1191
1254
|
let updatedRows = null;
|
|
1192
1255
|
if (shouldUpdateSession) {
|
|
@@ -1360,7 +1423,8 @@ var NeonStorageBackend = class {
|
|
|
1360
1423
|
userId: row.user_id,
|
|
1361
1424
|
headers: decryptObject(row.headers),
|
|
1362
1425
|
authUrl: row.auth_url ?? void 0,
|
|
1363
|
-
status: row.status ?? "pending"
|
|
1426
|
+
status: row.status ?? "pending",
|
|
1427
|
+
toolPolicy: normalizeToolPolicy(row.tool_policy)
|
|
1364
1428
|
};
|
|
1365
1429
|
}
|
|
1366
1430
|
mapRowToCredentials(row, userId, sessionId) {
|
|
@@ -1383,42 +1447,48 @@ var NeonStorageBackend = class {
|
|
|
1383
1447
|
const status = session.status ?? "pending";
|
|
1384
1448
|
const createdAt = new Date(session.createdAt || Date.now()).toISOString();
|
|
1385
1449
|
const updatedAt = new Date(session.updatedAt ?? session.createdAt ?? Date.now()).toISOString();
|
|
1386
|
-
const
|
|
1450
|
+
const createdAtMs = new Date(createdAt).getTime();
|
|
1451
|
+
const expiresAt = resolveSessionExpiresAt(status, createdAtMs);
|
|
1452
|
+
const toolPolicy = normalizeToolPolicy(session.toolPolicy, createdAtMs);
|
|
1453
|
+
const columns = [
|
|
1454
|
+
"session_id",
|
|
1455
|
+
"user_id",
|
|
1456
|
+
"server_id",
|
|
1457
|
+
"server_name",
|
|
1458
|
+
"server_url",
|
|
1459
|
+
"transport_type",
|
|
1460
|
+
"callback_url",
|
|
1461
|
+
"created_at",
|
|
1462
|
+
"updated_at",
|
|
1463
|
+
"headers",
|
|
1464
|
+
"auth_url",
|
|
1465
|
+
"status",
|
|
1466
|
+
"expires_at"
|
|
1467
|
+
];
|
|
1468
|
+
const values = [
|
|
1469
|
+
sessionId,
|
|
1470
|
+
userId,
|
|
1471
|
+
session.serverId,
|
|
1472
|
+
session.serverName,
|
|
1473
|
+
session.serverUrl,
|
|
1474
|
+
session.transportType,
|
|
1475
|
+
session.callbackUrl,
|
|
1476
|
+
createdAt,
|
|
1477
|
+
updatedAt,
|
|
1478
|
+
encryptObject(session.headers),
|
|
1479
|
+
session.authUrl ?? null,
|
|
1480
|
+
status,
|
|
1481
|
+
expiresAt === null ? null : new Date(expiresAt).toISOString()
|
|
1482
|
+
];
|
|
1483
|
+
if (toolPolicy) {
|
|
1484
|
+
columns.push("tool_policy");
|
|
1485
|
+
values.push(toolPolicy);
|
|
1486
|
+
}
|
|
1487
|
+
const placeholders = values.map((_, i) => `$${i + 1}`);
|
|
1387
1488
|
try {
|
|
1388
1489
|
await this.sql.query(
|
|
1389
|
-
`INSERT INTO ${this.tableName} (
|
|
1390
|
-
|
|
1391
|
-
user_id,
|
|
1392
|
-
server_id,
|
|
1393
|
-
server_name,
|
|
1394
|
-
server_url,
|
|
1395
|
-
transport_type,
|
|
1396
|
-
callback_url,
|
|
1397
|
-
created_at,
|
|
1398
|
-
updated_at,
|
|
1399
|
-
headers,
|
|
1400
|
-
auth_url,
|
|
1401
|
-
status,
|
|
1402
|
-
expires_at
|
|
1403
|
-
) VALUES (
|
|
1404
|
-
$1, $2, $3, $4, $5, $6, $7, $8,
|
|
1405
|
-
$9, $10, $11, $12, $13
|
|
1406
|
-
)`,
|
|
1407
|
-
[
|
|
1408
|
-
sessionId,
|
|
1409
|
-
userId,
|
|
1410
|
-
session.serverId,
|
|
1411
|
-
session.serverName,
|
|
1412
|
-
session.serverUrl,
|
|
1413
|
-
session.transportType,
|
|
1414
|
-
session.callbackUrl,
|
|
1415
|
-
createdAt,
|
|
1416
|
-
updatedAt,
|
|
1417
|
-
encryptObject(session.headers),
|
|
1418
|
-
session.authUrl ?? null,
|
|
1419
|
-
status,
|
|
1420
|
-
expiresAt === null ? null : new Date(expiresAt).toISOString()
|
|
1421
|
-
]
|
|
1490
|
+
`INSERT INTO ${this.tableName} (${columns.join(", ")}) VALUES (${placeholders.join(", ")})`,
|
|
1491
|
+
values
|
|
1422
1492
|
);
|
|
1423
1493
|
} catch (error) {
|
|
1424
1494
|
if (error.code === "23505") {
|
|
@@ -1435,36 +1505,36 @@ var NeonStorageBackend = class {
|
|
|
1435
1505
|
const updatedSession = { ...currentSession, ...data };
|
|
1436
1506
|
const status = updatedSession.status ?? "pending";
|
|
1437
1507
|
const expiresAt = resolveSessionExpiresAt(status);
|
|
1438
|
-
const shouldUpdateSession = "serverId" in data || "serverName" in data || "serverUrl" in data || "transportType" in data || "callbackUrl" in data || "status" in data || "headers" in data || "authUrl" in data;
|
|
1508
|
+
const shouldUpdateSession = "serverId" in data || "serverName" in data || "serverUrl" in data || "transportType" in data || "callbackUrl" in data || "status" in data || "headers" in data || "authUrl" in data || "toolPolicy" in data;
|
|
1439
1509
|
if (shouldUpdateSession) {
|
|
1510
|
+
const setClauses = [];
|
|
1511
|
+
const values = [];
|
|
1512
|
+
let paramIndex = 1;
|
|
1513
|
+
const addSet = (column, value) => {
|
|
1514
|
+
setClauses.push(`${column} = $${paramIndex++}`);
|
|
1515
|
+
values.push(value);
|
|
1516
|
+
};
|
|
1517
|
+
addSet("server_id", updatedSession.serverId);
|
|
1518
|
+
addSet("server_name", updatedSession.serverName);
|
|
1519
|
+
addSet("server_url", updatedSession.serverUrl);
|
|
1520
|
+
addSet("transport_type", updatedSession.transportType);
|
|
1521
|
+
addSet("callback_url", updatedSession.callbackUrl);
|
|
1522
|
+
addSet("status", status);
|
|
1523
|
+
addSet("headers", encryptObject(updatedSession.headers));
|
|
1524
|
+
addSet("auth_url", updatedSession.authUrl ?? null);
|
|
1525
|
+
addSet("expires_at", expiresAt === null ? null : new Date(expiresAt).toISOString());
|
|
1526
|
+
if ("toolPolicy" in data) {
|
|
1527
|
+
const policyUpdatedAt = updatedSession.updatedAt ?? Date.now();
|
|
1528
|
+
const toolPolicy = normalizeToolPolicy(updatedSession.toolPolicy, policyUpdatedAt) ?? { mode: "all", toolIds: [], updatedAt: policyUpdatedAt };
|
|
1529
|
+
addSet("tool_policy", toolPolicy);
|
|
1530
|
+
}
|
|
1531
|
+
setClauses.push("updated_at = now()");
|
|
1440
1532
|
const updatedRows = await this.sql.query(
|
|
1441
1533
|
`UPDATE ${this.tableName}
|
|
1442
|
-
SET
|
|
1443
|
-
|
|
1444
|
-
server_name = $2,
|
|
1445
|
-
server_url = $3,
|
|
1446
|
-
transport_type = $4,
|
|
1447
|
-
callback_url = $5,
|
|
1448
|
-
status = $6,
|
|
1449
|
-
headers = $7,
|
|
1450
|
-
auth_url = $8,
|
|
1451
|
-
expires_at = $9,
|
|
1452
|
-
updated_at = now()
|
|
1453
|
-
WHERE user_id = $10 AND session_id = $11
|
|
1534
|
+
SET ${setClauses.join(", ")}
|
|
1535
|
+
WHERE user_id = $${paramIndex++} AND session_id = $${paramIndex++}
|
|
1454
1536
|
RETURNING id`,
|
|
1455
|
-
[
|
|
1456
|
-
updatedSession.serverId,
|
|
1457
|
-
updatedSession.serverName,
|
|
1458
|
-
updatedSession.serverUrl,
|
|
1459
|
-
updatedSession.transportType,
|
|
1460
|
-
updatedSession.callbackUrl,
|
|
1461
|
-
status,
|
|
1462
|
-
encryptObject(updatedSession.headers),
|
|
1463
|
-
updatedSession.authUrl ?? null,
|
|
1464
|
-
expiresAt === null ? null : new Date(expiresAt).toISOString(),
|
|
1465
|
-
userId,
|
|
1466
|
-
sessionId
|
|
1467
|
-
]
|
|
1537
|
+
[...values, userId, sessionId]
|
|
1468
1538
|
);
|
|
1469
1539
|
if (updatedRows.length === 0) {
|
|
1470
1540
|
throw new Error(`Session ${sessionId} not found for userId ${userId}`);
|
|
@@ -2384,7 +2454,15 @@ var MCPClient = class {
|
|
|
2384
2454
|
if (!existingSession && this.serverId && this.serverUrl && this.callbackUrl) {
|
|
2385
2455
|
this.createdAt = Date.now();
|
|
2386
2456
|
const updatedAt = this.createdAt;
|
|
2387
|
-
|
|
2457
|
+
this._onObservabilityEvent.fire({
|
|
2458
|
+
type: "mcp:client:session_created",
|
|
2459
|
+
level: "info",
|
|
2460
|
+
message: `Creating pending session ${this.sessionId} for connection setup`,
|
|
2461
|
+
sessionId: this.sessionId,
|
|
2462
|
+
serverId: this.serverId,
|
|
2463
|
+
timestamp: Date.now(),
|
|
2464
|
+
id: nanoid.nanoid()
|
|
2465
|
+
});
|
|
2388
2466
|
await sessions.create({
|
|
2389
2467
|
sessionId: this.sessionId,
|
|
2390
2468
|
userId: this.userId,
|
|
@@ -2514,7 +2592,15 @@ var MCPClient = class {
|
|
|
2514
2592
|
this.transportType = transportType;
|
|
2515
2593
|
this.emitStateChange("CONNECTED");
|
|
2516
2594
|
this.emitProgress("Connected successfully");
|
|
2517
|
-
|
|
2595
|
+
this._onObservabilityEvent.fire({
|
|
2596
|
+
type: "mcp:client:session_saved",
|
|
2597
|
+
level: "info",
|
|
2598
|
+
message: `Saving active session ${this.sessionId} (connect success)`,
|
|
2599
|
+
sessionId: this.sessionId,
|
|
2600
|
+
serverId: this.serverId,
|
|
2601
|
+
timestamp: Date.now(),
|
|
2602
|
+
id: nanoid.nanoid()
|
|
2603
|
+
});
|
|
2518
2604
|
await this.saveSession("active");
|
|
2519
2605
|
} catch (error) {
|
|
2520
2606
|
if (error instanceof auth_js.UnauthorizedError || error instanceof Error && error.message.toLowerCase().includes("unauthorized")) {
|
|
@@ -2531,7 +2617,15 @@ var MCPClient = class {
|
|
|
2531
2617
|
throw new Error(message);
|
|
2532
2618
|
}
|
|
2533
2619
|
this.emitStateChange("AUTHENTICATING");
|
|
2534
|
-
|
|
2620
|
+
this._onObservabilityEvent.fire({
|
|
2621
|
+
type: "mcp:client:session_saved",
|
|
2622
|
+
level: "info",
|
|
2623
|
+
message: `Saving pending OAuth session ${this.sessionId}`,
|
|
2624
|
+
sessionId: this.sessionId,
|
|
2625
|
+
serverId: this.serverId,
|
|
2626
|
+
timestamp: Date.now(),
|
|
2627
|
+
id: nanoid.nanoid()
|
|
2628
|
+
});
|
|
2535
2629
|
await this.saveSession("pending");
|
|
2536
2630
|
if (this.serverId) {
|
|
2537
2631
|
this._onConnectionEvent.fire({
|
|
@@ -2606,27 +2700,25 @@ var MCPClient = class {
|
|
|
2606
2700
|
this.emitStateChange("AUTHENTICATED");
|
|
2607
2701
|
authenticatedStateEmitted = true;
|
|
2608
2702
|
}
|
|
2609
|
-
this.emitProgress("Creating authenticated client...");
|
|
2610
|
-
this.client = new index_js.Client(
|
|
2611
|
-
{
|
|
2612
|
-
name: MCP_CLIENT_NAME,
|
|
2613
|
-
version: MCP_CLIENT_VERSION
|
|
2614
|
-
},
|
|
2615
|
-
{
|
|
2616
|
-
capabilities: {
|
|
2617
|
-
extensions: {
|
|
2618
|
-
"io.modelcontextprotocol/ui": {
|
|
2619
|
-
mimeTypes: ["text/html+mcp"]
|
|
2620
|
-
}
|
|
2621
|
-
}
|
|
2622
|
-
}
|
|
2623
|
-
}
|
|
2624
|
-
);
|
|
2625
2703
|
this.emitStateChange("CONNECTING");
|
|
2704
|
+
if (this.client.transport) {
|
|
2705
|
+
try {
|
|
2706
|
+
await this.client.close();
|
|
2707
|
+
} catch {
|
|
2708
|
+
}
|
|
2709
|
+
}
|
|
2626
2710
|
await this.client.connect(this.transport);
|
|
2627
2711
|
this.transportType = currentType;
|
|
2628
2712
|
this.emitStateChange("CONNECTED");
|
|
2629
|
-
|
|
2713
|
+
this._onObservabilityEvent.fire({
|
|
2714
|
+
type: "mcp:client:session_saved",
|
|
2715
|
+
level: "info",
|
|
2716
|
+
message: `Saving active session ${this.sessionId} (OAuth complete)`,
|
|
2717
|
+
sessionId: this.sessionId,
|
|
2718
|
+
serverId: this.serverId,
|
|
2719
|
+
timestamp: Date.now(),
|
|
2720
|
+
id: nanoid.nanoid()
|
|
2721
|
+
});
|
|
2630
2722
|
await this.saveSession("active");
|
|
2631
2723
|
return;
|
|
2632
2724
|
} catch (error) {
|
|
@@ -2661,24 +2753,28 @@ var MCPClient = class {
|
|
|
2661
2753
|
throw lastError;
|
|
2662
2754
|
}
|
|
2663
2755
|
}
|
|
2756
|
+
/**
|
|
2757
|
+
* Lists all available tools from the connected MCP server without emitting discovery events.
|
|
2758
|
+
* Gateways use this to apply policy before publishing tools to agents or UI state.
|
|
2759
|
+
*/
|
|
2760
|
+
async fetchTools() {
|
|
2761
|
+
const request = {
|
|
2762
|
+
method: "tools/list",
|
|
2763
|
+
params: {}
|
|
2764
|
+
};
|
|
2765
|
+
return await this.withRetry(
|
|
2766
|
+
() => this.client.request(request, types_js.ListToolsResultSchema)
|
|
2767
|
+
);
|
|
2768
|
+
}
|
|
2664
2769
|
/**
|
|
2665
2770
|
* Lists all available tools from the connected MCP server
|
|
2666
2771
|
* @returns List of tools with their schemas and descriptions
|
|
2667
2772
|
* @throws {Error} When client is not connected
|
|
2668
2773
|
*/
|
|
2669
2774
|
async listTools() {
|
|
2670
|
-
if (!this.client) {
|
|
2671
|
-
throw new Error("Not connected to server");
|
|
2672
|
-
}
|
|
2673
2775
|
this.emitStateChange("DISCOVERING");
|
|
2674
2776
|
try {
|
|
2675
|
-
const
|
|
2676
|
-
method: "tools/list",
|
|
2677
|
-
params: {}
|
|
2678
|
-
};
|
|
2679
|
-
const result = await this.withRetry(
|
|
2680
|
-
() => this.client.request(request, types_js.ListToolsResultSchema)
|
|
2681
|
-
);
|
|
2777
|
+
const result = await this.fetchTools();
|
|
2682
2778
|
if (this.serverId) {
|
|
2683
2779
|
this._onConnectionEvent.fire({
|
|
2684
2780
|
type: "tools_discovered",
|
|
@@ -2707,9 +2803,6 @@ var MCPClient = class {
|
|
|
2707
2803
|
* @throws {Error} When client is not connected
|
|
2708
2804
|
*/
|
|
2709
2805
|
async callTool(toolName, toolArgs) {
|
|
2710
|
-
if (!this.client) {
|
|
2711
|
-
throw new Error("Not connected to server");
|
|
2712
|
-
}
|
|
2713
2806
|
const request = {
|
|
2714
2807
|
method: "tools/call",
|
|
2715
2808
|
params: {
|
|
@@ -2763,9 +2856,6 @@ var MCPClient = class {
|
|
|
2763
2856
|
* @throws {Error} When client is not connected
|
|
2764
2857
|
*/
|
|
2765
2858
|
async listPrompts() {
|
|
2766
|
-
if (!this.client) {
|
|
2767
|
-
throw new Error("Not connected to server");
|
|
2768
|
-
}
|
|
2769
2859
|
this.emitStateChange("DISCOVERING");
|
|
2770
2860
|
try {
|
|
2771
2861
|
const request = {
|
|
@@ -2793,9 +2883,6 @@ var MCPClient = class {
|
|
|
2793
2883
|
* @throws {Error} When client is not connected
|
|
2794
2884
|
*/
|
|
2795
2885
|
async getPrompt(name, args) {
|
|
2796
|
-
if (!this.client) {
|
|
2797
|
-
throw new Error("Not connected to server");
|
|
2798
|
-
}
|
|
2799
2886
|
const request = {
|
|
2800
2887
|
method: "prompts/get",
|
|
2801
2888
|
params: {
|
|
@@ -2813,9 +2900,6 @@ var MCPClient = class {
|
|
|
2813
2900
|
* @throws {Error} When client is not connected
|
|
2814
2901
|
*/
|
|
2815
2902
|
async listResources() {
|
|
2816
|
-
if (!this.client) {
|
|
2817
|
-
throw new Error("Not connected to server");
|
|
2818
|
-
}
|
|
2819
2903
|
this.emitStateChange("DISCOVERING");
|
|
2820
2904
|
try {
|
|
2821
2905
|
const request = {
|
|
@@ -2842,9 +2926,6 @@ var MCPClient = class {
|
|
|
2842
2926
|
* @throws {Error} When client is not connected
|
|
2843
2927
|
*/
|
|
2844
2928
|
async readResource(uri) {
|
|
2845
|
-
if (!this.client) {
|
|
2846
|
-
throw new Error("Not connected to server");
|
|
2847
|
-
}
|
|
2848
2929
|
const request = {
|
|
2849
2930
|
method: "resources/read",
|
|
2850
2931
|
params: {
|
|
@@ -2900,7 +2981,16 @@ var MCPClient = class {
|
|
|
2900
2981
|
try {
|
|
2901
2982
|
await this.ensureSession();
|
|
2902
2983
|
} catch (error) {
|
|
2903
|
-
|
|
2984
|
+
this._onObservabilityEvent.fire({
|
|
2985
|
+
type: "mcp:client:error",
|
|
2986
|
+
level: "warn",
|
|
2987
|
+
message: "Initialization failed during clearSession",
|
|
2988
|
+
sessionId: this.sessionId,
|
|
2989
|
+
serverId: this.serverId,
|
|
2990
|
+
payload: { error: String(error) },
|
|
2991
|
+
timestamp: Date.now(),
|
|
2992
|
+
id: nanoid.nanoid()
|
|
2993
|
+
});
|
|
2904
2994
|
}
|
|
2905
2995
|
if (this.oauthProvider) {
|
|
2906
2996
|
await this.oauthProvider.invalidateCredentials("all");
|
|
@@ -3013,6 +3103,69 @@ var MCPClient = class {
|
|
|
3013
3103
|
|
|
3014
3104
|
// src/server/mcp/multi-session-client.ts
|
|
3015
3105
|
init_cjs_shims();
|
|
3106
|
+
|
|
3107
|
+
// src/server/mcp/tool-policy-gateway.ts
|
|
3108
|
+
init_cjs_shims();
|
|
3109
|
+
var ToolPolicyGateway = class {
|
|
3110
|
+
constructor(userId, sessionId, client) {
|
|
3111
|
+
this.userId = userId;
|
|
3112
|
+
this.sessionId = sessionId;
|
|
3113
|
+
this.client = client;
|
|
3114
|
+
}
|
|
3115
|
+
isConnected() {
|
|
3116
|
+
return this.client.isConnected();
|
|
3117
|
+
}
|
|
3118
|
+
getServerId() {
|
|
3119
|
+
return this.client.getServerId?.();
|
|
3120
|
+
}
|
|
3121
|
+
getServerName() {
|
|
3122
|
+
return this.client.getServerName?.();
|
|
3123
|
+
}
|
|
3124
|
+
getServerUrl() {
|
|
3125
|
+
return this.client.getServerUrl?.();
|
|
3126
|
+
}
|
|
3127
|
+
getSessionId() {
|
|
3128
|
+
return this.client.getSessionId?.() ?? this.sessionId;
|
|
3129
|
+
}
|
|
3130
|
+
async listTools() {
|
|
3131
|
+
const session = await this.getSession();
|
|
3132
|
+
const result = await this.client.fetchTools();
|
|
3133
|
+
const tools = this.filterTools(session, result.tools);
|
|
3134
|
+
return {
|
|
3135
|
+
...result,
|
|
3136
|
+
tools
|
|
3137
|
+
};
|
|
3138
|
+
}
|
|
3139
|
+
async listAllTools() {
|
|
3140
|
+
return await this.client.fetchTools();
|
|
3141
|
+
}
|
|
3142
|
+
async callTool(name, args) {
|
|
3143
|
+
const session = await this.getSession();
|
|
3144
|
+
this.assertAllowed(session, name);
|
|
3145
|
+
return await this.client.callTool(name, args);
|
|
3146
|
+
}
|
|
3147
|
+
filterTools(session, tools) {
|
|
3148
|
+
return filterToolsByPolicy(tools, session.toolPolicy, this.getPolicyServerId(session));
|
|
3149
|
+
}
|
|
3150
|
+
assertAllowed(session, toolName) {
|
|
3151
|
+
assertToolAllowed(session.toolPolicy, toolName, this.getPolicyServerId(session));
|
|
3152
|
+
}
|
|
3153
|
+
async getSession() {
|
|
3154
|
+
const session = await sessions.get(this.userId, this.sessionId);
|
|
3155
|
+
if (!session) {
|
|
3156
|
+
throw new Error("Session not found");
|
|
3157
|
+
}
|
|
3158
|
+
return session;
|
|
3159
|
+
}
|
|
3160
|
+
getPolicyServerId(session) {
|
|
3161
|
+
return this.client.getServerId?.() ?? session.serverId;
|
|
3162
|
+
}
|
|
3163
|
+
};
|
|
3164
|
+
function createToolPolicyGateway(userId, sessionId, client) {
|
|
3165
|
+
return new ToolPolicyGateway(userId, sessionId, client);
|
|
3166
|
+
}
|
|
3167
|
+
|
|
3168
|
+
// src/server/mcp/multi-session-client.ts
|
|
3016
3169
|
var DEFAULT_TIMEOUT_MS = 15e3;
|
|
3017
3170
|
var DEFAULT_MAX_RETRIES = 2;
|
|
3018
3171
|
var DEFAULT_RETRY_DELAY_MS = 1e3;
|
|
@@ -3077,7 +3230,9 @@ var MultiSessionClient = class {
|
|
|
3077
3230
|
* or to route a tool call to the right client by `serverId`.
|
|
3078
3231
|
*/
|
|
3079
3232
|
getClients() {
|
|
3080
|
-
return this.clients
|
|
3233
|
+
return this.clients.map(
|
|
3234
|
+
(client) => createToolPolicyGateway(this.userId, client.getSessionId(), client)
|
|
3235
|
+
);
|
|
3081
3236
|
}
|
|
3082
3237
|
/**
|
|
3083
3238
|
* Removes and disconnects a single session by ID.
|
|
@@ -3316,6 +3471,12 @@ var SSEConnectionManager = class {
|
|
|
3316
3471
|
case "listTools":
|
|
3317
3472
|
result = await this.listTools(request.params);
|
|
3318
3473
|
break;
|
|
3474
|
+
case "setToolPolicy":
|
|
3475
|
+
result = await this.setToolPolicy(request.params);
|
|
3476
|
+
break;
|
|
3477
|
+
case "getToolPolicy":
|
|
3478
|
+
result = await this.getToolPolicy(request.params);
|
|
3479
|
+
break;
|
|
3319
3480
|
case "callTool":
|
|
3320
3481
|
result = await this.callTool(request.params);
|
|
3321
3482
|
break;
|
|
@@ -3372,7 +3533,8 @@ var SSEConnectionManager = class {
|
|
|
3372
3533
|
transport: s.transportType,
|
|
3373
3534
|
createdAt: s.createdAt,
|
|
3374
3535
|
updatedAt: s.updatedAt ?? s.createdAt,
|
|
3375
|
-
status: s.status ?? "pending"
|
|
3536
|
+
status: s.status ?? "pending",
|
|
3537
|
+
toolPolicy: s.toolPolicy
|
|
3376
3538
|
}))
|
|
3377
3539
|
};
|
|
3378
3540
|
}
|
|
@@ -3382,7 +3544,7 @@ var SSEConnectionManager = class {
|
|
|
3382
3544
|
async connect(params) {
|
|
3383
3545
|
const { serverName, serverUrl, callbackUrl, transportType } = params;
|
|
3384
3546
|
const headers = normalizeHeaders(params.headers);
|
|
3385
|
-
const serverId = params.serverId && params.serverId.length <= 12 ? params.serverId :
|
|
3547
|
+
const serverId = params.serverId && params.serverId.length <= 12 ? params.serverId : generateServerId();
|
|
3386
3548
|
const existingSessions = await sessions.list(this.userId);
|
|
3387
3549
|
const duplicate = existingSessions.find(
|
|
3388
3550
|
(s) => s.serverId === serverId || s.serverUrl === serverUrl
|
|
@@ -3420,7 +3582,7 @@ var SSEConnectionManager = class {
|
|
|
3420
3582
|
this.sendEvent(event);
|
|
3421
3583
|
});
|
|
3422
3584
|
await client.connect();
|
|
3423
|
-
await
|
|
3585
|
+
await this.listPolicyFilteredTools(sessionId);
|
|
3424
3586
|
return {
|
|
3425
3587
|
sessionId,
|
|
3426
3588
|
success: true
|
|
@@ -3491,22 +3653,98 @@ var SSEConnectionManager = class {
|
|
|
3491
3653
|
this.clients.set(sessionId, client);
|
|
3492
3654
|
return client;
|
|
3493
3655
|
}
|
|
3656
|
+
async listPolicyFilteredTools(sessionId) {
|
|
3657
|
+
const session = await sessions.get(this.userId, sessionId);
|
|
3658
|
+
if (!session) {
|
|
3659
|
+
throw new Error("Session not found");
|
|
3660
|
+
}
|
|
3661
|
+
const client = await this.getOrCreateClient(sessionId);
|
|
3662
|
+
const gateway = createToolPolicyGateway(this.userId, sessionId, client);
|
|
3663
|
+
const result = await gateway.listTools();
|
|
3664
|
+
this.emitConnectionEvent({
|
|
3665
|
+
type: "tools_discovered",
|
|
3666
|
+
sessionId,
|
|
3667
|
+
serverId: session.serverId ?? "unknown",
|
|
3668
|
+
toolCount: result.tools.length,
|
|
3669
|
+
tools: result.tools,
|
|
3670
|
+
timestamp: Date.now()
|
|
3671
|
+
});
|
|
3672
|
+
return { session, result };
|
|
3673
|
+
}
|
|
3494
3674
|
/**
|
|
3495
3675
|
* List tools from a session
|
|
3496
3676
|
*/
|
|
3497
3677
|
async listTools(params) {
|
|
3498
3678
|
const { sessionId } = params;
|
|
3499
|
-
const
|
|
3500
|
-
const result = await client.listTools();
|
|
3679
|
+
const { result } = await this.listPolicyFilteredTools(sessionId);
|
|
3501
3680
|
return { tools: result.tools };
|
|
3502
3681
|
}
|
|
3682
|
+
/**
|
|
3683
|
+
* Get all raw tools with effective access state for management UI.
|
|
3684
|
+
*/
|
|
3685
|
+
async getToolPolicy(params) {
|
|
3686
|
+
const { sessionId } = params;
|
|
3687
|
+
const session = await sessions.get(this.userId, sessionId);
|
|
3688
|
+
if (!session) {
|
|
3689
|
+
throw new Error("Session not found");
|
|
3690
|
+
}
|
|
3691
|
+
const client = await this.getOrCreateClient(sessionId);
|
|
3692
|
+
const allTools = await client.fetchTools();
|
|
3693
|
+
const toolPolicy = session.toolPolicy ?? {
|
|
3694
|
+
mode: "all",
|
|
3695
|
+
toolIds: [],
|
|
3696
|
+
updatedAt: session.updatedAt ?? session.createdAt
|
|
3697
|
+
};
|
|
3698
|
+
const serverId = session.serverId ?? "unknown";
|
|
3699
|
+
const tools = allTools.tools.map((tool) => ({
|
|
3700
|
+
...tool,
|
|
3701
|
+
toolId: createToolId(serverId, tool.name),
|
|
3702
|
+
allowed: isToolAllowed(toolPolicy, tool.name, session.serverId)
|
|
3703
|
+
}));
|
|
3704
|
+
return {
|
|
3705
|
+
toolPolicy,
|
|
3706
|
+
tools,
|
|
3707
|
+
toolCount: tools.length,
|
|
3708
|
+
allowedToolCount: tools.filter((tool) => tool.allowed).length
|
|
3709
|
+
};
|
|
3710
|
+
}
|
|
3711
|
+
/**
|
|
3712
|
+
* Update per-session tool access policy.
|
|
3713
|
+
*/
|
|
3714
|
+
async setToolPolicy(params) {
|
|
3715
|
+
const { sessionId } = params;
|
|
3716
|
+
const session = await sessions.get(this.userId, sessionId);
|
|
3717
|
+
if (!session) {
|
|
3718
|
+
throw new Error("Session not found");
|
|
3719
|
+
}
|
|
3720
|
+
const client = await this.getOrCreateClient(sessionId);
|
|
3721
|
+
const allTools = await client.fetchTools();
|
|
3722
|
+
const toolPolicy = normalizeToolPolicyForUpdate(params.toolPolicy);
|
|
3723
|
+
validateToolPolicyAgainstTools(toolPolicy, allTools.tools, session.serverId);
|
|
3724
|
+
await sessions.update(this.userId, sessionId, { toolPolicy });
|
|
3725
|
+
const filteredTools = createToolPolicyGateway(this.userId, sessionId, client).filterTools({ ...session, toolPolicy }, allTools.tools);
|
|
3726
|
+
this.emitConnectionEvent({
|
|
3727
|
+
type: "tools_discovered",
|
|
3728
|
+
sessionId,
|
|
3729
|
+
serverId: session.serverId ?? "unknown",
|
|
3730
|
+
toolCount: filteredTools.length,
|
|
3731
|
+
tools: filteredTools,
|
|
3732
|
+
timestamp: Date.now()
|
|
3733
|
+
});
|
|
3734
|
+
return {
|
|
3735
|
+
success: true,
|
|
3736
|
+
toolPolicy,
|
|
3737
|
+
tools: filteredTools,
|
|
3738
|
+
toolCount: filteredTools.length
|
|
3739
|
+
};
|
|
3740
|
+
}
|
|
3503
3741
|
/**
|
|
3504
3742
|
* Call a tool on the MCP server
|
|
3505
3743
|
*/
|
|
3506
3744
|
async callTool(params) {
|
|
3507
3745
|
const { sessionId, toolName, toolArgs } = params;
|
|
3508
3746
|
const client = await this.getOrCreateClient(sessionId);
|
|
3509
|
-
const result = await client.callTool(toolName, toolArgs);
|
|
3747
|
+
const result = await createToolPolicyGateway(this.userId, sessionId, client).callTool(toolName, toolArgs);
|
|
3510
3748
|
const meta = result._meta || {};
|
|
3511
3749
|
return {
|
|
3512
3750
|
...result,
|
|
@@ -3556,7 +3794,7 @@ var SSEConnectionManager = class {
|
|
|
3556
3794
|
client.onObservabilityEvent((event) => this.sendEvent(event));
|
|
3557
3795
|
await client.connect();
|
|
3558
3796
|
this.clients.set(sessionId, client);
|
|
3559
|
-
const tools = await
|
|
3797
|
+
const { result: tools } = await this.listPolicyFilteredTools(sessionId);
|
|
3560
3798
|
return { success: true, toolCount: tools.tools.length };
|
|
3561
3799
|
} catch (error) {
|
|
3562
3800
|
this.emitConnectionEvent({
|
|
@@ -3604,7 +3842,7 @@ var SSEConnectionManager = class {
|
|
|
3604
3842
|
client.onConnectionEvent((event) => this.emitConnectionEvent(event));
|
|
3605
3843
|
await client.finishAuth(code, oauthState);
|
|
3606
3844
|
this.clients.set(sessionId, client);
|
|
3607
|
-
const tools = await
|
|
3845
|
+
const { result: tools } = await this.listPolicyFilteredTools(sessionId);
|
|
3608
3846
|
return { success: true, toolCount: tools.tools.length };
|
|
3609
3847
|
} catch (error) {
|
|
3610
3848
|
this.emitConnectionEvent({
|