@mcp-ts/sdk 2.4.3 → 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 (49) 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/client/index.d.mts +2 -2
  12. package/dist/client/index.d.ts +2 -2
  13. package/dist/client/react.d.mts +4 -5
  14. package/dist/client/react.d.ts +4 -5
  15. package/dist/client/react.js.map +1 -1
  16. package/dist/client/react.mjs.map +1 -1
  17. package/dist/client/vue.d.mts +4 -5
  18. package/dist/client/vue.d.ts +4 -5
  19. package/dist/client/vue.js.map +1 -1
  20. package/dist/client/vue.mjs.map +1 -1
  21. package/dist/{index-B8kJSrBJ.d.ts → index-CZk2gu2E.d.ts} +1 -1
  22. package/dist/{index-DiJsm_lK.d.mts → index-CkM3p0eE.d.mts} +1 -1
  23. package/dist/index.d.mts +4 -4
  24. package/dist/index.d.ts +4 -4
  25. package/dist/index.js +36 -56
  26. package/dist/index.js.map +1 -1
  27. package/dist/index.mjs +36 -56
  28. package/dist/index.mjs.map +1 -1
  29. package/dist/{multi-session-client-DOBvtaQV.d.ts → multi-session-client-ChQrBZhF.d.mts} +4 -5
  30. package/dist/{multi-session-client-B6hsYO8V.d.mts → multi-session-client-QOOPdEVp.d.ts} +4 -5
  31. package/dist/server/index.d.mts +4 -4
  32. package/dist/server/index.d.ts +4 -4
  33. package/dist/server/index.js +36 -56
  34. package/dist/server/index.js.map +1 -1
  35. package/dist/server/index.mjs +36 -56
  36. package/dist/server/index.mjs.map +1 -1
  37. package/dist/shared/index.d.mts +4 -4
  38. package/dist/shared/index.d.ts +4 -4
  39. package/dist/shared/index.js.map +1 -1
  40. package/dist/shared/index.mjs.map +1 -1
  41. package/dist/{tool-router-CbG4Tum6.d.mts → tool-router-CGs3IDOJ.d.mts} +1 -1
  42. package/dist/{tool-router-ChIhPwgP.d.ts → tool-router-DQ-HrD7W.d.ts} +1 -1
  43. package/dist/{types-CjczQwNX.d.mts → types-Bf-7GOLW.d.mts} +0 -2
  44. package/dist/{types-CjczQwNX.d.ts → types-Bf-7GOLW.d.ts} +0 -2
  45. package/package.json +1 -1
  46. package/src/client/react/use-mcp.ts +0 -1
  47. package/src/client/vue/use-mcp.ts +0 -1
  48. package/src/server/mcp/oauth-client.ts +41 -76
  49. package/src/shared/events.ts +0 -2
@@ -1,5 +1,5 @@
1
1
  import { Tool } from '@modelcontextprotocol/sdk/types.js';
2
- import { A as ToolClientProvider, T as ToolClient } from './types-CjczQwNX.mjs';
2
+ import { A as ToolClientProvider, T as ToolClient } from './types-Bf-7GOLW.mjs';
3
3
 
4
4
  /**
5
5
  * ToolIndex — Lightweight in-memory search index for MCP tool discovery.
@@ -1,5 +1,5 @@
1
1
  import { Tool } from '@modelcontextprotocol/sdk/types.js';
2
- import { A as ToolClientProvider, T as ToolClient } from './types-CjczQwNX.js';
2
+ import { A as ToolClientProvider, T as ToolClient } from './types-Bf-7GOLW.js';
3
3
 
4
4
  /**
5
5
  * ToolIndex — Lightweight in-memory search index for MCP tool discovery.
@@ -2,7 +2,6 @@ import { Tool } from '@modelcontextprotocol/sdk/types.js';
2
2
 
3
3
  /**
4
4
  * Simple event emitter pattern for MCP connection events
5
- * Inspired by Cloudflare's agents pattern but adapted for serverless
6
5
  */
7
6
  type Disposable = {
8
7
  dispose(): void;
@@ -10,7 +9,6 @@ type Disposable = {
10
9
  type Event<T> = (listener: (event: T) => void) => Disposable;
11
10
  /**
12
11
  * Event emitter class for type-safe event handling
13
- * Similar to Cloudflare's Emitter but simplified for our use case
14
12
  */
15
13
  declare class Emitter<T> {
16
14
  private listeners;
@@ -2,7 +2,6 @@ import { Tool } from '@modelcontextprotocol/sdk/types.js';
2
2
 
3
3
  /**
4
4
  * Simple event emitter pattern for MCP connection events
5
- * Inspired by Cloudflare's agents pattern but adapted for serverless
6
5
  */
7
6
  type Disposable = {
8
7
  dispose(): void;
@@ -10,7 +9,6 @@ type Disposable = {
10
9
  type Event<T> = (listener: (event: T) => void) => Disposable;
11
10
  /**
12
11
  * Event emitter class for type-safe event handling
13
- * Similar to Cloudflare's Emitter but simplified for our use case
14
12
  */
15
13
  declare class Emitter<T> {
16
14
  private listeners;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mcp-ts/sdk",
3
- "version": "2.4.3",
3
+ "version": "2.4.4",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -1,7 +1,6 @@
1
1
  /**
2
2
  * useMcp React Hook
3
3
  * Manages MCP connections with SSE-based real-time updates
4
- * Based on Cloudflare's agents pattern
5
4
  */
6
5
 
7
6
  import { useEffect, useRef, useState, useCallback, useMemo } from 'react';
@@ -1,7 +1,6 @@
1
1
  /**
2
2
  * useMcp Vue Composable
3
3
  * Manages MCP connections with SSE-based real-time updates
4
- * Based on Cloudflare's agents pattern
5
4
  */
6
5
 
7
6
  import { ref, onMounted, onUnmounted, watch, computed, shallowRef } from 'vue';
@@ -79,7 +79,7 @@ export interface MCPOAuthClientOptions {
79
79
  * Emits connection lifecycle events for observability
80
80
  */
81
81
  export class MCPClient {
82
- private client: Client | null = null;
82
+ private client: Client;
83
83
  public oauthProvider: AgentsOAuthProvider | null = null;
84
84
  private transport: StreamableHTTPClientTransport | SSEClientTransport | null = null;
85
85
  private userId: string;
@@ -131,6 +131,22 @@ export class MCPClient {
131
131
  this.clientUri = options.clientUri;
132
132
  this.logoUri = options.logoUri;
133
133
  this.policyUri = options.policyUri;
134
+
135
+ this.client = new Client(
136
+ {
137
+ name: MCP_CLIENT_NAME,
138
+ version: MCP_CLIENT_VERSION,
139
+ },
140
+ {
141
+ capabilities: {
142
+ extensions: {
143
+ 'io.modelcontextprotocol/ui': {
144
+ mimeTypes: ['text/html+mcp'],
145
+ },
146
+ },
147
+ } as McpAppClientCapabilities,
148
+ }
149
+ );
134
150
  }
135
151
 
136
152
  /**
@@ -275,13 +291,12 @@ export class MCPClient {
275
291
  }
276
292
 
277
293
  /**
278
- * Initializes client components (client, transport, OAuth provider)
279
- * Loads missing configuration from Redis session store if needed
280
- * This method is idempotent and safe to call multiple times
294
+ * Ensures session metadata and OAuth provider are loaded.
295
+ * Does NOT create the SDK Client callers that need one create it themselves.
281
296
  * @private
282
297
  */
283
- private async initialize(): Promise<void> {
284
- if (this.client && this.oauthProvider) {
298
+ private async ensureSession(): Promise<void> {
299
+ if (this.oauthProvider) {
285
300
  return;
286
301
  }
287
302
 
@@ -336,24 +351,6 @@ export class MCPClient {
336
351
  });
337
352
  }
338
353
 
339
- if (!this.client) {
340
- this.client = new Client(
341
- {
342
- name: MCP_CLIENT_NAME,
343
- version: MCP_CLIENT_VERSION,
344
- },
345
- {
346
- capabilities: {
347
- extensions: {
348
- 'io.modelcontextprotocol/ui': {
349
- mimeTypes: ['text/html+mcp'],
350
- },
351
- },
352
- } as McpAppClientCapabilities
353
- }
354
- );
355
- }
356
-
357
354
  // Create session in the session store if it doesn't exist yet
358
355
  // This is needed BEFORE OAuth flow starts because the OAuth provider
359
356
  // will call saveCodeVerifier() which requires the session to exist
@@ -380,6 +377,8 @@ export class MCPClient {
380
377
  }
381
378
  }
382
379
 
380
+
381
+
383
382
  /**
384
383
  * Saves current session state to the session store
385
384
  * Creates new session if it doesn't exist, updates if it does
@@ -509,31 +508,21 @@ export class MCPClient {
509
508
  * @throws {Error} When connection fails for other reasons
510
509
  */
511
510
  async connect(): Promise<void> {
512
- // Re-entry guard: if a previous SDK Client is still attached to a transport
513
- // (e.g. a stale session from a prior connect() call on the same MCPClient
514
- // instance), close and detach it before proceeding. The MCP SDK client will
515
- // throw if asked to connect while a transport is already attached, and the
516
- // stale transport would send an expired mcp-session-id to the remote server
517
- // causing "Session not found. Reconnect without session header." errors.
518
- //
519
- // We also null out this.client so that initialize() creates a fresh Client
520
- // instance with a clean transport slot, rather than reusing the old one.
521
- // The oauthProvider is intentionally preserved — OAuth tokens remain valid
522
- // across reconnects; only the transport session needs to be renegotiated.
523
- if (this.client?.transport) {
511
+ // Close any existing transport so we can negotiate a fresh session.
512
+ // The SDK Client throws if asked to connect() while a transport is
513
+ // already attached; close() detaches it cleanly so the same Client
514
+ // instance can be reused.
515
+ if (this.client.transport) {
524
516
  this.transport = null;
525
- try {
526
- await this.client.close();
527
- } catch {
517
+ try { await this.client.close(); } catch {
528
518
  // Closing a transport that may have already failed is best-effort.
529
519
  }
530
- this.client = null;
531
520
  }
532
521
 
533
- await this.initialize();
522
+ await this.ensureSession();
534
523
 
535
- if (!this.client || !this.oauthProvider) {
536
- const error = 'Client or OAuth provider not initialized';
524
+ if (!this.oauthProvider) {
525
+ const error = 'OAuth provider not initialized';
537
526
  this.emitError(error, 'connection');
538
527
  this.emitStateChange('FAILED');
539
528
  throw new Error(error);
@@ -643,7 +632,7 @@ export class MCPClient {
643
632
  this.emitStateChange('AUTHENTICATING');
644
633
  this.emitProgress('Exchanging authorization code for tokens...');
645
634
 
646
- await this.initialize();
635
+ await this.ensureSession();
647
636
 
648
637
  if (!this.oauthProvider) {
649
638
  const error = 'OAuth provider not initialized';
@@ -1013,10 +1002,9 @@ export class MCPClient {
1013
1002
  return await fn();
1014
1003
  } catch (error) {
1015
1004
  if (!(error instanceof Error && error.message.includes('MCP_SESSION_EXPIRED'))) throw error;
1016
- if (this.client) {
1005
+ if (this.client.transport) {
1017
1006
  try { await this.client.close(); } catch {}
1018
1007
  this.transport = null;
1019
- this.client = null;
1020
1008
  }
1021
1009
  await this.reconnect();
1022
1010
  return await fn();
@@ -1030,31 +1018,9 @@ export class MCPClient {
1030
1018
  * @throws {Error} When OAuth provider is not initialized
1031
1019
  */
1032
1020
  async reconnect(): Promise<void> {
1033
- await this.initialize();
1034
-
1035
- if (!this.oauthProvider) {
1036
- throw new Error('OAuth provider not initialized');
1037
- }
1038
-
1039
- // Close the client initialize() may have created — we need a fresh
1040
- // client that will negotiate a new transport session.
1041
- if (this.client) {
1042
- try { await this.client.close(); } catch {}
1043
- }
1044
-
1045
- this.client = new Client(
1046
- {
1047
- name: MCP_CLIENT_NAME,
1048
- version: MCP_CLIENT_VERSION,
1049
- },
1050
- { capabilities: {} }
1051
- );
1052
-
1053
- // Use default logic to get transport, defaulting to what's stored or auto
1054
- const tt = this.transportType || 'streamable-http';
1055
- this.transport = this.getTransport(tt);
1056
-
1057
- await this.client.connect(this.transport);
1021
+ await this.ensureSession();
1022
+ if (!this.oauthProvider) throw new Error('OAuth provider not initialized');
1023
+ await this.connect();
1058
1024
  }
1059
1025
 
1060
1026
  /**
@@ -1063,7 +1029,7 @@ export class MCPClient {
1063
1029
  */
1064
1030
  async clearSession(): Promise<void> {
1065
1031
  try {
1066
- await this.initialize();
1032
+ await this.ensureSession();
1067
1033
  } catch (error) {
1068
1034
  console.warn('[MCPClient] Initialization failed during clearSession:', error);
1069
1035
  }
@@ -1081,7 +1047,7 @@ export class MCPClient {
1081
1047
  * @returns True if connected, false otherwise
1082
1048
  */
1083
1049
  isConnected(): boolean {
1084
- return this.client !== null;
1050
+ return this.client.transport !== undefined;
1085
1051
  }
1086
1052
 
1087
1053
  /**
@@ -1108,10 +1074,9 @@ export class MCPClient {
1108
1074
  }
1109
1075
  }
1110
1076
 
1111
- if (this.client) {
1112
- this.client.close();
1077
+ if (this.client.transport) {
1078
+ try { await this.client.close(); } catch {}
1113
1079
  }
1114
- this.client = null;
1115
1080
  this.oauthProvider = null;
1116
1081
  this.transport = null;
1117
1082
 
@@ -1,6 +1,5 @@
1
1
  /**
2
2
  * Simple event emitter pattern for MCP connection events
3
- * Inspired by Cloudflare's agents pattern but adapted for serverless
4
3
  */
5
4
 
6
5
  export type Disposable = {
@@ -11,7 +10,6 @@ export type Event<T> = (listener: (event: T) => void) => Disposable;
11
10
 
12
11
  /**
13
12
  * Event emitter class for type-safe event handling
14
- * Similar to Cloudflare's Emitter but simplified for our use case
15
13
  */
16
14
  export class Emitter<T> {
17
15
  private listeners: Set<(event: T) => void> = new Set();