@mcp-ts/sdk 2.3.3 → 2.4.0

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 (82) hide show
  1. package/README.md +113 -30
  2. package/dist/adapters/agui-adapter.d.mts +3 -3
  3. package/dist/adapters/agui-adapter.d.ts +3 -3
  4. package/dist/adapters/agui-middleware.d.mts +3 -3
  5. package/dist/adapters/agui-middleware.d.ts +3 -3
  6. package/dist/adapters/ai-adapter.d.mts +3 -3
  7. package/dist/adapters/ai-adapter.d.ts +3 -3
  8. package/dist/adapters/langchain-adapter.d.mts +3 -3
  9. package/dist/adapters/langchain-adapter.d.ts +3 -3
  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 +2 -2
  13. package/dist/client/index.d.ts +2 -2
  14. package/dist/client/index.js +2 -2
  15. package/dist/client/index.js.map +1 -1
  16. package/dist/client/index.mjs +2 -2
  17. package/dist/client/index.mjs.map +1 -1
  18. package/dist/client/react.d.mts +9 -8
  19. package/dist/client/react.d.ts +9 -8
  20. package/dist/client/react.js +66 -26
  21. package/dist/client/react.js.map +1 -1
  22. package/dist/client/react.mjs +67 -27
  23. package/dist/client/react.mjs.map +1 -1
  24. package/dist/client/vue.d.mts +6 -5
  25. package/dist/client/vue.d.ts +6 -5
  26. package/dist/client/vue.js +27 -17
  27. package/dist/client/vue.js.map +1 -1
  28. package/dist/client/vue.mjs +27 -17
  29. package/dist/client/vue.mjs.map +1 -1
  30. package/dist/{index-Cfjsme-a.d.mts → index-ByIjEReo.d.mts} +2 -2
  31. package/dist/{index-CmjMd2ac.d.ts → index-CtXvKl8N.d.ts} +2 -2
  32. package/dist/index.d.mts +5 -5
  33. package/dist/index.d.ts +5 -5
  34. package/dist/index.js +729 -397
  35. package/dist/index.js.map +1 -1
  36. package/dist/index.mjs +724 -396
  37. package/dist/index.mjs.map +1 -1
  38. package/dist/{multi-session-client-DYNe6az3.d.mts → multi-session-client-CIMUGF8S.d.mts} +15 -41
  39. package/dist/{multi-session-client-BYtguGJm.d.ts → multi-session-client-CnvZEGPY.d.ts} +15 -41
  40. package/dist/server/index.d.mts +45 -17
  41. package/dist/server/index.d.ts +45 -17
  42. package/dist/server/index.js +721 -391
  43. package/dist/server/index.js.map +1 -1
  44. package/dist/server/index.mjs +718 -391
  45. package/dist/server/index.mjs.map +1 -1
  46. package/dist/shared/index.d.mts +9 -8
  47. package/dist/shared/index.d.ts +9 -8
  48. package/dist/shared/index.js +7 -5
  49. package/dist/shared/index.js.map +1 -1
  50. package/dist/shared/index.mjs +5 -4
  51. package/dist/shared/index.mjs.map +1 -1
  52. package/dist/{tool-router-BMzhoNYt.d.ts → tool-router-CZMrOG8J.d.ts} +1 -1
  53. package/dist/{tool-router-BhHsvBfP.d.mts → tool-router-CuApsDiV.d.mts} +1 -1
  54. package/dist/{types-CxFaaZrM.d.mts → types-DCk_IF4L.d.mts} +5 -3
  55. package/dist/{types-CxFaaZrM.d.ts → types-DCk_IF4L.d.ts} +5 -3
  56. package/migrations/neon/20260513010000_install_mcp_sessions.sql +40 -3
  57. package/migrations/neon/20260513020000_add_session_cleanup_cron.sql +4 -4
  58. package/migrations/supabase/20260330195700_install_mcp_sessions.sql +67 -3
  59. package/migrations/supabase/20260421010000_add_session_cleanup_cron.sql +6 -6
  60. package/package.json +13 -3
  61. package/src/client/core/sse-client.ts +2 -2
  62. package/src/client/react/index.ts +1 -1
  63. package/src/client/react/oauth-popup.tsx +34 -13
  64. package/src/client/react/use-mcp.ts +19 -45
  65. package/src/client/utils/session-state.ts +43 -0
  66. package/src/client/vue/use-mcp.ts +18 -47
  67. package/src/server/handlers/sse-handler.ts +9 -4
  68. package/src/server/mcp/multi-session-client.ts +2 -6
  69. package/src/server/mcp/oauth-client.ts +73 -220
  70. package/src/server/mcp/storage-oauth-provider.ts +79 -50
  71. package/src/server/storage/file-backend.ts +74 -18
  72. package/src/server/storage/index.ts +2 -4
  73. package/src/server/storage/memory-backend.ts +49 -13
  74. package/src/server/storage/neon-backend.ts +201 -68
  75. package/src/server/storage/redis-backend.ts +81 -23
  76. package/src/server/storage/session-lifecycle.ts +78 -0
  77. package/src/server/storage/sqlite-backend.ts +89 -15
  78. package/src/server/storage/supabase-backend.ts +188 -63
  79. package/src/server/storage/types.ts +49 -16
  80. package/src/shared/constants.ts +5 -6
  81. package/src/shared/types.ts +5 -3
  82. package/src/shared/utils.ts +26 -0
@@ -5,6 +5,15 @@ import type {
5
5
  OAuthClientInformationMixed,
6
6
  } from '@modelcontextprotocol/sdk/shared/auth.js';
7
7
 
8
+ export interface OAuthState {
9
+ nonce: string;
10
+ sessionId: string;
11
+ serverId: string;
12
+ createdAt: number;
13
+ }
14
+
15
+ export type SessionStatus = 'pending' | 'active';
16
+
8
17
  export interface Session {
9
18
  sessionId: string;
10
19
  serverId?: string; // Database server ID for mapping
@@ -13,20 +22,31 @@ export interface Session {
13
22
  transportType: 'sse' | 'streamable-http';
14
23
  callbackUrl: string;
15
24
  createdAt: number;
25
+ updatedAt?: number;
26
+ /**
27
+ * Storage-owned expiration timestamp for pending/inactive sessions.
28
+ * Active sessions use updatedAt-based dormancy cleanup instead.
29
+ */
30
+ expiresAt?: number | null;
16
31
  userId: string;
17
32
  headers?: Record<string, string>;
33
+ authUrl?: string | null;
18
34
  /**
19
- * Session status marker used for TTL transitions:
20
- * - false: short-lived intermediate/error/auth-pending session state
21
- * (keep this value when connection/auth is incomplete or failed)
22
- * - true: active long-lived session state after successful connection/auth completion
23
- */
24
- active?: boolean;
25
- // OAuth data (consolidated)
26
- clientInformation?: OAuthClientInformationMixed;
27
- tokens?: OAuthTokens;
28
- codeVerifier?: string;
29
- clientId?: string;
35
+ * Session status marker used for lifecycle cleanup:
36
+ * - pending: short-lived intermediate/auth-pending session state
37
+ * - active: restorable session after successful connection/auth completion
38
+ */
39
+ status?: SessionStatus;
40
+ }
41
+
42
+ export interface SessionCredentials {
43
+ sessionId: string;
44
+ userId: string;
45
+ clientInformation?: OAuthClientInformationMixed | null;
46
+ tokens?: OAuthTokens | null;
47
+ codeVerifier?: string | null;
48
+ clientId?: string | null;
49
+ oauthState?: OAuthState | null;
30
50
  }
31
51
 
32
52
  export type SessionMutationType = 'create' | 'update' | 'delete';
@@ -38,7 +58,6 @@ export interface SessionMutationEvent {
38
58
  timestamp: number;
39
59
  session?: Session;
40
60
  patch?: Partial<Session>;
41
- ttl?: number;
42
61
  }
43
62
 
44
63
  export type SessionMutationListener = (event: SessionMutationEvent) => void | Promise<void>;
@@ -72,24 +91,38 @@ export interface SessionStore {
72
91
  /**
73
92
  * Creates a new session. Throws if session already exists.
74
93
  * @param session - Session data to create
75
- * @param ttl - Optional TTL in seconds (defaults to backend's default)
76
94
  */
77
- create(session: Session, ttl?: number): Promise<void>;
95
+ create(session: Session): Promise<void>;
78
96
 
79
97
  /**
80
98
  * Updates an existing session with partial data. Throws if session does not exist.
81
99
  * @param userId - User identifier
82
100
  * @param sessionId - Session identifier
83
101
  * @param data - Partial session data to update
84
- * @param ttl - Optional TTL in seconds (defaults to backend's default)
85
102
  */
86
- update(userId: string, sessionId: string, data: Partial<Session>, ttl?: number): Promise<void>;
103
+ update(userId: string, sessionId: string, data: Partial<Session>): Promise<void>;
104
+
105
+ /**
106
+ * Patches runtime credentials for an existing session.
107
+ * These values are separated from connection metadata in durable SQL stores.
108
+ */
109
+ patchCredentials(userId: string, sessionId: string, data: Partial<SessionCredentials>): Promise<void>;
87
110
 
88
111
  /**
89
112
  * Retrieves a session
90
113
  */
91
114
  get(userId: string, sessionId: string): Promise<Session | null>;
92
115
 
116
+ /**
117
+ * Retrieves runtime credentials for a session.
118
+ */
119
+ getCredentials(userId: string, sessionId: string): Promise<SessionCredentials | null>;
120
+
121
+ /**
122
+ * Clears runtime credentials without removing connection metadata.
123
+ */
124
+ clearCredentials(userId: string, sessionId: string): Promise<void>;
125
+
93
126
  /**
94
127
  * Gets full session data for all sessions owned by a user
95
128
  */
@@ -3,9 +3,11 @@
3
3
  * Eliminates magic numbers and enables consistent configuration
4
4
  */
5
5
 
6
- // Redis TTL and Session Management
7
- export const SESSION_TTL_SECONDS = 43200; // 12 hours
6
+ // Session lifecycle
8
7
  export const STATE_EXPIRATION_MS = 10 * 60 * 1000; // 10 minutes for OAuth state
8
+ export const PENDING_SESSION_EXPIRATION_SECONDS = Math.floor(STATE_EXPIRATION_MS / 1000);
9
+ export const DORMANT_SESSION_EXPIRATION_MS = 30 * 24 * 60 * 60 * 1000; // 30 days
10
+ export const DORMANT_SESSION_EXPIRATION_SECONDS = Math.floor(DORMANT_SESSION_EXPIRATION_MS / 1000);
9
11
 
10
12
  // Heartbeat and Connection
11
13
  export const DEFAULT_HEARTBEAT_INTERVAL_MS = 30000; // 30 seconds
@@ -13,16 +15,13 @@ export const DEFAULT_HEARTBEAT_INTERVAL_MS = 30000; // 30 seconds
13
15
  // Redis Key Prefixes
14
16
  export const REDIS_KEY_PREFIX = 'mcp:session:';
15
17
 
16
- // Token Management
17
- export const TOKEN_EXPIRY_BUFFER_MS = 5 * 60 * 1000; // 5 minute buffer before expiry
18
-
19
18
  // Client Information
20
19
  export const DEFAULT_CLIENT_NAME = 'MCP Assistant';
21
20
  export const DEFAULT_CLIENT_URI = 'https://mcp-assistant.in';
22
21
  export const DEFAULT_LOGO_URI = 'https://mcp-assistant.in/logo.svg';
23
22
  export const DEFAULT_POLICY_URI = 'https://mcp-assistant.in/privacy';
24
23
  export const SOFTWARE_ID = '@mcp-ts';
25
- export const SOFTWARE_VERSION = '1.3.4';
24
+ export const SOFTWARE_VERSION = '2.3.4';
26
25
 
27
26
  // MCP Client Configuration
28
27
  export const MCP_CLIENT_NAME = 'mcp-ts-oauth-client';
@@ -168,6 +168,7 @@ export type ToolInfo = {
168
168
 
169
169
  // Transport type
170
170
  export type TransportType = 'sse' | 'streamable-http';
171
+ export type SessionStatus = 'pending' | 'active';
171
172
 
172
173
  // SSE/RPC types
173
174
  export type McpRpcMethod =
@@ -234,7 +235,7 @@ export interface ReadResourceParams {
234
235
  }
235
236
 
236
237
  export interface FinishAuthParams {
237
- sessionId: string;
238
+ state: string;
238
239
  code: string;
239
240
  }
240
241
 
@@ -256,11 +257,12 @@ export interface SessionInfo {
256
257
  serverUrl: string;
257
258
  transport: TransportType;
258
259
  createdAt: number;
260
+ updatedAt?: number;
259
261
  /**
260
262
  * Session readiness for auto-restore.
261
- * false means auth is pending and should be resumed explicitly by user action.
263
+ * `pending` means auth is in progress and should be resumed explicitly by user action.
262
264
  */
263
- active?: boolean;
265
+ status: SessionStatus;
264
266
  }
265
267
 
266
268
  export interface SessionListResult {
@@ -1,5 +1,7 @@
1
1
  import { customAlphabet } from 'nanoid';
2
2
 
3
+ const OAUTH_STATE_SEPARATOR = '.';
4
+
3
5
  /** first char: letters only (required by OpenAI) */
4
6
  const firstChar = customAlphabet(
5
7
  'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz',
@@ -36,3 +38,27 @@ export function sanitizeServerLabel(name: string): string {
36
38
  export function generateSessionId(): string {
37
39
  return firstChar() + rest();
38
40
  }
41
+
42
+ export interface ParsedOAuthState {
43
+ nonce: string;
44
+ sessionId: string;
45
+ }
46
+
47
+ export function formatOAuthState(nonce: string, sessionId: string): string {
48
+ return `${nonce}${OAUTH_STATE_SEPARATOR}${sessionId}`;
49
+ }
50
+
51
+ export function parseOAuthState(state: string): ParsedOAuthState | undefined {
52
+ const separatorIndex = state.indexOf(OAUTH_STATE_SEPARATOR);
53
+ if (separatorIndex <= 0 || separatorIndex === state.length - 1) {
54
+ return undefined;
55
+ }
56
+
57
+ const nonce = state.slice(0, separatorIndex);
58
+ const sessionId = state.slice(separatorIndex + 1);
59
+ if (!nonce || !sessionId || sessionId.includes(OAUTH_STATE_SEPARATOR)) {
60
+ return undefined;
61
+ }
62
+
63
+ return { nonce, sessionId };
64
+ }