@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.
- package/README.md +113 -30
- package/dist/adapters/agui-adapter.d.mts +3 -3
- package/dist/adapters/agui-adapter.d.ts +3 -3
- package/dist/adapters/agui-middleware.d.mts +3 -3
- package/dist/adapters/agui-middleware.d.ts +3 -3
- package/dist/adapters/ai-adapter.d.mts +3 -3
- package/dist/adapters/ai-adapter.d.ts +3 -3
- package/dist/adapters/langchain-adapter.d.mts +3 -3
- package/dist/adapters/langchain-adapter.d.ts +3 -3
- package/dist/adapters/mastra-adapter.d.mts +1 -1
- package/dist/adapters/mastra-adapter.d.ts +1 -1
- package/dist/client/index.d.mts +2 -2
- package/dist/client/index.d.ts +2 -2
- package/dist/client/index.js +2 -2
- package/dist/client/index.js.map +1 -1
- package/dist/client/index.mjs +2 -2
- package/dist/client/index.mjs.map +1 -1
- package/dist/client/react.d.mts +9 -8
- package/dist/client/react.d.ts +9 -8
- package/dist/client/react.js +66 -26
- package/dist/client/react.js.map +1 -1
- package/dist/client/react.mjs +67 -27
- package/dist/client/react.mjs.map +1 -1
- package/dist/client/vue.d.mts +6 -5
- package/dist/client/vue.d.ts +6 -5
- package/dist/client/vue.js +27 -17
- package/dist/client/vue.js.map +1 -1
- package/dist/client/vue.mjs +27 -17
- package/dist/client/vue.mjs.map +1 -1
- package/dist/{index-Cfjsme-a.d.mts → index-ByIjEReo.d.mts} +2 -2
- package/dist/{index-CmjMd2ac.d.ts → index-CtXvKl8N.d.ts} +2 -2
- package/dist/index.d.mts +5 -5
- package/dist/index.d.ts +5 -5
- package/dist/index.js +729 -397
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +724 -396
- package/dist/index.mjs.map +1 -1
- package/dist/{multi-session-client-DYNe6az3.d.mts → multi-session-client-CIMUGF8S.d.mts} +15 -41
- package/dist/{multi-session-client-BYtguGJm.d.ts → multi-session-client-CnvZEGPY.d.ts} +15 -41
- package/dist/server/index.d.mts +45 -17
- package/dist/server/index.d.ts +45 -17
- package/dist/server/index.js +721 -391
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +718 -391
- package/dist/server/index.mjs.map +1 -1
- package/dist/shared/index.d.mts +9 -8
- package/dist/shared/index.d.ts +9 -8
- package/dist/shared/index.js +7 -5
- package/dist/shared/index.js.map +1 -1
- package/dist/shared/index.mjs +5 -4
- package/dist/shared/index.mjs.map +1 -1
- package/dist/{tool-router-BMzhoNYt.d.ts → tool-router-CZMrOG8J.d.ts} +1 -1
- package/dist/{tool-router-BhHsvBfP.d.mts → tool-router-CuApsDiV.d.mts} +1 -1
- package/dist/{types-CxFaaZrM.d.mts → types-DCk_IF4L.d.mts} +5 -3
- package/dist/{types-CxFaaZrM.d.ts → types-DCk_IF4L.d.ts} +5 -3
- package/migrations/neon/20260513010000_install_mcp_sessions.sql +40 -3
- package/migrations/neon/20260513020000_add_session_cleanup_cron.sql +4 -4
- package/migrations/supabase/20260330195700_install_mcp_sessions.sql +67 -3
- package/migrations/supabase/20260421010000_add_session_cleanup_cron.sql +6 -6
- package/package.json +13 -3
- package/src/client/core/sse-client.ts +2 -2
- package/src/client/react/index.ts +1 -1
- package/src/client/react/oauth-popup.tsx +34 -13
- package/src/client/react/use-mcp.ts +19 -45
- package/src/client/utils/session-state.ts +43 -0
- package/src/client/vue/use-mcp.ts +18 -47
- package/src/server/handlers/sse-handler.ts +9 -4
- package/src/server/mcp/multi-session-client.ts +2 -6
- package/src/server/mcp/oauth-client.ts +73 -220
- package/src/server/mcp/storage-oauth-provider.ts +79 -50
- package/src/server/storage/file-backend.ts +74 -18
- package/src/server/storage/index.ts +2 -4
- package/src/server/storage/memory-backend.ts +49 -13
- package/src/server/storage/neon-backend.ts +201 -68
- package/src/server/storage/redis-backend.ts +81 -23
- package/src/server/storage/session-lifecycle.ts +78 -0
- package/src/server/storage/sqlite-backend.ts +89 -15
- package/src/server/storage/supabase-backend.ts +188 -63
- package/src/server/storage/types.ts +49 -16
- package/src/shared/constants.ts +5 -6
- package/src/shared/types.ts +5 -3
- 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
|
|
20
|
-
* -
|
|
21
|
-
*
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|
|
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
|
|
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
|
*/
|
package/src/shared/constants.ts
CHANGED
|
@@ -3,9 +3,11 @@
|
|
|
3
3
|
* Eliminates magic numbers and enables consistent configuration
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
//
|
|
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 = '
|
|
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';
|
package/src/shared/types.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
-
*
|
|
263
|
+
* `pending` means auth is in progress and should be resumed explicitly by user action.
|
|
262
264
|
*/
|
|
263
|
-
|
|
265
|
+
status: SessionStatus;
|
|
264
266
|
}
|
|
265
267
|
|
|
266
268
|
export interface SessionListResult {
|
package/src/shared/utils.ts
CHANGED
|
@@ -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
|
+
}
|