@mcp-ts/sdk 2.4.1 → 2.4.2

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 (42) hide show
  1. package/dist/adapters/agui-adapter.d.mts +3 -4
  2. package/dist/adapters/agui-adapter.d.ts +3 -4
  3. package/dist/adapters/agui-middleware.d.mts +3 -4
  4. package/dist/adapters/agui-middleware.d.ts +3 -4
  5. package/dist/adapters/ai-adapter.d.mts +3 -4
  6. package/dist/adapters/ai-adapter.d.ts +3 -4
  7. package/dist/adapters/langchain-adapter.d.mts +3 -4
  8. package/dist/adapters/langchain-adapter.d.ts +3 -4
  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 -3
  12. package/dist/client/index.d.ts +2 -3
  13. package/dist/client/react.d.mts +4 -6
  14. package/dist/client/react.d.ts +4 -6
  15. package/dist/client/vue.d.mts +4 -6
  16. package/dist/client/vue.d.ts +4 -6
  17. package/dist/{index-Ch7ouNSa.d.ts → index-B8kJSrBJ.d.ts} +1 -2
  18. package/dist/{index-L5XoXgsb.d.mts → index-DiJsm_lK.d.mts} +1 -2
  19. package/dist/index.d.mts +5 -6
  20. package/dist/index.d.ts +5 -6
  21. package/dist/index.js +103 -95
  22. package/dist/index.js.map +1 -1
  23. package/dist/index.mjs +103 -95
  24. package/dist/index.mjs.map +1 -1
  25. package/dist/{multi-session-client-Bwm-efqg.d.ts → multi-session-client-BluyCPo9.d.ts} +201 -71
  26. package/dist/{multi-session-client-k-9RvWvi.d.mts → multi-session-client-CWs-AE78.d.mts} +201 -71
  27. package/dist/server/index.d.mts +5 -128
  28. package/dist/server/index.d.ts +5 -128
  29. package/dist/server/index.js +103 -95
  30. package/dist/server/index.js.map +1 -1
  31. package/dist/server/index.mjs +103 -95
  32. package/dist/server/index.mjs.map +1 -1
  33. package/dist/shared/index.d.mts +4 -5
  34. package/dist/shared/index.d.ts +4 -5
  35. package/dist/{tool-router-CuApsDiV.d.mts → tool-router-CbG4Tum6.d.mts} +1 -1
  36. package/dist/{tool-router-CZMrOG8J.d.ts → tool-router-ChIhPwgP.d.ts} +1 -1
  37. package/dist/{types-DCk_IF4L.d.mts → types-CjczQwNX.d.mts} +122 -1
  38. package/dist/{types-DCk_IF4L.d.ts → types-CjczQwNX.d.ts} +122 -1
  39. package/package.json +1 -1
  40. package/src/server/mcp/multi-session-client.ts +177 -132
  41. package/dist/events-C4m7tK1U.d.mts +0 -122
  42. package/dist/events-C4m7tK1U.d.ts +0 -122
@@ -1,54 +1,90 @@
1
-
2
-
3
1
  import { MCPClient } from './oauth-client.js';
4
2
  import { sessions, type Session } from '../storage/index.js';
3
+ import type { ToolClientProvider } from '../../shared/types.js';
4
+
5
+ // ---------------------------------------------------------------------------
6
+ // Constants
7
+ // ---------------------------------------------------------------------------
5
8
 
6
9
  const DEFAULT_TIMEOUT_MS = 15000;
7
10
  const DEFAULT_MAX_RETRIES = 2;
8
11
  const DEFAULT_RETRY_DELAY_MS = 1000;
9
12
  const CONNECTION_BATCH_SIZE = 5;
10
13
 
11
- /**
12
- * Manages multiple MCP connections for a single user.
13
- * Allows aggregating tools from all connected servers.
14
- */
14
+ // ---------------------------------------------------------------------------
15
+ // Types
16
+ // ---------------------------------------------------------------------------
17
+
15
18
  export interface MultiSessionOptions {
16
19
  /**
17
- * Connection timeout in milliseconds
20
+ * Connection timeout in milliseconds.
18
21
  * @default 15000
19
22
  */
20
23
  timeout?: number;
24
+
21
25
  /**
22
- * Maximum number of retry attempts
26
+ * Maximum number of retry attempts per session.
23
27
  * @default 2
24
28
  */
25
29
  maxRetries?: number;
30
+
26
31
  /**
27
- * Delay between retries in milliseconds
32
+ * Delay between retry attempts in milliseconds.
28
33
  * @default 1000
29
34
  */
30
35
  retryDelay?: number;
36
+
37
+ /**
38
+ * Custom session provider. When provided, `connect()` calls this
39
+ * instead of querying the storage backend. Useful when sessions are
40
+ * synced externally (e.g. via Supabase Realtime, WebSocket, or an
41
+ * in-memory cache).
42
+ *
43
+ * Default: reads from the storage backend via `sessions.list(userId)`.
44
+ */
45
+ sessionProvider?: () => Promise<Session[]>;
46
+
47
+ /**
48
+ * Called after a session is successfully connected.
49
+ */
50
+ onSessionConnected?: (sessionId: string, client: MCPClient) => void;
51
+
52
+ /**
53
+ * Called when a session is evicted from the in-memory client list
54
+ * because it no longer exists in the active sessions list.
55
+ */
56
+ onSessionEvicted?: (sessionId: string) => void;
57
+
58
+ /**
59
+ * Called when all retry attempts for a session have been exhausted.
60
+ */
61
+ onSessionFailed?: (sessionId: string, error: unknown) => void;
31
62
  }
32
63
 
64
+ // ---------------------------------------------------------------------------
65
+ // MultiSessionClient
66
+ // ---------------------------------------------------------------------------
67
+
33
68
  /**
34
69
  * Manages multiple MCP client connections for a single user.
35
70
  *
36
- * On a traditional long-running server, you can cache this instance per user
37
- * so the connections stay alive between requests. On serverless, a new instance
38
- * will be created per invocation, but the underlying session data is always
39
- * read from the storage backend so nothing is lost between calls.
71
+ * Cached instances stay alive between requests on long-running servers.
72
+ * On serverless, the underlying session data persists in storage the
73
+ * client rehydrates from `sessionProvider` (or the default storage backend)
74
+ * each time `connect()` is called.
75
+ *
76
+ * @implements {ToolClientProvider}
40
77
  */
41
- export class MultiSessionClient {
78
+ export class MultiSessionClient implements ToolClientProvider {
42
79
  private clients: MCPClient[] = [];
80
+ private connectionPromises = new Map<string, Promise<void>>();
43
81
  private userId: string;
44
- private options: MultiSessionOptions;
82
+ private options: Required<Pick<MultiSessionOptions, 'timeout' | 'maxRetries' | 'retryDelay'>> &
83
+ Pick<MultiSessionOptions, 'sessionProvider' | 'onSessionConnected' | 'onSessionEvicted' | 'onSessionFailed'>;
45
84
 
46
85
  /**
47
- * Creates a new MultiSessionClient for the given user userId.
48
- *
49
- * @param userId - A unique string identifying the user (e.g. user ID or email).
50
- * @param options - Optional tuning for connection timeout, retry count, and retry delay.
51
- * Falls back to sensible defaults if not provided.
86
+ * @param userId - Unique identifier for the user (e.g. user ID or email).
87
+ * @param options - Optional tuning and lifecycle hooks.
52
88
  */
53
89
  constructor(userId: string, options: MultiSessionOptions = {}) {
54
90
  this.userId = userId;
@@ -56,36 +92,110 @@ export class MultiSessionClient {
56
92
  timeout: DEFAULT_TIMEOUT_MS,
57
93
  maxRetries: DEFAULT_MAX_RETRIES,
58
94
  retryDelay: DEFAULT_RETRY_DELAY_MS,
59
- ...options
95
+ ...options,
60
96
  };
61
97
  }
62
98
 
99
+ // -----------------------------------------------------------------------
100
+ // Public API
101
+ // -----------------------------------------------------------------------
102
+
103
+ /**
104
+ * Fetches active sessions and establishes connections to all of them.
105
+ *
106
+ * Call this once after creating the client. On long-running servers you
107
+ * can cache the `MultiSessionClient` instance and call `connect()` on
108
+ * each request — already-connected sessions are skipped internally.
109
+ */
110
+ async connect(): Promise<void> {
111
+ const sessions = await this.fetchActiveSessions();
112
+ const activeSessionIds = new Set(sessions.map(s => s.sessionId));
113
+
114
+ // Evict clients whose sessions no longer appear in the active list.
115
+ // Without this, a stale MCPClient with a live SDK transport would
116
+ // stay in the clients array after its session was deleted externally
117
+ // (e.g. via the SSE handler's clearSession()), causing OAuth refreshes
118
+ // to fail with a FK violation when they try to patchCredentials()
119
+ // against the now-deleted session.
120
+ for (const client of this.clients) {
121
+ if (!activeSessionIds.has(client.getSessionId())) {
122
+ this.options.onSessionEvicted?.(client.getSessionId());
123
+ }
124
+ }
125
+ this.clients = this.clients.filter(c => activeSessionIds.has(c.getSessionId()));
126
+
127
+ await this.connectInBatches(sessions);
128
+ }
129
+
130
+ /**
131
+ * Drops all cached `MCPClient` instances and reconnects fresh from storage.
132
+ *
133
+ * Call this when downstream MCP servers have expired their transport sessions
134
+ * (e.g. after a remote server restart) and subsequent tool calls return
135
+ * "Session not found. Reconnect without session header." errors.
136
+ *
137
+ * OAuth tokens are preserved in the storage backend — no re-authentication
138
+ * is required. Only the in-memory transport sessions are cleared.
139
+ */
140
+ async reconnect(): Promise<void> {
141
+ await this.disconnect();
142
+ await this.connect();
143
+ }
144
+
145
+ /**
146
+ * Returns all currently connected `MCPClient` instances.
147
+ *
148
+ * Use this to enumerate available tools across all connected servers,
149
+ * or to route a tool call to the right client by `serverId`.
150
+ */
151
+ getClients(): MCPClient[] {
152
+ return this.clients;
153
+ }
154
+
155
+ /**
156
+ * Gracefully disconnects all active MCP clients and clears the internal list.
157
+ *
158
+ * For Streamable HTTP sessions, each client sends an HTTP DELETE to its MCP
159
+ * endpoint per the spec before closing locally. All disconnects run in
160
+ * parallel so shutdown is not serialised across many sessions.
161
+ *
162
+ * Call this during server shutdown or when a user logs out to free up
163
+ * underlying transport resources (SSE streams, HTTP connections, etc.).
164
+ */
165
+ async disconnect(): Promise<void> {
166
+ await Promise.all(this.clients.map((client) => client.disconnect()));
167
+ this.clients = [];
168
+ }
169
+
170
+ // -----------------------------------------------------------------------
171
+ // Internals
172
+ // -----------------------------------------------------------------------
173
+
63
174
  /**
64
- * Fetches all sessions for this userId from storage and returns only the
65
- * ones that are ready to connect.
175
+ * Resolves the list of sessions to connect.
66
176
  *
67
- * A session is considered connectable when:
68
- * - It has a `serverId`, `serverUrl`, and `callbackUrl` (i.e. it was fully initialized)
69
- * - Its status is `active`. Pending sessions are skipped here
70
- * and let the OAuth flow complete separately before we try to reconnect them.
177
+ * Uses the custom `sessionProvider` when provided, otherwise falls back
178
+ * to querying the storage backend via `sessions.list(userId)`.
71
179
  */
72
- private async getActiveSessions(): Promise<Session[]> {
73
- const sessionList = await sessions.list(this.userId);
74
- const valid = sessionList.filter(s =>
180
+ private async fetchActiveSessions(): Promise<Session[]> {
181
+ const sessionList = this.options.sessionProvider
182
+ ? await this.options.sessionProvider()
183
+ : await sessions.list(this.userId);
184
+
185
+ return sessionList.filter(s =>
75
186
  s.serverId &&
76
187
  s.serverUrl &&
77
188
  s.callbackUrl &&
78
189
  s.status === 'active'
79
190
  );
80
- return valid;
81
191
  }
82
192
 
83
193
  /**
84
- * Connects to a list of sessions in controlled batches of `CONNECTION_BATCH_SIZE`.
194
+ * Connects a list of sessions in controlled batches.
85
195
  *
86
- * Batching prevents overwhelming the event loop or external servers when a user
87
- * has many active MCP sessions (e.g. 20+ servers). Within each batch, sessions
88
- * are connected concurrently using `Promise.all` for speed.
196
+ * Batching prevents overwhelming the event loop or external servers when
197
+ * a user has many active MCP sessions. Within each batch, sessions are
198
+ * connected concurrently using `Promise.all`.
89
199
  */
90
200
  private async connectInBatches(sessions: Session[]): Promise<void> {
91
201
  for (let i = 0; i < sessions.length; i += CONNECTION_BATCH_SIZE) {
@@ -94,38 +204,30 @@ export class MultiSessionClient {
94
204
  }
95
205
  }
96
206
 
97
- private connectionPromises = new Map<string, Promise<void>>();
98
-
99
207
  /**
100
- * Connects a single session, with built-in deduplication to prevent race conditions.
208
+ * Connects a single session, with deduplication to prevent race conditions.
101
209
  *
102
- * - If a client for this session already exists and is connected, returns immediately.
103
- * - If the existing client entry is no longer connected (e.g. it was explicitly
104
- * disconnected), it is evicted so that `establishConnectionWithRetries` creates a
105
- * fresh transport preventing "Client already connected" errors from the SDK.
106
- * - If a connection attempt for this session is already in-flight (e.g. from a
107
- * concurrent call), it joins the existing promise instead of starting a new one.
108
- * This is the key concurrency lock the `connectionPromises` map acts as a
109
- * per-session mutex so we never spin up two physical connections for the same session.
110
- * - On completion (success or failure), the promise is cleaned up from the map.
210
+ * - If a client for this session already exists and is connected, returns
211
+ * immediately.
212
+ * - If the existing client entry is no longer connected (e.g. explicit
213
+ * disconnect), it is evicted so a fresh transport is created.
214
+ * - If a connection attempt for this session is already in-flight, the
215
+ * existing promise is reused as a per-session mutex.
216
+ * - On completion (success or failure), the promise is cleaned up from
217
+ * the connectionPromises map.
111
218
  */
112
219
  private async connectSession(session: Session): Promise<void> {
113
220
  const existing = this.clients.find(c => c.getSessionId() === session.sessionId);
114
221
 
115
222
  if (existing) {
116
223
  if (existing.isConnected()) {
117
- // Genuinely connected — nothing to do.
118
224
  return;
119
225
  }
120
226
 
121
- // Client entry exists but is no longer connected (explicit disconnect or
122
- // a prior failed reconnect attempt). Remove it so the fresh connect below
123
- // starts with a clean slate and the underlying SDK Client doesn't complain
124
- // about an already-attached transport.
227
+ this.options.onSessionEvicted?.(existing.getSessionId());
125
228
  this.clients = this.clients.filter(c => c !== existing);
126
229
  }
127
230
 
128
- // Avoid concurrent connection attempts for the same session
129
231
  if (this.connectionPromises.has(session.sessionId)) {
130
232
  return this.connectionPromises.get(session.sessionId)!;
131
233
  }
@@ -142,22 +244,19 @@ export class MultiSessionClient {
142
244
  }
143
245
 
144
246
  /**
145
- * The core connection loop for a single session.
247
+ * Core connection loop for a single session with retry logic.
146
248
  *
147
- * Attempts to establish a physical MCP connection, retrying up to `maxRetries` times
148
- * if the connection fails. Each attempt:
149
- * 1. Creates a fresh `MCPClient` instance from the session data.
150
- * 2. Races the connect call against a timeout promise — if the server doesn't respond
151
- * within `timeoutMs`, the attempt is aborted and counted as a failure.
152
- * 3. On success, replaces any stale client entry for this session in the `clients` array.
249
+ * 1. Creates a fresh `MCPClient` from the session data.
250
+ * 2. Races `client.connect()` against a timeout.
251
+ * 3. On success, replaces any stale entry and fires `onSessionConnected`.
153
252
  * 4. On failure, waits `retryDelay` ms before the next attempt.
154
253
  *
155
- * If all attempts are exhausted, logs an error and returns silently (does not throw),
156
- * so a single bad server doesn't block the rest of the batch from connecting.
254
+ * If all attempts are exhausted, logs an error and returns silently so
255
+ * a single bad server doesn't block the rest of the batch.
157
256
  */
158
257
  private async establishConnectionWithRetries(session: Session): Promise<void> {
159
- const maxRetries = this.options.maxRetries ?? DEFAULT_MAX_RETRIES;
160
- const retryDelay = this.options.retryDelay ?? DEFAULT_RETRY_DELAY_MS;
258
+ const maxRetries = this.options.maxRetries;
259
+ const retryDelay = this.options.retryDelay;
161
260
  let lastError: unknown;
162
261
 
163
262
  for (let attempt = 0; attempt <= maxRetries; attempt++) {
@@ -173,10 +272,13 @@ export class MultiSessionClient {
173
272
  headers: session.headers,
174
273
  });
175
274
 
176
- const timeoutMs = this.options.timeout ?? DEFAULT_TIMEOUT_MS;
275
+ const timeoutMs = this.options.timeout;
177
276
  let timeoutTimer: ReturnType<typeof setTimeout>;
178
277
  const timeoutPromise = new Promise<never>((_, reject) => {
179
- timeoutTimer = setTimeout(() => reject(new Error(`Connection timed out after ${timeoutMs}ms`)), timeoutMs);
278
+ timeoutTimer = setTimeout(
279
+ () => reject(new Error(`Connection timed out after ${timeoutMs}ms`)),
280
+ timeoutMs,
281
+ );
180
282
  });
181
283
 
182
284
  try {
@@ -185,10 +287,11 @@ export class MultiSessionClient {
185
287
  clearTimeout(timeoutTimer!);
186
288
  }
187
289
 
188
- // Always replace the disconnected client entry
189
290
  this.clients = this.clients.filter(c => c.getSessionId() !== session.sessionId);
190
291
  this.clients.push(client);
191
- return; // successfully connected
292
+ this.options.onSessionConnected?.(session.sessionId, client);
293
+ return;
294
+
192
295
  } catch (error) {
193
296
  lastError = error;
194
297
  if (attempt < maxRetries) {
@@ -197,69 +300,11 @@ export class MultiSessionClient {
197
300
  }
198
301
  }
199
302
 
200
- console.error(`[MultiSessionClient] Failed to connect to session ${session.sessionId} after ${maxRetries + 1} attempts:`, lastError);
201
- }
202
-
203
- /**
204
- * The main entry point. Fetches all active sessions for this userId from
205
- * storage and establishes connections to all of them in batches.
206
- *
207
- * Call this once after creating the client. On traditional servers, you can
208
- * cache the `MultiSessionClient` instance after calling `connect()` to avoid
209
- * re-fetching and re-connecting on every request.
210
- */
211
- async connect(): Promise<void> {
212
- const sessions = await this.getActiveSessions();
213
- const activeSessionIds = new Set(sessions.map(s => s.sessionId));
214
-
215
- // Prune stale clients whose sessions no longer exist in storage.
216
- // Otherwise a lingering MCPClient with a still-alive SDK Client
217
- // transport triggers OAuth refreshes on listTools(), and the
218
- // StorageOAuthClientProvider.state() -> patchCredentials() call
219
- // fails with a FK violation because the session was deleted.
220
- this.clients = this.clients.filter(c => activeSessionIds.has(c.getSessionId()));
221
-
222
- await this.connectInBatches(sessions);
223
- }
224
-
225
- /**
226
- * Drops all cached `MCPClient` instances and reconnects fresh from storage.
227
- *
228
- * Call this when downstream MCP servers have expired their transport sessions
229
- * (e.g. after a remote server restart) and subsequent tool calls return
230
- * "Session not found. Reconnect without session header." errors.
231
- *
232
- * OAuth tokens are preserved in the storage backend — no re-authentication
233
- * is required. Only the in-memory transport sessions are cleared.
234
- */
235
- async reconnect(): Promise<void> {
236
- await this.disconnect();
237
- await this.connect();
238
- }
239
-
240
- /**
241
- * Returns all currently connected `MCPClient` instances.
242
- *
243
- * Use this to enumerate available tools across all connected servers,
244
- * or to route a tool call to the right client by `serverId`.
245
- */
246
- getClients(): MCPClient[] {
247
- return this.clients;
248
- }
249
-
250
- /**
251
- * Gracefully disconnects all active MCP clients and clears the internal client list.
252
- *
253
- * For Streamable HTTP sessions, each client sends an HTTP DELETE to its MCP
254
- * endpoint per the spec before closing locally. All disconnects run in
255
- * parallel so shutdown is not serialised across many sessions.
256
- *
257
- * Call this during server shutdown or when a user logs out to free up
258
- * underlying transport resources (SSE streams, HTTP connections, etc.).
259
- */
260
- async disconnect(): Promise<void> {
261
- await Promise.all(this.clients.map((client) => client.disconnect()));
262
- this.clients = [];
303
+ this.options.onSessionFailed?.(session.sessionId, lastError);
304
+ console.error(
305
+ `[MultiSessionClient] Failed to connect to session ${session.sessionId} ` +
306
+ `after ${maxRetries + 1} attempts:`,
307
+ lastError,
308
+ );
263
309
  }
264
310
  }
265
-
@@ -1,122 +0,0 @@
1
- /**
2
- * Simple event emitter pattern for MCP connection events
3
- * Inspired by Cloudflare's agents pattern but adapted for serverless
4
- */
5
- type Disposable = {
6
- dispose(): void;
7
- };
8
- type Event<T> = (listener: (event: T) => void) => Disposable;
9
- /**
10
- * Event emitter class for type-safe event handling
11
- * Similar to Cloudflare's Emitter but simplified for our use case
12
- */
13
- declare class Emitter<T> {
14
- private listeners;
15
- /**
16
- * Subscribe to events
17
- * @param listener - Callback function to handle events
18
- * @returns Disposable to unsubscribe
19
- */
20
- get event(): Event<T>;
21
- /**
22
- * Fire an event to all listeners
23
- * @param event - Event data to emit
24
- */
25
- fire(event: T): void;
26
- /**
27
- * Clear all listeners
28
- */
29
- dispose(): void;
30
- /**
31
- * Get number of active listeners
32
- */
33
- get listenerCount(): number;
34
- }
35
- /**
36
- * Connection state types matching your existing ConnectionStatus
37
- * Extended with more granular states for better observability
38
- */
39
- type McpConnectionState = 'DISCONNECTED' | 'CONNECTING' | 'AUTHENTICATING' | 'AUTHENTICATED' | 'DISCOVERING' | 'CONNECTED' | 'READY' | 'VALIDATING' | 'RECONNECTING' | 'INITIALIZING' | 'FAILED';
40
- /**
41
- * MCP Connection Event Types
42
- * Discriminated union for type-safe event handling
43
- */
44
- type McpConnectionEvent = {
45
- type: 'state_changed';
46
- sessionId: string;
47
- serverId: string;
48
- serverName: string;
49
- serverUrl: string;
50
- createdAt?: number;
51
- state: McpConnectionState;
52
- previousState: McpConnectionState;
53
- timestamp: number;
54
- } | {
55
- type: 'tools_discovered';
56
- sessionId: string;
57
- serverId: string;
58
- toolCount: number;
59
- tools: any[];
60
- timestamp: number;
61
- } | {
62
- type: 'auth_required';
63
- sessionId: string;
64
- serverId: string;
65
- authUrl: string;
66
- timestamp: number;
67
- } | {
68
- type: 'error';
69
- sessionId: string;
70
- serverId: string;
71
- error: string;
72
- errorType: 'connection' | 'auth' | 'validation' | 'unknown';
73
- timestamp: number;
74
- } | {
75
- type: 'disconnected';
76
- sessionId: string;
77
- serverId: string;
78
- timestamp: number;
79
- } | {
80
- type: 'progress';
81
- sessionId: string;
82
- serverId: string;
83
- message: string;
84
- timestamp: number;
85
- };
86
- /**
87
- * Event fired when a tool execution returns a UI resource URI
88
- */
89
- interface McpAppsUIEvent {
90
- type: 'mcp-apps-ui';
91
- sessionId: string;
92
- resourceUri: string;
93
- toolName: string;
94
- result: unknown;
95
- timestamp: number;
96
- }
97
- /**
98
- * Observability event for debugging and monitoring
99
- */
100
- interface McpObservabilityEvent {
101
- type?: string;
102
- level?: 'debug' | 'info' | 'warn' | 'error';
103
- message?: string;
104
- displayMessage?: string;
105
- sessionId?: string;
106
- serverId?: string;
107
- payload?: Record<string, any>;
108
- metadata?: Record<string, any>;
109
- timestamp: number;
110
- id?: string;
111
- }
112
- /**
113
- * DisposableStore for managing multiple disposables
114
- * Useful for cleanup in React hooks
115
- */
116
- declare class DisposableStore {
117
- private disposables;
118
- add(disposable: Disposable): void;
119
- dispose(): void;
120
- }
121
-
122
- export { type Disposable as D, Emitter as E, type McpConnectionEvent as M, DisposableStore as a, type Event as b, type McpConnectionState as c, type McpObservabilityEvent as d, type McpAppsUIEvent as e };
@@ -1,122 +0,0 @@
1
- /**
2
- * Simple event emitter pattern for MCP connection events
3
- * Inspired by Cloudflare's agents pattern but adapted for serverless
4
- */
5
- type Disposable = {
6
- dispose(): void;
7
- };
8
- type Event<T> = (listener: (event: T) => void) => Disposable;
9
- /**
10
- * Event emitter class for type-safe event handling
11
- * Similar to Cloudflare's Emitter but simplified for our use case
12
- */
13
- declare class Emitter<T> {
14
- private listeners;
15
- /**
16
- * Subscribe to events
17
- * @param listener - Callback function to handle events
18
- * @returns Disposable to unsubscribe
19
- */
20
- get event(): Event<T>;
21
- /**
22
- * Fire an event to all listeners
23
- * @param event - Event data to emit
24
- */
25
- fire(event: T): void;
26
- /**
27
- * Clear all listeners
28
- */
29
- dispose(): void;
30
- /**
31
- * Get number of active listeners
32
- */
33
- get listenerCount(): number;
34
- }
35
- /**
36
- * Connection state types matching your existing ConnectionStatus
37
- * Extended with more granular states for better observability
38
- */
39
- type McpConnectionState = 'DISCONNECTED' | 'CONNECTING' | 'AUTHENTICATING' | 'AUTHENTICATED' | 'DISCOVERING' | 'CONNECTED' | 'READY' | 'VALIDATING' | 'RECONNECTING' | 'INITIALIZING' | 'FAILED';
40
- /**
41
- * MCP Connection Event Types
42
- * Discriminated union for type-safe event handling
43
- */
44
- type McpConnectionEvent = {
45
- type: 'state_changed';
46
- sessionId: string;
47
- serverId: string;
48
- serverName: string;
49
- serverUrl: string;
50
- createdAt?: number;
51
- state: McpConnectionState;
52
- previousState: McpConnectionState;
53
- timestamp: number;
54
- } | {
55
- type: 'tools_discovered';
56
- sessionId: string;
57
- serverId: string;
58
- toolCount: number;
59
- tools: any[];
60
- timestamp: number;
61
- } | {
62
- type: 'auth_required';
63
- sessionId: string;
64
- serverId: string;
65
- authUrl: string;
66
- timestamp: number;
67
- } | {
68
- type: 'error';
69
- sessionId: string;
70
- serverId: string;
71
- error: string;
72
- errorType: 'connection' | 'auth' | 'validation' | 'unknown';
73
- timestamp: number;
74
- } | {
75
- type: 'disconnected';
76
- sessionId: string;
77
- serverId: string;
78
- timestamp: number;
79
- } | {
80
- type: 'progress';
81
- sessionId: string;
82
- serverId: string;
83
- message: string;
84
- timestamp: number;
85
- };
86
- /**
87
- * Event fired when a tool execution returns a UI resource URI
88
- */
89
- interface McpAppsUIEvent {
90
- type: 'mcp-apps-ui';
91
- sessionId: string;
92
- resourceUri: string;
93
- toolName: string;
94
- result: unknown;
95
- timestamp: number;
96
- }
97
- /**
98
- * Observability event for debugging and monitoring
99
- */
100
- interface McpObservabilityEvent {
101
- type?: string;
102
- level?: 'debug' | 'info' | 'warn' | 'error';
103
- message?: string;
104
- displayMessage?: string;
105
- sessionId?: string;
106
- serverId?: string;
107
- payload?: Record<string, any>;
108
- metadata?: Record<string, any>;
109
- timestamp: number;
110
- id?: string;
111
- }
112
- /**
113
- * DisposableStore for managing multiple disposables
114
- * Useful for cleanup in React hooks
115
- */
116
- declare class DisposableStore {
117
- private disposables;
118
- add(disposable: Disposable): void;
119
- dispose(): void;
120
- }
121
-
122
- export { type Disposable as D, Emitter as E, type McpConnectionEvent as M, DisposableStore as a, type Event as b, type McpConnectionState as c, type McpObservabilityEvent as d, type McpAppsUIEvent as e };