@mcp-ts/sdk 2.4.1 → 2.4.2
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/adapters/agui-adapter.d.mts +3 -4
- package/dist/adapters/agui-adapter.d.ts +3 -4
- package/dist/adapters/agui-middleware.d.mts +3 -4
- package/dist/adapters/agui-middleware.d.ts +3 -4
- package/dist/adapters/ai-adapter.d.mts +3 -4
- package/dist/adapters/ai-adapter.d.ts +3 -4
- package/dist/adapters/langchain-adapter.d.mts +3 -4
- package/dist/adapters/langchain-adapter.d.ts +3 -4
- package/dist/adapters/mastra-adapter.d.mts +2 -2
- package/dist/adapters/mastra-adapter.d.ts +2 -2
- package/dist/client/index.d.mts +2 -3
- package/dist/client/index.d.ts +2 -3
- package/dist/client/react.d.mts +4 -6
- package/dist/client/react.d.ts +4 -6
- package/dist/client/vue.d.mts +4 -6
- package/dist/client/vue.d.ts +4 -6
- package/dist/{index-Ch7ouNSa.d.ts → index-B8kJSrBJ.d.ts} +1 -2
- package/dist/{index-L5XoXgsb.d.mts → index-DiJsm_lK.d.mts} +1 -2
- package/dist/index.d.mts +5 -6
- package/dist/index.d.ts +5 -6
- package/dist/index.js +103 -95
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +103 -95
- package/dist/index.mjs.map +1 -1
- package/dist/{multi-session-client-Bwm-efqg.d.ts → multi-session-client-BluyCPo9.d.ts} +201 -71
- package/dist/{multi-session-client-k-9RvWvi.d.mts → multi-session-client-CWs-AE78.d.mts} +201 -71
- package/dist/server/index.d.mts +5 -128
- package/dist/server/index.d.ts +5 -128
- package/dist/server/index.js +103 -95
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +103 -95
- package/dist/server/index.mjs.map +1 -1
- package/dist/shared/index.d.mts +4 -5
- package/dist/shared/index.d.ts +4 -5
- package/dist/{tool-router-CuApsDiV.d.mts → tool-router-CbG4Tum6.d.mts} +1 -1
- package/dist/{tool-router-CZMrOG8J.d.ts → tool-router-ChIhPwgP.d.ts} +1 -1
- package/dist/{types-DCk_IF4L.d.mts → types-CjczQwNX.d.mts} +122 -1
- package/dist/{types-DCk_IF4L.d.ts → types-CjczQwNX.d.ts} +122 -1
- package/package.json +1 -1
- package/src/server/mcp/multi-session-client.ts +177 -132
- package/dist/events-C4m7tK1U.d.mts +0 -122
- package/dist/events-C4m7tK1U.d.ts +0 -122
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { m as Event, M as McpConnectionEvent, t as McpObservabilityEvent, s as McpConnectionState, A as ToolClientProvider } from './types-CjczQwNX.js';
|
|
2
2
|
import { ListToolsResult, CallToolResult, ListPromptsResult, GetPromptResult, ListResourcesResult, ReadResourceResult } from '@modelcontextprotocol/sdk/types.js';
|
|
3
3
|
import { OAuthClientProvider } from '@modelcontextprotocol/sdk/client/auth.js';
|
|
4
4
|
import { OAuthClientMetadata, OAuthClientInformationMixed, OAuthClientInformationFull, OAuthTokens } from '@modelcontextprotocol/sdk/shared/auth.js';
|
|
@@ -328,102 +328,192 @@ declare class MCPClient {
|
|
|
328
328
|
getSessionId(): string;
|
|
329
329
|
}
|
|
330
330
|
|
|
331
|
+
interface OAuthState {
|
|
332
|
+
nonce: string;
|
|
333
|
+
sessionId: string;
|
|
334
|
+
serverId: string;
|
|
335
|
+
createdAt: number;
|
|
336
|
+
}
|
|
337
|
+
type SessionStatus = 'pending' | 'active';
|
|
338
|
+
interface Session {
|
|
339
|
+
sessionId: string;
|
|
340
|
+
serverId?: string;
|
|
341
|
+
serverName?: string;
|
|
342
|
+
serverUrl: string;
|
|
343
|
+
transportType: 'sse' | 'streamable-http';
|
|
344
|
+
callbackUrl: string;
|
|
345
|
+
createdAt: number;
|
|
346
|
+
updatedAt?: number;
|
|
347
|
+
/**
|
|
348
|
+
* Storage-owned expiration timestamp for pending/inactive sessions.
|
|
349
|
+
* Active sessions use updatedAt-based dormancy cleanup instead.
|
|
350
|
+
*/
|
|
351
|
+
expiresAt?: number | null;
|
|
352
|
+
userId: string;
|
|
353
|
+
headers?: Record<string, string>;
|
|
354
|
+
authUrl?: string | null;
|
|
355
|
+
/**
|
|
356
|
+
* Session status marker used for lifecycle cleanup:
|
|
357
|
+
* - pending: short-lived intermediate/auth-pending session state
|
|
358
|
+
* - active: restorable session after successful connection/auth completion
|
|
359
|
+
*/
|
|
360
|
+
status?: SessionStatus;
|
|
361
|
+
}
|
|
362
|
+
interface SessionCredentials {
|
|
363
|
+
sessionId: string;
|
|
364
|
+
userId: string;
|
|
365
|
+
clientInformation?: OAuthClientInformationMixed | null;
|
|
366
|
+
tokens?: OAuthTokens | null;
|
|
367
|
+
codeVerifier?: string | null;
|
|
368
|
+
clientId?: string | null;
|
|
369
|
+
oauthState?: OAuthState | null;
|
|
370
|
+
}
|
|
371
|
+
type SessionMutationType = 'create' | 'update' | 'delete';
|
|
372
|
+
interface SessionMutationEvent {
|
|
373
|
+
type: SessionMutationType;
|
|
374
|
+
userId: string;
|
|
375
|
+
sessionId: string;
|
|
376
|
+
timestamp: number;
|
|
377
|
+
session?: Session;
|
|
378
|
+
patch?: Partial<Session>;
|
|
379
|
+
}
|
|
380
|
+
type SessionMutationListener = (event: SessionMutationEvent) => void | Promise<void>;
|
|
331
381
|
/**
|
|
332
|
-
*
|
|
333
|
-
* Allows aggregating tools from all connected servers.
|
|
382
|
+
* Interface for MCP session stores.
|
|
334
383
|
*/
|
|
384
|
+
interface SessionStore {
|
|
385
|
+
/**
|
|
386
|
+
* Optional initialization (e.g., database connection)
|
|
387
|
+
*/
|
|
388
|
+
init?(): Promise<void>;
|
|
389
|
+
/**
|
|
390
|
+
* Generates a unique session ID
|
|
391
|
+
*/
|
|
392
|
+
generateSessionId(): string;
|
|
393
|
+
/**
|
|
394
|
+
* Creates a new session. Throws if session already exists.
|
|
395
|
+
* @param session - Session data to create
|
|
396
|
+
*/
|
|
397
|
+
create(session: Session): Promise<void>;
|
|
398
|
+
/**
|
|
399
|
+
* Updates an existing session with partial data. Throws if session does not exist.
|
|
400
|
+
* @param userId - User identifier
|
|
401
|
+
* @param sessionId - Session identifier
|
|
402
|
+
* @param data - Partial session data to update
|
|
403
|
+
*/
|
|
404
|
+
update(userId: string, sessionId: string, data: Partial<Session>): Promise<void>;
|
|
405
|
+
/**
|
|
406
|
+
* Patches runtime credentials for an existing session.
|
|
407
|
+
* These values are separated from connection metadata in durable SQL stores.
|
|
408
|
+
*/
|
|
409
|
+
patchCredentials(userId: string, sessionId: string, data: Partial<SessionCredentials>): Promise<void>;
|
|
410
|
+
/**
|
|
411
|
+
* Retrieves a session
|
|
412
|
+
*/
|
|
413
|
+
get(userId: string, sessionId: string): Promise<Session | null>;
|
|
414
|
+
/**
|
|
415
|
+
* Retrieves runtime credentials for a session.
|
|
416
|
+
*/
|
|
417
|
+
getCredentials(userId: string, sessionId: string): Promise<SessionCredentials | null>;
|
|
418
|
+
/**
|
|
419
|
+
* Clears runtime credentials without removing connection metadata.
|
|
420
|
+
*/
|
|
421
|
+
clearCredentials(userId: string, sessionId: string): Promise<void>;
|
|
422
|
+
/**
|
|
423
|
+
* Gets full session data for all sessions owned by a user
|
|
424
|
+
*/
|
|
425
|
+
list(userId: string): Promise<Session[]>;
|
|
426
|
+
/**
|
|
427
|
+
* Removes a session
|
|
428
|
+
*/
|
|
429
|
+
delete(userId: string, sessionId: string): Promise<void>;
|
|
430
|
+
/**
|
|
431
|
+
* Gets all session IDs owned by a user
|
|
432
|
+
*/
|
|
433
|
+
listIds(userId: string): Promise<string[]>;
|
|
434
|
+
/**
|
|
435
|
+
* Gets all session IDs across all users (Admin)
|
|
436
|
+
*/
|
|
437
|
+
listAllIds(): Promise<string[]>;
|
|
438
|
+
/**
|
|
439
|
+
* Clears all sessions (Admin)
|
|
440
|
+
*/
|
|
441
|
+
clearAll(): Promise<void>;
|
|
442
|
+
/**
|
|
443
|
+
* Clean up expired sessions
|
|
444
|
+
*/
|
|
445
|
+
cleanupExpired(): Promise<void>;
|
|
446
|
+
/**
|
|
447
|
+
* Disconnect from storage backend
|
|
448
|
+
*/
|
|
449
|
+
disconnect(): Promise<void>;
|
|
450
|
+
}
|
|
451
|
+
|
|
335
452
|
interface MultiSessionOptions {
|
|
336
453
|
/**
|
|
337
|
-
* Connection timeout in milliseconds
|
|
454
|
+
* Connection timeout in milliseconds.
|
|
338
455
|
* @default 15000
|
|
339
456
|
*/
|
|
340
457
|
timeout?: number;
|
|
341
458
|
/**
|
|
342
|
-
* Maximum number of retry attempts
|
|
459
|
+
* Maximum number of retry attempts per session.
|
|
343
460
|
* @default 2
|
|
344
461
|
*/
|
|
345
462
|
maxRetries?: number;
|
|
346
463
|
/**
|
|
347
|
-
* Delay between
|
|
464
|
+
* Delay between retry attempts in milliseconds.
|
|
348
465
|
* @default 1000
|
|
349
466
|
*/
|
|
350
467
|
retryDelay?: number;
|
|
351
|
-
}
|
|
352
|
-
/**
|
|
353
|
-
* Manages multiple MCP client connections for a single user.
|
|
354
|
-
*
|
|
355
|
-
* On a traditional long-running server, you can cache this instance per user
|
|
356
|
-
* so the connections stay alive between requests. On serverless, a new instance
|
|
357
|
-
* will be created per invocation, but the underlying session data is always
|
|
358
|
-
* read from the storage backend so nothing is lost between calls.
|
|
359
|
-
*/
|
|
360
|
-
declare class MultiSessionClient {
|
|
361
|
-
private clients;
|
|
362
|
-
private userId;
|
|
363
|
-
private options;
|
|
364
468
|
/**
|
|
365
|
-
*
|
|
469
|
+
* Custom session provider. When provided, `connect()` calls this
|
|
470
|
+
* instead of querying the storage backend. Useful when sessions are
|
|
471
|
+
* synced externally (e.g. via Supabase Realtime, WebSocket, or an
|
|
472
|
+
* in-memory cache).
|
|
366
473
|
*
|
|
367
|
-
*
|
|
368
|
-
* @param options - Optional tuning for connection timeout, retry count, and retry delay.
|
|
369
|
-
* Falls back to sensible defaults if not provided.
|
|
474
|
+
* Default: reads from the storage backend via `sessions.list(userId)`.
|
|
370
475
|
*/
|
|
371
|
-
|
|
476
|
+
sessionProvider?: () => Promise<Session[]>;
|
|
372
477
|
/**
|
|
373
|
-
*
|
|
374
|
-
* ones that are ready to connect.
|
|
375
|
-
*
|
|
376
|
-
* A session is considered connectable when:
|
|
377
|
-
* - It has a `serverId`, `serverUrl`, and `callbackUrl` (i.e. it was fully initialized)
|
|
378
|
-
* - Its status is `active`. Pending sessions are skipped here
|
|
379
|
-
* and let the OAuth flow complete separately before we try to reconnect them.
|
|
478
|
+
* Called after a session is successfully connected.
|
|
380
479
|
*/
|
|
381
|
-
|
|
480
|
+
onSessionConnected?: (sessionId: string, client: MCPClient) => void;
|
|
382
481
|
/**
|
|
383
|
-
*
|
|
384
|
-
*
|
|
385
|
-
* Batching prevents overwhelming the event loop or external servers when a user
|
|
386
|
-
* has many active MCP sessions (e.g. 20+ servers). Within each batch, sessions
|
|
387
|
-
* are connected concurrently using `Promise.all` for speed.
|
|
482
|
+
* Called when a session is evicted from the in-memory client list
|
|
483
|
+
* because it no longer exists in the active sessions list.
|
|
388
484
|
*/
|
|
389
|
-
|
|
390
|
-
private connectionPromises;
|
|
485
|
+
onSessionEvicted?: (sessionId: string) => void;
|
|
391
486
|
/**
|
|
392
|
-
*
|
|
393
|
-
*
|
|
394
|
-
* - If a client for this session already exists and is connected, returns immediately.
|
|
395
|
-
* - If the existing client entry is no longer connected (e.g. it was explicitly
|
|
396
|
-
* disconnected), it is evicted so that `establishConnectionWithRetries` creates a
|
|
397
|
-
* fresh transport — preventing "Client already connected" errors from the SDK.
|
|
398
|
-
* - If a connection attempt for this session is already in-flight (e.g. from a
|
|
399
|
-
* concurrent call), it joins the existing promise instead of starting a new one.
|
|
400
|
-
* This is the key concurrency lock — the `connectionPromises` map acts as a
|
|
401
|
-
* per-session mutex so we never spin up two physical connections for the same session.
|
|
402
|
-
* - On completion (success or failure), the promise is cleaned up from the map.
|
|
487
|
+
* Called when all retry attempts for a session have been exhausted.
|
|
403
488
|
*/
|
|
404
|
-
|
|
489
|
+
onSessionFailed?: (sessionId: string, error: unknown) => void;
|
|
490
|
+
}
|
|
491
|
+
/**
|
|
492
|
+
* Manages multiple MCP client connections for a single user.
|
|
493
|
+
*
|
|
494
|
+
* Cached instances stay alive between requests on long-running servers.
|
|
495
|
+
* On serverless, the underlying session data persists in storage — the
|
|
496
|
+
* client rehydrates from `sessionProvider` (or the default storage backend)
|
|
497
|
+
* each time `connect()` is called.
|
|
498
|
+
*
|
|
499
|
+
* @implements {ToolClientProvider}
|
|
500
|
+
*/
|
|
501
|
+
declare class MultiSessionClient implements ToolClientProvider {
|
|
502
|
+
private clients;
|
|
503
|
+
private connectionPromises;
|
|
504
|
+
private userId;
|
|
505
|
+
private options;
|
|
405
506
|
/**
|
|
406
|
-
*
|
|
407
|
-
*
|
|
408
|
-
* Attempts to establish a physical MCP connection, retrying up to `maxRetries` times
|
|
409
|
-
* if the connection fails. Each attempt:
|
|
410
|
-
* 1. Creates a fresh `MCPClient` instance from the session data.
|
|
411
|
-
* 2. Races the connect call against a timeout promise — if the server doesn't respond
|
|
412
|
-
* within `timeoutMs`, the attempt is aborted and counted as a failure.
|
|
413
|
-
* 3. On success, replaces any stale client entry for this session in the `clients` array.
|
|
414
|
-
* 4. On failure, waits `retryDelay` ms before the next attempt.
|
|
415
|
-
*
|
|
416
|
-
* If all attempts are exhausted, logs an error and returns silently (does not throw),
|
|
417
|
-
* so a single bad server doesn't block the rest of the batch from connecting.
|
|
507
|
+
* @param userId - Unique identifier for the user (e.g. user ID or email).
|
|
508
|
+
* @param options - Optional tuning and lifecycle hooks.
|
|
418
509
|
*/
|
|
419
|
-
|
|
510
|
+
constructor(userId: string, options?: MultiSessionOptions);
|
|
420
511
|
/**
|
|
421
|
-
*
|
|
422
|
-
* storage and establishes connections to all of them in batches.
|
|
512
|
+
* Fetches active sessions and establishes connections to all of them.
|
|
423
513
|
*
|
|
424
|
-
* Call this once after creating the client. On
|
|
425
|
-
* cache the `MultiSessionClient` instance
|
|
426
|
-
*
|
|
514
|
+
* Call this once after creating the client. On long-running servers you
|
|
515
|
+
* can cache the `MultiSessionClient` instance and call `connect()` on
|
|
516
|
+
* each request — already-connected sessions are skipped internally.
|
|
427
517
|
*/
|
|
428
518
|
connect(): Promise<void>;
|
|
429
519
|
/**
|
|
@@ -445,7 +535,7 @@ declare class MultiSessionClient {
|
|
|
445
535
|
*/
|
|
446
536
|
getClients(): MCPClient[];
|
|
447
537
|
/**
|
|
448
|
-
* Gracefully disconnects all active MCP clients and clears the internal
|
|
538
|
+
* Gracefully disconnects all active MCP clients and clears the internal list.
|
|
449
539
|
*
|
|
450
540
|
* For Streamable HTTP sessions, each client sends an HTTP DELETE to its MCP
|
|
451
541
|
* endpoint per the spec before closing locally. All disconnects run in
|
|
@@ -455,6 +545,46 @@ declare class MultiSessionClient {
|
|
|
455
545
|
* underlying transport resources (SSE streams, HTTP connections, etc.).
|
|
456
546
|
*/
|
|
457
547
|
disconnect(): Promise<void>;
|
|
548
|
+
/**
|
|
549
|
+
* Resolves the list of sessions to connect.
|
|
550
|
+
*
|
|
551
|
+
* Uses the custom `sessionProvider` when provided, otherwise falls back
|
|
552
|
+
* to querying the storage backend via `sessions.list(userId)`.
|
|
553
|
+
*/
|
|
554
|
+
private fetchActiveSessions;
|
|
555
|
+
/**
|
|
556
|
+
* Connects a list of sessions in controlled batches.
|
|
557
|
+
*
|
|
558
|
+
* Batching prevents overwhelming the event loop or external servers when
|
|
559
|
+
* a user has many active MCP sessions. Within each batch, sessions are
|
|
560
|
+
* connected concurrently using `Promise.all`.
|
|
561
|
+
*/
|
|
562
|
+
private connectInBatches;
|
|
563
|
+
/**
|
|
564
|
+
* Connects a single session, with deduplication to prevent race conditions.
|
|
565
|
+
*
|
|
566
|
+
* - If a client for this session already exists and is connected, returns
|
|
567
|
+
* immediately.
|
|
568
|
+
* - If the existing client entry is no longer connected (e.g. explicit
|
|
569
|
+
* disconnect), it is evicted so a fresh transport is created.
|
|
570
|
+
* - If a connection attempt for this session is already in-flight, the
|
|
571
|
+
* existing promise is reused as a per-session mutex.
|
|
572
|
+
* - On completion (success or failure), the promise is cleaned up from
|
|
573
|
+
* the connectionPromises map.
|
|
574
|
+
*/
|
|
575
|
+
private connectSession;
|
|
576
|
+
/**
|
|
577
|
+
* Core connection loop for a single session with retry logic.
|
|
578
|
+
*
|
|
579
|
+
* 1. Creates a fresh `MCPClient` from the session data.
|
|
580
|
+
* 2. Races `client.connect()` against a timeout.
|
|
581
|
+
* 3. On success, replaces any stale entry and fires `onSessionConnected`.
|
|
582
|
+
* 4. On failure, waits `retryDelay` ms before the next attempt.
|
|
583
|
+
*
|
|
584
|
+
* If all attempts are exhausted, logs an error and returns silently so
|
|
585
|
+
* a single bad server doesn't block the rest of the batch.
|
|
586
|
+
*/
|
|
587
|
+
private establishConnectionWithRetries;
|
|
458
588
|
}
|
|
459
589
|
|
|
460
|
-
export { MCPClient as M,
|
|
590
|
+
export { MCPClient as M, type Session as S, MultiSessionClient as a, type SessionMutationEvent as b, type SessionMutationListener as c, type SessionMutationType as d, type SessionStore as e, StorageOAuthClientProvider as f };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { m as Event, M as McpConnectionEvent, t as McpObservabilityEvent, s as McpConnectionState, A as ToolClientProvider } from './types-CjczQwNX.mjs';
|
|
2
2
|
import { ListToolsResult, CallToolResult, ListPromptsResult, GetPromptResult, ListResourcesResult, ReadResourceResult } from '@modelcontextprotocol/sdk/types.js';
|
|
3
3
|
import { OAuthClientProvider } from '@modelcontextprotocol/sdk/client/auth.js';
|
|
4
4
|
import { OAuthClientMetadata, OAuthClientInformationMixed, OAuthClientInformationFull, OAuthTokens } from '@modelcontextprotocol/sdk/shared/auth.js';
|
|
@@ -328,102 +328,192 @@ declare class MCPClient {
|
|
|
328
328
|
getSessionId(): string;
|
|
329
329
|
}
|
|
330
330
|
|
|
331
|
+
interface OAuthState {
|
|
332
|
+
nonce: string;
|
|
333
|
+
sessionId: string;
|
|
334
|
+
serverId: string;
|
|
335
|
+
createdAt: number;
|
|
336
|
+
}
|
|
337
|
+
type SessionStatus = 'pending' | 'active';
|
|
338
|
+
interface Session {
|
|
339
|
+
sessionId: string;
|
|
340
|
+
serverId?: string;
|
|
341
|
+
serverName?: string;
|
|
342
|
+
serverUrl: string;
|
|
343
|
+
transportType: 'sse' | 'streamable-http';
|
|
344
|
+
callbackUrl: string;
|
|
345
|
+
createdAt: number;
|
|
346
|
+
updatedAt?: number;
|
|
347
|
+
/**
|
|
348
|
+
* Storage-owned expiration timestamp for pending/inactive sessions.
|
|
349
|
+
* Active sessions use updatedAt-based dormancy cleanup instead.
|
|
350
|
+
*/
|
|
351
|
+
expiresAt?: number | null;
|
|
352
|
+
userId: string;
|
|
353
|
+
headers?: Record<string, string>;
|
|
354
|
+
authUrl?: string | null;
|
|
355
|
+
/**
|
|
356
|
+
* Session status marker used for lifecycle cleanup:
|
|
357
|
+
* - pending: short-lived intermediate/auth-pending session state
|
|
358
|
+
* - active: restorable session after successful connection/auth completion
|
|
359
|
+
*/
|
|
360
|
+
status?: SessionStatus;
|
|
361
|
+
}
|
|
362
|
+
interface SessionCredentials {
|
|
363
|
+
sessionId: string;
|
|
364
|
+
userId: string;
|
|
365
|
+
clientInformation?: OAuthClientInformationMixed | null;
|
|
366
|
+
tokens?: OAuthTokens | null;
|
|
367
|
+
codeVerifier?: string | null;
|
|
368
|
+
clientId?: string | null;
|
|
369
|
+
oauthState?: OAuthState | null;
|
|
370
|
+
}
|
|
371
|
+
type SessionMutationType = 'create' | 'update' | 'delete';
|
|
372
|
+
interface SessionMutationEvent {
|
|
373
|
+
type: SessionMutationType;
|
|
374
|
+
userId: string;
|
|
375
|
+
sessionId: string;
|
|
376
|
+
timestamp: number;
|
|
377
|
+
session?: Session;
|
|
378
|
+
patch?: Partial<Session>;
|
|
379
|
+
}
|
|
380
|
+
type SessionMutationListener = (event: SessionMutationEvent) => void | Promise<void>;
|
|
331
381
|
/**
|
|
332
|
-
*
|
|
333
|
-
* Allows aggregating tools from all connected servers.
|
|
382
|
+
* Interface for MCP session stores.
|
|
334
383
|
*/
|
|
384
|
+
interface SessionStore {
|
|
385
|
+
/**
|
|
386
|
+
* Optional initialization (e.g., database connection)
|
|
387
|
+
*/
|
|
388
|
+
init?(): Promise<void>;
|
|
389
|
+
/**
|
|
390
|
+
* Generates a unique session ID
|
|
391
|
+
*/
|
|
392
|
+
generateSessionId(): string;
|
|
393
|
+
/**
|
|
394
|
+
* Creates a new session. Throws if session already exists.
|
|
395
|
+
* @param session - Session data to create
|
|
396
|
+
*/
|
|
397
|
+
create(session: Session): Promise<void>;
|
|
398
|
+
/**
|
|
399
|
+
* Updates an existing session with partial data. Throws if session does not exist.
|
|
400
|
+
* @param userId - User identifier
|
|
401
|
+
* @param sessionId - Session identifier
|
|
402
|
+
* @param data - Partial session data to update
|
|
403
|
+
*/
|
|
404
|
+
update(userId: string, sessionId: string, data: Partial<Session>): Promise<void>;
|
|
405
|
+
/**
|
|
406
|
+
* Patches runtime credentials for an existing session.
|
|
407
|
+
* These values are separated from connection metadata in durable SQL stores.
|
|
408
|
+
*/
|
|
409
|
+
patchCredentials(userId: string, sessionId: string, data: Partial<SessionCredentials>): Promise<void>;
|
|
410
|
+
/**
|
|
411
|
+
* Retrieves a session
|
|
412
|
+
*/
|
|
413
|
+
get(userId: string, sessionId: string): Promise<Session | null>;
|
|
414
|
+
/**
|
|
415
|
+
* Retrieves runtime credentials for a session.
|
|
416
|
+
*/
|
|
417
|
+
getCredentials(userId: string, sessionId: string): Promise<SessionCredentials | null>;
|
|
418
|
+
/**
|
|
419
|
+
* Clears runtime credentials without removing connection metadata.
|
|
420
|
+
*/
|
|
421
|
+
clearCredentials(userId: string, sessionId: string): Promise<void>;
|
|
422
|
+
/**
|
|
423
|
+
* Gets full session data for all sessions owned by a user
|
|
424
|
+
*/
|
|
425
|
+
list(userId: string): Promise<Session[]>;
|
|
426
|
+
/**
|
|
427
|
+
* Removes a session
|
|
428
|
+
*/
|
|
429
|
+
delete(userId: string, sessionId: string): Promise<void>;
|
|
430
|
+
/**
|
|
431
|
+
* Gets all session IDs owned by a user
|
|
432
|
+
*/
|
|
433
|
+
listIds(userId: string): Promise<string[]>;
|
|
434
|
+
/**
|
|
435
|
+
* Gets all session IDs across all users (Admin)
|
|
436
|
+
*/
|
|
437
|
+
listAllIds(): Promise<string[]>;
|
|
438
|
+
/**
|
|
439
|
+
* Clears all sessions (Admin)
|
|
440
|
+
*/
|
|
441
|
+
clearAll(): Promise<void>;
|
|
442
|
+
/**
|
|
443
|
+
* Clean up expired sessions
|
|
444
|
+
*/
|
|
445
|
+
cleanupExpired(): Promise<void>;
|
|
446
|
+
/**
|
|
447
|
+
* Disconnect from storage backend
|
|
448
|
+
*/
|
|
449
|
+
disconnect(): Promise<void>;
|
|
450
|
+
}
|
|
451
|
+
|
|
335
452
|
interface MultiSessionOptions {
|
|
336
453
|
/**
|
|
337
|
-
* Connection timeout in milliseconds
|
|
454
|
+
* Connection timeout in milliseconds.
|
|
338
455
|
* @default 15000
|
|
339
456
|
*/
|
|
340
457
|
timeout?: number;
|
|
341
458
|
/**
|
|
342
|
-
* Maximum number of retry attempts
|
|
459
|
+
* Maximum number of retry attempts per session.
|
|
343
460
|
* @default 2
|
|
344
461
|
*/
|
|
345
462
|
maxRetries?: number;
|
|
346
463
|
/**
|
|
347
|
-
* Delay between
|
|
464
|
+
* Delay between retry attempts in milliseconds.
|
|
348
465
|
* @default 1000
|
|
349
466
|
*/
|
|
350
467
|
retryDelay?: number;
|
|
351
|
-
}
|
|
352
|
-
/**
|
|
353
|
-
* Manages multiple MCP client connections for a single user.
|
|
354
|
-
*
|
|
355
|
-
* On a traditional long-running server, you can cache this instance per user
|
|
356
|
-
* so the connections stay alive between requests. On serverless, a new instance
|
|
357
|
-
* will be created per invocation, but the underlying session data is always
|
|
358
|
-
* read from the storage backend so nothing is lost between calls.
|
|
359
|
-
*/
|
|
360
|
-
declare class MultiSessionClient {
|
|
361
|
-
private clients;
|
|
362
|
-
private userId;
|
|
363
|
-
private options;
|
|
364
468
|
/**
|
|
365
|
-
*
|
|
469
|
+
* Custom session provider. When provided, `connect()` calls this
|
|
470
|
+
* instead of querying the storage backend. Useful when sessions are
|
|
471
|
+
* synced externally (e.g. via Supabase Realtime, WebSocket, or an
|
|
472
|
+
* in-memory cache).
|
|
366
473
|
*
|
|
367
|
-
*
|
|
368
|
-
* @param options - Optional tuning for connection timeout, retry count, and retry delay.
|
|
369
|
-
* Falls back to sensible defaults if not provided.
|
|
474
|
+
* Default: reads from the storage backend via `sessions.list(userId)`.
|
|
370
475
|
*/
|
|
371
|
-
|
|
476
|
+
sessionProvider?: () => Promise<Session[]>;
|
|
372
477
|
/**
|
|
373
|
-
*
|
|
374
|
-
* ones that are ready to connect.
|
|
375
|
-
*
|
|
376
|
-
* A session is considered connectable when:
|
|
377
|
-
* - It has a `serverId`, `serverUrl`, and `callbackUrl` (i.e. it was fully initialized)
|
|
378
|
-
* - Its status is `active`. Pending sessions are skipped here
|
|
379
|
-
* and let the OAuth flow complete separately before we try to reconnect them.
|
|
478
|
+
* Called after a session is successfully connected.
|
|
380
479
|
*/
|
|
381
|
-
|
|
480
|
+
onSessionConnected?: (sessionId: string, client: MCPClient) => void;
|
|
382
481
|
/**
|
|
383
|
-
*
|
|
384
|
-
*
|
|
385
|
-
* Batching prevents overwhelming the event loop or external servers when a user
|
|
386
|
-
* has many active MCP sessions (e.g. 20+ servers). Within each batch, sessions
|
|
387
|
-
* are connected concurrently using `Promise.all` for speed.
|
|
482
|
+
* Called when a session is evicted from the in-memory client list
|
|
483
|
+
* because it no longer exists in the active sessions list.
|
|
388
484
|
*/
|
|
389
|
-
|
|
390
|
-
private connectionPromises;
|
|
485
|
+
onSessionEvicted?: (sessionId: string) => void;
|
|
391
486
|
/**
|
|
392
|
-
*
|
|
393
|
-
*
|
|
394
|
-
* - If a client for this session already exists and is connected, returns immediately.
|
|
395
|
-
* - If the existing client entry is no longer connected (e.g. it was explicitly
|
|
396
|
-
* disconnected), it is evicted so that `establishConnectionWithRetries` creates a
|
|
397
|
-
* fresh transport — preventing "Client already connected" errors from the SDK.
|
|
398
|
-
* - If a connection attempt for this session is already in-flight (e.g. from a
|
|
399
|
-
* concurrent call), it joins the existing promise instead of starting a new one.
|
|
400
|
-
* This is the key concurrency lock — the `connectionPromises` map acts as a
|
|
401
|
-
* per-session mutex so we never spin up two physical connections for the same session.
|
|
402
|
-
* - On completion (success or failure), the promise is cleaned up from the map.
|
|
487
|
+
* Called when all retry attempts for a session have been exhausted.
|
|
403
488
|
*/
|
|
404
|
-
|
|
489
|
+
onSessionFailed?: (sessionId: string, error: unknown) => void;
|
|
490
|
+
}
|
|
491
|
+
/**
|
|
492
|
+
* Manages multiple MCP client connections for a single user.
|
|
493
|
+
*
|
|
494
|
+
* Cached instances stay alive between requests on long-running servers.
|
|
495
|
+
* On serverless, the underlying session data persists in storage — the
|
|
496
|
+
* client rehydrates from `sessionProvider` (or the default storage backend)
|
|
497
|
+
* each time `connect()` is called.
|
|
498
|
+
*
|
|
499
|
+
* @implements {ToolClientProvider}
|
|
500
|
+
*/
|
|
501
|
+
declare class MultiSessionClient implements ToolClientProvider {
|
|
502
|
+
private clients;
|
|
503
|
+
private connectionPromises;
|
|
504
|
+
private userId;
|
|
505
|
+
private options;
|
|
405
506
|
/**
|
|
406
|
-
*
|
|
407
|
-
*
|
|
408
|
-
* Attempts to establish a physical MCP connection, retrying up to `maxRetries` times
|
|
409
|
-
* if the connection fails. Each attempt:
|
|
410
|
-
* 1. Creates a fresh `MCPClient` instance from the session data.
|
|
411
|
-
* 2. Races the connect call against a timeout promise — if the server doesn't respond
|
|
412
|
-
* within `timeoutMs`, the attempt is aborted and counted as a failure.
|
|
413
|
-
* 3. On success, replaces any stale client entry for this session in the `clients` array.
|
|
414
|
-
* 4. On failure, waits `retryDelay` ms before the next attempt.
|
|
415
|
-
*
|
|
416
|
-
* If all attempts are exhausted, logs an error and returns silently (does not throw),
|
|
417
|
-
* so a single bad server doesn't block the rest of the batch from connecting.
|
|
507
|
+
* @param userId - Unique identifier for the user (e.g. user ID or email).
|
|
508
|
+
* @param options - Optional tuning and lifecycle hooks.
|
|
418
509
|
*/
|
|
419
|
-
|
|
510
|
+
constructor(userId: string, options?: MultiSessionOptions);
|
|
420
511
|
/**
|
|
421
|
-
*
|
|
422
|
-
* storage and establishes connections to all of them in batches.
|
|
512
|
+
* Fetches active sessions and establishes connections to all of them.
|
|
423
513
|
*
|
|
424
|
-
* Call this once after creating the client. On
|
|
425
|
-
* cache the `MultiSessionClient` instance
|
|
426
|
-
*
|
|
514
|
+
* Call this once after creating the client. On long-running servers you
|
|
515
|
+
* can cache the `MultiSessionClient` instance and call `connect()` on
|
|
516
|
+
* each request — already-connected sessions are skipped internally.
|
|
427
517
|
*/
|
|
428
518
|
connect(): Promise<void>;
|
|
429
519
|
/**
|
|
@@ -445,7 +535,7 @@ declare class MultiSessionClient {
|
|
|
445
535
|
*/
|
|
446
536
|
getClients(): MCPClient[];
|
|
447
537
|
/**
|
|
448
|
-
* Gracefully disconnects all active MCP clients and clears the internal
|
|
538
|
+
* Gracefully disconnects all active MCP clients and clears the internal list.
|
|
449
539
|
*
|
|
450
540
|
* For Streamable HTTP sessions, each client sends an HTTP DELETE to its MCP
|
|
451
541
|
* endpoint per the spec before closing locally. All disconnects run in
|
|
@@ -455,6 +545,46 @@ declare class MultiSessionClient {
|
|
|
455
545
|
* underlying transport resources (SSE streams, HTTP connections, etc.).
|
|
456
546
|
*/
|
|
457
547
|
disconnect(): Promise<void>;
|
|
548
|
+
/**
|
|
549
|
+
* Resolves the list of sessions to connect.
|
|
550
|
+
*
|
|
551
|
+
* Uses the custom `sessionProvider` when provided, otherwise falls back
|
|
552
|
+
* to querying the storage backend via `sessions.list(userId)`.
|
|
553
|
+
*/
|
|
554
|
+
private fetchActiveSessions;
|
|
555
|
+
/**
|
|
556
|
+
* Connects a list of sessions in controlled batches.
|
|
557
|
+
*
|
|
558
|
+
* Batching prevents overwhelming the event loop or external servers when
|
|
559
|
+
* a user has many active MCP sessions. Within each batch, sessions are
|
|
560
|
+
* connected concurrently using `Promise.all`.
|
|
561
|
+
*/
|
|
562
|
+
private connectInBatches;
|
|
563
|
+
/**
|
|
564
|
+
* Connects a single session, with deduplication to prevent race conditions.
|
|
565
|
+
*
|
|
566
|
+
* - If a client for this session already exists and is connected, returns
|
|
567
|
+
* immediately.
|
|
568
|
+
* - If the existing client entry is no longer connected (e.g. explicit
|
|
569
|
+
* disconnect), it is evicted so a fresh transport is created.
|
|
570
|
+
* - If a connection attempt for this session is already in-flight, the
|
|
571
|
+
* existing promise is reused as a per-session mutex.
|
|
572
|
+
* - On completion (success or failure), the promise is cleaned up from
|
|
573
|
+
* the connectionPromises map.
|
|
574
|
+
*/
|
|
575
|
+
private connectSession;
|
|
576
|
+
/**
|
|
577
|
+
* Core connection loop for a single session with retry logic.
|
|
578
|
+
*
|
|
579
|
+
* 1. Creates a fresh `MCPClient` from the session data.
|
|
580
|
+
* 2. Races `client.connect()` against a timeout.
|
|
581
|
+
* 3. On success, replaces any stale entry and fires `onSessionConnected`.
|
|
582
|
+
* 4. On failure, waits `retryDelay` ms before the next attempt.
|
|
583
|
+
*
|
|
584
|
+
* If all attempts are exhausted, logs an error and returns silently so
|
|
585
|
+
* a single bad server doesn't block the rest of the batch.
|
|
586
|
+
*/
|
|
587
|
+
private establishConnectionWithRetries;
|
|
458
588
|
}
|
|
459
589
|
|
|
460
|
-
export { MCPClient as M,
|
|
590
|
+
export { MCPClient as M, type Session as S, MultiSessionClient as a, type SessionMutationEvent as b, type SessionMutationListener as c, type SessionMutationType as d, type SessionStore as e, StorageOAuthClientProvider as f };
|