@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.
- package/dist/client/react.d.mts +81 -2
- package/dist/client/react.d.ts +81 -2
- package/dist/client/react.js +316 -3
- package/dist/client/react.js.map +1 -1
- package/dist/client/react.mjs +312 -4
- package/dist/client/react.mjs.map +1 -1
- package/dist/client/vue.js +11 -2
- package/dist/client/vue.js.map +1 -1
- package/dist/client/vue.mjs +11 -2
- package/dist/client/vue.mjs.map +1 -1
- package/dist/index.js +55 -11
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +55 -11
- package/dist/index.mjs.map +1 -1
- package/dist/server/index.js +55 -11
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +55 -11
- package/dist/server/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/client/react/index.ts +14 -0
- package/src/client/react/oauth-popup.tsx +446 -0
- package/src/client/react/use-mcp.ts +36 -3
- package/src/client/vue/use-mcp.ts +38 -3
- package/src/server/handlers/sse-handler.ts +39 -0
- package/src/server/mcp/oauth-client.ts +32 -14
- package/supabase/migrations/20260421010000_add_session_cleanup_cron.sql +32 -0
|
@@ -500,16 +500,10 @@ export class MCPClient {
|
|
|
500
500
|
this.emitStateChange('CONNECTED');
|
|
501
501
|
this.emitProgress('Connected successfully');
|
|
502
502
|
|
|
503
|
-
//
|
|
504
|
-
//
|
|
505
|
-
|
|
506
|
-
|
|
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
|
-
//
|
|
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
|
-
|
|
627
|
-
|
|
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.';
|