@mcp-ts/sdk 2.3.3 → 2.3.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mcp-ts/sdk",
3
- "version": "2.3.3",
3
+ "version": "2.3.4",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -4,9 +4,6 @@ import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/
4
4
  import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';
5
5
  import {
6
6
  UnauthorizedError as SDKUnauthorizedError,
7
- refreshAuthorization,
8
- discoverOAuthProtectedResourceMetadata,
9
- discoverAuthorizationServerMetadata,
10
7
  } from '@modelcontextprotocol/sdk/client/auth.js';
11
8
  import {
12
9
  ListToolsRequest,
@@ -28,7 +25,6 @@ import {
28
25
  ReadResourceResult,
29
26
  ReadResourceResultSchema,
30
27
  } from '@modelcontextprotocol/sdk/types.js';
31
- import type { OAuthTokens, OAuthClientInformationFull } from '@modelcontextprotocol/sdk/shared/auth.js';
32
28
  import { StorageOAuthClientProvider, type AgentsOAuthProvider } from './storage-oauth-provider.js';
33
29
  import { sanitizeServerLabel } from '../../shared/utils.js';
34
30
  import { Emitter, type McpConnectionEvent, type McpObservabilityEvent, type McpConnectionState } from '../../shared/events.js';
@@ -60,20 +56,6 @@ interface McpAppClientCapabilities extends Omit<ClientCapabilities, 'extensions'
60
56
  };
61
57
  }
62
58
 
63
- function isInvalidRefreshTokenError(error: unknown): boolean {
64
- if (!(error instanceof Error)) {
65
- return false;
66
- }
67
-
68
- const text = `${error.name} ${error.message}`.toLowerCase();
69
- return (
70
- text.includes('invalidgrant') ||
71
- text.includes('invalid_grant') ||
72
- text.includes('invalid refresh token') ||
73
- /refresh\s+token\s+(?:is\s+)?(?:invalid|expired|revoked)/i.test(text)
74
- );
75
- }
76
-
77
59
  export interface MCPOAuthClientOptions {
78
60
  serverUrl?: string;
79
61
  serverName?: string;
@@ -504,9 +486,6 @@ export class MCPClient {
504
486
  }
505
487
 
506
488
  try {
507
- this.emitProgress('Validating OAuth tokens...');
508
- await this.getValidTokens();
509
-
510
489
  this.emitStateChange('CONNECTING');
511
490
 
512
491
  /** Use the tryConnect loop to handle transport fallbacks */
@@ -947,79 +926,6 @@ export class MCPClient {
947
926
  return await this.client.request(request, ReadResourceResultSchema);
948
927
  }
949
928
 
950
- /**
951
- * Refreshes the OAuth access token using the refresh token
952
- * Discovers OAuth metadata from server and exchanges refresh token for new access token
953
- * @returns True if refresh was successful, false otherwise
954
- */
955
- async refreshToken(): Promise<boolean> {
956
- await this.initialize();
957
-
958
- if (!this.oauthProvider) {
959
- return false;
960
- }
961
-
962
- const tokens = await this.oauthProvider.tokens();
963
- if (!tokens || !tokens.refresh_token) {
964
- return false;
965
- }
966
-
967
- const clientInformation = await this.oauthProvider.clientInformation();
968
- if (!clientInformation) {
969
- return false;
970
- }
971
-
972
- try {
973
- const resourceMetadata = await discoverOAuthProtectedResourceMetadata(this.serverUrl!);
974
- const authServerUrl = resourceMetadata?.authorization_servers?.[0] || this.serverUrl!;
975
- const authMetadata = await discoverAuthorizationServerMetadata(authServerUrl);
976
-
977
- const newTokens = await refreshAuthorization(authServerUrl, {
978
- metadata: authMetadata,
979
- clientInformation,
980
- refreshToken: tokens.refresh_token,
981
- });
982
-
983
- await this.oauthProvider.saveTokens(newTokens);
984
- return true;
985
- } catch (error) {
986
- console.error('[OAuth] Token refresh failed:', error);
987
- if (isInvalidRefreshTokenError(error)) {
988
- try {
989
- await this.oauthProvider.invalidateCredentials?.('tokens');
990
- this.emitProgress('OAuth refresh token is invalid; requesting reauthorization...');
991
- } catch (invalidateError) {
992
- console.warn('[OAuth] Failed to invalidate stale refresh token credentials:', invalidateError);
993
- }
994
- }
995
- return false;
996
- }
997
- }
998
-
999
- /**
1000
- * Ensures OAuth tokens are valid, refreshing them if expired
1001
- * Called automatically by connect() - rarely needs to be called manually
1002
- * @returns True if valid tokens are available, false otherwise
1003
- */
1004
- async getValidTokens(): Promise<boolean> {
1005
- await this.initialize();
1006
-
1007
- if (!this.oauthProvider) {
1008
- return false;
1009
- }
1010
-
1011
- const tokens = await this.oauthProvider.tokens();
1012
- if (!tokens) {
1013
- return false;
1014
- }
1015
-
1016
- if (this.oauthProvider.isTokenExpired()) {
1017
- return await this.refreshToken();
1018
- }
1019
-
1020
- return true;
1021
- }
1022
-
1023
929
  /**
1024
930
  * Reconnects to MCP server using existing OAuth provider from Redis
1025
931
  * Used for session restoration in serverless environments
@@ -1176,10 +1082,14 @@ export class MCPClient {
1176
1082
 
1177
1083
  /**
1178
1084
  * Gets MCP server configuration for all active user sessions
1179
- * Loads sessions from Redis, validates OAuth tokens, refreshes if expired
1180
- * Returns ready-to-use configuration with valid auth headers
1085
+ * Loads sessions from storage and returns server connection metadata.
1086
+ * OAuth refresh is handled by SDK transports through their authProvider.
1087
+ * @deprecated This returns legacy connection metadata only and does not
1088
+ * include OAuth tokens or generated Authorization headers. Prefer
1089
+ * MultiSessionClient or explicit MCPClient instances so SDK transports can
1090
+ * own OAuth refresh and reauthorization.
1181
1091
  * @param userId - User ID to fetch sessions for
1182
- * @returns Object keyed by sanitized server labels containing transport, url, headers, etc.
1092
+ * @returns Object keyed by sanitized server labels containing transport and url.
1183
1093
  * @static
1184
1094
  */
1185
1095
  static async getMcpServerConfig(userId: string): Promise<Record<string, any>> {
@@ -1202,34 +1112,6 @@ export class MCPClient {
1202
1112
  return;
1203
1113
  }
1204
1114
 
1205
- // Get OAuth headers if session requires authentication
1206
- let headers: Record<string, string> | undefined;
1207
- try {
1208
- // Inject existing session data to avoid redundant session store reads in initialize()
1209
- const client = new MCPClient({
1210
- userId,
1211
- sessionId,
1212
- serverId: sessionData.serverId,
1213
- serverUrl: sessionData.serverUrl,
1214
- callbackUrl: sessionData.callbackUrl,
1215
- serverName: sessionData.serverName,
1216
- transportType: sessionData.transportType,
1217
- headers: sessionData.headers,
1218
- });
1219
-
1220
- await client.initialize();
1221
-
1222
- const hasValidTokens = await client.getValidTokens();
1223
- if (hasValidTokens && client.oauthProvider) {
1224
- const tokens = await client.oauthProvider.tokens();
1225
- if (tokens?.access_token) {
1226
- headers = { Authorization: `Bearer ${tokens.access_token}` };
1227
- }
1228
- }
1229
- } catch (error) {
1230
- console.warn(`[MCP] Failed to get OAuth tokens for ${sessionId}:`, error);
1231
- }
1232
-
1233
1115
  // Build server config
1234
1116
  const label = sanitizeServerLabel(
1235
1117
  sessionData.serverName || sessionData.serverId || 'server'
@@ -1242,7 +1124,6 @@ export class MCPClient {
1242
1124
  serverName: sessionData.serverName,
1243
1125
  serverLabel: label,
1244
1126
  }),
1245
- ...(headers && { headers }),
1246
1127
  };
1247
1128
  } catch (error) {
1248
1129
  await sessions.delete(userId, sessionId);
@@ -180,7 +180,7 @@ export class NeonStorageBackend implements SessionStore {
180
180
  updatedSession.active ?? false,
181
181
  encryptObject(updatedSession.headers),
182
182
  updatedSession.clientInformation,
183
- encryptObject(updatedSession.tokens),
183
+ updatedSession.tokens === undefined ? null : encryptObject(updatedSession.tokens),
184
184
  updatedSession.codeVerifier,
185
185
  updatedSession.clientId,
186
186
  expiresAt,
@@ -107,7 +107,7 @@ export class SupabaseStorageBackend implements SessionStore {
107
107
  if ('active' in data) updateData.active = data.active;
108
108
  if ('headers' in data) updateData.headers = encryptObject(data.headers);
109
109
  if ('clientInformation' in data) updateData.client_information = data.clientInformation;
110
- if ('tokens' in data) updateData.tokens = encryptObject(data.tokens);
110
+ if ('tokens' in data) updateData.tokens = data.tokens === undefined ? null : encryptObject(data.tokens);
111
111
  if ('codeVerifier' in data) updateData.code_verifier = data.codeVerifier;
112
112
  if ('clientId' in data) updateData.client_id = data.clientId;
113
113