@mcp-ts/sdk 1.3.4 → 1.3.5

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 (58) 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/client/index.d.mts +1 -0
  13. package/dist/client/index.d.ts +1 -0
  14. package/dist/client/index.js +14 -5
  15. package/dist/client/index.js.map +1 -1
  16. package/dist/client/index.mjs +14 -5
  17. package/dist/client/index.mjs.map +1 -1
  18. package/dist/client/react.js +15 -6
  19. package/dist/client/react.js.map +1 -1
  20. package/dist/client/react.mjs +15 -6
  21. package/dist/client/react.mjs.map +1 -1
  22. package/dist/client/vue.js +15 -6
  23. package/dist/client/vue.js.map +1 -1
  24. package/dist/client/vue.mjs +15 -6
  25. package/dist/client/vue.mjs.map +1 -1
  26. package/dist/index.d.mts +1 -1
  27. package/dist/index.d.ts +1 -1
  28. package/dist/index.js +201 -158
  29. package/dist/index.js.map +1 -1
  30. package/dist/index.mjs +201 -158
  31. package/dist/index.mjs.map +1 -1
  32. package/dist/{multi-session-client-FAFpUzZ4.d.ts → multi-session-client-BYLarghq.d.ts} +29 -19
  33. package/dist/{multi-session-client-DzjmT7FX.d.mts → multi-session-client-CzhMkE0k.d.mts} +29 -19
  34. package/dist/server/index.d.mts +1 -1
  35. package/dist/server/index.d.ts +1 -1
  36. package/dist/server/index.js +193 -151
  37. package/dist/server/index.js.map +1 -1
  38. package/dist/server/index.mjs +193 -151
  39. package/dist/server/index.mjs.map +1 -1
  40. package/dist/shared/index.d.mts +2 -2
  41. package/dist/shared/index.d.ts +2 -2
  42. package/dist/shared/index.js +2 -2
  43. package/dist/shared/index.js.map +1 -1
  44. package/dist/shared/index.mjs +2 -2
  45. package/dist/shared/index.mjs.map +1 -1
  46. package/package.json +1 -1
  47. package/src/client/core/sse-client.ts +371 -354
  48. package/src/client/react/use-mcp.ts +31 -31
  49. package/src/client/vue/use-mcp.ts +77 -77
  50. package/src/server/handlers/nextjs-handler.ts +194 -197
  51. package/src/server/handlers/sse-handler.ts +62 -111
  52. package/src/server/mcp/oauth-client.ts +67 -79
  53. package/src/server/mcp/storage-oauth-provider.ts +71 -38
  54. package/src/server/storage/index.ts +15 -13
  55. package/src/server/storage/redis-backend.ts +93 -23
  56. package/src/server/storage/types.ts +12 -12
  57. package/src/shared/constants.ts +2 -2
  58. package/src/shared/event-routing.ts +28 -0
package/dist/index.js CHANGED
@@ -142,10 +142,10 @@ var REDIS_KEY_PREFIX = "mcp:session:";
142
142
  var TOKEN_EXPIRY_BUFFER_MS = 5 * 60 * 1e3;
143
143
  var DEFAULT_CLIENT_NAME = "MCP Assistant";
144
144
  var DEFAULT_CLIENT_URI = "https://mcp-assistant.in";
145
- var DEFAULT_LOGO_URI = "https://mcp-assistant.in/logo.png";
145
+ var DEFAULT_LOGO_URI = "https://mcp-assistant.in/logo.svg";
146
146
  var DEFAULT_POLICY_URI = "https://mcp-assistant.in/privacy";
147
147
  var SOFTWARE_ID = "@mcp-ts";
148
- var SOFTWARE_VERSION = "1.0.0-beta.5";
148
+ var SOFTWARE_VERSION = "1.3.4";
149
149
  var MCP_CLIENT_NAME = "mcp-ts-oauth-client";
150
150
  var MCP_CLIENT_VERSION = "2.0";
151
151
 
@@ -163,6 +163,8 @@ var RedisStorageBackend = class {
163
163
  this.redis = redis2;
164
164
  __publicField(this, "DEFAULT_TTL", SESSION_TTL_SECONDS);
165
165
  __publicField(this, "KEY_PREFIX", "mcp:session:");
166
+ __publicField(this, "IDENTITY_KEY_PREFIX", "mcp:identity:");
167
+ __publicField(this, "IDENTITY_KEY_SUFFIX", ":sessions");
166
168
  }
167
169
  /**
168
170
  * Generates Redis key for a specific session
@@ -176,7 +178,34 @@ var RedisStorageBackend = class {
176
178
  * @private
177
179
  */
178
180
  getIdentityKey(identity) {
179
- return `mcp:identity:${identity}:sessions`;
181
+ return `${this.IDENTITY_KEY_PREFIX}${identity}${this.IDENTITY_KEY_SUFFIX}`;
182
+ }
183
+ parseIdentityFromKey(identityKey) {
184
+ return identityKey.slice(
185
+ this.IDENTITY_KEY_PREFIX.length,
186
+ identityKey.length - this.IDENTITY_KEY_SUFFIX.length
187
+ );
188
+ }
189
+ async scanKeys(pattern) {
190
+ const redis2 = this.redis;
191
+ if (typeof redis2.scan !== "function") {
192
+ return await this.redis.keys(pattern);
193
+ }
194
+ const keys = /* @__PURE__ */ new Set();
195
+ let cursor = "0";
196
+ try {
197
+ do {
198
+ const [nextCursor, batch] = await redis2.scan(cursor, "MATCH", pattern, "COUNT", 100);
199
+ cursor = nextCursor;
200
+ for (const key of batch) {
201
+ keys.add(key);
202
+ }
203
+ } while (cursor !== "0");
204
+ } catch (error) {
205
+ console.warn("[RedisStorage] SCAN failed, falling back to KEYS:", error);
206
+ return await this.redis.keys(pattern);
207
+ }
208
+ return Array.from(keys);
180
209
  }
181
210
  generateSessionId() {
182
211
  return firstChar() + rest();
@@ -244,17 +273,13 @@ var RedisStorageBackend = class {
244
273
  }
245
274
  }
246
275
  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
- }
276
+ const sessions = await this.getIdentitySessionsData(identity);
277
+ return sessions.map((session) => session.sessionId);
254
278
  }
255
279
  async getIdentitySessionsData(identity) {
256
280
  try {
257
- const sessionIds = await this.redis.smembers(this.getIdentityKey(identity));
281
+ const identityKey = this.getIdentityKey(identity);
282
+ const sessionIds = await this.redis.smembers(identityKey);
258
283
  if (sessionIds.length === 0) return [];
259
284
  const results = await Promise.all(
260
285
  sessionIds.map(async (sessionId) => {
@@ -262,6 +287,10 @@ var RedisStorageBackend = class {
262
287
  return data ? JSON.parse(data) : null;
263
288
  })
264
289
  );
290
+ const staleSessionIds = sessionIds.filter((_, index) => results[index] === null);
291
+ if (staleSessionIds.length > 0) {
292
+ await this.redis.srem(identityKey, ...staleSessionIds);
293
+ }
265
294
  return results.filter((session) => session !== null);
266
295
  } catch (error) {
267
296
  console.error(`[RedisStorage] Failed to get session data for ${identity}:`, error);
@@ -280,9 +309,22 @@ var RedisStorageBackend = class {
280
309
  }
281
310
  async getAllSessionIds() {
282
311
  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, ""));
312
+ const keys = await this.scanKeys(`${this.KEY_PREFIX}*`);
313
+ const sessions = await Promise.all(
314
+ keys.map(async (key) => {
315
+ const data = await this.redis.get(key);
316
+ if (!data) {
317
+ return null;
318
+ }
319
+ try {
320
+ return JSON.parse(data).sessionId;
321
+ } catch (error) {
322
+ console.error("[RedisStorage] Failed to parse session while listing all session IDs:", error);
323
+ return null;
324
+ }
325
+ })
326
+ );
327
+ return sessions.filter((sessionId) => sessionId !== null);
286
328
  } catch (error) {
287
329
  console.error("[RedisStorage] Failed to get all sessions:", error);
288
330
  return [];
@@ -290,10 +332,11 @@ var RedisStorageBackend = class {
290
332
  }
291
333
  async clearAll() {
292
334
  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);
335
+ const keys = await this.scanKeys(`${this.KEY_PREFIX}*`);
336
+ const identityKeys = await this.scanKeys(`${this.IDENTITY_KEY_PREFIX}*${this.IDENTITY_KEY_SUFFIX}`);
337
+ const allKeys = [...keys, ...identityKeys];
338
+ if (allKeys.length > 0) {
339
+ await this.redis.del(...allKeys);
297
340
  }
298
341
  } catch (error) {
299
342
  console.error("[RedisStorage] Failed to clear sessions:", error);
@@ -301,12 +344,24 @@ var RedisStorageBackend = class {
301
344
  }
302
345
  async cleanupExpiredSessions() {
303
346
  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);
347
+ const identityKeys = await this.scanKeys(`${this.IDENTITY_KEY_PREFIX}*${this.IDENTITY_KEY_SUFFIX}`);
348
+ for (const identityKey of identityKeys) {
349
+ const identity = this.parseIdentityFromKey(identityKey);
350
+ const sessionIds = await this.redis.smembers(identityKey);
351
+ if (sessionIds.length === 0) {
352
+ await this.redis.del(identityKey);
353
+ continue;
354
+ }
355
+ const existenceChecks = await Promise.all(
356
+ sessionIds.map((sessionId) => this.redis.exists(this.getSessionKey(identity, sessionId)))
357
+ );
358
+ const staleSessionIds = sessionIds.filter((_, index) => existenceChecks[index] === 0);
359
+ if (staleSessionIds.length > 0) {
360
+ await this.redis.srem(identityKey, ...staleSessionIds);
361
+ }
362
+ const remainingCount = await this.redis.scard(identityKey);
363
+ if (remainingCount === 0) {
364
+ await this.redis.del(identityKey);
310
365
  }
311
366
  }
312
367
  } catch (error) {
@@ -677,6 +732,12 @@ var SqliteStorage = class {
677
732
  // src/server/storage/index.ts
678
733
  var storageInstance = null;
679
734
  var storagePromise = null;
735
+ async function initializeStorage(store) {
736
+ if (typeof store.init === "function") {
737
+ await store.init();
738
+ }
739
+ return store;
740
+ }
680
741
  async function createStorage() {
681
742
  const type = process.env.MCP_TS_STORAGE_TYPE?.toLowerCase();
682
743
  if (type === "redis") {
@@ -700,16 +761,12 @@ async function createStorage() {
700
761
  console.warn('[Storage] MCP_TS_STORAGE_TYPE is "file" but MCP_TS_STORAGE_FILE is missing');
701
762
  }
702
763
  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;
764
+ return await initializeStorage(new FileStorageBackend({ path: filePath }));
706
765
  }
707
766
  if (type === "sqlite") {
708
767
  const dbPath = process.env.MCP_TS_STORAGE_SQLITE_PATH;
709
768
  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;
769
+ return await initializeStorage(new SqliteStorage({ path: dbPath }));
713
770
  }
714
771
  if (type === "memory") {
715
772
  console.log("[Storage] Using In-Memory storage (Explicit)");
@@ -729,15 +786,11 @@ async function createStorage() {
729
786
  }
730
787
  if (process.env.MCP_TS_STORAGE_FILE) {
731
788
  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;
789
+ return await initializeStorage(new FileStorageBackend({ path: process.env.MCP_TS_STORAGE_FILE }));
735
790
  }
736
791
  if (process.env.MCP_TS_STORAGE_SQLITE_PATH) {
737
792
  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;
793
+ return await initializeStorage(new SqliteStorage({ path: process.env.MCP_TS_STORAGE_SQLITE_PATH }));
741
794
  }
742
795
  console.log("[Storage] No storage configured. Using In-Memory storage (Default).");
743
796
  return new MemoryStorageBackend();
@@ -747,7 +800,10 @@ async function getStorage() {
747
800
  return storageInstance;
748
801
  }
749
802
  if (!storagePromise) {
750
- storagePromise = createStorage();
803
+ storagePromise = createStorage().catch((error) => {
804
+ storagePromise = null;
805
+ throw error;
806
+ });
751
807
  }
752
808
  storageInstance = await storagePromise;
753
809
  return storageInstance;
@@ -768,43 +824,49 @@ var storage = new Proxy({}, {
768
824
  // src/server/mcp/storage-oauth-provider.ts
769
825
  var StorageOAuthClientProvider = class {
770
826
  /**
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
827
+ * Creates a new storage-backed OAuth provider
828
+ * @param options - Provider configuration
778
829
  */
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;
830
+ constructor(options) {
831
+ __publicField(this, "identity");
832
+ __publicField(this, "serverId");
833
+ __publicField(this, "sessionId");
834
+ __publicField(this, "redirectUrl");
835
+ __publicField(this, "clientName");
836
+ __publicField(this, "clientUri");
837
+ __publicField(this, "logoUri");
838
+ __publicField(this, "policyUri");
839
+ __publicField(this, "clientSecret");
785
840
  __publicField(this, "_authUrl");
786
841
  __publicField(this, "_clientId");
787
842
  __publicField(this, "onRedirectCallback");
788
843
  __publicField(this, "tokenExpiresAt");
789
- this.onRedirectCallback = onRedirect;
844
+ this.identity = options.identity;
845
+ this.serverId = options.serverId;
846
+ this.sessionId = options.sessionId;
847
+ this.redirectUrl = options.redirectUrl;
848
+ this.clientName = options.clientName;
849
+ this.clientUri = options.clientUri;
850
+ this.logoUri = options.logoUri;
851
+ this.policyUri = options.policyUri;
852
+ this._clientId = options.clientId;
853
+ this.clientSecret = options.clientSecret;
854
+ this.onRedirectCallback = options.onRedirect;
790
855
  }
791
856
  get clientMetadata() {
792
857
  return {
793
- client_name: this.clientName,
794
- client_uri: this.clientUri,
858
+ client_name: this.clientName || DEFAULT_CLIENT_NAME,
859
+ client_uri: this.clientUri || DEFAULT_CLIENT_URI,
860
+ logo_uri: this.logoUri || DEFAULT_LOGO_URI,
861
+ policy_uri: this.policyUri || DEFAULT_POLICY_URI,
795
862
  grant_types: ["authorization_code", "refresh_token"],
796
863
  redirect_uris: [this.redirectUrl],
797
864
  response_types: ["code"],
798
- token_endpoint_auth_method: "none",
799
- ...this._clientId ? { client_id: this._clientId } : {}
865
+ token_endpoint_auth_method: this.clientSecret ? "client_secret_basic" : "none",
866
+ software_id: SOFTWARE_ID,
867
+ software_version: SOFTWARE_VERSION
800
868
  };
801
869
  }
802
- get clientUri() {
803
- return new URL(this.redirectUrl).origin;
804
- }
805
- get redirectUrl() {
806
- return this.baseRedirectUrl;
807
- }
808
870
  get clientId() {
809
871
  return this._clientId;
810
872
  }
@@ -839,7 +901,16 @@ var StorageOAuthClientProvider = class {
839
901
  if (data.clientId && !this._clientId) {
840
902
  this._clientId = data.clientId;
841
903
  }
842
- return data.clientInformation;
904
+ if (data.clientInformation) {
905
+ return data.clientInformation;
906
+ }
907
+ if (!this._clientId) {
908
+ return void 0;
909
+ }
910
+ return {
911
+ client_id: this._clientId,
912
+ ...this.clientSecret ? { client_secret: this.clientSecret } : {}
913
+ };
843
914
  }
844
915
  /**
845
916
  * Stores OAuth client information
@@ -867,14 +938,14 @@ var StorageOAuthClientProvider = class {
867
938
  async state() {
868
939
  return this.sessionId;
869
940
  }
870
- async checkState(state) {
941
+ async checkState(_state) {
871
942
  const data = await storage.getSession(this.identity, this.sessionId);
872
943
  if (!data) {
873
944
  return { valid: false, error: "Session not found" };
874
945
  }
875
946
  return { valid: true, serverId: this.serverId };
876
947
  }
877
- async consumeState(state) {
948
+ async consumeState(_state) {
878
949
  }
879
950
  async redirectToAuthorization(authUrl) {
880
951
  this._authUrl = authUrl.toString();
@@ -886,7 +957,6 @@ var StorageOAuthClientProvider = class {
886
957
  if (scope === "all") {
887
958
  await storage.removeSession(this.identity, this.sessionId);
888
959
  } else {
889
- await this.getSessionData();
890
960
  const updates = {};
891
961
  if (scope === "client") {
892
962
  updates.clientInformation = void 0;
@@ -1274,41 +1344,33 @@ var MCPClient = class _MCPClient {
1274
1344
  if (!this.serverUrl || !this.callbackUrl || !this.serverId) {
1275
1345
  throw new Error("Missing required connection metadata");
1276
1346
  }
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
1347
  if (!this.oauthProvider) {
1288
1348
  if (!this.serverId) {
1289
1349
  throw new Error("serverId required for OAuth provider initialization");
1290
1350
  }
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) => {
1351
+ this.oauthProvider = new StorageOAuthClientProvider({
1352
+ identity: this.identity,
1353
+ serverId: this.serverId,
1354
+ sessionId: this.sessionId,
1355
+ redirectUrl: this.callbackUrl,
1356
+ clientName: this.clientName,
1357
+ clientUri: this.clientUri,
1358
+ logoUri: this.logoUri,
1359
+ policyUri: this.policyUri,
1360
+ clientId: this.clientId,
1361
+ clientSecret: this.clientSecret,
1362
+ onRedirect: (redirectUrl) => {
1298
1363
  if (this.onRedirect) {
1299
1364
  this.onRedirect(redirectUrl);
1300
1365
  }
1301
1366
  }
1302
- );
1303
- if (this.clientId && this.oauthProvider) {
1304
- this.oauthProvider.clientId = this.clientId;
1305
- }
1367
+ });
1306
1368
  }
1307
1369
  if (!this.client) {
1308
1370
  this.client = new index_js.Client(
1309
1371
  {
1310
- name: "mcp-ts-oauth-client",
1311
- version: "2.0"
1372
+ name: MCP_CLIENT_NAME,
1373
+ version: MCP_CLIENT_VERSION
1312
1374
  },
1313
1375
  {
1314
1376
  capabilities: {
@@ -1503,8 +1565,8 @@ var MCPClient = class _MCPClient {
1503
1565
  this.emitProgress("Creating authenticated client...");
1504
1566
  this.client = new index_js.Client(
1505
1567
  {
1506
- name: "mcp-ts-oauth-client",
1507
- version: "2.0"
1568
+ name: MCP_CLIENT_NAME,
1569
+ version: MCP_CLIENT_VERSION
1508
1570
  },
1509
1571
  {
1510
1572
  capabilities: {
@@ -1799,8 +1861,8 @@ var MCPClient = class _MCPClient {
1799
1861
  }
1800
1862
  this.client = new index_js.Client(
1801
1863
  {
1802
- name: "mcp-ts-oauth-client",
1803
- version: "2.0"
1864
+ name: MCP_CLIENT_NAME,
1865
+ version: MCP_CLIENT_VERSION
1804
1866
  },
1805
1867
  { capabilities: {} }
1806
1868
  );
@@ -2069,6 +2131,27 @@ var MultiSessionClient = class {
2069
2131
  }
2070
2132
  };
2071
2133
 
2134
+ // src/shared/event-routing.ts
2135
+ function isRpcResponseEvent(event) {
2136
+ return "id" in event && ("result" in event || "error" in event);
2137
+ }
2138
+ function isConnectionEvent(event) {
2139
+ if (!("type" in event)) {
2140
+ return false;
2141
+ }
2142
+ switch (event.type) {
2143
+ case "state_changed":
2144
+ case "tools_discovered":
2145
+ case "auth_required":
2146
+ case "error":
2147
+ case "disconnected":
2148
+ case "progress":
2149
+ return true;
2150
+ default:
2151
+ return false;
2152
+ }
2153
+ }
2154
+
2072
2155
  // src/server/handlers/sse-handler.ts
2073
2156
  var DEFAULT_HEARTBEAT_INTERVAL = 3e4;
2074
2157
  var SSEConnectionManager = class {
@@ -2211,16 +2294,6 @@ var SSEConnectionManager = class {
2211
2294
  throw new Error(`Connection already exists for server: ${duplicate.serverUrl || duplicate.serverId} (${duplicate.serverName})`);
2212
2295
  }
2213
2296
  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
2297
  try {
2225
2298
  const clientMetadata = await this.getResolvedClientMetadata();
2226
2299
  const client = new MCPClient({
@@ -2231,17 +2304,8 @@ var SSEConnectionManager = class {
2231
2304
  serverUrl,
2232
2305
  callbackUrl,
2233
2306
  transportType,
2234
- ...clientMetadata,
2307
+ ...clientMetadata
2235
2308
  // 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
2309
  });
2246
2310
  this.clients.set(sessionId, client);
2247
2311
  client.onConnectionEvent((event) => {
@@ -2251,20 +2315,19 @@ var SSEConnectionManager = class {
2251
2315
  this.sendEvent(event);
2252
2316
  });
2253
2317
  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
- });
2318
+ await client.listTools();
2263
2319
  return {
2264
2320
  sessionId,
2265
2321
  success: true
2266
2322
  };
2267
2323
  } catch (error) {
2324
+ if (error instanceof UnauthorizedError) {
2325
+ this.clients.delete(sessionId);
2326
+ return {
2327
+ sessionId,
2328
+ success: true
2329
+ };
2330
+ }
2268
2331
  this.emitConnectionEvent({
2269
2332
  type: "error",
2270
2333
  sessionId,
@@ -2366,14 +2429,6 @@ var SSEConnectionManager = class {
2366
2429
  await client.connect();
2367
2430
  this.clients.set(sessionId, client);
2368
2431
  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
2432
  return { success: true, toolCount: tools.tools.length };
2378
2433
  } catch (error) {
2379
2434
  this.emitConnectionEvent({
@@ -2396,16 +2451,6 @@ var SSEConnectionManager = class {
2396
2451
  if (!session) {
2397
2452
  throw new Error("Session not found");
2398
2453
  }
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
2454
  try {
2410
2455
  const client = new MCPClient({
2411
2456
  identity: this.identity,
@@ -2415,14 +2460,6 @@ var SSEConnectionManager = class {
2415
2460
  await client.finishAuth(code);
2416
2461
  this.clients.set(sessionId, client);
2417
2462
  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
2463
  return { success: true, toolCount: tools.tools.length };
2427
2464
  } catch (error) {
2428
2465
  this.emitConnectionEvent({
@@ -2500,9 +2537,9 @@ function createSSEHandler(options) {
2500
2537
  });
2501
2538
  writeSSEEvent(res, "connected", { timestamp: Date.now() });
2502
2539
  const manager = new SSEConnectionManager(options, (event) => {
2503
- if ("id" in event) {
2540
+ if (isRpcResponseEvent(event)) {
2504
2541
  writeSSEEvent(res, "rpc-response", event);
2505
- } else if ("type" in event && "sessionId" in event) {
2542
+ } else if (isConnectionEvent(event)) {
2506
2543
  writeSSEEvent(res, "connection", event);
2507
2544
  } else {
2508
2545
  writeSSEEvent(res, "observability", event);
@@ -2533,9 +2570,6 @@ function writeSSEEvent(res, event, data) {
2533
2570
  }
2534
2571
 
2535
2572
  // src/server/handlers/nextjs-handler.ts
2536
- function isRpcResponseEvent(event) {
2537
- return "id" in event && ("result" in event || "error" in event);
2538
- }
2539
2573
  function createNextMcpHandler(options = {}) {
2540
2574
  const {
2541
2575
  getIdentity = (request) => new URL(request.url).searchParams.get("identity"),
@@ -2626,7 +2660,7 @@ data: ${JSON.stringify(data)}
2626
2660
  (event) => {
2627
2661
  if (isRpcResponseEvent(event)) {
2628
2662
  sendSSE("rpc-response", event);
2629
- } else if ("type" in event && "sessionId" in event) {
2663
+ } else if (isConnectionEvent(event)) {
2630
2664
  sendSSE("connection", event);
2631
2665
  } else {
2632
2666
  sendSSE("observability", event);
@@ -2683,6 +2717,7 @@ data: ${JSON.stringify(data)}
2683
2717
  }
2684
2718
  return { GET, POST };
2685
2719
  }
2720
+ var CONNECTION_EVENT_INTERVAL_MS = 300;
2686
2721
  var SSEClient = class {
2687
2722
  constructor(options) {
2688
2723
  this.options = options;
@@ -2787,10 +2822,12 @@ var SSEClient = class {
2787
2822
  const data2 = await response.json();
2788
2823
  return this.parseRpcResponse(data2);
2789
2824
  }
2790
- const data = await this.readRpcResponseFromStream(response);
2825
+ const data = await this.readRpcResponseFromStream(response, {
2826
+ delayConnectionEvents: method === "connect" || method === "restoreSession" || method === "finishAuth"
2827
+ });
2791
2828
  return this.parseRpcResponse(data);
2792
2829
  }
2793
- async readRpcResponseFromStream(response) {
2830
+ async readRpcResponseFromStream(response, options = {}) {
2794
2831
  if (!response.body) {
2795
2832
  throw new Error("Streaming response body is missing");
2796
2833
  }
@@ -2798,7 +2835,7 @@ var SSEClient = class {
2798
2835
  const decoder = new TextDecoder();
2799
2836
  let buffer = "";
2800
2837
  let rpcResponse = null;
2801
- const dispatchBlock = (block) => {
2838
+ const dispatchBlock = async (block) => {
2802
2839
  const lines = block.split("\n");
2803
2840
  let eventName = "message";
2804
2841
  const dataLines = [];
@@ -2826,6 +2863,9 @@ var SSEClient = class {
2826
2863
  break;
2827
2864
  case "connection":
2828
2865
  this.options.onConnectionEvent?.(payload);
2866
+ if (options.delayConnectionEvents) {
2867
+ await this.sleep(CONNECTION_EVENT_INTERVAL_MS);
2868
+ }
2829
2869
  break;
2830
2870
  case "observability":
2831
2871
  this.options.onObservabilityEvent?.(payload);
@@ -2845,18 +2885,21 @@ var SSEClient = class {
2845
2885
  const separatorLength = separatorMatch[0].length;
2846
2886
  const block = buffer.slice(0, separatorIndex);
2847
2887
  buffer = buffer.slice(separatorIndex + separatorLength);
2848
- dispatchBlock(block);
2888
+ await dispatchBlock(block);
2849
2889
  separatorMatch = buffer.match(/\r?\n\r?\n/);
2850
2890
  }
2851
2891
  }
2852
2892
  if (buffer.trim()) {
2853
- dispatchBlock(buffer);
2893
+ await dispatchBlock(buffer);
2854
2894
  }
2855
2895
  if (!rpcResponse) {
2856
2896
  throw new Error("Missing rpc-response event in streamed RPC result");
2857
2897
  }
2858
2898
  return rpcResponse;
2859
2899
  }
2900
+ sleep(ms) {
2901
+ return new Promise((resolve) => setTimeout(resolve, ms));
2902
+ }
2860
2903
  parseRpcResponse(data) {
2861
2904
  if ("result" in data) {
2862
2905
  return data.result;