@mcp-ts/sdk 1.3.6 → 1.3.7
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/dist/adapters/agui-adapter.d.mts +1 -1
- package/dist/adapters/agui-adapter.d.ts +1 -1
- package/dist/adapters/agui-adapter.js +2 -2
- package/dist/adapters/agui-adapter.js.map +1 -1
- package/dist/adapters/agui-adapter.mjs +2 -2
- package/dist/adapters/agui-adapter.mjs.map +1 -1
- package/dist/adapters/agui-middleware.d.mts +1 -1
- package/dist/adapters/agui-middleware.d.ts +1 -1
- package/dist/adapters/agui-middleware.js.map +1 -1
- package/dist/adapters/agui-middleware.mjs.map +1 -1
- package/dist/adapters/ai-adapter.d.mts +1 -1
- package/dist/adapters/ai-adapter.d.ts +1 -1
- package/dist/adapters/ai-adapter.js +1 -1
- package/dist/adapters/ai-adapter.js.map +1 -1
- package/dist/adapters/ai-adapter.mjs +1 -1
- package/dist/adapters/ai-adapter.mjs.map +1 -1
- package/dist/adapters/langchain-adapter.d.mts +1 -1
- package/dist/adapters/langchain-adapter.d.ts +1 -1
- package/dist/adapters/langchain-adapter.js +1 -1
- package/dist/adapters/langchain-adapter.js.map +1 -1
- package/dist/adapters/langchain-adapter.mjs +1 -1
- package/dist/adapters/langchain-adapter.mjs.map +1 -1
- package/dist/adapters/mastra-adapter.d.mts +1 -1
- package/dist/adapters/mastra-adapter.d.ts +1 -1
- package/dist/adapters/mastra-adapter.js +1 -1
- package/dist/adapters/mastra-adapter.js.map +1 -1
- package/dist/adapters/mastra-adapter.mjs +1 -1
- package/dist/adapters/mastra-adapter.mjs.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +134 -71
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +134 -71
- package/dist/index.mjs.map +1 -1
- package/dist/{multi-session-client-BYLarghq.d.ts → multi-session-client-CHE8QpVE.d.ts} +75 -5
- package/dist/{multi-session-client-CzhMkE0k.d.mts → multi-session-client-CQsRbxYI.d.mts} +75 -5
- package/dist/server/index.d.mts +1 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +134 -71
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +134 -71
- package/dist/server/index.mjs.map +1 -1
- package/dist/shared/index.js +10 -2
- package/dist/shared/index.js.map +1 -1
- package/dist/shared/index.mjs +10 -2
- package/dist/shared/index.mjs.map +1 -1
- package/package.json +2 -2
- package/src/adapters/agui-adapter.ts +222 -222
- package/src/adapters/ai-adapter.ts +115 -115
- package/src/adapters/langchain-adapter.ts +127 -127
- package/src/adapters/mastra-adapter.ts +126 -126
- package/src/server/mcp/multi-session-client.ts +135 -39
- package/src/server/storage/file-backend.ts +3 -16
- package/src/server/storage/index.ts +1 -0
- package/src/server/storage/memory-backend.ts +3 -16
- package/src/server/storage/redis-backend.ts +3 -16
- package/src/server/storage/sqlite-backend.ts +2 -6
- package/src/server/storage/supabase-backend.ts +2 -1
- package/src/shared/utils.ts +22 -0
package/dist/index.js
CHANGED
|
@@ -175,7 +175,8 @@ var SOFTWARE_VERSION = "1.3.4";
|
|
|
175
175
|
var MCP_CLIENT_NAME = "mcp-ts-oauth-client";
|
|
176
176
|
var MCP_CLIENT_VERSION = "2.0";
|
|
177
177
|
|
|
178
|
-
// src/
|
|
178
|
+
// src/shared/utils.ts
|
|
179
|
+
init_cjs_shims();
|
|
179
180
|
var firstChar = nanoid.customAlphabet(
|
|
180
181
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
|
|
181
182
|
1
|
|
@@ -184,6 +185,18 @@ var rest = nanoid.customAlphabet(
|
|
|
184
185
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
|
|
185
186
|
11
|
|
186
187
|
);
|
|
188
|
+
function sanitizeServerLabel(name) {
|
|
189
|
+
let sanitized = name.replace(/[^a-zA-Z0-9-_]/g, "_").replace(/_{2,}/g, "_").toLowerCase();
|
|
190
|
+
if (!/^[a-zA-Z]/.test(sanitized)) {
|
|
191
|
+
sanitized = "s_" + sanitized;
|
|
192
|
+
}
|
|
193
|
+
return sanitized;
|
|
194
|
+
}
|
|
195
|
+
function generateSessionId() {
|
|
196
|
+
return firstChar() + rest();
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// src/server/storage/redis-backend.ts
|
|
187
200
|
var RedisStorageBackend = class {
|
|
188
201
|
constructor(redis2) {
|
|
189
202
|
this.redis = redis2;
|
|
@@ -242,7 +255,7 @@ var RedisStorageBackend = class {
|
|
|
242
255
|
return Array.from(keys);
|
|
243
256
|
}
|
|
244
257
|
generateSessionId() {
|
|
245
|
-
return
|
|
258
|
+
return generateSessionId();
|
|
246
259
|
}
|
|
247
260
|
async createSession(session, ttl) {
|
|
248
261
|
const { sessionId, identity } = session;
|
|
@@ -413,14 +426,6 @@ var RedisStorageBackend = class {
|
|
|
413
426
|
|
|
414
427
|
// src/server/storage/memory-backend.ts
|
|
415
428
|
init_cjs_shims();
|
|
416
|
-
var firstChar2 = nanoid.customAlphabet(
|
|
417
|
-
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
|
|
418
|
-
1
|
|
419
|
-
);
|
|
420
|
-
var rest2 = nanoid.customAlphabet(
|
|
421
|
-
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
|
|
422
|
-
11
|
|
423
|
-
);
|
|
424
429
|
var MemoryStorageBackend = class {
|
|
425
430
|
constructor() {
|
|
426
431
|
// Map<identity:sessionId, SessionData>
|
|
@@ -435,7 +440,7 @@ var MemoryStorageBackend = class {
|
|
|
435
440
|
return `${identity}:${sessionId}`;
|
|
436
441
|
}
|
|
437
442
|
generateSessionId() {
|
|
438
|
-
return
|
|
443
|
+
return generateSessionId();
|
|
439
444
|
}
|
|
440
445
|
async createSession(session, ttl) {
|
|
441
446
|
const { sessionId, identity } = session;
|
|
@@ -509,14 +514,6 @@ var MemoryStorageBackend = class {
|
|
|
509
514
|
|
|
510
515
|
// src/server/storage/file-backend.ts
|
|
511
516
|
init_cjs_shims();
|
|
512
|
-
var firstChar3 = nanoid.customAlphabet(
|
|
513
|
-
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
|
|
514
|
-
1
|
|
515
|
-
);
|
|
516
|
-
var rest3 = nanoid.customAlphabet(
|
|
517
|
-
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
|
|
518
|
-
11
|
|
519
|
-
);
|
|
520
517
|
var FileStorageBackend = class {
|
|
521
518
|
/**
|
|
522
519
|
* @param options.path Path to the JSON file storage (default: ./sessions.json)
|
|
@@ -567,7 +564,7 @@ var FileStorageBackend = class {
|
|
|
567
564
|
return `${identity}:${sessionId}`;
|
|
568
565
|
}
|
|
569
566
|
generateSessionId() {
|
|
570
|
-
return
|
|
567
|
+
return generateSessionId();
|
|
571
568
|
}
|
|
572
569
|
async createSession(session, ttl) {
|
|
573
570
|
await this.ensureInitialized();
|
|
@@ -677,12 +674,7 @@ var SqliteStorage = class {
|
|
|
677
674
|
}
|
|
678
675
|
}
|
|
679
676
|
generateSessionId() {
|
|
680
|
-
|
|
681
|
-
let result = "";
|
|
682
|
-
for (let i = 0; i < 32; i++) {
|
|
683
|
-
result += chars.charAt(Math.floor(Math.random() * chars.length));
|
|
684
|
-
}
|
|
685
|
-
return result;
|
|
677
|
+
return generateSessionId();
|
|
686
678
|
}
|
|
687
679
|
async createSession(session, ttl) {
|
|
688
680
|
this.ensureInitialized();
|
|
@@ -797,7 +789,7 @@ var SupabaseStorageBackend = class {
|
|
|
797
789
|
console.log('[mcp-ts][Storage] Supabase: \u2713 "mcp_sessions" table verified.');
|
|
798
790
|
}
|
|
799
791
|
generateSessionId() {
|
|
800
|
-
return
|
|
792
|
+
return generateSessionId();
|
|
801
793
|
}
|
|
802
794
|
mapRowToSessionData(row) {
|
|
803
795
|
return {
|
|
@@ -1238,16 +1230,6 @@ var StorageOAuthClientProvider = class {
|
|
|
1238
1230
|
}
|
|
1239
1231
|
};
|
|
1240
1232
|
|
|
1241
|
-
// src/shared/utils.ts
|
|
1242
|
-
init_cjs_shims();
|
|
1243
|
-
function sanitizeServerLabel(name) {
|
|
1244
|
-
let sanitized = name.replace(/[^a-zA-Z0-9-_]/g, "_").replace(/_{2,}/g, "_").toLowerCase();
|
|
1245
|
-
if (!/^[a-zA-Z]/.test(sanitized)) {
|
|
1246
|
-
sanitized = "s_" + sanitized;
|
|
1247
|
-
}
|
|
1248
|
-
return sanitized;
|
|
1249
|
-
}
|
|
1250
|
-
|
|
1251
1233
|
// src/shared/events.ts
|
|
1252
1234
|
init_cjs_shims();
|
|
1253
1235
|
var Emitter = class {
|
|
@@ -2281,47 +2263,132 @@ var MCPClient = class _MCPClient {
|
|
|
2281
2263
|
|
|
2282
2264
|
// src/server/mcp/multi-session-client.ts
|
|
2283
2265
|
init_cjs_shims();
|
|
2266
|
+
var DEFAULT_TIMEOUT_MS = 15e3;
|
|
2267
|
+
var DEFAULT_MAX_RETRIES = 2;
|
|
2268
|
+
var DEFAULT_RETRY_DELAY_MS = 1e3;
|
|
2269
|
+
var CONNECTION_BATCH_SIZE = 5;
|
|
2284
2270
|
var MultiSessionClient = class {
|
|
2271
|
+
/**
|
|
2272
|
+
* Creates a new MultiSessionClient for the given user identity.
|
|
2273
|
+
*
|
|
2274
|
+
* @param identity - A unique string identifying the user (e.g. user ID or email).
|
|
2275
|
+
* @param options - Optional tuning for connection timeout, retry count, and retry delay.
|
|
2276
|
+
* Falls back to sensible defaults if not provided.
|
|
2277
|
+
*/
|
|
2285
2278
|
constructor(identity, options = {}) {
|
|
2286
2279
|
__publicField(this, "clients", []);
|
|
2287
2280
|
__publicField(this, "identity");
|
|
2288
2281
|
__publicField(this, "options");
|
|
2282
|
+
__publicField(this, "connectionPromises", /* @__PURE__ */ new Map());
|
|
2289
2283
|
this.identity = identity;
|
|
2290
2284
|
this.options = {
|
|
2291
|
-
timeout:
|
|
2292
|
-
maxRetries:
|
|
2293
|
-
retryDelay:
|
|
2285
|
+
timeout: DEFAULT_TIMEOUT_MS,
|
|
2286
|
+
maxRetries: DEFAULT_MAX_RETRIES,
|
|
2287
|
+
retryDelay: DEFAULT_RETRY_DELAY_MS,
|
|
2294
2288
|
...options
|
|
2295
2289
|
};
|
|
2296
2290
|
}
|
|
2291
|
+
/**
|
|
2292
|
+
* Fetches all sessions for this identity from storage and returns only the
|
|
2293
|
+
* ones that are ready to connect.
|
|
2294
|
+
*
|
|
2295
|
+
* A session is considered connectable when:
|
|
2296
|
+
* - It has a `serverId`, `serverUrl`, and `callbackUrl` (i.e. it was fully initialized)
|
|
2297
|
+
* - Its `active` flag is not explicitly `false` — sessions with `active: false` are
|
|
2298
|
+
* either mid-OAuth flow, auth-pending, or previously failed. We skip those here
|
|
2299
|
+
* and let the OAuth flow complete separately before we try to reconnect them.
|
|
2300
|
+
*
|
|
2301
|
+
* Note: Sessions where `active` is `undefined` (legacy records) are included
|
|
2302
|
+
* for backwards compatibility.
|
|
2303
|
+
*/
|
|
2297
2304
|
async getActiveSessions() {
|
|
2298
2305
|
const sessions = await storage.getIdentitySessionsData(this.identity);
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2306
|
+
const valid = sessions.filter(
|
|
2307
|
+
(s) => s.serverId && s.serverUrl && s.callbackUrl && s.active !== false
|
|
2308
|
+
// exclude OAuth-pending / failed sessions
|
|
2302
2309
|
);
|
|
2303
|
-
const valid = sessions.filter((s) => s.serverId && s.serverUrl && s.callbackUrl);
|
|
2304
|
-
console.log(`[MultiSessionClient] Filtered valid sessions:`, valid.length);
|
|
2305
2310
|
return valid;
|
|
2306
2311
|
}
|
|
2312
|
+
/**
|
|
2313
|
+
* Connects to a list of sessions in controlled batches of `CONNECTION_BATCH_SIZE`.
|
|
2314
|
+
*
|
|
2315
|
+
* Batching prevents overwhelming the event loop or external servers when a user
|
|
2316
|
+
* has many active MCP sessions (e.g. 20+ servers). Within each batch, sessions
|
|
2317
|
+
* are connected concurrently using `Promise.all` for speed.
|
|
2318
|
+
*/
|
|
2307
2319
|
async connectInBatches(sessions) {
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
const batch = sessions.slice(i, i + BATCH_SIZE);
|
|
2320
|
+
for (let i = 0; i < sessions.length; i += CONNECTION_BATCH_SIZE) {
|
|
2321
|
+
const batch = sessions.slice(i, i + CONNECTION_BATCH_SIZE);
|
|
2311
2322
|
await Promise.all(batch.map((session) => this.connectSession(session)));
|
|
2312
2323
|
}
|
|
2313
2324
|
}
|
|
2325
|
+
/**
|
|
2326
|
+
* Connects a single session, with built-in deduplication to prevent race conditions.
|
|
2327
|
+
*
|
|
2328
|
+
* - If a client for this session already exists and is connected, returns immediately.
|
|
2329
|
+
* - If a connection attempt for this session is already in-flight (e.g. from a
|
|
2330
|
+
* concurrent call), it joins the existing promise instead of starting a new one.
|
|
2331
|
+
* This is the key concurrency lock — the `connectionPromises` map acts as a
|
|
2332
|
+
* per-session mutex so we never spin up two physical connections for the same session.
|
|
2333
|
+
* - On completion (success or failure), the promise is cleaned up from the map.
|
|
2334
|
+
*/
|
|
2314
2335
|
async connectSession(session) {
|
|
2315
2336
|
const existingClient = this.clients.find((c) => c.getSessionId() === session.sessionId);
|
|
2316
2337
|
if (existingClient?.isConnected()) {
|
|
2317
2338
|
return;
|
|
2318
2339
|
}
|
|
2319
|
-
|
|
2320
|
-
|
|
2340
|
+
if (this.connectionPromises.has(session.sessionId)) {
|
|
2341
|
+
return this.connectionPromises.get(session.sessionId);
|
|
2342
|
+
}
|
|
2343
|
+
const connectPromise = this.establishConnectionWithRetries(session);
|
|
2344
|
+
this.connectionPromises.set(session.sessionId, connectPromise);
|
|
2345
|
+
try {
|
|
2346
|
+
await connectPromise;
|
|
2347
|
+
} finally {
|
|
2348
|
+
this.connectionPromises.delete(session.sessionId);
|
|
2349
|
+
}
|
|
2350
|
+
}
|
|
2351
|
+
/**
|
|
2352
|
+
* The core connection loop for a single session.
|
|
2353
|
+
*
|
|
2354
|
+
* Attempts to establish a physical MCP connection, retrying up to `maxRetries` times
|
|
2355
|
+
* if the connection fails. Each attempt:
|
|
2356
|
+
* 1. Creates a fresh `MCPClient` instance from the session data.
|
|
2357
|
+
* 2. Races the connect call against a timeout promise — if the server doesn't respond
|
|
2358
|
+
* within `timeoutMs`, the attempt is aborted and counted as a failure.
|
|
2359
|
+
* 3. On success, replaces any stale client entry for this session in the `clients` array.
|
|
2360
|
+
* 4. On failure, waits `retryDelay` ms before the next attempt.
|
|
2361
|
+
*
|
|
2362
|
+
* If all attempts are exhausted, logs an error and returns silently (does not throw),
|
|
2363
|
+
* so a single bad server doesn't block the rest of the batch from connecting.
|
|
2364
|
+
*/
|
|
2365
|
+
async establishConnectionWithRetries(session) {
|
|
2366
|
+
const maxRetries = this.options.maxRetries ?? DEFAULT_MAX_RETRIES;
|
|
2367
|
+
const retryDelay = this.options.retryDelay ?? DEFAULT_RETRY_DELAY_MS;
|
|
2321
2368
|
let lastError;
|
|
2322
2369
|
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
2323
2370
|
try {
|
|
2324
|
-
const client =
|
|
2371
|
+
const client = new MCPClient({
|
|
2372
|
+
identity: this.identity,
|
|
2373
|
+
sessionId: session.sessionId,
|
|
2374
|
+
serverId: session.serverId,
|
|
2375
|
+
serverUrl: session.serverUrl,
|
|
2376
|
+
callbackUrl: session.callbackUrl,
|
|
2377
|
+
serverName: session.serverName,
|
|
2378
|
+
transportType: session.transportType,
|
|
2379
|
+
headers: session.headers
|
|
2380
|
+
});
|
|
2381
|
+
const timeoutMs = this.options.timeout ?? DEFAULT_TIMEOUT_MS;
|
|
2382
|
+
let timeoutTimer;
|
|
2383
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
2384
|
+
timeoutTimer = setTimeout(() => reject(new Error(`Connection timed out after ${timeoutMs}ms`)), timeoutMs);
|
|
2385
|
+
});
|
|
2386
|
+
try {
|
|
2387
|
+
await Promise.race([client.connect(), timeoutPromise]);
|
|
2388
|
+
} finally {
|
|
2389
|
+
clearTimeout(timeoutTimer);
|
|
2390
|
+
}
|
|
2391
|
+
this.clients = this.clients.filter((c) => c.getSessionId() !== session.sessionId);
|
|
2325
2392
|
this.clients.push(client);
|
|
2326
2393
|
return;
|
|
2327
2394
|
} catch (error) {
|
|
@@ -2333,36 +2400,32 @@ var MultiSessionClient = class {
|
|
|
2333
2400
|
}
|
|
2334
2401
|
console.error(`[MultiSessionClient] Failed to connect to session ${session.sessionId} after ${maxRetries + 1} attempts:`, lastError);
|
|
2335
2402
|
}
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
transportType: session.transportType,
|
|
2345
|
-
headers: session.headers
|
|
2346
|
-
});
|
|
2347
|
-
const timeoutMs = this.options.timeout ?? 15e3;
|
|
2348
|
-
const timeoutPromise = new Promise((_, reject) => {
|
|
2349
|
-
setTimeout(() => reject(new Error(`Connection timed out after ${timeoutMs}ms`)), timeoutMs);
|
|
2350
|
-
});
|
|
2351
|
-
await Promise.race([client.connect(), timeoutPromise]);
|
|
2352
|
-
return client;
|
|
2353
|
-
}
|
|
2403
|
+
/**
|
|
2404
|
+
* The main entry point. Fetches all active sessions for this identity from
|
|
2405
|
+
* storage and establishes connections to all of them in batches.
|
|
2406
|
+
*
|
|
2407
|
+
* Call this once after creating the client. On traditional servers, you can
|
|
2408
|
+
* cache the `MultiSessionClient` instance after calling `connect()` to avoid
|
|
2409
|
+
* re-fetching and re-connecting on every request.
|
|
2410
|
+
*/
|
|
2354
2411
|
async connect() {
|
|
2355
2412
|
const sessions = await this.getActiveSessions();
|
|
2356
2413
|
await this.connectInBatches(sessions);
|
|
2357
2414
|
}
|
|
2358
2415
|
/**
|
|
2359
|
-
* Returns
|
|
2416
|
+
* Returns all currently connected `MCPClient` instances.
|
|
2417
|
+
*
|
|
2418
|
+
* Use this to enumerate available tools across all connected servers,
|
|
2419
|
+
* or to route a tool call to the right client by `serverId`.
|
|
2360
2420
|
*/
|
|
2361
2421
|
getClients() {
|
|
2362
2422
|
return this.clients;
|
|
2363
2423
|
}
|
|
2364
2424
|
/**
|
|
2365
|
-
*
|
|
2425
|
+
* Gracefully disconnects all active MCP clients and clears the internal client list.
|
|
2426
|
+
*
|
|
2427
|
+
* Call this during server shutdown or when a user logs out to free up
|
|
2428
|
+
* underlying transport resources (SSE streams, HTTP connections, etc.).
|
|
2366
2429
|
*/
|
|
2367
2430
|
disconnect() {
|
|
2368
2431
|
this.clients.forEach((client) => client.disconnect());
|