@mcp-ts/sdk 2.4.0 → 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/README.md +58 -19
- 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-CtXvKl8N.d.ts → index-B8kJSrBJ.d.ts} +1 -2
- package/dist/{index-ByIjEReo.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 +149 -90
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +149 -90
- package/dist/index.mjs.map +1 -1
- package/dist/{multi-session-client-CnvZEGPY.d.ts → multi-session-client-BluyCPo9.d.ts} +219 -66
- package/dist/{multi-session-client-CIMUGF8S.d.mts → multi-session-client-CWs-AE78.d.mts} +219 -66
- package/dist/server/index.d.mts +6 -129
- package/dist/server/index.d.ts +6 -129
- package/dist/server/index.js +149 -90
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +149 -90
- 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/shared/index.js.map +1 -1
- package/dist/shared/index.mjs.map +1 -1
- 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.ts → types-CjczQwNX.d.mts} +122 -1
- package/dist/{types-DCk_IF4L.d.mts → types-CjczQwNX.d.ts} +122 -1
- package/migrations/v2.3.4/neon/20260513010000_install_mcp_sessions.sql +69 -0
- package/migrations/v2.3.4/neon/20260513020000_add_session_cleanup_cron.sql +35 -0
- package/migrations/v2.3.4/supabase/20260330195700_install_mcp_sessions.sql +82 -0
- package/migrations/v2.3.4/supabase/20260421010000_add_session_cleanup_cron.sql +32 -0
- package/package.json +1 -1
- package/src/server/handlers/sse-handler.ts +7 -5
- package/src/server/mcp/multi-session-client.ts +186 -100
- package/src/server/mcp/oauth-client.ts +60 -10
- package/src/shared/events.ts +0 -1
- package/dist/events-CK3N--3g.d.mts +0 -123
- package/dist/events-CK3N--3g.d.ts +0 -123
|
@@ -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';
|
|
@@ -282,10 +282,15 @@ declare class MCPClient {
|
|
|
282
282
|
*/
|
|
283
283
|
isConnected(): boolean;
|
|
284
284
|
/**
|
|
285
|
-
* Disconnects from the MCP server and cleans up resources
|
|
286
|
-
* Does not remove session from Redis
|
|
285
|
+
* Disconnects from the MCP server and cleans up resources.
|
|
286
|
+
* Does not remove session from Redis — use clearSession() for that.
|
|
287
|
+
*
|
|
288
|
+
* For Streamable HTTP sessions, sends an HTTP DELETE to the MCP endpoint
|
|
289
|
+
* before closing, as recommended by the MCP Streamable HTTP spec
|
|
290
|
+
* (section "Session Management", rule 5). This is best-effort — errors
|
|
291
|
+
* (e.g. server already restarted, 404/405 responses) are silently ignored.
|
|
287
292
|
*/
|
|
288
|
-
disconnect(
|
|
293
|
+
disconnect(): Promise<void>;
|
|
289
294
|
/**
|
|
290
295
|
* Dispose of all event emitters
|
|
291
296
|
* Call this when the client is no longer needed
|
|
@@ -323,115 +328,263 @@ declare class MCPClient {
|
|
|
323
328
|
getSessionId(): string;
|
|
324
329
|
}
|
|
325
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>;
|
|
326
381
|
/**
|
|
327
|
-
*
|
|
328
|
-
* Allows aggregating tools from all connected servers.
|
|
382
|
+
* Interface for MCP session stores.
|
|
329
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
|
+
|
|
330
452
|
interface MultiSessionOptions {
|
|
331
453
|
/**
|
|
332
|
-
* Connection timeout in milliseconds
|
|
454
|
+
* Connection timeout in milliseconds.
|
|
333
455
|
* @default 15000
|
|
334
456
|
*/
|
|
335
457
|
timeout?: number;
|
|
336
458
|
/**
|
|
337
|
-
* Maximum number of retry attempts
|
|
459
|
+
* Maximum number of retry attempts per session.
|
|
338
460
|
* @default 2
|
|
339
461
|
*/
|
|
340
462
|
maxRetries?: number;
|
|
341
463
|
/**
|
|
342
|
-
* Delay between
|
|
464
|
+
* Delay between retry attempts in milliseconds.
|
|
343
465
|
* @default 1000
|
|
344
466
|
*/
|
|
345
467
|
retryDelay?: number;
|
|
468
|
+
/**
|
|
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).
|
|
473
|
+
*
|
|
474
|
+
* Default: reads from the storage backend via `sessions.list(userId)`.
|
|
475
|
+
*/
|
|
476
|
+
sessionProvider?: () => Promise<Session[]>;
|
|
477
|
+
/**
|
|
478
|
+
* Called after a session is successfully connected.
|
|
479
|
+
*/
|
|
480
|
+
onSessionConnected?: (sessionId: string, client: MCPClient) => void;
|
|
481
|
+
/**
|
|
482
|
+
* Called when a session is evicted from the in-memory client list
|
|
483
|
+
* because it no longer exists in the active sessions list.
|
|
484
|
+
*/
|
|
485
|
+
onSessionEvicted?: (sessionId: string) => void;
|
|
486
|
+
/**
|
|
487
|
+
* Called when all retry attempts for a session have been exhausted.
|
|
488
|
+
*/
|
|
489
|
+
onSessionFailed?: (sessionId: string, error: unknown) => void;
|
|
346
490
|
}
|
|
347
491
|
/**
|
|
348
492
|
* Manages multiple MCP client connections for a single user.
|
|
349
493
|
*
|
|
350
|
-
*
|
|
351
|
-
*
|
|
352
|
-
*
|
|
353
|
-
*
|
|
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}
|
|
354
500
|
*/
|
|
355
|
-
declare class MultiSessionClient {
|
|
501
|
+
declare class MultiSessionClient implements ToolClientProvider {
|
|
356
502
|
private clients;
|
|
503
|
+
private connectionPromises;
|
|
357
504
|
private userId;
|
|
358
505
|
private options;
|
|
359
506
|
/**
|
|
360
|
-
*
|
|
361
|
-
*
|
|
362
|
-
* @param userId - A unique string identifying the user (e.g. user ID or email).
|
|
363
|
-
* @param options - Optional tuning for connection timeout, retry count, and retry delay.
|
|
364
|
-
* Falls back to sensible defaults if not provided.
|
|
507
|
+
* @param userId - Unique identifier for the user (e.g. user ID or email).
|
|
508
|
+
* @param options - Optional tuning and lifecycle hooks.
|
|
365
509
|
*/
|
|
366
510
|
constructor(userId: string, options?: MultiSessionOptions);
|
|
367
511
|
/**
|
|
368
|
-
* Fetches
|
|
369
|
-
* ones that are ready to connect.
|
|
512
|
+
* Fetches active sessions and establishes connections to all of them.
|
|
370
513
|
*
|
|
371
|
-
*
|
|
372
|
-
*
|
|
373
|
-
*
|
|
374
|
-
* and let the OAuth flow complete separately before we try to reconnect them.
|
|
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.
|
|
375
517
|
*/
|
|
376
|
-
|
|
518
|
+
connect(): Promise<void>;
|
|
377
519
|
/**
|
|
378
|
-
*
|
|
520
|
+
* Drops all cached `MCPClient` instances and reconnects fresh from storage.
|
|
379
521
|
*
|
|
380
|
-
*
|
|
381
|
-
*
|
|
382
|
-
*
|
|
522
|
+
* Call this when downstream MCP servers have expired their transport sessions
|
|
523
|
+
* (e.g. after a remote server restart) and subsequent tool calls return
|
|
524
|
+
* "Session not found. Reconnect without session header." errors.
|
|
525
|
+
*
|
|
526
|
+
* OAuth tokens are preserved in the storage backend — no re-authentication
|
|
527
|
+
* is required. Only the in-memory transport sessions are cleared.
|
|
383
528
|
*/
|
|
384
|
-
|
|
385
|
-
private connectionPromises;
|
|
529
|
+
reconnect(): Promise<void>;
|
|
386
530
|
/**
|
|
387
|
-
*
|
|
531
|
+
* Returns all currently connected `MCPClient` instances.
|
|
388
532
|
*
|
|
389
|
-
*
|
|
390
|
-
*
|
|
391
|
-
* concurrent call), it joins the existing promise instead of starting a new one.
|
|
392
|
-
* This is the key concurrency lock — the `connectionPromises` map acts as a
|
|
393
|
-
* per-session mutex so we never spin up two physical connections for the same session.
|
|
394
|
-
* - On completion (success or failure), the promise is cleaned up from the map.
|
|
533
|
+
* Use this to enumerate available tools across all connected servers,
|
|
534
|
+
* or to route a tool call to the right client by `serverId`.
|
|
395
535
|
*/
|
|
396
|
-
|
|
536
|
+
getClients(): MCPClient[];
|
|
397
537
|
/**
|
|
398
|
-
*
|
|
538
|
+
* Gracefully disconnects all active MCP clients and clears the internal list.
|
|
399
539
|
*
|
|
400
|
-
*
|
|
401
|
-
*
|
|
402
|
-
*
|
|
403
|
-
* 2. Races the connect call against a timeout promise — if the server doesn't respond
|
|
404
|
-
* within `timeoutMs`, the attempt is aborted and counted as a failure.
|
|
405
|
-
* 3. On success, replaces any stale client entry for this session in the `clients` array.
|
|
406
|
-
* 4. On failure, waits `retryDelay` ms before the next attempt.
|
|
540
|
+
* For Streamable HTTP sessions, each client sends an HTTP DELETE to its MCP
|
|
541
|
+
* endpoint per the spec before closing locally. All disconnects run in
|
|
542
|
+
* parallel so shutdown is not serialised across many sessions.
|
|
407
543
|
*
|
|
408
|
-
*
|
|
409
|
-
*
|
|
544
|
+
* Call this during server shutdown or when a user logs out to free up
|
|
545
|
+
* underlying transport resources (SSE streams, HTTP connections, etc.).
|
|
410
546
|
*/
|
|
411
|
-
|
|
547
|
+
disconnect(): Promise<void>;
|
|
412
548
|
/**
|
|
413
|
-
*
|
|
414
|
-
* storage and establishes connections to all of them in batches.
|
|
549
|
+
* Resolves the list of sessions to connect.
|
|
415
550
|
*
|
|
416
|
-
*
|
|
417
|
-
*
|
|
418
|
-
* re-fetching and re-connecting on every request.
|
|
551
|
+
* Uses the custom `sessionProvider` when provided, otherwise falls back
|
|
552
|
+
* to querying the storage backend via `sessions.list(userId)`.
|
|
419
553
|
*/
|
|
420
|
-
|
|
554
|
+
private fetchActiveSessions;
|
|
421
555
|
/**
|
|
422
|
-
*
|
|
556
|
+
* Connects a list of sessions in controlled batches.
|
|
423
557
|
*
|
|
424
|
-
*
|
|
425
|
-
*
|
|
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`.
|
|
426
561
|
*/
|
|
427
|
-
|
|
562
|
+
private connectInBatches;
|
|
428
563
|
/**
|
|
429
|
-
*
|
|
564
|
+
* Connects a single session, with deduplication to prevent race conditions.
|
|
430
565
|
*
|
|
431
|
-
*
|
|
432
|
-
*
|
|
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.
|
|
433
574
|
*/
|
|
434
|
-
|
|
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;
|
|
435
588
|
}
|
|
436
589
|
|
|
437
|
-
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 };
|