@mcp-ts/sdk 1.6.2 → 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 (113) 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 +15 -19
  41. package/dist/client/react.js.map +1 -1
  42. package/dist/client/react.mjs +15 -19
  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/use-mcp-apps.tsx +1 -1
  90. package/src/client/react/use-mcp.ts +11 -11
  91. package/src/client/vue/use-mcp.ts +10 -10
  92. package/src/server/handlers/nextjs-handler.ts +18 -15
  93. package/src/server/handlers/sse-handler.ts +29 -29
  94. package/src/server/index.ts +1 -1
  95. package/src/server/mcp/multi-session-client.ts +17 -17
  96. package/src/server/mcp/oauth-client.ts +37 -37
  97. package/src/server/mcp/storage-oauth-provider.ts +17 -17
  98. package/src/server/storage/file-backend.ts +25 -25
  99. package/src/server/storage/index.ts +67 -10
  100. package/src/server/storage/memory-backend.ts +34 -34
  101. package/src/server/storage/neon-backend.ts +281 -0
  102. package/src/server/storage/redis-backend.ts +64 -64
  103. package/src/server/storage/sqlite-backend.ts +33 -33
  104. package/src/server/storage/supabase-backend.ts +23 -24
  105. package/src/server/storage/types.ts +18 -21
  106. package/src/shared/errors.ts +1 -1
  107. package/src/shared/index.ts +1 -2
  108. package/src/shared/meta-tools.ts +4 -6
  109. package/src/shared/schema-compressor.ts +2 -42
  110. package/src/shared/tool-index.ts +89 -84
  111. package/src/shared/tool-router.ts +0 -24
  112. package/src/shared/types.ts +4 -4
  113. /package/{supabase/migrations → migrations/supabase}/20260421010000_add_session_cleanup_cron.sql +0 -0
@@ -197,35 +197,35 @@ var RedisStorageBackend = class {
197
197
  this.redis = redis2;
198
198
  __publicField(this, "DEFAULT_TTL", SESSION_TTL_SECONDS);
199
199
  __publicField(this, "KEY_PREFIX", "mcp:session:");
200
- __publicField(this, "IDENTITY_KEY_PREFIX", "mcp:identity:");
201
- __publicField(this, "IDENTITY_KEY_SUFFIX", ":sessions");
200
+ __publicField(this, "USER_ID_KEY_PREFIX", "mcp:userId:");
201
+ __publicField(this, "USER_ID_KEY_SUFFIX", ":sessions");
202
202
  }
203
203
  async init() {
204
204
  try {
205
205
  await this.redis.ping();
206
206
  console.log("[mcp-ts][Storage] Redis: \u2713 Connected to server.");
207
207
  } catch (error) {
208
- throw new Error(`[RedisStorage] Failed to connect to Redis: ${error.message}`);
208
+ throw new Error(`[RedisStorageBackend] Failed to connect to Redis: ${error.message}`);
209
209
  }
210
210
  }
211
211
  /**
212
212
  * Generates Redis key for a specific session
213
213
  * @private
214
214
  */
215
- getSessionKey(identity, sessionId) {
216
- return `${this.KEY_PREFIX}${identity}:${sessionId}`;
215
+ getSessionKey(userId, sessionId) {
216
+ return `${this.KEY_PREFIX}${userId}:${sessionId}`;
217
217
  }
218
218
  /**
219
- * Generates Redis key for tracking all sessions for an identity
219
+ * Generates Redis key for tracking all sessions for a user
220
220
  * @private
221
221
  */
222
- getIdentityKey(identity) {
223
- return `${this.IDENTITY_KEY_PREFIX}${identity}${this.IDENTITY_KEY_SUFFIX}`;
222
+ getUserIdKey(userId) {
223
+ return `${this.USER_ID_KEY_PREFIX}${userId}${this.USER_ID_KEY_SUFFIX}`;
224
224
  }
225
- parseIdentityFromKey(identityKey) {
226
- return identityKey.slice(
227
- this.IDENTITY_KEY_PREFIX.length,
228
- identityKey.length - this.IDENTITY_KEY_SUFFIX.length
225
+ parseUserIdFromKey(userIdKey) {
226
+ return userIdKey.slice(
227
+ this.USER_ID_KEY_PREFIX.length,
228
+ userIdKey.length - this.USER_ID_KEY_SUFFIX.length
229
229
  );
230
230
  }
231
231
  async scanKeys(pattern) {
@@ -244,7 +244,7 @@ var RedisStorageBackend = class {
244
244
  }
245
245
  } while (cursor !== "0");
246
246
  } catch (error) {
247
- console.warn("[RedisStorage] SCAN failed, falling back to KEYS:", error);
247
+ console.warn("[RedisStorageBackend] SCAN failed, falling back to KEYS:", error);
248
248
  return await this.redis.keys(pattern);
249
249
  }
250
250
  return Array.from(keys);
@@ -252,11 +252,11 @@ var RedisStorageBackend = class {
252
252
  generateSessionId() {
253
253
  return generateSessionId();
254
254
  }
255
- async createSession(session, ttl) {
256
- const { sessionId, identity } = session;
257
- if (!sessionId || !identity) throw new Error("identity and sessionId required");
258
- const sessionKey = this.getSessionKey(identity, sessionId);
259
- const identityKey = this.getIdentityKey(identity);
255
+ async create(session, ttl) {
256
+ const { sessionId, userId } = session;
257
+ if (!sessionId || !userId) throw new Error("userId and sessionId required");
258
+ const sessionKey = this.getSessionKey(userId, sessionId);
259
+ const userIdKey = this.getUserIdKey(userId);
260
260
  const effectiveTtl = ttl ?? this.DEFAULT_TTL;
261
261
  const result = await this.redis.set(
262
262
  sessionKey,
@@ -268,10 +268,10 @@ var RedisStorageBackend = class {
268
268
  if (result !== "OK") {
269
269
  throw new Error(`Session ${sessionId} already exists`);
270
270
  }
271
- await this.redis.sadd(identityKey, sessionId);
271
+ await this.redis.sadd(userIdKey, sessionId);
272
272
  }
273
- async updateSession(identity, sessionId, data, ttl) {
274
- const sessionKey = this.getSessionKey(identity, sessionId);
273
+ async update(userId, sessionId, data, ttl) {
274
+ const sessionKey = this.getSessionKey(userId, sessionId);
275
275
  const effectiveTtl = ttl ?? this.DEFAULT_TTL;
276
276
  const script = `
277
277
  local currentStr = redis.call("GET", KEYS[1])
@@ -297,62 +297,62 @@ var RedisStorageBackend = class {
297
297
  effectiveTtl
298
298
  );
299
299
  if (result === 0) {
300
- throw new Error(`Session ${sessionId} not found for identity ${identity}`);
300
+ throw new Error(`Session ${sessionId} not found for userId ${userId}`);
301
301
  }
302
302
  }
303
- async getSession(identity, sessionId) {
303
+ async get(userId, sessionId) {
304
304
  try {
305
- const sessionKey = this.getSessionKey(identity, sessionId);
305
+ const sessionKey = this.getSessionKey(userId, sessionId);
306
306
  const sessionDataStr = await this.redis.get(sessionKey);
307
307
  if (!sessionDataStr) {
308
308
  return null;
309
309
  }
310
- const sessionData = JSON.parse(sessionDataStr);
311
- return sessionData;
310
+ const Session = JSON.parse(sessionDataStr);
311
+ return Session;
312
312
  } catch (error) {
313
- console.error("[RedisStorage] Failed to get session:", error);
313
+ console.error("[RedisStorageBackend] Failed to get session:", error);
314
314
  return null;
315
315
  }
316
316
  }
317
- async getIdentityMcpSessions(identity) {
318
- const sessions = await this.getIdentitySessionsData(identity);
319
- return sessions.map((session) => session.sessionId);
317
+ async listIds(userId) {
318
+ const sessions2 = await this.list(userId);
319
+ return sessions2.map((session) => session.sessionId);
320
320
  }
321
- async getIdentitySessionsData(identity) {
321
+ async list(userId) {
322
322
  try {
323
- const identityKey = this.getIdentityKey(identity);
324
- const sessionIds = await this.redis.smembers(identityKey);
323
+ const userIdKey = this.getUserIdKey(userId);
324
+ const sessionIds = await this.redis.smembers(userIdKey);
325
325
  if (sessionIds.length === 0) return [];
326
326
  const results = await Promise.all(
327
327
  sessionIds.map(async (sessionId) => {
328
- const data = await this.redis.get(this.getSessionKey(identity, sessionId));
328
+ const data = await this.redis.get(this.getSessionKey(userId, sessionId));
329
329
  return data ? JSON.parse(data) : null;
330
330
  })
331
331
  );
332
332
  const staleSessionIds = sessionIds.filter((_, index) => results[index] === null);
333
333
  if (staleSessionIds.length > 0) {
334
- await this.redis.srem(identityKey, ...staleSessionIds);
334
+ await this.redis.srem(userIdKey, ...staleSessionIds);
335
335
  }
336
336
  return results.filter((session) => session !== null);
337
337
  } catch (error) {
338
- console.error(`[RedisStorage] Failed to get session data for ${identity}:`, error);
338
+ console.error(`[RedisStorageBackend] Failed to get session data for ${userId}:`, error);
339
339
  return [];
340
340
  }
341
341
  }
342
- async removeSession(identity, sessionId) {
342
+ async delete(userId, sessionId) {
343
343
  try {
344
- const sessionKey = this.getSessionKey(identity, sessionId);
345
- const identityKey = this.getIdentityKey(identity);
346
- await this.redis.srem(identityKey, sessionId);
344
+ const sessionKey = this.getSessionKey(userId, sessionId);
345
+ const userIdKey = this.getUserIdKey(userId);
346
+ await this.redis.srem(userIdKey, sessionId);
347
347
  await this.redis.del(sessionKey);
348
348
  } catch (error) {
349
- console.error("[RedisStorage] Failed to remove session:", error);
349
+ console.error("[RedisStorageBackend] Failed to remove session:", error);
350
350
  }
351
351
  }
352
- async getAllSessionIds() {
352
+ async listAllIds() {
353
353
  try {
354
354
  const keys = await this.scanKeys(`${this.KEY_PREFIX}*`);
355
- const sessions = await Promise.all(
355
+ const sessions2 = await Promise.all(
356
356
  keys.map(async (key) => {
357
357
  const data = await this.redis.get(key);
358
358
  if (!data) {
@@ -361,60 +361,60 @@ var RedisStorageBackend = class {
361
361
  try {
362
362
  return JSON.parse(data).sessionId;
363
363
  } catch (error) {
364
- console.error("[RedisStorage] Failed to parse session while listing all session IDs:", error);
364
+ console.error("[RedisStorageBackend] Failed to parse session while listing all session IDs:", error);
365
365
  return null;
366
366
  }
367
367
  })
368
368
  );
369
- return sessions.filter((sessionId) => sessionId !== null);
369
+ return sessions2.filter((sessionId) => sessionId !== null);
370
370
  } catch (error) {
371
- console.error("[RedisStorage] Failed to get all sessions:", error);
371
+ console.error("[RedisStorageBackend] Failed to get all sessions:", error);
372
372
  return [];
373
373
  }
374
374
  }
375
375
  async clearAll() {
376
376
  try {
377
377
  const keys = await this.scanKeys(`${this.KEY_PREFIX}*`);
378
- const identityKeys = await this.scanKeys(`${this.IDENTITY_KEY_PREFIX}*${this.IDENTITY_KEY_SUFFIX}`);
379
- const allKeys = [...keys, ...identityKeys];
378
+ const userIdKeys = await this.scanKeys(`${this.USER_ID_KEY_PREFIX}*${this.USER_ID_KEY_SUFFIX}`);
379
+ const allKeys = [...keys, ...userIdKeys];
380
380
  if (allKeys.length > 0) {
381
381
  await this.redis.del(...allKeys);
382
382
  }
383
383
  } catch (error) {
384
- console.error("[RedisStorage] Failed to clear sessions:", error);
384
+ console.error("[RedisStorageBackend] Failed to clear sessions:", error);
385
385
  }
386
386
  }
387
- async cleanupExpiredSessions() {
387
+ async cleanupExpired() {
388
388
  try {
389
- const identityKeys = await this.scanKeys(`${this.IDENTITY_KEY_PREFIX}*${this.IDENTITY_KEY_SUFFIX}`);
390
- for (const identityKey of identityKeys) {
391
- const identity = this.parseIdentityFromKey(identityKey);
392
- const sessionIds = await this.redis.smembers(identityKey);
389
+ const userIdKeys = await this.scanKeys(`${this.USER_ID_KEY_PREFIX}*${this.USER_ID_KEY_SUFFIX}`);
390
+ for (const userIdKey of userIdKeys) {
391
+ const userId = this.parseUserIdFromKey(userIdKey);
392
+ const sessionIds = await this.redis.smembers(userIdKey);
393
393
  if (sessionIds.length === 0) {
394
- await this.redis.del(identityKey);
394
+ await this.redis.del(userIdKey);
395
395
  continue;
396
396
  }
397
397
  const existenceChecks = await Promise.all(
398
- sessionIds.map((sessionId) => this.redis.exists(this.getSessionKey(identity, sessionId)))
398
+ sessionIds.map((sessionId) => this.redis.exists(this.getSessionKey(userId, sessionId)))
399
399
  );
400
400
  const staleSessionIds = sessionIds.filter((_, index) => existenceChecks[index] === 0);
401
401
  if (staleSessionIds.length > 0) {
402
- await this.redis.srem(identityKey, ...staleSessionIds);
402
+ await this.redis.srem(userIdKey, ...staleSessionIds);
403
403
  }
404
- const remainingCount = await this.redis.scard(identityKey);
404
+ const remainingCount = await this.redis.scard(userIdKey);
405
405
  if (remainingCount === 0) {
406
- await this.redis.del(identityKey);
406
+ await this.redis.del(userIdKey);
407
407
  }
408
408
  }
409
409
  } catch (error) {
410
- console.error("[RedisStorage] Failed to cleanup expired sessions:", error);
410
+ console.error("[RedisStorageBackend] Failed to cleanup expired sessions:", error);
411
411
  }
412
412
  }
413
413
  async disconnect() {
414
414
  try {
415
415
  await this.redis.quit();
416
416
  } catch (error) {
417
- console.error("[RedisStorage] Failed to disconnect:", error);
417
+ console.error("[RedisStorageBackend] Failed to disconnect:", error);
418
418
  }
419
419
  }
420
420
  };
@@ -423,36 +423,36 @@ var RedisStorageBackend = class {
423
423
  init_cjs_shims();
424
424
  var MemoryStorageBackend = class {
425
425
  constructor() {
426
- // Map<identity:sessionId, SessionData>
426
+ // Map<userId:sessionId, Session>
427
427
  __publicField(this, "sessions", /* @__PURE__ */ new Map());
428
- // Map<identity, Set<sessionId>>
429
- __publicField(this, "identitySessions", /* @__PURE__ */ new Map());
428
+ // Map<userId, Set<sessionId>>
429
+ __publicField(this, "userIdSessions", /* @__PURE__ */ new Map());
430
430
  }
431
431
  async init() {
432
432
  console.log("[mcp-ts][Storage] Memory: \u2713 internal memory store active.");
433
433
  }
434
- getSessionKey(identity, sessionId) {
435
- return `${identity}:${sessionId}`;
434
+ getSessionKey(userId, sessionId) {
435
+ return `${userId}:${sessionId}`;
436
436
  }
437
437
  generateSessionId() {
438
438
  return generateSessionId();
439
439
  }
440
- async createSession(session, ttl) {
441
- const { sessionId, identity } = session;
442
- if (!sessionId || !identity) throw new Error("identity and sessionId required");
443
- const sessionKey = this.getSessionKey(identity, sessionId);
440
+ async create(session, ttl) {
441
+ const { sessionId, userId } = session;
442
+ if (!sessionId || !userId) throw new Error("userId and sessionId required");
443
+ const sessionKey = this.getSessionKey(userId, sessionId);
444
444
  if (this.sessions.has(sessionKey)) {
445
445
  throw new Error(`Session ${sessionId} already exists`);
446
446
  }
447
447
  this.sessions.set(sessionKey, session);
448
- if (!this.identitySessions.has(identity)) {
449
- this.identitySessions.set(identity, /* @__PURE__ */ new Set());
448
+ if (!this.userIdSessions.has(userId)) {
449
+ this.userIdSessions.set(userId, /* @__PURE__ */ new Set());
450
450
  }
451
- this.identitySessions.get(identity).add(sessionId);
451
+ this.userIdSessions.get(userId).add(sessionId);
452
452
  }
453
- async updateSession(identity, sessionId, data, ttl) {
454
- if (!identity || !sessionId) throw new Error("identity and sessionId required");
455
- const sessionKey = this.getSessionKey(identity, sessionId);
453
+ async update(userId, sessionId, data, ttl) {
454
+ if (!userId || !sessionId) throw new Error("userId and sessionId required");
455
+ const sessionKey = this.getSessionKey(userId, sessionId);
456
456
  const current = this.sessions.get(sessionKey);
457
457
  if (!current) {
458
458
  throw new Error(`Session ${sessionId} not found`);
@@ -463,45 +463,45 @@ var MemoryStorageBackend = class {
463
463
  };
464
464
  this.sessions.set(sessionKey, updated);
465
465
  }
466
- async getSession(identity, sessionId) {
467
- const sessionKey = this.getSessionKey(identity, sessionId);
466
+ async get(userId, sessionId) {
467
+ const sessionKey = this.getSessionKey(userId, sessionId);
468
468
  return this.sessions.get(sessionKey) || null;
469
469
  }
470
- async getIdentityMcpSessions(identity) {
471
- const set = this.identitySessions.get(identity);
470
+ async listIds(userId) {
471
+ const set = this.userIdSessions.get(userId);
472
472
  return set ? Array.from(set) : [];
473
473
  }
474
- async getIdentitySessionsData(identity) {
475
- const set = this.identitySessions.get(identity);
474
+ async list(userId) {
475
+ const set = this.userIdSessions.get(userId);
476
476
  if (!set) return [];
477
477
  const results = [];
478
478
  for (const sessionId of set) {
479
- const session = this.sessions.get(this.getSessionKey(identity, sessionId));
479
+ const session = this.sessions.get(this.getSessionKey(userId, sessionId));
480
480
  if (session) {
481
481
  results.push(session);
482
482
  }
483
483
  }
484
484
  return results;
485
485
  }
486
- async removeSession(identity, sessionId) {
487
- const sessionKey = this.getSessionKey(identity, sessionId);
486
+ async delete(userId, sessionId) {
487
+ const sessionKey = this.getSessionKey(userId, sessionId);
488
488
  this.sessions.delete(sessionKey);
489
- const set = this.identitySessions.get(identity);
489
+ const set = this.userIdSessions.get(userId);
490
490
  if (set) {
491
491
  set.delete(sessionId);
492
492
  if (set.size === 0) {
493
- this.identitySessions.delete(identity);
493
+ this.userIdSessions.delete(userId);
494
494
  }
495
495
  }
496
496
  }
497
- async getAllSessionIds() {
497
+ async listAllIds() {
498
498
  return Array.from(this.sessions.values()).map((s) => s.sessionId);
499
499
  }
500
500
  async clearAll() {
501
501
  this.sessions.clear();
502
- this.identitySessions.clear();
502
+ this.userIdSessions.clear();
503
503
  }
504
- async cleanupExpiredSessions() {
504
+ async cleanupExpired() {
505
505
  }
506
506
  async disconnect() {
507
507
  }
@@ -532,7 +532,7 @@ var FileStorageBackend = class {
532
532
  this.memoryCache = /* @__PURE__ */ new Map();
533
533
  if (Array.isArray(json)) {
534
534
  json.forEach((s) => {
535
- this.memoryCache.set(this.getSessionKey(s.identity || "unknown", s.sessionId), s);
535
+ this.memoryCache.set(this.getSessionKey(s.userId || "unknown", s.sessionId), s);
536
536
  });
537
537
  }
538
538
  } catch (error) {
@@ -552,30 +552,30 @@ var FileStorageBackend = class {
552
552
  }
553
553
  async flush() {
554
554
  if (!this.memoryCache) return;
555
- const sessions = Array.from(this.memoryCache.values());
556
- await fs2.promises.writeFile(this.filePath, JSON.stringify(sessions, null, 2), "utf-8");
555
+ const sessions2 = Array.from(this.memoryCache.values());
556
+ await fs2.promises.writeFile(this.filePath, JSON.stringify(sessions2, null, 2), "utf-8");
557
557
  }
558
- getSessionKey(identity, sessionId) {
559
- return `${identity}:${sessionId}`;
558
+ getSessionKey(userId, sessionId) {
559
+ return `${userId}:${sessionId}`;
560
560
  }
561
561
  generateSessionId() {
562
562
  return generateSessionId();
563
563
  }
564
- async createSession(session, ttl) {
564
+ async create(session, ttl) {
565
565
  await this.ensureInitialized();
566
- const { sessionId, identity } = session;
567
- if (!sessionId || !identity) throw new Error("identity and sessionId required");
568
- const sessionKey = this.getSessionKey(identity, sessionId);
566
+ const { sessionId, userId } = session;
567
+ if (!sessionId || !userId) throw new Error("userId and sessionId required");
568
+ const sessionKey = this.getSessionKey(userId, sessionId);
569
569
  if (this.memoryCache.has(sessionKey)) {
570
570
  throw new Error(`Session ${sessionId} already exists`);
571
571
  }
572
572
  this.memoryCache.set(sessionKey, session);
573
573
  await this.flush();
574
574
  }
575
- async updateSession(identity, sessionId, data, ttl) {
575
+ async update(userId, sessionId, data, ttl) {
576
576
  await this.ensureInitialized();
577
- if (!identity || !sessionId) throw new Error("identity and sessionId required");
578
- const sessionKey = this.getSessionKey(identity, sessionId);
577
+ if (!userId || !sessionId) throw new Error("userId and sessionId required");
578
+ const sessionKey = this.getSessionKey(userId, sessionId);
579
579
  const current = this.memoryCache.get(sessionKey);
580
580
  if (!current) {
581
581
  throw new Error(`Session ${sessionId} not found`);
@@ -587,27 +587,27 @@ var FileStorageBackend = class {
587
587
  this.memoryCache.set(sessionKey, updated);
588
588
  await this.flush();
589
589
  }
590
- async getSession(identity, sessionId) {
590
+ async get(userId, sessionId) {
591
591
  await this.ensureInitialized();
592
- const sessionKey = this.getSessionKey(identity, sessionId);
592
+ const sessionKey = this.getSessionKey(userId, sessionId);
593
593
  return this.memoryCache.get(sessionKey) || null;
594
594
  }
595
- async getIdentitySessionsData(identity) {
595
+ async list(userId) {
596
596
  await this.ensureInitialized();
597
- return Array.from(this.memoryCache.values()).filter((s) => s.identity === identity);
597
+ return Array.from(this.memoryCache.values()).filter((s) => s.userId === userId);
598
598
  }
599
- async getIdentityMcpSessions(identity) {
599
+ async listIds(userId) {
600
600
  await this.ensureInitialized();
601
- return Array.from(this.memoryCache.values()).filter((s) => s.identity === identity).map((s) => s.sessionId);
601
+ return Array.from(this.memoryCache.values()).filter((s) => s.userId === userId).map((s) => s.sessionId);
602
602
  }
603
- async removeSession(identity, sessionId) {
603
+ async delete(userId, sessionId) {
604
604
  await this.ensureInitialized();
605
- const sessionKey = this.getSessionKey(identity, sessionId);
605
+ const sessionKey = this.getSessionKey(userId, sessionId);
606
606
  if (this.memoryCache.delete(sessionKey)) {
607
607
  await this.flush();
608
608
  }
609
609
  }
610
- async getAllSessionIds() {
610
+ async listAllIds() {
611
611
  await this.ensureInitialized();
612
612
  return Array.from(this.memoryCache.values()).map((s) => s.sessionId);
613
613
  }
@@ -616,7 +616,7 @@ var FileStorageBackend = class {
616
616
  this.memoryCache.clear();
617
617
  await this.flush();
618
618
  }
619
- async cleanupExpiredSessions() {
619
+ async cleanupExpired() {
620
620
  await this.ensureInitialized();
621
621
  }
622
622
  async disconnect() {
@@ -646,11 +646,11 @@ var SqliteStorage = class {
646
646
  this.db.exec(`
647
647
  CREATE TABLE IF NOT EXISTS ${this.table} (
648
648
  sessionId TEXT PRIMARY KEY,
649
- identity TEXT NOT NULL,
649
+ userId TEXT NOT NULL,
650
650
  data TEXT NOT NULL,
651
651
  expiresAt INTEGER
652
652
  );
653
- CREATE INDEX IF NOT EXISTS idx_${this.table}_identity ON ${this.table}(identity);
653
+ CREATE INDEX IF NOT EXISTS idx_${this.table}_userId ON ${this.table}(userId);
654
654
  `);
655
655
  this.initialized = true;
656
656
  console.log(`[mcp-ts][Storage] SQLite: \u2713 database at ${this.dbPath} verified.`);
@@ -671,18 +671,18 @@ var SqliteStorage = class {
671
671
  generateSessionId() {
672
672
  return generateSessionId();
673
673
  }
674
- async createSession(session, ttl) {
674
+ async create(session, ttl) {
675
675
  this.ensureInitialized();
676
- const { sessionId, identity } = session;
677
- if (!sessionId || !identity) {
678
- throw new Error("identity and sessionId required");
676
+ const { sessionId, userId } = session;
677
+ if (!sessionId || !userId) {
678
+ throw new Error("userId and sessionId required");
679
679
  }
680
680
  const expiresAt = ttl ? Date.now() + ttl * 1e3 : null;
681
681
  try {
682
682
  const stmt = this.db.prepare(
683
- `INSERT INTO ${this.table} (sessionId, identity, data, expiresAt) VALUES (?, ?, ?, ?)`
683
+ `INSERT INTO ${this.table} (sessionId, userId, data, expiresAt) VALUES (?, ?, ?, ?)`
684
684
  );
685
- stmt.run(sessionId, identity, JSON.stringify(session), expiresAt);
685
+ stmt.run(sessionId, userId, JSON.stringify(session), expiresAt);
686
686
  } catch (error) {
687
687
  if (error.code === "SQLITE_CONSTRAINT_PRIMARYKEY") {
688
688
  throw new Error(`Session ${sessionId} already exists`);
@@ -690,55 +690,55 @@ var SqliteStorage = class {
690
690
  throw error;
691
691
  }
692
692
  }
693
- async updateSession(identity, sessionId, data, ttl) {
693
+ async update(userId, sessionId, data, ttl) {
694
694
  this.ensureInitialized();
695
- if (!sessionId || !identity) {
696
- throw new Error("identity and sessionId required");
695
+ if (!sessionId || !userId) {
696
+ throw new Error("userId and sessionId required");
697
697
  }
698
- const currentSession = await this.getSession(identity, sessionId);
698
+ const currentSession = await this.get(userId, sessionId);
699
699
  if (!currentSession) {
700
- throw new Error(`Session ${sessionId} not found for identity ${identity}`);
700
+ throw new Error(`Session ${sessionId} not found for userId ${userId}`);
701
701
  }
702
702
  const updatedSession = { ...currentSession, ...data };
703
703
  const expiresAt = ttl ? Date.now() + ttl * 1e3 : null;
704
704
  const stmt = this.db.prepare(
705
- `UPDATE ${this.table} SET data = ?, expiresAt = ? WHERE sessionId = ? AND identity = ?`
705
+ `UPDATE ${this.table} SET data = ?, expiresAt = ? WHERE sessionId = ? AND userId = ?`
706
706
  );
707
- stmt.run(JSON.stringify(updatedSession), expiresAt, sessionId, identity);
707
+ stmt.run(JSON.stringify(updatedSession), expiresAt, sessionId, userId);
708
708
  }
709
- async getSession(identity, sessionId) {
709
+ async get(userId, sessionId) {
710
710
  this.ensureInitialized();
711
711
  const stmt = this.db.prepare(
712
- `SELECT data FROM ${this.table} WHERE sessionId = ? AND identity = ?`
712
+ `SELECT data FROM ${this.table} WHERE sessionId = ? AND userId = ?`
713
713
  );
714
- const row = stmt.get(sessionId, identity);
714
+ const row = stmt.get(sessionId, userId);
715
715
  if (!row) return null;
716
716
  return JSON.parse(row.data);
717
717
  }
718
- async getIdentitySessionsData(identity) {
718
+ async list(userId) {
719
719
  this.ensureInitialized();
720
720
  const stmt = this.db.prepare(
721
- `SELECT data FROM ${this.table} WHERE identity = ?`
721
+ `SELECT data FROM ${this.table} WHERE userId = ?`
722
722
  );
723
- const rows = stmt.all(identity);
723
+ const rows = stmt.all(userId);
724
724
  return rows.map((row) => JSON.parse(row.data));
725
725
  }
726
- async getIdentityMcpSessions(identity) {
726
+ async listIds(userId) {
727
727
  this.ensureInitialized();
728
728
  const stmt = this.db.prepare(
729
- `SELECT sessionId FROM ${this.table} WHERE identity = ?`
729
+ `SELECT sessionId FROM ${this.table} WHERE userId = ?`
730
730
  );
731
- const rows = stmt.all(identity);
731
+ const rows = stmt.all(userId);
732
732
  return rows.map((row) => row.sessionId);
733
733
  }
734
- async removeSession(identity, sessionId) {
734
+ async delete(userId, sessionId) {
735
735
  this.ensureInitialized();
736
736
  const stmt = this.db.prepare(
737
- `DELETE FROM ${this.table} WHERE sessionId = ? AND identity = ?`
737
+ `DELETE FROM ${this.table} WHERE sessionId = ? AND userId = ?`
738
738
  );
739
- stmt.run(sessionId, identity);
739
+ stmt.run(sessionId, userId);
740
740
  }
741
- async getAllSessionIds() {
741
+ async listAllIds() {
742
742
  this.ensureInitialized();
743
743
  const stmt = this.db.prepare(`SELECT sessionId FROM ${this.table}`);
744
744
  const rows = stmt.all();
@@ -749,7 +749,7 @@ var SqliteStorage = class {
749
749
  const stmt = this.db.prepare(`DELETE FROM ${this.table}`);
750
750
  stmt.run();
751
751
  }
752
- async cleanupExpiredSessions() {
752
+ async cleanupExpired() {
753
753
  this.ensureInitialized();
754
754
  const now = Date.now();
755
755
  const stmt = this.db.prepare(
@@ -866,7 +866,7 @@ var SupabaseStorageBackend = class {
866
866
  transportType: row.transport_type,
867
867
  callbackUrl: row.callback_url,
868
868
  createdAt: new Date(row.created_at).getTime(),
869
- identity: row.identity,
869
+ userId: row.user_id,
870
870
  headers: decryptObject(row.headers),
871
871
  active: row.active,
872
872
  clientInformation: row.client_information,
@@ -875,22 +875,21 @@ var SupabaseStorageBackend = class {
875
875
  clientId: row.client_id
876
876
  };
877
877
  }
878
- async createSession(session, ttl) {
879
- const { sessionId, identity } = session;
880
- if (!sessionId || !identity) throw new Error("identity and sessionId required");
878
+ async create(session, ttl) {
879
+ const { sessionId, userId } = session;
880
+ if (!sessionId || !userId) throw new Error("userId and sessionId required");
881
881
  const effectiveTtl = ttl ?? this.DEFAULT_TTL;
882
882
  const expiresAt = new Date(Date.now() + effectiveTtl * 1e3).toISOString();
883
883
  const { error } = await this.supabase.from("mcp_sessions").insert({
884
884
  session_id: sessionId,
885
- user_id: identity,
886
- // Maps user_id to identity to support RLS using auth.uid()
885
+ user_id: userId,
886
+ // Maps user_id to userId to support RLS using auth.uid()
887
887
  server_id: session.serverId,
888
888
  server_name: session.serverName,
889
889
  server_url: session.serverUrl,
890
890
  transport_type: session.transportType,
891
891
  callback_url: session.callbackUrl,
892
892
  created_at: new Date(session.createdAt || Date.now()).toISOString(),
893
- identity,
894
893
  headers: encryptObject(session.headers),
895
894
  active: session.active ?? false,
896
895
  client_information: session.clientInformation,
@@ -906,7 +905,7 @@ var SupabaseStorageBackend = class {
906
905
  throw new Error(`Failed to create session in Supabase: ${error.message}`);
907
906
  }
908
907
  }
909
- async updateSession(identity, sessionId, data, ttl) {
908
+ async update(userId, sessionId, data, ttl) {
910
909
  const effectiveTtl = ttl ?? this.DEFAULT_TTL;
911
910
  const expiresAt = new Date(Date.now() + effectiveTtl * 1e3).toISOString();
912
911
  const updateData = {
@@ -924,16 +923,16 @@ var SupabaseStorageBackend = class {
924
923
  if ("tokens" in data) updateData.tokens = encryptObject(data.tokens);
925
924
  if ("codeVerifier" in data) updateData.code_verifier = data.codeVerifier;
926
925
  if ("clientId" in data) updateData.client_id = data.clientId;
927
- const { data: updatedRows, error } = await this.supabase.from("mcp_sessions").update(updateData).eq("identity", identity).eq("session_id", sessionId).select("id");
926
+ const { data: updatedRows, error } = await this.supabase.from("mcp_sessions").update(updateData).eq("user_id", userId).eq("session_id", sessionId).select("id");
928
927
  if (error) {
929
928
  throw new Error(`Failed to update session: ${error.message}`);
930
929
  }
931
930
  if (!updatedRows || updatedRows.length === 0) {
932
- throw new Error(`Session ${sessionId} not found for identity ${identity}`);
931
+ throw new Error(`Session ${sessionId} not found for userId ${userId}`);
933
932
  }
934
933
  }
935
- async getSession(identity, sessionId) {
936
- const { data, error } = await this.supabase.from("mcp_sessions").select("*").eq("identity", identity).eq("session_id", sessionId).maybeSingle();
934
+ async get(userId, sessionId) {
935
+ const { data, error } = await this.supabase.from("mcp_sessions").select("*").eq("user_id", userId).eq("session_id", sessionId).maybeSingle();
937
936
  if (error) {
938
937
  console.error("[SupabaseStorage] Failed to get session:", error);
939
938
  return null;
@@ -941,29 +940,29 @@ var SupabaseStorageBackend = class {
941
940
  if (!data) return null;
942
941
  return this.mapRowToSessionData(data);
943
942
  }
944
- async getIdentitySessionsData(identity) {
945
- const { data, error } = await this.supabase.from("mcp_sessions").select("*").eq("identity", identity);
943
+ async list(userId) {
944
+ const { data, error } = await this.supabase.from("mcp_sessions").select("*").eq("user_id", userId);
946
945
  if (error) {
947
- console.error(`[SupabaseStorage] Failed to get session data for ${identity}:`, error);
946
+ console.error(`[SupabaseStorage] Failed to get session data for ${userId}:`, error);
948
947
  return [];
949
948
  }
950
949
  return data.map((row) => this.mapRowToSessionData(row));
951
950
  }
952
- async removeSession(identity, sessionId) {
953
- const { error } = await this.supabase.from("mcp_sessions").delete().eq("identity", identity).eq("session_id", sessionId);
951
+ async delete(userId, sessionId) {
952
+ const { error } = await this.supabase.from("mcp_sessions").delete().eq("user_id", userId).eq("session_id", sessionId);
954
953
  if (error) {
955
954
  console.error("[SupabaseStorage] Failed to remove session:", error);
956
955
  }
957
956
  }
958
- async getIdentityMcpSessions(identity) {
959
- const { data, error } = await this.supabase.from("mcp_sessions").select("session_id").eq("identity", identity);
957
+ async listIds(userId) {
958
+ const { data, error } = await this.supabase.from("mcp_sessions").select("session_id").eq("user_id", userId);
960
959
  if (error) {
961
- console.error(`[SupabaseStorage] Failed to get sessions for ${identity}:`, error);
960
+ console.error(`[SupabaseStorage] Failed to get sessions for ${userId}:`, error);
962
961
  return [];
963
962
  }
964
963
  return data.map((row) => row.session_id);
965
964
  }
966
- async getAllSessionIds() {
965
+ async listAllIds() {
967
966
  const { data, error } = await this.supabase.from("mcp_sessions").select("session_id");
968
967
  if (error) {
969
968
  console.error("[SupabaseStorage] Failed to get all sessions:", error);
@@ -977,7 +976,7 @@ var SupabaseStorageBackend = class {
977
976
  console.error("[SupabaseStorage] Failed to clear sessions:", error);
978
977
  }
979
978
  }
980
- async cleanupExpiredSessions() {
979
+ async cleanupExpired() {
981
980
  const { error } = await this.supabase.from("mcp_sessions").delete().lt("expires_at", (/* @__PURE__ */ new Date()).toISOString());
982
981
  if (error) {
983
982
  console.error("[SupabaseStorage] Failed to cleanup expired sessions:", error);
@@ -987,10 +986,254 @@ var SupabaseStorageBackend = class {
987
986
  }
988
987
  };
989
988
 
989
+ // src/server/storage/neon-backend.ts
990
+ init_cjs_shims();
991
+ var NeonStorageBackend = class {
992
+ constructor(sql, options = {}) {
993
+ this.sql = sql;
994
+ __publicField(this, "DEFAULT_TTL", SESSION_TTL_SECONDS);
995
+ __publicField(this, "tableName");
996
+ const schema = options.schema || "public";
997
+ const table = options.table || "mcp_sessions";
998
+ this.tableName = `${this.quoteIdentifier(schema)}.${this.quoteIdentifier(table)}`;
999
+ }
1000
+ async init() {
1001
+ const [{ exists } = { exists: null }] = await this.sql.query(
1002
+ "SELECT to_regclass($1) AS exists",
1003
+ [this.tableName.replace(/"/g, "")]
1004
+ );
1005
+ if (!exists) {
1006
+ throw new Error(
1007
+ '[NeonStorage] Table "mcp_sessions" not found in your database. Please create it using the Neon storage guide in docs/storage-backends/neon.md.'
1008
+ );
1009
+ }
1010
+ console.log('[mcp-ts][Storage] Neon: "mcp_sessions" table verified.');
1011
+ }
1012
+ generateSessionId() {
1013
+ return generateSessionId();
1014
+ }
1015
+ quoteIdentifier(identifier) {
1016
+ if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(identifier)) {
1017
+ throw new Error(`Invalid Neon storage identifier: ${identifier}`);
1018
+ }
1019
+ return `"${identifier}"`;
1020
+ }
1021
+ mapRowToSessionData(row) {
1022
+ return {
1023
+ sessionId: row.session_id,
1024
+ serverId: row.server_id ?? void 0,
1025
+ serverName: row.server_name ?? void 0,
1026
+ serverUrl: row.server_url,
1027
+ transportType: row.transport_type,
1028
+ callbackUrl: row.callback_url,
1029
+ createdAt: new Date(row.created_at).getTime(),
1030
+ userId: row.user_id,
1031
+ headers: decryptObject(row.headers),
1032
+ active: row.active ?? false,
1033
+ clientInformation: row.client_information,
1034
+ tokens: decryptObject(row.tokens),
1035
+ codeVerifier: row.code_verifier ?? void 0,
1036
+ clientId: row.client_id ?? void 0
1037
+ };
1038
+ }
1039
+ async create(session, ttl) {
1040
+ const { sessionId, userId } = session;
1041
+ if (!sessionId || !userId) throw new Error("userId and sessionId required");
1042
+ const effectiveTtl = ttl ?? this.DEFAULT_TTL;
1043
+ const expiresAt = new Date(Date.now() + effectiveTtl * 1e3).toISOString();
1044
+ try {
1045
+ await this.sql.query(
1046
+ `INSERT INTO ${this.tableName} (
1047
+ session_id,
1048
+ user_id,
1049
+ server_id,
1050
+ server_name,
1051
+ server_url,
1052
+ transport_type,
1053
+ callback_url,
1054
+ created_at,
1055
+ headers,
1056
+ active,
1057
+ client_information,
1058
+ tokens,
1059
+ code_verifier,
1060
+ client_id,
1061
+ expires_at
1062
+ ) VALUES (
1063
+ $1, $2, $3, $4, $5, $6, $7, $8,
1064
+ $9, $10, $11, $12, $13, $14, $15
1065
+ )`,
1066
+ [
1067
+ sessionId,
1068
+ userId,
1069
+ session.serverId,
1070
+ session.serverName,
1071
+ session.serverUrl,
1072
+ session.transportType,
1073
+ session.callbackUrl,
1074
+ new Date(session.createdAt || Date.now()).toISOString(),
1075
+ encryptObject(session.headers),
1076
+ session.active ?? false,
1077
+ session.clientInformation,
1078
+ encryptObject(session.tokens),
1079
+ session.codeVerifier,
1080
+ session.clientId,
1081
+ expiresAt
1082
+ ]
1083
+ );
1084
+ } catch (error) {
1085
+ if (error.code === "23505") {
1086
+ throw new Error(`Session ${sessionId} already exists`);
1087
+ }
1088
+ throw new Error(`Failed to create session in Neon: ${error.message}`);
1089
+ }
1090
+ }
1091
+ async update(userId, sessionId, data, ttl) {
1092
+ const currentSession = await this.get(userId, sessionId);
1093
+ if (!currentSession) {
1094
+ throw new Error(`Session ${sessionId} not found for userId ${userId}`);
1095
+ }
1096
+ const updatedSession = { ...currentSession, ...data };
1097
+ const effectiveTtl = ttl ?? this.DEFAULT_TTL;
1098
+ const expiresAt = new Date(Date.now() + effectiveTtl * 1e3).toISOString();
1099
+ const updatedRows = await this.sql.query(
1100
+ `UPDATE ${this.tableName}
1101
+ SET
1102
+ server_id = $1,
1103
+ server_name = $2,
1104
+ server_url = $3,
1105
+ transport_type = $4,
1106
+ callback_url = $5,
1107
+ active = $6,
1108
+ headers = $7,
1109
+ client_information = $8,
1110
+ tokens = $9,
1111
+ code_verifier = $10,
1112
+ client_id = $11,
1113
+ expires_at = $12,
1114
+ updated_at = now()
1115
+ WHERE user_id = $13 AND session_id = $14
1116
+ RETURNING id`,
1117
+ [
1118
+ updatedSession.serverId,
1119
+ updatedSession.serverName,
1120
+ updatedSession.serverUrl,
1121
+ updatedSession.transportType,
1122
+ updatedSession.callbackUrl,
1123
+ updatedSession.active ?? false,
1124
+ encryptObject(updatedSession.headers),
1125
+ updatedSession.clientInformation,
1126
+ encryptObject(updatedSession.tokens),
1127
+ updatedSession.codeVerifier,
1128
+ updatedSession.clientId,
1129
+ expiresAt,
1130
+ userId,
1131
+ sessionId
1132
+ ]
1133
+ );
1134
+ if (updatedRows.length === 0) {
1135
+ throw new Error(`Session ${sessionId} not found for userId ${userId}`);
1136
+ }
1137
+ }
1138
+ async get(userId, sessionId) {
1139
+ try {
1140
+ const rows = await this.sql.query(
1141
+ `SELECT * FROM ${this.tableName} WHERE user_id = $1 AND session_id = $2`,
1142
+ [userId, sessionId]
1143
+ );
1144
+ return rows[0] ? this.mapRowToSessionData(rows[0]) : null;
1145
+ } catch (error) {
1146
+ console.error("[NeonStorage] Failed to get session:", error);
1147
+ return null;
1148
+ }
1149
+ }
1150
+ async list(userId) {
1151
+ try {
1152
+ const rows = await this.sql.query(
1153
+ `SELECT * FROM ${this.tableName} WHERE user_id = $1`,
1154
+ [userId]
1155
+ );
1156
+ return rows.map((row) => this.mapRowToSessionData(row));
1157
+ } catch (error) {
1158
+ console.error(`[NeonStorage] Failed to get session data for ${userId}:`, error);
1159
+ return [];
1160
+ }
1161
+ }
1162
+ async delete(userId, sessionId) {
1163
+ try {
1164
+ await this.sql.query(
1165
+ `DELETE FROM ${this.tableName} WHERE user_id = $1 AND session_id = $2`,
1166
+ [userId, sessionId]
1167
+ );
1168
+ } catch (error) {
1169
+ console.error("[NeonStorage] Failed to remove session:", error);
1170
+ }
1171
+ }
1172
+ async listIds(userId) {
1173
+ try {
1174
+ const rows = await this.sql.query(
1175
+ `SELECT session_id FROM ${this.tableName} WHERE user_id = $1`,
1176
+ [userId]
1177
+ );
1178
+ return rows.map((row) => row.session_id);
1179
+ } catch (error) {
1180
+ console.error(`[NeonStorage] Failed to get sessions for ${userId}:`, error);
1181
+ return [];
1182
+ }
1183
+ }
1184
+ async listAllIds() {
1185
+ try {
1186
+ const rows = await this.sql.query(
1187
+ `SELECT session_id FROM ${this.tableName}`
1188
+ );
1189
+ return rows.map((row) => row.session_id);
1190
+ } catch (error) {
1191
+ console.error("[NeonStorage] Failed to get all sessions:", error);
1192
+ return [];
1193
+ }
1194
+ }
1195
+ async clearAll() {
1196
+ try {
1197
+ await this.sql.query(`DELETE FROM ${this.tableName}`);
1198
+ } catch (error) {
1199
+ console.error("[NeonStorage] Failed to clear sessions:", error);
1200
+ }
1201
+ }
1202
+ async cleanupExpired() {
1203
+ try {
1204
+ await this.sql.query(
1205
+ `DELETE FROM ${this.tableName} WHERE expires_at < $1`,
1206
+ [(/* @__PURE__ */ new Date()).toISOString()]
1207
+ );
1208
+ } catch (error) {
1209
+ console.error("[NeonStorage] Failed to cleanup expired sessions:", error);
1210
+ }
1211
+ }
1212
+ async disconnect() {
1213
+ }
1214
+ };
1215
+
990
1216
  // src/server/storage/types.ts
991
1217
  init_cjs_shims();
992
1218
 
993
1219
  // src/server/storage/index.ts
1220
+ function warnIfNeonConnectionStringIsInsecure(connectionString) {
1221
+ try {
1222
+ const url = new URL(connectionString);
1223
+ const sslMode = url.searchParams.get("sslmode");
1224
+ const channelBinding = url.searchParams.get("channel_binding");
1225
+ if (!sslMode) {
1226
+ console.warn("[mcp-ts][Storage] Neon connection string does not include sslmode. Neon recommends sslmode=verify-full for the strongest certificate verification.");
1227
+ } else if (!["verify-full", "require"].includes(sslMode)) {
1228
+ console.warn(`[mcp-ts][Storage] Neon connection string uses sslmode=${sslMode}. Use sslmode=verify-full or sslmode=require for secure connections.`);
1229
+ }
1230
+ if (!channelBinding) {
1231
+ console.warn("[mcp-ts][Storage] Neon connection string does not include channel_binding=require. Add it when supported by your runtime and connection path.");
1232
+ }
1233
+ } catch {
1234
+ console.warn("[mcp-ts][Storage] Neon connection string could not be parsed for SSL checks.");
1235
+ }
1236
+ }
994
1237
  var storageInstance = null;
995
1238
  var storagePromise = null;
996
1239
  async function initializeStorage(store) {
@@ -1047,6 +1290,24 @@ async function createStorage() {
1047
1290
  }
1048
1291
  }
1049
1292
  }
1293
+ if (type === "neon") {
1294
+ const connectionString = process.env.NEON_DATABASE_URL || process.env.DATABASE_URL;
1295
+ if (!connectionString) {
1296
+ console.warn('[mcp-ts][Storage] Explicit selection "neon" requires NEON_DATABASE_URL or DATABASE_URL.');
1297
+ } else {
1298
+ try {
1299
+ const { neon } = await import('@neondatabase/serverless');
1300
+ warnIfNeonConnectionStringIsInsecure(connectionString);
1301
+ const sql = neon(connectionString);
1302
+ console.log('[mcp-ts][Storage] Explicit selection: "neon"');
1303
+ return await initializeStorage(new NeonStorageBackend(sql));
1304
+ } catch (error) {
1305
+ console.error("[mcp-ts][Storage] Failed to initialize Neon:", error.message);
1306
+ console.log("[mcp-ts][Storage] Falling back to In-Memory storage");
1307
+ return await initializeStorage(new MemoryStorageBackend());
1308
+ }
1309
+ }
1310
+ }
1050
1311
  if (type === "memory") {
1051
1312
  console.log('[mcp-ts][Storage] Explicit selection: "memory"');
1052
1313
  return await initializeStorage(new MemoryStorageBackend());
@@ -1085,6 +1346,17 @@ async function createStorage() {
1085
1346
  console.error("[mcp-ts][Storage] Supabase auto-detection failed:", error.message);
1086
1347
  }
1087
1348
  }
1349
+ if (process.env.NEON_DATABASE_URL) {
1350
+ try {
1351
+ const { neon } = await import('@neondatabase/serverless');
1352
+ warnIfNeonConnectionStringIsInsecure(process.env.NEON_DATABASE_URL);
1353
+ const sql = neon(process.env.NEON_DATABASE_URL);
1354
+ console.log('[mcp-ts][Storage] Auto-detection: "neon" (via NEON_DATABASE_URL)');
1355
+ return await initializeStorage(new NeonStorageBackend(sql));
1356
+ } catch (error) {
1357
+ console.error("[mcp-ts][Storage] Neon auto-detection failed:", error.message);
1358
+ }
1359
+ }
1088
1360
  console.log('[mcp-ts][Storage] Defaulting to: "memory"');
1089
1361
  return await initializeStorage(new MemoryStorageBackend());
1090
1362
  }
@@ -1101,7 +1373,7 @@ async function getStorage() {
1101
1373
  storageInstance = await storagePromise;
1102
1374
  return storageInstance;
1103
1375
  }
1104
- var storage = new Proxy({}, {
1376
+ var sessions = new Proxy({}, {
1105
1377
  get(_target, prop) {
1106
1378
  return async (...args) => {
1107
1379
  const instance = await getStorage();
@@ -1117,11 +1389,11 @@ var storage = new Proxy({}, {
1117
1389
  // src/server/mcp/storage-oauth-provider.ts
1118
1390
  var StorageOAuthClientProvider = class {
1119
1391
  /**
1120
- * Creates a new storage-backed OAuth provider
1392
+ * Creates a new session-backed OAuth provider
1121
1393
  * @param options - Provider configuration
1122
1394
  */
1123
1395
  constructor(options) {
1124
- __publicField(this, "identity");
1396
+ __publicField(this, "userId");
1125
1397
  __publicField(this, "serverId");
1126
1398
  __publicField(this, "sessionId");
1127
1399
  __publicField(this, "redirectUrl");
@@ -1134,7 +1406,7 @@ var StorageOAuthClientProvider = class {
1134
1406
  __publicField(this, "_clientId");
1135
1407
  __publicField(this, "onRedirectCallback");
1136
1408
  __publicField(this, "tokenExpiresAt");
1137
- this.identity = options.identity;
1409
+ this.userId = options.userId;
1138
1410
  this.serverId = options.serverId;
1139
1411
  this.sessionId = options.sessionId;
1140
1412
  this.redirectUrl = options.redirectUrl;
@@ -1167,24 +1439,24 @@ var StorageOAuthClientProvider = class {
1167
1439
  this._clientId = clientId_;
1168
1440
  }
1169
1441
  /**
1170
- * Loads OAuth data from storage session
1442
+ * Loads OAuth data from the session store
1171
1443
  * @private
1172
1444
  */
1173
1445
  async getSessionData() {
1174
- const data = await storage.getSession(this.identity, this.sessionId);
1446
+ const data = await sessions.get(this.userId, this.sessionId);
1175
1447
  if (!data) {
1176
1448
  return {};
1177
1449
  }
1178
1450
  return data;
1179
1451
  }
1180
1452
  /**
1181
- * Saves OAuth data to storage
1453
+ * Saves OAuth data to the session store
1182
1454
  * @param data - Partial OAuth data to save
1183
1455
  * @private
1184
1456
  * @throws Error if session doesn't exist (session must be created by controller layer)
1185
1457
  */
1186
1458
  async saveSessionData(data) {
1187
- await storage.updateSession(this.identity, this.sessionId, data);
1459
+ await sessions.update(this.userId, this.sessionId, data);
1188
1460
  }
1189
1461
  /**
1190
1462
  * Retrieves stored OAuth client information
@@ -1232,7 +1504,7 @@ var StorageOAuthClientProvider = class {
1232
1504
  return this.sessionId;
1233
1505
  }
1234
1506
  async checkState(_state) {
1235
- const data = await storage.getSession(this.identity, this.sessionId);
1507
+ const data = await sessions.get(this.userId, this.sessionId);
1236
1508
  if (!data) {
1237
1509
  return { valid: false, error: "Session not found" };
1238
1510
  }
@@ -1248,7 +1520,7 @@ var StorageOAuthClientProvider = class {
1248
1520
  }
1249
1521
  async invalidateCredentials(scope) {
1250
1522
  if (scope === "all") {
1251
- await storage.removeSession(this.identity, this.sessionId);
1523
+ await sessions.delete(this.userId, this.sessionId);
1252
1524
  } else {
1253
1525
  const updates = {};
1254
1526
  if (scope === "client") {
@@ -1376,14 +1648,14 @@ var RpcErrorCodes = {
1376
1648
  var MCPClient = class _MCPClient {
1377
1649
  /**
1378
1650
  * Creates a new MCP client instance
1379
- * Can be initialized with minimal options (identity + sessionId) for session restoration
1651
+ * Can be initialized with minimal options (userId + sessionId) for session restoration
1380
1652
  * @param options - Client configuration options
1381
1653
  */
1382
1654
  constructor(options) {
1383
1655
  __publicField(this, "client", null);
1384
1656
  __publicField(this, "oauthProvider", null);
1385
1657
  __publicField(this, "transport", null);
1386
- __publicField(this, "identity");
1658
+ __publicField(this, "userId");
1387
1659
  __publicField(this, "serverId");
1388
1660
  __publicField(this, "sessionId");
1389
1661
  __publicField(this, "serverName");
@@ -1410,7 +1682,7 @@ var MCPClient = class _MCPClient {
1410
1682
  this.serverName = options.serverName;
1411
1683
  this.callbackUrl = options.callbackUrl;
1412
1684
  this.onRedirect = options.onRedirect;
1413
- this.identity = options.identity;
1685
+ this.userId = options.userId;
1414
1686
  this.serverId = options.serverId;
1415
1687
  this.sessionId = options.sessionId;
1416
1688
  this.transportType = options.transportType;
@@ -1549,7 +1821,7 @@ var MCPClient = class _MCPClient {
1549
1821
  this.emitStateChange("INITIALIZING");
1550
1822
  this.emitProgress("Loading session configuration...");
1551
1823
  if (!this.serverUrl || !this.callbackUrl || !this.serverId) {
1552
- const sessionData = await storage.getSession(this.identity, this.sessionId);
1824
+ const sessionData = await sessions.get(this.userId, this.sessionId);
1553
1825
  if (!sessionData) {
1554
1826
  throw new Error(`Session not found: ${this.sessionId}`);
1555
1827
  }
@@ -1568,7 +1840,7 @@ var MCPClient = class _MCPClient {
1568
1840
  throw new Error("serverId required for OAuth provider initialization");
1569
1841
  }
1570
1842
  this.oauthProvider = new StorageOAuthClientProvider({
1571
- identity: this.identity,
1843
+ userId: this.userId,
1572
1844
  serverId: this.serverId,
1573
1845
  sessionId: this.sessionId,
1574
1846
  redirectUrl: this.callbackUrl,
@@ -1602,18 +1874,18 @@ var MCPClient = class _MCPClient {
1602
1874
  }
1603
1875
  );
1604
1876
  }
1605
- const existingSession = await storage.getSession(this.identity, this.sessionId);
1877
+ const existingSession = await sessions.get(this.userId, this.sessionId);
1606
1878
  if (!existingSession && this.serverId && this.serverUrl && this.callbackUrl) {
1607
1879
  this.createdAt = Date.now();
1608
1880
  console.log(`[MCPClient] Creating initial session ${this.sessionId} for OAuth flow`);
1609
- await storage.createSession({
1881
+ await sessions.create({
1610
1882
  sessionId: this.sessionId,
1611
- identity: this.identity,
1883
+ userId: this.userId,
1612
1884
  serverId: this.serverId,
1613
1885
  serverName: this.serverName,
1614
1886
  serverUrl: this.serverUrl,
1615
1887
  callbackUrl: this.callbackUrl,
1616
- transportType: this.transportType || "streamable_http",
1888
+ transportType: this.transportType || "streamable-http",
1617
1889
  headers: this.headers,
1618
1890
  createdAt: this.createdAt,
1619
1891
  active: false
@@ -1621,7 +1893,7 @@ var MCPClient = class _MCPClient {
1621
1893
  }
1622
1894
  }
1623
1895
  /**
1624
- * Saves current session state to storage
1896
+ * Saves current session state to the session store
1625
1897
  * Creates new session if it doesn't exist, updates if it does
1626
1898
  * @param ttl - Time-to-live in seconds (defaults to 12hr for connected sessions)
1627
1899
  * @param active - Session status marker used to avoid unnecessary TTL rewrites
@@ -1633,21 +1905,21 @@ var MCPClient = class _MCPClient {
1633
1905
  }
1634
1906
  const sessionData = {
1635
1907
  sessionId: this.sessionId,
1636
- identity: this.identity,
1908
+ userId: this.userId,
1637
1909
  serverId: this.serverId,
1638
1910
  serverName: this.serverName,
1639
1911
  serverUrl: this.serverUrl,
1640
1912
  callbackUrl: this.callbackUrl,
1641
- transportType: this.transportType || "streamable_http",
1913
+ transportType: this.transportType || "streamable-http",
1642
1914
  headers: this.headers,
1643
1915
  createdAt: this.createdAt || Date.now(),
1644
1916
  active
1645
1917
  };
1646
- const existingSession = await storage.getSession(this.identity, this.sessionId);
1918
+ const existingSession = await sessions.get(this.userId, this.sessionId);
1647
1919
  if (existingSession) {
1648
- await storage.updateSession(this.identity, this.sessionId, sessionData, ttl);
1920
+ await sessions.update(this.userId, this.sessionId, sessionData, ttl);
1649
1921
  } else {
1650
- await storage.createSession(sessionData, ttl);
1922
+ await sessions.create(sessionData, ttl);
1651
1923
  }
1652
1924
  }
1653
1925
  /**
@@ -1656,7 +1928,7 @@ var MCPClient = class _MCPClient {
1656
1928
  * @private
1657
1929
  */
1658
1930
  async tryConnect() {
1659
- const transportsToTry = this.transportType ? [this.transportType] : ["streamable_http", "sse"];
1931
+ const transportsToTry = this.transportType ? [this.transportType] : ["streamable-http", "sse"];
1660
1932
  let lastError;
1661
1933
  for (const currentType of transportsToTry) {
1662
1934
  const isLastAttempt = currentType === transportsToTry[transportsToTry.length - 1];
@@ -1728,7 +2000,7 @@ var MCPClient = class _MCPClient {
1728
2000
  this.emitError(message, "auth");
1729
2001
  this.emitStateChange("FAILED");
1730
2002
  try {
1731
- await storage.removeSession(this.identity, this.sessionId);
2003
+ await sessions.delete(this.userId, this.sessionId);
1732
2004
  } catch {
1733
2005
  }
1734
2006
  throw new Error(message);
@@ -1754,9 +2026,9 @@ var MCPClient = class _MCPClient {
1754
2026
  this.emitError(errorMessage, "connection");
1755
2027
  this.emitStateChange("FAILED");
1756
2028
  try {
1757
- const existingSession = await storage.getSession(this.identity, this.sessionId);
2029
+ const existingSession = await sessions.get(this.userId, this.sessionId);
1758
2030
  if (!existingSession || existingSession.active !== true) {
1759
- await storage.removeSession(this.identity, this.sessionId);
2031
+ await sessions.delete(this.userId, this.sessionId);
1760
2032
  }
1761
2033
  } catch {
1762
2034
  }
@@ -1780,7 +2052,7 @@ var MCPClient = class _MCPClient {
1780
2052
  this.emitStateChange("FAILED");
1781
2053
  throw new Error(error);
1782
2054
  }
1783
- const transportsToTry = this.transportType ? [this.transportType] : ["streamable_http", "sse"];
2055
+ const transportsToTry = this.transportType ? [this.transportType] : ["streamable-http", "sse"];
1784
2056
  let lastError;
1785
2057
  let tokensExchanged = false;
1786
2058
  let authenticatedStateEmitted = false;
@@ -2104,7 +2376,7 @@ var MCPClient = class _MCPClient {
2104
2376
  },
2105
2377
  { capabilities: {} }
2106
2378
  );
2107
- const tt = this.transportType || "streamable_http";
2379
+ const tt = this.transportType || "streamable-http";
2108
2380
  this.transport = this.getTransport(tt);
2109
2381
  await this.client.connect(this.transport);
2110
2382
  }
@@ -2121,7 +2393,7 @@ var MCPClient = class _MCPClient {
2121
2393
  if (this.oauthProvider) {
2122
2394
  await this.oauthProvider.invalidateCredentials("all");
2123
2395
  }
2124
- await storage.removeSession(this.identity, this.sessionId);
2396
+ await sessions.delete(this.userId, this.sessionId);
2125
2397
  this.disconnect();
2126
2398
  }
2127
2399
  /**
@@ -2189,10 +2461,10 @@ var MCPClient = class _MCPClient {
2189
2461
  }
2190
2462
  /**
2191
2463
  * Gets the transport type being used
2192
- * @returns Transport type (defaults to 'streamable_http')
2464
+ * @returns Transport type (defaults to 'streamable-http')
2193
2465
  */
2194
2466
  getTransportType() {
2195
- return this.transportType || "streamable_http";
2467
+ return this.transportType || "streamable-http";
2196
2468
  }
2197
2469
  /**
2198
2470
  * Gets the human-readable server name
@@ -2219,25 +2491,25 @@ var MCPClient = class _MCPClient {
2219
2491
  * Gets MCP server configuration for all active user sessions
2220
2492
  * Loads sessions from Redis, validates OAuth tokens, refreshes if expired
2221
2493
  * Returns ready-to-use configuration with valid auth headers
2222
- * @param identity - User ID to fetch sessions for
2494
+ * @param userId - User ID to fetch sessions for
2223
2495
  * @returns Object keyed by sanitized server labels containing transport, url, headers, etc.
2224
2496
  * @static
2225
2497
  */
2226
- static async getMcpServerConfig(identity) {
2498
+ static async getMcpServerConfig(userId) {
2227
2499
  const mcpConfig = {};
2228
- const sessions = await storage.getIdentitySessionsData(identity);
2500
+ const sessionList = await sessions.list(userId);
2229
2501
  await Promise.all(
2230
- sessions.map(async (sessionData) => {
2502
+ sessionList.map(async (sessionData) => {
2231
2503
  const { sessionId } = sessionData;
2232
2504
  try {
2233
2505
  if (!sessionData.serverId || !sessionData.transportType || !sessionData.serverUrl || !sessionData.callbackUrl) {
2234
- await storage.removeSession(identity, sessionId);
2506
+ await sessions.delete(userId, sessionId);
2235
2507
  return;
2236
2508
  }
2237
2509
  let headers;
2238
2510
  try {
2239
2511
  const client = new _MCPClient({
2240
- identity,
2512
+ userId,
2241
2513
  sessionId,
2242
2514
  serverId: sessionData.serverId,
2243
2515
  serverUrl: sessionData.serverUrl,
@@ -2270,7 +2542,7 @@ var MCPClient = class _MCPClient {
2270
2542
  ...headers && { headers }
2271
2543
  };
2272
2544
  } catch (error) {
2273
- await storage.removeSession(identity, sessionId);
2545
+ await sessions.delete(userId, sessionId);
2274
2546
  console.warn(`[MCP] Failed to process session ${sessionId}:`, error);
2275
2547
  }
2276
2548
  })
@@ -2287,18 +2559,18 @@ var DEFAULT_RETRY_DELAY_MS = 1e3;
2287
2559
  var CONNECTION_BATCH_SIZE = 5;
2288
2560
  var MultiSessionClient = class {
2289
2561
  /**
2290
- * Creates a new MultiSessionClient for the given user identity.
2562
+ * Creates a new MultiSessionClient for the given user userId.
2291
2563
  *
2292
- * @param identity - A unique string identifying the user (e.g. user ID or email).
2564
+ * @param userId - A unique string identifying the user (e.g. user ID or email).
2293
2565
  * @param options - Optional tuning for connection timeout, retry count, and retry delay.
2294
2566
  * Falls back to sensible defaults if not provided.
2295
2567
  */
2296
- constructor(identity, options = {}) {
2568
+ constructor(userId, options = {}) {
2297
2569
  __publicField(this, "clients", []);
2298
- __publicField(this, "identity");
2570
+ __publicField(this, "userId");
2299
2571
  __publicField(this, "options");
2300
2572
  __publicField(this, "connectionPromises", /* @__PURE__ */ new Map());
2301
- this.identity = identity;
2573
+ this.userId = userId;
2302
2574
  this.options = {
2303
2575
  timeout: DEFAULT_TIMEOUT_MS,
2304
2576
  maxRetries: DEFAULT_MAX_RETRIES,
@@ -2307,7 +2579,7 @@ var MultiSessionClient = class {
2307
2579
  };
2308
2580
  }
2309
2581
  /**
2310
- * Fetches all sessions for this identity from storage and returns only the
2582
+ * Fetches all sessions for this userId from storage and returns only the
2311
2583
  * ones that are ready to connect.
2312
2584
  *
2313
2585
  * A session is considered connectable when:
@@ -2320,8 +2592,8 @@ var MultiSessionClient = class {
2320
2592
  * for backwards compatibility.
2321
2593
  */
2322
2594
  async getActiveSessions() {
2323
- const sessions = await storage.getIdentitySessionsData(this.identity);
2324
- const valid = sessions.filter(
2595
+ const sessionList = await sessions.list(this.userId);
2596
+ const valid = sessionList.filter(
2325
2597
  (s) => s.serverId && s.serverUrl && s.callbackUrl && s.active !== false
2326
2598
  // exclude OAuth-pending / failed sessions
2327
2599
  );
@@ -2334,9 +2606,9 @@ var MultiSessionClient = class {
2334
2606
  * has many active MCP sessions (e.g. 20+ servers). Within each batch, sessions
2335
2607
  * are connected concurrently using `Promise.all` for speed.
2336
2608
  */
2337
- async connectInBatches(sessions) {
2338
- for (let i = 0; i < sessions.length; i += CONNECTION_BATCH_SIZE) {
2339
- const batch = sessions.slice(i, i + CONNECTION_BATCH_SIZE);
2609
+ async connectInBatches(sessions2) {
2610
+ for (let i = 0; i < sessions2.length; i += CONNECTION_BATCH_SIZE) {
2611
+ const batch = sessions2.slice(i, i + CONNECTION_BATCH_SIZE);
2340
2612
  await Promise.all(batch.map((session) => this.connectSession(session)));
2341
2613
  }
2342
2614
  }
@@ -2387,7 +2659,7 @@ var MultiSessionClient = class {
2387
2659
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
2388
2660
  try {
2389
2661
  const client = new MCPClient({
2390
- identity: this.identity,
2662
+ userId: this.userId,
2391
2663
  sessionId: session.sessionId,
2392
2664
  serverId: session.serverId,
2393
2665
  serverUrl: session.serverUrl,
@@ -2419,7 +2691,7 @@ var MultiSessionClient = class {
2419
2691
  console.error(`[MultiSessionClient] Failed to connect to session ${session.sessionId} after ${maxRetries + 1} attempts:`, lastError);
2420
2692
  }
2421
2693
  /**
2422
- * The main entry point. Fetches all active sessions for this identity from
2694
+ * The main entry point. Fetches all active sessions for this userId from
2423
2695
  * storage and establishes connections to all of them in batches.
2424
2696
  *
2425
2697
  * Call this once after creating the client. On traditional servers, you can
@@ -2427,8 +2699,8 @@ var MultiSessionClient = class {
2427
2699
  * re-fetching and re-connecting on every request.
2428
2700
  */
2429
2701
  async connect() {
2430
- const sessions = await this.getActiveSessions();
2431
- await this.connectInBatches(sessions);
2702
+ const sessions2 = await this.getActiveSessions();
2703
+ await this.connectInBatches(sessions2);
2432
2704
  }
2433
2705
  /**
2434
2706
  * Returns all currently connected `MCPClient` instances.
@@ -2487,11 +2759,11 @@ var SSEConnectionManager = class {
2487
2759
  constructor(options, sendEvent) {
2488
2760
  this.options = options;
2489
2761
  this.sendEvent = sendEvent;
2490
- __publicField(this, "identity");
2762
+ __publicField(this, "userId");
2491
2763
  __publicField(this, "clients", /* @__PURE__ */ new Map());
2492
2764
  __publicField(this, "heartbeatTimer");
2493
2765
  __publicField(this, "isActive", true);
2494
- this.identity = options.identity;
2766
+ this.userId = options.userId;
2495
2767
  this.startHeartbeat();
2496
2768
  }
2497
2769
  /**
@@ -2531,8 +2803,8 @@ var SSEConnectionManager = class {
2531
2803
  try {
2532
2804
  let result;
2533
2805
  switch (request.method) {
2534
- case "getSessions":
2535
- result = await this.getSessions();
2806
+ case "listSessions":
2807
+ result = await this.listSessions();
2536
2808
  break;
2537
2809
  case "connect":
2538
2810
  result = await this.connect(request.params);
@@ -2546,8 +2818,8 @@ var SSEConnectionManager = class {
2546
2818
  case "callTool":
2547
2819
  result = await this.callTool(request.params);
2548
2820
  break;
2549
- case "restoreSession":
2550
- result = await this.restoreSession(request.params);
2821
+ case "getSession":
2822
+ result = await this.getSession(request.params);
2551
2823
  break;
2552
2824
  case "finishAuth":
2553
2825
  result = await this.finishAuth(request.params);
@@ -2586,12 +2858,12 @@ var SSEConnectionManager = class {
2586
2858
  }
2587
2859
  }
2588
2860
  /**
2589
- * Get all sessions for the current identity
2861
+ * Get all sessions for the current userId
2590
2862
  */
2591
- async getSessions() {
2592
- const sessions = await storage.getIdentitySessionsData(this.identity);
2863
+ async listSessions() {
2864
+ const sessionList = await sessions.list(this.userId);
2593
2865
  return {
2594
- sessions: sessions.map((s) => ({
2866
+ sessions: sessionList.map((s) => ({
2595
2867
  sessionId: s.sessionId,
2596
2868
  serverId: s.serverId,
2597
2869
  serverName: s.serverName,
@@ -2608,14 +2880,14 @@ var SSEConnectionManager = class {
2608
2880
  async connect(params) {
2609
2881
  const { serverName, serverUrl, callbackUrl, transportType } = params;
2610
2882
  const headers = normalizeHeaders(params.headers);
2611
- const serverId = params.serverId && params.serverId.length <= 12 ? params.serverId : await storage.generateSessionId();
2612
- const existingSessions = await storage.getIdentitySessionsData(this.identity);
2883
+ const serverId = params.serverId && params.serverId.length <= 12 ? params.serverId : await sessions.generateSessionId();
2884
+ const existingSessions = await sessions.list(this.userId);
2613
2885
  const duplicate = existingSessions.find(
2614
2886
  (s) => s.serverId === serverId || s.serverUrl === serverUrl
2615
2887
  );
2616
2888
  if (duplicate) {
2617
2889
  if (duplicate.active === false) {
2618
- await this.restoreSession({ sessionId: duplicate.sessionId });
2890
+ await this.getSession({ sessionId: duplicate.sessionId });
2619
2891
  return {
2620
2892
  sessionId: duplicate.sessionId,
2621
2893
  success: true
@@ -2623,11 +2895,11 @@ var SSEConnectionManager = class {
2623
2895
  }
2624
2896
  throw new Error(`Connection already exists for server: ${duplicate.serverUrl || duplicate.serverId} (${duplicate.serverName})`);
2625
2897
  }
2626
- const sessionId = await storage.generateSessionId();
2898
+ const sessionId = await sessions.generateSessionId();
2627
2899
  try {
2628
2900
  const clientMetadata = await this.getResolvedClientMetadata();
2629
2901
  const client = new MCPClient({
2630
- identity: this.identity,
2902
+ userId: this.userId,
2631
2903
  sessionId,
2632
2904
  serverId,
2633
2905
  serverName,
@@ -2682,7 +2954,7 @@ var SSEConnectionManager = class {
2682
2954
  client.disconnect();
2683
2955
  this.clients.delete(sessionId);
2684
2956
  } else {
2685
- await storage.removeSession(this.identity, sessionId);
2957
+ await sessions.delete(this.userId, sessionId);
2686
2958
  }
2687
2959
  return { success: true };
2688
2960
  }
@@ -2694,12 +2966,12 @@ var SSEConnectionManager = class {
2694
2966
  if (existing) {
2695
2967
  return existing;
2696
2968
  }
2697
- const session = await storage.getSession(this.identity, sessionId);
2969
+ const session = await sessions.get(this.userId, sessionId);
2698
2970
  if (!session) {
2699
2971
  throw new Error("Session not found");
2700
2972
  }
2701
2973
  const client = new MCPClient({
2702
- identity: this.identity,
2974
+ userId: this.userId,
2703
2975
  sessionId,
2704
2976
  // These fields are optional in MCPClient, but when rehydrating a known
2705
2977
  // stored session on the server we pass them explicitly to preserve the
@@ -2746,9 +3018,9 @@ var SSEConnectionManager = class {
2746
3018
  /**
2747
3019
  * Restore and validate an existing session
2748
3020
  */
2749
- async restoreSession(params) {
3021
+ async getSession(params) {
2750
3022
  const { sessionId } = params;
2751
- const session = await storage.getSession(this.identity, sessionId);
3023
+ const session = await sessions.get(this.userId, sessionId);
2752
3024
  if (!session) {
2753
3025
  throw new Error("Session not found");
2754
3026
  }
@@ -2765,7 +3037,7 @@ var SSEConnectionManager = class {
2765
3037
  try {
2766
3038
  const clientMetadata = await this.getResolvedClientMetadata();
2767
3039
  const client = new MCPClient({
2768
- identity: this.identity,
3040
+ userId: this.userId,
2769
3041
  sessionId,
2770
3042
  // These fields are optional in MCPClient, but when rehydrating a known
2771
3043
  // stored session on the server we pass them explicitly to preserve the
@@ -2802,13 +3074,13 @@ var SSEConnectionManager = class {
2802
3074
  */
2803
3075
  async finishAuth(params) {
2804
3076
  const { sessionId, code } = params;
2805
- const session = await storage.getSession(this.identity, sessionId);
3077
+ const session = await sessions.get(this.userId, sessionId);
2806
3078
  if (!session) {
2807
3079
  throw new Error("Session not found");
2808
3080
  }
2809
3081
  try {
2810
3082
  const client = new MCPClient({
2811
- identity: this.identity,
3083
+ userId: this.userId,
2812
3084
  sessionId,
2813
3085
  // These fields are optional in MCPClient, but when rehydrating a known
2814
3086
  // stored session on the server we pass them explicitly to preserve the
@@ -2819,7 +3091,7 @@ var SSEConnectionManager = class {
2819
3091
  serverUrl: session.serverUrl,
2820
3092
  callbackUrl: session.callbackUrl,
2821
3093
  // NOTE: transportType is intentionally omitted here.
2822
- // The session's stored transportType is a placeholder ('streamable_http')
3094
+ // The session's stored transportType is a placeholder ('streamable-http')
2823
3095
  // set before transport negotiation. Omitting it lets MCPClient auto-negotiate
2824
3096
  // (try streamable_http → SSE fallback), which is critical for servers like
2825
3097
  // Neon that only support SSE transport.
@@ -2942,18 +3214,21 @@ function writeSSEEvent(res, event, data) {
2942
3214
  init_cjs_shims();
2943
3215
  function createNextMcpHandler(options = {}) {
2944
3216
  const {
2945
- getIdentity = (request) => new URL(request.url).searchParams.get("identity"),
3217
+ getUserId = (request) => request.headers.get("x-mcp-user-id"),
2946
3218
  getAuthToken = (request) => {
2947
- const url = new URL(request.url);
2948
- return url.searchParams.get("token") || request.headers.get("authorization");
3219
+ const authHeader = request.headers.get("authorization");
3220
+ if (authHeader?.toLowerCase().startsWith("bearer ")) {
3221
+ return authHeader.slice(7);
3222
+ }
3223
+ return authHeader;
2949
3224
  },
2950
3225
  authenticate = () => true,
2951
3226
  heartbeatInterval = 3e4,
2952
3227
  clientDefaults,
2953
3228
  getClientMetadata
2954
3229
  } = options;
2955
- const toManagerOptions = (identity, resolvedClientMetadata) => ({
2956
- identity,
3230
+ const toManagerOptions = (userId, resolvedClientMetadata) => ({
3231
+ userId,
2957
3232
  heartbeatInterval,
2958
3233
  clientDefaults: resolvedClientMetadata
2959
3234
  });
@@ -2972,13 +3247,13 @@ function createNextMcpHandler(options = {}) {
2972
3247
  );
2973
3248
  }
2974
3249
  async function POST(request) {
2975
- const identity = getIdentity(request);
3250
+ const userId = getUserId(request);
2976
3251
  const authToken = getAuthToken(request);
2977
3252
  const acceptsEventStream = (request.headers.get("accept") || "").toLowerCase().includes("text/event-stream");
2978
- if (!identity) {
2979
- return Response.json({ error: { code: "MISSING_IDENTITY", message: "Missing identity" } }, { status: 400 });
3253
+ if (!userId) {
3254
+ return Response.json({ error: { code: "MISSING_userId", message: "Missing userId" } }, { status: 400 });
2980
3255
  }
2981
- const isAuthorized = await authenticate(identity, authToken);
3256
+ const isAuthorized = await authenticate(userId, authToken);
2982
3257
  if (!isAuthorized) {
2983
3258
  return Response.json({ error: { code: "UNAUTHORIZED", message: "Unauthorized" } }, { status: 401 });
2984
3259
  }
@@ -3000,7 +3275,7 @@ function createNextMcpHandler(options = {}) {
3000
3275
  const resolvedClientMetadata = await resolveClientMetadata(request);
3001
3276
  if (!acceptsEventStream) {
3002
3277
  const manager2 = new SSEConnectionManager(
3003
- toManagerOptions(identity, resolvedClientMetadata),
3278
+ toManagerOptions(userId, resolvedClientMetadata),
3004
3279
  () => {
3005
3280
  }
3006
3281
  );
@@ -3026,7 +3301,7 @@ data: ${JSON.stringify(data)}
3026
3301
  });
3027
3302
  };
3028
3303
  const manager = new SSEConnectionManager(
3029
- toManagerOptions(identity, resolvedClientMetadata),
3304
+ toManagerOptions(userId, resolvedClientMetadata),
3030
3305
  (event) => {
3031
3306
  if (isRpcResponseEvent(event)) {
3032
3307
  sendSSE("rpc-response", event);
@@ -3069,7 +3344,7 @@ data: ${JSON.stringify(data)}
3069
3344
  } catch (error) {
3070
3345
  const err = error instanceof Error ? error : new Error("Unknown error");
3071
3346
  console.error("[MCP Next Handler] Failed to handle RPC", {
3072
- identity,
3347
+ userId,
3073
3348
  message: err.message,
3074
3349
  stack: err.stack,
3075
3350
  rawBody: rawBody.slice(0, 500)
@@ -3096,6 +3371,6 @@ exports.UnauthorizedError = UnauthorizedError;
3096
3371
  exports.createNextMcpHandler = createNextMcpHandler;
3097
3372
  exports.createSSEHandler = createSSEHandler;
3098
3373
  exports.sanitizeServerLabel = sanitizeServerLabel;
3099
- exports.storage = storage;
3374
+ exports.sessions = sessions;
3100
3375
  //# sourceMappingURL=index.js.map
3101
3376
  //# sourceMappingURL=index.js.map