@mcp-ts/sdk 1.6.1 → 2.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.
Files changed (114) hide show
  1. package/README.md +12 -6
  2. package/dist/adapters/agui-adapter.d.mts +3 -3
  3. package/dist/adapters/agui-adapter.d.ts +3 -3
  4. package/dist/adapters/agui-adapter.js +4 -5
  5. package/dist/adapters/agui-adapter.js.map +1 -1
  6. package/dist/adapters/agui-adapter.mjs +4 -5
  7. package/dist/adapters/agui-adapter.mjs.map +1 -1
  8. package/dist/adapters/agui-middleware.d.mts +3 -3
  9. package/dist/adapters/agui-middleware.d.ts +3 -3
  10. package/dist/adapters/ai-adapter.d.mts +9 -3
  11. package/dist/adapters/ai-adapter.d.ts +9 -3
  12. package/dist/adapters/ai-adapter.js +20 -6
  13. package/dist/adapters/ai-adapter.js.map +1 -1
  14. package/dist/adapters/ai-adapter.mjs +20 -6
  15. package/dist/adapters/ai-adapter.mjs.map +1 -1
  16. package/dist/adapters/langchain-adapter.d.mts +3 -3
  17. package/dist/adapters/langchain-adapter.d.ts +3 -3
  18. package/dist/adapters/langchain-adapter.js +9 -6
  19. package/dist/adapters/langchain-adapter.js.map +1 -1
  20. package/dist/adapters/langchain-adapter.mjs +9 -6
  21. package/dist/adapters/langchain-adapter.mjs.map +1 -1
  22. package/dist/adapters/mastra-adapter.d.mts +1 -1
  23. package/dist/adapters/mastra-adapter.d.ts +1 -1
  24. package/dist/adapters/mastra-adapter.js +5 -1
  25. package/dist/adapters/mastra-adapter.js.map +1 -1
  26. package/dist/adapters/mastra-adapter.mjs +5 -1
  27. package/dist/adapters/mastra-adapter.mjs.map +1 -1
  28. package/dist/bin/mcp-ts.js +7 -1
  29. package/dist/bin/mcp-ts.js.map +1 -1
  30. package/dist/bin/mcp-ts.mjs +7 -1
  31. package/dist/bin/mcp-ts.mjs.map +1 -1
  32. package/dist/client/index.d.mts +2 -2
  33. package/dist/client/index.d.ts +2 -2
  34. package/dist/client/index.js +9 -13
  35. package/dist/client/index.js.map +1 -1
  36. package/dist/client/index.mjs +9 -13
  37. package/dist/client/index.mjs.map +1 -1
  38. package/dist/client/react.d.mts +7 -7
  39. package/dist/client/react.d.ts +7 -7
  40. package/dist/client/react.js +111 -63
  41. package/dist/client/react.js.map +1 -1
  42. package/dist/client/react.mjs +111 -63
  43. package/dist/client/react.mjs.map +1 -1
  44. package/dist/client/vue.d.mts +7 -7
  45. package/dist/client/vue.d.ts +7 -7
  46. package/dist/client/vue.js +14 -18
  47. package/dist/client/vue.js.map +1 -1
  48. package/dist/client/vue.mjs +14 -18
  49. package/dist/client/vue.mjs.map +1 -1
  50. package/dist/{index-DhA-OEAe.d.ts → index-C9gvpxy5.d.ts} +5 -5
  51. package/dist/{index-bFL4ZF2N.d.mts → index-eaH14_5u.d.mts} +5 -5
  52. package/dist/index.d.mts +6 -6
  53. package/dist/index.d.ts +6 -6
  54. package/dist/index.js +616 -370
  55. package/dist/index.js.map +1 -1
  56. package/dist/index.mjs +615 -370
  57. package/dist/index.mjs.map +1 -1
  58. package/dist/{multi-session-client-CHE8QpVE.d.ts → multi-session-client-BYtguGJm.d.ts} +22 -22
  59. package/dist/{multi-session-client-CQsRbxYI.d.mts → multi-session-client-DYNe6az3.d.mts} +22 -22
  60. package/dist/server/index.d.mts +31 -34
  61. package/dist/server/index.d.ts +31 -34
  62. package/dist/server/index.js +531 -256
  63. package/dist/server/index.js.map +1 -1
  64. package/dist/server/index.mjs +530 -256
  65. package/dist/server/index.mjs.map +1 -1
  66. package/dist/shared/index.d.mts +5 -5
  67. package/dist/shared/index.d.ts +5 -5
  68. package/dist/shared/index.js +76 -101
  69. package/dist/shared/index.js.map +1 -1
  70. package/dist/shared/index.mjs +76 -101
  71. package/dist/shared/index.mjs.map +1 -1
  72. package/dist/{tool-router-Dh2804tM.d.ts → tool-router-Ddtybmr0.d.ts} +71 -73
  73. package/dist/{tool-router-BVaV1udm.d.mts → tool-router-Dnd6IOKC.d.mts} +71 -73
  74. package/dist/{types-rIuN1CQi.d.mts → types-BCAG20P6.d.mts} +4 -4
  75. package/dist/{types-rIuN1CQi.d.ts → types-BCAG20P6.d.ts} +4 -4
  76. package/dist/{utils-0qmYrqoa.d.mts → utils-DELRKQPU.d.mts} +1 -1
  77. package/dist/{utils-0qmYrqoa.d.ts → utils-DELRKQPU.d.ts} +1 -1
  78. package/migrations/neon/20260513010000_install_mcp_sessions.sql +69 -0
  79. package/migrations/neon/20260513020000_add_session_cleanup_cron.sql +35 -0
  80. package/{supabase/migrations → migrations/supabase}/20260330195700_install_mcp_sessions.sql +7 -9
  81. package/package.json +14 -5
  82. package/src/adapters/ai-adapter.ts +30 -1
  83. package/src/adapters/langchain-adapter.ts +6 -2
  84. package/src/adapters/mastra-adapter.ts +6 -2
  85. package/src/bin/mcp-ts.ts +8 -1
  86. package/src/client/core/app-host.ts +1 -1
  87. package/src/client/core/sse-client.ts +12 -14
  88. package/src/client/core/types.ts +1 -1
  89. package/src/client/react/oauth-popup.tsx +111 -51
  90. package/src/client/react/use-mcp-apps.tsx +1 -1
  91. package/src/client/react/use-mcp.ts +11 -11
  92. package/src/client/vue/use-mcp.ts +10 -10
  93. package/src/server/handlers/nextjs-handler.ts +18 -15
  94. package/src/server/handlers/sse-handler.ts +29 -29
  95. package/src/server/index.ts +1 -1
  96. package/src/server/mcp/multi-session-client.ts +17 -17
  97. package/src/server/mcp/oauth-client.ts +37 -37
  98. package/src/server/mcp/storage-oauth-provider.ts +17 -17
  99. package/src/server/storage/file-backend.ts +25 -25
  100. package/src/server/storage/index.ts +67 -10
  101. package/src/server/storage/memory-backend.ts +34 -34
  102. package/src/server/storage/neon-backend.ts +281 -0
  103. package/src/server/storage/redis-backend.ts +64 -64
  104. package/src/server/storage/sqlite-backend.ts +33 -33
  105. package/src/server/storage/supabase-backend.ts +23 -24
  106. package/src/server/storage/types.ts +18 -21
  107. package/src/shared/errors.ts +1 -1
  108. package/src/shared/index.ts +1 -2
  109. package/src/shared/meta-tools.ts +4 -6
  110. package/src/shared/schema-compressor.ts +2 -42
  111. package/src/shared/tool-index.ts +89 -84
  112. package/src/shared/tool-router.ts +0 -24
  113. package/src/shared/types.ts +4 -4
  114. /package/{supabase/migrations → migrations/supabase}/20260421010000_add_session_cleanup_cron.sql +0 -0
package/dist/index.js CHANGED
@@ -203,35 +203,35 @@ var RedisStorageBackend = class {
203
203
  this.redis = redis2;
204
204
  __publicField(this, "DEFAULT_TTL", SESSION_TTL_SECONDS);
205
205
  __publicField(this, "KEY_PREFIX", "mcp:session:");
206
- __publicField(this, "IDENTITY_KEY_PREFIX", "mcp:identity:");
207
- __publicField(this, "IDENTITY_KEY_SUFFIX", ":sessions");
206
+ __publicField(this, "USER_ID_KEY_PREFIX", "mcp:userId:");
207
+ __publicField(this, "USER_ID_KEY_SUFFIX", ":sessions");
208
208
  }
209
209
  async init() {
210
210
  try {
211
211
  await this.redis.ping();
212
212
  console.log("[mcp-ts][Storage] Redis: \u2713 Connected to server.");
213
213
  } catch (error) {
214
- throw new Error(`[RedisStorage] Failed to connect to Redis: ${error.message}`);
214
+ throw new Error(`[RedisStorageBackend] Failed to connect to Redis: ${error.message}`);
215
215
  }
216
216
  }
217
217
  /**
218
218
  * Generates Redis key for a specific session
219
219
  * @private
220
220
  */
221
- getSessionKey(identity, sessionId) {
222
- return `${this.KEY_PREFIX}${identity}:${sessionId}`;
221
+ getSessionKey(userId, sessionId) {
222
+ return `${this.KEY_PREFIX}${userId}:${sessionId}`;
223
223
  }
224
224
  /**
225
- * Generates Redis key for tracking all sessions for an identity
225
+ * Generates Redis key for tracking all sessions for a user
226
226
  * @private
227
227
  */
228
- getIdentityKey(identity) {
229
- return `${this.IDENTITY_KEY_PREFIX}${identity}${this.IDENTITY_KEY_SUFFIX}`;
228
+ getUserIdKey(userId) {
229
+ return `${this.USER_ID_KEY_PREFIX}${userId}${this.USER_ID_KEY_SUFFIX}`;
230
230
  }
231
- parseIdentityFromKey(identityKey) {
232
- return identityKey.slice(
233
- this.IDENTITY_KEY_PREFIX.length,
234
- identityKey.length - this.IDENTITY_KEY_SUFFIX.length
231
+ parseUserIdFromKey(userIdKey) {
232
+ return userIdKey.slice(
233
+ this.USER_ID_KEY_PREFIX.length,
234
+ userIdKey.length - this.USER_ID_KEY_SUFFIX.length
235
235
  );
236
236
  }
237
237
  async scanKeys(pattern) {
@@ -250,7 +250,7 @@ var RedisStorageBackend = class {
250
250
  }
251
251
  } while (cursor !== "0");
252
252
  } catch (error) {
253
- console.warn("[RedisStorage] SCAN failed, falling back to KEYS:", error);
253
+ console.warn("[RedisStorageBackend] SCAN failed, falling back to KEYS:", error);
254
254
  return await this.redis.keys(pattern);
255
255
  }
256
256
  return Array.from(keys);
@@ -258,11 +258,11 @@ var RedisStorageBackend = class {
258
258
  generateSessionId() {
259
259
  return generateSessionId();
260
260
  }
261
- async createSession(session, ttl) {
262
- const { sessionId, identity } = session;
263
- if (!sessionId || !identity) throw new Error("identity and sessionId required");
264
- const sessionKey = this.getSessionKey(identity, sessionId);
265
- const identityKey = this.getIdentityKey(identity);
261
+ async create(session, ttl) {
262
+ const { sessionId, userId } = session;
263
+ if (!sessionId || !userId) throw new Error("userId and sessionId required");
264
+ const sessionKey = this.getSessionKey(userId, sessionId);
265
+ const userIdKey = this.getUserIdKey(userId);
266
266
  const effectiveTtl = ttl ?? this.DEFAULT_TTL;
267
267
  const result = await this.redis.set(
268
268
  sessionKey,
@@ -274,10 +274,10 @@ var RedisStorageBackend = class {
274
274
  if (result !== "OK") {
275
275
  throw new Error(`Session ${sessionId} already exists`);
276
276
  }
277
- await this.redis.sadd(identityKey, sessionId);
277
+ await this.redis.sadd(userIdKey, sessionId);
278
278
  }
279
- async updateSession(identity, sessionId, data, ttl) {
280
- const sessionKey = this.getSessionKey(identity, sessionId);
279
+ async update(userId, sessionId, data, ttl) {
280
+ const sessionKey = this.getSessionKey(userId, sessionId);
281
281
  const effectiveTtl = ttl ?? this.DEFAULT_TTL;
282
282
  const script = `
283
283
  local currentStr = redis.call("GET", KEYS[1])
@@ -303,62 +303,62 @@ var RedisStorageBackend = class {
303
303
  effectiveTtl
304
304
  );
305
305
  if (result === 0) {
306
- throw new Error(`Session ${sessionId} not found for identity ${identity}`);
306
+ throw new Error(`Session ${sessionId} not found for userId ${userId}`);
307
307
  }
308
308
  }
309
- async getSession(identity, sessionId) {
309
+ async get(userId, sessionId) {
310
310
  try {
311
- const sessionKey = this.getSessionKey(identity, sessionId);
311
+ const sessionKey = this.getSessionKey(userId, sessionId);
312
312
  const sessionDataStr = await this.redis.get(sessionKey);
313
313
  if (!sessionDataStr) {
314
314
  return null;
315
315
  }
316
- const sessionData = JSON.parse(sessionDataStr);
317
- return sessionData;
316
+ const Session = JSON.parse(sessionDataStr);
317
+ return Session;
318
318
  } catch (error) {
319
- console.error("[RedisStorage] Failed to get session:", error);
319
+ console.error("[RedisStorageBackend] Failed to get session:", error);
320
320
  return null;
321
321
  }
322
322
  }
323
- async getIdentityMcpSessions(identity) {
324
- const sessions = await this.getIdentitySessionsData(identity);
325
- return sessions.map((session) => session.sessionId);
323
+ async listIds(userId) {
324
+ const sessions2 = await this.list(userId);
325
+ return sessions2.map((session) => session.sessionId);
326
326
  }
327
- async getIdentitySessionsData(identity) {
327
+ async list(userId) {
328
328
  try {
329
- const identityKey = this.getIdentityKey(identity);
330
- const sessionIds = await this.redis.smembers(identityKey);
329
+ const userIdKey = this.getUserIdKey(userId);
330
+ const sessionIds = await this.redis.smembers(userIdKey);
331
331
  if (sessionIds.length === 0) return [];
332
332
  const results = await Promise.all(
333
333
  sessionIds.map(async (sessionId) => {
334
- const data = await this.redis.get(this.getSessionKey(identity, sessionId));
334
+ const data = await this.redis.get(this.getSessionKey(userId, sessionId));
335
335
  return data ? JSON.parse(data) : null;
336
336
  })
337
337
  );
338
338
  const staleSessionIds = sessionIds.filter((_, index) => results[index] === null);
339
339
  if (staleSessionIds.length > 0) {
340
- await this.redis.srem(identityKey, ...staleSessionIds);
340
+ await this.redis.srem(userIdKey, ...staleSessionIds);
341
341
  }
342
342
  return results.filter((session) => session !== null);
343
343
  } catch (error) {
344
- console.error(`[RedisStorage] Failed to get session data for ${identity}:`, error);
344
+ console.error(`[RedisStorageBackend] Failed to get session data for ${userId}:`, error);
345
345
  return [];
346
346
  }
347
347
  }
348
- async removeSession(identity, sessionId) {
348
+ async delete(userId, sessionId) {
349
349
  try {
350
- const sessionKey = this.getSessionKey(identity, sessionId);
351
- const identityKey = this.getIdentityKey(identity);
352
- await this.redis.srem(identityKey, sessionId);
350
+ const sessionKey = this.getSessionKey(userId, sessionId);
351
+ const userIdKey = this.getUserIdKey(userId);
352
+ await this.redis.srem(userIdKey, sessionId);
353
353
  await this.redis.del(sessionKey);
354
354
  } catch (error) {
355
- console.error("[RedisStorage] Failed to remove session:", error);
355
+ console.error("[RedisStorageBackend] Failed to remove session:", error);
356
356
  }
357
357
  }
358
- async getAllSessionIds() {
358
+ async listAllIds() {
359
359
  try {
360
360
  const keys = await this.scanKeys(`${this.KEY_PREFIX}*`);
361
- const sessions = await Promise.all(
361
+ const sessions2 = await Promise.all(
362
362
  keys.map(async (key) => {
363
363
  const data = await this.redis.get(key);
364
364
  if (!data) {
@@ -367,60 +367,60 @@ var RedisStorageBackend = class {
367
367
  try {
368
368
  return JSON.parse(data).sessionId;
369
369
  } catch (error) {
370
- console.error("[RedisStorage] Failed to parse session while listing all session IDs:", error);
370
+ console.error("[RedisStorageBackend] Failed to parse session while listing all session IDs:", error);
371
371
  return null;
372
372
  }
373
373
  })
374
374
  );
375
- return sessions.filter((sessionId) => sessionId !== null);
375
+ return sessions2.filter((sessionId) => sessionId !== null);
376
376
  } catch (error) {
377
- console.error("[RedisStorage] Failed to get all sessions:", error);
377
+ console.error("[RedisStorageBackend] Failed to get all sessions:", error);
378
378
  return [];
379
379
  }
380
380
  }
381
381
  async clearAll() {
382
382
  try {
383
383
  const keys = await this.scanKeys(`${this.KEY_PREFIX}*`);
384
- const identityKeys = await this.scanKeys(`${this.IDENTITY_KEY_PREFIX}*${this.IDENTITY_KEY_SUFFIX}`);
385
- const allKeys = [...keys, ...identityKeys];
384
+ const userIdKeys = await this.scanKeys(`${this.USER_ID_KEY_PREFIX}*${this.USER_ID_KEY_SUFFIX}`);
385
+ const allKeys = [...keys, ...userIdKeys];
386
386
  if (allKeys.length > 0) {
387
387
  await this.redis.del(...allKeys);
388
388
  }
389
389
  } catch (error) {
390
- console.error("[RedisStorage] Failed to clear sessions:", error);
390
+ console.error("[RedisStorageBackend] Failed to clear sessions:", error);
391
391
  }
392
392
  }
393
- async cleanupExpiredSessions() {
393
+ async cleanupExpired() {
394
394
  try {
395
- const identityKeys = await this.scanKeys(`${this.IDENTITY_KEY_PREFIX}*${this.IDENTITY_KEY_SUFFIX}`);
396
- for (const identityKey of identityKeys) {
397
- const identity = this.parseIdentityFromKey(identityKey);
398
- const sessionIds = await this.redis.smembers(identityKey);
395
+ const userIdKeys = await this.scanKeys(`${this.USER_ID_KEY_PREFIX}*${this.USER_ID_KEY_SUFFIX}`);
396
+ for (const userIdKey of userIdKeys) {
397
+ const userId = this.parseUserIdFromKey(userIdKey);
398
+ const sessionIds = await this.redis.smembers(userIdKey);
399
399
  if (sessionIds.length === 0) {
400
- await this.redis.del(identityKey);
400
+ await this.redis.del(userIdKey);
401
401
  continue;
402
402
  }
403
403
  const existenceChecks = await Promise.all(
404
- sessionIds.map((sessionId) => this.redis.exists(this.getSessionKey(identity, sessionId)))
404
+ sessionIds.map((sessionId) => this.redis.exists(this.getSessionKey(userId, sessionId)))
405
405
  );
406
406
  const staleSessionIds = sessionIds.filter((_, index) => existenceChecks[index] === 0);
407
407
  if (staleSessionIds.length > 0) {
408
- await this.redis.srem(identityKey, ...staleSessionIds);
408
+ await this.redis.srem(userIdKey, ...staleSessionIds);
409
409
  }
410
- const remainingCount = await this.redis.scard(identityKey);
410
+ const remainingCount = await this.redis.scard(userIdKey);
411
411
  if (remainingCount === 0) {
412
- await this.redis.del(identityKey);
412
+ await this.redis.del(userIdKey);
413
413
  }
414
414
  }
415
415
  } catch (error) {
416
- console.error("[RedisStorage] Failed to cleanup expired sessions:", error);
416
+ console.error("[RedisStorageBackend] Failed to cleanup expired sessions:", error);
417
417
  }
418
418
  }
419
419
  async disconnect() {
420
420
  try {
421
421
  await this.redis.quit();
422
422
  } catch (error) {
423
- console.error("[RedisStorage] Failed to disconnect:", error);
423
+ console.error("[RedisStorageBackend] Failed to disconnect:", error);
424
424
  }
425
425
  }
426
426
  };
@@ -429,36 +429,36 @@ var RedisStorageBackend = class {
429
429
  init_cjs_shims();
430
430
  var MemoryStorageBackend = class {
431
431
  constructor() {
432
- // Map<identity:sessionId, SessionData>
432
+ // Map<userId:sessionId, Session>
433
433
  __publicField(this, "sessions", /* @__PURE__ */ new Map());
434
- // Map<identity, Set<sessionId>>
435
- __publicField(this, "identitySessions", /* @__PURE__ */ new Map());
434
+ // Map<userId, Set<sessionId>>
435
+ __publicField(this, "userIdSessions", /* @__PURE__ */ new Map());
436
436
  }
437
437
  async init() {
438
438
  console.log("[mcp-ts][Storage] Memory: \u2713 internal memory store active.");
439
439
  }
440
- getSessionKey(identity, sessionId) {
441
- return `${identity}:${sessionId}`;
440
+ getSessionKey(userId, sessionId) {
441
+ return `${userId}:${sessionId}`;
442
442
  }
443
443
  generateSessionId() {
444
444
  return generateSessionId();
445
445
  }
446
- async createSession(session, ttl) {
447
- const { sessionId, identity } = session;
448
- if (!sessionId || !identity) throw new Error("identity and sessionId required");
449
- const sessionKey = this.getSessionKey(identity, sessionId);
446
+ async create(session, ttl) {
447
+ const { sessionId, userId } = session;
448
+ if (!sessionId || !userId) throw new Error("userId and sessionId required");
449
+ const sessionKey = this.getSessionKey(userId, sessionId);
450
450
  if (this.sessions.has(sessionKey)) {
451
451
  throw new Error(`Session ${sessionId} already exists`);
452
452
  }
453
453
  this.sessions.set(sessionKey, session);
454
- if (!this.identitySessions.has(identity)) {
455
- this.identitySessions.set(identity, /* @__PURE__ */ new Set());
454
+ if (!this.userIdSessions.has(userId)) {
455
+ this.userIdSessions.set(userId, /* @__PURE__ */ new Set());
456
456
  }
457
- this.identitySessions.get(identity).add(sessionId);
457
+ this.userIdSessions.get(userId).add(sessionId);
458
458
  }
459
- async updateSession(identity, sessionId, data, ttl) {
460
- if (!identity || !sessionId) throw new Error("identity and sessionId required");
461
- const sessionKey = this.getSessionKey(identity, sessionId);
459
+ async update(userId, sessionId, data, ttl) {
460
+ if (!userId || !sessionId) throw new Error("userId and sessionId required");
461
+ const sessionKey = this.getSessionKey(userId, sessionId);
462
462
  const current = this.sessions.get(sessionKey);
463
463
  if (!current) {
464
464
  throw new Error(`Session ${sessionId} not found`);
@@ -469,45 +469,45 @@ var MemoryStorageBackend = class {
469
469
  };
470
470
  this.sessions.set(sessionKey, updated);
471
471
  }
472
- async getSession(identity, sessionId) {
473
- const sessionKey = this.getSessionKey(identity, sessionId);
472
+ async get(userId, sessionId) {
473
+ const sessionKey = this.getSessionKey(userId, sessionId);
474
474
  return this.sessions.get(sessionKey) || null;
475
475
  }
476
- async getIdentityMcpSessions(identity) {
477
- const set = this.identitySessions.get(identity);
476
+ async listIds(userId) {
477
+ const set = this.userIdSessions.get(userId);
478
478
  return set ? Array.from(set) : [];
479
479
  }
480
- async getIdentitySessionsData(identity) {
481
- const set = this.identitySessions.get(identity);
480
+ async list(userId) {
481
+ const set = this.userIdSessions.get(userId);
482
482
  if (!set) return [];
483
483
  const results = [];
484
484
  for (const sessionId of set) {
485
- const session = this.sessions.get(this.getSessionKey(identity, sessionId));
485
+ const session = this.sessions.get(this.getSessionKey(userId, sessionId));
486
486
  if (session) {
487
487
  results.push(session);
488
488
  }
489
489
  }
490
490
  return results;
491
491
  }
492
- async removeSession(identity, sessionId) {
493
- const sessionKey = this.getSessionKey(identity, sessionId);
492
+ async delete(userId, sessionId) {
493
+ const sessionKey = this.getSessionKey(userId, sessionId);
494
494
  this.sessions.delete(sessionKey);
495
- const set = this.identitySessions.get(identity);
495
+ const set = this.userIdSessions.get(userId);
496
496
  if (set) {
497
497
  set.delete(sessionId);
498
498
  if (set.size === 0) {
499
- this.identitySessions.delete(identity);
499
+ this.userIdSessions.delete(userId);
500
500
  }
501
501
  }
502
502
  }
503
- async getAllSessionIds() {
503
+ async listAllIds() {
504
504
  return Array.from(this.sessions.values()).map((s) => s.sessionId);
505
505
  }
506
506
  async clearAll() {
507
507
  this.sessions.clear();
508
- this.identitySessions.clear();
508
+ this.userIdSessions.clear();
509
509
  }
510
- async cleanupExpiredSessions() {
510
+ async cleanupExpired() {
511
511
  }
512
512
  async disconnect() {
513
513
  }
@@ -538,7 +538,7 @@ var FileStorageBackend = class {
538
538
  this.memoryCache = /* @__PURE__ */ new Map();
539
539
  if (Array.isArray(json)) {
540
540
  json.forEach((s) => {
541
- this.memoryCache.set(this.getSessionKey(s.identity || "unknown", s.sessionId), s);
541
+ this.memoryCache.set(this.getSessionKey(s.userId || "unknown", s.sessionId), s);
542
542
  });
543
543
  }
544
544
  } catch (error) {
@@ -558,30 +558,30 @@ var FileStorageBackend = class {
558
558
  }
559
559
  async flush() {
560
560
  if (!this.memoryCache) return;
561
- const sessions = Array.from(this.memoryCache.values());
562
- await fs2.promises.writeFile(this.filePath, JSON.stringify(sessions, null, 2), "utf-8");
561
+ const sessions2 = Array.from(this.memoryCache.values());
562
+ await fs2.promises.writeFile(this.filePath, JSON.stringify(sessions2, null, 2), "utf-8");
563
563
  }
564
- getSessionKey(identity, sessionId) {
565
- return `${identity}:${sessionId}`;
564
+ getSessionKey(userId, sessionId) {
565
+ return `${userId}:${sessionId}`;
566
566
  }
567
567
  generateSessionId() {
568
568
  return generateSessionId();
569
569
  }
570
- async createSession(session, ttl) {
570
+ async create(session, ttl) {
571
571
  await this.ensureInitialized();
572
- const { sessionId, identity } = session;
573
- if (!sessionId || !identity) throw new Error("identity and sessionId required");
574
- const sessionKey = this.getSessionKey(identity, sessionId);
572
+ const { sessionId, userId } = session;
573
+ if (!sessionId || !userId) throw new Error("userId and sessionId required");
574
+ const sessionKey = this.getSessionKey(userId, sessionId);
575
575
  if (this.memoryCache.has(sessionKey)) {
576
576
  throw new Error(`Session ${sessionId} already exists`);
577
577
  }
578
578
  this.memoryCache.set(sessionKey, session);
579
579
  await this.flush();
580
580
  }
581
- async updateSession(identity, sessionId, data, ttl) {
581
+ async update(userId, sessionId, data, ttl) {
582
582
  await this.ensureInitialized();
583
- if (!identity || !sessionId) throw new Error("identity and sessionId required");
584
- const sessionKey = this.getSessionKey(identity, sessionId);
583
+ if (!userId || !sessionId) throw new Error("userId and sessionId required");
584
+ const sessionKey = this.getSessionKey(userId, sessionId);
585
585
  const current = this.memoryCache.get(sessionKey);
586
586
  if (!current) {
587
587
  throw new Error(`Session ${sessionId} not found`);
@@ -593,27 +593,27 @@ var FileStorageBackend = class {
593
593
  this.memoryCache.set(sessionKey, updated);
594
594
  await this.flush();
595
595
  }
596
- async getSession(identity, sessionId) {
596
+ async get(userId, sessionId) {
597
597
  await this.ensureInitialized();
598
- const sessionKey = this.getSessionKey(identity, sessionId);
598
+ const sessionKey = this.getSessionKey(userId, sessionId);
599
599
  return this.memoryCache.get(sessionKey) || null;
600
600
  }
601
- async getIdentitySessionsData(identity) {
601
+ async list(userId) {
602
602
  await this.ensureInitialized();
603
- return Array.from(this.memoryCache.values()).filter((s) => s.identity === identity);
603
+ return Array.from(this.memoryCache.values()).filter((s) => s.userId === userId);
604
604
  }
605
- async getIdentityMcpSessions(identity) {
605
+ async listIds(userId) {
606
606
  await this.ensureInitialized();
607
- return Array.from(this.memoryCache.values()).filter((s) => s.identity === identity).map((s) => s.sessionId);
607
+ return Array.from(this.memoryCache.values()).filter((s) => s.userId === userId).map((s) => s.sessionId);
608
608
  }
609
- async removeSession(identity, sessionId) {
609
+ async delete(userId, sessionId) {
610
610
  await this.ensureInitialized();
611
- const sessionKey = this.getSessionKey(identity, sessionId);
611
+ const sessionKey = this.getSessionKey(userId, sessionId);
612
612
  if (this.memoryCache.delete(sessionKey)) {
613
613
  await this.flush();
614
614
  }
615
615
  }
616
- async getAllSessionIds() {
616
+ async listAllIds() {
617
617
  await this.ensureInitialized();
618
618
  return Array.from(this.memoryCache.values()).map((s) => s.sessionId);
619
619
  }
@@ -622,7 +622,7 @@ var FileStorageBackend = class {
622
622
  this.memoryCache.clear();
623
623
  await this.flush();
624
624
  }
625
- async cleanupExpiredSessions() {
625
+ async cleanupExpired() {
626
626
  await this.ensureInitialized();
627
627
  }
628
628
  async disconnect() {
@@ -652,11 +652,11 @@ var SqliteStorage = class {
652
652
  this.db.exec(`
653
653
  CREATE TABLE IF NOT EXISTS ${this.table} (
654
654
  sessionId TEXT PRIMARY KEY,
655
- identity TEXT NOT NULL,
655
+ userId TEXT NOT NULL,
656
656
  data TEXT NOT NULL,
657
657
  expiresAt INTEGER
658
658
  );
659
- CREATE INDEX IF NOT EXISTS idx_${this.table}_identity ON ${this.table}(identity);
659
+ CREATE INDEX IF NOT EXISTS idx_${this.table}_userId ON ${this.table}(userId);
660
660
  `);
661
661
  this.initialized = true;
662
662
  console.log(`[mcp-ts][Storage] SQLite: \u2713 database at ${this.dbPath} verified.`);
@@ -677,18 +677,18 @@ var SqliteStorage = class {
677
677
  generateSessionId() {
678
678
  return generateSessionId();
679
679
  }
680
- async createSession(session, ttl) {
680
+ async create(session, ttl) {
681
681
  this.ensureInitialized();
682
- const { sessionId, identity } = session;
683
- if (!sessionId || !identity) {
684
- throw new Error("identity and sessionId required");
682
+ const { sessionId, userId } = session;
683
+ if (!sessionId || !userId) {
684
+ throw new Error("userId and sessionId required");
685
685
  }
686
686
  const expiresAt = ttl ? Date.now() + ttl * 1e3 : null;
687
687
  try {
688
688
  const stmt = this.db.prepare(
689
- `INSERT INTO ${this.table} (sessionId, identity, data, expiresAt) VALUES (?, ?, ?, ?)`
689
+ `INSERT INTO ${this.table} (sessionId, userId, data, expiresAt) VALUES (?, ?, ?, ?)`
690
690
  );
691
- stmt.run(sessionId, identity, JSON.stringify(session), expiresAt);
691
+ stmt.run(sessionId, userId, JSON.stringify(session), expiresAt);
692
692
  } catch (error) {
693
693
  if (error.code === "SQLITE_CONSTRAINT_PRIMARYKEY") {
694
694
  throw new Error(`Session ${sessionId} already exists`);
@@ -696,55 +696,55 @@ var SqliteStorage = class {
696
696
  throw error;
697
697
  }
698
698
  }
699
- async updateSession(identity, sessionId, data, ttl) {
699
+ async update(userId, sessionId, data, ttl) {
700
700
  this.ensureInitialized();
701
- if (!sessionId || !identity) {
702
- throw new Error("identity and sessionId required");
701
+ if (!sessionId || !userId) {
702
+ throw new Error("userId and sessionId required");
703
703
  }
704
- const currentSession = await this.getSession(identity, sessionId);
704
+ const currentSession = await this.get(userId, sessionId);
705
705
  if (!currentSession) {
706
- throw new Error(`Session ${sessionId} not found for identity ${identity}`);
706
+ throw new Error(`Session ${sessionId} not found for userId ${userId}`);
707
707
  }
708
708
  const updatedSession = { ...currentSession, ...data };
709
709
  const expiresAt = ttl ? Date.now() + ttl * 1e3 : null;
710
710
  const stmt = this.db.prepare(
711
- `UPDATE ${this.table} SET data = ?, expiresAt = ? WHERE sessionId = ? AND identity = ?`
711
+ `UPDATE ${this.table} SET data = ?, expiresAt = ? WHERE sessionId = ? AND userId = ?`
712
712
  );
713
- stmt.run(JSON.stringify(updatedSession), expiresAt, sessionId, identity);
713
+ stmt.run(JSON.stringify(updatedSession), expiresAt, sessionId, userId);
714
714
  }
715
- async getSession(identity, sessionId) {
715
+ async get(userId, sessionId) {
716
716
  this.ensureInitialized();
717
717
  const stmt = this.db.prepare(
718
- `SELECT data FROM ${this.table} WHERE sessionId = ? AND identity = ?`
718
+ `SELECT data FROM ${this.table} WHERE sessionId = ? AND userId = ?`
719
719
  );
720
- const row = stmt.get(sessionId, identity);
720
+ const row = stmt.get(sessionId, userId);
721
721
  if (!row) return null;
722
722
  return JSON.parse(row.data);
723
723
  }
724
- async getIdentitySessionsData(identity) {
724
+ async list(userId) {
725
725
  this.ensureInitialized();
726
726
  const stmt = this.db.prepare(
727
- `SELECT data FROM ${this.table} WHERE identity = ?`
727
+ `SELECT data FROM ${this.table} WHERE userId = ?`
728
728
  );
729
- const rows = stmt.all(identity);
729
+ const rows = stmt.all(userId);
730
730
  return rows.map((row) => JSON.parse(row.data));
731
731
  }
732
- async getIdentityMcpSessions(identity) {
732
+ async listIds(userId) {
733
733
  this.ensureInitialized();
734
734
  const stmt = this.db.prepare(
735
- `SELECT sessionId FROM ${this.table} WHERE identity = ?`
735
+ `SELECT sessionId FROM ${this.table} WHERE userId = ?`
736
736
  );
737
- const rows = stmt.all(identity);
737
+ const rows = stmt.all(userId);
738
738
  return rows.map((row) => row.sessionId);
739
739
  }
740
- async removeSession(identity, sessionId) {
740
+ async delete(userId, sessionId) {
741
741
  this.ensureInitialized();
742
742
  const stmt = this.db.prepare(
743
- `DELETE FROM ${this.table} WHERE sessionId = ? AND identity = ?`
743
+ `DELETE FROM ${this.table} WHERE sessionId = ? AND userId = ?`
744
744
  );
745
- stmt.run(sessionId, identity);
745
+ stmt.run(sessionId, userId);
746
746
  }
747
- async getAllSessionIds() {
747
+ async listAllIds() {
748
748
  this.ensureInitialized();
749
749
  const stmt = this.db.prepare(`SELECT sessionId FROM ${this.table}`);
750
750
  const rows = stmt.all();
@@ -755,7 +755,7 @@ var SqliteStorage = class {
755
755
  const stmt = this.db.prepare(`DELETE FROM ${this.table}`);
756
756
  stmt.run();
757
757
  }
758
- async cleanupExpiredSessions() {
758
+ async cleanupExpired() {
759
759
  this.ensureInitialized();
760
760
  const now = Date.now();
761
761
  const stmt = this.db.prepare(
@@ -872,7 +872,7 @@ var SupabaseStorageBackend = class {
872
872
  transportType: row.transport_type,
873
873
  callbackUrl: row.callback_url,
874
874
  createdAt: new Date(row.created_at).getTime(),
875
- identity: row.identity,
875
+ userId: row.user_id,
876
876
  headers: decryptObject(row.headers),
877
877
  active: row.active,
878
878
  clientInformation: row.client_information,
@@ -881,22 +881,21 @@ var SupabaseStorageBackend = class {
881
881
  clientId: row.client_id
882
882
  };
883
883
  }
884
- async createSession(session, ttl) {
885
- const { sessionId, identity } = session;
886
- if (!sessionId || !identity) throw new Error("identity and sessionId required");
884
+ async create(session, ttl) {
885
+ const { sessionId, userId } = session;
886
+ if (!sessionId || !userId) throw new Error("userId and sessionId required");
887
887
  const effectiveTtl = ttl ?? this.DEFAULT_TTL;
888
888
  const expiresAt = new Date(Date.now() + effectiveTtl * 1e3).toISOString();
889
889
  const { error } = await this.supabase.from("mcp_sessions").insert({
890
890
  session_id: sessionId,
891
- user_id: identity,
892
- // Maps user_id to identity to support RLS using auth.uid()
891
+ user_id: userId,
892
+ // Maps user_id to userId to support RLS using auth.uid()
893
893
  server_id: session.serverId,
894
894
  server_name: session.serverName,
895
895
  server_url: session.serverUrl,
896
896
  transport_type: session.transportType,
897
897
  callback_url: session.callbackUrl,
898
898
  created_at: new Date(session.createdAt || Date.now()).toISOString(),
899
- identity,
900
899
  headers: encryptObject(session.headers),
901
900
  active: session.active ?? false,
902
901
  client_information: session.clientInformation,
@@ -912,7 +911,7 @@ var SupabaseStorageBackend = class {
912
911
  throw new Error(`Failed to create session in Supabase: ${error.message}`);
913
912
  }
914
913
  }
915
- async updateSession(identity, sessionId, data, ttl) {
914
+ async update(userId, sessionId, data, ttl) {
916
915
  const effectiveTtl = ttl ?? this.DEFAULT_TTL;
917
916
  const expiresAt = new Date(Date.now() + effectiveTtl * 1e3).toISOString();
918
917
  const updateData = {
@@ -930,16 +929,16 @@ var SupabaseStorageBackend = class {
930
929
  if ("tokens" in data) updateData.tokens = encryptObject(data.tokens);
931
930
  if ("codeVerifier" in data) updateData.code_verifier = data.codeVerifier;
932
931
  if ("clientId" in data) updateData.client_id = data.clientId;
933
- const { data: updatedRows, error } = await this.supabase.from("mcp_sessions").update(updateData).eq("identity", identity).eq("session_id", sessionId).select("id");
932
+ const { data: updatedRows, error } = await this.supabase.from("mcp_sessions").update(updateData).eq("user_id", userId).eq("session_id", sessionId).select("id");
934
933
  if (error) {
935
934
  throw new Error(`Failed to update session: ${error.message}`);
936
935
  }
937
936
  if (!updatedRows || updatedRows.length === 0) {
938
- throw new Error(`Session ${sessionId} not found for identity ${identity}`);
937
+ throw new Error(`Session ${sessionId} not found for userId ${userId}`);
939
938
  }
940
939
  }
941
- async getSession(identity, sessionId) {
942
- const { data, error } = await this.supabase.from("mcp_sessions").select("*").eq("identity", identity).eq("session_id", sessionId).maybeSingle();
940
+ async get(userId, sessionId) {
941
+ const { data, error } = await this.supabase.from("mcp_sessions").select("*").eq("user_id", userId).eq("session_id", sessionId).maybeSingle();
943
942
  if (error) {
944
943
  console.error("[SupabaseStorage] Failed to get session:", error);
945
944
  return null;
@@ -947,29 +946,29 @@ var SupabaseStorageBackend = class {
947
946
  if (!data) return null;
948
947
  return this.mapRowToSessionData(data);
949
948
  }
950
- async getIdentitySessionsData(identity) {
951
- const { data, error } = await this.supabase.from("mcp_sessions").select("*").eq("identity", identity);
949
+ async list(userId) {
950
+ const { data, error } = await this.supabase.from("mcp_sessions").select("*").eq("user_id", userId);
952
951
  if (error) {
953
- console.error(`[SupabaseStorage] Failed to get session data for ${identity}:`, error);
952
+ console.error(`[SupabaseStorage] Failed to get session data for ${userId}:`, error);
954
953
  return [];
955
954
  }
956
955
  return data.map((row) => this.mapRowToSessionData(row));
957
956
  }
958
- async removeSession(identity, sessionId) {
959
- const { error } = await this.supabase.from("mcp_sessions").delete().eq("identity", identity).eq("session_id", sessionId);
957
+ async delete(userId, sessionId) {
958
+ const { error } = await this.supabase.from("mcp_sessions").delete().eq("user_id", userId).eq("session_id", sessionId);
960
959
  if (error) {
961
960
  console.error("[SupabaseStorage] Failed to remove session:", error);
962
961
  }
963
962
  }
964
- async getIdentityMcpSessions(identity) {
965
- const { data, error } = await this.supabase.from("mcp_sessions").select("session_id").eq("identity", identity);
963
+ async listIds(userId) {
964
+ const { data, error } = await this.supabase.from("mcp_sessions").select("session_id").eq("user_id", userId);
966
965
  if (error) {
967
- console.error(`[SupabaseStorage] Failed to get sessions for ${identity}:`, error);
966
+ console.error(`[SupabaseStorage] Failed to get sessions for ${userId}:`, error);
968
967
  return [];
969
968
  }
970
969
  return data.map((row) => row.session_id);
971
970
  }
972
- async getAllSessionIds() {
971
+ async listAllIds() {
973
972
  const { data, error } = await this.supabase.from("mcp_sessions").select("session_id");
974
973
  if (error) {
975
974
  console.error("[SupabaseStorage] Failed to get all sessions:", error);
@@ -983,7 +982,7 @@ var SupabaseStorageBackend = class {
983
982
  console.error("[SupabaseStorage] Failed to clear sessions:", error);
984
983
  }
985
984
  }
986
- async cleanupExpiredSessions() {
985
+ async cleanupExpired() {
987
986
  const { error } = await this.supabase.from("mcp_sessions").delete().lt("expires_at", (/* @__PURE__ */ new Date()).toISOString());
988
987
  if (error) {
989
988
  console.error("[SupabaseStorage] Failed to cleanup expired sessions:", error);
@@ -993,10 +992,254 @@ var SupabaseStorageBackend = class {
993
992
  }
994
993
  };
995
994
 
995
+ // src/server/storage/neon-backend.ts
996
+ init_cjs_shims();
997
+ var NeonStorageBackend = class {
998
+ constructor(sql, options = {}) {
999
+ this.sql = sql;
1000
+ __publicField(this, "DEFAULT_TTL", SESSION_TTL_SECONDS);
1001
+ __publicField(this, "tableName");
1002
+ const schema = options.schema || "public";
1003
+ const table = options.table || "mcp_sessions";
1004
+ this.tableName = `${this.quoteIdentifier(schema)}.${this.quoteIdentifier(table)}`;
1005
+ }
1006
+ async init() {
1007
+ const [{ exists } = { exists: null }] = await this.sql.query(
1008
+ "SELECT to_regclass($1) AS exists",
1009
+ [this.tableName.replace(/"/g, "")]
1010
+ );
1011
+ if (!exists) {
1012
+ throw new Error(
1013
+ '[NeonStorage] Table "mcp_sessions" not found in your database. Please create it using the Neon storage guide in docs/storage-backends/neon.md.'
1014
+ );
1015
+ }
1016
+ console.log('[mcp-ts][Storage] Neon: "mcp_sessions" table verified.');
1017
+ }
1018
+ generateSessionId() {
1019
+ return generateSessionId();
1020
+ }
1021
+ quoteIdentifier(identifier) {
1022
+ if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(identifier)) {
1023
+ throw new Error(`Invalid Neon storage identifier: ${identifier}`);
1024
+ }
1025
+ return `"${identifier}"`;
1026
+ }
1027
+ mapRowToSessionData(row) {
1028
+ return {
1029
+ sessionId: row.session_id,
1030
+ serverId: row.server_id ?? void 0,
1031
+ serverName: row.server_name ?? void 0,
1032
+ serverUrl: row.server_url,
1033
+ transportType: row.transport_type,
1034
+ callbackUrl: row.callback_url,
1035
+ createdAt: new Date(row.created_at).getTime(),
1036
+ userId: row.user_id,
1037
+ headers: decryptObject(row.headers),
1038
+ active: row.active ?? false,
1039
+ clientInformation: row.client_information,
1040
+ tokens: decryptObject(row.tokens),
1041
+ codeVerifier: row.code_verifier ?? void 0,
1042
+ clientId: row.client_id ?? void 0
1043
+ };
1044
+ }
1045
+ async create(session, ttl) {
1046
+ const { sessionId, userId } = session;
1047
+ if (!sessionId || !userId) throw new Error("userId and sessionId required");
1048
+ const effectiveTtl = ttl ?? this.DEFAULT_TTL;
1049
+ const expiresAt = new Date(Date.now() + effectiveTtl * 1e3).toISOString();
1050
+ try {
1051
+ await this.sql.query(
1052
+ `INSERT INTO ${this.tableName} (
1053
+ session_id,
1054
+ user_id,
1055
+ server_id,
1056
+ server_name,
1057
+ server_url,
1058
+ transport_type,
1059
+ callback_url,
1060
+ created_at,
1061
+ headers,
1062
+ active,
1063
+ client_information,
1064
+ tokens,
1065
+ code_verifier,
1066
+ client_id,
1067
+ expires_at
1068
+ ) VALUES (
1069
+ $1, $2, $3, $4, $5, $6, $7, $8,
1070
+ $9, $10, $11, $12, $13, $14, $15
1071
+ )`,
1072
+ [
1073
+ sessionId,
1074
+ userId,
1075
+ session.serverId,
1076
+ session.serverName,
1077
+ session.serverUrl,
1078
+ session.transportType,
1079
+ session.callbackUrl,
1080
+ new Date(session.createdAt || Date.now()).toISOString(),
1081
+ encryptObject(session.headers),
1082
+ session.active ?? false,
1083
+ session.clientInformation,
1084
+ encryptObject(session.tokens),
1085
+ session.codeVerifier,
1086
+ session.clientId,
1087
+ expiresAt
1088
+ ]
1089
+ );
1090
+ } catch (error) {
1091
+ if (error.code === "23505") {
1092
+ throw new Error(`Session ${sessionId} already exists`);
1093
+ }
1094
+ throw new Error(`Failed to create session in Neon: ${error.message}`);
1095
+ }
1096
+ }
1097
+ async update(userId, sessionId, data, ttl) {
1098
+ const currentSession = await this.get(userId, sessionId);
1099
+ if (!currentSession) {
1100
+ throw new Error(`Session ${sessionId} not found for userId ${userId}`);
1101
+ }
1102
+ const updatedSession = { ...currentSession, ...data };
1103
+ const effectiveTtl = ttl ?? this.DEFAULT_TTL;
1104
+ const expiresAt = new Date(Date.now() + effectiveTtl * 1e3).toISOString();
1105
+ const updatedRows = await this.sql.query(
1106
+ `UPDATE ${this.tableName}
1107
+ SET
1108
+ server_id = $1,
1109
+ server_name = $2,
1110
+ server_url = $3,
1111
+ transport_type = $4,
1112
+ callback_url = $5,
1113
+ active = $6,
1114
+ headers = $7,
1115
+ client_information = $8,
1116
+ tokens = $9,
1117
+ code_verifier = $10,
1118
+ client_id = $11,
1119
+ expires_at = $12,
1120
+ updated_at = now()
1121
+ WHERE user_id = $13 AND session_id = $14
1122
+ RETURNING id`,
1123
+ [
1124
+ updatedSession.serverId,
1125
+ updatedSession.serverName,
1126
+ updatedSession.serverUrl,
1127
+ updatedSession.transportType,
1128
+ updatedSession.callbackUrl,
1129
+ updatedSession.active ?? false,
1130
+ encryptObject(updatedSession.headers),
1131
+ updatedSession.clientInformation,
1132
+ encryptObject(updatedSession.tokens),
1133
+ updatedSession.codeVerifier,
1134
+ updatedSession.clientId,
1135
+ expiresAt,
1136
+ userId,
1137
+ sessionId
1138
+ ]
1139
+ );
1140
+ if (updatedRows.length === 0) {
1141
+ throw new Error(`Session ${sessionId} not found for userId ${userId}`);
1142
+ }
1143
+ }
1144
+ async get(userId, sessionId) {
1145
+ try {
1146
+ const rows = await this.sql.query(
1147
+ `SELECT * FROM ${this.tableName} WHERE user_id = $1 AND session_id = $2`,
1148
+ [userId, sessionId]
1149
+ );
1150
+ return rows[0] ? this.mapRowToSessionData(rows[0]) : null;
1151
+ } catch (error) {
1152
+ console.error("[NeonStorage] Failed to get session:", error);
1153
+ return null;
1154
+ }
1155
+ }
1156
+ async list(userId) {
1157
+ try {
1158
+ const rows = await this.sql.query(
1159
+ `SELECT * FROM ${this.tableName} WHERE user_id = $1`,
1160
+ [userId]
1161
+ );
1162
+ return rows.map((row) => this.mapRowToSessionData(row));
1163
+ } catch (error) {
1164
+ console.error(`[NeonStorage] Failed to get session data for ${userId}:`, error);
1165
+ return [];
1166
+ }
1167
+ }
1168
+ async delete(userId, sessionId) {
1169
+ try {
1170
+ await this.sql.query(
1171
+ `DELETE FROM ${this.tableName} WHERE user_id = $1 AND session_id = $2`,
1172
+ [userId, sessionId]
1173
+ );
1174
+ } catch (error) {
1175
+ console.error("[NeonStorage] Failed to remove session:", error);
1176
+ }
1177
+ }
1178
+ async listIds(userId) {
1179
+ try {
1180
+ const rows = await this.sql.query(
1181
+ `SELECT session_id FROM ${this.tableName} WHERE user_id = $1`,
1182
+ [userId]
1183
+ );
1184
+ return rows.map((row) => row.session_id);
1185
+ } catch (error) {
1186
+ console.error(`[NeonStorage] Failed to get sessions for ${userId}:`, error);
1187
+ return [];
1188
+ }
1189
+ }
1190
+ async listAllIds() {
1191
+ try {
1192
+ const rows = await this.sql.query(
1193
+ `SELECT session_id FROM ${this.tableName}`
1194
+ );
1195
+ return rows.map((row) => row.session_id);
1196
+ } catch (error) {
1197
+ console.error("[NeonStorage] Failed to get all sessions:", error);
1198
+ return [];
1199
+ }
1200
+ }
1201
+ async clearAll() {
1202
+ try {
1203
+ await this.sql.query(`DELETE FROM ${this.tableName}`);
1204
+ } catch (error) {
1205
+ console.error("[NeonStorage] Failed to clear sessions:", error);
1206
+ }
1207
+ }
1208
+ async cleanupExpired() {
1209
+ try {
1210
+ await this.sql.query(
1211
+ `DELETE FROM ${this.tableName} WHERE expires_at < $1`,
1212
+ [(/* @__PURE__ */ new Date()).toISOString()]
1213
+ );
1214
+ } catch (error) {
1215
+ console.error("[NeonStorage] Failed to cleanup expired sessions:", error);
1216
+ }
1217
+ }
1218
+ async disconnect() {
1219
+ }
1220
+ };
1221
+
996
1222
  // src/server/storage/types.ts
997
1223
  init_cjs_shims();
998
1224
 
999
1225
  // src/server/storage/index.ts
1226
+ function warnIfNeonConnectionStringIsInsecure(connectionString) {
1227
+ try {
1228
+ const url = new URL(connectionString);
1229
+ const sslMode = url.searchParams.get("sslmode");
1230
+ const channelBinding = url.searchParams.get("channel_binding");
1231
+ if (!sslMode) {
1232
+ console.warn("[mcp-ts][Storage] Neon connection string does not include sslmode. Neon recommends sslmode=verify-full for the strongest certificate verification.");
1233
+ } else if (!["verify-full", "require"].includes(sslMode)) {
1234
+ console.warn(`[mcp-ts][Storage] Neon connection string uses sslmode=${sslMode}. Use sslmode=verify-full or sslmode=require for secure connections.`);
1235
+ }
1236
+ if (!channelBinding) {
1237
+ console.warn("[mcp-ts][Storage] Neon connection string does not include channel_binding=require. Add it when supported by your runtime and connection path.");
1238
+ }
1239
+ } catch {
1240
+ console.warn("[mcp-ts][Storage] Neon connection string could not be parsed for SSL checks.");
1241
+ }
1242
+ }
1000
1243
  var storageInstance = null;
1001
1244
  var storagePromise = null;
1002
1245
  async function initializeStorage(store) {
@@ -1053,6 +1296,24 @@ async function createStorage() {
1053
1296
  }
1054
1297
  }
1055
1298
  }
1299
+ if (type === "neon") {
1300
+ const connectionString = process.env.NEON_DATABASE_URL || process.env.DATABASE_URL;
1301
+ if (!connectionString) {
1302
+ console.warn('[mcp-ts][Storage] Explicit selection "neon" requires NEON_DATABASE_URL or DATABASE_URL.');
1303
+ } else {
1304
+ try {
1305
+ const { neon } = await import('@neondatabase/serverless');
1306
+ warnIfNeonConnectionStringIsInsecure(connectionString);
1307
+ const sql = neon(connectionString);
1308
+ console.log('[mcp-ts][Storage] Explicit selection: "neon"');
1309
+ return await initializeStorage(new NeonStorageBackend(sql));
1310
+ } catch (error) {
1311
+ console.error("[mcp-ts][Storage] Failed to initialize Neon:", error.message);
1312
+ console.log("[mcp-ts][Storage] Falling back to In-Memory storage");
1313
+ return await initializeStorage(new MemoryStorageBackend());
1314
+ }
1315
+ }
1316
+ }
1056
1317
  if (type === "memory") {
1057
1318
  console.log('[mcp-ts][Storage] Explicit selection: "memory"');
1058
1319
  return await initializeStorage(new MemoryStorageBackend());
@@ -1091,6 +1352,17 @@ async function createStorage() {
1091
1352
  console.error("[mcp-ts][Storage] Supabase auto-detection failed:", error.message);
1092
1353
  }
1093
1354
  }
1355
+ if (process.env.NEON_DATABASE_URL) {
1356
+ try {
1357
+ const { neon } = await import('@neondatabase/serverless');
1358
+ warnIfNeonConnectionStringIsInsecure(process.env.NEON_DATABASE_URL);
1359
+ const sql = neon(process.env.NEON_DATABASE_URL);
1360
+ console.log('[mcp-ts][Storage] Auto-detection: "neon" (via NEON_DATABASE_URL)');
1361
+ return await initializeStorage(new NeonStorageBackend(sql));
1362
+ } catch (error) {
1363
+ console.error("[mcp-ts][Storage] Neon auto-detection failed:", error.message);
1364
+ }
1365
+ }
1094
1366
  console.log('[mcp-ts][Storage] Defaulting to: "memory"');
1095
1367
  return await initializeStorage(new MemoryStorageBackend());
1096
1368
  }
@@ -1107,7 +1379,7 @@ async function getStorage() {
1107
1379
  storageInstance = await storagePromise;
1108
1380
  return storageInstance;
1109
1381
  }
1110
- var storage = new Proxy({}, {
1382
+ var sessions = new Proxy({}, {
1111
1383
  get(_target, prop) {
1112
1384
  return async (...args) => {
1113
1385
  const instance = await getStorage();
@@ -1123,11 +1395,11 @@ var storage = new Proxy({}, {
1123
1395
  // src/server/mcp/storage-oauth-provider.ts
1124
1396
  var StorageOAuthClientProvider = class {
1125
1397
  /**
1126
- * Creates a new storage-backed OAuth provider
1398
+ * Creates a new session-backed OAuth provider
1127
1399
  * @param options - Provider configuration
1128
1400
  */
1129
1401
  constructor(options) {
1130
- __publicField(this, "identity");
1402
+ __publicField(this, "userId");
1131
1403
  __publicField(this, "serverId");
1132
1404
  __publicField(this, "sessionId");
1133
1405
  __publicField(this, "redirectUrl");
@@ -1140,7 +1412,7 @@ var StorageOAuthClientProvider = class {
1140
1412
  __publicField(this, "_clientId");
1141
1413
  __publicField(this, "onRedirectCallback");
1142
1414
  __publicField(this, "tokenExpiresAt");
1143
- this.identity = options.identity;
1415
+ this.userId = options.userId;
1144
1416
  this.serverId = options.serverId;
1145
1417
  this.sessionId = options.sessionId;
1146
1418
  this.redirectUrl = options.redirectUrl;
@@ -1173,24 +1445,24 @@ var StorageOAuthClientProvider = class {
1173
1445
  this._clientId = clientId_;
1174
1446
  }
1175
1447
  /**
1176
- * Loads OAuth data from storage session
1448
+ * Loads OAuth data from the session store
1177
1449
  * @private
1178
1450
  */
1179
1451
  async getSessionData() {
1180
- const data = await storage.getSession(this.identity, this.sessionId);
1452
+ const data = await sessions.get(this.userId, this.sessionId);
1181
1453
  if (!data) {
1182
1454
  return {};
1183
1455
  }
1184
1456
  return data;
1185
1457
  }
1186
1458
  /**
1187
- * Saves OAuth data to storage
1459
+ * Saves OAuth data to the session store
1188
1460
  * @param data - Partial OAuth data to save
1189
1461
  * @private
1190
1462
  * @throws Error if session doesn't exist (session must be created by controller layer)
1191
1463
  */
1192
1464
  async saveSessionData(data) {
1193
- await storage.updateSession(this.identity, this.sessionId, data);
1465
+ await sessions.update(this.userId, this.sessionId, data);
1194
1466
  }
1195
1467
  /**
1196
1468
  * Retrieves stored OAuth client information
@@ -1238,7 +1510,7 @@ var StorageOAuthClientProvider = class {
1238
1510
  return this.sessionId;
1239
1511
  }
1240
1512
  async checkState(_state) {
1241
- const data = await storage.getSession(this.identity, this.sessionId);
1513
+ const data = await sessions.get(this.userId, this.sessionId);
1242
1514
  if (!data) {
1243
1515
  return { valid: false, error: "Session not found" };
1244
1516
  }
@@ -1254,7 +1526,7 @@ var StorageOAuthClientProvider = class {
1254
1526
  }
1255
1527
  async invalidateCredentials(scope) {
1256
1528
  if (scope === "all") {
1257
- await storage.removeSession(this.identity, this.sessionId);
1529
+ await sessions.delete(this.userId, this.sessionId);
1258
1530
  } else {
1259
1531
  const updates = {};
1260
1532
  if (scope === "client") {
@@ -1439,7 +1711,7 @@ var ToolExecutionError = class extends McpError {
1439
1711
  };
1440
1712
  var RpcErrorCodes = {
1441
1713
  EXECUTION_ERROR: "EXECUTION_ERROR",
1442
- MISSING_IDENTITY: "MISSING_IDENTITY",
1714
+ MISSING_USER_ID: "MISSING_USER_ID",
1443
1715
  UNAUTHORIZED: "UNAUTHORIZED",
1444
1716
  NO_CONNECTION: "NO_CONNECTION",
1445
1717
  UNKNOWN_METHOD: "UNKNOWN_METHOD",
@@ -1450,14 +1722,14 @@ var RpcErrorCodes = {
1450
1722
  var MCPClient = class _MCPClient {
1451
1723
  /**
1452
1724
  * Creates a new MCP client instance
1453
- * Can be initialized with minimal options (identity + sessionId) for session restoration
1725
+ * Can be initialized with minimal options (userId + sessionId) for session restoration
1454
1726
  * @param options - Client configuration options
1455
1727
  */
1456
1728
  constructor(options) {
1457
1729
  __publicField(this, "client", null);
1458
1730
  __publicField(this, "oauthProvider", null);
1459
1731
  __publicField(this, "transport", null);
1460
- __publicField(this, "identity");
1732
+ __publicField(this, "userId");
1461
1733
  __publicField(this, "serverId");
1462
1734
  __publicField(this, "sessionId");
1463
1735
  __publicField(this, "serverName");
@@ -1484,7 +1756,7 @@ var MCPClient = class _MCPClient {
1484
1756
  this.serverName = options.serverName;
1485
1757
  this.callbackUrl = options.callbackUrl;
1486
1758
  this.onRedirect = options.onRedirect;
1487
- this.identity = options.identity;
1759
+ this.userId = options.userId;
1488
1760
  this.serverId = options.serverId;
1489
1761
  this.sessionId = options.sessionId;
1490
1762
  this.transportType = options.transportType;
@@ -1623,7 +1895,7 @@ var MCPClient = class _MCPClient {
1623
1895
  this.emitStateChange("INITIALIZING");
1624
1896
  this.emitProgress("Loading session configuration...");
1625
1897
  if (!this.serverUrl || !this.callbackUrl || !this.serverId) {
1626
- const sessionData = await storage.getSession(this.identity, this.sessionId);
1898
+ const sessionData = await sessions.get(this.userId, this.sessionId);
1627
1899
  if (!sessionData) {
1628
1900
  throw new Error(`Session not found: ${this.sessionId}`);
1629
1901
  }
@@ -1642,7 +1914,7 @@ var MCPClient = class _MCPClient {
1642
1914
  throw new Error("serverId required for OAuth provider initialization");
1643
1915
  }
1644
1916
  this.oauthProvider = new StorageOAuthClientProvider({
1645
- identity: this.identity,
1917
+ userId: this.userId,
1646
1918
  serverId: this.serverId,
1647
1919
  sessionId: this.sessionId,
1648
1920
  redirectUrl: this.callbackUrl,
@@ -1676,18 +1948,18 @@ var MCPClient = class _MCPClient {
1676
1948
  }
1677
1949
  );
1678
1950
  }
1679
- const existingSession = await storage.getSession(this.identity, this.sessionId);
1951
+ const existingSession = await sessions.get(this.userId, this.sessionId);
1680
1952
  if (!existingSession && this.serverId && this.serverUrl && this.callbackUrl) {
1681
1953
  this.createdAt = Date.now();
1682
1954
  console.log(`[MCPClient] Creating initial session ${this.sessionId} for OAuth flow`);
1683
- await storage.createSession({
1955
+ await sessions.create({
1684
1956
  sessionId: this.sessionId,
1685
- identity: this.identity,
1957
+ userId: this.userId,
1686
1958
  serverId: this.serverId,
1687
1959
  serverName: this.serverName,
1688
1960
  serverUrl: this.serverUrl,
1689
1961
  callbackUrl: this.callbackUrl,
1690
- transportType: this.transportType || "streamable_http",
1962
+ transportType: this.transportType || "streamable-http",
1691
1963
  headers: this.headers,
1692
1964
  createdAt: this.createdAt,
1693
1965
  active: false
@@ -1695,7 +1967,7 @@ var MCPClient = class _MCPClient {
1695
1967
  }
1696
1968
  }
1697
1969
  /**
1698
- * Saves current session state to storage
1970
+ * Saves current session state to the session store
1699
1971
  * Creates new session if it doesn't exist, updates if it does
1700
1972
  * @param ttl - Time-to-live in seconds (defaults to 12hr for connected sessions)
1701
1973
  * @param active - Session status marker used to avoid unnecessary TTL rewrites
@@ -1707,21 +1979,21 @@ var MCPClient = class _MCPClient {
1707
1979
  }
1708
1980
  const sessionData = {
1709
1981
  sessionId: this.sessionId,
1710
- identity: this.identity,
1982
+ userId: this.userId,
1711
1983
  serverId: this.serverId,
1712
1984
  serverName: this.serverName,
1713
1985
  serverUrl: this.serverUrl,
1714
1986
  callbackUrl: this.callbackUrl,
1715
- transportType: this.transportType || "streamable_http",
1987
+ transportType: this.transportType || "streamable-http",
1716
1988
  headers: this.headers,
1717
1989
  createdAt: this.createdAt || Date.now(),
1718
1990
  active
1719
1991
  };
1720
- const existingSession = await storage.getSession(this.identity, this.sessionId);
1992
+ const existingSession = await sessions.get(this.userId, this.sessionId);
1721
1993
  if (existingSession) {
1722
- await storage.updateSession(this.identity, this.sessionId, sessionData, ttl);
1994
+ await sessions.update(this.userId, this.sessionId, sessionData, ttl);
1723
1995
  } else {
1724
- await storage.createSession(sessionData, ttl);
1996
+ await sessions.create(sessionData, ttl);
1725
1997
  }
1726
1998
  }
1727
1999
  /**
@@ -1730,7 +2002,7 @@ var MCPClient = class _MCPClient {
1730
2002
  * @private
1731
2003
  */
1732
2004
  async tryConnect() {
1733
- const transportsToTry = this.transportType ? [this.transportType] : ["streamable_http", "sse"];
2005
+ const transportsToTry = this.transportType ? [this.transportType] : ["streamable-http", "sse"];
1734
2006
  let lastError;
1735
2007
  for (const currentType of transportsToTry) {
1736
2008
  const isLastAttempt = currentType === transportsToTry[transportsToTry.length - 1];
@@ -1802,7 +2074,7 @@ var MCPClient = class _MCPClient {
1802
2074
  this.emitError(message, "auth");
1803
2075
  this.emitStateChange("FAILED");
1804
2076
  try {
1805
- await storage.removeSession(this.identity, this.sessionId);
2077
+ await sessions.delete(this.userId, this.sessionId);
1806
2078
  } catch {
1807
2079
  }
1808
2080
  throw new Error(message);
@@ -1828,9 +2100,9 @@ var MCPClient = class _MCPClient {
1828
2100
  this.emitError(errorMessage, "connection");
1829
2101
  this.emitStateChange("FAILED");
1830
2102
  try {
1831
- const existingSession = await storage.getSession(this.identity, this.sessionId);
2103
+ const existingSession = await sessions.get(this.userId, this.sessionId);
1832
2104
  if (!existingSession || existingSession.active !== true) {
1833
- await storage.removeSession(this.identity, this.sessionId);
2105
+ await sessions.delete(this.userId, this.sessionId);
1834
2106
  }
1835
2107
  } catch {
1836
2108
  }
@@ -1854,7 +2126,7 @@ var MCPClient = class _MCPClient {
1854
2126
  this.emitStateChange("FAILED");
1855
2127
  throw new Error(error);
1856
2128
  }
1857
- const transportsToTry = this.transportType ? [this.transportType] : ["streamable_http", "sse"];
2129
+ const transportsToTry = this.transportType ? [this.transportType] : ["streamable-http", "sse"];
1858
2130
  let lastError;
1859
2131
  let tokensExchanged = false;
1860
2132
  let authenticatedStateEmitted = false;
@@ -2178,7 +2450,7 @@ var MCPClient = class _MCPClient {
2178
2450
  },
2179
2451
  { capabilities: {} }
2180
2452
  );
2181
- const tt = this.transportType || "streamable_http";
2453
+ const tt = this.transportType || "streamable-http";
2182
2454
  this.transport = this.getTransport(tt);
2183
2455
  await this.client.connect(this.transport);
2184
2456
  }
@@ -2195,7 +2467,7 @@ var MCPClient = class _MCPClient {
2195
2467
  if (this.oauthProvider) {
2196
2468
  await this.oauthProvider.invalidateCredentials("all");
2197
2469
  }
2198
- await storage.removeSession(this.identity, this.sessionId);
2470
+ await sessions.delete(this.userId, this.sessionId);
2199
2471
  this.disconnect();
2200
2472
  }
2201
2473
  /**
@@ -2263,10 +2535,10 @@ var MCPClient = class _MCPClient {
2263
2535
  }
2264
2536
  /**
2265
2537
  * Gets the transport type being used
2266
- * @returns Transport type (defaults to 'streamable_http')
2538
+ * @returns Transport type (defaults to 'streamable-http')
2267
2539
  */
2268
2540
  getTransportType() {
2269
- return this.transportType || "streamable_http";
2541
+ return this.transportType || "streamable-http";
2270
2542
  }
2271
2543
  /**
2272
2544
  * Gets the human-readable server name
@@ -2293,25 +2565,25 @@ var MCPClient = class _MCPClient {
2293
2565
  * Gets MCP server configuration for all active user sessions
2294
2566
  * Loads sessions from Redis, validates OAuth tokens, refreshes if expired
2295
2567
  * Returns ready-to-use configuration with valid auth headers
2296
- * @param identity - User ID to fetch sessions for
2568
+ * @param userId - User ID to fetch sessions for
2297
2569
  * @returns Object keyed by sanitized server labels containing transport, url, headers, etc.
2298
2570
  * @static
2299
2571
  */
2300
- static async getMcpServerConfig(identity) {
2572
+ static async getMcpServerConfig(userId) {
2301
2573
  const mcpConfig = {};
2302
- const sessions = await storage.getIdentitySessionsData(identity);
2574
+ const sessionList = await sessions.list(userId);
2303
2575
  await Promise.all(
2304
- sessions.map(async (sessionData) => {
2576
+ sessionList.map(async (sessionData) => {
2305
2577
  const { sessionId } = sessionData;
2306
2578
  try {
2307
2579
  if (!sessionData.serverId || !sessionData.transportType || !sessionData.serverUrl || !sessionData.callbackUrl) {
2308
- await storage.removeSession(identity, sessionId);
2580
+ await sessions.delete(userId, sessionId);
2309
2581
  return;
2310
2582
  }
2311
2583
  let headers;
2312
2584
  try {
2313
2585
  const client = new _MCPClient({
2314
- identity,
2586
+ userId,
2315
2587
  sessionId,
2316
2588
  serverId: sessionData.serverId,
2317
2589
  serverUrl: sessionData.serverUrl,
@@ -2344,7 +2616,7 @@ var MCPClient = class _MCPClient {
2344
2616
  ...headers && { headers }
2345
2617
  };
2346
2618
  } catch (error) {
2347
- await storage.removeSession(identity, sessionId);
2619
+ await sessions.delete(userId, sessionId);
2348
2620
  console.warn(`[MCP] Failed to process session ${sessionId}:`, error);
2349
2621
  }
2350
2622
  })
@@ -2361,18 +2633,18 @@ var DEFAULT_RETRY_DELAY_MS = 1e3;
2361
2633
  var CONNECTION_BATCH_SIZE = 5;
2362
2634
  var MultiSessionClient = class {
2363
2635
  /**
2364
- * Creates a new MultiSessionClient for the given user identity.
2636
+ * Creates a new MultiSessionClient for the given user userId.
2365
2637
  *
2366
- * @param identity - A unique string identifying the user (e.g. user ID or email).
2638
+ * @param userId - A unique string identifying the user (e.g. user ID or email).
2367
2639
  * @param options - Optional tuning for connection timeout, retry count, and retry delay.
2368
2640
  * Falls back to sensible defaults if not provided.
2369
2641
  */
2370
- constructor(identity, options = {}) {
2642
+ constructor(userId, options = {}) {
2371
2643
  __publicField(this, "clients", []);
2372
- __publicField(this, "identity");
2644
+ __publicField(this, "userId");
2373
2645
  __publicField(this, "options");
2374
2646
  __publicField(this, "connectionPromises", /* @__PURE__ */ new Map());
2375
- this.identity = identity;
2647
+ this.userId = userId;
2376
2648
  this.options = {
2377
2649
  timeout: DEFAULT_TIMEOUT_MS,
2378
2650
  maxRetries: DEFAULT_MAX_RETRIES,
@@ -2381,7 +2653,7 @@ var MultiSessionClient = class {
2381
2653
  };
2382
2654
  }
2383
2655
  /**
2384
- * Fetches all sessions for this identity from storage and returns only the
2656
+ * Fetches all sessions for this userId from storage and returns only the
2385
2657
  * ones that are ready to connect.
2386
2658
  *
2387
2659
  * A session is considered connectable when:
@@ -2394,8 +2666,8 @@ var MultiSessionClient = class {
2394
2666
  * for backwards compatibility.
2395
2667
  */
2396
2668
  async getActiveSessions() {
2397
- const sessions = await storage.getIdentitySessionsData(this.identity);
2398
- const valid = sessions.filter(
2669
+ const sessionList = await sessions.list(this.userId);
2670
+ const valid = sessionList.filter(
2399
2671
  (s) => s.serverId && s.serverUrl && s.callbackUrl && s.active !== false
2400
2672
  // exclude OAuth-pending / failed sessions
2401
2673
  );
@@ -2408,9 +2680,9 @@ var MultiSessionClient = class {
2408
2680
  * has many active MCP sessions (e.g. 20+ servers). Within each batch, sessions
2409
2681
  * are connected concurrently using `Promise.all` for speed.
2410
2682
  */
2411
- async connectInBatches(sessions) {
2412
- for (let i = 0; i < sessions.length; i += CONNECTION_BATCH_SIZE) {
2413
- const batch = sessions.slice(i, i + CONNECTION_BATCH_SIZE);
2683
+ async connectInBatches(sessions2) {
2684
+ for (let i = 0; i < sessions2.length; i += CONNECTION_BATCH_SIZE) {
2685
+ const batch = sessions2.slice(i, i + CONNECTION_BATCH_SIZE);
2414
2686
  await Promise.all(batch.map((session) => this.connectSession(session)));
2415
2687
  }
2416
2688
  }
@@ -2461,7 +2733,7 @@ var MultiSessionClient = class {
2461
2733
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
2462
2734
  try {
2463
2735
  const client = new MCPClient({
2464
- identity: this.identity,
2736
+ userId: this.userId,
2465
2737
  sessionId: session.sessionId,
2466
2738
  serverId: session.serverId,
2467
2739
  serverUrl: session.serverUrl,
@@ -2493,7 +2765,7 @@ var MultiSessionClient = class {
2493
2765
  console.error(`[MultiSessionClient] Failed to connect to session ${session.sessionId} after ${maxRetries + 1} attempts:`, lastError);
2494
2766
  }
2495
2767
  /**
2496
- * The main entry point. Fetches all active sessions for this identity from
2768
+ * The main entry point. Fetches all active sessions for this userId from
2497
2769
  * storage and establishes connections to all of them in batches.
2498
2770
  *
2499
2771
  * Call this once after creating the client. On traditional servers, you can
@@ -2501,8 +2773,8 @@ var MultiSessionClient = class {
2501
2773
  * re-fetching and re-connecting on every request.
2502
2774
  */
2503
2775
  async connect() {
2504
- const sessions = await this.getActiveSessions();
2505
- await this.connectInBatches(sessions);
2776
+ const sessions2 = await this.getActiveSessions();
2777
+ await this.connectInBatches(sessions2);
2506
2778
  }
2507
2779
  /**
2508
2780
  * Returns all currently connected `MCPClient` instances.
@@ -2561,11 +2833,11 @@ var SSEConnectionManager = class {
2561
2833
  constructor(options, sendEvent) {
2562
2834
  this.options = options;
2563
2835
  this.sendEvent = sendEvent;
2564
- __publicField(this, "identity");
2836
+ __publicField(this, "userId");
2565
2837
  __publicField(this, "clients", /* @__PURE__ */ new Map());
2566
2838
  __publicField(this, "heartbeatTimer");
2567
2839
  __publicField(this, "isActive", true);
2568
- this.identity = options.identity;
2840
+ this.userId = options.userId;
2569
2841
  this.startHeartbeat();
2570
2842
  }
2571
2843
  /**
@@ -2605,8 +2877,8 @@ var SSEConnectionManager = class {
2605
2877
  try {
2606
2878
  let result;
2607
2879
  switch (request.method) {
2608
- case "getSessions":
2609
- result = await this.getSessions();
2880
+ case "listSessions":
2881
+ result = await this.listSessions();
2610
2882
  break;
2611
2883
  case "connect":
2612
2884
  result = await this.connect(request.params);
@@ -2620,8 +2892,8 @@ var SSEConnectionManager = class {
2620
2892
  case "callTool":
2621
2893
  result = await this.callTool(request.params);
2622
2894
  break;
2623
- case "restoreSession":
2624
- result = await this.restoreSession(request.params);
2895
+ case "getSession":
2896
+ result = await this.getSession(request.params);
2625
2897
  break;
2626
2898
  case "finishAuth":
2627
2899
  result = await this.finishAuth(request.params);
@@ -2660,12 +2932,12 @@ var SSEConnectionManager = class {
2660
2932
  }
2661
2933
  }
2662
2934
  /**
2663
- * Get all sessions for the current identity
2935
+ * Get all sessions for the current userId
2664
2936
  */
2665
- async getSessions() {
2666
- const sessions = await storage.getIdentitySessionsData(this.identity);
2937
+ async listSessions() {
2938
+ const sessionList = await sessions.list(this.userId);
2667
2939
  return {
2668
- sessions: sessions.map((s) => ({
2940
+ sessions: sessionList.map((s) => ({
2669
2941
  sessionId: s.sessionId,
2670
2942
  serverId: s.serverId,
2671
2943
  serverName: s.serverName,
@@ -2682,14 +2954,14 @@ var SSEConnectionManager = class {
2682
2954
  async connect(params) {
2683
2955
  const { serverName, serverUrl, callbackUrl, transportType } = params;
2684
2956
  const headers = normalizeHeaders(params.headers);
2685
- const serverId = params.serverId && params.serverId.length <= 12 ? params.serverId : await storage.generateSessionId();
2686
- const existingSessions = await storage.getIdentitySessionsData(this.identity);
2957
+ const serverId = params.serverId && params.serverId.length <= 12 ? params.serverId : await sessions.generateSessionId();
2958
+ const existingSessions = await sessions.list(this.userId);
2687
2959
  const duplicate = existingSessions.find(
2688
2960
  (s) => s.serverId === serverId || s.serverUrl === serverUrl
2689
2961
  );
2690
2962
  if (duplicate) {
2691
2963
  if (duplicate.active === false) {
2692
- await this.restoreSession({ sessionId: duplicate.sessionId });
2964
+ await this.getSession({ sessionId: duplicate.sessionId });
2693
2965
  return {
2694
2966
  sessionId: duplicate.sessionId,
2695
2967
  success: true
@@ -2697,11 +2969,11 @@ var SSEConnectionManager = class {
2697
2969
  }
2698
2970
  throw new Error(`Connection already exists for server: ${duplicate.serverUrl || duplicate.serverId} (${duplicate.serverName})`);
2699
2971
  }
2700
- const sessionId = await storage.generateSessionId();
2972
+ const sessionId = await sessions.generateSessionId();
2701
2973
  try {
2702
2974
  const clientMetadata = await this.getResolvedClientMetadata();
2703
2975
  const client = new MCPClient({
2704
- identity: this.identity,
2976
+ userId: this.userId,
2705
2977
  sessionId,
2706
2978
  serverId,
2707
2979
  serverName,
@@ -2756,7 +3028,7 @@ var SSEConnectionManager = class {
2756
3028
  client.disconnect();
2757
3029
  this.clients.delete(sessionId);
2758
3030
  } else {
2759
- await storage.removeSession(this.identity, sessionId);
3031
+ await sessions.delete(this.userId, sessionId);
2760
3032
  }
2761
3033
  return { success: true };
2762
3034
  }
@@ -2768,12 +3040,12 @@ var SSEConnectionManager = class {
2768
3040
  if (existing) {
2769
3041
  return existing;
2770
3042
  }
2771
- const session = await storage.getSession(this.identity, sessionId);
3043
+ const session = await sessions.get(this.userId, sessionId);
2772
3044
  if (!session) {
2773
3045
  throw new Error("Session not found");
2774
3046
  }
2775
3047
  const client = new MCPClient({
2776
- identity: this.identity,
3048
+ userId: this.userId,
2777
3049
  sessionId,
2778
3050
  // These fields are optional in MCPClient, but when rehydrating a known
2779
3051
  // stored session on the server we pass them explicitly to preserve the
@@ -2820,9 +3092,9 @@ var SSEConnectionManager = class {
2820
3092
  /**
2821
3093
  * Restore and validate an existing session
2822
3094
  */
2823
- async restoreSession(params) {
3095
+ async getSession(params) {
2824
3096
  const { sessionId } = params;
2825
- const session = await storage.getSession(this.identity, sessionId);
3097
+ const session = await sessions.get(this.userId, sessionId);
2826
3098
  if (!session) {
2827
3099
  throw new Error("Session not found");
2828
3100
  }
@@ -2839,7 +3111,7 @@ var SSEConnectionManager = class {
2839
3111
  try {
2840
3112
  const clientMetadata = await this.getResolvedClientMetadata();
2841
3113
  const client = new MCPClient({
2842
- identity: this.identity,
3114
+ userId: this.userId,
2843
3115
  sessionId,
2844
3116
  // These fields are optional in MCPClient, but when rehydrating a known
2845
3117
  // stored session on the server we pass them explicitly to preserve the
@@ -2876,13 +3148,13 @@ var SSEConnectionManager = class {
2876
3148
  */
2877
3149
  async finishAuth(params) {
2878
3150
  const { sessionId, code } = params;
2879
- const session = await storage.getSession(this.identity, sessionId);
3151
+ const session = await sessions.get(this.userId, sessionId);
2880
3152
  if (!session) {
2881
3153
  throw new Error("Session not found");
2882
3154
  }
2883
3155
  try {
2884
3156
  const client = new MCPClient({
2885
- identity: this.identity,
3157
+ userId: this.userId,
2886
3158
  sessionId,
2887
3159
  // These fields are optional in MCPClient, but when rehydrating a known
2888
3160
  // stored session on the server we pass them explicitly to preserve the
@@ -2893,7 +3165,7 @@ var SSEConnectionManager = class {
2893
3165
  serverUrl: session.serverUrl,
2894
3166
  callbackUrl: session.callbackUrl,
2895
3167
  // NOTE: transportType is intentionally omitted here.
2896
- // The session's stored transportType is a placeholder ('streamable_http')
3168
+ // The session's stored transportType is a placeholder ('streamable-http')
2897
3169
  // set before transport negotiation. Omitting it lets MCPClient auto-negotiate
2898
3170
  // (try streamable_http → SSE fallback), which is critical for servers like
2899
3171
  // Neon that only support SSE transport.
@@ -3016,18 +3288,21 @@ function writeSSEEvent(res, event, data) {
3016
3288
  init_cjs_shims();
3017
3289
  function createNextMcpHandler(options = {}) {
3018
3290
  const {
3019
- getIdentity = (request) => new URL(request.url).searchParams.get("identity"),
3291
+ getUserId = (request) => request.headers.get("x-mcp-user-id"),
3020
3292
  getAuthToken = (request) => {
3021
- const url = new URL(request.url);
3022
- return url.searchParams.get("token") || request.headers.get("authorization");
3293
+ const authHeader = request.headers.get("authorization");
3294
+ if (authHeader?.toLowerCase().startsWith("bearer ")) {
3295
+ return authHeader.slice(7);
3296
+ }
3297
+ return authHeader;
3023
3298
  },
3024
3299
  authenticate = () => true,
3025
3300
  heartbeatInterval = 3e4,
3026
3301
  clientDefaults,
3027
3302
  getClientMetadata
3028
3303
  } = options;
3029
- const toManagerOptions = (identity, resolvedClientMetadata) => ({
3030
- identity,
3304
+ const toManagerOptions = (userId, resolvedClientMetadata) => ({
3305
+ userId,
3031
3306
  heartbeatInterval,
3032
3307
  clientDefaults: resolvedClientMetadata
3033
3308
  });
@@ -3046,13 +3321,13 @@ function createNextMcpHandler(options = {}) {
3046
3321
  );
3047
3322
  }
3048
3323
  async function POST(request) {
3049
- const identity = getIdentity(request);
3324
+ const userId = getUserId(request);
3050
3325
  const authToken = getAuthToken(request);
3051
3326
  const acceptsEventStream = (request.headers.get("accept") || "").toLowerCase().includes("text/event-stream");
3052
- if (!identity) {
3053
- return Response.json({ error: { code: "MISSING_IDENTITY", message: "Missing identity" } }, { status: 400 });
3327
+ if (!userId) {
3328
+ return Response.json({ error: { code: "MISSING_userId", message: "Missing userId" } }, { status: 400 });
3054
3329
  }
3055
- const isAuthorized = await authenticate(identity, authToken);
3330
+ const isAuthorized = await authenticate(userId, authToken);
3056
3331
  if (!isAuthorized) {
3057
3332
  return Response.json({ error: { code: "UNAUTHORIZED", message: "Unauthorized" } }, { status: 401 });
3058
3333
  }
@@ -3074,7 +3349,7 @@ function createNextMcpHandler(options = {}) {
3074
3349
  const resolvedClientMetadata = await resolveClientMetadata(request);
3075
3350
  if (!acceptsEventStream) {
3076
3351
  const manager2 = new SSEConnectionManager(
3077
- toManagerOptions(identity, resolvedClientMetadata),
3352
+ toManagerOptions(userId, resolvedClientMetadata),
3078
3353
  () => {
3079
3354
  }
3080
3355
  );
@@ -3100,7 +3375,7 @@ data: ${JSON.stringify(data)}
3100
3375
  });
3101
3376
  };
3102
3377
  const manager = new SSEConnectionManager(
3103
- toManagerOptions(identity, resolvedClientMetadata),
3378
+ toManagerOptions(userId, resolvedClientMetadata),
3104
3379
  (event) => {
3105
3380
  if (isRpcResponseEvent(event)) {
3106
3381
  sendSSE("rpc-response", event);
@@ -3143,7 +3418,7 @@ data: ${JSON.stringify(data)}
3143
3418
  } catch (error) {
3144
3419
  const err = error instanceof Error ? error : new Error("Unknown error");
3145
3420
  console.error("[MCP Next Handler] Failed to handle RPC", {
3146
- identity,
3421
+ userId,
3147
3422
  message: err.message,
3148
3423
  stack: err.stack,
3149
3424
  rawBody: rawBody.slice(0, 500)
@@ -3189,8 +3464,8 @@ var SSEClient = class {
3189
3464
  isConnected() {
3190
3465
  return this.connected;
3191
3466
  }
3192
- async getSessions() {
3193
- return this.sendRequest("getSessions");
3467
+ async listSessions() {
3468
+ return this.sendRequest("listSessions");
3194
3469
  }
3195
3470
  async connectToServer(params) {
3196
3471
  return this.sendRequest("connect", params);
@@ -3206,8 +3481,8 @@ var SSEClient = class {
3206
3481
  this.emitUiEventIfPresent(result, sessionId, toolName);
3207
3482
  return result;
3208
3483
  }
3209
- async restoreSession(sessionId) {
3210
- return this.sendRequest("restoreSession", { sessionId });
3484
+ async getSession(sessionId) {
3485
+ return this.sendRequest("getSession", { sessionId });
3211
3486
  }
3212
3487
  async finishAuth(sessionId, code) {
3213
3488
  return this.sendRequest("finishAuth", { sessionId, code });
@@ -3273,7 +3548,7 @@ var SSEClient = class {
3273
3548
  return this.parseRpcResponse(data2);
3274
3549
  }
3275
3550
  const data = await this.readRpcResponseFromStream(response, {
3276
- delayConnectionEvents: method === "connect" || method === "restoreSession" || method === "finishAuth"
3551
+ delayConnectionEvents: method === "connect" || method === "getSession" || method === "finishAuth"
3277
3552
  });
3278
3553
  return this.parseRpcResponse(data);
3279
3554
  }
@@ -3363,17 +3638,13 @@ var SSEClient = class {
3363
3638
  throw new Error("Invalid RPC response format");
3364
3639
  }
3365
3640
  buildUrl() {
3366
- const url = new URL(this.options.url, globalThis.location?.origin);
3367
- url.searchParams.set("identity", this.options.identity);
3368
- if (this.options.authToken) {
3369
- url.searchParams.set("token", this.options.authToken);
3370
- }
3371
- return url.toString();
3641
+ return new URL(this.options.url, globalThis.location?.origin).toString();
3372
3642
  }
3373
3643
  buildHeaders() {
3374
3644
  const headers = {
3375
3645
  "Content-Type": "application/json",
3376
- "Accept": "text/event-stream"
3646
+ "Accept": "text/event-stream",
3647
+ "x-mcp-user-id": this.options.userId
3377
3648
  };
3378
3649
  if (this.options.authToken) {
3379
3650
  headers["Authorization"] = `Bearer ${this.options.authToken}`;
@@ -3842,7 +4113,7 @@ var AppHost = class {
3842
4113
  async getSessionId() {
3843
4114
  if (this.sessionId) return this.sessionId;
3844
4115
  if (!this.client) return void 0;
3845
- const result = await this.client.getSessions();
4116
+ const result = await this.client.listSessions();
3846
4117
  return result.sessions?.[0]?.sessionId;
3847
4118
  }
3848
4119
  isMcpUri(url) {
@@ -3923,17 +4194,7 @@ init_cjs_shims();
3923
4194
 
3924
4195
  // src/shared/tool-index.ts
3925
4196
  init_cjs_shims();
3926
- var CALIBRATION_DIVISOR = 3.6;
3927
- function classifyChar(ch) {
3928
- const code = ch.charCodeAt(0);
3929
- if (code <= 32 || ch === "{" || ch === "}" || ch === "[" || ch === "]" || ch === ":" || ch === ",") return 1;
3930
- if (code >= 33 && code <= 47) return 1.5;
3931
- if (code >= 48 && code <= 57) return 2;
3932
- if (code >= 65 && code <= 90) return 3.5;
3933
- if (code >= 97 && code <= 122) return 4;
3934
- return 2.5;
3935
- }
3936
- var ToolIndex = class _ToolIndex {
4197
+ var ToolIndex = class {
3937
4198
  constructor(options = {}) {
3938
4199
  /** All indexed tools keyed by name (supports duplicates). */
3939
4200
  __publicField(this, "tools", /* @__PURE__ */ new Map());
@@ -3951,8 +4212,6 @@ var ToolIndex = class _ToolIndex {
3951
4212
  __publicField(this, "docLengths", /* @__PURE__ */ new Map());
3952
4213
  /** BM25: average document length across the entire index. */
3953
4214
  __publicField(this, "avgDocLength", 0);
3954
- /** Cached total estimated token cost across all indexed tools. */
3955
- __publicField(this, "totalTokenCost", 0);
3956
4215
  __publicField(this, "options");
3957
4216
  this.options = {
3958
4217
  embedFn: options.embedFn ?? void 0,
@@ -3975,7 +4234,6 @@ var ToolIndex = class _ToolIndex {
3975
4234
  this.embeddings.clear();
3976
4235
  this.docLengths.clear();
3977
4236
  this.avgDocLength = 0;
3978
- this.totalTokenCost = 0;
3979
4237
  const allTokenSets = /* @__PURE__ */ new Map();
3980
4238
  let totalLength = 0;
3981
4239
  for (const tool of tools) {
@@ -3984,19 +4242,17 @@ var ToolIndex = class _ToolIndex {
3984
4242
  this.tools.set(tool.name, []);
3985
4243
  }
3986
4244
  this.tools.get(tool.name).push(tool);
3987
- const estimatedTokens = _ToolIndex.estimateTokens(tool);
3988
4245
  this.toolSummaries.set(docKey, {
3989
4246
  name: tool.name,
3990
4247
  description: tool.description ?? "",
3991
4248
  serverName: tool.serverName,
3992
4249
  serverId: tool.serverId,
3993
- sessionId: tool.sessionId,
3994
- estimatedTokens
4250
+ sessionId: tool.sessionId
3995
4251
  });
3996
- this.totalTokenCost += estimatedTokens;
3997
- const text = this.buildSearchableText(tool).toLowerCase();
4252
+ const rawText = this.buildSearchableText(tool);
4253
+ const text = rawText.toLowerCase();
3998
4254
  this.searchTexts.set(docKey, text);
3999
- const tokens = this.tokenize(text);
4255
+ const tokens = this.tokenize(rawText);
4000
4256
  const tf = /* @__PURE__ */ new Map();
4001
4257
  const uniqueTokens = /* @__PURE__ */ new Set();
4002
4258
  for (const tok of tokens) {
@@ -4260,30 +4516,6 @@ var ToolIndex = class _ToolIndex {
4260
4516
  }
4261
4517
  return count;
4262
4518
  }
4263
- /** Total estimated token cost of all indexed tool schemas. */
4264
- getTotalTokenCost() {
4265
- return this.totalTokenCost;
4266
- }
4267
- // -----------------------------------------------------------------------
4268
- // Static Helpers
4269
- // -----------------------------------------------------------------------
4270
- /**
4271
- * Estimate token count of a tool's full schema (name + description + inputSchema).
4272
- *
4273
- * Uses character-class weighted counting calibrated against cl100k_base.
4274
- * Accuracy is typically within ±10% for JSON Schema payloads.
4275
- */
4276
- static estimateTokens(tool) {
4277
- const parts = [tool.name];
4278
- if (tool.description) parts.push(tool.description);
4279
- if (tool.inputSchema) parts.push(JSON.stringify(tool.inputSchema));
4280
- const text = parts.join(" ");
4281
- let weightedLen = 0;
4282
- for (let i = 0; i < text.length; i++) {
4283
- weightedLen += 1 / classifyChar(text[i]);
4284
- }
4285
- return Math.ceil(weightedLen / (1 / CALIBRATION_DIVISOR));
4286
- }
4287
4519
  // -----------------------------------------------------------------------
4288
4520
  // Internals
4289
4521
  // -----------------------------------------------------------------------
@@ -4292,18 +4524,74 @@ var ToolIndex = class _ToolIndex {
4292
4524
  const parts = [tool.name];
4293
4525
  if (tool.description) parts.push(tool.description);
4294
4526
  if (tool.inputSchema && typeof tool.inputSchema === "object") {
4295
- const schema = tool.inputSchema;
4296
- const props = schema.properties;
4297
- if (props) {
4298
- for (const [key, val] of Object.entries(props)) {
4299
- parts.push(key);
4300
- if (val && typeof val === "object" && val.description) {
4301
- parts.push(val.description);
4302
- }
4527
+ this.collectSchemaSearchText(tool.inputSchema, parts);
4528
+ }
4529
+ return parts.join(" ");
4530
+ }
4531
+ /** Recursively collect JSON Schema argument names and descriptions. */
4532
+ collectSchemaSearchText(schema, parts, seen = /* @__PURE__ */ new WeakSet()) {
4533
+ if (!schema || typeof schema !== "object") return;
4534
+ if (seen.has(schema)) return;
4535
+ seen.add(schema);
4536
+ if (Array.isArray(schema)) {
4537
+ for (const item of schema) {
4538
+ this.collectSchemaSearchText(item, parts, seen);
4539
+ }
4540
+ return;
4541
+ }
4542
+ const schemaObject = schema;
4543
+ this.pushStringValue(schemaObject.description, parts);
4544
+ this.pushStringValue(schemaObject.title, parts);
4545
+ const properties = schemaObject.properties;
4546
+ if (properties && typeof properties === "object" && !Array.isArray(properties)) {
4547
+ for (const [propertyName, propertySchema] of Object.entries(properties)) {
4548
+ parts.push(propertyName);
4549
+ this.collectSchemaSearchText(propertySchema, parts, seen);
4550
+ }
4551
+ }
4552
+ const patternProperties = schemaObject.patternProperties;
4553
+ if (patternProperties && typeof patternProperties === "object" && !Array.isArray(patternProperties)) {
4554
+ for (const [propertyPattern, propertySchema] of Object.entries(patternProperties)) {
4555
+ parts.push(propertyPattern);
4556
+ this.collectSchemaSearchText(propertySchema, parts, seen);
4557
+ }
4558
+ }
4559
+ const dependentSchemas = schemaObject.dependentSchemas;
4560
+ if (dependentSchemas && typeof dependentSchemas === "object" && !Array.isArray(dependentSchemas)) {
4561
+ for (const [propertyName, dependentSchema] of Object.entries(dependentSchemas)) {
4562
+ parts.push(propertyName);
4563
+ this.collectSchemaSearchText(dependentSchema, parts, seen);
4564
+ }
4565
+ }
4566
+ for (const key of [
4567
+ "items",
4568
+ "additionalProperties",
4569
+ "contains",
4570
+ "propertyNames",
4571
+ "if",
4572
+ "then",
4573
+ "else",
4574
+ "not"
4575
+ ]) {
4576
+ this.collectSchemaSearchText(schemaObject[key], parts, seen);
4577
+ }
4578
+ for (const key of ["allOf", "anyOf", "oneOf", "prefixItems"]) {
4579
+ this.collectSchemaSearchText(schemaObject[key], parts, seen);
4580
+ }
4581
+ for (const key of ["$defs", "definitions"]) {
4582
+ const definitions = schemaObject[key];
4583
+ if (definitions && typeof definitions === "object" && !Array.isArray(definitions)) {
4584
+ for (const [definitionName, definitionSchema] of Object.entries(definitions)) {
4585
+ parts.push(definitionName);
4586
+ this.collectSchemaSearchText(definitionSchema, parts, seen);
4303
4587
  }
4304
4588
  }
4305
4589
  }
4306
- return parts.join(" ");
4590
+ }
4591
+ pushStringValue(value, parts) {
4592
+ if (typeof value === "string" && value.trim()) {
4593
+ parts.push(value);
4594
+ }
4307
4595
  }
4308
4596
  getDocumentKey(tool) {
4309
4597
  return `${tool.sessionId}::${tool.serverId}::${tool.name}`;
@@ -4324,7 +4612,7 @@ var ToolIndex = class _ToolIndex {
4324
4612
  }
4325
4613
  /** Simple whitespace + camelCase + snake_case tokenizer. */
4326
4614
  tokenize(text) {
4327
- return text.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/[_-]/g, " ").replace(/[^a-z0-9\s]/g, "").split(/\s+/).filter((t) => t.length > 1);
4615
+ return text.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/[_-]/g, " ").toLowerCase().replace(/[^a-z0-9\s]/g, "").split(/\s+/).filter((t) => t.length > 1);
4328
4616
  }
4329
4617
  /** Cosine similarity between two vectors. */
4330
4618
  cosineSimilarity(a, b) {
@@ -4380,27 +4668,6 @@ var SchemaCompressor = class _SchemaCompressor {
4380
4668
  const limited = options?.maxTools ? tools.slice(0, options.maxTools) : tools;
4381
4669
  return limited.map((t) => _SchemaCompressor.toCompact(t));
4382
4670
  }
4383
- /**
4384
- * Estimate token savings from using compact vs full tool schemas.
4385
- */
4386
- static estimateSavings(tools) {
4387
- let fullTokens = 0;
4388
- let compactTokens = 0;
4389
- for (const tool of tools) {
4390
- fullTokens += ToolIndex.estimateTokens(tool);
4391
- const compact = _SchemaCompressor.toCompact(tool);
4392
- const text = [compact.name, compact.description ?? "", compact.parameterHint ?? ""].join(" ");
4393
- compactTokens += Math.ceil(text.length / 4);
4394
- }
4395
- const saved = fullTokens - compactTokens;
4396
- const pct = fullTokens > 0 ? (saved / fullTokens * 100).toFixed(1) : "0.0";
4397
- return {
4398
- fullTokens,
4399
- compactTokens,
4400
- savedTokens: saved,
4401
- savingsPercent: `${pct}%`
4402
- };
4403
- }
4404
4671
  };
4405
4672
 
4406
4673
  // src/shared/meta-tools.ts
@@ -4597,7 +4864,7 @@ async function executeMetaTool(toolName, args, router, callToolFn) {
4597
4864
  const lines = [];
4598
4865
  if (found.length > 0) {
4599
4866
  lines.push(...found.map(
4600
- (t, i) => `${i + 1}. **${t.name}** (server: ${t.serverName}, serverId: ${t.serverId})
4867
+ (t, i) => `${i + 1}. **${t.name}** (serverName: ${t.serverName}, serverId: ${t.serverId})
4601
4868
  ${t.description}`
4602
4869
  ));
4603
4870
  }
@@ -4625,7 +4892,7 @@ async function executeMetaTool(toolName, args, router, callToolFn) {
4625
4892
  serverName: query || void 0
4626
4893
  });
4627
4894
  const text = servers.length === 0 ? "No connected servers found." : servers.map(
4628
- (server, i) => `${i + 1}. **${server.serverName}** (serverId: ${server.serverId}, sessionId: ${server.sessionId})
4895
+ (server, i) => `${i + 1}. **${server.serverName}** (serverId: ${server.serverId})
4629
4896
  Tool count: ${server.toolCount}`
4630
4897
  ).join("\n");
4631
4898
  return {
@@ -4732,9 +4999,8 @@ async function executeMetaTool(toolName, args, router, callToolFn) {
4732
4999
  }
4733
5000
  function formatToolSummaries(tools) {
4734
5001
  return tools.map(
4735
- (t, i) => `${i + 1}. **${t.name}** (server: ${t.serverName}, serverId: ${t.serverId})
4736
- ${t.description}
4737
- Estimated tokens: ${t.estimatedTokens}`
5002
+ (t, i) => `${i + 1}. **${t.name}** (serverName: ${t.serverName}, serverId: ${t.serverId})
5003
+ ${t.description}`
4738
5004
  );
4739
5005
  }
4740
5006
  function isMetaTool(toolName) {
@@ -4877,26 +5143,6 @@ var ToolRouter = class {
4877
5143
  getActiveGroups() {
4878
5144
  return [...this.activeGroups];
4879
5145
  }
4880
- // -----------------------------------------------------------------------
4881
- // Stats & Introspection
4882
- // -----------------------------------------------------------------------
4883
- /** Total token cost of all tools if loaded without filtering. */
4884
- getTotalTokenCost() {
4885
- return this.index.getTotalTokenCost();
4886
- }
4887
- /** Estimate token cost of the currently filtered tool set. */
4888
- async getFilteredTokenCost() {
4889
- const tools = await this.getFilteredTools();
4890
- let total = 0;
4891
- for (const tool of tools) {
4892
- total += ToolIndex.estimateTokens(tool);
4893
- }
4894
- return total;
4895
- }
4896
- /** Get compression stats showing savings from current strategy. */
4897
- getCompressionStats() {
4898
- return SchemaCompressor.estimateSavings(this.allTools);
4899
- }
4900
5146
  /** Number of total indexed tools. */
4901
5147
  get totalToolCount() {
4902
5148
  return this.allTools.length;
@@ -5099,6 +5345,6 @@ exports.isListToolsSuccess = isListToolsSuccess;
5099
5345
  exports.isMetaTool = isMetaTool;
5100
5346
  exports.resolveMetaToolProxy = resolveMetaToolProxy;
5101
5347
  exports.sanitizeServerLabel = sanitizeServerLabel;
5102
- exports.storage = storage;
5348
+ exports.sessions = sessions;
5103
5349
  //# sourceMappingURL=index.js.map
5104
5350
  //# sourceMappingURL=index.js.map