@mcp-ts/sdk 1.5.0 → 1.5.1

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.
@@ -500,16 +500,10 @@ export class MCPClient {
500
500
  this.emitStateChange('CONNECTED');
501
501
  this.emitProgress('Connected successfully');
502
502
 
503
- // Promote short-lived OAuth-pending session TTL to long-lived active TTL once.
504
- // Also persist when transport negotiation changed the effective transport.
505
- const existingSession = await storage.getSession(this.identity, this.sessionId);
506
- const needsTransportUpdate = !existingSession || existingSession.transportType !== this.transportType;
507
- const needsTtlPromotion = !existingSession || existingSession.active !== true;
508
-
509
- if (needsTransportUpdate || needsTtlPromotion) {
510
- console.log(`[MCPClient] Saving session ${this.sessionId} with 12hr TTL (connect success)`);
511
- await this.saveSession(SESSION_TTL_SECONDS, true);
512
- }
503
+ // Refresh session metadata on every successful connect so active sessions
504
+ // record ongoing usage and don't look dormant to storage cleanup jobs.
505
+ console.log(`[MCPClient] Saving session ${this.sessionId} with 12hr TTL (connect success)`);
506
+ await this.saveSession(SESSION_TTL_SECONDS, true);
513
507
  } catch (error) {
514
508
  /** Handle Authentication Errors */
515
509
  if (
@@ -537,11 +531,17 @@ export class MCPClient {
537
531
  : `OAuth authorization URL not available: ${detail}`;
538
532
  this.emitError(message, 'auth');
539
533
  this.emitStateChange('FAILED');
534
+
535
+ // Proactive Cleanup: This session has reached a terminal failure state.
536
+ // We remove it now to ensure the database remains lean, bypassing the
537
+ // automated lifecycle sweep.
540
538
  try {
541
539
  await storage.removeSession(this.identity, this.sessionId);
542
540
  } catch {
543
- // best-effort cleanup
541
+ // Non-blocking: Proactive cleanup failures are suppressed to prioritize
542
+ // the original error context.
544
543
  }
544
+
545
545
  throw new Error(message);
546
546
  }
547
547
 
@@ -571,6 +571,19 @@ export class MCPClient {
571
571
  const errorMessage = error instanceof Error ? error.message : 'Connection failed';
572
572
  this.emitError(errorMessage, 'connection');
573
573
  this.emitStateChange('FAILED');
574
+
575
+ // Terminal Handshake Failure: only purge transient sessions. Active
576
+ // sessions may still hold valid credentials for a later reconnect.
577
+ try {
578
+ const existingSession = await storage.getSession(this.identity, this.sessionId);
579
+ if (!existingSession || existingSession.active !== true) {
580
+ await storage.removeSession(this.identity, this.sessionId);
581
+ }
582
+ } catch {
583
+ // Non-blocking: Cleanup is performed on a best-effort basis and should
584
+ // not interfere with the primary error propagation.
585
+ }
586
+
574
587
  throw error;
575
588
  }
576
589
  }
@@ -606,6 +619,7 @@ export class MCPClient {
606
619
 
607
620
  let lastError: unknown;
608
621
  let tokensExchanged = false;
622
+ let authenticatedStateEmitted = false;
609
623
 
610
624
  for (const currentType of transportsToTry) {
611
625
  const isLastAttempt = currentType === transportsToTry[transportsToTry.length - 1];
@@ -623,10 +637,11 @@ export class MCPClient {
623
637
  this.emitProgress(`Tokens already exchanged, skipping auth step for ${currentType}...`);
624
638
  }
625
639
 
626
- /** Success! Update transport type */
627
- this.transportType = currentType;
640
+ if (!authenticatedStateEmitted) {
641
+ this.emitStateChange('AUTHENTICATED');
642
+ authenticatedStateEmitted = true;
643
+ }
628
644
 
629
- this.emitStateChange('AUTHENTICATED');
630
645
  this.emitProgress('Creating authenticated client...');
631
646
 
632
647
  this.client = new Client(
@@ -650,6 +665,9 @@ export class MCPClient {
650
665
  /** We explicitly try to connect with the transport we just auth'd with first */
651
666
  await this.client.connect(this.transport);
652
667
 
668
+ /** Connection succeeded — lock in the transport type */
669
+ this.transportType = currentType;
670
+
653
671
  this.emitStateChange('CONNECTED');
654
672
  // Update session with 12hr TTL after successful OAuth
655
673
  console.log(`[MCPClient] Updating session ${this.sessionId} to 12hr TTL (OAuth complete)`);
@@ -0,0 +1,32 @@
1
+ -- Enable the pg_cron extension (available on all Supabase plans).
2
+ -- This is idempotent and safe to run multiple times.
3
+ CREATE EXTENSION IF NOT EXISTS pg_cron;
4
+
5
+ -- ─────────────────────────────────────────────────────────────────────────────
6
+ -- Stage 1: Short-term Transient Purge (every 5 minutes)
7
+ -- ─────────────────────────────────────────────────────────────────────────────
8
+ -- Targets sessions that are NOT active (failed connections, abandoned OAuth
9
+ -- flows, mid-flow errors) whose TTL has expired. Active sessions are explicitly
10
+ -- excluded from this sweep to preserve automation credentials.
11
+ --
12
+ -- The idx_mcp_sessions_expires_at index ensures this is a fast indexed scan.
13
+ SELECT cron.schedule(
14
+ 'cleanup-transient-sessions',
15
+ '*/5 * * * *',
16
+ $$DELETE FROM public.mcp_sessions WHERE expires_at < now() AND active IS NOT TRUE;$$
17
+ );
18
+
19
+ -- ─────────────────────────────────────────────────────────────────────────────
20
+ -- Stage 2: Long-term Dormancy Eviction (daily at midnight UTC)
21
+ -- ─────────────────────────────────────────────────────────────────────────────
22
+ -- Safety net for sessions that were successfully established (active = true)
23
+ -- but have been completely untouched for 30+ days. This prevents "active"
24
+ -- records from persisting indefinitely if they are genuinely abandoned.
25
+ SELECT cron.schedule(
26
+ 'cleanup-dormant-sessions',
27
+ '0 0 * * *',
28
+ $$DELETE FROM public.mcp_sessions WHERE active = true AND updated_at < now() - interval '30 days';$$
29
+ );
30
+
31
+ -- Add a comment on the extension for visibility in Supabase Dashboard
32
+ COMMENT ON EXTENSION pg_cron IS 'Automated Session Lifecycle Management.';