@mcp-ts/sdk 1.3.4 → 1.3.6
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/README.md +404 -400
- package/dist/adapters/agui-adapter.d.mts +1 -1
- package/dist/adapters/agui-adapter.d.ts +1 -1
- package/dist/adapters/agui-middleware.d.mts +1 -1
- package/dist/adapters/agui-middleware.d.ts +1 -1
- package/dist/adapters/ai-adapter.d.mts +1 -1
- package/dist/adapters/ai-adapter.d.ts +1 -1
- package/dist/adapters/langchain-adapter.d.mts +1 -1
- package/dist/adapters/langchain-adapter.d.ts +1 -1
- package/dist/adapters/mastra-adapter.d.mts +1 -1
- package/dist/adapters/mastra-adapter.d.ts +1 -1
- package/dist/bin/mcp-ts.d.mts +1 -0
- package/dist/bin/mcp-ts.d.ts +1 -0
- package/dist/bin/mcp-ts.js +105 -0
- package/dist/bin/mcp-ts.js.map +1 -0
- package/dist/bin/mcp-ts.mjs +82 -0
- package/dist/bin/mcp-ts.mjs.map +1 -0
- package/dist/client/index.d.mts +1 -0
- package/dist/client/index.d.ts +1 -0
- package/dist/client/index.js +14 -5
- package/dist/client/index.js.map +1 -1
- package/dist/client/index.mjs +14 -5
- package/dist/client/index.mjs.map +1 -1
- package/dist/client/react.js +15 -6
- package/dist/client/react.js.map +1 -1
- package/dist/client/react.mjs +15 -6
- package/dist/client/react.mjs.map +1 -1
- package/dist/client/vue.js +15 -6
- package/dist/client/vue.js.map +1 -1
- package/dist/client/vue.mjs +15 -6
- package/dist/client/vue.mjs.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +480 -179
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +418 -179
- package/dist/index.mjs.map +1 -1
- package/dist/{multi-session-client-FAFpUzZ4.d.ts → multi-session-client-BYLarghq.d.ts} +29 -19
- package/dist/{multi-session-client-DzjmT7FX.d.mts → multi-session-client-CzhMkE0k.d.mts} +29 -19
- package/dist/server/index.d.mts +1 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +455 -172
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +410 -172
- package/dist/server/index.mjs.map +1 -1
- package/dist/shared/index.d.mts +2 -2
- package/dist/shared/index.d.ts +2 -2
- package/dist/shared/index.js +2 -2
- package/dist/shared/index.js.map +1 -1
- package/dist/shared/index.mjs +2 -2
- package/dist/shared/index.mjs.map +1 -1
- package/package.json +19 -6
- package/src/bin/mcp-ts.ts +102 -0
- package/src/client/core/sse-client.ts +371 -354
- package/src/client/react/use-mcp.ts +31 -31
- package/src/client/vue/use-mcp.ts +77 -77
- package/src/server/handlers/nextjs-handler.ts +204 -207
- package/src/server/handlers/sse-handler.ts +14 -63
- package/src/server/mcp/oauth-client.ts +67 -79
- package/src/server/mcp/storage-oauth-provider.ts +71 -38
- package/src/server/storage/file-backend.ts +1 -0
- package/src/server/storage/index.ts +82 -38
- package/src/server/storage/memory-backend.ts +4 -0
- package/src/server/storage/redis-backend.ts +102 -23
- package/src/server/storage/sqlite-backend.ts +1 -0
- package/src/server/storage/supabase-backend.ts +227 -0
- package/src/server/storage/types.ts +12 -12
- package/src/shared/constants.ts +2 -2
- package/src/shared/event-routing.ts +28 -0
- package/supabase/migrations/20260330195700_install_mcp_sessions.sql +84 -0
package/dist/index.js
CHANGED
|
@@ -43,6 +43,12 @@ var __export = (target, all) => {
|
|
|
43
43
|
};
|
|
44
44
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
45
45
|
|
|
46
|
+
// node_modules/tsup/assets/cjs_shims.js
|
|
47
|
+
var init_cjs_shims = __esm({
|
|
48
|
+
"node_modules/tsup/assets/cjs_shims.js"() {
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
|
|
46
52
|
// src/server/storage/redis.ts
|
|
47
53
|
var redis_exports = {};
|
|
48
54
|
__export(redis_exports, {
|
|
@@ -118,6 +124,7 @@ async function closeRedis() {
|
|
|
118
124
|
var redisInstance, redis;
|
|
119
125
|
var init_redis = __esm({
|
|
120
126
|
"src/server/storage/redis.ts"() {
|
|
127
|
+
init_cjs_shims();
|
|
121
128
|
redisInstance = null;
|
|
122
129
|
redis = new Proxy({}, {
|
|
123
130
|
get(_target, prop) {
|
|
@@ -134,7 +141,26 @@ var init_redis = __esm({
|
|
|
134
141
|
}
|
|
135
142
|
});
|
|
136
143
|
|
|
144
|
+
// src/index.ts
|
|
145
|
+
init_cjs_shims();
|
|
146
|
+
|
|
147
|
+
// src/server/index.ts
|
|
148
|
+
init_cjs_shims();
|
|
149
|
+
|
|
150
|
+
// src/server/mcp/oauth-client.ts
|
|
151
|
+
init_cjs_shims();
|
|
152
|
+
|
|
153
|
+
// src/server/mcp/storage-oauth-provider.ts
|
|
154
|
+
init_cjs_shims();
|
|
155
|
+
|
|
156
|
+
// src/server/storage/index.ts
|
|
157
|
+
init_cjs_shims();
|
|
158
|
+
|
|
159
|
+
// src/server/storage/redis-backend.ts
|
|
160
|
+
init_cjs_shims();
|
|
161
|
+
|
|
137
162
|
// src/shared/constants.ts
|
|
163
|
+
init_cjs_shims();
|
|
138
164
|
var SESSION_TTL_SECONDS = 43200;
|
|
139
165
|
var STATE_EXPIRATION_MS = 10 * 60 * 1e3;
|
|
140
166
|
var DEFAULT_HEARTBEAT_INTERVAL_MS = 3e4;
|
|
@@ -142,10 +168,10 @@ var REDIS_KEY_PREFIX = "mcp:session:";
|
|
|
142
168
|
var TOKEN_EXPIRY_BUFFER_MS = 5 * 60 * 1e3;
|
|
143
169
|
var DEFAULT_CLIENT_NAME = "MCP Assistant";
|
|
144
170
|
var DEFAULT_CLIENT_URI = "https://mcp-assistant.in";
|
|
145
|
-
var DEFAULT_LOGO_URI = "https://mcp-assistant.in/logo.
|
|
171
|
+
var DEFAULT_LOGO_URI = "https://mcp-assistant.in/logo.svg";
|
|
146
172
|
var DEFAULT_POLICY_URI = "https://mcp-assistant.in/privacy";
|
|
147
173
|
var SOFTWARE_ID = "@mcp-ts";
|
|
148
|
-
var SOFTWARE_VERSION = "1.
|
|
174
|
+
var SOFTWARE_VERSION = "1.3.4";
|
|
149
175
|
var MCP_CLIENT_NAME = "mcp-ts-oauth-client";
|
|
150
176
|
var MCP_CLIENT_VERSION = "2.0";
|
|
151
177
|
|
|
@@ -163,6 +189,16 @@ var RedisStorageBackend = class {
|
|
|
163
189
|
this.redis = redis2;
|
|
164
190
|
__publicField(this, "DEFAULT_TTL", SESSION_TTL_SECONDS);
|
|
165
191
|
__publicField(this, "KEY_PREFIX", "mcp:session:");
|
|
192
|
+
__publicField(this, "IDENTITY_KEY_PREFIX", "mcp:identity:");
|
|
193
|
+
__publicField(this, "IDENTITY_KEY_SUFFIX", ":sessions");
|
|
194
|
+
}
|
|
195
|
+
async init() {
|
|
196
|
+
try {
|
|
197
|
+
await this.redis.ping();
|
|
198
|
+
console.log("[mcp-ts][Storage] Redis: \u2713 Connected to server.");
|
|
199
|
+
} catch (error) {
|
|
200
|
+
throw new Error(`[RedisStorage] Failed to connect to Redis: ${error.message}`);
|
|
201
|
+
}
|
|
166
202
|
}
|
|
167
203
|
/**
|
|
168
204
|
* Generates Redis key for a specific session
|
|
@@ -176,7 +212,34 @@ var RedisStorageBackend = class {
|
|
|
176
212
|
* @private
|
|
177
213
|
*/
|
|
178
214
|
getIdentityKey(identity) {
|
|
179
|
-
return
|
|
215
|
+
return `${this.IDENTITY_KEY_PREFIX}${identity}${this.IDENTITY_KEY_SUFFIX}`;
|
|
216
|
+
}
|
|
217
|
+
parseIdentityFromKey(identityKey) {
|
|
218
|
+
return identityKey.slice(
|
|
219
|
+
this.IDENTITY_KEY_PREFIX.length,
|
|
220
|
+
identityKey.length - this.IDENTITY_KEY_SUFFIX.length
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
async scanKeys(pattern) {
|
|
224
|
+
const redis2 = this.redis;
|
|
225
|
+
if (typeof redis2.scan !== "function") {
|
|
226
|
+
return await this.redis.keys(pattern);
|
|
227
|
+
}
|
|
228
|
+
const keys = /* @__PURE__ */ new Set();
|
|
229
|
+
let cursor = "0";
|
|
230
|
+
try {
|
|
231
|
+
do {
|
|
232
|
+
const [nextCursor, batch] = await redis2.scan(cursor, "MATCH", pattern, "COUNT", 100);
|
|
233
|
+
cursor = nextCursor;
|
|
234
|
+
for (const key of batch) {
|
|
235
|
+
keys.add(key);
|
|
236
|
+
}
|
|
237
|
+
} while (cursor !== "0");
|
|
238
|
+
} catch (error) {
|
|
239
|
+
console.warn("[RedisStorage] SCAN failed, falling back to KEYS:", error);
|
|
240
|
+
return await this.redis.keys(pattern);
|
|
241
|
+
}
|
|
242
|
+
return Array.from(keys);
|
|
180
243
|
}
|
|
181
244
|
generateSessionId() {
|
|
182
245
|
return firstChar() + rest();
|
|
@@ -244,17 +307,13 @@ var RedisStorageBackend = class {
|
|
|
244
307
|
}
|
|
245
308
|
}
|
|
246
309
|
async getIdentityMcpSessions(identity) {
|
|
247
|
-
const
|
|
248
|
-
|
|
249
|
-
return await this.redis.smembers(identityKey);
|
|
250
|
-
} catch (error) {
|
|
251
|
-
console.error(`[RedisStorage] Failed to get sessions for ${identity}:`, error);
|
|
252
|
-
return [];
|
|
253
|
-
}
|
|
310
|
+
const sessions = await this.getIdentitySessionsData(identity);
|
|
311
|
+
return sessions.map((session) => session.sessionId);
|
|
254
312
|
}
|
|
255
313
|
async getIdentitySessionsData(identity) {
|
|
256
314
|
try {
|
|
257
|
-
const
|
|
315
|
+
const identityKey = this.getIdentityKey(identity);
|
|
316
|
+
const sessionIds = await this.redis.smembers(identityKey);
|
|
258
317
|
if (sessionIds.length === 0) return [];
|
|
259
318
|
const results = await Promise.all(
|
|
260
319
|
sessionIds.map(async (sessionId) => {
|
|
@@ -262,6 +321,10 @@ var RedisStorageBackend = class {
|
|
|
262
321
|
return data ? JSON.parse(data) : null;
|
|
263
322
|
})
|
|
264
323
|
);
|
|
324
|
+
const staleSessionIds = sessionIds.filter((_, index) => results[index] === null);
|
|
325
|
+
if (staleSessionIds.length > 0) {
|
|
326
|
+
await this.redis.srem(identityKey, ...staleSessionIds);
|
|
327
|
+
}
|
|
265
328
|
return results.filter((session) => session !== null);
|
|
266
329
|
} catch (error) {
|
|
267
330
|
console.error(`[RedisStorage] Failed to get session data for ${identity}:`, error);
|
|
@@ -280,9 +343,22 @@ var RedisStorageBackend = class {
|
|
|
280
343
|
}
|
|
281
344
|
async getAllSessionIds() {
|
|
282
345
|
try {
|
|
283
|
-
const
|
|
284
|
-
const
|
|
285
|
-
|
|
346
|
+
const keys = await this.scanKeys(`${this.KEY_PREFIX}*`);
|
|
347
|
+
const sessions = await Promise.all(
|
|
348
|
+
keys.map(async (key) => {
|
|
349
|
+
const data = await this.redis.get(key);
|
|
350
|
+
if (!data) {
|
|
351
|
+
return null;
|
|
352
|
+
}
|
|
353
|
+
try {
|
|
354
|
+
return JSON.parse(data).sessionId;
|
|
355
|
+
} catch (error) {
|
|
356
|
+
console.error("[RedisStorage] Failed to parse session while listing all session IDs:", error);
|
|
357
|
+
return null;
|
|
358
|
+
}
|
|
359
|
+
})
|
|
360
|
+
);
|
|
361
|
+
return sessions.filter((sessionId) => sessionId !== null);
|
|
286
362
|
} catch (error) {
|
|
287
363
|
console.error("[RedisStorage] Failed to get all sessions:", error);
|
|
288
364
|
return [];
|
|
@@ -290,10 +366,11 @@ var RedisStorageBackend = class {
|
|
|
290
366
|
}
|
|
291
367
|
async clearAll() {
|
|
292
368
|
try {
|
|
293
|
-
const
|
|
294
|
-
const
|
|
295
|
-
|
|
296
|
-
|
|
369
|
+
const keys = await this.scanKeys(`${this.KEY_PREFIX}*`);
|
|
370
|
+
const identityKeys = await this.scanKeys(`${this.IDENTITY_KEY_PREFIX}*${this.IDENTITY_KEY_SUFFIX}`);
|
|
371
|
+
const allKeys = [...keys, ...identityKeys];
|
|
372
|
+
if (allKeys.length > 0) {
|
|
373
|
+
await this.redis.del(...allKeys);
|
|
297
374
|
}
|
|
298
375
|
} catch (error) {
|
|
299
376
|
console.error("[RedisStorage] Failed to clear sessions:", error);
|
|
@@ -301,12 +378,24 @@ var RedisStorageBackend = class {
|
|
|
301
378
|
}
|
|
302
379
|
async cleanupExpiredSessions() {
|
|
303
380
|
try {
|
|
304
|
-
const
|
|
305
|
-
const
|
|
306
|
-
|
|
307
|
-
const
|
|
308
|
-
if (
|
|
309
|
-
await this.redis.del(
|
|
381
|
+
const identityKeys = await this.scanKeys(`${this.IDENTITY_KEY_PREFIX}*${this.IDENTITY_KEY_SUFFIX}`);
|
|
382
|
+
for (const identityKey of identityKeys) {
|
|
383
|
+
const identity = this.parseIdentityFromKey(identityKey);
|
|
384
|
+
const sessionIds = await this.redis.smembers(identityKey);
|
|
385
|
+
if (sessionIds.length === 0) {
|
|
386
|
+
await this.redis.del(identityKey);
|
|
387
|
+
continue;
|
|
388
|
+
}
|
|
389
|
+
const existenceChecks = await Promise.all(
|
|
390
|
+
sessionIds.map((sessionId) => this.redis.exists(this.getSessionKey(identity, sessionId)))
|
|
391
|
+
);
|
|
392
|
+
const staleSessionIds = sessionIds.filter((_, index) => existenceChecks[index] === 0);
|
|
393
|
+
if (staleSessionIds.length > 0) {
|
|
394
|
+
await this.redis.srem(identityKey, ...staleSessionIds);
|
|
395
|
+
}
|
|
396
|
+
const remainingCount = await this.redis.scard(identityKey);
|
|
397
|
+
if (remainingCount === 0) {
|
|
398
|
+
await this.redis.del(identityKey);
|
|
310
399
|
}
|
|
311
400
|
}
|
|
312
401
|
} catch (error) {
|
|
@@ -321,6 +410,9 @@ var RedisStorageBackend = class {
|
|
|
321
410
|
}
|
|
322
411
|
}
|
|
323
412
|
};
|
|
413
|
+
|
|
414
|
+
// src/server/storage/memory-backend.ts
|
|
415
|
+
init_cjs_shims();
|
|
324
416
|
var firstChar2 = nanoid.customAlphabet(
|
|
325
417
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
|
|
326
418
|
1
|
|
@@ -336,6 +428,9 @@ var MemoryStorageBackend = class {
|
|
|
336
428
|
// Map<identity, Set<sessionId>>
|
|
337
429
|
__publicField(this, "identitySessions", /* @__PURE__ */ new Map());
|
|
338
430
|
}
|
|
431
|
+
async init() {
|
|
432
|
+
console.log("[mcp-ts][Storage] Memory: \u2713 internal memory store active.");
|
|
433
|
+
}
|
|
339
434
|
getSessionKey(identity, sessionId) {
|
|
340
435
|
return `${identity}:${sessionId}`;
|
|
341
436
|
}
|
|
@@ -411,6 +506,9 @@ var MemoryStorageBackend = class {
|
|
|
411
506
|
async disconnect() {
|
|
412
507
|
}
|
|
413
508
|
};
|
|
509
|
+
|
|
510
|
+
// src/server/storage/file-backend.ts
|
|
511
|
+
init_cjs_shims();
|
|
414
512
|
var firstChar3 = nanoid.customAlphabet(
|
|
415
513
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
|
|
416
514
|
1
|
|
@@ -455,6 +553,7 @@ var FileStorageBackend = class {
|
|
|
455
553
|
}
|
|
456
554
|
}
|
|
457
555
|
this.initialized = true;
|
|
556
|
+
console.log(`[mcp-ts][Storage] File: \u2713 storage directory at ${path__namespace.dirname(this.filePath)} verified.`);
|
|
458
557
|
}
|
|
459
558
|
async ensureInitialized() {
|
|
460
559
|
if (!this.initialized) await this.init();
|
|
@@ -531,6 +630,9 @@ var FileStorageBackend = class {
|
|
|
531
630
|
async disconnect() {
|
|
532
631
|
}
|
|
533
632
|
};
|
|
633
|
+
|
|
634
|
+
// src/server/storage/sqlite-backend.ts
|
|
635
|
+
init_cjs_shims();
|
|
534
636
|
var SqliteStorage = class {
|
|
535
637
|
constructor(options = {}) {
|
|
536
638
|
__publicField(this, "db", null);
|
|
@@ -559,6 +661,7 @@ var SqliteStorage = class {
|
|
|
559
661
|
CREATE INDEX IF NOT EXISTS idx_${this.table}_identity ON ${this.table}(identity);
|
|
560
662
|
`);
|
|
561
663
|
this.initialized = true;
|
|
664
|
+
console.log(`[mcp-ts][Storage] SQLite: \u2713 database at ${this.dbPath} verified.`);
|
|
562
665
|
} catch (error) {
|
|
563
666
|
if (error.code === "MODULE_NOT_FOUND" || error.message?.includes("better-sqlite3")) {
|
|
564
667
|
throw new Error(
|
|
@@ -674,9 +777,170 @@ var SqliteStorage = class {
|
|
|
674
777
|
}
|
|
675
778
|
};
|
|
676
779
|
|
|
780
|
+
// src/server/storage/supabase-backend.ts
|
|
781
|
+
init_cjs_shims();
|
|
782
|
+
var SupabaseStorageBackend = class {
|
|
783
|
+
constructor(supabase) {
|
|
784
|
+
this.supabase = supabase;
|
|
785
|
+
__publicField(this, "DEFAULT_TTL", SESSION_TTL_SECONDS);
|
|
786
|
+
}
|
|
787
|
+
async init() {
|
|
788
|
+
const { error } = await this.supabase.from("mcp_sessions").select("session_id").limit(0);
|
|
789
|
+
if (error) {
|
|
790
|
+
if (error.code === "42P01") {
|
|
791
|
+
throw new Error(
|
|
792
|
+
'[SupabaseStorage] Table "mcp_sessions" not found in your database. Please run "npx mcp-ts supabase-init" in your project to set up the required table and RLS policies.'
|
|
793
|
+
);
|
|
794
|
+
}
|
|
795
|
+
throw new Error(`[SupabaseStorage] Initialization check failed: ${error.message}`);
|
|
796
|
+
}
|
|
797
|
+
console.log('[mcp-ts][Storage] Supabase: \u2713 "mcp_sessions" table verified.');
|
|
798
|
+
}
|
|
799
|
+
generateSessionId() {
|
|
800
|
+
return crypto.randomUUID();
|
|
801
|
+
}
|
|
802
|
+
mapRowToSessionData(row) {
|
|
803
|
+
return {
|
|
804
|
+
sessionId: row.session_id,
|
|
805
|
+
serverId: row.server_id,
|
|
806
|
+
serverName: row.server_name,
|
|
807
|
+
serverUrl: row.server_url,
|
|
808
|
+
transportType: row.transport_type,
|
|
809
|
+
callbackUrl: row.callback_url,
|
|
810
|
+
createdAt: new Date(row.created_at).getTime(),
|
|
811
|
+
identity: row.identity,
|
|
812
|
+
headers: row.headers,
|
|
813
|
+
active: row.active,
|
|
814
|
+
clientInformation: row.client_information,
|
|
815
|
+
tokens: row.tokens,
|
|
816
|
+
codeVerifier: row.code_verifier,
|
|
817
|
+
clientId: row.client_id
|
|
818
|
+
};
|
|
819
|
+
}
|
|
820
|
+
async createSession(session, ttl) {
|
|
821
|
+
const { sessionId, identity } = session;
|
|
822
|
+
if (!sessionId || !identity) throw new Error("identity and sessionId required");
|
|
823
|
+
const effectiveTtl = ttl ?? this.DEFAULT_TTL;
|
|
824
|
+
const expiresAt = new Date(Date.now() + effectiveTtl * 1e3).toISOString();
|
|
825
|
+
const { error } = await this.supabase.from("mcp_sessions").insert({
|
|
826
|
+
session_id: sessionId,
|
|
827
|
+
user_id: identity,
|
|
828
|
+
// Maps user_id to identity to support RLS using auth.uid()
|
|
829
|
+
server_id: session.serverId,
|
|
830
|
+
server_name: session.serverName,
|
|
831
|
+
server_url: session.serverUrl,
|
|
832
|
+
transport_type: session.transportType,
|
|
833
|
+
callback_url: session.callbackUrl,
|
|
834
|
+
created_at: new Date(session.createdAt || Date.now()).toISOString(),
|
|
835
|
+
identity,
|
|
836
|
+
headers: session.headers,
|
|
837
|
+
active: session.active ?? false,
|
|
838
|
+
client_information: session.clientInformation,
|
|
839
|
+
tokens: session.tokens,
|
|
840
|
+
code_verifier: session.codeVerifier,
|
|
841
|
+
client_id: session.clientId,
|
|
842
|
+
expires_at: expiresAt
|
|
843
|
+
});
|
|
844
|
+
if (error) {
|
|
845
|
+
if (error.code === "23505") {
|
|
846
|
+
throw new Error(`Session ${sessionId} already exists`);
|
|
847
|
+
}
|
|
848
|
+
throw new Error(`Failed to create session in Supabase: ${error.message}`);
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
async updateSession(identity, sessionId, data, ttl) {
|
|
852
|
+
const effectiveTtl = ttl ?? this.DEFAULT_TTL;
|
|
853
|
+
const expiresAt = new Date(Date.now() + effectiveTtl * 1e3).toISOString();
|
|
854
|
+
const updateData = {
|
|
855
|
+
expires_at: expiresAt,
|
|
856
|
+
updated_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
857
|
+
};
|
|
858
|
+
if ("serverId" in data) updateData.server_id = data.serverId;
|
|
859
|
+
if ("serverName" in data) updateData.server_name = data.serverName;
|
|
860
|
+
if ("serverUrl" in data) updateData.server_url = data.serverUrl;
|
|
861
|
+
if ("transportType" in data) updateData.transport_type = data.transportType;
|
|
862
|
+
if ("callbackUrl" in data) updateData.callback_url = data.callbackUrl;
|
|
863
|
+
if ("active" in data) updateData.active = data.active;
|
|
864
|
+
if ("headers" in data) updateData.headers = data.headers;
|
|
865
|
+
if ("clientInformation" in data) updateData.client_information = data.clientInformation;
|
|
866
|
+
if ("tokens" in data) updateData.tokens = data.tokens;
|
|
867
|
+
if ("codeVerifier" in data) updateData.code_verifier = data.codeVerifier;
|
|
868
|
+
if ("clientId" in data) updateData.client_id = data.clientId;
|
|
869
|
+
const { data: updatedRows, error } = await this.supabase.from("mcp_sessions").update(updateData).eq("identity", identity).eq("session_id", sessionId).select("id");
|
|
870
|
+
if (error) {
|
|
871
|
+
throw new Error(`Failed to update session: ${error.message}`);
|
|
872
|
+
}
|
|
873
|
+
if (!updatedRows || updatedRows.length === 0) {
|
|
874
|
+
throw new Error(`Session ${sessionId} not found for identity ${identity}`);
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
async getSession(identity, sessionId) {
|
|
878
|
+
const { data, error } = await this.supabase.from("mcp_sessions").select("*").eq("identity", identity).eq("session_id", sessionId).maybeSingle();
|
|
879
|
+
if (error) {
|
|
880
|
+
console.error("[SupabaseStorage] Failed to get session:", error);
|
|
881
|
+
return null;
|
|
882
|
+
}
|
|
883
|
+
if (!data) return null;
|
|
884
|
+
return this.mapRowToSessionData(data);
|
|
885
|
+
}
|
|
886
|
+
async getIdentitySessionsData(identity) {
|
|
887
|
+
const { data, error } = await this.supabase.from("mcp_sessions").select("*").eq("identity", identity);
|
|
888
|
+
if (error) {
|
|
889
|
+
console.error(`[SupabaseStorage] Failed to get session data for ${identity}:`, error);
|
|
890
|
+
return [];
|
|
891
|
+
}
|
|
892
|
+
return data.map((row) => this.mapRowToSessionData(row));
|
|
893
|
+
}
|
|
894
|
+
async removeSession(identity, sessionId) {
|
|
895
|
+
const { error } = await this.supabase.from("mcp_sessions").delete().eq("identity", identity).eq("session_id", sessionId);
|
|
896
|
+
if (error) {
|
|
897
|
+
console.error("[SupabaseStorage] Failed to remove session:", error);
|
|
898
|
+
}
|
|
899
|
+
}
|
|
900
|
+
async getIdentityMcpSessions(identity) {
|
|
901
|
+
const { data, error } = await this.supabase.from("mcp_sessions").select("session_id").eq("identity", identity);
|
|
902
|
+
if (error) {
|
|
903
|
+
console.error(`[SupabaseStorage] Failed to get sessions for ${identity}:`, error);
|
|
904
|
+
return [];
|
|
905
|
+
}
|
|
906
|
+
return data.map((row) => row.session_id);
|
|
907
|
+
}
|
|
908
|
+
async getAllSessionIds() {
|
|
909
|
+
const { data, error } = await this.supabase.from("mcp_sessions").select("session_id");
|
|
910
|
+
if (error) {
|
|
911
|
+
console.error("[SupabaseStorage] Failed to get all sessions:", error);
|
|
912
|
+
return [];
|
|
913
|
+
}
|
|
914
|
+
return data.map((row) => row.session_id);
|
|
915
|
+
}
|
|
916
|
+
async clearAll() {
|
|
917
|
+
const { error } = await this.supabase.from("mcp_sessions").delete().neq("session_id", "");
|
|
918
|
+
if (error) {
|
|
919
|
+
console.error("[SupabaseStorage] Failed to clear sessions:", error);
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
async cleanupExpiredSessions() {
|
|
923
|
+
const { error } = await this.supabase.from("mcp_sessions").delete().lt("expires_at", (/* @__PURE__ */ new Date()).toISOString());
|
|
924
|
+
if (error) {
|
|
925
|
+
console.error("[SupabaseStorage] Failed to cleanup expired sessions:", error);
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
async disconnect() {
|
|
929
|
+
}
|
|
930
|
+
};
|
|
931
|
+
|
|
932
|
+
// src/server/storage/types.ts
|
|
933
|
+
init_cjs_shims();
|
|
934
|
+
|
|
677
935
|
// src/server/storage/index.ts
|
|
678
936
|
var storageInstance = null;
|
|
679
937
|
var storagePromise = null;
|
|
938
|
+
async function initializeStorage(store) {
|
|
939
|
+
if (typeof store.init === "function") {
|
|
940
|
+
await store.init();
|
|
941
|
+
}
|
|
942
|
+
return store;
|
|
943
|
+
}
|
|
680
944
|
async function createStorage() {
|
|
681
945
|
const type = process.env.MCP_TS_STORAGE_TYPE?.toLowerCase();
|
|
682
946
|
if (type === "redis") {
|
|
@@ -686,68 +950,95 @@ async function createStorage() {
|
|
|
686
950
|
try {
|
|
687
951
|
const { getRedis: getRedis2 } = await Promise.resolve().then(() => (init_redis(), redis_exports));
|
|
688
952
|
const redis2 = await getRedis2();
|
|
689
|
-
console.log(
|
|
690
|
-
return new RedisStorageBackend(redis2);
|
|
953
|
+
console.log('[mcp-ts][Storage] Explicit selection: "redis"');
|
|
954
|
+
return await initializeStorage(new RedisStorageBackend(redis2));
|
|
691
955
|
} catch (error) {
|
|
692
|
-
console.error("[Storage] Failed to initialize Redis:", error.message);
|
|
693
|
-
console.log("[Storage] Falling back to In-Memory storage");
|
|
694
|
-
return new MemoryStorageBackend();
|
|
956
|
+
console.error("[mcp-ts][Storage] Failed to initialize Redis:", error.message);
|
|
957
|
+
console.log("[mcp-ts][Storage] Falling back to In-Memory storage");
|
|
958
|
+
return await initializeStorage(new MemoryStorageBackend());
|
|
695
959
|
}
|
|
696
960
|
}
|
|
697
961
|
if (type === "file") {
|
|
698
962
|
const filePath = process.env.MCP_TS_STORAGE_FILE;
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
}
|
|
702
|
-
console.log(`[Storage] Using File storage (${filePath}) (Explicit)`);
|
|
703
|
-
const store = new FileStorageBackend({ path: filePath });
|
|
704
|
-
store.init().catch((err) => console.error("[Storage] Failed to initialize file storage:", err));
|
|
705
|
-
return store;
|
|
963
|
+
console.log(`[mcp-ts][Storage] Explicit selection: "file" (${filePath || "default"})`);
|
|
964
|
+
return await initializeStorage(new FileStorageBackend({ path: filePath }));
|
|
706
965
|
}
|
|
707
966
|
if (type === "sqlite") {
|
|
708
967
|
const dbPath = process.env.MCP_TS_STORAGE_SQLITE_PATH;
|
|
709
|
-
console.log(`[Storage]
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
968
|
+
console.log(`[mcp-ts][Storage] Explicit selection: "sqlite" (${dbPath || "default"})`);
|
|
969
|
+
return await initializeStorage(new SqliteStorage({ path: dbPath }));
|
|
970
|
+
}
|
|
971
|
+
if (type === "supabase") {
|
|
972
|
+
const url = process.env.SUPABASE_URL;
|
|
973
|
+
const key = process.env.SUPABASE_SERVICE_ROLE_KEY || process.env.SUPABASE_ANON_KEY;
|
|
974
|
+
if (!url || !key) {
|
|
975
|
+
console.warn('[mcp-ts][Storage] Explicit selection "supabase" requires SUPABASE_URL and SUPABASE_SERVICE_ROLE_KEY.');
|
|
976
|
+
} else {
|
|
977
|
+
if (!process.env.SUPABASE_SERVICE_ROLE_KEY) {
|
|
978
|
+
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.');
|
|
979
|
+
}
|
|
980
|
+
try {
|
|
981
|
+
const { createClient } = await import('@supabase/supabase-js');
|
|
982
|
+
const client = createClient(url, key);
|
|
983
|
+
console.log('[mcp-ts][Storage] Explicit selection: "supabase"');
|
|
984
|
+
return await initializeStorage(new SupabaseStorageBackend(client));
|
|
985
|
+
} catch (error) {
|
|
986
|
+
console.error("[mcp-ts][Storage] Failed to initialize Supabase:", error.message);
|
|
987
|
+
console.log("[mcp-ts][Storage] Falling back to In-Memory storage");
|
|
988
|
+
return await initializeStorage(new MemoryStorageBackend());
|
|
989
|
+
}
|
|
990
|
+
}
|
|
713
991
|
}
|
|
714
992
|
if (type === "memory") {
|
|
715
|
-
console.log(
|
|
716
|
-
return new MemoryStorageBackend();
|
|
993
|
+
console.log('[mcp-ts][Storage] Explicit selection: "memory"');
|
|
994
|
+
return await initializeStorage(new MemoryStorageBackend());
|
|
717
995
|
}
|
|
718
996
|
if (process.env.REDIS_URL) {
|
|
719
997
|
try {
|
|
720
998
|
const { getRedis: getRedis2 } = await Promise.resolve().then(() => (init_redis(), redis_exports));
|
|
721
999
|
const redis2 = await getRedis2();
|
|
722
|
-
console.log(
|
|
723
|
-
return new RedisStorageBackend(redis2);
|
|
1000
|
+
console.log('[mcp-ts][Storage] Auto-detection: "redis" (via REDIS_URL)');
|
|
1001
|
+
return await initializeStorage(new RedisStorageBackend(redis2));
|
|
724
1002
|
} catch (error) {
|
|
725
|
-
console.error("[Storage] Redis auto-detection failed:", error.message);
|
|
726
|
-
console.log("[Storage] Falling back to
|
|
727
|
-
return new MemoryStorageBackend();
|
|
1003
|
+
console.error("[mcp-ts][Storage] Redis auto-detection failed:", error.message);
|
|
1004
|
+
console.log("[mcp-ts][Storage] Falling back to next available backend");
|
|
728
1005
|
}
|
|
729
1006
|
}
|
|
730
1007
|
if (process.env.MCP_TS_STORAGE_FILE) {
|
|
731
|
-
console.log(`[Storage] Auto-
|
|
732
|
-
|
|
733
|
-
store.init().catch((err) => console.error("[Storage] Failed to initialize file storage:", err));
|
|
734
|
-
return store;
|
|
1008
|
+
console.log(`[mcp-ts][Storage] Auto-detection: "file" (${process.env.MCP_TS_STORAGE_FILE})`);
|
|
1009
|
+
return await initializeStorage(new FileStorageBackend({ path: process.env.MCP_TS_STORAGE_FILE }));
|
|
735
1010
|
}
|
|
736
1011
|
if (process.env.MCP_TS_STORAGE_SQLITE_PATH) {
|
|
737
|
-
console.log(`[Storage] Auto-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
1012
|
+
console.log(`[mcp-ts][Storage] Auto-detection: "sqlite" (${process.env.MCP_TS_STORAGE_SQLITE_PATH})`);
|
|
1013
|
+
return await initializeStorage(new SqliteStorage({ path: process.env.MCP_TS_STORAGE_SQLITE_PATH }));
|
|
1014
|
+
}
|
|
1015
|
+
if (process.env.SUPABASE_URL && (process.env.SUPABASE_SERVICE_ROLE_KEY || process.env.SUPABASE_ANON_KEY)) {
|
|
1016
|
+
try {
|
|
1017
|
+
const { createClient } = await import('@supabase/supabase-js');
|
|
1018
|
+
const url = process.env.SUPABASE_URL;
|
|
1019
|
+
const key = process.env.SUPABASE_SERVICE_ROLE_KEY || process.env.SUPABASE_ANON_KEY;
|
|
1020
|
+
if (!process.env.SUPABASE_SERVICE_ROLE_KEY) {
|
|
1021
|
+
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.');
|
|
1022
|
+
}
|
|
1023
|
+
const client = createClient(url, key);
|
|
1024
|
+
console.log('[mcp-ts][Storage] Auto-detection: "supabase" (via SUPABASE_URL)');
|
|
1025
|
+
return await initializeStorage(new SupabaseStorageBackend(client));
|
|
1026
|
+
} catch (error) {
|
|
1027
|
+
console.error("[mcp-ts][Storage] Supabase auto-detection failed:", error.message);
|
|
1028
|
+
}
|
|
741
1029
|
}
|
|
742
|
-
console.log(
|
|
743
|
-
return new MemoryStorageBackend();
|
|
1030
|
+
console.log('[mcp-ts][Storage] Defaulting to: "memory"');
|
|
1031
|
+
return await initializeStorage(new MemoryStorageBackend());
|
|
744
1032
|
}
|
|
745
1033
|
async function getStorage() {
|
|
746
1034
|
if (storageInstance) {
|
|
747
1035
|
return storageInstance;
|
|
748
1036
|
}
|
|
749
1037
|
if (!storagePromise) {
|
|
750
|
-
storagePromise = createStorage()
|
|
1038
|
+
storagePromise = createStorage().catch((error) => {
|
|
1039
|
+
storagePromise = null;
|
|
1040
|
+
throw error;
|
|
1041
|
+
});
|
|
751
1042
|
}
|
|
752
1043
|
storageInstance = await storagePromise;
|
|
753
1044
|
return storageInstance;
|
|
@@ -768,43 +1059,49 @@ var storage = new Proxy({}, {
|
|
|
768
1059
|
// src/server/mcp/storage-oauth-provider.ts
|
|
769
1060
|
var StorageOAuthClientProvider = class {
|
|
770
1061
|
/**
|
|
771
|
-
* Creates a new
|
|
772
|
-
* @param
|
|
773
|
-
* @param serverId - Server identifier (for tracking which server this OAuth session belongs to)
|
|
774
|
-
* @param sessionId - Session identifier (used as OAuth state)
|
|
775
|
-
* @param clientName - OAuth client name
|
|
776
|
-
* @param baseRedirectUrl - OAuth callback URL
|
|
777
|
-
* @param onRedirect - Optional callback when redirect to authorization is needed
|
|
1062
|
+
* Creates a new storage-backed OAuth provider
|
|
1063
|
+
* @param options - Provider configuration
|
|
778
1064
|
*/
|
|
779
|
-
constructor(
|
|
780
|
-
this
|
|
781
|
-
this
|
|
782
|
-
this
|
|
783
|
-
this
|
|
784
|
-
this
|
|
1065
|
+
constructor(options) {
|
|
1066
|
+
__publicField(this, "identity");
|
|
1067
|
+
__publicField(this, "serverId");
|
|
1068
|
+
__publicField(this, "sessionId");
|
|
1069
|
+
__publicField(this, "redirectUrl");
|
|
1070
|
+
__publicField(this, "clientName");
|
|
1071
|
+
__publicField(this, "clientUri");
|
|
1072
|
+
__publicField(this, "logoUri");
|
|
1073
|
+
__publicField(this, "policyUri");
|
|
1074
|
+
__publicField(this, "clientSecret");
|
|
785
1075
|
__publicField(this, "_authUrl");
|
|
786
1076
|
__publicField(this, "_clientId");
|
|
787
1077
|
__publicField(this, "onRedirectCallback");
|
|
788
1078
|
__publicField(this, "tokenExpiresAt");
|
|
789
|
-
this.
|
|
1079
|
+
this.identity = options.identity;
|
|
1080
|
+
this.serverId = options.serverId;
|
|
1081
|
+
this.sessionId = options.sessionId;
|
|
1082
|
+
this.redirectUrl = options.redirectUrl;
|
|
1083
|
+
this.clientName = options.clientName;
|
|
1084
|
+
this.clientUri = options.clientUri;
|
|
1085
|
+
this.logoUri = options.logoUri;
|
|
1086
|
+
this.policyUri = options.policyUri;
|
|
1087
|
+
this._clientId = options.clientId;
|
|
1088
|
+
this.clientSecret = options.clientSecret;
|
|
1089
|
+
this.onRedirectCallback = options.onRedirect;
|
|
790
1090
|
}
|
|
791
1091
|
get clientMetadata() {
|
|
792
1092
|
return {
|
|
793
|
-
client_name: this.clientName,
|
|
794
|
-
client_uri: this.clientUri,
|
|
1093
|
+
client_name: this.clientName || DEFAULT_CLIENT_NAME,
|
|
1094
|
+
client_uri: this.clientUri || DEFAULT_CLIENT_URI,
|
|
1095
|
+
logo_uri: this.logoUri || DEFAULT_LOGO_URI,
|
|
1096
|
+
policy_uri: this.policyUri || DEFAULT_POLICY_URI,
|
|
795
1097
|
grant_types: ["authorization_code", "refresh_token"],
|
|
796
1098
|
redirect_uris: [this.redirectUrl],
|
|
797
1099
|
response_types: ["code"],
|
|
798
|
-
token_endpoint_auth_method: "none",
|
|
799
|
-
|
|
1100
|
+
token_endpoint_auth_method: this.clientSecret ? "client_secret_basic" : "none",
|
|
1101
|
+
software_id: SOFTWARE_ID,
|
|
1102
|
+
software_version: SOFTWARE_VERSION
|
|
800
1103
|
};
|
|
801
1104
|
}
|
|
802
|
-
get clientUri() {
|
|
803
|
-
return new URL(this.redirectUrl).origin;
|
|
804
|
-
}
|
|
805
|
-
get redirectUrl() {
|
|
806
|
-
return this.baseRedirectUrl;
|
|
807
|
-
}
|
|
808
1105
|
get clientId() {
|
|
809
1106
|
return this._clientId;
|
|
810
1107
|
}
|
|
@@ -839,7 +1136,16 @@ var StorageOAuthClientProvider = class {
|
|
|
839
1136
|
if (data.clientId && !this._clientId) {
|
|
840
1137
|
this._clientId = data.clientId;
|
|
841
1138
|
}
|
|
842
|
-
|
|
1139
|
+
if (data.clientInformation) {
|
|
1140
|
+
return data.clientInformation;
|
|
1141
|
+
}
|
|
1142
|
+
if (!this._clientId) {
|
|
1143
|
+
return void 0;
|
|
1144
|
+
}
|
|
1145
|
+
return {
|
|
1146
|
+
client_id: this._clientId,
|
|
1147
|
+
...this.clientSecret ? { client_secret: this.clientSecret } : {}
|
|
1148
|
+
};
|
|
843
1149
|
}
|
|
844
1150
|
/**
|
|
845
1151
|
* Stores OAuth client information
|
|
@@ -867,14 +1173,14 @@ var StorageOAuthClientProvider = class {
|
|
|
867
1173
|
async state() {
|
|
868
1174
|
return this.sessionId;
|
|
869
1175
|
}
|
|
870
|
-
async checkState(
|
|
1176
|
+
async checkState(_state) {
|
|
871
1177
|
const data = await storage.getSession(this.identity, this.sessionId);
|
|
872
1178
|
if (!data) {
|
|
873
1179
|
return { valid: false, error: "Session not found" };
|
|
874
1180
|
}
|
|
875
1181
|
return { valid: true, serverId: this.serverId };
|
|
876
1182
|
}
|
|
877
|
-
async consumeState(
|
|
1183
|
+
async consumeState(_state) {
|
|
878
1184
|
}
|
|
879
1185
|
async redirectToAuthorization(authUrl) {
|
|
880
1186
|
this._authUrl = authUrl.toString();
|
|
@@ -886,7 +1192,6 @@ var StorageOAuthClientProvider = class {
|
|
|
886
1192
|
if (scope === "all") {
|
|
887
1193
|
await storage.removeSession(this.identity, this.sessionId);
|
|
888
1194
|
} else {
|
|
889
|
-
await this.getSessionData();
|
|
890
1195
|
const updates = {};
|
|
891
1196
|
if (scope === "client") {
|
|
892
1197
|
updates.clientInformation = void 0;
|
|
@@ -934,6 +1239,7 @@ var StorageOAuthClientProvider = class {
|
|
|
934
1239
|
};
|
|
935
1240
|
|
|
936
1241
|
// src/shared/utils.ts
|
|
1242
|
+
init_cjs_shims();
|
|
937
1243
|
function sanitizeServerLabel(name) {
|
|
938
1244
|
let sanitized = name.replace(/[^a-zA-Z0-9-_]/g, "_").replace(/_{2,}/g, "_").toLowerCase();
|
|
939
1245
|
if (!/^[a-zA-Z]/.test(sanitized)) {
|
|
@@ -943,6 +1249,7 @@ function sanitizeServerLabel(name) {
|
|
|
943
1249
|
}
|
|
944
1250
|
|
|
945
1251
|
// src/shared/events.ts
|
|
1252
|
+
init_cjs_shims();
|
|
946
1253
|
var Emitter = class {
|
|
947
1254
|
constructor() {
|
|
948
1255
|
__publicField(this, "listeners", /* @__PURE__ */ new Set());
|
|
@@ -1004,6 +1311,7 @@ var DisposableStore = class {
|
|
|
1004
1311
|
};
|
|
1005
1312
|
|
|
1006
1313
|
// src/shared/errors.ts
|
|
1314
|
+
init_cjs_shims();
|
|
1007
1315
|
var McpError = class extends Error {
|
|
1008
1316
|
constructor(code, message, cause) {
|
|
1009
1317
|
super(message);
|
|
@@ -1274,41 +1582,33 @@ var MCPClient = class _MCPClient {
|
|
|
1274
1582
|
if (!this.serverUrl || !this.callbackUrl || !this.serverId) {
|
|
1275
1583
|
throw new Error("Missing required connection metadata");
|
|
1276
1584
|
}
|
|
1277
|
-
const clientMetadata = {
|
|
1278
|
-
client_name: this.clientName || "MCP Assistant",
|
|
1279
|
-
redirect_uris: [this.callbackUrl],
|
|
1280
|
-
token_endpoint_auth_method: this.clientSecret ? "client_secret_basic" : "none",
|
|
1281
|
-
client_uri: this.clientUri || "https://mcp-assistant.in",
|
|
1282
|
-
logo_uri: this.logoUri || "https://mcp-assistant.in/logo.png",
|
|
1283
|
-
policy_uri: this.policyUri || "https://mcp-assistant.in/privacy",
|
|
1284
|
-
...this.clientId ? { client_id: this.clientId } : {},
|
|
1285
|
-
...this.clientSecret ? { client_secret: this.clientSecret } : {}
|
|
1286
|
-
};
|
|
1287
1585
|
if (!this.oauthProvider) {
|
|
1288
1586
|
if (!this.serverId) {
|
|
1289
1587
|
throw new Error("serverId required for OAuth provider initialization");
|
|
1290
1588
|
}
|
|
1291
|
-
this.oauthProvider = new StorageOAuthClientProvider(
|
|
1292
|
-
this.identity,
|
|
1293
|
-
this.serverId,
|
|
1294
|
-
this.sessionId,
|
|
1295
|
-
|
|
1296
|
-
this.
|
|
1297
|
-
|
|
1589
|
+
this.oauthProvider = new StorageOAuthClientProvider({
|
|
1590
|
+
identity: this.identity,
|
|
1591
|
+
serverId: this.serverId,
|
|
1592
|
+
sessionId: this.sessionId,
|
|
1593
|
+
redirectUrl: this.callbackUrl,
|
|
1594
|
+
clientName: this.clientName,
|
|
1595
|
+
clientUri: this.clientUri,
|
|
1596
|
+
logoUri: this.logoUri,
|
|
1597
|
+
policyUri: this.policyUri,
|
|
1598
|
+
clientId: this.clientId,
|
|
1599
|
+
clientSecret: this.clientSecret,
|
|
1600
|
+
onRedirect: (redirectUrl) => {
|
|
1298
1601
|
if (this.onRedirect) {
|
|
1299
1602
|
this.onRedirect(redirectUrl);
|
|
1300
1603
|
}
|
|
1301
1604
|
}
|
|
1302
|
-
);
|
|
1303
|
-
if (this.clientId && this.oauthProvider) {
|
|
1304
|
-
this.oauthProvider.clientId = this.clientId;
|
|
1305
|
-
}
|
|
1605
|
+
});
|
|
1306
1606
|
}
|
|
1307
1607
|
if (!this.client) {
|
|
1308
1608
|
this.client = new index_js.Client(
|
|
1309
1609
|
{
|
|
1310
|
-
name:
|
|
1311
|
-
version:
|
|
1610
|
+
name: MCP_CLIENT_NAME,
|
|
1611
|
+
version: MCP_CLIENT_VERSION
|
|
1312
1612
|
},
|
|
1313
1613
|
{
|
|
1314
1614
|
capabilities: {
|
|
@@ -1503,8 +1803,8 @@ var MCPClient = class _MCPClient {
|
|
|
1503
1803
|
this.emitProgress("Creating authenticated client...");
|
|
1504
1804
|
this.client = new index_js.Client(
|
|
1505
1805
|
{
|
|
1506
|
-
name:
|
|
1507
|
-
version:
|
|
1806
|
+
name: MCP_CLIENT_NAME,
|
|
1807
|
+
version: MCP_CLIENT_VERSION
|
|
1508
1808
|
},
|
|
1509
1809
|
{
|
|
1510
1810
|
capabilities: {
|
|
@@ -1799,8 +2099,8 @@ var MCPClient = class _MCPClient {
|
|
|
1799
2099
|
}
|
|
1800
2100
|
this.client = new index_js.Client(
|
|
1801
2101
|
{
|
|
1802
|
-
name:
|
|
1803
|
-
version:
|
|
2102
|
+
name: MCP_CLIENT_NAME,
|
|
2103
|
+
version: MCP_CLIENT_VERSION
|
|
1804
2104
|
},
|
|
1805
2105
|
{ capabilities: {} }
|
|
1806
2106
|
);
|
|
@@ -1980,6 +2280,7 @@ var MCPClient = class _MCPClient {
|
|
|
1980
2280
|
};
|
|
1981
2281
|
|
|
1982
2282
|
// src/server/mcp/multi-session-client.ts
|
|
2283
|
+
init_cjs_shims();
|
|
1983
2284
|
var MultiSessionClient = class {
|
|
1984
2285
|
constructor(identity, options = {}) {
|
|
1985
2286
|
__publicField(this, "clients", []);
|
|
@@ -2069,6 +2370,31 @@ var MultiSessionClient = class {
|
|
|
2069
2370
|
}
|
|
2070
2371
|
};
|
|
2071
2372
|
|
|
2373
|
+
// src/server/handlers/sse-handler.ts
|
|
2374
|
+
init_cjs_shims();
|
|
2375
|
+
|
|
2376
|
+
// src/shared/event-routing.ts
|
|
2377
|
+
init_cjs_shims();
|
|
2378
|
+
function isRpcResponseEvent(event) {
|
|
2379
|
+
return "id" in event && ("result" in event || "error" in event);
|
|
2380
|
+
}
|
|
2381
|
+
function isConnectionEvent(event) {
|
|
2382
|
+
if (!("type" in event)) {
|
|
2383
|
+
return false;
|
|
2384
|
+
}
|
|
2385
|
+
switch (event.type) {
|
|
2386
|
+
case "state_changed":
|
|
2387
|
+
case "tools_discovered":
|
|
2388
|
+
case "auth_required":
|
|
2389
|
+
case "error":
|
|
2390
|
+
case "disconnected":
|
|
2391
|
+
case "progress":
|
|
2392
|
+
return true;
|
|
2393
|
+
default:
|
|
2394
|
+
return false;
|
|
2395
|
+
}
|
|
2396
|
+
}
|
|
2397
|
+
|
|
2072
2398
|
// src/server/handlers/sse-handler.ts
|
|
2073
2399
|
var DEFAULT_HEARTBEAT_INTERVAL = 3e4;
|
|
2074
2400
|
var SSEConnectionManager = class {
|
|
@@ -2211,16 +2537,6 @@ var SSEConnectionManager = class {
|
|
|
2211
2537
|
throw new Error(`Connection already exists for server: ${duplicate.serverUrl || duplicate.serverId} (${duplicate.serverName})`);
|
|
2212
2538
|
}
|
|
2213
2539
|
const sessionId = await storage.generateSessionId();
|
|
2214
|
-
this.emitConnectionEvent({
|
|
2215
|
-
type: "state_changed",
|
|
2216
|
-
sessionId,
|
|
2217
|
-
serverId,
|
|
2218
|
-
serverName,
|
|
2219
|
-
serverUrl,
|
|
2220
|
-
state: "CONNECTING",
|
|
2221
|
-
previousState: "DISCONNECTED",
|
|
2222
|
-
timestamp: Date.now()
|
|
2223
|
-
});
|
|
2224
2540
|
try {
|
|
2225
2541
|
const clientMetadata = await this.getResolvedClientMetadata();
|
|
2226
2542
|
const client = new MCPClient({
|
|
@@ -2231,17 +2547,8 @@ var SSEConnectionManager = class {
|
|
|
2231
2547
|
serverUrl,
|
|
2232
2548
|
callbackUrl,
|
|
2233
2549
|
transportType,
|
|
2234
|
-
...clientMetadata
|
|
2550
|
+
...clientMetadata
|
|
2235
2551
|
// Spread client metadata (clientName, clientUri, logoUri, policyUri)
|
|
2236
|
-
onRedirect: (authUrl) => {
|
|
2237
|
-
this.emitConnectionEvent({
|
|
2238
|
-
type: "auth_required",
|
|
2239
|
-
sessionId,
|
|
2240
|
-
serverId,
|
|
2241
|
-
authUrl,
|
|
2242
|
-
timestamp: Date.now()
|
|
2243
|
-
});
|
|
2244
|
-
}
|
|
2245
2552
|
});
|
|
2246
2553
|
this.clients.set(sessionId, client);
|
|
2247
2554
|
client.onConnectionEvent((event) => {
|
|
@@ -2251,20 +2558,19 @@ var SSEConnectionManager = class {
|
|
|
2251
2558
|
this.sendEvent(event);
|
|
2252
2559
|
});
|
|
2253
2560
|
await client.connect();
|
|
2254
|
-
|
|
2255
|
-
this.emitConnectionEvent({
|
|
2256
|
-
type: "tools_discovered",
|
|
2257
|
-
sessionId,
|
|
2258
|
-
serverId,
|
|
2259
|
-
toolCount: tools.tools.length,
|
|
2260
|
-
tools: tools.tools,
|
|
2261
|
-
timestamp: Date.now()
|
|
2262
|
-
});
|
|
2561
|
+
await client.listTools();
|
|
2263
2562
|
return {
|
|
2264
2563
|
sessionId,
|
|
2265
2564
|
success: true
|
|
2266
2565
|
};
|
|
2267
2566
|
} catch (error) {
|
|
2567
|
+
if (error instanceof UnauthorizedError) {
|
|
2568
|
+
this.clients.delete(sessionId);
|
|
2569
|
+
return {
|
|
2570
|
+
sessionId,
|
|
2571
|
+
success: true
|
|
2572
|
+
};
|
|
2573
|
+
}
|
|
2268
2574
|
this.emitConnectionEvent({
|
|
2269
2575
|
type: "error",
|
|
2270
2576
|
sessionId,
|
|
@@ -2366,14 +2672,6 @@ var SSEConnectionManager = class {
|
|
|
2366
2672
|
await client.connect();
|
|
2367
2673
|
this.clients.set(sessionId, client);
|
|
2368
2674
|
const tools = await client.listTools();
|
|
2369
|
-
this.emitConnectionEvent({
|
|
2370
|
-
type: "tools_discovered",
|
|
2371
|
-
sessionId,
|
|
2372
|
-
serverId: session.serverId ?? "unknown",
|
|
2373
|
-
toolCount: tools.tools.length,
|
|
2374
|
-
tools: tools.tools,
|
|
2375
|
-
timestamp: Date.now()
|
|
2376
|
-
});
|
|
2377
2675
|
return { success: true, toolCount: tools.tools.length };
|
|
2378
2676
|
} catch (error) {
|
|
2379
2677
|
this.emitConnectionEvent({
|
|
@@ -2396,16 +2694,6 @@ var SSEConnectionManager = class {
|
|
|
2396
2694
|
if (!session) {
|
|
2397
2695
|
throw new Error("Session not found");
|
|
2398
2696
|
}
|
|
2399
|
-
this.emitConnectionEvent({
|
|
2400
|
-
type: "state_changed",
|
|
2401
|
-
sessionId,
|
|
2402
|
-
serverId: session.serverId ?? "unknown",
|
|
2403
|
-
serverName: session.serverName ?? "Unknown",
|
|
2404
|
-
serverUrl: session.serverUrl,
|
|
2405
|
-
state: "AUTHENTICATING",
|
|
2406
|
-
previousState: "DISCONNECTED",
|
|
2407
|
-
timestamp: Date.now()
|
|
2408
|
-
});
|
|
2409
2697
|
try {
|
|
2410
2698
|
const client = new MCPClient({
|
|
2411
2699
|
identity: this.identity,
|
|
@@ -2415,14 +2703,6 @@ var SSEConnectionManager = class {
|
|
|
2415
2703
|
await client.finishAuth(code);
|
|
2416
2704
|
this.clients.set(sessionId, client);
|
|
2417
2705
|
const tools = await client.listTools();
|
|
2418
|
-
this.emitConnectionEvent({
|
|
2419
|
-
type: "tools_discovered",
|
|
2420
|
-
sessionId,
|
|
2421
|
-
serverId: session.serverId ?? "unknown",
|
|
2422
|
-
toolCount: tools.tools.length,
|
|
2423
|
-
tools: tools.tools,
|
|
2424
|
-
timestamp: Date.now()
|
|
2425
|
-
});
|
|
2426
2706
|
return { success: true, toolCount: tools.tools.length };
|
|
2427
2707
|
} catch (error) {
|
|
2428
2708
|
this.emitConnectionEvent({
|
|
@@ -2500,9 +2780,9 @@ function createSSEHandler(options) {
|
|
|
2500
2780
|
});
|
|
2501
2781
|
writeSSEEvent(res, "connected", { timestamp: Date.now() });
|
|
2502
2782
|
const manager = new SSEConnectionManager(options, (event) => {
|
|
2503
|
-
if (
|
|
2783
|
+
if (isRpcResponseEvent(event)) {
|
|
2504
2784
|
writeSSEEvent(res, "rpc-response", event);
|
|
2505
|
-
} else if (
|
|
2785
|
+
} else if (isConnectionEvent(event)) {
|
|
2506
2786
|
writeSSEEvent(res, "connection", event);
|
|
2507
2787
|
} else {
|
|
2508
2788
|
writeSSEEvent(res, "observability", event);
|
|
@@ -2533,9 +2813,7 @@ function writeSSEEvent(res, event, data) {
|
|
|
2533
2813
|
}
|
|
2534
2814
|
|
|
2535
2815
|
// src/server/handlers/nextjs-handler.ts
|
|
2536
|
-
|
|
2537
|
-
return "id" in event && ("result" in event || "error" in event);
|
|
2538
|
-
}
|
|
2816
|
+
init_cjs_shims();
|
|
2539
2817
|
function createNextMcpHandler(options = {}) {
|
|
2540
2818
|
const {
|
|
2541
2819
|
getIdentity = (request) => new URL(request.url).searchParams.get("identity"),
|
|
@@ -2626,7 +2904,7 @@ data: ${JSON.stringify(data)}
|
|
|
2626
2904
|
(event) => {
|
|
2627
2905
|
if (isRpcResponseEvent(event)) {
|
|
2628
2906
|
sendSSE("rpc-response", event);
|
|
2629
|
-
} else if (
|
|
2907
|
+
} else if (isConnectionEvent(event)) {
|
|
2630
2908
|
sendSSE("connection", event);
|
|
2631
2909
|
} else {
|
|
2632
2910
|
sendSSE("observability", event);
|
|
@@ -2683,6 +2961,13 @@ data: ${JSON.stringify(data)}
|
|
|
2683
2961
|
}
|
|
2684
2962
|
return { GET, POST };
|
|
2685
2963
|
}
|
|
2964
|
+
|
|
2965
|
+
// src/client/index.ts
|
|
2966
|
+
init_cjs_shims();
|
|
2967
|
+
|
|
2968
|
+
// src/client/core/sse-client.ts
|
|
2969
|
+
init_cjs_shims();
|
|
2970
|
+
var CONNECTION_EVENT_INTERVAL_MS = 300;
|
|
2686
2971
|
var SSEClient = class {
|
|
2687
2972
|
constructor(options) {
|
|
2688
2973
|
this.options = options;
|
|
@@ -2787,10 +3072,12 @@ var SSEClient = class {
|
|
|
2787
3072
|
const data2 = await response.json();
|
|
2788
3073
|
return this.parseRpcResponse(data2);
|
|
2789
3074
|
}
|
|
2790
|
-
const data = await this.readRpcResponseFromStream(response
|
|
3075
|
+
const data = await this.readRpcResponseFromStream(response, {
|
|
3076
|
+
delayConnectionEvents: method === "connect" || method === "restoreSession" || method === "finishAuth"
|
|
3077
|
+
});
|
|
2791
3078
|
return this.parseRpcResponse(data);
|
|
2792
3079
|
}
|
|
2793
|
-
async readRpcResponseFromStream(response) {
|
|
3080
|
+
async readRpcResponseFromStream(response, options = {}) {
|
|
2794
3081
|
if (!response.body) {
|
|
2795
3082
|
throw new Error("Streaming response body is missing");
|
|
2796
3083
|
}
|
|
@@ -2798,7 +3085,7 @@ var SSEClient = class {
|
|
|
2798
3085
|
const decoder = new TextDecoder();
|
|
2799
3086
|
let buffer = "";
|
|
2800
3087
|
let rpcResponse = null;
|
|
2801
|
-
const dispatchBlock = (block) => {
|
|
3088
|
+
const dispatchBlock = async (block) => {
|
|
2802
3089
|
const lines = block.split("\n");
|
|
2803
3090
|
let eventName = "message";
|
|
2804
3091
|
const dataLines = [];
|
|
@@ -2826,6 +3113,9 @@ var SSEClient = class {
|
|
|
2826
3113
|
break;
|
|
2827
3114
|
case "connection":
|
|
2828
3115
|
this.options.onConnectionEvent?.(payload);
|
|
3116
|
+
if (options.delayConnectionEvents) {
|
|
3117
|
+
await this.sleep(CONNECTION_EVENT_INTERVAL_MS);
|
|
3118
|
+
}
|
|
2829
3119
|
break;
|
|
2830
3120
|
case "observability":
|
|
2831
3121
|
this.options.onObservabilityEvent?.(payload);
|
|
@@ -2845,18 +3135,21 @@ var SSEClient = class {
|
|
|
2845
3135
|
const separatorLength = separatorMatch[0].length;
|
|
2846
3136
|
const block = buffer.slice(0, separatorIndex);
|
|
2847
3137
|
buffer = buffer.slice(separatorIndex + separatorLength);
|
|
2848
|
-
dispatchBlock(block);
|
|
3138
|
+
await dispatchBlock(block);
|
|
2849
3139
|
separatorMatch = buffer.match(/\r?\n\r?\n/);
|
|
2850
3140
|
}
|
|
2851
3141
|
}
|
|
2852
3142
|
if (buffer.trim()) {
|
|
2853
|
-
dispatchBlock(buffer);
|
|
3143
|
+
await dispatchBlock(buffer);
|
|
2854
3144
|
}
|
|
2855
3145
|
if (!rpcResponse) {
|
|
2856
3146
|
throw new Error("Missing rpc-response event in streamed RPC result");
|
|
2857
3147
|
}
|
|
2858
3148
|
return rpcResponse;
|
|
2859
3149
|
}
|
|
3150
|
+
sleep(ms) {
|
|
3151
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
3152
|
+
}
|
|
2860
3153
|
parseRpcResponse(data) {
|
|
2861
3154
|
if ("result" in data) {
|
|
2862
3155
|
return data.result;
|
|
@@ -2922,6 +3215,9 @@ var SSEClient = class {
|
|
|
2922
3215
|
}
|
|
2923
3216
|
}
|
|
2924
3217
|
};
|
|
3218
|
+
|
|
3219
|
+
// src/client/core/app-host.ts
|
|
3220
|
+
init_cjs_shims();
|
|
2925
3221
|
var HOST_INFO = { name: "mcp-ts-host", version: "1.0.0" };
|
|
2926
3222
|
var SANDBOX_PERMISSIONS = [
|
|
2927
3223
|
"allow-scripts",
|
|
@@ -3219,7 +3515,11 @@ var AppHost = class {
|
|
|
3219
3515
|
}
|
|
3220
3516
|
};
|
|
3221
3517
|
|
|
3518
|
+
// src/shared/index.ts
|
|
3519
|
+
init_cjs_shims();
|
|
3520
|
+
|
|
3222
3521
|
// src/shared/types.ts
|
|
3522
|
+
init_cjs_shims();
|
|
3223
3523
|
function isConnectSuccess(response) {
|
|
3224
3524
|
return "success" in response && response.success === true;
|
|
3225
3525
|
}
|
|
@@ -3237,6 +3537,7 @@ function isCallToolSuccess(response) {
|
|
|
3237
3537
|
}
|
|
3238
3538
|
|
|
3239
3539
|
// src/shared/tool-utils.ts
|
|
3540
|
+
init_cjs_shims();
|
|
3240
3541
|
function getToolUiResourceUri(tool) {
|
|
3241
3542
|
const meta = tool._meta;
|
|
3242
3543
|
if (!meta?.ui) return void 0;
|