@mcp-ts/sdk 2.4.2 → 2.4.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.
Files changed (56) hide show
  1. package/dist/adapters/agui-adapter.d.mts +3 -3
  2. package/dist/adapters/agui-adapter.d.ts +3 -3
  3. package/dist/adapters/agui-middleware.d.mts +3 -3
  4. package/dist/adapters/agui-middleware.d.ts +3 -3
  5. package/dist/adapters/ai-adapter.d.mts +3 -3
  6. package/dist/adapters/ai-adapter.d.ts +3 -3
  7. package/dist/adapters/langchain-adapter.d.mts +3 -3
  8. package/dist/adapters/langchain-adapter.d.ts +3 -3
  9. package/dist/adapters/mastra-adapter.d.mts +2 -2
  10. package/dist/adapters/mastra-adapter.d.ts +2 -2
  11. package/dist/bin/mcp-ts.js +5 -5
  12. package/dist/bin/mcp-ts.js.map +1 -1
  13. package/dist/bin/mcp-ts.mjs +5 -5
  14. package/dist/bin/mcp-ts.mjs.map +1 -1
  15. package/dist/client/index.d.mts +2 -2
  16. package/dist/client/index.d.ts +2 -2
  17. package/dist/client/react.d.mts +4 -5
  18. package/dist/client/react.d.ts +4 -5
  19. package/dist/client/react.js.map +1 -1
  20. package/dist/client/react.mjs.map +1 -1
  21. package/dist/client/vue.d.mts +4 -5
  22. package/dist/client/vue.d.ts +4 -5
  23. package/dist/client/vue.js.map +1 -1
  24. package/dist/client/vue.mjs.map +1 -1
  25. package/dist/{index-B8kJSrBJ.d.ts → index-CZk2gu2E.d.ts} +1 -1
  26. package/dist/{index-DiJsm_lK.d.mts → index-CkM3p0eE.d.mts} +1 -1
  27. package/dist/index.d.mts +4 -4
  28. package/dist/index.d.ts +4 -4
  29. package/dist/index.js +99 -63
  30. package/dist/index.js.map +1 -1
  31. package/dist/index.mjs +99 -63
  32. package/dist/index.mjs.map +1 -1
  33. package/dist/{multi-session-client-CWs-AE78.d.mts → multi-session-client-ChQrBZhF.d.mts} +21 -5
  34. package/dist/{multi-session-client-BluyCPo9.d.ts → multi-session-client-QOOPdEVp.d.ts} +21 -5
  35. package/dist/server/index.d.mts +4 -4
  36. package/dist/server/index.d.ts +4 -4
  37. package/dist/server/index.js +99 -63
  38. package/dist/server/index.js.map +1 -1
  39. package/dist/server/index.mjs +99 -63
  40. package/dist/server/index.mjs.map +1 -1
  41. package/dist/shared/index.d.mts +4 -4
  42. package/dist/shared/index.d.ts +4 -4
  43. package/dist/shared/index.js.map +1 -1
  44. package/dist/shared/index.mjs.map +1 -1
  45. package/dist/{tool-router-CbG4Tum6.d.mts → tool-router-CGs3IDOJ.d.mts} +1 -1
  46. package/dist/{tool-router-ChIhPwgP.d.ts → tool-router-DQ-HrD7W.d.ts} +1 -1
  47. package/dist/{types-CjczQwNX.d.mts → types-Bf-7GOLW.d.mts} +0 -2
  48. package/dist/{types-CjczQwNX.d.ts → types-Bf-7GOLW.d.ts} +0 -2
  49. package/package.json +1 -1
  50. package/src/bin/mcp-ts.ts +5 -5
  51. package/src/client/react/use-mcp.ts +0 -1
  52. package/src/client/vue/use-mcp.ts +0 -1
  53. package/src/server/mcp/multi-session-client.ts +13 -0
  54. package/src/server/mcp/oauth-client.ts +82 -75
  55. package/src/server/storage/index.ts +8 -8
  56. package/src/shared/events.ts +0 -2
package/dist/index.js CHANGED
@@ -1741,12 +1741,12 @@ async function createStorage() {
1741
1741
  }
1742
1742
  if (type === "supabase") {
1743
1743
  const url = process.env.SUPABASE_URL;
1744
- const key = process.env.SUPABASE_SERVICE_ROLE_KEY || process.env.SUPABASE_ANON_KEY;
1744
+ const key = process.env.SUPABASE_SECRET_KEY || process.env.SUPABASE_ANON_KEY;
1745
1745
  if (!url || !key) {
1746
- console.warn('[mcp-ts][Storage] Explicit selection "supabase" requires SUPABASE_URL and SUPABASE_SERVICE_ROLE_KEY.');
1746
+ console.warn('[mcp-ts][Storage] Explicit selection "supabase" requires SUPABASE_URL and SUPABASE_SECRET_KEY.');
1747
1747
  } else {
1748
- if (!process.env.SUPABASE_SERVICE_ROLE_KEY) {
1749
- console.warn('[mcp-ts][Storage] \u26A0\uFE0F Warning: Using "SUPABASE_ANON_KEY" for server-side storage. You may encounter RLS policy violations. "SUPABASE_SERVICE_ROLE_KEY" is recommended.');
1748
+ if (!process.env.SUPABASE_SECRET_KEY) {
1749
+ console.warn('[mcp-ts][Storage] \u26A0\uFE0F Warning: Using "SUPABASE_ANON_KEY" for server-side storage. You may encounter RLS policy violations. "SUPABASE_SECRET_KEY" is recommended.');
1750
1750
  }
1751
1751
  try {
1752
1752
  const { createClient } = await import('@supabase/supabase-js');
@@ -1801,13 +1801,13 @@ async function createStorage() {
1801
1801
  console.log(`[mcp-ts][Storage] Auto-detection: "sqlite" (${process.env.MCP_TS_STORAGE_SQLITE_PATH})`);
1802
1802
  return await initializeStorage(new SqliteStorage({ path: process.env.MCP_TS_STORAGE_SQLITE_PATH }));
1803
1803
  }
1804
- if (process.env.SUPABASE_URL && (process.env.SUPABASE_SERVICE_ROLE_KEY || process.env.SUPABASE_ANON_KEY)) {
1804
+ if (process.env.SUPABASE_URL && (process.env.SUPABASE_SECRET_KEY || process.env.SUPABASE_ANON_KEY)) {
1805
1805
  try {
1806
1806
  const { createClient } = await import('@supabase/supabase-js');
1807
1807
  const url = process.env.SUPABASE_URL;
1808
- const key = process.env.SUPABASE_SERVICE_ROLE_KEY || process.env.SUPABASE_ANON_KEY;
1809
- if (!process.env.SUPABASE_SERVICE_ROLE_KEY) {
1810
- console.warn('[mcp-ts][Storage] \u26A0\uFE0F Warning: Using "SUPABASE_ANON_KEY" for server-side storage. You may encounter RLS policy violations. "SUPABASE_SERVICE_ROLE_KEY" is recommended.');
1808
+ const key = process.env.SUPABASE_SECRET_KEY || process.env.SUPABASE_ANON_KEY;
1809
+ if (!process.env.SUPABASE_SECRET_KEY) {
1810
+ console.warn('[mcp-ts][Storage] \u26A0\uFE0F Warning: Using "SUPABASE_ANON_KEY" for server-side storage. You may encounter RLS policy violations. "SUPABASE_SECRET_KEY" is recommended.');
1811
1811
  }
1812
1812
  const client = createClient(url, key);
1813
1813
  console.log('[mcp-ts][Storage] Auto-detection: "supabase" (via SUPABASE_URL)');
@@ -2224,7 +2224,7 @@ var MCPClient = class {
2224
2224
  * @param options - Client configuration options
2225
2225
  */
2226
2226
  constructor(options) {
2227
- __publicField(this, "client", null);
2227
+ __publicField(this, "client");
2228
2228
  __publicField(this, "oauthProvider", null);
2229
2229
  __publicField(this, "transport", null);
2230
2230
  __publicField(this, "userId");
@@ -2265,6 +2265,21 @@ var MCPClient = class {
2265
2265
  this.clientUri = options.clientUri;
2266
2266
  this.logoUri = options.logoUri;
2267
2267
  this.policyUri = options.policyUri;
2268
+ this.client = new index_js.Client(
2269
+ {
2270
+ name: MCP_CLIENT_NAME,
2271
+ version: MCP_CLIENT_VERSION
2272
+ },
2273
+ {
2274
+ capabilities: {
2275
+ extensions: {
2276
+ "io.modelcontextprotocol/ui": {
2277
+ mimeTypes: ["text/html+mcp"]
2278
+ }
2279
+ }
2280
+ }
2281
+ }
2282
+ );
2268
2283
  }
2269
2284
  /**
2270
2285
  * Emit a connection state change event
@@ -2375,7 +2390,6 @@ var MCPClient = class {
2375
2390
  const response = await fetch(url, { ...init, signal });
2376
2391
  const hasSessionHeader = init?.headers && new Headers(init.headers).has("mcp-session-id");
2377
2392
  if (response.status === 404 && hasSessionHeader) {
2378
- this.client = null;
2379
2393
  throw new Error("MCP_SESSION_EXPIRED: Downstream session was not found on the server.");
2380
2394
  }
2381
2395
  return response;
@@ -2391,13 +2405,12 @@ var MCPClient = class {
2391
2405
  }
2392
2406
  }
2393
2407
  /**
2394
- * Initializes client components (client, transport, OAuth provider)
2395
- * Loads missing configuration from Redis session store if needed
2396
- * This method is idempotent and safe to call multiple times
2408
+ * Ensures session metadata and OAuth provider are loaded.
2409
+ * Does NOT create the SDK Client callers that need one create it themselves.
2397
2410
  * @private
2398
2411
  */
2399
- async initialize() {
2400
- if (this.client && this.oauthProvider) {
2412
+ async ensureSession() {
2413
+ if (this.oauthProvider) {
2401
2414
  return;
2402
2415
  }
2403
2416
  this.emitStateChange("INITIALIZING");
@@ -2440,23 +2453,6 @@ var MCPClient = class {
2440
2453
  }
2441
2454
  });
2442
2455
  }
2443
- if (!this.client) {
2444
- this.client = new index_js.Client(
2445
- {
2446
- name: MCP_CLIENT_NAME,
2447
- version: MCP_CLIENT_VERSION
2448
- },
2449
- {
2450
- capabilities: {
2451
- extensions: {
2452
- "io.modelcontextprotocol/ui": {
2453
- mimeTypes: ["text/html+mcp"]
2454
- }
2455
- }
2456
- }
2457
- }
2458
- );
2459
- }
2460
2456
  if (existingSession === null) {
2461
2457
  existingSession = await sessions.get(this.userId, this.sessionId);
2462
2458
  }
@@ -2573,17 +2569,16 @@ var MCPClient = class {
2573
2569
  * @throws {Error} When connection fails for other reasons
2574
2570
  */
2575
2571
  async connect() {
2576
- if (this.client?.transport) {
2572
+ if (this.client.transport) {
2577
2573
  this.transport = null;
2578
2574
  try {
2579
2575
  await this.client.close();
2580
2576
  } catch {
2581
2577
  }
2582
- this.client = null;
2583
2578
  }
2584
- await this.initialize();
2585
- if (!this.client || !this.oauthProvider) {
2586
- const error = "Client or OAuth provider not initialized";
2579
+ await this.ensureSession();
2580
+ if (!this.oauthProvider) {
2581
+ const error = "OAuth provider not initialized";
2587
2582
  this.emitError(error, "connection");
2588
2583
  this.emitStateChange("FAILED");
2589
2584
  throw new Error(error);
@@ -2650,7 +2645,7 @@ var MCPClient = class {
2650
2645
  async finishAuth(authCode, state) {
2651
2646
  this.emitStateChange("AUTHENTICATING");
2652
2647
  this.emitProgress("Exchanging authorization code for tokens...");
2653
- await this.initialize();
2648
+ await this.ensureSession();
2654
2649
  if (!this.oauthProvider) {
2655
2650
  const error = "OAuth provider not initialized";
2656
2651
  this.emitError(error, "auth");
@@ -2756,7 +2751,9 @@ var MCPClient = class {
2756
2751
  method: "tools/list",
2757
2752
  params: {}
2758
2753
  };
2759
- const result = await this.client.request(request, types_js.ListToolsResultSchema);
2754
+ const result = await this.withRetry(
2755
+ () => this.client.request(request, types_js.ListToolsResultSchema)
2756
+ );
2760
2757
  if (this.serverId) {
2761
2758
  this._onConnectionEvent.fire({
2762
2759
  type: "tools_discovered",
@@ -2796,7 +2793,9 @@ var MCPClient = class {
2796
2793
  }
2797
2794
  };
2798
2795
  try {
2799
- const result = await this.client.request(request, types_js.CallToolResultSchema);
2796
+ const result = await this.withRetry(
2797
+ () => this.client.request(request, types_js.CallToolResultSchema)
2798
+ );
2800
2799
  this._onObservabilityEvent.fire({
2801
2800
  type: "mcp:client:tool_call",
2802
2801
  level: "info",
@@ -2848,7 +2847,9 @@ var MCPClient = class {
2848
2847
  method: "prompts/list",
2849
2848
  params: {}
2850
2849
  };
2851
- const result = await this.client.request(request, types_js.ListPromptsResultSchema);
2850
+ const result = await this.withRetry(
2851
+ () => this.client.request(request, types_js.ListPromptsResultSchema)
2852
+ );
2852
2853
  this.emitStateChange("READY");
2853
2854
  this.emitProgress(`Discovered ${result.prompts.length} prompts`);
2854
2855
  return result;
@@ -2877,7 +2878,9 @@ var MCPClient = class {
2877
2878
  arguments: args
2878
2879
  }
2879
2880
  };
2880
- return await this.client.request(request, types_js.GetPromptResultSchema);
2881
+ return await this.withRetry(
2882
+ () => this.client.request(request, types_js.GetPromptResultSchema)
2883
+ );
2881
2884
  }
2882
2885
  /**
2883
2886
  * Lists all available resources from the connected MCP server
@@ -2894,7 +2897,9 @@ var MCPClient = class {
2894
2897
  method: "resources/list",
2895
2898
  params: {}
2896
2899
  };
2897
- const result = await this.client.request(request, types_js.ListResourcesResultSchema);
2900
+ const result = await this.withRetry(
2901
+ () => this.client.request(request, types_js.ListResourcesResultSchema)
2902
+ );
2898
2903
  this.emitStateChange("READY");
2899
2904
  this.emitProgress(`Discovered ${result.resources.length} resources`);
2900
2905
  return result;
@@ -2921,7 +2926,35 @@ var MCPClient = class {
2921
2926
  uri
2922
2927
  }
2923
2928
  };
2924
- return await this.client.request(request, types_js.ReadResourceResultSchema);
2929
+ return await this.withRetry(
2930
+ () => this.client.request(request, types_js.ReadResourceResultSchema)
2931
+ );
2932
+ }
2933
+ /**
2934
+ * Wraps an MCP request with automatic transport-session recovery.
2935
+ *
2936
+ * When the downstream MCP server rejects the request with a 404 indicating
2937
+ * the transport session has expired, this method tears down the stale SDK
2938
+ * client and transport, calls {@link reconnect} to negotiate a fresh session,
2939
+ * and retries the request once.
2940
+ *
2941
+ * Non-transient errors (network failures, auth errors, etc.) propagate as-is.
2942
+ */
2943
+ async withRetry(fn) {
2944
+ try {
2945
+ return await fn();
2946
+ } catch (error) {
2947
+ if (!(error instanceof Error && error.message.includes("MCP_SESSION_EXPIRED"))) throw error;
2948
+ if (this.client.transport) {
2949
+ try {
2950
+ await this.client.close();
2951
+ } catch {
2952
+ }
2953
+ this.transport = null;
2954
+ }
2955
+ await this.reconnect();
2956
+ return await fn();
2957
+ }
2925
2958
  }
2926
2959
  /**
2927
2960
  * Reconnects to MCP server using existing OAuth provider from Redis
@@ -2930,20 +2963,9 @@ var MCPClient = class {
2930
2963
  * @throws {Error} When OAuth provider is not initialized
2931
2964
  */
2932
2965
  async reconnect() {
2933
- await this.initialize();
2934
- if (!this.oauthProvider) {
2935
- throw new Error("OAuth provider not initialized");
2936
- }
2937
- this.client = new index_js.Client(
2938
- {
2939
- name: MCP_CLIENT_NAME,
2940
- version: MCP_CLIENT_VERSION
2941
- },
2942
- { capabilities: {} }
2943
- );
2944
- const tt = this.transportType || "streamable-http";
2945
- this.transport = this.getTransport(tt);
2946
- await this.client.connect(this.transport);
2966
+ await this.ensureSession();
2967
+ if (!this.oauthProvider) throw new Error("OAuth provider not initialized");
2968
+ await this.connect();
2947
2969
  }
2948
2970
  /**
2949
2971
  * Completely removes the session from Redis including all OAuth data
@@ -2951,7 +2973,7 @@ var MCPClient = class {
2951
2973
  */
2952
2974
  async clearSession() {
2953
2975
  try {
2954
- await this.initialize();
2976
+ await this.ensureSession();
2955
2977
  } catch (error) {
2956
2978
  console.warn("[MCPClient] Initialization failed during clearSession:", error);
2957
2979
  }
@@ -2966,7 +2988,7 @@ var MCPClient = class {
2966
2988
  * @returns True if connected, false otherwise
2967
2989
  */
2968
2990
  isConnected() {
2969
- return this.client !== null;
2991
+ return this.client.transport !== void 0;
2970
2992
  }
2971
2993
  /**
2972
2994
  * Disconnects from the MCP server and cleans up resources.
@@ -2984,10 +3006,12 @@ var MCPClient = class {
2984
3006
  } catch {
2985
3007
  }
2986
3008
  }
2987
- if (this.client) {
2988
- this.client.close();
3009
+ if (this.client.transport) {
3010
+ try {
3011
+ await this.client.close();
3012
+ } catch {
3013
+ }
2989
3014
  }
2990
- this.client = null;
2991
3015
  this.oauthProvider = null;
2992
3016
  this.transport = null;
2993
3017
  if (this.serverId) {
@@ -3130,6 +3154,18 @@ var MultiSessionClient = class {
3130
3154
  getClients() {
3131
3155
  return this.clients;
3132
3156
  }
3157
+ /**
3158
+ * Removes and disconnects a single session by ID.
3159
+ *
3160
+ * @returns `true` if the session was found and removed, `false` if not found.
3161
+ */
3162
+ async removeSession(sessionId) {
3163
+ const idx = this.clients.findIndex((c) => c.getSessionId() === sessionId);
3164
+ if (idx === -1) return false;
3165
+ const [client] = this.clients.splice(idx, 1);
3166
+ await client.disconnect();
3167
+ return true;
3168
+ }
3133
3169
  /**
3134
3170
  * Gracefully disconnects all active MCP clients and clears the internal list.
3135
3171
  *