@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
@@ -42,6 +42,12 @@ var __export = (target, all) => {
42
42
  };
43
43
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
44
44
 
45
+ // node_modules/tsup/assets/cjs_shims.js
46
+ var init_cjs_shims = __esm({
47
+ "node_modules/tsup/assets/cjs_shims.js"() {
48
+ }
49
+ });
50
+
45
51
  // src/server/storage/redis.ts
46
52
  var redis_exports = {};
47
53
  __export(redis_exports, {
@@ -117,6 +123,7 @@ async function closeRedis() {
117
123
  var redisInstance, redis;
118
124
  var init_redis = __esm({
119
125
  "src/server/storage/redis.ts"() {
126
+ init_cjs_shims();
120
127
  redisInstance = null;
121
128
  redis = new Proxy({}, {
122
129
  get(_target, prop) {
@@ -133,10 +140,34 @@ var init_redis = __esm({
133
140
  }
134
141
  });
135
142
 
143
+ // src/server/index.ts
144
+ init_cjs_shims();
145
+
146
+ // src/server/mcp/oauth-client.ts
147
+ init_cjs_shims();
148
+
149
+ // src/server/mcp/storage-oauth-provider.ts
150
+ init_cjs_shims();
151
+
152
+ // src/server/storage/index.ts
153
+ init_cjs_shims();
154
+
155
+ // src/server/storage/redis-backend.ts
156
+ init_cjs_shims();
157
+
136
158
  // src/shared/constants.ts
159
+ init_cjs_shims();
137
160
  var SESSION_TTL_SECONDS = 43200;
138
161
  var STATE_EXPIRATION_MS = 10 * 60 * 1e3;
139
162
  var TOKEN_EXPIRY_BUFFER_MS = 5 * 60 * 1e3;
163
+ var DEFAULT_CLIENT_NAME = "MCP Assistant";
164
+ var DEFAULT_CLIENT_URI = "https://mcp-assistant.in";
165
+ var DEFAULT_LOGO_URI = "https://mcp-assistant.in/logo.svg";
166
+ var DEFAULT_POLICY_URI = "https://mcp-assistant.in/privacy";
167
+ var SOFTWARE_ID = "@mcp-ts";
168
+ var SOFTWARE_VERSION = "1.3.4";
169
+ var MCP_CLIENT_NAME = "mcp-ts-oauth-client";
170
+ var MCP_CLIENT_VERSION = "2.0";
140
171
 
141
172
  // src/server/storage/redis-backend.ts
142
173
  var firstChar = nanoid.customAlphabet(
@@ -152,6 +183,16 @@ var RedisStorageBackend = class {
152
183
  this.redis = redis2;
153
184
  __publicField(this, "DEFAULT_TTL", SESSION_TTL_SECONDS);
154
185
  __publicField(this, "KEY_PREFIX", "mcp:session:");
186
+ __publicField(this, "IDENTITY_KEY_PREFIX", "mcp:identity:");
187
+ __publicField(this, "IDENTITY_KEY_SUFFIX", ":sessions");
188
+ }
189
+ async init() {
190
+ try {
191
+ await this.redis.ping();
192
+ console.log("[mcp-ts][Storage] Redis: \u2713 Connected to server.");
193
+ } catch (error) {
194
+ throw new Error(`[RedisStorage] Failed to connect to Redis: ${error.message}`);
195
+ }
155
196
  }
156
197
  /**
157
198
  * Generates Redis key for a specific session
@@ -165,7 +206,34 @@ var RedisStorageBackend = class {
165
206
  * @private
166
207
  */
167
208
  getIdentityKey(identity) {
168
- return `mcp:identity:${identity}:sessions`;
209
+ return `${this.IDENTITY_KEY_PREFIX}${identity}${this.IDENTITY_KEY_SUFFIX}`;
210
+ }
211
+ parseIdentityFromKey(identityKey) {
212
+ return identityKey.slice(
213
+ this.IDENTITY_KEY_PREFIX.length,
214
+ identityKey.length - this.IDENTITY_KEY_SUFFIX.length
215
+ );
216
+ }
217
+ async scanKeys(pattern) {
218
+ const redis2 = this.redis;
219
+ if (typeof redis2.scan !== "function") {
220
+ return await this.redis.keys(pattern);
221
+ }
222
+ const keys = /* @__PURE__ */ new Set();
223
+ let cursor = "0";
224
+ try {
225
+ do {
226
+ const [nextCursor, batch] = await redis2.scan(cursor, "MATCH", pattern, "COUNT", 100);
227
+ cursor = nextCursor;
228
+ for (const key of batch) {
229
+ keys.add(key);
230
+ }
231
+ } while (cursor !== "0");
232
+ } catch (error) {
233
+ console.warn("[RedisStorage] SCAN failed, falling back to KEYS:", error);
234
+ return await this.redis.keys(pattern);
235
+ }
236
+ return Array.from(keys);
169
237
  }
170
238
  generateSessionId() {
171
239
  return firstChar() + rest();
@@ -233,17 +301,13 @@ var RedisStorageBackend = class {
233
301
  }
234
302
  }
235
303
  async getIdentityMcpSessions(identity) {
236
- const identityKey = this.getIdentityKey(identity);
237
- try {
238
- return await this.redis.smembers(identityKey);
239
- } catch (error) {
240
- console.error(`[RedisStorage] Failed to get sessions for ${identity}:`, error);
241
- return [];
242
- }
304
+ const sessions = await this.getIdentitySessionsData(identity);
305
+ return sessions.map((session) => session.sessionId);
243
306
  }
244
307
  async getIdentitySessionsData(identity) {
245
308
  try {
246
- const sessionIds = await this.redis.smembers(this.getIdentityKey(identity));
309
+ const identityKey = this.getIdentityKey(identity);
310
+ const sessionIds = await this.redis.smembers(identityKey);
247
311
  if (sessionIds.length === 0) return [];
248
312
  const results = await Promise.all(
249
313
  sessionIds.map(async (sessionId) => {
@@ -251,6 +315,10 @@ var RedisStorageBackend = class {
251
315
  return data ? JSON.parse(data) : null;
252
316
  })
253
317
  );
318
+ const staleSessionIds = sessionIds.filter((_, index) => results[index] === null);
319
+ if (staleSessionIds.length > 0) {
320
+ await this.redis.srem(identityKey, ...staleSessionIds);
321
+ }
254
322
  return results.filter((session) => session !== null);
255
323
  } catch (error) {
256
324
  console.error(`[RedisStorage] Failed to get session data for ${identity}:`, error);
@@ -269,9 +337,22 @@ var RedisStorageBackend = class {
269
337
  }
270
338
  async getAllSessionIds() {
271
339
  try {
272
- const pattern = `${this.KEY_PREFIX}*`;
273
- const keys = await this.redis.keys(pattern);
274
- return keys.map((key) => key.replace(this.KEY_PREFIX, ""));
340
+ const keys = await this.scanKeys(`${this.KEY_PREFIX}*`);
341
+ const sessions = await Promise.all(
342
+ keys.map(async (key) => {
343
+ const data = await this.redis.get(key);
344
+ if (!data) {
345
+ return null;
346
+ }
347
+ try {
348
+ return JSON.parse(data).sessionId;
349
+ } catch (error) {
350
+ console.error("[RedisStorage] Failed to parse session while listing all session IDs:", error);
351
+ return null;
352
+ }
353
+ })
354
+ );
355
+ return sessions.filter((sessionId) => sessionId !== null);
275
356
  } catch (error) {
276
357
  console.error("[RedisStorage] Failed to get all sessions:", error);
277
358
  return [];
@@ -279,10 +360,11 @@ var RedisStorageBackend = class {
279
360
  }
280
361
  async clearAll() {
281
362
  try {
282
- const pattern = `${this.KEY_PREFIX}*`;
283
- const keys = await this.redis.keys(pattern);
284
- if (keys.length > 0) {
285
- await this.redis.del(...keys);
363
+ const keys = await this.scanKeys(`${this.KEY_PREFIX}*`);
364
+ const identityKeys = await this.scanKeys(`${this.IDENTITY_KEY_PREFIX}*${this.IDENTITY_KEY_SUFFIX}`);
365
+ const allKeys = [...keys, ...identityKeys];
366
+ if (allKeys.length > 0) {
367
+ await this.redis.del(...allKeys);
286
368
  }
287
369
  } catch (error) {
288
370
  console.error("[RedisStorage] Failed to clear sessions:", error);
@@ -290,12 +372,24 @@ var RedisStorageBackend = class {
290
372
  }
291
373
  async cleanupExpiredSessions() {
292
374
  try {
293
- const pattern = `${this.KEY_PREFIX}*`;
294
- const keys = await this.redis.keys(pattern);
295
- for (const key of keys) {
296
- const ttl = await this.redis.ttl(key);
297
- if (ttl <= 0) {
298
- await this.redis.del(key);
375
+ const identityKeys = await this.scanKeys(`${this.IDENTITY_KEY_PREFIX}*${this.IDENTITY_KEY_SUFFIX}`);
376
+ for (const identityKey of identityKeys) {
377
+ const identity = this.parseIdentityFromKey(identityKey);
378
+ const sessionIds = await this.redis.smembers(identityKey);
379
+ if (sessionIds.length === 0) {
380
+ await this.redis.del(identityKey);
381
+ continue;
382
+ }
383
+ const existenceChecks = await Promise.all(
384
+ sessionIds.map((sessionId) => this.redis.exists(this.getSessionKey(identity, sessionId)))
385
+ );
386
+ const staleSessionIds = sessionIds.filter((_, index) => existenceChecks[index] === 0);
387
+ if (staleSessionIds.length > 0) {
388
+ await this.redis.srem(identityKey, ...staleSessionIds);
389
+ }
390
+ const remainingCount = await this.redis.scard(identityKey);
391
+ if (remainingCount === 0) {
392
+ await this.redis.del(identityKey);
299
393
  }
300
394
  }
301
395
  } catch (error) {
@@ -310,6 +404,9 @@ var RedisStorageBackend = class {
310
404
  }
311
405
  }
312
406
  };
407
+
408
+ // src/server/storage/memory-backend.ts
409
+ init_cjs_shims();
313
410
  var firstChar2 = nanoid.customAlphabet(
314
411
  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
315
412
  1
@@ -325,6 +422,9 @@ var MemoryStorageBackend = class {
325
422
  // Map<identity, Set<sessionId>>
326
423
  __publicField(this, "identitySessions", /* @__PURE__ */ new Map());
327
424
  }
425
+ async init() {
426
+ console.log("[mcp-ts][Storage] Memory: \u2713 internal memory store active.");
427
+ }
328
428
  getSessionKey(identity, sessionId) {
329
429
  return `${identity}:${sessionId}`;
330
430
  }
@@ -400,6 +500,9 @@ var MemoryStorageBackend = class {
400
500
  async disconnect() {
401
501
  }
402
502
  };
503
+
504
+ // src/server/storage/file-backend.ts
505
+ init_cjs_shims();
403
506
  var firstChar3 = nanoid.customAlphabet(
404
507
  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
405
508
  1
@@ -444,6 +547,7 @@ var FileStorageBackend = class {
444
547
  }
445
548
  }
446
549
  this.initialized = true;
550
+ console.log(`[mcp-ts][Storage] File: \u2713 storage directory at ${path__namespace.dirname(this.filePath)} verified.`);
447
551
  }
448
552
  async ensureInitialized() {
449
553
  if (!this.initialized) await this.init();
@@ -520,6 +624,9 @@ var FileStorageBackend = class {
520
624
  async disconnect() {
521
625
  }
522
626
  };
627
+
628
+ // src/server/storage/sqlite-backend.ts
629
+ init_cjs_shims();
523
630
  var SqliteStorage = class {
524
631
  constructor(options = {}) {
525
632
  __publicField(this, "db", null);
@@ -548,6 +655,7 @@ var SqliteStorage = class {
548
655
  CREATE INDEX IF NOT EXISTS idx_${this.table}_identity ON ${this.table}(identity);
549
656
  `);
550
657
  this.initialized = true;
658
+ console.log(`[mcp-ts][Storage] SQLite: \u2713 database at ${this.dbPath} verified.`);
551
659
  } catch (error) {
552
660
  if (error.code === "MODULE_NOT_FOUND" || error.message?.includes("better-sqlite3")) {
553
661
  throw new Error(
@@ -663,9 +771,170 @@ var SqliteStorage = class {
663
771
  }
664
772
  };
665
773
 
774
+ // src/server/storage/supabase-backend.ts
775
+ init_cjs_shims();
776
+ var SupabaseStorageBackend = class {
777
+ constructor(supabase) {
778
+ this.supabase = supabase;
779
+ __publicField(this, "DEFAULT_TTL", SESSION_TTL_SECONDS);
780
+ }
781
+ async init() {
782
+ const { error } = await this.supabase.from("mcp_sessions").select("session_id").limit(0);
783
+ if (error) {
784
+ if (error.code === "42P01") {
785
+ throw new Error(
786
+ '[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.'
787
+ );
788
+ }
789
+ throw new Error(`[SupabaseStorage] Initialization check failed: ${error.message}`);
790
+ }
791
+ console.log('[mcp-ts][Storage] Supabase: \u2713 "mcp_sessions" table verified.');
792
+ }
793
+ generateSessionId() {
794
+ return crypto.randomUUID();
795
+ }
796
+ mapRowToSessionData(row) {
797
+ return {
798
+ sessionId: row.session_id,
799
+ serverId: row.server_id,
800
+ serverName: row.server_name,
801
+ serverUrl: row.server_url,
802
+ transportType: row.transport_type,
803
+ callbackUrl: row.callback_url,
804
+ createdAt: new Date(row.created_at).getTime(),
805
+ identity: row.identity,
806
+ headers: row.headers,
807
+ active: row.active,
808
+ clientInformation: row.client_information,
809
+ tokens: row.tokens,
810
+ codeVerifier: row.code_verifier,
811
+ clientId: row.client_id
812
+ };
813
+ }
814
+ async createSession(session, ttl) {
815
+ const { sessionId, identity } = session;
816
+ if (!sessionId || !identity) throw new Error("identity and sessionId required");
817
+ const effectiveTtl = ttl ?? this.DEFAULT_TTL;
818
+ const expiresAt = new Date(Date.now() + effectiveTtl * 1e3).toISOString();
819
+ const { error } = await this.supabase.from("mcp_sessions").insert({
820
+ session_id: sessionId,
821
+ user_id: identity,
822
+ // Maps user_id to identity to support RLS using auth.uid()
823
+ server_id: session.serverId,
824
+ server_name: session.serverName,
825
+ server_url: session.serverUrl,
826
+ transport_type: session.transportType,
827
+ callback_url: session.callbackUrl,
828
+ created_at: new Date(session.createdAt || Date.now()).toISOString(),
829
+ identity,
830
+ headers: session.headers,
831
+ active: session.active ?? false,
832
+ client_information: session.clientInformation,
833
+ tokens: session.tokens,
834
+ code_verifier: session.codeVerifier,
835
+ client_id: session.clientId,
836
+ expires_at: expiresAt
837
+ });
838
+ if (error) {
839
+ if (error.code === "23505") {
840
+ throw new Error(`Session ${sessionId} already exists`);
841
+ }
842
+ throw new Error(`Failed to create session in Supabase: ${error.message}`);
843
+ }
844
+ }
845
+ async updateSession(identity, sessionId, data, ttl) {
846
+ const effectiveTtl = ttl ?? this.DEFAULT_TTL;
847
+ const expiresAt = new Date(Date.now() + effectiveTtl * 1e3).toISOString();
848
+ const updateData = {
849
+ expires_at: expiresAt,
850
+ updated_at: (/* @__PURE__ */ new Date()).toISOString()
851
+ };
852
+ if ("serverId" in data) updateData.server_id = data.serverId;
853
+ if ("serverName" in data) updateData.server_name = data.serverName;
854
+ if ("serverUrl" in data) updateData.server_url = data.serverUrl;
855
+ if ("transportType" in data) updateData.transport_type = data.transportType;
856
+ if ("callbackUrl" in data) updateData.callback_url = data.callbackUrl;
857
+ if ("active" in data) updateData.active = data.active;
858
+ if ("headers" in data) updateData.headers = data.headers;
859
+ if ("clientInformation" in data) updateData.client_information = data.clientInformation;
860
+ if ("tokens" in data) updateData.tokens = data.tokens;
861
+ if ("codeVerifier" in data) updateData.code_verifier = data.codeVerifier;
862
+ if ("clientId" in data) updateData.client_id = data.clientId;
863
+ const { data: updatedRows, error } = await this.supabase.from("mcp_sessions").update(updateData).eq("identity", identity).eq("session_id", sessionId).select("id");
864
+ if (error) {
865
+ throw new Error(`Failed to update session: ${error.message}`);
866
+ }
867
+ if (!updatedRows || updatedRows.length === 0) {
868
+ throw new Error(`Session ${sessionId} not found for identity ${identity}`);
869
+ }
870
+ }
871
+ async getSession(identity, sessionId) {
872
+ const { data, error } = await this.supabase.from("mcp_sessions").select("*").eq("identity", identity).eq("session_id", sessionId).maybeSingle();
873
+ if (error) {
874
+ console.error("[SupabaseStorage] Failed to get session:", error);
875
+ return null;
876
+ }
877
+ if (!data) return null;
878
+ return this.mapRowToSessionData(data);
879
+ }
880
+ async getIdentitySessionsData(identity) {
881
+ const { data, error } = await this.supabase.from("mcp_sessions").select("*").eq("identity", identity);
882
+ if (error) {
883
+ console.error(`[SupabaseStorage] Failed to get session data for ${identity}:`, error);
884
+ return [];
885
+ }
886
+ return data.map((row) => this.mapRowToSessionData(row));
887
+ }
888
+ async removeSession(identity, sessionId) {
889
+ const { error } = await this.supabase.from("mcp_sessions").delete().eq("identity", identity).eq("session_id", sessionId);
890
+ if (error) {
891
+ console.error("[SupabaseStorage] Failed to remove session:", error);
892
+ }
893
+ }
894
+ async getIdentityMcpSessions(identity) {
895
+ const { data, error } = await this.supabase.from("mcp_sessions").select("session_id").eq("identity", identity);
896
+ if (error) {
897
+ console.error(`[SupabaseStorage] Failed to get sessions for ${identity}:`, error);
898
+ return [];
899
+ }
900
+ return data.map((row) => row.session_id);
901
+ }
902
+ async getAllSessionIds() {
903
+ const { data, error } = await this.supabase.from("mcp_sessions").select("session_id");
904
+ if (error) {
905
+ console.error("[SupabaseStorage] Failed to get all sessions:", error);
906
+ return [];
907
+ }
908
+ return data.map((row) => row.session_id);
909
+ }
910
+ async clearAll() {
911
+ const { error } = await this.supabase.from("mcp_sessions").delete().neq("session_id", "");
912
+ if (error) {
913
+ console.error("[SupabaseStorage] Failed to clear sessions:", error);
914
+ }
915
+ }
916
+ async cleanupExpiredSessions() {
917
+ const { error } = await this.supabase.from("mcp_sessions").delete().lt("expires_at", (/* @__PURE__ */ new Date()).toISOString());
918
+ if (error) {
919
+ console.error("[SupabaseStorage] Failed to cleanup expired sessions:", error);
920
+ }
921
+ }
922
+ async disconnect() {
923
+ }
924
+ };
925
+
926
+ // src/server/storage/types.ts
927
+ init_cjs_shims();
928
+
666
929
  // src/server/storage/index.ts
667
930
  var storageInstance = null;
668
931
  var storagePromise = null;
932
+ async function initializeStorage(store) {
933
+ if (typeof store.init === "function") {
934
+ await store.init();
935
+ }
936
+ return store;
937
+ }
669
938
  async function createStorage() {
670
939
  const type = process.env.MCP_TS_STORAGE_TYPE?.toLowerCase();
671
940
  if (type === "redis") {
@@ -675,68 +944,95 @@ async function createStorage() {
675
944
  try {
676
945
  const { getRedis: getRedis2 } = await Promise.resolve().then(() => (init_redis(), redis_exports));
677
946
  const redis2 = await getRedis2();
678
- console.log("[Storage] Using Redis storage (Explicit)");
679
- return new RedisStorageBackend(redis2);
947
+ console.log('[mcp-ts][Storage] Explicit selection: "redis"');
948
+ return await initializeStorage(new RedisStorageBackend(redis2));
680
949
  } catch (error) {
681
- console.error("[Storage] Failed to initialize Redis:", error.message);
682
- console.log("[Storage] Falling back to In-Memory storage");
683
- return new MemoryStorageBackend();
950
+ console.error("[mcp-ts][Storage] Failed to initialize Redis:", error.message);
951
+ console.log("[mcp-ts][Storage] Falling back to In-Memory storage");
952
+ return await initializeStorage(new MemoryStorageBackend());
684
953
  }
685
954
  }
686
955
  if (type === "file") {
687
956
  const filePath = process.env.MCP_TS_STORAGE_FILE;
688
- if (!filePath) {
689
- console.warn('[Storage] MCP_TS_STORAGE_TYPE is "file" but MCP_TS_STORAGE_FILE is missing');
690
- }
691
- console.log(`[Storage] Using File storage (${filePath}) (Explicit)`);
692
- const store = new FileStorageBackend({ path: filePath });
693
- store.init().catch((err) => console.error("[Storage] Failed to initialize file storage:", err));
694
- return store;
957
+ console.log(`[mcp-ts][Storage] Explicit selection: "file" (${filePath || "default"})`);
958
+ return await initializeStorage(new FileStorageBackend({ path: filePath }));
695
959
  }
696
960
  if (type === "sqlite") {
697
961
  const dbPath = process.env.MCP_TS_STORAGE_SQLITE_PATH;
698
- console.log(`[Storage] Using SQLite storage (${dbPath || "default"}) (Explicit)`);
699
- const store = new SqliteStorage({ path: dbPath });
700
- store.init().catch((err) => console.error("[Storage] Failed to initialize SQLite storage:", err));
701
- return store;
962
+ console.log(`[mcp-ts][Storage] Explicit selection: "sqlite" (${dbPath || "default"})`);
963
+ return await initializeStorage(new SqliteStorage({ path: dbPath }));
964
+ }
965
+ if (type === "supabase") {
966
+ const url = process.env.SUPABASE_URL;
967
+ const key = process.env.SUPABASE_SERVICE_ROLE_KEY || process.env.SUPABASE_ANON_KEY;
968
+ if (!url || !key) {
969
+ console.warn('[mcp-ts][Storage] Explicit selection "supabase" requires SUPABASE_URL and SUPABASE_SERVICE_ROLE_KEY.');
970
+ } else {
971
+ if (!process.env.SUPABASE_SERVICE_ROLE_KEY) {
972
+ 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.');
973
+ }
974
+ try {
975
+ const { createClient } = await import('@supabase/supabase-js');
976
+ const client = createClient(url, key);
977
+ console.log('[mcp-ts][Storage] Explicit selection: "supabase"');
978
+ return await initializeStorage(new SupabaseStorageBackend(client));
979
+ } catch (error) {
980
+ console.error("[mcp-ts][Storage] Failed to initialize Supabase:", error.message);
981
+ console.log("[mcp-ts][Storage] Falling back to In-Memory storage");
982
+ return await initializeStorage(new MemoryStorageBackend());
983
+ }
984
+ }
702
985
  }
703
986
  if (type === "memory") {
704
- console.log("[Storage] Using In-Memory storage (Explicit)");
705
- return new MemoryStorageBackend();
987
+ console.log('[mcp-ts][Storage] Explicit selection: "memory"');
988
+ return await initializeStorage(new MemoryStorageBackend());
706
989
  }
707
990
  if (process.env.REDIS_URL) {
708
991
  try {
709
992
  const { getRedis: getRedis2 } = await Promise.resolve().then(() => (init_redis(), redis_exports));
710
993
  const redis2 = await getRedis2();
711
- console.log("[Storage] Auto-detected REDIS_URL. Using Redis storage.");
712
- return new RedisStorageBackend(redis2);
994
+ console.log('[mcp-ts][Storage] Auto-detection: "redis" (via REDIS_URL)');
995
+ return await initializeStorage(new RedisStorageBackend(redis2));
713
996
  } catch (error) {
714
- console.error("[Storage] Redis auto-detection failed:", error.message);
715
- console.log("[Storage] Falling back to In-Memory storage");
716
- return new MemoryStorageBackend();
997
+ console.error("[mcp-ts][Storage] Redis auto-detection failed:", error.message);
998
+ console.log("[mcp-ts][Storage] Falling back to next available backend");
717
999
  }
718
1000
  }
719
1001
  if (process.env.MCP_TS_STORAGE_FILE) {
720
- console.log(`[Storage] Auto-detected MCP_TS_STORAGE_FILE. Using File storage (${process.env.MCP_TS_STORAGE_FILE}).`);
721
- const store = new FileStorageBackend({ path: process.env.MCP_TS_STORAGE_FILE });
722
- store.init().catch((err) => console.error("[Storage] Failed to initialize file storage:", err));
723
- return store;
1002
+ console.log(`[mcp-ts][Storage] Auto-detection: "file" (${process.env.MCP_TS_STORAGE_FILE})`);
1003
+ return await initializeStorage(new FileStorageBackend({ path: process.env.MCP_TS_STORAGE_FILE }));
724
1004
  }
725
1005
  if (process.env.MCP_TS_STORAGE_SQLITE_PATH) {
726
- console.log(`[Storage] Auto-detected MCP_TS_STORAGE_SQLITE_PATH. Using SQLite storage (${process.env.MCP_TS_STORAGE_SQLITE_PATH}).`);
727
- const store = new SqliteStorage({ path: process.env.MCP_TS_STORAGE_SQLITE_PATH });
728
- store.init().catch((err) => console.error("[Storage] Failed to initialize SQLite storage:", err));
729
- return store;
1006
+ console.log(`[mcp-ts][Storage] Auto-detection: "sqlite" (${process.env.MCP_TS_STORAGE_SQLITE_PATH})`);
1007
+ return await initializeStorage(new SqliteStorage({ path: process.env.MCP_TS_STORAGE_SQLITE_PATH }));
1008
+ }
1009
+ if (process.env.SUPABASE_URL && (process.env.SUPABASE_SERVICE_ROLE_KEY || process.env.SUPABASE_ANON_KEY)) {
1010
+ try {
1011
+ const { createClient } = await import('@supabase/supabase-js');
1012
+ const url = process.env.SUPABASE_URL;
1013
+ const key = process.env.SUPABASE_SERVICE_ROLE_KEY || process.env.SUPABASE_ANON_KEY;
1014
+ if (!process.env.SUPABASE_SERVICE_ROLE_KEY) {
1015
+ 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.');
1016
+ }
1017
+ const client = createClient(url, key);
1018
+ console.log('[mcp-ts][Storage] Auto-detection: "supabase" (via SUPABASE_URL)');
1019
+ return await initializeStorage(new SupabaseStorageBackend(client));
1020
+ } catch (error) {
1021
+ console.error("[mcp-ts][Storage] Supabase auto-detection failed:", error.message);
1022
+ }
730
1023
  }
731
- console.log("[Storage] No storage configured. Using In-Memory storage (Default).");
732
- return new MemoryStorageBackend();
1024
+ console.log('[mcp-ts][Storage] Defaulting to: "memory"');
1025
+ return await initializeStorage(new MemoryStorageBackend());
733
1026
  }
734
1027
  async function getStorage() {
735
1028
  if (storageInstance) {
736
1029
  return storageInstance;
737
1030
  }
738
1031
  if (!storagePromise) {
739
- storagePromise = createStorage();
1032
+ storagePromise = createStorage().catch((error) => {
1033
+ storagePromise = null;
1034
+ throw error;
1035
+ });
740
1036
  }
741
1037
  storageInstance = await storagePromise;
742
1038
  return storageInstance;
@@ -757,43 +1053,49 @@ var storage = new Proxy({}, {
757
1053
  // src/server/mcp/storage-oauth-provider.ts
758
1054
  var StorageOAuthClientProvider = class {
759
1055
  /**
760
- * Creates a new Storage-backed OAuth provider
761
- * @param identity - User/Client identifier
762
- * @param serverId - Server identifier (for tracking which server this OAuth session belongs to)
763
- * @param sessionId - Session identifier (used as OAuth state)
764
- * @param clientName - OAuth client name
765
- * @param baseRedirectUrl - OAuth callback URL
766
- * @param onRedirect - Optional callback when redirect to authorization is needed
1056
+ * Creates a new storage-backed OAuth provider
1057
+ * @param options - Provider configuration
767
1058
  */
768
- constructor(identity, serverId, sessionId, clientName, baseRedirectUrl, onRedirect) {
769
- this.identity = identity;
770
- this.serverId = serverId;
771
- this.sessionId = sessionId;
772
- this.clientName = clientName;
773
- this.baseRedirectUrl = baseRedirectUrl;
1059
+ constructor(options) {
1060
+ __publicField(this, "identity");
1061
+ __publicField(this, "serverId");
1062
+ __publicField(this, "sessionId");
1063
+ __publicField(this, "redirectUrl");
1064
+ __publicField(this, "clientName");
1065
+ __publicField(this, "clientUri");
1066
+ __publicField(this, "logoUri");
1067
+ __publicField(this, "policyUri");
1068
+ __publicField(this, "clientSecret");
774
1069
  __publicField(this, "_authUrl");
775
1070
  __publicField(this, "_clientId");
776
1071
  __publicField(this, "onRedirectCallback");
777
1072
  __publicField(this, "tokenExpiresAt");
778
- this.onRedirectCallback = onRedirect;
1073
+ this.identity = options.identity;
1074
+ this.serverId = options.serverId;
1075
+ this.sessionId = options.sessionId;
1076
+ this.redirectUrl = options.redirectUrl;
1077
+ this.clientName = options.clientName;
1078
+ this.clientUri = options.clientUri;
1079
+ this.logoUri = options.logoUri;
1080
+ this.policyUri = options.policyUri;
1081
+ this._clientId = options.clientId;
1082
+ this.clientSecret = options.clientSecret;
1083
+ this.onRedirectCallback = options.onRedirect;
779
1084
  }
780
1085
  get clientMetadata() {
781
1086
  return {
782
- client_name: this.clientName,
783
- client_uri: this.clientUri,
1087
+ client_name: this.clientName || DEFAULT_CLIENT_NAME,
1088
+ client_uri: this.clientUri || DEFAULT_CLIENT_URI,
1089
+ logo_uri: this.logoUri || DEFAULT_LOGO_URI,
1090
+ policy_uri: this.policyUri || DEFAULT_POLICY_URI,
784
1091
  grant_types: ["authorization_code", "refresh_token"],
785
1092
  redirect_uris: [this.redirectUrl],
786
1093
  response_types: ["code"],
787
- token_endpoint_auth_method: "none",
788
- ...this._clientId ? { client_id: this._clientId } : {}
1094
+ token_endpoint_auth_method: this.clientSecret ? "client_secret_basic" : "none",
1095
+ software_id: SOFTWARE_ID,
1096
+ software_version: SOFTWARE_VERSION
789
1097
  };
790
1098
  }
791
- get clientUri() {
792
- return new URL(this.redirectUrl).origin;
793
- }
794
- get redirectUrl() {
795
- return this.baseRedirectUrl;
796
- }
797
1099
  get clientId() {
798
1100
  return this._clientId;
799
1101
  }
@@ -828,7 +1130,16 @@ var StorageOAuthClientProvider = class {
828
1130
  if (data.clientId && !this._clientId) {
829
1131
  this._clientId = data.clientId;
830
1132
  }
831
- return data.clientInformation;
1133
+ if (data.clientInformation) {
1134
+ return data.clientInformation;
1135
+ }
1136
+ if (!this._clientId) {
1137
+ return void 0;
1138
+ }
1139
+ return {
1140
+ client_id: this._clientId,
1141
+ ...this.clientSecret ? { client_secret: this.clientSecret } : {}
1142
+ };
832
1143
  }
833
1144
  /**
834
1145
  * Stores OAuth client information
@@ -856,14 +1167,14 @@ var StorageOAuthClientProvider = class {
856
1167
  async state() {
857
1168
  return this.sessionId;
858
1169
  }
859
- async checkState(state) {
1170
+ async checkState(_state) {
860
1171
  const data = await storage.getSession(this.identity, this.sessionId);
861
1172
  if (!data) {
862
1173
  return { valid: false, error: "Session not found" };
863
1174
  }
864
1175
  return { valid: true, serverId: this.serverId };
865
1176
  }
866
- async consumeState(state) {
1177
+ async consumeState(_state) {
867
1178
  }
868
1179
  async redirectToAuthorization(authUrl) {
869
1180
  this._authUrl = authUrl.toString();
@@ -875,7 +1186,6 @@ var StorageOAuthClientProvider = class {
875
1186
  if (scope === "all") {
876
1187
  await storage.removeSession(this.identity, this.sessionId);
877
1188
  } else {
878
- await this.getSessionData();
879
1189
  const updates = {};
880
1190
  if (scope === "client") {
881
1191
  updates.clientInformation = void 0;
@@ -923,6 +1233,7 @@ var StorageOAuthClientProvider = class {
923
1233
  };
924
1234
 
925
1235
  // src/shared/utils.ts
1236
+ init_cjs_shims();
926
1237
  function sanitizeServerLabel(name) {
927
1238
  let sanitized = name.replace(/[^a-zA-Z0-9-_]/g, "_").replace(/_{2,}/g, "_").toLowerCase();
928
1239
  if (!/^[a-zA-Z]/.test(sanitized)) {
@@ -932,6 +1243,7 @@ function sanitizeServerLabel(name) {
932
1243
  }
933
1244
 
934
1245
  // src/shared/events.ts
1246
+ init_cjs_shims();
935
1247
  var Emitter = class {
936
1248
  constructor() {
937
1249
  __publicField(this, "listeners", /* @__PURE__ */ new Set());
@@ -979,6 +1291,7 @@ var Emitter = class {
979
1291
  };
980
1292
 
981
1293
  // src/shared/errors.ts
1294
+ init_cjs_shims();
982
1295
  var McpError = class extends Error {
983
1296
  constructor(code, message, cause) {
984
1297
  super(message);
@@ -1195,41 +1508,33 @@ var MCPClient = class _MCPClient {
1195
1508
  if (!this.serverUrl || !this.callbackUrl || !this.serverId) {
1196
1509
  throw new Error("Missing required connection metadata");
1197
1510
  }
1198
- const clientMetadata = {
1199
- client_name: this.clientName || "MCP Assistant",
1200
- redirect_uris: [this.callbackUrl],
1201
- token_endpoint_auth_method: this.clientSecret ? "client_secret_basic" : "none",
1202
- client_uri: this.clientUri || "https://mcp-assistant.in",
1203
- logo_uri: this.logoUri || "https://mcp-assistant.in/logo.png",
1204
- policy_uri: this.policyUri || "https://mcp-assistant.in/privacy",
1205
- ...this.clientId ? { client_id: this.clientId } : {},
1206
- ...this.clientSecret ? { client_secret: this.clientSecret } : {}
1207
- };
1208
1511
  if (!this.oauthProvider) {
1209
1512
  if (!this.serverId) {
1210
1513
  throw new Error("serverId required for OAuth provider initialization");
1211
1514
  }
1212
- this.oauthProvider = new StorageOAuthClientProvider(
1213
- this.identity,
1214
- this.serverId,
1215
- this.sessionId,
1216
- clientMetadata.client_name ?? "MCP Assistant",
1217
- this.callbackUrl,
1218
- (redirectUrl) => {
1515
+ this.oauthProvider = new StorageOAuthClientProvider({
1516
+ identity: this.identity,
1517
+ serverId: this.serverId,
1518
+ sessionId: this.sessionId,
1519
+ redirectUrl: this.callbackUrl,
1520
+ clientName: this.clientName,
1521
+ clientUri: this.clientUri,
1522
+ logoUri: this.logoUri,
1523
+ policyUri: this.policyUri,
1524
+ clientId: this.clientId,
1525
+ clientSecret: this.clientSecret,
1526
+ onRedirect: (redirectUrl) => {
1219
1527
  if (this.onRedirect) {
1220
1528
  this.onRedirect(redirectUrl);
1221
1529
  }
1222
1530
  }
1223
- );
1224
- if (this.clientId && this.oauthProvider) {
1225
- this.oauthProvider.clientId = this.clientId;
1226
- }
1531
+ });
1227
1532
  }
1228
1533
  if (!this.client) {
1229
1534
  this.client = new index_js.Client(
1230
1535
  {
1231
- name: "mcp-ts-oauth-client",
1232
- version: "2.0"
1536
+ name: MCP_CLIENT_NAME,
1537
+ version: MCP_CLIENT_VERSION
1233
1538
  },
1234
1539
  {
1235
1540
  capabilities: {
@@ -1424,8 +1729,8 @@ var MCPClient = class _MCPClient {
1424
1729
  this.emitProgress("Creating authenticated client...");
1425
1730
  this.client = new index_js.Client(
1426
1731
  {
1427
- name: "mcp-ts-oauth-client",
1428
- version: "2.0"
1732
+ name: MCP_CLIENT_NAME,
1733
+ version: MCP_CLIENT_VERSION
1429
1734
  },
1430
1735
  {
1431
1736
  capabilities: {
@@ -1720,8 +2025,8 @@ var MCPClient = class _MCPClient {
1720
2025
  }
1721
2026
  this.client = new index_js.Client(
1722
2027
  {
1723
- name: "mcp-ts-oauth-client",
1724
- version: "2.0"
2028
+ name: MCP_CLIENT_NAME,
2029
+ version: MCP_CLIENT_VERSION
1725
2030
  },
1726
2031
  { capabilities: {} }
1727
2032
  );
@@ -1901,6 +2206,7 @@ var MCPClient = class _MCPClient {
1901
2206
  };
1902
2207
 
1903
2208
  // src/server/mcp/multi-session-client.ts
2209
+ init_cjs_shims();
1904
2210
  var MultiSessionClient = class {
1905
2211
  constructor(identity, options = {}) {
1906
2212
  __publicField(this, "clients", []);
@@ -1990,6 +2296,31 @@ var MultiSessionClient = class {
1990
2296
  }
1991
2297
  };
1992
2298
 
2299
+ // src/server/handlers/sse-handler.ts
2300
+ init_cjs_shims();
2301
+
2302
+ // src/shared/event-routing.ts
2303
+ init_cjs_shims();
2304
+ function isRpcResponseEvent(event) {
2305
+ return "id" in event && ("result" in event || "error" in event);
2306
+ }
2307
+ function isConnectionEvent(event) {
2308
+ if (!("type" in event)) {
2309
+ return false;
2310
+ }
2311
+ switch (event.type) {
2312
+ case "state_changed":
2313
+ case "tools_discovered":
2314
+ case "auth_required":
2315
+ case "error":
2316
+ case "disconnected":
2317
+ case "progress":
2318
+ return true;
2319
+ default:
2320
+ return false;
2321
+ }
2322
+ }
2323
+
1993
2324
  // src/server/handlers/sse-handler.ts
1994
2325
  var DEFAULT_HEARTBEAT_INTERVAL = 3e4;
1995
2326
  var SSEConnectionManager = class {
@@ -2132,16 +2463,6 @@ var SSEConnectionManager = class {
2132
2463
  throw new Error(`Connection already exists for server: ${duplicate.serverUrl || duplicate.serverId} (${duplicate.serverName})`);
2133
2464
  }
2134
2465
  const sessionId = await storage.generateSessionId();
2135
- this.emitConnectionEvent({
2136
- type: "state_changed",
2137
- sessionId,
2138
- serverId,
2139
- serverName,
2140
- serverUrl,
2141
- state: "CONNECTING",
2142
- previousState: "DISCONNECTED",
2143
- timestamp: Date.now()
2144
- });
2145
2466
  try {
2146
2467
  const clientMetadata = await this.getResolvedClientMetadata();
2147
2468
  const client = new MCPClient({
@@ -2152,17 +2473,8 @@ var SSEConnectionManager = class {
2152
2473
  serverUrl,
2153
2474
  callbackUrl,
2154
2475
  transportType,
2155
- ...clientMetadata,
2476
+ ...clientMetadata
2156
2477
  // Spread client metadata (clientName, clientUri, logoUri, policyUri)
2157
- onRedirect: (authUrl) => {
2158
- this.emitConnectionEvent({
2159
- type: "auth_required",
2160
- sessionId,
2161
- serverId,
2162
- authUrl,
2163
- timestamp: Date.now()
2164
- });
2165
- }
2166
2478
  });
2167
2479
  this.clients.set(sessionId, client);
2168
2480
  client.onConnectionEvent((event) => {
@@ -2172,20 +2484,19 @@ var SSEConnectionManager = class {
2172
2484
  this.sendEvent(event);
2173
2485
  });
2174
2486
  await client.connect();
2175
- const tools = await client.listTools();
2176
- this.emitConnectionEvent({
2177
- type: "tools_discovered",
2178
- sessionId,
2179
- serverId,
2180
- toolCount: tools.tools.length,
2181
- tools: tools.tools,
2182
- timestamp: Date.now()
2183
- });
2487
+ await client.listTools();
2184
2488
  return {
2185
2489
  sessionId,
2186
2490
  success: true
2187
2491
  };
2188
2492
  } catch (error) {
2493
+ if (error instanceof UnauthorizedError) {
2494
+ this.clients.delete(sessionId);
2495
+ return {
2496
+ sessionId,
2497
+ success: true
2498
+ };
2499
+ }
2189
2500
  this.emitConnectionEvent({
2190
2501
  type: "error",
2191
2502
  sessionId,
@@ -2287,14 +2598,6 @@ var SSEConnectionManager = class {
2287
2598
  await client.connect();
2288
2599
  this.clients.set(sessionId, client);
2289
2600
  const tools = await client.listTools();
2290
- this.emitConnectionEvent({
2291
- type: "tools_discovered",
2292
- sessionId,
2293
- serverId: session.serverId ?? "unknown",
2294
- toolCount: tools.tools.length,
2295
- tools: tools.tools,
2296
- timestamp: Date.now()
2297
- });
2298
2601
  return { success: true, toolCount: tools.tools.length };
2299
2602
  } catch (error) {
2300
2603
  this.emitConnectionEvent({
@@ -2317,16 +2620,6 @@ var SSEConnectionManager = class {
2317
2620
  if (!session) {
2318
2621
  throw new Error("Session not found");
2319
2622
  }
2320
- this.emitConnectionEvent({
2321
- type: "state_changed",
2322
- sessionId,
2323
- serverId: session.serverId ?? "unknown",
2324
- serverName: session.serverName ?? "Unknown",
2325
- serverUrl: session.serverUrl,
2326
- state: "AUTHENTICATING",
2327
- previousState: "DISCONNECTED",
2328
- timestamp: Date.now()
2329
- });
2330
2623
  try {
2331
2624
  const client = new MCPClient({
2332
2625
  identity: this.identity,
@@ -2336,14 +2629,6 @@ var SSEConnectionManager = class {
2336
2629
  await client.finishAuth(code);
2337
2630
  this.clients.set(sessionId, client);
2338
2631
  const tools = await client.listTools();
2339
- this.emitConnectionEvent({
2340
- type: "tools_discovered",
2341
- sessionId,
2342
- serverId: session.serverId ?? "unknown",
2343
- toolCount: tools.tools.length,
2344
- tools: tools.tools,
2345
- timestamp: Date.now()
2346
- });
2347
2632
  return { success: true, toolCount: tools.tools.length };
2348
2633
  } catch (error) {
2349
2634
  this.emitConnectionEvent({
@@ -2421,9 +2706,9 @@ function createSSEHandler(options) {
2421
2706
  });
2422
2707
  writeSSEEvent(res, "connected", { timestamp: Date.now() });
2423
2708
  const manager = new SSEConnectionManager(options, (event) => {
2424
- if ("id" in event) {
2709
+ if (isRpcResponseEvent(event)) {
2425
2710
  writeSSEEvent(res, "rpc-response", event);
2426
- } else if ("type" in event && "sessionId" in event) {
2711
+ } else if (isConnectionEvent(event)) {
2427
2712
  writeSSEEvent(res, "connection", event);
2428
2713
  } else {
2429
2714
  writeSSEEvent(res, "observability", event);
@@ -2454,9 +2739,7 @@ function writeSSEEvent(res, event, data) {
2454
2739
  }
2455
2740
 
2456
2741
  // src/server/handlers/nextjs-handler.ts
2457
- function isRpcResponseEvent(event) {
2458
- return "id" in event && ("result" in event || "error" in event);
2459
- }
2742
+ init_cjs_shims();
2460
2743
  function createNextMcpHandler(options = {}) {
2461
2744
  const {
2462
2745
  getIdentity = (request) => new URL(request.url).searchParams.get("identity"),
@@ -2547,7 +2830,7 @@ data: ${JSON.stringify(data)}
2547
2830
  (event) => {
2548
2831
  if (isRpcResponseEvent(event)) {
2549
2832
  sendSSE("rpc-response", event);
2550
- } else if ("type" in event && "sessionId" in event) {
2833
+ } else if (isConnectionEvent(event)) {
2551
2834
  sendSSE("connection", event);
2552
2835
  } else {
2553
2836
  sendSSE("observability", event);