@mcp-ts/sdk 1.3.4 → 1.3.6

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 (70) hide show
  1. package/README.md +404 -400
  2. package/dist/adapters/agui-adapter.d.mts +1 -1
  3. package/dist/adapters/agui-adapter.d.ts +1 -1
  4. package/dist/adapters/agui-middleware.d.mts +1 -1
  5. package/dist/adapters/agui-middleware.d.ts +1 -1
  6. package/dist/adapters/ai-adapter.d.mts +1 -1
  7. package/dist/adapters/ai-adapter.d.ts +1 -1
  8. package/dist/adapters/langchain-adapter.d.mts +1 -1
  9. package/dist/adapters/langchain-adapter.d.ts +1 -1
  10. package/dist/adapters/mastra-adapter.d.mts +1 -1
  11. package/dist/adapters/mastra-adapter.d.ts +1 -1
  12. package/dist/bin/mcp-ts.d.mts +1 -0
  13. package/dist/bin/mcp-ts.d.ts +1 -0
  14. package/dist/bin/mcp-ts.js +105 -0
  15. package/dist/bin/mcp-ts.js.map +1 -0
  16. package/dist/bin/mcp-ts.mjs +82 -0
  17. package/dist/bin/mcp-ts.mjs.map +1 -0
  18. package/dist/client/index.d.mts +1 -0
  19. package/dist/client/index.d.ts +1 -0
  20. package/dist/client/index.js +14 -5
  21. package/dist/client/index.js.map +1 -1
  22. package/dist/client/index.mjs +14 -5
  23. package/dist/client/index.mjs.map +1 -1
  24. package/dist/client/react.js +15 -6
  25. package/dist/client/react.js.map +1 -1
  26. package/dist/client/react.mjs +15 -6
  27. package/dist/client/react.mjs.map +1 -1
  28. package/dist/client/vue.js +15 -6
  29. package/dist/client/vue.js.map +1 -1
  30. package/dist/client/vue.mjs +15 -6
  31. package/dist/client/vue.mjs.map +1 -1
  32. package/dist/index.d.mts +1 -1
  33. package/dist/index.d.ts +1 -1
  34. package/dist/index.js +480 -179
  35. package/dist/index.js.map +1 -1
  36. package/dist/index.mjs +418 -179
  37. package/dist/index.mjs.map +1 -1
  38. package/dist/{multi-session-client-FAFpUzZ4.d.ts → multi-session-client-BYLarghq.d.ts} +29 -19
  39. package/dist/{multi-session-client-DzjmT7FX.d.mts → multi-session-client-CzhMkE0k.d.mts} +29 -19
  40. package/dist/server/index.d.mts +1 -1
  41. package/dist/server/index.d.ts +1 -1
  42. package/dist/server/index.js +455 -172
  43. package/dist/server/index.js.map +1 -1
  44. package/dist/server/index.mjs +410 -172
  45. package/dist/server/index.mjs.map +1 -1
  46. package/dist/shared/index.d.mts +2 -2
  47. package/dist/shared/index.d.ts +2 -2
  48. package/dist/shared/index.js +2 -2
  49. package/dist/shared/index.js.map +1 -1
  50. package/dist/shared/index.mjs +2 -2
  51. package/dist/shared/index.mjs.map +1 -1
  52. package/package.json +19 -6
  53. package/src/bin/mcp-ts.ts +102 -0
  54. package/src/client/core/sse-client.ts +371 -354
  55. package/src/client/react/use-mcp.ts +31 -31
  56. package/src/client/vue/use-mcp.ts +77 -77
  57. package/src/server/handlers/nextjs-handler.ts +204 -207
  58. package/src/server/handlers/sse-handler.ts +14 -63
  59. package/src/server/mcp/oauth-client.ts +67 -79
  60. package/src/server/mcp/storage-oauth-provider.ts +71 -38
  61. package/src/server/storage/file-backend.ts +1 -0
  62. package/src/server/storage/index.ts +82 -38
  63. package/src/server/storage/memory-backend.ts +4 -0
  64. package/src/server/storage/redis-backend.ts +102 -23
  65. package/src/server/storage/sqlite-backend.ts +1 -0
  66. package/src/server/storage/supabase-backend.ts +227 -0
  67. package/src/server/storage/types.ts +12 -12
  68. package/src/shared/constants.ts +2 -2
  69. package/src/shared/event-routing.ts +28 -0
  70. package/supabase/migrations/20260330195700_install_mcp_sessions.sql +84 -0
package/dist/index.js CHANGED
@@ -43,6 +43,12 @@ var __export = (target, all) => {
43
43
  };
44
44
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
45
45
 
46
+ // node_modules/tsup/assets/cjs_shims.js
47
+ var init_cjs_shims = __esm({
48
+ "node_modules/tsup/assets/cjs_shims.js"() {
49
+ }
50
+ });
51
+
46
52
  // src/server/storage/redis.ts
47
53
  var redis_exports = {};
48
54
  __export(redis_exports, {
@@ -118,6 +124,7 @@ async function closeRedis() {
118
124
  var redisInstance, redis;
119
125
  var init_redis = __esm({
120
126
  "src/server/storage/redis.ts"() {
127
+ init_cjs_shims();
121
128
  redisInstance = null;
122
129
  redis = new Proxy({}, {
123
130
  get(_target, prop) {
@@ -134,7 +141,26 @@ var init_redis = __esm({
134
141
  }
135
142
  });
136
143
 
144
+ // src/index.ts
145
+ init_cjs_shims();
146
+
147
+ // src/server/index.ts
148
+ init_cjs_shims();
149
+
150
+ // src/server/mcp/oauth-client.ts
151
+ init_cjs_shims();
152
+
153
+ // src/server/mcp/storage-oauth-provider.ts
154
+ init_cjs_shims();
155
+
156
+ // src/server/storage/index.ts
157
+ init_cjs_shims();
158
+
159
+ // src/server/storage/redis-backend.ts
160
+ init_cjs_shims();
161
+
137
162
  // src/shared/constants.ts
163
+ init_cjs_shims();
138
164
  var SESSION_TTL_SECONDS = 43200;
139
165
  var STATE_EXPIRATION_MS = 10 * 60 * 1e3;
140
166
  var DEFAULT_HEARTBEAT_INTERVAL_MS = 3e4;
@@ -142,10 +168,10 @@ var REDIS_KEY_PREFIX = "mcp:session:";
142
168
  var TOKEN_EXPIRY_BUFFER_MS = 5 * 60 * 1e3;
143
169
  var DEFAULT_CLIENT_NAME = "MCP Assistant";
144
170
  var DEFAULT_CLIENT_URI = "https://mcp-assistant.in";
145
- var DEFAULT_LOGO_URI = "https://mcp-assistant.in/logo.png";
171
+ var DEFAULT_LOGO_URI = "https://mcp-assistant.in/logo.svg";
146
172
  var DEFAULT_POLICY_URI = "https://mcp-assistant.in/privacy";
147
173
  var SOFTWARE_ID = "@mcp-ts";
148
- var SOFTWARE_VERSION = "1.0.0-beta.5";
174
+ var SOFTWARE_VERSION = "1.3.4";
149
175
  var MCP_CLIENT_NAME = "mcp-ts-oauth-client";
150
176
  var MCP_CLIENT_VERSION = "2.0";
151
177
 
@@ -163,6 +189,16 @@ var RedisStorageBackend = class {
163
189
  this.redis = redis2;
164
190
  __publicField(this, "DEFAULT_TTL", SESSION_TTL_SECONDS);
165
191
  __publicField(this, "KEY_PREFIX", "mcp:session:");
192
+ __publicField(this, "IDENTITY_KEY_PREFIX", "mcp:identity:");
193
+ __publicField(this, "IDENTITY_KEY_SUFFIX", ":sessions");
194
+ }
195
+ async init() {
196
+ try {
197
+ await this.redis.ping();
198
+ console.log("[mcp-ts][Storage] Redis: \u2713 Connected to server.");
199
+ } catch (error) {
200
+ throw new Error(`[RedisStorage] Failed to connect to Redis: ${error.message}`);
201
+ }
166
202
  }
167
203
  /**
168
204
  * Generates Redis key for a specific session
@@ -176,7 +212,34 @@ var RedisStorageBackend = class {
176
212
  * @private
177
213
  */
178
214
  getIdentityKey(identity) {
179
- return `mcp:identity:${identity}:sessions`;
215
+ return `${this.IDENTITY_KEY_PREFIX}${identity}${this.IDENTITY_KEY_SUFFIX}`;
216
+ }
217
+ parseIdentityFromKey(identityKey) {
218
+ return identityKey.slice(
219
+ this.IDENTITY_KEY_PREFIX.length,
220
+ identityKey.length - this.IDENTITY_KEY_SUFFIX.length
221
+ );
222
+ }
223
+ async scanKeys(pattern) {
224
+ const redis2 = this.redis;
225
+ if (typeof redis2.scan !== "function") {
226
+ return await this.redis.keys(pattern);
227
+ }
228
+ const keys = /* @__PURE__ */ new Set();
229
+ let cursor = "0";
230
+ try {
231
+ do {
232
+ const [nextCursor, batch] = await redis2.scan(cursor, "MATCH", pattern, "COUNT", 100);
233
+ cursor = nextCursor;
234
+ for (const key of batch) {
235
+ keys.add(key);
236
+ }
237
+ } while (cursor !== "0");
238
+ } catch (error) {
239
+ console.warn("[RedisStorage] SCAN failed, falling back to KEYS:", error);
240
+ return await this.redis.keys(pattern);
241
+ }
242
+ return Array.from(keys);
180
243
  }
181
244
  generateSessionId() {
182
245
  return firstChar() + rest();
@@ -244,17 +307,13 @@ var RedisStorageBackend = class {
244
307
  }
245
308
  }
246
309
  async getIdentityMcpSessions(identity) {
247
- const identityKey = this.getIdentityKey(identity);
248
- try {
249
- return await this.redis.smembers(identityKey);
250
- } catch (error) {
251
- console.error(`[RedisStorage] Failed to get sessions for ${identity}:`, error);
252
- return [];
253
- }
310
+ const sessions = await this.getIdentitySessionsData(identity);
311
+ return sessions.map((session) => session.sessionId);
254
312
  }
255
313
  async getIdentitySessionsData(identity) {
256
314
  try {
257
- const sessionIds = await this.redis.smembers(this.getIdentityKey(identity));
315
+ const identityKey = this.getIdentityKey(identity);
316
+ const sessionIds = await this.redis.smembers(identityKey);
258
317
  if (sessionIds.length === 0) return [];
259
318
  const results = await Promise.all(
260
319
  sessionIds.map(async (sessionId) => {
@@ -262,6 +321,10 @@ var RedisStorageBackend = class {
262
321
  return data ? JSON.parse(data) : null;
263
322
  })
264
323
  );
324
+ const staleSessionIds = sessionIds.filter((_, index) => results[index] === null);
325
+ if (staleSessionIds.length > 0) {
326
+ await this.redis.srem(identityKey, ...staleSessionIds);
327
+ }
265
328
  return results.filter((session) => session !== null);
266
329
  } catch (error) {
267
330
  console.error(`[RedisStorage] Failed to get session data for ${identity}:`, error);
@@ -280,9 +343,22 @@ var RedisStorageBackend = class {
280
343
  }
281
344
  async getAllSessionIds() {
282
345
  try {
283
- const pattern = `${this.KEY_PREFIX}*`;
284
- const keys = await this.redis.keys(pattern);
285
- return keys.map((key) => key.replace(this.KEY_PREFIX, ""));
346
+ const keys = await this.scanKeys(`${this.KEY_PREFIX}*`);
347
+ const sessions = await Promise.all(
348
+ keys.map(async (key) => {
349
+ const data = await this.redis.get(key);
350
+ if (!data) {
351
+ return null;
352
+ }
353
+ try {
354
+ return JSON.parse(data).sessionId;
355
+ } catch (error) {
356
+ console.error("[RedisStorage] Failed to parse session while listing all session IDs:", error);
357
+ return null;
358
+ }
359
+ })
360
+ );
361
+ return sessions.filter((sessionId) => sessionId !== null);
286
362
  } catch (error) {
287
363
  console.error("[RedisStorage] Failed to get all sessions:", error);
288
364
  return [];
@@ -290,10 +366,11 @@ var RedisStorageBackend = class {
290
366
  }
291
367
  async clearAll() {
292
368
  try {
293
- const pattern = `${this.KEY_PREFIX}*`;
294
- const keys = await this.redis.keys(pattern);
295
- if (keys.length > 0) {
296
- await this.redis.del(...keys);
369
+ const keys = await this.scanKeys(`${this.KEY_PREFIX}*`);
370
+ const identityKeys = await this.scanKeys(`${this.IDENTITY_KEY_PREFIX}*${this.IDENTITY_KEY_SUFFIX}`);
371
+ const allKeys = [...keys, ...identityKeys];
372
+ if (allKeys.length > 0) {
373
+ await this.redis.del(...allKeys);
297
374
  }
298
375
  } catch (error) {
299
376
  console.error("[RedisStorage] Failed to clear sessions:", error);
@@ -301,12 +378,24 @@ var RedisStorageBackend = class {
301
378
  }
302
379
  async cleanupExpiredSessions() {
303
380
  try {
304
- const pattern = `${this.KEY_PREFIX}*`;
305
- const keys = await this.redis.keys(pattern);
306
- for (const key of keys) {
307
- const ttl = await this.redis.ttl(key);
308
- if (ttl <= 0) {
309
- await this.redis.del(key);
381
+ const identityKeys = await this.scanKeys(`${this.IDENTITY_KEY_PREFIX}*${this.IDENTITY_KEY_SUFFIX}`);
382
+ for (const identityKey of identityKeys) {
383
+ const identity = this.parseIdentityFromKey(identityKey);
384
+ const sessionIds = await this.redis.smembers(identityKey);
385
+ if (sessionIds.length === 0) {
386
+ await this.redis.del(identityKey);
387
+ continue;
388
+ }
389
+ const existenceChecks = await Promise.all(
390
+ sessionIds.map((sessionId) => this.redis.exists(this.getSessionKey(identity, sessionId)))
391
+ );
392
+ const staleSessionIds = sessionIds.filter((_, index) => existenceChecks[index] === 0);
393
+ if (staleSessionIds.length > 0) {
394
+ await this.redis.srem(identityKey, ...staleSessionIds);
395
+ }
396
+ const remainingCount = await this.redis.scard(identityKey);
397
+ if (remainingCount === 0) {
398
+ await this.redis.del(identityKey);
310
399
  }
311
400
  }
312
401
  } catch (error) {
@@ -321,6 +410,9 @@ var RedisStorageBackend = class {
321
410
  }
322
411
  }
323
412
  };
413
+
414
+ // src/server/storage/memory-backend.ts
415
+ init_cjs_shims();
324
416
  var firstChar2 = nanoid.customAlphabet(
325
417
  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
326
418
  1
@@ -336,6 +428,9 @@ var MemoryStorageBackend = class {
336
428
  // Map<identity, Set<sessionId>>
337
429
  __publicField(this, "identitySessions", /* @__PURE__ */ new Map());
338
430
  }
431
+ async init() {
432
+ console.log("[mcp-ts][Storage] Memory: \u2713 internal memory store active.");
433
+ }
339
434
  getSessionKey(identity, sessionId) {
340
435
  return `${identity}:${sessionId}`;
341
436
  }
@@ -411,6 +506,9 @@ var MemoryStorageBackend = class {
411
506
  async disconnect() {
412
507
  }
413
508
  };
509
+
510
+ // src/server/storage/file-backend.ts
511
+ init_cjs_shims();
414
512
  var firstChar3 = nanoid.customAlphabet(
415
513
  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
416
514
  1
@@ -455,6 +553,7 @@ var FileStorageBackend = class {
455
553
  }
456
554
  }
457
555
  this.initialized = true;
556
+ console.log(`[mcp-ts][Storage] File: \u2713 storage directory at ${path__namespace.dirname(this.filePath)} verified.`);
458
557
  }
459
558
  async ensureInitialized() {
460
559
  if (!this.initialized) await this.init();
@@ -531,6 +630,9 @@ var FileStorageBackend = class {
531
630
  async disconnect() {
532
631
  }
533
632
  };
633
+
634
+ // src/server/storage/sqlite-backend.ts
635
+ init_cjs_shims();
534
636
  var SqliteStorage = class {
535
637
  constructor(options = {}) {
536
638
  __publicField(this, "db", null);
@@ -559,6 +661,7 @@ var SqliteStorage = class {
559
661
  CREATE INDEX IF NOT EXISTS idx_${this.table}_identity ON ${this.table}(identity);
560
662
  `);
561
663
  this.initialized = true;
664
+ console.log(`[mcp-ts][Storage] SQLite: \u2713 database at ${this.dbPath} verified.`);
562
665
  } catch (error) {
563
666
  if (error.code === "MODULE_NOT_FOUND" || error.message?.includes("better-sqlite3")) {
564
667
  throw new Error(
@@ -674,9 +777,170 @@ var SqliteStorage = class {
674
777
  }
675
778
  };
676
779
 
780
+ // src/server/storage/supabase-backend.ts
781
+ init_cjs_shims();
782
+ var SupabaseStorageBackend = class {
783
+ constructor(supabase) {
784
+ this.supabase = supabase;
785
+ __publicField(this, "DEFAULT_TTL", SESSION_TTL_SECONDS);
786
+ }
787
+ async init() {
788
+ const { error } = await this.supabase.from("mcp_sessions").select("session_id").limit(0);
789
+ if (error) {
790
+ if (error.code === "42P01") {
791
+ throw new Error(
792
+ '[SupabaseStorage] Table "mcp_sessions" not found in your database. Please run "npx mcp-ts supabase-init" in your project to set up the required table and RLS policies.'
793
+ );
794
+ }
795
+ throw new Error(`[SupabaseStorage] Initialization check failed: ${error.message}`);
796
+ }
797
+ console.log('[mcp-ts][Storage] Supabase: \u2713 "mcp_sessions" table verified.');
798
+ }
799
+ generateSessionId() {
800
+ return crypto.randomUUID();
801
+ }
802
+ mapRowToSessionData(row) {
803
+ return {
804
+ sessionId: row.session_id,
805
+ serverId: row.server_id,
806
+ serverName: row.server_name,
807
+ serverUrl: row.server_url,
808
+ transportType: row.transport_type,
809
+ callbackUrl: row.callback_url,
810
+ createdAt: new Date(row.created_at).getTime(),
811
+ identity: row.identity,
812
+ headers: row.headers,
813
+ active: row.active,
814
+ clientInformation: row.client_information,
815
+ tokens: row.tokens,
816
+ codeVerifier: row.code_verifier,
817
+ clientId: row.client_id
818
+ };
819
+ }
820
+ async createSession(session, ttl) {
821
+ const { sessionId, identity } = session;
822
+ if (!sessionId || !identity) throw new Error("identity and sessionId required");
823
+ const effectiveTtl = ttl ?? this.DEFAULT_TTL;
824
+ const expiresAt = new Date(Date.now() + effectiveTtl * 1e3).toISOString();
825
+ const { error } = await this.supabase.from("mcp_sessions").insert({
826
+ session_id: sessionId,
827
+ user_id: identity,
828
+ // Maps user_id to identity to support RLS using auth.uid()
829
+ server_id: session.serverId,
830
+ server_name: session.serverName,
831
+ server_url: session.serverUrl,
832
+ transport_type: session.transportType,
833
+ callback_url: session.callbackUrl,
834
+ created_at: new Date(session.createdAt || Date.now()).toISOString(),
835
+ identity,
836
+ headers: session.headers,
837
+ active: session.active ?? false,
838
+ client_information: session.clientInformation,
839
+ tokens: session.tokens,
840
+ code_verifier: session.codeVerifier,
841
+ client_id: session.clientId,
842
+ expires_at: expiresAt
843
+ });
844
+ if (error) {
845
+ if (error.code === "23505") {
846
+ throw new Error(`Session ${sessionId} already exists`);
847
+ }
848
+ throw new Error(`Failed to create session in Supabase: ${error.message}`);
849
+ }
850
+ }
851
+ async updateSession(identity, sessionId, data, ttl) {
852
+ const effectiveTtl = ttl ?? this.DEFAULT_TTL;
853
+ const expiresAt = new Date(Date.now() + effectiveTtl * 1e3).toISOString();
854
+ const updateData = {
855
+ expires_at: expiresAt,
856
+ updated_at: (/* @__PURE__ */ new Date()).toISOString()
857
+ };
858
+ if ("serverId" in data) updateData.server_id = data.serverId;
859
+ if ("serverName" in data) updateData.server_name = data.serverName;
860
+ if ("serverUrl" in data) updateData.server_url = data.serverUrl;
861
+ if ("transportType" in data) updateData.transport_type = data.transportType;
862
+ if ("callbackUrl" in data) updateData.callback_url = data.callbackUrl;
863
+ if ("active" in data) updateData.active = data.active;
864
+ if ("headers" in data) updateData.headers = data.headers;
865
+ if ("clientInformation" in data) updateData.client_information = data.clientInformation;
866
+ if ("tokens" in data) updateData.tokens = data.tokens;
867
+ if ("codeVerifier" in data) updateData.code_verifier = data.codeVerifier;
868
+ if ("clientId" in data) updateData.client_id = data.clientId;
869
+ const { data: updatedRows, error } = await this.supabase.from("mcp_sessions").update(updateData).eq("identity", identity).eq("session_id", sessionId).select("id");
870
+ if (error) {
871
+ throw new Error(`Failed to update session: ${error.message}`);
872
+ }
873
+ if (!updatedRows || updatedRows.length === 0) {
874
+ throw new Error(`Session ${sessionId} not found for identity ${identity}`);
875
+ }
876
+ }
877
+ async getSession(identity, sessionId) {
878
+ const { data, error } = await this.supabase.from("mcp_sessions").select("*").eq("identity", identity).eq("session_id", sessionId).maybeSingle();
879
+ if (error) {
880
+ console.error("[SupabaseStorage] Failed to get session:", error);
881
+ return null;
882
+ }
883
+ if (!data) return null;
884
+ return this.mapRowToSessionData(data);
885
+ }
886
+ async getIdentitySessionsData(identity) {
887
+ const { data, error } = await this.supabase.from("mcp_sessions").select("*").eq("identity", identity);
888
+ if (error) {
889
+ console.error(`[SupabaseStorage] Failed to get session data for ${identity}:`, error);
890
+ return [];
891
+ }
892
+ return data.map((row) => this.mapRowToSessionData(row));
893
+ }
894
+ async removeSession(identity, sessionId) {
895
+ const { error } = await this.supabase.from("mcp_sessions").delete().eq("identity", identity).eq("session_id", sessionId);
896
+ if (error) {
897
+ console.error("[SupabaseStorage] Failed to remove session:", error);
898
+ }
899
+ }
900
+ async getIdentityMcpSessions(identity) {
901
+ const { data, error } = await this.supabase.from("mcp_sessions").select("session_id").eq("identity", identity);
902
+ if (error) {
903
+ console.error(`[SupabaseStorage] Failed to get sessions for ${identity}:`, error);
904
+ return [];
905
+ }
906
+ return data.map((row) => row.session_id);
907
+ }
908
+ async getAllSessionIds() {
909
+ const { data, error } = await this.supabase.from("mcp_sessions").select("session_id");
910
+ if (error) {
911
+ console.error("[SupabaseStorage] Failed to get all sessions:", error);
912
+ return [];
913
+ }
914
+ return data.map((row) => row.session_id);
915
+ }
916
+ async clearAll() {
917
+ const { error } = await this.supabase.from("mcp_sessions").delete().neq("session_id", "");
918
+ if (error) {
919
+ console.error("[SupabaseStorage] Failed to clear sessions:", error);
920
+ }
921
+ }
922
+ async cleanupExpiredSessions() {
923
+ const { error } = await this.supabase.from("mcp_sessions").delete().lt("expires_at", (/* @__PURE__ */ new Date()).toISOString());
924
+ if (error) {
925
+ console.error("[SupabaseStorage] Failed to cleanup expired sessions:", error);
926
+ }
927
+ }
928
+ async disconnect() {
929
+ }
930
+ };
931
+
932
+ // src/server/storage/types.ts
933
+ init_cjs_shims();
934
+
677
935
  // src/server/storage/index.ts
678
936
  var storageInstance = null;
679
937
  var storagePromise = null;
938
+ async function initializeStorage(store) {
939
+ if (typeof store.init === "function") {
940
+ await store.init();
941
+ }
942
+ return store;
943
+ }
680
944
  async function createStorage() {
681
945
  const type = process.env.MCP_TS_STORAGE_TYPE?.toLowerCase();
682
946
  if (type === "redis") {
@@ -686,68 +950,95 @@ async function createStorage() {
686
950
  try {
687
951
  const { getRedis: getRedis2 } = await Promise.resolve().then(() => (init_redis(), redis_exports));
688
952
  const redis2 = await getRedis2();
689
- console.log("[Storage] Using Redis storage (Explicit)");
690
- return new RedisStorageBackend(redis2);
953
+ console.log('[mcp-ts][Storage] Explicit selection: "redis"');
954
+ return await initializeStorage(new RedisStorageBackend(redis2));
691
955
  } catch (error) {
692
- console.error("[Storage] Failed to initialize Redis:", error.message);
693
- console.log("[Storage] Falling back to In-Memory storage");
694
- return new MemoryStorageBackend();
956
+ console.error("[mcp-ts][Storage] Failed to initialize Redis:", error.message);
957
+ console.log("[mcp-ts][Storage] Falling back to In-Memory storage");
958
+ return await initializeStorage(new MemoryStorageBackend());
695
959
  }
696
960
  }
697
961
  if (type === "file") {
698
962
  const filePath = process.env.MCP_TS_STORAGE_FILE;
699
- if (!filePath) {
700
- console.warn('[Storage] MCP_TS_STORAGE_TYPE is "file" but MCP_TS_STORAGE_FILE is missing');
701
- }
702
- console.log(`[Storage] Using File storage (${filePath}) (Explicit)`);
703
- const store = new FileStorageBackend({ path: filePath });
704
- store.init().catch((err) => console.error("[Storage] Failed to initialize file storage:", err));
705
- return store;
963
+ console.log(`[mcp-ts][Storage] Explicit selection: "file" (${filePath || "default"})`);
964
+ return await initializeStorage(new FileStorageBackend({ path: filePath }));
706
965
  }
707
966
  if (type === "sqlite") {
708
967
  const dbPath = process.env.MCP_TS_STORAGE_SQLITE_PATH;
709
- console.log(`[Storage] Using SQLite storage (${dbPath || "default"}) (Explicit)`);
710
- const store = new SqliteStorage({ path: dbPath });
711
- store.init().catch((err) => console.error("[Storage] Failed to initialize SQLite storage:", err));
712
- return store;
968
+ console.log(`[mcp-ts][Storage] Explicit selection: "sqlite" (${dbPath || "default"})`);
969
+ return await initializeStorage(new SqliteStorage({ path: dbPath }));
970
+ }
971
+ if (type === "supabase") {
972
+ const url = process.env.SUPABASE_URL;
973
+ const key = process.env.SUPABASE_SERVICE_ROLE_KEY || process.env.SUPABASE_ANON_KEY;
974
+ if (!url || !key) {
975
+ console.warn('[mcp-ts][Storage] Explicit selection "supabase" requires SUPABASE_URL and SUPABASE_SERVICE_ROLE_KEY.');
976
+ } else {
977
+ if (!process.env.SUPABASE_SERVICE_ROLE_KEY) {
978
+ console.warn('[mcp-ts][Storage] \u26A0\uFE0F Warning: Using "SUPABASE_ANON_KEY" for server-side storage. You may encounter RLS policy violations. "SUPABASE_SERVICE_ROLE_KEY" is recommended.');
979
+ }
980
+ try {
981
+ const { createClient } = await import('@supabase/supabase-js');
982
+ const client = createClient(url, key);
983
+ console.log('[mcp-ts][Storage] Explicit selection: "supabase"');
984
+ return await initializeStorage(new SupabaseStorageBackend(client));
985
+ } catch (error) {
986
+ console.error("[mcp-ts][Storage] Failed to initialize Supabase:", error.message);
987
+ console.log("[mcp-ts][Storage] Falling back to In-Memory storage");
988
+ return await initializeStorage(new MemoryStorageBackend());
989
+ }
990
+ }
713
991
  }
714
992
  if (type === "memory") {
715
- console.log("[Storage] Using In-Memory storage (Explicit)");
716
- return new MemoryStorageBackend();
993
+ console.log('[mcp-ts][Storage] Explicit selection: "memory"');
994
+ return await initializeStorage(new MemoryStorageBackend());
717
995
  }
718
996
  if (process.env.REDIS_URL) {
719
997
  try {
720
998
  const { getRedis: getRedis2 } = await Promise.resolve().then(() => (init_redis(), redis_exports));
721
999
  const redis2 = await getRedis2();
722
- console.log("[Storage] Auto-detected REDIS_URL. Using Redis storage.");
723
- return new RedisStorageBackend(redis2);
1000
+ console.log('[mcp-ts][Storage] Auto-detection: "redis" (via REDIS_URL)');
1001
+ return await initializeStorage(new RedisStorageBackend(redis2));
724
1002
  } catch (error) {
725
- console.error("[Storage] Redis auto-detection failed:", error.message);
726
- console.log("[Storage] Falling back to In-Memory storage");
727
- return new MemoryStorageBackend();
1003
+ console.error("[mcp-ts][Storage] Redis auto-detection failed:", error.message);
1004
+ console.log("[mcp-ts][Storage] Falling back to next available backend");
728
1005
  }
729
1006
  }
730
1007
  if (process.env.MCP_TS_STORAGE_FILE) {
731
- console.log(`[Storage] Auto-detected MCP_TS_STORAGE_FILE. Using File storage (${process.env.MCP_TS_STORAGE_FILE}).`);
732
- const store = new FileStorageBackend({ path: process.env.MCP_TS_STORAGE_FILE });
733
- store.init().catch((err) => console.error("[Storage] Failed to initialize file storage:", err));
734
- return store;
1008
+ console.log(`[mcp-ts][Storage] Auto-detection: "file" (${process.env.MCP_TS_STORAGE_FILE})`);
1009
+ return await initializeStorage(new FileStorageBackend({ path: process.env.MCP_TS_STORAGE_FILE }));
735
1010
  }
736
1011
  if (process.env.MCP_TS_STORAGE_SQLITE_PATH) {
737
- console.log(`[Storage] Auto-detected MCP_TS_STORAGE_SQLITE_PATH. Using SQLite storage (${process.env.MCP_TS_STORAGE_SQLITE_PATH}).`);
738
- const store = new SqliteStorage({ path: process.env.MCP_TS_STORAGE_SQLITE_PATH });
739
- store.init().catch((err) => console.error("[Storage] Failed to initialize SQLite storage:", err));
740
- return store;
1012
+ console.log(`[mcp-ts][Storage] Auto-detection: "sqlite" (${process.env.MCP_TS_STORAGE_SQLITE_PATH})`);
1013
+ return await initializeStorage(new SqliteStorage({ path: process.env.MCP_TS_STORAGE_SQLITE_PATH }));
1014
+ }
1015
+ if (process.env.SUPABASE_URL && (process.env.SUPABASE_SERVICE_ROLE_KEY || process.env.SUPABASE_ANON_KEY)) {
1016
+ try {
1017
+ const { createClient } = await import('@supabase/supabase-js');
1018
+ const url = process.env.SUPABASE_URL;
1019
+ const key = process.env.SUPABASE_SERVICE_ROLE_KEY || process.env.SUPABASE_ANON_KEY;
1020
+ if (!process.env.SUPABASE_SERVICE_ROLE_KEY) {
1021
+ console.warn('[mcp-ts][Storage] \u26A0\uFE0F Warning: Using "SUPABASE_ANON_KEY" for server-side storage. You may encounter RLS policy violations. "SUPABASE_SERVICE_ROLE_KEY" is recommended.');
1022
+ }
1023
+ const client = createClient(url, key);
1024
+ console.log('[mcp-ts][Storage] Auto-detection: "supabase" (via SUPABASE_URL)');
1025
+ return await initializeStorage(new SupabaseStorageBackend(client));
1026
+ } catch (error) {
1027
+ console.error("[mcp-ts][Storage] Supabase auto-detection failed:", error.message);
1028
+ }
741
1029
  }
742
- console.log("[Storage] No storage configured. Using In-Memory storage (Default).");
743
- return new MemoryStorageBackend();
1030
+ console.log('[mcp-ts][Storage] Defaulting to: "memory"');
1031
+ return await initializeStorage(new MemoryStorageBackend());
744
1032
  }
745
1033
  async function getStorage() {
746
1034
  if (storageInstance) {
747
1035
  return storageInstance;
748
1036
  }
749
1037
  if (!storagePromise) {
750
- storagePromise = createStorage();
1038
+ storagePromise = createStorage().catch((error) => {
1039
+ storagePromise = null;
1040
+ throw error;
1041
+ });
751
1042
  }
752
1043
  storageInstance = await storagePromise;
753
1044
  return storageInstance;
@@ -768,43 +1059,49 @@ var storage = new Proxy({}, {
768
1059
  // src/server/mcp/storage-oauth-provider.ts
769
1060
  var StorageOAuthClientProvider = class {
770
1061
  /**
771
- * Creates a new Storage-backed OAuth provider
772
- * @param identity - User/Client identifier
773
- * @param serverId - Server identifier (for tracking which server this OAuth session belongs to)
774
- * @param sessionId - Session identifier (used as OAuth state)
775
- * @param clientName - OAuth client name
776
- * @param baseRedirectUrl - OAuth callback URL
777
- * @param onRedirect - Optional callback when redirect to authorization is needed
1062
+ * Creates a new storage-backed OAuth provider
1063
+ * @param options - Provider configuration
778
1064
  */
779
- constructor(identity, serverId, sessionId, clientName, baseRedirectUrl, onRedirect) {
780
- this.identity = identity;
781
- this.serverId = serverId;
782
- this.sessionId = sessionId;
783
- this.clientName = clientName;
784
- this.baseRedirectUrl = baseRedirectUrl;
1065
+ constructor(options) {
1066
+ __publicField(this, "identity");
1067
+ __publicField(this, "serverId");
1068
+ __publicField(this, "sessionId");
1069
+ __publicField(this, "redirectUrl");
1070
+ __publicField(this, "clientName");
1071
+ __publicField(this, "clientUri");
1072
+ __publicField(this, "logoUri");
1073
+ __publicField(this, "policyUri");
1074
+ __publicField(this, "clientSecret");
785
1075
  __publicField(this, "_authUrl");
786
1076
  __publicField(this, "_clientId");
787
1077
  __publicField(this, "onRedirectCallback");
788
1078
  __publicField(this, "tokenExpiresAt");
789
- this.onRedirectCallback = onRedirect;
1079
+ this.identity = options.identity;
1080
+ this.serverId = options.serverId;
1081
+ this.sessionId = options.sessionId;
1082
+ this.redirectUrl = options.redirectUrl;
1083
+ this.clientName = options.clientName;
1084
+ this.clientUri = options.clientUri;
1085
+ this.logoUri = options.logoUri;
1086
+ this.policyUri = options.policyUri;
1087
+ this._clientId = options.clientId;
1088
+ this.clientSecret = options.clientSecret;
1089
+ this.onRedirectCallback = options.onRedirect;
790
1090
  }
791
1091
  get clientMetadata() {
792
1092
  return {
793
- client_name: this.clientName,
794
- client_uri: this.clientUri,
1093
+ client_name: this.clientName || DEFAULT_CLIENT_NAME,
1094
+ client_uri: this.clientUri || DEFAULT_CLIENT_URI,
1095
+ logo_uri: this.logoUri || DEFAULT_LOGO_URI,
1096
+ policy_uri: this.policyUri || DEFAULT_POLICY_URI,
795
1097
  grant_types: ["authorization_code", "refresh_token"],
796
1098
  redirect_uris: [this.redirectUrl],
797
1099
  response_types: ["code"],
798
- token_endpoint_auth_method: "none",
799
- ...this._clientId ? { client_id: this._clientId } : {}
1100
+ token_endpoint_auth_method: this.clientSecret ? "client_secret_basic" : "none",
1101
+ software_id: SOFTWARE_ID,
1102
+ software_version: SOFTWARE_VERSION
800
1103
  };
801
1104
  }
802
- get clientUri() {
803
- return new URL(this.redirectUrl).origin;
804
- }
805
- get redirectUrl() {
806
- return this.baseRedirectUrl;
807
- }
808
1105
  get clientId() {
809
1106
  return this._clientId;
810
1107
  }
@@ -839,7 +1136,16 @@ var StorageOAuthClientProvider = class {
839
1136
  if (data.clientId && !this._clientId) {
840
1137
  this._clientId = data.clientId;
841
1138
  }
842
- return data.clientInformation;
1139
+ if (data.clientInformation) {
1140
+ return data.clientInformation;
1141
+ }
1142
+ if (!this._clientId) {
1143
+ return void 0;
1144
+ }
1145
+ return {
1146
+ client_id: this._clientId,
1147
+ ...this.clientSecret ? { client_secret: this.clientSecret } : {}
1148
+ };
843
1149
  }
844
1150
  /**
845
1151
  * Stores OAuth client information
@@ -867,14 +1173,14 @@ var StorageOAuthClientProvider = class {
867
1173
  async state() {
868
1174
  return this.sessionId;
869
1175
  }
870
- async checkState(state) {
1176
+ async checkState(_state) {
871
1177
  const data = await storage.getSession(this.identity, this.sessionId);
872
1178
  if (!data) {
873
1179
  return { valid: false, error: "Session not found" };
874
1180
  }
875
1181
  return { valid: true, serverId: this.serverId };
876
1182
  }
877
- async consumeState(state) {
1183
+ async consumeState(_state) {
878
1184
  }
879
1185
  async redirectToAuthorization(authUrl) {
880
1186
  this._authUrl = authUrl.toString();
@@ -886,7 +1192,6 @@ var StorageOAuthClientProvider = class {
886
1192
  if (scope === "all") {
887
1193
  await storage.removeSession(this.identity, this.sessionId);
888
1194
  } else {
889
- await this.getSessionData();
890
1195
  const updates = {};
891
1196
  if (scope === "client") {
892
1197
  updates.clientInformation = void 0;
@@ -934,6 +1239,7 @@ var StorageOAuthClientProvider = class {
934
1239
  };
935
1240
 
936
1241
  // src/shared/utils.ts
1242
+ init_cjs_shims();
937
1243
  function sanitizeServerLabel(name) {
938
1244
  let sanitized = name.replace(/[^a-zA-Z0-9-_]/g, "_").replace(/_{2,}/g, "_").toLowerCase();
939
1245
  if (!/^[a-zA-Z]/.test(sanitized)) {
@@ -943,6 +1249,7 @@ function sanitizeServerLabel(name) {
943
1249
  }
944
1250
 
945
1251
  // src/shared/events.ts
1252
+ init_cjs_shims();
946
1253
  var Emitter = class {
947
1254
  constructor() {
948
1255
  __publicField(this, "listeners", /* @__PURE__ */ new Set());
@@ -1004,6 +1311,7 @@ var DisposableStore = class {
1004
1311
  };
1005
1312
 
1006
1313
  // src/shared/errors.ts
1314
+ init_cjs_shims();
1007
1315
  var McpError = class extends Error {
1008
1316
  constructor(code, message, cause) {
1009
1317
  super(message);
@@ -1274,41 +1582,33 @@ var MCPClient = class _MCPClient {
1274
1582
  if (!this.serverUrl || !this.callbackUrl || !this.serverId) {
1275
1583
  throw new Error("Missing required connection metadata");
1276
1584
  }
1277
- const clientMetadata = {
1278
- client_name: this.clientName || "MCP Assistant",
1279
- redirect_uris: [this.callbackUrl],
1280
- token_endpoint_auth_method: this.clientSecret ? "client_secret_basic" : "none",
1281
- client_uri: this.clientUri || "https://mcp-assistant.in",
1282
- logo_uri: this.logoUri || "https://mcp-assistant.in/logo.png",
1283
- policy_uri: this.policyUri || "https://mcp-assistant.in/privacy",
1284
- ...this.clientId ? { client_id: this.clientId } : {},
1285
- ...this.clientSecret ? { client_secret: this.clientSecret } : {}
1286
- };
1287
1585
  if (!this.oauthProvider) {
1288
1586
  if (!this.serverId) {
1289
1587
  throw new Error("serverId required for OAuth provider initialization");
1290
1588
  }
1291
- this.oauthProvider = new StorageOAuthClientProvider(
1292
- this.identity,
1293
- this.serverId,
1294
- this.sessionId,
1295
- clientMetadata.client_name ?? "MCP Assistant",
1296
- this.callbackUrl,
1297
- (redirectUrl) => {
1589
+ this.oauthProvider = new StorageOAuthClientProvider({
1590
+ identity: this.identity,
1591
+ serverId: this.serverId,
1592
+ sessionId: this.sessionId,
1593
+ redirectUrl: this.callbackUrl,
1594
+ clientName: this.clientName,
1595
+ clientUri: this.clientUri,
1596
+ logoUri: this.logoUri,
1597
+ policyUri: this.policyUri,
1598
+ clientId: this.clientId,
1599
+ clientSecret: this.clientSecret,
1600
+ onRedirect: (redirectUrl) => {
1298
1601
  if (this.onRedirect) {
1299
1602
  this.onRedirect(redirectUrl);
1300
1603
  }
1301
1604
  }
1302
- );
1303
- if (this.clientId && this.oauthProvider) {
1304
- this.oauthProvider.clientId = this.clientId;
1305
- }
1605
+ });
1306
1606
  }
1307
1607
  if (!this.client) {
1308
1608
  this.client = new index_js.Client(
1309
1609
  {
1310
- name: "mcp-ts-oauth-client",
1311
- version: "2.0"
1610
+ name: MCP_CLIENT_NAME,
1611
+ version: MCP_CLIENT_VERSION
1312
1612
  },
1313
1613
  {
1314
1614
  capabilities: {
@@ -1503,8 +1803,8 @@ var MCPClient = class _MCPClient {
1503
1803
  this.emitProgress("Creating authenticated client...");
1504
1804
  this.client = new index_js.Client(
1505
1805
  {
1506
- name: "mcp-ts-oauth-client",
1507
- version: "2.0"
1806
+ name: MCP_CLIENT_NAME,
1807
+ version: MCP_CLIENT_VERSION
1508
1808
  },
1509
1809
  {
1510
1810
  capabilities: {
@@ -1799,8 +2099,8 @@ var MCPClient = class _MCPClient {
1799
2099
  }
1800
2100
  this.client = new index_js.Client(
1801
2101
  {
1802
- name: "mcp-ts-oauth-client",
1803
- version: "2.0"
2102
+ name: MCP_CLIENT_NAME,
2103
+ version: MCP_CLIENT_VERSION
1804
2104
  },
1805
2105
  { capabilities: {} }
1806
2106
  );
@@ -1980,6 +2280,7 @@ var MCPClient = class _MCPClient {
1980
2280
  };
1981
2281
 
1982
2282
  // src/server/mcp/multi-session-client.ts
2283
+ init_cjs_shims();
1983
2284
  var MultiSessionClient = class {
1984
2285
  constructor(identity, options = {}) {
1985
2286
  __publicField(this, "clients", []);
@@ -2069,6 +2370,31 @@ var MultiSessionClient = class {
2069
2370
  }
2070
2371
  };
2071
2372
 
2373
+ // src/server/handlers/sse-handler.ts
2374
+ init_cjs_shims();
2375
+
2376
+ // src/shared/event-routing.ts
2377
+ init_cjs_shims();
2378
+ function isRpcResponseEvent(event) {
2379
+ return "id" in event && ("result" in event || "error" in event);
2380
+ }
2381
+ function isConnectionEvent(event) {
2382
+ if (!("type" in event)) {
2383
+ return false;
2384
+ }
2385
+ switch (event.type) {
2386
+ case "state_changed":
2387
+ case "tools_discovered":
2388
+ case "auth_required":
2389
+ case "error":
2390
+ case "disconnected":
2391
+ case "progress":
2392
+ return true;
2393
+ default:
2394
+ return false;
2395
+ }
2396
+ }
2397
+
2072
2398
  // src/server/handlers/sse-handler.ts
2073
2399
  var DEFAULT_HEARTBEAT_INTERVAL = 3e4;
2074
2400
  var SSEConnectionManager = class {
@@ -2211,16 +2537,6 @@ var SSEConnectionManager = class {
2211
2537
  throw new Error(`Connection already exists for server: ${duplicate.serverUrl || duplicate.serverId} (${duplicate.serverName})`);
2212
2538
  }
2213
2539
  const sessionId = await storage.generateSessionId();
2214
- this.emitConnectionEvent({
2215
- type: "state_changed",
2216
- sessionId,
2217
- serverId,
2218
- serverName,
2219
- serverUrl,
2220
- state: "CONNECTING",
2221
- previousState: "DISCONNECTED",
2222
- timestamp: Date.now()
2223
- });
2224
2540
  try {
2225
2541
  const clientMetadata = await this.getResolvedClientMetadata();
2226
2542
  const client = new MCPClient({
@@ -2231,17 +2547,8 @@ var SSEConnectionManager = class {
2231
2547
  serverUrl,
2232
2548
  callbackUrl,
2233
2549
  transportType,
2234
- ...clientMetadata,
2550
+ ...clientMetadata
2235
2551
  // Spread client metadata (clientName, clientUri, logoUri, policyUri)
2236
- onRedirect: (authUrl) => {
2237
- this.emitConnectionEvent({
2238
- type: "auth_required",
2239
- sessionId,
2240
- serverId,
2241
- authUrl,
2242
- timestamp: Date.now()
2243
- });
2244
- }
2245
2552
  });
2246
2553
  this.clients.set(sessionId, client);
2247
2554
  client.onConnectionEvent((event) => {
@@ -2251,20 +2558,19 @@ var SSEConnectionManager = class {
2251
2558
  this.sendEvent(event);
2252
2559
  });
2253
2560
  await client.connect();
2254
- const tools = await client.listTools();
2255
- this.emitConnectionEvent({
2256
- type: "tools_discovered",
2257
- sessionId,
2258
- serverId,
2259
- toolCount: tools.tools.length,
2260
- tools: tools.tools,
2261
- timestamp: Date.now()
2262
- });
2561
+ await client.listTools();
2263
2562
  return {
2264
2563
  sessionId,
2265
2564
  success: true
2266
2565
  };
2267
2566
  } catch (error) {
2567
+ if (error instanceof UnauthorizedError) {
2568
+ this.clients.delete(sessionId);
2569
+ return {
2570
+ sessionId,
2571
+ success: true
2572
+ };
2573
+ }
2268
2574
  this.emitConnectionEvent({
2269
2575
  type: "error",
2270
2576
  sessionId,
@@ -2366,14 +2672,6 @@ var SSEConnectionManager = class {
2366
2672
  await client.connect();
2367
2673
  this.clients.set(sessionId, client);
2368
2674
  const tools = await client.listTools();
2369
- this.emitConnectionEvent({
2370
- type: "tools_discovered",
2371
- sessionId,
2372
- serverId: session.serverId ?? "unknown",
2373
- toolCount: tools.tools.length,
2374
- tools: tools.tools,
2375
- timestamp: Date.now()
2376
- });
2377
2675
  return { success: true, toolCount: tools.tools.length };
2378
2676
  } catch (error) {
2379
2677
  this.emitConnectionEvent({
@@ -2396,16 +2694,6 @@ var SSEConnectionManager = class {
2396
2694
  if (!session) {
2397
2695
  throw new Error("Session not found");
2398
2696
  }
2399
- this.emitConnectionEvent({
2400
- type: "state_changed",
2401
- sessionId,
2402
- serverId: session.serverId ?? "unknown",
2403
- serverName: session.serverName ?? "Unknown",
2404
- serverUrl: session.serverUrl,
2405
- state: "AUTHENTICATING",
2406
- previousState: "DISCONNECTED",
2407
- timestamp: Date.now()
2408
- });
2409
2697
  try {
2410
2698
  const client = new MCPClient({
2411
2699
  identity: this.identity,
@@ -2415,14 +2703,6 @@ var SSEConnectionManager = class {
2415
2703
  await client.finishAuth(code);
2416
2704
  this.clients.set(sessionId, client);
2417
2705
  const tools = await client.listTools();
2418
- this.emitConnectionEvent({
2419
- type: "tools_discovered",
2420
- sessionId,
2421
- serverId: session.serverId ?? "unknown",
2422
- toolCount: tools.tools.length,
2423
- tools: tools.tools,
2424
- timestamp: Date.now()
2425
- });
2426
2706
  return { success: true, toolCount: tools.tools.length };
2427
2707
  } catch (error) {
2428
2708
  this.emitConnectionEvent({
@@ -2500,9 +2780,9 @@ function createSSEHandler(options) {
2500
2780
  });
2501
2781
  writeSSEEvent(res, "connected", { timestamp: Date.now() });
2502
2782
  const manager = new SSEConnectionManager(options, (event) => {
2503
- if ("id" in event) {
2783
+ if (isRpcResponseEvent(event)) {
2504
2784
  writeSSEEvent(res, "rpc-response", event);
2505
- } else if ("type" in event && "sessionId" in event) {
2785
+ } else if (isConnectionEvent(event)) {
2506
2786
  writeSSEEvent(res, "connection", event);
2507
2787
  } else {
2508
2788
  writeSSEEvent(res, "observability", event);
@@ -2533,9 +2813,7 @@ function writeSSEEvent(res, event, data) {
2533
2813
  }
2534
2814
 
2535
2815
  // src/server/handlers/nextjs-handler.ts
2536
- function isRpcResponseEvent(event) {
2537
- return "id" in event && ("result" in event || "error" in event);
2538
- }
2816
+ init_cjs_shims();
2539
2817
  function createNextMcpHandler(options = {}) {
2540
2818
  const {
2541
2819
  getIdentity = (request) => new URL(request.url).searchParams.get("identity"),
@@ -2626,7 +2904,7 @@ data: ${JSON.stringify(data)}
2626
2904
  (event) => {
2627
2905
  if (isRpcResponseEvent(event)) {
2628
2906
  sendSSE("rpc-response", event);
2629
- } else if ("type" in event && "sessionId" in event) {
2907
+ } else if (isConnectionEvent(event)) {
2630
2908
  sendSSE("connection", event);
2631
2909
  } else {
2632
2910
  sendSSE("observability", event);
@@ -2683,6 +2961,13 @@ data: ${JSON.stringify(data)}
2683
2961
  }
2684
2962
  return { GET, POST };
2685
2963
  }
2964
+
2965
+ // src/client/index.ts
2966
+ init_cjs_shims();
2967
+
2968
+ // src/client/core/sse-client.ts
2969
+ init_cjs_shims();
2970
+ var CONNECTION_EVENT_INTERVAL_MS = 300;
2686
2971
  var SSEClient = class {
2687
2972
  constructor(options) {
2688
2973
  this.options = options;
@@ -2787,10 +3072,12 @@ var SSEClient = class {
2787
3072
  const data2 = await response.json();
2788
3073
  return this.parseRpcResponse(data2);
2789
3074
  }
2790
- const data = await this.readRpcResponseFromStream(response);
3075
+ const data = await this.readRpcResponseFromStream(response, {
3076
+ delayConnectionEvents: method === "connect" || method === "restoreSession" || method === "finishAuth"
3077
+ });
2791
3078
  return this.parseRpcResponse(data);
2792
3079
  }
2793
- async readRpcResponseFromStream(response) {
3080
+ async readRpcResponseFromStream(response, options = {}) {
2794
3081
  if (!response.body) {
2795
3082
  throw new Error("Streaming response body is missing");
2796
3083
  }
@@ -2798,7 +3085,7 @@ var SSEClient = class {
2798
3085
  const decoder = new TextDecoder();
2799
3086
  let buffer = "";
2800
3087
  let rpcResponse = null;
2801
- const dispatchBlock = (block) => {
3088
+ const dispatchBlock = async (block) => {
2802
3089
  const lines = block.split("\n");
2803
3090
  let eventName = "message";
2804
3091
  const dataLines = [];
@@ -2826,6 +3113,9 @@ var SSEClient = class {
2826
3113
  break;
2827
3114
  case "connection":
2828
3115
  this.options.onConnectionEvent?.(payload);
3116
+ if (options.delayConnectionEvents) {
3117
+ await this.sleep(CONNECTION_EVENT_INTERVAL_MS);
3118
+ }
2829
3119
  break;
2830
3120
  case "observability":
2831
3121
  this.options.onObservabilityEvent?.(payload);
@@ -2845,18 +3135,21 @@ var SSEClient = class {
2845
3135
  const separatorLength = separatorMatch[0].length;
2846
3136
  const block = buffer.slice(0, separatorIndex);
2847
3137
  buffer = buffer.slice(separatorIndex + separatorLength);
2848
- dispatchBlock(block);
3138
+ await dispatchBlock(block);
2849
3139
  separatorMatch = buffer.match(/\r?\n\r?\n/);
2850
3140
  }
2851
3141
  }
2852
3142
  if (buffer.trim()) {
2853
- dispatchBlock(buffer);
3143
+ await dispatchBlock(buffer);
2854
3144
  }
2855
3145
  if (!rpcResponse) {
2856
3146
  throw new Error("Missing rpc-response event in streamed RPC result");
2857
3147
  }
2858
3148
  return rpcResponse;
2859
3149
  }
3150
+ sleep(ms) {
3151
+ return new Promise((resolve) => setTimeout(resolve, ms));
3152
+ }
2860
3153
  parseRpcResponse(data) {
2861
3154
  if ("result" in data) {
2862
3155
  return data.result;
@@ -2922,6 +3215,9 @@ var SSEClient = class {
2922
3215
  }
2923
3216
  }
2924
3217
  };
3218
+
3219
+ // src/client/core/app-host.ts
3220
+ init_cjs_shims();
2925
3221
  var HOST_INFO = { name: "mcp-ts-host", version: "1.0.0" };
2926
3222
  var SANDBOX_PERMISSIONS = [
2927
3223
  "allow-scripts",
@@ -3219,7 +3515,11 @@ var AppHost = class {
3219
3515
  }
3220
3516
  };
3221
3517
 
3518
+ // src/shared/index.ts
3519
+ init_cjs_shims();
3520
+
3222
3521
  // src/shared/types.ts
3522
+ init_cjs_shims();
3223
3523
  function isConnectSuccess(response) {
3224
3524
  return "success" in response && response.success === true;
3225
3525
  }
@@ -3237,6 +3537,7 @@ function isCallToolSuccess(response) {
3237
3537
  }
3238
3538
 
3239
3539
  // src/shared/tool-utils.ts
3540
+ init_cjs_shims();
3240
3541
  function getToolUiResourceUri(tool) {
3241
3542
  const meta = tool._meta;
3242
3543
  if (!meta?.ui) return void 0;